Merge branch 'develop'

This commit is contained in:
Jon 2021-09-28 09:30:08 -04:00
commit 57b2a1b28b
No known key found for this signature in database
GPG key ID: 9665BA6CF5DC2671
3 changed files with 162 additions and 5 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
*.log
*.yml
.vscode/settings.json

View file

@ -35,3 +35,24 @@ tags:
hdts: HDTorrents
tv-vault: TV-Vault
cartoonchaos: CartoonChaos
#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> 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> 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

View file

@ -64,6 +64,13 @@ parser.add_argument('-ro', '--rem-orphaned',
help='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 Qbitorrent. Any data not referenced in Qbitorrent will be moved into '
' `/data/torrents/orphaned_data` folder for you to review/delete.')
parser.add_argument('-tnhl', '--tag-nohardlinks',
dest='tag_nohardlinks',
action='store_const',
const='tag_nohardlinks',
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'
'to 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('--dry-run',
dest='dry_run',
action='store_const',
@ -146,7 +153,7 @@ def get_tags(urls):
if i in url:
tag = f
if tag: return tag,trunc_val(url, '/')
tag = ''
tag = ('','')
logger.warning('No tags matched. Check your config.yml file. Setting tag to NULL')
return tag
@ -154,13 +161,13 @@ def remove_empty_directories(pathlib_root_dir):
# list all directories recursively and sort them by path,
# longest first
L = sorted(
pathlib_root_dir.glob("**"),
pathlib_root_dir.glob("*/*"),
key=lambda p: len(str(p)),
reverse=True,
)
for pdir in L:
try:
pdir.rmdir() # remove directory if empty
pdir.rmdir() # remove directory if empty
except OSError:
continue # catch and continue if non-empty
@ -195,7 +202,7 @@ def recheck():
torrentdict = get_torrent_info(client.torrents.info(sort='added_on',reverse=True))
for torrent in torrent_sorted_list:
new_tag,t_url = get_tags([x.url for x in torrent.trackers if x.url.startswith('http')])
if torrent.tags == '': torrent.add_tags(tags=new_tag)
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
if torrent.progress == 1:
if args.dry_run == 'dry_run':
@ -316,7 +323,7 @@ def update_tags():
num_tags = 0
torrent_list = client.torrents.info(sort='added_on',reverse=True)
for torrent in torrent_list:
if torrent.tags == '':
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')])
if args.dry_run == 'dry_run':
logger.dryrun(f'\n - Torrent Name: {torrent.name}'
@ -464,6 +471,133 @@ def rem_orphaned():
else:
logger.info('No Orphaned Files found.')
def tag_nohardlinks():
if args.tag_nohardlinks == 'tag_nohardlinks':
nohardlinks = cfg['nohardlinks']
if 'root_dir' in cfg['directory']:
root_path = os.path.join(cfg['directory']['root_dir'], '')
else:
logger.error('root_dir not defined in config.')
return
if 'remote_dir' in cfg['directory']:
remote_path = os.path.join(cfg['directory']['remote_dir'], '')
else:
remote_path = root_path
for category in nohardlinks:
t_count = 0 #counter for the number of torrents that has no hard links
t_del = 0 #counter for the number of torrents that has no hard links and meets the criteria for ratio limit/seed limit for deletion
t_del_cs = 0 #counter for the number of torrents that has no hard links and meets the criteria for ratio limit/seed limit for deletion including cross-seeds
n_info = ''
tdel_dict = {} #dictionary to track the torrent names and content path that meet the deletion criteria
torrent_list = client.torrents.info(category=category,filter='completed')
if len(torrent_list) == 0:
logger.error('The category ('+category+') defined in config.yml inside the nohardlinks section does not match any category in qbittorrent. Please make sure the category defined in config matches with one in qbittorrent.')
continue
for torrent in torrent_list:
if args.dry_run != 'dry_run':
torrent.resume()
#Checks for any hard links and not already tagged
if (nohardlink(torrent['content_path'].replace(root_path,remote_path))):
#Will only tag new torrents that don't have noHL tag
if('noHL' not in torrent.tags):
t_count += 1
n_info += (f'\n - Torrent Name: {torrent.name} has no hard links found.')
n_info += (' Adding tags noHL.')
if(nohardlinks[category] != None):
#set the max seeding time for the torrent
if ('max_seeding_time' in nohardlinks[category]):
seeding_time_limit = nohardlinks[category]['max_seeding_time']
n_info += (' \n Setting max seed time to ' + str(seeding_time_limit) + '.')
else:
seeding_time_limit = -2
#set the max ratio for the torrent
if ('max_ratio' in nohardlinks[category]):
ratio_limit = nohardlinks[category]['max_ratio']
n_info += (' \n Setting max ratio to ' + str(ratio_limit)+ '.')
else:
ratio_limit = -2
else:
seeding_time_limit = -2
ratio_limit = -2
if args.dry_run != 'dry_run':
#set the tag for no hard links
torrent.add_tags(tags='noHL')
client.torrents_set_share_limits(ratio_limit,seeding_time_limit,torrent.hash)
#Cleans up previously tagged noHL torrents
else:
if(nohardlinks[category] != None):
# Deletes torrent with data if cleanup is set to true and meets the ratio/seeding requirements
if ('cleanup' in nohardlinks[category] and nohardlinks[category]['cleanup'] and torrent.state_enum.is_paused and len(nohardlinks[category])>0):
t_del += 1
n_info += (f'\n - Torrent Name: {torrent.name} has no hard links found and meets ratio/seeding requirements.')
tdel_dict[torrent.name] = torrent['content_path'].replace(root_path,remote_path)
if args.dry_run == 'dry_run':
n_info += (' \n Cleanup flag set to true. NOT Deleting torrent + contents.')
else:
n_info += (' \n Cleanup flag set to true. Deleting torrent + contents.')
if(nohardlinks[category] != None):
#loop through torrent list again for cleanup purposes
if ('cleanup' in nohardlinks[category] and nohardlinks[category]['cleanup']):
for torrent in torrent_list:
if torrent.name in tdel_dict.keys() and 'noHL' in torrent.tags:
#Double check that the content path is the same before we delete anything
if torrent['content_path'].replace(root_path,remote_path) == tdel_dict[torrent.name]:
t_del_cs += 1
if args.dry_run != 'dry_run':
if (os.path.exists(torrent['content_path'].replace(root_path,remote_path))):
torrent.delete(hash=torrent.hash, delete_files=True)
else:
torrent.delete(hash=torrent.hash, delete_files=False)
#Checks to see if previous noHL tagged torrents now have hard links.
if (not (nohardlink(torrent['content_path'].replace(root_path,remote_path))) and ('noHL' in torrent.tags)):
n_info += (f'\n - Previous Tagged noHL Torrent Name: {torrent.name} has hard links found now.')
n_info += (' Removing tags noHL.')
n_info += (' Removing ratio and seeding time limits.')
if args.dry_run != 'dry_run':
#Remove tags and share limits
torrent.remove_tags(tags='noHL')
client.torrents_set_share_limits(-2,-2,torrent.hash)
if args.dry_run == 'dry_run':
if t_count >= 1 or len(n_info) > 1:
logger.dryrun(n_info)
logger.dryrun(f'Did not tag/set ratio limit/seeding time for {t_count} .torrents(s)')
if t_del >= 1:
logger.dryrun(f'Did not delete {t_del} .torrents(s) or content files.')
logger.dryrun(f'Did not delete {t_del_cs} .torrents(s) (including cross-seed) or content files.')
else:
logger.dryrun('No torrents to tag with no hard links.')
else:
if t_count >= 1 or len(n_info) > 1:
logger.info(n_info)
logger.info(f'tag/set ratio limit/seeding time for {t_count} .torrents(s)')
if t_del >= 1:
logger.info(f'Deleted {t_del} .torrents(s) AND content files.')
logger.info(f'Deleted {t_del_cs} .torrents(s) (includes cross-seed torrents) AND content files.')
else:
logger.info('No torrents to tag with no hard links.')
#will check if there are any hard links if it passes a file or folder
def nohardlink(file):
check = True
if (os.path.isfile(file)):
if (os.stat(file).st_nlink > 1):
check = False
else:
for path, subdirs, files in os.walk(file):
for x in files:
if (os.stat(os.path.join(path,x)).st_nlink > 1):
check = False
return check
def run():
update_category()
@ -472,6 +606,7 @@ def run():
cross_seed()
recheck()
rem_orphaned()
tag_nohardlinks()
if __name__ == '__main__':
run()