├── .gitignore ├── AliasReplace ├── plugin.png ├── plugin.py └── plugin.xml ├── ChapterInspection ├── plugin.png ├── plugin.py └── plugin.xml ├── LICENSE ├── README.md └── s2t-t2s ├── opencc.zip ├── plugin.png ├── plugin.py └── plugin.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.csv 2 | Backup/ 3 | Others/ -------------------------------------------------------------------------------- /AliasReplace/plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spaceskynet/Sigil-Plugins/ac09a1c0de8371d52dbb04d8c5b3c75245eb1e82/AliasReplace/plugin.png -------------------------------------------------------------------------------- /AliasReplace/plugin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | #-*- coding: utf-8 -*- 3 | # By: SpaceSkyNet 4 | 5 | import csv 6 | from PyQt5.QtGui import QIcon, QFontMetrics 7 | from PyQt5.QtWidgets import (QDialog, QPushButton, QFileDialog, 8 | QLabel, QApplication, QVBoxLayout, QHBoxLayout) 9 | from PyQt5.QtCore import Qt 10 | import sys, os 11 | 12 | class askSetting(QDialog): 13 | 14 | def __init__(self, 15 | app=None, 16 | parent=None, 17 | bk=None, 18 | items=None): 19 | 20 | super(askSetting, self).__init__(parent) 21 | 22 | self.app = app 23 | self.items = items 24 | 25 | self.setWindowIcon(QIcon(os.path.join(bk._w.plugin_dir, 'AliasReplace', 'plugin.png'))) 26 | 27 | H_layout = QHBoxLayout() 28 | V_layout = QVBoxLayout() 29 | 30 | choice_filepath = '' 31 | self.filepath_label = QLabel(choice_filepath) 32 | #self.filepath_label.setMaximumSize(250, 15) 33 | H_layout.addWidget(self.filepath_label) 34 | self.file_btn = QPushButton('选取文件', self) 35 | self.file_btn.clicked.connect(lambda: (self.open_file(bk))) 36 | self.file_btn.setFocusPolicy(Qt.StrongFocus) 37 | H_layout.addStretch(1) 38 | H_layout.addWidget(self.file_btn) 39 | V_layout.addLayout(H_layout) 40 | self.btn = QPushButton('确定', self) 41 | self.btn.clicked.connect(lambda: (self.bye(items))) 42 | self.btn.setFocusPolicy(Qt.StrongFocus) 43 | 44 | V_layout.addWidget(self.btn) 45 | 46 | self.setLayout(V_layout) 47 | self.setWindowTitle(' 别名替换 ') 48 | self.setFixedSize(400, 100) 49 | def open_file(self, bk): 50 | filePath, fileType = QFileDialog.getOpenFileName(self, "选取文件", os.path.join(bk._w.plugin_dir, 'AliasReplace'), 51 | "Csv file(*.csv)") 52 | #print(filePath) 53 | fontWidth = QFontMetrics(self.filepath_label.font()) 54 | elideNote = fontWidth.elidedText(filePath, Qt.ElideMiddle, 250) 55 | 56 | self.filepath_label.setText(elideNote) 57 | self.filepath_label.setToolTip(filePath) 58 | 59 | self.items['choice_filepath'] = filePath 60 | print('Chosen:', filePath) 61 | 62 | 63 | def bye(self, items): 64 | self.close() 65 | self.app.exit(1) 66 | 67 | def convName(bk): 68 | items = {'choice_filepath': ''} 69 | 70 | app = QApplication(sys.argv) 71 | ask = askSetting(app=app, items=items, bk=bk) 72 | ask.show() 73 | rtnCode = app.exec_() 74 | if rtnCode != 1: 75 | print('User abort by closing Setting dialog') 76 | return -1 77 | if not items['choice_filepath']: 78 | filepath = os.path.join(bk._w.plugin_dir, 'NameMap', 'NameMap.csv') 79 | if os.path.exists(filepath): 80 | items['choice_filepath'] = filepath 81 | print('Auto choice the default file!') 82 | else: 83 | print('No file is selected!') 84 | return -1 85 | 86 | csv_filepath = items['choice_filepath'] 87 | replace_list = [] 88 | print("Selected:", csv_filepath) 89 | with open(csv_filepath, encoding = "utf-8") as f: 90 | f_csv = csv.reader(f) 91 | for row in f_csv: 92 | target_name = row[1] 93 | row = row[2:] 94 | for origin_name in row: 95 | if origin_name: replace_list.append((origin_name, target_name)) 96 | 97 | #print(replace_list) 98 | 99 | # convert html/xhtml files 100 | for (file_id, _) in bk.text_iter(): 101 | file_href = bk.id_to_href(file_id) 102 | file_basename = bk.href_to_basename(file_href) 103 | file_mime = bk.id_to_mime(file_id) 104 | html_original = bk.readfile(file_id) 105 | for replace_name in replace_list: 106 | html_original = html_original.replace(*replace_name) 107 | bk.writefile(file_id, html_original) 108 | print('Changed:', file_basename, file_mime) 109 | 110 | # convert ncx file 111 | NCX_id = bk.gettocid() 112 | if not NCX_id: 113 | print('ncx file is not exists!') 114 | return -1 115 | 116 | NCX_mime = bk.id_to_mime(NCX_id) 117 | NCX_href = bk.id_to_href(NCX_id) 118 | NCX_original = bk.readfile(NCX_id) 119 | for replace_name in replace_list: 120 | NCX_original = NCX_original.replace(*replace_name) 121 | bk.writefile(NCX_id, NCX_original) 122 | print('Changed:', NCX_href, NCX_mime) 123 | 124 | # convert opf file 125 | OPF_basename = 'content.opf' 126 | OPF_mime = 'application/oebps-package+xml' 127 | metadata = bk.getmetadataxml() 128 | for replace_name in replace_list: 129 | metadata = metadata.replace(*replace_name) 130 | bk.setmetadataxml(metadata) 131 | 132 | print('Changed:', OPF_basename, OPF_mime) 133 | 134 | print("Success!") 135 | return 0 136 | 137 | def run(bk): 138 | return convName(bk) -------------------------------------------------------------------------------- /AliasReplace/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | AliasReplace 4 | edit 5 | SpaceSkyNet 6 | 别名替换 7 | python3.4 8 | 0.1 9 | osx,unx,win 10 | true 11 | -------------------------------------------------------------------------------- /ChapterInspection/plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spaceskynet/Sigil-Plugins/ac09a1c0de8371d52dbb04d8c5b3c75245eb1e82/ChapterInspection/plugin.png -------------------------------------------------------------------------------- /ChapterInspection/plugin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | #-*- coding: utf-8 -*- 3 | # By: SpaceSkyNet 4 | 5 | import re 6 | from lxml import etree 7 | from PyQt5.QtGui import QIcon 8 | from PyQt5.QtWidgets import (QDialog, QPushButton, QTableWidgetItem, QHeaderView, QMessageBox, QAbstractItemView, 9 | QProgressBar, QApplication, QHBoxLayout, QVBoxLayout, QTableWidget) 10 | from PyQt5.QtCore import Qt 11 | import sys, os 12 | 13 | styleSheet = ''' 14 | #BlueProgressBar { 15 | margin: 2px; 16 | text-align: center; 17 | border: 2px solid #A9A9A9; 18 | background-color: #FFFFFF; 19 | } 20 | #BlueProgressBar::chunk { 21 | background-color: #2196F3; 22 | } 23 | ''' 24 | 25 | class askSetting(QDialog): 26 | 27 | def __init__(self, 28 | app=None, 29 | parent=None, 30 | bk=None, 31 | items=None): 32 | 33 | super(askSetting, self).__init__(parent) 34 | 35 | self.app = app 36 | self.items = items 37 | 38 | self.setWindowIcon(QIcon(os.path.join(bk._w.plugin_dir, 'ChapterInspection', 'plugin.png'))) 39 | 40 | V_layout = QVBoxLayout() 41 | H_layout = QHBoxLayout() 42 | self.chapter_table = QTableWidget(self) 43 | self.chapter_table = self.setChapterTable(self.chapter_table, bk) 44 | 45 | V_layout.addWidget(self.chapter_table) 46 | H_layout.addStretch(0) 47 | self.recheck_btn = QPushButton('重新检查', self) 48 | self.recheck_btn.clicked.connect(lambda: (self.recheckChapter(bk))) 49 | self.recheck_btn.setFocusPolicy(Qt.StrongFocus) 50 | H_layout.addWidget(self.recheck_btn) 51 | 52 | H_layout.addStretch(1) 53 | self.exit_btn = QPushButton('关闭', self) 54 | self.exit_btn.clicked.connect(lambda: (self.bye(items))) 55 | self.exit_btn.setFocusPolicy(Qt.StrongFocus) 56 | 57 | H_layout.addWidget(self.exit_btn) 58 | V_layout.addLayout(H_layout) 59 | self.setLayout(V_layout) 60 | self.setWindowTitle(' 分章检查 ') 61 | self.setFixedSize(900, 500) 62 | 63 | def setChapterTable(self, chapter_table, bk): 64 | chapter_check = checkChapter(bk) 65 | chapters_len = len(chapter_check) 66 | chapter_table.setRowCount(chapters_len) 67 | chapter_table.setColumnCount(3) 68 | chapter_table.setColumnWidth(0, 300) 69 | chapter_table.setColumnWidth(1, 450) 70 | chapter_table.setColumnWidth(2, 50) 71 | chapter_table.horizontalHeader().setStretchLastSection(True) 72 | chapter_table.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed) 73 | chapter_table.verticalHeader().setDefaultSectionSize(25) 74 | chapter_table.setHorizontalHeaderLabels(['章节标题', '章节长度', '结果']) 75 | max_chapter_len = max([chapter_len for _, chapter_len, _ in chapter_check]) 76 | for row in range(chapters_len): 77 | chapter_name, chapter_len, chapter_result = chapter_check[row] 78 | chapter_result = '异常' if chapter_result else '' 79 | chapter_table.setItem(row, 0, QTableWidgetItem(chapter_name)) 80 | pbar = QProgressBar(self, textVisible=True, objectName="BlueProgressBar") 81 | pbar.setMinimum(0) 82 | pbar.setMaximum(max_chapter_len) 83 | pbar.setValue(chapter_len) 84 | pbar.setFormat("%v") 85 | chapter_table.setCellWidget(row, 1, pbar) 86 | chapter_table.setItem(row, 2, QTableWidgetItem(chapter_result)) 87 | chapter_table.setEditTriggers(QAbstractItemView.NoEditTriggers) 88 | return chapter_table 89 | 90 | def recheckChapter(self, bk): 91 | self.chapter_table = self.setChapterTable(self.chapter_table, bk) 92 | QMessageBox.information(self, '提示信息', '重新检查完毕!', QMessageBox.Ok) 93 | 94 | 95 | def bye(self, items): 96 | self.close() 97 | self.app.exit(1) 98 | 99 | def getChapterInfo(bk): 100 | NCX_id = bk.gettocid() 101 | if not NCX_id: 102 | print('ncx file is not exists!') 103 | os._exit(-1) 104 | 105 | NCX_original = bk.readfile(NCX_id) 106 | NCX_original_xml = etree.XML(NCX_original.encode(encoding = "utf-8")) 107 | chapter_info = [] 108 | for i in NCX_original_xml.xpath("//*"): 109 | chapter_name, chapter_href = '', '' 110 | if "navPoint" in i.tag: 111 | for j in i.xpath('*'): 112 | if 'content' in j.tag: 113 | for key, value in j.items(): 114 | if key == 'src': 115 | chapter_href = value 116 | elif 'navLabel' in j.tag: 117 | chapter_name = j.xpath('*')[0].text 118 | chapter_info.append((chapter_name, chapter_href)) 119 | #print(chapter_info) 120 | return chapter_info 121 | 122 | def stripHtmlTags(content): 123 | re_h = re.compile(']*>') 124 | content = re_h.sub('', content) 125 | return content 126 | 127 | def intervalRecursion(L, R, max_frequency, interval, sum, all_sum, max_index): 128 | if max_frequency >= 1.0 or R - L == max_index: return (0, max_index) 129 | if sum / all_sum >= max_frequency: return (L, R) 130 | if L > 0 and R < max_index: 131 | i_L, i_R = interval[L - 1], interval[R + 1] 132 | if i_L > i_R: 133 | if (sum + i_R) / all_sum >= max_frequency: return (L, R + 1) 134 | elif (sum + i_L) / all_sum >= max_frequency: return (L - 1, R) 135 | else: 136 | if (sum + i_L) / all_sum >= max_frequency: return (L - 1, R) 137 | elif (sum + i_R) / all_sum >= max_frequency: return (L, R + 1) 138 | if (sum + i_L + i_R) / all_sum >= max_frequency: return (L - 1, R + 1) 139 | return intervalRecursion(L - 1, R + 1, max_frequency, interval, sum + i_L + i_R, all_sum, max_index) 140 | elif L == 0: 141 | index_R = min(R + 1, max_index) 142 | i_R = interval[index_R] 143 | if (sum + i_R) / all_sum >= max_frequency: return (L, R + 1) 144 | return intervalRecursion(L, R + 1, max_frequency, interval, sum + i_R, all_sum, max_index) 145 | else: 146 | index_L = max(L - 1, 0) 147 | i_L = interval[index_L] 148 | if (sum + i_L) / all_sum >= max_frequency: return (L - 1, R) 149 | return intervalRecursion(L - 1, R, max_frequency, interval, sum + i_L, all_sum, max_index) 150 | 151 | 152 | def maxFrequencyInterval(interval, key, max_frequency = 0.8, parts = 10): 153 | Min, Max = key(interval[0]), key(interval[-1]) 154 | Max = Max + 10 - (Max - Min) % 10 155 | part_interval_lens = [] 156 | i, cnt = 0, 0 157 | for num in interval: 158 | num = key(num) 159 | p_R = Min + i * (Max - Min) // parts 160 | if num <= p_R: 161 | cnt += 1 162 | else: 163 | i += 1 164 | part_interval_lens.append(cnt) 165 | cnt = 1 166 | part_interval_lens.append(cnt) 167 | #print(part_interval_lens, len(part_interval_lens)) 168 | max_len, max_pos = max(part_interval_lens), 0 169 | for i in range(len(part_interval_lens)): 170 | if part_interval_lens[i] == max_len: 171 | max_pos = i 172 | break 173 | #print(i, i, max_frequency, part_interval_lens, max_len, len(interval), len(part_interval_lens) - 1) 174 | L, R = intervalRecursion(i, i, max_frequency, part_interval_lens, max_len, len(interval), len(part_interval_lens) - 1) 175 | return (Min + (L - 1) * (Max - Min) // parts, Min + R * (Max - Min) // parts) 176 | 177 | 178 | def checkChapter(bk): 179 | chapter_info = getChapterInfo(bk) 180 | chapter_check = [] 181 | for i, (chapter_name, chapter_href) in enumerate(chapter_info): 182 | pos = chapter_href.find('#') 183 | if pos != -1: chapter_href = chapter_href[:pos] 184 | chapter_id = bk.href_to_id(chapter_href) 185 | #print(chapter_href, chapter_id) 186 | chapter_content = bk.readfile(chapter_id) 187 | chapter_len = len(stripHtmlTags(chapter_content)) 188 | chapter_check.append([i, chapter_len, False]) 189 | key=lambda x: x[1] 190 | chapter_check.sort(key = key) 191 | L, R = maxFrequencyInterval(chapter_check, key) 192 | chapter_check.sort(key = lambda x: x[0]) 193 | for i in range(len(chapter_check)): 194 | chapter_check[i][0] = chapter_info[i][0] 195 | if key(chapter_check[i]) < L or key(chapter_check[i]) > R: 196 | chapter_check[i][2] = True 197 | #print(L, R, chapter_check) 198 | print('All is Checked!') 199 | #os.system('pause') 200 | return chapter_check 201 | 202 | def checkChapterRunner(bk): 203 | #chapter_check = checkChapter(bk) 204 | items = {'max_frequency': 0.8, 'parts': 10} 205 | app = QApplication(sys.argv) 206 | app.setStyleSheet(styleSheet) 207 | ask = askSetting(app=app, items=items, bk=bk) 208 | ask.show() 209 | rtnCode = app.exec_() 210 | 211 | print("Success!") 212 | return 0 213 | 214 | def run(bk): 215 | return checkChapterRunner(bk) -------------------------------------------------------------------------------- /ChapterInspection/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | ChapterInspection 4 | validation 5 | SpaceSkyNet 6 | 分章检查 7 | python3.4 8 | 0.1 9 | osx,unx,win 10 | true 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 spaceskynet 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sigil Plugins By SpaceSkyNet 2 | 3 | There are some sigil plugins written by me. 4 | 5 | 一些 Sigil 插件。 6 | 7 | ## s2t - t2s (简繁中文转换) 8 | 9 | 使用 OpenCC 库进行转换,使用前请先在Python环境上安装OpenCC,或者将`s2t-t2s`文件夹下的`opencc.zip`解压放入Sigil程序目录的`Lib\site-packages`下。 10 | 11 | ![s2t - t2s](https://i.loli.net/2020/07/24/AMsH1bY2S5VctD6.png) 12 | 13 | ## AliasReplace (别名替换) 14 | 15 | 解决译制小说中存在的译名不统一的问题,需要提供一张`csv`对照表。 16 | 17 | 格式如下(可提供多行): 18 | 19 | `id, target_name, origin_name_1, origin_name_2 ...` 20 | 21 | **Ex:** `1, Bob, Pop, Pob, Bop` 22 | 23 | 默认读取插件目录下的`NameMap.csv`。 24 | 25 | ![AliasReplace](https://i.loli.net/2020/07/24/e3ikV8blvNsZGEA.png) 26 | 27 | ## ChapterInspection (分章检查) 28 | 29 | 检查各章节的字数是否符合集中趋势,不符合输出`异常`。 30 | 31 | ![ChapterInspection](https://i.loli.net/2020/07/24/gQlXOP1zVauoqxG.png) 32 | -------------------------------------------------------------------------------- /s2t-t2s/opencc.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spaceskynet/Sigil-Plugins/ac09a1c0de8371d52dbb04d8c5b3c75245eb1e82/s2t-t2s/opencc.zip -------------------------------------------------------------------------------- /s2t-t2s/plugin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spaceskynet/Sigil-Plugins/ac09a1c0de8371d52dbb04d8c5b3c75245eb1e82/s2t-t2s/plugin.png -------------------------------------------------------------------------------- /s2t-t2s/plugin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | #-*- coding: utf-8 -*- 3 | # By: SpaceSkyNet 4 | 5 | from lxml import etree 6 | from PyQt5.QtGui import QIcon 7 | from PyQt5.QtWidgets import (QDialog, QPushButton, QComboBox, 8 | QLabel, QApplication, QVBoxLayout) 9 | from PyQt5.QtCore import Qt 10 | import sys, os 11 | 12 | lang_lists = ['简体到繁体(OpenCC标准)', '繁体(OpenCC标准)到简体', '简体到繁体(中国台湾)', '繁体(中国台湾)到简体', '简体到繁体(中国香港)', '繁体(中国香港)到简体', '简体到繁体(中国台湾,包括常用词汇)', '繁体(中国台湾)到简体(包括常用词汇)', '繁体(OpenCC标准)到繁体(中国台湾)', '繁体(中国香港)到繁体(OpenCC 标准)', '繁体(OpenCC标准)到繁体(中国香港)', '繁体(OpenCC标准,旧字体)到日文新字体', '日文新字体到繁体(OpenCC 标准,旧字体)', '繁体(中国台湾)到繁体(OpenCC 标准)', ] 13 | select_lang_json = ['s2t.json', 't2s.json', 's2tw.json', 'tw2s.json', 's2hk.json', 'hk2s.json', 's2twp.json', 'tw2sp.json', 't2tw.json', 'hk2t.json', 't2hk.json', 't2jp.json', 'jp2t.json', 'tw2t.json', ] 14 | target_langcode_lists = ['zh-CHT', 'zh-CN', 'zh-TW', 'zh-CN', 'zh-HK', 'zh-CN', 'zh-TW', 'zh-CN', 'zh-TW', 'zh-CHT', 'zh-HK', 'ja-JP', 'zh-CHT', 'zh-CHT'] 15 | 16 | class askSetting(QDialog): 17 | 18 | def __init__(self, 19 | app=None, 20 | parent=None, 21 | bk=None, 22 | items=None): 23 | 24 | super(askSetting, self).__init__(parent) 25 | 26 | self.app = app 27 | self.items = items 28 | 29 | self.setWindowIcon(QIcon(os.path.join(bk._w.plugin_dir, 's2t-t2s', 'plugin.png'))) 30 | global lang_lists 31 | self.choice_list = lang_lists 32 | 33 | layout = QVBoxLayout() 34 | 35 | choice_info = '选择转换方式:' 36 | layout.addWidget(QLabel(choice_info)) 37 | self.lang_combobox = QComboBox(self) 38 | self.lang_combobox.addItems(self.choice_list) 39 | self.lang_combobox.setCurrentIndex(items['current_index']) 40 | layout.addWidget(self.lang_combobox) 41 | self.lang_combobox.currentIndexChanged.connect(lambda: self.on_combobox_func()) 42 | #print('UI', items) 43 | self.btn = QPushButton('确定', self) 44 | self.btn.clicked.connect(lambda: (self.bye(items))) 45 | self.btn.setFocusPolicy(Qt.StrongFocus) 46 | 47 | layout.addWidget(self.btn) 48 | 49 | self.setLayout(layout) 50 | self.setWindowTitle(' 简繁转换设置 ') 51 | def on_combobox_func(self): 52 | self.items['current_index'] = self.lang_combobox.currentIndex() 53 | 54 | def bye(self, items): 55 | self.close() 56 | self.app.exit(1) 57 | 58 | def convLang(bk): 59 | items = {'current_index': 0} 60 | 61 | app = QApplication(sys.argv) 62 | ask = askSetting(app=app, items=items, bk=bk) 63 | ask.show() 64 | rtnCode = app.exec_() 65 | if rtnCode != 1: 66 | print('User abort by closing Setting dialog') 67 | return -1 68 | try: 69 | import opencc 70 | except: 71 | print('Please install the OpenCC Lib!') 72 | return -1 73 | 74 | global lang_lists, select_lang_json, target_langcode_lists 75 | 76 | c_index = items['current_index'] 77 | print("Selected:", lang_lists[c_index]) 78 | converter = opencc.OpenCC(select_lang_json[c_index]) 79 | 80 | # convert html/xhtml files 81 | for (file_id, _) in bk.text_iter(): 82 | file_href = bk.id_to_href(file_id) 83 | file_basename = bk.href_to_basename(file_href) 84 | file_mime = bk.id_to_mime(file_id) 85 | html_original = bk.readfile(file_id) 86 | html_original_conv = converter.convert(html_original) 87 | bk.writefile(file_id, html_original_conv) 88 | print('Changed:', file_basename, file_mime) 89 | 90 | # convert ncx file 91 | NCX_id = bk.gettocid() 92 | if not NCX_id: 93 | print('ncx file is not exists!') 94 | return -1 95 | 96 | NCX_mime = bk.id_to_mime(NCX_id) 97 | NCX_href = bk.id_to_href(NCX_id) 98 | NCX_original = bk.readfile(NCX_id) 99 | NCX_original = converter.convert(NCX_original) 100 | bk.writefile(NCX_id, NCX_original) 101 | print('Changed:', NCX_href, NCX_mime) 102 | 103 | # convert opf file 104 | OPF_basename = 'content.opf' 105 | OPF_mime = 'application/oebps-package+xml' 106 | metadata = bk.getmetadataxml() 107 | metadata_xml = etree.XML(metadata) 108 | 109 | for i in metadata_xml.xpath('//child::*'): 110 | if 'language' in i.tag: 111 | i.text = target_langcode_lists[c_index] 112 | 113 | metadata_conv = converter.convert(etree.tostring(metadata_xml, encoding="utf-8", xml_declaration=True).decode('utf8')) 114 | bk.setmetadataxml(metadata_conv) 115 | 116 | guide = bk.getguide() 117 | guide_conv = [] 118 | for i in range(len(guide)): 119 | guide_conv.append([]) 120 | for j in range(len(guide[i])): 121 | guide_conv[i].append(converter.convert(guide[i][j])) 122 | bk.setguide(guide_conv) 123 | print('Changed:', OPF_basename, OPF_mime) 124 | 125 | print("Success!") 126 | return 0 127 | 128 | def run(bk): 129 | return convLang(bk) -------------------------------------------------------------------------------- /s2t-t2s/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | s2t-t2s 4 | edit 5 | SpaceSkyNet 6 | 中文简繁转换 7 | python3.4 8 | 0.1 9 | osx,unx,win 10 | true 11 | --------------------------------------------------------------------------------