def parse_exth(data, pos): ret = {} n = 0 if (pos != data.find('EXTH')): LOG(0, "EXTH header not found where it should be @%d" % pos) return None else: end = pos + calcsize(EXTH_FMT) (hlen, count) = unpack(EXTH_FMT, data[pos:end]) LOG(4, "pos: %d, EXTH header len: %d, record count: %d" % ( pos, hlen, count)) pos = end while n < count: end = pos + calcsize(">2I") t, l = unpack(">2I", data[pos:end]) v = data[end:pos + l] if l - 8 == 4: v = unpack(">I", v)[0] if t in EXTH_RECORD_TYPES: rec = EXTH_RECORD_TYPES[t] LOG(4, "EXTH record '%s' @%d+%d: '%s'" % ( rec, pos, l - 8, v)) if rec not in ret: ret[rec] = [v] else: ret[rec].append(v) else: LOG(4, "Found an unknown EXTH record type %d @%d+%d: '%s'" % (t, pos, l - 8, repr(v))) pos += l n += 1 return ret
def delete_collection(kjd, collection): cn = COLLNAME % collection LOG(3, "Deleting collection %s" % cn) if cn in kjd: del kjd[cn] else: LOG(1, 'Collection %s does not exist' % collection)
def add_item(kjd, collection, hash): cn = COLLNAME % collection if not ((cn) in kjd): LOG(1, "Error. collection %s does not exist" % collection) else: if hash in kjd[cn]['items']: LOG(1, "%s was already in %s" % (hash, cn)) else: kjd[cn]['items'].append(hash) update_ts(kjd[cn])
def add_collection(kjd, collection): time_ms = int(time() * 1000) new_item = {} cn = COLLNAME % collection LOG(3, "Adding collection %s" % cn) if not ((cn) in kjd): kjd[cn] = {'items': [], 'lastAccess': time_ms} else: LOG(1, "Collection %s already exists" % collection) update_ts(kjd[cn])
def remove_item(kjd, collection, hash): cn = COLLNAME % collection if not ((cn) in kjd): LOG(1, "Error. collection %s does not exist" % collection) else: if hash not in kjd[cn]['items']: return else: kjd[cn]['items'].remove(hash) update_ts(kjd[cn])
def get_books(progress_func=lambda: None): ret = {} files = glob.glob("%s/*" % BOOKPATH) for c, fn in enumerate(files): progress_func(c) LOG(3, "\n - Processing file #%d: %s" % (c, fn)) key = make_hash(fn.replace(BOOKPATH, KINDLE_INTERNAL_PATH)) val = ebook.Book(fn) if val.is_a_book: ret[key] = val return ret
def load_data(): try: return json.load(open(JSONFILE, 'r')) except IOError: LOG(2, "File %s not found" % JSONFILE) return dict()
def __init__(self, fn): self.filename = fn # Set some fields to defaults self.title = fn self.author = "??" self.language = "??" self.is_a_book = False f = open(fn) d = f.read(68) f.close() encodings = { 1252: 'cp1252', 65001: 'utf-8' } supported_types = ('BOOKMOBI', 'TEXtREAd') self.type = d[60:68] if self.type not in supported_types: LOG(1, "Unsupported file type %s" % (self.type)) return None try: db = parse_palmdb(fn) except: return None self.is_a_book = True # now we have a better guess at the title, use it for now self.title = db.name self.records = db.records rec0 = self.records[0].data #LOG(5,repr(rec0)) if self.type == 'BOOKMOBI': LOG(3, "This is a MOBI book") self.mobi = {} for field, pos, fmt in MOBI_HDR_FIELDS: end = pos + calcsize(fmt) if (end > len(rec0) or ("header_len" in self.mobi and end > self.mobi["header_len"])): continue LOG(4, "field: %s, fmt: %s, @ [%d:%d], data: %s" % ( field, fmt, pos, end, repr(rec0[pos:end]))) (self.mobi[field], ) = unpack(">%s" % fmt, rec0[pos:end]) LOG(3, "self.mobi: %s" % repr(self.mobi)) # Get and decode the book name if self.mobi['locale_language'] in LANGUAGES: lang = LANGUAGES[self.mobi['locale_language']] if self.mobi['locale_country'] == 0: LOG(2, "Book language: %s" % lang[0][1]) self.language = "%s (%s)" % (lang[0][1], lang[0][0]) elif self.mobi['locale_country'] in lang: country = lang[self.mobi['locale_country']] LOG(2, "Book language is %s (%s)" % ( lang[0][1], country[1])) self.language = "%s (%s-%s)" % ( lang[0][1], lang[0][0], country[0] ) pos = self.mobi['full_name_offs'] end = pos + self.mobi['full_name_len'] self.title = rec0[pos:end].decode(encodings[self.mobi['encoding']]) LOG(2, "Book name: %s" % self.title) if self.mobi['id'] != 'MOBI': LOG(0, "Mobi header missing!") return None if (0x40 & self.mobi['exth_flags']): # check for EXTH self.exth = parse_exth(rec0, self.mobi['header_len'] + 16) LOG(3, "EXTH header: %s" % repr(self.exth)) if 'author' in self.exth: self.author = ' & '.join(self.exth['author']) else: self.author = "n/a" self.rawdata = d if (('updated title' in self.exth) and (type(self.exth['updated title']) is str)): self.title = ' '.join(self.exth['updated title']) elif self.type == 'TEXtREAd': LOG(2, "This is an older MOBI book") self.rawdata = d compression, data_len, rec_count, rec_size, pos = unpack( PRC_HDRFMT, rec0[:calcsize(PRC_HDRFMT)]) LOG(3, "compression %d, data_len %d, rec_count %d, rec_size %d" % (compression, data_len, rec_count, rec_size)) if compression == 2: data = uncompress(self.records[1].data) else: data = self.records[1].data from BeautifulSoup import BeautifulSoup soup = BeautifulSoup(data) self.metadata = soup.fetch("dc-metadata") try: self.title = soup.fetch("dc:title")[0].getText() self.author = soup.fetch("dc:creator")[0].getText() self.language = soup.fetch("dc:language")[0].getText() except: self.title, self.author, self.language = ("Unknown", "Unknown", "en-us")