mirror of
https://github.com/yihong0618/Kindle_download_helper.git
synced 2025-11-22 07:59:04 +08:00
feat: epub
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -133,3 +133,4 @@ dmypy.json
|
||||
|
||||
# remove MacOS .DS_Store
|
||||
.DS_Store
|
||||
EPUB/
|
||||
@@ -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()
|
||||
|
||||
335
gui/ui_kindle.py
335
gui/ui_kindle.py
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -22,6 +22,7 @@ charMap1 = b"n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M"
|
||||
charMap3 = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||
charMap4 = b"ABCDEFGHIJKLMNPQRSTUVWXYZ123456789"
|
||||
|
||||
|
||||
# crypto digestroutines
|
||||
def MD5(message):
|
||||
ctx = hashlib.md5()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
requests
|
||||
browser-cookie3
|
||||
mobi
|
||||
pywin32 ; sys_platform == 'win32'
|
||||
|
||||
Reference in New Issue
Block a user