1 # This file is part of Librarian, licensed under GNU Affero GPLv3 or later.
 
   2 # Copyright © Fundacja Wolne Lektury. See NOTICE for more information.
 
   6 from librarian import DirDocProvider, ParseError
 
   7 from librarian.parser import WLDocument
 
   8 from librarian.cover import make_cover, COVER_CLASSES
 
  12     """Option for optparse. Use it like `optparse.OptionParser.add_option`."""
 
  13     def __init__(self, *names, **options):
 
  15         self.options = options
 
  17     def add(self, parser):
 
  18         parser.add_option(*self.names, **self.options)
 
  21         return self.options['dest']
 
  23     def value(self, options):
 
  24         return getattr(options, self.name())
 
  28     """A class for creating book2... scripts.
 
  30     Subclass it for any format you want to convert to.
 
  32     format_name = None  # Set format name, like "PDF".
 
  33     ext = None  # Set file extension, like "pdf".
 
  34     uses_cover = False  # Can it add a cover?
 
  35     cover_optional = True  # Only relevant if uses_cover
 
  36     uses_provider = False  # Does it need a DocProvider?
 
  37     transform = None  # Transform method. Uses WLDocument.as_{ext} by default.
 
  38     parser_options = []  # List of Option objects for additional parser args.
 
  39     # List of Option objects for additional transform args.
 
  40     transform_options = []
 
  41     # List of Option objects for supported transform flags.
 
  46         # Parse commandline arguments
 
  47         usage = """Usage: %%prog [options] SOURCE [SOURCE...]
 
  48         Convert SOURCE files to %s format.""" % cls.format_name
 
  50         parser = optparse.OptionParser(usage=usage)
 
  53             '-v', '--verbose', action='store_true', dest='verbose',
 
  54             default=False, help='print status messages to stdout')
 
  56             '-d', '--make-dir', action='store_true', dest='make_dir',
 
  58             help='create a directory for author and put the output file in it'
 
  61             '-o', '--output-file', dest='output_file', metavar='FILE',
 
  62             help='specifies the output file')
 
  64             '-O', '--output-dir', dest='output_dir', metavar='DIR',
 
  65             help='specifies the directory for output'
 
  68             if cls.cover_optional:
 
  70                     '-c', '--with-cover', action='store_true',
 
  71                     dest='with_cover', default=False,
 
  72                     help='create default cover'
 
  75                 '-C', '--image-cache', dest='image_cache', metavar='URL',
 
  76                 help='prefix for image download cache'
 
  77                 + (' (implies --with-cover)' if cls.cover_optional else '')
 
  80                 '--cover-class', dest='cover_class',
 
  81                 help='cover class name'
 
  85                 + cls.transform_options
 
  86                 + cls.transform_flags):
 
  89         options, input_filenames = parser.parse_args()
 
  91         if len(input_filenames) < 1:
 
  95         # Prepare additional args for parser.
 
  97         for option in cls.parser_options:
 
  98             parser_args[option.name()] = option.value(options)
 
  99         # Prepare additional args for transform method.
 
 101         for option in cls.transform_options:
 
 102             transform_args[option.name()] = option.value(options)
 
 103         # Add flags to transform_args, if any.
 
 106             for flag in cls.transform_flags
 
 107             if flag.value(options)
 
 110             transform_args['flags'] = transform_flags
 
 112             transform_args['verbose'] = True
 
 113         # Add cover support, if any.
 
 115             if options.image_cache:
 
 116                 def cover_class(book_info, *args, **kwargs):
 
 118                         book_info, image_cache=options.image_cache,
 
 119                         cover_class=options.cover_class,
 
 122                 transform_args['cover'] = cover_class
 
 123             elif not cls.cover_optional or options.with_cover:
 
 124                 cover_class = COVER_CLASSES.get(
 
 125                     options.cover_class, make_cover)
 
 126                 transform_args['cover'] = cover_class
 
 130             for main_input in input_filenames:
 
 134             if isinstance(main_input, bytes):
 
 135                 main_input = main_input.decode('utf-8')
 
 137             # Where to find input?
 
 138             if cls.uses_provider:
 
 139                 path, fname = os.path.realpath(main_input).rsplit('/', 1)
 
 140                 provider = DirDocProvider(path)
 
 144             # Where to write output?
 
 145             if not (options.output_file or options.output_dir):
 
 146                 output_file = os.path.splitext(main_input)[0] + '.' + cls.ext
 
 148                 output_file = options.output_file
 
 150             # Do the transformation.
 
 151             doc = WLDocument.from_file(main_input, provider=provider,
 
 153             transform = cls.transform
 
 154             if transform is None:
 
 155                 transform = getattr(WLDocument, 'as_%s' % cls.ext)
 
 156             output = transform(doc, **transform_args)
 
 158             doc.save_output_file(output, output_file, options.output_dir,
 
 159                                  options.make_dir, cls.ext)
 
 161         except ParseError as e:
 
 162             print('%(file)s:%(name)s:%(message)s' % {
 
 164                 'name': e.__class__.__name__,