Add export support for the MDict dictionary format
This commit is contained in:
parent
e4a2e75d82
commit
4c837cd72d
53 changed files with 2233 additions and 275 deletions
204
bot/mdict/exporters/export.py
Normal file
204
bot/mdict/exporters/export.py
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
# pylint: disable=too-few-public-methods
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import shutil
|
||||
from abc import ABC, abstractmethod
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from platformdirs import user_documents_dir, user_cache_dir
|
||||
|
||||
from bot.targets import Targets
|
||||
from bot.mdict.terms.factory import new_terminator
|
||||
|
||||
|
||||
class Exporter(ABC):
|
||||
def __init__(self, target):
|
||||
self._target = target
|
||||
self._terminator = new_terminator(target)
|
||||
self._build_dir = None
|
||||
self._build_media_dir = None
|
||||
self._description_file = None
|
||||
self._out_dir = None
|
||||
|
||||
def export(self, entries, media_dir, icon_file):
|
||||
self._init_build_media_dir(media_dir)
|
||||
self._init_description_file(entries)
|
||||
terms = self._get_terms(entries)
|
||||
print(f"Exporting {len(terms)} Mdict keys...")
|
||||
self._write_mdx_file(terms)
|
||||
self._write_mdd_file()
|
||||
self._write_icon_file(icon_file)
|
||||
self._rm_build_dir()
|
||||
|
||||
def _get_build_dir(self):
|
||||
if self._build_dir is not None:
|
||||
return self._build_dir
|
||||
cache_dir = user_cache_dir("jitenbot")
|
||||
build_directory = os.path.join(cache_dir, "mdict_build")
|
||||
if Path(build_directory).is_dir():
|
||||
shutil.rmtree(build_directory)
|
||||
os.makedirs(build_directory)
|
||||
self._build_dir = build_directory
|
||||
return self._build_dir
|
||||
|
||||
def _init_build_media_dir(self, media_dir):
|
||||
build_dir = self._get_build_dir()
|
||||
build_media_dir = os.path.join(build_dir, self._target.value)
|
||||
if media_dir is not None:
|
||||
print("Copying media files to build directory...")
|
||||
shutil.copytree(media_dir, build_media_dir)
|
||||
else:
|
||||
os.makedirs(build_media_dir)
|
||||
css_file = self._get_css_file()
|
||||
shutil.copy(css_file, build_media_dir)
|
||||
self._terminator.set_media_dir(build_media_dir)
|
||||
self._build_media_dir = build_media_dir
|
||||
|
||||
def _init_description_file(self, entries):
|
||||
filename = f"{self._target.value}.mdx.description.html"
|
||||
original_file = os.path.join(
|
||||
"data", "mdict", "description", filename)
|
||||
with open(original_file, "r", encoding="utf8") as f:
|
||||
description = f.read()
|
||||
description = description.replace(
|
||||
"{{revision}}", self._get_revision(entries))
|
||||
description = description.replace(
|
||||
"{{attribution}}", self._get_attribution(entries))
|
||||
build_dir = self._get_build_dir()
|
||||
description_file = os.path.join(build_dir, filename)
|
||||
with open(description_file, "w", encoding="utf8") as f:
|
||||
f.write(description)
|
||||
self._description_file = description_file
|
||||
|
||||
def _get_terms(self, entries):
|
||||
terms = []
|
||||
entries_len = len(entries)
|
||||
for idx, entry in enumerate(entries):
|
||||
update = f"Creating Mdict terms for entry {idx+1}/{entries_len}"
|
||||
print(update, end='\r', flush=True)
|
||||
new_terms = self._terminator.make_terms(entry)
|
||||
for term in new_terms:
|
||||
terms.append(term)
|
||||
print()
|
||||
return terms
|
||||
|
||||
def _write_mdx_file(self, terms):
|
||||
out_dir = self._get_out_dir()
|
||||
out_file = os.path.join(out_dir, f"{self._target.value}.mdx")
|
||||
params = [
|
||||
"mdict",
|
||||
"-a", self._get_term_file(terms),
|
||||
"--title", self._get_title_file(),
|
||||
"--description", self._description_file,
|
||||
out_file
|
||||
]
|
||||
subprocess.run(params, check=True)
|
||||
|
||||
def _write_mdd_file(self):
|
||||
out_dir = self._get_out_dir()
|
||||
out_file = os.path.join(out_dir, f"{self._target.value}.mdd")
|
||||
params = [
|
||||
"mdict",
|
||||
"-a", self._build_media_dir,
|
||||
"--title", self._get_title_file(),
|
||||
"--description", self._description_file,
|
||||
out_file
|
||||
]
|
||||
subprocess.run(params, check=True)
|
||||
|
||||
def _write_icon_file(self, icon_file):
|
||||
premade_icon_file = f"data/mdict/icon/{self._target.value}.png"
|
||||
out_dir = self._get_out_dir()
|
||||
out_file = os.path.join(out_dir, f"{self._target.value}.png")
|
||||
if icon_file is not None and Path(icon_file).is_file():
|
||||
shutil.copy(icon_file, out_file)
|
||||
elif Path(premade_icon_file).is_file():
|
||||
shutil.copy(premade_icon_file, out_file)
|
||||
|
||||
def _get_out_dir(self):
|
||||
if self._out_dir is not None:
|
||||
return self._out_dir
|
||||
out_dir = os.path.join(
|
||||
user_documents_dir(), "jitenbot", "mdict", self._target.value)
|
||||
if Path(out_dir).is_dir():
|
||||
shutil.rmtree(out_dir)
|
||||
os.makedirs(out_dir)
|
||||
self._out_dir = out_dir
|
||||
return out_dir
|
||||
|
||||
def _get_term_file(self, terms):
|
||||
build_dir = self._get_build_dir()
|
||||
term_file = os.path.join(build_dir, f"{self._target.value}.mdx.txt")
|
||||
with open(term_file, "w", encoding="utf8") as f:
|
||||
for term in terms:
|
||||
f.write("\n".join(term))
|
||||
f.write("\n</>\n")
|
||||
return term_file
|
||||
|
||||
def _get_title_file(self):
|
||||
return os.path.join(
|
||||
"data", "mdict", "title",
|
||||
f"{self._target.value}.mdx.title.html")
|
||||
|
||||
def _get_css_file(self):
|
||||
return os.path.join(
|
||||
"data", "mdict", "css",
|
||||
f"{self._target.value}.css")
|
||||
|
||||
def _rm_build_dir(self):
|
||||
build_dir = self._get_build_dir()
|
||||
shutil.rmtree(build_dir)
|
||||
|
||||
@abstractmethod
|
||||
def _get_revision(self, entries):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def _get_attribution(self, entries):
|
||||
pass
|
||||
|
||||
|
||||
class _JitenonExporter(Exporter):
|
||||
def _get_revision(self, entries):
|
||||
modified_date = None
|
||||
for entry in entries:
|
||||
if modified_date is None or entry.modified_date > modified_date:
|
||||
modified_date = entry.modified_date
|
||||
revision = modified_date.strftime("%Y年%m月%d日閲覧")
|
||||
return revision
|
||||
|
||||
def _get_attribution(self, entries):
|
||||
modified_date = None
|
||||
for entry in entries:
|
||||
if modified_date is None or entry.modified_date > modified_date:
|
||||
attribution = entry.attribution
|
||||
return attribution
|
||||
|
||||
|
||||
class JitenonKokugoExporter(_JitenonExporter):
|
||||
pass
|
||||
|
||||
|
||||
class JitenonYojiExporter(_JitenonExporter):
|
||||
pass
|
||||
|
||||
|
||||
class JitenonKotowazaExporter(_JitenonExporter):
|
||||
pass
|
||||
|
||||
|
||||
class _MonokakidoExporter(Exporter):
|
||||
def _get_revision(self, entries):
|
||||
timestamp = datetime.now().strftime("%Y年%m月%d日作成")
|
||||
return timestamp
|
||||
|
||||
|
||||
class Smk8Exporter(_MonokakidoExporter):
|
||||
def _get_attribution(self, entries):
|
||||
return "© Sanseido Co., LTD. 2020"
|
||||
|
||||
|
||||
class Daijirin2Exporter(_MonokakidoExporter):
|
||||
def _get_attribution(self, entries):
|
||||
return "© Sanseido Co., LTD. 2019"
|
||||
18
bot/mdict/exporters/factory.py
Normal file
18
bot/mdict/exporters/factory.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
from bot.targets import Targets
|
||||
|
||||
from bot.mdict.exporters.export import JitenonKokugoExporter
|
||||
from bot.mdict.exporters.export import JitenonYojiExporter
|
||||
from bot.mdict.exporters.export import JitenonKotowazaExporter
|
||||
from bot.mdict.exporters.export import Smk8Exporter
|
||||
from bot.mdict.exporters.export import Daijirin2Exporter
|
||||
|
||||
|
||||
def new_mdict_exporter(target):
|
||||
exporter_map = {
|
||||
Targets.JITENON_KOKUGO: JitenonKokugoExporter,
|
||||
Targets.JITENON_YOJI: JitenonYojiExporter,
|
||||
Targets.JITENON_KOTOWAZA: JitenonKotowazaExporter,
|
||||
Targets.SMK8: Smk8Exporter,
|
||||
Targets.DAIJIRIN2: Daijirin2Exporter,
|
||||
}
|
||||
return exporter_map[target](target)
|
||||
Loading…
Reference in a new issue