Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ reader/dist/*
*.ipynb
ArknightsGameData_YoStar/
/ArknightsResource
/htmls
*.epub
13 changes: 11 additions & 2 deletions codespace.sh
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
# using light yellow color
echo -e "\033[1;33m Initializing... \033[0m"
pip install openpyxl > /dev/null 2>&1
echo -e "\033[1;33m Downloading latest data... \033[0m"
git clone https://github.com/Kengxxiao/ArknightsGameData.git
# using light green color
echo -e "\033[1;32m Initialization complete. \033[0m"
echo -e "\033[1;33m Available servers:\033[0m zh_CN, en_US, ko_KR, ja_JP, zh_TW"
echo -e "Enter the server you want to use, press Enter to continue, Blank for zh_CN: "
read server
echo -e "\033[1;33m Downloading latest data... \033[0m"
if [ -z "$server" ]; then
server="zh_CN"
git clone https://github.com/Kengxxiao/ArknightsGameData.git
else
server=$server
# only pull the $server folder from Kengxxiao/ArknightsGameData_YoStar
git clone --depth 1 --filter=blob:none --sparse https://github.com/Kengxxiao/ArknightsGameData_YoStar.git
cd ArknightsGameData_YoStar
git sparse-checkout init --cone
git sparse-checkout set $server
cd ..
mv ArknightsGameData_YoStar/$server ArknightsGameData
fi

echo -e "Current Server: \033[1;33m $server\033[0m"
Expand Down
183 changes: 183 additions & 0 deletions epub_convert.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
from ebooklib import epub
from pathlib import Path
from jsonconvert import reader
from typing import Iterable

import json
import re

import func

import argparse

EPUB_CHAPTER_TEMPLATE = """<html>
<head>
<meta charset="UTF-8" />
<title>{story.storyCode} {story.storyName} {story.avgTag}</title>
</head>
<body>
{lines}
</body>
</html>"""

DOCTOR = "Doctor"

EPUB_NAME_TEMPLATE = '<p id="{index}"><strong>{name}</strong>&emsp;{content}</p>'

EPUB_BRANCH_TEMPLATE = '<li><a href="#{index}">{option}</a></li>'


def parseContent(content: str, doctor=DOCTOR) -> str:
color_re = re.compile(r"<color=([\w#]+)>(.+?)<\/color>", re.MULTILINE)
nbsp_sub_before = re.compile(r"(\s+)(<\/?\w+>)", re.MULTILINE)
nbsp_sub_after = re.compile(r"(<\/?\w+>)(\s+)", re.MULTILINE)
content = content.replace("{@nickname}", doctor)
content = re.sub(r"(?:\r\n|\r|\n|\\n|\\r)", "<br>", content)
content = color_re.sub(r'<span style="color:\1">\2</span>', content)
content = nbsp_sub_before.sub(r"&nbsp;\2", content)
content = nbsp_sub_after.sub(r"\1&nbsp;", content)
return content


def parseHTML(story_json):
lines = []
rawlist = story_json["storyList"]
for lidx, line in enumerate(rawlist):
index = line["id"]
prop: str = line["prop"].lower()
attrs = line["attributes"]

if prop == "name":
lines.append(
EPUB_NAME_TEMPLATE.format(
index=f'line{index}',
name=attrs.get('name',''), content=parseContent(attrs.get("content", ""))
)
)

if prop == 'multiline':
lines.append(
EPUB_NAME_TEMPLATE.format(
index=f'line{index}',
name=attrs.get('name',''), content=parseContent(attrs.get("content", ""))
)
)

if prop == 'decision':
options = attrs['options'].split(';')
values = attrs['values'].split(';')
targetLines = line['targetLine']
options_html = []
for i in range(min(len(values),len(options))):
options_html.append(EPUB_BRANCH_TEMPLATE.format(index=targetLines.get(f'option{values[i]}',f'{index+1}'), option=options[i]))
lines.append(
'<p id="line{index}">\n<ol>\n{options}\n</ol>\n</p>'.format(index=index, options='\n'.join(options_html))
)

if prop == 'predicate':
if line.get('endOfOpt'):
lines.append('<p id="line{index}">---End of Options---</p>'.format(index=index))
else:
lines.append('<p id="line{index}">---{option}---</p>'.format(index=index,option=attrs['references'].replace(';', '&')))

if prop == 'subtitle':
lines.append('<br/><p id="line{index}">{content}</p><br/>'.format(index=index, content=parseContent(attrs.get('text', ''))))

if prop == 'sticker':
lines.append('<br/><p id="line{index}"><strong>{content}</strong></p>'.format(index=index, content=parseContent(attrs.get('text', ''))))

if prop == 'stickerclear':
lines.append('<br/>')

if prop == 'image':
lines.append('<p id="line{index}">{content}</p>'.format(index=index, content=attrs.get('image', '')))


return lines

parser = argparse.ArgumentParser()
parser.add_argument("event_id", help="Event ID")
parser.add_argument("-l", "--lang", help="Language", default="zh_CN")
args = parser.parse_args()



DATA_PATH = Path(r"ArknightsStoryJson")

lang = args.lang
epub_lang = lang.replace("_", "-")
event_id = args.event_id
event: Iterable[func.Story] = func.Event(DATA_PATH, lang, event_id)

file_name = f"{event.eventid}_{event.name}.epub"

book = epub.EpubBook()
book.set_identifier(f"{event.eventid} {lang}")
book.set_title(event.name)
book.set_language(epub_lang)
book.add_author("HyperGryph")

chapters = []
for idx, story in enumerate(event):
print(f"Processing {story.storyCode} {story.storyName} {story.avgTag}")
chapter = epub.EpubHtml(
title=f"{story.storyCode} {story.storyName} {story.avgTag}",
file_name=f"{story.storyCode}_{story.storyName}_{story.avgTag}.xhtml",
lang=epub_lang,
)
with open(story.storyTxt.with_suffix(".json"), encoding="utf-8") as f:
story_json = json.load(f)

lines = parseHTML(story_json)
if len(lines) == 0:
lines = ["<p>Empty Chapter.</p>"]
chapter.content = EPUB_CHAPTER_TEMPLATE.format(story=story, lines="\n".join(lines))
with open(f'htmls/{chapter.file_name}', 'w', encoding='utf-8') as f:
f.write(chapter.content)
book.add_item(chapter)
chapters.append(chapter)

book.toc = chapters
book.add_item(epub.EpubNcx())
book.add_item(epub.EpubNav())

style = '''
@namespace epub "http://www.idpf.org/2007/ops";

body {
font-family: Cambria, Liberation Serif, Bitstream Vera Serif, Georgia, Times, Times New Roman, serif;
}

h2 {
text-align: left;
text-transform: uppercase;
font-weight: 200;
}

ol {
list-style-type: none;
}

ol > li:first-child {
margin-top: 0.3em;
}


nav[epub|type~='toc'] > ol > li > ol {
list-style-type:square;
}


nav[epub|type~='toc'] > ol > li > ol > li {
margin-top: 0.3em;
}

'''

# add css file
nav_css = epub.EpubItem(uid="style_nav", file_name="style/nav.css", media_type="text/css", content=style)
book.add_item(nav_css)

book.spine = ["nav"] + chapters

epub.write_epub(file_name, book, {})
4 changes: 2 additions & 2 deletions func.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def __init__(self, data_dir:Path, lang:str, eventid:str):
self.storyList = self.review['infoUnlockDatas']


def __getitem__(self, idx):
def __getitem__(self, idx)->'Story':
return Story(self, self.storyList[idx])

def __len__(self):
Expand All @@ -45,7 +45,7 @@ def __init__(self, event:Event, storyData:dict):
self.storyData = storyData
self.storyCode = storyData['storyCode']
self.avgTag = storyData['avgTag'] if storyData['avgTag'] else ''
self.storyName = storyData['storyName']
self.storyName = storyData['storyName'].strip()
self.storyInfo = self.root_dir/'gamedata/story/[uc]{}.txt'.format(storyData['storyInfo']) if storyData['storyInfo'] else None
self.storyTxt = self.root_dir/'gamedata/story/{}.txt'.format(storyData['storyTxt'])
self.f = storyData['storyTxt']
Expand Down