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 cStringIO import StringIO
from calibre import prints
from calibre.ebooks.mobi import MobiError
from calibre.ebooks.mobi.writer import rescale_image, MAX_THUMB_DIMEN
from calibre.ebooks.mobi.langcodes import iana2mobi
@ -85,6 +86,8 @@ class StreamSlicer(object):
self._stream.truncate(value)
class MetadataUpdater(object):
DRM_KEY_SIZE = 48
def __init__(self, stream):
self.stream = stream
data = self.data = StreamSlicer(stream)
@ -104,6 +107,7 @@ class MetadataUpdater(object):
self.cover_record = self.thumbnail_record = None
self.timestamp = None
self.pdbrecords = self.get_pdbrecords()
self.drm_block = self.fetchDRMdata()
self.original_exth_records = {}
if not have_exth:
@ -112,6 +116,40 @@ class MetadataUpdater(object):
# Fetch timestamp, cover_record, thumbnail_record
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):
stream = self.stream
record0 = self.record0
@ -210,8 +248,13 @@ class MetadataUpdater(object):
exth = ['EXTH', pack('>II', 12, 0), pad]
exth = ''.join(exth)
# Update title_offset, title_len if new_title
self.record0[0x54:0x58] = pack('>L', 0x10 + mobi_header_length + len(exth))
# Update drm_offset
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:
self.record0[0x58:0x5c] = pack('>L', len(new_title))
@ -219,6 +262,7 @@ class MetadataUpdater(object):
new_record0 = StringIO()
new_record0.write(self.record0[:0x10 + mobi_header_length])
new_record0.write(exth)
new_record0.write(self.drm_block)
if new_title:
#new_record0.write(new_title.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)
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
for id in sorted(self.original_exth_records):

View File

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

View File

@ -357,6 +357,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
self.pubdate.setDate(QDate(pubdate.year, pubdate.month,
pubdate.day))
timestamp = db.timestamp(self.id, index_is_id=True)
self.orig_timestamp = timestamp
self.date.setDate(QDate(timestamp.year, timestamp.month,
timestamp.day))
@ -656,6 +657,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
self.db.set_pubdate(self.id, d)
d = self.date.date()
d = qt_to_dt(d)
if d.date() != self.orig_timestamp.date():
self.db.set_timestamp(self.id, d)
if self.cover_changed:

View File

@ -1751,7 +1751,7 @@ class EPUB_MOBI(CatalogPlugin):
today = datetime.datetime.now()
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
for (i, date) in enumerate(self.DATE_RANGE):
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])
else:
date_range = 'Last %d days' % (self.DATE_RANGE[i])
for book in self.booksByDateRange:
book_time = datetime.datetime(book['timestamp'].year, book['timestamp'].month, book['timestamp'].day)
if (today_time-book_time).days <= date_range_limit:
#print "generateHTMLByDateAdded: %s added %d days ago" % (book['title'], (today_time-book_time).days)
book_time = datetime.datetime(book['timestamp'].year,
book['timestamp'].month,
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)
books_added_in_date_range = True
else:
break
dtc = add_books_to_HTML_by_date_range(date_range_list, date_range, dtc)
date_range_list = [book]