mirror of
https://github.com/StuffAnThings/qbit_manage.git
synced 2025-10-08 21:06:28 +08:00
Merge pull request #53 from StuffAnThings/develop
This commit is contained in:
commit
43764a826e
5 changed files with 39 additions and 30 deletions
24
Dockerfile
24
Dockerfile
|
@ -1,15 +1,11 @@
|
||||||
FROM python:3.9-slim
|
FROM hotio/base:alpine
|
||||||
RUN echo "**** install system packages ****" \
|
|
||||||
&& apt-get update \
|
RUN apk add --no-cache py3-pip
|
||||||
&& apt-get upgrade -y --no-install-recommends \
|
COPY --chown=hotio:users requirements.txt /
|
||||||
&& apt-get install -y tzdata --no-install-recommends \
|
|
||||||
&& apt-get install -y gcc g++ libxml2-dev libxslt-dev libz-dev
|
|
||||||
COPY requirements.txt /
|
|
||||||
RUN echo "**** install python packages ****" \
|
RUN echo "**** install python packages ****" \
|
||||||
&& pip3 install --no-cache-dir --upgrade --requirement /requirements.txt \
|
&& pip3 install --user --no-cache-dir --upgrade --requirement /requirements.txt \
|
||||||
&& apt-get autoremove -y \
|
&& rm -rf /requirements.txt /tmp/* /var/tmp/*
|
||||||
&& apt-get clean \
|
|
||||||
&& rm -rf /requirements.txt /tmp/* /var/tmp/* /var/lib/apt/lists/*
|
COPY --chown=hotio:users . "${APP_DIR}"
|
||||||
COPY . /
|
WORKDIR ${APP_DIR}
|
||||||
VOLUME /config
|
ENTRYPOINT ["python3", "qbit_manage.py"]
|
||||||
ENTRYPOINT ["python3","qbit_manage.py"]
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
3.0.0
|
3.0.1
|
|
@ -57,7 +57,7 @@ class Config:
|
||||||
self.nohardlinks[cat]['max_seeding_time'] = self.util.check_for_attribute(self.data, "max_seeding_time", parent="nohardlinks", subparent=cat, var_type="int", default_int=-2, default_is_none=True,do_print=False)
|
self.nohardlinks[cat]['max_seeding_time'] = self.util.check_for_attribute(self.data, "max_seeding_time", parent="nohardlinks", subparent=cat, var_type="int", default_int=-2, default_is_none=True,do_print=False)
|
||||||
self.nohardlinks[cat]['limit_upload_speed'] = self.util.check_for_attribute(self.data, "limit_upload_speed", parent="nohardlinks", subparent=cat, var_type="int", default_int=-1, default_is_none=True,do_print=False)
|
self.nohardlinks[cat]['limit_upload_speed'] = self.util.check_for_attribute(self.data, "limit_upload_speed", parent="nohardlinks", subparent=cat, var_type="int", default_int=-1, default_is_none=True,do_print=False)
|
||||||
else:
|
else:
|
||||||
raise Failed(f"Config Error: Category {cat} is defined under nohardlinks attribute but is not defined in the cat attriute.")
|
raise Failed(f"Config Error: Category {cat} is defined under nohardlinks attribute but is not defined in the cat attribute.")
|
||||||
else:
|
else:
|
||||||
if self.args["tag_nohardlinks"]:
|
if self.args["tag_nohardlinks"]:
|
||||||
raise Failed("Config Error: nohardlinks attribute not found")
|
raise Failed("Config Error: nohardlinks attribute not found")
|
||||||
|
@ -129,7 +129,11 @@ class Config:
|
||||||
if isinstance(tag_details,str):
|
if isinstance(tag_details,str):
|
||||||
tags['new_tag'] = self.util.check_for_attribute(self.data, tag_url, parent="tags",default=default_tag)
|
tags['new_tag'] = self.util.check_for_attribute(self.data, tag_url, parent="tags",default=default_tag)
|
||||||
self.util.check_for_attribute(self.data, "tag", parent="tags",subparent=tag_url, default=tags['new_tag'],do_print=False)
|
self.util.check_for_attribute(self.data, "tag", parent="tags",subparent=tag_url, default=tags['new_tag'],do_print=False)
|
||||||
if tags['new_tag'] == default_tag: self.data['tags'][tag_url]['tag'] = default_tag
|
if tags['new_tag'] == default_tag:
|
||||||
|
try:
|
||||||
|
self.data['tags'][tag_url]['tag'] = default_tag
|
||||||
|
except Exception as e:
|
||||||
|
self.data['tags'][tag_url] = {'tag': default_tag}
|
||||||
# Using Format 2
|
# Using Format 2
|
||||||
else:
|
else:
|
||||||
tags['new_tag'] = self.util.check_for_attribute(self.data, "tag", parent="tags", subparent=tag_url, default=tag_url)
|
tags['new_tag'] = self.util.check_for_attribute(self.data, "tag", parent="tags", subparent=tag_url, default=tag_url)
|
||||||
|
@ -141,7 +145,10 @@ class Config:
|
||||||
if tags['url']:
|
if tags['url']:
|
||||||
default_tag = tags['url'].split('/')[2].split(':')[0]
|
default_tag = tags['url'].split('/')[2].split(':')[0]
|
||||||
tags['new_tag'] = self.util.check_for_attribute(self.data, "tag", parent="tags",subparent=default_tag, default=default_tag)
|
tags['new_tag'] = self.util.check_for_attribute(self.data, "tag", parent="tags",subparent=default_tag, default=default_tag)
|
||||||
self.data['tags'][default_tag]['tag'] = default_tag
|
try:
|
||||||
|
self.data['tags'][default_tag]['tag'] = default_tag
|
||||||
|
except Exception as e:
|
||||||
|
self.data['tags'][default_tag] = {'tag': default_tag}
|
||||||
logger.warning(f'No tags matched for {tags["url"]}. Please check your config.yml file. Setting tag to {default_tag}')
|
logger.warning(f'No tags matched for {tags["url"]}. Please check your config.yml file. Setting tag to {default_tag}')
|
||||||
return (tags)
|
return (tags)
|
||||||
|
|
||||||
|
|
|
@ -202,8 +202,6 @@ class Qbt:
|
||||||
else:
|
else:
|
||||||
# Deletes torrent with data if cleanup is set to true and meets the ratio/seeding requirements
|
# Deletes torrent with data if cleanup is set to true and meets the ratio/seeding requirements
|
||||||
if (nohardlinks[category]['cleanup'] and torrent.state_enum.is_paused and len(nohardlinks[category])>0):
|
if (nohardlinks[category]['cleanup'] and torrent.state_enum.is_paused and len(nohardlinks[category])>0):
|
||||||
print_line(f'Torrent Name: {torrent.name} has no hard links found and meets ratio/seeding requirements.',loglevel)
|
|
||||||
print_line(util.insert_space(f"Cleanup flag set to true. {'Not Deleting' if dry_run else 'Deleting'} torrent + contents.",6),loglevel)
|
|
||||||
tdel_dict[torrent.name] = torrent['content_path'].replace(root_dir,root_dir)
|
tdel_dict[torrent.name] = torrent['content_path'].replace(root_dir,root_dir)
|
||||||
#Checks to see if previous noHL tagged torrents now have hard links.
|
#Checks to see if previous noHL tagged torrents now have hard links.
|
||||||
if (not (util.nohardlink(torrent['content_path'].replace(root_dir,root_dir))) and ('noHL' in torrent.tags)):
|
if (not (util.nohardlink(torrent['content_path'].replace(root_dir,root_dir))) and ('noHL' in torrent.tags)):
|
||||||
|
@ -221,14 +219,16 @@ class Qbt:
|
||||||
if torrent.name in tdel_dict.keys() and 'noHL' in torrent.tags:
|
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
|
#Double check that the content path is the same before we delete anything
|
||||||
if torrent['content_path'].replace(root_dir,root_dir) == tdel_dict[torrent.name]:
|
if torrent['content_path'].replace(root_dir,root_dir) == tdel_dict[torrent.name]:
|
||||||
|
print_line(f'Torrent Name: {torrent.name}',loglevel)
|
||||||
|
print_line(util.insert_space(f"Cleanup: True [No hard links found and meets Share Limits.]",5),loglevel)
|
||||||
if (os.path.exists(torrent['content_path'].replace(root_dir,root_dir))):
|
if (os.path.exists(torrent['content_path'].replace(root_dir,root_dir))):
|
||||||
if not dry_run: self.tor_delete_recycle(torrent)
|
if not dry_run: self.tor_delete_recycle(torrent)
|
||||||
del_tor_cont += 1
|
del_tor_cont += 1
|
||||||
print_line(util.insert_space(f'Deleted .torrent AND content files.',8),loglevel)
|
print_line(util.insert_space(f'Deleted .torrent AND content files.',13),loglevel)
|
||||||
else:
|
else:
|
||||||
if not dry_run: torrent.delete(hash=torrent.hash, delete_files=False)
|
if not dry_run: torrent.delete(hash=torrent.hash, delete_files=False)
|
||||||
del_tor += 1
|
del_tor += 1
|
||||||
print_line(util.insert_space(f'Deleted .torrent but NOT content files.',8),loglevel)
|
print_line(util.insert_space(f'Deleted .torrent but NOT content files.',13),loglevel)
|
||||||
if num_tags >= 1:
|
if num_tags >= 1:
|
||||||
print_line(f"{'Did not Tag/set' if dry_run else 'Tag/set'} share limits for {num_tags} .torrent{'s.' if num_tags > 1 else '.'}",loglevel)
|
print_line(f"{'Did not Tag/set' if dry_run else 'Tag/set'} share limits for {num_tags} .torrent{'s.' if num_tags > 1 else '.'}",loglevel)
|
||||||
else:
|
else:
|
||||||
|
@ -341,8 +341,8 @@ class Qbt:
|
||||||
print_line(util.insert_space(f'Save_Path: {dest}',6),loglevel)
|
print_line(util.insert_space(f'Save_Path: {dest}',6),loglevel)
|
||||||
added += 1
|
added += 1
|
||||||
if not dry_run:
|
if not dry_run:
|
||||||
client.torrents.add(torrent_files=src, save_path=dest, category=category, tags='cross-seed', is_paused=True)
|
self.client.torrents.add(torrent_files=src, save_path=dest, category=category, tags='cross-seed', is_paused=True)
|
||||||
shutil.move(src, dir_cs_out)
|
util.move_files(src,dir_cs_out)
|
||||||
else:
|
else:
|
||||||
print_line(f'Found {t_name} in {dir_cs} but original torrent is not complete.',loglevel)
|
print_line(f'Found {t_name} in {dir_cs} but original torrent is not complete.',loglevel)
|
||||||
print_line(f'Not adding to qBittorrent',loglevel)
|
print_line(f'Not adding to qBittorrent',loglevel)
|
||||||
|
|
|
@ -72,7 +72,12 @@ divider = get_arg("QBT_DIVIDER", args.divider)
|
||||||
screen_width = get_arg("QBT_WIDTH", args.width, arg_int=True)
|
screen_width = get_arg("QBT_WIDTH", args.width, arg_int=True)
|
||||||
stats = {}
|
stats = {}
|
||||||
args = {}
|
args = {}
|
||||||
default_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "config")
|
|
||||||
|
if os.path.isdir('/config'):
|
||||||
|
default_dir = '/config'
|
||||||
|
else:
|
||||||
|
default_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "config")
|
||||||
|
|
||||||
for v in ['run','sch','config_file','log_file','cross_seed','recheck','cat_update','tag_update','rem_unregistered','rem_orphaned','tag_nohardlinks','skip_recycle','dry_run','log_level','divider','screen_width']:
|
for v in ['run','sch','config_file','log_file','cross_seed','recheck','cat_update','tag_update','rem_unregistered','rem_orphaned','tag_nohardlinks','skip_recycle','dry_run','log_level','divider','screen_width']:
|
||||||
args[v] = eval(v)
|
args[v] = eval(v)
|
||||||
|
|
||||||
|
@ -101,7 +106,7 @@ logger.setLevel(log_lev)
|
||||||
|
|
||||||
def fmt_filter(record):
|
def fmt_filter(record):
|
||||||
record.levelname = f"[{record.levelname}]"
|
record.levelname = f"[{record.levelname}]"
|
||||||
#record.filename = f"[{record.filename}:{record.lineno}]"
|
record.filename = f"[{record.filename}:{record.lineno}]"
|
||||||
return True
|
return True
|
||||||
|
|
||||||
cmd_handler = logging.StreamHandler()
|
cmd_handler = logging.StreamHandler()
|
||||||
|
@ -118,14 +123,14 @@ with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "VERSION")) a
|
||||||
version = line
|
version = line
|
||||||
break
|
break
|
||||||
|
|
||||||
|
log_path = os.path.join(default_dir, "logs")
|
||||||
file_logger = os.path.join(default_dir, "logs", log_file)
|
file_logger = os.path.join(log_path, log_file)
|
||||||
max_bytes = 1024 * 1024 * 2
|
max_bytes = 1024 * 1024 * 2
|
||||||
file_handler = RotatingFileHandler(file_logger, delay=True, mode="w", maxBytes=max_bytes, backupCount=10, encoding="utf-8")
|
file_handler = RotatingFileHandler(file_logger, delay=True, mode="w", maxBytes=max_bytes, backupCount=10, encoding="utf-8")
|
||||||
util.apply_formatter(file_handler)
|
util.apply_formatter(file_handler)
|
||||||
file_handler.addFilter(fmt_filter)
|
file_handler.addFilter(fmt_filter)
|
||||||
logger.addHandler(file_handler)
|
logger.addHandler(file_handler)
|
||||||
|
os.chmod(log_path, 0o777)
|
||||||
|
|
||||||
def start():
|
def start():
|
||||||
start_time = datetime.now()
|
start_time = datetime.now()
|
||||||
|
@ -215,11 +220,11 @@ def start():
|
||||||
|
|
||||||
end_time = datetime.now()
|
end_time = datetime.now()
|
||||||
run_time = str(end_time - start_time).split('.')[0]
|
run_time = str(end_time - start_time).split('.')[0]
|
||||||
#util.separator(f"Finished {start_type}Run\n {', '.join(stats_summary) if len(stats_summary)>0 else ''} \nRun Time: {run_time}")
|
|
||||||
util.separator(f"Finished {start_type}Run\n {os.linesep.join(stats_summary) if len(stats_summary)>0 else ''} \nRun Time: {run_time}")
|
util.separator(f"Finished {start_type}Run\n {os.linesep.join(stats_summary) if len(stats_summary)>0 else ''} \nRun Time: {run_time}")
|
||||||
|
|
||||||
def end():
|
def end():
|
||||||
logger.info("Exiting Qbit_manage")
|
logger.info("Exiting Qbit_manage")
|
||||||
|
os.chmod(file_logger, 0o777)
|
||||||
logger.removeHandler(file_handler)
|
logger.removeHandler(file_handler)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
@ -255,6 +260,7 @@ if __name__ == '__main__':
|
||||||
logger.debug(f" --width (QBT_WIDTH): {screen_width}")
|
logger.debug(f" --width (QBT_WIDTH): {screen_width}")
|
||||||
logger.debug("")
|
logger.debug("")
|
||||||
|
|
||||||
|
os.chmod(file_logger, 0o777)
|
||||||
try:
|
try:
|
||||||
if run:
|
if run:
|
||||||
logger.info(f" Run Mode: Script will exit after completion.")
|
logger.info(f" Run Mode: Script will exit after completion.")
|
||||||
|
|
Loading…
Add table
Reference in a new issue