diff --git a/.gitignore b/.gitignore index da47f49..6bdb6aa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,164 +1,164 @@ -*.log -*.json -*.csv - -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/#use-with-ide -.pdm.toml - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. +*.log +*.json +*.csv + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ \ No newline at end of file diff --git a/README.md b/README.md index d39a876..d3b77a7 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,8 @@ Config.json "po_key": "", "po_token": "", "delete_torrents": false + "enable_dragnet": false, + "dragnet_outfile": "./orphaned.csv" } ``` @@ -74,4 +76,5 @@ You will need a category-whitelist.json in the root directory. This will ignore | use_log | true or false to enable or disable writing to alog file | | po_key | pushover key | | po_token | pushover api token | -| delete_torrents | true or false to enable or disable deletion. Useful for dry-runs | \ No newline at end of file +| delete_torrents | true or false to enable or disable deletion. Useful for dry-runs | +| enable_dragnet | true or false to enable dragnet functionality. Useful for debugging | \ No newline at end of file diff --git a/config.json.example b/config.json.example index 6dba164..2fa9c9e 100644 --- a/config.json.example +++ b/config.json.example @@ -13,5 +13,7 @@ "use_log": true, "po_key": "", "po_token": "", - "delete_torrents": false + "delete_torrents": false, + "enable_dragnet": true, + "dragnet_outfile": "./orphaned.csv" } \ No newline at end of file diff --git a/qbit-maid.py b/qbit-maid.py index f6c90c9..2b47055 100644 --- a/qbit-maid.py +++ b/qbit-maid.py @@ -43,6 +43,8 @@ class Qbt: self.tracker_non_protected_tag = self.config["non_protected_tag"] self.minimum_age = self.config["minimum_age"] self.age = self.config["age"] + self.enable_dragnet = self.config["enable_dragnet"] + self.dragnet_outfile = self.config["dragnet_outfile"] # Calling log and notify functions torlog(self) tornotify(self) diff --git a/qprocess.py b/qprocess.py index 95b08bc..5e69688 100644 --- a/qprocess.py +++ b/qprocess.py @@ -1,3 +1,6 @@ +from cgitb import enable + + def torprocessor(self): """Main logic to sort through both self.tracker_nonprotected_list and self.tracker_protected_list If torrent meets criteria for deletion, its infohash_v1 will be appended to self.torrent_hash_delete_list @@ -32,7 +35,8 @@ def torprocessor(self): if self.use_log: self.tl.info(f'Submitted ["{canidate["name"][0:20]}..."] for deletion.') else: - dragnet(self,canidate['state'],canidate['ratio'],canidate["tags"],canidate['added_on'],self.age,self.t.time(),canidate['infohash_v1'],canidate["name"][0:20]) + if self.enable_dragnet: + dragnet(self,canidate['state'],canidate['ratio'],canidate["tags"],canidate['added_on'],self.age,self.t.time(),canidate['infohash_v1'],canidate["name"][0:20]) self.tl.info(f'["{canidate["name"][0:20]}..."] is orphaned.') self.up_tor_counter += 1 continue @@ -72,7 +76,7 @@ def isnonprotectedtor(setnonprotectedtag, tortags): def dragnet(self,state,ratio,tags,added,age,time,thash,tname): header = ['state','ratio','tags','added','age','time','thash','tname'] row = [state,ratio,tags,added,age,time,thash,tname] - with open('./orphanedtorrents.csv', 'w', encoding='UTF8', newline='') as f: + with open(self.dragnet_outfile, 'w', encoding='UTF8', newline='') as f: writer = self.cv.writer(f) if f.tell() == 0: writer.writerow(header) diff --git a/test_qbitmaid.py b/test_qbitmaid.py index 8181b59..a2874a6 100644 --- a/test_qbitmaid.py +++ b/test_qbitmaid.py @@ -1,97 +1,97 @@ -import unittest -from qlist import ispreme,iscatignored,istrackerblank,isprotectedtracker,isnotprotectedtracker,istagblank -from qprocess import isdownloading,isprotectedunderratio,isoldtor,isprotectedoverratio,isnonprotectedtor - -class TestQbitmaid(unittest.TestCase): - def test_ispreme_sanity(self): - self.assertTrue(ispreme(1,1,1)) - self.assertFalse(ispreme(1,1,3)) - - def test_ispreme(self): - pass - - def test_iscatignored_sanity(self): - self.assertTrue(iscatignored('a', ['a','b','c'])) - self.assertTrue(iscatignored('b', ['a','b','c'])) - self.assertTrue(iscatignored('c', ['a','b','c'])) - self.assertFalse(iscatignored('d', ['a','b','c'])) - self.assertFalse(iscatignored(1, ['a','b','c'])) - self.assertFalse(iscatignored(1.0000000, ['a','b','c'])) - - def test_iscatignored(self): - pass - - def test_istrackerblank_sanity(self): - self.assertTrue(istrackerblank('')) - self.assertFalse(istrackerblank('a')) - self.assertFalse(istrackerblank(1)) - self.assertFalse(istrackerblank(1.00000000)) - - def test_istrackerblank(self): - pass - - def test_isprotectedtracker_sanity(self): - self.assertTrue(isprotectedtracker('https://a.com/',['a.com','b.me','c.io'])) - self.assertFalse(isprotectedtracker('https://google.com/',['a.com','b.me','c.io'])) - self.assertFalse(isprotectedtracker('https://d.com',['a.com','b.me','c.io'])) - - def test_isprotectedtracker(self): - pass - - def test_isnotprotectedtracker_sanity(self): - self.assertFalse(isnotprotectedtracker('https://a.com/',['a.com','b.me','c.io'])) - self.assertTrue(isnotprotectedtracker('https://google.com/',['a.com','b.me','c.io'])) - self.assertTrue(isnotprotectedtracker('https://d.com',['a.com','b.me','c.io'])) - - def test_isnotprotectedtracker(self): - pass - - def test_istagblank(self): - self.assertTrue(istagblank('')) - self.assertFalse(istagblank('a')) - self.assertFalse(istagblank(1)) - self.assertFalse(istagblank(1.0001)) - self.assertFalse(istagblank(False)) - self.assertFalse(istagblank(True)) - - def test_isdownloading_sanity(self): - self.assertTrue(isdownloading('downloading')) - - def test_isdownloading(self): - self.assertFalse(isdownloading('DOWNLOADING')) - self.assertFalse(isdownloading('dOwNlOaDiNg')) - - def test_isprotectedunderratio_sanity(self): - self.assertTrue(isprotectedunderratio(0.5,1,'a','a,b,c')) - - def test_isprotectedunderratio(self): - pass - - def test_isoldtor_sanity(self): - self.assertTrue(isoldtor(1,2,4)) - - def test_isoldtor(self): - self.assertFalse(isoldtor(1661150664,2419200,1662049004.2101078)) - self.assertFalse(isoldtor(1661150664,2419200,1662049004)) - self.assertFalse(isoldtor(1661150664.000000,2419200.0000000,1662049004.2101078)) - - def test_isprotectedoverratio_sanity(self): - self.assertTrue(isprotectedoverratio(2,1,'a','a,b,c')) - - def test_isprotectedoverratio(self): - pass - - def test_isnonprotectedtor_sanity(self): - self.assertTrue(isnonprotectedtor('a','a,b,c')) - - def test_isnonprotectedtor(self): - pass - - # def test__sanity(self): - # pass - - # def test_(self): - # pass - -if __name__ == '__main__': +import unittest +from qlist import ispreme,iscatignored,istrackerblank,isprotectedtracker,isnotprotectedtracker,istagblank +from qprocess import isdownloading,isprotectedunderratio,isoldtor,isprotectedoverratio,isnonprotectedtor + +class TestQbitmaid(unittest.TestCase): + def test_ispreme_sanity(self): + self.assertTrue(ispreme(1,1,1)) + self.assertFalse(ispreme(1,1,3)) + + def test_ispreme(self): + pass + + def test_iscatignored_sanity(self): + self.assertTrue(iscatignored('a', ['a','b','c'])) + self.assertTrue(iscatignored('b', ['a','b','c'])) + self.assertTrue(iscatignored('c', ['a','b','c'])) + self.assertFalse(iscatignored('d', ['a','b','c'])) + self.assertFalse(iscatignored(1, ['a','b','c'])) + self.assertFalse(iscatignored(1.0000000, ['a','b','c'])) + + def test_iscatignored(self): + pass + + def test_istrackerblank_sanity(self): + self.assertTrue(istrackerblank('')) + self.assertFalse(istrackerblank('a')) + self.assertFalse(istrackerblank(1)) + self.assertFalse(istrackerblank(1.00000000)) + + def test_istrackerblank(self): + pass + + def test_isprotectedtracker_sanity(self): + self.assertTrue(isprotectedtracker('https://a.com/',['a.com','b.me','c.io'])) + self.assertFalse(isprotectedtracker('https://google.com/',['a.com','b.me','c.io'])) + self.assertFalse(isprotectedtracker('https://d.com',['a.com','b.me','c.io'])) + + def test_isprotectedtracker(self): + pass + + def test_isnotprotectedtracker_sanity(self): + self.assertFalse(isnotprotectedtracker('https://a.com/',['a.com','b.me','c.io'])) + self.assertTrue(isnotprotectedtracker('https://google.com/',['a.com','b.me','c.io'])) + self.assertTrue(isnotprotectedtracker('https://d.com',['a.com','b.me','c.io'])) + + def test_isnotprotectedtracker(self): + pass + + def test_istagblank(self): + self.assertTrue(istagblank('')) + self.assertFalse(istagblank('a')) + self.assertFalse(istagblank(1)) + self.assertFalse(istagblank(1.0001)) + self.assertFalse(istagblank(False)) + self.assertFalse(istagblank(True)) + + def test_isdownloading_sanity(self): + self.assertTrue(isdownloading('downloading')) + + def test_isdownloading(self): + self.assertFalse(isdownloading('DOWNLOADING')) + self.assertFalse(isdownloading('dOwNlOaDiNg')) + + def test_isprotectedunderratio_sanity(self): + self.assertTrue(isprotectedunderratio(0.5,1,'a','a,b,c')) + + def test_isprotectedunderratio(self): + pass + + def test_isoldtor_sanity(self): + self.assertTrue(isoldtor(1,2,4)) + + def test_isoldtor(self): + self.assertFalse(isoldtor(1661150664,2419200,1662049004.2101078)) + self.assertFalse(isoldtor(1661150664,2419200,1662049004)) + self.assertFalse(isoldtor(1661150664.000000,2419200.0000000,1662049004.2101078)) + + def test_isprotectedoverratio_sanity(self): + self.assertTrue(isprotectedoverratio(2,1,'a','a,b,c')) + + def test_isprotectedoverratio(self): + pass + + def test_isnonprotectedtor_sanity(self): + self.assertTrue(isnonprotectedtor('a','a,b,c')) + + def test_isnonprotectedtor(self): + pass + + # def test__sanity(self): + # pass + + # def test_(self): + # pass + +if __name__ == '__main__': unittest.main() \ No newline at end of file