mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
KG updates
This commit is contained in:
commit
995348a914
@ -4,11 +4,11 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>,' \
|
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>,' \
|
||||||
' and Alex Bramley <a.bramley at gmail.com>.'
|
' and Alex Bramley <a.bramley at gmail.com>.'
|
||||||
|
|
||||||
import os, shutil, uuid
|
import os, shutil, uuid, re
|
||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
from mimetypes import guess_type as guess_mimetype
|
from mimetypes import guess_type as guess_mimetype
|
||||||
|
|
||||||
from BeautifulSoup import BeautifulSoup
|
from BeautifulSoup import BeautifulSoup, NavigableString
|
||||||
from lxml import html
|
from lxml import html
|
||||||
from pychm.chm import CHMFile
|
from pychm.chm import CHMFile
|
||||||
from pychm.chmlib import (
|
from pychm.chmlib import (
|
||||||
@ -29,6 +29,17 @@ def match_string(s1, s2_already_lowered):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def check_all_prev_empty(tag):
|
||||||
|
if tag is None:
|
||||||
|
return True
|
||||||
|
if tag.__class__ == NavigableString and not check_empty(tag):
|
||||||
|
return False
|
||||||
|
return check_all_prev_empty(tag.previousSibling)
|
||||||
|
|
||||||
|
def check_empty(s, rex = re.compile(r'\S')):
|
||||||
|
return rex.search(s) is None
|
||||||
|
|
||||||
|
|
||||||
def option_parser():
|
def option_parser():
|
||||||
parser = OptionParser(usage=_('%prog [options] mybook.chm'))
|
parser = OptionParser(usage=_('%prog [options] mybook.chm'))
|
||||||
parser.add_option('--output-dir', '-d', default='.', help=_('Output directory. Defaults to current directory'), dest='output')
|
parser.add_option('--output-dir', '-d', default='.', help=_('Output directory. Defaults to current directory'), dest='output')
|
||||||
@ -155,6 +166,12 @@ class CHMReader(CHMFile):
|
|||||||
# for some very odd reason each page's content appears to be in a table
|
# for some very odd reason each page's content appears to be in a table
|
||||||
# too. and this table has sub-tables for random asides... grr.
|
# too. and this table has sub-tables for random asides... grr.
|
||||||
|
|
||||||
|
# remove br at top of page if present after nav bars removed
|
||||||
|
br = soup('br')
|
||||||
|
if br:
|
||||||
|
if check_all_prev_empty(br[0].previousSibling):
|
||||||
|
br[0].extract()
|
||||||
|
|
||||||
# some images seem to be broken in some chm's :/
|
# some images seem to be broken in some chm's :/
|
||||||
for img in soup('img'):
|
for img in soup('img'):
|
||||||
try:
|
try:
|
||||||
|
@ -10,6 +10,7 @@ import re
|
|||||||
import struct
|
import struct
|
||||||
import textwrap
|
import textwrap
|
||||||
import cStringIO
|
import cStringIO
|
||||||
|
import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PIL import Image as PILImage
|
from PIL import Image as PILImage
|
||||||
@ -806,13 +807,20 @@ def get_metadata(stream):
|
|||||||
if mh.exth.mi is not None:
|
if mh.exth.mi is not None:
|
||||||
mi = mh.exth.mi
|
mi = mh.exth.mi
|
||||||
else:
|
else:
|
||||||
with TemporaryDirectory('_mobi_meta_reader') as tdir:
|
size = sys.maxint
|
||||||
with CurrentDir(tdir):
|
if hasattr(stream, 'seek') and hasattr(stream, 'tell'):
|
||||||
mr = MobiReader(stream, log)
|
pos = stream.tell()
|
||||||
parse_cache = {}
|
stream.seek(0, 2)
|
||||||
mr.extract_content(tdir, parse_cache)
|
size = stream.tell()
|
||||||
if mr.embedded_mi is not None:
|
stream.seek(pos)
|
||||||
mi = mr.embedded_mi
|
if size < 4*1024*1024:
|
||||||
|
with TemporaryDirectory('_mobi_meta_reader') as tdir:
|
||||||
|
with CurrentDir(tdir):
|
||||||
|
mr = MobiReader(stream, log)
|
||||||
|
parse_cache = {}
|
||||||
|
mr.extract_content(tdir, parse_cache)
|
||||||
|
if mr.embedded_mi is not None:
|
||||||
|
mi = mr.embedded_mi
|
||||||
if hasattr(mh.exth, 'cover_offset'):
|
if hasattr(mh.exth, 'cover_offset'):
|
||||||
cover_index = mh.first_image_index + mh.exth.cover_offset
|
cover_index = mh.first_image_index + mh.exth.cover_offset
|
||||||
data = mh.section_data(int(cover_index))
|
data = mh.section_data(int(cover_index))
|
||||||
|
@ -177,7 +177,7 @@ class EbookIterator(object):
|
|||||||
plumber.opts, plumber.input_fmt, self.log,
|
plumber.opts, plumber.input_fmt, self.log,
|
||||||
{}, self.base)
|
{}, self.base)
|
||||||
|
|
||||||
if processed or plumber.input_fmt.lower() in ('pdf', 'rb') and \
|
if processed or plumber.input_fmt.lower() in ('pdb', 'pdf', 'rb') and \
|
||||||
not hasattr(self.pathtoopf, 'manifest'):
|
not hasattr(self.pathtoopf, 'manifest'):
|
||||||
self.pathtoopf = create_oebbook(self.log, self.pathtoopf, plumber.opts,
|
self.pathtoopf = create_oebbook(self.log, self.pathtoopf, plumber.opts,
|
||||||
plumber.input_plugin)
|
plumber.input_plugin)
|
||||||
|
@ -11,12 +11,14 @@ class PDBError(Exception):
|
|||||||
from calibre.ebooks.pdb.ereader.reader import Reader as ereader_reader
|
from calibre.ebooks.pdb.ereader.reader import Reader as ereader_reader
|
||||||
from calibre.ebooks.pdb.palmdoc.reader import Reader as palmdoc_reader
|
from calibre.ebooks.pdb.palmdoc.reader import Reader as palmdoc_reader
|
||||||
from calibre.ebooks.pdb.ztxt.reader import Reader as ztxt_reader
|
from calibre.ebooks.pdb.ztxt.reader import Reader as ztxt_reader
|
||||||
|
from calibre.ebooks.pdb.pdf.reader import Reader as pdf_reader
|
||||||
|
|
||||||
FORMAT_READERS = {
|
FORMAT_READERS = {
|
||||||
'PNPdPPrs': ereader_reader,
|
'PNPdPPrs': ereader_reader,
|
||||||
'PNRdPPrs': ereader_reader,
|
'PNRdPPrs': ereader_reader,
|
||||||
'zTXTGPlm': ztxt_reader,
|
'zTXTGPlm': ztxt_reader,
|
||||||
'TEXtREAd': palmdoc_reader,
|
'TEXtREAd': palmdoc_reader,
|
||||||
|
'.pdfADBE': pdf_reader,
|
||||||
}
|
}
|
||||||
|
|
||||||
from calibre.ebooks.pdb.palmdoc.writer import Writer as palmdoc_writer
|
from calibre.ebooks.pdb.palmdoc.writer import Writer as palmdoc_writer
|
||||||
@ -34,8 +36,8 @@ IDENTITY_TO_NAME = {
|
|||||||
'PNRdPPrs': 'eReader',
|
'PNRdPPrs': 'eReader',
|
||||||
'zTXTGPlm': 'zTXT',
|
'zTXTGPlm': 'zTXT',
|
||||||
'TEXtREAd': 'PalmDOC',
|
'TEXtREAd': 'PalmDOC',
|
||||||
|
|
||||||
'.pdfADBE': 'Adobe Reader',
|
'.pdfADBE': 'Adobe Reader',
|
||||||
|
|
||||||
'BVokBDIC': 'BDicty',
|
'BVokBDIC': 'BDicty',
|
||||||
'DB99DBOS': 'DB (Database program)',
|
'DB99DBOS': 'DB (Database program)',
|
||||||
'vIMGView': 'FireViewer (ImageViewer)',
|
'vIMGView': 'FireViewer (ImageViewer)',
|
||||||
|
0
src/calibre/ebooks/pdb/pdf/__init__.py
Normal file
0
src/calibre/ebooks/pdb/pdf/__init__.py
Normal file
38
src/calibre/ebooks/pdb/pdf/reader.py
Normal file
38
src/calibre/ebooks/pdb/pdf/reader.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
'''
|
||||||
|
Read content from palmdoc pdb file.
|
||||||
|
'''
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2010, John Schember <john@nachtimwald.com>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
import cStringIO
|
||||||
|
|
||||||
|
from calibre.ebooks.pdb.formatreader import FormatReader
|
||||||
|
from calibre.ptempfile import TemporaryFile
|
||||||
|
|
||||||
|
class Reader(FormatReader):
|
||||||
|
|
||||||
|
def __init__(self, header, stream, log, options):
|
||||||
|
self.header = header
|
||||||
|
self.stream = stream
|
||||||
|
self.log = log
|
||||||
|
self.options = options
|
||||||
|
setattr(self.options, 'new_pdf_engine', False)
|
||||||
|
setattr(self.options, 'no_images', False)
|
||||||
|
setattr(self.options, 'unwrap_factor', 0.5)
|
||||||
|
|
||||||
|
def extract_content(self, output_dir):
|
||||||
|
self.log.info('Extracting PDF...')
|
||||||
|
|
||||||
|
with TemporaryFile() as pdf_n:
|
||||||
|
pdf = open(pdf_n, 'rw+b')
|
||||||
|
for x in xrange(self.header.section_count()):
|
||||||
|
pdf.write(self.header.section_data(x))
|
||||||
|
|
||||||
|
from calibre.customize.ui import plugin_for_input_format
|
||||||
|
pdf.seek(0)
|
||||||
|
return plugin_for_input_format('pdf').convert(pdf, self.options,
|
||||||
|
'pdf', self.log, [])
|
@ -150,23 +150,20 @@ class Catalog(QDialog, Ui_Dialog):
|
|||||||
ans = w.options()
|
ans = w.options()
|
||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
def save_catalog_settings(self):
|
||||||
|
self.catalog_format = unicode(self.format.currentText())
|
||||||
|
dynamic.set('catalog_preferred_format', self.catalog_format)
|
||||||
|
self.catalog_title = unicode(self.title.text())
|
||||||
|
dynamic.set('catalog_last_used_title', self.catalog_title)
|
||||||
|
self.catalog_sync = bool(self.sync.isChecked())
|
||||||
|
dynamic.set('catalog_sync_to_device', self.catalog_sync)
|
||||||
|
|
||||||
def apply(self):
|
def apply(self):
|
||||||
# Store current values without building catalog
|
# Store current values without building catalog
|
||||||
self.catalog_format = unicode(self.format.currentText())
|
self.save_catalog_settings()
|
||||||
dynamic.set('catalog_preferred_format', self.catalog_format)
|
|
||||||
self.catalog_title = unicode(self.title.text())
|
|
||||||
dynamic.set('catalog_last_used_title', self.catalog_title)
|
|
||||||
self.catalog_sync = bool(self.sync.isChecked())
|
|
||||||
dynamic.set('catalog_sync_to_device', self.catalog_sync)
|
|
||||||
if self.tabs.count() > 1:
|
if self.tabs.count() > 1:
|
||||||
w = self.tabs.widget(1)
|
self.tabs.widget(1).options()
|
||||||
ans = w.options()
|
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
self.catalog_format = unicode(self.format.currentText())
|
self.save_catalog_settings()
|
||||||
dynamic.set('catalog_preferred_format', self.catalog_format)
|
return QDialog.accept(self)
|
||||||
self.catalog_title = unicode(self.title.text())
|
|
||||||
dynamic.set('catalog_last_used_title', self.catalog_title)
|
|
||||||
self.catalog_sync = bool(self.sync.isChecked())
|
|
||||||
dynamic.set('catalog_sync_to_device', self.catalog_sync)
|
|
||||||
QDialog.accept(self)
|
|
||||||
|
@ -17,110 +17,94 @@
|
|||||||
<iconset>
|
<iconset>
|
||||||
<normaloff>:/images/library.png</normaloff>:/images/library.png</iconset>
|
<normaloff>:/images/library.png</normaloff>:/images/library.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<property name="geometry">
|
<item row="0" column="0">
|
||||||
<rect>
|
<widget class="QLabel" name="count">
|
||||||
<x>383</x>
|
<property name="font">
|
||||||
<y>470</y>
|
<font>
|
||||||
<width>211</width>
|
<weight>75</weight>
|
||||||
<height>32</height>
|
<bold>true</bold>
|
||||||
</rect>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
<property name="orientation">
|
<property name="text">
|
||||||
<enum>Qt::Horizontal</enum>
|
<string>Generate catalog for {0} books</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="standardButtons">
|
</widget>
|
||||||
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
</item>
|
||||||
</property>
|
<item row="1" column="0" colspan="2">
|
||||||
</widget>
|
<widget class="QTabWidget" name="tabs">
|
||||||
<widget class="QTabWidget" name="tabs">
|
<property name="currentIndex">
|
||||||
<property name="geometry">
|
<number>0</number>
|
||||||
<rect>
|
</property>
|
||||||
<x>12</x>
|
<widget class="QWidget" name="tab">
|
||||||
<y>39</y>
|
<attribute name="title">
|
||||||
<width>579</width>
|
<string>Catalog options</string>
|
||||||
<height>411</height>
|
</attribute>
|
||||||
</rect>
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
</property>
|
<item row="0" column="0">
|
||||||
<property name="currentIndex">
|
<widget class="QLabel" name="label">
|
||||||
<number>0</number>
|
<property name="text">
|
||||||
</property>
|
<string>Catalog &format:</string>
|
||||||
<widget class="QWidget" name="tab">
|
</property>
|
||||||
<attribute name="title">
|
<property name="buddy">
|
||||||
<string>Catalog options</string>
|
<cstring>format</cstring>
|
||||||
</attribute>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
</widget>
|
||||||
<item row="0" column="0">
|
</item>
|
||||||
<widget class="QLabel" name="label">
|
<item row="0" column="2">
|
||||||
<property name="text">
|
<widget class="QComboBox" name="format"/>
|
||||||
<string>Catalog &format:</string>
|
</item>
|
||||||
</property>
|
<item row="1" column="0">
|
||||||
<property name="buddy">
|
<widget class="QLabel" name="label_2">
|
||||||
<cstring>format</cstring>
|
<property name="text">
|
||||||
</property>
|
<string>Catalog &title (existing catalog with the same title will be replaced):</string>
|
||||||
</widget>
|
</property>
|
||||||
</item>
|
<property name="wordWrap">
|
||||||
<item row="0" column="2">
|
<bool>true</bool>
|
||||||
<widget class="QComboBox" name="format"/>
|
</property>
|
||||||
</item>
|
<property name="buddy">
|
||||||
<item row="1" column="0">
|
<cstring>title</cstring>
|
||||||
<widget class="QLabel" name="label_2">
|
</property>
|
||||||
<property name="text">
|
</widget>
|
||||||
<string>Catalog &title (existing catalog with the same title will be replaced):</string>
|
</item>
|
||||||
</property>
|
<item row="1" column="2">
|
||||||
<property name="wordWrap">
|
<widget class="QLineEdit" name="title"/>
|
||||||
<bool>true</bool>
|
</item>
|
||||||
</property>
|
<item row="3" column="0">
|
||||||
<property name="buddy">
|
<widget class="QCheckBox" name="sync">
|
||||||
<cstring>title</cstring>
|
<property name="text">
|
||||||
</property>
|
<string>&Send catalog to device automatically</string>
|
||||||
</widget>
|
</property>
|
||||||
</item>
|
</widget>
|
||||||
<item row="1" column="2">
|
</item>
|
||||||
<widget class="QLineEdit" name="title"/>
|
<item row="2" column="1">
|
||||||
</item>
|
<spacer name="verticalSpacer">
|
||||||
<item row="3" column="0">
|
<property name="orientation">
|
||||||
<widget class="QCheckBox" name="sync">
|
<enum>Qt::Vertical</enum>
|
||||||
<property name="text">
|
</property>
|
||||||
<string>&Send catalog to device automatically</string>
|
<property name="sizeHint" stdset="0">
|
||||||
</property>
|
<size>
|
||||||
</widget>
|
<width>20</width>
|
||||||
</item>
|
<height>299</height>
|
||||||
<item row="2" column="1">
|
</size>
|
||||||
<spacer name="verticalSpacer">
|
</property>
|
||||||
<property name="orientation">
|
</spacer>
|
||||||
<enum>Qt::Vertical</enum>
|
</item>
|
||||||
</property>
|
</layout>
|
||||||
<property name="sizeHint" stdset="0">
|
</widget>
|
||||||
<size>
|
</widget>
|
||||||
<width>20</width>
|
</item>
|
||||||
<height>299</height>
|
<item row="2" column="1">
|
||||||
</size>
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
</property>
|
<property name="orientation">
|
||||||
</spacer>
|
<enum>Qt::Horizontal</enum>
|
||||||
</item>
|
</property>
|
||||||
</layout>
|
<property name="standardButtons">
|
||||||
</widget>
|
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
</widget>
|
</property>
|
||||||
<widget class="QLabel" name="count">
|
</widget>
|
||||||
<property name="geometry">
|
</item>
|
||||||
<rect>
|
</layout>
|
||||||
<x>12</x>
|
|
||||||
<y>12</y>
|
|
||||||
<width>301</width>
|
|
||||||
<height>17</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<weight>75</weight>
|
|
||||||
<bold>true</bold>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Generate catalog for {0} books</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../../../work/calibre/resources/images.qrc"/>
|
<include location="../../../work/calibre/resources/images.qrc"/>
|
||||||
|
@ -991,7 +991,6 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
self.library_view.model().current_changed(current_idx, current_idx)
|
self.library_view.model().current_changed(current_idx, current_idx)
|
||||||
|
|
||||||
def __add_filesystem_book(self, paths, allow_device=True):
|
def __add_filesystem_book(self, paths, allow_device=True):
|
||||||
print 222, paths
|
|
||||||
if isinstance(paths, basestring):
|
if isinstance(paths, basestring):
|
||||||
paths = [paths]
|
paths = [paths]
|
||||||
books = [path for path in map(os.path.abspath, paths) if os.access(path,
|
books = [path for path in map(os.path.abspath, paths) if os.access(path,
|
||||||
|
@ -180,7 +180,7 @@ Why is my device not detected in linux?
|
|||||||
|
|
||||||
grep SYSFS_DEPRECATED /boot/config-`uname -r`
|
grep SYSFS_DEPRECATED /boot/config-`uname -r`
|
||||||
|
|
||||||
You should see something like ``CONFIG_SYSFS_DEPRECATED_V2 is not set``.
|
You should see something like ``CONFIG_SYSFS_DEPRECATED_V2 is not set``. If you don't you have to either recompile your kernel with the correct setting, or upgrade your linux distro to a more modern version, where this will not be set.
|
||||||
|
|
||||||
Library Management
|
Library Management
|
||||||
------------------
|
------------------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user