diff --git a/fb2mobi-gui.py b/fb2mobi-gui.py index 7702842..fbf2d9f 100644 --- a/fb2mobi-gui.py +++ b/fb2mobi-gui.py @@ -10,9 +10,9 @@ import shutil from PyQt5.QtWidgets import (QApplication, QMainWindow, QFileDialog, QTreeWidgetItem, QMessageBox, QDialog, QWidget, - QLabel, QAbstractItemView) + QLabel, QAbstractItemView, QSizePolicy) from PyQt5.QtGui import QIcon, QPixmap -from PyQt5.QtCore import QThread, pyqtSignal, QEvent, Qt, QTranslator, QLocale, QT_TR_NOOP as tr +from PyQt5.QtCore import QObject, QThread, pyqtSignal, QEvent, Qt, QTranslator, QLocale, QCoreApplication, QTimer from ui.MainWindow import Ui_MainWindow from ui.AboutDialog import Ui_AboutDialog @@ -21,6 +21,7 @@ from ui.gui_config import GuiConfig import ui.images_rc import ui.ui_version +from ui.fb2meta import Fb2Meta from modules.config import ConverterConfig import fb2mobi @@ -28,8 +29,13 @@ import version +TREE_LIST_CSS_ACTIVE = "selection-color: white; selection-background-color: #386CDA; alternate-background-color: #F3F6FA;" +TREE_LIST_CSS_UNACTIVE = "selection-color: black; selection-background-color: #D4D4D4; alternate-background-color: #F3F6FA;" + SUPPORT_URL = u'http://www.the-ebook.org/forum/viewtopic.php?t=30380' +_translate = QCoreApplication.translate + class CopyThread(QThread): copyBegin = pyqtSignal(object) @@ -96,9 +102,15 @@ def run(self): dest_file = None if not self.cancel: self.convertBegin.emit(file) + dest_file = self.getDestFileName(file) + # Перед конвертацией удалим старый файл + if os.path.exists(dest_file): + os.remove(dest_file) fb2mobi.process_file(self.config, file, None) - if not os.path.exists(self.getDestFileName(file)): + + if not os.path.exists(dest_file): + dest_file = None result = False else: dest_file = self.getDestFileName(file) @@ -109,6 +121,7 @@ def run(self): self.convertAllDone.emit() + def getDestFileName(self, file): if self.config.output_dir is None: output_dir = os.path.abspath(os.path.split(file)[0]) @@ -143,8 +156,6 @@ def __init__(self, parent, config): self.lineDestPath.setText(self.config.outputFolder) self.checkConvertToSrc.setChecked(self.config.convertToSourceDirectory) - # self.buttonBox.button(self.buttonBox.Cancel).setText('Отмена') - if self.config.hyphens.lower() == 'yes': self.radioHypYes.setChecked(True) self.radioHypNo.setChecked(False) @@ -175,7 +186,7 @@ def selectPath(self, path): if not path: path = os.path.expanduser('~') - dlgPath = QFileDialog(self, tr('Select folder'), path) + dlgPath = QFileDialog(self, _translate('fb2mobi-gui', 'Select folder'), path) dlgPath.setFileMode(QFileDialog.Directory) dlgPath.setOption(QFileDialog.ShowDirsOnly, True) @@ -246,6 +257,7 @@ def __init__(self): self.convert_worker = None self.copy_worker = None + self.is_convert_cancel = False self.rootFileList = self.treeFileList.invisibleRootItem() self.iconWhite = QIcon(':/Images/bullet_white.png') @@ -253,6 +265,9 @@ def __init__(self): self.iconGreen = QIcon(':/Images/bullet_green.png') self.iconGo = QIcon(':/Images/bullet_go.png') + self.pixmapConnected = QPixmap(':/Images/bullet_green.png') + self.pixmapNotConnected = QPixmap(':/Images/bullet_red.png') + config_file_name = "fb2mobi.config" log_file_name = "fb2mobi.log" gui_config_file = 'fb2mobi-gui.config' @@ -325,10 +340,66 @@ def __init__(self): self.setWindowIcon(QIcon(':/Images/icon32.png')) self.treeFileList.installEventFilter(self) + self.labelKindleStatus = QLabel() + self.labelKindleStatusIcon = QLabel() + self.labelStatus = QLabel() + + # Для Mac OS небольшой хак UI + if sys.platform == 'darwin': + font = self.labelKindleStatus.font() + font.setPointSize(11) + self.labelKindleStatus.setFont(font) + self.labelStatus.setFont(font) + self.treeFileList.setFont(font) + self.treeFileList.setAttribute(Qt.WA_MacShowFocusRect, 0) + self.treeFileList.setStyleSheet(TREE_LIST_CSS_ACTIVE) + self.labelStatus.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) + + + self.statusBar().addWidget(self.labelStatus, 1) + self.statusBar().addWidget(self.labelKindleStatusIcon) + self.statusBar().addWidget(self.labelKindleStatus) + + if self.gui_config.columns['0']: + self.treeFileList.setColumnWidth(0, self.gui_config.columns['0']) + self.treeFileList.setColumnWidth(1, self.gui_config.columns['1']) + self.treeFileList.setColumnWidth(2, self.gui_config.columns['2']) + + + self.timerKindleStatus = QTimer() + self.timerKindleStatus.timeout.connect(self.checkKindleStatus) + self.timerKindleStatus.start(1500) + + + def event(self, event): + if event.type() == QEvent.WindowActivate: + if sys.platform == 'darwin': + self.treeFileList.setStyleSheet(TREE_LIST_CSS_ACTIVE) + elif event.type() == QEvent.WindowDeactivate: + if sys.platform == 'darwin': + self.treeFileList.setStyleSheet(TREE_LIST_CSS_UNACTIVE) + + return super(MainAppWindow, self).event(event) + + + def checkKindleStatus(self): + if self.gui_config.kindleCopyToDevice: + if os.path.isdir(self.gui_config.kindlePath): + self.labelKindleStatusIcon.setPixmap(self.pixmapConnected) + self.labelKindleStatus.setText(_translate('fb2mobi-gui', 'Device connected')) + else: + self.labelKindleStatusIcon.setPixmap(self.pixmapNotConnected) + self.labelKindleStatus.setText(_translate('fb2mobi-gui', 'Device not connected')) + + else: + self.labelKindleStatus.setText('') + self.labelKindleStatusIcon.clear() + def eventFilter(self, source, event): if event.type() == QEvent.KeyPress: - if (event.key() == Qt.Key_Delete or (event.key() == Qt.Key_Backspace and event.modifiers() == Qt.ControlModifier)): + if (event.key() == Qt.Key_Delete or (event.key() == Qt.Key_Backspace + and event.modifiers() == Qt.ControlModifier)): self.deleteRecAction() return True @@ -366,8 +437,8 @@ def checkDestDir(self): if not os.path.exists(filename): msg = QMessageBox() msg.setIcon(QMessageBox.Critical) - msg.setText(tr('Folder does not exist.')) - msg.setWindowTitle(tr('Error')) + msg.setText(_translate('fb2mobi-gui', 'Folder does not exist.')) + msg.setWindowTitle(_translate('fb2mobi-gui', 'Error')) msg.exec_() return False @@ -375,20 +446,29 @@ def checkDestDir(self): return True + def showMessage(self, message): + self.labelStatus.setText(message) + + + def clearMessage(self): + self.labelStatus.setText('') + + def startConvert(self): if self.rootFileList.childCount() > 0: if not self.checkDestDir(): return if not self.convertRun: - self.btnStart.setText(tr('Cancel')) - self.actionConvert.setText(tr('Cancel conversion')) + self.btnStart.setText(_translate('fb2mobi-gui', 'Cancel')) + self.actionConvert.setText(_translate('fb2mobi-gui', 'Cancel conversion')) self.convertRun = True + self.is_convert_cancel = False self.allControlsEnabled(False) files = [] for i in range(self.rootFileList.childCount()): - files.append(self.rootFileList.child(i).text(0)) + files.append(self.rootFileList.child(i).text(2)) self.progressBar.setRange(0, len(files)) self.progressBar.setValue(0) @@ -403,6 +483,7 @@ def startConvert(self): self.convert_worker.start() else: + self.is_convert_cancel = True self.convert_worker.stop() self.btnStart.setEnabled(False) self.actionConvert.setEnabled(False) @@ -410,15 +491,15 @@ def startConvert(self): def convertAllDone(self): self.convertRun = False - self.btnStart.setText(tr('Start')) - self.actionConvert.setText(tr('Start conversion')) + self.btnStart.setText(_translate('fb2mobi-gui', 'Start')) + self.actionConvert.setText(_translate('fb2mobi-gui', 'Start conversion')) self.allControlsEnabled(True) - self.statusBar().clearMessage() + self.clearMessage() time.sleep(0.5) self.progressBar.setVisible(False) - if self.gui_config.kindleCopyToDevice: + if self.gui_config.kindleCopyToDevice and not self.is_convert_cancel: if self.gui_config.kindlePath and os.path.exists(self.gui_config.kindlePath): self.copy_worker = CopyThread(self.convertedFiles, self.gui_config.kindlePath) self.copy_worker.copyBegin.connect(self.copyBegin) @@ -433,12 +514,13 @@ def convertAllDone(self): self.allControlsEnabled(False, True) self.copy_worker.start() else: - msg = QMessageBox(QMessageBox.Critical, tr('Error'), tr('Error when copying files - device not found.'), QMessageBox.Ok, self) + msg = QMessageBox(QMessageBox.Critical, _translate('fb2mobi-gui', 'Error'), _translate('fb2mobi-gui', + 'Error when copying files - device not found.'), QMessageBox.Ok, self) msg.exec_() def copyBegin(self, file): - self.statusBar().showMessage(tr('Copying file to device: {0}').format(os.path.split(file)[1])) + self.showMessage(_translate('fb2mobi-gui', 'Copying file to device: {0}').format(os.path.split(file)[1])) def copyDone(self): @@ -449,7 +531,7 @@ def copyDone(self): def copyAllDone(self): if self.gui_config.kindleSyncCovers: if self.gui_config.kindlePath and os.path.exists(self.gui_config.kindlePath): - self.statusBar().showMessage(tr('Syncronize covers')) + self.showMessage(_translate('fb2mobi-gui', 'Syncronizing covers')) self.progressBar.setMinimum(0) self.progressBar.setMaximum(0) try: @@ -460,17 +542,17 @@ def copyAllDone(self): time.sleep(0.5) self.progressBar.setVisible(False) self.allControlsEnabled(True) - self.statusBar().clearMessage() + self.clearMessage() def convertBegin(self, file): found = False item = None - self.statusBar().showMessage(tr('Converting file: {0}').format(os.path.split(file)[1])) + self.showMessage(_translate('fb2mobi-gui', 'Converting file: {0}').format(os.path.split(file)[1])) for i in range(self.rootFileList.childCount()): - if file == self.rootFileList.child(i).text(0): + if file == self.rootFileList.child(i).text(2): found = True item = self.rootFileList.child(i) self.treeFileList.scrollToItem(item, QAbstractItemView.EnsureVisible) @@ -488,7 +570,7 @@ def convertDone(self, file, result, dest_file): self.convertedFiles.append(dest_file) for i in range(self.rootFileList.childCount()): - if file == self.rootFileList.child(i).text(0): + if file == self.rootFileList.child(i).text(2): found = True item = self.rootFileList.child(i) break @@ -526,14 +608,24 @@ def addFile(self, file): file = os.path.normpath(file) for i in range(self.rootFileList.childCount()): - if file == self.rootFileList.child(i).text(0): + if file == self.rootFileList.child(i).text(2): found = True break if not found: + meta = Fb2Meta(file) + meta.get() + item = QTreeWidgetItem(0) - item.setText(0, file) item.setIcon(0, self.iconWhite) + item.setText(0, meta.book_title) + item.setText(1, meta.get_autors()) + item.setText(2, file) + # Установим подсказки + item.setToolTip(0, meta.book_title) + item.setToolTip(1, meta.get_autors()) + item.setToolTip(2, file) + self.treeFileList.addTopLevelItem(item) @@ -551,9 +643,10 @@ def addFilesAction(self): if not self.savedPath: self.savedPath = os.path.expanduser('~') - fileDialog = QFileDialog(self, tr('Select files'), self.savedPath) + fileDialog = QFileDialog(self, _translate('fb2mobi-gui', 'Select files'), self.savedPath) fileDialog.setFileMode(QFileDialog.ExistingFiles) - fileDialog.setNameFilters([tr('Fb2 files (*.fb2 *.fb2.zip *.zip)'), tr('All files (*.*)')]) + fileDialog.setNameFilters([_translate('fb2mobi-gui', 'Fb2 files (*.fb2 *.fb2.zip *.zip)'), + _translate('fb2mobi-gui', 'All files (*.*)')]) if fileDialog.exec_(): self.savedPath = fileDialog.directory().absolutePath() @@ -570,7 +663,11 @@ def closeApp(self): self.gui_config.geometry['x'] = win_x self.gui_config.geometry['y'] = win_y self.gui_config.geometry['width'] = win_width - self.gui_config.geometry['height'] = win_height + self.gui_config.geometry['height'] = win_height + + self.gui_config.columns['0'] = self.treeFileList.columnWidth(0) + self.gui_config.columns['1'] = self.treeFileList.columnWidth(1) + self.gui_config.columns['2'] = self.treeFileList.columnWidth(2) self.gui_config.write() @@ -608,6 +705,20 @@ def about(self): def closeEvent(self, event): self.closeApp() + +class AppEventFilter(QObject): + def __init__(self, app_win): + super(AppEventFilter, self).__init__() + self.app_win = app_win + + def eventFilter(self, receiver, event): + if event.type() == QEvent.FileOpen: + self.app_win.addFiles([event.file()]) + return True + else: + return super(AppEventFilter, self).eventFilter(receiver, event) + + if __name__ == '__main__': app = QApplication(sys.argv) @@ -626,4 +737,7 @@ def closeEvent(self, event): mainAppWindow = MainAppWindow() mainAppWindow.show() + appEventFilter = AppEventFilter(mainAppWindow) + app.installEventFilter(appEventFilter) + sys.exit(app.exec_()) diff --git a/fb2mobi_ru.ts b/fb2mobi_ru.ts index 5281bfb..c17139c 100644 --- a/fb2mobi_ru.ts +++ b/fb2mobi_ru.ts @@ -1,79 +1,6 @@ - - @default - - - Select files - Выберите файлы - - - - Select folder - Выберите папку - - - - Folder does not exist. - Указанная папка не существует. - - - - Error - Ошибка - - - - Cancel - Стоп - - - - Cancel conversion - Прервать конвертацию - - - - Start - Пуск - - - - Start conversion - Конвертировать - - - - Error when copying files - device not found. - Ошибка копирования файлов - устройство не найдено. - - - - Copying file to device: {0} - Копирование файла: {0} - - - - Syncronizing covers - Синхронизация обложек - - - - Converting file: {0} - Обработка файла: {0} - - - - Fb2 files (*.fb2 *.fb2.zip *.zip) - Файлы fb2 (*.fb2 *.fb2.zip *.zip) - - - - All files (*.*) - Все файлы (*.*) - - AboutDialog @@ -120,74 +47,79 @@ - + Start Пуск - + Settings... Настройки... - + File Файл - + Help Справка - + Edit Правка - + Add... Добавить файлы... - + Ctrl+O - + Start conversion Конвертировать - + Exit Выход - + Support forum Форум поддержки - + About... О программе... - + View log Посмотреть журнал - + Delete Удалить - Файл - + Title + Название + + + + Author + Автор @@ -268,4 +200,87 @@ Синхронизировать обложки + + fb2mobi-gui + + + Select folder + Выберите папку + + + + Folder does not exist. + Указанная папка не существует. + + + + Error + Ошибка + + + + Cancel + Стоп + + + + Cancel conversion + Прервать конвертацию + + + + Start + Пуск + + + + Start conversion + Конвертировать + + + + Error when copying files - device not found. + Ошибка копирования файлов - устройство не найдено. + + + + Copying file to device: {0} + Копирование файла: {0} + + + + Converting file: {0} + Обработка файла: {0} + + + + Select files + Выберите файлы + + + + Fb2 files (*.fb2 *.fb2.zip *.zip) + Файлы fb2 (*.fb2 *.fb2.zip *.zip) + + + + All files (*.*) + Все файлы (*.*) + + + + Syncronizing covers + Синхронизация обложек + + + + Device connected + Устройство обнаружено + + + + Device not connected + Устройство не обнаружено + + diff --git a/setup-all.mac.cx_freeze.py b/setup-all.mac.cx_freeze.py index 547f20a..05c0f11 100644 --- a/setup-all.mac.cx_freeze.py +++ b/setup-all.mac.cx_freeze.py @@ -45,20 +45,7 @@ (os.path.join(base_dir, 'ui/locale/fb2mobi_ru.qm'), 'ui/locale/fb2mobi_ru.qm'), ] - -plist = {} - -# plist = { -# 'CFBundleDocumentTypes': [{ -# 'CFBundleTypeName': 'Folder', -# 'CFBundleTypeRole': 'Viewer', -# 'LSItemContentTypes': ['public.folder'], -# 'CFBundleTypeExtensions': ['fb2', 'zip'], -# 'CFBundleTypeName': 'FB2 Document', -# 'CFBundleTypeRole': 'Viewer', -# }] -# } - +plist = os.path.join(base_dir, 'ui/Info.plist') setup( name = "fb2mobi-gui", diff --git a/ui/Info.plist b/ui/Info.plist new file mode 100644 index 0000000..a6fccdc --- /dev/null +++ b/ui/Info.plist @@ -0,0 +1,34 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleDisplayName + fb2mobi-gui + CFBundleDocumentTypes + + + CFBundleTypeOSTypes + + **** + + CFBundleTypeRole + Viewer + + + CFBundleTypeExtensions + + fb2 + zip + + CFBundleTypeRole + Viewer + + + CFBundleExecutable + fb2mobi-gui + CFBundleIconFile + icon.icns + + diff --git a/ui/MainWindow.py b/ui/MainWindow.py index e755de2..4cec3fe 100644 --- a/ui/MainWindow.py +++ b/ui/MainWindow.py @@ -33,7 +33,7 @@ def setupUi(self, MainWindow): self.treeFileList.setAlternatingRowColors(True) self.treeFileList.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) self.treeFileList.setObjectName("treeFileList") - self.treeFileList.header().setVisible(False) + self.treeFileList.header().setVisible(True) self.verticalLayout.addWidget(self.splitter) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") @@ -66,7 +66,7 @@ def setupUi(self, MainWindow): self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 763, 21)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 763, 22)) self.menubar.setObjectName("menubar") self.menu = QtWidgets.QMenu(self.menubar) self.menu.setObjectName("menu") @@ -129,7 +129,9 @@ def setupUi(self, MainWindow): def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "fb2mobi")) - self.treeFileList.headerItem().setText(0, _translate("MainWindow", "Файл")) + self.treeFileList.headerItem().setText(0, _translate("MainWindow", "Title")) + self.treeFileList.headerItem().setText(1, _translate("MainWindow", "Author")) + self.treeFileList.headerItem().setText(2, _translate("MainWindow", "File")) self.btnStart.setText(_translate("MainWindow", "Start")) self.btnSettings.setText(_translate("MainWindow", "Settings...")) self.menu.setTitle(_translate("MainWindow", "File")) diff --git a/ui/MainWindow.ui b/ui/MainWindow.ui index a640e40..5e7d659 100644 --- a/ui/MainWindow.ui +++ b/ui/MainWindow.ui @@ -45,11 +45,21 @@ QAbstractItemView::ExtendedSelection - false + true - Файл + Title + + + + + Author + + + + + File @@ -127,7 +137,7 @@ 0 0 763 - 21 + 22 diff --git a/ui/SettingsDialog.ui b/ui/SettingsDialog.ui index 2d1b9e6..9c790b0 100644 --- a/ui/SettingsDialog.ui +++ b/ui/SettingsDialog.ui @@ -189,7 +189,7 @@ - Sync covers + Syncronize covers diff --git a/ui/__init__.py b/ui/__init__.py index 9943efe..456cc64 100644 --- a/ui/__init__.py +++ b/ui/__init__.py @@ -1 +1 @@ -__all__ = ['MainWindnow', 'images_rc', 'gui_config', 'AboutDialog', 'ui_version'] \ No newline at end of file +__all__ = ['MainWindnow', 'images_rc', 'gui_config', 'AboutDialog', 'ui_version', 'fb2meta'] \ No newline at end of file diff --git a/ui/fb2meta.py b/ui/fb2meta.py new file mode 100644 index 0000000..1677060 --- /dev/null +++ b/ui/fb2meta.py @@ -0,0 +1,236 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import base64 +import os +import zipfile +import codecs + +from io import StringIO, BytesIO +from lxml import etree +from lxml.etree import QName + + +def indent(elem, level=0): + '''Функция для улучшения вида xml/html. + Вставляет символы пробела согласно уровню вложенности тэга + ''' + + i = '\n' + level * ' ' + if len(elem): + if not elem.text or not elem.text.strip(): + elem.text = i + ' ' + if not elem.tail or not elem.tail.strip(): + elem.tail = i + for elem in elem: + indent(elem, level + 1) + if not elem.tail or not elem.tail.strip(): + elem.tail = i + else: + if level and (not elem.tail or not elem.tail.strip()): + elem.tail = i + +class Author(): + def __init__(self): + self.first_name = '' + self.middle_name = '' + self.last_name = '' + + +class Sequence(): + def __init__(self): + self.name = '' + self.number = None + + +class Fb2Meta(): + def __init__(self, file): + self.file = file + + self.genre = [] + self.author = [] + self.book_title = '' + self.annotation = None + self.keywords = None + self.date = None + self.coverpage = '' + self.lang = 'ru' + self.src_lang = '' + self.translator = [] + self.sequence = [] + + self.coverdata = None + self.coverpage_href = '' + self.is_zip = False + + if os.path.splitext(self.file)[1].lower() == '.zip': + self.is_zip = True + + if self.is_zip: + zip_file = zipfile.ZipFile(self.file, 'r') + content = None + + if len(zip_file.namelist()) == 1: + f = zip_file.open(zip_file.namelist()[0]) + content = f.read() + f.close() + + self.tree = etree.parse(BytesIO(content), parser=etree.XMLParser(recover=True)) + else: + # TODO: архиве несколько файлов. Ошибка + pass + else: + self.tree = etree.parse(self.file, parser=etree.XMLParser(recover=True)) + + + def get_autors(self): + author_str = '' + + for author in self.author: + if len(author_str) > 0: + author_str += ', ' + + author_str += author.first_name + if author.middle_name: + author_str += ' ' + author.middle_name + + if author.last_name: + author_str += ' ' + author.last_name + + return author_str + + + def get(self): + ns = {'fb': 'http://www.gribuser.ru/xml/fictionbook/2.0'} + for title_info in self.tree.xpath('//fb:description/fb:title-info', namespaces=ns): + for elem in title_info: + if QName(elem).localname == 'genre': + self.genre.append(elem.text) + elif QName(elem).localname == 'author': + author = Author() + for e in elem: + if QName(e).localname == 'first-name': + author.first_name = e.text + elif QName(e).localname == 'middle-name': + author.middle_name = e.text + elif QName(e).localname == 'last-name': + author.last_name = e.text + self.author.append(author) + elif QName(elem).localname == 'book-title': + self.book_title = elem.text + elif QName(elem).localname == 'annotation': + self.annotation = elem + elif QName(elem).localname == 'keywords': + self.keywords = elem + elif QName(elem).localname == 'date': + self.date = elem + elif QName(elem).localname == 'coverpage': + for e in elem: + if QName(e).localname == 'image': + for attrib in e.attrib: + if QName(attrib).localname == 'href': + self.coverpage = e.attrib[attrib][1:] + self.coverpage_href = attrib + elif QName(elem).localname == 'lang': + self.lang = elem.text + elif QName(elem).localname == 'src-lang': + self.src_lang = elem.text + elif QName(elem).localname == 'translator': + self.translator.append(elem) + elif QName(elem).localname == 'sequence': + seq = Sequence() + for a in elem.attrib: + if a == 'name': + seq.name = elem.attrib[a] + elif a == 'number': + seq.number = elem.attrib[a] + self.sequence.append(seq) + + if self.coverpage: + for tag in self.tree.xpath('//fb:binary[@id="{0}"]'.format(self.coverpage), namespaces=ns): + self.coverdata = base64.b64decode(tag.text.encode('ascii')) + + + def _create_title_info(self): + ns = {'fb': 'http://www.gribuser.ru/xml/fictionbook/2.0'} + + title_info = etree.Element('title-info') + + for genre in self.genre: + etree.SubElement(title_info, 'genre').text = genre + + for author in self.author: + author_elem = etree.Element('author') + if author.first_name: + elem = etree.Element('first-name') + elem.text = author.first_name + author_elem.append(elem) + if author.middle_name: + elem = etree.Element('middle-name') + elem.text = author.middle_name + author_elem.append(elem) + if author.last_name: + elem = etree.Element('last-name') + elem.text = author.last_name + author_elem.append(elem) + title_info.append(author_elem) + + etree.SubElement(title_info, 'book-title').text = self.book_title + if self.annotation is not None: + title_info.append(self.annotation) + if self.keywords is not None: + title_info.append(self.keywords) + if self.date is not None: + title_info.append(self.date) + if self.coverpage: + elem = etree.SubElement(title_info, 'coverpage') + etree.SubElement(elem, 'image').attrib[self.coverpage_href] = '#{0}'.format(self.coverpage) + etree.SubElement(title_info, 'lang').text = self.lang + if self.src_lang: + etree.SubElement(title_info, 'src-lang').text = self.src_lang + for translator in self.translator: + title_info.append(translator) + for sequence in self.sequence: + elem = etree.SubElement(title_info, 'sequence') + if sequence.name: + elem.attrib['name'] = sequence.name + if sequence.number: + elem.attrib['number'] = sequence.name + + for elem in self.tree.xpath('//fb:description/fb:title-info', namespaces=ns): + elem.getparent().replace(elem, title_info) + + if self.coverpage and self.coverdata is not None: + image_elem = None + for elem in self.tree.xpath('//fb:binary[@id="{0}"]'.format(self.coverpage), namespaces=ns): + image_elem = elem + break + + if image_elem is None: + image_elem = etree.SubElement(self.tree, 'binary') + image_elem.attrib['id'] = self.coverpage + image_elem.attrib['content-type']='image/jpeg' + + image_elem.text = base64.encodebytes(self.coverdata) + + + def write(self): + ns = {'fb': 'http://www.gribuser.ru/xml/fictionbook/2.0'} + + self._create_title_info() + indent(self.tree.getroot()) + + if self.is_zip: + zip_file = zipfile.ZipFile(self.file, 'w', zipfile.ZIP_DEFLATED) + zip_file.writestr(os.path.splitext(self.file)[0], etree.tostring(self.tree, encoding='utf-8', method='xml', xml_declaration=True)) + zip_file.close() + else: + self.tree.write(self.file, encoding='utf-8', method='xml', xml_declaration=True, pretty_print=False) + +if __name__ == '__main__': + # meta = Fb2Meta('Судья Ди 01. Золото Будды.fb2.zip') + # meta = Fb2Meta('_test.fb2') + # meta = Fb2Meta('Судья Ди 09. Убийство среди лотосов.fb2') + meta = Fb2Meta('Судья Ди 09. Убийство среди лотосов.fb2.zip') + meta.get() + meta.write() diff --git a/ui/gui_config.py b/ui/gui_config.py index 616bc9d..f5cf20a 100644 --- a/ui/gui_config.py +++ b/ui/gui_config.py @@ -20,6 +20,11 @@ def __init__(self, config_file): self.kindleCopyToDevice = False self.kindleSyncCovers = False + self.columns = {} + self.columns['0'] = None + self.columns['1'] = None + self.columns['2'] = None + self.geometry = {} self.geometry['x'] = None self.geometry['y'] = None @@ -58,6 +63,9 @@ def load(self): elif e.tag == 'convertToSourceDirectory': self.convertToSourceDirectory = e.text.lower() == 'true' + elif e.tag == 'columns': + for c in e: + self.columns[c.tag[1:]] = int(c.text) if c.text else None elif e.tag == 'geometry': for g in e: self.geometry[g.tag] = int(g.text) if g.text else None @@ -74,6 +82,11 @@ def write(self): E('kindlePath', self.kindlePath) if self.kindlePath else E('kindlePath'), E('kindleCopyToDevice', str(self.kindleCopyToDevice)), E('kindleSyncCovers', str(self.kindleSyncCovers)), + E('columns', + E('c0', str(self.columns['0'])) if self.columns['0'] else E('c0'), + E('c1', str(self.columns['1'])) if self.columns['1'] else E('c1'), + E('c2', str(self.columns['2'])) if self.columns['2'] else E('c2') + ), E('geometry', E('x', str(self.geometry['x'])) if self.geometry['x'] else E('x'), E('y', str(self.geometry['y'])) if self.geometry['y'] else E('y'), diff --git a/ui/locale/fb2mobi_ru.qm b/ui/locale/fb2mobi_ru.qm index 0d070e7..e00a420 100644 Binary files a/ui/locale/fb2mobi_ru.qm and b/ui/locale/fb2mobi_ru.qm differ diff --git a/ui/ui_version.py b/ui/ui_version.py index 719e1d6..281e86d 100644 --- a/ui/ui_version.py +++ b/ui/ui_version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- -VERSION = u'2.1.0' \ No newline at end of file +VERSION = u'2.5.0' \ No newline at end of file diff --git a/version.py b/version.py index 22bbebc..a22c69d 100644 --- a/version.py +++ b/version.py @@ -4,4 +4,4 @@ WINDOWS = platform.system().lower() == "windows" -VERSION = u'3.6.10' +VERSION = u'3.6.11'