You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
253 lines
10 KiB
253 lines
10 KiB
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import os
|
|
import json
|
|
import shutil
|
|
import tempfile
|
|
import subprocess
|
|
|
|
from .common import isRoot
|
|
from .common import rootPath
|
|
from .common import saveFile
|
|
from .common import projectUrl
|
|
from .common import projectDesc
|
|
from .common import releaseInfo
|
|
from .common import createFolder
|
|
from .common import resourceInfo
|
|
|
|
from .sequence import txtSerialize
|
|
from .sequence import jsonSerialize
|
|
from .sequence import htmlSerialize
|
|
from .sequence import gitbookSummary
|
|
from .sequence import gitbookChapters
|
|
from .sequence import gitbookMetadata
|
|
|
|
|
|
def txtRelease(metadata: dict, content: dict) -> None:
|
|
saveFile(releaseInfo['txt'], txtSerialize(metadata, content))
|
|
|
|
|
|
def jsonRelease(metadata: dict, content: dict) -> None:
|
|
saveFile(releaseInfo['json'], jsonSerialize(metadata, content))
|
|
|
|
|
|
def gitbookRelease(metadata: dict, content: dict) -> None:
|
|
createFolder(releaseInfo['gitbook'])
|
|
createFolder(os.path.join(releaseInfo['gitbook'], './assets/'))
|
|
createFolder(os.path.join(releaseInfo['gitbook'], './chapter/'))
|
|
|
|
cover = gitbookMetadata(metadata)
|
|
for (resName, resUrls) in resourceInfo.items():
|
|
cover += '{% hint style="success" %}\n' \
|
|
+ '### >>> [%s](%s) <<<\n' % (resName, resUrls[0]) \
|
|
+ '{% endhint %}\n\n'
|
|
cover += '{%% embed url="%s" %%}\n项目地址\n{%% endembed %%}\n' % projectUrl
|
|
|
|
saveFile(os.path.join(releaseInfo['gitbook'], 'README.md'), cover)
|
|
saveFile(os.path.join(releaseInfo['gitbook'], 'SUMMARY.md'), gitbookSummary(content))
|
|
for (chapterPath, chapterContent) in gitbookChapters(content).items():
|
|
saveFile(os.path.join(releaseInfo['gitbook'], chapterPath), chapterContent)
|
|
shutil.copy( # gitbook cover
|
|
os.path.join(rootPath, './assets/cover.jpg'),
|
|
os.path.join(releaseInfo['gitbook'], './assets/cover.jpg')
|
|
)
|
|
|
|
|
|
def staticDepends(workDir: str, metadata: dict, content: dict) -> None:
|
|
createFolder(os.path.join(workDir, './assets/'))
|
|
createFolder(os.path.join(workDir, './chapter/'))
|
|
|
|
cover = gitbookMetadata(metadata) + '<hr/>\n'
|
|
for (resName, resUrls) in resourceInfo.items():
|
|
cover += '\n{% hint style="tip" %}\n' \
|
|
+ '#### [%s](%s)([备用地址](%s))\n' % (resName, resUrls[0], resUrls[1]) \
|
|
+ '{% endhint %}\n'
|
|
|
|
bookInfo = json.dumps({
|
|
'title': metadata['name'],
|
|
'author': metadata['author'],
|
|
'description': projectDesc,
|
|
"language": "zh-hans",
|
|
'plugins': [
|
|
'-lunr', '-search', '-sharing', 'hints', 'github',
|
|
'hide-element', 'fontsettings', 'image-captions', 'back-to-top-button'
|
|
],
|
|
'pluginsConfig': {
|
|
'github': {'url': projectUrl},
|
|
'hide-element': {
|
|
'elements': ['.gitbook-link']
|
|
}
|
|
}
|
|
})
|
|
saveFile(os.path.join(workDir, 'README.md'), cover)
|
|
saveFile(os.path.join(workDir, 'book.json'), bookInfo)
|
|
saveFile(os.path.join(workDir, 'SUMMARY.md'), gitbookSummary(content))
|
|
for (chapterPath, chapterContent) in gitbookChapters(content).items():
|
|
saveFile(os.path.join(workDir, chapterPath), chapterContent)
|
|
shutil.copy( # gitbook cover
|
|
os.path.join(rootPath, './assets/cover.jpg'),
|
|
os.path.join(workDir, './assets/cover.jpg')
|
|
)
|
|
|
|
|
|
def htmlCompress(file: str) -> None:
|
|
rawHtml = open(file).read().split('\n')
|
|
with open(file, 'w') as fileObj:
|
|
fileObj.write('\n'.join([x.strip() for x in rawHtml if x.strip() != '']) + '\n')
|
|
|
|
|
|
def staticBuild(workDir: str) -> None:
|
|
buildDir = '/xxrs/'
|
|
nodeImage = 'node:10-alpine'
|
|
buildCommand = 'docker run --rm -v %s:%s --entrypoint sh %s -c "%s"' % (
|
|
workDir, buildDir, nodeImage,
|
|
'npm install gitbook-cli -g && gitbook install %s && gitbook build %s --log=debug' % (
|
|
buildDir, buildDir
|
|
)
|
|
)
|
|
print('Gitbook Build -> %s' % workDir)
|
|
subprocess.Popen(buildCommand, shell = True).wait() # blocking wait
|
|
os.rename(os.path.join(workDir, '_book'), os.path.join(workDir, 'XXRS'))
|
|
htmlCompress(os.path.join(workDir, './XXRS/index.html'))
|
|
chapterFolder = os.path.join(workDir, './XXRS/chapter/')
|
|
for file in os.listdir(chapterFolder): # compress html content
|
|
htmlCompress(os.path.join(chapterFolder, file))
|
|
os.system('cd %s && tar cJf %s XXRS' % (workDir, releaseInfo['static']))
|
|
|
|
|
|
def staticRelease(metadata: dict, content: dict) -> None:
|
|
if not isRoot():
|
|
print('\033[0;33mDue to the permission problems, it is recommended to run under root user.\033[0m')
|
|
return
|
|
tempDir = tempfile.TemporaryDirectory() # access temporary directory
|
|
staticDepends(tempDir.name, metadata, content)
|
|
staticBuild(tempDir.name)
|
|
tempDir.cleanup()
|
|
|
|
|
|
def calibreDepends(workDir: str, metadata: dict, content: dict) -> None:
|
|
metaInfo = [
|
|
'<?xml version="1.0"?>',
|
|
'<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">',
|
|
'<rootfiles>',
|
|
'<rootfile full-path="content.opf" media-type="application/oebps-package+xml"/>',
|
|
'</rootfiles>',
|
|
'</container>',
|
|
]
|
|
opfInfo = [
|
|
'<?xml version="1.0" encoding="utf-8"?>',
|
|
'<package xmlns="http://www.idpf.org/2007/opf" version="2.0" unique-identifier="uuid_id">',
|
|
'<opf:metadata xmlns:opf="http://www.idpf.org/2007/opf" xmlns:dc="http://purl.org/dc/elements/1.1/">',
|
|
'<dc:title>%s</dc:title>' % metadata['name'],
|
|
'<dc:language>zho</dc:language>',
|
|
'<dc:publisher>Dnomd343</dc:publisher>',
|
|
'<dc:creator opf:file-as="%(aut)s" opf:role="aut">%(aut)s</dc:creator>' % {'aut': metadata['author']},
|
|
'<dc:contributor opf:file-as="calibre" opf:role="bkp">%s</dc:contributor>' % projectUrl,
|
|
'<dc:description>%s</dc:description>' % '<div>%s</div>' % (
|
|
''.join(['<p>%s</p>' % x for x in metadata['desc']])
|
|
),
|
|
'<meta name="calibre:author_link_map" content="{"%s": ""}"/>' % metadata['author'],
|
|
'<meta name="calibre:title_sort" content="%s"/>' % metadata['name'],
|
|
'</opf:metadata>',
|
|
'<manifest>',
|
|
'<item id="html" href="xxrs.html" media-type="application/xhtml+xml"/>',
|
|
'<item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml"/>',
|
|
'</manifest>',
|
|
'<spine toc="ncx">', '<itemref idref="html"/>', '</spine>',
|
|
'</package>',
|
|
]
|
|
createFolder(os.path.join(workDir, 'META-INF'))
|
|
saveFile(os.path.join(workDir, 'mimetype'), 'application/epub+zip')
|
|
saveFile(os.path.join(workDir, 'content.opf'), '\n'.join(opfInfo) + '\n')
|
|
saveFile(os.path.join(workDir, 'xxrs.html'), htmlSerialize(metadata, content))
|
|
saveFile(os.path.join(workDir, 'META-INF', 'container.xml'), '\n'.join(metaInfo) + '\n')
|
|
|
|
|
|
def calibreRelease(metadata: dict, content: dict) -> None:
|
|
tempDir = tempfile.TemporaryDirectory() # access temporary directory
|
|
calibreDepends(tempDir.name, metadata, content)
|
|
os.system('cd %s && zip -r xxrs.zip *' % tempDir.name)
|
|
shutil.move(os.path.join(tempDir.name, 'xxrs.zip'), releaseInfo['calibre'])
|
|
tempDir.cleanup()
|
|
|
|
|
|
def calibreBuild(workDir: str, suffix: str, extOption: list, metadata: dict, content: dict) -> None:
|
|
buildDir = '/xxrs/'
|
|
calibreImage = 'linuxserver/calibre'
|
|
calibreCommand = [
|
|
'ebook-convert',
|
|
'xxrs.zip', 'xxrs%s' % suffix,
|
|
'--output-profile=generic_eink',
|
|
'--level1-toc=\'//h:h2\'',
|
|
'--cover=cover.jpg',
|
|
'--toc-title=目录',
|
|
'--remove-paragraph-spacing',
|
|
'--remove-paragraph-spacing-indent-size=2',
|
|
'--verbose',
|
|
]
|
|
buildCommand = 'docker run --rm -t -v %s:%s --workdir %s --entrypoint bash %s -c "%s"' % (
|
|
workDir, buildDir, buildDir, calibreImage, ' '.join(calibreCommand + extOption)
|
|
)
|
|
calibreDepends(workDir, metadata, content) # generate calibre input
|
|
os.system('cd %s && zip -r xxrs.zip *' % workDir) # compress as zip file
|
|
shutil.copy(
|
|
os.path.join(rootPath, './assets/cover.jpg'),
|
|
os.path.join(workDir, './cover.jpg') # load ebook cover
|
|
)
|
|
subprocess.Popen(buildCommand, shell = True).wait() # blocking wait
|
|
|
|
|
|
def epubRelease(metadata: dict, content: dict) -> None:
|
|
tempDir = tempfile.TemporaryDirectory() # access temporary directory
|
|
print('Calibre EPUB Build -> %s' % tempDir.name)
|
|
calibreBuild(tempDir.name, '.epub', [], metadata, content)
|
|
shutil.copy(os.path.join(tempDir.name, './xxrs.epub'), releaseInfo['epub'])
|
|
tempDir.cleanup()
|
|
|
|
|
|
# MOBI Type: KF7 = 0 (old) / KF7 + KF8 = 1 (both) / KF8 = 2 (new)
|
|
def mobiRelease(metadata: dict, content: dict, mobiType: int = 1) -> None:
|
|
mobiOption = ['--mobi-toc-at-start']
|
|
if mobiType == 0:
|
|
mobiOption.append('--mobi-file-type=old')
|
|
elif mobiType == 1:
|
|
mobiOption.append('--mobi-file-type=both')
|
|
elif mobiType == 2:
|
|
mobiOption.append('--mobi-file-type=new')
|
|
else:
|
|
print('Unknown MOBI type')
|
|
return
|
|
tempDir = tempfile.TemporaryDirectory() # access temporary directory
|
|
print('Calibre MOBI Build -> %s' % tempDir.name)
|
|
calibreBuild(tempDir.name, '.mobi', mobiOption, metadata, content)
|
|
shutil.copy(os.path.join(tempDir.name, './xxrs.mobi'), releaseInfo['mobi'])
|
|
tempDir.cleanup()
|
|
|
|
|
|
def setPdocMark(originFile: str, targetFile: str) -> None:
|
|
jdkImage = 'openjdk:17-alpine'
|
|
tempDir = tempfile.TemporaryDirectory() # access temporary directory
|
|
suffix = os.path.splitext(originFile)[-1]
|
|
shutil.copy(originFile, os.path.join(tempDir.name, 'xxrs%s' % suffix))
|
|
shutil.copy(
|
|
os.path.join(os.path.dirname(os.path.realpath(__file__)), 'mobi-meta.jar'), # script folder
|
|
os.path.join(tempDir.name, 'mobi-meta.jar')
|
|
)
|
|
dockerCommand = 'docker run --rm -v %(src)s:%(tmp)s --workdir %(tmp)s --entrypoint sh %(img)s -c "%(cmd)s"' % {
|
|
'src': tempDir.name,
|
|
'tmp': '/xxrs/',
|
|
'img': jdkImage,
|
|
'cmd': 'java -jar mobi-meta.jar edit xxrs%s xxrs_mod%s --pdoc' % (suffix, suffix),
|
|
}
|
|
subprocess.Popen(dockerCommand, shell = True).wait() # blocking wait
|
|
shutil.copy(os.path.join(tempDir.name, 'xxrs_mod%s' % suffix), targetFile)
|
|
tempDir.cleanup()
|
|
|
|
|
|
def azw3Release(metadata: dict, content: dict) -> None:
|
|
tempDir = tempfile.TemporaryDirectory() # access temporary directory
|
|
print('Calibre AZW3 Build -> %s' % tempDir.name)
|
|
calibreBuild(tempDir.name, '.azw3', ['--mobi-toc-at-start'], metadata, content)
|
|
setPdocMark(os.path.join(tempDir.name, './xxrs.azw3'), releaseInfo['azw3'])
|
|
tempDir.cleanup()
|
|
|