GwR work in progress DRM metadata edits, fix for timestamp

This commit is contained in:
GRiker 2010-02-17 14:51:06 -07:00
commit d6de6a564c
4 changed files with 62 additions and 8 deletions

View File

@ -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):

View File

@ -310,6 +310,7 @@ class Serializer(object):
text = text.replace('&', '&') text = text.replace('&', '&')
text = text.replace('<', '&lt;') text = text.replace('<', '&lt;')
text = text.replace('>', '&gt;') text = text.replace('>', '&gt;')
text = text.replace(u'\u00AD', '') # Soft-hyphen
if quot: if quot:
text = text.replace('"', '&quot;') text = text.replace('"', '&quot;')
self.buffer.write(encode(text)) self.buffer.write(encode(text))

View File

@ -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,6 +657,7 @@ 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)
if d.date() != self.orig_timestamp.date():
self.db.set_timestamp(self.id, d) self.db.set_timestamp(self.id, d)
if self.cover_changed: if self.cover_changed:

View File

@ -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]