feat: epub

This commit is contained in:
yihong0618
2023-03-10 08:50:56 +08:00
parent ef0058c49d
commit 50e3ed0eeb
8 changed files with 354 additions and 160 deletions

1
.gitignore vendored
View File

@@ -133,3 +133,4 @@ dmypy.json
# remove MacOS .DS_Store
.DS_Store
EPUB/

View File

@@ -1813,10 +1813,17 @@ qt_resource_struct = b"\
\x00\x00\x01\x81Cj\xfeG\
"
def qInitResources():
QtCore.qRegisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data)
QtCore.qRegisterResourceData(
0x03, qt_resource_struct, qt_resource_name, qt_resource_data
)
def qCleanupResources():
QtCore.qUnregisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data)
QtCore.qUnregisterResourceData(
0x03, qt_resource_struct, qt_resource_name, qt_resource_data
)
qInitResources()

View File

@@ -8,265 +8,293 @@
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QAbstractItemView, QApplication, QCheckBox, QDialog, QGroupBox,
QHBoxLayout, QHeaderView, QLabel, QLineEdit,
QPlainTextEdit, QPushButton, QRadioButton, QSizePolicy,
QSpinBox, QTableView, QTextBrowser, QVBoxLayout,
QWidget)
from PySide6.QtCore import (
QCoreApplication,
QDate,
QDateTime,
QLocale,
QMetaObject,
QObject,
QPoint,
QRect,
QSize,
QTime,
QUrl,
Qt,
)
from PySide6.QtGui import (
QBrush,
QColor,
QConicalGradient,
QCursor,
QFont,
QFontDatabase,
QGradient,
QIcon,
QImage,
QKeySequence,
QLinearGradient,
QPainter,
QPalette,
QPixmap,
QRadialGradient,
QTransform,
)
from PySide6.QtWidgets import (
QAbstractItemView,
QApplication,
QCheckBox,
QDialog,
QGroupBox,
QHBoxLayout,
QHeaderView,
QLabel,
QLineEdit,
QPlainTextEdit,
QPushButton,
QRadioButton,
QSizePolicy,
QSpinBox,
QTableView,
QTextBrowser,
QVBoxLayout,
QWidget,
)
import gui.icon_rc as icon_rc
class Ui_MainDialog(object):
def setupUi(self, MainDialog):
if not MainDialog.objectName():
MainDialog.setObjectName(u"MainDialog")
MainDialog.setObjectName("MainDialog")
MainDialog.resize(1190, 872)
icon = QIcon()
icon.addFile(u":/icon/resource/kindle.png", QSize(), QIcon.Normal, QIcon.Off)
icon.addFile(":/icon/resource/kindle.png", QSize(), QIcon.Normal, QIcon.Off)
MainDialog.setWindowIcon(icon)
self.horizontalLayout = QHBoxLayout(MainDialog)
self.horizontalLayout.setSpacing(10)
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.horizontalLayout.setObjectName("horizontalLayout")
self.leftLayout = QVBoxLayout()
self.leftLayout.setObjectName(u"leftLayout")
self.leftLayout.setObjectName("leftLayout")
self.listBox = QGroupBox(MainDialog)
self.listBox.setObjectName(u"listBox")
self.listBox.setObjectName("listBox")
self.verticalLayout_5 = QVBoxLayout(self.listBox)
self.verticalLayout_5.setObjectName(u"verticalLayout_5")
self.verticalLayout_5.setObjectName("verticalLayout_5")
self.widget = QWidget(self.listBox)
self.widget.setObjectName(u"widget")
self.widget.setObjectName("widget")
self.widget.setMinimumSize(QSize(0, 0))
self.widget.setBaseSize(QSize(0, 0))
self.horizontalLayout_6 = QHBoxLayout(self.widget)
self.horizontalLayout_6.setObjectName(u"horizontalLayout_6")
self.horizontalLayout_6.setObjectName("horizontalLayout_6")
self.horizontalLayout_6.setContentsMargins(0, 0, 0, 0)
self.radioEBOK = QRadioButton(self.widget)
self.radioEBOK.setObjectName(u"radioEBOK")
self.radioEBOK.setObjectName("radioEBOK")
self.radioEBOK.setChecked(True)
self.horizontalLayout_6.addWidget(self.radioEBOK)
self.radioPDO = QRadioButton(self.widget)
self.radioPDO.setObjectName(u"radioPDO")
self.radioPDO.setObjectName("radioPDO")
self.horizontalLayout_6.addWidget(self.radioPDO)
self.fetchButton = QPushButton(self.widget)
self.fetchButton.setObjectName(u"fetchButton")
self.fetchButton.setObjectName("fetchButton")
self.horizontalLayout_6.addWidget(self.fetchButton)
self.verticalLayout_5.addWidget(self.widget, 0, Qt.AlignRight)
self.bookView = QTableView(self.listBox)
self.bookView.setObjectName(u"bookView")
self.bookView.setObjectName("bookView")
self.bookView.setSelectionBehavior(QAbstractItemView.SelectRows)
self.verticalLayout_5.addWidget(self.bookView)
self.horizontalLayout_4 = QHBoxLayout()
self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.label_2 = QLabel(self.listBox)
self.label_2.setObjectName(u"label_2")
self.label_2.setObjectName("label_2")
self.horizontalLayout_4.addWidget(self.label_2)
self.outDirEdit = QLineEdit(self.listBox)
self.outDirEdit.setObjectName(u"outDirEdit")
self.outDirEdit.setObjectName("outDirEdit")
self.horizontalLayout_4.addWidget(self.outDirEdit)
self.browseButton = QPushButton(self.listBox)
self.browseButton.setObjectName(u"browseButton")
self.browseButton.setObjectName("browseButton")
self.horizontalLayout_4.addWidget(self.browseButton)
self.downloadButton = QPushButton(self.listBox)
self.downloadButton.setObjectName(u"downloadButton")
self.downloadButton.setObjectName("downloadButton")
self.horizontalLayout_4.addWidget(self.downloadButton)
self.selectedButton = QPushButton(self.listBox)
self.selectedButton.setObjectName(u"selectedButton")
self.selectedButton.setObjectName("selectedButton")
self.horizontalLayout_4.addWidget(self.selectedButton)
self.dedrmCkb = QCheckBox(self.listBox)
self.dedrmCkb.setObjectName(u"dedrmCkb")
self.dedrmCkb.setObjectName("dedrmCkb")
self.horizontalLayout_4.addWidget(self.dedrmCkb)
self.verticalLayout_5.addLayout(self.horizontalLayout_4)
self.leftLayout.addWidget(self.listBox)
self.groupBox_2 = QGroupBox(MainDialog)
self.groupBox_2.setObjectName(u"groupBox_2")
self.groupBox_2.setObjectName("groupBox_2")
self.groupBox_2.setMaximumSize(QSize(16777215, 200))
self.verticalLayout_7 = QVBoxLayout(self.groupBox_2)
self.verticalLayout_7.setObjectName(u"verticalLayout_7")
self.verticalLayout_7.setObjectName("verticalLayout_7")
self.logBrowser = QTextBrowser(self.groupBox_2)
self.logBrowser.setObjectName(u"logBrowser")
self.logBrowser.setObjectName("logBrowser")
self.verticalLayout_7.addWidget(self.logBrowser)
self.leftLayout.addWidget(self.groupBox_2)
self.horizontalLayout.addLayout(self.leftLayout)
self.rightLayout = QVBoxLayout()
self.rightLayout.setSpacing(6)
self.rightLayout.setObjectName(u"rightLayout")
self.rightLayout.setObjectName("rightLayout")
self.settingsBox = QGroupBox(MainDialog)
self.settingsBox.setObjectName(u"settingsBox")
self.settingsBox.setObjectName("settingsBox")
self.settingsBox.setMaximumSize(QSize(400, 16777215))
self.verticalLayout = QVBoxLayout(self.settingsBox)
self.verticalLayout.setObjectName(u"verticalLayout")
self.verticalLayout.setObjectName("verticalLayout")
self.loginGroupBox = QGroupBox(self.settingsBox)
self.loginGroupBox.setObjectName(u"loginGroupBox")
self.loginGroupBox.setObjectName("loginGroupBox")
self.horizontalLayout_2 = QHBoxLayout(self.loginGroupBox)
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.verticalLayout_2 = QVBoxLayout()
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.radioCOM = QRadioButton(self.loginGroupBox)
self.radioCOM.setObjectName(u"radioCOM")
self.radioCOM.setObjectName("radioCOM")
self.verticalLayout_2.addWidget(self.radioCOM)
self.radioCN = QRadioButton(self.loginGroupBox)
self.radioCN.setObjectName(u"radioCN")
self.radioCN.setObjectName("radioCN")
self.radioCN.setChecked(True)
self.verticalLayout_2.addWidget(self.radioCN)
self.radioJP = QRadioButton(self.loginGroupBox)
self.radioJP.setObjectName(u"radioJP")
self.radioJP.setObjectName("radioJP")
self.verticalLayout_2.addWidget(self.radioJP)
self.radioDE = QRadioButton(self.loginGroupBox)
self.radioDE.setObjectName(u"radioDE")
self.radioDE.setObjectName("radioDE")
self.verticalLayout_2.addWidget(self.radioDE)
self.radioUK = QRadioButton(self.loginGroupBox)
self.radioUK.setObjectName(u"radioUK")
self.radioUK.setObjectName("radioUK")
self.verticalLayout_2.addWidget(self.radioUK)
self.horizontalLayout_2.addLayout(self.verticalLayout_2)
self.loginButton = QPushButton(self.loginGroupBox)
self.loginButton.setObjectName(u"loginButton")
self.loginButton.setObjectName("loginButton")
self.loginButton.setMaximumSize(QSize(80, 16777215))
self.horizontalLayout_2.addWidget(self.loginButton)
self.verticalLayout.addWidget(self.loginGroupBox)
self.cookiesGroupBox = QGroupBox(self.settingsBox)
self.cookiesGroupBox.setObjectName(u"cookiesGroupBox")
self.cookiesGroupBox.setObjectName("cookiesGroupBox")
self.verticalLayout_3 = QVBoxLayout(self.cookiesGroupBox)
self.verticalLayout_3.setObjectName(u"verticalLayout_3")
self.verticalLayout_3.setObjectName("verticalLayout_3")
self.cookieTextEdit = QPlainTextEdit(self.cookiesGroupBox)
self.cookieTextEdit.setObjectName(u"cookieTextEdit")
self.cookieTextEdit.setObjectName("cookieTextEdit")
self.cookieTextEdit.setEnabled(False)
self.verticalLayout_3.addWidget(self.cookieTextEdit)
self.horizontalLayout_3 = QHBoxLayout()
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
self.radioFromInput = QRadioButton(self.cookiesGroupBox)
self.radioFromInput.setObjectName(u"radioFromInput")
self.radioFromInput.setObjectName("radioFromInput")
self.horizontalLayout_3.addWidget(self.radioFromInput)
self.radioFromBrowser = QRadioButton(self.cookiesGroupBox)
self.radioFromBrowser.setObjectName(u"radioFromBrowser")
self.radioFromBrowser.setObjectName("radioFromBrowser")
self.radioFromBrowser.setChecked(True)
self.horizontalLayout_3.addWidget(self.radioFromBrowser)
self.verticalLayout_3.addLayout(self.horizontalLayout_3)
self.verticalLayout.addWidget(self.cookiesGroupBox)
self.groupBox = QGroupBox(self.settingsBox)
self.groupBox.setObjectName(u"groupBox")
self.groupBox.setObjectName("groupBox")
self.verticalLayout_4 = QVBoxLayout(self.groupBox)
self.verticalLayout_4.setObjectName(u"verticalLayout_4")
self.verticalLayout_4.setObjectName("verticalLayout_4")
self.csrfEdit = QLineEdit(self.groupBox)
self.csrfEdit.setObjectName(u"csrfEdit")
self.csrfEdit.setObjectName("csrfEdit")
self.verticalLayout_4.addWidget(self.csrfEdit)
self.verticalLayout.addWidget(self.groupBox)
self.horizontalLayout_5 = QHBoxLayout()
self.horizontalLayout_5.setObjectName(u"horizontalLayout_5")
self.horizontalLayout_5.setObjectName("horizontalLayout_5")
self.label = QLabel(self.settingsBox)
self.label.setObjectName(u"label")
self.label.setObjectName("label")
self.horizontalLayout_5.addWidget(self.label)
self.cutLengthSpin = QSpinBox(self.settingsBox)
self.cutLengthSpin.setObjectName(u"cutLengthSpin")
self.cutLengthSpin.setObjectName("cutLengthSpin")
self.cutLengthSpin.setMaximum(999)
self.cutLengthSpin.setValue(100)
self.horizontalLayout_5.addWidget(self.cutLengthSpin)
self.verticalLayout.addLayout(self.horizontalLayout_5)
self.rightLayout.addWidget(self.settingsBox, 0, Qt.AlignTop)
self.copyrightBox = QGroupBox(MainDialog)
self.copyrightBox.setObjectName(u"copyrightBox")
self.copyrightBox.setObjectName("copyrightBox")
self.verticalLayout_6 = QVBoxLayout(self.copyrightBox)
self.verticalLayout_6.setObjectName(u"verticalLayout_6")
self.verticalLayout_6.setObjectName("verticalLayout_6")
self.label_6 = QLabel(self.copyrightBox)
self.label_6.setObjectName(u"label_6")
self.label_6.setObjectName("label_6")
self.verticalLayout_6.addWidget(self.label_6)
self.label_3 = QLabel(self.copyrightBox)
self.label_3.setObjectName(u"label_3")
self.label_3.setObjectName("label_3")
self.label_3.setTextFormat(Qt.MarkdownText)
self.verticalLayout_6.addWidget(self.label_3)
self.label_4 = QLabel(self.copyrightBox)
self.label_4.setObjectName(u"label_4")
self.label_4.setObjectName("label_4")
self.label_4.setTextFormat(Qt.MarkdownText)
self.verticalLayout_6.addWidget(self.label_4)
self.label_5 = QLabel(self.copyrightBox)
self.label_5.setObjectName(u"label_5")
self.label_5.setObjectName("label_5")
self.verticalLayout_6.addWidget(self.label_5)
self.rightLayout.addWidget(self.copyrightBox, 0, Qt.AlignTop)
self.horizontalLayout.addLayout(self.rightLayout)
self.horizontalLayout.setStretch(0, 1)
@@ -274,44 +302,127 @@ class Ui_MainDialog(object):
self.retranslateUi(MainDialog)
QMetaObject.connectSlotsByName(MainDialog)
# setupUi
def retranslateUi(self, MainDialog):
MainDialog.setWindowTitle(QCoreApplication.translate("MainDialog", u"Kindle \u4e0b\u8f7d\u52a9\u624b", None))
self.listBox.setTitle(QCoreApplication.translate("MainDialog", u"\u4e0b\u8f7d\u5217\u8868", None))
self.radioEBOK.setText(QCoreApplication.translate("MainDialog", u"\u7535\u5b50\u4e66", None))
self.radioPDO.setText(QCoreApplication.translate("MainDialog", u"\u4e2a\u4eba\u6587\u6863", None))
self.fetchButton.setText(QCoreApplication.translate("MainDialog", u"\u83b7\u53d6\u4e0b\u8f7d\u5217\u8868", None))
self.label_2.setText(QCoreApplication.translate("MainDialog", u"\u76ee\u6807\u6587\u4ef6\u5939", None))
self.outDirEdit.setText(QCoreApplication.translate("MainDialog", u"DOWNLOADS", None))
self.browseButton.setText(QCoreApplication.translate("MainDialog", u"\u6d4f\u89c8...", None))
self.downloadButton.setText(QCoreApplication.translate("MainDialog", u"\u4e0b\u8f7d\u5168\u90e8", None))
self.selectedButton.setText(QCoreApplication.translate("MainDialog", u"Download Selected", None))
self.dedrmCkb.setText(QCoreApplication.translate("MainDialog", u"DeDRM", None))
self.groupBox_2.setTitle(QCoreApplication.translate("MainDialog", u"\u8f93\u51fa", None))
self.logBrowser.setHtml(QCoreApplication.translate("MainDialog", u"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><meta charset=\"utf-8\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"hr { height: 1px; border-width: 0; }\n"
"</style></head><body style=\" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;\">\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Microsoft YaHei UI'; font-size:9pt;\"><br /></p></body></html>", None))
self.settingsBox.setTitle(QCoreApplication.translate("MainDialog", u"\u8bbe\u7f6e", None))
MainDialog.setWindowTitle(
QCoreApplication.translate(
"MainDialog", "Kindle \u4e0b\u8f7d\u52a9\u624b", None
)
)
self.listBox.setTitle(
QCoreApplication.translate("MainDialog", "\u4e0b\u8f7d\u5217\u8868", None)
)
self.radioEBOK.setText(
QCoreApplication.translate("MainDialog", "\u7535\u5b50\u4e66", None)
)
self.radioPDO.setText(
QCoreApplication.translate("MainDialog", "\u4e2a\u4eba\u6587\u6863", None)
)
self.fetchButton.setText(
QCoreApplication.translate(
"MainDialog", "\u83b7\u53d6\u4e0b\u8f7d\u5217\u8868", None
)
)
self.label_2.setText(
QCoreApplication.translate(
"MainDialog", "\u76ee\u6807\u6587\u4ef6\u5939", None
)
)
self.outDirEdit.setText(
QCoreApplication.translate("MainDialog", "DOWNLOADS", None)
)
self.browseButton.setText(
QCoreApplication.translate("MainDialog", "\u6d4f\u89c8...", None)
)
self.downloadButton.setText(
QCoreApplication.translate("MainDialog", "\u4e0b\u8f7d\u5168\u90e8", None)
)
self.selectedButton.setText(
QCoreApplication.translate("MainDialog", "Download Selected", None)
)
self.dedrmCkb.setText(QCoreApplication.translate("MainDialog", "DeDRM", None))
self.groupBox_2.setTitle(
QCoreApplication.translate("MainDialog", "\u8f93\u51fa", None)
)
self.logBrowser.setHtml(
QCoreApplication.translate(
"MainDialog",
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">\n'
'<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css">\n'
"p, li { white-space: pre-wrap; }\n"
"hr { height: 1px; border-width: 0; }\n"
"</style></head><body style=\" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;\">\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Microsoft YaHei UI'; font-size:9pt;\"><br /></p></body></html>",
None,
)
)
self.settingsBox.setTitle(
QCoreApplication.translate("MainDialog", "\u8bbe\u7f6e", None)
)
self.loginGroupBox.setTitle("")
self.radioCOM.setText(QCoreApplication.translate("MainDialog", u"\u7f8e\u4e9a(.com)", None))
self.radioCN.setText(QCoreApplication.translate("MainDialog", u"\u4e2d\u4e9a(.cn)", None))
self.radioJP.setText(QCoreApplication.translate("MainDialog", u"\u65e5\u4e9a(.jp)", None))
self.radioDE.setText(QCoreApplication.translate("MainDialog", u"\u5fb7\u4e9a(.de)", None))
self.radioUK.setText(QCoreApplication.translate("MainDialog", u"\u82F1\u4e9a(.uk)", None))
self.loginButton.setText(QCoreApplication.translate("MainDialog", u"\u767b\u5f55", None))
self.cookiesGroupBox.setTitle(QCoreApplication.translate("MainDialog", u"Cookies", None))
self.radioFromInput.setText(QCoreApplication.translate("MainDialog", u"\u6765\u81ea\u8f93\u5165", None))
self.radioFromBrowser.setText(QCoreApplication.translate("MainDialog", u"\u6765\u81ea\u6d4f\u89c8\u5668", None))
self.groupBox.setTitle(QCoreApplication.translate("MainDialog", u"CSRF Token", None))
self.label.setText(QCoreApplication.translate("MainDialog", u"\u6587\u4ef6\u540d\u622a\u65ad", None))
self.radioCOM.setText(
QCoreApplication.translate("MainDialog", "\u7f8e\u4e9a(.com)", None)
)
self.radioCN.setText(
QCoreApplication.translate("MainDialog", "\u4e2d\u4e9a(.cn)", None)
)
self.radioJP.setText(
QCoreApplication.translate("MainDialog", "\u65e5\u4e9a(.jp)", None)
)
self.radioDE.setText(
QCoreApplication.translate("MainDialog", "\u5fb7\u4e9a(.de)", None)
)
self.radioUK.setText(
QCoreApplication.translate("MainDialog", "\u82F1\u4e9a(.uk)", None)
)
self.loginButton.setText(
QCoreApplication.translate("MainDialog", "\u767b\u5f55", None)
)
self.cookiesGroupBox.setTitle(
QCoreApplication.translate("MainDialog", "Cookies", None)
)
self.radioFromInput.setText(
QCoreApplication.translate("MainDialog", "\u6765\u81ea\u8f93\u5165", None)
)
self.radioFromBrowser.setText(
QCoreApplication.translate(
"MainDialog", "\u6765\u81ea\u6d4f\u89c8\u5668", None
)
)
self.groupBox.setTitle(
QCoreApplication.translate("MainDialog", "CSRF Token", None)
)
self.label.setText(
QCoreApplication.translate(
"MainDialog", "\u6587\u4ef6\u540d\u622a\u65ad", None
)
)
self.copyrightBox.setTitle("")
self.label_6.setText(QCoreApplication.translate("MainDialog", u"\u9690\u79c1\u58f0\u660e\uff1a\u6211\u4eec\u4e0d\u4f1a\u6536\u96c6\u4efb\u4f55\u7528\u6237\u4fe1\u606f\uff0c\u8bf7\u653e\u5fc3\u4f7f\u7528", None))
self.label_3.setText(QCoreApplication.translate("MainDialog", u"Copyright 2022 \u00a9 [yihong0618](https://github.com/yihong0618) and [frostming](https://github.com/frostming)", None))
self.label_4.setText(QCoreApplication.translate("MainDialog", u"GitHub: <https://github.com/yihong0618/Kindle_download_helper>", None))
self.label_5.setText(QCoreApplication.translate("MainDialog", u"License: GPL V3", None))
# retranslateUi
self.label_6.setText(
QCoreApplication.translate(
"MainDialog",
"\u9690\u79c1\u58f0\u660e\uff1a\u6211\u4eec\u4e0d\u4f1a\u6536\u96c6\u4efb\u4f55\u7528\u6237\u4fe1\u606f\uff0c\u8bf7\u653e\u5fc3\u4f7f\u7528",
None,
)
)
self.label_3.setText(
QCoreApplication.translate(
"MainDialog",
"Copyright 2022 \u00a9 [yihong0618](https://github.com/yihong0618) and [frostming](https://github.com/frostming)",
None,
)
)
self.label_4.setText(
QCoreApplication.translate(
"MainDialog",
"GitHub: <https://github.com/yihong0618/Kindle_download_helper>",
None,
)
)
self.label_5.setText(
QCoreApplication.translate("MainDialog", "License: GPL V3", None)
)
# retranslateUi

View File

@@ -9,6 +9,7 @@ from kindle_download_helper.config import (
DEFAULT_OUT_DIR,
DEFAULT_SESSION_FILE,
DEFAULT_OUT_DEDRM_DIR,
DEFAULT_OUT_EPUB_DIR,
)
logger = logging.getLogger("kindle")
@@ -18,29 +19,46 @@ logger.addHandler(fh)
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# download selected books for cli
def download_selected_books(kindle, options):
# get all books and get the default device
print('Getting all books, please wait...')
print("Getting all books, please wait...")
books = kindle.get_all_books(filetype=options.filetype)
device = kindle.find_device()
# print all books
for idx, book in enumerate(books):
print('Index: ' + '{:>5d}'.format(idx+1) + ' | Title: ' + book['title'] + ' | asin: '+book['asin'])
print(
"Index: "
+ "{:>5d}".format(idx + 1)
+ " | Title: "
+ book["title"]
+ " | asin: "
+ book["asin"]
)
# download loop
while True:
# get the indices of the books to download
indices = input('Input the index of books you want to download, split by space (q to quit, l to list books).\n').split()
indices = input(
"Input the index of books you want to download, split by space (q to quit, l to list books).\n"
).split()
# if input "q", quit
# if input "l", list all books again
if indices[0] == 'q':
if indices[0] == "q":
break
elif indices[0] == 'l':
elif indices[0] == "l":
for idx, book in enumerate(books):
print('Index: ' + '{:>5d}'.format(idx+1) + ' | Title: ' + book['title'] + ' | asin: '+book['asin'])
print(
"Index: "
+ "{:>5d}".format(idx + 1)
+ " | Title: "
+ book["title"]
+ " | asin: "
+ book["asin"]
)
continue
# decode the indices
@@ -48,21 +66,21 @@ def download_selected_books(kindle, options):
flag = True
for idx in indices:
if idx.isnumeric() == False:
if ':' in idx:
if ":" in idx:
# if is not a number, and ":" in it, then it is a range
# decode the range
idx_begin, idx_end = [int(i) for i in idx.split(':')]
idx_begin, idx_end = [int(i) for i in idx.split(":")]
# append the range to downlist
extend_list = [i for i in range(idx_begin-1, idx_end)]
extend_list = [i for i in range(idx_begin - 1, idx_end)]
downlist.extend(extend_list)
else:
# if is not a number, and no ":" in it, then it is an error
print('Input error, please input numbers!!!')
print("Input error, please input numbers!!!")
flag = False
break
else:
# if is a number, then append it to downlist
downlist.append(int(idx)-1)
downlist.append(int(idx) - 1)
if not flag:
continue
@@ -71,29 +89,49 @@ def download_selected_books(kindle, options):
# check if the indices are valid
if max(downlist) >= len(books) or min(downlist) < 0:
print('Input error, please input numbers between 1 and ' + str(len(books)) + '!!!')
print(
"Input error, please input numbers between 1 and "
+ str(len(books))
+ "!!!"
)
continue
# print the books to download
for idx in downlist:
print('Index: ' + '{:>5d}'.format(idx+1) + ' | Title: ' + books[idx]['title'] + ' | asin: '+books[idx]['asin'])
print('Downloading ' + str(len(downlist)) + ' books:')
print(
"Index: "
+ "{:>5d}".format(idx + 1)
+ " | Title: "
+ books[idx]["title"]
+ " | asin: "
+ books[idx]["asin"]
)
print("Downloading " + str(len(downlist)) + " books:")
# ask if to continue
while True:
flag = input('Continue? (y/n)')
if flag == 'y' or flag == 'n':
flag = input("Continue? (y/n)")
if flag == "y" or flag == "n":
break
else:
print('Input error, please input y or n')
if flag == 'n':
print("Input error, please input y or n")
if flag == "n":
continue
# download the books
for i, idx in enumerate(downlist):
print('Downloading ' + str(i+1) + '/' + str(len(downlist)) + ' ' + books[idx]['title'] + ' ...')
print(
"Downloading "
+ str(i + 1)
+ "/"
+ str(len(downlist))
+ " "
+ books[idx]["title"]
+ " ..."
)
kindle.download_one_book(books[idx], device, idx, filetype=options.filetype)
print('Download finished.')
print("Download finished.")
def main():
logger.setLevel(os.environ.get("LOGGING_LEVEL", "INFO"))
@@ -165,6 +203,12 @@ def main():
default=DEFAULT_OUT_DEDRM_DIR,
help="dwonload output dedrm dir",
)
parser.add_argument(
"-oe",
"--outepubmdir",
default=DEFAULT_OUT_EPUB_DIR,
help="dwonload output epub dir",
)
parser.add_argument(
"-s",
"--session-file",
@@ -226,11 +270,16 @@ def main():
# for dedrm
if not os.path.exists(options.outdedrmdir):
os.makedirs(options.outdedrmdir)
# for epub
if not os.path.exists(options.outepubmdir):
os.makedirs(options.outepubmdir)
kindle = Kindle(
options.csrf_token,
options.domain,
options.outdir,
options.outdedrmdir,
options.outepubmdir,
options.cut_length,
session_file=options.session_file,
device_sn=options.device_sn,
@@ -265,7 +314,9 @@ def main():
# check the download mode
if options.mode == "all":
# download all books
kindle.download_books(start_index=options.index - 1, filetype=options.filetype)
kindle.download_books(
start_index=options.index - 1, filetype=options.filetype
)
elif options.mode == "sel":
# download selected books
download_selected_books(kindle, options)

View File

@@ -4,6 +4,7 @@ from kindle_download_helper.user_agents import USER_AGENTS
DEFAULT_OUT_DIR = "DOWNLOADS"
DEFAULT_OUT_DEDRM_DIR = "DEDRMS"
DEFAULT_OUT_EPUB_DIR = "EPUB"
DEFAULT_SESSION_FILE = ".kindle_session"
KINDLE_HEADER = {

View File

@@ -22,6 +22,7 @@ charMap1 = b"n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M"
charMap3 = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
charMap4 = b"ABCDEFGHIJKLMNPQRSTUVWXYZ123456789"
# crypto digestroutines
def MD5(message):
ctx = hashlib.md5()

View File

@@ -13,6 +13,8 @@ import re
import time
import urllib
import pathlib
import shutil
from mobi import extract
from http.cookies import SimpleCookie
import requests
@@ -23,8 +25,9 @@ from kindle_download_helper.dedrm import MobiBook, get_pid_list
from kindle_download_helper.config import (
KINDLE_URLS,
DEFAULT_OUT_DIR,
DEFAULT_SESSION_FILE,
DEFAULT_OUT_DEDRM_DIR,
DEFAULT_OUT_EPUB_DIR,
DEFAULT_SESSION_FILE,
CONTENT_TYPES,
KINDLE_STAT_TEMPLATE,
)
@@ -48,6 +51,7 @@ logger.addHandler(fh)
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
class Kindle:
def __init__(
self,
@@ -55,6 +59,7 @@ class Kindle:
domain="cn",
out_dir=DEFAULT_OUT_DIR,
out_dedrm_dir=DEFAULT_OUT_DEDRM_DIR,
out_epub_dir=DEFAULT_OUT_EPUB_DIR,
cut_length=100,
session_file=DEFAULT_SESSION_FILE,
**kwargs,
@@ -64,6 +69,7 @@ class Kindle:
self.total_to_download = 0
self.out_dir = out_dir
self.out_dedrm_dir = out_dedrm_dir
self.out_epub_dir = out_epub_dir
self.dedrm = False
self.cut_length = cut_length
self.not_done = False
@@ -104,7 +110,7 @@ class Kindle:
if not self.session.cookies:
logger.debug("No cookie found, trying to load from browsers")
try:
self.set_cookie(browser_cookie3.load(domain_name="amazon"))
self.set_cookie(browser_cookie3.load())
except:
print("not found browser_cookie3 here, you should use --cookie command")
@@ -364,7 +370,9 @@ class Kindle:
book_title = book.get("title", "")
# filter the brackets in the book title
book_title = re.sub(r"(\[^)]*\|\([^)]*\)|\【[^)]*\】|\[[^)]*\])", "", book_title)
book_title = re.sub(
r"(\[^)]*\|\([^)]*\)|\【[^)]*\】|\[[^)]*\])", "", book_title
)
book_title = book_title.replace(" ", "")
if book.get("category", "") == "KindleEBook":
@@ -466,27 +474,28 @@ class Kindle:
out = os.path.join(self.out_dir, name)
out_dedrm = os.path.join(self.out_dedrm_dir, name)
out_epub = os.path.join(self.out_epub_dir, name.split(".")[0] + ".epub")
#normally one owns no more than 9999 books
# normally one owns no more than 9999 books
count_digit_length = 4
size_length = 6
size_in_mb = round(float(total_size) / (1024*1024), 3)
size_in_mb = round(float(total_size) / (1024 * 1024), 3)
logger.info(
f"[{index+1:>{count_digit_length}}/{self.total_to_download:>{count_digit_length}}][{size_in_mb:> {size_length}}Mb]Downloading {name}"
)
#try if we can writ the file
try :
# try if we can write the file
try:
pathlib.Path(out).touch()
except OSError as e:
if e.errno == 36 : #means file name too long
if e.errno == 36: # means file name too long
name = self.trim_title_suffix(title) + extname
logger.info(f"Original filename too long, trim to {name}")
out = os.path.join(self.out_dir, name)
out_dedrm = os.path.join(self.out_dedrm_dir, name)
else :
else:
logger.error(e)
with open(out, "wb") as f:
@@ -501,6 +510,14 @@ class Kindle:
totalpids = get_pid_list(md1, md2, [self.device_serial_number], [])
totalpids = list(set(totalpids))
mb.make_drm_file(totalpids, out_dedrm)
time.sleep(1)
# save to EPUB
epub_dir, epub_file = extract(out_dedrm)
print(epub_file)
shutil.copy2(epub_file, out_epub)
# delete it
shutil.rmtree(epub_dir)
except Exception as e:
logger.error("DeDRM failed for %s: %s", name, e)
pass
@@ -538,7 +555,11 @@ class Kindle:
with open(os.path.join(self.out_dir, "key.txt"), "w") as f:
f.write(f"Key is: {device['deviceSerialNumber']}")
logger.info("the device serial number can also be found here: {0}".format(os.path.join(self.out_dir, "key.txt")))
logger.info(
"the device serial number can also be found here: {0}".format(
os.path.join(self.out_dir, "key.txt")
)
)
def trim_title_suffix(self, title):
return re.sub(r"([^]+?|【[^】]+】?)", "", title)

View File

@@ -1,3 +1,4 @@
requests
browser-cookie3
mobi
pywin32 ; sys_platform == 'win32'