Skip to content

Commit

Permalink
fix: stdout with unicode characters
Browse files Browse the repository at this point in the history
  • Loading branch information
pirtim committed Mar 27, 2017
1 parent 582dfb9 commit 3d350fd
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 30 deletions.
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ Installation
---
1. Right click the preferences button in calibre, select get new plugins, scroll down the list and choose the DjVuMaker plugin to install
* Or clone this repo and install from source
```bash
git clone https://github.com/kfix/calibre_plugin_djvumaker
cd calibre_plugin_djvumaker
calibre-customize -b ./
```
2. [Required] Build the conversion programs (**fixme: works only on macOS**, check next section for solution)
```calibre-debug -R djvumaker -- backend install djvudigital```
```bash
git clone https://github.com/kfix/calibre_plugin_djvumaker
cd calibre_plugin_djvumaker
calibre-customize -b ./
```
2. [Required] Build the conversion programs (**fixme: works only on macOS**, check next section for solution)\
```calibre-debug -R djvumaker -- backend install djvudigital```
3. (Re)start Calibre and start converting your PDF books!

4. [Optional] go to Preferences -> Interface::Toolbars so you can place the DJVU menu where you see fit.
Expand All @@ -33,10 +33,10 @@ Installation of secondary backend
For all having troubles with building GsDjvu there is possibility to install secondary backend - [pdf2djvu](http://jwilk.net/software/pdf2djvu).
The "pdf2djvu" is a pdf to djvu converter developed by Jakub Wilk ([GitHub](https://github.com/jwilk/pdf2djvu)).
Although slower than djvudigital it's installation is much simplier. There is also a posibility to install it through *this* plugin:
```bash
calibre-debug -R djvumaker -- backend install pdf2djvu #(should work for any OS)
calibre-debug -R djvumaker -- backend set pdf2djvu
```
```bash
calibre-debug -R djvumaker -- backend install pdf2djvu #(should work for any OS)
calibre-debug -R djvumaker -- backend set pdf2djvu
```

Also you can just add pdf2djvu to your path and:
```calibre-debug -R djvumaker -- backend set pdf2djvu```
Expand All @@ -53,8 +53,8 @@ Therefore both packages must be built by the user in a complicated procedure, wh
Q: Why not write a "standard" Conversion Plugin for DjVU?
---
Calibre's conversion API currently supports two pipelines:
1) markup-based ebooks (book.xfmt > book.OEB > book.yfmt): useless for working on image-based scans.
2) comic books (*.cbz): unusably slow for library books due to its over-reliance on Python for its transform pipeline.
1. markup-based ebooks (book.xfmt > book.OEB > book.yfmt): useless for working on image-based scans.
2. comic books (*.cbz): unusably slow for library books due to its over-reliance on Python for its transform pipeline.

Only ghostscript+gsdjvu delivers usable conversion times for large scanned books.
Patching Calibre's conversion API to add a 3rd pipeline to support them would be far more involved than this sub-500-line plugin (excluding these explanations :-).
55 changes: 38 additions & 17 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def empty_function(*args, **kwargs):
class DJVUmaker(FileTypePlugin, InterfaceActionBase): #multiple inheritance for gui hooks!
name = PLUGINNAME # Name of the plugin
description = 'Convert raster-based document files (Postscript, PDF) to DJVU with GUI button and on-import'
# TODO: ON IMPORT?!?!
supported_platforms = ['linux', 'osx', 'windows'] # Platforms this plugin will run on
author = 'Joey Korkames' # The author of this plugin
version = PLUGINVER # The version number of this plugin
Expand All @@ -60,7 +61,7 @@ class DJVUmaker(FileTypePlugin, InterfaceActionBase): #multiple inheritance for
minimum_calibre_version = (2, 22, 0) #needs the new db api w/id() bugfix, and podofo.image_count()
actual_plugin = 'calibre_plugins.djvumaker.gui:ConvertToDJVUAction' #InterfaceAction plugin location
REGISTERED_BACKENDS = collections.OrderedDict()

@classmethod
def register_backend(cls, fun):
cls.REGISTERED_BACKENDS[fun.__name__] = fun
Expand All @@ -78,7 +79,7 @@ def __init__(self, *args, **kwargs):
DEFAULT_STORE_VALUES['use_backend'] = 'djvudigital'
else:
raise Exception('No djvudigital backend.')

# JSONConfig is a dict-like object,
# if coresponding .json file has not a specific key, it's got from .defaults
self.plugin_prefs = JSONConfig(os.path.join('plugins', PLUGINNAME))
Expand All @@ -96,8 +97,20 @@ def run_backend(self, *args, **kwargs):
kwargs['preferences'] = self.plugin_prefs
return self.REGISTERED_BACKENDS[use_backend](*args, **kwargs)

def customization_help(self, gui=False):
return 'Enter additional `djvudigital --help` command-flags here:'
def customization_help(self, gui=True):
# method required by calibre
# TODO: add info about current JSON settings
current_backend = self.plugin_prefs['use_backend']
flags = ''.join(self.plugin_prefs[current_backend]['flags'])
command = current_backend + flags
help_command = 'calibre-debug -r djvumaker -- --help'
info = ('<p>You can enter overwritting command and flags to create djvu files.<br>'
'Currently set command is: {}<br><br>'
'You can read more about plugin customization running "{}" from command line.</p>').format(command, help_command) # TODO: tab
return info

# return 'Enter additional `djvudigital --help` command-flags here:'

# os.system('MANPAGER=cat djvudigital --help')
#TODO: make custom config widget so we can have attrs for each of the wrappers:
# djvudigital minidjvu, c44, etc.
Expand All @@ -114,8 +127,8 @@ def cli_main(self, args):
return sys.exit()
options = parser.parse_args(args)
options.func(options)
def cli_test(self, args):

def cli_test(self, args):
prints(subprocess.check_output(['pwd']))

def cli_backend(self, args):
Expand All @@ -133,7 +146,7 @@ def cli_install_backend(self, args):
installed_backend = [k for k, v in {
item : self.plugin_prefs[item]['installed'] for item in self.REGISTERED_BACKENDS
}.iteritems() if v]
prints('Currently installed backends: {}'.format(
prints('Currently installed backends: {}'.format(
', '.join(installed_backend) if installed_backend else 'None'))
sys.exit()

Expand Down Expand Up @@ -184,7 +197,7 @@ def cli_set_backend(self, args):
else:
raise Exception('Backend not recognized.')
return None

def cli_convert(self, args):
printsd(args)
if args.all:
Expand All @@ -206,7 +219,7 @@ def cli_convert(self, args):
if is_rasterbook(args.path):
# `calibre-debug -r djvumaker test.pdf` -> tempfile(test.djvu)
djvu = self.run_backend(args.path)

if djvu:
prints(("\n\nopening djvused in subshell, press Ctrl+D to exit and"
"delete '%s'\n\n") % djvu)
Expand All @@ -217,10 +230,10 @@ def cli_convert(self, args):
os.system("stat '%s'" % djvu)
os.system("djvused -e dump '%s'" % djvu)
os.system("djvused -v '%s'" % djvu)
elif args.id is not None:
elif args.id is not None:
printsd('in convert by id')
# `calibre-debug -r djvumaker 123 #id(123).pdf` -> tempfile(id(123).djvu)
self.postimport(args.id, 'pdf') # bookid and book_format, can go really wrong
self.postimport(args.id, 'pdf') # bookid and book_format, can go really wrong

# -- calibre filetype plugin mandatory methods --
def run(self, path_to_ebook):
Expand Down Expand Up @@ -309,7 +322,7 @@ def prints(p): prints(p+'\n')
#elif hasattr(self, gui): #if we have the calibre gui running,
# we can give it a threadedjob and not use fork_job
else: #!fork_job & !gui
prints("Starts backend")
prints("Starts backend")
djvu = self.run_backend(path_to_ebook, cmdflags, log)
# if self.plugin_prefs['Options']['use_backend'] == 'djvudigital':
# djvu = djvudigital(path_to_ebook, cmdflags, log)
Expand Down Expand Up @@ -390,16 +403,23 @@ def wrapper(srcdoc, cmdflags=None, log=None, *args, **kwargs):
def merge_prints(*args, **kwargs):
if kwargs:
raise Exception('Passed **kwargs: {} to prints which uses sys.stdout.write'.format(kwargs))
line = ' '.join(('{}: '.format(PLUGINNAME),) + args)

# log('starting logging')
# log(str(args))
# log('end logging')
# log('stdout encoding: ' + sys.stdout.encoding)

args = map(force_unicode, args)
line = ' '.join(['{}: '.format(PLUGINNAME)] + args)
return line

if log: #divert our streaming output printing to the caller's logger
def prints(*args, **kwargs):
def prints(*args, **kwargs):
log_prints = partial(log.prints, 1) #log.print(INFO, yaddayadda)
return log_prints(merge_prints(*args, **kwargs))
else:
#def prints(p): print p
# prints = sys.stdout.write
# prints = sys.stdout.write
def prints(*args, **kwargs):
return sys.stdout.write(merge_prints(*args, **kwargs))

Expand All @@ -418,6 +438,7 @@ def prints(*args, **kwargs):

proc = subprocess.Popen(cmd, env=env, bufsize=cmdbuf, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
# TODO: aborting doesn't work
#stderr:csepdjvu, stdout: ghostscript & djvudigital
if cmdbuf > 0: #stream the output
while proc.poll() is None:
Expand All @@ -432,7 +453,7 @@ def prints(*args, **kwargs):
if err.errno == errno.ENOENT:
prints(
('$PATH[{}]\n/{} script not available to perform conversion:'
'{} must be installed').format(os.environ['PATH'], cmd[0],
'{} must be installed').format(os.environ['PATH'], cmd[0],
fun.__name__))
return False
if proc.returncode != 0:
Expand Down Expand Up @@ -468,7 +489,7 @@ def pdf2djvu(srcdoc, cmdflags, djvu, preferences):
@DJVUmaker.register_backend
@job_handler
def djvudigital(srcdoc, cmdflags, djvu, preferences):
'''djvudigital backend shell command generation'''
'''djvudigital backend shell command generation'''
raise_if_not_supported(srcdoc, ['pdf', 'ps'])
return ['djvudigital'] + cmdflags + [srcdoc, djvu.name] # command passed to subprocess

Expand Down
2 changes: 2 additions & 0 deletions utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,8 @@ def unpack_zip_or_tar(PLUGINNAME, fpath, log):
# Python 2.7 Standard Library cannot unpack tar.xz archive, do this manually or through shell
# it can not work on macOS
subprocess.call(['tar', 'xf', fpath, '-C', os.path.dirname(fpath)])
# DEBUG TODO: you have to make it still...
# deosn't work for linux or mac then
log('Extracted downloaded archive')
os.remove(fpath)
log('Removed downloaded archive')
Expand Down

0 comments on commit 3d350fd

Please sign in to comment.