From 747c5f69c6c08cc65481095068a65297e51cd1a3 Mon Sep 17 00:00:00 2001 From: Azalea <22280294+hykilpikonna@users.noreply.github.com> Date: Mon, 9 Mar 2026 00:52:03 -0400 Subject: [PATCH] [F] Fix bugs --- pyproject.toml | 1 + utils.py | 5 +++++ utils_qb.py | 28 ++++++++++++++++++++++++++-- uv.lock | 8 ++++++++ workflow.py | 21 +++++++++------------ 5 files changed, 49 insertions(+), 14 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7dcf923..f666e8e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,6 +5,7 @@ description = "Something to track your torrent trackers" readme = "README.md" requires-python = ">=3.12" dependencies = [ + "bencodepy>=0.9.5", "openai>=2.26.0", "playwright", "pyotp", diff --git a/utils.py b/utils.py index d8cd1df..7b1c753 100644 --- a/utils.py +++ b/utils.py @@ -33,6 +33,11 @@ def with_disk_cache(subdir_name: str): cache_p.parent.mkdir(parents=True, exist_ok=True) cache_p.write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding="utf-8") + + # Write arguments to a .txt file for easy lookup + txt_p = cache_p.with_suffix('.txt') + txt_p.write_text(f"Args: {args}\nKwargs: {kwargs}", encoding="utf-8") + return result return wrapper return decorator diff --git a/utils_qb.py b/utils_qb.py index 4625356..042cc46 100644 --- a/utils_qb.py +++ b/utils_qb.py @@ -1,4 +1,6 @@ import os +import hashlib +import bencodepy from qbittorrentapi import Client import tomllib from pathlib import Path @@ -25,8 +27,12 @@ def download_torrent(qb_client: Client, torrent_source: str, save_path: str) -> :return: Response from the API. """ if os.path.isfile(torrent_source): - # It's a local .torrent file - return qb_client.torrents_add(torrent_files=torrent_source, save_path=save_path) + # Open and read the bytes explicitly so that qb uploads the file data, + # negating local path security issues on the remote instance + with open(torrent_source, "rb") as f: + torrent_filename = os.path.basename(torrent_source) + # Pass dictionary mappings to `torrent_files` to upload binary streams directly + return qb_client.torrents_add(torrent_files={torrent_filename: f.read()}, save_path=save_path) else: # It's a magnet link or URL return qb_client.torrents_add(urls=torrent_source, save_path=save_path) @@ -57,3 +63,21 @@ def get_torrent_file_tree(qb_client: Client, torrent_hash: str) -> list: except Exception as e: print(f"Error fetching file tree for {torrent_hash}: {e}") return [] + +def get_torrent_hash(filepath: str) -> str: + """ + Parses a local .torrent file and computes its info hash directly. + """ + try: + with open(filepath, "rb") as f: + torrent_data = bencodepy.decode(f.read()) + + # Info dictionary is under b"info" + info_data = torrent_data[b"info"] + info_encoded = bencodepy.encode(info_data) + + # Calculate SHA1 hash of the bencoded info dictionary + return hashlib.sha1(info_encoded).hexdigest() + except Exception as e: + print(f"Could not parse torrent hash from {filepath}: {e}") + return "" diff --git a/uv.lock b/uv.lock index 718a654..f12e698 100644 --- a/uv.lock +++ b/uv.lock @@ -24,6 +24,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, ] +[[package]] +name = "bencodepy" +version = "0.9.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/72/e2ee9f8a93c92af1ba2d7ef903fd653ef397564ef7715c6ab3eb462f6e29/bencodepy-0.9.5.zip", hash = "sha256:af472134d73ea58edab3c2cb2f2cf61eb9d783908284c3d2d5b1cfd38df864b8", size = 3598, upload-time = "2015-10-16T21:30:09.066Z" } + [[package]] name = "certifi" version = "2025.11.12" @@ -470,6 +476,7 @@ name = "trackertracker" version = "0.1.0" source = { virtual = "." } dependencies = [ + { name = "bencodepy" }, { name = "openai" }, { name = "playwright" }, { name = "pyotp" }, @@ -478,6 +485,7 @@ dependencies = [ [package.metadata] requires-dist = [ + { name = "bencodepy", specifier = ">=0.9.5" }, { name = "openai", specifier = ">=2.26.0" }, { name = "playwright" }, { name = "pyotp" }, diff --git a/workflow.py b/workflow.py index 7f5dde4..b3eac20 100644 --- a/workflow.py +++ b/workflow.py @@ -11,7 +11,8 @@ from utils_mteam import ( from utils_qb import ( get_qb_client, download_torrent, - get_torrent_file_tree + get_torrent_file_tree, + get_torrent_hash ) from utils_ai import ( @@ -94,21 +95,17 @@ def process_imdb_workflow(imdb_id: str, dl_dir: str = "/data/qb", jellyfin_dir: print(f"\n=== [4] Adding torrent to qBittorrent ===") download_torrent(qb, torrent_path, dl_dir) + # Parse local hash directly instead of hoping qB orders correctly + t_hash = get_torrent_hash(torrent_path) + if not t_hash: + print(f"Could not compute hash for {torrent_path}, skipping!") + continue + print(f"\n=== [5] Waiting for download to finish ===") # Wait slightly for qB to process the adding request time.sleep(3) - # Best effort to grab the hash of the torrent we just added - # (Assuming it's the most recently added sorted descending) - recent_torrents = qb.torrents_info(sort="added_on", reverse=True) - if not recent_torrents: - print("Could not find any torrents in qB!") - continue - - target_torrent = recent_torrents[0] - t_hash = target_torrent.hash - t_name = target_torrent.name - print(f"Tracking torrent: {t_name} (Hash: {t_hash})") + print(f"Tracking torrent Hash: {t_hash}") while True: info = qb.torrents_info(hashes=t_hash)