diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index be137c0..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: release - -on: - push: - tags: - - "v*" - -jobs: - release: - uses: nzbgetcom/nzbget-extensions/.github/workflows/extension-release.yml@main - with: - release-file-list: main.py manifest.json - release-file-name: easysort - release-dir: EasySort diff --git a/.github/workflows/tasks.yml b/.github/workflows/tasks.yml new file mode 100644 index 0000000..70174b9 --- /dev/null +++ b/.github/workflows/tasks.yml @@ -0,0 +1,32 @@ +name: extension tasks + +on: + push: + branches: + - main + tags: + - "v*" + pull_request: + branches: + - main + +jobs: + manifest: + uses: nzbgetcom/nzbget-extensions/.github/workflows/manifest.yml@main + + tests: + uses: nzbgetcom/nzbget-extensions/.github/workflows/python-tests.yml@main + with: + python-versions: "3.6 3.7 3.8 3.9 3.10 3.11 3.12" + supported-python-versions: "3.8 3.9 3.10 3.11 3.12" + test-script: tests.py + debug: true + + release: + if: startsWith(github.ref, 'refs/tags/v') + needs: [manifest, tests] + uses: nzbgetcom/nzbget-extensions/.github/workflows/extension-release.yml@main + with: + release-file-list: main.py manifest.json + release-file-name: easysort + release-dir: EasySort diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml deleted file mode 100644 index 4669ee0..0000000 --- a/.github/workflows/tests.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: tests - -on: - push: - branches: - - feature/* - - main - -jobs: - tests: - uses: nzbgetcom/nzbget-extensions/.github/workflows/python-tests.yml@main - with: - python-versions: "3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12" - supported-python-versions: "3.8 3.9 3.10 3.11 3.12" - test-script: tests.py diff --git a/README.md b/README.md index dcee678..da6a61d 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,26 @@ ## NZBGet Versions -- stable v23 [v3.0](https://github.com/nzbgetcom/Extension-EasySort/releases/tag/v3.0) +- stable v23 [v3.1](https://github.com/nzbgetcom/Extension-EasySort/releases/tag/v3.1) - legacy v22 [v2.0](https://github.com/nzbgetcom/Extension-EasySort/releases/tag/v2.0) > **Note:** This script is compatible with python 3.8.x and above. If you need support for Python 2.x versions then you can get legacy version [here](https://forum.nzbget.net/viewtopic.php?f=8&t=2163&p=23026&hilit=easysort#p23026). -# EasySort +## EasySort -Moves files into other location. -This script moves files with specified extensions into another -directory. It can also move into parent directory (flatten mode). -In addition there is an option to delete source directory with all remaining files. +This script moves files with specified extensions into another directory. -Author: Andrey Prygunkov +It offers flexible organization options: + + - Flat Mode:** Files are moved into the specified `DestDir` directory. + - Parent Directory Mode:** Files are moved into the parent directory using `DestDir=..` (flattening). + - Category Subdirectory Mode:** Files are organized into subdirectories within `DestDir` based on the category using `UseCategoryDir`. + - NZB Parent Subdirectory Mode:** Files are organized into subdirectories within `DestDir` based on the NZB filename using `UseNzbParentDir` + +You can combine `UseCategoryDir` and `UseNzbParentDir` for further organization. + +Additionally, there is an option to delete the source directory with all remaining files. + +## Authors: + - Andrey Prygunkov + - Denis diff --git a/main.py b/main.py index d37fcee..69a6dac 100644 --- a/main.py +++ b/main.py @@ -3,6 +3,7 @@ # EasySort post-processing script for NZBGet. # # Copyright (C) 2015 Andrey Prygunkov +# Copyright (C) 2024-2025 Denis # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by @@ -25,68 +26,94 @@ import traceback # Exit codes used by NZBGet -POSTPROCESS_SUCCESS=93 -POSTPROCESS_NONE=95 -POSTPROCESS_ERROR=94 +POSTPROCESS_SUCCESS = 93 +POSTPROCESS_NONE = 95 +POSTPROCESS_ERROR = 94 # Check if the script is called from nzbget 15.0 or later -if not 'NZBOP_NZBLOG' in os.environ: - print('*** NZBGet post-processing script ***') - print('This script is supposed to be called from nzbget (15.0 or later).') +if not "NZBOP_NZBLOG" in os.environ: + print("*** NZBGet post-processing script ***") + print("This script is supposed to be called from nzbget (15.0 or later).") sys.exit(POSTPROCESS_ERROR) # Check if directory still exist (for post-process again) -if not os.path.exists(os.environ['NZBPP_DIRECTORY']): - print('[INFO] Destination directory %s doesn\'t exist, exiting' % os.environ['NZBPP_DIRECTORY']) +if not os.path.exists(os.environ["NZBPP_DIRECTORY"]): + print( + "[INFO] Destination directory %s doesn't exist, exiting" + % os.environ["NZBPP_DIRECTORY"] + ) sys.exit(POSTPROCESS_NONE) # Check status for errors -if os.environ['NZBPP_TOTALSTATUS'] != 'SUCCESS': - print('[WARNING] Download of "%s" has failed, exiting' % (os.environ['NZBPP_NZBNAME'])) +if os.environ["NZBPP_TOTALSTATUS"] != "SUCCESS": + print( + '[WARNING] Download of "%s" has failed, exiting' % (os.environ["NZBPP_NZBNAME"]) + ) sys.exit(POSTPROCESS_NONE) # Check if all required script config options are present in config file -required_options = ('NZBPO_DestDir', 'NZBPO_UseCategoryDir', 'NZBPO_UseNzbParentDir', 'NZBPO_Extensions', 'NZBPO_MinSize', - 'NZBPO_Overwrite', 'NZBPO_Cleanup', 'NZBPO_Preview', 'NZBPO_Verbose') +required_options = ( + "NZBPP_NzbName", + "NZBPO_DestDir", + "NZBPO_UseCategoryDir", + "NZBPO_UseNzbParentDir", + "NZBPO_Extensions", + "NZBPO_MinSize", + "NZBPO_Overwrite", + "NZBPO_Cleanup", + "NZBPO_Preview", + "NZBPO_Verbose", + "NZBPP_Category", +) for optname in required_options: - if (not optname.upper() in os.environ): - print('[ERROR] Option %s is missing in configuration file. Please check script settings' % optname[6:]) + if not optname.upper() in os.environ: + print( + "[ERROR] Option %s is missing in configuration file. Please check script settings" + % optname[6:] + ) sys.exit(POSTPROCESS_ERROR) # Init script config options -nzb_name=os.environ['NZBPP_NZBNAME'] -download_dir=os.environ['NZBPP_DIRECTORY'] -dest_dir=os.environ['NZBPO_DESTDIR'] -useCategoryDir=os.environ['NZBPO_UseCategoryDir'] == 'yes' -useNzbParentDir=os.environ['NZBPO_UseNzbParentDir'] == 'yes' -extensions=os.environ['NZBPO_EXTENSIONS'].lower().split(',') -min_size=int(os.environ['NZBPO_MINSIZE']) +nzb_name = os.environ["NZBPP_NZBNAME"] +download_dir = os.environ["NZBPP_DIRECTORY"] +dest_dir = os.environ["NZBPO_DESTDIR"] +use_category_dir = os.environ["NZBPO_USECATEGORYDIR"] == "yes" +use_nzb_parent_dir = os.environ["NZBPO_USENZBPARENTDIR"] == "yes" +extensions = os.environ["NZBPO_EXTENSIONS"].lower().split(",") +min_size = int(os.environ["NZBPO_MINSIZE"]) min_size <<= 10 -overwrite=os.environ['NZBPO_OVERWRITE'] == 'yes' -cleanup=os.environ['NZBPO_CLEANUP'] == 'yes' -preview=os.environ['NZBPO_PREVIEW'] == 'yes' -verbose=os.environ['NZBPO_VERBOSE'] == 'yes' - -if dest_dir == '': - print('[WARNING] Option DestDir cannot be empty, exiting') +overwrite = os.environ["NZBPO_OVERWRITE"] == "yes" +cleanup = os.environ["NZBPO_CLEANUP"] == "yes" +preview = os.environ["NZBPO_PREVIEW"] == "yes" +verbose = os.environ["NZBPO_VERBOSE"] == "yes" +category = os.environ["NZBPP_CATEGORY"] + +if dest_dir == "": + print("[WARNING] Option DestDir cannot be empty, exiting") sys.exit(POSTPROCESS_ERROR) # Relative paths -if not (dest_dir[1] == '/' or dest_dir[1] == '\\' or (len(dest_dir) > 2) and dest_dir[2] == ':'): - dest_dir = os.path.join(download_dir, dest_dir) -dest_dir = os.path.abspath(dest_dir) +if not ( + dest_dir[1] == "/" + or dest_dir[1] == "\\" + or (len(dest_dir) > 2) + and dest_dir[2] == ":" +): + dest_dir = os.path.join(download_dir, dest_dir) + +if use_category_dir: + dest_dir = os.path.join(dest_dir, category) -if useCategoryDir: - dest_dir = os.path.join(dest_dir, os.environ['NZBPP_CATEGORY']) +if use_nzb_parent_dir: + dest_dir = os.path.join(dest_dir, nzb_name) -if useNzbParentDir: - dest_dir = os.path.join(dest_dir, os.environ['NZBPP_NZBNAME']) +dest_dir = os.path.abspath(dest_dir) if verbose: - print('Normalized dest directory: %s' % dest_dir) + print("Normalized dest directory: %s" % dest_dir) if preview: - print('[WARNING] *** PREVIEW MODE ON - NO CHANGES TO FILE SYSTEM ***') + print("[WARNING] *** PREVIEW MODE ON - NO CHANGES TO FILE SYSTEM ***") # List of moved files (source path) moved_src_files = [] @@ -96,55 +123,58 @@ # Separator character used between file name and opening brace # for duplicate files such as "My Movie (2).mkv" -dupe_separator = ' ' +dupe_separator = " " + def guess_dupe_separator(filename): - """ Find out a char most suitable as dupe_separator - """ + """Find out a char most suitable as dupe_separator""" global dupe_separator - dupe_separator = ' ' + dupe_separator = " " fname = os.path.splitext(filename)[0] - if (fname.find('.') > -1): - dupe_separator = '.' + if fname.find(".") > -1: + dupe_separator = "." return - if (fname.find('_') > -1): - dupe_separator = '_' + if fname.find("_") > -1: + dupe_separator = "_" return + def unique_name(new): - """ Adds unique numeric suffix to destination file name to avoid overwriting - such as "filename.(2).ext", "filename.(3).ext", etc. - If existing file was created by the script it is renamed to "filename.(1).ext". + """Adds unique numeric suffix to destination file name to avoid overwriting + such as "filename.(2).ext", "filename.(3).ext", etc. + If existing file was created by the script it is renamed to "filename.(1).ext". """ fname, fext = os.path.splitext(new) suffix_num = 2 while True: - new_name = fname + dupe_separator + '(' + str(suffix_num) + ')' + fext + new_name = fname + dupe_separator + "(" + str(suffix_num) + ")" + fext if not os.path.exists(new_name) and new_name not in moved_dst_files: break suffix_num += 1 return new_name + def optimized_move(old, new): try: os.rename(old, new) except OSError as ex: - print('[DETAIL] Rename failed ({}), performing copy: {}'.format(ex, new)) + print("[DETAIL] Rename failed ({}), performing copy: {}".format(ex, new)) shutil.copyfile(old, new) os.remove(old) + def rename(old, new): - """ Moves the file to its sorted location. - It creates any necessary directories to place the new file and moves it. + """Moves the file to its sorted location. + It creates any necessary directories to place the new file and moves it. """ if os.path.exists(new) or new in moved_dst_files: if overwrite and new not in moved_dst_files: os.remove(new) optimized_move(old, new) - print('[INFO] Overwrote: %s' % new) + print("[INFO] Overwrote: %s" % new) else: # rename to filename.(2).ext, filename.(3).ext, etc. new = unique_name(new) @@ -154,29 +184,31 @@ def rename(old, new): if not os.path.exists(os.path.dirname(new)): os.makedirs(os.path.dirname(new)) optimized_move(old, new) - print('[INFO] Moved: %s' % new) + print("[INFO] Moved: %s" % new) moved_src_files.append(old) moved_dst_files.append(new) return new + def cleanup_download_dir(): if verbose: - print('Cleanup') + print("Cleanup") - # Now delete all files with nice logging + # Now delete all files with nice logging for root, dirs, files in os.walk(download_dir): for filename in files: path = os.path.join(root, filename) if not preview or path not in moved_src_files: if not preview: os.remove(path) - print('[INFO] Deleted: %s' % path) + print("[INFO] Deleted: %s" % path) if not preview: shutil.rmtree(download_dir) - print('[INFO] Deleted: %s' % download_dir) + print("[INFO] Deleted: %s" % download_dir) + def construct_path(filename): - """ Parses the filename and generates new name for renaming """ + """Parses the filename and generates new name for renaming""" if verbose: print("filename: %s" % filename) @@ -192,10 +224,11 @@ def construct_path(filename): new_path = os.path.join(dest_dir, filename) if verbose: - print('destination path: %s' % new_path) - + print("destination path: %s" % new_path) + return new_path + # Flag indicating that anything was moved. Cleanup possible. files_moved = False @@ -209,18 +242,19 @@ def construct_path(filename): for old_filename in files: try: if verbose: - print('[INFO] Processing: %s' % old_filename) + print("[INFO] Processing: %s" % old_filename) old_path = os.path.join(root, old_filename) # Check extension - if extensions != ['']: + if extensions != [""]: ext = os.path.splitext(old_filename)[1].lower() - if ext not in extensions: continue + if ext not in extensions: + continue # Check minimum file size if os.path.getsize(old_path) < min_size: - print('[INFO] Skipping small: %s' % old_filename) + print("[INFO] Skipping small: %s" % old_filename) continue # This is our file, we should process it @@ -228,12 +262,12 @@ def construct_path(filename): except Exception as e: errors = True - print('[ERROR] Failed: %s' % old_filename) - print('[ERROR] %s' % e) + print("[ERROR] Failed: %s" % old_filename) + print("[ERROR] %s" % e) traceback.print_exc() if verbose: - print('File list: %s' % move_files) + print("File list: %s" % move_files) for old_path in move_files: try: @@ -246,22 +280,22 @@ def construct_path(filename): except Exception as e: errors = True - print('[ERROR] Failed: %s' % old_filename) - print('[ERROR] %s' % e) + print("[ERROR] Failed: %s" % old_filename) + print("[ERROR] %s" % e) traceback.print_exc() # Inform NZBGet about new destination path -finaldir = '' +finaldir = "" uniquedirs = [] for filename in moved_dst_files: dir = os.path.dirname(filename) if dir not in uniquedirs: uniquedirs.append(dir) - finaldir += '|' if finaldir != '' else '' + finaldir += "|" if finaldir != "" else "" finaldir += dir -if finaldir != '': - print('[NZB] FINALDIR=%s' % finaldir) +if finaldir != "": + print("[NZB] FINALDIR=%s" % finaldir) # Cleanup if: # 1) files were moved AND diff --git a/manifest.json b/manifest.json index ed7c2fd..b6499df 100644 --- a/manifest.json +++ b/manifest.json @@ -4,15 +4,24 @@ "homepage": "https://github.com/nzbgetcom/Extension-EasySort/", "kind": "POST-PROCESSING", "displayName": "Easy Sort", - "version": "3.1.0", + "version": "3.1", + "nzbgetMinVersion": "23.0", "author": "Andrey Prygunkov", "license": "GPLv3", "about": "Moves files after download into other locations.", "queueEvents": "", "description": [ - " This script moves files with specified extensions into another", - "directory. It can also move into parent directory (flatten mode). In addition", - "there is an option to delete source directory with all remaining files." + "This script moves files with specified extensions into another directory.", + "It offers flexible organization options:", + "", + "- Flat Mode: Files are moved into the specified `DestDir` directory.", + "- Parent Directory Mode: Files are moved into the parent directory using `DestDir=..` (flattening).", + "- Category Subdirectory Mode: Files are organized into subdirectories within `DestDir` based on the category using `UseCategoryDir`.", + "- NZB Parent Subdirectory Mode: Files are organized into subdirectories within `DestDir` based on the NZB filename using `UseNzbParentDir`", + "", + "You can combine `UseCategoryDir` and `UseNzbParentDir` for further organization.", + "", + "Additionally, there is an option to delete the source directory with all remaining files." ], "requirements": [ "This script requires Python 3.8+ to be installed on your system." @@ -32,7 +41,7 @@ { "name": "UseCategoryDir", "displayName": "UseCategoryDir", - "value": "yes", + "value": "no", "description": [ "Create subdirectory in based on category-name.", "", @@ -48,7 +57,7 @@ { "name": "UseNzbParentDir", "displayName": "UseNzbParentDir", - "value": "yes", + "value": "no", "description": [ "Create subdirectory for each nzb-file.", "", @@ -152,4 +161,4 @@ ], "commands": [], "taskTime": "" -} \ No newline at end of file +} diff --git a/tests.py b/tests.py index 387ea1c..899e72c 100644 --- a/tests.py +++ b/tests.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2024 Denis +# Copyright (C) 2024-2025 Denis # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by @@ -13,7 +13,7 @@ # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License -# along with the program. If not, see . +# along with the program. If not, see . # @@ -25,87 +25,128 @@ import shutil import json -POSTPROCESS_SUCCESS=93 -POSTPROCESS_NONE=95 -POSTPROCESS_ERROR=94 +POSTPROCESS_SUCCESS = 93 +POSTPROCESS_NONE = 95 +POSTPROCESS_ERROR = 94 root = dirname(__file__) -test_data_dir = root + '/test_data/' -tmp_dir = root + '/tmp/' -dst_dir = root + '/tmp/dst/' -dwn_dir = root + '/tmp/dwn/' -test_file = 'movie.mp4' - -host = '127.0.0.1' -username = 'TestUser' -password = 'TestPassword' -port = '6789' - -def get_python(): - if os.name == 'nt': - return 'python' - return 'python3' +test_data_dir = root + "/test_data/" +tmp_dir = root + "/tmp/" +dst_dir = root + "/tmp/dst/" +dwn_dir = root + "/tmp/dwn/" +test_file = "movie.mp4" +nzb_name = "TestNZB" +category = "Movies" + +host = "127.0.0.1" +username = "TestUser" +password = "TestPassword" +port = "6789" + + +def get_python(): + if os.name == "nt": + return "python" + return "python3" + def run_script(): - sys.stdout.flush() - proc = subprocess.Popen([get_python(), root + '/main.py'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=os.environ.copy()) - out, err = proc.communicate() - proc.pid - ret_code = proc.returncode - return (out.decode(), int(ret_code), err.decode()) + sys.stdout.flush() + proc = subprocess.Popen( + [get_python(), root + "/main.py"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=os.environ.copy(), + ) + out, err = proc.communicate() + proc.pid + ret_code = proc.returncode + return (out.decode(), int(ret_code), err.decode()) + def set_defaults_env(): - # NZBGet global options - os.environ['NZBOP_CONTROLPORT'] = port - os.environ['NZBOP_CONTROLIP'] = host - os.environ['NZBOP_CONTROLUSERNAME'] = username - os.environ['NZBOP_CONTROLPASSWORD'] = password - os.environ['NZBOP_NZBLOG'] = tmp_dir + '/log.txt' - os.environ['NZBPP_TOTALSTATUS'] = 'SUCCESS' - os.environ['NZBPO_PASSACTION'] = 'PASSACTION' - - # script options - os.environ['NZBPO_OVERWRITE'] = 'yes' - os.environ['NZBPO_CLEANUP'] = 'yes' - os.environ['NZBPO_PREVIEW'] = 'no' - os.environ['NZBPO_VERBOSE'] = 'no' - os.environ['NZBPP_TOTALSTATUS'] = 'SUCCESS' - os.environ['NZBPP_DIRECTORY'] = dwn_dir - os.environ['NZBNA_NZBNAME'] = 'TestNZB' - os.environ['NZBOP_TEMPDIR'] = tmp_dir - os.environ['NZBPO_DESTDIR'] = dst_dir - os.environ['NZBPO_EXTENSIONS'] = '.mp4' - os.environ['NZBPP_NZBNAME'] = test_file + # NZBGet global options + os.environ["NZBOP_CONTROLPORT"] = port + os.environ["NZBOP_CONTROLIP"] = host + os.environ["NZBOP_CONTROLUSERNAME"] = username + os.environ["NZBOP_CONTROLPASSWORD"] = password + os.environ["NZBOP_NZBLOG"] = tmp_dir + "/log.txt" + os.environ["NZBPP_TOTALSTATUS"] = "SUCCESS" + os.environ["NZBPO_PASSACTION"] = "PASSACTION" + os.environ["NZBPP_CATEGORY"] = "" + + # script options + os.environ["NZBPO_OVERWRITE"] = "yes" + os.environ["NZBPO_CLEANUP"] = "yes" + os.environ["NZBPO_PREVIEW"] = "no" + os.environ["NZBPO_VERBOSE"] = "no" + os.environ["NZBPP_TOTALSTATUS"] = "SUCCESS" + os.environ["NZBPP_DIRECTORY"] = dwn_dir + os.environ["NZBPP_NZBNAME"] = nzb_name + os.environ["NZBOP_TEMPDIR"] = tmp_dir + os.environ["NZBPO_DESTDIR"] = dst_dir + os.environ["NZBPO_EXTENSIONS"] = ".mp4" + os.environ["NZBPO_USECATEGORYDIR"] = "no" + os.environ["NZBPO_USENZBPARENTDIR"] = "no" + os.environ["NZBPO_MINSIZE"] = "0" + class Tests(unittest.TestCase): - def test_do_nothing_if_file_too_small(self): - os.mkdir(tmp_dir) - os.mkdir(dwn_dir) - shutil.copyfile(test_data_dir + test_file, dwn_dir + test_file) - set_defaults_env() - os.environ['NZBPO_MINSIZE'] = '1000' - [_, code, _] = run_script() - shutil.rmtree(tmp_dir) - self.assertEqual(code, POSTPROCESS_NONE) - - def test_move_file(self): - os.mkdir(tmp_dir) - os.mkdir(dwn_dir) - shutil.copyfile(test_data_dir + test_file, dwn_dir + test_file) - set_defaults_env() - os.environ['NZBPO_MINSIZE'] = '0' - [_, code, _] = run_script() - shutil.rmtree(tmp_dir) - self.assertEqual(code, POSTPROCESS_SUCCESS) - - def test_manifest(self): - with open(root + '/manifest.json', encoding='utf-8') as file: - try: - json.loads(file.read()) - except ValueError as e: - self.fail('manifest.json is not valid.') - - -if __name__ == '__main__': - unittest.main() + def test_do_nothing_if_file_too_small(self): + os.mkdir(tmp_dir) + os.mkdir(dwn_dir) + shutil.copyfile(test_data_dir + test_file, dwn_dir + test_file) + set_defaults_env() + os.environ["NZBPO_MINSIZE"] = "1000" + [_, code, _] = run_script() + shutil.rmtree(tmp_dir) + self.assertEqual(code, POSTPROCESS_NONE) + + def test_move_file(self): + os.mkdir(tmp_dir) + os.mkdir(dwn_dir) + shutil.copyfile(test_data_dir + test_file, dwn_dir + test_file) + set_defaults_env() + [_, code, _] = run_script() + self.assertTrue(os.path.exists(dst_dir + test_file)) + shutil.rmtree(tmp_dir) + self.assertEqual(code, POSTPROCESS_SUCCESS) + + def test_move_file_with_category(self): + os.mkdir(tmp_dir) + os.mkdir(dwn_dir) + shutil.copyfile(test_data_dir + test_file, dwn_dir + test_file) + set_defaults_env() + os.environ["NZBPP_CATEGORY"] = category + os.environ["NZBPO_USECATEGORYDIR"] = "yes" + [_, code, _] = run_script() + self.assertTrue(os.path.exists(dst_dir + category + "/" + test_file)) + shutil.rmtree(tmp_dir) + self.assertEqual(code, POSTPROCESS_SUCCESS) + + def test_move_file_with_category_and_nzb_parent(self): + os.mkdir(tmp_dir) + os.mkdir(dwn_dir) + shutil.copyfile(test_data_dir + test_file, dwn_dir + test_file) + set_defaults_env() + os.environ["NZBPP_CATEGORY"] = category + os.environ["NZBPO_USENZBPARENTDIR"] = "yes" + os.environ["NZBPO_USECATEGORYDIR"] = "yes" + [_, code, _] = run_script() + self.assertTrue( + os.path.exists(dst_dir + "/" + category + "/" + nzb_name + "/" + test_file) + ) + shutil.rmtree(tmp_dir) + self.assertEqual(code, POSTPROCESS_SUCCESS) + + def test_manifest(self): + with open(root + "/manifest.json", encoding="utf-8") as file: + try: + json.loads(file.read()) + except ValueError as e: + self.fail("manifest.json is not valid.") + + +if __name__ == "__main__": + unittest.main()