mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 02:34:06 -04:00
Pull from driver-dev
This commit is contained in:
commit
ecc05f20bc
@ -300,6 +300,17 @@ class PDFMetadataWriter(MetadataWriterPlugin):
|
|||||||
from calibre.ebooks.metadata.pdf import set_metadata
|
from calibre.ebooks.metadata.pdf import set_metadata
|
||||||
set_metadata(stream, mi)
|
set_metadata(stream, mi)
|
||||||
|
|
||||||
|
class PDBMetadataWriter(MetadataWriterPlugin):
|
||||||
|
|
||||||
|
name = 'Set PDB metadata'
|
||||||
|
file_types = set(['pdb'])
|
||||||
|
description = _('Set metadata from %s files') % 'PDB'
|
||||||
|
author = 'John Schember'
|
||||||
|
|
||||||
|
def set_metadata(self, stream, mi, type):
|
||||||
|
from calibre.ebooks.metadata.pdb import set_metadata
|
||||||
|
set_metadata(stream, mi)
|
||||||
|
|
||||||
|
|
||||||
from calibre.ebooks.epub.input import EPUBInput
|
from calibre.ebooks.epub.input import EPUBInput
|
||||||
from calibre.ebooks.mobi.input import MOBIInput
|
from calibre.ebooks.mobi.input import MOBIInput
|
||||||
|
@ -10,8 +10,8 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from calibre.ebooks.metadata import MetaInformation
|
from calibre.ebooks.metadata import MetaInformation, authors_to_string
|
||||||
from calibre.ebooks.pdb.header import PdbHeaderReader
|
from calibre.ebooks.pdb.header import PdbHeaderReader, PdbHeaderBuilder
|
||||||
from calibre.ebooks.pdb.ereader.reader import HeaderRecord
|
from calibre.ebooks.pdb.ereader.reader import HeaderRecord
|
||||||
|
|
||||||
def get_metadata(stream, extract_cover=True):
|
def get_metadata(stream, extract_cover=True):
|
||||||
@ -24,8 +24,8 @@ def get_metadata(stream, extract_cover=True):
|
|||||||
pheader = PdbHeaderReader(stream)
|
pheader = PdbHeaderReader(stream)
|
||||||
hr = HeaderRecord(pheader.section_data(0))
|
hr = HeaderRecord(pheader.section_data(0))
|
||||||
|
|
||||||
if hr.version in (2, 10):
|
if hr.version in (2, 10) and hr.has_metadata == 1:
|
||||||
try:
|
try:
|
||||||
mdata = pheader.section_data(hr.metadata_offset)
|
mdata = pheader.section_data(hr.metadata_offset)
|
||||||
|
|
||||||
mdata = mdata.split('\x00')
|
mdata = mdata.split('\x00')
|
||||||
@ -41,3 +41,42 @@ def get_metadata(stream, extract_cover=True):
|
|||||||
|
|
||||||
return mi
|
return mi
|
||||||
|
|
||||||
|
def set_metadata(stream, mi):
|
||||||
|
pheader = PdbHeaderReader(stream)
|
||||||
|
sections = [pheader.section_data(x) for x in range(0, pheader.section_count())]
|
||||||
|
hr = HeaderRecord(sections[0])
|
||||||
|
|
||||||
|
if hr.version not in (2, 10):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Create a metadata record for the file if one does not alreay exist
|
||||||
|
if not hr.has_metadata:
|
||||||
|
sections += ['', 'MeTaInFo\x00']
|
||||||
|
last_data = len(sections) - 1
|
||||||
|
|
||||||
|
for i in range(0, 132, 2):
|
||||||
|
val, = struct.unpack('>H', sections[0][i:i+2])
|
||||||
|
if val >= hr.last_data_offset:
|
||||||
|
sections[0][i:i+2] = struct.pack('>H', last_data)
|
||||||
|
|
||||||
|
sections[0][24:26] = struct.pack('>H', 1) # Set has metadata
|
||||||
|
sections[0][44:46] = struct.pack('>H', last_data - 1) # Set location of metadata
|
||||||
|
sections[0][52:54] = struct.pack('>H', last_data) # Ensure last data offset is updated
|
||||||
|
|
||||||
|
# Merge the metadata into the file
|
||||||
|
file_mi = get_metadata(stream, False)
|
||||||
|
file_mi.smart_update(mi)
|
||||||
|
sections[hr.metadata_offset] = '%s\x00%s\x00%s\x00%s\x00%s\x00' % \
|
||||||
|
(file_mi.title, authors_to_string(file_mi.authors), '', file_mi.publisher, file_mi.isbn)
|
||||||
|
|
||||||
|
# Rebuild the PDB wrapper because the offsets have changed due to the
|
||||||
|
# new metadata.
|
||||||
|
pheader_builder = PdbHeaderBuilder(pheader.ident, pheader.title)
|
||||||
|
stream.seek(0)
|
||||||
|
stream.truncate(0)
|
||||||
|
pheader_builder.build_header([len(x) for x in sections], stream)
|
||||||
|
|
||||||
|
# Write the data back to the file
|
||||||
|
for item in sections:
|
||||||
|
stream.write(item)
|
||||||
|
|
||||||
|
@ -12,11 +12,18 @@ import re
|
|||||||
|
|
||||||
from calibre.ebooks.metadata import MetaInformation
|
from calibre.ebooks.metadata import MetaInformation
|
||||||
from calibre.ebooks.pdb.header import PdbHeaderReader
|
from calibre.ebooks.pdb.header import PdbHeaderReader
|
||||||
from calibre.ebooks.metadata.ereader import get_metadata as eReader
|
from calibre.ebooks.metadata.ereader import get_metadata as get_eReader
|
||||||
|
|
||||||
MREADER = {
|
MREADER = {
|
||||||
'PNPdPPrs' : eReader,
|
'PNPdPPrs' : get_eReader,
|
||||||
'PNRdPPrs' : eReader,
|
'PNRdPPrs' : get_eReader,
|
||||||
|
}
|
||||||
|
|
||||||
|
from calibre.ebooks.metadata.ereader import set_metadata as set_eReader
|
||||||
|
|
||||||
|
MWRITER = {
|
||||||
|
'PNPdPPrs' : set_eReader,
|
||||||
|
'PNRdPPrs' : set_eReader,
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_metadata(stream, extract_cover=True):
|
def get_metadata(stream, extract_cover=True):
|
||||||
@ -34,3 +41,16 @@ def get_metadata(stream, extract_cover=True):
|
|||||||
|
|
||||||
return MetadataReader(stream, extract_cover)
|
return MetadataReader(stream, extract_cover)
|
||||||
|
|
||||||
|
def set_metadata(stream, mi):
|
||||||
|
stream.seek(0)
|
||||||
|
|
||||||
|
pheader = PdbHeaderReader(stream)
|
||||||
|
|
||||||
|
MetadataWriter = MWRITER.get(pheader.ident, None)
|
||||||
|
|
||||||
|
if MetadataWriter:
|
||||||
|
MetadataWriter(stream, mi)
|
||||||
|
|
||||||
|
stream.seek(0)
|
||||||
|
stream.write(re.sub('[^-A-Za-z0-9]+', '_', mi.title).ljust(32, '\x00')[:32])
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@ import os, re, struct, zlib
|
|||||||
|
|
||||||
from calibre import CurrentDir
|
from calibre import CurrentDir
|
||||||
from calibre.ebooks import DRMError
|
from calibre.ebooks import DRMError
|
||||||
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.pml.pmlconverter import pml_to_html, \
|
from calibre.ebooks.pml.pmlconverter import pml_to_html, \
|
||||||
@ -31,6 +30,7 @@ class HeaderRecord(object):
|
|||||||
def __init__(self, raw):
|
def __init__(self, raw):
|
||||||
self.version, = struct.unpack('>H', raw[0:2])
|
self.version, = struct.unpack('>H', raw[0:2])
|
||||||
self.non_text_offset, = struct.unpack('>H', raw[12:14])
|
self.non_text_offset, = struct.unpack('>H', raw[12:14])
|
||||||
|
self.has_metadata, = struct.unpack('>H', raw[24:26])
|
||||||
self.footnote_rec, = struct.unpack('>H', raw[28:30])
|
self.footnote_rec, = struct.unpack('>H', raw[28:30])
|
||||||
self.sidebar_rec, = struct.unpack('>H', raw[30:32])
|
self.sidebar_rec, = struct.unpack('>H', raw[30:32])
|
||||||
self.bookmark_offset, = struct.unpack('>H', raw[32:34])
|
self.bookmark_offset, = struct.unpack('>H', raw[32:34])
|
||||||
@ -62,6 +62,9 @@ class Reader(FormatReader):
|
|||||||
else:
|
else:
|
||||||
raise EreaderError('Unknown book version %i.' % self.header_record.version)
|
raise EreaderError('Unknown book version %i.' % self.header_record.version)
|
||||||
|
|
||||||
|
from calibre.ebooks.metadata.pdb import get_metadata
|
||||||
|
self.mi = get_metadata(stream, False)
|
||||||
|
|
||||||
def section_data(self, number):
|
def section_data(self, number):
|
||||||
return self.sections[number]
|
return self.sections[number]
|
||||||
|
|
||||||
@ -144,10 +147,8 @@ class Reader(FormatReader):
|
|||||||
return opf_path
|
return opf_path
|
||||||
|
|
||||||
def create_opf(self, output_dir, images):
|
def create_opf(self, output_dir, images):
|
||||||
mi = MetaInformation(None, None)
|
|
||||||
|
|
||||||
with CurrentDir(output_dir):
|
with CurrentDir(output_dir):
|
||||||
opf = OPFCreator(output_dir, mi)
|
opf = OPFCreator(output_dir, self.mi)
|
||||||
|
|
||||||
manifest = [('index.html', None)]
|
manifest = [('index.html', None)]
|
||||||
|
|
||||||
|
@ -18,11 +18,7 @@ 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.pml.pmlconverter import html_to_pml
|
from calibre.ebooks.pml.pmlconverter import html_to_pml
|
||||||
|
|
||||||
# We are using the older identity because we do not user newer features
|
IDENTITY = 'PNRdPPrs'
|
||||||
# (sidebar, footnotes). This will ensure compatibility with older readers.
|
|
||||||
# If newer features are used (anything supported by dropbook but not by makebook
|
|
||||||
# change the identity to the newer PNRdPPrs.
|
|
||||||
IDENTITY = 'PNPdPPrs'
|
|
||||||
|
|
||||||
# This is an arbitrary number that is small enough to work. The actual maximum
|
# This is an arbitrary number that is small enough to work. The actual maximum
|
||||||
# record size is unknown.
|
# record size is unknown.
|
||||||
|
@ -220,9 +220,11 @@ class DeviceManager(Thread):
|
|||||||
'''Copy books from device to disk'''
|
'''Copy books from device to disk'''
|
||||||
for path in paths:
|
for path in paths:
|
||||||
name = path.rpartition('/')[2]
|
name = path.rpartition('/')[2]
|
||||||
f = open(os.path.join(target, name), 'wb')
|
dest = os.path.join(target, name)
|
||||||
self.device.get_file(path, f)
|
if os.path.abspath(dest) != os.path.abspath(path):
|
||||||
f.close()
|
f = open(dest, 'wb')
|
||||||
|
self.device.get_file(path, f)
|
||||||
|
f.close()
|
||||||
|
|
||||||
def save_books(self, done, paths, target):
|
def save_books(self, done, paths, target):
|
||||||
return self.create_job(self._save_books, done, args=[paths, target],
|
return self.create_job(self._save_books, done, args=[paths, target],
|
||||||
@ -493,6 +495,7 @@ class DeviceGUI(object):
|
|||||||
return
|
return
|
||||||
files, _auto_ids = self.library_view.model().get_preferred_formats_from_ids(ids,
|
files, _auto_ids = self.library_view.model().get_preferred_formats_from_ids(ids,
|
||||||
fmts, paths=True, set_metadata=True,
|
fmts, paths=True, set_metadata=True,
|
||||||
|
specific_format=specific_format,
|
||||||
exclude_auto=do_auto_convert)
|
exclude_auto=do_auto_convert)
|
||||||
if do_auto_convert:
|
if do_auto_convert:
|
||||||
ids = list(set(ids).difference(_auto_ids))
|
ids = list(set(ids).difference(_auto_ids))
|
||||||
@ -563,9 +566,9 @@ class DeviceGUI(object):
|
|||||||
autos = [self.library_view.model().db.title(id, index_is_id=True) for id in auto]
|
autos = [self.library_view.model().db.title(id, index_is_id=True) for id in auto]
|
||||||
autos = '\n'.join('%s'%i for i in autos)
|
autos = '\n'.join('%s'%i for i in autos)
|
||||||
info_dialog(self, _('No suitable formats'),
|
info_dialog(self, _('No suitable formats'),
|
||||||
_('Auto converting the following books before uploading to '
|
_('Auto converting the following books before sending via '
|
||||||
'the device:'), det_msg=autos, show=True)
|
'email:'), det_msg=autos, show=True)
|
||||||
self.auto_convert_mail(to, delete_from_library, auto, format)
|
self.auto_convert_mail(to, fmts, delete_from_library, auto, format)
|
||||||
|
|
||||||
if bad:
|
if bad:
|
||||||
bad = '\n'.join('%s'%(i,) for i in bad)
|
bad = '\n'.join('%s'%(i,) for i in bad)
|
||||||
|
@ -1051,7 +1051,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
current = self.library_view.currentIndex()
|
current = self.library_view.currentIndex()
|
||||||
self.library_view.model().current_changed(current, previous)
|
self.library_view.model().current_changed(current, previous)
|
||||||
|
|
||||||
def auto_convert_mail(self, to, delete_from_library, book_ids, format):
|
def auto_convert_mail(self, to, fmts, delete_from_library, book_ids, format):
|
||||||
previous = self.library_view.currentIndex()
|
previous = self.library_view.currentIndex()
|
||||||
rows = [x.row() for x in \
|
rows = [x.row() for x in \
|
||||||
self.library_view.selectionModel().selectedRows()]
|
self.library_view.selectionModel().selectedRows()]
|
||||||
@ -1062,7 +1062,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
job = self.job_manager.run_job(Dispatcher(self.book_auto_converted_mail),
|
job = self.job_manager.run_job(Dispatcher(self.book_auto_converted_mail),
|
||||||
func, args=args, description=desc)
|
func, args=args, description=desc)
|
||||||
self.conversion_jobs[job] = (temp_files, fmt, id,
|
self.conversion_jobs[job] = (temp_files, fmt, id,
|
||||||
delete_from_library, to)
|
delete_from_library, to, fmts)
|
||||||
|
|
||||||
if changed:
|
if changed:
|
||||||
self.library_view.model().refresh_rows(rows)
|
self.library_view.model().refresh_rows(rows)
|
||||||
@ -1141,7 +1141,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
self.sync_to_device(on_card, False, specific_format=fmt, send_ids=[book_id], do_auto_convert=False)
|
self.sync_to_device(on_card, False, specific_format=fmt, send_ids=[book_id], do_auto_convert=False)
|
||||||
|
|
||||||
def book_auto_converted_mail(self, job):
|
def book_auto_converted_mail(self, job):
|
||||||
temp_files, fmt, book_id, delete_from_library, to = self.conversion_jobs.pop(job)
|
temp_files, fmt, book_id, delete_from_library, to, fmts = self.conversion_jobs.pop(job)
|
||||||
try:
|
try:
|
||||||
if job.failed:
|
if job.failed:
|
||||||
self.job_exception(job)
|
self.job_exception(job)
|
||||||
@ -1162,7 +1162,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
current = self.library_view.currentIndex()
|
current = self.library_view.currentIndex()
|
||||||
self.library_view.model().current_changed(current, QModelIndex())
|
self.library_view.model().current_changed(current, QModelIndex())
|
||||||
|
|
||||||
self.send_by_mail(to, fmt, delete_from_library, send_ids=[book_id], do_auto_convert=False)
|
self.send_by_mail(to, fmts, delete_from_library, specific_format=fmt, send_ids=[book_id], do_auto_convert=False)
|
||||||
|
|
||||||
def book_converted(self, job):
|
def book_converted(self, job):
|
||||||
temp_files, fmt, book_id = self.conversion_jobs.pop(job)
|
temp_files, fmt, book_id = self.conversion_jobs.pop(job)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user