diff --git a/src/calibre/ebooks/metadata/mobi.py b/src/calibre/ebooks/metadata/mobi.py index 1de73d7dd4..e0a3dfc28b 100644 --- a/src/calibre/ebooks/metadata/mobi.py +++ b/src/calibre/ebooks/metadata/mobi.py @@ -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): diff --git a/src/calibre/ebooks/mobi/writer.py b/src/calibre/ebooks/mobi/writer.py index c5bcee7e45..8de702a617 100644 --- a/src/calibre/ebooks/mobi/writer.py +++ b/src/calibre/ebooks/mobi/writer.py @@ -310,6 +310,7 @@ class Serializer(object): text = text.replace('&', '&') text = text.replace('<', '<') text = text.replace('>', '>') + text = text.replace(u'\u00AD', '') # Soft-hyphen if quot: text = text.replace('"', '"') self.buffer.write(encode(text)) diff --git a/src/calibre/gui2/dialogs/metadata_single.py b/src/calibre/gui2/dialogs/metadata_single.py index 5d698f88f9..8e40dc053c 100644 --- a/src/calibre/gui2/dialogs/metadata_single.py +++ b/src/calibre/gui2/dialogs/metadata_single.py @@ -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,7 +657,8 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): self.db.set_pubdate(self.id, d) d = self.date.date() 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_data is not None: diff --git a/src/calibre/library/catalog.py b/src/calibre/library/catalog.py index c0065c24c9..ea306162ae 100644 --- a/src/calibre/library/catalog.py +++ b/src/calibre/library/catalog.py @@ -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]