Skip to content

Commit

Permalink
Merge pull request #72 from Zeal-L/develop
Browse files Browse the repository at this point in the history
新增漫画ID直搜功能,动态修改保存格式
  • Loading branch information
Zeal-L authored Aug 29, 2023
2 parents 3232223 + 8e904bb commit 3ff5d65
Show file tree
Hide file tree
Showing 15 changed files with 420 additions and 210 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ body:
id: version
attributes:
label: 哔哩哔哩漫画下载器版本号
placeholder: v1.3.0
placeholder: v1.3.2
validations:
required: true
- type: dropdown
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

## ✨ 主要功能 / 特性
- **黑科技下载未解锁章节!**
- **支持已购被下架漫画下载**
- **已打包成单个可执行文件,双击即用!**
- **易操作的图形界面!~~(不用再费劲的部署环境跑命令行)~~**
- **无需漫画ID,可直接关键词搜索漫画!并附带搜索词高亮!**
Expand Down Expand Up @@ -78,6 +79,7 @@
- **值得注意的是:本软件不支持断点续传和下载任务缓存的功能 ~~(毕竟一章漫画太小了,好像也没什么必要,断了不如重下)~~,所以请确保不要在下载中途关闭!**
- **程序缓存和日志历史文件存在 `C:\Users\AppData\Roaming\BiliBili-Manga-Downloader\` 目录下,可以通过"清空用户数据"功能一键删除**
- **如果想用"本地库存"功能,需要注意的是:下载好的漫画章节名以及保存的 `元数据.json` 都不能更改,否则将会无法正确读取漫画数据**
- **已购被下架的漫画虽然不能通过关键词搜索到,但是可以通过漫画ID直接访问,如果你购买过那么就可以成功下载**


## 💕 友情推荐
Expand Down
13 changes: 13 additions & 0 deletions UPDATE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
## ⚰️ 更新记录

### **[v1.3.2](https://github.com/Zeal-L/BiliBili-Manga-Downloader/releases/tag/v1.3.2)** - *2022-08-30*
- 新增功能:
- 新增漫画ID直搜功能,以支持下载已经下架的漫画 ([#30][i30])
- 修复bug:
- 修复了一个可能会导致下载完成后下载列表显示错误的bug
- 修复了一个下载失败后任务未能正确移除的bug
- 优化设置:
- 保存格式现在可以动态修改了
- 为了避免总进度条频繁回退,改为包括已经完成的任务

[i30]: https://github.com/Zeal-L/BiliBili-Manga-Downloader/issues/30

### **[v1.3.1](https://github.com/Zeal-L/BiliBili-Manga-Downloader/releases/tag/v1.3.1)** - *2022-08-25*
- 修复bug:
- 修复了一个在保存格式为 `pdf` 时导致内存泄漏的bug ([#68][i68])
Expand Down
8 changes: 3 additions & 5 deletions src/BiliPlus.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ def getEpisodesInfo(self) -> list[Episode]:
for episode in reversed(biliplus_ep_list):
epi = BiliPlusEpisode(
episode,
self.sessdata,
self.headers,
self.comic_id,
self.data,
Expand All @@ -71,7 +70,7 @@ def retrieveAvailableEpisode(self, episodes: list[BiliPlusEpisode], comic_id: st
@retry(
stop_max_delay=MAX_RETRY_SMALL, wait_exponential_multiplier=RETRY_WAIT_EX
)
def _(url: str = biliplus_detail_url) -> dict:
def _(url: str) -> dict:
try:
res = requests.post(
url,
Expand All @@ -92,7 +91,7 @@ def _(url: str = biliplus_detail_url) -> dict:
return res.text

try:
biliplus_html = _()
biliplus_html = _(biliplus_detail_url)
except requests.RequestException as e:
logger.error(f"漫画id:{self.comic_id} 在BiliPlus重复获取漫画信息多次后失败!\n{e}")
logger.exception(e)
Expand Down Expand Up @@ -138,13 +137,12 @@ class BiliPlusEpisode(Episode):
def __init__(
self,
episode: dict,
sessData: str,
headers: str,
comic_id: str,
comic_info: dict,
mainGUI: MainGUI,
) -> None:
super().__init__(episode, sessData, comic_id, comic_info, mainGUI)
super().__init__(episode, comic_id, comic_info, mainGUI)
self.headers = headers
self.comic_id = comic_id

Expand Down
9 changes: 4 additions & 5 deletions src/Comic.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ class Comic:
def __init__(self, comic_id: int, mainGUI: MainGUI) -> None:
self.mainGUI = mainGUI
self.comic_id = comic_id
self.sessdata = mainGUI.getConfig("cookie")
self.save_path = mainGUI.getConfig("save_path")
self.num_thread = mainGUI.getConfig("num_thread")
self.num_downloaded = 0
Expand All @@ -40,7 +39,7 @@ def __init__(self, comic_id: int, mainGUI: MainGUI) -> None:
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36",
"origin": "https://manga.bilibili.com",
"referer": f"https://manga.bilibili.com/detail/mc{comic_id}?from=manga_homepage",
"cookie": f"SESSDATA={self.sessdata}",
"cookie": f"SESSDATA={mainGUI.getConfig('cookie')}",
}
self.payload = {"comic_id": self.comic_id}

Expand All @@ -53,15 +52,15 @@ def getComicInfo(self) -> dict:
"""

@retry(
stop_max_delay=MAX_RETRY_SMALL, wait_exponential_multiplier=RETRY_WAIT_EX
stop_max_delay=MAX_RETRY_SMALL-5000, wait_exponential_multiplier=RETRY_WAIT_EX
)
def _() -> dict:
try:
res = requests.post(
self.detail_url,
headers=self.headers,
data=self.payload,
timeout=TIMEOUT_SMALL,
timeout=TIMEOUT_SMALL-3,
)
except requests.RequestException as e:
logger.warning(f"漫画id:{self.comic_id} 获取漫画信息失败! 重试中...\n{e}")
Expand Down Expand Up @@ -156,7 +155,7 @@ def getEpisodesInfo(self) -> list[Episode]:
ep_list = self.data["ep_list"]
for episode in reversed(ep_list):
epi = Episode(
episode, self.sessdata, self.comic_id, self.data, self.mainGUI
episode, self.comic_id, self.data, self.mainGUI
)
self.episodes.append(epi)
if epi.isDownloaded():
Expand Down
30 changes: 14 additions & 16 deletions src/DownloadManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@ class DownloadManager:
def __init__(
self,
max_workers: int,
save_method: str,
signal_rate_progress: SignalInstance,
signal_message_box: SignalInstance,
) -> None:
self.id_count = 0
self.save_method = save_method
self.executor = ThreadPoolExecutor(max_workers=max_workers)
self.signal_rate_progress = signal_rate_progress
self.signal_message_box = signal_message_box
Expand Down Expand Up @@ -167,26 +165,16 @@ def __thread__EpisodeTask(self, curr_id: int, epi: Episode) -> None:

# ?###########################################################
# ? 保存图片
save_path = None
if rate == 1:
if self.save_method == "PDF":
epi.saveToPDF(imgs_path)
elif self.save_method == "文件夹-图片":
epi.saveToFolder(imgs_path)
elif self.save_method == "7z压缩包":
epi.saveTo7z(imgs_path)

save_path = epi.save(imgs_path)
epi.clearAfterSave(imgs_path)

self.updateTaskInfo(curr_id, rate)
self.signal_rate_progress.emit(
{
"taskID": curr_id,
"rate": int(rate * 100),
}
{"taskID": curr_id, "rate": int(rate * 100), "path": save_path}
)

self.clearAfterFinish(curr_id)

############################################################
# ? 为以后的特典下载留的接口

Expand All @@ -198,7 +186,7 @@ def __thread__EpisodeTask(self, curr_id: int, epi: Episode) -> None:

############################################################

def clearAfterFinish(self, curr_id) -> None:
def clearAfterFinish(self, curr_id: int) -> None:
"""任务完成后的清理工作
Args:
Expand All @@ -208,6 +196,16 @@ def clearAfterFinish(self, curr_id) -> None:

############################################################

def clearAll(self) -> None:
"""任务完成后的清理工作
Args:
curr_id (int): 当前任务的ID
"""
self.all_tasks.clear()

############################################################

def reportError(self, curr_id: int) -> None:
"""任务出错时的处理
Expand Down
69 changes: 42 additions & 27 deletions src/Episode.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ class Episode:
def __init__(
self,
episode: dict,
sessData: str,
comic_id: str,
comic_info: dict,
mainGUI: MainGUI,
Expand Down Expand Up @@ -86,20 +85,10 @@ def __init__(
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36",
"origin": "https://manga.bilibili.com",
"referer": f"https://manga.bilibili.com/detail/mc{comic_id}/{self.id}?from=manga_homepage",
"cookie": f"SESSDATA={sessData}",
"cookie": f"SESSDATA={mainGUI.getConfig('cookie')}",
}
self.save_path = comic_info["save_path"]
self.save_method = mainGUI.getConfig("save_method")
self.epi_path_pdf = os.path.join(self.save_path, f"{self.title}.pdf")
self.epi_path_folder = os.path.join(self.save_path, f"{self.title}")
self.epi_path_7z = os.path.join(self.save_path, f"{self.title}.7z")

if self.save_method == "PDF":
self.epi_path = self.epi_path_pdf
elif self.save_method == "文件夹-图片":
self.epi_path = self.epi_path_folder
elif self.save_method == "7z压缩包":
self.epi_path = self.epi_path_7z
self.epi_path = os.path.join(self.save_path, f"{self.title}")

############################################################
def init_imgsList(self) -> bool:
Expand Down Expand Up @@ -225,6 +214,30 @@ def _() -> None:
f"《{self.comic_name}》章节:{self.title} 删除临时图片多次后失败!\n请手动删除!\n\n更多详细信息请查看日志文件, 或联系开发者!"
)

############################################################

def save(self, imgs_path: list[str]) -> str:
"""保存章节
Args:
imgs_path (list): 临时图片路径列表
Returns:
str: 保存路径
"""
save_method = self.mainGUI.getConfig("save_method")
save_path = ""
if save_method == "PDF":
self.saveToPDF(imgs_path)
save_path = f"{self.epi_path}.pdf"
elif save_method == "文件夹-图片":
self.saveToFolder(imgs_path)
save_path = self.epi_path
elif save_method == "7z压缩包":
self.saveTo7z(imgs_path)
save_path = f"{self.epi_path}.7z"
return save_path

############################################################
def saveToPDF(self, imgs_path: list[str]) -> None:
"""将图片保存为PDF文件
Expand All @@ -234,7 +247,7 @@ def saveToPDF(self, imgs_path: list[str]) -> None:
"""

@retry(stop_max_attempt_number=5)
def _():
def _() -> None:
try:
# 因为pdf的兼容性, 统一转换为RGB模式
temp_imgs = [Image.open(x) for x in imgs_path]
Expand All @@ -243,7 +256,7 @@ def _():
temp_imgs[i] = img.convert("RGB")

temp_imgs[0].save(
self.epi_path_pdf,
f"{self.epi_path}.pdf",
save_all=True,
append_images=temp_imgs[1:],
quality=95,
Expand All @@ -254,7 +267,7 @@ def _():
img.close()

# 在pdf文件属性中记录章节标题作者和软件版本以及版权信息
with open(self.epi_path_pdf, "rb") as f:
with open(f"{self.epi_path}.pdf", "rb") as f:
pdf = PdfReader(f)
pdf_writer = PdfWriter()
pdf_writer.append_pages_from_reader(pdf)
Expand All @@ -265,7 +278,7 @@ def _():
"/Creator": f"{__app_name__} {__version__} {__copyright__}",
}
)
with open(self.epi_path_pdf, "wb") as f:
with open(f"{self.epi_path}.pdf", "wb") as f:
pdf_writer.write(f)

except OSError as e:
Expand Down Expand Up @@ -318,14 +331,16 @@ def jpg_exif(img_path: str):
if img_format == "jpg":
jpg_exif(img_path)
except piexif.InvalidImageDataError as e:
logger.warning(f"Failed to insert exif data for {img_path}: {e}")
logger.warning(
f"Failed to insert exif data for {img_path}: {e}"
)
logger.exception(e)

# 复制图片到文件夹
shutil.copy2(
img_path,
os.path.join(
self.epi_path_folder, f"{str(index).zfill(3)}.{img_format}"
self.epi_path, f"{str(index).zfill(3)}.{img_format}"
),
)

Expand All @@ -336,8 +351,8 @@ def jpg_exif(img_path: str):
raise e

try:
if not os.path.exists(self.epi_path_folder):
os.makedirs(self.epi_path_folder)
if not os.path.exists(self.epi_path):
os.makedirs(self.epi_path)
_()
except OSError as e:
logger.error(f"《{self.comic_name}》章节:{self.title} 保存图片到文件夹多次后失败!\n{e}")
Expand All @@ -359,15 +374,15 @@ def saveTo7z(self, imgs_path: list[str]) -> None:
@retry(stop_max_attempt_number=5)
def _():
try:
with SevenZipFile(f"{self.epi_path_7z}", "w") as z:
with SevenZipFile(f"{self.epi_path}.7z", "w") as z:
# 压缩文件里不要子目录,全部存在根目录
for root, _dirs, files in os.walk(self.epi_path_folder):
for root, _dirs, files in os.walk(self.epi_path):
for file in files:
z.write(
os.path.join(root, file),
os.path.basename(os.path.join(root, file)),
)
shutil.rmtree(self.epi_path_folder)
shutil.rmtree(self.epi_path)
except OSError as e:
logger.error(
f"《{self.comic_name}》章节:{self.title} 保存图片到7z失败! 重试中...\n{e}"
Expand Down Expand Up @@ -486,7 +501,7 @@ def isDownloaded(self) -> bool:
bool: True: 已下载; False: 未下载
"""
return (
os.path.exists(self.epi_path_pdf)
or os.path.exists(self.epi_path_folder)
or os.path.exists(self.epi_path_7z)
os.path.exists(self.epi_path)
or os.path.exists(f"{self.epi_path}.pdf")
or os.path.exists(f"{self.epi_path}.7z")
)
2 changes: 1 addition & 1 deletion src/Utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from ui.MainGUI import MainGUI

__app_name__ = "BiliBili-Manga-Downloader"
__version__ = "1.3.1"
__version__ = "1.3.2"
__author__ = "Zeal L"
__copyright__ = "Copyright (C) 2023 Zeal L"

Expand Down
Loading

0 comments on commit 3ff5d65

Please sign in to comment.