mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
GwR work in progress DRM metadata edits, fix for timestamp
This commit is contained in:
commit
d6de6a564c
@ -12,6 +12,7 @@ __docformat__ = 'restructuredtext en'
|
|||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
|
|
||||||
|
from calibre import prints
|
||||||
from calibre.ebooks.mobi import MobiError
|
from calibre.ebooks.mobi import MobiError
|
||||||
from calibre.ebooks.mobi.writer import rescale_image, MAX_THUMB_DIMEN
|
from calibre.ebooks.mobi.writer import rescale_image, MAX_THUMB_DIMEN
|
||||||
from calibre.ebooks.mobi.langcodes import iana2mobi
|
from calibre.ebooks.mobi.langcodes import iana2mobi
|
||||||
@ -85,6 +86,8 @@ class StreamSlicer(object):
|
|||||||
self._stream.truncate(value)
|
self._stream.truncate(value)
|
||||||
|
|
||||||
class MetadataUpdater(object):
|
class MetadataUpdater(object):
|
||||||
|
DRM_KEY_SIZE = 48
|
||||||
|
|
||||||
def __init__(self, stream):
|
def __init__(self, stream):
|
||||||
self.stream = stream
|
self.stream = stream
|
||||||
data = self.data = StreamSlicer(stream)
|
data = self.data = StreamSlicer(stream)
|
||||||
@ -104,6 +107,7 @@ class MetadataUpdater(object):
|
|||||||
self.cover_record = self.thumbnail_record = None
|
self.cover_record = self.thumbnail_record = None
|
||||||
self.timestamp = None
|
self.timestamp = None
|
||||||
self.pdbrecords = self.get_pdbrecords()
|
self.pdbrecords = self.get_pdbrecords()
|
||||||
|
self.drm_block = self.fetchDRMdata()
|
||||||
|
|
||||||
self.original_exth_records = {}
|
self.original_exth_records = {}
|
||||||
if not have_exth:
|
if not have_exth:
|
||||||
@ -112,6 +116,40 @@ class MetadataUpdater(object):
|
|||||||
# Fetch timestamp, cover_record, thumbnail_record
|
# Fetch timestamp, cover_record, thumbnail_record
|
||||||
self.fetchEXTHFields()
|
self.fetchEXTHFields()
|
||||||
|
|
||||||
|
def fetchDRMdata(self):
|
||||||
|
''' Grab everything between end of EXTH and title '''
|
||||||
|
'''
|
||||||
|
if False and self.have_exth:
|
||||||
|
print "incoming file has EXTH header"
|
||||||
|
# 20:24 = mobiHeaderLength, 16=PDBHeader size, 4 = len('EXTH')
|
||||||
|
exth_off = int(unpack('>I', self.record0[20:24])[0] + 16)
|
||||||
|
print "exth_off = 0x%x" % exth_off
|
||||||
|
exth_len_offset = exth_off + 4
|
||||||
|
print "exth_len_offset = 0x%x" % exth_len_offset
|
||||||
|
exth_len = int(unpack('>I', self.record0[exth_len_offset:exth_len_offset+4])[0])
|
||||||
|
print "len(EXTH) = 0x%x" % exth_len
|
||||||
|
title_offset = int(unpack('>I', self.record0[0x54:0x58])[0])
|
||||||
|
print "offset of full title = 0x%x" % title_offset
|
||||||
|
drm_off = exth_off + exth_len
|
||||||
|
print "DRM data begins at 0x%x" % drm_off
|
||||||
|
print "DRM len is 0x%x bytes" % (title_offset - drm_off)
|
||||||
|
return self.record0[drm_off:drm_off + (title_offset - drm_off)]
|
||||||
|
else:
|
||||||
|
'''
|
||||||
|
if True:
|
||||||
|
drm_offset = int(unpack('>I', self.record0[0xa8:0xac])[0])
|
||||||
|
self.drm_key_count = int(unpack('>I', self.record0[0xac:0xb0])[0])
|
||||||
|
drm_string = ''
|
||||||
|
for x in range(self.drm_key_count):
|
||||||
|
base_addr = drm_offset + (x * self.DRM_KEY_SIZE)
|
||||||
|
drm_string += self.record0[base_addr:base_addr + self.DRM_KEY_SIZE]
|
||||||
|
return drm_string
|
||||||
|
else:
|
||||||
|
drm_offset = int(unpack('>I', self.record0[0xa8:0xac])[0])
|
||||||
|
title_offset = int(unpack('>I', self.record0[0x54:0x58])[0])
|
||||||
|
drm_blocklen = title_offset - drm_offset
|
||||||
|
return self.record0[drm_offset:drm_offset + drm_blocklen]
|
||||||
|
|
||||||
def fetchEXTHFields(self):
|
def fetchEXTHFields(self):
|
||||||
stream = self.stream
|
stream = self.stream
|
||||||
record0 = self.record0
|
record0 = self.record0
|
||||||
@ -210,8 +248,13 @@ class MetadataUpdater(object):
|
|||||||
exth = ['EXTH', pack('>II', 12, 0), pad]
|
exth = ['EXTH', pack('>II', 12, 0), pad]
|
||||||
exth = ''.join(exth)
|
exth = ''.join(exth)
|
||||||
|
|
||||||
# Update title_offset, title_len if new_title
|
# Update drm_offset
|
||||||
self.record0[0x54:0x58] = pack('>L', 0x10 + mobi_header_length + len(exth))
|
self.record0[0xa8:0xac] = pack('>L', 0x10 + mobi_header_length + len(exth))
|
||||||
|
if True:
|
||||||
|
self.record0[0xb0:0xb4] = pack('>L', len(self.drm_block))
|
||||||
|
# Update title_offset
|
||||||
|
self.record0[0x54:0x58] = pack('>L', 0x10 + mobi_header_length + len(exth) + len(self.drm_block))
|
||||||
|
|
||||||
if new_title:
|
if new_title:
|
||||||
self.record0[0x58:0x5c] = pack('>L', len(new_title))
|
self.record0[0x58:0x5c] = pack('>L', len(new_title))
|
||||||
|
|
||||||
@ -219,6 +262,7 @@ class MetadataUpdater(object):
|
|||||||
new_record0 = StringIO()
|
new_record0 = StringIO()
|
||||||
new_record0.write(self.record0[:0x10 + mobi_header_length])
|
new_record0.write(self.record0[:0x10 + mobi_header_length])
|
||||||
new_record0.write(exth)
|
new_record0.write(exth)
|
||||||
|
new_record0.write(self.drm_block)
|
||||||
if new_title:
|
if new_title:
|
||||||
#new_record0.write(new_title.encode(self.codec, 'replace'))
|
#new_record0.write(new_title.encode(self.codec, 'replace'))
|
||||||
new_title = (new_title or _('Unknown')).encode(self.codec, 'replace')
|
new_title = (new_title or _('Unknown')).encode(self.codec, 'replace')
|
||||||
@ -343,7 +387,8 @@ class MetadataUpdater(object):
|
|||||||
pop_exth_record(202)
|
pop_exth_record(202)
|
||||||
|
|
||||||
if getattr(self, 'encryption_type', -1) != 0:
|
if getattr(self, 'encryption_type', -1) != 0:
|
||||||
raise MobiError('Setting metadata in DRMed MOBI files is not supported.')
|
prints(u"Setting metadata for '%s' (DRM)" % mi.title)
|
||||||
|
# raise MobiError('Setting metadata in DRMed MOBI files is not supported.')
|
||||||
|
|
||||||
# Restore any original EXTH fields that weren't modified/updated
|
# Restore any original EXTH fields that weren't modified/updated
|
||||||
for id in sorted(self.original_exth_records):
|
for id in sorted(self.original_exth_records):
|
||||||
|
@ -310,6 +310,7 @@ class Serializer(object):
|
|||||||
text = text.replace('&', '&')
|
text = text.replace('&', '&')
|
||||||
text = text.replace('<', '<')
|
text = text.replace('<', '<')
|
||||||
text = text.replace('>', '>')
|
text = text.replace('>', '>')
|
||||||
|
text = text.replace(u'\u00AD', '') # Soft-hyphen
|
||||||
if quot:
|
if quot:
|
||||||
text = text.replace('"', '"')
|
text = text.replace('"', '"')
|
||||||
self.buffer.write(encode(text))
|
self.buffer.write(encode(text))
|
||||||
|
@ -357,6 +357,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
|||||||
self.pubdate.setDate(QDate(pubdate.year, pubdate.month,
|
self.pubdate.setDate(QDate(pubdate.year, pubdate.month,
|
||||||
pubdate.day))
|
pubdate.day))
|
||||||
timestamp = db.timestamp(self.id, index_is_id=True)
|
timestamp = db.timestamp(self.id, index_is_id=True)
|
||||||
|
self.orig_timestamp = timestamp
|
||||||
self.date.setDate(QDate(timestamp.year, timestamp.month,
|
self.date.setDate(QDate(timestamp.year, timestamp.month,
|
||||||
timestamp.day))
|
timestamp.day))
|
||||||
|
|
||||||
@ -656,7 +657,8 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
|||||||
self.db.set_pubdate(self.id, d)
|
self.db.set_pubdate(self.id, d)
|
||||||
d = self.date.date()
|
d = self.date.date()
|
||||||
d = qt_to_dt(d)
|
d = qt_to_dt(d)
|
||||||
self.db.set_timestamp(self.id, d)
|
if d.date() != self.orig_timestamp.date():
|
||||||
|
self.db.set_timestamp(self.id, d)
|
||||||
|
|
||||||
if self.cover_changed:
|
if self.cover_changed:
|
||||||
if self.cover_data is not None:
|
if self.cover_data is not None:
|
||||||
|
@ -1751,7 +1751,7 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
|
|
||||||
today = datetime.datetime.now()
|
today = datetime.datetime.now()
|
||||||
date_range_list = []
|
date_range_list = []
|
||||||
today_time = datetime.datetime(today.year, today.month, today.day)
|
today_time = datetime.datetime(today.year, today.month, today.day, 23, 59, 59)
|
||||||
books_added_in_date_range = False
|
books_added_in_date_range = False
|
||||||
for (i, date) in enumerate(self.DATE_RANGE):
|
for (i, date) in enumerate(self.DATE_RANGE):
|
||||||
date_range_limit = self.DATE_RANGE[i]
|
date_range_limit = self.DATE_RANGE[i]
|
||||||
@ -1759,14 +1759,20 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
date_range = '%d to %d days ago' % (self.DATE_RANGE[i-1], self.DATE_RANGE[i])
|
date_range = '%d to %d days ago' % (self.DATE_RANGE[i-1], self.DATE_RANGE[i])
|
||||||
else:
|
else:
|
||||||
date_range = 'Last %d days' % (self.DATE_RANGE[i])
|
date_range = 'Last %d days' % (self.DATE_RANGE[i])
|
||||||
|
|
||||||
for book in self.booksByDateRange:
|
for book in self.booksByDateRange:
|
||||||
book_time = datetime.datetime(book['timestamp'].year, book['timestamp'].month, book['timestamp'].day)
|
book_time = datetime.datetime(book['timestamp'].year,
|
||||||
if (today_time-book_time).days <= date_range_limit:
|
book['timestamp'].month,
|
||||||
#print "generateHTMLByDateAdded: %s added %d days ago" % (book['title'], (today_time-book_time).days)
|
book['timestamp'].day,
|
||||||
|
book['timestamp'].hour,
|
||||||
|
book['timestamp'].minute)
|
||||||
|
delta = today_time-book_time
|
||||||
|
if delta.days <= date_range_limit:
|
||||||
date_range_list.append(book)
|
date_range_list.append(book)
|
||||||
books_added_in_date_range = True
|
books_added_in_date_range = True
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
dtc = add_books_to_HTML_by_date_range(date_range_list, date_range, dtc)
|
dtc = add_books_to_HTML_by_date_range(date_range_list, date_range, dtc)
|
||||||
date_range_list = [book]
|
date_range_list = [book]
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user