import sys import os import re import datetime from PyQt6.QtWidgets import ( QApplication, QWidget, QVBoxLayout, QPushButton, QLabel, QListWidget, QFileDialog, QMessageBox, QLineEdit, QFormLayout, QDialog, QDialogButtonBox ) from PyQt6.QtGui import QIcon import config from exportbooknotes import BookNotesExporter from booklist_parse import BookListManager class ConfigDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("配置参数") layout = QFormLayout(self) self.inputs = {} for attr in dir(config): if attr.isupper(): val = getattr(config, attr) inp = QLineEdit(str(val)) layout.addRow(attr, inp) self.inputs[attr] = inp buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) buttons.accepted.connect(self.accept) buttons.rejected.connect(self.reject) layout.addWidget(buttons) def get_config(self): return {k: v.text() for k, v in self.inputs.items()} class IBookExportApp(QWidget): def __init__(self): super().__init__() self.setWindowTitle("iBooks 笔记导出工具") self.resize(600, 400) # 设置窗口图标 if os.path.exists(config.APP_ICON): self.setWindowIcon(QIcon(config.APP_ICON)) self.exporter = BookNotesExporter(config) self.manager = BookListManager(plist_path=config.LOCAL_BOOKS_PLIST, db_path=config.LOCAL_LIBRARY_DB) self.booksinfo = self.manager.get_books_info() self.last_open_times = self.manager.get_books_last_open() self.assetid2name = {} self.assetid2lastopen = {} for assetid, info in self.booksinfo.items(): name = info.get('displayname') or info.get('itemname') or assetid if '-' in name: name = name.split('-', 1)[0].strip() self.assetid2name[assetid] = name ts = self.last_open_times.get(assetid, {}).get('last_open', 0) self.assetid2lastopen[assetid] = ts sorted_assetids = sorted(self.assetid2name.keys(), key=lambda aid: self.assetid2lastopen[aid], reverse=True) self.sorted_assetids = sorted_assetids layout = QVBoxLayout(self) self.label = QLabel("请选择要导出的书籍:") layout.addWidget(self.label) self.listwidget = QListWidget() for aid in sorted_assetids: self.listwidget.addItem(f"{self.assetid2name[aid]} [{self.assetid2lastopen[aid]}]") layout.addWidget(self.listwidget) # 回车直接导出(使用事件过滤器) self.listwidget.installEventFilter(self) self.export_btn = QPushButton("导出") self.export_btn.clicked.connect(self.export_notes) self.config_btn = QPushButton("配置参数") self.config_btn.clicked.connect(self.show_config) layout.addWidget(self.export_btn) layout.addWidget(self.config_btn) def eventFilter(self, obj, event): from PyQt6.QtCore import QEvent, Qt if obj == self.listwidget and event.type() == QEvent.Type.KeyPress: # 检查回车键(Enter/Return) if event.key() in (0x01000004, 0x01000005): # Qt.Key_Return, Qt.Key_Enter self.export_notes() return True return super().eventFilter(obj, event) def show_config(self): dlg = ConfigDialog(self) if dlg.exec(): new_config = dlg.get_config() # 这里只是演示,实际可写入config.py或动态加载 QMessageBox.information(self, "提示", "配置已更新(仅本次运行有效)") def export_notes(self): from exportbooknotes import sync_source_files sync_source_files(config) idx = self.listwidget.currentRow() if idx < 0: QMessageBox.warning(self, "提示", "请先选择一本书") return assetid = self.sorted_assetids[idx] selected_booksnote = self.exporter.build_booksnote(bookid=assetid) selected_booksinfo = {assetid: self.booksinfo.get(assetid, {})} bookname = selected_booksinfo[assetid].get("displayname") or selected_booksinfo[assetid].get("itemname") or assetid ts = datetime.datetime.now().strftime('%m%d%H%M') shortname = re.split(r'[.::_\【\[\((]', bookname)[0].strip() export_dir = getattr(config, "EXPORT_NOTES_DIR", os.getcwd()) if not os.path.exists(export_dir): os.makedirs(export_dir) out_path = os.path.join(export_dir, f"notes_{shortname}-{ts}.md") self.exporter.export_booksnote_to_md(selected_booksnote, selected_booksinfo, out_path) QMessageBox.information(self, "导出成功", f"已导出到:{out_path}") if __name__ == "__main__": app = QApplication(sys.argv) # 设置应用程序图标 if os.path.exists(config.APP_ICON): app.setWindowIcon(QIcon(config.APP_ICON)) win = IBookExportApp() win.show() sys.exit(app.exec())