chapisha/helpers/pages.py
def create_content_opf(metadata: WorkMetadata, image_manifest: list[str], spine: list[Matter]) -> str:
    """
    Load the default `content.opf` file, and generate the required terms for the creative work. Return xhtml as a string.
    
    Parameters
    ----------
    metadata: WorkMetadata
        All the terms for updating the work, not all compulsory
    manifest: list of str
        Complete resource manifest for the work, derived from `ZipFile.namelist()`
    spine: list of Matter
        Spine and guide list of Matter, with `dedication` at 0, if present

    Returns
    -------
    str: xhtml response for `content.opf` as a str.
    """
    with open(DATA_PATH / "xhtml" / DEFAULT_CONTENT_OPF, "r+", encoding="utf-8") as opf_file:
        opf_xml = opf_file.read()
        ################################################################################################################
        # METADATA
        ################################################################################################################
        # dc:identifier
        opf_xml = opf_xml.replace('<dc:identifier id="uid"></dc:identifier>', 
                                  F'<dc:identifier id="uid">{metadata.identifier}</dc:identifier>')
        # dc:date
        opf_xml = opf_xml.replace('<dc:date></dc:date>', 
                                  F'<dc:date>{metadata.isodate.isoformat().split("T")[0]}T00:00:00Z</dc:date>')
        # meta dcterms:modified date.now
        opf_xml = opf_xml.replace('<meta property="dcterms:modified"></meta>', 
                                  F'<meta property="dcterms:modified">{datetime.datetime.now(zoneinfo.ZoneInfo("Europe/Paris")).isoformat("T", "seconds").split("+")[0]}Z</meta>')
        # dc:rights
        opf_xml = opf_xml.replace('<dc:rights></dc:rights>',
                                  F'<dc:rights>{metadata.rights} For full license information see the Colophon (colophon.xhtml) included at the end of this ebook.</dc:rights>')
        # dc:publisher
        if metadata.publisher:
            opf_xml = opf_xml.replace('<meta property="se:url.homepage" refines="#generator">https://github.com/whythawk/chapisha</meta>', 
                                      F'''<meta property="se:url.homepage" refines="#generator">https://github.com/whythawk/chapisha</meta>\n\t\t<dc:publisher id="publisher">{metadata.publisher}</dc:publisher>\n\t\t<meta property="file-as" refines="#publisher">{metadata.publisher}</meta>''')
        # dc:title
        opf_xml = opf_xml.replace('<dc:title id="title"></dc:title>\n\t\t<meta property="file-as" refines="#title"></meta>', 
                                  F'<dc:title id="title">{metadata.title}</dc:title>\n\t\t<meta property="file-as" refines="#title">{metadata.title}</meta>')
        # dc:subject
        subject_xml = ""
        if metadata.subject and len(metadata.subject):
            if isinstance(metadata.subject, str):
                metadata.subject = [metadata.subject]
            for i, subject in enumerate(metadata.subject):
                subject_xml += F'\t\t<dc:subject id="subject-{i+1}">{subject}</dc:subject>\n'
        opf_xml = opf_xml.replace('\t\t<dc:subject id="subject-1"></dc:subject>\n', 
                                  subject_xml)
        # dc:description
        description_xml = ""
        if metadata.description:
            description_xml = F'<dc:description id="description">{metadata.description}</dc:description>'
        opf_xml = opf_xml.replace('<dc:description id="description"></dc:description>', 
                                  description_xml)
        # meta long-description
        long_description_xml = ""
        if metadata.long_description:
            long_description = "\n\n".join(formats.get_text_paragraphs(metadata.long_description))
            long_description_xml = F'<meta id="long-description" property="se:long-description" refines="#description">{long_description}</meta>'
        opf_xml = opf_xml.replace('<meta id="long-description" property="se:long-description" refines="#description"></meta>', 
                                  long_description_xml)
        # dc:language
        opf_xml = opf_xml.replace('<dc:language></dc:language>', 
                                  F'<dc:language>{metadata.language}</dc:language>')
        # meta word-count
        word_count_xml = ""
        if metadata.word_count:
            word_count_xml = F'<meta property="se:word-count">{metadata.word_count}</meta>'
        opf_xml = opf_xml.replace('<meta property="se:word-count"></meta>', 
                                  word_count_xml)
        # dc:creator
        creator_xml = ""
        for i, creator in enumerate(metadata.creator):
            creator_xml += F'\t\t<dc:creator id="author-{i+1}">{creator}</dc:creator>\n'
        opf_xml = opf_xml.replace('\t\t<dc:creator id="author"></dc:creator>\n', 
                                  creator_xml)
        # dc:contributor
        contributor_xml = ""
        if metadata.contributor and len(metadata.contributor):
            for i, contributor in enumerate(metadata.contributor):
                contributor_xml += F'\t\t<dc:contributor id="{contributor.role}-{i+1}">{contributor.name}</dc:contributor>\n'
        opf_xml = opf_xml.replace('\t\t<dc:contributor id="artist"></dc:contributor>\n', 
                                  contributor_xml)
        ################################################################################################################
        # MANIFEST
        ################################################################################################################
        # IMAGES
        image_manifest_xml = ""
        for img in image_manifest:
            media_type = img.split(".")[-1]
            if media_type == "svg": media_type = "svg+xml"
            if media_type == "jpg": media_type = "jpeg"
            if "cover." in img:
                image_manifest_xml += F'\t\t<item href="{img}" id="{img.replace("images/","")}" media-type="image/{media_type}" properties="cover-image"/>\n'
            else:
                image_manifest_xml += F'\t\t<item href="{img}" id="{img.replace("images/","")}" media-type="image/{media_type}"/>\n'
        opf_xml = opf_xml.replace('\t\t<item href="images/titlepage.png" id="titlepage.png" media-type="image/png"/>\n', 
                                  image_manifest_xml)
        # CHAPTERS
        chapter_manifest_xml = ""
        spine_xml = ""
        chapter = 1
        for matter in spine:
            if matter.content == FrontMatter.dedication:
                chapter_manifest_xml += '\t\t<item href="text/dedication.xhtml" id="dedication.xhtml" media-type="application/xhtml+xml"/>\n'
                spine_xml += '\t\t<itemref idref="dedication.xhtml"/>\n'
            if matter.partition == MatterPartition.body:
                chapter_manifest_xml += F'\t\t<item href="text/chapter-{chapter}.xhtml" id="chapter-{chapter}.xhtml" media-type="application/xhtml+xml"/>\n'
                spine_xml += F'\t\t<itemref idref="chapter-{chapter}.xhtml"/>\n'
                chapter += 1
        opf_xml = opf_xml.replace('\t\t<item href="text/chapter-1.xhtml" id="chapter-1.xhtml" media-type="application/xhtml+xml"/>\n',
                                  chapter_manifest_xml)
        opf_xml = opf_xml.replace('\t\t<itemref idref="chapter-1.xhtml"/>\n',
                                  spine_xml)
    return opf_xml

    Load the default `content.opf` file, and generate the required terms for the creative work. Return xhtml as a string.
    
    Parameters
    ----------
    metadata: WorkMetadata
        All the terms for updating the work, not all compulsory
    manifest: list of str
        Complete resource manifest for the work, derived from `ZipFile.namelist()`
    spine: list of Matter
        Spine and guide list of Matter, with `dedication` at 0, if present

    Returns
    -------
    str: xhtml response for `content.opf` as a str.
    
Load the default `content.opf` file, and generate the required terms for the creative work. Return xhtml as a string.
Parameters

WorkMetadata
All the terms for updating the work, not all compulsory
manifest: list of str
Complete resource manifest for the work, derived from `ZipFile.namelist()`
spine: list of Matter
Spine and guide list of Matter, with `dedication` at 0, if present

Returns

xhtml response for `content.opf` as a str.
Load the default ` content . opf ` file and generate the required terms for the creative work . Return xhtml as a string . Parameters WorkMetadata All the terms for updating the work not all compulsory manifest : list of str Complete resource manifest for the work derived from ` ZipFile . namelist () ` spine : list of Matter Spine and guide list of Matter with ` dedication ` at 0 if present Returns xhtml response for ` content . opf ` as a str .
def create_content_opf(metadata: WorkMetadata, image_manifest: list[str], spine: list[Matter]) -> str:
    with open(DATA_PATH / "xhtml" / DEFAULT_CONTENT_OPF, "r+", encoding="utf-8") as opf_file:
        opf_xml = opf_file.read()
        opf_xml = opf_xml.replace('<dc:identifier id="uid"></dc:identifier>', 
                                  F'<dc:identifier id="uid">{metadata.identifier}</dc:identifier>')
        opf_xml = opf_xml.replace('<dc:date></dc:date>', 
                                  F'<dc:date>{metadata.isodate.isoformat().split("T")[0]}T00:00:00Z</dc:date>')
        opf_xml = opf_xml.replace('<meta property="dcterms:modified"></meta>', 
                                  F'<meta property="dcterms:modified">{datetime.datetime.now(zoneinfo.ZoneInfo("Europe/Paris")).isoformat("T", "seconds").split("+")[0]}Z</meta>')
        opf_xml = opf_xml.replace('<dc:rights></dc:rights>',
                                  F'<dc:rights>{metadata.rights} For full license information see the Colophon (colophon.xhtml) included at the end of this ebook.</dc:rights>')
        if metadata.publisher:
            opf_xml = opf_xml.replace('<meta property="se:url.homepage" refines="#generator">https://github.com/whythawk/chapisha</meta>', 
                                      F'''<meta property="se:url.homepage" refines="#generator">https://github.com/whythawk/chapisha</meta>\n\t\t<dc:publisher id="publisher">{metadata.publisher}</dc:publisher>\n\t\t<meta property="file-as" refines="#publisher">{metadata.publisher}</meta>''')
        opf_xml = opf_xml.replace('<dc:title id="title"></dc:title>\n\t\t<meta property="file-as" refines="#title"></meta>', 
                                  F'<dc:title id="title">{metadata.title}</dc:title>\n\t\t<meta property="file-as" refines="#title">{metadata.title}</meta>')
        subject_xml = ""
        if metadata.subject and len(metadata.subject):
            if isinstance(metadata.subject, str):
                metadata.subject = [metadata.subject]
            for i, subject in enumerate(metadata.subject):
                subject_xml += F'\t\t<dc:subject id="subject-{i+1}">{subject}</dc:subject>\n'
        opf_xml = opf_xml.replace('\t\t<dc:subject id="subject-1"></dc:subject>\n', 
                                  subject_xml)
        description_xml = ""
        if metadata.description:
            description_xml = F'<dc:description id="description">{metadata.description}</dc:description>'
        opf_xml = opf_xml.replace('<dc:description id="description"></dc:description>', 
                                  description_xml)
        long_description_xml = ""
        if metadata.long_description:
            long_description = "\n\n".join(formats.get_text_paragraphs(metadata.long_description))
            long_description_xml = F'<meta id="long-description" property="se:long-description" refines="#description">{long_description}</meta>'
        opf_xml = opf_xml.replace('<meta id="long-description" property="se:long-description" refines="#description"></meta>', 
                                  long_description_xml)
        opf_xml = opf_xml.replace('<dc:language></dc:language>', 
                                  F'<dc:language>{metadata.language}</dc:language>')
        word_count_xml = ""
        if metadata.word_count:
            word_count_xml = F'<meta property="se:word-count">{metadata.word_count}</meta>'
        opf_xml = opf_xml.replace('<meta property="se:word-count"></meta>', 
                                  word_count_xml)
        creator_xml = ""
        for i, creator in enumerate(metadata.creator):
            creator_xml += F'\t\t<dc:creator id="author-{i+1}">{creator}</dc:creator>\n'
        opf_xml = opf_xml.replace('\t\t<dc:creator id="author"></dc:creator>\n', 
                                  creator_xml)
        contributor_xml = ""
        if metadata.contributor and len(metadata.contributor):
            for i, contributor in enumerate(metadata.contributor):
                contributor_xml += F'\t\t<dc:contributor id="{contributor.role}-{i+1}">{contributor.name}</dc:contributor>\n'
        opf_xml = opf_xml.replace('\t\t<dc:contributor id="artist"></dc:contributor>\n', 
                                  contributor_xml)
        image_manifest_xml = ""
        for img in image_manifest:
            media_type = img.split(".")[-1]
            if media_type == "svg": media_type = "svg+xml"
            if media_type == "jpg": media_type = "jpeg"
            if "cover." in img:
                image_manifest_xml += F'\t\t<item href="{img}" id="{img.replace("images/","")}" media-type="image/{media_type}" properties="cover-image"/>\n'
            else:
                image_manifest_xml += F'\t\t<item href="{img}" id="{img.replace("images/","")}" media-type="image/{media_type}"/>\n'
        opf_xml = opf_xml.replace('\t\t<item href="images/titlepage.png" id="titlepage.png" media-type="image/png"/>\n', 
                                  image_manifest_xml)
        chapter_manifest_xml = ""
        spine_xml = ""
        chapter = 1
        for matter in spine:
            if matter.content == FrontMatter.dedication:
                chapter_manifest_xml += '\t\t<item href="text/dedication.xhtml" id="dedication.xhtml" media-type="application/xhtml+xml"/>\n'
                spine_xml += '\t\t<itemref idref="dedication.xhtml"/>\n'
            if matter.partition == MatterPartition.body:
                chapter_manifest_xml += F'\t\t<item href="text/chapter-{chapter}.xhtml" id="chapter-{chapter}.xhtml" media-type="application/xhtml+xml"/>\n'
                spine_xml += F'\t\t<itemref idref="chapter-{chapter}.xhtml"/>\n'
                chapter += 1
        opf_xml = opf_xml.replace('\t\t<item href="text/chapter-1.xhtml" id="chapter-1.xhtml" media-type="application/xhtml+xml"/>\n',
                                  chapter_manifest_xml)
        opf_xml = opf_xml.replace('\t\t<itemref idref="chapter-1.xhtml"/>\n',
                                  spine_xml)
    return opf_xml
def create_content_opf ( metadata : WorkMetadata , image_manifest : list [ str ] , spine : list [ Matter ] ) -> str : with open ( DATA_PATH / "xhtml" / DEFAULT_CONTENT_OPF , "r+" , encoding = "utf-8" ) as opf_file : opf_xml = opf_file . read ( ) opf_xml = opf_xml . replace ( '<dc:identifier id="uid"></dc:identifier>' , F'<dc:identifier id="uid">{metadata.identifier}</dc:identifier>' ) opf_xml = opf_xml . replace ( '<dc:date></dc:date>' , F'<dc:date>{metadata.isodate.isoformat().split("T")[0]}T00:00:00Z</dc:date>' ) opf_xml = opf_xml . replace ( '<meta property="dcterms:modified"></meta>' , F'<meta property="dcterms:modified">{datetime.datetime.now(zoneinfo.ZoneInfo("Europe/Paris")).isoformat("T", "seconds").split("+")[0]}Z</meta>' ) opf_xml = opf_xml . replace ( '<dc:rights></dc:rights>' , F'<dc:rights>{metadata.rights} For full license information see the Colophon (colophon.xhtml) included at the end of this ebook.</dc:rights>' ) if metadata . publisher : opf_xml = opf_xml . replace ( '<meta property="se:url.homepage" refines="#generator">https://github.com/whythawk/chapisha</meta>' , F'''<meta property="se:url.homepage" refines="#generator">https://github.com/whythawk/chapisha</meta>\n\t\t<dc:publisher id="publisher">{metadata.publisher}</dc:publisher>\n\t\t<meta property="file-as" refines="#publisher">{metadata.publisher}</meta>''' ) opf_xml = opf_xml . replace ( '<dc:title id="title"></dc:title>\n\t\t<meta property="file-as" refines="#title"></meta>' , F'<dc:title id="title">{metadata.title}</dc:title>\n\t\t<meta property="file-as" refines="#title">{metadata.title}</meta>' ) subject_xml = "" if metadata . subject and len ( metadata . subject ) : if isinstance ( metadata . subject , str ) : metadata . subject = [ metadata . subject ] for i , subject in enumerate ( metadata . subject ) : subject_xml += F'\t\t<dc:subject id="subject-{i+1}">{subject}</dc:subject>\n' opf_xml = opf_xml . replace ( '\t\t<dc:subject id="subject-1"></dc:subject>\n' , subject_xml ) description_xml = "" if metadata . description : description_xml = F'<dc:description id="description">{metadata.description}</dc:description>' opf_xml = opf_xml . replace ( '<dc:description id="description"></dc:description>' , description_xml ) long_description_xml = "" if metadata . long_description : long_description = "\n\n" . join ( formats . get_text_paragraphs ( metadata . long_description ) ) long_description_xml = F'<meta id="long-description" property="se:long-description" refines="#description">{long_description}</meta>' opf_xml = opf_xml . replace ( '<meta id="long-description" property="se:long-description" refines="#description"></meta>' , long_description_xml ) opf_xml = opf_xml . replace ( '<dc:language></dc:language>' , F'<dc:language>{metadata.language}</dc:language>' ) word_count_xml = "" if metadata . word_count : word_count_xml = F'<meta property="se:word-count">{metadata.word_count}</meta>' opf_xml = opf_xml . replace ( '<meta property="se:word-count"></meta>' , word_count_xml ) creator_xml = "" for i , creator in enumerate ( metadata . creator ) : creator_xml += F'\t\t<dc:creator id="author-{i+1}">{creator}</dc:creator>\n' opf_xml = opf_xml . replace ( '\t\t<dc:creator id="author"></dc:creator>\n' , creator_xml ) contributor_xml = "" if metadata . contributor and len ( metadata . contributor ) : for i , contributor in enumerate ( metadata . contributor ) : contributor_xml += F'\t\t<dc:contributor id="{contributor.role}-{i+1}">{contributor.name}</dc:contributor>\n' opf_xml = opf_xml . replace ( '\t\t<dc:contributor id="artist"></dc:contributor>\n' , contributor_xml ) image_manifest_xml = "" for img in image_manifest : media_type = img . split ( "." ) [ - 1 ] if media_type == "svg" : media_type = "svg+xml" if media_type == "jpg" : media_type = "jpeg" if "cover." in img : image_manifest_xml += F'\t\t<item href="{img}" id="{img.replace("images/","")}" media-type="image/{media_type}" properties="cover-image"/>\n' else : image_manifest_xml += F'\t\t<item href="{img}" id="{img.replace("images/","")}" media-type="image/{media_type}"/>\n' opf_xml = opf_xml . replace ( '\t\t<item href="images/titlepage.png" id="titlepage.png" media-type="image/png"/>\n' , image_manifest_xml ) chapter_manifest_xml = "" spine_xml = "" chapter = 1 for matter in spine : if matter . content == FrontMatter . dedication : chapter_manifest_xml += '\t\t<item href="text/dedication.xhtml" id="dedication.xhtml" media-type="application/xhtml+xml"/>\n' spine_xml += '\t\t<itemref idref="dedication.xhtml"/>\n' if matter . partition == MatterPartition . body : chapter_manifest_xml += F'\t\t<item href="text/chapter-{chapter}.xhtml" id="chapter-{chapter}.xhtml" media-type="application/xhtml+xml"/>\n' spine_xml += F'\t\t<itemref idref="chapter-{chapter}.xhtml"/>\n' chapter += 1 opf_xml = opf_xml . replace ( '\t\t<item href="text/chapter-1.xhtml" id="chapter-1.xhtml" media-type="application/xhtml+xml"/>\n' , chapter_manifest_xml ) opf_xml = opf_xml . replace ( '\t\t<itemref idref="chapter-1.xhtml"/>\n' , spine_xml ) return opf_xml
Load the default `content.opf` file, and generate the required terms for the creative work.
Load the default ` content . opf ` file and generate the required terms for the creative work .
"""
    Load the default `content.opf` file, and generate the required terms for the creative work. Return xhtml as a string.
    
    Parameters
    ----------
    metadata: WorkMetadata
        All the terms for updating the work, not all compulsory
    manifest: list of str
        Complete resource manifest for the work, derived from `ZipFile.namelist()`
    spine: list of Matter
        Spine and guide list of Matter, with `dedication` at 0, if present

    Returns
    -------
    str: xhtml response for `content.opf` as a str.
    """ ################################################################################################################ # METADATA ################################################################################################################ # dc:identifier # dc:date # meta dcterms:modified date.now # dc:rights # dc:publisher # dc:title # dc:subject # dc:description # meta long-description # dc:language # meta word-count # dc:creator # dc:contributor ################################################################################################################ # MANIFEST ################################################################################################################ # IMAGES # CHAPTERS
metadata
WorkMetadata
image_manifest
list[str]
spine
list[Matter]