This commit is contained in:
caiwx86 2025-07-11 15:12:15 +08:00
parent 1d47c245e3
commit e1059cc262
4 changed files with 86 additions and 8 deletions

6
run.py
View File

@ -6,12 +6,12 @@ logger = setup_logging(__name__)
async def main(): async def main():
# 配置下载参数 # 配置下载参数
#manga_url = "https://rouman5.com/books/cm693tf2z0170dr07ve0hpa7s" # manga_url = "https://rouman5.com/books/4355ff5c-98d7-45c0-95a9-b4023b8eb812"
manga_list_url = "https://rouman5.com/books?continued=undefined" manga_list_url = "https://rouman5.com/books?continued=undefined"
# 开始下载 # 开始下载
#await MangaManager().download_manga(manga_url) # await MangaManager().download_manga(manga_url)
for i in range(0,77): for i in range(0,80):
await MangaManager().download_list_manga(f"{manga_list_url}&page={i}") await MangaManager().download_list_manga(f"{manga_list_url}&page={i}")
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -479,7 +479,7 @@ class ComicInfoXml:
raise ValueError("请提供 cbz_path 或 xml_file 参数, 否则无法处理 XML 文件") raise ValueError("请提供 cbz_path 或 xml_file 参数, 否则无法处理 XML 文件")
return xml_parse(xml_content) return xml_parse(xml_content)
def update_comicinfo_count(self, count, cbz_path: Path) -> Path: def update_comicinfo_count_or_number(self, cbz_path: Path, count = -1, number = -1) -> Path:
""" 更新 ComicInfo.xml 中的 PageCount 字段 """ 更新 ComicInfo.xml 中的 PageCount 字段
Args: Args:
cbz_path (Path): CBZ 文件路径 cbz_path (Path): CBZ 文件路径
@ -490,7 +490,10 @@ class ComicInfoXml:
""" """
# 读取 ComicInfo.xml 文件 # 读取 ComicInfo.xml 文件
comicinfo = self._xml_file_to_comicinfo(cbz_path=cbz_path) comicinfo = self._xml_file_to_comicinfo(cbz_path=cbz_path)
comicinfo.Count = count if count != -1:
comicinfo.Count = count
if number != -1:
comicinfo.Number = number
# 保存更新后的 ComicInfo.xml 文件 # 保存更新后的 ComicInfo.xml 文件
return self._parse_comicinfo(comicinfo, save_dir=os.path.dirname(cbz_path)) return self._parse_comicinfo(comicinfo, save_dir=os.path.dirname(cbz_path))

View File

@ -875,4 +875,70 @@ class MangaUtils:
] ]
if len(self.data) != original_count: if len(self.data) != original_count:
self._build_index() self._build_index()
self._save_data() self._save_data()
class KomgaAPI():
import requests
from requests.auth import HTTPBasicAuth
# 配置信息
KOMGA_URL = "https://komga.caiwenxiu.cn" # 替换为你的Komga地址
USERNAME = "caiwenxiu0806@163.com" # 管理员邮箱
PASSWORD = "cwx@komga"
def search_series_id(self, search_name):
"""
搜索漫画系列
:param search_name: 漫画名称
:return: 返回搜索结果
"""
response = self.requests.get(
f"{self.KOMGA_URL}/api/v1/series",
params={"search": search_name},
auth=self.HTTPBasicAuth(self.USERNAME, self.PASSWORD)
)
# 解析结果
if response.status_code == 200:
series_list = response.json()["content"]
for series in series_list:
if series['metadata']['title'] == search_name:
# 输出匹配的漫画信息
print(f"找到漫画: {series['metadata']['title']}, ID: {series['id']}")
return series['id']
break
print(f"类似标题: {series['metadata']['title']}, ID: {series['id']}")
else:
print(f"搜索失败: {response.status_code}")
def update_series_status(self, series_id, status):
"""更新漫画系列状态"""
# 构建 API 端点
endpoint = f"{self.KOMGA_URL}/api/v1/series/{series_id}/metadata"
# 准备请求数据
payload = {
"status": status
}
# 发送 PATCH 请求
response = self.requests.patch(
endpoint,
json=payload,
auth=self.HTTPBasicAuth(self.USERNAME, self.PASSWORD),
headers={"Content-Type": "application/json"}
)
# 检查响应
if response.status_code == 200 or 204:
print(f"成功将系列 {series_id} 状态更新为 '{status}'")
return True
else:
print(f"更新失败: {response.status_code} - {response.text}")
return False
def update_series_ended(self, series_name, series_status="ENDED"):
series_id = self.search_series_id(series_name)
"""将漫画系列状态更新为已完结"""
return self.update_series_status(series_id, series_status)

View File

@ -82,7 +82,6 @@ class BaseSite(ABC):
#async def get_chapter_list(self, info: MangaInfo) -> List[Dict[str, str]]: #async def get_chapter_list(self, info: MangaInfo) -> List[Dict[str, str]]:
# """获取漫画章节列表""" # """获取漫画章节列表"""
# pass # pass
async def get_chapter_list(self, manga_info: MangaInfo) -> List[Dict[str, str]]: async def get_chapter_list(self, manga_info: MangaInfo) -> List[Dict[str, str]]:
"""获取章节列表""" """获取章节列表"""
try: try:
@ -93,6 +92,7 @@ class BaseSite(ABC):
last_chapter = list_chapter[-1] if list_chapter else [] last_chapter = list_chapter[-1] if list_chapter else []
# 临时添加end # 临时添加end
down_chapter = [] down_chapter = []
downloaded_chapter = []
for chapter in list_chapter: for chapter in list_chapter:
cbz_path = FileNaming.chapter_cbz(manga_info=manga_info,chapter=chapter) cbz_path = FileNaming.chapter_cbz(manga_info=manga_info,chapter=chapter)
if os.path.exists(cbz_path): if os.path.exists(cbz_path):
@ -102,7 +102,7 @@ class BaseSite(ABC):
ci = ComicInfoXml()._xml_file_to_comicinfo(cbz_path=cbz_path) ci = ComicInfoXml()._xml_file_to_comicinfo(cbz_path=cbz_path)
if ci.Count == "": if ci.Count == "":
# 生成ComicInfo.xml # 生成ComicInfo.xml
xml_path = ComicInfoXml().update_comicinfo_count(count=len(list_chapter), cbz_path=cbz_path) xml_path = ComicInfoXml().update_comicinfo_count_or_number(cbz_path=cbz_path, count=len(list_chapter))
# 更新ComicInfo.xml至CBZ文件中 # 更新ComicInfo.xml至CBZ文件中
CBZUtils().update_cbz_with_new_xml(cbz_path, xml_path.read_text(encoding="utf-8")) CBZUtils().update_cbz_with_new_xml(cbz_path, xml_path.read_text(encoding="utf-8"))
# 更新完成后删除临时生成的ComicInfo.xml # 更新完成后删除临时生成的ComicInfo.xml
@ -111,7 +111,16 @@ class BaseSite(ABC):
# 临时添加end # 临时添加end
logger.debug(f"{chapter.title} 章节已存在") logger.debug(f"{chapter.title} 章节已存在")
chapter.status = "downloaded" chapter.status = "downloaded"
downloaded_chapter.append({ "name" : chapter.title, "status": chapter.status, "path" : cbz_path })
down_chapter.append(chapter) down_chapter.append(chapter)
if manga_info.status == "已完结":
from src.common.utils import KomgaAPI
if len(downloaded_chapter) == len(list_chapter):
logger.info(f"{manga_info.title} 漫画已完结, 章节已全部下载完成")
KomgaAPI().update_series_ended(manga_info.title)
logger.info(f"{manga_info.title} 漫画已完结, 已更新KOMGA状态")
else:
logger.info(f"{manga_info.title} 漫画已完结, 但章节未全部下载完成, 可能是网络问题或其他原因")
return down_chapter return down_chapter
except Exception as e: except Exception as e:
if isinstance(e, (ParseError, SiteError)): if isinstance(e, (ParseError, SiteError)):