Skip to content

Commit

Permalink
Merge pull request #127 from Zeal-L/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
Zeal-L committed Mar 30, 2024
2 parents b52e34d + 0075418 commit fb8a296
Show file tree
Hide file tree
Showing 25 changed files with 8,475 additions and 8,289 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
sh setup.sh
bash setup.sh
- name: Analysing the code with pylint
id: pylint
- name: Analysing the code with ruff
id: ruff
run: |
poetry run pylint $(git ls-files '*.py' | grep -v "PySide_src")
poetry run ruff format -q $(git ls-files '*.py' | grep -v "PySide_src")
continue-on-error: true
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
- **特别提示: 毕竟是要提供 Cookie 给第三方网站托管,因此可能会有潜在的安全风险。敏感人群请不要使用自己主账号的 Cookie**
- `BiliPlus``Cookie` 获取方法跟上述一致,在 [ComicWebReader](https://www.biliplus.com/manga/) 登入后在开发者工具中找到 `access_key` 粘贴到程序设置选项中的 `BiliPlus Cookie` 即可

- **兼容性:支持Windows与Linux平台,MacOs需要自行编译,发现问题的欢迎提Issues**
- **兼容性:支持Windows、MacOS与Linux平台,发现问题的欢迎提Issues**
- **搜索 / 选择章节 / 下载 的功能介绍我想已经不言而喻了,这就是图形化界面的好处!**
- **值得注意的是:本软件不支持断点续传和下载任务缓存的功能 ~~(毕竟一章漫画太小了,好像也没什么必要,断了不如重下)~~,所以请确保不要在下载中途关闭!**
- **程序缓存和日志历史文件存在 `C:\Users\AppData\Roaming\BiliBili-Manga-Downloader\` 目录下,可以通过"清空用户数据"功能一键删除**
Expand Down
33 changes: 31 additions & 2 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,48 @@


import ctypes
import subprocess
from sys import argv, exit, platform

from PySide6.QtWidgets import QApplication, QMessageBox

from src.ui.MainGUI import MainGUI
from src.Utils import __main_window_title__, __version__
from src.Utils import __main_window_title__, logger

if __name__ == "__main__":
app = QApplication.instance() or QApplication(argv)

if platform == "win32" and ctypes.windll.user32.FindWindowW(None, __main_window_title__) != 0:
box = QMessageBox.information(None, "提示", "有一个我已经不满足不了你吗?\n\t...(。•ˇ‸ˇ•。) ...")
box = QMessageBox.information(
None, "提示", "有一个我已经不满足不了你吗?\n\t...(。•ˇ‸ˇ•。) ..."
)
exit(0)
elif platform == "darwin":
script = """
set windowTitle to "{}"
tell application "System Events"
set listOfProcesses to every process whose visible is true
repeat with proc in listOfProcesses
try
if exists (window 1 of proc where the name contains windowTitle) then
return true
end if
end try
end repeat
end tell
return false
""".format(__main_window_title__)

try:
output = subprocess.check_output(["osascript", "-e", script], text=True).strip()
if output == "true":
QMessageBox.information(
None, "提示", "有一个我已经不满足不了你吗?\n\t...(。•ˇ‸ˇ•。) ..."
)
exit(1)
except subprocess.CalledProcessError as e:
logger.error("检查是否有重复窗口时出错:", e)
exit(1)

window = MainGUI(app)
window.show()
Expand Down
Empty file modified build.sh
100644 → 100755
Empty file.
1,183 changes: 568 additions & 615 deletions poetry.lock

Large diffs are not rendered by default.

43 changes: 21 additions & 22 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,40 +1,39 @@
[tool.poetry]
name = "bilibili-manga-downloader"
version = "1.5.0"
description = "一个好用的哔哩哔哩漫画下载器,拥有图形界面,支持关键词搜索漫画和二维码登入,黑科技下载未解锁章节,多线程下载,多种保存格式,本地漫画管理,一键检查更新!"
authors = ["Zeal-L <zeal.liang@gmail.com>"]
description = "一个好用的哔哩哔哩漫画下载器,拥有图形界面,支持关键词搜索漫画和二维码登入,黑科技下载未解锁章节,多线程下载,多种保存格式,本地漫画管理,一键检查更新!"
license = "AGPL-3.0"
name = "bilibili-manga-downloader"
readme = "README.md"
version = "1.5.1"

[tool.poetry.dependencies]
python = ">=3.12,<3.13"
beautifulsoup4 = "^4.12.3"
piexif = "^1.1.3"
pillow = "10.2.0"
py7zr = "^0.20.8"
pypdf2 = "^3.0.1"
pyside6 = "^6.6.0"
requests = "^2.31.0"
retrying = "^1.3.4"
pillow = "^10.1.0"
pypdf = "^4.0.2"
pypinyin = "^0.49.0"
qt-material = "^2.14"
beautifulsoup4 = "^4.12.2"
pyside6 = "^6.6.2"
python = ">=3.12,<3.13"
qrcode = "^7.4.2"
qt-material = "^2.14"
requests = "^2.31.0"
retrying = "^1.3.4"

[tool.poetry.group.dev.dependencies]
auto-py-to-exe = "^2.42.0"
pyinstaller = "^6.4.0"
rich = "^13.7.0"
ruff = "^0.2.2"

[[tool.poetry.source]]
name = "mirrors"
url = "https://pypi.tuna.tsinghua.edu.cn/simple/"
priority = "supplemental"


[tool.poetry.group.dev.dependencies]
rich = "^13.7.0"
pylint = "^3.0.2"
pyinstaller = "^6.2.0"
auto-py-to-exe = "^2.42.0"
url = "https://pypi.tuna.tsinghua.edu.cn/simple/"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
requires = ["poetry-core"]

[tool.black]
line-length = 100
[tool.ruff]
line-length = 100
15 changes: 12 additions & 3 deletions setup.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,18 @@ poetry run pyside6-uic src/ui/PySide_src/myAbout.ui -o src/ui/PySide_src/myAbout
poetry run pyside6-uic src/ui/PySide_src/qrCode.ui -o src/ui/PySide_src/qrCode_ui.py

echo -e "\033[34m\n 修复UI文件中的导入问题 ... \n\033[0m"
sed -i 's/resource_rc/src.ui.PySide_src.resource_rc/' src/ui/PySide_src/mainWindow_ui.py
sed -i 's/resource_rc/src.ui.PySide_src.resource_rc/' src/ui/PySide_src/myAbout_ui.py
sed -i 's/resource_rc/src.ui.PySide_src.resource_rc/' src/ui/PySide_src/qrCode_ui.py
if [[ "$OSTYPE" == "darwin"* ]]; then
# macOS
SED_INPLACE=(-i '')
else
# 其他环境,假设使用 GNU sed
SED_INPLACE=(-i)
fi

sed "${SED_INPLACE[@]}" 's/resource_rc/src.ui.PySide_src.resource_rc/' src/ui/PySide_src/mainWindow_ui.py
sed "${SED_INPLACE[@]}" 's/resource_rc/src.ui.PySide_src.resource_rc/' src/ui/PySide_src/myAbout_ui.py
sed "${SED_INPLACE[@]}" 's/resource_rc/src.ui.PySide_src.resource_rc/' src/ui/PySide_src/qrCode_ui.py


echo -e "\033[34m\n 显示虚拟环境相关信息 ... \n\033[0m"
poetry debug info
Expand Down
35 changes: 21 additions & 14 deletions src/BiliPlus.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def __init__(self, comic_id: int, mainGUI: MainGUI) -> None:
self.access_key = mainGUI.getConfig("biliplus_cookie")
self.headers = {
"User-Agent": f"{__app_name__}/{__version__}",
"cookie": f"manga_pic_format=jpg-full;login=2;access_key={self.access_key}",
"cookie": f"manga_pic_format=jpg-full;manga_sharing=on;login=2;access_key={self.access_key}",
}

############################################################
Expand All @@ -51,13 +51,9 @@ def getEpisodesInfo(self) -> list[Episode]:
# ?###########################################################
# ? 解析 Biliplus 章节
biliplus_ep_list = self.data["ep_list"]
for episode in reversed(biliplus_ep_list):
for idx, episode in enumerate(reversed(biliplus_ep_list), start=1):
epi = BiliPlusEpisode(
episode,
self.headers,
self.comic_id,
self.data,
self.mainGUI,
episode, self.headers, self.comic_id, self.data, self.mainGUI, idx
)
self.episodes.append(epi)
if epi.isDownloaded():
Expand Down Expand Up @@ -97,7 +93,7 @@ def _(url: str) -> str | None:

try:
biliplus_html = _(biliplus_detail_url)
if None == biliplus_html:
if None is biliplus_html:
self.mainGUI.signal_message_box.emit(
"BiliPlus无法解析任何章节,可能有如下两种可能\n"
"1、您的BiliPlus Cookie无效,请更新您的BiliPlus Cookie\n"
Expand All @@ -123,7 +119,9 @@ def _(url: str) -> str | None:
total_ep = total_ep_element.contents[0].split("/")[1]
total_pages = int(int(total_ep) / 200) + 1
for pages in range(2, total_pages + 1):
self.mainGUI.signal_resolve_status.emit(f"正在解析漫画章节({pages}/{total_pages})...")
self.mainGUI.signal_resolve_status.emit(
f"正在解析漫画章节({pages}/{total_pages})..."
)
page_html = _(f"{biliplus_detail_url}&page={pages}")
document = BeautifulSoup(page_html, "html.parser")
ep_items = document.find_all("div", {"class": "episode-item"})
Expand Down Expand Up @@ -152,8 +150,9 @@ def __init__(
comic_id: str,
comic_info: dict,
mainGUI: MainGUI,
idx: int,
) -> None:
super().__init__(episode, comic_id, comic_info, mainGUI)
super().__init__(episode, comic_id, comic_info, mainGUI, idx)
self.headers = headers
self.comic_id = comic_id

Expand All @@ -180,7 +179,9 @@ def _() -> list[dict]:
timeout=TIMEOUT_SMALL,
)
except requests.RequestException as e:
logger.warning(f"《{self.comic_name}》章节:{self.title},从BiliPlus获取图片列表失败! 重试中...\n{e}")
logger.warning(
f"《{self.comic_name}》章节:{self.title},从BiliPlus获取图片列表失败! 重试中...\n{e}"
)
raise e
if res.status_code != 200:
logger.warning(
Expand All @@ -193,7 +194,9 @@ def _() -> list[dict]:
try:
biliplus_html = _()
except requests.RequestException as e:
logger.error(f"《{self.comic_name}》章节:{self.title} 从BiliPlus重复获取图片列表多次后失败!,跳过!\n{e}")
logger.error(
f"《{self.comic_name}》章节:{self.title} 从BiliPlus重复获取图片列表多次后失败!,跳过!\n{e}"
)
logger.exception(e)
self.mainGUI.signal_message_box.emit(
f"《{self.comic_name}》章节:{self.title} 从BiliPlus重复获取图片列表多次后失败!\n"
Expand All @@ -215,13 +218,17 @@ def _() -> list[dict]:
biliplus_imgs_token.append({"url": url, "token": token})
self.imgs_token = biliplus_imgs_token
if not biliplus_imgs_token:
logger.error(f"《{self.comic_name}》章节:{self.title} 在处理BiliPlus地址时因获取的Token无效导致失败!")
logger.error(
f"《{self.comic_name}》章节:{self.title} 在处理BiliPlus地址时因获取的Token无效导致失败!"
)
self.mainGUI.signal_message_box.emit(
f"《{self.comic_name}》章节:{self.title} 在处理BiliPlus解锁章节图片地址时因获取的Token无效导致失败!"
)
return False
except requests.RequestException as e:
logger.error(f"《{self.comic_name}》章节:{self.title} 在处理BiliPlus解锁章节图片地址时失败!\n{e}")
logger.error(
f"《{self.comic_name}》章节:{self.title} 在处理BiliPlus解锁章节图片地址时失败!\n{e}"
)
logger.exception(e)
self.mainGUI.signal_message_box.emit(
f"《{self.comic_name}》章节:{self.title} 在处理BiliPlus解锁章节图片地址时失败!\n\n"
Expand Down
29 changes: 21 additions & 8 deletions src/BiliQrCode.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ def __init__(self, mainGUI: MainGUI) -> None:
self.code_url = None
self.qrcode_key = None
self.close_flag = False
self.headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
"origin": "https://manga.bilibili.com",
}

def generate(self) -> str | None:
"""生成登入二维码
Expand All @@ -42,12 +46,14 @@ def generate(self) -> str | None:
@retry(stop_max_delay=MAX_RETRY_SMALL, wait_exponential_multiplier=RETRY_WAIT_EX)
def _() -> dict:
try:
res = requests.get(self.generate_url, timeout=TIMEOUT_SMALL)
res = requests.get(self.generate_url, headers=self.headers, timeout=TIMEOUT_SMALL)
except requests.RequestException as e:
logger.warning(f"获取登入二维码失败! 重试中...\n {e}")
raise e
if res.status_code != 200:
logger.warning(f"获取登入二维码失败! 状态码:{res.status_code}, 理由: {res.reason} 重试中...")
logger.warning(
f"获取登入二维码失败! 状态码:{res.status_code}, 理由: {res.reason} 重试中..."
)
raise requests.HTTPError()
return res.json()["data"]

Expand All @@ -57,11 +63,13 @@ def _() -> dict:
data = _()
self.code_url = data["url"]
self.qrcode_key = data["qrcode_key"]
except requests.RequestException as e:
except (requests.RequestException, requests.HTTPError) as e:
logger.error(f"重复获取登入二维码多次后失败! {e}")
logger.exception(e)
QMessageBox.warning(
self.mainGUI, "警告", "重复获取登入二维码多次后失败!\n请检查网络连接或者重启软件!\n\n更多详细信息请查看日志文件"
self.mainGUI,
"警告",
"重复获取登入二维码多次后失败!\n请检查网络连接或者重启软件!\n\n更多详细信息请查看日志文件",
)
return None

Expand All @@ -85,6 +93,7 @@ def _() -> dict:
try:
res = requests.get(
self.poll_url,
headers=self.headers,
params={
"qrcode_key": self.qrcode_key,
},
Expand All @@ -94,16 +103,20 @@ def _() -> dict:
logger.warning(f"确认二维码登入失败! 重试中...\n {e}")
raise e
if res.status_code != 200:
logger.warning(f"确认二维码登入失败! 状态码:{res.status_code}, 理由: {res.reason} 重试中...")
logger.warning(
f"确认二维码登入失败! 状态码:{res.status_code}, 理由: {res.reason} 重试中..."
)
raise requests.HTTPError()
return res.json()["data"]

try:
data = _()
except requests.RequestException as e:
except (requests.RequestException, requests.HTTPError) as e:
logger.error(f"重复确认登入多次后失败! {e}")
logger.exception(e)
QMessageBox.warning(self.mainGUI, "警告", "重复确认登入多次后失败!\n请检查网络连接或者重启软件!\n\n更多详细信息请查看日志文件")
self.mainGUI.signal_message_box.emit(
"重复确认登入多次后失败!\n请检查网络连接或者重启软件!\n\n更多详细信息请查看日志文件"
)
return None

return data
Expand All @@ -120,7 +133,7 @@ def get_cookie(self, qr_res: SignalInstance) -> None:
data = self.confirm()

# 扫码登录成功或者二维码过期或者请求失败
if data["code"] in [0, 86038] or data is None:
if data is None or data["code"] in [0, 86038]:
qr_res.emit(data)
break

Expand Down
20 changes: 14 additions & 6 deletions src/Comic.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ def _() -> dict:
# ? 解析漫画信息
self.data["title"] = myStrFilter(self.data["title"])
self.data["author_name"] = ",".join(self.data["author_name"])
self.data["author_name"] = self.data["author_name"].replace("作者:", "").replace("出品:", "")
self.data["author_name"] = (
self.data["author_name"].replace("作者:", "").replace("出品:", "")
)
self.data["author_name"] = myStrFilter(self.data["author_name"])
self.data["styles"] = ",".join(self.data["styles"])
if self.comic_id in self.mainGUI.my_library:
Expand All @@ -112,11 +114,15 @@ def _() -> bytes:
logger.warning(f"获取封面图片失败! 重试中...\n{e}")
raise e
if res.status_code != 200:
logger.warning(f"获取封面图片失败! 状态码:{res.status_code}, 理由: {res.reason} 重试中...")
logger.warning(
f"获取封面图片失败! 状态码:{res.status_code}, 理由: {res.reason} 重试中..."
)
raise requests.HTTPError()
isValid, md5 = isCheckSumValid(res.headers["Etag"], res.content)
if not isValid:
logger.warning(f"图片内容 Checksum 不正确! 重试中...\n\t{res.headers['Etag']}{md5}")
logger.warning(
f"图片内容 Checksum 不正确! 重试中...\n\t{res.headers['Etag']}{md5}"
)
raise requests.HTTPError()
return res.content

Expand All @@ -127,7 +133,9 @@ def _() -> bytes:
except RetryError as e:
logger.error(f"获取封面图片多次后失败,跳过!\n{e}")
self.mainGUI.signal_message_box.emit(
"获取封面图片多次后失败!\n" "请检查网络连接或者重启软件!\n\n" "更多详细信息请查看日志文件, 或联系开发者!"
"获取封面图片多次后失败!\n"
"请检查网络连接或者重启软件!\n\n"
"更多详细信息请查看日志文件, 或联系开发者!"
)
return open(":/imgs/fail_img.jpg", encoding="utf-8")

Expand All @@ -146,8 +154,8 @@ def getEpisodesInfo(self) -> list[Episode]:
# ?###########################################################
# ? 解析章节
ep_list = self.data["ep_list"]
for episode in reversed(ep_list):
epi = Episode(episode, self.comic_id, self.data, self.mainGUI)
for idx, episode in enumerate(reversed(ep_list), start=1):
epi = Episode(episode, self.comic_id, self.data, self.mainGUI, idx)
self.episodes.append(epi)
if epi.isDownloaded():
self.num_downloaded += 1
Expand Down

0 comments on commit fb8a296

Please sign in to comment.