mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-07 00:16:57 +08:00
fix: enhance error handling and logging for subtitle download process
This commit is contained in:
+94
-22
@@ -72,6 +72,29 @@ class DownloadChain(ChainBase):
|
|||||||
"""
|
"""
|
||||||
return Path(file_name).suffix.lower() in settings.RMT_SUBEXT
|
return Path(file_name).suffix.lower() in settings.RMT_SUBEXT
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _get_subtitle_working_dir(
|
||||||
|
cls,
|
||||||
|
storage_chain: StorageChain,
|
||||||
|
storage: str,
|
||||||
|
target_path: Path,
|
||||||
|
) -> Tuple[Optional[schemas.FileItem], str]:
|
||||||
|
"""
|
||||||
|
获取字幕保存目录,返回失败原因供前端展示。
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
working_dir_item = storage_chain.get_folder(storage, target_path)
|
||||||
|
except Exception as err:
|
||||||
|
message = f"下载目录获取失败,无法保存字幕:{target_path} - {str(err)}"
|
||||||
|
logger.error(message)
|
||||||
|
return None, message
|
||||||
|
|
||||||
|
if not working_dir_item:
|
||||||
|
message = f"下载目录不存在,无法保存字幕:{target_path}"
|
||||||
|
logger.error(message)
|
||||||
|
return None, message
|
||||||
|
return working_dir_item, ""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _detect_subtitle_fallback_name(subtitle: SubtitleInfo, content: bytes) -> str:
|
def _detect_subtitle_fallback_name(subtitle: SubtitleInfo, content: bytes) -> str:
|
||||||
"""
|
"""
|
||||||
@@ -115,26 +138,49 @@ class DownloadChain(ChainBase):
|
|||||||
storage: str,
|
storage: str,
|
||||||
working_dir_item: schemas.FileItem,
|
working_dir_item: schemas.FileItem,
|
||||||
subtitle_file: Path,
|
subtitle_file: Path,
|
||||||
) -> Optional[str]:
|
) -> Tuple[Optional[str], str]:
|
||||||
"""
|
"""
|
||||||
上传单个字幕文件到目标目录。
|
上传单个字幕文件到目标目录。
|
||||||
"""
|
"""
|
||||||
target_sub_file = Path(working_dir_item.path) / subtitle_file.name
|
target_sub_file = Path(working_dir_item.path) / subtitle_file.name
|
||||||
if storage_chain.get_file_item(storage, target_sub_file):
|
if storage_chain.get_file_item(storage, target_sub_file):
|
||||||
logger.info(f"字幕文件已存在:{target_sub_file}")
|
logger.info(f"字幕文件已存在:{target_sub_file}")
|
||||||
return target_sub_file.as_posix()
|
return target_sub_file.as_posix(), ""
|
||||||
logger.info(f"转移字幕 {subtitle_file} 到 {target_sub_file} ...")
|
logger.info(f"转移字幕 {subtitle_file} 到 {target_sub_file} ...")
|
||||||
uploaded = storage_chain.upload_file(working_dir_item, subtitle_file)
|
uploaded = storage_chain.upload_file(working_dir_item, subtitle_file)
|
||||||
if uploaded:
|
if uploaded:
|
||||||
return uploaded.path
|
return uploaded.path, ""
|
||||||
return None
|
message = f"保存字幕文件失败:{target_sub_file}"
|
||||||
|
logger.error(message)
|
||||||
|
return None, message
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _build_subtitle_download_error(response) -> str:
|
||||||
|
"""
|
||||||
|
从字幕下载响应中提取前端可展示的失败原因。
|
||||||
|
"""
|
||||||
|
status_code = getattr(response, "status_code", None)
|
||||||
|
reason = getattr(response, "reason", "") or ""
|
||||||
|
message = "下载字幕文件失败"
|
||||||
|
if status_code:
|
||||||
|
message = f"{message},状态码:{status_code}"
|
||||||
|
if reason:
|
||||||
|
message = f"{message} {reason}"
|
||||||
|
try:
|
||||||
|
response_text = (getattr(response, "text", "") or "").strip()
|
||||||
|
response_text = re.sub(r"\s+", " ", response_text)
|
||||||
|
if response_text:
|
||||||
|
message = f"{message}:{response_text[:200]}"
|
||||||
|
except Exception as err:
|
||||||
|
logger.debug(f"读取字幕下载失败响应内容失败:{str(err)}")
|
||||||
|
return message
|
||||||
|
|
||||||
def _save_subtitle_response(
|
def _save_subtitle_response(
|
||||||
self,
|
self,
|
||||||
subtitle: SubtitleInfo,
|
subtitle: SubtitleInfo,
|
||||||
response,
|
response,
|
||||||
target_dir: Path,
|
target_dir: Path,
|
||||||
) -> List[str]:
|
) -> Tuple[bool, str, List[str]]:
|
||||||
"""
|
"""
|
||||||
保存字幕下载响应到目标目录。
|
保存字幕下载响应到目标目录。
|
||||||
"""
|
"""
|
||||||
@@ -147,23 +193,27 @@ class DownloadChain(ChainBase):
|
|||||||
fallback_name=fallback_name,
|
fallback_name=fallback_name,
|
||||||
)
|
)
|
||||||
if not self._is_subtitle_archive(file_name) and not self._is_subtitle_file(file_name):
|
if not self._is_subtitle_archive(file_name) and not self._is_subtitle_file(file_name):
|
||||||
logger.warn(f"下载链接不是支持的字幕文件:{subtitle.enclosure} - {file_name}")
|
message = f"下载链接不是支持的字幕文件:{file_name}"
|
||||||
return []
|
logger.warn(f"{message},链接:{subtitle.enclosure}")
|
||||||
|
return False, message, []
|
||||||
|
|
||||||
file_uri = FileURI.from_uri(target_dir.as_posix())
|
file_uri = FileURI.from_uri(target_dir.as_posix())
|
||||||
storage = file_uri.storage
|
storage = file_uri.storage
|
||||||
target_path = Path(file_uri.path)
|
target_path = Path(file_uri.path)
|
||||||
storage_chain = StorageChain()
|
storage_chain = StorageChain()
|
||||||
working_dir_item = storage_chain.get_folder(storage, target_path)
|
working_dir_item, message = self._get_subtitle_working_dir(
|
||||||
|
storage_chain=storage_chain,
|
||||||
|
storage=storage,
|
||||||
|
target_path=target_path,
|
||||||
|
)
|
||||||
if not working_dir_item:
|
if not working_dir_item:
|
||||||
logger.error(f"下载目录不存在,无法保存字幕:{target_path}")
|
return False, message, []
|
||||||
return []
|
|
||||||
|
|
||||||
saved_files = []
|
saved_files = []
|
||||||
settings.TEMP_PATH.mkdir(parents=True, exist_ok=True)
|
|
||||||
temp_file = settings.TEMP_PATH / file_name
|
temp_file = settings.TEMP_PATH / file_name
|
||||||
temp_extract_dir = temp_file.with_name(temp_file.stem)
|
temp_extract_dir = temp_file.with_name(temp_file.stem)
|
||||||
try:
|
try:
|
||||||
|
settings.TEMP_PATH.mkdir(parents=True, exist_ok=True)
|
||||||
temp_file.write_bytes(response.content)
|
temp_file.write_bytes(response.content)
|
||||||
if self._is_subtitle_archive(file_name):
|
if self._is_subtitle_archive(file_name):
|
||||||
try:
|
try:
|
||||||
@@ -173,10 +223,11 @@ class DownloadChain(ChainBase):
|
|||||||
archive_format=self._subtitle_archive_format(file_name),
|
archive_format=self._subtitle_archive_format(file_name),
|
||||||
)
|
)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"字幕压缩包解压失败:{temp_file} - {str(err)}")
|
message = f"字幕压缩包解压失败:{str(err)}"
|
||||||
return []
|
logger.error(f"{message},文件:{temp_file}")
|
||||||
|
return False, message, []
|
||||||
for sub_file in SystemUtils.list_files(temp_extract_dir, settings.RMT_SUBEXT):
|
for sub_file in SystemUtils.list_files(temp_extract_dir, settings.RMT_SUBEXT):
|
||||||
uploaded_path = self._upload_subtitle_file(
|
uploaded_path, message = self._upload_subtitle_file(
|
||||||
storage_chain=storage_chain,
|
storage_chain=storage_chain,
|
||||||
storage=storage,
|
storage=storage,
|
||||||
working_dir_item=working_dir_item,
|
working_dir_item=working_dir_item,
|
||||||
@@ -184,8 +235,10 @@ class DownloadChain(ChainBase):
|
|||||||
)
|
)
|
||||||
if uploaded_path:
|
if uploaded_path:
|
||||||
saved_files.append(uploaded_path)
|
saved_files.append(uploaded_path)
|
||||||
|
elif message:
|
||||||
|
logger.error(message)
|
||||||
else:
|
else:
|
||||||
uploaded_path = self._upload_subtitle_file(
|
uploaded_path, message = self._upload_subtitle_file(
|
||||||
storage_chain=storage_chain,
|
storage_chain=storage_chain,
|
||||||
storage=storage,
|
storage=storage,
|
||||||
working_dir_item=working_dir_item,
|
working_dir_item=working_dir_item,
|
||||||
@@ -193,7 +246,17 @@ class DownloadChain(ChainBase):
|
|||||||
)
|
)
|
||||||
if uploaded_path:
|
if uploaded_path:
|
||||||
saved_files.append(uploaded_path)
|
saved_files.append(uploaded_path)
|
||||||
return saved_files
|
elif message:
|
||||||
|
return False, message, []
|
||||||
|
if not saved_files:
|
||||||
|
message = "未保存任何字幕文件"
|
||||||
|
logger.error(message)
|
||||||
|
return False, message, []
|
||||||
|
return True, "字幕文件保存成功", saved_files
|
||||||
|
except Exception as err:
|
||||||
|
message = f"保存字幕文件失败:{str(err)}"
|
||||||
|
logger.error(message)
|
||||||
|
return False, message, []
|
||||||
finally:
|
finally:
|
||||||
try:
|
try:
|
||||||
if temp_extract_dir.exists():
|
if temp_extract_dir.exists():
|
||||||
@@ -245,17 +308,26 @@ class DownloadChain(ChainBase):
|
|||||||
ua=subtitle.site_ua or settings.USER_AGENT,
|
ua=subtitle.site_ua or settings.USER_AGENT,
|
||||||
proxies=settings.PROXY if subtitle.site_proxy else None,
|
proxies=settings.PROXY if subtitle.site_proxy else None,
|
||||||
)
|
)
|
||||||
response = request.get_res(subtitle.enclosure)
|
try:
|
||||||
if not response or response.status_code != 200:
|
response = request.get_res(subtitle.enclosure, raise_exception=True)
|
||||||
return False, "下载字幕文件失败", []
|
except Exception as err:
|
||||||
|
message = f"下载字幕文件失败:{str(err)}"
|
||||||
|
logger.error(message)
|
||||||
|
return False, message, []
|
||||||
|
if response is None:
|
||||||
|
return False, "下载字幕文件失败:未收到站点响应", []
|
||||||
|
if response.status_code != 200:
|
||||||
|
message = self._build_subtitle_download_error(response)
|
||||||
|
logger.error(message)
|
||||||
|
return False, message, []
|
||||||
|
|
||||||
saved_files = self._save_subtitle_response(
|
success, message, saved_files = self._save_subtitle_response(
|
||||||
subtitle=subtitle,
|
subtitle=subtitle,
|
||||||
response=response,
|
response=response,
|
||||||
target_dir=target_dir,
|
target_dir=target_dir,
|
||||||
)
|
)
|
||||||
if not saved_files:
|
if not success:
|
||||||
return False, "未保存任何字幕文件", []
|
return False, message, []
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"{mediainfo.title_year} 字幕下载完成:{subtitle.site_name} - {subtitle.title},用户:{username}"
|
f"{mediainfo.title_year} 字幕下载完成:{subtitle.site_name} - {subtitle.title},用户:{username}"
|
||||||
|
|||||||
Reference in New Issue
Block a user