diff --git a/pytorrent/services/rtorrent/files.py b/pytorrent/services/rtorrent/files.py index 8653c97..4315880 100644 --- a/pytorrent/services/rtorrent/files.py +++ b/pytorrent/services/rtorrent/files.py @@ -1,6 +1,7 @@ from __future__ import annotations from .client import * +from ...config import BASE_DIR def torrent_files(profile: dict, torrent_hash: str) -> list[dict]: rows = client_for(profile).f.multicall(torrent_hash, "", "f.path=", "f.size_bytes=", "f.completed_chunks=", "f.size_chunks=", "f.priority=") @@ -131,6 +132,7 @@ _MEDIA_INFO_EXTENSIONS = { } _MEDIA_INFO_SAMPLE_BYTES = 32 * 1024 * 1024 _MEDIA_INFO_CHUNK_BYTES = 1024 * 1024 +_MEDIA_INFO_TMP_DIR = BASE_DIR / "data" / "media-info-samples" def _media_info_supported(path: str) -> bool: @@ -138,11 +140,23 @@ def _media_info_supported(path: str) -> bool: return LocalPath(str(path or "")).suffix.lower() in _MEDIA_INFO_EXTENSIONS +def _media_info_sample_suffix(source_path: str) -> str: + suffix = LocalPath(str(source_path or "")).suffix.lower() + if suffix and len(suffix) <= 16 and all(ch.isalnum() or ch in ".-_" for ch in suffix): + return suffix + return ".bin" + + def _media_info_temp_sample(profile: dict, source_path: str, max_bytes: int) -> tuple[str, int]: - # Note: hachoir needs a seekable file, so this writes a bounded sample to disk instead of loading whole media into RAM. + # Note: hachoir needs a seekable file, so this writes a bounded sample into the app data directory instead of loading whole media into RAM. import tempfile - fd, tmp_path = tempfile.mkstemp(prefix="pytorrent-mediainfo-", suffix=LocalPath(source_path).suffix) + _MEDIA_INFO_TMP_DIR.mkdir(parents=True, exist_ok=True) + fd, tmp_path = tempfile.mkstemp( + prefix="pytorrent-mediainfo-", + suffix=_media_info_sample_suffix(source_path), + dir=str(_MEDIA_INFO_TMP_DIR), + ) written = 0 try: with os.fdopen(fd, "wb") as tmp: @@ -283,7 +297,8 @@ def torrent_file_media_info(profile: dict, torrent_hash: str, index: int, max_by tmp_path = None try: tmp_path, written = _media_info_temp_sample(profile, remote_path, max(1024 * 1024, int(max_bytes))) - parser = createParser(tmp_path, real_filename=LocalPath(name).name) + # Note: Do not pass real_filename here; some hachoir versions treat it as an input path and fail for nested torrent file names. + parser = createParser(tmp_path) if parser is None: result.update({"sample_bytes": written, "error": "hachoir could not detect this media container."}) return result