Fix lint errors

This commit is contained in:
Labrys of Knossos 2022-12-19 15:13:03 -05:00
commit 27f6c05788
34 changed files with 313 additions and 285 deletions

62
.flake8 Normal file
View file

@ -0,0 +1,62 @@
[flake8]
max-line-length = 79
max-doc-length = 79
verbose = 2
statistics = True
min-version = 2.7
require-code = True
exclude =
.github/
.pytest_cache/
.tox/
.venv*/
build/
htmlcov/
logs/
ignore =
; -- flake8 --
; E501 line too long
; E722 do not use bare 'except' (duplicates B001)
; W503 line break before binary operator
; W505 doc line too long
E501, E722, W503, W505
; -- flake8-docstrings --
; D100 Missing docstring in public module
; D101 Missing docstring in public class
; D102 Missing docstring in public method
; D103 Missing docstring in public function
; D104 Missing docstring in public package
; D105 Missing docstring in magic method
; D107 Missing docstring in __init__
; D200 One-line docstring should fit on one line with quotes
; D202 No blank lines allowed after function docstring
; D205 1 blank line required between summary line and description
; D400 First line should end with a period
; D401 First line should be in imperative mood
; D402 First line should not be the function's "signature"
D100, D101, D102, D103, D104, D105, D107
; -- flake8-future-import --
; x = 1 for missing, 5 for present
; FIx6 nested_scopes 2.2
; FIx7 generators 2.3
; FIx2 with_statement 2.6
; FIx1 absolute_import 3.0
; FIx0 division 3.0
; FIx3 print_function 3.0
; FIx4 unicode_literals 3.0
; FIx5 generator_stop 3.7
; FIx8 annotations 4.0
; FI90 __future__ import does not exist
FI10, FI11, FI13, FI14, FI58
per-file-ignores =
; F401 imported but unused
; E402 module level import not at top of file
; nzbTo*.py: E265, E266, E402
; TorrentToMedia.py: E402
; nzb2media/__init__.py: E402, F401
; nzb2media/utils/__init__.py: F401
; nzb2media/plugins/downloaders/configuration.py: F401
; nzb2media/plugins/downloaders/utils.py: F401

View file

@ -5,10 +5,45 @@ repos:
- id: trailing-whitespace - id: trailing-whitespace
- id: end-of-file-fixer - id: end-of-file-fixer
- id: check-yaml - id: check-yaml
- id: check-json
- id: check-toml
- id: check-xml
- id: check-case-conflict
- id: debug-statements - id: debug-statements
- id: detect-private-key
- id: double-quote-string-fixer - id: double-quote-string-fixer
- id: fix-byte-order-marker
- id: name-tests-test - id: name-tests-test
- id: requirements-txt-fixer - id: requirements-txt-fixer
- repo: https://github.com/pycqa/flake8
rev: '6.0.0'
hooks:
- id: flake8
name: Flake8 primary tests
additional_dependencies:
- flake8-bugbear
- flake8-commas
- flake8-comprehensions
- flake8-docstrings
- flake8-future-import
- id: flake8
name: Flake8 selective tests
args: [
# ** SELECTIVE TESTS **
# Run flake8 tests (with plugins) for specific optional codes defined below
# -- flake8 --
# E123 closing bracket does not match indentation of opening brackets line
# E226 missing whitespace around arithmetic operator
# E241 multiple spaces after ,
# E242 tab after ,
# E704 multiple statements on one line
# W504 line break after binary operator
# W505 doc line too long
# -- flake8-bugbear --
# B902 Invalid first argument used for instance method.
# B903 Data class should be immutable or use __slots__ to save memory.
'--select=B902,B903,E123,E226,E241,E242,E704,W504,W505'
]
- repo: https://github.com/asottile/add-trailing-comma - repo: https://github.com/asottile/add-trailing-comma
rev: v2.4.0 rev: v2.4.0
hooks: hooks:
@ -34,5 +69,5 @@ repos:
[ [
"-rn", # Only display messages "-rn", # Only display messages
"-sn", # Disable score "-sn", # Disable score
"--rcfile=.pylintrc.ini", # Link to your config file "--rcfile=.pylintrc", # Link to your config file
] ]

View file

@ -38,6 +38,70 @@ load-plugins=
# no Warning level messages displayed, use"--disable=all --enable=classes # no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W" # --disable=W"
# See below for a list of codes
disable=
E1101, # no-member
W0141, # bad-builtin
W0149, # while-used
W0160, # consider-ternary-expression
W0201, # attribute-defined-outside-init
W0212, # protected-access
W0511, # fixme
W0601, # global-variable-undefined
W0602, # global-variable-not-assigned
W0603, # global-statement
W0612, # unused-variable
W0621, # redefined-outer-name
W0631, # undefined-loop-variable
W0703, # broad-except
W0717, # too-many-try-statements
W1202, # logging-format-interpolation
W1203, # logging-fstring-interpolation
W1404, # implicit-str-concat
W2901, # redefined-loop-name
W3101, # missing-timeout
W6001, # deprecated-typing-alias
C0103, # invalid-name
C0114, # missing-module-docstring
C0115, # missing-class-docstring
C0116, # missing-function-docstring
C0201, # consider-iterating-dictionary
C0206, # consider-using-dict-items
C0301, # line-too-long
C0415, # import-outside-toplevel
R0204, # redifined-variable-type
R0401, # cyclic-import
R0801, # duplicate-code
R0903, # too-few-public-methods
R0902, # too-many-instance-attributes
R0911, # too-many-return-statements
R0912, # too-many-branches
R0913, # too-many-arguments
R0914, # too-many-locals
R0915, # too-many-statements
R0916, # too-many-boolean-expressions
R1260, # too-complex
R1702, # too-many-nested-blocks
R1704, # redefined-argument-from-local
R1710, # inconsistent-return-statements
R5601, # confusing-consecutive-elif
R6103, # consider-using-assignment-expr
I0011, # locally-disabled
I0020, # suppressed-message
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
enable=
# ------------------------ CODES ------------------------
; # --- FATAL --------- ; # --- FATAL ---------
; F0001, # fatal ; F0001, # fatal
; F0002, # astroid-error ; F0002, # astroid-error
@ -459,70 +523,3 @@ load-plugins=
; I0022, # deprecated-pragma ; I0022, # deprecated-pragma
; I0023, # use-symbolic-message-instead ; I0023, # use-symbolic-message-instead
; I1101, # c-extension-no-member ; I1101, # c-extension-no-member
disable=
E1101, # no-member
W0141, # bad-builtin
W0149, # while-used
W0160, # consider-ternary-expression
W0201, # attribute-defined-outside-init
W0212, # protected-access
W0511, # fixme
W0601, # global-variable-undefined
W0602, # global-variable-not-assigned
W0603, # global-statement
W0612, # unused-variable
W0621, # redefined-outer-name
W0631, # undefined-loop-variable
W0703, # broad-except
W0717, # too-many-try-statements
W1202, # logging-format-interpolation
W1203, # logging-fstring-interpolation
W1404, # implicit-str-concat
W2901, # redefined-loop-name
W3101, # missing-timeout
W6001, # deprecated-typing-alias
W9016, # missing-type-do
C0103, # invalid-name
C0114, # missing-module-docstring
C0115, # missing-class-docstring
C0116, # missing-function-docstring
C0199, # docstring-first-line-empty
C0201, # consider-iterating-dictionary
C0206, # consider-using-dict-items
C0301, # line-too-long
C0415, # import-outside-toplevel
C1901, # compare-to-empty-string
C2001, # compare-to-zero
R0204, # redifined-variable-type
R0401, # cyclic-import
R0801, # duplicate-code
R0903, # too-few-public-methods
R0902, # too-many-instance-attributes
R0911, # too-many-return-statements
R0912, # too-many-branches
R0913, # too-many-arguments
R0914, # too-many-locals
R0915, # too-many-statements
R0916, # too-many-boolean-expressions
R1260, # too-complex
R1702, # too-many-nested-blocks
R1704, # redefined-argument-from-local
R1710, # inconsistent-return-statements
R5501, # else-if-used
R5601, # confusing-consecutive-elif
R6003, # consider-alternative-union-syntax
R6102, # consider-using-tuple
R6103, # consider-using-assignment-expr
I0011, # locally-disabled
I0020, # suppressed-message
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
enable=

View file

@ -53,7 +53,7 @@ def process_torrent(input_directory, input_name, input_category, input_hash, inp
input_directory, input_name, input_category, input_directory, input_name, input_category,
root, nzb2media.CATEGORIES, root, nzb2media.CATEGORIES,
) )
if input_category == '': if not input_category:
input_category = 'UNCAT' input_category = 'UNCAT'
usercat = input_category usercat = input_category
@ -132,7 +132,7 @@ def process_torrent(input_directory, input_name, input_category, input_hash, inp
input_files = nzb2media.list_media_files(input_directory, archives=False, other=True, otherext=extensions) input_files = nzb2media.list_media_files(input_directory, archives=False, other=True, otherext=extensions)
else: else:
input_files = nzb2media.list_media_files(input_directory, other=True, otherext=extensions) input_files = nzb2media.list_media_files(input_directory, other=True, otherext=extensions)
if len(input_files) == 0 and os.path.isfile(input_directory): if not input_files and os.path.isfile(input_directory):
input_files = [input_directory] input_files = [input_directory]
log.debug(f'Found 1 file to process: {input_directory}') log.debug(f'Found 1 file to process: {input_directory}')
else: else:
@ -173,7 +173,7 @@ def process_torrent(input_directory, input_name, input_category, input_hash, inp
else: else:
continue # This file has not been recently moved or created, skip it continue # This file has not been recently moved or created, skip it
if torrent_no_link == 0: if not torrent_no_link:
try: try:
nzb2media.copy_link(input_file, target_file, nzb2media.USE_LINK) nzb2media.copy_link(input_file, target_file, nzb2media.USE_LINK)
nzb2media.remove_read_only(target_file) nzb2media.remove_read_only(target_file)
@ -246,7 +246,7 @@ def process_torrent(input_directory, input_name, input_category, input_hash, inp
plex_update(input_category) plex_update(input_category)
if result.status_code != 0: if result.status_code:
if not nzb2media.TORRENT_RESUME_ON_FAILURE: if not nzb2media.TORRENT_RESUME_ON_FAILURE:
log.error( log.error(
'A problem was reported in the autoProcess* script. ' 'A problem was reported in the autoProcess* script. '
@ -344,11 +344,11 @@ def main(args):
dir_name, input_name, subsection, input_hash or None, input_id or None, dir_name, input_name, subsection, input_hash or None, input_id or None,
client_agent, client_agent,
) )
if results.status_code != 0: if results.status_code:
log.error(f'A problem was reported when trying to perform a manual run for {section}:{subsection}.') log.error(f'A problem was reported when trying to perform a manual run for {section}:{subsection}.')
result = results result = results
if result.status_code == 0: if not result.status_code:
log.info(f'The {args[0]} script completed successfully.') log.info(f'The {args[0]} script completed successfully.')
else: else:
log.error(f'A problem was reported in the {args[0]} script.') log.error(f'A problem was reported in the {args[0]} script.')

View file

@ -7,6 +7,20 @@ trigger:
- master - master
jobs: jobs:
- job: 'Lint'
pool:
vmImage: 'Ubuntu-latest'
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.x'
architecture: 'x64'
- script: |
pip install pre-commit pylint -r requirements.txt
pre-commit run --all-files
displayName: 'Run pre-commit tests'
- job: 'Test' - job: 'Test'
pool: pool:

View file

@ -1,5 +1,10 @@
black
bump2version bump2version
flake8
flake8-bugbear
flake8-commas
flake8-comprehensions
flake8-docstrings
flake8-future-import
mypy mypy
pre-commit pre-commit
pylint[spelling] pylint[spelling]

View file

@ -11,11 +11,11 @@ import subprocess
import sys import sys
import time import time
import typing import typing
from subprocess import PIPE, DEVNULL from subprocess import DEVNULL
from nzb2media import tool
from nzb2media import databases from nzb2media import databases
from nzb2media import main_db from nzb2media import main_db
from nzb2media import tool
from nzb2media import version_check from nzb2media import version_check
from nzb2media.configuration import Config from nzb2media.configuration import Config
from nzb2media.nzb.configuration import configure_nzbs from nzb2media.nzb.configuration import configure_nzbs
@ -29,22 +29,6 @@ from nzb2media.utils.processes import restart
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
log.addHandler(logging.NullHandler()) log.addHandler(logging.NullHandler())
try:
import win32event
except ImportError:
if sys.platform == 'win32':
sys.exit('Please install pywin32')
def which(name) -> pathlib.Path | None:
with subprocess.Popen(['which', name], stdout=PIPE) as proc:
try:
proc_out, proc_err = proc.communicate()
except Exception:
return None
else:
location = proc_out.strip().decode()
return pathlib.Path(location)
def module_path(module=__file__): def module_path(module=__file__):

View file

@ -41,7 +41,7 @@ def process(*, section: str, dir_name: str, input_name: str = '', status: int =
input_name, dir_name = convert_to_ascii(input_name, dir_name) input_name, dir_name = convert_to_ascii(input_name, dir_name)
fields = input_name.split('-') fields = input_name.split('-')
gamez_id = fields[0].replace('[', '').replace(']', '').replace(' ', '') gamez_id = fields[0].replace('[', '').replace(']', '').replace(' ', '')
download_status = 'Downloaded' if status == 0 else 'Wanted' download_status = 'Downloaded' if not status else 'Wanted'
params = {'api_key': apikey, 'mode': 'UPDATEREQUESTEDSTATUS', 'db_id': gamez_id, 'status': download_status} params = {'api_key': apikey, 'mode': 'UPDATEREQUESTEDSTATUS', 'db_id': gamez_id, 'status': download_status}
log.debug(f'Opening URL: {url}') log.debug(f'Opening URL: {url}')
try: try:

View file

@ -151,10 +151,10 @@ def process(*, section: str, dir_name: str, input_name: str = '', status: int =
status = 1 status = 1
if 'NZBOP_VERSION' in os.environ and os.environ['NZBOP_VERSION'][0:5] >= '14.0': if 'NZBOP_VERSION' in os.environ and os.environ['NZBOP_VERSION'][0:5] >= '14.0':
print('[NZB] MARK=BAD') print('[NZB] MARK=BAD')
if status == 0: if not status:
if nzb2media.TRANSCODE == 1: if nzb2media.TRANSCODE == 1:
result, new_dir_name = transcoder.transcode_directory(dir_name) result, new_dir_name = transcoder.transcode_directory(dir_name)
if result == 0: if not result:
log.debug(f'Transcoding succeeded for files in {dir_name}') log.debug(f'Transcoding succeeded for files in {dir_name}')
dir_name = new_dir_name dir_name = new_dir_name
log.debug(f'Config setting \'chmodDirectory\' currently set to {oct(chmod_directory)}') log.debug(f'Config setting \'chmodDirectory\' currently set to {oct(chmod_directory)}')

View file

@ -69,7 +69,7 @@ def process(*, section: str, dir_name: str, input_name: str = '', status: int =
# if listMediaFiles(dir_name, media=False, audio=True, meta=False, archives=False) and status: # if listMediaFiles(dir_name, media=False, audio=True, meta=False, archives=False) and status:
# logger.info('Status shown as failed from Downloader, but valid video files found. Setting as successful.', SECTION) # logger.info('Status shown as failed from Downloader, but valid video files found. Setting as successful.', SECTION)
# status = 0 # status = 0
if status == 0 and section == 'HeadPhones': if not status and section == 'HeadPhones':
params = {'apikey': apikey, 'cmd': 'forceProcess', 'dir': remote_dir(dir_name) if remote_path else dir_name} params = {'apikey': apikey, 'cmd': 'forceProcess', 'dir': remote_dir(dir_name) if remote_path else dir_name}
res = force_process(params, url, apikey, input_name, dir_name, section, wait_for) res = force_process(params, url, apikey, input_name, dir_name, section, wait_for)
if res.status_code in {0, 1}: if res.status_code in {0, 1}:
@ -81,7 +81,7 @@ def process(*, section: str, dir_name: str, input_name: str = '', status: int =
# The status hasn't changed. uTorrent can resume seeding now. # The status hasn't changed. uTorrent can resume seeding now.
log.warning(f'The music album does not appear to have changed status after {wait_for} minutes. Please check your Logs') log.warning(f'The music album does not appear to have changed status after {wait_for} minutes. Please check your Logs')
return ProcessResult.failure(f'{section}: Failed to post-process - No change in wanted status') return ProcessResult.failure(f'{section}: Failed to post-process - No change in wanted status')
if status == 0 and section == 'Lidarr': if not status and section == 'Lidarr':
route = f'{web_root}/api/v1/command' route = f'{web_root}/api/v1/command'
url = nzb2media.utils.common.create_url(scheme, host, port, route) url = nzb2media.utils.common.create_url(scheme, host, port, route)
headers = {'X-Api-Key': apikey} headers = {'X-Api-Key': apikey}

View file

@ -130,10 +130,10 @@ def process(*, section: str, dir_name: str, input_name: str = '', status: int =
import_subs(video) import_subs(video)
rename_subs(dir_name) rename_subs(dir_name)
if num_files > 0: if num_files > 0:
if valid_files == num_files and not status == 0: if valid_files == num_files and status:
log.info('Found Valid Videos. Setting status Success') log.info('Found Valid Videos. Setting status Success')
status = 0 status = 0
if valid_files < num_files and status == 0: if valid_files < num_files and not status:
log.info('Found corrupt videos. Setting status Failed') log.info('Found corrupt videos. Setting status Failed')
status = 1 status = 1
if 'NZBOP_VERSION' in os.environ and os.environ['NZBOP_VERSION'][0:5] >= '14.0': if 'NZBOP_VERSION' in os.environ and os.environ['NZBOP_VERSION'][0:5] >= '14.0':
@ -150,7 +150,7 @@ def process(*, section: str, dir_name: str, input_name: str = '', status: int =
return ProcessResult.success() return ProcessResult.success()
elif nzb_extraction_by == 'Destination': elif nzb_extraction_by == 'Destination':
log.info('Check for media files ignored because nzbExtractionBy is set to Destination.') log.info('Check for media files ignored because nzbExtractionBy is set to Destination.')
if status == 0: if not status:
log.info('Setting Status Success.') log.info('Setting Status Success.')
else: else:
log.info('Downloader reported an error during download or verification. Processing this as a failed download.') log.info('Downloader reported an error during download or verification. Processing this as a failed download.')
@ -160,9 +160,10 @@ def process(*, section: str, dir_name: str, input_name: str = '', status: int =
status = 1 status = 1
if 'NZBOP_VERSION' in os.environ and os.environ['NZBOP_VERSION'][0:5] >= '14.0': if 'NZBOP_VERSION' in os.environ and os.environ['NZBOP_VERSION'][0:5] >= '14.0':
print('[NZB] MARK=BAD') print('[NZB] MARK=BAD')
if status == 0 and nzb2media.TRANSCODE == 1: # only transcode successful downloads if not status and nzb2media.TRANSCODE == 1:
# only transcode successful downloads
result, new_dir_name = transcoder.transcode_directory(dir_name) result, new_dir_name = transcoder.transcode_directory(dir_name)
if result == 0: if not result:
log.debug(f'SUCCESS: Transcoding succeeded for files in {dir_name}') log.debug(f'SUCCESS: Transcoding succeeded for files in {dir_name}')
dir_name = new_dir_name dir_name = new_dir_name
log.debug(f'Config setting \'chmodDirectory\' currently set to {oct(chmod_directory)}') log.debug(f'Config setting \'chmodDirectory\' currently set to {oct(chmod_directory)}')
@ -230,7 +231,7 @@ def process(*, section: str, dir_name: str, input_name: str = '', status: int =
for key, val in list(fork_params.items()): for key, val in list(fork_params.items()):
if val is None: if val is None:
del fork_params[key] del fork_params[key]
if status == 0: if not status:
if section == 'NzbDrone' and not apikey: if section == 'NzbDrone' and not apikey:
log.info('No Sonarr apikey entered. Processing completed.') log.info('No Sonarr apikey entered. Processing completed.')
return ProcessResult.success(f'{section}: Successfully post-processed {input_name}') return ProcessResult.success(f'{section}: Successfully post-processed {input_name}')
@ -338,9 +339,8 @@ def process(*, section: str, dir_name: str, input_name: str = '', status: int =
elif section == 'SiCKRAGE': elif section == 'SiCKRAGE':
if api_version >= 2: if api_version >= 2:
success = True success = True
else: elif response.json()['result'] == 'success':
if response.json()['result'] == 'success': success = True
success = True
elif section == 'NzbDrone': elif section == 'NzbDrone':
try: try:
res = response.json() res = response.json()
@ -351,7 +351,7 @@ def process(*, section: str, dir_name: str, input_name: str = '', status: int =
log.warning(f'No scan id was returned due to: {error}') log.warning(f'No scan id was returned due to: {error}')
scan_id = None scan_id = None
started = False started = False
if status != 0 and delete_failed and not os.path.dirname(dir_name) == dir_name: if status and delete_failed and not os.path.dirname(dir_name) == dir_name:
log.debug(f'Deleting failed files and folder {dir_name}') log.debug(f'Deleting failed files and folder {dir_name}')
remove_dir(dir_name) remove_dir(dir_name)
if success: if success:

View file

@ -73,9 +73,8 @@ class Section(configobj.Section):
if key in options: if key in options:
return options[key] return options[key]
del subsections[subsection] del subsections[subsection]
else: elif section not in key:
if section not in key: del to_return[section]
del to_return[section]
# cleanout empty sections and subsections # cleanout empty sections and subsections
for key in [k for (k, v) in to_return.items() if not v]: for key in [k for (k, v) in to_return.items() if not v]:
del to_return[key] del to_return[key]

View file

@ -113,21 +113,21 @@ def extract(file_path, output_destination):
cmd2.append('-p-') # don't prompt for password. cmd2.append('-p-') # don't prompt for password.
with Popen(cmd2, stdout=DEVNULL, stderr=DEVNULL, startupinfo=info) as proc: with Popen(cmd2, stdout=DEVNULL, stderr=DEVNULL, startupinfo=info) as proc:
res = proc.wait() # should extract files fine. res = proc.wait() # should extract files fine.
if res == 0: # Both Linux and Windows return 0 for successful. if not res: # Both Linux and Windows return 0 for successful.
log.info(f'EXTRACTOR: Extraction was successful for {file_path} to {output_destination}') log.info(f'EXTRACTOR: Extraction was successful for {file_path} to {output_destination}')
success = 1 success = 1
elif len(passwords) > 0 and 'gunzip' not in cmd: elif len(passwords) > 0 and 'gunzip' not in cmd:
log.info('EXTRACTOR: Attempting to extract with passwords') log.info('EXTRACTOR: Attempting to extract with passwords')
for password in passwords: for password in passwords:
if password == '': # if edited in windows or otherwise if blank lines. if not password:
continue continue # if edited in windows or otherwise if blank lines.
cmd2 = cmd cmd2 = cmd
# append password here. # append password here.
passcmd = f'-p{password}' passcmd = f'-p{password}'
cmd2.append(passcmd) cmd2.append(passcmd)
with Popen(cmd2, stdout=DEVNULL, stderr=DEVNULL, startupinfo=info) as proc: with Popen(cmd2, stdout=DEVNULL, stderr=DEVNULL, startupinfo=info) as proc:
res = proc.wait() # should extract files fine. res = proc.wait() # should extract files fine.
if (res >= 0 and platform == 'Windows') or res == 0: if not res or (res >= 0 and platform == 'Windows'):
log.info(f'EXTRACTOR: Extraction was successful for {file_path} to {output_destination} using password: {password}') log.info(f'EXTRACTOR: Extraction was successful for {file_path} to {output_destination} using password: {password}')
success = 1 success = 1
break break

View file

@ -20,8 +20,8 @@ class GitHub:
return data.json() if data.ok else [] return data.json() if data.ok else []
def commits(self): def commits(self):
""" """Get the 100 most recent commits from the specified user/repo/branch, starting from HEAD.
Get the 100 most recent commits from the specified user/repo/branch, starting from HEAD.
user: The github username of the person whose repo you're querying user: The github username of the person whose repo you're querying
repo: The repo name to query repo: The repo name to query
branch: Optional, the branch name to show commits from branch: Optional, the branch name to show commits from
@ -30,8 +30,8 @@ class GitHub:
return self._access_api(['repos', self.github_repo_user, self.github_repo, 'commits'], params={'per_page': 100, 'sha': self.branch}) return self._access_api(['repos', self.github_repo_user, self.github_repo, 'commits'], params={'per_page': 100, 'sha': self.branch})
def compare(self, base, head, per_page=1): def compare(self, base, head, per_page=1):
""" """Get compares between base and head.
Get compares between base and head.
user: The github username of the person whose repo you're querying user: The github username of the person whose repo you're querying
repo: The repo name to query repo: The repo name to query
base: Start compare from branch base: Start compare from branch

View file

@ -11,9 +11,9 @@ log = logging.getLogger(__name__)
log.addHandler(logging.NullHandler()) log.addHandler(logging.NullHandler())
def db_filename(filename='nzbtomedia.db', suffix=None): def db_filename(filename: str = 'nzbtomedia.db', suffix: str | None = None):
""" """Return the correct location of the database file.
Return the correct location of the database file.
@param filename: The sqlite database filename to use. If not specified, will be made to be nzbtomedia.db @param filename: The sqlite database filename to use. If not specified, will be made to be nzbtomedia.db
@param suffix: The suffix to append to the filename. A '.' will be added @param suffix: The suffix to append to the filename. A '.' will be added
automatically, i.e. suffix='v0' will make dbfile.db.v0 automatically, i.e. suffix='v0' will make dbfile.db.v0

View file

@ -17,6 +17,7 @@ log.addHandler(logging.NullHandler())
class InitSickBeard: class InitSickBeard:
"""SickBeard init class. """SickBeard init class.
Used to determine which SickBeard fork object to initialize. Used to determine which SickBeard fork object to initialize.
""" """
@ -204,7 +205,9 @@ class InitSickBeard:
def _init_fork(self): def _init_fork(self):
# These need to be imported here, to prevent a circular import. # These need to be imported here, to prevent a circular import.
from .pymedusa import PyMedusa, PyMedusaApiV1, PyMedusaApiV2 from .pymedusa import PyMedusa
from .pymedusa import PyMedusaApiV1
from .pymedusa import PyMedusaApiV2
mapped_forks = {'Medusa': PyMedusa, 'Medusa-api': PyMedusaApiV1, 'Medusa-apiv2': PyMedusaApiV2} mapped_forks = {'Medusa': PyMedusa, 'Medusa-api': PyMedusaApiV1, 'Medusa-apiv2': PyMedusaApiV2}
log.debug(f'Create object for fork {self.fork}') log.debug(f'Create object for fork {self.fork}')
@ -243,7 +246,8 @@ class SickBeard:
self.success = False self.success = False
def initialize(self, dir_name, input_name=None, failed=False, client_agent='manual'): def initialize(self, dir_name, input_name=None, failed=False, client_agent='manual'):
"""We need to call this explicitely because we need some variables. """We need to call this explicitly because we need some variables.
We can't pass these directly through the constructor. We can't pass these directly through the constructor.
""" """
self.dir_name = dir_name self.dir_name = dir_name
@ -358,6 +362,7 @@ class SickBeard:
def process_response(self, response: requests.Response) -> ProcessResult: def process_response(self, response: requests.Response) -> ProcessResult:
"""Iterate over the lines returned, and log. """Iterate over the lines returned, and log.
:param response: Streamed Requests response object. :param response: Streamed Requests response object.
This method will need to be overwritten in the forks, for alternative response handling. This method will need to be overwritten in the forks, for alternative response handling.
""" """

View file

@ -38,7 +38,7 @@ def process():
continue continue
input_name = os.path.basename(dir_name) input_name = os.path.basename(dir_name)
results = nzb.process(dir_name, input_name, 0, client_agent=client_agent, download_id=download_id or None, input_category=subsection) results = nzb.process(dir_name, input_name, 0, client_agent=client_agent, download_id=download_id or None, input_category=subsection)
if results.status_code != 0: if results.status_code:
log.error(f'A problem was reported when trying to perform a manual run for {section}:{subsection}.') log.error(f'A problem was reported when trying to perform a manual run for {section}:{subsection}.')
result = results result = results
return result return result

View file

@ -85,7 +85,7 @@ def process(input_directory, input_name=None, status=0, client_agent='manual', d
processor = process_map[section_name] processor = process_map[section_name]
result = processor(section=section_name, dir_name=input_directory, input_name=input_name, status=status, client_agent=client_agent, download_id=download_id, input_category=input_category, failure_link=failure_link) result = processor(section=section_name, dir_name=input_directory, input_name=input_name, status=status, client_agent=client_agent, download_id=download_id, input_category=input_category, failure_link=failure_link)
plex_update(input_category) plex_update(input_category)
if result.status_code == 0: if not result.status_code:
if client_agent != 'manual': if client_agent != 'manual':
# update download status in our DB # update download status in our DB
update_download_info_status(input_name, 1) update_download_info_status(input_name, 1)

View file

@ -18,6 +18,7 @@ def process_script():
def process(args): def process(args):
"""Process job from SABnzb. """Process job from SABnzb.
SABnzbd arguments: SABnzbd arguments:
1. The final directory of the job (full path) 1. The final directory of the job (full path)
2. The original name of the NZB file 2. The original name of the NZB file

View file

@ -164,7 +164,7 @@ def par2(dirname):
result = proc.returncode result = proc.returncode
except Exception: except Exception:
log.error(f'par2 file processing for {parfile} has failed') log.error(f'par2 file processing for {parfile} has failed')
if result == 0: if not result:
log.info('par2 file processing succeeded') log.info('par2 file processing succeeded')
os.chdir(pwd) os.chdir(pwd)

View file

@ -11,7 +11,8 @@ import shutil
import subprocess import subprocess
import sys import sys
import time import time
from subprocess import PIPE, DEVNULL from subprocess import DEVNULL
from subprocess import PIPE
from babelfish import Language from babelfish import Language
@ -30,7 +31,7 @@ def is_video_good(video: pathlib.Path, status, require_lan=None):
disable = True disable = True
else: else:
test_details, res = get_video_details(nzb2media.TEST_FILE) test_details, res = get_video_details(nzb2media.TEST_FILE)
if res != 0 or test_details.get('error'): if res or test_details.get('error'):
disable = True disable = True
log.info('DISABLED: ffprobe failed to analyse test file. Stopping corruption check.') log.info('DISABLED: ffprobe failed to analyse test file. Stopping corruption check.')
if test_details.get('streams'): if test_details.get('streams'):
@ -47,7 +48,7 @@ def is_video_good(video: pathlib.Path, status, require_lan=None):
return True return True
log.info(f'Checking [{video.name}] for corruption, please stand by ...') log.info(f'Checking [{video.name}] for corruption, please stand by ...')
video_details, result = get_video_details(video) video_details, result = get_video_details(video)
if result != 0: if result:
log.error(f'FAILED: [{video.name}] is corrupted!') log.error(f'FAILED: [{video.name}] is corrupted!')
return False return False
if video_details.get('error'): if video_details.get('error'):
@ -125,7 +126,7 @@ def get_video_details(videofile, img=None):
def check_vid_file(video_details, result): def check_vid_file(video_details, result):
if result != 0: if result:
return False return False
if video_details.get('error'): if video_details.get('error'):
return False return False
@ -381,7 +382,7 @@ def build_commands(file, new_dir, movie_name):
audio_cmd2.extend([f'-c:a:{used_audio}', 'copy']) audio_cmd2.extend([f'-c:a:{used_audio}', 'copy'])
elif audio3: elif audio3:
# wrong language, wrong codec just pick the default audio track # wrong language, wrong codec just pick the default audio track
_inded = audio3[0]['index'] _index = audio3[0]['index']
map_cmd.extend(['-map', f'0:{_index}']) map_cmd.extend(['-map', f'0:{_index}'])
a_mapped.extend([audio3[0]['index']]) a_mapped.extend([audio3[0]['index']])
bitrate = int(float(audio3[0].get('bit_rate', 0))) / 1000 bitrate = int(float(audio3[0].get('bit_rate', 0))) / 1000
@ -423,11 +424,10 @@ def build_commands(file, new_dir, movie_name):
channels = int(float(audio.get('channels', 0))) channels = int(float(audio.get('channels', 0)))
if audio['codec_name'] in nzb2media.ACODEC3_ALLOW: if audio['codec_name'] in nzb2media.ACODEC3_ALLOW:
audio_cmd3.extend([f'-c:a:{used_audio}', 'copy']) audio_cmd3.extend([f'-c:a:{used_audio}', 'copy'])
elif nzb2media.ACODEC3:
audio_cmd3.extend([f'-c:a:{used_audio}', nzb2media.ACODEC3])
else: else:
if nzb2media.ACODEC3: audio_cmd3.extend([f'-c:a:{used_audio}', 'copy'])
audio_cmd3.extend([f'-c:a:{used_audio}', nzb2media.ACODEC3])
else:
audio_cmd3.extend([f'-c:a:{used_audio}', 'copy'])
if nzb2media.ACHANNELS3 and channels and channels > nzb2media.ACHANNELS3: if nzb2media.ACHANNELS3 and channels and channels > nzb2media.ACHANNELS3:
audio_cmd3.extend([f'-ac:a:{used_audio}', str(nzb2media.ACHANNELS3)]) audio_cmd3.extend([f'-ac:a:{used_audio}', str(nzb2media.ACHANNELS3)])
if audio_cmd3[1] == 'copy': if audio_cmd3[1] == 'copy':
@ -519,11 +519,10 @@ def build_commands(file, new_dir, movie_name):
map_cmd.extend(['-map', f'{num}:0']) map_cmd.extend(['-map', f'{num}:0'])
if not nzb2media.ALLOWSUBS or (not s_mapped and not num): if not nzb2media.ALLOWSUBS or (not s_mapped and not num):
sub_cmd.extend(['-sn']) sub_cmd.extend(['-sn'])
elif nzb2media.SCODEC:
sub_cmd.extend(['-c:s', nzb2media.SCODEC])
else: else:
if nzb2media.SCODEC: sub_cmd.extend(['-c:s', 'copy'])
sub_cmd.extend(['-c:s', nzb2media.SCODEC])
else:
sub_cmd.extend(['-c:s', 'copy'])
command.extend(map_cmd) command.extend(map_cmd)
command.extend(video_cmd) command.extend(video_cmd)
command.extend(audio_cmd) command.extend(audio_cmd)
@ -586,7 +585,7 @@ def extract_subs(file, newfile_path):
result = proc.returncode result = proc.returncode
except Exception: except Exception:
log.error('Extracting subtitle has failed') log.error('Extracting subtitle has failed')
if result == 0: if not result:
try: try:
shutil.copymode(file, output_file) shutil.copymode(file, output_file)
except Exception: except Exception:
@ -888,7 +887,7 @@ def transcode_directory(dir_name):
result = proc.returncode result = proc.returncode
except Exception: except Exception:
log.error(f'Transcoding of video {newfile_path} has failed') log.error(f'Transcoding of video {newfile_path} has failed')
if nzb2media.SUBSDIR and result == 0 and isinstance(file, str): if nzb2media.SUBSDIR and not result and isinstance(file, str):
for sub in get_subs(file): for sub in get_subs(file):
name = os.path.splitext(os.path.split(file)[1])[0] name = os.path.splitext(os.path.split(file)[1])[0]
subname = os.path.split(sub)[1] subname = os.path.split(sub)[1]
@ -896,7 +895,7 @@ def transcode_directory(dir_name):
newpath = os.path.join(nzb2media.SUBSDIR, subname.replace(name, newname)) newpath = os.path.join(nzb2media.SUBSDIR, subname.replace(name, newname))
if not os.path.isfile(newpath): if not os.path.isfile(newpath):
os.rename(sub, newpath) os.rename(sub, newpath)
if result == 0: if not result:
try: try:
shutil.copymode(file, newfile_path) shutil.copymode(file, newfile_path)
except Exception: except Exception:
@ -920,7 +919,7 @@ def transcode_directory(dir_name):
time.sleep(5) time.sleep(5)
os.rmdir(nzb2media.MOUNTED) os.rmdir(nzb2media.MOUNTED)
nzb2media.MOUNTED = None nzb2media.MOUNTED = None
if final_result == 0 and not nzb2media.DUPLICATE: if not final_result and not nzb2media.DUPLICATE:
for file in rem_list: for file in rem_list:
try: try:
os.unlink(file) os.unlink(file)

View file

@ -108,9 +108,9 @@ def external_script(output_destination, torrent_name, torrent_label, settings):
file_name, file_extension = os.path.splitext(file) file_name, file_extension = os.path.splitext(file)
if file_extension in nzb2media.USER_SCRIPT_MEDIAEXTENSIONS or nzb2media.USER_SCRIPT_MEDIAEXTENSIONS == 'ALL': if file_extension in nzb2media.USER_SCRIPT_MEDIAEXTENSIONS or nzb2media.USER_SCRIPT_MEDIAEXTENSIONS == 'ALL':
num_files_new += 1 num_files_new += 1
if nzb2media.USER_SCRIPT_CLEAN == int(1) and num_files_new == 0 and final_result == 0: if nzb2media.USER_SCRIPT_CLEAN == 1 and not num_files_new and not final_result:
log.info(f'All files have been processed. Cleaning outputDirectory {output_destination}') log.info(f'All files have been processed. Cleaning outputDirectory {output_destination}')
remove_dir(output_destination) remove_dir(output_destination)
elif nzb2media.USER_SCRIPT_CLEAN == int(1) and num_files_new != 0: elif nzb2media.USER_SCRIPT_CLEAN == 1 and num_files_new:
log.info(f'{num_files} files were processed, but {num_files_new} still remain. outputDirectory will not be cleaned.') log.info(f'{num_files} files were processed, but {num_files_new} still remain. outputDirectory will not be cleaned.')
return ProcessResult(status_code=final_result, message='User Script Completed') return ProcessResult(status_code=final_result, message='User Script Completed')

View file

@ -59,7 +59,8 @@ def char_replace(name_in):
def convert_to_ascii(input_name, dir_name): def convert_to_ascii(input_name, dir_name):
ascii_convert = int(nzb2media.CFG['ASCII']['convert']) ascii_convert = int(nzb2media.CFG['ASCII']['convert'])
if ascii_convert == 0 or os.name == 'nt': # just return if we don't want to convert or on windows os and '\' is replaced!. if not ascii_convert or os.name == 'nt':
# just return if we don't want to convert or on windows os and '\' is replaced!.
return input_name, dir_name return input_name, dir_name
encoded, input_name = char_replace(input_name) encoded, input_name = char_replace(input_name)
directory, base = os.path.split(dir_name) directory, base = os.path.split(dir_name)

View file

@ -32,7 +32,7 @@ def find_imdbid(dir_name, input_name, omdb_api_key) -> str:
return imdbid return imdbid
if 'NZBPR__DNZB_MOREINFO' in os.environ: if 'NZBPR__DNZB_MOREINFO' in os.environ:
dnzb_more_info = os.environ.get('NZBPR__DNZB_MOREINFO', '') dnzb_more_info = os.environ.get('NZBPR__DNZB_MOREINFO', '')
if dnzb_more_info != '': if dnzb_more_info:
regex = re.compile(r'^http://www.imdb.com/title/(tt[0-9]+)/$', re.IGNORECASE) regex = re.compile(r'^http://www.imdb.com/title/(tt[0-9]+)/$', re.IGNORECASE)
match = regex.match(dnzb_more_info) match = regex.match(dnzb_more_info)
if match: if match:

View file

@ -12,11 +12,12 @@ log = logging.getLogger(__name__)
log.addHandler(logging.NullHandler()) log.addHandler(logging.NullHandler())
try: try:
from jaraco.windows.filesystem import islink, readlink from jaraco.windows.filesystem import islink
from jaraco.windows.filesystem import readlink
except ImportError: except ImportError:
if os.name != 'nt': if os.name != 'nt':
from os.path import islink
from os import readlink from os import readlink
from os.path import islink
else: else:
raise raise

View file

@ -4,8 +4,8 @@ import re
def sanitize_name(name): def sanitize_name(name):
""" """Remove bad chars from the filename.
Remove bad chars from the filename.
>>> sanitize_name('a/b/c') >>> sanitize_name('a/b/c')
'a-b-c' 'a-b-c'
>>> sanitize_name('abc') >>> sanitize_name('abc')
@ -23,8 +23,8 @@ def sanitize_name(name):
def clean_file_name(filename): def clean_file_name(filename):
""" """Clean up nzb name by removing any . and _ characters and trailing hyphens.
Clean up nzb name by removing any . and _ characters and trailing hyphens.
Is basically equivalent to replacing all _ and . with a Is basically equivalent to replacing all _ and . with a
space, but handles decimal numbers in string, for example: space, but handles decimal numbers in string, for example:
""" """

View file

@ -101,7 +101,7 @@ def parse_synods():
log.error('unable to find download details in Synology DS') log.error('unable to find download details in Synology DS')
# Syno paths appear to be relative. Let's test to see if the returned path exists, and if not append to /volume1/ # Syno paths appear to be relative. Let's test to see if the returned path exists, and if not append to /volume1/
if not os.path.isdir(input_directory): if not os.path.isdir(input_directory):
for root in ['/volume1/', '/volume2/', '/volume3/', '/volume4/']: for root in ('/volume1/', '/volume2/', '/volume3/', '/volume4/'):
if os.path.isdir(os.path.join(root, input_directory)): if os.path.isdir(os.path.join(root, input_directory)):
input_directory = os.path.join(root, input_directory) input_directory = os.path.join(root, input_directory)
break break

View file

@ -14,8 +14,8 @@ log.addHandler(logging.NullHandler())
def onerror(func, path, exc_info): def onerror(func, path, exc_info):
""" """Error handler for ``shutil.rmtree``.
Error handler for ``shutil.rmtree``.
If the error is due to an access error (read only file) If the error is due to an access error (read only file)
it attempts to add write permission and then retries. it attempts to add write permission and then retries.
If the error is for another reason it re-raises the error. If the error is for another reason it re-raises the error.
@ -83,7 +83,7 @@ def remove_empty_folders(path, remove_root=True):
remove_empty_folders(fullpath) remove_empty_folders(fullpath)
# if folder empty, delete it # if folder empty, delete it
files = os.listdir(path) files = os.listdir(path)
if len(files) == 0 and remove_root: if not files and remove_root:
log.debug(f'Removing empty folder:{path}') log.debug(f'Removing empty folder:{path}')
os.rmdir(path) os.rmdir(path)

View file

@ -10,14 +10,12 @@ import typing
import nzb2media import nzb2media
if os.name == 'nt': if os.name == 'nt':
# pylint: disable-next=no-name-in-module
from win32event import CreateMutex
# pylint: disable-next=no-name-in-module # pylint: disable-next=no-name-in-module
from win32api import CloseHandle from win32api import CloseHandle
# pylint: disable-next=no-name-in-module # pylint: disable-next=no-name-in-module
from win32api import GetLastError from win32api import GetLastError
# pylint: disable-next=no-name-in-module
from win32event import CreateMutex
from winerror import ERROR_ALREADY_EXISTS from winerror import ERROR_ALREADY_EXISTS
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -96,6 +94,8 @@ class PosixProcess:
self.pidpath.unlink() self.pidpath.unlink()
# Alternative union syntax using | fails on Python < 3.10
# pylint: disable-next=consider-alternative-union-syntax
ProcessType = typing.Type[typing.Union[PosixProcess, WindowsProcess]] ProcessType = typing.Type[typing.Union[PosixProcess, WindowsProcess]]
if os.name == 'nt': if os.name == 'nt':
RunningProcess: ProcessType = WindowsProcess RunningProcess: ProcessType = WindowsProcess

View file

@ -30,15 +30,15 @@ def create_torrent_class(client_agent) -> object | None:
def pause_torrent(client_agent, input_hash, input_id, input_name): def pause_torrent(client_agent, input_hash, input_id, input_name):
log.debug(f'Stopping torrent {input_name} in {client_agent} while processing') log.debug(f'Stopping torrent {input_name} in {client_agent} while processing')
try: try:
if client_agent == 'utorrent' and nzb2media.TORRENT_CLASS != '': if client_agent == 'utorrent' and nzb2media.TORRENT_CLASS:
nzb2media.TORRENT_CLASS.stop(input_hash) nzb2media.TORRENT_CLASS.stop(input_hash)
if client_agent == 'transmission' and nzb2media.TORRENT_CLASS != '': if client_agent == 'transmission' and nzb2media.TORRENT_CLASS:
nzb2media.TORRENT_CLASS.stop_torrent(input_id) nzb2media.TORRENT_CLASS.stop_torrent(input_id)
if client_agent == 'synods' and nzb2media.TORRENT_CLASS != '': if client_agent == 'synods' and nzb2media.TORRENT_CLASS:
nzb2media.TORRENT_CLASS.pause_task(input_id) nzb2media.TORRENT_CLASS.pause_task(input_id)
if client_agent == 'deluge' and nzb2media.TORRENT_CLASS != '': if client_agent == 'deluge' and nzb2media.TORRENT_CLASS:
nzb2media.TORRENT_CLASS.core.pause_torrent([input_id]) nzb2media.TORRENT_CLASS.core.pause_torrent([input_id])
if client_agent == 'qbittorrent' and nzb2media.TORRENT_CLASS != '': if client_agent == 'qbittorrent' and nzb2media.TORRENT_CLASS:
nzb2media.TORRENT_CLASS.pause(input_hash) nzb2media.TORRENT_CLASS.pause(input_hash)
time.sleep(5) time.sleep(5)
except Exception: except Exception:
@ -50,15 +50,15 @@ def resume_torrent(client_agent, input_hash, input_id, input_name):
return return
log.debug(f'Starting torrent {input_name} in {client_agent}') log.debug(f'Starting torrent {input_name} in {client_agent}')
try: try:
if client_agent == 'utorrent' and nzb2media.TORRENT_CLASS != '': if client_agent == 'utorrent' and nzb2media.TORRENT_CLASS:
nzb2media.TORRENT_CLASS.start(input_hash) nzb2media.TORRENT_CLASS.start(input_hash)
if client_agent == 'transmission' and nzb2media.TORRENT_CLASS != '': if client_agent == 'transmission' and nzb2media.TORRENT_CLASS:
nzb2media.TORRENT_CLASS.start_torrent(input_id) nzb2media.TORRENT_CLASS.start_torrent(input_id)
if client_agent == 'synods' and nzb2media.TORRENT_CLASS != '': if client_agent == 'synods' and nzb2media.TORRENT_CLASS:
nzb2media.TORRENT_CLASS.resume_task(input_id) nzb2media.TORRENT_CLASS.resume_task(input_id)
if client_agent == 'deluge' and nzb2media.TORRENT_CLASS != '': if client_agent == 'deluge' and nzb2media.TORRENT_CLASS:
nzb2media.TORRENT_CLASS.core.resume_torrent([input_id]) nzb2media.TORRENT_CLASS.core.resume_torrent([input_id])
if client_agent == 'qbittorrent' and nzb2media.TORRENT_CLASS != '': if client_agent == 'qbittorrent' and nzb2media.TORRENT_CLASS:
nzb2media.TORRENT_CLASS.resume(input_hash) nzb2media.TORRENT_CLASS.resume(input_hash)
time.sleep(5) time.sleep(5)
except Exception: except Exception:
@ -69,16 +69,16 @@ def remove_torrent(client_agent, input_hash, input_id, input_name):
if nzb2media.DELETE_ORIGINAL == 1 or nzb2media.USE_LINK == 'move': if nzb2media.DELETE_ORIGINAL == 1 or nzb2media.USE_LINK == 'move':
log.debug(f'Deleting torrent {input_name} from {client_agent}') log.debug(f'Deleting torrent {input_name} from {client_agent}')
try: try:
if client_agent == 'utorrent' and nzb2media.TORRENT_CLASS != '': if client_agent == 'utorrent' and nzb2media.TORRENT_CLASS:
nzb2media.TORRENT_CLASS.removedata(input_hash) nzb2media.TORRENT_CLASS.removedata(input_hash)
nzb2media.TORRENT_CLASS.remove(input_hash) nzb2media.TORRENT_CLASS.remove(input_hash)
if client_agent == 'transmission' and nzb2media.TORRENT_CLASS != '': if client_agent == 'transmission' and nzb2media.TORRENT_CLASS:
nzb2media.TORRENT_CLASS.remove_torrent(input_id, True) nzb2media.TORRENT_CLASS.remove_torrent(input_id, True)
if client_agent == 'synods' and nzb2media.TORRENT_CLASS != '': if client_agent == 'synods' and nzb2media.TORRENT_CLASS:
nzb2media.TORRENT_CLASS.delete_task(input_id) nzb2media.TORRENT_CLASS.delete_task(input_id)
if client_agent == 'deluge' and nzb2media.TORRENT_CLASS != '': if client_agent == 'deluge' and nzb2media.TORRENT_CLASS:
nzb2media.TORRENT_CLASS.core.remove_torrent(input_id, True) nzb2media.TORRENT_CLASS.core.remove_torrent(input_id, True)
if client_agent == 'qbittorrent' and nzb2media.TORRENT_CLASS != '': if client_agent == 'qbittorrent' and nzb2media.TORRENT_CLASS:
nzb2media.TORRENT_CLASS.delete_permanently(input_hash) nzb2media.TORRENT_CLASS.delete_permanently(input_hash)
time.sleep(5) time.sleep(5)
except Exception: except Exception:

View file

@ -11,7 +11,8 @@ import stat
import subprocess import subprocess
import tarfile import tarfile
import traceback import traceback
from subprocess import PIPE, STDOUT from subprocess import PIPE
from subprocess import STDOUT
from urllib.request import urlretrieve from urllib.request import urlretrieve
import nzb2media import nzb2media
@ -40,8 +41,8 @@ class CheckVersion:
@staticmethod @staticmethod
def find_install_type(): def find_install_type():
""" """Determine how this copy of SB was installed.
Determine how this copy of SB was installed.
returns: type of installation. Possible values are: returns: type of installation. Possible values are:
'win': any compiled windows build 'win': any compiled windows build
'git': running from source using git 'git': running from source using git
@ -55,8 +56,8 @@ class CheckVersion:
return install_type return install_type
def check_for_new_version(self, force=False): def check_for_new_version(self, force=False):
""" """Check the internet for a newer version.
Check the internet for a newer version.
returns: bool, True for new version or False for no new version. returns: bool, True for new version or False for no new version.
force: if true the VERSION_NOTIFY setting will be ignored and a check will be forced force: if true the VERSION_NOTIFY setting will be ignored and a check will be forced
""" """
@ -114,7 +115,7 @@ class GitUpdateManager(UpdateManager):
main_git = 'git' main_git = 'git'
log.debug(f'Checking if we can use git commands: {main_git} {test_cmd}') log.debug(f'Checking if we can use git commands: {main_git} {test_cmd}')
output, err, exit_status = self._run_git(main_git, test_cmd) output, err, exit_status = self._run_git(main_git, test_cmd)
if exit_status == 0: if not exit_status:
log.debug(f'Using: {main_git}') log.debug(f'Using: {main_git}')
return main_git return main_git
log.debug(f'Not using: {main_git}') log.debug(f'Not using: {main_git}')
@ -131,7 +132,7 @@ class GitUpdateManager(UpdateManager):
for cur_git in alternative_git: for cur_git in alternative_git:
log.debug(f'Checking if we can use git commands: {cur_git} {test_cmd}') log.debug(f'Checking if we can use git commands: {cur_git} {test_cmd}')
output, err, exit_status = self._run_git(cur_git, test_cmd) output, err, exit_status = self._run_git(cur_git, test_cmd)
if exit_status == 0: if not exit_status:
log.debug(f'Using: {cur_git}') log.debug(f'Using: {cur_git}')
return cur_git return cur_git
log.debug(f'Not using: {cur_git}') log.debug(f'Not using: {cur_git}')
@ -160,7 +161,7 @@ class GitUpdateManager(UpdateManager):
log.error(f'Command {cmd} didn\'t work') log.error(f'Command {cmd} didn\'t work')
proc_status = 1 proc_status = 1
proc_status = 128 if ('fatal:' in result) or proc_err else proc_status proc_status = 128 if ('fatal:' in result) or proc_err else proc_status
if proc_status == 0: if not proc_status:
log.debug(f'{cmd} : returned successful') log.debug(f'{cmd} : returned successful')
proc_status = 0 proc_status = 0
elif nzb2media.LOG_GIT and proc_status in {1, 128}: elif nzb2media.LOG_GIT and proc_status in {1, 128}:
@ -172,13 +173,13 @@ class GitUpdateManager(UpdateManager):
return result, proc_err, proc_status return result, proc_err, proc_status
def _find_installed_version(self): def _find_installed_version(self):
""" """Attempt to find the currently installed version of Sick Beard.
Attempt to find the currently installed version of Sick Beard.
Uses git show to get commit version. Uses git show to get commit version.
Returns: True for success or False for failure Returns: True for success or False for failure
""" """
output, err, exit_status = self._run_git(self._git_path, 'rev-parse HEAD') output, err, exit_status = self._run_git(self._git_path, 'rev-parse HEAD')
if exit_status == 0 and output: if not exit_status and output:
cur_commit_hash = output.strip() cur_commit_hash = output.strip()
if not re.match('^[a-z0-9]+$', cur_commit_hash): if not re.match('^[a-z0-9]+$', cur_commit_hash):
log.error('Output doesn\'t look like a hash, not using it') log.error('Output doesn\'t look like a hash, not using it')
@ -192,7 +193,7 @@ class GitUpdateManager(UpdateManager):
def _find_git_branch(self): def _find_git_branch(self):
nzb2media.NZBTOMEDIA_BRANCH = self.get_github_branch() nzb2media.NZBTOMEDIA_BRANCH = self.get_github_branch()
branch_info, err, exit_status = self._run_git(self._git_path, 'symbolic-ref -q HEAD') branch_info, err, exit_status = self._run_git(self._git_path, 'symbolic-ref -q HEAD')
if exit_status == 0 and branch_info: if not exit_status and branch_info:
branch = branch_info.strip().replace('refs/heads/', '', 1) branch = branch_info.strip().replace('refs/heads/', '', 1)
if branch: if branch:
nzb2media.NZBTOMEDIA_BRANCH = branch nzb2media.NZBTOMEDIA_BRANCH = branch
@ -200,8 +201,8 @@ class GitUpdateManager(UpdateManager):
return nzb2media.GIT_BRANCH return nzb2media.GIT_BRANCH
def _check_github_for_update(self): def _check_github_for_update(self):
""" """Check Github for a new version.
Check Github for a new version.
Uses git commands to check if there is a newer version than Uses git commands to check if there is a newer version than
the provided commit hash. If there is a newer version it the provided commit hash. If there is a newer version it
sets _num_commits_behind. sets _num_commits_behind.
@ -211,12 +212,12 @@ class GitUpdateManager(UpdateManager):
self._num_commits_ahead = 0 self._num_commits_ahead = 0
# get all new info from github # get all new info from github
output, err, exit_status = self._run_git(self._git_path, 'fetch origin') output, err, exit_status = self._run_git(self._git_path, 'fetch origin')
if not exit_status == 0: if exit_status:
log.error('Unable to contact github, can\'t check for update') log.error('Unable to contact github, can\'t check for update')
return return
# get latest commit_hash from remote # get latest commit_hash from remote
output, err, exit_status = self._run_git(self._git_path, 'rev-parse --verify --quiet \'@{upstream}\'') output, err, exit_status = self._run_git(self._git_path, 'rev-parse --verify --quiet \'@{upstream}\'')
if exit_status == 0 and output: if not exit_status and output:
cur_commit_hash = output.strip() cur_commit_hash = output.strip()
if not re.match('^[a-z0-9]+$', cur_commit_hash): if not re.match('^[a-z0-9]+$', cur_commit_hash):
log.debug('Output doesn\'t look like a hash, not using it') log.debug('Output doesn\'t look like a hash, not using it')
@ -227,7 +228,7 @@ class GitUpdateManager(UpdateManager):
return return
# get number of commits behind and ahead (option --count not supported git < 1.7.2) # get number of commits behind and ahead (option --count not supported git < 1.7.2)
output, err, exit_status = self._run_git(self._git_path, 'rev-list --left-right \'@{upstream}\'...HEAD') output, err, exit_status = self._run_git(self._git_path, 'rev-list --left-right \'@{upstream}\'...HEAD')
if exit_status == 0 and output: if not exit_status and output:
try: try:
self._num_commits_behind = int(output.count('<')) self._num_commits_behind = int(output.count('<'))
self._num_commits_ahead = int(output.count('>')) self._num_commits_ahead = int(output.count('>'))
@ -267,7 +268,7 @@ class GitUpdateManager(UpdateManager):
Returns a bool depending on the call's success. Returns a bool depending on the call's success.
""" """
output, err, exit_status = self._run_git(self._git_path, f'pull origin {self.branch}') output, err, exit_status = self._run_git(self._git_path, f'pull origin {self.branch}')
if exit_status == 0: if not exit_status:
return True return True
return False return False
@ -308,7 +309,7 @@ class SourceUpdateManager(UpdateManager):
return False return False
def _check_github_for_update(self): def _check_github_for_update(self):
""" Check Github for a new version. """Check Github for a new version.
Uses pygithub to ask github if there is a newer version than Uses pygithub to ask github if there is a newer version than
the provided commit hash. If there is a newer version it sets the provided commit hash. If there is a newer version it sets

View file

@ -46,7 +46,7 @@ def main(args, section=None):
else: else:
manual.process() manual.process()
if result.status_code == 0: if not result.status_code:
log.info(f'The {args[0]} script completed successfully.') log.info(f'The {args[0]} script completed successfully.')
if result.message: if result.message:
print(result.message + '!') print(result.message + '!')

View file

@ -1,9 +1,16 @@
#! /usr/bin/env python
from __future__ import annotations from __future__ import annotations
import sys
import pytest
import nzb2media import nzb2media
from nzb2media import transcoder from nzb2media import transcoder
@pytest.mark.xfail(
sys.platform == 'win32' and sys.version_info < (3, 8),
reason='subprocess.Popen does not support pathlib.Path commands in Python 3.7',
)
def test_transcoder_check(): def test_transcoder_check():
assert transcoder.is_video_good(nzb2media.TEST_FILE, 1) is True assert transcoder.is_video_good(nzb2media.TEST_FILE, 1) is True

91
tox.ini
View file

@ -27,98 +27,15 @@ deps =
pytest-cov pytest-cov
-rrequirements.txt -rrequirements.txt
commands = commands =
{posargs:pytest -vvv --cov --cov-report=term-missing --cov-branch tests} {posargs:pytest -vvv -rA --cov --cov-report=term-missing --cov-branch tests}
[flake8]
max-line-length = 79
max-doc-length = 79
verbose = 2
statistics = True
min-version = 2.7
require-code = True
exclude =
.github/
.pytest_cache/
.tox/
.venv*/
build/
htmlcov/
logs/
ignore =
; -- flake8 --
; E501 line too long
; E722 do not use bare 'except' (duplicates B001)
; W503 line break before binary operator
; W505 doc line too long
E501, E722, W503, W505
; -- flake8-docstrings --
; D100 Missing docstring in public module
; D101 Missing docstring in public class
; D102 Missing docstring in public method
; D103 Missing docstring in public function
; D104 Missing docstring in public package
; D105 Missing docstring in magic method
; D107 Missing docstring in __init__
; D200 One-line docstring should fit on one line with quotes
; D202 No blank lines allowed after function docstring
; D205 1 blank line required between summary line and description
; D400 First line should end with a period
; D401 First line should be in imperative mood
; D402 First line should not be the function's "signature"
D100, D101, D102, D103, D104, D105, D107
; -- flake8-future-import --
; x = 1 for missing, 5 for present
; FIx6 nested_scopes 2.2
; FIx7 generators 2.3
; FIx2 with_statement 2.6
; FIx1 absolute_import 3.0
; FIx0 division 3.0
; FIx3 print_function 3.0
; FIx4 unicode_literals 3.0
; FIx5 generator_stop 3.7
; FIx8 annotations 4.0
; FI90 __future__ import does not exist
FI10, FI11, FI13, FI14, FI58
per-file-ignores =
; F401 imported but unused
; E402 module level import not at top of file
nzbTo*.py: E265, E266, E402
TorrentToMedia.py: E402
nzb2media/__init__.py: E402, F401
nzb2media/utils/__init__.py: F401
nzb2media/plugins/downloaders/configuration.py: F401
nzb2media/plugins/downloaders/utils.py: F401
[testenv:check] [testenv:check]
deps = deps =
flake8 pre-commit
flake8-bugbear
flake8-commas
flake8-comprehensions
flake8-docstrings
flake8-future-import
skip_install = true skip_install = true
commands = commands =
; ** PRIMARY TESTS ** pre-commit autoupdate
; Run flake8 tests (with plugins) using default test selections pre-commit run --all-files
flake8
; ** SELECTIVE TESTS **
; Run flake8 tests (with plugins) for specific optional codes defined below
; -- flake8 --
; E123 closing bracket does not match indentation of opening brackets line
; E226 missing whitespace around arithmetic operator
; E241 multiple spaces after ,
; E242 tab after ,
; E704 multiple statements on one line
; W504 line break after binary operator
; W505 doc line too long
; -- flake8-bugbear --
; B902 Invalid first argument used for instance method.
; B903 Data class should be immutable or use __slots__ to save memory.
flake8 --select=B902,B903,E123,E226,E241,E242,E704,W504,W505
[coverage:run] [coverage:run]