diff --git a/.github/workflows/update-supported-versions.yml b/.github/workflows/update-supported-versions.yml index 99318079..af54058a 100644 --- a/.github/workflows/update-supported-versions.yml +++ b/.github/workflows/update-supported-versions.yml @@ -42,7 +42,7 @@ jobs: - name: Create Pull Request id: cpr - uses: peter-evans/create-pull-request@v6 + uses: peter-evans/create-pull-request@v7 with: commit-message: Update SUPPORTED_VERSIONS.json title: "Update SUPPORTED_VERSIONS.json for ${{ github.event.inputs.targetBranch || github.ref_name }}" diff --git a/CHANGELOG b/CHANGELOG index 1fa7ad71..c2bdb4a6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,16 +1,16 @@ +# Requirements Updated +- qbittorrent-api==2024.8.65 +- croniter==3.0.3 +- humanize==4.10.0 + # New Updates -- BHD config options are now deprecated due to qbm no longer needing to use the api to detect unregistered torrents (Closes #595) -- Updates mover script to add logging and default to completed torrents only with new optional argument (`--status-filter`) +- Adds `force_auto_tmm_ignore_tags` feature to ignore tags when force_auto_tmm is enabled (#634) # Bug Fixes -- Adds new ignore message for unregistered torrents (Closes #592) -- Allow `max_seeding_time` to be unlimited (-1) if min_seeding_time is set (Closes #596) -- Fixes checking tracker status for udp/wss (Closes #586) -- Fixes Logging header not getting logged in every run (Closes #591) -- Fixes min_seeding_time tag removal when max_seeding_time is -1 (#Closes 598) -- Fixes Remove orphaned without moving to orphaned_dir (Closes #590) -- Fixes bug in printing schedule mode when run is set to True -- Modifies noHL threshold to 0.1 to address false positives +- 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 @bakerboy448, @ineednewpajamas, @lflare, @convexshiba for their contributions! -**Full Changelog**: https://github.com/StuffAnThings/qbit_manage/compare/v4.1.6...v4.1.7 +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 diff --git a/Dockerfile b/Dockerfile index 8a0ec774..d22953d2 100755 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,8 @@ FROM python:3.11-alpine ARG BRANCH_NAME=master -ENV BRANCH_NAME ${BRANCH_NAME} -ENV TINI_VERSION v0.19.0 -ENV QBM_DOCKER True +ENV BRANCH_NAME=${BRANCH_NAME} +ENV TINI_VERSION=v0.19.0 +ENV QBM_DOCKER=True COPY requirements.txt / diff --git a/README.md b/README.md index 81da3f4f..d1cf7192 100755 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Generally expect new releases of Qbittorrent to not immediately be supported. Su Check out the [wiki](https://github.com/StuffAnThings/qbit_manage/wiki) for installation help -1. Install qbit_manage either by installing Python 3.8.1+ on the localhost and following the [Local Installation](https://github.com/StuffAnThings/qbit_manage/wiki/Local-Installations) Guide or by installing Docker and following the [Docker Installation](https://github.com/StuffAnThings/qbit_manage/wiki/Docker-Installation) Guide or the [unRAID Installation](https://github.com/StuffAnThings/qbit_manage/wiki/Unraid-Installation) Guide. +1. Install qbit_manage either by installing Python 3.9.0+ on the localhost and following the [Local Installation](https://github.com/StuffAnThings/qbit_manage/wiki/Local-Installations) Guide or by installing Docker and following the [Docker Installation](https://github.com/StuffAnThings/qbit_manage/wiki/Docker-Installation) Guide or the [unRAID Installation](https://github.com/StuffAnThings/qbit_manage/wiki/Unraid-Installation) Guide. 1. Once installed, you have to [set up your Configuration](https://github.com/StuffAnThings/qbit_manage/wiki/Config-Setup) by create a [Configuration File](https://github.com/StuffAnThings/qbit_manage/blob/master/config/config.yml.sample) filled with all your values to connect to your qBittorrent instance. 1. Please refer to the list of [Commands](https://github.com/StuffAnThings/qbit_manage/wiki/Commands) that can be used with this tool. diff --git a/SUPPORTED_VERSIONS.json b/SUPPORTED_VERSIONS.json index 6dc59e4c..3f7e699c 100644 --- a/SUPPORTED_VERSIONS.json +++ b/SUPPORTED_VERSIONS.json @@ -1,10 +1,10 @@ { "master": { - "qbit": "v4.6.5", - "qbitapi": "2024.5.63" + "qbit": "v4.6.6", + "qbitapi": "2024.8.65" }, "develop": { - "qbit": "v4.6.5", - "qbitapi": "2024.5.63" + "qbit": "v4.6.6", + "qbitapi": "2024.8.65" } } diff --git a/VERSION b/VERSION index 9edf2a44..a7c00da3 100755 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.1.7 +4.1.8 diff --git a/config/config.yml.sample b/config/config.yml.sample index 70d6ac5c..c7b6f57c 100755 --- a/config/config.yml.sample +++ b/config/config.yml.sample @@ -26,6 +26,9 @@ qbt: settings: force_auto_tmm: False # Will force qBittorrent to enable Automatic Torrent Management for each torrent. + force_auto_tmm_ignore_tags: #Torrents with these tags will be ignored when force_auto_tmm is enabled. + - cross-seed + - Upload tracker_error_tag: issue # Will set the tag of any torrents that do not have a working tracker. nohardlinks_tag: noHL # Will set the tag of any torrents with no hardlinks. share_limits_tag: ~share_limit # Will add this tag when applying share limits to provide an easy way to filter torrents by share limit group/priority for each torrent @@ -36,7 +39,7 @@ settings: cat_filter_completed: True # Filters for completed torrents only when running cat_update command share_limits_filter_completed: True # Filters for completed torrents only when running share_limits command tag_nohardlinks_filter_completed: True # Filters for completed torrents only when running tag_nohardlinks command - cat_update_all: True # Checks and udpates all torrent categories if set to True when running cat_update command, otherwise only update torrents that are uncategorized + cat_update_all: True # Checks and updates all torrent categories if set to True when running cat_update command, otherwise only update torrents that are uncategorized directory: # Do not remove these diff --git a/docs/Config-Setup.md b/docs/Config-Setup.md index 708f3947..2aa5ced4 100644 --- a/docs/Config-Setup.md +++ b/docs/Config-Setup.md @@ -46,6 +46,7 @@ This section defines any settings defined in the configuration. | Variable | Definition | Default Values | Required | | :-------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------| :----------------- | :----------------- | | `force_auto_tmm` | Will force qBittorrent to enable Automatic Torrent Management for each torrent. | False |
| +| `force_auto_tmm_ignore_tags` | Torrents with these tags will be ignored when force_auto_tmm is enabled. | |
| | `tracker_error_tag` | Define the tag of any torrents that do not have a working tracker. (Used in `--rem-unregistered` and `--tag-tracker-error`) | issue |
| | `nohardlinks_tag` | Define the tag of any torrents that don't have hardlinks (Used in `--tag-nohardlinks`) | noHL |
| | `share_limits_tag` | Will add this tag when applying share limits to provide an easy way to filter torrents by share limit group/priority for each torrent. For example, if you have a share-limit group `cross-seed` with a priority of 2 and the default share_limits_tag `~share_limits` would add the tag `~share_limit_2.cross-seed` (Used in `--share-limits`) | ~share_limit |
| diff --git a/docs/Home.md b/docs/Home.md index a0329fe2..c4f058a2 100644 --- a/docs/Home.md +++ b/docs/Home.md @@ -4,9 +4,9 @@ This wiki should tell you everything you need to know about the script to get it ## Getting Started -1. Install qbit_manage either by installing Python3.8.1+ on the localhost and following the [Local Installation](https://github.com/StuffAnThings/qbit_manage/wiki/Local-Installations) Guide or by installing Docker and following the [Docker Installation](https://github.com/StuffAnThings/qbit_manage/wiki/Docker-Installation) Guide or the [unRAID Installation](https://github.com/StuffAnThings/qbit_manage/wiki/Unraid-Installation) Guide.
-2. Once installed, you have to [set up your Configuration](https://github.com/StuffAnThings/qbit_manage/wiki/Config-Setup) by create a [Configuration File](https://github.com/StuffAnThings/qbit_manage/blob/master/config/config.yml.sample) filled with all your values to connect to your qBittorrent instance. -3. Please refer to the list of [Commands](https://github.com/StuffAnThings/qbit_manage/wiki/Commands) that can be used with this tool. +1. Install qbit_manage either by installing Python3.9.0+ on the localhost and following the [Local Installation](https://github.com/StuffAnThings/qbit_manage/wiki/Local-Installations) Guide or by installing Docker and following the [Docker Installation](https://github.com/StuffAnThings/qbit_manage/wiki/Docker-Installation) Guide or the [unRAID Installation](https://github.com/StuffAnThings/qbit_manage/wiki/Unraid-Installation) Guide.
+1. Once installed, you have to [set up your Configuration](https://github.com/StuffAnThings/qbit_manage/wiki/Config-Setup) by create a [Configuration File](https://github.com/StuffAnThings/qbit_manage/blob/master/config/config.yml.sample) filled with all your values to connect to your qBittorrent instance. +1. Please refer to the list of [Commands](https://github.com/StuffAnThings/qbit_manage/wiki/Commands) that can be used with this tool. ## Support diff --git a/docs/Local-Installations.md b/docs/Local-Installations.md index 14090d11..58679876 100644 --- a/docs/Local-Installations.md +++ b/docs/Local-Installations.md @@ -1,6 +1,6 @@ # Local Installations -* Requires `python 3.8.1`. Dependencies must be installed by running: +* Requires `python 3.9.0`. Dependencies must be installed by running: Navigate to the directory you'd liked to clone the repo into diff --git a/docs/_Sidebar.md b/docs/_Sidebar.md index 0af94854..06180c84 100644 --- a/docs/_Sidebar.md +++ b/docs/_Sidebar.md @@ -13,7 +13,7 @@ - [settings](Config-Setup#settings) - [directory](Config-Setup#directory) - [cat](Config-Setup#cat) - - [cat_changes](Config-Setup#cat_changes) + - [cat_change](Config-Setup#cat_change) - [tracker](Config-Setup#tracker) - [nohardlinks](Config-Setup#nohardlinks) - [share_limits](Config-Setup#share_limits) diff --git a/modules/config.py b/modules/config.py index f5453655..209b5a7e 100755 --- a/modules/config.py +++ b/modules/config.py @@ -229,6 +229,9 @@ def hooks(attr): "cat_update_all": self.util.check_for_attribute( self.data, "cat_update_all", parent="settings", var_type="bool", default=True ), + "force_auto_tmm_ignore_tags": self.util.check_for_attribute( + self.data, "force_auto_tmm_ignore_tags", parent="settings", var_type="list", default=[] + ), } self.tracker_error_tag = self.settings["tracker_error_tag"] diff --git a/modules/core/share_limits.py b/modules/core/share_limits.py index 23920364..7a37a268 100644 --- a/modules/core/share_limits.py +++ b/modules/core/share_limits.py @@ -112,7 +112,7 @@ def cleanup_torrents_for_group(self, group_name, priority): if not self.config.dry_run: self.qbt.tor_delete_recycle(torrent, attr) body += logger.print_line( - logger.insert_space("Deleted .torrent but NOT content files.", 8), + logger.insert_space("Deleted .torrent but NOT content files. Reason: is cross-seed", 8), self.config.loglevel, ) else: @@ -131,7 +131,13 @@ def cleanup_torrents_for_group(self, group_name, priority): if not self.config.dry_run: self.qbt.tor_delete_recycle(torrent, attr) body += logger.print_line( - logger.insert_space("Deleted .torrent but NOT content files.", 8), self.config.loglevel + logger.insert_space( + "Deleted .torrent but NOT content files. Reason: path does not exist [path=" + + torrent["content_path"].replace(self.root_dir, self.remote_dir) + + "].", + 8, + ), + self.config.loglevel, ) attr["body"] = "\n".join(body) if not group_notifications: diff --git a/modules/qbittorrent.py b/modules/qbittorrent.py index d99c7fce..4211df4d 100755 --- a/modules/qbittorrent.py +++ b/modules/qbittorrent.py @@ -125,7 +125,9 @@ def get_torrent_info(self): logger.separator("Checking Settings", space=False, border=False) if settings["force_auto_tmm"]: logger.print_line( - "force_auto_tmm set to True. Will force Auto Torrent Management for all torrents.", self.config.loglevel + "force_auto_tmm set to True. Will force Auto Torrent Management " + "for all torrents without matching force_auto_tmm_ignore_tags.", + self.config.loglevel, ) logger.separator("Gathering Torrent Information", space=True, border=True) for torrent in self.torrent_list: @@ -134,7 +136,14 @@ def get_torrent_info(self): status = None working_tracker = None issue = {"potential": False} - if torrent.auto_tmm is False and settings["force_auto_tmm"] and torrent.category != "" and not self.config.dry_run: + if ( + torrent.auto_tmm is False + and settings["force_auto_tmm"] + and torrent.category != "" + and not self.config.dry_run + # check whether the torrent has a matching tag to ignore force_auto_tmm. + and not any(tag in torrent.tags for tag in self.config.settings.get("force_auto_tmm_ignore_tags", [])) + ): torrent.set_auto_management(True) try: torrent_name = torrent.name diff --git a/modules/util.py b/modules/util.py index 689c8038..c4684686 100755 --- a/modules/util.py +++ b/modules/util.py @@ -536,22 +536,26 @@ def __init__(self, root_dir, remote_dir): def get_inode_count(self): self.inode_count = {} for file in self.root_files: - try: - inode_no = os.stat(file.replace(self.root_dir, self.remote_dir)).st_ino - except PermissionError as perm: - logger.warning(f"{perm} : file {file} has permission issues. Skipping...") - continue - except FileNotFoundError as file_not_found_error: - logger.warning(f"{file_not_found_error} : File {file} not found. Skipping...") - continue - except Exception as ex: - logger.stacktrace() - logger.error(ex) + # Only check hardlinks for files that are symlinks + if os.path.isfile(file) and os.path.islink(file): continue - if inode_no in self.inode_count: - self.inode_count[inode_no] += 1 else: - self.inode_count[inode_no] = 1 + try: + inode_no = os.stat(file.replace(self.root_dir, self.remote_dir)).st_ino + except PermissionError as perm: + logger.warning(f"{perm} : file {file} has permission issues. Skipping...") + continue + except FileNotFoundError as file_not_found_error: + logger.warning(f"{file_not_found_error} : File {file} not found. Skipping...") + continue + except Exception as ex: + logger.stacktrace() + logger.error(ex) + continue + if inode_no in self.inode_count: + self.inode_count[inode_no] += 1 + else: + self.inode_count[inode_no] = 1 def nohardlink(self, file, notify, ignore_root_dir): """ diff --git a/qbit_manage.py b/qbit_manage.py index e149bd90..43cf1460 100755 --- a/qbit_manage.py +++ b/qbit_manage.py @@ -671,8 +671,10 @@ def print_logo(logger): next_run_time = schedule_every_x_minutes(sch) if startupDelay: run_mode_message += f"\n Startup Delay: Initial Run will start after {startupDelay} seconds" + logger.info(run_mode_message) time.sleep(startupDelay) - logger.info(run_mode_message) + else: + logger.info(run_mode_message) start_loop(True) while not killer.kill_now: diff --git a/requirements-dev.txt b/requirements-dev.txt index 175e64ab..325e4be0 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,2 +1,2 @@ -flake8==7.1.0 -pre-commit==3.7.1 +flake8==7.1.1 +pre-commit==3.8.0 diff --git a/requirements.txt b/requirements.txt index 508bad69..3affde0e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ bencodepy==0.9.5 -croniter==2.0.5 +croniter==3.0.3 GitPython==3.1.43 -humanize==4.9.0 +humanize==4.10.0 pytimeparse2==1.7.1 qbittorrent-api==2024.8.65 requests==2.32.3 diff --git a/tox.ini b/tox.ini index 135a0aa2..aa931434 100755 --- a/tox.ini +++ b/tox.ini @@ -8,7 +8,7 @@ tox_pip_extensions_ext_venv_update = true deps = -r{toxinidir}/requirements.txt -r{toxinidir}/requirements-dev.txt -passenv = HOME SSH_AUTH_SOCK USER +passenv = HOME,SSH_AUTH_SOCK,USER [testenv:venv] envdir = venv