Exemplo n.º 1
0
    def build_records(self, oeb, writer, for_joint):
        metadata = writer.oeb.metadata
        # The text records
        for x in ('last_text_record_idx', 'first_non_text_record_idx'):
            setattr(self, x.rpartition('_')[0], getattr(writer, x))
        self.records = writer.records
        self.text_length = writer.text_length

        # KF8 Indices
        self.chunk_index = len(self.records)
        self.records.extend(writer.chunk_records)
        self.skel_index = len(self.records)
        self.records.extend(writer.skel_records)
        self.guide_index = NULL_INDEX
        if writer.guide_records:
            self.guide_index = len(self.records)
            self.records.extend(writer.guide_records)
        self.ncx_index = NULL_INDEX
        if writer.ncx_records:
            self.ncx_index = len(self.records)
            self.records.extend(writer.ncx_records)

        # Resources
        resources = writer.resources
        for x in ('cover_offset', 'thumbnail_offset', 'masthead_offset'):
            setattr(self, x, getattr(resources, x))

        self.first_resource_record = NULL_INDEX
        before = len(self.records)
        if resources.records:
            self.first_resource_record = len(self.records)
            if not for_joint:
                resources.serialize(self.records, writer.used_images)
        self.num_of_resources = len(self.records) - before

        # FDST
        self.fdst_count = writer.fdst_count
        self.fdst_record = len(self.records)
        self.records.extend(writer.fdst_records)

        # FLIS/FCIS
        self.flis_record = len(self.records)
        self.records.append(FLIS)
        self.fcis_record = len(self.records)
        self.records.append(fcis(self.text_length))

        # EOF
        self.records.append(b'\xe9\x8e\r\n') # EOF record

        # Miscellaneous header fields
        self.compression = writer.compress
        self.book_type = 0x101 if writer.opts.mobi_periodical else 2
        self.full_title = utf8_text(unicode(metadata.title[0]))
        self.title_length = len(self.full_title)
        self.extra_data_flags = 0b1
        if writer.has_tbs:
            self.extra_data_flags |= 0b10
        self.uid = random.randint(0, 0xffffffff)

        self.language_code = self.iana2mobi()
        self.exth_flags = 0b1010000
        if writer.opts.mobi_periodical:
            self.exth_flags |= 0b1000
        if resources.has_fonts:
            self.exth_flags |= 0b1000000000000

        self.opts = writer.opts
        self.start_offset = writer.start_offset
        self.metadata = metadata
        self.kuc = 0 if len(resources.records) > 0 else None
Exemplo n.º 2
0
def build_exth(metadata, prefer_author_sort=False, is_periodical=False,
        share_not_sync=True, cover_offset=None, thumbnail_offset=None,
        start_offset=None, mobi_doctype=2, num_of_resources=None,
        kf8_unknown_count=0, be_kindlegen2=False, kf8_header_index=None,
        opts=None):
    exth = BytesIO()
    nrecs = 0

    for term in metadata:
        if term not in EXTH_CODES: continue
        code = EXTH_CODES[term]
        items = metadata[term]
        if term == 'creator':
            if prefer_author_sort:
                creators = [authors_to_sort_string([unicode(c)]) for c in
                            items]
            else:
                creators = [unicode(c) for c in items]
            items = creators
        elif term == 'rights':
            try:
                rights = utf8_text(unicode(metadata.rights[0]))
            except:
                rights = b'Unknown'
            exth.write(pack(b'>II', EXTH_CODES['rights'], len(rights) + 8))
            exth.write(rights)
            nrecs += 1
            continue

        for item in items:
            data = unicode(item)
            if term != 'description':
                data = COLLAPSE_RE.sub(' ', data)
            if term == 'identifier':
                if data.lower().startswith('urn:isbn:'):
                    data = data[9:]
                elif item.scheme.lower() == 'isbn':
                    pass
                else:
                    continue
            if term == 'language':
                d2 = usr_lang_as_iso639_1(data)
                if d2:
                    data = d2
            data = utf8_text(data)
            exth.write(pack(b'>II', code, len(data) + 8))
            exth.write(data)
            nrecs += 1

    # Write UUID as ASIN
    uuid = None
    from calibre.ebooks.oeb.base import OPF
    for x in metadata['identifier']:
        if (x.get(OPF('scheme'), None).lower() == 'uuid' or
                unicode(x).startswith('urn:uuid:')):
            uuid = unicode(x).split(':')[-1]
            break
    if uuid is None:
        from uuid import uuid4
        uuid = str(uuid4())

    if isinstance(uuid, unicode):
        uuid = uuid.encode('utf-8')
    if not share_not_sync:
        exth.write(pack(b'>II', 113, len(uuid) + 8))
        exth.write(uuid)
        nrecs += 1

    # Write UUID as SOURCE
    c_uuid = b'calibre:%s' % uuid
    exth.write(pack(b'>II', 112, len(c_uuid) + 8))
    exth.write(c_uuid)
    nrecs += 1

    # Write cdetype
    if not is_periodical:
        if not share_not_sync:
            exth.write(pack(b'>II', 501, 12))
            exth.write(b'EBOK')
            nrecs += 1
    else:
        ids = {0x101:b'NWPR', 0x103:b'MAGZ'}.get(mobi_doctype, None)
        if ids:
            exth.write(pack(b'>II', 501, 12))
            exth.write(ids)
            nrecs += 1

    # Add a publication date entry
    datestr = None
    if metadata['date']:
        datestr = str(metadata['date'][0])
    elif metadata['timestamp']:
        datestr = str(metadata['timestamp'][0])
    
    if not datestr:
        raise ValueError("missing date or timestamp")

    datestr = bytes(datestr)
    exth.write(pack(b'>II', EXTH_CODES['pubdate'], len(datestr) + 8))
    exth.write(datestr)
    nrecs += 1
    if is_periodical:
        exth.write(pack(b'>II', EXTH_CODES['lastupdatetime'], len(datestr) + 8))
        exth.write(datestr)
        nrecs += 1

    if be_kindlegen2:
        vals = {204:201, 205:2, 206:5, 207:0}
    elif is_periodical:
        # Pretend to be amazon's super secret periodical generator
        vals = {204:201, 205:2, 206:0, 207:101}
    else:
        # Pretend to be kindlegen 1.2
        vals = {204:201, 205:1, 206:2, 207:33307}
    for code, val in vals.iteritems():
        exth.write(pack(b'>III', code, 12, val))
        nrecs += 1

    if cover_offset is not None:
        exth.write(pack(b'>III', EXTH_CODES['coveroffset'], 12,
            cover_offset))
        exth.write(pack(b'>III', EXTH_CODES['hasfakecover'], 12, 0))
        nrecs += 2
    if thumbnail_offset is not None:
        exth.write(pack(b'>III', EXTH_CODES['thumboffset'], 12,
            thumbnail_offset))
        thumbnail_uri_str = bytes('kindle:embed:%s' %(to_base(thumbnail_offset, base=32, min_num_digits=4)))
        exth.write(pack(b'>II', EXTH_CODES['kf8_thumbnail_uri'], len(thumbnail_uri_str) + 8))
        exth.write(thumbnail_uri_str)
        nrecs += 2

    if start_offset is not None:
        try:
            len(start_offset)
        except TypeError:
            start_offset = [start_offset]
        for so in start_offset:
            if so is not None:
                exth.write(pack(b'>III', EXTH_CODES['startreading'], 12,
                    so))
                nrecs += 1

    if kf8_header_index is not None:
        exth.write(pack(b'>III', EXTH_CODES['kf8_header_index'], 12,
            kf8_header_index))
        nrecs += 1

    if num_of_resources is not None:
        exth.write(pack(b'>III', EXTH_CODES['num_of_resources'], 12,
            num_of_resources))
        nrecs += 1

    if kf8_unknown_count is not None:
        exth.write(pack(b'>III', EXTH_CODES['kf8_unknown_count'], 12,
            kf8_unknown_count))
        nrecs += 1
    
    #Extra metadata for fullscrenn
    if opts and opts.book_mode == 'comic': #added for kindleear [insert0003 2017-09-03]
        exth.write(pack(b'>II', EXTH_CODES['RegionMagnification'], 13))
        exth.write(b'false')
        exth.write(pack(b'>II', EXTH_CODES['book-type'], 13))
        exth.write(b'comic')
        exth.write(pack(b'>II', EXTH_CODES['zero-gutter'], 12))
        exth.write(b'true')
        exth.write(pack(b'>II', EXTH_CODES['zero-margin'], 12))
        exth.write(b'true')
        exth.write(pack(b'>II', EXTH_CODES['primary-writing-mode'], 21))
        exth.write(b'horizontal-lr')
        exth.write(pack(b'>II', EXTH_CODES['fixed-layout'], 12))
        exth.write(b'true')
        exth.write(pack(b'>II', EXTH_CODES['orientation-lock'], 16))
        exth.write(b'portrait')
        original_resolution = b'%dx%d' % opts.dest.comic_screen_size #sth like comic_screen_size = (1072, 1430)
        exth.write(pack(b'>II', EXTH_CODES['original-resolution'], len(original_resolution) + 8))
        exth.write(original_resolution)
        nrecs += 8
        
    exth = exth.getvalue()
    trail = len(exth) % 4
    pad = b'\0' * (4 - trail) # Always pad w/ at least 1 byte
    exth = [b'EXTH', pack(b'>II', len(exth) + 12, nrecs), exth, pad]
    return b''.join(exth)
Exemplo n.º 3
0
def build_exth(metadata, prefer_author_sort=False, is_periodical=False,
        share_not_sync=True, cover_offset=None, thumbnail_offset=None,
        start_offset=None, mobi_doctype=2, num_of_resources=None,
        kf8_unknown_count=0, be_kindlegen2=False, kf8_header_index=None,
        page_progression_direction=None, primary_writing_mode=None):
    exth = BytesIO()
    nrecs = 0

    for term in metadata:
        if term not in EXTH_CODES:
            continue
        code = EXTH_CODES[term]
        items = metadata[term]
        if term == 'creator':
            if prefer_author_sort:
                creators = [authors_to_sort_string([unicode_type(c)]) for c in
                            items]
            else:
                creators = [unicode_type(c) for c in items]
            items = creators
        elif term == 'rights':
            try:
                rights = utf8_text(unicode_type(metadata.rights[0]))
            except:
                rights = b'Unknown'
            exth.write(pack(b'>II', EXTH_CODES['rights'], len(rights) + 8))
            exth.write(rights)
            nrecs += 1
            continue

        for item in items:
            data = unicode_type(item)
            if term != 'description':
                data = COLLAPSE_RE.sub(' ', data)
            if term == 'identifier':
                if data.lower().startswith('urn:isbn:'):
                    data = data[9:]
                elif item.scheme.lower() == 'isbn':
                    pass
                else:
                    continue
            if term == 'language':
                d2 = lang_as_iso639_1(data)
                if d2:
                    data = d2
            data = utf8_text(data)
            exth.write(pack(b'>II', code, len(data) + 8))
            exth.write(data)
            nrecs += 1

    # Write UUID as ASIN
    uuid = None
    from calibre.ebooks.oeb.base import OPF
    for x in metadata['identifier']:
        if (x.get(OPF('scheme'), None).lower() == 'uuid' or
                unicode_type(x).startswith('urn:uuid:')):
            uuid = unicode_type(x).split(':')[-1]
            break
    if uuid is None:
        from uuid import uuid4
        uuid = str(uuid4())

    if isinstance(uuid, unicode_type):
        uuid = uuid.encode('utf-8')
    if not share_not_sync:
        exth.write(pack(b'>II', 113, len(uuid) + 8))
        exth.write(uuid)
        nrecs += 1

    # Write UUID as SOURCE
    c_uuid = b'calibre:%s' % uuid
    exth.write(pack(b'>II', 112, len(c_uuid) + 8))
    exth.write(c_uuid)
    nrecs += 1

    # Write cdetype
    if not is_periodical:
        if not share_not_sync:
            exth.write(pack(b'>II', 501, 12))
            exth.write(b'EBOK')
            nrecs += 1
    else:
        ids = {0x101:b'NWPR', 0x103:b'MAGZ'}.get(mobi_doctype, None)
        if ids:
            exth.write(pack(b'>II', 501, 12))
            exth.write(ids)
            nrecs += 1

    # Add a publication date entry
    if metadata['date']:
        datestr = str(metadata['date'][0])
    elif metadata['timestamp']:
        datestr = str(metadata['timestamp'][0])

    if datestr is None:
        raise ValueError("missing date or timestamp")

    datestr = bytes(datestr)
    exth.write(pack(b'>II', EXTH_CODES['pubdate'], len(datestr) + 8))
    exth.write(datestr)
    nrecs += 1
    if is_periodical:
        exth.write(pack(b'>II', EXTH_CODES['lastupdatetime'], len(datestr) + 8))
        exth.write(datestr)
        nrecs += 1

    if be_kindlegen2:
        mv = 200 if iswindows else 202 if isosx else 201
        vals = {204:mv, 205:2, 206:9, 207:0}
    elif is_periodical:
        # Pretend to be amazon's super secret periodical generator
        vals = {204:201, 205:2, 206:0, 207:101}
    else:
        # Pretend to be kindlegen 1.2
        vals = {204:201, 205:1, 206:2, 207:33307}
    for code, val in vals.iteritems():
        exth.write(pack(b'>III', code, 12, val))
        nrecs += 1
    if be_kindlegen2:
        revnum = b'0730-890adc2'
        exth.write(pack(b'>II', 535, 8 + len(revnum)) + revnum)
        nrecs += 1

    if cover_offset is not None:
        exth.write(pack(b'>III', EXTH_CODES['coveroffset'], 12,
            cover_offset))
        exth.write(pack(b'>III', EXTH_CODES['hasfakecover'], 12, 0))
        nrecs += 2
    if thumbnail_offset is not None:
        exth.write(pack(b'>III', EXTH_CODES['thumboffset'], 12,
            thumbnail_offset))
        thumbnail_uri_str = bytes('kindle:embed:%s' %(to_base(thumbnail_offset, base=32, min_num_digits=4)))
        exth.write(pack(b'>II', EXTH_CODES['kf8_thumbnail_uri'], len(thumbnail_uri_str) + 8))
        exth.write(thumbnail_uri_str)
        nrecs += 2

    if start_offset is not None:
        try:
            len(start_offset)
        except TypeError:
            start_offset = [start_offset]
        for so in start_offset:
            if so is not None:
                exth.write(pack(b'>III', EXTH_CODES['startreading'], 12,
                    so))
                nrecs += 1

    if kf8_header_index is not None:
        exth.write(pack(b'>III', EXTH_CODES['kf8_header_index'], 12,
            kf8_header_index))
        nrecs += 1

    if num_of_resources is not None:
        exth.write(pack(b'>III', EXTH_CODES['num_of_resources'], 12,
            num_of_resources))
        nrecs += 1

    if kf8_unknown_count is not None:
        exth.write(pack(b'>III', EXTH_CODES['kf8_unknown_count'], 12,
            kf8_unknown_count))
        nrecs += 1

    if primary_writing_mode:
        pwm = primary_writing_mode.encode('utf-8')
        exth.write(pack(b'>II', EXTH_CODES['primary_writing_mode'], len(pwm) + 8))
        exth.write(pwm)
        nrecs += 1

    if page_progression_direction in {'rtl', 'ltr', 'default'}:
        ppd = bytes(page_progression_direction)
        exth.write(pack(b'>II', EXTH_CODES['page_progression_direction'], len(ppd) + 8))
        exth.write(ppd)
        nrecs += 1

    exth = exth.getvalue()
    trail = len(exth) % 4
    pad = b'\0' * (4 - trail)  # Always pad w/ at least 1 byte
    exth = [b'EXTH', pack(b'>II', len(exth) + 12, nrecs), exth, pad]
    return b''.join(exth)
Exemplo n.º 4
0
def build_exth(metadata,
               prefer_author_sort=False,
               is_periodical=False,
               share_not_sync=True,
               cover_offset=None,
               thumbnail_offset=None,
               start_offset=None,
               mobi_doctype=2,
               num_of_resources=None,
               kf8_unknown_count=0,
               be_kindlegen2=False,
               kf8_header_index=None,
               opts=None):
    exth = BytesIO()
    nrecs = 0

    for term in metadata:
        if term not in EXTH_CODES: continue
        code = EXTH_CODES[term]
        items = metadata[term]
        if term == 'creator':
            if prefer_author_sort:
                creators = [
                    authors_to_sort_string([unicode(c)]) for c in items
                ]
            else:
                creators = [unicode(c) for c in items]
            items = creators
        elif term == 'rights':
            try:
                rights = utf8_text(unicode(metadata.rights[0]))
            except:
                rights = b'Unknown'
            exth.write(pack(b'>II', EXTH_CODES['rights'], len(rights) + 8))
            exth.write(rights)
            nrecs += 1
            continue

        for item in items:
            data = unicode(item)
            if term != 'description':
                data = COLLAPSE_RE.sub(' ', data)
            if term == 'identifier':
                if data.lower().startswith('urn:isbn:'):
                    data = data[9:]
                elif item.scheme.lower() == 'isbn':
                    pass
                else:
                    continue
            if term == 'language':
                d2 = usr_lang_as_iso639_1(data)
                if d2:
                    data = d2
            data = utf8_text(data)
            exth.write(pack(b'>II', code, len(data) + 8))
            exth.write(data)
            nrecs += 1

    # Write UUID as ASIN
    uuid = None
    from calibre.ebooks.oeb.base import OPF
    for x in metadata['identifier']:
        if (x.get(OPF('scheme'), None).lower() == 'uuid'
                or unicode(x).startswith('urn:uuid:')):
            uuid = unicode(x).split(':')[-1]
            break
    if uuid is None:
        from uuid import uuid4
        uuid = str(uuid4())

    if isinstance(uuid, unicode):
        uuid = uuid.encode('utf-8')
    if not share_not_sync:
        exth.write(pack(b'>II', 113, len(uuid) + 8))
        exth.write(uuid)
        nrecs += 1

    # Write UUID as SOURCE
    c_uuid = b'calibre:%s' % uuid
    exth.write(pack(b'>II', 112, len(c_uuid) + 8))
    exth.write(c_uuid)
    nrecs += 1

    # Write cdetype
    if not is_periodical:
        if not share_not_sync:
            exth.write(pack(b'>II', 501, 12))
            exth.write(b'EBOK')
            nrecs += 1
    else:
        ids = {0x101: b'NWPR', 0x103: b'MAGZ'}.get(mobi_doctype, None)
        if ids:
            exth.write(pack(b'>II', 501, 12))
            exth.write(ids)
            nrecs += 1

    # Add a publication date entry
    datestr = None
    if metadata['date']:
        datestr = str(metadata['date'][0])
    elif metadata['timestamp']:
        datestr = str(metadata['timestamp'][0])

    if not datestr:
        raise ValueError("missing date or timestamp")

    datestr = bytes(datestr)
    exth.write(pack(b'>II', EXTH_CODES['pubdate'], len(datestr) + 8))
    exth.write(datestr)
    nrecs += 1
    if is_periodical:
        exth.write(pack(b'>II', EXTH_CODES['lastupdatetime'],
                        len(datestr) + 8))
        exth.write(datestr)
        nrecs += 1

    if be_kindlegen2:
        vals = {204: 201, 205: 2, 206: 5, 207: 0}
    elif is_periodical:
        # Pretend to be amazon's super secret periodical generator
        vals = {204: 201, 205: 2, 206: 0, 207: 101}
    else:
        # Pretend to be kindlegen 1.2
        vals = {204: 201, 205: 1, 206: 2, 207: 33307}
    for code, val in vals.iteritems():
        exth.write(pack(b'>III', code, 12, val))
        nrecs += 1

    if cover_offset is not None:
        exth.write(pack(b'>III', EXTH_CODES['coveroffset'], 12, cover_offset))
        exth.write(pack(b'>III', EXTH_CODES['hasfakecover'], 12, 0))
        nrecs += 2
    if thumbnail_offset is not None:
        exth.write(
            pack(b'>III', EXTH_CODES['thumboffset'], 12, thumbnail_offset))
        thumbnail_uri_str = bytes(
            'kindle:embed:%s' %
            (to_base(thumbnail_offset, base=32, min_num_digits=4)))
        exth.write(
            pack(b'>II', EXTH_CODES['kf8_thumbnail_uri'],
                 len(thumbnail_uri_str) + 8))
        exth.write(thumbnail_uri_str)
        nrecs += 2

    if start_offset is not None:
        try:
            len(start_offset)
        except TypeError:
            start_offset = [start_offset]
        for so in start_offset:
            if so is not None:
                exth.write(pack(b'>III', EXTH_CODES['startreading'], 12, so))
                nrecs += 1

    if kf8_header_index is not None:
        exth.write(
            pack(b'>III', EXTH_CODES['kf8_header_index'], 12,
                 kf8_header_index))
        nrecs += 1

    if num_of_resources is not None:
        exth.write(
            pack(b'>III', EXTH_CODES['num_of_resources'], 12,
                 num_of_resources))
        nrecs += 1

    if kf8_unknown_count is not None:
        exth.write(
            pack(b'>III', EXTH_CODES['kf8_unknown_count'], 12,
                 kf8_unknown_count))
        nrecs += 1

    #Extra metadata for fullscrenn
    if opts and opts.book_mode == 'comic':  #added for kindleear [insert0003 2017-09-03]
        exth.write(pack(b'>II', EXTH_CODES['RegionMagnification'], 13))
        exth.write(b'false')
        exth.write(pack(b'>II', EXTH_CODES['book-type'], 13))
        exth.write(b'comic')
        exth.write(pack(b'>II', EXTH_CODES['zero-gutter'], 12))
        exth.write(b'true')
        exth.write(pack(b'>II', EXTH_CODES['zero-margin'], 12))
        exth.write(b'true')
        exth.write(pack(b'>II', EXTH_CODES['primary-writing-mode'], 21))
        exth.write(b'horizontal-lr')
        exth.write(pack(b'>II', EXTH_CODES['fixed-layout'], 12))
        exth.write(b'true')
        exth.write(pack(b'>II', EXTH_CODES['orientation-lock'], 16))
        exth.write(b'portrait')
        original_resolution = b'%dx%d' % opts.dest.comic_screen_size  #sth like comic_screen_size = (1072, 1430)
        exth.write(
            pack(b'>II', EXTH_CODES['original-resolution'],
                 len(original_resolution) + 8))
        exth.write(original_resolution)
        nrecs += 8

    exth = exth.getvalue()
    trail = len(exth) % 4
    pad = b'\0' * (4 - trail)  # Always pad w/ at least 1 byte
    exth = [b'EXTH', pack(b'>II', len(exth) + 12, nrecs), exth, pad]
    return b''.join(exth)
Exemplo n.º 5
0
def build_exth(metadata, prefer_author_sort=False, is_periodical=False,
        share_not_sync=True, cover_offset=None, thumbnail_offset=None,
        start_offset=None, mobi_doctype=2, num_of_resources=None,
        kf8_unknown_count=0, be_kindlegen2=False, kf8_header_index=None):
    exth = BytesIO()
    nrecs = 0

    for term in metadata:
        if term not in EXTH_CODES:
            continue
        code = EXTH_CODES[term]
        items = metadata[term]
        if term == 'creator':
            if prefer_author_sort:
                creators = [authors_to_sort_string([unicode(c)]) for c in
                            items]
            else:
                creators = [unicode(c) for c in items]
            items = creators
        elif term == 'rights':
            try:
                rights = utf8_text(unicode(metadata.rights[0]))
            except:
                rights = b'Unknown'
            exth.write(pack(b'>II', EXTH_CODES['rights'], len(rights) + 8))
            exth.write(rights)
            nrecs += 1
            continue

        for item in items:
            data = unicode(item)
            if term != 'description':
                data = COLLAPSE_RE.sub(' ', data)
            if term == 'identifier':
                if data.lower().startswith('urn:isbn:'):
                    data = data[9:]
                elif item.scheme.lower() == 'isbn':
                    pass
                else:
                    continue
            if term == 'language':
                d2 = lang_as_iso639_1(data)
                if d2:
                    data = d2
            data = utf8_text(data)
            exth.write(pack(b'>II', code, len(data) + 8))
            exth.write(data)
            nrecs += 1

    # Write UUID as ASIN
    uuid = None
    from calibre.ebooks.oeb.base import OPF
    for x in metadata['identifier']:
        if (x.get(OPF('scheme'), None).lower() == 'uuid' or
                unicode(x).startswith('urn:uuid:')):
            uuid = unicode(x).split(':')[-1]
            break
    if uuid is None:
        from uuid import uuid4
        uuid = str(uuid4())

    if isinstance(uuid, unicode):
        uuid = uuid.encode('utf-8')
    if not share_not_sync:
        exth.write(pack(b'>II', 113, len(uuid) + 8))
        exth.write(uuid)
        nrecs += 1

    # Write UUID as SOURCE
    c_uuid = b'calibre:%s' % uuid
    exth.write(pack(b'>II', 112, len(c_uuid) + 8))
    exth.write(c_uuid)
    nrecs += 1

    # Write cdetype
    if not is_periodical:
        if not share_not_sync:
            exth.write(pack(b'>II', 501, 12))
            exth.write(b'EBOK')
            nrecs += 1
    else:
        ids = {0x101:b'NWPR', 0x103:b'MAGZ'}.get(mobi_doctype, None)
        if ids:
            exth.write(pack(b'>II', 501, 12))
            exth.write(ids)
            nrecs += 1

    # Add a publication date entry
    if metadata['date']:
        datestr = str(metadata['date'][0])
    elif metadata['timestamp']:
        datestr = str(metadata['timestamp'][0])

    if datestr is None:
        raise ValueError("missing date or timestamp")

    datestr = bytes(datestr)
    exth.write(pack(b'>II', EXTH_CODES['pubdate'], len(datestr) + 8))
    exth.write(datestr)
    nrecs += 1
    if is_periodical:
        exth.write(pack(b'>II', EXTH_CODES['lastupdatetime'], len(datestr) + 8))
        exth.write(datestr)
        nrecs += 1

    if be_kindlegen2:
        mv = 200 if iswindows else 202 if isosx else 201
        vals = {204:mv, 205:2, 206:9, 207:0}
    elif is_periodical:
        # Pretend to be amazon's super secret periodical generator
        vals = {204:201, 205:2, 206:0, 207:101}
    else:
        # Pretend to be kindlegen 1.2
        vals = {204:201, 205:1, 206:2, 207:33307}
    for code, val in vals.iteritems():
        exth.write(pack(b'>III', code, 12, val))
        nrecs += 1
    if be_kindlegen2:
        revnum = b'0730-890adc2'
        exth.write(pack(b'>II', 535, 8 + len(revnum)) + revnum)
        nrecs += 1

    if cover_offset is not None:
        exth.write(pack(b'>III', EXTH_CODES['coveroffset'], 12,
            cover_offset))
        exth.write(pack(b'>III', EXTH_CODES['hasfakecover'], 12, 0))
        nrecs += 2
    if thumbnail_offset is not None:
        exth.write(pack(b'>III', EXTH_CODES['thumboffset'], 12,
            thumbnail_offset))
        thumbnail_uri_str = bytes('kindle:embed:%s' %(to_base(thumbnail_offset, base=32, min_num_digits=4)))
        exth.write(pack(b'>II', EXTH_CODES['kf8_thumbnail_uri'], len(thumbnail_uri_str) + 8))
        exth.write(thumbnail_uri_str)
        nrecs += 2

    if start_offset is not None:
        try:
            len(start_offset)
        except TypeError:
            start_offset = [start_offset]
        for so in start_offset:
            if so is not None:
                exth.write(pack(b'>III', EXTH_CODES['startreading'], 12,
                    so))
                nrecs += 1

    if kf8_header_index is not None:
        exth.write(pack(b'>III', EXTH_CODES['kf8_header_index'], 12,
            kf8_header_index))
        nrecs += 1

    if num_of_resources is not None:
        exth.write(pack(b'>III', EXTH_CODES['num_of_resources'], 12,
            num_of_resources))
        nrecs += 1

    if kf8_unknown_count is not None:
        exth.write(pack(b'>III', EXTH_CODES['kf8_unknown_count'], 12,
            kf8_unknown_count))
        nrecs += 1

    exth = exth.getvalue()
    trail = len(exth) % 4
    pad = b'\0' * (4 - trail)  # Always pad w/ at least 1 byte
    exth = [b'EXTH', pack(b'>II', len(exth) + 12, nrecs), exth, pad]
    return b''.join(exth)
Exemplo n.º 6
0
def build_exth(metadata,
               prefer_author_sort=False,
               is_periodical=False,
               share_not_sync=True,
               cover_offset=None,
               thumbnail_offset=None,
               start_offset=None,
               mobi_doctype=2,
               num_of_resources=None,
               kf8_unknown_count=0,
               be_kindlegen2=False,
               kf8_header_index=None):
    exth = BytesIO()
    nrecs = 0

    for term in metadata:
        if term not in EXTH_CODES: continue
        code = EXTH_CODES[term]
        items = metadata[term]
        if term == 'creator':
            if prefer_author_sort:
                creators = [unicode(c.file_as or c) for c in items][:1]
            else:
                creators = [unicode(c) for c in items]
            items = creators
        for item in items:
            data = unicode(item)
            if term != 'description':
                data = COLLAPSE_RE.sub(' ', data)
            if term == 'identifier':
                if data.lower().startswith('urn:isbn:'):
                    data = data[9:]
                elif item.scheme.lower() == 'isbn':
                    pass
                else:
                    continue
            data = utf8_text(data)
            exth.write(pack(b'>II', code, len(data) + 8))
            exth.write(data)
            nrecs += 1
        if term == 'rights':
            try:
                rights = utf8_text(unicode(metadata.rights[0]))
            except:
                rights = b'Unknown'
            exth.write(pack(b'>II', EXTH_CODES['rights'], len(rights) + 8))
            exth.write(rights)
            nrecs += 1

    # Write UUID as ASIN
    uuid = None
    from calibre.ebooks.oeb.base import OPF
    for x in metadata['identifier']:
        if (x.get(OPF('scheme'), None).lower() == 'uuid'
                or unicode(x).startswith('urn:uuid:')):
            uuid = unicode(x).split(':')[-1]
            break
    if uuid is None:
        from uuid import uuid4
        uuid = str(uuid4())

    if isinstance(uuid, unicode):
        uuid = uuid.encode('utf-8')
    if not share_not_sync:
        exth.write(pack(b'>II', 113, len(uuid) + 8))
        exth.write(uuid)
        nrecs += 1

    # Write cdetype
    if not is_periodical:
        if not share_not_sync:
            exth.write(pack(b'>II', 501, 12))
            exth.write(b'EBOK')
            nrecs += 1
    else:
        ids = {0x101: b'NWPR', 0x103: b'MAGZ'}.get(mobi_doctype, None)
        if ids:
            exth.write(pack(b'>II', 501, 12))
            exth.write(ids)
            nrecs += 1

    # Add a publication date entry
    if metadata['date']:
        datestr = str(metadata['date'][0])
    elif metadata['timestamp']:
        datestr = str(metadata['timestamp'][0])

    if datestr is None:
        raise ValueError("missing date or timestamp")

    datestr = bytes(datestr)
    exth.write(pack(b'>II', EXTH_CODES['pubdate'], len(datestr) + 8))
    exth.write(datestr)
    nrecs += 1
    if is_periodical:
        exth.write(pack(b'>II', EXTH_CODES['lastupdatetime'],
                        len(datestr) + 8))
        exth.write(datestr)
        nrecs += 1

    if be_kindlegen2:
        vals = {204: 201, 205: 2, 206: 2, 207: 35621}
    elif is_periodical:
        # Pretend to be amazon's super secret periodical generator
        vals = {204: 201, 205: 2, 206: 0, 207: 101}
    else:
        # Pretend to be kindlegen 1.2
        vals = {204: 201, 205: 1, 206: 2, 207: 33307}
    for code, val in vals.iteritems():
        exth.write(pack(b'>III', code, 12, val))
        nrecs += 1

    if cover_offset is not None:
        exth.write(pack(b'>III', EXTH_CODES['coveroffset'], 12, cover_offset))
        exth.write(pack(b'>III', EXTH_CODES['hasfakecover'], 12, 0))
        nrecs += 2
    if thumbnail_offset is not None:
        exth.write(
            pack(b'>III', EXTH_CODES['thumboffset'], 12, thumbnail_offset))
        nrecs += 1

    if start_offset is not None:
        try:
            len(start_offset)
        except TypeError:
            start_offset = [start_offset]
        for so in start_offset:
            if so is not None:
                exth.write(pack(b'>III', EXTH_CODES['startreading'], 12, so))
                nrecs += 1

    if kf8_header_index is not None:
        exth.write(
            pack(b'>III', EXTH_CODES['kf8_header_index'], 12,
                 kf8_header_index))
        nrecs += 1

    if num_of_resources is not None:
        exth.write(
            pack(b'>III', EXTH_CODES['num_of_resources'], 12,
                 num_of_resources))
        nrecs += 1

    if kf8_unknown_count is not None:
        exth.write(
            pack(b'>III', EXTH_CODES['kf8_unknown_count'], 12,
                 kf8_unknown_count))
        nrecs += 1

    exth = exth.getvalue()
    trail = len(exth) % 4
    pad = b'\0' * (4 - trail)  # Always pad w/ at least 1 byte
    exth = [b'EXTH', pack(b'>II', len(exth) + 12, nrecs), exth, pad]
    return b''.join(exth)