mirror of
https://github.com/StuffAnThings/qbit_manage.git
synced 2025-10-09 21:36:52 +08:00
commit
cb6592e5f8
8 changed files with 189 additions and 156 deletions
|
@ -17,5 +17,6 @@ config
|
||||||
Dockerfile
|
Dockerfile
|
||||||
venv
|
venv
|
||||||
.idea
|
.idea
|
||||||
|
.env
|
||||||
test.py
|
test.py
|
||||||
!config/config.yml.sample
|
!config/config.yml.sample
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -7,3 +7,5 @@ __pycache__/
|
||||||
*.yml
|
*.yml
|
||||||
.vscode/*
|
.vscode/*
|
||||||
!.github/**
|
!.github/**
|
||||||
|
*.svg
|
||||||
|
.env
|
10
README.md
10
README.md
|
@ -1,4 +1,4 @@
|
||||||
# qBit Management
|
# <img src="qbm_logo.png" width="75"> qBit Management
|
||||||
|
|
||||||
[](https://github.com/StuffAnThings/qbit_manage/releases)
|
[](https://github.com/StuffAnThings/qbit_manage/releases)
|
||||||
[](https://github.com/StuffAnThings/qbit_manage/tree/develop)
|
[](https://github.com/StuffAnThings/qbit_manage/tree/develop)
|
||||||
|
@ -9,10 +9,10 @@
|
||||||
|
|
||||||
This is a program used to manage your qBittorrent instance such as:
|
This is a program used to manage your qBittorrent instance such as:
|
||||||
|
|
||||||
* Tag torrents based on tracker URL (only tag torrents that have no tags)
|
* Tag torrents based on tracker URL and set seed goals/limit upload speed by tag (only tag torrents that have no tags)
|
||||||
* Update categories based on save directory
|
* Update categories based on save directory
|
||||||
* Remove unregistered torrents (delete data & torrent if it is not being cross-seeded, otherwise it will just remove the torrent)
|
* Remove unregistered torrents (delete data & torrent if it is not being cross-seeded, otherwise it will just remove the torrent)
|
||||||
* Automatically add [cross-seed](https://github.com/mmgoodnow/cross-seed) torrents in paused state (used in conjunction with the [cross-seed](https://github.com/mmgoodnow/cross-seed) script) <-- cross-seed now allows for torrent injections directly to qBit.
|
* Automatically add [cross-seed](https://github.com/mmgoodnow/cross-seed) torrents in paused state. **\*Note: cross-seed now allows for torrent injections directly to qBit, making this feature obsolete.\***
|
||||||
* Recheck paused torrents sorted by lowest size and resume if completed
|
* Recheck paused torrents sorted by lowest size and resume if completed
|
||||||
* Remove orphaned files from your root directory that are not referenced by qBittorrent
|
* Remove orphaned files from your root directory that are not referenced by qBittorrent
|
||||||
* Tag any torrents that have no hard links and allows optional cleanup to delete these torrents and contents based on maximum ratio and/or time seeded
|
* Tag any torrents that have no hard links and allows optional cleanup to delete these torrents and contents based on maximum ratio and/or time seeded
|
||||||
|
@ -30,7 +30,7 @@ To run the script in an interactive terminal run:
|
||||||
* add your qBittorrent host, user and pass. If you are not using a username and password you can remove the `user` and `pass` lines.
|
* add your qBittorrent host, user and pass. If you are not using a username and password you can remove the `user` and `pass` lines.
|
||||||
* add your `cross_seed` and `root_dir`. If you're running cross-seed in a docker container you must fill out `remote_dir` as well.
|
* add your `cross_seed` and `root_dir`. If you're running cross-seed in a docker container you must fill out `remote_dir` as well.
|
||||||
* Add your categories and save path to match with what is being used in your qBittorrent instance. I suggest using the full path when defining `save_path`
|
* Add your categories and save path to match with what is being used in your qBittorrent instance. I suggest using the full path when defining `save_path`
|
||||||
* Add the `tag` definition based on tracker URL
|
* Add the `tag` definition based on tracker URL (optional add seed goals/limit upload speed by tag)
|
||||||
* Modify the `nohardlinks` by specifying your completed movies/series category to match with qBittorrent. Please ensure the `root_dir` and/or `remote_dir` is added in the `directory` section
|
* Modify the `nohardlinks` by specifying your completed movies/series category to match with qBittorrent. Please ensure the `root_dir` and/or `remote_dir` is added in the `directory` section
|
||||||
* `root_dir` needs to be defined in order to use the RecycleBin function. If optional `empty_after_x_days` is not defined then it will never empty the RecycleBin. Setting it to 0 will empty the RecycleBin immediately.
|
* `root_dir` needs to be defined in order to use the RecycleBin function. If optional `empty_after_x_days` is not defined then it will never empty the RecycleBin. Setting it to 0 will empty the RecycleBin immediately.
|
||||||
* Modify the `orphaned` section to define file patterns not to consider as orphans. Use this to exclude your incomplete torrents directory, or to ignore auto-generated files such as Thumbs.db.
|
* Modify the `orphaned` section to define file patterns not to consider as orphans. Use this to exclude your incomplete torrents directory, or to ignore auto-generated files such as Thumbs.db.
|
||||||
|
@ -51,7 +51,7 @@ python qbit_manage.py -h
|
||||||
| `-cs` or `--cross-seed` | QBT_CROSS_SEED | Use this after running [cross-seed script](https://github.com/mmgoodnow/cross-seed) to add torrents from the cross-seed output folder to qBittorrent | False |
|
| `-cs` or `--cross-seed` | QBT_CROSS_SEED | Use this after running [cross-seed script](https://github.com/mmgoodnow/cross-seed) to add torrents from the cross-seed output folder to qBittorrent | False |
|
||||||
| `-re` or `--recheck` | QBT_RECHECK | Recheck paused torrents sorted by lowest size. Resume if Completed. | False |
|
| `-re` or `--recheck` | QBT_RECHECK | Recheck paused torrents sorted by lowest size. Resume if Completed. | False |
|
||||||
| `-cu` or `--cat-update` | QBT_CAT_UPDATE | Use this if you would like to update your categories. | False |
|
| `-cu` or `--cat-update` | QBT_CAT_UPDATE | Use this if you would like to update your categories. | False |
|
||||||
| `-tu` or `--tag-update` | QBT_TAG_UPDATE | Use this if you would like to update your tags. (Only adds tags to untagged torrents) | False |
|
| `-tu` or `--tag-update` | QBT_TAG_UPDATE | Use this if you would like to update your tags and/or set seed goals/limit upload speed by tag. (Only adds tags to untagged torrents) | False |
|
||||||
| `-ru` or `--rem-unregistered` | QBT_REM_UNREGISTERED | Use this if you would like to remove unregistered torrents. (It will the delete data & torrent if it is not being cross-seeded, otherwise it will just remove the torrent without deleting data) | False |
|
| `-ru` or `--rem-unregistered` | QBT_REM_UNREGISTERED | Use this if you would like to remove unregistered torrents. (It will the delete data & torrent if it is not being cross-seeded, otherwise it will just remove the torrent without deleting data) | False |
|
||||||
| `-ro` or `--rem-orphaned` | QBT_REM_ORPHANED | Use this if you would like to remove orphaned files from your `root_dir` directory that are not referenced by any torrents. It will scan your `root_dir` directory and compare it with what is in qBittorrent. Any data not referenced in qBittorrent will be moved into `/data/torrents/orphaned_data` folder for you to review/delete. | False |
|
| `-ro` or `--rem-orphaned` | QBT_REM_ORPHANED | Use this if you would like to remove orphaned files from your `root_dir` directory that are not referenced by any torrents. It will scan your `root_dir` directory and compare it with what is in qBittorrent. Any data not referenced in qBittorrent will be moved into `/data/torrents/orphaned_data` folder for you to review/delete. | False |
|
||||||
| `-tnhl` or `--tag-nohardlinks` | QBT_TAG_NOHARDLINKS | Use this to tag any torrents that do not have any hard links associated with any of the files. This is useful for those that use Sonarr/Radarr that hard links your media files with the torrents for seeding. When files get upgraded they no longer become linked with your media therefore will be tagged with a new tag noHL. You can then safely delete/remove these torrents to free up any extra space that is not being used by your media folder. | False |
|
| `-tnhl` or `--tag-nohardlinks` | QBT_TAG_NOHARDLINKS | Use this to tag any torrents that do not have any hard links associated with any of the files. This is useful for those that use Sonarr/Radarr that hard links your media files with the torrents for seeding. When files get upgraded they no longer become linked with your media therefore will be tagged with a new tag noHL. You can then safely delete/remove these torrents to free up any extra space that is not being used by your media folder. | False |
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
2.1
|
2.2
|
|
@ -1,87 +0,0 @@
|
||||||
# qBittorrent parameters
|
|
||||||
qbt:
|
|
||||||
host: "localhost:8080"
|
|
||||||
user: "username"
|
|
||||||
pass: "password"
|
|
||||||
|
|
||||||
directory:
|
|
||||||
# Do not remove these
|
|
||||||
# Cross-seed var: </your/path/here/> #Output directory of cross-seed
|
|
||||||
# root_dir var: </your/path/here/> #Root downloads directory used to check for orphaned files and used in RecycleBin
|
|
||||||
# <OPTIONAL> remote_dir var: </your/path/here/> # Path of docker host mapping of root_dir. Must be set if you are using docker!
|
|
||||||
cross_seed: "/your/path/here/"
|
|
||||||
root_dir: "/data/torrents/"
|
|
||||||
remote_dir: "/mnt/user/data/torrents/"
|
|
||||||
|
|
||||||
# Category/Pathing Parameters
|
|
||||||
cat:
|
|
||||||
# <Category Name> : <save_path> #Path of your save directory. Can be a keyword or full path
|
|
||||||
movies: "/data/torrents/Movies"
|
|
||||||
tv: "TV"
|
|
||||||
|
|
||||||
# Tag Parameters
|
|
||||||
tags:
|
|
||||||
# <Tracker URL Keyword>: <Tag Name>
|
|
||||||
animebytes.tv: AnimeBytes
|
|
||||||
avistaz: Avistaz
|
|
||||||
beyond-hd: Beyond-HD
|
|
||||||
blutopia: Blutopia
|
|
||||||
cartoonchaos: CartoonChaos
|
|
||||||
digitalcore: DigitalCore
|
|
||||||
gazellegames: GGn
|
|
||||||
hdts: HDTorrents
|
|
||||||
landof.tv: BroadcasTheNet
|
|
||||||
myanonamouse: MaM
|
|
||||||
passthepopcorn: PassThePopcorn
|
|
||||||
privatehd: PrivateHD
|
|
||||||
tleechreload: TorrentLeech
|
|
||||||
torrentdb: TorrentDB
|
|
||||||
torrentleech: TorrentLeech
|
|
||||||
tv-vault: TV-Vault
|
|
||||||
|
|
||||||
#Tag Movies/Series that are not hard linked
|
|
||||||
nohardlinks:
|
|
||||||
# Mandatory to fill out directory parameter above to use this function (root_dir/remote_dir)
|
|
||||||
# This variable should be set to your category name of your completed movies/completed series in qbit. Acceptable variable can be any category you would like to tag if there are no hardlinks found
|
|
||||||
movies-completed:
|
|
||||||
#<OPTIONAL> exclude_tags var: Will exclude the following tags when searching through the category.
|
|
||||||
exclude_tags:
|
|
||||||
- Beyond-HD
|
|
||||||
- AnimeBytes
|
|
||||||
- MaM
|
|
||||||
#<OPTIONAL> cleanup var: WARNING!! Setting this as true Will remove and delete contents of any torrents that are in paused state and has the NoHL tag
|
|
||||||
cleanup: false
|
|
||||||
#<OPTIONAL> max_ratio var: Will set the torrent Maximum share ratio until torrent is stopped from seeding/uploading
|
|
||||||
max_ratio: 4.0
|
|
||||||
#<OPTIONAL> seeding time var: Will set the torrent Maximum seeding time (min) until torrent is stopped from seeding
|
|
||||||
max_seeding_time: 86400
|
|
||||||
|
|
||||||
#Can have additional categories set with separate ratio/seeding times defined.
|
|
||||||
series-completed:
|
|
||||||
#<OPTIONAL> exclude_tags var: Will exclude the following tags when searching through the category.
|
|
||||||
exclude_tags:
|
|
||||||
- Beyond-HD
|
|
||||||
- BroadcasTheNet
|
|
||||||
#<OPTIONAL> cleanup var: WARNING!! Setting this as true Will remove and delete contents of any torrents that are in paused state and has the NoHL tag
|
|
||||||
cleanup: false
|
|
||||||
#<OPTIONAL> max_ratio var: Will set the torrent Maximum share ratio until torrent is stopped from seeding/uploading
|
|
||||||
max_ratio: 4.0
|
|
||||||
#<OPTIONAL> seeding time var: Will set the torrent Maximum seeding time (min) until torrent is stopped from seeding
|
|
||||||
max_seeding_time: 86400
|
|
||||||
|
|
||||||
#Recycle Bin method of deletion will move files into the recycle bin instead of directly deleting them in qbit
|
|
||||||
recyclebin:
|
|
||||||
enabled: true
|
|
||||||
#<OPTIONAL> empty_after_x_days var: Will automatically remove all files and folders in recycle bin after x days.
|
|
||||||
# If this variable is not defined it, the RecycleBin will never be emptied.
|
|
||||||
# Setting this variable to 0 will delete files immediately.
|
|
||||||
empty_after_x_days: 60
|
|
||||||
|
|
||||||
# Orphaned files are those in the root_dir download directory that are not referenced by any active torrents.
|
|
||||||
orphaned:
|
|
||||||
# File patterns that will not be considered orphaned files. Handy for generated files that aren't part of the torrent but belong with the torrent's files
|
|
||||||
exclude_patterns:
|
|
||||||
- "**/.DS_Store"
|
|
||||||
- "**/Thumbs.db"
|
|
||||||
- "**/@eaDir"
|
|
||||||
- "/data/torrents/temp/**"
|
|
|
@ -20,17 +20,25 @@ cat:
|
||||||
movies: "/data/torrents/Movies"
|
movies: "/data/torrents/Movies"
|
||||||
tv: "TV"
|
tv: "TV"
|
||||||
|
|
||||||
# Tag Parameters
|
# Tag Parameters (Use either Format 1 or Format 2)
|
||||||
tags:
|
tags:
|
||||||
|
# Format 1
|
||||||
# <Tracker URL Keyword>: <Tag Name>
|
# <Tracker URL Keyword>: <Tag Name>
|
||||||
|
# Format 2
|
||||||
|
# <Tracker URL Keyword>:
|
||||||
|
# tag: <Tag Name>
|
||||||
|
# <MANDATORY> Will set the torrent Maximum share ratio until torrent is stopped from seeding/uploading. -2 means the global limit should be used, -1 means no limit.
|
||||||
|
# max_ratio: 5.0
|
||||||
|
# <OPTIONAL> Will set the torrent Maximum seeding time (min) until torrent is stopped from seeding. -2 means the global limit should be used, -1 means no limit.
|
||||||
|
# max_seeding_time: 129600
|
||||||
|
# <OPTIONAL> Will limit the upload speed KiB/s (KiloBytes/second) (-1 sets the limit to infinity)
|
||||||
|
# limit_upload_speed: 150
|
||||||
|
|
||||||
|
#Format 1 Examples
|
||||||
animebytes.tv: AnimeBytes
|
animebytes.tv: AnimeBytes
|
||||||
avistaz: Avistaz
|
|
||||||
beyond-hd: Beyond-HD
|
beyond-hd: Beyond-HD
|
||||||
blutopia: Blutopia
|
blutopia: Blutopia
|
||||||
cartoonchaos: CartoonChaos
|
cartoonchaos: CartoonChaos
|
||||||
digitalcore: DigitalCore
|
|
||||||
gazellegames: GGn
|
|
||||||
hdts: HDTorrents
|
|
||||||
landof.tv: BroadcasTheNet
|
landof.tv: BroadcasTheNet
|
||||||
myanonamouse: MaM
|
myanonamouse: MaM
|
||||||
passthepopcorn: PassThePopcorn
|
passthepopcorn: PassThePopcorn
|
||||||
|
@ -40,6 +48,22 @@ tags:
|
||||||
torrentleech: TorrentLeech
|
torrentleech: TorrentLeech
|
||||||
tv-vault: TV-Vault
|
tv-vault: TV-Vault
|
||||||
|
|
||||||
|
#Format 2 Examples
|
||||||
|
avistaz:
|
||||||
|
tag: Avistaz
|
||||||
|
max_ratio: 5.0
|
||||||
|
max_seeding_time: 129600
|
||||||
|
limit_upload_speed: 150
|
||||||
|
digitalcore
|
||||||
|
tag: DigitalCore
|
||||||
|
max_ratio: 5.0
|
||||||
|
gazellegames:
|
||||||
|
tag: GGn
|
||||||
|
limit_upload_speed: 150
|
||||||
|
hdts:
|
||||||
|
tag: HDTorrents
|
||||||
|
max_seeding_time: 129600
|
||||||
|
|
||||||
#Tag Movies/Series that are not hard linked
|
#Tag Movies/Series that are not hard linked
|
||||||
nohardlinks:
|
nohardlinks:
|
||||||
# Mandatory to fill out directory parameter above to use this function (root_dir/remote_dir)
|
# Mandatory to fill out directory parameter above to use this function (root_dir/remote_dir)
|
||||||
|
|
171
qbit_manage.py
171
qbit_manage.py
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
|
|
||||||
import argparse, logging, os, sys, time, shutil, urllib3, stat, fnmatch
|
import argparse, logging, os, sys, time, shutil, stat, fnmatch
|
||||||
from logging.handlers import RotatingFileHandler
|
from logging.handlers import RotatingFileHandler
|
||||||
from datetime import timedelta,datetime
|
from datetime import timedelta,datetime
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
@ -8,7 +8,7 @@ from pathlib import Path
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import yaml, schedule
|
import yaml, schedule
|
||||||
from qbittorrentapi import Client
|
from qbittorrentapi import Client, LoginFailed, APIConnectionError
|
||||||
from modules.docker import GracefulKiller
|
from modules.docker import GracefulKiller
|
||||||
from modules import util
|
from modules import util
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
|
@ -28,7 +28,7 @@ parser.add_argument('-lf', '--log-file', dest='logfile', action='store',default=
|
||||||
parser.add_argument('-cs', '--cross-seed', dest='cross_seed', action="store_true", default=False, help='Use this after running cross-seed script to add torrents from the cross-seed output folder to qBittorrent')
|
parser.add_argument('-cs', '--cross-seed', dest='cross_seed', action="store_true", default=False, help='Use this after running cross-seed script to add torrents from the cross-seed output folder to qBittorrent')
|
||||||
parser.add_argument('-re', '--recheck', dest='recheck', action="store_true", default=False, help='Recheck paused torrents sorted by lowest size. Resume if Completed.')
|
parser.add_argument('-re', '--recheck', dest='recheck', action="store_true", default=False, help='Recheck paused torrents sorted by lowest size. Resume if Completed.')
|
||||||
parser.add_argument('-cu', '--cat-update', dest='cat_update', action="store_true", default=False, help='Use this if you would like to update your categories.')
|
parser.add_argument('-cu', '--cat-update', dest='cat_update', action="store_true", default=False, help='Use this if you would like to update your categories.')
|
||||||
parser.add_argument('-tu', '--tag-update', dest='tag_update', action="store_true", default=False, help='Use this if you would like to update your tags. (Only adds tags to untagged torrents)')
|
parser.add_argument('-tu', '--tag-update', dest='tag_update', action="store_true", default=False, help='Use this if you would like to update your tags and/or set seed goals/limit upload speed by tag. (Only adds tags to untagged torrents)')
|
||||||
parser.add_argument('-ru', '--rem-unregistered', dest='rem_unregistered', action="store_true", default=False, help='Use this if you would like to remove unregistered torrents.')
|
parser.add_argument('-ru', '--rem-unregistered', dest='rem_unregistered', action="store_true", default=False, help='Use this if you would like to remove unregistered torrents.')
|
||||||
parser.add_argument('-ro', '--rem-orphaned', dest='rem_orphaned', action="store_true", default=False, help='Use this if you would like to remove unregistered torrents.')
|
parser.add_argument('-ro', '--rem-orphaned', dest='rem_orphaned', action="store_true", default=False, help='Use this if you would like to remove unregistered torrents.')
|
||||||
parser.add_argument('-tnhl', '--tag-nohardlinks', dest='tag_nohardlinks', action="store_true", default=False, help='Use this to tag any torrents that do not have any hard links associated with any of the files. This is useful for those that use Sonarr/Radarr which hard link your media files with the torrents for seeding. When files get upgraded they no longer become linked with your media therefore will be tagged with a new tag noHL. You can then safely delete/remove these torrents to free up any extra space that is not being used by your media folder.')
|
parser.add_argument('-tnhl', '--tag-nohardlinks', dest='tag_nohardlinks', action="store_true", default=False, help='Use this to tag any torrents that do not have any hard links associated with any of the files. This is useful for those that use Sonarr/Radarr which hard link your media files with the torrents for seeding. When files get upgraded they no longer become linked with your media therefore will be tagged with a new tag noHL. You can then safely delete/remove these torrents to free up any extra space that is not being used by your media folder.')
|
||||||
|
@ -132,8 +132,6 @@ else:
|
||||||
|
|
||||||
|
|
||||||
os.makedirs(os.path.join(default_dir, "logs"), exist_ok=True)
|
os.makedirs(os.path.join(default_dir, "logs"), exist_ok=True)
|
||||||
urllib3.disable_warnings()
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger('qBit Manage')
|
logger = logging.getLogger('qBit Manage')
|
||||||
logging.DRYRUN = 25
|
logging.DRYRUN = 25
|
||||||
|
@ -180,10 +178,12 @@ if 'pass' in cfg['qbt']:
|
||||||
else:
|
else:
|
||||||
password = ''
|
password = ''
|
||||||
|
|
||||||
client = Client(host=host,
|
client = Client(host=host, username=username, password=password)
|
||||||
username=username,
|
try:
|
||||||
password=password)
|
client.auth_log_in()
|
||||||
|
except (LoginFailed,APIConnectionError)as e:
|
||||||
|
logger.error(e)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
############FUNCTIONS##############
|
############FUNCTIONS##############
|
||||||
#truncate the value of the torrent url to remove sensitive information
|
#truncate the value of the torrent url to remove sensitive information
|
||||||
|
@ -203,24 +203,42 @@ def get_category(path):
|
||||||
category = ''
|
category = ''
|
||||||
return category
|
return category
|
||||||
category = ''
|
category = ''
|
||||||
logger.warning('No categories matched. Check your config.yml file. - Setting category to NULL')
|
logger.warning(f'No categories matched for the save path {path}. Check your config.yml file. - Setting category to NULL')
|
||||||
return category
|
return category
|
||||||
|
|
||||||
#Get tags from config file based on keyword
|
#Get tags from config file based on keyword
|
||||||
def get_tags(urls):
|
def get_tags(urls):
|
||||||
if 'tags' in cfg and cfg["tags"] != None:
|
new_tag = ''
|
||||||
tag_path = cfg['tags']
|
max_ratio = ''
|
||||||
for i, f in tag_path.items():
|
max_seeding_time = ''
|
||||||
for url in urls:
|
limit_upload_speed = ''
|
||||||
if i in url:
|
url = trunc_val(urls[0], '/')
|
||||||
tag = f
|
if 'tags' in cfg and cfg["tags"] != None and urls:
|
||||||
if tag: return tag,trunc_val(url, '/')
|
tag_values = cfg['tags']
|
||||||
|
for tag_url, tag_details in tag_values.items():
|
||||||
|
new_tag = ''
|
||||||
|
max_ratio = ''
|
||||||
|
max_seeding_time = ''
|
||||||
|
limit_upload_speed = ''
|
||||||
|
# If using Format 1
|
||||||
|
if(type(tag_details) == str):
|
||||||
|
new_tag = tag_details
|
||||||
|
# Using Format 2
|
||||||
else:
|
else:
|
||||||
tag = ('','')
|
if 'tag' in tag_details:
|
||||||
return tag
|
new_tag = tag_details['tag']
|
||||||
tag = ('','')
|
else:
|
||||||
logger.warning('No tags matched. Check your config.yml file. Setting tag to NULL')
|
logger.warning(f'No tags defined for {tag_url}. Please check your config.yml file.')
|
||||||
return tag
|
if 'max_ratio' in tag_details: max_ratio = tag_details['max_ratio']
|
||||||
|
if 'max_seeding_time' in tag_details: max_seeding_time = tag_details['max_seeding_time']
|
||||||
|
if 'limit_upload_speed' in tag_details: limit_upload_speed = tag_details['limit_upload_speed']
|
||||||
|
for url in urls:
|
||||||
|
if tag_url in url:
|
||||||
|
return (new_tag,trunc_val(url, '/'),max_ratio,max_seeding_time,limit_upload_speed)
|
||||||
|
else:
|
||||||
|
return (new_tag,url,max_ratio,max_seeding_time,limit_upload_speed)
|
||||||
|
logger.warning(f'No tags matched for {url}. Please check your config.yml file. Setting tag to NULL')
|
||||||
|
return (new_tag,url,max_ratio,max_seeding_time,limit_upload_speed)
|
||||||
|
|
||||||
|
|
||||||
#Move files from source to destination, mod variable is to change the date modified of the file being moved
|
#Move files from source to destination, mod variable is to change the date modified of the file being moved
|
||||||
|
@ -266,6 +284,8 @@ def get_torrent_info(t_list):
|
||||||
save_path = torrent.save_path
|
save_path = torrent.save_path
|
||||||
category = get_category(save_path)
|
category = get_category(save_path)
|
||||||
is_complete = False
|
is_complete = False
|
||||||
|
msg = None
|
||||||
|
status = None
|
||||||
if torrent.name in torrentdict:
|
if torrent.name in torrentdict:
|
||||||
t_count = torrentdict[torrent.name]['count'] + 1
|
t_count = torrentdict[torrent.name]['count'] + 1
|
||||||
msg_list = torrentdict[torrent.name]['msg']
|
msg_list = torrentdict[torrent.name]['msg']
|
||||||
|
@ -278,9 +298,12 @@ def get_torrent_info(t_list):
|
||||||
status_list = []
|
status_list = []
|
||||||
is_complete = torrent.state_enum.is_complete
|
is_complete = torrent.state_enum.is_complete
|
||||||
first_hash = torrent.hash
|
first_hash = torrent.hash
|
||||||
|
try:
|
||||||
msg,status = [(x.msg,x.status) for x in torrent.trackers if x.url.startswith('http')][0]
|
msg,status = [(x.msg,x.status) for x in torrent.trackers if x.url.startswith('http')][0]
|
||||||
msg_list.append(msg)
|
except IndexError:
|
||||||
status_list.append(status)
|
pass
|
||||||
|
if msg != None: msg_list.append(msg)
|
||||||
|
if status != None: status_list.append(status)
|
||||||
torrentattr = {'Category': category, 'save_path': save_path, 'count': t_count, 'msg': msg_list, 'status': status_list, 'is_complete': is_complete, 'first_hash':first_hash}
|
torrentattr = {'Category': category, 'save_path': save_path, 'count': t_count, 'msg': msg_list, 'status': status_list, 'is_complete': is_complete, 'first_hash':first_hash}
|
||||||
torrentdict[torrent.name] = torrentattr
|
torrentdict[torrent.name] = torrentattr
|
||||||
return torrentdict
|
return torrentdict
|
||||||
|
@ -293,8 +316,7 @@ def set_recheck():
|
||||||
torrent_sorted_list = client.torrents.info(status_filter='paused',sort='size')
|
torrent_sorted_list = client.torrents.info(status_filter='paused',sort='size')
|
||||||
if torrent_sorted_list:
|
if torrent_sorted_list:
|
||||||
for torrent in torrent_sorted_list:
|
for torrent in torrent_sorted_list:
|
||||||
new_tag,t_url = get_tags([x.url for x in torrent.trackers if x.url.startswith('http')])
|
new_tag = get_tags([x.url for x in torrent.trackers if x.url.startswith('http')])[0]
|
||||||
if torrent.tags == '' or ('cross-seed' in torrent.tags and len([e for e in torrent.tags.split(",") if not 'noHL' in e]) == 1): torrent.add_tags(tags=new_tag)
|
|
||||||
#Resume torrent if completed
|
#Resume torrent if completed
|
||||||
if torrent.progress == 1:
|
if torrent.progress == 1:
|
||||||
#Check to see if torrent meets AutoTorrentManagement criteria
|
#Check to see if torrent meets AutoTorrentManagement criteria
|
||||||
|
@ -304,16 +326,16 @@ def set_recheck():
|
||||||
logger.debug(util.insert_space(f'-- Seeding Time vs Max Seed Time: {timedelta(seconds=torrent.seeding_time)} < {timedelta(minutes=torrent.max_seeding_time)}',4))
|
logger.debug(util.insert_space(f'-- Seeding Time vs Max Seed Time: {timedelta(seconds=torrent.seeding_time)} < {timedelta(minutes=torrent.max_seeding_time)}',4))
|
||||||
if torrent.ratio < torrent.max_ratio and (torrent.seeding_time < (torrent.max_seeding_time * 60)):
|
if torrent.ratio < torrent.max_ratio and (torrent.seeding_time < (torrent.max_seeding_time * 60)):
|
||||||
if dry_run:
|
if dry_run:
|
||||||
logger.dryrun(f'Not Resuming {new_tag} - {torrent.name}')
|
logger.dryrun(f'Not Resuming [{new_tag}] - {torrent.name}')
|
||||||
else:
|
else:
|
||||||
logger.info(f'Resuming {new_tag} - {torrent.name}')
|
logger.info(f'Resuming [{new_tag}] - {torrent.name}')
|
||||||
torrent.resume()
|
torrent.resume()
|
||||||
#Recheck
|
#Recheck
|
||||||
elif torrent.progress == 0 and torrentdict[torrent.name]['is_complete'] and not torrent.state_enum.is_checking:
|
elif torrent.progress == 0 and torrentdict[torrent.name]['is_complete'] and not torrent.state_enum.is_checking:
|
||||||
if dry_run:
|
if dry_run:
|
||||||
logger.dryrun(f'Not Rechecking {new_tag} - {torrent.name}')
|
logger.dryrun(f'Not Rechecking [{new_tag}] - {torrent.name}')
|
||||||
else:
|
else:
|
||||||
logger.info(f'Rechecking {new_tag} - {torrent.name}')
|
logger.info(f'Rechecking [{new_tag}] - {torrent.name}')
|
||||||
torrent.recheck()
|
torrent.recheck()
|
||||||
|
|
||||||
# Function used to move any torrents from the cross seed directory to the correct save directory
|
# Function used to move any torrents from the cross seed directory to the correct save directory
|
||||||
|
@ -406,10 +428,11 @@ def set_category():
|
||||||
num_cat = 0
|
num_cat = 0
|
||||||
for torrent in torrent_list:
|
for torrent in torrent_list:
|
||||||
if torrent.category == '':
|
if torrent.category == '':
|
||||||
for x in torrent.trackers:
|
|
||||||
if x.url.startswith('http'):
|
|
||||||
t_url = trunc_val(x.url, '/')
|
|
||||||
new_cat = get_category(torrent.save_path)
|
new_cat = get_category(torrent.save_path)
|
||||||
|
try:
|
||||||
|
t_url = [trunc_val(x.url, '/') for x in torrent.trackers if x.url.startswith('http')][0]
|
||||||
|
except IndexError:
|
||||||
|
t_url = None
|
||||||
if dry_run:
|
if dry_run:
|
||||||
logger.dryrun(util.insert_space(f'Torrent Name: {torrent.name}',3))
|
logger.dryrun(util.insert_space(f'Torrent Name: {torrent.name}',3))
|
||||||
logger.dryrun(util.insert_space(f'New Category: {new_cat}',3))
|
logger.dryrun(util.insert_space(f'New Category: {new_cat}',3))
|
||||||
|
@ -439,18 +462,84 @@ def set_tags():
|
||||||
num_tags = 0
|
num_tags = 0
|
||||||
for torrent in torrent_list:
|
for torrent in torrent_list:
|
||||||
if torrent.tags == '' or ('cross-seed' in torrent.tags and len([e for e in torrent.tags.split(",") if not 'noHL' in e]) == 1):
|
if torrent.tags == '' or ('cross-seed' in torrent.tags and len([e for e in torrent.tags.split(",") if not 'noHL' in e]) == 1):
|
||||||
new_tag,t_url = get_tags([x.url for x in torrent.trackers if x.url.startswith('http')])
|
new_tag,url,max_ratio,max_seeding_time,limit_upload_speed = get_tags([x.url for x in torrent.trackers if x.url.startswith('http')])
|
||||||
|
if new_tag:
|
||||||
if dry_run:
|
if dry_run:
|
||||||
|
num_tags += 1
|
||||||
logger.dryrun(util.insert_space(f'Torrent Name: {torrent.name}',3))
|
logger.dryrun(util.insert_space(f'Torrent Name: {torrent.name}',3))
|
||||||
logger.dryrun(util.insert_space(f'New Tag: {new_tag}',8))
|
logger.dryrun(util.insert_space(f'New Tag: {new_tag}',8))
|
||||||
logger.dryrun(util.insert_space(f'Tracker: {t_url}',8))
|
logger.dryrun(util.insert_space(f'Tracker: {url}',8))
|
||||||
num_tags += 1
|
if limit_upload_speed:
|
||||||
|
if limit_upload_speed == -1:
|
||||||
|
logger.dryrun(util.insert_space(f'Limit UL Speed: Infinity',1))
|
||||||
|
else:
|
||||||
|
logger.dryrun(util.insert_space(f'Limit UL Speed: {limit_upload_speed} kB/s',1))
|
||||||
|
if max_ratio:
|
||||||
|
if max_ratio == -2:
|
||||||
|
logger.dryrun(util.insert_space(f'Share Limit: Use Global Share Limit',4))
|
||||||
|
continue
|
||||||
|
elif max_ratio == -1:
|
||||||
|
logger.dryrun(util.insert_space(f'Share Limit: Set No Share Limit',4))
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
max_ratio = torrent.max_ratio
|
||||||
|
if max_seeding_time:
|
||||||
|
if max_seeding_time == -2:
|
||||||
|
logger.dryrun(util.insert_space(f'Share Limit: Use Global Share Limit',4))
|
||||||
|
continue
|
||||||
|
elif max_seeding_time == -1:
|
||||||
|
logger.dryrun(util.insert_space(f'Share Limit: Set No Share Limit',4))
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
max_seeding_time = torrent.max_seeding_time
|
||||||
|
if max_ratio != torrent.max_ratio and max_seeding_time != torrent.max_seeding_time:
|
||||||
|
logger.dryrun(util.insert_space(f'Share Limit: Max Ratio = {max_ratio}, Max Seed Time = {max_seeding_time} min',4))
|
||||||
|
elif max_ratio != torrent.max_ratio:
|
||||||
|
logger.dryrun(util.insert_space(f'Share Limit: Max Ratio = {max_ratio}',4))
|
||||||
|
elif max_seeding_time != torrent.max_seeding_time:
|
||||||
|
logger.dryrun(util.insert_space(f'Share Limit: Max Seed Time = {max_seeding_time} min',4))
|
||||||
else:
|
else:
|
||||||
logger.info(util.insert_space(f'Torrent Name: {torrent.name}',3))
|
|
||||||
logger.info(util.insert_space(f'New Tag: {new_tag}',8))
|
|
||||||
logger.info(util.insert_space(f'Tracker: {t_url}',8))
|
|
||||||
torrent.add_tags(tags=new_tag)
|
torrent.add_tags(tags=new_tag)
|
||||||
num_tags += 1
|
num_tags += 1
|
||||||
|
logger.info(util.insert_space(f'Torrent Name: {torrent.name}',3))
|
||||||
|
logger.info(util.insert_space(f'New Tag: {new_tag}',8))
|
||||||
|
logger.info(util.insert_space(f'Tracker: {url}',8))
|
||||||
|
if limit_upload_speed:
|
||||||
|
if limit_upload_speed == -1:
|
||||||
|
logger.info(util.insert_space(f'Limit UL Speed: Infinity',1))
|
||||||
|
else:
|
||||||
|
logger.info(util.insert_space(f'Limit UL Speed: {limit_upload_speed} kB/s',1))
|
||||||
|
torrent.set_upload_limit(limit_upload_speed*1024)
|
||||||
|
if max_ratio:
|
||||||
|
if max_ratio == -2:
|
||||||
|
logger.info(util.insert_space(f'Share Limit: Use Global Share Limit',4))
|
||||||
|
torrent.set_share_limits(-2,-2)
|
||||||
|
continue
|
||||||
|
elif max_ratio == -1:
|
||||||
|
logger.info(util.insert_space(f'Share Limit: Set No Share Limit',4))
|
||||||
|
torrent.set_share_limits(-1,-1)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
max_ratio = torrent.max_ratio
|
||||||
|
if max_seeding_time:
|
||||||
|
if max_seeding_time == -2:
|
||||||
|
logger.info(util.insert_space(f'Share Limit: Use Global Share Limit',4))
|
||||||
|
torrent.set_share_limits(-2,-2)
|
||||||
|
continue
|
||||||
|
elif max_seeding_time == -1:
|
||||||
|
logger.info(util.insert_space(f'Share Limit: Set No Share Limit',4))
|
||||||
|
torrent.set_share_limits(-1,-1)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
max_seeding_time = torrent.max_seeding_time
|
||||||
|
if max_ratio != torrent.max_ratio and max_seeding_time != torrent.max_seeding_time:
|
||||||
|
logger.info(util.insert_space(f'Share Limit: Max Ratio = {max_ratio}, Max Seed Time = {max_seeding_time} min',4))
|
||||||
|
elif max_ratio != torrent.max_ratio:
|
||||||
|
logger.info(util.insert_space(f'Share Limit: Max Ratio = {max_ratio}',4))
|
||||||
|
elif max_seeding_time != torrent.max_seeding_time:
|
||||||
|
logger.info(util.insert_space(f'Share Limit: Max Seed Time = {max_seeding_time} min',4))
|
||||||
|
torrent.set_share_limits(max_ratio,max_seeding_time)
|
||||||
|
|
||||||
if dry_run:
|
if dry_run:
|
||||||
if num_tags >= 1:
|
if num_tags >= 1:
|
||||||
logger.dryrun(f'Did not update {num_tags} new tags.')
|
logger.dryrun(f'Did not update {num_tags} new tags.')
|
||||||
|
@ -552,6 +641,7 @@ def set_rem_unregistered():
|
||||||
def set_rem_orphaned():
|
def set_rem_orphaned():
|
||||||
if rem_orphaned:
|
if rem_orphaned:
|
||||||
util.separator(f"Checking for Orphaned Files", space=False, border=False)
|
util.separator(f"Checking for Orphaned Files", space=False, border=False)
|
||||||
|
global torrent_list
|
||||||
torrent_files = []
|
torrent_files = []
|
||||||
root_files = []
|
root_files = []
|
||||||
orphaned_files = []
|
orphaned_files = []
|
||||||
|
@ -563,6 +653,9 @@ def set_rem_orphaned():
|
||||||
else:
|
else:
|
||||||
root_files = [os.path.join(path, name) for path, subdirs, files in os.walk(root_path) for name in files if os.path.join(root_path,'orphaned_data') not in path and os.path.join(root_path,'.RecycleBin') not in path]
|
root_files = [os.path.join(path, name) for path, subdirs, files in os.walk(root_path) for name in files if os.path.join(root_path,'orphaned_data') not in path and os.path.join(root_path,'.RecycleBin') not in path]
|
||||||
|
|
||||||
|
#Get an updated list of torrents
|
||||||
|
torrent_list = client.torrents.info(sort='added_on')
|
||||||
|
|
||||||
for torrent in torrent_list:
|
for torrent in torrent_list:
|
||||||
for file in torrent.files:
|
for file in torrent.files:
|
||||||
torrent_files.append(os.path.join(torrent.save_path,file.name))
|
torrent_files.append(os.path.join(torrent.save_path,file.name))
|
||||||
|
|
BIN
qbm_logo.png
Normal file
BIN
qbm_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 316 KiB |
Loading…
Add table
Reference in a new issue