mirror of
https://github.com/yihong0618/Kindle_download_helper.git
synced 2025-11-22 07:59:04 +08:00
add a GUI written by qtpython
This commit is contained in:
53
kindle.py
53
kindle.py
@@ -4,6 +4,7 @@ Great Thanks
|
||||
"""
|
||||
|
||||
from http.cookies import SimpleCookie
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
@@ -14,6 +15,8 @@ import browsercookie
|
||||
import requests
|
||||
import argparse
|
||||
|
||||
logger = logging.getLogger("kindle")
|
||||
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
DEFAULT_OUT_DIR = "DOWNLOADS"
|
||||
@@ -35,7 +38,7 @@ KINDLE_URLS = {
|
||||
"payload": "https://www.amazon.cn/hz/mycd/ajax",
|
||||
},
|
||||
"com": {
|
||||
"bookall": "https://www.amazon.cn/hz/mycd/myx#/home/content/booksAll",
|
||||
"bookall": "https://www.amazon.com/hz/mycd/myx#/home/content/booksAll",
|
||||
"download": "https://cde-ta-g7g.amazon.com/FionaCDEServiceEngine/FSDownloadContent?type={}&key={}&fsn={}&device_type={}&customerId={}",
|
||||
"payload": "https://www.amazon.com/hz/mycd/ajax",
|
||||
},
|
||||
@@ -62,6 +65,9 @@ class Kindle:
|
||||
raise Exception("Please make sure your amazon cookie is right")
|
||||
self.session.cookies = cookiejar
|
||||
|
||||
def set_cookie_from_browser(self):
|
||||
self.set_cookie(browsercookie.load())
|
||||
|
||||
@staticmethod
|
||||
def _parse_kindle_cookie(kindle_cookie):
|
||||
cookie = SimpleCookie()
|
||||
@@ -105,7 +111,7 @@ class Kindle:
|
||||
devices = r.json()["GetDevices"]["devices"]
|
||||
return [device for device in devices if "deviceSerialNumber" in device]
|
||||
|
||||
def get_all_asins(self, filetype="EBOK"):
|
||||
def get_all_books(self, filetype="EBOK"):
|
||||
"""
|
||||
TODO: refactor this function
|
||||
"""
|
||||
@@ -125,31 +131,36 @@ class Kindle:
|
||||
}
|
||||
|
||||
if filetype == "EBOK":
|
||||
payload["param"]["OwnershipData"].update({
|
||||
"originType": ["Purchase"],
|
||||
})
|
||||
payload["param"]["OwnershipData"].update(
|
||||
{
|
||||
"originType": ["Purchase"],
|
||||
}
|
||||
)
|
||||
else:
|
||||
batchSize = 18
|
||||
payload["param"]["OwnershipData"].update({
|
||||
"batchSize": batchSize,
|
||||
"isExtendedMYK": False,
|
||||
})
|
||||
payload["param"]["OwnershipData"].update(
|
||||
{
|
||||
"batchSize": batchSize,
|
||||
"isExtendedMYK": False,
|
||||
}
|
||||
)
|
||||
|
||||
asins = []
|
||||
books = []
|
||||
while True:
|
||||
r = self.session.post(
|
||||
self.urls["payload"],
|
||||
data={"data": json.dumps(payload), "csrfToken": self.csrf_token},
|
||||
)
|
||||
r.raise_for_status()
|
||||
result = r.json()
|
||||
asins += [book["asin"] for book in result["OwnershipData"]["items"]]
|
||||
books += result["OwnershipData"]["items"]
|
||||
|
||||
if result["OwnershipData"]["hasMoreItems"]:
|
||||
startIndex += batchSize
|
||||
payload["param"]["OwnershipData"]["startIndex"] = startIndex
|
||||
else:
|
||||
break
|
||||
return asins
|
||||
return books
|
||||
|
||||
def make_session(self):
|
||||
session = requests.Session()
|
||||
@@ -175,21 +186,21 @@ class Kindle:
|
||||
name = name[: self.cut_length - 5] + name[-5:]
|
||||
total_size = r.headers["Content-length"]
|
||||
out = os.path.join(self.out_dir, name)
|
||||
print(
|
||||
logger.info(
|
||||
f"({index}/{self.total_to_download})downloading {name} {total_size} bytes"
|
||||
)
|
||||
with open(out, "wb") as f:
|
||||
for chunk in r.iter_content(chunk_size=512):
|
||||
f.write(chunk)
|
||||
print(f"{name} downloaded")
|
||||
logger.info(f"{name} downloaded")
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
print(f"{asin} download failed")
|
||||
logger.info(str(e))
|
||||
logger.info(f"{asin} download failed")
|
||||
|
||||
def download_books(self, start_index=0, filetype="EBOK"):
|
||||
# use default device
|
||||
device = self.get_devices()[0]
|
||||
asins = self.get_all_asins(filetype=filetype)
|
||||
asins = [book["asin"] for book in self.get_all_books(filetype=filetype)]
|
||||
self.total_to_download = len(asins) - 1
|
||||
if start_index > 0:
|
||||
print(f"resuming the download {start_index}/{self.total_to_download}")
|
||||
@@ -198,7 +209,7 @@ class Kindle:
|
||||
self.download_one_book(asin, device, index, filetype)
|
||||
index += 1
|
||||
|
||||
print(
|
||||
logger.info(
|
||||
"\n\nAll done!\nNow you can use apprenticeharper's DeDRM tools "
|
||||
"(https://github.com/apprenticeharper/DeDRM_tools)\n"
|
||||
"with the following serial number to remove DRM: "
|
||||
@@ -209,6 +220,9 @@ class Kindle:
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
logger.setLevel(logging.INFO)
|
||||
logger.addHandler(logging.StreamHandler())
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("csrf_token", help="amazon or amazon cn csrf token")
|
||||
|
||||
@@ -267,6 +281,5 @@ if __name__ == "__main__":
|
||||
elif options.cookie:
|
||||
kindle.set_cookie_from_string(options.cookie)
|
||||
else:
|
||||
kindle.set_cookie(browsercookie.load())
|
||||
|
||||
kindle.set_cookie_from_browser()
|
||||
kindle.download_books(start_index=options.index, filetype=options.filetype)
|
||||
|
||||
234
kindle_gui.py
Normal file
234
kindle_gui.py
Normal file
@@ -0,0 +1,234 @@
|
||||
from contextlib import contextmanager
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from typing import NamedTuple
|
||||
import webbrowser
|
||||
from PySide6 import QtWidgets, QtCore
|
||||
|
||||
import kindle
|
||||
from kindle_helper_ui import Ui_MainDialog
|
||||
|
||||
logger = logging.getLogger("kindle")
|
||||
|
||||
|
||||
class SignalLogHandler(logging.Handler):
|
||||
def __init__(self, signal):
|
||||
super().__init__(logging.DEBUG)
|
||||
formatter = logging.Formatter("[%(asctime)s]%(levelname)s - %(message)s")
|
||||
self.setFormatter(formatter)
|
||||
self.signal = signal
|
||||
|
||||
def emit(self, record):
|
||||
msg = self.format(record)
|
||||
self.signal.emit(msg)
|
||||
|
||||
|
||||
class Book(NamedTuple):
|
||||
id: int
|
||||
title: str
|
||||
author: str
|
||||
asin: str
|
||||
|
||||
|
||||
class Worker(QtCore.QObject):
|
||||
finished = QtCore.Signal()
|
||||
progress = QtCore.Signal(int)
|
||||
logging = QtCore.Signal(str)
|
||||
|
||||
def __init__(self, iterable, kindle):
|
||||
super().__init__()
|
||||
self.iterable = iterable
|
||||
self.kindle = kindle
|
||||
|
||||
def run(self):
|
||||
logger.setLevel(logging.INFO)
|
||||
logger.handlers[:] = [SignalLogHandler(self.logging)]
|
||||
try:
|
||||
devices = self.kindle.get_devices()
|
||||
device = devices[0]
|
||||
for i, book in enumerate(self.iterable, 1):
|
||||
self.kindle.download_one_book(book.asin, device, i)
|
||||
self.progress.emit(i)
|
||||
except Exception:
|
||||
logger.exception("download failed")
|
||||
finally:
|
||||
self.finished.emit()
|
||||
|
||||
|
||||
class KindleMainDialog(QtWidgets.QDialog):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.ui = Ui_MainDialog()
|
||||
self.ui.setupUi(self)
|
||||
self.kindle = kindle.Kindle("")
|
||||
self.setup_signals()
|
||||
# self.setup_logger()
|
||||
self.book_model = BookItemModel(self.ui.bookView, [], ["序号", "书名", "作者"])
|
||||
self.ui.bookView.setModel(self.book_model)
|
||||
self.ui.bookView.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
|
||||
self.ui.bookView.horizontalHeader().setSectionResizeMode(
|
||||
1, QtWidgets.QHeaderView.Stretch
|
||||
)
|
||||
|
||||
def setup_signals(self):
|
||||
self.ui.radioFromInput.clicked.connect(self.on_from_input)
|
||||
self.ui.radioFromBrowser.clicked.connect(self.on_from_browser)
|
||||
self.ui.loginButton.clicked.connect(self.on_login_amazon)
|
||||
self.ui.browseButton.clicked.connect(self.on_browse_dir)
|
||||
self.ui.fetchButton.clicked.connect(self.on_fetch_books)
|
||||
self.ui.downloadButton.clicked.connect(self.on_download_books)
|
||||
|
||||
def show_error(self, message):
|
||||
msg = QtWidgets.QErrorMessage(self)
|
||||
msg.showMessage(message)
|
||||
|
||||
def on_error(self):
|
||||
exc_info = sys.exc_info()
|
||||
self.show_error(f"{exc_info[0].__name__}: {exc_info[1]}")
|
||||
|
||||
def setup_kindle(self):
|
||||
instance = self.kindle
|
||||
instance.csrf_token = self.ui.csrfEdit.text()
|
||||
instance.urls = kindle.KINDLE_URLS[self.getDomain()]
|
||||
instance.out_dir = self.ui.outDirEdit.text()
|
||||
instance.cut_length = self.ui.cutLengthSpin.value()
|
||||
instance.total_to_download = 0
|
||||
if self.ui.radioFromInput.isChecked():
|
||||
instance.set_cookie_from_string(self.ui.cookieTextEdit.text())
|
||||
else:
|
||||
instance.set_cookie_from_browser()
|
||||
if not instance.csrf_token:
|
||||
self.show_error("Please input CSRF token")
|
||||
|
||||
def getDomain(self):
|
||||
if self.ui.radioCN.isChecked():
|
||||
return "cn"
|
||||
else:
|
||||
return "com"
|
||||
|
||||
@QtCore.Slot()
|
||||
def on_login_amazon(self):
|
||||
url = kindle.KINDLE_URLS[self.getDomain()]["bookall"]
|
||||
webbrowser.open(url)
|
||||
|
||||
@QtCore.Slot()
|
||||
def on_from_input(self, checked):
|
||||
self.ui.cookieTextEdit.setEnabled(checked)
|
||||
|
||||
@QtCore.Slot()
|
||||
def on_from_browser(self, checked):
|
||||
self.ui.cookieTextEdit.setEnabled(not checked)
|
||||
|
||||
@QtCore.Slot()
|
||||
def on_browse_dir(self):
|
||||
file_dialog = QtWidgets.QFileDialog()
|
||||
file_dialog.setFileMode(QtWidgets.QFileDialog.Directory)
|
||||
file_dialog.setOption(QtWidgets.QFileDialog.ShowDirsOnly)
|
||||
if file_dialog.exec_():
|
||||
self.ui.outDirEdit.setText(file_dialog.selectedFiles()[0])
|
||||
|
||||
@QtCore.Slot()
|
||||
def on_fetch_books(self):
|
||||
self.ui.fetchButton.setEnabled(False)
|
||||
self.setup_kindle()
|
||||
try:
|
||||
all_books = self.kindle.get_all_books()
|
||||
book_data = [
|
||||
[item["title"], item["authors"], item["asin"]] for item in all_books
|
||||
]
|
||||
self.book_model.updateData(book_data)
|
||||
except Exception:
|
||||
self.on_error()
|
||||
finally:
|
||||
self.ui.fetchButton.setEnabled(True)
|
||||
|
||||
@contextmanager
|
||||
def make_progressbar(self, iterable, total):
|
||||
parent = self.ui.logBrowser.parent()
|
||||
progressbar = QtWidgets.QProgressBar(parent)
|
||||
|
||||
def gen():
|
||||
for i, item in enumerate(iterable, 1):
|
||||
try:
|
||||
yield item
|
||||
finally:
|
||||
progressbar.setValue(round(i / total * 100, 2))
|
||||
|
||||
yield gen()
|
||||
self.ui.verticalLayout_7.removeWidget(progressbar)
|
||||
|
||||
@QtCore.Slot()
|
||||
def on_download_books(self):
|
||||
self.setup_kindle()
|
||||
if not os.path.exists(self.kindle.out_dir):
|
||||
os.makedirs(self.kindle.out_dir)
|
||||
self.thread = QtCore.QThread()
|
||||
iterable, total = self.book_model._data, self.book_model.rowCount(0)
|
||||
self.kindle.total_to_download = total
|
||||
self.worker = Worker(iterable, self.kindle)
|
||||
self.worker.moveToThread(self.thread)
|
||||
parent = self.ui.logBrowser.parent()
|
||||
self.progressbar = QtWidgets.QProgressBar(parent)
|
||||
self.ui.verticalLayout_7.insertWidget(0, self.progressbar)
|
||||
self.thread.started.connect(self.worker.run)
|
||||
self.worker.finished.connect(self.thread.quit)
|
||||
self.worker.finished.connect(self.worker.deleteLater)
|
||||
self.thread.finished.connect(self.thread.deleteLater)
|
||||
self.worker.logging.connect(self.ui.logBrowser.append)
|
||||
self.worker.progress.connect(
|
||||
lambda n: self.progressbar.setValue(round(n / total * 100, 2))
|
||||
)
|
||||
self.ui.downloadButton.setEnabled(False)
|
||||
self.thread.finished.connect(self.on_finish_download)
|
||||
self.thread.start()
|
||||
|
||||
def on_finish_download(self):
|
||||
self.ui.verticalLayout_7.removeWidget(self.progressbar)
|
||||
self.progressbar.deleteLater()
|
||||
|
||||
|
||||
class BookItemModel(QtCore.QAbstractTableModel):
|
||||
def __init__(self, parent, data, header):
|
||||
super().__init__(parent)
|
||||
self._data = data
|
||||
self._header = header
|
||||
|
||||
def headerData(self, section, orientation, role):
|
||||
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
|
||||
return self._header[section]
|
||||
return None
|
||||
|
||||
def updateData(self, data):
|
||||
self._data = [Book(i, *row) for i, row in enumerate(data, 1)]
|
||||
self.layoutAboutToBeChanged.emit()
|
||||
self.dataChanged.emit(
|
||||
self.createIndex(0, 0),
|
||||
self.createIndex(self.rowCount(0), self.columnCount(0)),
|
||||
)
|
||||
self.layoutChanged.emit()
|
||||
|
||||
def data(self, index, role):
|
||||
if not index.isValid():
|
||||
return None
|
||||
value = self._data[index.row()][index.column()]
|
||||
if role == QtCore.Qt.DisplayRole:
|
||||
return value
|
||||
return None
|
||||
|
||||
def rowCount(self, parent):
|
||||
return len(self._data)
|
||||
|
||||
def columnCount(self, parent):
|
||||
return len(self._header)
|
||||
|
||||
|
||||
def main():
|
||||
app = QtWidgets.QApplication()
|
||||
dialog = KindleMainDialog()
|
||||
dialog.show()
|
||||
sys.exit(app.exec())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
280
kindle_helper.ui
Normal file
280
kindle_helper.ui
Normal file
@@ -0,0 +1,280 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainDialog</class>
|
||||
<widget class="QDialog" name="MainDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1190</width>
|
||||
<height>872</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Kindle 下载助手</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0">
|
||||
<property name="spacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="leftLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="listBox">
|
||||
<property name="title">
|
||||
<string>下载列表</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item alignment="Qt::AlignRight">
|
||||
<widget class="QPushButton" name="fetchButton">
|
||||
<property name="text">
|
||||
<string>获取书籍列表</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableView" name="bookView"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>目标文件夹</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="outDirEdit">
|
||||
<property name="text">
|
||||
<string>DOWNLOADS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="browseButton">
|
||||
<property name="text">
|
||||
<string>浏览...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="downloadButton">
|
||||
<property name="text">
|
||||
<string>下载全部</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>200</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>输出</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="logBrowser">
|
||||
<property name="html">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
hr { height: 1px; border-width: 0; }
|
||||
</style></head><body style=" font-family:'Microsoft YaHei UI'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<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;"><br /></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="rightLayout" stretch="0,0">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item alignment="Qt::AlignTop">
|
||||
<widget class="QGroupBox" name="settingsBox">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>400</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>设置</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="loginGroupBox">
|
||||
<property name="title">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioCOM">
|
||||
<property name="text">
|
||||
<string>美亚(.com)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioCN">
|
||||
<property name="text">
|
||||
<string>中亚(.cn)</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="loginButton">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>登录</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="cookiesGroupBox">
|
||||
<property name="title">
|
||||
<string>Cookies</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="cookieTextEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioFromInput">
|
||||
<property name="text">
|
||||
<string>来自输入</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioFromBrowser">
|
||||
<property name="text">
|
||||
<string>来自浏览器</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>CSRF Token</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="csrfEdit"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>文件名截断</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="cutLengthSpin">
|
||||
<property name="maximum">
|
||||
<number>999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item alignment="Qt::AlignTop">
|
||||
<widget class="QGroupBox" name="copyrightBox">
|
||||
<property name="title">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>隐私声明:我们不会收集任何用户信息,请放心使用</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Copyright 2022 © [yihong0618](https://github.com/yihong0618)</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::MarkdownText</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>GitHub: <https://github.com/yihong0618/Kindle_download_helper></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::MarkdownText</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>License: MIT</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
356
kindle_helper_ui.py
Normal file
356
kindle_helper_ui.py
Normal file
@@ -0,0 +1,356 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'kindle_helper.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.3.0
|
||||
##
|
||||
## 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 (
|
||||
QApplication,
|
||||
QDialog,
|
||||
QGroupBox,
|
||||
QHBoxLayout,
|
||||
QHeaderView,
|
||||
QLabel,
|
||||
QLineEdit,
|
||||
QPlainTextEdit,
|
||||
QPushButton,
|
||||
QRadioButton,
|
||||
QSizePolicy,
|
||||
QSpinBox,
|
||||
QTableView,
|
||||
QTextBrowser,
|
||||
QVBoxLayout,
|
||||
QWidget,
|
||||
)
|
||||
|
||||
|
||||
class Ui_MainDialog(object):
|
||||
def setupUi(self, MainDialog):
|
||||
if not MainDialog.objectName():
|
||||
MainDialog.setObjectName("MainDialog")
|
||||
MainDialog.resize(1190, 872)
|
||||
self.horizontalLayout = QHBoxLayout(MainDialog)
|
||||
self.horizontalLayout.setSpacing(10)
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.leftLayout = QVBoxLayout()
|
||||
self.leftLayout.setObjectName("leftLayout")
|
||||
self.listBox = QGroupBox(MainDialog)
|
||||
self.listBox.setObjectName("listBox")
|
||||
self.verticalLayout_5 = QVBoxLayout(self.listBox)
|
||||
self.verticalLayout_5.setObjectName("verticalLayout_5")
|
||||
self.fetchButton = QPushButton(self.listBox)
|
||||
self.fetchButton.setObjectName("fetchButton")
|
||||
|
||||
self.verticalLayout_5.addWidget(self.fetchButton, 0, Qt.AlignRight)
|
||||
|
||||
self.bookView = QTableView(self.listBox)
|
||||
self.bookView.setObjectName("bookView")
|
||||
|
||||
self.verticalLayout_5.addWidget(self.bookView)
|
||||
|
||||
self.horizontalLayout_4 = QHBoxLayout()
|
||||
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
|
||||
self.label_2 = QLabel(self.listBox)
|
||||
self.label_2.setObjectName("label_2")
|
||||
|
||||
self.horizontalLayout_4.addWidget(self.label_2)
|
||||
|
||||
self.outDirEdit = QLineEdit(self.listBox)
|
||||
self.outDirEdit.setObjectName("outDirEdit")
|
||||
|
||||
self.horizontalLayout_4.addWidget(self.outDirEdit)
|
||||
|
||||
self.browseButton = QPushButton(self.listBox)
|
||||
self.browseButton.setObjectName("browseButton")
|
||||
|
||||
self.horizontalLayout_4.addWidget(self.browseButton)
|
||||
|
||||
self.downloadButton = QPushButton(self.listBox)
|
||||
self.downloadButton.setObjectName("downloadButton")
|
||||
|
||||
self.horizontalLayout_4.addWidget(self.downloadButton)
|
||||
|
||||
self.verticalLayout_5.addLayout(self.horizontalLayout_4)
|
||||
|
||||
self.leftLayout.addWidget(self.listBox)
|
||||
|
||||
self.groupBox_2 = QGroupBox(MainDialog)
|
||||
self.groupBox_2.setObjectName("groupBox_2")
|
||||
self.groupBox_2.setMaximumSize(QSize(16777215, 200))
|
||||
self.verticalLayout_7 = QVBoxLayout(self.groupBox_2)
|
||||
self.verticalLayout_7.setObjectName("verticalLayout_7")
|
||||
self.logBrowser = QTextBrowser(self.groupBox_2)
|
||||
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("rightLayout")
|
||||
self.settingsBox = QGroupBox(MainDialog)
|
||||
self.settingsBox.setObjectName("settingsBox")
|
||||
self.settingsBox.setMaximumSize(QSize(400, 16777215))
|
||||
self.verticalLayout = QVBoxLayout(self.settingsBox)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.loginGroupBox = QGroupBox(self.settingsBox)
|
||||
self.loginGroupBox.setObjectName("loginGroupBox")
|
||||
self.horizontalLayout_2 = QHBoxLayout(self.loginGroupBox)
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
self.verticalLayout_2 = QVBoxLayout()
|
||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||
self.radioCOM = QRadioButton(self.loginGroupBox)
|
||||
self.radioCOM.setObjectName("radioCOM")
|
||||
|
||||
self.verticalLayout_2.addWidget(self.radioCOM)
|
||||
|
||||
self.radioCN = QRadioButton(self.loginGroupBox)
|
||||
self.radioCN.setObjectName("radioCN")
|
||||
self.radioCN.setChecked(True)
|
||||
|
||||
self.verticalLayout_2.addWidget(self.radioCN)
|
||||
|
||||
self.horizontalLayout_2.addLayout(self.verticalLayout_2)
|
||||
|
||||
self.loginButton = QPushButton(self.loginGroupBox)
|
||||
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("cookiesGroupBox")
|
||||
self.verticalLayout_3 = QVBoxLayout(self.cookiesGroupBox)
|
||||
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
||||
self.cookieTextEdit = QPlainTextEdit(self.cookiesGroupBox)
|
||||
self.cookieTextEdit.setObjectName("cookieTextEdit")
|
||||
|
||||
self.verticalLayout_3.addWidget(self.cookieTextEdit)
|
||||
|
||||
self.horizontalLayout_3 = QHBoxLayout()
|
||||
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
||||
self.radioFromInput = QRadioButton(self.cookiesGroupBox)
|
||||
self.radioFromInput.setObjectName("radioFromInput")
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.radioFromInput)
|
||||
|
||||
self.radioFromBrowser = QRadioButton(self.cookiesGroupBox)
|
||||
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("groupBox")
|
||||
self.verticalLayout_4 = QVBoxLayout(self.groupBox)
|
||||
self.verticalLayout_4.setObjectName("verticalLayout_4")
|
||||
self.csrfEdit = QLineEdit(self.groupBox)
|
||||
self.csrfEdit.setObjectName("csrfEdit")
|
||||
|
||||
self.verticalLayout_4.addWidget(self.csrfEdit)
|
||||
|
||||
self.verticalLayout.addWidget(self.groupBox)
|
||||
|
||||
self.horizontalLayout_5 = QHBoxLayout()
|
||||
self.horizontalLayout_5.setObjectName("horizontalLayout_5")
|
||||
self.label = QLabel(self.settingsBox)
|
||||
self.label.setObjectName("label")
|
||||
|
||||
self.horizontalLayout_5.addWidget(self.label)
|
||||
|
||||
self.cutLengthSpin = QSpinBox(self.settingsBox)
|
||||
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("copyrightBox")
|
||||
self.verticalLayout_6 = QVBoxLayout(self.copyrightBox)
|
||||
self.verticalLayout_6.setObjectName("verticalLayout_6")
|
||||
self.label_6 = QLabel(self.copyrightBox)
|
||||
self.label_6.setObjectName("label_6")
|
||||
|
||||
self.verticalLayout_6.addWidget(self.label_6)
|
||||
|
||||
self.label_3 = QLabel(self.copyrightBox)
|
||||
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("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("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)
|
||||
|
||||
self.retranslateUi(MainDialog)
|
||||
|
||||
QMetaObject.connectSlotsByName(MainDialog)
|
||||
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, MainDialog):
|
||||
MainDialog.setWindowTitle(
|
||||
QCoreApplication.translate(
|
||||
"MainDialog", "Kindle \u4e0b\u8f7d\u52a9\u624b", None
|
||||
)
|
||||
)
|
||||
self.listBox.setTitle(
|
||||
QCoreApplication.translate("MainDialog", "\u4e0b\u8f7d\u5217\u8868", None)
|
||||
)
|
||||
self.fetchButton.setText(
|
||||
QCoreApplication.translate(
|
||||
"MainDialog", "\u83b7\u53d6\u4e66\u7c4d\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.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:'Microsoft YaHei UI'; font-size:9pt; 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;"><br /></p></body></html>',
|
||||
None,
|
||||
)
|
||||
)
|
||||
self.settingsBox.setTitle(
|
||||
QCoreApplication.translate("MainDialog", "\u8bbe\u7f6e", None)
|
||||
)
|
||||
self.loginGroupBox.setTitle("")
|
||||
self.radioCOM.setText(
|
||||
QCoreApplication.translate("MainDialog", "\u7f8e\u4e9a(.com)", None)
|
||||
)
|
||||
self.radioCN.setText(
|
||||
QCoreApplication.translate("MainDialog", "\u4e2d\u4e9a(.cn)", 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",
|
||||
"\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)",
|
||||
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: MIT", None)
|
||||
)
|
||||
|
||||
# retranslateUi
|
||||
Reference in New Issue
Block a user