From 56496b0ea1cb38844c15b63572b827289170130b Mon Sep 17 00:00:00 2001 From: bobokun Date: Fri, 6 Sep 2024 09:02:59 -0400 Subject: [PATCH 1/7] 4.1.9 --- CHANGELOG | 18 +++------------- VERSION | 2 +- modules/util.py | 4 +--- scripts/edit_passkey.py | 47 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 19 deletions(-) create mode 100644 scripts/edit_passkey.py diff --git a/CHANGELOG b/CHANGELOG index c2bdb4a6..b61f94f6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,16 +1,4 @@ -# Requirements Updated -- qbittorrent-api==2024.8.65 -- croniter==3.0.3 -- humanize==4.10.0 - -# New Updates -- Adds `force_auto_tmm_ignore_tags` feature to ignore tags when force_auto_tmm is enabled (#634) - # Bug Fixes -- Fixes Print the schedule and delay before starting the sleep (Closes [#605](https://github.com/StuffAnThings/qbit_manage/issues/605)) -- Fixes noHL counting symlinks as part of its logic (Closes [#608](https://github.com/StuffAnThings/qbit_manage/issues/608)) -- Fix typos in documentation (#627) -- Extended logging to explain why torrent files were not deleted (#625) - -Special thanks to @ineednewpajamas, @glicholas, @Minituff, @Dark3clipse, @TJZine for their contributions! -**Full Changelog**: https://github.com/StuffAnThings/qbit_manage/compare/v4.1.7...v4.1.8 +- Fixes Blutopia torrents being deleted due to passkeys being invalid (#646) +- Adds edit_passkey.py script +**Full Changelog**: https://github.com/StuffAnThings/qbit_manage/compare/v4.1.8...v4.1.9 diff --git a/VERSION b/VERSION index a7c00da3..18837e70 100755 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.1.8 +4.1.9 diff --git a/modules/util.py b/modules/util.py index c4684686..52aab3d4 100755 --- a/modules/util.py +++ b/modules/util.py @@ -94,10 +94,8 @@ class TorrentMessages: IGNORE_MSGS = [ "YOU HAVE REACHED THE CLIENT LIMIT FOR THIS TORRENT", - "MISSING PASSKEY", + "PASSKEY", # Any mention of passkeys should be a clear sign it should NOT be deleted "MISSING INFO_HASH", - "PASSKEY IS INVALID", - "INVALID PASSKEY", "EXPECTED VALUE (LIST, DICT, INT OR STRING) IN BENCODED STRING", "COULD NOT PARSE BENCODED DATA", "STREAM TRUNCATED", diff --git a/scripts/edit_passkey.py b/scripts/edit_passkey.py new file mode 100644 index 00000000..13346d52 --- /dev/null +++ b/scripts/edit_passkey.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +# This standalone script is used to edit passkeys from one tracker. +# Needs to have qbittorrent-api installed +# pip3 install qbittorrent-api +import sys + +# --DEFINE VARIABLES--# +qbt_host = "qbittorrent:8080" +qbt_user = None +qbt_pass = None +TRACKER = "blutopia" # Part of the tracker URL, e.g., "blutopia" or "your-tracker.com" +OLD_PASSKEY = "OLD_PASSKEY" +NEW_PASSKEY = "NEW_PASSKEY" +# --DEFINE VARIABLES--# +# --START SCRIPT--# + +try: + from qbittorrentapi import APIConnectionError + from qbittorrentapi import Client + from qbittorrentapi import LoginFailed +except ModuleNotFoundError: + print('Requirements Error: qbittorrent-api not installed. Please install using the command "pip install qbittorrent-api"') + sys.exit(1) + + +if __name__ == "__main__": + try: + client = Client(host=qbt_host, username=qbt_user, password=qbt_pass) + except LoginFailed: + raise ("Qbittorrent Error: Failed to login. Invalid username/password.") + except APIConnectionError: + raise ("Qbittorrent Error: Unable to connect to the client.") + except Exception: + raise ("Qbittorrent Error: Unable to connect to the client.") + torrent_list = client.torrents.info(sort="added_on", reverse=True) + + for torrent in torrent_list: + for x in torrent.trackers: + if TRACKER in x.url and OLD_PASSKEY in x.url: + try: + newurl = x.url.replace(OLD_PASSKEY, NEW_PASSKEY) + print(f"Updating passkey for torrent name: {torrent.name}\n") + torrent.remove_trackers(urls=x.url) + torrent.add_trackers(urls=newurl) + except Exception as e: + print(f"Error updating tracker for {torrent.name}: {e}") + print("Passkey update completed.") From 06fadc60310eeaf30b2be905d4e7dcea6b264426 Mon Sep 17 00:00:00 2001 From: ineednewpajamas <73252768+ineednewpajamas@users.noreply.github.com> Date: Fri, 6 Sep 2024 12:51:41 -0500 Subject: [PATCH 2/7] Create recyclebin_recovery.py --- scripts/recyclebin_recovery.py | 72 ++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 scripts/recyclebin_recovery.py diff --git a/scripts/recyclebin_recovery.py b/scripts/recyclebin_recovery.py new file mode 100644 index 00000000..a5c94567 --- /dev/null +++ b/scripts/recyclebin_recovery.py @@ -0,0 +1,72 @@ +#!/usr/bin/python3 +import os +import shutil +import argparse +import sys + +def move_files(src, dest, debug=True): + """Move files from source to destination""" + dest_path = os.path.dirname(dest) + if debug: + print(f"From: {src} To: {dest}") + else: + if os.path.isdir(dest_path) is False: + os.makedirs(dest_path, exist_ok=True) + try: + shutil.move(src, dest) + except PermissionError as perm: + print(perm) + except FileNotFoundError as file: + print(f"{file} : source: {src} -> destination: {dest}") + except Exception as ex: + print(ex) + +def joiner(base, add): + """Join two paths together, just makes for less characters""" + return os.path.join(base, add) + +def ls(path): + """Kind of like bash ls, less characters""" + return os.listdir(path) + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + prog='QBM_Recovery', + description='Move files in the RecycleBin back into place', + epilog='Don\'t forget to restart qbittorrent...' + ) + parser.add_argument( + '--debug', + action="store_true", + default=False, + help="Print debug statements instead of taking action", + ) + args = parser.parse_args() + + debug = args.debug + base_dir = '/data/torrents/.RecycleBin' + btbackup_dir = '/var/opt/docker/docker_configs/qbittorrent/config/data/BT_backup/' + + try: + for dir in ls(base_dir): # torrents tv movies torrents_json links + dir_path = joiner(base_dir, dir) + if dir == 'torrents_json': # skip + continue + elif dir == 'torrents': # move as is + for subdir in ls(dir_path): + subdir_path = joiner(dir_path, subdir) + move_files(subdir_path, btbackup_dir, debug) + elif dir == 'links': # will have a subfolder + for subdir in ls(dir_path): + subdir_path = joiner(dir_path, subdir) # will be like /data/torrents/.RecycleBin/links/TorrentLeech + for tdir in ls(subdir_path): # the action torrent files + tdir_path = joiner(subdir_path, tdir) + move_files(tdir_path, tdir_path.replace('/.RecycleBin', ''), debug) + else: # movies tv + for subdir in ls(dir_path): + # might be a file, might be a folder + subdir_path = joiner(dir_path, subdir) + move_files(subdir_path, subdir_path.replace('/.RecycleBin', ''), debug) + print("\n\nRemember to restart Qbittorent: docker compose restart qbittorrent") + except KeyboardInterrupt: + sys.exit(1) From e0286810ee33a3a54b420cce74aa35191225a583 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 6 Sep 2024 17:53:38 +0000 Subject: [PATCH 3/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- scripts/recyclebin_recovery.py | 120 +++++++++++++++++---------------- 1 file changed, 62 insertions(+), 58 deletions(-) diff --git a/scripts/recyclebin_recovery.py b/scripts/recyclebin_recovery.py index a5c94567..86b52317 100644 --- a/scripts/recyclebin_recovery.py +++ b/scripts/recyclebin_recovery.py @@ -1,72 +1,76 @@ #!/usr/bin/python3 +import argparse import os import shutil -import argparse import sys + def move_files(src, dest, debug=True): - """Move files from source to destination""" - dest_path = os.path.dirname(dest) - if debug: - print(f"From: {src} To: {dest}") - else: - if os.path.isdir(dest_path) is False: - os.makedirs(dest_path, exist_ok=True) - try: - shutil.move(src, dest) - except PermissionError as perm: - print(perm) - except FileNotFoundError as file: - print(f"{file} : source: {src} -> destination: {dest}") - except Exception as ex: - print(ex) + """Move files from source to destination""" + dest_path = os.path.dirname(dest) + if debug: + print(f"From: {src} To: {dest}") + else: + if os.path.isdir(dest_path) is False: + os.makedirs(dest_path, exist_ok=True) + try: + shutil.move(src, dest) + except PermissionError as perm: + print(perm) + except FileNotFoundError as file: + print(f"{file} : source: {src} -> destination: {dest}") + except Exception as ex: + print(ex) + def joiner(base, add): - """Join two paths together, just makes for less characters""" - return os.path.join(base, add) + """Join two paths together, just makes for less characters""" + return os.path.join(base, add) + def ls(path): - """Kind of like bash ls, less characters""" - return os.listdir(path) + """Kind of like bash ls, less characters""" + return os.listdir(path) + if __name__ == "__main__": - parser = argparse.ArgumentParser( - prog='QBM_Recovery', - description='Move files in the RecycleBin back into place', - epilog='Don\'t forget to restart qbittorrent...' - ) - parser.add_argument( - '--debug', - action="store_true", - default=False, - help="Print debug statements instead of taking action", - ) - args = parser.parse_args() + parser = argparse.ArgumentParser( + prog="QBM_Recovery", + description="Move files in the RecycleBin back into place", + epilog="Don't forget to restart qbittorrent...", + ) + parser.add_argument( + "--debug", + action="store_true", + default=False, + help="Print debug statements instead of taking action", + ) + args = parser.parse_args() - debug = args.debug - base_dir = '/data/torrents/.RecycleBin' - btbackup_dir = '/var/opt/docker/docker_configs/qbittorrent/config/data/BT_backup/' + debug = args.debug + base_dir = "/data/torrents/.RecycleBin" + btbackup_dir = "/var/opt/docker/docker_configs/qbittorrent/config/data/BT_backup/" - try: - for dir in ls(base_dir): # torrents tv movies torrents_json links - dir_path = joiner(base_dir, dir) - if dir == 'torrents_json': # skip - continue - elif dir == 'torrents': # move as is - for subdir in ls(dir_path): - subdir_path = joiner(dir_path, subdir) - move_files(subdir_path, btbackup_dir, debug) - elif dir == 'links': # will have a subfolder - for subdir in ls(dir_path): - subdir_path = joiner(dir_path, subdir) # will be like /data/torrents/.RecycleBin/links/TorrentLeech - for tdir in ls(subdir_path): # the action torrent files - tdir_path = joiner(subdir_path, tdir) - move_files(tdir_path, tdir_path.replace('/.RecycleBin', ''), debug) - else: # movies tv - for subdir in ls(dir_path): - # might be a file, might be a folder - subdir_path = joiner(dir_path, subdir) - move_files(subdir_path, subdir_path.replace('/.RecycleBin', ''), debug) - print("\n\nRemember to restart Qbittorent: docker compose restart qbittorrent") - except KeyboardInterrupt: - sys.exit(1) + try: + for dir in ls(base_dir): # torrents tv movies torrents_json links + dir_path = joiner(base_dir, dir) + if dir == "torrents_json": # skip + continue + elif dir == "torrents": # move as is + for subdir in ls(dir_path): + subdir_path = joiner(dir_path, subdir) + move_files(subdir_path, btbackup_dir, debug) + elif dir == "links": # will have a subfolder + for subdir in ls(dir_path): + subdir_path = joiner(dir_path, subdir) # will be like /data/torrents/.RecycleBin/links/TorrentLeech + for tdir in ls(subdir_path): # the action torrent files + tdir_path = joiner(subdir_path, tdir) + move_files(tdir_path, tdir_path.replace("/.RecycleBin", ""), debug) + else: # movies tv + for subdir in ls(dir_path): + # might be a file, might be a folder + subdir_path = joiner(dir_path, subdir) + move_files(subdir_path, subdir_path.replace("/.RecycleBin", ""), debug) + print("\n\nRemember to restart Qbittorent: docker compose restart qbittorrent") + except KeyboardInterrupt: + sys.exit(1) From eb359be657b4740bc0437481688ad7e8bbedf375 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Fri, 6 Sep 2024 13:06:37 -0500 Subject: [PATCH 4/7] Update recyclebin_recovery.py made some tweaks and added ingesting qbit_manage config --- scripts/recyclebin_recovery.py | 43 ++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/scripts/recyclebin_recovery.py b/scripts/recyclebin_recovery.py index 86b52317..63449300 100644 --- a/scripts/recyclebin_recovery.py +++ b/scripts/recyclebin_recovery.py @@ -3,6 +3,7 @@ import os import shutil import sys +import yaml def move_files(src, dest, debug=True): @@ -11,7 +12,7 @@ def move_files(src, dest, debug=True): if debug: print(f"From: {src} To: {dest}") else: - if os.path.isdir(dest_path) is False: + if not os.path.isdir(dest_path): os.makedirs(dest_path, exist_ok=True) try: shutil.move(src, dest) @@ -33,23 +34,50 @@ def ls(path): return os.listdir(path) +def load_config(config_path): + """Load configuration from qbit manage's YAML config""" + with open(config_path, 'r') as file: + return yaml.safe_load(file) + + if __name__ == "__main__": parser = argparse.ArgumentParser( prog="QBM_Recovery", description="Move files in the RecycleBin back into place", epilog="Don't forget to restart qbittorrent...", ) + parser.add_argument( + "--config", + type=str, + default="config.yml", + help="path to qbit_manages configuration file", + ) parser.add_argument( "--debug", action="store_true", default=False, help="Print debug statements instead of taking action", ) + parser.add_argument( + "--base-dir", + type=str, + help="Base directory of the RecycleBin", + ) + parser.add_argument( + "--btbackup-dir", + type=str, + help="Destination directory for BT_backup", + ) args = parser.parse_args() + # Load configuration from YAML + config = load_config(args.config) + + # Retrieve directories from the config with defaults if not present + base_dir = args.base_dir or config.get('directory', {}).get('recycle_bin') + btbackup_dir = args.btbackup_dir or config.get('directory', {}).get('torrents_dir') + debug = args.debug - base_dir = "/data/torrents/.RecycleBin" - btbackup_dir = "/var/opt/docker/docker_configs/qbittorrent/config/data/BT_backup/" try: for dir in ls(base_dir): # torrents tv movies torrents_json links @@ -62,15 +90,16 @@ def ls(path): move_files(subdir_path, btbackup_dir, debug) elif dir == "links": # will have a subfolder for subdir in ls(dir_path): - subdir_path = joiner(dir_path, subdir) # will be like /data/torrents/.RecycleBin/links/TorrentLeech + subdir_path = joiner(dir_path, subdir) for tdir in ls(subdir_path): # the action torrent files tdir_path = joiner(subdir_path, tdir) - move_files(tdir_path, tdir_path.replace("/.RecycleBin", ""), debug) + move_files(tdir_path, tdir_path.replace(base_dir, ""), debug) else: # movies tv for subdir in ls(dir_path): # might be a file, might be a folder subdir_path = joiner(dir_path, subdir) - move_files(subdir_path, subdir_path.replace("/.RecycleBin", ""), debug) - print("\n\nRemember to restart Qbittorent: docker compose restart qbittorrent") + move_files(subdir_path, subdir_path.replace(base_dir, ""), debug) + print("\n\nRemember to restart Qbittorrent: docker compose restart qbittorrent") except KeyboardInterrupt: sys.exit(1) + From acfbf7b1ed1a2d9136df7e2114f8d77c7ab77cbe Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 6 Sep 2024 18:08:05 +0000 Subject: [PATCH 5/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- scripts/recyclebin_recovery.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/recyclebin_recovery.py b/scripts/recyclebin_recovery.py index 63449300..b55d0bea 100644 --- a/scripts/recyclebin_recovery.py +++ b/scripts/recyclebin_recovery.py @@ -3,6 +3,7 @@ import os import shutil import sys + import yaml @@ -36,7 +37,7 @@ def ls(path): def load_config(config_path): """Load configuration from qbit manage's YAML config""" - with open(config_path, 'r') as file: + with open(config_path) as file: return yaml.safe_load(file) @@ -72,11 +73,11 @@ def load_config(config_path): # Load configuration from YAML config = load_config(args.config) - + # Retrieve directories from the config with defaults if not present - base_dir = args.base_dir or config.get('directory', {}).get('recycle_bin') - btbackup_dir = args.btbackup_dir or config.get('directory', {}).get('torrents_dir') - + base_dir = args.base_dir or config.get("directory", {}).get("recycle_bin") + btbackup_dir = args.btbackup_dir or config.get("directory", {}).get("torrents_dir") + debug = args.debug try: @@ -102,4 +103,3 @@ def load_config(config_path): print("\n\nRemember to restart Qbittorrent: docker compose restart qbittorrent") except KeyboardInterrupt: sys.exit(1) - From 30865e99e36f33c964ae4a9a2783fb17aad022d8 Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Fri, 6 Sep 2024 13:10:11 -0500 Subject: [PATCH 6/7] fixes --- scripts/recyclebin_recovery.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/recyclebin_recovery.py b/scripts/recyclebin_recovery.py index b55d0bea..740e0f0e 100644 --- a/scripts/recyclebin_recovery.py +++ b/scripts/recyclebin_recovery.py @@ -50,13 +50,12 @@ def load_config(config_path): parser.add_argument( "--config", type=str, - default="config.yml", + default="../config/config.yml", help="path to qbit_manages configuration file", ) parser.add_argument( "--debug", action="store_true", - default=False, help="Print debug statements instead of taking action", ) parser.add_argument( From c900f4ea5af802fa62a30ffcede9e7a3db795ecf Mon Sep 17 00:00:00 2001 From: bakerboy448 <55419169+bakerboy448@users.noreply.github.com> Date: Sat, 7 Sep 2024 07:59:56 -0500 Subject: [PATCH 7/7] (ci) only build develop on develop push (#649) --- .github/workflows/develop.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index aeaf12e2..421c4c95 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -3,8 +3,6 @@ name: Docker Develop Release on: push: branches: [ develop ] - pull_request: - branches: [ develop ] jobs: