mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Pull from driver-dev
This commit is contained in:
commit
8be2541738
@ -292,7 +292,8 @@ from calibre.ebooks.oeb.output import OEBOutput
|
|||||||
from calibre.ebooks.epub.output import EPUBOutput
|
from calibre.ebooks.epub.output import EPUBOutput
|
||||||
from calibre.ebooks.txt.output import TXTOutput
|
from calibre.ebooks.txt.output import TXTOutput
|
||||||
from calibre.ebooks.pdf.output import PDFOutput
|
from calibre.ebooks.pdf.output import PDFOutput
|
||||||
from calibre.ebooks.pdb.ereader.output import EREADEROutput
|
from calibre.ebooks.pml.input import PMLInput
|
||||||
|
from calibre.ebooks.pml.output import PMLOutput
|
||||||
from calibre.customize.profiles import input_profiles, output_profiles
|
from calibre.customize.profiles import input_profiles, output_profiles
|
||||||
|
|
||||||
from calibre.devices.prs500.driver import PRS500
|
from calibre.devices.prs500.driver import PRS500
|
||||||
@ -303,11 +304,14 @@ from calibre.devices.kindle.driver import KINDLE
|
|||||||
from calibre.devices.kindle.driver import KINDLE2
|
from calibre.devices.kindle.driver import KINDLE2
|
||||||
from calibre.devices.blackberry.driver import BLACKBERRY
|
from calibre.devices.blackberry.driver import BLACKBERRY
|
||||||
from calibre.devices.eb600.driver import EB600
|
from calibre.devices.eb600.driver import EB600
|
||||||
|
from calibre.devices.jetbook.driver import JETBOOK
|
||||||
|
|
||||||
plugins = [HTML2ZIP, EPUBInput, MOBIInput, PDBInput, PDFInput, HTMLInput,
|
plugins = [HTML2ZIP, EPUBInput, MOBIInput, PDBInput, PDFInput, HTMLInput,
|
||||||
TXTInput, OEBOutput, TXTOutput, PDFOutput, LITInput, ComicInput,
|
TXTInput, OEBOutput, TXTOutput, PDFOutput, LITInput, ComicInput,
|
||||||
FB2Input, ODTInput, RTFInput, EPUBOutput, EREADEROutput, RecipeInput]
|
FB2Input, ODTInput, RTFInput, EPUBOutput, RecipeInput, PMLInput,
|
||||||
plugins += [PRS505, PRS700, CYBOOKG3, KINDLE, KINDLE2, BLACKBERRY, EB600]
|
PMLOutput]
|
||||||
|
plugins += [PRS505, PRS700, CYBOOKG3, KINDLE, KINDLE2, BLACKBERRY, EB600, \
|
||||||
|
JETBOOK]
|
||||||
plugins += [x for x in list(locals().values()) if isinstance(x, type) and \
|
plugins += [x for x in list(locals().values()) if isinstance(x, type) and \
|
||||||
x.__name__.endswith('MetadataReader')]
|
x.__name__.endswith('MetadataReader')]
|
||||||
plugins += [x for x in list(locals().values()) if isinstance(x, type) and \
|
plugins += [x for x in list(locals().values()) if isinstance(x, type) and \
|
||||||
|
@ -212,6 +212,30 @@ class DevicePlugin(Plugin):
|
|||||||
'''
|
'''
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def config_widget(cls):
|
||||||
|
'''
|
||||||
|
Should return a QWidget. The QWidget contains the settings for the device interface
|
||||||
|
'''
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def save_settings(cls, settings_widget):
|
||||||
|
'''
|
||||||
|
Should save settings to disk. Takes the widget created in config_widget
|
||||||
|
and saves all settings to disk.
|
||||||
|
'''
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def settings(cls):
|
||||||
|
'''
|
||||||
|
Should return an opts object. The opts object should have one attribute
|
||||||
|
`formats` whihc is an ordered list of formats for the device.
|
||||||
|
'''
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BookList(list):
|
class BookList(list):
|
||||||
|
@ -7,7 +7,7 @@ Device driver for Ectaco Jetbook firmware >= JL04_v030e
|
|||||||
import os, re, sys, shutil
|
import os, re, sys, shutil
|
||||||
from itertools import cycle
|
from itertools import cycle
|
||||||
|
|
||||||
from calibre.devices.usbms.driver import USBMS, metadata_from_formats
|
from calibre.devices.usbms.driver import USBMS
|
||||||
from calibre import sanitize_file_name as sanitize
|
from calibre import sanitize_file_name as sanitize
|
||||||
|
|
||||||
class JETBOOK(USBMS):
|
class JETBOOK(USBMS):
|
||||||
@ -99,6 +99,7 @@ class JETBOOK(USBMS):
|
|||||||
|
|
||||||
return txt
|
return txt
|
||||||
|
|
||||||
|
from calibre.devices.usbms.driver import metadata_from_formats
|
||||||
mi = metadata_from_formats([path])
|
mi = metadata_from_formats([path])
|
||||||
|
|
||||||
if (mi.title==_('Unknown') or mi.authors==[_('Unknown')]) \
|
if (mi.title==_('Unknown') or mi.authors==[_('Unknown')]) \
|
||||||
|
@ -13,7 +13,7 @@ from calibre import __version__, iswindows, __appname__
|
|||||||
from calibre.devices.errors import PathError
|
from calibre.devices.errors import PathError
|
||||||
from calibre.utils.terminfo import TerminalController
|
from calibre.utils.terminfo import TerminalController
|
||||||
from calibre.devices.errors import ArgumentError, DeviceError, DeviceLocked
|
from calibre.devices.errors import ArgumentError, DeviceError, DeviceLocked
|
||||||
from calibre.devices import devices
|
from calibre.customize.ui import device_plugins
|
||||||
from calibre.devices.scanner import DeviceScanner
|
from calibre.devices.scanner import DeviceScanner
|
||||||
|
|
||||||
MINIMUM_COL_WIDTH = 12 #: Minimum width of columns in ls output
|
MINIMUM_COL_WIDTH = 12 #: Minimum width of columns in ls output
|
||||||
@ -203,7 +203,7 @@ def main():
|
|||||||
_wmi = wmi.WMI()
|
_wmi = wmi.WMI()
|
||||||
scanner = DeviceScanner(_wmi)
|
scanner = DeviceScanner(_wmi)
|
||||||
scanner.scan()
|
scanner.scan()
|
||||||
for d in devices():
|
for d in device_plugins():
|
||||||
if scanner.is_device_connected(d):
|
if scanner.is_device_connected(d):
|
||||||
dev = d(log_packets=options.log_packets)
|
dev = d(log_packets=options.log_packets)
|
||||||
|
|
||||||
|
@ -10,9 +10,10 @@ import os, subprocess, time, re
|
|||||||
|
|
||||||
from calibre.devices.interface import DevicePlugin
|
from calibre.devices.interface import DevicePlugin
|
||||||
from calibre.devices.errors import DeviceError
|
from calibre.devices.errors import DeviceError
|
||||||
|
from calibre.devices.usbms.deviceconfig import DeviceConfig
|
||||||
from calibre import iswindows, islinux, isosx, __appname__
|
from calibre import iswindows, islinux, isosx, __appname__
|
||||||
|
|
||||||
class Device(DevicePlugin):
|
class Device(DeviceConfig, DevicePlugin):
|
||||||
'''
|
'''
|
||||||
This class provides logic common to all drivers for devices that export themselves
|
This class provides logic common to all drivers for devices that export themselves
|
||||||
as USB Mass Storage devices. If you are writing such a driver, inherit from this
|
as USB Mass Storage devices. If you are writing such a driver, inherit from this
|
||||||
@ -94,7 +95,7 @@ class Device(DevicePlugin):
|
|||||||
for pid in cls.PRODUCT_ID:
|
for pid in cls.PRODUCT_ID:
|
||||||
fdi_base_values = dict(
|
fdi_base_values = dict(
|
||||||
app=__appname__,
|
app=__appname__,
|
||||||
deviceclass=cls.__name__,
|
deviceclass=cls.__class__.__name__,
|
||||||
vendor_id=hex(vid),
|
vendor_id=hex(vid),
|
||||||
product_id=hex(pid),
|
product_id=hex(pid),
|
||||||
main_memory=cls.MAIN_MEMORY_VOLUME_LABEL,
|
main_memory=cls.MAIN_MEMORY_VOLUME_LABEL,
|
||||||
|
38
src/calibre/devices/usbms/deviceconfig.py
Normal file
38
src/calibre/devices/usbms/deviceconfig.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
__license__ = 'GPL 3'
|
||||||
|
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
from calibre.utils.config import Config, ConfigProxy
|
||||||
|
|
||||||
|
class DeviceConfig(object):
|
||||||
|
|
||||||
|
HELP_MESSAGE = _('Ordered list of formats the device will accept')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _config(cls):
|
||||||
|
c = Config('device_drivers_%s' % cls.__class__.__name__, _('settings for device drivers'))
|
||||||
|
c.add_opt('format_map', default=cls.FORMATS, help=cls.HELP_MESSAGE)
|
||||||
|
return c
|
||||||
|
|
||||||
|
def _configProxy(cls):
|
||||||
|
return ConfigProxy(cls._config())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def config_widget(cls):
|
||||||
|
from calibre.gui2.device_drivers.configwidget import ConfigWidget
|
||||||
|
cw = ConfigWidget(cls.configProxy(cls._config()), cls.FORMATS)
|
||||||
|
return cw
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def save_settings(cls, config_widget):
|
||||||
|
cls.configProxy(cls._config())['format_map'] = config_widget.format_map()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def settings(cls):
|
||||||
|
return cls._config().parse()
|
||||||
|
|
||||||
|
def customization_help(cls, gui=False):
|
||||||
|
return cls.HELP_MESSAGE
|
||||||
|
|
@ -251,19 +251,23 @@ OptionRecommendation(name='page_breaks_before',
|
|||||||
|
|
||||||
OptionRecommendation(name='margin_top',
|
OptionRecommendation(name='margin_top',
|
||||||
recommended_value=5.0, level=OptionRecommendation.LOW,
|
recommended_value=5.0, level=OptionRecommendation.LOW,
|
||||||
help=_('Set the top margin in pts. Default is %default')),
|
help=_('Set the top margin in pts. Default is %default. '
|
||||||
|
'Note: 72 pts equals 1 inch')),
|
||||||
|
|
||||||
OptionRecommendation(name='margin_bottom',
|
OptionRecommendation(name='margin_bottom',
|
||||||
recommended_value=5.0, level=OptionRecommendation.LOW,
|
recommended_value=5.0, level=OptionRecommendation.LOW,
|
||||||
help=_('Set the bottom margin in pts. Default is %default')),
|
help=_('Set the bottom margin in pts. Default is %default. '
|
||||||
|
'Note: 72 pts equals 1 inch')),
|
||||||
|
|
||||||
OptionRecommendation(name='margin_left',
|
OptionRecommendation(name='margin_left',
|
||||||
recommended_value=5.0, level=OptionRecommendation.LOW,
|
recommended_value=5.0, level=OptionRecommendation.LOW,
|
||||||
help=_('Set the left margin in pts. Default is %default')),
|
help=_('Set the left margin in pts. Default is %default. '
|
||||||
|
'Note: 72 pts equals 1 inch')),
|
||||||
|
|
||||||
OptionRecommendation(name='margin_right',
|
OptionRecommendation(name='margin_right',
|
||||||
recommended_value=5.0, level=OptionRecommendation.LOW,
|
recommended_value=5.0, level=OptionRecommendation.LOW,
|
||||||
help=_('Set the right margin in pts. Default is %default')),
|
help=_('Set the right margin in pts. Default is %default. '
|
||||||
|
'Note: 72 pts equals 1 inch')),
|
||||||
|
|
||||||
OptionRecommendation(name='dont_justify',
|
OptionRecommendation(name='dont_justify',
|
||||||
recommended_value=False, level=OptionRecommendation.LOW,
|
recommended_value=False, level=OptionRecommendation.LOW,
|
||||||
|
@ -33,7 +33,7 @@ from calibre.ebooks.lrf.html.table import Table
|
|||||||
from calibre import filename_to_utf8, setup_cli_handlers, __appname__, \
|
from calibre import filename_to_utf8, setup_cli_handlers, __appname__, \
|
||||||
fit_image, preferred_encoding
|
fit_image, preferred_encoding
|
||||||
from calibre.ptempfile import PersistentTemporaryFile
|
from calibre.ptempfile import PersistentTemporaryFile
|
||||||
from calibre.devices.interface import Device
|
from calibre.devices.interface import DevicePlugin as Device
|
||||||
from calibre.ebooks.lrf.html.color_map import lrs_color
|
from calibre.ebooks.lrf.html.color_map import lrs_color
|
||||||
from calibre.ebooks.chardet import xml_to_unicode
|
from calibre.ebooks.chardet import xml_to_unicode
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
__license__ = 'GPL 3'
|
__license__ = 'GPL 3'
|
||||||
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
|
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
@ -15,7 +15,7 @@ from calibre.ebooks import DRMError
|
|||||||
from calibre.ebooks.metadata import MetaInformation
|
from calibre.ebooks.metadata import MetaInformation
|
||||||
from calibre.ebooks.pdb.formatreader import FormatReader
|
from calibre.ebooks.pdb.formatreader import FormatReader
|
||||||
from calibre.ebooks.pdb.ereader import EreaderError
|
from calibre.ebooks.pdb.ereader import EreaderError
|
||||||
from calibre.ebooks.pdb.ereader.pmlconverter import pml_to_html, \
|
from calibre.ebooks.pml.pmlconverter import pml_to_html, \
|
||||||
footnote_sidebar_to_html
|
footnote_sidebar_to_html
|
||||||
from calibre.ebooks.mobi.palmdoc import decompress_doc
|
from calibre.ebooks.mobi.palmdoc import decompress_doc
|
||||||
from calibre.ebooks.metadata.opf2 import OPFCreator
|
from calibre.ebooks.metadata.opf2 import OPFCreator
|
||||||
|
@ -11,7 +11,7 @@ import Image, cStringIO
|
|||||||
from calibre.ebooks.oeb.base import OEB_IMAGES
|
from calibre.ebooks.oeb.base import OEB_IMAGES
|
||||||
from calibre.ebooks.pdb.header import PdbHeaderBuilder
|
from calibre.ebooks.pdb.header import PdbHeaderBuilder
|
||||||
from calibre.ebooks.pdb.ereader import image_name
|
from calibre.ebooks.pdb.ereader import image_name
|
||||||
from calibre.ebooks.pdb.ereader.pmlconverter import html_to_pml
|
from calibre.ebooks.pml.pmlconverter import html_to_pml
|
||||||
|
|
||||||
IDENTITY = 'PNPdPPrs'
|
IDENTITY = 'PNPdPPrs'
|
||||||
|
|
||||||
@ -31,13 +31,14 @@ class Writer(object):
|
|||||||
|
|
||||||
lengths = [len(i) for i in sections]
|
lengths = [len(i) for i in sections]
|
||||||
|
|
||||||
pdbHeaderBuilder = PdbHeaderBuilder(IDENTITY, 'test book')
|
pdbHeaderBuilder = PdbHeaderBuilder(IDENTITY, '')
|
||||||
pdbHeaderBuilder.build_header(lengths, out_stream)
|
pdbHeaderBuilder.build_header(lengths, out_stream)
|
||||||
|
|
||||||
for item in sections:
|
for item in sections:
|
||||||
out_stream.write(item)
|
out_stream.write(item)
|
||||||
|
|
||||||
def _text(self, pages):
|
def _text(self, pages):
|
||||||
|
# Todo: Split pages over 65505 Bytes
|
||||||
pml_pages = []
|
pml_pages = []
|
||||||
|
|
||||||
for page in pages:
|
for page in pages:
|
||||||
@ -46,6 +47,7 @@ class Writer(object):
|
|||||||
return pml_pages
|
return pml_pages
|
||||||
|
|
||||||
def _images(self, manifest):
|
def _images(self, manifest):
|
||||||
|
# Todo: resize images over 65505 Bytes
|
||||||
images = []
|
images = []
|
||||||
|
|
||||||
for item in manifest:
|
for item in manifest:
|
||||||
@ -69,9 +71,19 @@ class Writer(object):
|
|||||||
return images
|
return images
|
||||||
|
|
||||||
def _metadata(self, metadata):
|
def _metadata(self, metadata):
|
||||||
return 'test\x00\x00\x00\x00\x00'
|
'''
|
||||||
|
Metadata takes the form:
|
||||||
|
title\x00
|
||||||
|
author\x00
|
||||||
|
copyright\x00
|
||||||
|
publisher\x00
|
||||||
|
isbn\x00
|
||||||
|
'''
|
||||||
|
return '\x00\x00\x00\x00\x00'
|
||||||
|
|
||||||
def _header_record(self, text_items, image_items):
|
def _header_record(self, text_items, image_items):
|
||||||
|
# Todo: Find out more about header and add correct values to the file
|
||||||
|
# can be read by eReader reader software.
|
||||||
'''
|
'''
|
||||||
text_items = the number of text pages
|
text_items = the number of text pages
|
||||||
image_items = the number of images
|
image_items = the number of images
|
||||||
|
@ -63,7 +63,9 @@ class PDFOutput(OutputFormatPlugin):
|
|||||||
|
|
||||||
def convert_text(self, oeb_book):
|
def convert_text(self, oeb_book):
|
||||||
with TemporaryDirectory('_pdf_out') as oebdir:
|
with TemporaryDirectory('_pdf_out') as oebdir:
|
||||||
OEBOutput(None).convert(oeb_book, oebdir, self.input_plugin, self.opts, self.log)
|
from calibre.customize.ui import plugin_for_output_format
|
||||||
|
oeb_output = plugin_for_output_format('oeb')
|
||||||
|
oeb_output.convert(oeb, oeb_dir, self.input_plugin, self.opts, self.log)
|
||||||
|
|
||||||
opfpath = glob.glob(os.path.join(oebdir, '*.opf'))[0]
|
opfpath = glob.glob(os.path.join(oebdir, '*.opf'))[0]
|
||||||
opf = OPF(opfpath, os.path.dirname(opfpath))
|
opf = OPF(opfpath, os.path.dirname(opfpath))
|
||||||
|
0
src/calibre/ebooks/pml/__init__.py
Normal file
0
src/calibre/ebooks/pml/__init__.py
Normal file
99
src/calibre/ebooks/pml/input.py
Normal file
99
src/calibre/ebooks/pml/input.py
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
import glob, os, shutil
|
||||||
|
|
||||||
|
from calibre.customize.conversion import InputFormatPlugin
|
||||||
|
from calibre.ptempfile import TemporaryDirectory
|
||||||
|
from calibre.utils.zipfile import ZipFile
|
||||||
|
from calibre.ebooks.pml.pmlconverter import pml_to_html
|
||||||
|
from calibre.ebooks.metadata.opf2 import OPFCreator
|
||||||
|
|
||||||
|
class PMLInput(InputFormatPlugin):
|
||||||
|
|
||||||
|
name = 'PML Input'
|
||||||
|
author = 'John Schember'
|
||||||
|
description = 'Convert PML to OEB'
|
||||||
|
# pmlz is a zip file containing pml files and png images.
|
||||||
|
file_types = set(['pml', 'pmlz'])
|
||||||
|
|
||||||
|
def process_pml(self, pml_path, html_path):
|
||||||
|
pclose = False
|
||||||
|
hclose = False
|
||||||
|
|
||||||
|
if not hasattr(pml_path, 'read'):
|
||||||
|
pml_stream = open(pml_path, 'rb')
|
||||||
|
pclose = True
|
||||||
|
else:
|
||||||
|
pml_stream = pml_path
|
||||||
|
|
||||||
|
if not hasattr(html_path, 'write'):
|
||||||
|
html_stream = open(html_path, 'wb')
|
||||||
|
hclose = True
|
||||||
|
else:
|
||||||
|
html_stream = html_path
|
||||||
|
|
||||||
|
ienc = pml_stream.encoding if pml_stream.encoding else 'utf-8'
|
||||||
|
if self.options.input_encoding:
|
||||||
|
ienc = self.options.input_encoding
|
||||||
|
|
||||||
|
html = pml_to_html(pml_stream.read().decode(ienc))
|
||||||
|
html_stream.write('<html><head><title /></head><body>' + html + '</body></html>')
|
||||||
|
|
||||||
|
if pclose:
|
||||||
|
pml_stream.close()
|
||||||
|
if hclose:
|
||||||
|
html_stream.close()
|
||||||
|
|
||||||
|
def convert(self, stream, options, file_ext, log,
|
||||||
|
accelerators):
|
||||||
|
self.options = options
|
||||||
|
pages, images = [], []
|
||||||
|
|
||||||
|
if file_ext == 'pmlz':
|
||||||
|
with TemporaryDirectory('_unpmlz') as tdir:
|
||||||
|
zf = ZipFile(stream)
|
||||||
|
zf.extractall(tdir)
|
||||||
|
|
||||||
|
pmls = glob.glob(os.path.join(tdir, '*.pml'))
|
||||||
|
for pml in pmls:
|
||||||
|
html_name = os.path.splitext(os.path.basename(pml))[0]+'.html'
|
||||||
|
html_path = os.path.join(os.getcwd(), html_name)
|
||||||
|
|
||||||
|
pages.append(html_name)
|
||||||
|
self.process_pml(pml, html_path)
|
||||||
|
|
||||||
|
imgs = glob.glob(os.path.join(tdir, '*.png'))
|
||||||
|
for img in imgs:
|
||||||
|
pimg_name = os.path.basename(img)
|
||||||
|
pimg_path = os.path.join(os.getcwd(), 'images', pimg_name)
|
||||||
|
|
||||||
|
images.append(pimg_name)
|
||||||
|
|
||||||
|
shutil.move(img, pimg_path)
|
||||||
|
else:
|
||||||
|
self.process_pml(stream, 'index.html')
|
||||||
|
|
||||||
|
pages.append('index.html')
|
||||||
|
images = []
|
||||||
|
|
||||||
|
# We want pages to be orded alphabetically.
|
||||||
|
pages.sort()
|
||||||
|
|
||||||
|
manifest_items = []
|
||||||
|
for item in pages+images:
|
||||||
|
manifest_items.append((item, None))
|
||||||
|
|
||||||
|
from calibre.ebooks.metadata.meta import get_metadata
|
||||||
|
mi = get_metadata(stream, 'pml')
|
||||||
|
opf = OPFCreator(os.getcwd(), mi)
|
||||||
|
opf.create_manifest(manifest_items)
|
||||||
|
opf.create_spine(pages)
|
||||||
|
with open('metadata.opf', 'wb') as opffile:
|
||||||
|
opf.render(opffile)
|
||||||
|
|
||||||
|
return os.path.join(os.getcwd(), 'metadata.opf')
|
||||||
|
|
55
src/calibre/ebooks/pml/output.py
Normal file
55
src/calibre/ebooks/pml/output.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
__license__ = 'GPL 3'
|
||||||
|
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
import Image, cStringIO
|
||||||
|
|
||||||
|
from calibre.customize.conversion import OutputFormatPlugin
|
||||||
|
from calibre.ptempfile import TemporaryDirectory
|
||||||
|
from calibre.utils.zipfile import ZipFile
|
||||||
|
from calibre.ebooks.oeb.base import OEB_IMAGES
|
||||||
|
from calibre.ebooks.pml.pmlconverter import html_to_pml
|
||||||
|
|
||||||
|
class PMLOutput(OutputFormatPlugin):
|
||||||
|
|
||||||
|
name = 'PML Output'
|
||||||
|
author = 'John Schember'
|
||||||
|
file_type = 'pmlz'
|
||||||
|
|
||||||
|
def convert(self, oeb_book, output_path, input_plugin, opts, log):
|
||||||
|
with TemporaryDirectory('_pmlz_output') as tdir:
|
||||||
|
self.process_spine(oeb_book.spine, tdir)
|
||||||
|
self.write_images(oeb_book.manifest, tdir)
|
||||||
|
|
||||||
|
pmlz = ZipFile(output_path, 'w')
|
||||||
|
pmlz.add_dir(tdir)
|
||||||
|
|
||||||
|
def process_spine(self, spine, out_dir):
|
||||||
|
for item in spine:
|
||||||
|
html = html_to_pml(unicode(item)).encode('utf-8')
|
||||||
|
|
||||||
|
name = os.path.splitext(os.path.basename(item.href))[0] + '.pml'
|
||||||
|
path = os.path.join(out_dir, name)
|
||||||
|
|
||||||
|
with open(path, 'wb') as out:
|
||||||
|
out.write(html)
|
||||||
|
|
||||||
|
def write_images(self, manifest, out_dir):
|
||||||
|
for item in manifest:
|
||||||
|
if item.media_type in OEB_IMAGES:
|
||||||
|
im = Image.open(cStringIO.StringIO(item.data))
|
||||||
|
|
||||||
|
data = cStringIO.StringIO()
|
||||||
|
im.save(data, 'PNG')
|
||||||
|
data = data.getvalue()
|
||||||
|
|
||||||
|
name = os.path.splitext(os.path.basename(item.href))[0] + '.png'
|
||||||
|
path = os.path.join(out_dir, name)
|
||||||
|
|
||||||
|
with open(path, 'wb') as out:
|
||||||
|
out.write(data)
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import with_statement
|
|
||||||
'''
|
'''
|
||||||
Convert pml markup to and from html
|
Convert pml markup to and from html
|
||||||
'''
|
'''
|
||||||
@ -47,6 +47,10 @@ PML_HTML_RULES = [
|
|||||||
(re.compile(r'\\Sd="(?P<target>.+?)"(?P<text>.+?)\\Sd'), lambda match: '<a href="#sidebar-%s">%s</a>' % (match.group('target'), match.group('text'))),
|
(re.compile(r'\\Sd="(?P<target>.+?)"(?P<text>.+?)\\Sd'), lambda match: '<a href="#sidebar-%s">%s</a>' % (match.group('target'), match.group('text'))),
|
||||||
(re.compile(r'\\I'), lambda match: ''),
|
(re.compile(r'\\I'), lambda match: ''),
|
||||||
|
|
||||||
|
# Sidebar and Footnotes
|
||||||
|
(re.compile(r'<sidebar\s+id="(?P<target>.+?)">\s*(?P<text>.+?)\s*</sidebar>', re.DOTALL), lambda match: '<div id="sidebar-%s">%s</div>' % (match.group('target'), match.group('text'))),
|
||||||
|
(re.compile(r'<footnote\s+id="(?P<target>.+?)">\s*(?P<text>.+?)\s*</footnote>', re.DOTALL), lambda match: '<div id="footnote-%s">%s</div>' % (match.group('target'), match.group('text'))),
|
||||||
|
|
||||||
# eReader files are one paragraph per line.
|
# eReader files are one paragraph per line.
|
||||||
# This forces the lines to wrap properly.
|
# This forces the lines to wrap properly.
|
||||||
(re.compile('^(?P<text>.+)$', re.MULTILINE), lambda match: '<p>%s</p>' % match.group('text')),
|
(re.compile('^(?P<text>.+)$', re.MULTILINE), lambda match: '<p>%s</p>' % match.group('text')),
|
46
src/calibre/gui2/device_drivers/configwidget.py
Normal file
46
src/calibre/gui2/device_drivers/configwidget.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
__license__ = 'GPL 3'
|
||||||
|
__copyright__ = '2009, John Schember <john@nachtimwald.com>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
from PyQt4.Qt import QWidget, QListWidgetItem, Qt, QVariant, SIGNAL
|
||||||
|
|
||||||
|
from calibre.gui2.device_drivers.configwidget_ui import Ui_ConfigWidget
|
||||||
|
|
||||||
|
class ConfigWidget(QWidget, Ui_ConfigWidget):
|
||||||
|
|
||||||
|
def __init__(self, config, all_formats):
|
||||||
|
QWidget.__init__(self)
|
||||||
|
Ui_ConfigWidget.__init__(self)
|
||||||
|
self.setupUi(self)
|
||||||
|
|
||||||
|
self.config = config
|
||||||
|
|
||||||
|
format_map = config['format_map']
|
||||||
|
disabled_formats = list(set(all_formats).difference(format_map))
|
||||||
|
for format in format_map + disabled_formats:
|
||||||
|
item = QListWidgetItem(format, self.columns)
|
||||||
|
item.setData(Qt.UserRole, QVariant(format))
|
||||||
|
item.setFlags(Qt.ItemIsEnabled|Qt.ItemIsUserCheckable|Qt.ItemIsSelectable)
|
||||||
|
item.setCheckState(Qt.Checked if format in format_map else Qt.Unchecked)
|
||||||
|
|
||||||
|
self.connect(self.column_up, SIGNAL('clicked()'), self.up_column)
|
||||||
|
self.connect(self.column_down, SIGNAL('clicked()'), self.down_column)
|
||||||
|
|
||||||
|
def up_column(self):
|
||||||
|
idx = self.columns.currentRow()
|
||||||
|
if idx > 0:
|
||||||
|
self.columns.insertItem(idx-1, self.columns.takeItem(idx))
|
||||||
|
self.columns.setCurrentRow(idx-1)
|
||||||
|
|
||||||
|
def down_column(self):
|
||||||
|
idx = self.columns.currentRow()
|
||||||
|
if idx < self.columns.count()-1:
|
||||||
|
self.columns.insertItem(idx+1, self.columns.takeItem(idx))
|
||||||
|
self.columns.setCurrentRow(idx+1)
|
||||||
|
|
||||||
|
def format_map(self):
|
||||||
|
formats = [unicode(self.columns.item(i).data(Qt.UserRole).toString()) for i in range(self.columns.count()) if self.columns.item(i).checkState()==Qt.Checked]
|
||||||
|
return formats
|
||||||
|
|
85
src/calibre/gui2/device_drivers/configwidget.ui
Normal file
85
src/calibre/gui2/device_drivers/configwidget.ui
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ConfigWidget</class>
|
||||||
|
<widget class="QWidget" name="ConfigWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>442</width>
|
||||||
|
<height>332</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Select avaliable formats and their order for this device</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="columns">
|
||||||
|
<property name="alternatingRowColors">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="column_up">
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../gui2/images.qrc">
|
||||||
|
<normaloff>:/images/arrow-up.svg</normaloff>:/images/arrow-up.svg</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="column_down">
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../../gui2/images.qrc">
|
||||||
|
<normaloff>:/images/arrow-down.svg</normaloff>:/images/arrow-down.svg</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../../gui2/images.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
@ -5,8 +5,9 @@ import sys, os, shutil
|
|||||||
from subprocess import check_call, call
|
from subprocess import check_call, call
|
||||||
|
|
||||||
from calibre import __version__, __appname__
|
from calibre import __version__, __appname__
|
||||||
|
from calibre.customize.ui import device_plugins
|
||||||
|
|
||||||
DEVICES = devices()
|
DEVICES = device_plugins()
|
||||||
|
|
||||||
DESTDIR = ''
|
DESTDIR = ''
|
||||||
if os.environ.has_key('DESTDIR'):
|
if os.environ.has_key('DESTDIR'):
|
||||||
@ -292,7 +293,7 @@ def setup_udev_rules(group_file, reload, fatal_errors):
|
|||||||
</match>
|
</match>
|
||||||
</match>
|
</match>
|
||||||
</device>
|
</device>
|
||||||
'''%dict(cls=cls.__name__, vendor_id=cls.VENDOR_ID, product_id=cls.PRODUCT_ID,
|
'''%dict(cls=cls.__class__.__name__, vendor_id=cls.VENDOR_ID, product_id=cls.PRODUCT_ID,
|
||||||
prog=__appname__, bcd=cls.BCD))
|
prog=__appname__, bcd=cls.BCD))
|
||||||
fdi.write('\n'+cls.get_fdi())
|
fdi.write('\n'+cls.get_fdi())
|
||||||
fdi.write('\n</deviceinfo>\n')
|
fdi.write('\n</deviceinfo>\n')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user