mirror of
https://github.com/clinton-hall/nzbToMedia.git
synced 2025-08-20 21:33:13 -07:00
Merge pull request #1947 from clinton-hall/its-better-than-bad-its-good
Replace logger with Python standard library style logging
This commit is contained in:
commit
aaa9bbee2c
44 changed files with 862 additions and 1810 deletions
|
@ -1,9 +1,10 @@
|
||||||
import datetime
|
import datetime
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger, main_db
|
from nzb2media import main_db
|
||||||
from nzb2media.auto_process import comics, games, movies, music, tv, books
|
from nzb2media.auto_process import comics, games, movies, music, tv, books
|
||||||
from nzb2media.auto_process.common import ProcessResult
|
from nzb2media.auto_process.common import ProcessResult
|
||||||
from nzb2media.plugins.plex import plex_update
|
from nzb2media.plugins.plex import plex_update
|
||||||
|
@ -11,6 +12,9 @@ from nzb2media.user_scripts import external_script
|
||||||
from nzb2media.utils.encoding import char_replace, convert_to_ascii
|
from nzb2media.utils.encoding import char_replace, convert_to_ascii
|
||||||
from nzb2media.utils.links import replace_links
|
from nzb2media.utils.links import replace_links
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def process_torrent(input_directory, input_name, input_category, input_hash, input_id, client_agent):
|
def process_torrent(input_directory, input_name, input_category, input_hash, input_id, client_agent):
|
||||||
status = 1 # 1 = failed | 0 = success
|
status = 1 # 1 = failed | 0 = success
|
||||||
|
@ -18,7 +22,7 @@ def process_torrent(input_directory, input_name, input_category, input_hash, inp
|
||||||
found_file = 0
|
found_file = 0
|
||||||
|
|
||||||
if client_agent != 'manual' and not nzb2media.DOWNLOAD_INFO:
|
if client_agent != 'manual' and not nzb2media.DOWNLOAD_INFO:
|
||||||
logger.debug(f'Adding TORRENT download info for directory {input_directory} to database')
|
log.debug(f'Adding TORRENT download info for directory {input_directory} to database')
|
||||||
|
|
||||||
my_db = main_db.DBConnection()
|
my_db = main_db.DBConnection()
|
||||||
|
|
||||||
|
@ -42,7 +46,7 @@ def process_torrent(input_directory, input_name, input_category, input_hash, inp
|
||||||
}
|
}
|
||||||
my_db.upsert('downloads', new_value_dict, control_value_dict)
|
my_db.upsert('downloads', new_value_dict, control_value_dict)
|
||||||
|
|
||||||
logger.debug(f'Received Directory: {input_directory} | Name: {input_name} | Category: {input_category}')
|
log.debug(f'Received Directory: {input_directory} | Name: {input_name} | Category: {input_category}')
|
||||||
|
|
||||||
# Confirm the category by parsing directory structure
|
# Confirm the category by parsing directory structure
|
||||||
input_directory, input_name, input_category, root = nzb2media.category_search(
|
input_directory, input_name, input_category, root = nzb2media.category_search(
|
||||||
|
@ -54,11 +58,11 @@ def process_torrent(input_directory, input_name, input_category, input_hash, inp
|
||||||
|
|
||||||
usercat = input_category
|
usercat = input_category
|
||||||
|
|
||||||
logger.debug(f'Determined Directory: {input_directory} | Name: {input_name} | Category: {input_category}')
|
log.debug(f'Determined Directory: {input_directory} | Name: {input_name} | Category: {input_category}')
|
||||||
|
|
||||||
# auto-detect section
|
# auto-detect section
|
||||||
section = nzb2media.CFG.findsection(input_category).isenabled()
|
section = nzb2media.CFG.findsection(input_category).isenabled()
|
||||||
if section is None: #Check for user_scripts for 'ALL' and 'UNCAT'
|
if section is None: # Check for user_scripts for 'ALL' and 'UNCAT'
|
||||||
if usercat in nzb2media.CATEGORIES:
|
if usercat in nzb2media.CATEGORIES:
|
||||||
section = nzb2media.CFG.findsection('ALL').isenabled()
|
section = nzb2media.CFG.findsection('ALL').isenabled()
|
||||||
usercat = 'ALL'
|
usercat = 'ALL'
|
||||||
|
@ -66,18 +70,18 @@ def process_torrent(input_directory, input_name, input_category, input_hash, inp
|
||||||
section = nzb2media.CFG.findsection('UNCAT').isenabled()
|
section = nzb2media.CFG.findsection('UNCAT').isenabled()
|
||||||
usercat = 'UNCAT'
|
usercat = 'UNCAT'
|
||||||
if section is None: # We haven't found any categories to process.
|
if section is None: # We haven't found any categories to process.
|
||||||
logger.error(f'Category:[{input_category}] is not defined or is not enabled. Please rename it or ensure it is enabled for the appropriate section in your autoProcessMedia.cfg and try again.')
|
log.error(f'Category:[{input_category}] is not defined or is not enabled. Please rename it or ensure it is enabled for the appropriate section in your autoProcessMedia.cfg and try again.')
|
||||||
return [-1, '']
|
return [-1, '']
|
||||||
|
|
||||||
if len(section) > 1:
|
if len(section) > 1:
|
||||||
logger.error(f'Category:[{usercat}] is not unique, {section.keys()} are using it. Please rename it or disable all other sections using the same category name in your autoProcessMedia.cfg and try again.')
|
log.error(f'Category:[{usercat}] is not unique, {section.keys()} are using it. Please rename it or disable all other sections using the same category name in your autoProcessMedia.cfg and try again.')
|
||||||
return [-1, '']
|
return [-1, '']
|
||||||
|
|
||||||
if section:
|
if section:
|
||||||
section_name = section.keys()[0]
|
section_name = section.keys()[0]
|
||||||
logger.info(f'Auto-detected SECTION:{section_name}')
|
log.info(f'Auto-detected SECTION:{section_name}')
|
||||||
else:
|
else:
|
||||||
logger.error(f'Unable to locate a section with subsection:{input_category} enabled in your autoProcessMedia.cfg, exiting!')
|
log.error(f'Unable to locate a section with subsection:{input_category} enabled in your autoProcessMedia.cfg, exiting!')
|
||||||
return [-1, '']
|
return [-1, '']
|
||||||
|
|
||||||
section = dict(section[section_name][usercat]) # Type cast to dict() to allow effective usage of .get()
|
section = dict(section[section_name][usercat]) # Type cast to dict() to allow effective usage of .get()
|
||||||
|
@ -110,13 +114,13 @@ def process_torrent(input_directory, input_name, input_category, input_hash, inp
|
||||||
if output_destination in input_directory:
|
if output_destination in input_directory:
|
||||||
output_destination = input_directory
|
output_destination = input_directory
|
||||||
|
|
||||||
logger.info(f'Output directory set to: {output_destination}')
|
log.info(f'Output directory set to: {output_destination}')
|
||||||
|
|
||||||
if nzb2media.SAFE_MODE and output_destination == nzb2media.TORRENT_DEFAULT_DIRECTORY:
|
if nzb2media.SAFE_MODE and output_destination == nzb2media.TORRENT_DEFAULT_DIRECTORY:
|
||||||
logger.error(f'The output directory:[{input_directory}] is the Download Directory. Edit outputDirectory in autoProcessMedia.cfg. Exiting')
|
log.error(f'The output directory:[{input_directory}] is the Download Directory. Edit outputDirectory in autoProcessMedia.cfg. Exiting')
|
||||||
return [-1, '']
|
return [-1, '']
|
||||||
|
|
||||||
logger.debug(f'Scanning files in directory: {input_directory}')
|
log.debug(f'Scanning files in directory: {input_directory}')
|
||||||
|
|
||||||
if section_name in ['HeadPhones', 'Lidarr']:
|
if section_name in ['HeadPhones', 'Lidarr']:
|
||||||
nzb2media.NOFLATTEN.extend(
|
nzb2media.NOFLATTEN.extend(
|
||||||
|
@ -131,9 +135,9 @@ def process_torrent(input_directory, input_name, input_category, input_hash, inp
|
||||||
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 len(input_files) == 0 and os.path.isfile(input_directory):
|
||||||
input_files = [input_directory]
|
input_files = [input_directory]
|
||||||
logger.debug(f'Found 1 file to process: {input_directory}')
|
log.debug(f'Found 1 file to process: {input_directory}')
|
||||||
else:
|
else:
|
||||||
logger.debug(f'Found {len(input_files)} files in {input_directory}')
|
log.debug(f'Found {len(input_files)} files in {input_directory}')
|
||||||
for inputFile in input_files:
|
for inputFile in input_files:
|
||||||
file_path = os.path.dirname(inputFile)
|
file_path = os.path.dirname(inputFile)
|
||||||
file_name, file_ext = os.path.splitext(os.path.basename(inputFile))
|
file_name, file_ext = os.path.splitext(os.path.basename(inputFile))
|
||||||
|
@ -145,16 +149,16 @@ def process_torrent(input_directory, input_name, input_category, input_hash, inp
|
||||||
target_file = nzb2media.os.path.join(
|
target_file = nzb2media.os.path.join(
|
||||||
nzb2media.os.path.join(output_destination, os.path.basename(file_path)), full_file_name,
|
nzb2media.os.path.join(output_destination, os.path.basename(file_path)), full_file_name,
|
||||||
)
|
)
|
||||||
logger.debug(f'Setting outputDestination to {os.path.dirname(target_file)} to preserve folder structure')
|
log.debug(f'Setting outputDestination to {os.path.dirname(target_file)} to preserve folder structure')
|
||||||
if root == 1:
|
if root == 1:
|
||||||
if not found_file:
|
if not found_file:
|
||||||
logger.debug(f'Looking for {input_name} in: {inputFile}')
|
log.debug(f'Looking for {input_name} in: {inputFile}')
|
||||||
if any([
|
if any([
|
||||||
nzb2media.sanitize_name(input_name) in nzb2media.sanitize_name(inputFile),
|
nzb2media.sanitize_name(input_name) in nzb2media.sanitize_name(inputFile),
|
||||||
nzb2media.sanitize_name(file_name) in nzb2media.sanitize_name(input_name),
|
nzb2media.sanitize_name(file_name) in nzb2media.sanitize_name(input_name),
|
||||||
]):
|
]):
|
||||||
found_file = True
|
found_file = True
|
||||||
logger.debug(f'Found file {full_file_name} that matches Torrent Name {input_name}')
|
log.debug(f'Found file {full_file_name} that matches Torrent Name {input_name}')
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
@ -163,10 +167,10 @@ def process_torrent(input_directory, input_name, input_category, input_hash, inp
|
||||||
ctime_lapse = now - datetime.datetime.fromtimestamp(os.path.getctime(inputFile))
|
ctime_lapse = now - datetime.datetime.fromtimestamp(os.path.getctime(inputFile))
|
||||||
|
|
||||||
if not found_file:
|
if not found_file:
|
||||||
logger.debug('Looking for files with modified/created dates less than 5 minutes old.')
|
log.debug('Looking for files with modified/created dates less than 5 minutes old.')
|
||||||
if (mtime_lapse < datetime.timedelta(minutes=5)) or (ctime_lapse < datetime.timedelta(minutes=5)):
|
if (mtime_lapse < datetime.timedelta(minutes=5)) or (ctime_lapse < datetime.timedelta(minutes=5)):
|
||||||
found_file = True
|
found_file = True
|
||||||
logger.debug(f'Found file {full_file_name} with date modified/created less than 5 minutes ago.')
|
log.debug(f'Found file {full_file_name} with date modified/created less than 5 minutes ago.')
|
||||||
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
|
||||||
|
|
||||||
|
@ -175,12 +179,12 @@ def process_torrent(input_directory, input_name, input_category, input_hash, inp
|
||||||
nzb2media.copy_link(inputFile, target_file, nzb2media.USE_LINK)
|
nzb2media.copy_link(inputFile, target_file, nzb2media.USE_LINK)
|
||||||
nzb2media.remove_read_only(target_file)
|
nzb2media.remove_read_only(target_file)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error(f'Failed to link: {inputFile} to {target_file}')
|
log.error(f'Failed to link: {inputFile} to {target_file}')
|
||||||
|
|
||||||
input_name, output_destination = convert_to_ascii(input_name, output_destination)
|
input_name, output_destination = convert_to_ascii(input_name, output_destination)
|
||||||
|
|
||||||
if extract == 1:
|
if extract == 1:
|
||||||
logger.debug(f'Checking for archives to extract in directory: {input_directory}')
|
log.debug(f'Checking for archives to extract in directory: {input_directory}')
|
||||||
nzb2media.extract_files(input_directory, output_destination, keep_archive)
|
nzb2media.extract_files(input_directory, output_destination, keep_archive)
|
||||||
|
|
||||||
if input_category not in nzb2media.NOFLATTEN:
|
if input_category not in nzb2media.NOFLATTEN:
|
||||||
|
@ -193,20 +197,20 @@ def process_torrent(input_directory, input_name, input_category, input_hash, inp
|
||||||
nzb2media.list_media_files(output_destination, media=True, audio=False, meta=False, archives=False),
|
nzb2media.list_media_files(output_destination, media=True, audio=False, meta=False, archives=False),
|
||||||
)
|
)
|
||||||
if num_videos > 0:
|
if num_videos > 0:
|
||||||
logger.info(f'Found {num_videos} media files in {output_destination}')
|
log.info(f'Found {num_videos} media files in {output_destination}')
|
||||||
status = 0
|
status = 0
|
||||||
elif extract != 1:
|
elif extract != 1:
|
||||||
logger.info(f'Found no media files in {output_destination}. Sending to {section_name} to process')
|
log.info(f'Found no media files in {output_destination}. Sending to {section_name} to process')
|
||||||
status = 0
|
status = 0
|
||||||
else:
|
else:
|
||||||
logger.warning(f'Found no media files in {output_destination}')
|
log.warning(f'Found no media files in {output_destination}')
|
||||||
|
|
||||||
# Only these sections can handling failed downloads
|
# Only these sections can handling failed downloads
|
||||||
# so make sure everything else gets through without the check for failed
|
# so make sure everything else gets through without the check for failed
|
||||||
if section_name not in ['CouchPotato', 'Radarr', 'SickBeard', 'SiCKRAGE', 'NzbDrone', 'Sonarr', 'Watcher3']:
|
if section_name not in ['CouchPotato', 'Radarr', 'SickBeard', 'SiCKRAGE', 'NzbDrone', 'Sonarr', 'Watcher3']:
|
||||||
status = 0
|
status = 0
|
||||||
|
|
||||||
logger.info(f'Calling {section_name}:{usercat} to post-process:{input_name}')
|
log.info(f'Calling {section_name}:{usercat} to post-process:{input_name}')
|
||||||
|
|
||||||
if nzb2media.TORRENT_CHMOD_DIRECTORY:
|
if nzb2media.TORRENT_CHMOD_DIRECTORY:
|
||||||
nzb2media.rchmod(output_destination, nzb2media.TORRENT_CHMOD_DIRECTORY)
|
nzb2media.rchmod(output_destination, nzb2media.TORRENT_CHMOD_DIRECTORY)
|
||||||
|
@ -245,12 +249,12 @@ def process_torrent(input_directory, input_name, input_category, input_hash, inp
|
||||||
|
|
||||||
if result.status_code != 0:
|
if result.status_code != 0:
|
||||||
if not nzb2media.TORRENT_RESUME_ON_FAILURE:
|
if not nzb2media.TORRENT_RESUME_ON_FAILURE:
|
||||||
logger.error(
|
log.error(
|
||||||
'A problem was reported in the autoProcess* script. '
|
'A problem was reported in the autoProcess* script. '
|
||||||
'Torrent won\'t resume seeding (settings)',
|
'Torrent won\'t resume seeding (settings)',
|
||||||
)
|
)
|
||||||
elif client_agent != 'manual':
|
elif client_agent != 'manual':
|
||||||
logger.error(
|
log.error(
|
||||||
'A problem was reported in the autoProcess* script. '
|
'A problem was reported in the autoProcess* script. '
|
||||||
'If torrent was paused we will resume seeding',
|
'If torrent was paused we will resume seeding',
|
||||||
)
|
)
|
||||||
|
@ -263,10 +267,10 @@ def process_torrent(input_directory, input_name, input_category, input_hash, inp
|
||||||
|
|
||||||
# remove torrent
|
# remove torrent
|
||||||
if nzb2media.USE_LINK == 'move-sym' and not nzb2media.DELETE_ORIGINAL == 1:
|
if nzb2media.USE_LINK == 'move-sym' and not nzb2media.DELETE_ORIGINAL == 1:
|
||||||
logger.debug(f'Checking for sym-links to re-direct in: {input_directory}')
|
log.debug(f'Checking for sym-links to re-direct in: {input_directory}')
|
||||||
for dirpath, _, files in os.walk(input_directory):
|
for dirpath, _, files in os.walk(input_directory):
|
||||||
for file in files:
|
for file in files:
|
||||||
logger.debug(f'Checking symlink: {os.path.join(dirpath, file)}')
|
log.debug(f'Checking symlink: {os.path.join(dirpath, file)}')
|
||||||
replace_links(os.path.join(dirpath, file))
|
replace_links(os.path.join(dirpath, file))
|
||||||
nzb2media.remove_torrent(client_agent, input_hash, input_id, input_name)
|
nzb2media.remove_torrent(client_agent, input_hash, input_id, input_name)
|
||||||
|
|
||||||
|
@ -285,12 +289,12 @@ def main(args):
|
||||||
# clientAgent for Torrents
|
# clientAgent for Torrents
|
||||||
client_agent = nzb2media.TORRENT_CLIENT_AGENT
|
client_agent = nzb2media.TORRENT_CLIENT_AGENT
|
||||||
|
|
||||||
logger.info('#########################################################')
|
log.info('#########################################################')
|
||||||
logger.info(f'## ..::[{os.path.basename(__file__)}]::.. ##')
|
log.info(f'## ..::[{os.path.basename(__file__)}]::.. ##')
|
||||||
logger.info('#########################################################')
|
log.info('#########################################################')
|
||||||
|
|
||||||
# debug command line options
|
# debug command line options
|
||||||
logger.debug(f'Options passed into TorrentToMedia: {args}')
|
log.debug(f'Options passed into TorrentToMedia: {args}')
|
||||||
|
|
||||||
# Post-Processing Result
|
# Post-Processing Result
|
||||||
result = ProcessResult(
|
result = ProcessResult(
|
||||||
|
@ -301,33 +305,33 @@ def main(args):
|
||||||
try:
|
try:
|
||||||
input_directory, input_name, input_category, input_hash, input_id = nzb2media.parse_args(client_agent, args)
|
input_directory, input_name, input_category, input_hash, input_id = nzb2media.parse_args(client_agent, args)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error('There was a problem loading variables')
|
log.error('There was a problem loading variables')
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
if input_directory and input_name and input_hash and input_id:
|
if input_directory and input_name and input_hash and input_id:
|
||||||
result = process_torrent(input_directory, input_name, input_category, input_hash, input_id, client_agent)
|
result = process_torrent(input_directory, input_name, input_category, input_hash, input_id, client_agent)
|
||||||
elif nzb2media.TORRENT_NO_MANUAL:
|
elif nzb2media.TORRENT_NO_MANUAL:
|
||||||
logger.warning('Invalid number of arguments received from client, and no_manual set')
|
log.warning('Invalid number of arguments received from client, and no_manual set')
|
||||||
else:
|
else:
|
||||||
# Perform Manual Post-Processing
|
# Perform Manual Post-Processing
|
||||||
logger.warning('Invalid number of arguments received from client, Switching to manual run mode ...')
|
log.warning('Invalid number of arguments received from client, Switching to manual run mode ...')
|
||||||
|
|
||||||
for section, subsections in nzb2media.SECTIONS.items():
|
for section, subsections in nzb2media.SECTIONS.items():
|
||||||
for subsection in subsections:
|
for subsection in subsections:
|
||||||
if not nzb2media.CFG[section][subsection].isenabled():
|
if not nzb2media.CFG[section][subsection].isenabled():
|
||||||
continue
|
continue
|
||||||
for dir_name in nzb2media.get_dirs(section, subsection, link='hard'):
|
for dir_name in nzb2media.get_dirs(section, subsection, link='hard'):
|
||||||
logger.info(f'Starting manual run for {section}:{subsection} - Folder:{dir_name}')
|
log.info(f'Starting manual run for {section}:{subsection} - Folder:{dir_name}')
|
||||||
|
|
||||||
logger.info(f'Checking database for download info for {os.path.basename(dir_name)} ...')
|
log.info(f'Checking database for download info for {os.path.basename(dir_name)} ...')
|
||||||
nzb2media.DOWNLOAD_INFO = nzb2media.get_download_info(os.path.basename(dir_name), 0)
|
nzb2media.DOWNLOAD_INFO = nzb2media.get_download_info(os.path.basename(dir_name), 0)
|
||||||
if nzb2media.DOWNLOAD_INFO:
|
if nzb2media.DOWNLOAD_INFO:
|
||||||
client_agent = nzb2media.DOWNLOAD_INFO[0]['client_agent'] or 'manual'
|
client_agent = nzb2media.DOWNLOAD_INFO[0]['client_agent'] or 'manual'
|
||||||
input_hash = nzb2media.DOWNLOAD_INFO[0]['input_hash'] or ''
|
input_hash = nzb2media.DOWNLOAD_INFO[0]['input_hash'] or ''
|
||||||
input_id = nzb2media.DOWNLOAD_INFO[0]['input_id'] or ''
|
input_id = nzb2media.DOWNLOAD_INFO[0]['input_id'] or ''
|
||||||
logger.info(f'Found download info for {os.path.basename(dir_name)}, setting variables now ...')
|
log.info(f'Found download info for {os.path.basename(dir_name)}, setting variables now ...')
|
||||||
else:
|
else:
|
||||||
logger.info(f'Unable to locate download info for {os.path.basename(dir_name)}, continuing to try and process this release ...')
|
log.info(f'Unable to locate download info for {os.path.basename(dir_name)}, continuing to try and process this release ...')
|
||||||
client_agent = 'manual'
|
client_agent = 'manual'
|
||||||
input_hash = ''
|
input_hash = ''
|
||||||
input_id = ''
|
input_id = ''
|
||||||
|
@ -342,13 +346,13 @@ def main(args):
|
||||||
client_agent,
|
client_agent,
|
||||||
)
|
)
|
||||||
if results.status_code != 0:
|
if results.status_code != 0:
|
||||||
logger.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 result.status_code == 0:
|
||||||
logger.info(f'The {args[0]} script completed successfully.')
|
log.info(f'The {args[0]} script completed successfully.')
|
||||||
else:
|
else:
|
||||||
logger.error(f'A problem was reported in the {args[0]} script.')
|
log.error(f'A problem was reported in the {args[0]} script.')
|
||||||
del nzb2media.MYAPP
|
del nzb2media.MYAPP
|
||||||
return result.status_code
|
return result.status_code
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
import itertools
|
import itertools
|
||||||
import locale
|
import locale
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
import platform
|
import platform
|
||||||
|
@ -11,6 +12,9 @@ import sys
|
||||||
import time
|
import time
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import win32event
|
import win32event
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -43,7 +47,6 @@ CONFIG_TV_FILE = APP_ROOT / 'autoProcessTv.cfg'
|
||||||
TEST_FILE = APP_ROOT / 'tests' / 'test.mp4'
|
TEST_FILE = APP_ROOT / 'tests' / 'test.mp4'
|
||||||
MYAPP = None
|
MYAPP = None
|
||||||
|
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media import main_db
|
from nzb2media import main_db
|
||||||
from nzb2media import version_check
|
from nzb2media import version_check
|
||||||
from nzb2media import databases
|
from nzb2media import databases
|
||||||
|
@ -418,9 +421,7 @@ def configure_migration():
|
||||||
|
|
||||||
# run migrate to convert old cfg to new style cfg plus fix any cfg missing values/options.
|
# run migrate to convert old cfg to new style cfg plus fix any cfg missing values/options.
|
||||||
if not config.migrate():
|
if not config.migrate():
|
||||||
logger.error(
|
log.error(f'Unable to migrate config file {CONFIG_FILE}, exiting ...')
|
||||||
f'Unable to migrate config file {CONFIG_FILE}, exiting ...',
|
|
||||||
)
|
|
||||||
if 'NZBOP_SCRIPTDIR' in os.environ:
|
if 'NZBOP_SCRIPTDIR' in os.environ:
|
||||||
pass # We will try and read config from Environment.
|
pass # We will try and read config from Environment.
|
||||||
else:
|
else:
|
||||||
|
@ -431,7 +432,7 @@ def configure_migration():
|
||||||
CFG = config.addnzbget()
|
CFG = config.addnzbget()
|
||||||
|
|
||||||
else: # load newly migrated config
|
else: # load newly migrated config
|
||||||
logger.info(f'Loading config from [{CONFIG_FILE}]')
|
log.info(f'Loading config from [{CONFIG_FILE}]')
|
||||||
CFG = config()
|
CFG = config()
|
||||||
|
|
||||||
|
|
||||||
|
@ -449,7 +450,7 @@ def configure_logging_part_2():
|
||||||
|
|
||||||
if LOG_ENV:
|
if LOG_ENV:
|
||||||
for item in os.environ:
|
for item in os.environ:
|
||||||
logger.info(f'{item}: {os.environ[item]}', 'ENVIRONMENT')
|
log.info(f'{item}: {os.environ[item]}')
|
||||||
|
|
||||||
|
|
||||||
def configure_general():
|
def configure_general():
|
||||||
|
@ -494,7 +495,7 @@ def configure_updates():
|
||||||
|
|
||||||
# Check for updates via GitHUB
|
# Check for updates via GitHUB
|
||||||
if version_checker.check_for_new_version() and AUTO_UPDATE:
|
if version_checker.check_for_new_version() and AUTO_UPDATE:
|
||||||
logger.info('Auto-Updating nzbToMedia, Please wait ...')
|
log.info('Auto-Updating nzbToMedia, Please wait ...')
|
||||||
if version_checker.update():
|
if version_checker.update():
|
||||||
# restart nzbToMedia
|
# restart nzbToMedia
|
||||||
try:
|
try:
|
||||||
|
@ -503,14 +504,10 @@ def configure_updates():
|
||||||
pass
|
pass
|
||||||
restart()
|
restart()
|
||||||
else:
|
else:
|
||||||
logger.error(
|
log.error('Update failed, not restarting. Check your log for more information.')
|
||||||
'Update failed, not restarting. Check your log for more information.',
|
|
||||||
)
|
|
||||||
|
|
||||||
# Set Current Version
|
# Set Current Version
|
||||||
logger.info(
|
log.info(f'nzbToMedia Version:{NZBTOMEDIA_VERSION} Branch:{GIT_BRANCH} ({platform.system()} {platform.release()})')
|
||||||
f'nzbToMedia Version:{NZBTOMEDIA_VERSION} Branch:{GIT_BRANCH} ({platform.system()} {platform.release()})',
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def configure_wake_on_lan():
|
def configure_wake_on_lan():
|
||||||
|
@ -1425,22 +1422,14 @@ def configure_utility_locations():
|
||||||
|
|
||||||
if not (os.path.isfile(FFMPEG)): # problem
|
if not (os.path.isfile(FFMPEG)): # problem
|
||||||
FFMPEG = None
|
FFMPEG = None
|
||||||
logger.warning(
|
log.warning('Failed to locate ffmpeg.exe. Transcoding disabled!')
|
||||||
'Failed to locate ffmpeg.exe. Transcoding disabled!',
|
log.warning('Install ffmpeg with x264 support to enable this feature ...')
|
||||||
)
|
|
||||||
logger.warning(
|
|
||||||
'Install ffmpeg with x264 support to enable this feature ...',
|
|
||||||
)
|
|
||||||
|
|
||||||
if not (os.path.isfile(FFPROBE)):
|
if not (os.path.isfile(FFPROBE)):
|
||||||
FFPROBE = None
|
FFPROBE = None
|
||||||
if CHECK_MEDIA:
|
if CHECK_MEDIA:
|
||||||
logger.warning(
|
log.warning('Failed to locate ffprobe.exe. Video corruption detection disabled!')
|
||||||
'Failed to locate ffprobe.exe. Video corruption detection disabled!',
|
log.warning('Install ffmpeg with x264 support to enable this feature ...')
|
||||||
)
|
|
||||||
logger.warning(
|
|
||||||
'Install ffmpeg with x264 support to enable this feature ...',
|
|
||||||
)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if SYS_PATH:
|
if SYS_PATH:
|
||||||
|
@ -1476,9 +1465,7 @@ def configure_utility_locations():
|
||||||
pass
|
pass
|
||||||
if not SEVENZIP:
|
if not SEVENZIP:
|
||||||
SEVENZIP = None
|
SEVENZIP = None
|
||||||
logger.warning(
|
log.warning('Failed to locate 7zip. Transcoding of disk images and extraction of .7z files will not be possible!')
|
||||||
'Failed to locate 7zip. Transcoding of disk images and extraction of .7z files will not be possible!',
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
PAR2CMD = (
|
PAR2CMD = (
|
||||||
subprocess.Popen(['which', 'par2'], stdout=subprocess.PIPE)
|
subprocess.Popen(['which', 'par2'], stdout=subprocess.PIPE)
|
||||||
|
@ -1490,9 +1477,7 @@ def configure_utility_locations():
|
||||||
pass
|
pass
|
||||||
if not PAR2CMD:
|
if not PAR2CMD:
|
||||||
PAR2CMD = None
|
PAR2CMD = None
|
||||||
logger.warning(
|
log.warning('Failed to locate par2. Repair and rename using par files will not be possible!')
|
||||||
'Failed to locate par2. Repair and rename using par files will not be possible!',
|
|
||||||
)
|
|
||||||
if os.path.isfile(os.path.join(FFMPEG_PATH, 'ffmpeg')) or os.access(
|
if os.path.isfile(os.path.join(FFMPEG_PATH, 'ffmpeg')) or os.access(
|
||||||
os.path.join(FFMPEG_PATH, 'ffmpeg'),
|
os.path.join(FFMPEG_PATH, 'ffmpeg'),
|
||||||
os.X_OK,
|
os.X_OK,
|
||||||
|
@ -1529,10 +1514,8 @@ def configure_utility_locations():
|
||||||
pass
|
pass
|
||||||
if not FFMPEG:
|
if not FFMPEG:
|
||||||
FFMPEG = None
|
FFMPEG = None
|
||||||
logger.warning('Failed to locate ffmpeg. Transcoding disabled!')
|
log.warning('Failed to locate ffmpeg. Transcoding disabled!')
|
||||||
logger.warning(
|
log.warning('Install ffmpeg with x264 support to enable this feature ...')
|
||||||
'Install ffmpeg with x264 support to enable this feature ...',
|
|
||||||
)
|
|
||||||
|
|
||||||
if os.path.isfile(os.path.join(FFMPEG_PATH, 'ffprobe')) or os.access(
|
if os.path.isfile(os.path.join(FFMPEG_PATH, 'ffprobe')) or os.access(
|
||||||
os.path.join(FFMPEG_PATH, 'ffprobe'),
|
os.path.join(FFMPEG_PATH, 'ffprobe'),
|
||||||
|
@ -1571,14 +1554,8 @@ def configure_utility_locations():
|
||||||
if not FFPROBE:
|
if not FFPROBE:
|
||||||
FFPROBE = None
|
FFPROBE = None
|
||||||
if CHECK_MEDIA:
|
if CHECK_MEDIA:
|
||||||
logger.warning(
|
log.warning('Failed to locate ffprobe. Video corruption detection disabled!')
|
||||||
'Failed to locate ffprobe. Video corruption detection disabled!',
|
log.warning('Install ffmpeg with x264 support to enable this feature ...')
|
||||||
)
|
|
||||||
logger.warning(
|
|
||||||
'Install ffmpeg with x264 support to enable this feature ...',
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def initialize(section=None):
|
def initialize(section=None):
|
||||||
|
@ -1591,9 +1568,6 @@ def initialize(section=None):
|
||||||
configure_process()
|
configure_process()
|
||||||
configure_locale()
|
configure_locale()
|
||||||
|
|
||||||
# init logging
|
|
||||||
logger.ntm_log_instance.init_logging()
|
|
||||||
|
|
||||||
configure_migration()
|
configure_migration()
|
||||||
configure_logging_part_2()
|
configure_logging_part_2()
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media.auto_process.common import ProcessResult
|
from nzb2media.auto_process.common import ProcessResult
|
||||||
from nzb2media.utils.common import flatten
|
from nzb2media.utils.common import flatten
|
||||||
from nzb2media.utils.encoding import convert_to_ascii
|
from nzb2media.utils.encoding import convert_to_ascii
|
||||||
from nzb2media.utils.network import server_responding
|
from nzb2media.utils.network import server_responding
|
||||||
from nzb2media.utils.paths import remote_dir
|
from nzb2media.utils.paths import remote_dir
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def process(
|
def process(
|
||||||
*,
|
*,
|
||||||
|
@ -45,7 +49,7 @@ def process(
|
||||||
# Begin processing
|
# Begin processing
|
||||||
url = nzb2media.utils.common.create_url(scheme, host, port, web_root)
|
url = nzb2media.utils.common.create_url(scheme, host, port, web_root)
|
||||||
if not server_responding(url):
|
if not server_responding(url):
|
||||||
logger.error('Server did not respond. Exiting', section)
|
log.error('Server did not respond. Exiting')
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - {section} did not respond.',
|
f'{section}: Failed to post-process - {section} did not respond.',
|
||||||
)
|
)
|
||||||
|
@ -58,41 +62,39 @@ def process(
|
||||||
'dir': remote_dir(dir_name) if remote_path else dir_name,
|
'dir': remote_dir(dir_name) if remote_path else dir_name,
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(f'Opening URL: {url} with params: {params}', section)
|
log.debug(f'Opening URL: {url} with params: {params}')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
r = requests.get(url, params=params, verify=False, timeout=(30, 300))
|
response = requests.get(url, params=params, verify=False, timeout=(30, 300))
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.error('Unable to open URL')
|
log.error('Unable to open URL')
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - Unable to connect to '
|
f'{section}: Failed to post-process - Unable to connect to '
|
||||||
f'{section}',
|
f'{section}',
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.postprocess(f'{r.text}', section)
|
log.debug(response.text)
|
||||||
|
|
||||||
if r.status_code not in [
|
if response.status_code not in [
|
||||||
requests.codes.ok,
|
requests.codes.ok,
|
||||||
requests.codes.created,
|
requests.codes.created,
|
||||||
requests.codes.accepted,
|
requests.codes.accepted,
|
||||||
]:
|
]:
|
||||||
logger.error(f'Server returned status {r.status_code}', section)
|
log.error(f'Server returned status {response.status_code}')
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - Server returned status '
|
f'{section}: Failed to post-process - Server returned status '
|
||||||
f'{r.status_code}',
|
f'{response.status_code}',
|
||||||
)
|
)
|
||||||
elif r.text == 'OK':
|
elif response.text == 'OK':
|
||||||
logger.postprocess(
|
log.debug(
|
||||||
f'SUCCESS: ForceProcess for {dir_name} has been started in LazyLibrarian',
|
f'SUCCESS: ForceProcess for {dir_name} has been started in LazyLibrarian',
|
||||||
section,
|
|
||||||
)
|
)
|
||||||
return ProcessResult.success(
|
return ProcessResult.success(
|
||||||
f'{section}: Successfully post-processed {input_name}',
|
f'{section}: Successfully post-processed {input_name}',
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.error(
|
log.error(
|
||||||
f'FAILED: ForceProcess of {dir_name} has Failed in LazyLibrarian',
|
f'FAILED: ForceProcess of {dir_name} has Failed in LazyLibrarian',
|
||||||
section,
|
|
||||||
)
|
)
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - Returned log from {section} '
|
f'{section}: Failed to post-process - Returned log from {section} '
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media.auto_process.common import ProcessResult
|
from nzb2media.auto_process.common import ProcessResult
|
||||||
from nzb2media.utils.common import flatten
|
from nzb2media.utils.common import flatten
|
||||||
from nzb2media.utils.encoding import convert_to_ascii
|
from nzb2media.utils.encoding import convert_to_ascii
|
||||||
from nzb2media.utils.network import server_responding
|
from nzb2media.utils.network import server_responding
|
||||||
from nzb2media.utils.paths import remote_dir
|
from nzb2media.utils.paths import remote_dir
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def process(
|
def process(
|
||||||
*,
|
*,
|
||||||
|
@ -49,7 +52,7 @@ def process(
|
||||||
# Begin processing
|
# Begin processing
|
||||||
url = nzb2media.utils.common.create_url(scheme, host, port, web_root)
|
url = nzb2media.utils.common.create_url(scheme, host, port, web_root)
|
||||||
if not server_responding(url):
|
if not server_responding(url):
|
||||||
logger.error('Server did not respond. Exiting', section)
|
log.error('Server did not respond. Exiting')
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - {section} did not respond.',
|
f'{section}: Failed to post-process - {section} did not respond.',
|
||||||
)
|
)
|
||||||
|
@ -73,13 +76,13 @@ def process(
|
||||||
|
|
||||||
success = False
|
success = False
|
||||||
|
|
||||||
logger.debug(f'Opening URL: {url}', section)
|
log.debug(f'Opening URL: {url}')
|
||||||
try:
|
try:
|
||||||
r = requests.post(
|
r = requests.post(
|
||||||
url, params=params, stream=True, verify=False, timeout=(30, 300),
|
url, params=params, stream=True, verify=False, timeout=(30, 300),
|
||||||
)
|
)
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.error('Unable to open URL', section)
|
log.error('Unable to open URL')
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - Unable to connect to '
|
f'{section}: Failed to post-process - Unable to connect to '
|
||||||
f'{section}',
|
f'{section}',
|
||||||
|
@ -89,7 +92,7 @@ def process(
|
||||||
requests.codes.created,
|
requests.codes.created,
|
||||||
requests.codes.accepted,
|
requests.codes.accepted,
|
||||||
]:
|
]:
|
||||||
logger.error(f'Server returned status {r.status_code}', section)
|
log.error(f'Server returned status {r.status_code}')
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - Server returned status '
|
f'{section}: Failed to post-process - Server returned status '
|
||||||
f'{r.status_code}',
|
f'{r.status_code}',
|
||||||
|
@ -97,21 +100,19 @@ def process(
|
||||||
|
|
||||||
for line in r.text.split('\n'):
|
for line in r.text.split('\n'):
|
||||||
if line:
|
if line:
|
||||||
logger.postprocess(line, section)
|
log.debug(line)
|
||||||
if 'Post Processing SUCCESSFUL' in line:
|
if 'Post Processing SUCCESSFUL' in line:
|
||||||
success = True
|
success = True
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
logger.postprocess(
|
log.debug('SUCCESS: This issue has been processed successfully')
|
||||||
'SUCCESS: This issue has been processed successfully', section,
|
|
||||||
)
|
|
||||||
return ProcessResult.success(
|
return ProcessResult.success(
|
||||||
f'{section}: Successfully post-processed {input_name}',
|
f'{section}: Successfully post-processed {input_name}',
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
log.warning(
|
||||||
'The issue does not appear to have successfully processed. Please check your Logs',
|
'The issue does not appear to have successfully processed. '
|
||||||
section,
|
'Please check your Logs',
|
||||||
)
|
)
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - Returned log from '
|
f'{section}: Failed to post-process - Returned log from '
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from nzb2media import logger
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
class ProcessResult(typing.NamedTuple):
|
class ProcessResult(typing.NamedTuple):
|
||||||
|
@ -41,23 +43,22 @@ def command_complete(url, params, headers, section):
|
||||||
timeout=(30, 60),
|
timeout=(30, 60),
|
||||||
)
|
)
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.error(f'Unable to open URL: {url}', section)
|
log.error(f'Unable to open URL: {url}')
|
||||||
return None
|
return None
|
||||||
if r.status_code not in [
|
if r.status_code not in [
|
||||||
requests.codes.ok,
|
requests.codes.ok,
|
||||||
requests.codes.created,
|
requests.codes.created,
|
||||||
requests.codes.accepted,
|
requests.codes.accepted,
|
||||||
]:
|
]:
|
||||||
logger.error(f'Server returned status {r.status_code}', section)
|
log.error(f'Server returned status {r.status_code}')
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
return r.json()['status']
|
return r.json()['status']
|
||||||
except (ValueError, KeyError):
|
except (ValueError, KeyError):
|
||||||
# ValueError catches simplejson's JSONDecodeError and json's ValueError
|
# ValueError catches simplejson's JSONDecodeError and
|
||||||
logger.error(
|
# json's ValueError
|
||||||
f'{section} did not return expected json data.', section,
|
log.error(f'{section} did not return expected json data.')
|
||||||
)
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,14 +73,14 @@ def completed_download_handling(url2, headers, section='MAIN'):
|
||||||
timeout=(30, 60),
|
timeout=(30, 60),
|
||||||
)
|
)
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.error(f'Unable to open URL: {url2}', section)
|
log.error(f'Unable to open URL: {url2}')
|
||||||
return False
|
return False
|
||||||
if r.status_code not in [
|
if r.status_code not in [
|
||||||
requests.codes.ok,
|
requests.codes.ok,
|
||||||
requests.codes.created,
|
requests.codes.created,
|
||||||
requests.codes.accepted,
|
requests.codes.accepted,
|
||||||
]:
|
]:
|
||||||
logger.error(f'Server returned status {r.status_code}', section)
|
log.error(f'Server returned status {r.status_code}')
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media.auto_process.common import ProcessResult
|
from nzb2media.auto_process.common import ProcessResult
|
||||||
from nzb2media.utils.common import flatten
|
from nzb2media.utils.common import flatten
|
||||||
from nzb2media.utils.encoding import convert_to_ascii
|
from nzb2media.utils.encoding import convert_to_ascii
|
||||||
from nzb2media.utils.network import server_responding
|
from nzb2media.utils.network import server_responding
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def process(
|
def process(
|
||||||
*,
|
*,
|
||||||
|
@ -47,7 +50,7 @@ def process(
|
||||||
# Begin processing
|
# Begin processing
|
||||||
url = nzb2media.utils.common.create_url(scheme, host, port, web_root)
|
url = nzb2media.utils.common.create_url(scheme, host, port, web_root)
|
||||||
if not server_responding(url):
|
if not server_responding(url):
|
||||||
logger.error('Server did not respond. Exiting', section)
|
log.error('Server did not respond. Exiting')
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - {section} did not respond.',
|
f'{section}: Failed to post-process - {section} did not respond.',
|
||||||
)
|
)
|
||||||
|
@ -67,36 +70,30 @@ def process(
|
||||||
'status': download_status,
|
'status': download_status,
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(f'Opening URL: {url}', section)
|
log.debug(f'Opening URL: {url}')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
r = requests.get(url, params=params, verify=False, timeout=(30, 300))
|
r = requests.get(url, params=params, verify=False, timeout=(30, 300))
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.error('Unable to open URL')
|
log.error('Unable to open URL')
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - Unable to connect to '
|
f'{section}: Failed to post-process - Unable to connect to '
|
||||||
f'{section}',
|
f'{section}',
|
||||||
)
|
)
|
||||||
|
|
||||||
result = r.json()
|
result = r.json()
|
||||||
logger.postprocess(result, section)
|
log.debug(result)
|
||||||
if library:
|
if library:
|
||||||
logger.postprocess(f'moving files to library: {library}', section)
|
log.debug(f'moving files to library: {library}')
|
||||||
try:
|
try:
|
||||||
shutil.move(dir_name, os.path.join(library, input_name))
|
shutil.move(dir_name, os.path.join(library, input_name))
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error(
|
log.error(f'Unable to move {dir_name} to {os.path.join(library, input_name)}')
|
||||||
f'Unable to move {dir_name} to {os.path.join(library, input_name)}',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - Unable to move files',
|
f'{section}: Failed to post-process - Unable to move files',
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.error(
|
log.error('No library specified to move files to. Please edit your configuration.')
|
||||||
'No library specified to move files to. Please edit your configuration.',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - No library defined in '
|
f'{section}: Failed to post-process - No library defined in '
|
||||||
f'{section}',
|
f'{section}',
|
||||||
|
@ -107,24 +104,18 @@ def process(
|
||||||
requests.codes.created,
|
requests.codes.created,
|
||||||
requests.codes.accepted,
|
requests.codes.accepted,
|
||||||
]:
|
]:
|
||||||
logger.error(f'Server returned status {r.status_code}', section)
|
log.error(f'Server returned status {r.status_code}')
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - Server returned status '
|
f'{section}: Failed to post-process - Server returned status '
|
||||||
f'{r.status_code}',
|
f'{r.status_code}',
|
||||||
)
|
)
|
||||||
elif result['success']:
|
elif result['success']:
|
||||||
logger.postprocess(
|
log.debug(f'SUCCESS: Status for {gamez_id} has been set to {download_status} in Gamez')
|
||||||
f'SUCCESS: Status for {gamez_id} has been set to {download_status} in Gamez',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult.success(
|
return ProcessResult.success(
|
||||||
f'{section}: Successfully post-processed {input_name}',
|
f'{section}: Successfully post-processed {input_name}',
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.error(
|
log.error(f'FAILED: Status for {gamez_id} has NOT been updated in Gamez')
|
||||||
f'FAILED: Status for {gamez_id} has NOT been updated in Gamez',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - Returned log from {section} '
|
f'{section}: Failed to post-process - Returned log from {section} '
|
||||||
f'was not as expected.',
|
f'was not as expected.',
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media import transcoder
|
from nzb2media import transcoder
|
||||||
from nzb2media.auto_process.common import ProcessResult
|
from nzb2media.auto_process.common import ProcessResult
|
||||||
from nzb2media.auto_process.common import command_complete
|
from nzb2media.auto_process.common import command_complete
|
||||||
|
@ -25,6 +25,9 @@ from nzb2media.utils.nzb import report_nzb
|
||||||
from nzb2media.utils.paths import remote_dir
|
from nzb2media.utils.paths import remote_dir
|
||||||
from nzb2media.utils.paths import remove_dir
|
from nzb2media.utils.paths import remove_dir
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def process(
|
def process(
|
||||||
*,
|
*,
|
||||||
|
@ -87,9 +90,7 @@ def process(
|
||||||
route = web_root
|
route = web_root
|
||||||
base_url = nzb2media.utils.common.create_url(scheme, host, port, route)
|
base_url = nzb2media.utils.common.create_url(scheme, host, port, route)
|
||||||
if not apikey:
|
if not apikey:
|
||||||
logger.info(
|
log.info('No CouchPotato or Radarr apikey entered. Performing transcoder functions only')
|
||||||
'No CouchPotato or Radarr apikey entered. Performing transcoder functions only',
|
|
||||||
)
|
|
||||||
release = None
|
release = None
|
||||||
elif server_responding(base_url):
|
elif server_responding(base_url):
|
||||||
if section == 'CouchPotato':
|
if section == 'CouchPotato':
|
||||||
|
@ -97,7 +98,7 @@ def process(
|
||||||
else:
|
else:
|
||||||
release = None
|
release = None
|
||||||
else:
|
else:
|
||||||
logger.error('Server did not respond. Exiting', section)
|
log.error('Server did not respond. Exiting')
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - {section} did not respond.',
|
f'{section}: Failed to post-process - {section} did not respond.',
|
||||||
)
|
)
|
||||||
|
@ -141,9 +142,7 @@ def process(
|
||||||
)
|
)
|
||||||
and extract
|
and extract
|
||||||
):
|
):
|
||||||
logger.debug(
|
log.debug(f'Checking for archives to extract in directory: {dir_name}')
|
||||||
f'Checking for archives to extract in directory: {dir_name}',
|
|
||||||
)
|
|
||||||
nzb2media.extract_files(dir_name)
|
nzb2media.extract_files(dir_name)
|
||||||
input_name, dir_name = convert_to_ascii(input_name, dir_name)
|
input_name, dir_name = convert_to_ascii(input_name, dir_name)
|
||||||
|
|
||||||
|
@ -165,16 +164,10 @@ def process(
|
||||||
rename_subs(dir_name)
|
rename_subs(dir_name)
|
||||||
if num_files and valid_files == num_files:
|
if num_files and valid_files == num_files:
|
||||||
if status:
|
if status:
|
||||||
logger.info(
|
log.info(f'Status shown as failed from Downloader, but {good_files} valid video files found. Setting as success.')
|
||||||
f'Status shown as failed from Downloader, but {good_files} valid video files found. Setting as success.',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
status = 0
|
status = 0
|
||||||
elif num_files and valid_files < num_files:
|
elif num_files and valid_files < num_files:
|
||||||
logger.info(
|
log.info('Status shown as success from Downloader, but corrupt video files found. Setting as failed.')
|
||||||
'Status shown as success from Downloader, but corrupt video files found. Setting as failed.',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
status = 1
|
status = 1
|
||||||
if (
|
if (
|
||||||
'NZBOP_VERSION' in os.environ
|
'NZBOP_VERSION' in os.environ
|
||||||
|
@ -182,33 +175,21 @@ def process(
|
||||||
):
|
):
|
||||||
print('[NZB] MARK=BAD')
|
print('[NZB] MARK=BAD')
|
||||||
if good_files == num_files:
|
if good_files == num_files:
|
||||||
logger.debug(
|
log.debug(f'Video marked as failed due to missing required language: {nzb2media.REQUIRE_LAN}')
|
||||||
f'Video marked as failed due to missing required language: {nzb2media.REQUIRE_LAN}',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
logger.debug(
|
log.debug('Video marked as failed due to missing playable audio or video')
|
||||||
'Video marked as failed due to missing playable audio or video',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
if (
|
if (
|
||||||
good_files < num_files and failure_link
|
good_files < num_files and failure_link
|
||||||
): # only report corrupt files
|
): # only report corrupt files
|
||||||
failure_link += '&corrupt=true'
|
failure_link += '&corrupt=true'
|
||||||
elif client_agent == 'manual':
|
elif client_agent == 'manual':
|
||||||
logger.warning(
|
log.warning(f'No media files found in directory {dir_name} to manually process.')
|
||||||
f'No media files found in directory {dir_name} to manually process.',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
message='',
|
message='',
|
||||||
status_code=0, # Success (as far as this script is concerned)
|
status_code=0, # Success (as far as this script is concerned)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
log.warning(f'No media files found in directory {dir_name}. Processing this as a failed download')
|
||||||
f'No media files found in directory {dir_name}. Processing this as a failed download',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
status = 1
|
status = 1
|
||||||
if (
|
if (
|
||||||
'NZBOP_VERSION' in os.environ
|
'NZBOP_VERSION' in os.environ
|
||||||
|
@ -220,25 +201,15 @@ def process(
|
||||||
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 result == 0:
|
||||||
logger.debug(
|
log.debug(f'Transcoding succeeded for files in {dir_name}')
|
||||||
f'Transcoding succeeded for files in {dir_name}', section,
|
|
||||||
)
|
|
||||||
dir_name = new_dir_name
|
dir_name = new_dir_name
|
||||||
|
|
||||||
logger.debug(
|
log.debug(f'Config setting \'chmodDirectory\' currently set to {oct(chmod_directory)}')
|
||||||
f'Config setting \'chmodDirectory\' currently set to {oct(chmod_directory)}',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
if chmod_directory:
|
if chmod_directory:
|
||||||
logger.info(
|
log.info(f'Attempting to set the octal permission of \'{oct(chmod_directory)}\' on directory \'{dir_name}\'')
|
||||||
f'Attempting to set the octal permission of \'{oct(chmod_directory)}\' on directory \'{dir_name}\'',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
nzb2media.rchmod(dir_name, chmod_directory)
|
nzb2media.rchmod(dir_name, chmod_directory)
|
||||||
else:
|
else:
|
||||||
logger.error(
|
log.error(f'Transcoding failed for files in {dir_name}')
|
||||||
f'Transcoding failed for files in {dir_name}', section,
|
|
||||||
)
|
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
message=f'{section}: Failed to post-process - Transcoding failed',
|
message=f'{section}: Failed to post-process - Transcoding failed',
|
||||||
status_code=1,
|
status_code=1,
|
||||||
|
@ -253,13 +224,11 @@ def process(
|
||||||
client_agent in [nzb2media.TORRENT_CLIENT_AGENT, 'manual']
|
client_agent in [nzb2media.TORRENT_CLIENT_AGENT, 'manual']
|
||||||
and nzb2media.USE_LINK == 'move-sym'
|
and nzb2media.USE_LINK == 'move-sym'
|
||||||
):
|
):
|
||||||
logger.debug(f'Renaming: {video} to: {video2}')
|
log.debug(f'Renaming: {video} to: {video2}')
|
||||||
os.rename(video, video2)
|
os.rename(video, video2)
|
||||||
|
|
||||||
if not apikey: # If only using Transcoder functions, exit here.
|
if not apikey: # If only using Transcoder functions, exit here.
|
||||||
logger.info(
|
log.info('No CouchPotato or Radarr or Watcher3 apikey entered. Processing completed.')
|
||||||
'No CouchPotato or Radarr or Watcher3 apikey entered. Processing completed.',
|
|
||||||
)
|
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
message=f'{section}: Successfully post-processed {input_name}',
|
message=f'{section}: Successfully post-processed {input_name}',
|
||||||
status_code=0,
|
status_code=0,
|
||||||
|
@ -281,10 +250,8 @@ def process(
|
||||||
command = 'renamer.scan'
|
command = 'renamer.scan'
|
||||||
|
|
||||||
url = f'{base_url}{command}'
|
url = f'{base_url}{command}'
|
||||||
logger.debug(f'Opening URL: {url} with PARAMS: {params}', section)
|
log.debug(f'Opening URL: {url} with PARAMS: {params}')
|
||||||
logger.postprocess(
|
log.debug(f'Starting {method} scan for {input_name}')
|
||||||
f'Starting {method} scan for {input_name}', section,
|
|
||||||
)
|
|
||||||
|
|
||||||
if section == 'Radarr':
|
if section == 'Radarr':
|
||||||
payload = {
|
payload = {
|
||||||
|
@ -295,12 +262,8 @@ def process(
|
||||||
}
|
}
|
||||||
if not download_id:
|
if not download_id:
|
||||||
payload.pop('downloadClientId')
|
payload.pop('downloadClientId')
|
||||||
logger.debug(
|
log.debug(f'Opening URL: {base_url} with PARAMS: {payload}')
|
||||||
f'Opening URL: {base_url} with PARAMS: {payload}', section,
|
log.debug(f'Starting DownloadedMoviesScan scan for {input_name}')
|
||||||
)
|
|
||||||
logger.postprocess(
|
|
||||||
f'Starting DownloadedMoviesScan scan for {input_name}', section,
|
|
||||||
)
|
|
||||||
|
|
||||||
if section == 'Watcher3':
|
if section == 'Watcher3':
|
||||||
if input_name and os.path.isfile(
|
if input_name and os.path.isfile(
|
||||||
|
@ -317,24 +280,20 @@ def process(
|
||||||
}
|
}
|
||||||
if not download_id:
|
if not download_id:
|
||||||
payload.pop('guid')
|
payload.pop('guid')
|
||||||
logger.debug(
|
log.debug(f'Opening URL: {base_url} with PARAMS: {payload}')
|
||||||
f'Opening URL: {base_url} with PARAMS: {payload}', section,
|
log.debug(f'Starting postprocessing scan for {input_name}')
|
||||||
)
|
|
||||||
logger.postprocess(
|
|
||||||
f'Starting postprocessing scan for {input_name}', section,
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if section == 'CouchPotato':
|
if section == 'CouchPotato':
|
||||||
r = requests.get(
|
response = requests.get(
|
||||||
url, params=params, verify=False, timeout=(30, 1800),
|
url, params=params, verify=False, timeout=(30, 1800),
|
||||||
)
|
)
|
||||||
elif section == 'Watcher3':
|
elif section == 'Watcher3':
|
||||||
r = requests.post(
|
response = requests.post(
|
||||||
base_url, data=payload, verify=False, timeout=(30, 1800),
|
base_url, data=payload, verify=False, timeout=(30, 1800),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
r = requests.post(
|
response = requests.post(
|
||||||
base_url,
|
base_url,
|
||||||
data=json.dumps(payload),
|
data=json.dumps(payload),
|
||||||
headers=headers,
|
headers=headers,
|
||||||
|
@ -343,30 +302,25 @@ def process(
|
||||||
timeout=(30, 1800),
|
timeout=(30, 1800),
|
||||||
)
|
)
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.error('Unable to open URL', section)
|
log.error('Unable to open URL')
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
message='{0}: Failed to post-process - Unable to connect to {0}'.format(
|
message=f'{section}: Failed to post-process - Unable to connect to {section}',
|
||||||
section,
|
|
||||||
),
|
|
||||||
status_code=1,
|
status_code=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
result = r.json()
|
result = response.json()
|
||||||
if r.status_code not in [
|
if response.status_code not in [
|
||||||
requests.codes.ok,
|
requests.codes.ok,
|
||||||
requests.codes.created,
|
requests.codes.created,
|
||||||
requests.codes.accepted,
|
requests.codes.accepted,
|
||||||
]:
|
]:
|
||||||
logger.error(f'Server returned status {r.status_code}', section)
|
log.error(f'Server returned status {response.status_code}')
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
message=f'{section}: Failed to post-process - Server returned status {r.status_code}',
|
message=f'{section}: Failed to post-process - Server returned status {response.status_code}',
|
||||||
status_code=1,
|
status_code=1,
|
||||||
)
|
)
|
||||||
elif section == 'CouchPotato' and result['success']:
|
elif section == 'CouchPotato' and result['success']:
|
||||||
logger.postprocess(
|
log.debug(f'SUCCESS: Finished {method} scan for folder {dir_name}')
|
||||||
f'SUCCESS: Finished {method} scan for folder {dir_name}',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
if method == 'manage':
|
if method == 'manage':
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
message=f'{section}: Successfully post-processed {input_name}',
|
message=f'{section}: Successfully post-processed {input_name}',
|
||||||
|
@ -375,13 +329,13 @@ def process(
|
||||||
elif section == 'Radarr':
|
elif section == 'Radarr':
|
||||||
try:
|
try:
|
||||||
scan_id = int(result['id'])
|
scan_id = int(result['id'])
|
||||||
logger.debug(f'Scan started with id: {scan_id}', section)
|
log.debug(f'Scan started with id: {scan_id}')
|
||||||
except Exception as e:
|
except Exception as error:
|
||||||
logger.warning(f'No scan id was returned due to: {e}', section)
|
log.warning(f'No scan id was returned due to: {error}')
|
||||||
scan_id = None
|
scan_id = None
|
||||||
elif section == 'Watcher3' and result['status'] == 'finished':
|
elif section == 'Watcher3' and result['status'] == 'finished':
|
||||||
update_movie_status = result['tasks']['update_movie_status']
|
update_movie_status = result['tasks']['update_movie_status']
|
||||||
logger.postprocess(f'Watcher3 updated status to {section}')
|
log.debug(f'Watcher3 updated status to {section}')
|
||||||
if update_movie_status == 'Finished':
|
if update_movie_status == 'Finished':
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
message=f'{section}: Successfully post-processed {input_name}',
|
message=f'{section}: Successfully post-processed {input_name}',
|
||||||
|
@ -393,38 +347,26 @@ def process(
|
||||||
status_code=1,
|
status_code=1,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.error(
|
log.error(f'FAILED: {method} scan was unable to finish for folder {dir_name}. exiting!')
|
||||||
f'FAILED: {method} scan was unable to finish for folder {dir_name}. exiting!',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
message=f'{section}: Failed to post-process - Server did not return success',
|
message=f'{section}: Failed to post-process - Server did not return success',
|
||||||
status_code=1,
|
status_code=1,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
nzb2media.FAILED = True
|
nzb2media.FAILED = True
|
||||||
logger.postprocess(
|
log.debug(f'FAILED DOWNLOAD DETECTED FOR {input_name}')
|
||||||
f'FAILED DOWNLOAD DETECTED FOR {input_name}', section,
|
|
||||||
)
|
|
||||||
if failure_link:
|
if failure_link:
|
||||||
report_nzb(failure_link, client_agent)
|
report_nzb(failure_link, client_agent)
|
||||||
|
|
||||||
if section == 'Radarr':
|
if section == 'Radarr':
|
||||||
logger.postprocess(
|
log.debug(f'SUCCESS: Sending failed download to {section} for CDH processing')
|
||||||
f'SUCCESS: Sending failed download to {section} for CDH processing',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
message='{0}: Sending failed download back to {0}'.format(
|
message=f'{section}: Sending failed download back to {section}',
|
||||||
section,
|
status_code=1,
|
||||||
),
|
# Return as failed to flag this in the downloader.
|
||||||
status_code=1, # Return as failed to flag this in the downloader.
|
|
||||||
) # Return failed flag, but log the event as successful.
|
) # Return failed flag, but log the event as successful.
|
||||||
elif section == 'Watcher3':
|
elif section == 'Watcher3':
|
||||||
logger.postprocess(
|
log.debug(f'Sending failed download to {section} for CDH processing')
|
||||||
f'Sending failed download to {section} for CDH processing',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
path = remote_dir(dir_name) if remote_path else dir_name
|
path = remote_dir(dir_name) if remote_path else dir_name
|
||||||
if input_name and os.path.isfile(
|
if input_name and os.path.isfile(
|
||||||
os.path.join(dir_name, input_name),
|
os.path.join(dir_name, input_name),
|
||||||
|
@ -436,17 +378,16 @@ def process(
|
||||||
'guid': download_id,
|
'guid': download_id,
|
||||||
'mode': 'failed',
|
'mode': 'failed',
|
||||||
}
|
}
|
||||||
r = requests.post(
|
response = requests.post(
|
||||||
base_url, data=payload, verify=False, timeout=(30, 1800),
|
base_url, data=payload, verify=False, timeout=(30, 1800),
|
||||||
)
|
)
|
||||||
result = r.json()
|
result = response.json()
|
||||||
logger.postprocess(f'Watcher3 response: {result}')
|
log.debug(f'Watcher3 response: {result}')
|
||||||
if result['status'] == 'finished':
|
if result['status'] == 'finished':
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
message='{0}: Sending failed download back to {0}'.format(
|
message=f'{section}: Sending failed download back to {section}',
|
||||||
section,
|
status_code=1,
|
||||||
),
|
# Return as failed to flag this in the downloader.
|
||||||
status_code=1, # Return as failed to flag this in the downloader.
|
|
||||||
) # Return failed flag, but log the event as successful.
|
) # Return failed flag, but log the event as successful.
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -454,117 +395,93 @@ def process(
|
||||||
and os.path.isdir(dir_name)
|
and os.path.isdir(dir_name)
|
||||||
and not os.path.dirname(dir_name) == dir_name
|
and not os.path.dirname(dir_name) == dir_name
|
||||||
):
|
):
|
||||||
logger.postprocess(
|
log.debug(f'Deleting failed files and folder {dir_name}')
|
||||||
f'Deleting failed files and folder {dir_name}', section,
|
|
||||||
)
|
|
||||||
remove_dir(dir_name)
|
remove_dir(dir_name)
|
||||||
|
|
||||||
if not release_id and not media_id:
|
if not release_id and not media_id:
|
||||||
logger.error(
|
log.error(f'Could not find a downloaded movie in the database matching {input_name}, exiting!')
|
||||||
f'Could not find a downloaded movie in the database matching {input_name}, exiting!',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
message='{0}: Failed to post-process - Failed download not found in {0}'.format(
|
message='{0}: Failed to post-process - Failed download not found in {0}'.format(section),
|
||||||
section,
|
|
||||||
),
|
|
||||||
status_code=1,
|
status_code=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
if release_id:
|
if release_id:
|
||||||
logger.postprocess(
|
log.debug(f'Setting failed release {input_name} to ignored ...')
|
||||||
f'Setting failed release {input_name} to ignored ...', section,
|
|
||||||
)
|
|
||||||
|
|
||||||
url = f'{base_url}release.ignore'
|
url = f'{base_url}release.ignore'
|
||||||
params = {'id': release_id}
|
params = {'id': release_id}
|
||||||
|
|
||||||
logger.debug(f'Opening URL: {url} with PARAMS: {params}', section)
|
log.debug(f'Opening URL: {url} with PARAMS: {params}')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
r = requests.get(
|
response = requests.get(
|
||||||
url, params=params, verify=False, timeout=(30, 120),
|
url, params=params, verify=False,
|
||||||
|
timeout=(30, 120),
|
||||||
)
|
)
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.error(f'Unable to open URL {url}', section)
|
log.error(f'Unable to open URL {url}')
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
message='{0}: Failed to post-process - Unable to connect to {0}'.format(
|
message='{0}: Failed to post-process - Unable to connect to {0}'.format(section),
|
||||||
section,
|
|
||||||
),
|
|
||||||
status_code=1,
|
status_code=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
result = r.json()
|
result = response.json()
|
||||||
if r.status_code not in [
|
if response.status_code not in [
|
||||||
requests.codes.ok,
|
requests.codes.ok,
|
||||||
requests.codes.created,
|
requests.codes.created,
|
||||||
requests.codes.accepted,
|
requests.codes.accepted,
|
||||||
]:
|
]:
|
||||||
logger.error(
|
log.error(f'Server returned status {response.status_code}')
|
||||||
f'Server returned status {r.status_code}', section,
|
|
||||||
)
|
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
status_code=1,
|
status_code=1,
|
||||||
message=f'{section}: Failed to post-process - Server returned status {r.status_code}',
|
message=f'{section}: Failed to post-process - Server returned status {response.status_code}',
|
||||||
)
|
)
|
||||||
elif result['success']:
|
elif result['success']:
|
||||||
logger.postprocess(
|
log.debug(f'SUCCESS: {input_name} has been set to ignored ...')
|
||||||
f'SUCCESS: {input_name} has been set to ignored ...',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
log.warning(f'FAILED: Unable to set {input_name} to ignored!')
|
||||||
f'FAILED: Unable to set {input_name} to ignored!', section,
|
|
||||||
)
|
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
message=f'{section}: Failed to post-process - Unable to set {input_name} to ignored',
|
message=f'{section}: Failed to post-process - Unable to set {input_name} to ignored',
|
||||||
status_code=1,
|
status_code=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.postprocess(
|
log.debug('Trying to snatch the next highest ranked release.')
|
||||||
'Trying to snatch the next highest ranked release.', section,
|
|
||||||
)
|
|
||||||
|
|
||||||
url = f'{base_url}movie.searcher.try_next'
|
url = f'{base_url}movie.searcher.try_next'
|
||||||
logger.debug(f'Opening URL: {url}', section)
|
log.debug(f'Opening URL: {url}')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
r = requests.get(
|
response = requests.get(
|
||||||
url,
|
url,
|
||||||
params={'media_id': media_id},
|
params={'media_id': media_id},
|
||||||
verify=False,
|
verify=False,
|
||||||
timeout=(30, 600),
|
timeout=(30, 600),
|
||||||
)
|
)
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.error(f'Unable to open URL {url}', section)
|
log.error(f'Unable to open URL {url}')
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - Unable to connect to '
|
f'{section}: Failed to post-process - Unable to connect to '
|
||||||
f'{section}',
|
f'{section}',
|
||||||
)
|
)
|
||||||
|
|
||||||
result = r.json()
|
result = response.json()
|
||||||
if r.status_code not in [
|
if response.status_code not in [
|
||||||
requests.codes.ok,
|
requests.codes.ok,
|
||||||
requests.codes.created,
|
requests.codes.created,
|
||||||
requests.codes.accepted,
|
requests.codes.accepted,
|
||||||
]:
|
]:
|
||||||
logger.error(f'Server returned status {r.status_code}', section)
|
log.error(f'Server returned status {response.status_code}')
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - Server returned status '
|
f'{section}: Failed to post-process - Server returned status '
|
||||||
f'{r.status_code}',
|
f'{response.status_code}',
|
||||||
)
|
)
|
||||||
elif result['success']:
|
elif result['success']:
|
||||||
logger.postprocess(
|
log.debug('SUCCESS: Snatched the next highest release ...')
|
||||||
'SUCCESS: Snatched the next highest release ...', section,
|
|
||||||
)
|
|
||||||
return ProcessResult.success(
|
return ProcessResult.success(
|
||||||
f'{section}: Successfully snatched next highest release',
|
f'{section}: Successfully snatched next highest release',
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.postprocess(
|
log.debug('SUCCESS: Unable to find a new release to snatch now. CP will keep searching!')
|
||||||
'SUCCESS: Unable to find a new release to snatch now. CP will keep searching!',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult.success(
|
return ProcessResult.success(
|
||||||
f'{section}: No new release found now. '
|
f'{section}: No new release found now. '
|
||||||
f'{section} will keep searching',
|
f'{section} will keep searching',
|
||||||
|
@ -585,9 +502,7 @@ def process(
|
||||||
# we will now check to see if CPS has finished renaming before returning to TorrentToMedia and unpausing.
|
# we will now check to see if CPS has finished renaming before returning to TorrentToMedia and unpausing.
|
||||||
timeout = time.time() + 60 * wait_for
|
timeout = time.time() + 60 * wait_for
|
||||||
while time.time() < timeout: # only wait 2 (default) minutes, then return.
|
while time.time() < timeout: # only wait 2 (default) minutes, then return.
|
||||||
logger.postprocess(
|
log.debug('Checking for status change, please stand by ...')
|
||||||
'Checking for status change, please stand by ...', section,
|
|
||||||
)
|
|
||||||
if section == 'CouchPotato':
|
if section == 'CouchPotato':
|
||||||
release = get_release(base_url, imdbid, download_id, release_id)
|
release = get_release(base_url, imdbid, download_id, release_id)
|
||||||
scan_id = None
|
scan_id = None
|
||||||
|
@ -601,19 +516,13 @@ def process(
|
||||||
release_status_old is None
|
release_status_old is None
|
||||||
): # we didn't have a release before, but now we do.
|
): # we didn't have a release before, but now we do.
|
||||||
title = release[release_id]['title']
|
title = release[release_id]['title']
|
||||||
logger.postprocess(
|
log.debug(f'SUCCESS: Movie {title} has now been added to CouchPotato with release status of [{str(release_status_new).upper()}]')
|
||||||
f'SUCCESS: Movie {title} has now been added to CouchPotato with release status of [{str(release_status_new).upper()}]',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult.success(
|
return ProcessResult.success(
|
||||||
f'{section}: Successfully post-processed {input_name}',
|
f'{section}: Successfully post-processed {input_name}',
|
||||||
)
|
)
|
||||||
|
|
||||||
if release_status_new != release_status_old:
|
if release_status_new != release_status_old:
|
||||||
logger.postprocess(
|
log.debug(f'SUCCESS: Release {release_id} has now been marked with a status of [{str(release_status_new).upper()}]')
|
||||||
f'SUCCESS: Release {release_id} has now been marked with a status of [{str(release_status_new).upper()}]',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult.success(
|
return ProcessResult.success(
|
||||||
f'{section}: Successfully post-processed {input_name}',
|
f'{section}: Successfully post-processed {input_name}',
|
||||||
)
|
)
|
||||||
|
@ -623,33 +532,21 @@ def process(
|
||||||
url = f'{base_url}/{scan_id}'
|
url = f'{base_url}/{scan_id}'
|
||||||
command_status = command_complete(url, params, headers, section)
|
command_status = command_complete(url, params, headers, section)
|
||||||
if command_status:
|
if command_status:
|
||||||
logger.debug(
|
log.debug(f'The Scan command return status: {command_status}')
|
||||||
f'The Scan command return status: {command_status}',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
if command_status in ['completed']:
|
if command_status in ['completed']:
|
||||||
logger.debug(
|
log.debug('The Scan command has completed successfully. Renaming was successful.')
|
||||||
'The Scan command has completed successfully. Renaming was successful.',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult.success(
|
return ProcessResult.success(
|
||||||
f'{section}: Successfully post-processed {input_name}',
|
f'{section}: Successfully post-processed {input_name}',
|
||||||
)
|
)
|
||||||
elif command_status in ['failed']:
|
elif command_status in ['failed']:
|
||||||
logger.debug(
|
log.debug('The Scan command has failed. Renaming was not successful.')
|
||||||
'The Scan command has failed. Renaming was not successful.',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
# return ProcessResult(
|
# return ProcessResult(
|
||||||
# message='{0}: Failed to post-process {1}'.format(section, input_name),
|
# message='{0}: Failed to post-process {1}'.format(section, input_name),
|
||||||
# status_code=1,
|
# status_code=1,
|
||||||
# )
|
# )
|
||||||
|
|
||||||
if not os.path.isdir(dir_name):
|
if not os.path.isdir(dir_name):
|
||||||
logger.postprocess(
|
log.debug(f'SUCCESS: Input Directory [{dir_name}] has been processed and removed')
|
||||||
f'SUCCESS: Input Directory [{dir_name}] has been processed and removed',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult.success(
|
return ProcessResult.success(
|
||||||
f'{section}: Successfully post-processed {input_name}',
|
f'{section}: Successfully post-processed {input_name}',
|
||||||
)
|
)
|
||||||
|
@ -657,10 +554,7 @@ def process(
|
||||||
elif not list_media_files(
|
elif not list_media_files(
|
||||||
dir_name, media=True, audio=False, meta=False, archives=True,
|
dir_name, media=True, audio=False, meta=False, archives=True,
|
||||||
):
|
):
|
||||||
logger.postprocess(
|
log.debug(f'SUCCESS: Input Directory [{dir_name}] has no remaining media files. This has been fully processed.')
|
||||||
f'SUCCESS: Input Directory [{dir_name}] has no remaining media files. This has been fully processed.',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult.success(
|
return ProcessResult.success(
|
||||||
f'{section}: Successfully post-processed {input_name}',
|
f'{section}: Successfully post-processed {input_name}',
|
||||||
)
|
)
|
||||||
|
@ -672,19 +566,12 @@ def process(
|
||||||
if section == 'Radarr' and completed_download_handling(
|
if section == 'Radarr' and completed_download_handling(
|
||||||
url2, headers, section=section,
|
url2, headers, section=section,
|
||||||
):
|
):
|
||||||
logger.debug(
|
log.debug(f'The Scan command did not return status completed, but complete Download Handling is enabled. Passing back to {section}.')
|
||||||
f'The Scan command did not return status completed, but complete Download Handling is enabled. Passing back to {section}.',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult.success(
|
return ProcessResult.success(
|
||||||
f'{section}: Complete DownLoad Handling is enabled. Passing back '
|
f'{section}: Complete DownLoad Handling is enabled. Passing back '
|
||||||
f'to {section}',
|
f'to {section}',
|
||||||
)
|
)
|
||||||
logger.warning(
|
log.warning(f'{input_name} does not appear to have changed status after {wait_for} minutes, Please check your logs.')
|
||||||
f'{input_name} does not appear to have changed status after {wait_for} minutes, Please check your logs.',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
|
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - No change in status',
|
f'{section}: Failed to post-process - No change in status',
|
||||||
)
|
)
|
||||||
|
@ -703,33 +590,33 @@ def get_release(base_url, imdb_id=None, download_id=None, release_id=None):
|
||||||
params['id'] = release_id or imdb_id
|
params['id'] = release_id or imdb_id
|
||||||
|
|
||||||
if not (release_id or imdb_id or download_id):
|
if not (release_id or imdb_id or download_id):
|
||||||
logger.debug('No information available to filter CP results')
|
log.debug('No information available to filter CP results')
|
||||||
return results
|
return results
|
||||||
|
|
||||||
url = f'{base_url}{cmd}'
|
url = f'{base_url}{cmd}'
|
||||||
logger.debug(f'Opening URL: {url} with PARAMS: {params}')
|
log.debug(f'Opening URL: {url} with PARAMS: {params}')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
r = requests.get(url, params=params, verify=False, timeout=(30, 60))
|
r = requests.get(url, params=params, verify=False, timeout=(30, 60))
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.error(f'Unable to open URL {url}')
|
log.error(f'Unable to open URL {url}')
|
||||||
return results
|
return results
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = r.json()
|
result = r.json()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
# ValueError catches simplejson's JSONDecodeError and json's ValueError
|
# ValueError catches simplejson's JSONDecodeError and json's ValueError
|
||||||
logger.error('CouchPotato returned the following non-json data')
|
log.error('CouchPotato returned the following non-json data')
|
||||||
for line in r.iter_lines():
|
for line in r.iter_lines():
|
||||||
logger.error(line)
|
log.error(line)
|
||||||
return results
|
return results
|
||||||
|
|
||||||
if not result['success']:
|
if not result['success']:
|
||||||
if 'error' in result:
|
if 'error' in result:
|
||||||
logger.error(result['error'])
|
log.error(result['error'])
|
||||||
else:
|
else:
|
||||||
id_param = params['id']
|
id_param = params['id']
|
||||||
logger.error(f'no media found for id {id_param}')
|
log.error(f'no media found for id {id_param}')
|
||||||
return results
|
return results
|
||||||
|
|
||||||
# Gather release info and return it back, no need to narrow results
|
# Gather release info and return it back, no need to narrow results
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media.auto_process.common import ProcessResult
|
from nzb2media.auto_process.common import ProcessResult
|
||||||
from nzb2media.auto_process.common import command_complete
|
from nzb2media.auto_process.common import command_complete
|
||||||
from nzb2media.scene_exceptions import process_all_exceptions
|
from nzb2media.scene_exceptions import process_all_exceptions
|
||||||
|
@ -18,6 +18,9 @@ from nzb2media.utils.network import server_responding
|
||||||
from nzb2media.utils.paths import remote_dir
|
from nzb2media.utils.paths import remote_dir
|
||||||
from nzb2media.utils.paths import remove_dir
|
from nzb2media.utils.paths import remove_dir
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def process(
|
def process(
|
||||||
*,
|
*,
|
||||||
|
@ -60,7 +63,7 @@ def process(
|
||||||
route = f'{web_root}/api/v1' if section == 'Lidarr' else f'{web_root}/api'
|
route = f'{web_root}/api/v1' if section == 'Lidarr' else f'{web_root}/api'
|
||||||
url = nzb2media.utils.common.create_url(scheme, host, port, route)
|
url = nzb2media.utils.common.create_url(scheme, host, port, route)
|
||||||
if not server_responding(url):
|
if not server_responding(url):
|
||||||
logger.error('Server did not respond. Exiting', section)
|
log.error('Server did not respond. Exiting')
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - {section} did not respond.',
|
f'{section}: Failed to post-process - {section} did not respond.',
|
||||||
)
|
)
|
||||||
|
@ -89,9 +92,7 @@ def process(
|
||||||
)
|
)
|
||||||
and extract
|
and extract
|
||||||
):
|
):
|
||||||
logger.debug(
|
log.debug(f'Checking for archives to extract in directory: {dir_name}')
|
||||||
f'Checking for archives to extract in directory: {dir_name}',
|
|
||||||
)
|
|
||||||
nzb2media.extract_files(dir_name)
|
nzb2media.extract_files(dir_name)
|
||||||
input_name, dir_name = convert_to_ascii(input_name, dir_name)
|
input_name, dir_name = convert_to_ascii(input_name, dir_name)
|
||||||
|
|
||||||
|
@ -128,10 +129,7 @@ def process(
|
||||||
return res
|
return res
|
||||||
|
|
||||||
# The status hasn't changed. uTorrent can resume seeding now.
|
# The status hasn't changed. uTorrent can resume seeding now.
|
||||||
logger.warning(
|
log.warning(f'The music album does not appear to have changed status after {wait_for} minutes. Please check your Logs')
|
||||||
f'The music album does not appear to have changed status after {wait_for} minutes. Please check your Logs',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - No change in wanted status',
|
f'{section}: Failed to post-process - No change in wanted status',
|
||||||
)
|
)
|
||||||
|
@ -141,13 +139,13 @@ def process(
|
||||||
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}
|
||||||
if remote_path:
|
if remote_path:
|
||||||
logger.debug(f'remote_path: {remote_dir(dir_name)}', section)
|
log.debug(f'remote_path: {remote_dir(dir_name)}')
|
||||||
data = {'name': 'Rename', 'path': remote_dir(dir_name)}
|
data = {'name': 'Rename', 'path': remote_dir(dir_name)}
|
||||||
else:
|
else:
|
||||||
logger.debug(f'path: {dir_name}', section)
|
log.debug(f'path: {dir_name}')
|
||||||
data = {'name': 'Rename', 'path': dir_name}
|
data = {'name': 'Rename', 'path': dir_name}
|
||||||
try:
|
try:
|
||||||
logger.debug(f'Opening URL: {url} with data: {data}', section)
|
log.debug(f'Opening URL: {url} with data: {data}')
|
||||||
r = requests.post(
|
r = requests.post(
|
||||||
url,
|
url,
|
||||||
data=json.dumps(data),
|
data=json.dumps(data),
|
||||||
|
@ -157,7 +155,7 @@ def process(
|
||||||
timeout=(30, 1800),
|
timeout=(30, 1800),
|
||||||
)
|
)
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.error(f'Unable to open URL: {url}', section)
|
log.error(f'Unable to open URL: {url}')
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - Unable to connect to '
|
f'{section}: Failed to post-process - Unable to connect to '
|
||||||
f'{section}',
|
f'{section}',
|
||||||
|
@ -166,9 +164,9 @@ def process(
|
||||||
try:
|
try:
|
||||||
res = r.json()
|
res = r.json()
|
||||||
scan_id = int(res['id'])
|
scan_id = int(res['id'])
|
||||||
logger.debug(f'Scan started with id: {scan_id}', section)
|
log.debug(f'Scan started with id: {scan_id}')
|
||||||
except Exception as e:
|
except Exception as error:
|
||||||
logger.warning(f'No scan id was returned due to: {e}', section)
|
log.warning(f'No scan id was returned due to: {error}')
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - Unable to start scan',
|
f'{section}: Failed to post-process - Unable to start scan',
|
||||||
)
|
)
|
||||||
|
@ -183,38 +181,24 @@ def process(
|
||||||
break
|
break
|
||||||
n += 1
|
n += 1
|
||||||
if command_status:
|
if command_status:
|
||||||
logger.debug(
|
log.debug(f'The Scan command return status: {command_status}')
|
||||||
f'The Scan command return status: {command_status}', section,
|
|
||||||
)
|
|
||||||
if not os.path.exists(dir_name):
|
if not os.path.exists(dir_name):
|
||||||
logger.debug(
|
log.debug(f'The directory {dir_name} has been removed. Renaming was successful.')
|
||||||
f'The directory {dir_name} has been removed. Renaming was successful.',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult.success(
|
return ProcessResult.success(
|
||||||
f'{section}: Successfully post-processed {input_name}',
|
f'{section}: Successfully post-processed {input_name}',
|
||||||
)
|
)
|
||||||
elif command_status and command_status in ['completed']:
|
elif command_status and command_status in ['completed']:
|
||||||
logger.debug(
|
log.debug('The Scan command has completed successfully. Renaming was successful.')
|
||||||
'The Scan command has completed successfully. Renaming was successful.',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult.success(
|
return ProcessResult.success(
|
||||||
f'{section}: Successfully post-processed {input_name}',
|
f'{section}: Successfully post-processed {input_name}',
|
||||||
)
|
)
|
||||||
elif command_status and command_status in ['failed']:
|
elif command_status and command_status in ['failed']:
|
||||||
logger.debug(
|
log.debug('The Scan command has failed. Renaming was not successful.')
|
||||||
'The Scan command has failed. Renaming was not successful.',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
# return ProcessResult.failure(
|
# return ProcessResult.failure(
|
||||||
# f'{section}: Failed to post-process {input_name}'
|
# f'{section}: Failed to post-process {input_name}'
|
||||||
# )
|
# )
|
||||||
else:
|
else:
|
||||||
logger.debug(
|
log.debug(f'The Scan command did not return status completed. Passing back to {section} to attempt complete download handling.')
|
||||||
f'The Scan command did not return status completed. Passing back to {section} to attempt complete download handling.',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
message=f'{section}: Passing back to {section} to attempt '
|
message=f'{section}: Passing back to {section} to attempt '
|
||||||
f'Complete Download Handling',
|
f'Complete Download Handling',
|
||||||
|
@ -223,24 +207,19 @@ def process(
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if section == 'Lidarr':
|
if section == 'Lidarr':
|
||||||
logger.postprocess(
|
log.debug(f'FAILED: The download failed. Sending failed download to {section} for CDH processing')
|
||||||
f'FAILED: The download failed. Sending failed download to {section} for CDH processing',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
# Return as failed to flag this in the downloader.
|
# Return as failed to flag this in the downloader.
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Download Failed. Sending back to {section}',
|
f'{section}: Download Failed. Sending back to {section}',
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.warning('FAILED DOWNLOAD DETECTED', section)
|
log.warning('FAILED DOWNLOAD DETECTED')
|
||||||
if (
|
if (
|
||||||
delete_failed
|
delete_failed
|
||||||
and os.path.isdir(dir_name)
|
and os.path.isdir(dir_name)
|
||||||
and not os.path.dirname(dir_name) == dir_name
|
and not os.path.dirname(dir_name) == dir_name
|
||||||
):
|
):
|
||||||
logger.postprocess(
|
log.postprocess(f'Deleting failed files and folder {dir_name}')
|
||||||
f'Deleting failed files and folder {dir_name}', section,
|
|
||||||
)
|
|
||||||
remove_dir(dir_name)
|
remove_dir(dir_name)
|
||||||
# Return as failed to flag this in the downloader.
|
# Return as failed to flag this in the downloader.
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
|
@ -252,21 +231,19 @@ def process(
|
||||||
|
|
||||||
|
|
||||||
def get_status(url, apikey, dir_name):
|
def get_status(url, apikey, dir_name):
|
||||||
logger.debug(
|
log.debug(f'Attempting to get current status for release:{os.path.basename(dir_name)}')
|
||||||
f'Attempting to get current status for release:{os.path.basename(dir_name)}',
|
|
||||||
)
|
|
||||||
|
|
||||||
params = {
|
params = {
|
||||||
'apikey': apikey,
|
'apikey': apikey,
|
||||||
'cmd': 'getHistory',
|
'cmd': 'getHistory',
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(f'Opening URL: {url} with PARAMS: {params}')
|
log.debug(f'Opening URL: {url} with PARAMS: {params}')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
r = requests.get(url, params=params, verify=False, timeout=(30, 120))
|
r = requests.get(url, params=params, verify=False, timeout=(30, 120))
|
||||||
except requests.RequestException:
|
except requests.RequestException:
|
||||||
logger.error('Unable to open URL')
|
log.error('Unable to open URL')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -285,43 +262,34 @@ def force_process(
|
||||||
):
|
):
|
||||||
release_status = get_status(url, apikey, dir_name)
|
release_status = get_status(url, apikey, dir_name)
|
||||||
if not release_status:
|
if not release_status:
|
||||||
logger.error(
|
log.error(f'Could not find a status for {input_name}, is it in the wanted list ?')
|
||||||
f'Could not find a status for {input_name}, is it in the wanted list ?',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.debug(f'Opening URL: {url} with PARAMS: {params}', section)
|
log.debug(f'Opening URL: {url} with PARAMS: {params}')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
r = requests.get(url, params=params, verify=False, timeout=(30, 300))
|
r = requests.get(url, params=params, verify=False, timeout=(30, 300))
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.error(f'Unable to open URL {url}', section)
|
log.error(f'Unable to open URL {url}')
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - Unable to connect to '
|
f'{section}: Failed to post-process - Unable to connect to '
|
||||||
f'{section}',
|
f'{section}',
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.debug(f'Result: {r.text}', section)
|
log.debug(f'Result: {r.text}')
|
||||||
|
|
||||||
if r.status_code not in [
|
if r.status_code not in [
|
||||||
requests.codes.ok,
|
requests.codes.ok,
|
||||||
requests.codes.created,
|
requests.codes.created,
|
||||||
requests.codes.accepted,
|
requests.codes.accepted,
|
||||||
]:
|
]:
|
||||||
logger.error(f'Server returned status {r.status_code}', section)
|
log.error(f'Server returned status {r.status_code}')
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - Server returned status {r.status_code}',
|
f'{section}: Failed to post-process - Server returned status {r.status_code}',
|
||||||
)
|
)
|
||||||
elif r.text == 'OK':
|
elif r.text == 'OK':
|
||||||
logger.postprocess(
|
log.debug(f'SUCCESS: Post-Processing started for {input_name} in folder {dir_name} ...')
|
||||||
f'SUCCESS: Post-Processing started for {input_name} in folder {dir_name} ...',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
logger.error(
|
log.error(f'FAILED: Post-Processing has NOT started for {input_name} in folder {dir_name}. exiting!')
|
||||||
f'FAILED: Post-Processing has NOT started for {input_name} in folder {dir_name}. exiting!',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - Returned log from {section} '
|
f'{section}: Failed to post-process - Returned log from {section} '
|
||||||
f'was not as expected.',
|
f'was not as expected.',
|
||||||
|
@ -334,18 +302,12 @@ def force_process(
|
||||||
if (
|
if (
|
||||||
current_status is not None and current_status != release_status
|
current_status is not None and current_status != release_status
|
||||||
): # Something has changed. CPS must have processed this movie.
|
): # Something has changed. CPS must have processed this movie.
|
||||||
logger.postprocess(
|
log.debug(f'SUCCESS: This release is now marked as status [{current_status}]')
|
||||||
f'SUCCESS: This release is now marked as status [{current_status}]',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult.success(
|
return ProcessResult.success(
|
||||||
f'{section}: Successfully post-processed {input_name}',
|
f'{section}: Successfully post-processed {input_name}',
|
||||||
)
|
)
|
||||||
if not os.path.isdir(dir_name):
|
if not os.path.isdir(dir_name):
|
||||||
logger.postprocess(
|
log.debug(f'SUCCESS: The input directory {dir_name} has been removed Processing must have finished.')
|
||||||
f'SUCCESS: The input directory {dir_name} has been removed Processing must have finished.',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult.success(
|
return ProcessResult.success(
|
||||||
f'{section}: Successfully post-processed {input_name}',
|
f'{section}: Successfully post-processed {input_name}',
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
||||||
import copy
|
import copy
|
||||||
import errno
|
import errno
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
@ -11,7 +12,6 @@ from oauthlib.oauth2 import LegacyApplicationClient
|
||||||
from requests_oauthlib import OAuth2Session
|
from requests_oauthlib import OAuth2Session
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media import transcoder
|
from nzb2media import transcoder
|
||||||
from nzb2media.auto_process.common import ProcessResult
|
from nzb2media.auto_process.common import ProcessResult
|
||||||
from nzb2media.auto_process.common import command_complete
|
from nzb2media.auto_process.common import command_complete
|
||||||
|
@ -28,6 +28,9 @@ from nzb2media.utils.nzb import report_nzb
|
||||||
from nzb2media.utils.paths import remote_dir
|
from nzb2media.utils.paths import remote_dir
|
||||||
from nzb2media.utils.paths import remove_dir
|
from nzb2media.utils.paths import remove_dir
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def process(
|
def process(
|
||||||
*,
|
*,
|
||||||
|
@ -91,12 +94,10 @@ def process(
|
||||||
# Should be changed after refactor.
|
# Should be changed after refactor.
|
||||||
fork, fork_params = init_sickbeard.auto_fork()
|
fork, fork_params = init_sickbeard.auto_fork()
|
||||||
elif not username and not apikey and not sso_username:
|
elif not username and not apikey and not sso_username:
|
||||||
logger.info(
|
log.info('No SickBeard / SiCKRAGE username or Sonarr apikey entered. Performing transcoder functions only')
|
||||||
'No SickBeard / SiCKRAGE username or Sonarr apikey entered. Performing transcoder functions only',
|
|
||||||
)
|
|
||||||
fork, fork_params = 'None', {}
|
fork, fork_params = 'None', {}
|
||||||
else:
|
else:
|
||||||
logger.error('Server did not respond. Exiting', section)
|
log.error('Server did not respond. Exiting')
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - {section} did not respond.',
|
f'{section}: Failed to post-process - {section} did not respond.',
|
||||||
)
|
)
|
||||||
|
@ -124,9 +125,9 @@ def process(
|
||||||
if dir_name:
|
if dir_name:
|
||||||
try:
|
try:
|
||||||
os.makedirs(dir_name) # Attempt to create the directory
|
os.makedirs(dir_name) # Attempt to create the directory
|
||||||
except OSError as e:
|
except OSError as error:
|
||||||
# Re-raise the error if it wasn't about the directory not existing
|
# Re-raise the error if it wasn't about the directory not existing
|
||||||
if e.errno != errno.EEXIST:
|
if error.errno != errno.EEXIST:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
if 'process_method' not in fork_params or (
|
if 'process_method' not in fork_params or (
|
||||||
|
@ -151,9 +152,7 @@ def process(
|
||||||
)
|
)
|
||||||
and extract
|
and extract
|
||||||
):
|
):
|
||||||
logger.debug(
|
log.debug(f'Checking for archives to extract in directory: {dir_name}')
|
||||||
f'Checking for archives to extract in directory: {dir_name}',
|
|
||||||
)
|
|
||||||
nzb2media.extract_files(dir_name)
|
nzb2media.extract_files(dir_name)
|
||||||
input_name, dir_name = convert_to_ascii(input_name, dir_name)
|
input_name, dir_name = convert_to_ascii(input_name, dir_name)
|
||||||
|
|
||||||
|
@ -180,10 +179,10 @@ def process(
|
||||||
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 not status == 0:
|
||||||
logger.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 status == 0:
|
||||||
logger.info('Found corrupt videos. Setting status Failed')
|
log.info('Found corrupt videos. Setting status Failed')
|
||||||
status = 1
|
status = 1
|
||||||
if (
|
if (
|
||||||
'NZBOP_VERSION' in os.environ
|
'NZBOP_VERSION' in os.environ
|
||||||
|
@ -191,42 +190,26 @@ def process(
|
||||||
):
|
):
|
||||||
print('[NZB] MARK=BAD')
|
print('[NZB] MARK=BAD')
|
||||||
if good_files == num_files:
|
if good_files == num_files:
|
||||||
logger.debug(
|
log.debug(f'Video marked as failed due to missing required language: {nzb2media.REQUIRE_LAN}')
|
||||||
f'Video marked as failed due to missing required language: {nzb2media.REQUIRE_LAN}',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
logger.debug(
|
log.debug('Video marked as failed due to missing playable audio or video')
|
||||||
'Video marked as failed due to missing playable audio or video',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
if (
|
if (
|
||||||
good_files < num_files and failure_link
|
good_files < num_files and failure_link
|
||||||
): # only report corrupt files
|
): # only report corrupt files
|
||||||
failure_link += '&corrupt=true'
|
failure_link += '&corrupt=true'
|
||||||
elif client_agent == 'manual':
|
elif client_agent == 'manual':
|
||||||
logger.warning(
|
log.warning(f'No media files found in directory {dir_name} to manually process.')
|
||||||
f'No media files found in directory {dir_name} to manually process.',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
# Success (as far as this script is concerned)
|
# Success (as far as this script is concerned)
|
||||||
return ProcessResult.success()
|
return ProcessResult.success()
|
||||||
elif nzb_extraction_by == 'Destination':
|
elif nzb_extraction_by == 'Destination':
|
||||||
logger.info(
|
log.info('Check for media files ignored because nzbExtractionBy is set to Destination.')
|
||||||
'Check for media files ignored because nzbExtractionBy is set to Destination.',
|
|
||||||
)
|
|
||||||
if status == 0:
|
if status == 0:
|
||||||
logger.info('Setting Status Success.')
|
log.info('Setting Status Success.')
|
||||||
else:
|
else:
|
||||||
logger.info(
|
log.info('Downloader reported an error during download or verification. Processing this as a failed download.')
|
||||||
'Downloader reported an error during download or verification. Processing this as a failed download.',
|
|
||||||
)
|
|
||||||
status = 1
|
status = 1
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
log.warning(f'No media files found in directory {dir_name}. Processing this as a failed download')
|
||||||
f'No media files found in directory {dir_name}. Processing this as a failed download',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
status = 1
|
status = 1
|
||||||
if (
|
if (
|
||||||
'NZBOP_VERSION' in os.environ
|
'NZBOP_VERSION' in os.environ
|
||||||
|
@ -239,26 +222,15 @@ def process(
|
||||||
): # only transcode successful downloads
|
): # 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 result == 0:
|
||||||
logger.debug(
|
log.debug(f'SUCCESS: Transcoding succeeded for files in {dir_name}')
|
||||||
f'SUCCESS: Transcoding succeeded for files in {dir_name}',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
dir_name = new_dir_name
|
dir_name = new_dir_name
|
||||||
|
|
||||||
logger.debug(
|
log.debug(f'Config setting \'chmodDirectory\' currently set to {oct(chmod_directory)}')
|
||||||
f'Config setting \'chmodDirectory\' currently set to {oct(chmod_directory)}',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
if chmod_directory:
|
if chmod_directory:
|
||||||
logger.info(
|
log.info(f'Attempting to set the octal permission of \'{oct(chmod_directory)}\' on directory \'{dir_name}\'')
|
||||||
f'Attempting to set the octal permission of \'{oct(chmod_directory)}\' on directory \'{dir_name}\'',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
nzb2media.rchmod(dir_name, chmod_directory)
|
nzb2media.rchmod(dir_name, chmod_directory)
|
||||||
else:
|
else:
|
||||||
logger.error(
|
log.error(f'FAILED: Transcoding failed for files in {dir_name}')
|
||||||
f'FAILED: Transcoding failed for files in {dir_name}', section,
|
|
||||||
)
|
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - Transcoding failed',
|
f'{section}: Failed to post-process - Transcoding failed',
|
||||||
)
|
)
|
||||||
|
@ -344,45 +316,31 @@ def process(
|
||||||
|
|
||||||
if status == 0:
|
if status == 0:
|
||||||
if section == 'NzbDrone' and not apikey:
|
if section == 'NzbDrone' and not apikey:
|
||||||
logger.info('No Sonarr apikey entered. Processing completed.')
|
log.info('No Sonarr apikey entered. Processing completed.')
|
||||||
return ProcessResult.success(
|
return ProcessResult.success(
|
||||||
f'{section}: Successfully post-processed {input_name}',
|
f'{section}: Successfully post-processed {input_name}',
|
||||||
)
|
)
|
||||||
logger.postprocess(
|
log.debug('SUCCESS: The download succeeded, sending a post-process request')
|
||||||
'SUCCESS: The download succeeded, sending a post-process request',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
nzb2media.FAILED = True
|
nzb2media.FAILED = True
|
||||||
if failure_link:
|
if failure_link:
|
||||||
report_nzb(failure_link, client_agent)
|
report_nzb(failure_link, client_agent)
|
||||||
if 'failed' in fork_params:
|
if 'failed' in fork_params:
|
||||||
logger.postprocess(
|
log.debug(f'FAILED: The download failed. Sending \'failed\' process request to {fork} branch')
|
||||||
f'FAILED: The download failed. Sending \'failed\' process request to {fork} branch',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
elif section == 'NzbDrone':
|
elif section == 'NzbDrone':
|
||||||
logger.postprocess(
|
log.debug(f'FAILED: The download failed. Sending failed download to {fork} for CDH processing')
|
||||||
f'FAILED: The download failed. Sending failed download to {fork} for CDH processing',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
# Return as failed to flag this in the downloader.
|
# Return as failed to flag this in the downloader.
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Download Failed. Sending back to {section}',
|
f'{section}: Download Failed. Sending back to {section}',
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.postprocess(
|
log.debug(f'FAILED: The download failed. {fork} branch does not handle failed downloads. Nothing to process')
|
||||||
f'FAILED: The download failed. {fork} branch does not handle failed downloads. Nothing to process',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
if (
|
if (
|
||||||
delete_failed
|
delete_failed
|
||||||
and os.path.isdir(dir_name)
|
and os.path.isdir(dir_name)
|
||||||
and not os.path.dirname(dir_name) == dir_name
|
and not os.path.dirname(dir_name) == dir_name
|
||||||
):
|
):
|
||||||
logger.postprocess(
|
log.debug(f'Deleting failed files and folder {dir_name}')
|
||||||
f'Deleting failed files and folder {dir_name}', section,
|
|
||||||
)
|
|
||||||
remove_dir(dir_name)
|
remove_dir(dir_name)
|
||||||
# Return as failed to flag this in the downloader.
|
# Return as failed to flag this in the downloader.
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
|
@ -411,7 +369,7 @@ def process(
|
||||||
headers = {'X-Api-Key': apikey}
|
headers = {'X-Api-Key': apikey}
|
||||||
# params = {'sortKey': 'series.title', 'page': 1, 'pageSize': 1, 'sortDir': 'asc'}
|
# params = {'sortKey': 'series.title', 'page': 1, 'pageSize': 1, 'sortDir': 'asc'}
|
||||||
if remote_path:
|
if remote_path:
|
||||||
logger.debug(f'remote_path: {remote_dir(dir_name)}', section)
|
log.debug(f'remote_path: {remote_dir(dir_name)}')
|
||||||
data = {
|
data = {
|
||||||
'name': 'DownloadedEpisodesScan',
|
'name': 'DownloadedEpisodesScan',
|
||||||
'path': remote_dir(dir_name),
|
'path': remote_dir(dir_name),
|
||||||
|
@ -419,7 +377,7 @@ def process(
|
||||||
'importMode': import_mode,
|
'importMode': import_mode,
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
logger.debug(f'path: {dir_name}', section)
|
log.debug(f'path: {dir_name}')
|
||||||
data = {
|
data = {
|
||||||
'name': 'DownloadedEpisodesScan',
|
'name': 'DownloadedEpisodesScan',
|
||||||
'path': dir_name,
|
'path': dir_name,
|
||||||
|
@ -436,15 +394,14 @@ def process(
|
||||||
else:
|
else:
|
||||||
s = requests.Session()
|
s = requests.Session()
|
||||||
|
|
||||||
logger.debug(
|
log.debug(f'Opening URL: {url} with params: {fork_params}', section,
|
||||||
f'Opening URL: {url} with params: {fork_params}', section,
|
|
||||||
)
|
)
|
||||||
if not apikey and username and password:
|
if not apikey and username and password:
|
||||||
login = f'{web_root}/login'
|
login = f'{web_root}/login'
|
||||||
login_params = {'username': username, 'password': password}
|
login_params = {'username': username, 'password': password}
|
||||||
r = s.get(login, verify=False, timeout=(30, 60))
|
response = s.get(login, verify=False, timeout=(30, 60))
|
||||||
if r.status_code in [401, 403] and r.cookies.get('_xsrf'):
|
if response.status_code in [401, 403] and response.cookies.get('_xsrf'):
|
||||||
login_params['_xsrf'] = r.cookies.get('_xsrf')
|
login_params['_xsrf'] = response.cookies.get('_xsrf')
|
||||||
s.post(
|
s.post(
|
||||||
login,
|
login,
|
||||||
data=login_params,
|
data=login_params,
|
||||||
|
@ -452,7 +409,7 @@ def process(
|
||||||
verify=False,
|
verify=False,
|
||||||
timeout=(30, 60),
|
timeout=(30, 60),
|
||||||
)
|
)
|
||||||
r = s.get(
|
response = s.get(
|
||||||
url,
|
url,
|
||||||
auth=(username, password),
|
auth=(username, password),
|
||||||
params=fork_params,
|
params=fork_params,
|
||||||
|
@ -496,7 +453,7 @@ def process(
|
||||||
else:
|
else:
|
||||||
params = fork_params
|
params = fork_params
|
||||||
|
|
||||||
r = s.get(
|
response = s.get(
|
||||||
url,
|
url,
|
||||||
params=params,
|
params=params,
|
||||||
stream=True,
|
stream=True,
|
||||||
|
@ -504,8 +461,8 @@ def process(
|
||||||
timeout=(30, 1800),
|
timeout=(30, 1800),
|
||||||
)
|
)
|
||||||
elif section == 'NzbDrone':
|
elif section == 'NzbDrone':
|
||||||
logger.debug(f'Opening URL: {url} with data: {data}', section)
|
log.debug(f'Opening URL: {url} with data: {data}')
|
||||||
r = requests.post(
|
response = requests.post(
|
||||||
url,
|
url,
|
||||||
data=json.dumps(data),
|
data=json.dumps(data),
|
||||||
headers=headers,
|
headers=headers,
|
||||||
|
@ -514,21 +471,21 @@ def process(
|
||||||
timeout=(30, 1800),
|
timeout=(30, 1800),
|
||||||
)
|
)
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.error(f'Unable to open URL: {url}', section)
|
log.error(f'Unable to open URL: {url}')
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - Unable to connect to '
|
f'{section}: Failed to post-process - Unable to connect to '
|
||||||
f'{section}',
|
f'{section}',
|
||||||
)
|
)
|
||||||
|
|
||||||
if r.status_code not in [
|
if response.status_code not in [
|
||||||
requests.codes.ok,
|
requests.codes.ok,
|
||||||
requests.codes.created,
|
requests.codes.created,
|
||||||
requests.codes.accepted,
|
requests.codes.accepted,
|
||||||
]:
|
]:
|
||||||
logger.error(f'Server returned status {r.status_code}', section)
|
log.error(f'Server returned status {response.status_code}')
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process - Server returned status '
|
f'{section}: Failed to post-process - Server returned status '
|
||||||
f'{r.status_code}',
|
f'{response.status_code}',
|
||||||
)
|
)
|
||||||
|
|
||||||
success = False
|
success = False
|
||||||
|
@ -536,13 +493,13 @@ def process(
|
||||||
started = False
|
started = False
|
||||||
if section == 'SickBeard':
|
if section == 'SickBeard':
|
||||||
if apikey:
|
if apikey:
|
||||||
if r.json()['result'] == 'success':
|
if response.json()['result'] == 'success':
|
||||||
success = True
|
success = True
|
||||||
else:
|
else:
|
||||||
for line in r.iter_lines():
|
for line in response.iter_lines():
|
||||||
if line:
|
if line:
|
||||||
line = line.decode('utf-8')
|
line = line.decode('utf-8')
|
||||||
logger.postprocess(line, section)
|
log.debug(line)
|
||||||
if 'Moving file from' in line:
|
if 'Moving file from' in line:
|
||||||
input_name = os.path.split(line)[1]
|
input_name = os.path.split(line)[1]
|
||||||
if 'added to the queue' in line:
|
if 'added to the queue' in line:
|
||||||
|
@ -559,16 +516,16 @@ def process(
|
||||||
if api_version >= 2:
|
if api_version >= 2:
|
||||||
success = True
|
success = True
|
||||||
else:
|
else:
|
||||||
if r.json()['result'] == 'success':
|
if response.json()['result'] == 'success':
|
||||||
success = True
|
success = True
|
||||||
elif section == 'NzbDrone':
|
elif section == 'NzbDrone':
|
||||||
try:
|
try:
|
||||||
res = r.json()
|
res = response.json()
|
||||||
scan_id = int(res['id'])
|
scan_id = int(res['id'])
|
||||||
logger.debug(f'Scan started with id: {scan_id}', section)
|
log.debug(f'Scan started with id: {scan_id}')
|
||||||
started = True
|
started = True
|
||||||
except Exception as e:
|
except Exception as error:
|
||||||
logger.warning(f'No scan id was returned due to: {e}', section)
|
log.warning(f'No scan id was returned due to: {error}')
|
||||||
scan_id = None
|
scan_id = None
|
||||||
started = False
|
started = False
|
||||||
|
|
||||||
|
@ -577,9 +534,7 @@ def process(
|
||||||
and delete_failed
|
and delete_failed
|
||||||
and not os.path.dirname(dir_name) == dir_name
|
and not os.path.dirname(dir_name) == dir_name
|
||||||
):
|
):
|
||||||
logger.postprocess(
|
log.debug(f'Deleting failed files and folder {dir_name}')
|
||||||
f'Deleting failed files and folder {dir_name}', section,
|
|
||||||
)
|
|
||||||
remove_dir(dir_name)
|
remove_dir(dir_name)
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
|
@ -597,50 +552,33 @@ def process(
|
||||||
break
|
break
|
||||||
n += 1
|
n += 1
|
||||||
if command_status:
|
if command_status:
|
||||||
logger.debug(
|
log.debug(f'The Scan command return status: {command_status}')
|
||||||
f'The Scan command return status: {command_status}', section,
|
|
||||||
)
|
|
||||||
if not os.path.exists(dir_name):
|
if not os.path.exists(dir_name):
|
||||||
logger.debug(
|
log.debug(f'The directory {dir_name} has been removed. Renaming was successful.')
|
||||||
f'The directory {dir_name} has been removed. Renaming was successful.',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult.success(
|
return ProcessResult.success(
|
||||||
f'{section}: Successfully post-processed {input_name}',
|
f'{section}: Successfully post-processed {input_name}',
|
||||||
)
|
)
|
||||||
elif command_status and command_status in ['completed']:
|
elif command_status and command_status in ['completed']:
|
||||||
logger.debug(
|
log.debug('The Scan command has completed successfully. Renaming was successful.')
|
||||||
'The Scan command has completed successfully. Renaming was successful.',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult.success(
|
return ProcessResult.success(
|
||||||
f'{section}: Successfully post-processed {input_name}',
|
f'{section}: Successfully post-processed {input_name}',
|
||||||
)
|
)
|
||||||
elif command_status and command_status in ['failed']:
|
elif command_status and command_status in ['failed']:
|
||||||
logger.debug(
|
log.debug('The Scan command has failed. Renaming was not successful.')
|
||||||
'The Scan command has failed. Renaming was not successful.',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
# return ProcessResult.failure(
|
# return ProcessResult.failure(
|
||||||
# f'{section}: Failed to post-process {input_name}'
|
# f'{section}: Failed to post-process {input_name}'
|
||||||
# )
|
# )
|
||||||
|
|
||||||
url2 = nzb2media.utils.common.create_url(scheme, host, port, route)
|
url2 = nzb2media.utils.common.create_url(scheme, host, port, route)
|
||||||
if completed_download_handling(url2, headers, section=section):
|
if completed_download_handling(url2, headers, section=section):
|
||||||
logger.debug(
|
log.debug(f'The Scan command did not return status completed, but complete Download Handling is enabled. Passing back to {section}.')
|
||||||
f'The Scan command did not return status completed, but complete Download Handling is enabled. Passing back to {section}.',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
message=f'{section}: Complete DownLoad Handling is enabled. '
|
message=f'{section}: Complete DownLoad Handling is enabled. '
|
||||||
f'Passing back to {section}',
|
f'Passing back to {section}',
|
||||||
status_code=status,
|
status_code=status,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
log.warning('The Scan command did not return a valid status. Renaming was not successful.')
|
||||||
'The Scan command did not return a valid status. Renaming was not successful.',
|
|
||||||
section,
|
|
||||||
)
|
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{section}: Failed to post-process {input_name}',
|
f'{section}: Failed to post-process {input_name}',
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
@ -8,12 +9,15 @@ from itertools import chain
|
||||||
import configobj
|
import configobj
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
class Section(configobj.Section):
|
class Section(configobj.Section):
|
||||||
def isenabled(self):
|
def isenabled(self):
|
||||||
# checks if subsection enabled, returns true/false if subsection specified otherwise returns true/false in {}
|
# checks if subsection enabled, returns true/false if subsection
|
||||||
|
# specified otherwise returns true/false in {}
|
||||||
if not self.sections:
|
if not self.sections:
|
||||||
try:
|
try:
|
||||||
value = list(ConfigObj.find_key(self, 'enabled'))[0]
|
value = list(ConfigObj.find_key(self, 'enabled'))[0]
|
||||||
|
@ -119,7 +123,7 @@ class ConfigObj(configobj.ConfigObj, Section):
|
||||||
shutil.copyfile(nzb2media.CONFIG_SPEC_FILE, nzb2media.CONFIG_FILE)
|
shutil.copyfile(nzb2media.CONFIG_SPEC_FILE, nzb2media.CONFIG_FILE)
|
||||||
CFG_OLD = config(nzb2media.CONFIG_FILE)
|
CFG_OLD = config(nzb2media.CONFIG_FILE)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.error(f'Error {error} when copying to .cfg')
|
log.error(f'Error {error} when copying to .cfg')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# check for autoProcessMedia.cfg.spec and create if it does not exist
|
# check for autoProcessMedia.cfg.spec and create if it does not exist
|
||||||
|
@ -127,7 +131,7 @@ class ConfigObj(configobj.ConfigObj, Section):
|
||||||
shutil.copyfile(nzb2media.CONFIG_FILE, nzb2media.CONFIG_SPEC_FILE)
|
shutil.copyfile(nzb2media.CONFIG_FILE, nzb2media.CONFIG_SPEC_FILE)
|
||||||
CFG_NEW = config(nzb2media.CONFIG_SPEC_FILE)
|
CFG_NEW = config(nzb2media.CONFIG_SPEC_FILE)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.error(f'Error {error} when copying to .spec')
|
log.error(f'Error {error} when copying to .spec')
|
||||||
|
|
||||||
# check for autoProcessMedia.cfg and autoProcessMedia.cfg.spec and if they don't exist return and fail
|
# check for autoProcessMedia.cfg and autoProcessMedia.cfg.spec and if they don't exist return and fail
|
||||||
if CFG_NEW is None or CFG_OLD is None:
|
if CFG_NEW is None or CFG_OLD is None:
|
||||||
|
@ -314,11 +318,7 @@ class ConfigObj(configobj.ConfigObj, Section):
|
||||||
os.environ['NZBPO_NDCATEGORY']
|
os.environ['NZBPO_NDCATEGORY']
|
||||||
== os.environ['NZBPO_SBCATEGORY']
|
== os.environ['NZBPO_SBCATEGORY']
|
||||||
):
|
):
|
||||||
logger.warning(
|
log.warning('{x} category is set for SickBeard and Sonarr. Please check your config in NZBGet'.format(x=os.environ['NZBPO_NDCATEGORY']))
|
||||||
'{x} category is set for SickBeard and Sonarr. Please check your config in NZBGet'.format(
|
|
||||||
x=os.environ['NZBPO_NDCATEGORY'],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
if (
|
if (
|
||||||
'NZBPO_RACATEGORY' in os.environ
|
'NZBPO_RACATEGORY' in os.environ
|
||||||
and 'NZBPO_CPSCATEGORY' in os.environ
|
and 'NZBPO_CPSCATEGORY' in os.environ
|
||||||
|
@ -327,11 +327,7 @@ class ConfigObj(configobj.ConfigObj, Section):
|
||||||
os.environ['NZBPO_RACATEGORY']
|
os.environ['NZBPO_RACATEGORY']
|
||||||
== os.environ['NZBPO_CPSCATEGORY']
|
== os.environ['NZBPO_CPSCATEGORY']
|
||||||
):
|
):
|
||||||
logger.warning(
|
log.warning('{x} category is set for CouchPotato and Radarr. Please check your config in NZBGet'.format(x=os.environ['NZBPO_RACATEGORY']))
|
||||||
'{x} category is set for CouchPotato and Radarr. Please check your config in NZBGet'.format(
|
|
||||||
x=os.environ['NZBPO_RACATEGORY'],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
if (
|
if (
|
||||||
'NZBPO_RACATEGORY' in os.environ
|
'NZBPO_RACATEGORY' in os.environ
|
||||||
and 'NZBPO_W3CATEGORY' in os.environ
|
and 'NZBPO_W3CATEGORY' in os.environ
|
||||||
|
@ -340,11 +336,7 @@ class ConfigObj(configobj.ConfigObj, Section):
|
||||||
os.environ['NZBPO_RACATEGORY']
|
os.environ['NZBPO_RACATEGORY']
|
||||||
== os.environ['NZBPO_W3CATEGORY']
|
== os.environ['NZBPO_W3CATEGORY']
|
||||||
):
|
):
|
||||||
logger.warning(
|
log.warning('{x} category is set for Watcher3 and Radarr. Please check your config in NZBGet'.format(x=os.environ['NZBPO_RACATEGORY']))
|
||||||
'{x} category is set for Watcher3 and Radarr. Please check your config in NZBGet'.format(
|
|
||||||
x=os.environ['NZBPO_RACATEGORY'],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
if (
|
if (
|
||||||
'NZBPO_W3CATEGORY' in os.environ
|
'NZBPO_W3CATEGORY' in os.environ
|
||||||
and 'NZBPO_CPSCATEGORY' in os.environ
|
and 'NZBPO_CPSCATEGORY' in os.environ
|
||||||
|
@ -353,11 +345,7 @@ class ConfigObj(configobj.ConfigObj, Section):
|
||||||
os.environ['NZBPO_W3CATEGORY']
|
os.environ['NZBPO_W3CATEGORY']
|
||||||
== os.environ['NZBPO_CPSCATEGORY']
|
== os.environ['NZBPO_CPSCATEGORY']
|
||||||
):
|
):
|
||||||
logger.warning(
|
log.warning('{x} category is set for CouchPotato and Watcher3. Please check your config in NZBGet'.format(x=os.environ['NZBPO_W3CATEGORY']))
|
||||||
'{x} category is set for CouchPotato and Watcher3. Please check your config in NZBGet'.format(
|
|
||||||
x=os.environ['NZBPO_W3CATEGORY'],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
if (
|
if (
|
||||||
'NZBPO_LICATEGORY' in os.environ
|
'NZBPO_LICATEGORY' in os.environ
|
||||||
and 'NZBPO_HPCATEGORY' in os.environ
|
and 'NZBPO_HPCATEGORY' in os.environ
|
||||||
|
@ -366,11 +354,7 @@ class ConfigObj(configobj.ConfigObj, Section):
|
||||||
os.environ['NZBPO_LICATEGORY']
|
os.environ['NZBPO_LICATEGORY']
|
||||||
== os.environ['NZBPO_HPCATEGORY']
|
== os.environ['NZBPO_HPCATEGORY']
|
||||||
):
|
):
|
||||||
logger.warning(
|
log.warning('{x} category is set for HeadPhones and Lidarr. Please check your config in NZBGet'.format(x=os.environ['NZBPO_LICATEGORY']))
|
||||||
'{x} category is set for HeadPhones and Lidarr. Please check your config in NZBGet'.format(
|
|
||||||
x=os.environ['NZBPO_LICATEGORY'],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
section = 'Nzb'
|
section = 'Nzb'
|
||||||
key = 'NZBOP_DESTDIR'
|
key = 'NZBOP_DESTDIR'
|
||||||
if key in os.environ:
|
if key in os.environ:
|
||||||
|
@ -1119,14 +1103,14 @@ class ConfigObj(configobj.ConfigObj, Section):
|
||||||
cfg_new[section][os.environ[env_cat_key]]['enabled'] = 1
|
cfg_new[section][os.environ[env_cat_key]]['enabled'] = 1
|
||||||
|
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.debug(f'Error {error} when applying NZBGet config')
|
log.debug(f'Error {error} when applying NZBGet config')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# write our new config to autoProcessMedia.cfg
|
# write our new config to autoProcessMedia.cfg
|
||||||
cfg_new.filename = nzb2media.CONFIG_FILE
|
cfg_new.filename = nzb2media.CONFIG_FILE
|
||||||
cfg_new.write()
|
cfg_new.write()
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.debug(f'Error {error} when writing changes to .cfg')
|
log.debug(f'Error {error} when writing changes to .cfg')
|
||||||
|
|
||||||
return cfg_new
|
return cfg_new
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,25 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from nzb2media import logger
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
from nzb2media import main_db
|
from nzb2media import main_db
|
||||||
from nzb2media.utils.files import backup_versioned_file
|
from nzb2media.utils.files import backup_versioned_file
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
MIN_DB_VERSION = 1 # oldest db version we support migrating from
|
MIN_DB_VERSION = 1 # oldest db version we support migrating from
|
||||||
MAX_DB_VERSION = 2
|
MAX_DB_VERSION = 2
|
||||||
|
|
||||||
|
|
||||||
def backup_database(version):
|
def backup_database(version):
|
||||||
logger.info('Backing up database before upgrade')
|
log.info('Backing up database before upgrade')
|
||||||
if not backup_versioned_file(main_db.db_filename(), version):
|
if not backup_versioned_file(main_db.db_filename(), version):
|
||||||
logger.log_error_and_exit(
|
logging.critical('Database backup failed, abort upgrading database')
|
||||||
'Database backup failed, abort upgrading database',
|
sys.exit(1)
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
logger.info('Proceeding with upgrade')
|
log.info('Proceeding with upgrade')
|
||||||
|
|
||||||
|
|
||||||
# ======================
|
# ======================
|
||||||
|
@ -48,14 +52,12 @@ class InitialSchema(main_db.SchemaUpgrade):
|
||||||
cur_db_version = self.check_db_version()
|
cur_db_version = self.check_db_version()
|
||||||
|
|
||||||
if cur_db_version < MIN_DB_VERSION:
|
if cur_db_version < MIN_DB_VERSION:
|
||||||
logger.log_error_and_exit(
|
log.critical(f'Your database version ({cur_db_version}) is too old to migrate from what this version of nzbToMedia supports ({MIN_DB_VERSION}).\nPlease remove nzbtomedia.db file to begin fresh.')
|
||||||
f'Your database version ({cur_db_version}) is too old to migrate from what this version of nzbToMedia supports ({MIN_DB_VERSION}).\nPlease remove nzbtomedia.db file to begin fresh.',
|
sys.exit(1)
|
||||||
)
|
|
||||||
|
|
||||||
if cur_db_version > MAX_DB_VERSION:
|
if cur_db_version > MAX_DB_VERSION:
|
||||||
logger.log_error_and_exit(
|
log.critical(f'Your database version ({cur_db_version}) has been incremented past what this version of nzbToMedia supports ({MAX_DB_VERSION}).\nIf you have used other forks of nzbToMedia, your database may be unusable due to their modifications.')
|
||||||
f'Your database version ({cur_db_version}) has been incremented past what this version of nzbToMedia supports ({MAX_DB_VERSION}).\nIf you have used other forks of nzbToMedia, your database may be unusable due to their modifications.',
|
sys.exit(1)
|
||||||
)
|
|
||||||
if cur_db_version < MAX_DB_VERSION: # We need to upgrade.
|
if cur_db_version < MAX_DB_VERSION: # We need to upgrade.
|
||||||
queries = [
|
queries = [
|
||||||
'CREATE TABLE downloads2 (input_directory TEXT, input_name TEXT, input_hash TEXT, input_id TEXT, client_agent TEXT, status INTEGER, last_update NUMERIC, CONSTRAINT pk_downloadID PRIMARY KEY (input_directory, input_name));',
|
'CREATE TABLE downloads2 (input_directory TEXT, input_name TEXT, input_hash TEXT, input_id TEXT, client_agent TEXT, status INTEGER, last_update NUMERIC, CONSTRAINT pk_downloadID PRIMARY KEY (input_directory, input_name));',
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import shutil
|
import shutil
|
||||||
|
@ -11,13 +12,16 @@ from time import sleep
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def extract(file_path, output_destination):
|
def extract(file_path, output_destination):
|
||||||
success = 0
|
success = 0
|
||||||
# Using Windows
|
# Using Windows
|
||||||
if platform.system() == 'Windows':
|
if platform.system() == 'Windows':
|
||||||
if not os.path.exists(nzb2media.SEVENZIP):
|
if not os.path.exists(nzb2media.SEVENZIP):
|
||||||
nzb2media.logger.error('EXTRACTOR: Could not find 7-zip, Exiting')
|
log.error('EXTRACTOR: Could not find 7-zip, Exiting')
|
||||||
return False
|
return False
|
||||||
wscriptlocation = os.path.join(
|
wscriptlocation = os.path.join(
|
||||||
os.environ['WINDIR'], 'system32', 'wscript.exe',
|
os.environ['WINDIR'], 'system32', 'wscript.exe',
|
||||||
|
@ -109,20 +113,14 @@ def extract(file_path, output_destination):
|
||||||
): # we do have '7za'
|
): # we do have '7za'
|
||||||
extract_commands[k] = ['7za', 'x', '-y']
|
extract_commands[k] = ['7za', 'x', '-y']
|
||||||
else:
|
else:
|
||||||
nzb2media.logger.error(
|
log.error(f'EXTRACTOR: {cmd} not found, disabling support for {k}')
|
||||||
f'EXTRACTOR: {cmd} not found, disabling support for {k}',
|
|
||||||
)
|
|
||||||
del extract_commands[k]
|
del extract_commands[k]
|
||||||
devnull.close()
|
devnull.close()
|
||||||
else:
|
else:
|
||||||
nzb2media.logger.warning(
|
log.warning('EXTRACTOR: Cannot determine which tool to use when called from Transmission')
|
||||||
'EXTRACTOR: Cannot determine which tool to use when called from Transmission',
|
|
||||||
)
|
|
||||||
|
|
||||||
if not extract_commands:
|
if not extract_commands:
|
||||||
nzb2media.logger.warning(
|
log.warning('EXTRACTOR: No archive extracting programs found, plugin will be disabled')
|
||||||
'EXTRACTOR: No archive extracting programs found, plugin will be disabled',
|
|
||||||
)
|
|
||||||
|
|
||||||
ext = os.path.splitext(file_path)
|
ext = os.path.splitext(file_path)
|
||||||
cmd = []
|
cmd = []
|
||||||
|
@ -150,7 +148,7 @@ def extract(file_path, output_destination):
|
||||||
if ext[1] in extract_commands:
|
if ext[1] in extract_commands:
|
||||||
cmd = extract_commands[ext[1]]
|
cmd = extract_commands[ext[1]]
|
||||||
else:
|
else:
|
||||||
nzb2media.logger.debug(f'EXTRACTOR: Unknown file type: {ext[1]}')
|
log.debug(f'EXTRACTOR: Unknown file type: {ext[1]}')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Create outputDestination folder
|
# Create outputDestination folder
|
||||||
|
@ -166,8 +164,8 @@ def extract(file_path, output_destination):
|
||||||
else:
|
else:
|
||||||
passwords = []
|
passwords = []
|
||||||
|
|
||||||
nzb2media.logger.info(f'Extracting {file_path} to {output_destination}')
|
log.info(f'Extracting {file_path} to {output_destination}')
|
||||||
nzb2media.logger.debug(f'Extracting {cmd} {file_path} {output_destination}')
|
log.debug(f'Extracting {cmd} {file_path} {output_destination}')
|
||||||
|
|
||||||
orig_files = []
|
orig_files = []
|
||||||
orig_dirs = []
|
orig_dirs = []
|
||||||
|
@ -192,19 +190,17 @@ def extract(file_path, output_destination):
|
||||||
else:
|
else:
|
||||||
cmd = nzb2media.NICENESS + cmd
|
cmd = nzb2media.NICENESS + cmd
|
||||||
cmd2 = cmd
|
cmd2 = cmd
|
||||||
if not 'gunzip' in cmd: # gunzip doesn't support password
|
if 'gunzip' not in cmd: # gunzip doesn't support password
|
||||||
cmd2.append('-p-') # don't prompt for password.
|
cmd2.append('-p-') # don't prompt for password.
|
||||||
p = Popen(
|
p = Popen(
|
||||||
cmd2, stdout=devnull, stderr=devnull, startupinfo=info,
|
cmd2, stdout=devnull, stderr=devnull, startupinfo=info,
|
||||||
) # should extract files fine.
|
) # should extract files fine.
|
||||||
res = p.wait()
|
res = p.wait()
|
||||||
if res == 0: # Both Linux and Windows return 0 for successful.
|
if res == 0: # Both Linux and Windows return 0 for successful.
|
||||||
nzb2media.logger.info(
|
log.info(f'EXTRACTOR: Extraction was successful for {file_path} to {output_destination}')
|
||||||
f'EXTRACTOR: Extraction was successful for {file_path} to {output_destination}',
|
|
||||||
)
|
|
||||||
success = 1
|
success = 1
|
||||||
elif len(passwords) > 0 and not 'gunzip' in cmd:
|
elif len(passwords) > 0 and not 'gunzip' in cmd:
|
||||||
nzb2media.logger.info('EXTRACTOR: Attempting to extract with passwords')
|
log.info('EXTRACTOR: Attempting to extract with passwords')
|
||||||
for password in passwords:
|
for password in passwords:
|
||||||
if (
|
if (
|
||||||
password == ''
|
password == ''
|
||||||
|
@ -219,17 +215,13 @@ def extract(file_path, output_destination):
|
||||||
) # should extract files fine.
|
) # should extract files fine.
|
||||||
res = p.wait()
|
res = p.wait()
|
||||||
if (res >= 0 and platform == 'Windows') or res == 0:
|
if (res >= 0 and platform == 'Windows') or res == 0:
|
||||||
nzb2media.logger.info(
|
log.info(f'EXTRACTOR: Extraction was successful for {file_path} to {output_destination} using password: {password}')
|
||||||
f'EXTRACTOR: Extraction was successful for {file_path} to {output_destination} using password: {password}',
|
|
||||||
)
|
|
||||||
success = 1
|
success = 1
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
except Exception:
|
except Exception:
|
||||||
nzb2media.logger.error(
|
log.error(f'EXTRACTOR: Extraction failed for {file_path}. Could not call command {cmd}')
|
||||||
f'EXTRACTOR: Extraction failed for {file_path}. Could not call command {cmd}',
|
|
||||||
)
|
|
||||||
os.chdir(pwd)
|
os.chdir(pwd)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -256,7 +248,5 @@ def extract(file_path, output_destination):
|
||||||
pass
|
pass
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
nzb2media.logger.error(
|
log.error(f'EXTRACTOR: Extraction failed for {file_path}. Result was {res}')
|
||||||
f'EXTRACTOR: Extraction failed for {file_path}. Result was {res}',
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -1,319 +0,0 @@
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import functools
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import threading
|
|
||||||
|
|
||||||
import nzb2media
|
|
||||||
|
|
||||||
# number of log files to keep
|
|
||||||
NUM_LOGS = 3
|
|
||||||
|
|
||||||
# log size in bytes
|
|
||||||
LOG_SIZE = 10000000 # 10 megs
|
|
||||||
|
|
||||||
ERROR = logging.ERROR
|
|
||||||
WARNING = logging.WARNING
|
|
||||||
MESSAGE = logging.INFO
|
|
||||||
DEBUG = logging.DEBUG
|
|
||||||
POSTPROCESS = 21
|
|
||||||
DB = 5
|
|
||||||
|
|
||||||
reverseNames = {
|
|
||||||
'ERROR': ERROR,
|
|
||||||
'WARNING': WARNING,
|
|
||||||
'INFO': MESSAGE,
|
|
||||||
'DEBUG': DEBUG,
|
|
||||||
'POSTPROCESS': POSTPROCESS,
|
|
||||||
'DB': DB,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class NTMRotatingLogHandler:
|
|
||||||
def __init__(self, log_file, num_files, num_bytes):
|
|
||||||
self.num_files = num_files
|
|
||||||
self.num_bytes = num_bytes
|
|
||||||
|
|
||||||
self.log_file = log_file
|
|
||||||
self.log_file_path = log_file
|
|
||||||
self.cur_handler = None
|
|
||||||
|
|
||||||
self.writes_since_check = 0
|
|
||||||
|
|
||||||
self.console_logging = True
|
|
||||||
self.log_lock = threading.Lock()
|
|
||||||
|
|
||||||
def close_log(self, handler=None):
|
|
||||||
if not handler:
|
|
||||||
handler = self.cur_handler
|
|
||||||
|
|
||||||
if handler:
|
|
||||||
ntm_logger = logging.getLogger('nzbtomedia')
|
|
||||||
pp_logger = logging.getLogger('postprocess')
|
|
||||||
db_logger = logging.getLogger('db')
|
|
||||||
|
|
||||||
ntm_logger.removeHandler(handler)
|
|
||||||
pp_logger.removeHandler(handler)
|
|
||||||
db_logger.removeHandler(handler)
|
|
||||||
|
|
||||||
handler.flush()
|
|
||||||
handler.close()
|
|
||||||
|
|
||||||
def init_logging(self, console_logging=True):
|
|
||||||
|
|
||||||
if console_logging:
|
|
||||||
self.console_logging = console_logging
|
|
||||||
|
|
||||||
old_handler = None
|
|
||||||
|
|
||||||
# get old handler in case we want to close it
|
|
||||||
if self.cur_handler:
|
|
||||||
old_handler = self.cur_handler
|
|
||||||
else:
|
|
||||||
# Add a new logging levels
|
|
||||||
logging.addLevelName(21, 'POSTPROCESS')
|
|
||||||
logging.addLevelName(5, 'DB')
|
|
||||||
|
|
||||||
# only start consoleLogging on first initialize
|
|
||||||
if self.console_logging:
|
|
||||||
# define a Handler which writes INFO messages or higher to the sys.stderr
|
|
||||||
console = logging.StreamHandler()
|
|
||||||
|
|
||||||
# log-level
|
|
||||||
console.setLevel(DB)
|
|
||||||
|
|
||||||
# set a format which is simpler for console use
|
|
||||||
console.setFormatter(
|
|
||||||
DispatchingFormatter(
|
|
||||||
{
|
|
||||||
'nzbtomedia': logging.Formatter(
|
|
||||||
'[%(asctime)s] [%(levelname)s]::%(message)s',
|
|
||||||
'%H:%M:%S',
|
|
||||||
),
|
|
||||||
'postprocess': logging.Formatter(
|
|
||||||
'[%(asctime)s] [%(levelname)s]::%(message)s',
|
|
||||||
'%H:%M:%S',
|
|
||||||
),
|
|
||||||
'db': logging.Formatter(
|
|
||||||
'[%(asctime)s] [%(levelname)s]::%(message)s',
|
|
||||||
'%H:%M:%S',
|
|
||||||
),
|
|
||||||
},
|
|
||||||
logging.Formatter('%(message)s'),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
# add the handler to the root logger
|
|
||||||
logging.getLogger('nzbtomedia').addHandler(console)
|
|
||||||
logging.getLogger('postprocess').addHandler(console)
|
|
||||||
logging.getLogger('db').addHandler(console)
|
|
||||||
|
|
||||||
self.log_file_path = os.path.join(nzb2media.LOG_DIR, self.log_file)
|
|
||||||
|
|
||||||
self.cur_handler = self._config_handler()
|
|
||||||
|
|
||||||
logging.getLogger('nzbtomedia').addHandler(self.cur_handler)
|
|
||||||
logging.getLogger('postprocess').addHandler(self.cur_handler)
|
|
||||||
logging.getLogger('db').addHandler(self.cur_handler)
|
|
||||||
|
|
||||||
logging.getLogger('nzbtomedia').setLevel(logging.DEBUG)
|
|
||||||
logging.getLogger('postprocess').setLevel(POSTPROCESS)
|
|
||||||
logging.getLogger('db').setLevel(DB)
|
|
||||||
|
|
||||||
# already logging in new log folder, close the old handler
|
|
||||||
if old_handler:
|
|
||||||
self.close_log(old_handler)
|
|
||||||
|
|
||||||
def _config_handler(self):
|
|
||||||
"""Configure a file handler to log at file_name and return it."""
|
|
||||||
file_handler = logging.FileHandler(
|
|
||||||
self.log_file_path, encoding='utf-8',
|
|
||||||
)
|
|
||||||
|
|
||||||
file_handler.setLevel(DB)
|
|
||||||
|
|
||||||
file_handler.setFormatter(
|
|
||||||
DispatchingFormatter(
|
|
||||||
{
|
|
||||||
'nzbtomedia': logging.Formatter(
|
|
||||||
'%(asctime)s %(levelname)-8s::%(message)s',
|
|
||||||
'%Y-%m-%d %H:%M:%S',
|
|
||||||
),
|
|
||||||
'postprocess': logging.Formatter(
|
|
||||||
'%(asctime)s %(levelname)-8s::%(message)s',
|
|
||||||
'%Y-%m-%d %H:%M:%S',
|
|
||||||
),
|
|
||||||
'db': logging.Formatter(
|
|
||||||
'%(asctime)s %(levelname)-8s::%(message)s',
|
|
||||||
'%Y-%m-%d %H:%M:%S',
|
|
||||||
),
|
|
||||||
},
|
|
||||||
logging.Formatter('%(message)s'),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
return file_handler
|
|
||||||
|
|
||||||
def _log_file_name(self, i):
|
|
||||||
"""
|
|
||||||
Return a numbered log file name depending on i.
|
|
||||||
|
|
||||||
If i==0 it just uses logName, if not it appends it to the extension
|
|
||||||
e.g. (blah.log.3 for i == 3)
|
|
||||||
|
|
||||||
i: Log number to ues
|
|
||||||
"""
|
|
||||||
return self.log_file_path + (f'.{i}' if i else '')
|
|
||||||
|
|
||||||
def _num_logs(self):
|
|
||||||
"""
|
|
||||||
Scan the log folder and figure out how many log files there are already on disk.
|
|
||||||
|
|
||||||
Returns: The number of the last used file (eg. mylog.log.3 would return 3). If there are no logs it returns -1
|
|
||||||
"""
|
|
||||||
cur_log = 0
|
|
||||||
while os.path.isfile(self._log_file_name(cur_log)):
|
|
||||||
cur_log += 1
|
|
||||||
return cur_log - 1
|
|
||||||
|
|
||||||
def _rotate_logs(self):
|
|
||||||
|
|
||||||
ntm_logger = logging.getLogger('nzbtomedia')
|
|
||||||
pp_logger = logging.getLogger('postprocess')
|
|
||||||
db_logger = logging.getLogger('db')
|
|
||||||
|
|
||||||
# delete the old handler
|
|
||||||
if self.cur_handler:
|
|
||||||
self.close_log()
|
|
||||||
|
|
||||||
# rename or delete all the old log files
|
|
||||||
for i in range(self._num_logs(), -1, -1):
|
|
||||||
cur_file_name = self._log_file_name(i)
|
|
||||||
try:
|
|
||||||
if i >= NUM_LOGS:
|
|
||||||
os.remove(cur_file_name)
|
|
||||||
else:
|
|
||||||
os.rename(cur_file_name, self._log_file_name(i + 1))
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# the new log handler will always be on the un-numbered .log file
|
|
||||||
new_file_handler = self._config_handler()
|
|
||||||
|
|
||||||
self.cur_handler = new_file_handler
|
|
||||||
|
|
||||||
ntm_logger.addHandler(new_file_handler)
|
|
||||||
pp_logger.addHandler(new_file_handler)
|
|
||||||
db_logger.addHandler(new_file_handler)
|
|
||||||
|
|
||||||
def log(self, to_log, log_level=MESSAGE, section='MAIN'):
|
|
||||||
|
|
||||||
with self.log_lock:
|
|
||||||
|
|
||||||
# check the size and see if we need to rotate
|
|
||||||
if self.writes_since_check >= 10:
|
|
||||||
if (
|
|
||||||
os.path.isfile(self.log_file_path)
|
|
||||||
and os.path.getsize(self.log_file_path) >= LOG_SIZE
|
|
||||||
):
|
|
||||||
self._rotate_logs()
|
|
||||||
self.writes_since_check = 0
|
|
||||||
else:
|
|
||||||
self.writes_since_check += 1
|
|
||||||
|
|
||||||
try:
|
|
||||||
message = f'{section.upper()}: {to_log}'
|
|
||||||
except UnicodeError:
|
|
||||||
message = (
|
|
||||||
f'{section.upper()}: Message contains non-utf-8 string'
|
|
||||||
)
|
|
||||||
|
|
||||||
out_line = message
|
|
||||||
|
|
||||||
ntm_logger = logging.getLogger('nzbtomedia')
|
|
||||||
pp_logger = logging.getLogger('postprocess')
|
|
||||||
db_logger = logging.getLogger('db')
|
|
||||||
pp_logger.postprocess = functools.partial(
|
|
||||||
pp_logger.log, POSTPROCESS,
|
|
||||||
)
|
|
||||||
db_logger.db = functools.partial(db_logger.log, DB)
|
|
||||||
try:
|
|
||||||
if log_level == DEBUG:
|
|
||||||
if nzb2media.LOG_DEBUG == 1:
|
|
||||||
ntm_logger.debug(out_line)
|
|
||||||
elif log_level == MESSAGE:
|
|
||||||
ntm_logger.info(out_line)
|
|
||||||
elif log_level == WARNING:
|
|
||||||
ntm_logger.warning(out_line)
|
|
||||||
elif log_level == ERROR:
|
|
||||||
ntm_logger.error(out_line)
|
|
||||||
elif log_level == POSTPROCESS:
|
|
||||||
pp_logger.postprocess(out_line)
|
|
||||||
elif log_level == DB:
|
|
||||||
if nzb2media.LOG_DB == 1:
|
|
||||||
db_logger.db(out_line)
|
|
||||||
else:
|
|
||||||
ntm_logger.info(log_level, out_line)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def log_error_and_exit(self, error_msg):
|
|
||||||
log(error_msg, ERROR)
|
|
||||||
|
|
||||||
if 'NZBOP_SCRIPTDIR' in os.environ:
|
|
||||||
sys.exit(nzb2media.NZBGET_POSTPROCESS_ERROR)
|
|
||||||
elif not self.console_logging:
|
|
||||||
sys.exit(error_msg.encode(nzb2media.SYS_ENCODING, 'xmlcharrefreplace'))
|
|
||||||
else:
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
class DispatchingFormatter:
|
|
||||||
def __init__(self, formatters, default_formatter):
|
|
||||||
self._formatters = formatters
|
|
||||||
self._default_formatter = default_formatter
|
|
||||||
|
|
||||||
def format(self, record):
|
|
||||||
formatter = self._formatters.get(record.name, self._default_formatter)
|
|
||||||
return formatter.format(record)
|
|
||||||
|
|
||||||
|
|
||||||
ntm_log_instance = NTMRotatingLogHandler(nzb2media.LOG_FILE, NUM_LOGS, LOG_SIZE)
|
|
||||||
|
|
||||||
|
|
||||||
def log(to_log, log_level=MESSAGE, section='MAIN'):
|
|
||||||
ntm_log_instance.log(to_log, log_level, section)
|
|
||||||
|
|
||||||
|
|
||||||
def info(to_log, section='MAIN'):
|
|
||||||
log(to_log, MESSAGE, section)
|
|
||||||
|
|
||||||
|
|
||||||
def error(to_log, section='MAIN'):
|
|
||||||
log(to_log, ERROR, section)
|
|
||||||
|
|
||||||
|
|
||||||
def warning(to_log, section='MAIN'):
|
|
||||||
log(to_log, WARNING, section)
|
|
||||||
|
|
||||||
|
|
||||||
def debug(to_log, section='MAIN'):
|
|
||||||
log(to_log, DEBUG, section)
|
|
||||||
|
|
||||||
|
|
||||||
def postprocess(to_log, section='POSTPROCESS'):
|
|
||||||
log(to_log, POSTPROCESS, section)
|
|
||||||
|
|
||||||
|
|
||||||
def db(to_log, section='DB'):
|
|
||||||
log(to_log, DB, section)
|
|
||||||
|
|
||||||
|
|
||||||
def log_error_and_exit(error_msg):
|
|
||||||
ntm_log_instance.log_error_and_exit(error_msg)
|
|
||||||
|
|
||||||
|
|
||||||
def close():
|
|
||||||
ntm_log_instance.close_log()
|
|
|
@ -1,11 +1,14 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import re
|
import re
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def db_filename(filename='nzbtomedia.db', suffix=None):
|
def db_filename(filename='nzbtomedia.db', suffix=None):
|
||||||
|
@ -53,15 +56,12 @@ class DBConnection:
|
||||||
while attempt < 5:
|
while attempt < 5:
|
||||||
try:
|
try:
|
||||||
if args is None:
|
if args is None:
|
||||||
logger.log(f'{self.filename}: {query}', logger.DB)
|
log.debug(f'{self.filename}: {query}')
|
||||||
cursor = self.connection.cursor()
|
cursor = self.connection.cursor()
|
||||||
cursor.execute(query)
|
cursor.execute(query)
|
||||||
sql_result = cursor.fetchone()[0]
|
sql_result = cursor.fetchone()[0]
|
||||||
else:
|
else:
|
||||||
logger.log(
|
log.debug(f'{self.filename}: {query} with args {args}')
|
||||||
f'{self.filename}: {query} with args {args}',
|
|
||||||
logger.DB,
|
|
||||||
)
|
|
||||||
cursor = self.connection.cursor()
|
cursor = self.connection.cursor()
|
||||||
cursor.execute(query, args)
|
cursor.execute(query, args)
|
||||||
sql_result = cursor.fetchone()[0]
|
sql_result = cursor.fetchone()[0]
|
||||||
|
@ -73,16 +73,14 @@ class DBConnection:
|
||||||
'unable to open database file' in error.args[0]
|
'unable to open database file' in error.args[0]
|
||||||
or 'database is locked' in error.args[0]
|
or 'database is locked' in error.args[0]
|
||||||
):
|
):
|
||||||
logger.log(f'DB error: {error}', logger.WARNING)
|
log.warning(f'DB error: {error}')
|
||||||
attempt += 1
|
attempt += 1
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
else:
|
else:
|
||||||
logger.log(f'DB error: {error}', logger.ERROR)
|
log.error(f'DB error: {error}')
|
||||||
raise
|
raise
|
||||||
except sqlite3.DatabaseError as error:
|
except sqlite3.DatabaseError as error:
|
||||||
logger.log(
|
log.error(f'Fatal error executing query: {error}')
|
||||||
f'Fatal error executing query: {error}', logger.ERROR,
|
|
||||||
)
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
return sql_result
|
return sql_result
|
||||||
|
@ -99,21 +97,16 @@ class DBConnection:
|
||||||
for qu in querylist:
|
for qu in querylist:
|
||||||
if len(qu) == 1:
|
if len(qu) == 1:
|
||||||
if log_transaction:
|
if log_transaction:
|
||||||
logger.log(qu[0], logger.DEBUG)
|
log.debug(qu[0])
|
||||||
sql_result.append(self.connection.execute(qu[0]))
|
sql_result.append(self.connection.execute(qu[0]))
|
||||||
elif len(qu) > 1:
|
elif len(qu) > 1:
|
||||||
if log_transaction:
|
if log_transaction:
|
||||||
logger.log(
|
log.debug(f'{qu[0]} with args {qu[1]}')
|
||||||
f'{qu[0]} with args {qu[1]}', logger.DEBUG,
|
|
||||||
)
|
|
||||||
sql_result.append(
|
sql_result.append(
|
||||||
self.connection.execute(qu[0], qu[1]),
|
self.connection.execute(qu[0], qu[1]),
|
||||||
)
|
)
|
||||||
self.connection.commit()
|
self.connection.commit()
|
||||||
logger.log(
|
log.debug(f'Transaction with {len(querylist)} query\'s executed')
|
||||||
f'Transaction with {len(querylist)} query\'s executed',
|
|
||||||
logger.DEBUG,
|
|
||||||
)
|
|
||||||
return sql_result
|
return sql_result
|
||||||
except sqlite3.OperationalError as error:
|
except sqlite3.OperationalError as error:
|
||||||
sql_result = []
|
sql_result = []
|
||||||
|
@ -123,18 +116,16 @@ class DBConnection:
|
||||||
'unable to open database file' in error.args[0]
|
'unable to open database file' in error.args[0]
|
||||||
or 'database is locked' in error.args[0]
|
or 'database is locked' in error.args[0]
|
||||||
):
|
):
|
||||||
logger.log(f'DB error: {error}', logger.WARNING)
|
log.warning(f'DB error: {error}')
|
||||||
attempt += 1
|
attempt += 1
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
else:
|
else:
|
||||||
logger.log(f'DB error: {error}', logger.ERROR)
|
log.error(f'DB error: {error}')
|
||||||
raise
|
raise
|
||||||
except sqlite3.DatabaseError as error:
|
except sqlite3.DatabaseError as error:
|
||||||
if self.connection:
|
if self.connection:
|
||||||
self.connection.rollback()
|
self.connection.rollback()
|
||||||
logger.log(
|
log.error(f'Fatal error executing query: {error}')
|
||||||
f'Fatal error executing query: {error}', logger.ERROR,
|
|
||||||
)
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
return sql_result
|
return sql_result
|
||||||
|
@ -149,13 +140,10 @@ class DBConnection:
|
||||||
while attempt < 5:
|
while attempt < 5:
|
||||||
try:
|
try:
|
||||||
if args is None:
|
if args is None:
|
||||||
logger.log(f'{self.filename}: {query}', logger.DB)
|
log.debug(f'{self.filename}: {query}')
|
||||||
sql_result = self.connection.execute(query)
|
sql_result = self.connection.execute(query)
|
||||||
else:
|
else:
|
||||||
logger.log(
|
log.debug(f'{self.filename}: {query} with args {args}')
|
||||||
f'{self.filename}: {query} with args {args}',
|
|
||||||
logger.DB,
|
|
||||||
)
|
|
||||||
sql_result = self.connection.execute(query, args)
|
sql_result = self.connection.execute(query, args)
|
||||||
self.connection.commit()
|
self.connection.commit()
|
||||||
# get out of the connection attempt loop since we were successful
|
# get out of the connection attempt loop since we were successful
|
||||||
|
@ -165,16 +153,14 @@ class DBConnection:
|
||||||
'unable to open database file' in error.args[0]
|
'unable to open database file' in error.args[0]
|
||||||
or 'database is locked' in error.args[0]
|
or 'database is locked' in error.args[0]
|
||||||
):
|
):
|
||||||
logger.log(f'DB error: {error}', logger.WARNING)
|
log.warning(f'DB error: {error}')
|
||||||
attempt += 1
|
attempt += 1
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
else:
|
else:
|
||||||
logger.log(f'DB error: {error}', logger.ERROR)
|
log.error(f'DB error: {error}')
|
||||||
raise
|
raise
|
||||||
except sqlite3.DatabaseError as error:
|
except sqlite3.DatabaseError as error:
|
||||||
logger.log(
|
log.error(f'Fatal error executing query: {error}')
|
||||||
f'Fatal error executing query: {error}', logger.ERROR,
|
|
||||||
)
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
return sql_result
|
return sql_result
|
||||||
|
@ -240,7 +226,7 @@ class DBSanityCheck:
|
||||||
|
|
||||||
|
|
||||||
def upgrade_database(connection, schema):
|
def upgrade_database(connection, schema):
|
||||||
logger.log('Checking database structure...', logger.MESSAGE)
|
log.info('Checking database structure...')
|
||||||
_process_upgrade(connection, schema)
|
_process_upgrade(connection, schema)
|
||||||
|
|
||||||
|
|
||||||
|
@ -252,15 +238,9 @@ def pretty_name(class_name):
|
||||||
|
|
||||||
def _process_upgrade(connection, upgrade_class):
|
def _process_upgrade(connection, upgrade_class):
|
||||||
instance = upgrade_class(connection)
|
instance = upgrade_class(connection)
|
||||||
logger.log(
|
log.debug(f'Checking {pretty_name(upgrade_class.__name__)} database upgrade')
|
||||||
f'Checking {pretty_name(upgrade_class.__name__)} database upgrade',
|
|
||||||
logger.DEBUG,
|
|
||||||
)
|
|
||||||
if not instance.test():
|
if not instance.test():
|
||||||
logger.log(
|
log.info(f'Database upgrade required: {pretty_name(upgrade_class.__name__)}')
|
||||||
f'Database upgrade required: {pretty_name(upgrade_class.__name__)}',
|
|
||||||
logger.MESSAGE,
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
instance.execute()
|
instance.execute()
|
||||||
except sqlite3.DatabaseError as error:
|
except sqlite3.DatabaseError as error:
|
||||||
|
@ -268,15 +248,9 @@ def _process_upgrade(connection, upgrade_class):
|
||||||
f'Error in {upgrade_class.__name__}: {error}',
|
f'Error in {upgrade_class.__name__}: {error}',
|
||||||
)
|
)
|
||||||
raise
|
raise
|
||||||
logger.log(
|
log.debug(f'{upgrade_class.__name__} upgrade completed')
|
||||||
f'{upgrade_class.__name__} upgrade completed',
|
|
||||||
logger.DEBUG,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
logger.log(
|
log.debug(f'{upgrade_class.__name__} upgrade not required')
|
||||||
f'{upgrade_class.__name__} upgrade not required',
|
|
||||||
logger.DEBUG,
|
|
||||||
)
|
|
||||||
|
|
||||||
for upgradeSubClass in upgrade_class.__subclasses__():
|
for upgradeSubClass in upgrade_class.__subclasses__():
|
||||||
_process_upgrade(connection, upgradeSubClass)
|
_process_upgrade(connection, upgradeSubClass)
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
import nzb2media.utils.common
|
import nzb2media.utils.common
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media.auto_process.common import ProcessResult
|
from nzb2media.auto_process.common import ProcessResult
|
||||||
from nzb2media.managers.sickbeard import SickBeard
|
from nzb2media.managers.sickbeard import SickBeard
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
class PyMedusa(SickBeard):
|
class PyMedusa(SickBeard):
|
||||||
"""PyMedusa class."""
|
"""PyMedusa class."""
|
||||||
|
@ -39,10 +42,7 @@ class PyMedusaApiV1(SickBeard):
|
||||||
|
|
||||||
def api_call(self) -> ProcessResult:
|
def api_call(self) -> ProcessResult:
|
||||||
self._process_fork_prarams()
|
self._process_fork_prarams()
|
||||||
logger.debug(
|
log.debug(f'Opening URL: {self.url} with params: {self.sb_init.fork_params}')
|
||||||
f'Opening URL: {self.url} with params: {self.sb_init.fork_params}',
|
|
||||||
self.sb_init.section,
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
response = self.session.get(
|
response = self.session.get(
|
||||||
self.url,
|
self.url,
|
||||||
|
@ -53,10 +53,7 @@ class PyMedusaApiV1(SickBeard):
|
||||||
timeout=(30, 1800),
|
timeout=(30, 1800),
|
||||||
)
|
)
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.error(
|
log.error(f'Unable to open URL: {self.url}')
|
||||||
f'Unable to open URL: {self.url}',
|
|
||||||
self.sb_init.section,
|
|
||||||
)
|
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{self.sb_init.section}: Failed to post-process - Unable to '
|
f'{self.sb_init.section}: Failed to post-process - Unable to '
|
||||||
f'connect to {self.sb_init.section}',
|
f'connect to {self.sb_init.section}',
|
||||||
|
@ -68,10 +65,7 @@ class PyMedusaApiV1(SickBeard):
|
||||||
requests.codes.accepted,
|
requests.codes.accepted,
|
||||||
]
|
]
|
||||||
if response.status_code not in successful_status_codes:
|
if response.status_code not in successful_status_codes:
|
||||||
logger.error(
|
log.error(f'Server returned status {response.status_code}')
|
||||||
f'Server returned status {response.status_code}',
|
|
||||||
self.sb_init.section,
|
|
||||||
)
|
|
||||||
result = ProcessResult.failure(
|
result = ProcessResult.failure(
|
||||||
f'{self.sb_init.section}: Failed to post-process - Server '
|
f'{self.sb_init.section}: Failed to post-process - Server '
|
||||||
f'returned status {response.status_code}',
|
f'returned status {response.status_code}',
|
||||||
|
@ -99,7 +93,7 @@ class PyMedusaApiV2(SickBeard):
|
||||||
# Check for an apikey
|
# Check for an apikey
|
||||||
# This is required with using fork = medusa-apiv2
|
# This is required with using fork = medusa-apiv2
|
||||||
if not sb_init.apikey:
|
if not sb_init.apikey:
|
||||||
logger.error(
|
log.error(
|
||||||
'For the section SickBeard `fork = medusa-apiv2` you also '
|
'For the section SickBeard `fork = medusa-apiv2` you also '
|
||||||
'need to configure an `apikey`',
|
'need to configure an `apikey`',
|
||||||
)
|
)
|
||||||
|
@ -120,10 +114,7 @@ class PyMedusaApiV2(SickBeard):
|
||||||
try:
|
try:
|
||||||
response = self.session.get(url, verify=False, timeout=(30, 1800))
|
response = self.session.get(url, verify=False, timeout=(30, 1800))
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.error(
|
log.error('Unable to get postprocess identifier status')
|
||||||
'Unable to get postprocess identifier status',
|
|
||||||
self.sb_init.section,
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -135,7 +126,7 @@ class PyMedusaApiV2(SickBeard):
|
||||||
|
|
||||||
def api_call(self) -> ProcessResult:
|
def api_call(self) -> ProcessResult:
|
||||||
self._process_fork_prarams()
|
self._process_fork_prarams()
|
||||||
logger.debug(f'Opening URL: {self.url}', self.sb_init.section)
|
log.debug(f'Opening URL: {self.url}')
|
||||||
payload = self.sb_init.fork_params
|
payload = self.sb_init.fork_params
|
||||||
payload['resource'] = self.sb_init.fork_params['nzbName']
|
payload['resource'] = self.sb_init.fork_params['nzbName']
|
||||||
del payload['nzbName']
|
del payload['nzbName']
|
||||||
|
@ -156,10 +147,7 @@ class PyMedusaApiV2(SickBeard):
|
||||||
timeout=(30, 1800),
|
timeout=(30, 1800),
|
||||||
)
|
)
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.error(
|
log.error('Unable to send postprocess request')
|
||||||
'Unable to send postprocess request',
|
|
||||||
self.sb_init.section,
|
|
||||||
)
|
|
||||||
return ProcessResult.failure(
|
return ProcessResult.failure(
|
||||||
f'{self.sb_init.section}: Unable to send postprocess request '
|
f'{self.sb_init.section}: Unable to send postprocess request '
|
||||||
f'to PyMedusa',
|
f'to PyMedusa',
|
||||||
|
@ -170,7 +158,7 @@ class PyMedusaApiV2(SickBeard):
|
||||||
try:
|
try:
|
||||||
jdata = response.json()
|
jdata = response.json()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logger.debug('No data returned from provider')
|
log.debug('No data returned from provider')
|
||||||
return ProcessResult.failure('No data returned from provider')
|
return ProcessResult.failure('No data returned from provider')
|
||||||
else:
|
else:
|
||||||
jdata = {}
|
jdata = {}
|
||||||
|
@ -197,7 +185,7 @@ class PyMedusaApiV2(SickBeard):
|
||||||
# Log Medusa's PP logs here.
|
# Log Medusa's PP logs here.
|
||||||
if response.get('output'):
|
if response.get('output'):
|
||||||
for line in response['output']:
|
for line in response['output']:
|
||||||
logger.postprocess(line, self.sb_init.section)
|
log.postprocess(line)
|
||||||
|
|
||||||
# For now this will most likely always be True.
|
# For now this will most likely always be True.
|
||||||
# In the future we could return an exit state for when the PP in
|
# In the future we could return an exit state for when the PP in
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
import logging
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from oauthlib.oauth2 import LegacyApplicationClient
|
from oauthlib.oauth2 import LegacyApplicationClient
|
||||||
from requests_oauthlib import OAuth2Session
|
from requests_oauthlib import OAuth2Session
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media.auto_process.common import ProcessResult
|
from nzb2media.auto_process.common import ProcessResult
|
||||||
from nzb2media.utils.paths import remote_dir
|
from nzb2media.utils.paths import remote_dir
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
class InitSickBeard:
|
class InitSickBeard:
|
||||||
"""SickBeard init class.
|
"""SickBeard init class.
|
||||||
|
@ -61,7 +64,7 @@ class InitSickBeard:
|
||||||
# config settings
|
# config settings
|
||||||
if nzb2media.FORK_SET:
|
if nzb2media.FORK_SET:
|
||||||
# keep using determined fork for multiple (manual) post-processing
|
# keep using determined fork for multiple (manual) post-processing
|
||||||
logger.info(
|
log.info(
|
||||||
f'{self.section}:{self.input_category} fork already set to '
|
f'{self.section}:{self.input_category} fork already set to '
|
||||||
f'{nzb2media.FORK_SET[0]}',
|
f'{nzb2media.FORK_SET[0]}',
|
||||||
)
|
)
|
||||||
|
@ -88,7 +91,7 @@ class InitSickBeard:
|
||||||
protocol = 'https://' if self.ssl else 'http://'
|
protocol = 'https://' if self.ssl else 'http://'
|
||||||
|
|
||||||
if self.section == 'NzbDrone':
|
if self.section == 'NzbDrone':
|
||||||
logger.info(f'Attempting to verify {self.input_category} fork')
|
log.info(f'Attempting to verify {self.input_category} fork')
|
||||||
url = nzb2media.utils.common.create_url(
|
url = nzb2media.utils.common.create_url(
|
||||||
scheme=protocol,
|
scheme=protocol,
|
||||||
host=self.host,
|
host=self.host,
|
||||||
|
@ -97,20 +100,20 @@ class InitSickBeard:
|
||||||
)
|
)
|
||||||
headers = {'X-Api-Key': self.apikey}
|
headers = {'X-Api-Key': self.apikey}
|
||||||
try:
|
try:
|
||||||
r = requests.get(
|
response = requests.get(
|
||||||
url,
|
url,
|
||||||
headers=headers,
|
headers=headers,
|
||||||
stream=True,
|
stream=True,
|
||||||
verify=False,
|
verify=False,
|
||||||
)
|
)
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.warning(
|
log.warning(
|
||||||
f'Could not connect to {self.section}:'
|
f'Could not connect to {self.section}:'
|
||||||
f'{self.input_category} to verify fork!',
|
f'{self.input_category} to verify fork!',
|
||||||
)
|
)
|
||||||
|
|
||||||
if not r.ok:
|
if not response.ok:
|
||||||
logger.warning(
|
log.warning(
|
||||||
f'Connection to {self.section}:{self.input_category} '
|
f'Connection to {self.section}:{self.input_category} '
|
||||||
f'failed! Check your configuration',
|
f'failed! Check your configuration',
|
||||||
)
|
)
|
||||||
|
@ -118,7 +121,7 @@ class InitSickBeard:
|
||||||
self.fork = ['default', {}]
|
self.fork = ['default', {}]
|
||||||
|
|
||||||
elif self.section == 'SiCKRAGE':
|
elif self.section == 'SiCKRAGE':
|
||||||
logger.info(f'Attempting to verify {self.input_category} fork')
|
log.info(f'Attempting to verify {self.input_category} fork')
|
||||||
|
|
||||||
if self.api_version >= 2:
|
if self.api_version >= 2:
|
||||||
url = nzb2media.utils.common.create_url(
|
url = nzb2media.utils.common.create_url(
|
||||||
|
@ -156,27 +159,27 @@ class InitSickBeard:
|
||||||
password=self.sso_password,
|
password=self.sso_password,
|
||||||
)
|
)
|
||||||
token = oauth_token['access_token']
|
token = oauth_token['access_token']
|
||||||
r = requests.get(
|
response = requests.get(
|
||||||
url,
|
url,
|
||||||
headers={f'Authorization': f'Bearer {token}'},
|
headers={f'Authorization': f'Bearer {token}'},
|
||||||
stream=True,
|
stream=True,
|
||||||
verify=False,
|
verify=False,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
r = requests.get(
|
response = requests.get(
|
||||||
url,
|
url,
|
||||||
params=api_params,
|
params=api_params,
|
||||||
stream=True,
|
stream=True,
|
||||||
verify=False,
|
verify=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
if not r.ok:
|
if not response.ok:
|
||||||
logger.warning(
|
log.warning(
|
||||||
f'Connection to {self.section}:{self.input_category} '
|
f'Connection to {self.section}:{self.input_category} '
|
||||||
f'failed! Check your configuration',
|
f'failed! Check your configuration',
|
||||||
)
|
)
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.warning(
|
log.warning(
|
||||||
f'Could not connect to {self.section}:'
|
f'Could not connect to {self.section}:'
|
||||||
f'{self.input_category} to verify API version!',
|
f'{self.input_category} to verify API version!',
|
||||||
)
|
)
|
||||||
|
@ -198,9 +201,7 @@ class InitSickBeard:
|
||||||
elif self.fork == 'auto':
|
elif self.fork == 'auto':
|
||||||
self.detect_fork()
|
self.detect_fork()
|
||||||
|
|
||||||
logger.info(
|
log.info(f'{self.section}:{self.input_category} fork set to {self.fork[0]}')
|
||||||
f'{self.section}:{self.input_category} fork set to {self.fork[0]}',
|
|
||||||
)
|
|
||||||
nzb2media.FORK_SET = self.fork
|
nzb2media.FORK_SET = self.fork
|
||||||
self.fork, self.fork_params = self.fork[0], self.fork[1]
|
self.fork, self.fork_params = self.fork[0], self.fork[1]
|
||||||
# This will create the fork object, and attach to self.fork_obj.
|
# This will create the fork object, and attach to self.fork_obj.
|
||||||
|
@ -212,15 +213,15 @@ class InitSickBeard:
|
||||||
try:
|
try:
|
||||||
json_data = r.json()
|
json_data = r.json()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logger.error('Failed to get JSON data from response')
|
log.error('Failed to get JSON data from response')
|
||||||
logger.debug('Response received')
|
log.debug('Response received')
|
||||||
raise
|
raise
|
||||||
|
|
||||||
try:
|
try:
|
||||||
json_data = json_data['data']
|
json_data = json_data['data']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.error('Failed to get data from JSON')
|
log.error('Failed to get data from JSON')
|
||||||
logger.debug(f'Response received: {json_data}')
|
log.debug(f'Response received: {json_data}')
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
if isinstance(json_data, str):
|
if isinstance(json_data, str):
|
||||||
|
@ -232,13 +233,11 @@ class InitSickBeard:
|
||||||
# Find excess parameters
|
# Find excess parameters
|
||||||
excess_parameters = set(params).difference(optional_parameters)
|
excess_parameters = set(params).difference(optional_parameters)
|
||||||
excess_parameters.remove('cmd') # Don't remove cmd from api params
|
excess_parameters.remove('cmd') # Don't remove cmd from api params
|
||||||
logger.debug(
|
log.debug(f'Removing excess parameters: ' f'{sorted(excess_parameters)}')
|
||||||
f'Removing excess parameters: ' f'{sorted(excess_parameters)}',
|
|
||||||
)
|
|
||||||
rem_params.extend(excess_parameters)
|
rem_params.extend(excess_parameters)
|
||||||
return rem_params, True
|
return rem_params, True
|
||||||
except:
|
except:
|
||||||
logger.error('Failed to identify optionalParameters')
|
log.error('Failed to identify optionalParameters')
|
||||||
return rem_params, False
|
return rem_params, False
|
||||||
|
|
||||||
def detect_fork(self):
|
def detect_fork(self):
|
||||||
|
@ -246,7 +245,7 @@ class InitSickBeard:
|
||||||
detected = False
|
detected = False
|
||||||
params = nzb2media.ALL_FORKS
|
params = nzb2media.ALL_FORKS
|
||||||
rem_params = []
|
rem_params = []
|
||||||
logger.info(f'Attempting to auto-detect {self.input_category} fork')
|
log.info(f'Attempting to auto-detect {self.input_category} fork')
|
||||||
# Define the order to test.
|
# Define the order to test.
|
||||||
# Default must be first since default fork doesn't reject parameters.
|
# Default must be first since default fork doesn't reject parameters.
|
||||||
# Then in order of most unique parameters.
|
# Then in order of most unique parameters.
|
||||||
|
@ -270,7 +269,7 @@ class InitSickBeard:
|
||||||
|
|
||||||
# attempting to auto-detect fork
|
# attempting to auto-detect fork
|
||||||
try:
|
try:
|
||||||
s = requests.Session()
|
session = requests.Session()
|
||||||
|
|
||||||
if not self.apikey and self.username and self.password:
|
if not self.apikey and self.username and self.password:
|
||||||
login = nzb2media.utils.common.create_url(
|
login = nzb2media.utils.common.create_url(
|
||||||
|
@ -283,54 +282,54 @@ class InitSickBeard:
|
||||||
'username': self.username,
|
'username': self.username,
|
||||||
'password': self.password,
|
'password': self.password,
|
||||||
}
|
}
|
||||||
r = s.get(login, verify=False, timeout=(30, 60))
|
response = session.get(login, verify=False, timeout=(30, 60))
|
||||||
if r.status_code in [401, 403] and r.cookies.get('_xsrf'):
|
if response.status_code in [401, 403] and response.cookies.get('_xsrf'):
|
||||||
login_params['_xsrf'] = r.cookies.get('_xsrf')
|
login_params['_xsrf'] = response.cookies.get('_xsrf')
|
||||||
s.post(login, data=login_params, stream=True, verify=False)
|
session.post(login, data=login_params, stream=True, verify=False)
|
||||||
r = s.get(
|
response = session.get(
|
||||||
url,
|
url,
|
||||||
auth=(self.username, self.password),
|
auth=(self.username, self.password),
|
||||||
params=api_params,
|
params=api_params,
|
||||||
verify=False,
|
verify=False,
|
||||||
)
|
)
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.info(
|
log.info(
|
||||||
f'Could not connect to {self.section}:{self.input_category} '
|
f'Could not connect to {self.section}:{self.input_category} '
|
||||||
f'to perform auto-fork detection!',
|
f'to perform auto-fork detection!',
|
||||||
)
|
)
|
||||||
r = []
|
response = []
|
||||||
|
|
||||||
if r and r.ok:
|
if response and response.ok:
|
||||||
if self.apikey:
|
if self.apikey:
|
||||||
rem_params, found = self._api_check(r, params, rem_params)
|
rem_params, found = self._api_check(response, params, rem_params)
|
||||||
if found:
|
if found:
|
||||||
params['cmd'] = 'sg.postprocess'
|
params['cmd'] = 'sg.postprocess'
|
||||||
else: # try different api set for non-SickGear forks.
|
else: # try different api set for non-SickGear forks.
|
||||||
api_params = {'cmd': 'help', 'subject': 'postprocess'}
|
api_params = {'cmd': 'help', 'subject': 'postprocess'}
|
||||||
try:
|
try:
|
||||||
if not self.apikey and self.username and self.password:
|
if not self.apikey and self.username and self.password:
|
||||||
r = s.get(
|
response = session.get(
|
||||||
url,
|
url,
|
||||||
auth=(self.username, self.password),
|
auth=(self.username, self.password),
|
||||||
params=api_params,
|
params=api_params,
|
||||||
verify=False,
|
verify=False,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
r = s.get(url, params=api_params, verify=False)
|
response = session.get(url, params=api_params, verify=False)
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.info(
|
log.info(
|
||||||
f'Could not connect to {self.section}:'
|
f'Could not connect to {self.section}:'
|
||||||
f'{self.input_category} to perform auto-fork '
|
f'{self.input_category} to perform auto-fork '
|
||||||
f'detection!',
|
f'detection!',
|
||||||
)
|
)
|
||||||
rem_params, found = self._api_check(r, params, rem_params)
|
rem_params, found = self._api_check(response, params, rem_params)
|
||||||
params['cmd'] = 'postprocess'
|
params['cmd'] = 'postprocess'
|
||||||
else:
|
else:
|
||||||
# Find excess parameters
|
# Find excess parameters
|
||||||
rem_params.extend(
|
rem_params.extend(
|
||||||
param
|
param
|
||||||
for param in params
|
for param in params
|
||||||
if f'name="{param}"' not in r.text
|
if f'name="{param}"' not in response.text
|
||||||
)
|
)
|
||||||
|
|
||||||
# Remove excess params
|
# Remove excess params
|
||||||
|
@ -344,18 +343,18 @@ class InitSickBeard:
|
||||||
|
|
||||||
if detected:
|
if detected:
|
||||||
self.fork = fork
|
self.fork = fork
|
||||||
logger.info(
|
log.info(
|
||||||
f'{self.section}:{self.input_category} fork auto-detection '
|
f'{self.section}:{self.input_category} fork auto-detection '
|
||||||
f'successful ...',
|
f'successful ...',
|
||||||
)
|
)
|
||||||
elif rem_params:
|
elif rem_params:
|
||||||
logger.info(
|
log.info(
|
||||||
f'{self.section}:{self.input_category} fork auto-detection '
|
f'{self.section}:{self.input_category} fork auto-detection '
|
||||||
f'found custom params {params}',
|
f'found custom params {params}',
|
||||||
)
|
)
|
||||||
self.fork = ['custom', params]
|
self.fork = ['custom', params]
|
||||||
else:
|
else:
|
||||||
logger.info(
|
log.info(
|
||||||
f'{self.section}:{self.input_category} fork auto-detection '
|
f'{self.section}:{self.input_category} fork auto-detection '
|
||||||
f'failed',
|
f'failed',
|
||||||
)
|
)
|
||||||
|
@ -372,12 +371,12 @@ class InitSickBeard:
|
||||||
'Medusa-api': PyMedusaApiV1,
|
'Medusa-api': PyMedusaApiV1,
|
||||||
'Medusa-apiv2': PyMedusaApiV2,
|
'Medusa-apiv2': PyMedusaApiV2,
|
||||||
}
|
}
|
||||||
logger.debug(f'Create object for fork {self.fork}')
|
log.debug(f'Create object for fork {self.fork}')
|
||||||
if self.fork and mapped_forks.get(self.fork):
|
if self.fork and mapped_forks.get(self.fork):
|
||||||
# Create the fork object and pass self (SickBeardInit) to it for all the data, like Config.
|
# Create the fork object and pass self (SickBeardInit) to it for all the data, like Config.
|
||||||
self.fork_obj = mapped_forks[self.fork](self)
|
self.fork_obj = mapped_forks[self.fork](self)
|
||||||
else:
|
else:
|
||||||
logger.info(
|
log.info(
|
||||||
f'{self.section}:{self.input_category} Could not create a '
|
f'{self.section}:{self.input_category} Could not create a '
|
||||||
f'fork object for {self.fork}. Probaly class not added yet.',
|
f'fork object for {self.fork}. Probaly class not added yet.',
|
||||||
)
|
)
|
||||||
|
@ -538,10 +537,7 @@ class SickBeard:
|
||||||
def api_call(self) -> ProcessResult:
|
def api_call(self) -> ProcessResult:
|
||||||
"""Perform a base sickbeard api call."""
|
"""Perform a base sickbeard api call."""
|
||||||
self._process_fork_prarams()
|
self._process_fork_prarams()
|
||||||
logger.debug(
|
log.debug(f'Opening URL: {self.url} with params: {self.sb_init.fork_params}')
|
||||||
f'Opening URL: {self.url} with params: {self.sb_init.fork_params}',
|
|
||||||
self.sb_init.section,
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
if (
|
if (
|
||||||
not self.sb_init.apikey
|
not self.sb_init.apikey
|
||||||
|
@ -560,9 +556,9 @@ class SickBeard:
|
||||||
'username': self.sb_init.username,
|
'username': self.sb_init.username,
|
||||||
'password': self.sb_init.password,
|
'password': self.sb_init.password,
|
||||||
}
|
}
|
||||||
r = self.session.get(login, verify=False, timeout=(30, 60))
|
response = self.session.get(login, verify=False, timeout=(30, 60))
|
||||||
if r.status_code in [401, 403] and r.cookies.get('_xsrf'):
|
if response.status_code in [401, 403] and response.cookies.get('_xsrf'):
|
||||||
login_params['_xsrf'] = r.cookies.get('_xsrf')
|
login_params['_xsrf'] = response.cookies.get('_xsrf')
|
||||||
self.session.post(
|
self.session.post(
|
||||||
login,
|
login,
|
||||||
data=login_params,
|
data=login_params,
|
||||||
|
@ -579,10 +575,7 @@ class SickBeard:
|
||||||
timeout=(30, 1800),
|
timeout=(30, 1800),
|
||||||
)
|
)
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.error(
|
log.error(f'Unable to open URL: {self.url}')
|
||||||
f'Unable to open URL: {self.url}',
|
|
||||||
self.sb_init.section,
|
|
||||||
)
|
|
||||||
result = ProcessResult.failure(
|
result = ProcessResult.failure(
|
||||||
f'{self.sb_init.section}: Failed to post-process - Unable to '
|
f'{self.sb_init.section}: Failed to post-process - Unable to '
|
||||||
f'connect to {self.sb_init.section}',
|
f'connect to {self.sb_init.section}',
|
||||||
|
@ -594,10 +587,7 @@ class SickBeard:
|
||||||
requests.codes.accepted,
|
requests.codes.accepted,
|
||||||
]
|
]
|
||||||
if response.status_code not in successful_statuses:
|
if response.status_code not in successful_statuses:
|
||||||
logger.error(
|
log.error(f'Server returned status {response.status_code}')
|
||||||
f'Server returned status {response.status_code}',
|
|
||||||
self.sb_init.section,
|
|
||||||
)
|
|
||||||
result = ProcessResult.failure(
|
result = ProcessResult.failure(
|
||||||
f'{self.sb_init.section}: Failed to post-process - Server '
|
f'{self.sb_init.section}: Failed to post-process - Server '
|
||||||
f'returned status {response.status_code}',
|
f'returned status {response.status_code}',
|
||||||
|
@ -615,7 +605,7 @@ class SickBeard:
|
||||||
for line in response.iter_lines():
|
for line in response.iter_lines():
|
||||||
if line:
|
if line:
|
||||||
line = line.decode('utf-8')
|
line = line.decode('utf-8')
|
||||||
logger.postprocess(line, self.sb_init.section)
|
log.postprocess(line)
|
||||||
# if 'Moving file from' in line:
|
# if 'Moving file from' in line:
|
||||||
# input_name = os.path.split(line)[1]
|
# input_name = os.path.split(line)[1]
|
||||||
# if 'added to the queue' in line:
|
# if 'added to the queue' in line:
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def configure_plex(config):
|
def configure_plex(config):
|
||||||
|
@ -36,9 +40,7 @@ def plex_update(category):
|
||||||
section = None
|
section = None
|
||||||
if not nzb2media.PLEX_SECTION:
|
if not nzb2media.PLEX_SECTION:
|
||||||
return
|
return
|
||||||
logger.debug(
|
log.debug(f'Attempting to update Plex Library for category {category}.')
|
||||||
f'Attempting to update Plex Library for category {category}.', 'PLEX',
|
|
||||||
)
|
|
||||||
for item in nzb2media.PLEX_SECTION:
|
for item in nzb2media.PLEX_SECTION:
|
||||||
if item[0] == category:
|
if item[0] == category:
|
||||||
section = item[1]
|
section = item[1]
|
||||||
|
@ -46,6 +48,6 @@ def plex_update(category):
|
||||||
if section:
|
if section:
|
||||||
url = f'{url}{section}/refresh?X-Plex-Token={nzb2media.PLEX_TOKEN}'
|
url = f'{url}{section}/refresh?X-Plex-Token={nzb2media.PLEX_TOKEN}'
|
||||||
requests.get(url, timeout=(60, 120), verify=False)
|
requests.get(url, timeout=(60, 120), verify=False)
|
||||||
logger.debug('Plex Library has been refreshed.', 'PLEX')
|
log.debug('Plex Library has been refreshed.')
|
||||||
else:
|
else:
|
||||||
logger.debug('Could not identify section for plex update', 'PLEX')
|
log.debug('Could not identify section for plex update')
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
@ -7,7 +8,9 @@ import subliminal
|
||||||
from babelfish import Language
|
from babelfish import Language
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def import_subs(filename):
|
def import_subs(filename):
|
||||||
|
@ -29,9 +32,7 @@ def import_subs(filename):
|
||||||
if not languages:
|
if not languages:
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.info(
|
log.info(f'Attempting to download subtitles for {filename}')
|
||||||
f'Attempting to download subtitles for {filename}', 'SUBTITLES',
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
video = subliminal.scan_video(filename)
|
video = subliminal.scan_video(filename)
|
||||||
subtitles = subliminal.download_best_subtitles({video}, languages)
|
subtitles = subliminal.download_best_subtitles({video}, languages)
|
||||||
|
@ -42,11 +43,8 @@ def import_subs(filename):
|
||||||
video.name, subtitle.language,
|
video.name, subtitle.language,
|
||||||
)
|
)
|
||||||
os.chmod(subtitle_path, 0o644)
|
os.chmod(subtitle_path, 0o644)
|
||||||
except Exception as e:
|
except Exception as error:
|
||||||
logger.error(
|
log.error(f'Failed to download subtitles for {filename} due to: {error}')
|
||||||
f'Failed to download subtitles for {filename} due to: {e}',
|
|
||||||
'SUBTITLES',
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def rename_subs(path):
|
def rename_subs(path):
|
||||||
|
@ -110,16 +108,12 @@ def rename_subs(path):
|
||||||
break
|
break
|
||||||
new_sub = f'{new_sub}{ext}' # add extension now
|
new_sub = f'{new_sub}{ext}' # add extension now
|
||||||
if os.path.isfile(new_sub): # Don't copy over existing - final check.
|
if os.path.isfile(new_sub): # Don't copy over existing - final check.
|
||||||
logger.debug(
|
log.debug(f'Unable to rename sub file {sub} as destination {new_sub} already exists')
|
||||||
f'Unable to rename sub file {sub} as destination {new_sub} already exists',
|
|
||||||
)
|
|
||||||
continue
|
continue
|
||||||
logger.debug(
|
log.debug(f'Renaming sub file from {sub} to {new_sub}')
|
||||||
f'Renaming sub file from {sub} to {new_sub}',
|
|
||||||
)
|
|
||||||
renamed.append(new_sub)
|
renamed.append(new_sub)
|
||||||
try:
|
try:
|
||||||
os.rename(sub, new_sub)
|
os.rename(sub, new_sub)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.error(f'Unable to rename sub file due to: {error}')
|
log.error(f'Unable to rename sub file due to: {error}')
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media.auto_process.common import ProcessResult
|
from nzb2media.auto_process.common import ProcessResult
|
||||||
from nzb2media.processor import nzb
|
from nzb2media.processor import nzb
|
||||||
from nzb2media.utils.common import get_dirs
|
from nzb2media.utils.common import get_dirs
|
||||||
from nzb2media.utils.download_info import get_download_info
|
from nzb2media.utils.download_info import get_download_info
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def process():
|
def process():
|
||||||
# Perform Manual Post-Processing
|
# Perform Manual Post-Processing
|
||||||
logger.warning(
|
log.warning('Invalid number of arguments received from client, Switching to manual run mode ...')
|
||||||
'Invalid number of arguments received from client, Switching to manual run mode ...',
|
|
||||||
)
|
|
||||||
|
|
||||||
# Post-Processing Result
|
# Post-Processing Result
|
||||||
result = ProcessResult(
|
result = ProcessResult(
|
||||||
|
@ -27,29 +28,21 @@ def process():
|
||||||
if not nzb2media.CFG[section][subsection].isenabled():
|
if not nzb2media.CFG[section][subsection].isenabled():
|
||||||
continue
|
continue
|
||||||
for dir_name in get_dirs(section, subsection, link='move'):
|
for dir_name in get_dirs(section, subsection, link='move'):
|
||||||
logger.info(
|
log.info(f'Starting manual run for {section}:{subsection} - Folder: {dir_name}')
|
||||||
f'Starting manual run for {section}:{subsection} - Folder: {dir_name}',
|
log.info(f'Checking database for download info for {os.path.basename(dir_name)} ...')
|
||||||
)
|
|
||||||
logger.info(
|
|
||||||
f'Checking database for download info for {os.path.basename(dir_name)} ...',
|
|
||||||
)
|
|
||||||
|
|
||||||
nzb2media.DOWNLOAD_INFO = get_download_info(
|
nzb2media.DOWNLOAD_INFO = get_download_info(
|
||||||
os.path.basename(dir_name),
|
os.path.basename(dir_name),
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
if nzb2media.DOWNLOAD_INFO:
|
if nzb2media.DOWNLOAD_INFO:
|
||||||
logger.info(
|
log.info(f'Found download info for {os.path.basename(dir_name)}, setting variables now ...')
|
||||||
f'Found download info for {os.path.basename(dir_name)}, setting variables now ...',
|
|
||||||
)
|
|
||||||
client_agent = (
|
client_agent = (
|
||||||
nzb2media.DOWNLOAD_INFO[0]['client_agent'] or 'manual'
|
nzb2media.DOWNLOAD_INFO[0]['client_agent'] or 'manual'
|
||||||
)
|
)
|
||||||
download_id = nzb2media.DOWNLOAD_INFO[0]['input_id'] or ''
|
download_id = nzb2media.DOWNLOAD_INFO[0]['input_id'] or ''
|
||||||
else:
|
else:
|
||||||
logger.info(
|
log.info(f'Unable to locate download info for {os.path.basename(dir_name)}, continuing to try and process this release ...')
|
||||||
f'Unable to locate download info for {os.path.basename(dir_name)}, continuing to try and process this release ...',
|
|
||||||
)
|
|
||||||
client_agent = 'manual'
|
client_agent = 'manual'
|
||||||
download_id = ''
|
download_id = ''
|
||||||
|
|
||||||
|
@ -70,8 +63,6 @@ def process():
|
||||||
input_category=subsection,
|
input_category=subsection,
|
||||||
)
|
)
|
||||||
if results.status_code != 0:
|
if results.status_code != 0:
|
||||||
logger.error(
|
log.error(f'A problem was reported when trying to perform a manual run for {section}:{subsection}.')
|
||||||
f'A problem was reported when trying to perform a manual run for {section}:{subsection}.',
|
|
||||||
)
|
|
||||||
result = results
|
result = results
|
||||||
return result
|
return result
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import logging
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media import main_db
|
from nzb2media import main_db
|
||||||
from nzb2media.auto_process import books
|
from nzb2media.auto_process import books
|
||||||
from nzb2media.auto_process import comics
|
from nzb2media.auto_process import comics
|
||||||
|
@ -21,6 +21,9 @@ from nzb2media.utils.encoding import convert_to_ascii
|
||||||
from nzb2media.utils.files import extract_files
|
from nzb2media.utils.files import extract_files
|
||||||
from nzb2media.utils.nzb import get_nzoid
|
from nzb2media.utils.nzb import get_nzoid
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def process(
|
def process(
|
||||||
input_directory,
|
input_directory,
|
||||||
|
@ -32,9 +35,7 @@ def process(
|
||||||
failure_link=None,
|
failure_link=None,
|
||||||
):
|
):
|
||||||
if nzb2media.SAFE_MODE and input_directory == nzb2media.NZB_DEFAULT_DIRECTORY:
|
if nzb2media.SAFE_MODE and input_directory == nzb2media.NZB_DEFAULT_DIRECTORY:
|
||||||
logger.error(
|
log.error(f'The input directory:[{input_directory}] is the Default Download Directory. Please configure category directories to prevent processing of other media.')
|
||||||
f'The input directory:[{input_directory}] is the Default Download Directory. Please configure category directories to prevent processing of other media.',
|
|
||||||
)
|
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
message='',
|
message='',
|
||||||
status_code=-1,
|
status_code=-1,
|
||||||
|
@ -42,23 +43,16 @@ def process(
|
||||||
|
|
||||||
if not download_id and client_agent == 'sabnzbd':
|
if not download_id and client_agent == 'sabnzbd':
|
||||||
download_id = get_nzoid(input_name)
|
download_id = get_nzoid(input_name)
|
||||||
|
|
||||||
if client_agent != 'manual' and not nzb2media.DOWNLOAD_INFO:
|
if client_agent != 'manual' and not nzb2media.DOWNLOAD_INFO:
|
||||||
logger.debug(
|
log.debug(f'Adding NZB download info for directory {input_directory} to database')
|
||||||
f'Adding NZB download info for directory {input_directory} to database',
|
|
||||||
)
|
|
||||||
|
|
||||||
my_db = main_db.DBConnection()
|
my_db = main_db.DBConnection()
|
||||||
|
|
||||||
input_directory1 = input_directory
|
input_directory1 = input_directory
|
||||||
input_name1 = input_name
|
input_name1 = input_name
|
||||||
|
|
||||||
try:
|
try:
|
||||||
encoded, input_directory1 = char_replace(input_directory)
|
encoded, input_directory1 = char_replace(input_directory)
|
||||||
encoded, input_name1 = char_replace(input_name)
|
encoded, input_name1 = char_replace(input_name)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
control_value_dict = {'input_directory': input_directory1}
|
control_value_dict = {'input_directory': input_directory1}
|
||||||
new_value_dict = {
|
new_value_dict = {
|
||||||
'input_name': input_name1,
|
'input_name': input_name1,
|
||||||
|
@ -69,7 +63,6 @@ def process(
|
||||||
'last_update': datetime.date.today().toordinal(),
|
'last_update': datetime.date.today().toordinal(),
|
||||||
}
|
}
|
||||||
my_db.upsert('downloads', new_value_dict, control_value_dict)
|
my_db.upsert('downloads', new_value_dict, control_value_dict)
|
||||||
|
|
||||||
# auto-detect section
|
# auto-detect section
|
||||||
if input_category is None:
|
if input_category is None:
|
||||||
input_category = 'UNCAT'
|
input_category = 'UNCAT'
|
||||||
|
@ -78,68 +71,45 @@ def process(
|
||||||
if section is None:
|
if section is None:
|
||||||
section = nzb2media.CFG.findsection('ALL').isenabled()
|
section = nzb2media.CFG.findsection('ALL').isenabled()
|
||||||
if section is None:
|
if section is None:
|
||||||
logger.error(
|
log.error(f'Category:[{input_category}] is not defined or is not enabled. Please rename it or ensure it is enabled for the appropriate section in your autoProcessMedia.cfg and try again.')
|
||||||
f'Category:[{input_category}] is not defined or is not enabled. Please rename it or ensure it is enabled for the appropriate section in your autoProcessMedia.cfg and try again.',
|
|
||||||
)
|
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
message='',
|
message='',
|
||||||
status_code=-1,
|
status_code=-1,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
usercat = 'ALL'
|
usercat = 'ALL'
|
||||||
|
|
||||||
if len(section) > 1:
|
if len(section) > 1:
|
||||||
logger.error(
|
log.error(f'Category:[{input_category}] is not unique, {section.keys()} are using it. Please rename it or disable all other sections using the same category name in your autoProcessMedia.cfg and try again.')
|
||||||
f'Category:[{input_category}] is not unique, {section.keys()} are using it. Please rename it or disable all other sections using the same category name in your autoProcessMedia.cfg and try again.',
|
|
||||||
)
|
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
message='',
|
message='',
|
||||||
status_code=-1,
|
status_code=-1,
|
||||||
)
|
)
|
||||||
|
|
||||||
if section:
|
if section:
|
||||||
section_name = section.keys()[0]
|
section_name = section.keys()[0]
|
||||||
logger.info(f'Auto-detected SECTION:{section_name}')
|
log.info(f'Auto-detected SECTION:{section_name}')
|
||||||
else:
|
else:
|
||||||
logger.error(
|
log.error(f'Unable to locate a section with subsection:{input_category} enabled in your autoProcessMedia.cfg, exiting!')
|
||||||
f'Unable to locate a section with subsection:{input_category} enabled in your autoProcessMedia.cfg, exiting!',
|
|
||||||
)
|
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
status_code=-1,
|
status_code=-1,
|
||||||
message='',
|
message='',
|
||||||
)
|
)
|
||||||
|
|
||||||
cfg = dict(nzb2media.CFG[section_name][usercat])
|
cfg = dict(nzb2media.CFG[section_name][usercat])
|
||||||
|
|
||||||
extract = int(cfg.get('extract', 0))
|
extract = int(cfg.get('extract', 0))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if int(cfg.get('remote_path')) and not nzb2media.REMOTE_PATHS:
|
if int(cfg.get('remote_path')) and not nzb2media.REMOTE_PATHS:
|
||||||
logger.error(
|
log.error(f'Remote Path is enabled for {section_name}:{input_category} but no Network mount points are defined. Please check your autoProcessMedia.cfg, exiting!')
|
||||||
f'Remote Path is enabled for {section_name}:{input_category} but no Network mount points are defined. Please check your autoProcessMedia.cfg, exiting!',
|
|
||||||
)
|
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
status_code=-1,
|
status_code=-1,
|
||||||
message='',
|
message='',
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
remote_path = cfg.get('remote_path')
|
remote_path = cfg.get('remote_path')
|
||||||
logger.error(
|
log.error(f'Remote Path {remote_path} is not valid for {section_name}:{input_category} Please set this to either 0 to disable or 1 to enable!')
|
||||||
f'Remote Path {remote_path} is not valid for {section_name}:{input_category} Please set this to either 0 to disable or 1 to enable!',
|
|
||||||
)
|
|
||||||
|
|
||||||
input_name, input_directory = convert_to_ascii(input_name, input_directory)
|
input_name, input_directory = convert_to_ascii(input_name, input_directory)
|
||||||
|
|
||||||
if extract == 1 and not (status > 0 and nzb2media.NOEXTRACTFAILED):
|
if extract == 1 and not (status > 0 and nzb2media.NOEXTRACTFAILED):
|
||||||
logger.debug(
|
log.debug(f'Checking for archives to extract in directory: {input_directory}')
|
||||||
f'Checking for archives to extract in directory: {input_directory}',
|
|
||||||
)
|
|
||||||
extract_files(input_directory)
|
extract_files(input_directory)
|
||||||
|
log.info(f'Calling {section_name}:{input_category} to post-process:{input_name}')
|
||||||
logger.info(
|
|
||||||
f'Calling {section_name}:{input_category} to post-process:{input_name}',
|
|
||||||
)
|
|
||||||
|
|
||||||
if section_name == 'UserScript':
|
if section_name == 'UserScript':
|
||||||
result = external_script(
|
result = external_script(
|
||||||
input_directory, input_name, input_category, section[usercat],
|
input_directory, input_name, input_category, section[usercat],
|
||||||
|
@ -170,9 +140,7 @@ def process(
|
||||||
input_category=input_category,
|
input_category=input_category,
|
||||||
failure_link=failure_link,
|
failure_link=failure_link,
|
||||||
)
|
)
|
||||||
|
|
||||||
plex_update(input_category)
|
plex_update(input_category)
|
||||||
|
|
||||||
if result.status_code == 0:
|
if result.status_code == 0:
|
||||||
if client_agent != 'manual':
|
if client_agent != 'manual':
|
||||||
# update download status in our DB
|
# update download status in our DB
|
||||||
|
@ -184,7 +152,7 @@ def process(
|
||||||
'Radarr',
|
'Radarr',
|
||||||
'Lidarr',
|
'Lidarr',
|
||||||
]:
|
]:
|
||||||
# cleanup our processing folders of any misc unwanted files and empty directories
|
# cleanup our processing folders of any misc unwanted files and
|
||||||
|
# empty directories
|
||||||
clean_dir(input_directory, section_name, input_category)
|
clean_dir(input_directory, section_name, input_category)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media.processor import nzb
|
from nzb2media.processor import nzb
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def parse_download_id():
|
def parse_download_id():
|
||||||
"""Parse nzbget download_id from environment."""
|
"""Parse nzbget download_id from environment."""
|
||||||
|
@ -35,7 +38,7 @@ def _parse_total_status():
|
||||||
status_summary = os.environ['NZBPP_TOTALSTATUS']
|
status_summary = os.environ['NZBPP_TOTALSTATUS']
|
||||||
if status_summary != 'SUCCESS':
|
if status_summary != 'SUCCESS':
|
||||||
status = os.environ['NZBPP_STATUS']
|
status = os.environ['NZBPP_STATUS']
|
||||||
logger.info(f'Download failed with status {status}.')
|
log.info(f'Download failed with status {status}.')
|
||||||
return 1
|
return 1
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
@ -44,14 +47,14 @@ def _parse_par_status():
|
||||||
"""Parse nzbget par status from environment."""
|
"""Parse nzbget par status from environment."""
|
||||||
par_status = os.environ['NZBPP_PARSTATUS']
|
par_status = os.environ['NZBPP_PARSTATUS']
|
||||||
if par_status == '1' or par_status == '4':
|
if par_status == '1' or par_status == '4':
|
||||||
logger.warning('Par-repair failed, setting status \'failed\'')
|
log.warning('Par-repair failed, setting status \'failed\'')
|
||||||
return 1
|
return 1
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def _parse_unpack_status():
|
def _parse_unpack_status():
|
||||||
if os.environ['NZBPP_UNPACKSTATUS'] == '1':
|
if os.environ['NZBPP_UNPACKSTATUS'] == '1':
|
||||||
logger.warning('Unpack failed, setting status \'failed\'')
|
log.warning('Unpack failed, setting status \'failed\'')
|
||||||
return 1
|
return 1
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
@ -65,17 +68,11 @@ def _parse_health_status():
|
||||||
# Unpack was skipped due to nzb-file properties
|
# Unpack was skipped due to nzb-file properties
|
||||||
# or due to errors during par-check
|
# or due to errors during par-check
|
||||||
if int(os.environ['NZBPP_HEALTH']) < 1000:
|
if int(os.environ['NZBPP_HEALTH']) < 1000:
|
||||||
logger.warning(
|
log.warning('Download health is compromised and Par-check/repair disabled or no .par2 files found. Setting status \'failed\'')
|
||||||
'Download health is compromised and Par-check/repair disabled or no .par2 files found. Setting status \'failed\'',
|
|
||||||
)
|
|
||||||
status = 1
|
status = 1
|
||||||
else:
|
else:
|
||||||
logger.info(
|
log.info('Par-check/repair disabled or no .par2 files found, and Unpack not required. Health is ok so handle as though download successful')
|
||||||
'Par-check/repair disabled or no .par2 files found, and Unpack not required. Health is ok so handle as though download successful',
|
log.info('Please check your Par-check/repair settings for future downloads.')
|
||||||
)
|
|
||||||
logger.info(
|
|
||||||
'Please check your Par-check/repair settings for future downloads.',
|
|
||||||
)
|
|
||||||
return status
|
return status
|
||||||
|
|
||||||
|
|
||||||
|
@ -95,11 +92,9 @@ def check_version():
|
||||||
version = os.environ['NZBOP_VERSION']
|
version = os.environ['NZBOP_VERSION']
|
||||||
# Check if the script is called from nzbget 11.0 or later
|
# Check if the script is called from nzbget 11.0 or later
|
||||||
if version[0:5] < '11.0':
|
if version[0:5] < '11.0':
|
||||||
logger.error(
|
log.error(f'NZBGet Version {version} is not supported. Please update NZBGet.')
|
||||||
f'NZBGet Version {version} is not supported. Please update NZBGet.',
|
|
||||||
)
|
|
||||||
sys.exit(nzb2media.NZBGET_POSTPROCESS_ERROR)
|
sys.exit(nzb2media.NZBGET_POSTPROCESS_ERROR)
|
||||||
logger.info(f'Script triggered from NZBGet Version {version}.')
|
log.info(f'Script triggered from NZBGet Version {version}.')
|
||||||
|
|
||||||
|
|
||||||
def process():
|
def process():
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media.processor import nzb
|
from nzb2media.processor import nzb
|
||||||
|
|
||||||
# Constants
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
MINIMUM_ARGUMENTS = 8
|
MINIMUM_ARGUMENTS = 8
|
||||||
|
|
||||||
|
|
||||||
def process_script():
|
def process_script():
|
||||||
version = os.environ['SAB_VERSION']
|
version = os.environ['SAB_VERSION']
|
||||||
logger.info(f'Script triggered from SABnzbd {version}.')
|
log.info(f'Script triggered from SABnzbd {version}.')
|
||||||
return nzb.process(
|
return nzb.process(
|
||||||
input_directory=os.environ['SAB_COMPLETE_DIR'],
|
input_directory=os.environ['SAB_COMPLETE_DIR'],
|
||||||
input_name=os.environ['SAB_FINAL_NAME'],
|
input_name=os.environ['SAB_FINAL_NAME'],
|
||||||
|
@ -40,7 +42,7 @@ def process(args):
|
||||||
8. Failure URL
|
8. Failure URL
|
||||||
"""
|
"""
|
||||||
version = '0.7.17+' if len(args) > MINIMUM_ARGUMENTS else ''
|
version = '0.7.17+' if len(args) > MINIMUM_ARGUMENTS else ''
|
||||||
logger.info(f'Script triggered from SABnzbd {version}')
|
log.info(f'Script triggered from SABnzbd {version}')
|
||||||
return nzb.process(
|
return nzb.process(
|
||||||
input_directory=args[1],
|
input_directory=args[1],
|
||||||
input_name=args[2],
|
input_name=args[2],
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import re
|
import re
|
||||||
|
@ -7,9 +8,12 @@ import shlex
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media.utils.files import list_media_files
|
from nzb2media.utils.files import list_media_files
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
reverse_list = [
|
reverse_list = [
|
||||||
r'\.\d{2}e\d{2}s\.',
|
r'\.\d{2}e\d{2}s\.',
|
||||||
r'\.[pi]0801\.',
|
r'\.[pi]0801\.',
|
||||||
|
@ -113,14 +117,11 @@ def rename_file(filename, newfile_path):
|
||||||
+ '.NTM'
|
+ '.NTM'
|
||||||
+ os.path.splitext(newfile_path)[1]
|
+ os.path.splitext(newfile_path)[1]
|
||||||
)
|
)
|
||||||
logger.debug(
|
log.error(f'Replacing file name {filename} with download name {newfile_path}')
|
||||||
f'Replacing file name {filename} with download name {newfile_path}',
|
|
||||||
'EXCEPTION',
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
os.rename(filename, newfile_path)
|
os.rename(filename, newfile_path)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.error(f'Unable to rename file due to: {error}', 'EXCEPTION')
|
log.error(f'Unable to rename file due to: {error}')
|
||||||
|
|
||||||
|
|
||||||
def replace_filename(filename, dirname, name):
|
def replace_filename(filename, dirname, name):
|
||||||
|
@ -130,20 +131,12 @@ def replace_filename(filename, dirname, name):
|
||||||
is not None
|
is not None
|
||||||
):
|
):
|
||||||
newname = os.path.basename(dirname).replace(' ', '.')
|
newname = os.path.basename(dirname).replace(' ', '.')
|
||||||
logger.debug(
|
log.debug(f'Replacing file name {head} with directory name {newname}')
|
||||||
f'Replacing file name {head} with directory name {newname}',
|
|
||||||
'EXCEPTION',
|
|
||||||
)
|
|
||||||
elif media_pattern.search(name.replace(' ', '.').lower()) is not None:
|
elif media_pattern.search(name.replace(' ', '.').lower()) is not None:
|
||||||
newname = name.replace(' ', '.')
|
newname = name.replace(' ', '.')
|
||||||
logger.debug(
|
log.debug(f'Replacing file name {head} with download name {newname}')
|
||||||
f'Replacing file name {head} with download name {newname}',
|
|
||||||
'EXCEPTION',
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
log.warning(f'No name replacement determined for {head}')
|
||||||
f'No name replacement determined for {head}', 'EXCEPTION',
|
|
||||||
)
|
|
||||||
newname = name
|
newname = name
|
||||||
newfile = newname + file_extension
|
newfile = newname + file_extension
|
||||||
newfile_path = os.path.join(dirname, newfile)
|
newfile_path = os.path.join(dirname, newfile)
|
||||||
|
@ -169,10 +162,7 @@ def reverse_filename(filename, dirname, name):
|
||||||
else:
|
else:
|
||||||
newname = head[::-1].title()
|
newname = head[::-1].title()
|
||||||
newname = newname.replace(' ', '.')
|
newname = newname.replace(' ', '.')
|
||||||
logger.debug(
|
log.debug(f'Reversing filename {head} to {newname}')
|
||||||
f'Reversing filename {head} to {newname}',
|
|
||||||
'EXCEPTION',
|
|
||||||
)
|
|
||||||
newfile = newname + file_extension
|
newfile = newname + file_extension
|
||||||
newfile_path = os.path.join(dirname, newfile)
|
newfile_path = os.path.join(dirname, newfile)
|
||||||
return newfile_path
|
return newfile_path
|
||||||
|
@ -200,16 +190,11 @@ def rename_script(dirname):
|
||||||
)
|
)
|
||||||
if os.path.isfile(dest):
|
if os.path.isfile(dest):
|
||||||
continue
|
continue
|
||||||
logger.debug(
|
log.debug(f'Renaming file {orig} to {dest}')
|
||||||
f'Renaming file {orig} to {dest}',
|
|
||||||
'EXCEPTION',
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
os.rename(orig, dest)
|
os.rename(orig, dest)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.error(
|
log.error(f'Unable to rename file due to: {error}')
|
||||||
f'Unable to rename file due to: {error}', 'EXCEPTION',
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def par2(dirname):
|
def par2(dirname):
|
||||||
|
@ -231,12 +216,12 @@ def par2(dirname):
|
||||||
bitbucket = open('NUL')
|
bitbucket = open('NUL')
|
||||||
else:
|
else:
|
||||||
bitbucket = open('/dev/null')
|
bitbucket = open('/dev/null')
|
||||||
logger.info(f'Running par2 on file {parfile}.', 'PAR2')
|
log.info(f'Running par2 on file {parfile}.')
|
||||||
command = [nzb2media.PAR2CMD, 'r', parfile, '*']
|
command = [nzb2media.PAR2CMD, 'r', parfile, '*']
|
||||||
cmd = ''
|
cmd = ''
|
||||||
for item in command:
|
for item in command:
|
||||||
cmd = f'{cmd} {item}'
|
cmd = f'{cmd} {item}'
|
||||||
logger.debug(f'calling command:{cmd}', 'PAR2')
|
log.debug(f'calling command:{cmd}')
|
||||||
try:
|
try:
|
||||||
proc = subprocess.Popen(
|
proc = subprocess.Popen(
|
||||||
command, stdout=bitbucket, stderr=bitbucket,
|
command, stdout=bitbucket, stderr=bitbucket,
|
||||||
|
@ -244,11 +229,9 @@ def par2(dirname):
|
||||||
proc.communicate()
|
proc.communicate()
|
||||||
result = proc.returncode
|
result = proc.returncode
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error(
|
log.error(f'par2 file processing for {parfile} has failed')
|
||||||
f'par2 file processing for {parfile} has failed', 'PAR2',
|
|
||||||
)
|
|
||||||
if result == 0:
|
if result == 0:
|
||||||
logger.info('par2 file processing succeeded', 'PAR2')
|
log.info('par2 file processing succeeded')
|
||||||
os.chdir(pwd)
|
os.chdir(pwd)
|
||||||
bitbucket.close()
|
bitbucket.close()
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
from deluge_client import DelugeRPCClient
|
from deluge_client import DelugeRPCClient
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
|
log = logging.getLogger()
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def configure_client():
|
def configure_client():
|
||||||
|
@ -13,11 +17,11 @@ def configure_client():
|
||||||
user = nzb2media.DELUGE_USER
|
user = nzb2media.DELUGE_USER
|
||||||
password = nzb2media.DELUGE_PASSWORD
|
password = nzb2media.DELUGE_PASSWORD
|
||||||
|
|
||||||
logger.debug(f'Connecting to {agent}: http://{host}:{port}')
|
log.debug(f'Connecting to {agent}: http://{host}:{port}')
|
||||||
client = DelugeRPCClient(host, port, user, password)
|
client = DelugeRPCClient(host, port, user, password)
|
||||||
try:
|
try:
|
||||||
client.connect()
|
client.connect()
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error('Failed to connect to Deluge')
|
log.error('Failed to connect to Deluge')
|
||||||
else:
|
else:
|
||||||
return client
|
return client
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
from qbittorrent import Client as qBittorrentClient
|
from qbittorrent import Client as qBittorrentClient
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def configure_client():
|
def configure_client():
|
||||||
|
@ -13,13 +17,11 @@ def configure_client():
|
||||||
user = nzb2media.QBITTORRENT_USER
|
user = nzb2media.QBITTORRENT_USER
|
||||||
password = nzb2media.QBITTORRENT_PASSWORD
|
password = nzb2media.QBITTORRENT_PASSWORD
|
||||||
|
|
||||||
logger.debug(
|
log.debug(f'Connecting to {agent}: http://{host}:{port}')
|
||||||
f'Connecting to {agent}: http://{host}:{port}',
|
|
||||||
)
|
|
||||||
client = qBittorrentClient(f'http://{host}:{port}/')
|
client = qBittorrentClient(f'http://{host}:{port}/')
|
||||||
try:
|
try:
|
||||||
client.login(user, password)
|
client.login(user, password)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error('Failed to connect to qBittorrent')
|
log.error('Failed to connect to qBittorrent')
|
||||||
else:
|
else:
|
||||||
return client
|
return client
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
from syno.downloadstation import DownloadStation
|
from syno.downloadstation import DownloadStation
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def configure_client():
|
def configure_client():
|
||||||
|
@ -13,10 +16,10 @@ def configure_client():
|
||||||
user = nzb2media.SYNO_USER
|
user = nzb2media.SYNO_USER
|
||||||
password = nzb2media.SYNO_PASSWORD
|
password = nzb2media.SYNO_PASSWORD
|
||||||
|
|
||||||
logger.debug(f'Connecting to {agent}: http://{host}:{port}')
|
log.debug(f'Connecting to {agent}: http://{host}:{port}')
|
||||||
try:
|
try:
|
||||||
client = DownloadStation(host, port, user, password)
|
client = DownloadStation(host, port, user, password)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error('Failed to connect to synology')
|
log.error('Failed to connect to synology')
|
||||||
else:
|
else:
|
||||||
return client
|
return client
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
from transmissionrpc.client import Client as TransmissionClient
|
from transmissionrpc.client import Client as TransmissionClient
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def configure_client():
|
def configure_client():
|
||||||
|
@ -13,10 +17,10 @@ def configure_client():
|
||||||
user = nzb2media.TRANSMISSION_USER
|
user = nzb2media.TRANSMISSION_USER
|
||||||
password = nzb2media.TRANSMISSION_PASSWORD
|
password = nzb2media.TRANSMISSION_PASSWORD
|
||||||
|
|
||||||
logger.debug(f'Connecting to {agent}: http://{host}:{port}')
|
log.debug(f'Connecting to {agent}: http://{host}:{port}')
|
||||||
try:
|
try:
|
||||||
client = TransmissionClient(host, port, user, password)
|
client = TransmissionClient(host, port, user, password)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error('Failed to connect to Transmission')
|
log.error('Failed to connect to Transmission')
|
||||||
else:
|
else:
|
||||||
return client
|
return client
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
from utorrent.client import UTorrentClient
|
from utorrent.client import UTorrentClient
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def configure_client():
|
def configure_client():
|
||||||
|
@ -12,10 +16,10 @@ def configure_client():
|
||||||
user = nzb2media.UTORRENT_USER
|
user = nzb2media.UTORRENT_USER
|
||||||
password = nzb2media.UTORRENT_PASSWORD
|
password = nzb2media.UTORRENT_PASSWORD
|
||||||
|
|
||||||
logger.debug(f'Connecting to {agent}: {web_ui}')
|
log.debug(f'Connecting to {agent}: {web_ui}')
|
||||||
try:
|
try:
|
||||||
client = UTorrentClient(web_ui, user, password)
|
client = UTorrentClient(web_ui, user, password)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error('Failed to connect to uTorrent')
|
log.error('Failed to connect to uTorrent')
|
||||||
else:
|
else:
|
||||||
return client
|
return client
|
||||||
|
|
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
import errno
|
import errno
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
import platform
|
import platform
|
||||||
|
@ -14,9 +15,11 @@ import time
|
||||||
from babelfish import Language
|
from babelfish import Language
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media.utils.paths import make_dir
|
from nzb2media.utils.paths import make_dir
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
__author__ = 'Justin'
|
__author__ = 'Justin'
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,10 +38,7 @@ def is_video_good(video: pathlib.Path, status, require_lan=None):
|
||||||
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 != 0 or test_details.get('error'):
|
||||||
disable = True
|
disable = True
|
||||||
logger.info(
|
log.info('DISABLED: ffprobe failed to analyse test file. Stopping corruption check.')
|
||||||
'DISABLED: ffprobe failed to analyse test file. Stopping corruption check.',
|
|
||||||
'TRANSCODER',
|
|
||||||
)
|
|
||||||
if test_details.get('streams'):
|
if test_details.get('streams'):
|
||||||
vid_streams = [
|
vid_streams = [
|
||||||
item
|
item
|
||||||
|
@ -52,10 +52,7 @@ def is_video_good(video: pathlib.Path, status, require_lan=None):
|
||||||
]
|
]
|
||||||
if not (len(vid_streams) > 0 and len(aud_streams) > 0):
|
if not (len(vid_streams) > 0 and len(aud_streams) > 0):
|
||||||
disable = True
|
disable = True
|
||||||
logger.info(
|
log.info('DISABLED: ffprobe failed to analyse streams from test file. Stopping corruption check.')
|
||||||
'DISABLED: ffprobe failed to analyse streams from test file. Stopping corruption check.',
|
|
||||||
'TRANSCODER',
|
|
||||||
)
|
|
||||||
if disable:
|
if disable:
|
||||||
if status:
|
if status:
|
||||||
# if the download was 'failed', assume bad.
|
# if the download was 'failed', assume bad.
|
||||||
|
@ -64,21 +61,15 @@ def is_video_good(video: pathlib.Path, status, require_lan=None):
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
logger.info(
|
log.info(f'Checking [{video.name}] for corruption, please stand by ...')
|
||||||
f'Checking [{video.name}] for corruption, please stand by ...',
|
|
||||||
'TRANSCODER',
|
|
||||||
)
|
|
||||||
video_details, result = get_video_details(video)
|
video_details, result = get_video_details(video)
|
||||||
|
|
||||||
if result != 0:
|
if result != 0:
|
||||||
logger.error(f'FAILED: [{video.name}] is corrupted!', 'TRANSCODER')
|
log.error(f'FAILED: [{video.name}] is corrupted!')
|
||||||
return False
|
return False
|
||||||
if video_details.get('error'):
|
if video_details.get('error'):
|
||||||
error_details = video_details.get('error')
|
error_details = video_details.get('error')
|
||||||
logger.info(
|
log.info(f'FAILED: [{video.name}] returned error [{error_details}].')
|
||||||
f'FAILED: [{video.name}] returned error [{error_details}].',
|
|
||||||
'TRANSCODER',
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
if video_details.get('streams'):
|
if video_details.get('streams'):
|
||||||
video_streams = [
|
video_streams = [
|
||||||
|
@ -102,15 +93,10 @@ def is_video_good(video: pathlib.Path, status, require_lan=None):
|
||||||
else:
|
else:
|
||||||
valid_audio = audio_streams
|
valid_audio = audio_streams
|
||||||
if len(video_streams) > 0 and len(valid_audio) > 0:
|
if len(video_streams) > 0 and len(valid_audio) > 0:
|
||||||
logger.info(
|
log.info(f'SUCCESS: [{video.name}] has no corruption.')
|
||||||
f'SUCCESS: [{video.name}] has no corruption.', 'TRANSCODER',
|
|
||||||
)
|
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
logger.info(
|
log.info(f'FAILED: [{video.name}] has {len(video_streams)} video streams and {len(audio_streams)} audio streams. Assume corruption.')
|
||||||
f'FAILED: [{video.name}] has {len(video_streams)} video streams and {len(audio_streams)} audio streams. Assume corruption.',
|
|
||||||
'TRANSCODER',
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@ -125,7 +111,7 @@ def zip_out(file, img, bitbucket):
|
||||||
cmd, stdout=subprocess.PIPE, stderr=bitbucket,
|
cmd, stdout=subprocess.PIPE, stderr=bitbucket,
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error(f'Extracting [{file}] has failed', 'TRANSCODER')
|
log.error(f'Extracting [{file}] has failed')
|
||||||
return procin
|
return procin
|
||||||
|
|
||||||
|
|
||||||
|
@ -187,7 +173,7 @@ def get_video_details(videofile, img=None, bitbucket=None):
|
||||||
result = proc.returncode
|
result = proc.returncode
|
||||||
video_details = json.loads(out.decode())
|
video_details = json.loads(out.decode())
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error(f'Checking [{file}] has failed', 'TRANSCODER')
|
log.error(f'Checking [{file}] has failed')
|
||||||
return video_details, result
|
return video_details, result
|
||||||
|
|
||||||
|
|
||||||
|
@ -824,7 +810,7 @@ def extract_subs(file, newfile_path, bitbucket):
|
||||||
if platform.system() != 'Windows':
|
if platform.system() != 'Windows':
|
||||||
command = nzb2media.NICENESS + command
|
command = nzb2media.NICENESS + command
|
||||||
|
|
||||||
logger.info(f'Extracting {lan} subtitle from: {file}')
|
log.info(f'Extracting {lan} subtitle from: {file}')
|
||||||
print_cmd(command)
|
print_cmd(command)
|
||||||
result = 1 # set result to failed in case call fails.
|
result = 1 # set result to failed in case call fails.
|
||||||
try:
|
try:
|
||||||
|
@ -834,16 +820,16 @@ def extract_subs(file, newfile_path, bitbucket):
|
||||||
out, err = proc.communicate()
|
out, err = proc.communicate()
|
||||||
result = proc.returncode
|
result = proc.returncode
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error('Extracting subtitle has failed')
|
log.error('Extracting subtitle has failed')
|
||||||
|
|
||||||
if result == 0:
|
if result == 0:
|
||||||
try:
|
try:
|
||||||
shutil.copymode(file, output_file)
|
shutil.copymode(file, output_file)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
logger.info(f'Extracting {lan} subtitle from {file} has succeeded')
|
log.info(f'Extracting {lan} subtitle from {file} has succeeded')
|
||||||
else:
|
else:
|
||||||
logger.error('Extracting subtitles has failed')
|
log.error('Extracting subtitles has failed')
|
||||||
|
|
||||||
|
|
||||||
def process_list(it, new_dir, bitbucket):
|
def process_list(it, new_dir, bitbucket):
|
||||||
|
@ -859,14 +845,14 @@ def process_list(it, new_dir, bitbucket):
|
||||||
ext in ['.iso', '.bin', '.img']
|
ext in ['.iso', '.bin', '.img']
|
||||||
and ext not in nzb2media.IGNOREEXTENSIONS
|
and ext not in nzb2media.IGNOREEXTENSIONS
|
||||||
):
|
):
|
||||||
logger.debug(f'Attempting to rip disk image: {item}', 'TRANSCODER')
|
log.debug(f'Attempting to rip disk image: {item}')
|
||||||
new_list.extend(rip_iso(item, new_dir, bitbucket))
|
new_list.extend(rip_iso(item, new_dir, bitbucket))
|
||||||
rem_list.append(item)
|
rem_list.append(item)
|
||||||
elif (
|
elif (
|
||||||
re.match('.+VTS_[0-9][0-9]_[0-9].[Vv][Oo][Bb]', item)
|
re.match('.+VTS_[0-9][0-9]_[0-9].[Vv][Oo][Bb]', item)
|
||||||
and '.vob' not in nzb2media.IGNOREEXTENSIONS
|
and '.vob' not in nzb2media.IGNOREEXTENSIONS
|
||||||
):
|
):
|
||||||
logger.debug(f'Found VIDEO_TS image file: {item}', 'TRANSCODER')
|
log.debug(f'Found VIDEO_TS image file: {item}')
|
||||||
if not vts_path:
|
if not vts_path:
|
||||||
try:
|
try:
|
||||||
vts_path = re.match('(.+VIDEO_TS)', item).groups()[0]
|
vts_path = re.match('(.+VIDEO_TS)', item).groups()[0]
|
||||||
|
@ -877,7 +863,7 @@ def process_list(it, new_dir, bitbucket):
|
||||||
re.match('.+BDMV[/\\]SOURCE[/\\][0-9]+[0-9].[Mm][Tt][Ss]', item)
|
re.match('.+BDMV[/\\]SOURCE[/\\][0-9]+[0-9].[Mm][Tt][Ss]', item)
|
||||||
and '.mts' not in nzb2media.IGNOREEXTENSIONS
|
and '.mts' not in nzb2media.IGNOREEXTENSIONS
|
||||||
):
|
):
|
||||||
logger.debug(f'Found MTS image file: {item}', 'TRANSCODER')
|
log.debug(f'Found MTS image file: {item}')
|
||||||
if not mts_path:
|
if not mts_path:
|
||||||
try:
|
try:
|
||||||
mts_path = re.match('(.+BDMV[/\\]SOURCE)', item).groups()[
|
mts_path = re.match('(.+BDMV[/\\]SOURCE)', item).groups()[
|
||||||
|
@ -913,17 +899,11 @@ def process_list(it, new_dir, bitbucket):
|
||||||
it.extend(new_list)
|
it.extend(new_list)
|
||||||
for item in rem_list:
|
for item in rem_list:
|
||||||
it.remove(item)
|
it.remove(item)
|
||||||
logger.debug(
|
log.debug(f'Successfully extracted .vob file {new_list[0]} from disk image')
|
||||||
f'Successfully extracted .vob file {new_list[0]} from disk image',
|
|
||||||
'TRANSCODER',
|
|
||||||
)
|
|
||||||
elif new_list and not success:
|
elif new_list and not success:
|
||||||
new_list = []
|
new_list = []
|
||||||
rem_list = []
|
rem_list = []
|
||||||
logger.error(
|
log.error('Failed extracting .vob files from disk image. Stopping transcoding.')
|
||||||
'Failed extracting .vob files from disk image. Stopping transcoding.',
|
|
||||||
'TRANSCODER',
|
|
||||||
)
|
|
||||||
return it, rem_list, new_list, success
|
return it, rem_list, new_list, success
|
||||||
|
|
||||||
|
|
||||||
|
@ -931,10 +911,7 @@ def mount_iso(
|
||||||
item, new_dir, bitbucket,
|
item, new_dir, bitbucket,
|
||||||
): # Currently only supports Linux Mount when permissions allow.
|
): # Currently only supports Linux Mount when permissions allow.
|
||||||
if platform.system() == 'Windows':
|
if platform.system() == 'Windows':
|
||||||
logger.error(
|
log.error(f'No mounting options available under Windows for image file {item}')
|
||||||
f'No mounting options available under Windows for image file {item}',
|
|
||||||
'TRANSCODER',
|
|
||||||
)
|
|
||||||
return []
|
return []
|
||||||
mount_point = os.path.join(os.path.dirname(os.path.abspath(item)), 'temp')
|
mount_point = os.path.join(os.path.dirname(os.path.abspath(item)), 'temp')
|
||||||
make_dir(mount_point)
|
make_dir(mount_point)
|
||||||
|
@ -952,9 +929,7 @@ def mount_iso(
|
||||||
re.match('.+VTS_[0-9][0-9]_[0-9].[Vv][Oo][Bb]', full_path)
|
re.match('.+VTS_[0-9][0-9]_[0-9].[Vv][Oo][Bb]', full_path)
|
||||||
and '.vob' not in nzb2media.IGNOREEXTENSIONS
|
and '.vob' not in nzb2media.IGNOREEXTENSIONS
|
||||||
):
|
):
|
||||||
logger.debug(
|
log.debug(f'Found VIDEO_TS image file: {full_path}')
|
||||||
f'Found VIDEO_TS image file: {full_path}', 'TRANSCODER',
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
vts_path = re.match('(.+VIDEO_TS)', full_path).groups()[0]
|
vts_path = re.match('(.+VIDEO_TS)', full_path).groups()[0]
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -964,9 +939,7 @@ def mount_iso(
|
||||||
re.match('.+BDMV[/\\]STREAM[/\\][0-9]+[0-9].[Mm]', full_path)
|
re.match('.+BDMV[/\\]STREAM[/\\][0-9]+[0-9].[Mm]', full_path)
|
||||||
and '.mts' not in nzb2media.IGNOREEXTENSIONS
|
and '.mts' not in nzb2media.IGNOREEXTENSIONS
|
||||||
):
|
):
|
||||||
logger.debug(
|
log.debug(f'Found MTS image file: {full_path}')
|
||||||
f'Found MTS image file: {full_path}', 'TRANSCODER',
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
mts_path = re.match(
|
mts_path = re.match(
|
||||||
'(.+BDMV[/\\]STREAM)', full_path,
|
'(.+BDMV[/\\]STREAM)', full_path,
|
||||||
|
@ -974,10 +947,7 @@ def mount_iso(
|
||||||
except Exception:
|
except Exception:
|
||||||
mts_path = os.path.split(full_path)[0]
|
mts_path = os.path.split(full_path)[0]
|
||||||
return combine_mts(mts_path)
|
return combine_mts(mts_path)
|
||||||
logger.error(
|
log.error(f'No VIDEO_TS or BDMV/SOURCE folder found in image file {mount_point}')
|
||||||
f'No VIDEO_TS or BDMV/SOURCE folder found in image file {mount_point}',
|
|
||||||
'TRANSCODER',
|
|
||||||
)
|
|
||||||
return ['failure'] # If we got here, nothing matched our criteria
|
return ['failure'] # If we got here, nothing matched our criteria
|
||||||
|
|
||||||
|
|
||||||
|
@ -986,27 +956,18 @@ def rip_iso(item, new_dir, bitbucket):
|
||||||
failure_dir = 'failure'
|
failure_dir = 'failure'
|
||||||
# Mount the ISO in your OS and call combineVTS.
|
# Mount the ISO in your OS and call combineVTS.
|
||||||
if not nzb2media.SEVENZIP:
|
if not nzb2media.SEVENZIP:
|
||||||
logger.debug(
|
log.debug(f'No 7zip installed. Attempting to mount image file {item}')
|
||||||
f'No 7zip installed. Attempting to mount image file {item}',
|
|
||||||
'TRANSCODER',
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
new_files = mount_iso(
|
new_files = mount_iso(
|
||||||
item, new_dir, bitbucket,
|
item, new_dir, bitbucket,
|
||||||
) # Currently only works for Linux.
|
) # Currently only works for Linux.
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error(
|
log.error(f'Failed to mount and extract from image file {item}')
|
||||||
f'Failed to mount and extract from image file {item}',
|
|
||||||
'TRANSCODER',
|
|
||||||
)
|
|
||||||
new_files = [failure_dir]
|
new_files = [failure_dir]
|
||||||
return new_files
|
return new_files
|
||||||
cmd = [nzb2media.SEVENZIP, 'l', item]
|
cmd = [nzb2media.SEVENZIP, 'l', item]
|
||||||
try:
|
try:
|
||||||
logger.debug(
|
log.debug(f'Attempting to extract .vob or .mts from image file {item}')
|
||||||
f'Attempting to extract .vob or .mts from image file {item}',
|
|
||||||
'TRANSCODER',
|
|
||||||
)
|
|
||||||
print_cmd(cmd)
|
print_cmd(cmd)
|
||||||
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=bitbucket)
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=bitbucket)
|
||||||
out, err = proc.communicate()
|
out, err = proc.communicate()
|
||||||
|
@ -1078,13 +1039,10 @@ def rip_iso(item, new_dir, bitbucket):
|
||||||
name = os.path.splitext(os.path.split(item)[1])[0]
|
name = os.path.splitext(os.path.split(item)[1])[0]
|
||||||
new_files.append({item: {'name': name, 'files': combined}})
|
new_files.append({item: {'name': name, 'files': combined}})
|
||||||
if not new_files:
|
if not new_files:
|
||||||
logger.error(
|
log.error(f'No VIDEO_TS or BDMV/SOURCE folder found in image file. Attempting to mount and scan {item}')
|
||||||
f'No VIDEO_TS or BDMV/SOURCE folder found in image file. Attempting to mount and scan {item}',
|
|
||||||
'TRANSCODER',
|
|
||||||
)
|
|
||||||
new_files = mount_iso(item, new_dir, bitbucket)
|
new_files = mount_iso(item, new_dir, bitbucket)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error(f'Failed to extract from image file {item}', 'TRANSCODER')
|
log.error(f'Failed to extract from image file {item}')
|
||||||
new_files = [failure_dir]
|
new_files = [failure_dir]
|
||||||
return new_files
|
return new_files
|
||||||
|
|
||||||
|
@ -1184,13 +1142,13 @@ def print_cmd(command):
|
||||||
cmd = ''
|
cmd = ''
|
||||||
for item in command:
|
for item in command:
|
||||||
cmd = f'{cmd} {item}'
|
cmd = f'{cmd} {item}'
|
||||||
logger.debug(f'calling command:{cmd}')
|
log.debug(f'calling command:{cmd}')
|
||||||
|
|
||||||
|
|
||||||
def transcode_directory(dir_name):
|
def transcode_directory(dir_name):
|
||||||
if not nzb2media.FFMPEG:
|
if not nzb2media.FFMPEG:
|
||||||
return 1, dir_name
|
return 1, dir_name
|
||||||
logger.info('Checking for files to be transcoded')
|
log.info('Checking for files to be transcoded')
|
||||||
final_result = 0 # initialize as successful
|
final_result = 0 # initialize as successful
|
||||||
if nzb2media.OUTPUTVIDEOPATH:
|
if nzb2media.OUTPUTVIDEOPATH:
|
||||||
new_dir = nzb2media.OUTPUTVIDEOPATH
|
new_dir = nzb2media.OUTPUTVIDEOPATH
|
||||||
|
@ -1230,15 +1188,15 @@ def transcode_directory(dir_name):
|
||||||
|
|
||||||
try: # Try to remove the file that we're transcoding to just in case. (ffmpeg will return an error if it already exists for some reason)
|
try: # Try to remove the file that we're transcoding to just in case. (ffmpeg will return an error if it already exists for some reason)
|
||||||
os.remove(newfile_path)
|
os.remove(newfile_path)
|
||||||
except OSError as e:
|
except OSError as error:
|
||||||
if (
|
if (
|
||||||
e.errno != errno.ENOENT
|
error.errno != errno.ENOENT
|
||||||
): # Ignore the error if it's just telling us that the file doesn't exist
|
): # Ignore the error if it's just telling us that the file doesn't exist
|
||||||
logger.debug(f'Error when removing transcoding target: {e}')
|
log.debug(f'Error when removing transcoding target: {error}')
|
||||||
except Exception as e:
|
except Exception as error:
|
||||||
logger.debug(f'Error when removing transcoding target: {e}')
|
log.debug(f'Error when removing transcoding target: {error}')
|
||||||
|
|
||||||
logger.info(f'Transcoding video: {newfile_path}')
|
log.info(f'Transcoding video: {newfile_path}')
|
||||||
print_cmd(command)
|
print_cmd(command)
|
||||||
result = 1 # set result to failed in case call fails.
|
result = 1 # set result to failed in case call fails.
|
||||||
try:
|
try:
|
||||||
|
@ -1257,15 +1215,15 @@ def transcode_directory(dir_name):
|
||||||
for vob in data['files']:
|
for vob in data['files']:
|
||||||
procin = zip_out(vob, img, bitbucket)
|
procin = zip_out(vob, img, bitbucket)
|
||||||
if procin:
|
if procin:
|
||||||
logger.debug(f'Feeding in file: {vob} to Transcoder')
|
log.debug(f'Feeding in file: {vob} to Transcoder')
|
||||||
shutil.copyfileobj(procin.stdout, proc.stdin)
|
shutil.copyfileobj(procin.stdout, proc.stdin)
|
||||||
procin.stdout.close()
|
procin.stdout.close()
|
||||||
out, err = proc.communicate()
|
out, err = proc.communicate()
|
||||||
if err:
|
if err:
|
||||||
logger.error(f'Transcoder returned:{err} has failed')
|
log.error(f'Transcoder returned:{err} has failed')
|
||||||
result = proc.returncode
|
result = proc.returncode
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.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 result == 0 and isinstance(file, str):
|
||||||
for sub in get_subs(file):
|
for sub in get_subs(file):
|
||||||
|
@ -1283,7 +1241,7 @@ def transcode_directory(dir_name):
|
||||||
shutil.copymode(file, newfile_path)
|
shutil.copymode(file, newfile_path)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
logger.info(f'Transcoding of video to {newfile_path} succeeded')
|
log.info(f'Transcoding of video to {newfile_path} succeeded')
|
||||||
if os.path.isfile(newfile_path) and (
|
if os.path.isfile(newfile_path) and (
|
||||||
file in new_list or not nzb2media.DUPLICATE
|
file in new_list or not nzb2media.DUPLICATE
|
||||||
):
|
):
|
||||||
|
@ -1292,9 +1250,7 @@ def transcode_directory(dir_name):
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
logger.error(
|
log.error(f'Transcoding of video to {newfile_path} failed with result {result}')
|
||||||
f'Transcoding of video to {newfile_path} failed with result {result}',
|
|
||||||
)
|
|
||||||
# this will be 0 (successful) it all are successful, else will return a positive integer for failure.
|
# this will be 0 (successful) it all are successful, else will return a positive integer for failure.
|
||||||
final_result = final_result + result
|
final_result = final_result + result
|
||||||
if nzb2media.MOUNTED: # In case we mounted an .iso file, unmount here.
|
if nzb2media.MOUNTED: # In case we mounted an .iso file, unmount here.
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
from subprocess import Popen
|
from subprocess import Popen
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger, transcoder
|
from nzb2media import transcoder
|
||||||
from nzb2media.auto_process.common import ProcessResult
|
from nzb2media.auto_process.common import ProcessResult
|
||||||
from nzb2media.plugins.subtitles import import_subs
|
from nzb2media.plugins.subtitles import import_subs
|
||||||
from nzb2media.utils.files import list_media_files
|
from nzb2media.utils.files import list_media_files
|
||||||
from nzb2media.utils.paths import remove_dir
|
from nzb2media.utils.paths import remove_dir
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def external_script(output_destination, torrent_name, torrent_label, settings):
|
def external_script(output_destination, torrent_name, torrent_label, settings):
|
||||||
final_result = 0 # start at 0.
|
final_result = 0 # start at 0.
|
||||||
|
@ -23,9 +27,7 @@ def external_script(output_destination, torrent_name, torrent_label, settings):
|
||||||
nzb2media.USER_SCRIPT_MEDIAEXTENSIONS.lower().split(',')
|
nzb2media.USER_SCRIPT_MEDIAEXTENSIONS.lower().split(',')
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error(
|
log.error('user_script_mediaExtensions could not be set')
|
||||||
'user_script_mediaExtensions could not be set', 'USERSCRIPT',
|
|
||||||
)
|
|
||||||
nzb2media.USER_SCRIPT_MEDIAEXTENSIONS = []
|
nzb2media.USER_SCRIPT_MEDIAEXTENSIONS = []
|
||||||
|
|
||||||
nzb2media.USER_SCRIPT = settings.get('user_script_path', '')
|
nzb2media.USER_SCRIPT = settings.get('user_script_path', '')
|
||||||
|
@ -42,7 +44,7 @@ def external_script(output_destination, torrent_name, torrent_label, settings):
|
||||||
if isinstance(nzb2media.USER_SCRIPT_PARAM, str):
|
if isinstance(nzb2media.USER_SCRIPT_PARAM, str):
|
||||||
nzb2media.USER_SCRIPT_PARAM = nzb2media.USER_SCRIPT_PARAM.split(',')
|
nzb2media.USER_SCRIPT_PARAM = nzb2media.USER_SCRIPT_PARAM.split(',')
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error('user_script_params could not be set', 'USERSCRIPT')
|
log.error('user_script_params could not be set')
|
||||||
nzb2media.USER_SCRIPT_PARAM = []
|
nzb2media.USER_SCRIPT_PARAM = []
|
||||||
|
|
||||||
nzb2media.USER_SCRIPT_SUCCESSCODES = settings.get('user_script_successCodes', 0)
|
nzb2media.USER_SCRIPT_SUCCESSCODES = settings.get('user_script_successCodes', 0)
|
||||||
|
@ -52,7 +54,7 @@ def external_script(output_destination, torrent_name, torrent_label, settings):
|
||||||
nzb2media.USER_SCRIPT_SUCCESSCODES.split(',')
|
nzb2media.USER_SCRIPT_SUCCESSCODES.split(',')
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error('user_script_successCodes could not be set', 'USERSCRIPT')
|
log.error('user_script_successCodes could not be set')
|
||||||
nzb2media.USER_SCRIPT_SUCCESSCODES = 0
|
nzb2media.USER_SCRIPT_SUCCESSCODES = 0
|
||||||
|
|
||||||
nzb2media.USER_SCRIPT_CLEAN = int(settings.get('user_script_clean', 1))
|
nzb2media.USER_SCRIPT_CLEAN = int(settings.get('user_script_clean', 1))
|
||||||
|
@ -69,10 +71,7 @@ def external_script(output_destination, torrent_name, torrent_label, settings):
|
||||||
if transcoder.is_video_good(video, 0):
|
if transcoder.is_video_good(video, 0):
|
||||||
import_subs(video)
|
import_subs(video)
|
||||||
else:
|
else:
|
||||||
logger.info(
|
log.info(f'Corrupt video file found {video}. Deleting.')
|
||||||
f'Corrupt video file found {video}. Deleting.',
|
|
||||||
'USERSCRIPT',
|
|
||||||
)
|
|
||||||
os.unlink(video)
|
os.unlink(video)
|
||||||
|
|
||||||
for dirpath, _, filenames in os.walk(output_destination):
|
for dirpath, _, filenames in os.walk(output_destination):
|
||||||
|
@ -80,10 +79,7 @@ def external_script(output_destination, torrent_name, torrent_label, settings):
|
||||||
|
|
||||||
file_path = nzb2media.os.path.join(dirpath, file)
|
file_path = nzb2media.os.path.join(dirpath, file)
|
||||||
file_name, file_extension = os.path.splitext(file)
|
file_name, file_extension = os.path.splitext(file)
|
||||||
logger.debug(
|
log.debug(f'Checking file {file} to see if this should be processed.')
|
||||||
f'Checking file {file} to see if this should be processed.',
|
|
||||||
'USERSCRIPT',
|
|
||||||
)
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
file_extension in nzb2media.USER_SCRIPT_MEDIAEXTENSIONS
|
file_extension in nzb2media.USER_SCRIPT_MEDIAEXTENSIONS
|
||||||
|
@ -120,31 +116,21 @@ def external_script(output_destination, torrent_name, torrent_label, settings):
|
||||||
cmd = ''
|
cmd = ''
|
||||||
for item in command:
|
for item in command:
|
||||||
cmd = f'{cmd} {item}'
|
cmd = f'{cmd} {item}'
|
||||||
logger.info(
|
log.info(f'Running script {cmd} on file {file_path}.')
|
||||||
f'Running script {cmd} on file {file_path}.', 'USERSCRIPT',
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
p = Popen(command)
|
p = Popen(command)
|
||||||
res = p.wait()
|
res = p.wait()
|
||||||
if (
|
if (
|
||||||
str(res) in nzb2media.USER_SCRIPT_SUCCESSCODES
|
str(res) in nzb2media.USER_SCRIPT_SUCCESSCODES
|
||||||
): # Linux returns 0 for successful.
|
): # Linux returns 0 for successful.
|
||||||
logger.info(f'UserScript {command[0]} was successfull')
|
log.info(f'UserScript {command[0]} was successfull')
|
||||||
result = 0
|
result = 0
|
||||||
else:
|
else:
|
||||||
logger.error(
|
log.error(f'UserScript {command[0]} has failed with return code: {res}')
|
||||||
f'UserScript {command[0]} has failed with return code: {res}',
|
log.info(f'If the UserScript completed successfully you should add {res} to the user_script_successCodes')
|
||||||
'USERSCRIPT',
|
|
||||||
)
|
|
||||||
logger.info(
|
|
||||||
f'If the UserScript completed successfully you should add {res} to the user_script_successCodes',
|
|
||||||
'USERSCRIPT',
|
|
||||||
)
|
|
||||||
result = int(1)
|
result = int(1)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error(
|
log.error(f'UserScript {command[0]} has failed')
|
||||||
f'UserScript {command[0]} has failed', 'USERSCRIPT',
|
|
||||||
)
|
|
||||||
result = int(1)
|
result = int(1)
|
||||||
final_result += result
|
final_result += result
|
||||||
|
|
||||||
|
@ -164,14 +150,10 @@ def external_script(output_destination, torrent_name, torrent_label, settings):
|
||||||
and num_files_new == 0
|
and num_files_new == 0
|
||||||
and final_result == 0
|
and final_result == 0
|
||||||
):
|
):
|
||||||
logger.info(
|
log.info(f'All files have been processed. Cleaning outputDirectory {output_destination}')
|
||||||
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 == int(1) and num_files_new != 0:
|
||||||
logger.info(
|
log.info(f'{num_files} files were processed, but {num_files_new} still remain. outputDirectory will not be cleaned.')
|
||||||
f'{num_files} files were processed, but {num_files_new} still remain. outputDirectory will not be cleaned.',
|
|
||||||
)
|
|
||||||
return ProcessResult(
|
return ProcessResult(
|
||||||
status_code=final_result,
|
status_code=final_result,
|
||||||
message='User Script Completed',
|
message='User Script Completed',
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os.path
|
import os.path
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media.utils.files import list_media_files
|
from nzb2media.utils.files import list_media_files
|
||||||
from nzb2media.utils.files import move_file
|
from nzb2media.utils.files import move_file
|
||||||
from nzb2media.utils.paths import clean_directory
|
from nzb2media.utils.paths import clean_directory
|
||||||
from nzb2media.utils.paths import flatten_dir
|
from nzb2media.utils.paths import flatten_dir
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def flatten(output_destination):
|
def flatten(output_destination):
|
||||||
return flatten_dir(
|
return flatten_dir(
|
||||||
|
@ -33,7 +36,7 @@ def clean_dir(path, section, subsection):
|
||||||
def process_dir(path, link):
|
def process_dir(path, link):
|
||||||
folders = []
|
folders = []
|
||||||
|
|
||||||
logger.info(f'Searching {path} for mediafiles to post-process ...')
|
log.info(f'Searching {path} for mediafiles to post-process ...')
|
||||||
dir_contents = os.listdir(path)
|
dir_contents = os.listdir(path)
|
||||||
|
|
||||||
# search for single files and move them into their own folder for post-processing
|
# search for single files and move them into their own folder for post-processing
|
||||||
|
@ -55,16 +58,12 @@ def process_dir(path, link):
|
||||||
# Generate a list of media files
|
# Generate a list of media files
|
||||||
mediafiles = (item for item in filepaths if os.path.isfile(item))
|
mediafiles = (item for item in filepaths if os.path.isfile(item))
|
||||||
|
|
||||||
if any(sync_files):
|
if not any(sync_files):
|
||||||
logger.info('')
|
|
||||||
else:
|
|
||||||
for mediafile in mediafiles:
|
for mediafile in mediafiles:
|
||||||
try:
|
try:
|
||||||
move_file(mediafile, path, link)
|
move_file(mediafile, path, link)
|
||||||
except Exception as e:
|
except Exception as error:
|
||||||
logger.error(
|
log.error(f'Failed to move {os.path.split(mediafile)[1]} to its own directory: {error}')
|
||||||
f'Failed to move {os.path.split(mediafile)[1]} to its own directory: {e}',
|
|
||||||
)
|
|
||||||
|
|
||||||
# removeEmptyFolders(path, removeRoot=False)
|
# removeEmptyFolders(path, removeRoot=False)
|
||||||
|
|
||||||
|
@ -99,25 +98,19 @@ def get_dirs(section, subsection, link='hard'):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
to_return.extend(process_dir(directory, link))
|
to_return.extend(process_dir(directory, link))
|
||||||
except Exception as e:
|
except Exception as error:
|
||||||
logger.error(
|
log.error(f'Failed to add directories from {watch_directory} for post-processing: {error}')
|
||||||
f'Failed to add directories from {watch_directory} for post-processing: {e}',
|
|
||||||
)
|
|
||||||
|
|
||||||
if nzb2media.USE_LINK == 'move':
|
if nzb2media.USE_LINK == 'move':
|
||||||
try:
|
try:
|
||||||
output_directory = os.path.join(nzb2media.OUTPUT_DIRECTORY, subsection)
|
output_directory = os.path.join(nzb2media.OUTPUT_DIRECTORY, subsection)
|
||||||
if os.path.exists(output_directory):
|
if os.path.exists(output_directory):
|
||||||
to_return.extend(process_dir(output_directory, link))
|
to_return.extend(process_dir(output_directory, link))
|
||||||
except Exception as e:
|
except Exception as error:
|
||||||
logger.error(
|
log.error(f'Failed to add directories from {nzb2media.OUTPUT_DIRECTORY} for post-processing: {error}')
|
||||||
f'Failed to add directories from {nzb2media.OUTPUT_DIRECTORY} for post-processing: {e}',
|
|
||||||
)
|
|
||||||
|
|
||||||
if not to_return:
|
if not to_return:
|
||||||
logger.debug(
|
log.debug(f'No directories identified in {section}:{subsection} for post-processing')
|
||||||
f'No directories identified in {section}:{subsection} for post-processing',
|
|
||||||
)
|
|
||||||
|
|
||||||
return list(set(to_return))
|
return list(set(to_return))
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,25 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import logging
|
||||||
|
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media import main_db
|
from nzb2media import main_db
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
database = main_db.DBConnection()
|
database = main_db.DBConnection()
|
||||||
|
|
||||||
|
|
||||||
def update_download_info_status(input_name, status):
|
def update_download_info_status(input_name, status):
|
||||||
msg = 'Updating DB download status of {0} to {1}'
|
log.debug(f'Updating DB download status of {input_name} to {status}')
|
||||||
action = 'UPDATE downloads SET status=?, last_update=? WHERE input_name=?'
|
action = 'UPDATE downloads SET status=?, last_update=? WHERE input_name=?'
|
||||||
args = [status, datetime.date.today().toordinal(), input_name]
|
args = [status, datetime.date.today().toordinal(), input_name]
|
||||||
logger.db(msg.format(input_name, status))
|
|
||||||
database.action(action, args)
|
database.action(action, args)
|
||||||
|
|
||||||
|
|
||||||
def get_download_info(input_name, status):
|
def get_download_info(input_name, status):
|
||||||
msg = 'Getting download info for {0} from the DB'
|
log.debug(f'Getting download info for {input_name} from the DB')
|
||||||
action = 'SELECT * FROM downloads WHERE input_name=? AND status=?'
|
action = 'SELECT * FROM downloads WHERE input_name=? AND status=?'
|
||||||
args = [input_name, status]
|
args = [input_name, status]
|
||||||
logger.db(msg.format(input_name))
|
|
||||||
return database.select(action, args)
|
return database.select(action, args)
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def char_replace(name_in):
|
def char_replace(name_in):
|
||||||
|
@ -70,7 +73,7 @@ def convert_to_ascii(input_name, dir_name):
|
||||||
encoded, base2 = char_replace(base)
|
encoded, base2 = char_replace(base)
|
||||||
if encoded:
|
if encoded:
|
||||||
dir_name = os.path.join(directory, base2)
|
dir_name = os.path.join(directory, base2)
|
||||||
logger.info(f'Renaming directory to: {base2}.', 'ENCODER')
|
log.info(f'Renaming directory to: {base2}.')
|
||||||
os.rename(os.path.join(directory, base), dir_name)
|
os.rename(os.path.join(directory, base), dir_name)
|
||||||
if 'NZBOP_SCRIPTDIR' in os.environ:
|
if 'NZBOP_SCRIPTDIR' in os.environ:
|
||||||
print(f'[NZB] DIRECTORY={dir_name}')
|
print(f'[NZB] DIRECTORY={dir_name}')
|
||||||
|
@ -79,9 +82,7 @@ def convert_to_ascii(input_name, dir_name):
|
||||||
for subdirname in dirnames:
|
for subdirname in dirnames:
|
||||||
encoded, subdirname2 = char_replace(subdirname)
|
encoded, subdirname2 = char_replace(subdirname)
|
||||||
if encoded:
|
if encoded:
|
||||||
logger.info(
|
log.info(f'Renaming directory to: {subdirname2}.')
|
||||||
f'Renaming directory to: {subdirname2}.', 'ENCODER',
|
|
||||||
)
|
|
||||||
os.rename(
|
os.rename(
|
||||||
os.path.join(dirname, subdirname),
|
os.path.join(dirname, subdirname),
|
||||||
os.path.join(dirname, subdirname2),
|
os.path.join(dirname, subdirname2),
|
||||||
|
@ -91,7 +92,7 @@ def convert_to_ascii(input_name, dir_name):
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
encoded, filename2 = char_replace(filename)
|
encoded, filename2 = char_replace(filename)
|
||||||
if encoded:
|
if encoded:
|
||||||
logger.info(f'Renaming file to: {filename2}.', 'ENCODER')
|
log.info(f'Renaming file to: {filename2}.')
|
||||||
os.rename(
|
os.rename(
|
||||||
os.path.join(dirname, filename),
|
os.path.join(dirname, filename),
|
||||||
os.path.join(dirname, filename2),
|
os.path.join(dirname, filename2),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
|
@ -11,18 +12,18 @@ import mediafile
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import extractor
|
from nzb2media import extractor
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media.utils.links import copy_link
|
from nzb2media.utils.links import copy_link
|
||||||
from nzb2media.utils.naming import is_sample
|
from nzb2media.utils.naming import is_sample
|
||||||
from nzb2media.utils.naming import sanitize_name
|
from nzb2media.utils.naming import sanitize_name
|
||||||
from nzb2media.utils.paths import get_dir_size
|
from nzb2media.utils.paths import get_dir_size
|
||||||
from nzb2media.utils.paths import make_dir
|
from nzb2media.utils.paths import make_dir
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def move_file(filename, path, link):
|
def move_file(filename, path, link):
|
||||||
logger.debug(
|
log.debug(f'Found file {os.path.split(filename)[1]} in root directory {path}.')
|
||||||
f'Found file {os.path.split(filename)[1]} in root directory {path}.',
|
|
||||||
)
|
|
||||||
new_path = None
|
new_path = None
|
||||||
file_ext = os.path.splitext(filename)[1]
|
file_ext = os.path.splitext(filename)[1]
|
||||||
try:
|
try:
|
||||||
|
@ -47,10 +48,8 @@ def move_file(filename, path, link):
|
||||||
title = os.path.splitext(os.path.basename(filename))[0]
|
title = os.path.splitext(os.path.basename(filename))[0]
|
||||||
|
|
||||||
new_path = os.path.join(path, sanitize_name(title))
|
new_path = os.path.join(path, sanitize_name(title))
|
||||||
except Exception as e:
|
except Exception as error:
|
||||||
logger.error(
|
log.error(f'Exception parsing name for media file: {os.path.split(filename)[1]}: {error}')
|
||||||
f'Exception parsing name for media file: {os.path.split(filename)[1]}: {e}',
|
|
||||||
)
|
|
||||||
|
|
||||||
if not new_path:
|
if not new_path:
|
||||||
title = os.path.splitext(os.path.basename(filename))[0]
|
title = os.path.splitext(os.path.basename(filename))[0]
|
||||||
|
@ -95,9 +94,7 @@ def is_min_size(input_name, min_size):
|
||||||
try:
|
try:
|
||||||
input_size = get_dir_size(os.path.dirname(input_name))
|
input_size = get_dir_size(os.path.dirname(input_name))
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error(
|
log.error(f'Failed to get file size for {input_name}')
|
||||||
f'Failed to get file size for {input_name}', 'MINSIZE',
|
|
||||||
)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Ignore files under a certain size
|
# Ignore files under a certain size
|
||||||
|
@ -171,9 +168,7 @@ def list_media_files(
|
||||||
if delete_ignored == 1:
|
if delete_ignored == 1:
|
||||||
try:
|
try:
|
||||||
os.unlink(path)
|
os.unlink(path)
|
||||||
logger.debug(
|
log.debug(f'Ignored file {cur_file} has been removed ...')
|
||||||
f'Ignored file {cur_file} has been removed ...',
|
|
||||||
)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
@ -208,9 +203,7 @@ def list_media_files(
|
||||||
if delete_ignored == 1:
|
if delete_ignored == 1:
|
||||||
try:
|
try:
|
||||||
os.unlink(full_cur_file)
|
os.unlink(full_cur_file)
|
||||||
logger.debug(
|
log.debug(f'Ignored file {cur_file} has been removed ...')
|
||||||
f'Ignored file {cur_file} has been removed ...',
|
|
||||||
)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
continue
|
continue
|
||||||
|
@ -240,7 +233,7 @@ def extract_files(src, dst=None, keep_archive=None):
|
||||||
extracted_folder.append(dir_path)
|
extracted_folder.append(dir_path)
|
||||||
extracted_archive.append(archive_name)
|
extracted_archive.append(archive_name)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error(f'Extraction failed for: {full_file_name}')
|
log.error(f'Extraction failed for: {full_file_name}')
|
||||||
|
|
||||||
for folder in extracted_folder:
|
for folder in extracted_folder:
|
||||||
for inputFile in list_media_files(
|
for inputFile in list_media_files(
|
||||||
|
@ -251,52 +244,34 @@ def extract_files(src, dst=None, keep_archive=None):
|
||||||
archive_name = re.sub(r'part[0-9]+', '', archive_name)
|
archive_name = re.sub(r'part[0-9]+', '', archive_name)
|
||||||
if archive_name not in extracted_archive or keep_archive:
|
if archive_name not in extracted_archive or keep_archive:
|
||||||
continue # don't remove if we haven't extracted this archive, or if we want to preserve them.
|
continue # don't remove if we haven't extracted this archive, or if we want to preserve them.
|
||||||
logger.info(
|
log.info(f'Removing extracted archive {full_file_name} from folder {folder} ...')
|
||||||
f'Removing extracted archive {full_file_name} from folder {folder} ...',
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
if not os.access(inputFile, os.W_OK):
|
if not os.access(inputFile, os.W_OK):
|
||||||
os.chmod(inputFile, stat.S_IWUSR)
|
os.chmod(inputFile, stat.S_IWUSR)
|
||||||
os.remove(inputFile)
|
os.remove(inputFile)
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
except Exception as e:
|
except Exception as error:
|
||||||
logger.error(f'Unable to remove file {inputFile} due to: {e}')
|
log.error(f'Unable to remove file {inputFile} due to: {error}')
|
||||||
|
|
||||||
|
|
||||||
def backup_versioned_file(old_file, version):
|
def backup_versioned_file(old_file, version):
|
||||||
num_tries = 0
|
num_tries = 0
|
||||||
|
|
||||||
new_file = f'{old_file}.v{version}'
|
new_file = f'{old_file}.v{version}'
|
||||||
|
|
||||||
while not os.path.isfile(new_file):
|
while not os.path.isfile(new_file):
|
||||||
if not os.path.isfile(old_file):
|
if not os.path.isfile(old_file):
|
||||||
logger.log(
|
log.debug(f'Not creating backup, {old_file} doesn\'t exist')
|
||||||
f'Not creating backup, {old_file} doesn\'t exist', logger.DEBUG,
|
|
||||||
)
|
|
||||||
break
|
break
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logger.log(
|
log.debug(f'Trying to back up {old_file} to {new_file}')
|
||||||
f'Trying to back up {old_file} to {new_file}',
|
|
||||||
logger.DEBUG,
|
|
||||||
)
|
|
||||||
shutil.copy(old_file, new_file)
|
shutil.copy(old_file, new_file)
|
||||||
logger.log('Backup done', logger.DEBUG)
|
log.debug('Backup done')
|
||||||
break
|
break
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.log(
|
log.warning(f'Error while trying to back up {old_file} to {new_file} : {error}')
|
||||||
f'Error while trying to back up {old_file} to {new_file} : {error}',
|
|
||||||
logger.WARNING,
|
|
||||||
)
|
|
||||||
num_tries += 1
|
num_tries += 1
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
logger.log('Trying again.', logger.DEBUG)
|
log.debug('Trying again.')
|
||||||
|
|
||||||
if num_tries >= 10:
|
if num_tries >= 10:
|
||||||
logger.log(
|
log.error(f'Unable to back up {old_file} to {new_file} please do it manually.')
|
||||||
f'Unable to back up {old_file} to {new_file} please do it manually.',
|
|
||||||
logger.ERROR,
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -1,33 +1,35 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
import guessit
|
import guessit
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media.utils.naming import sanitize_name
|
from nzb2media.utils.naming import sanitize_name
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def find_imdbid(dir_name, input_name, omdb_api_key):
|
def find_imdbid(dir_name, input_name, omdb_api_key):
|
||||||
imdbid = None
|
imdbid = None
|
||||||
|
log.info(f'Attemping imdbID lookup for {input_name}')
|
||||||
logger.info(f'Attemping imdbID lookup for {input_name}')
|
|
||||||
|
|
||||||
# find imdbid in dirName
|
# find imdbid in dirName
|
||||||
logger.info('Searching folder and file names for imdbID ...')
|
log.info('Searching folder and file names for imdbID ...')
|
||||||
m = re.search(r'\b(tt\d{7,8})\b', dir_name + input_name)
|
m = re.search(r'\b(tt\d{7,8})\b', dir_name + input_name)
|
||||||
if m:
|
if m:
|
||||||
imdbid = m.group(1)
|
imdbid = m.group(1)
|
||||||
logger.info(f'Found imdbID [{imdbid}]')
|
log.info(f'Found imdbID [{imdbid}]')
|
||||||
return imdbid
|
return imdbid
|
||||||
if os.path.isdir(dir_name):
|
if os.path.isdir(dir_name):
|
||||||
for file in os.listdir(dir_name):
|
for file in os.listdir(dir_name):
|
||||||
m = re.search(r'\b(tt\d{7,8})\b', file)
|
m = re.search(r'\b(tt\d{7,8})\b', file)
|
||||||
if m:
|
if m:
|
||||||
imdbid = m.group(1)
|
imdbid = m.group(1)
|
||||||
logger.info(f'Found imdbID [{imdbid}] via file name')
|
log.info(f'Found imdbID [{imdbid}] via file name')
|
||||||
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', '')
|
||||||
|
@ -38,9 +40,9 @@ def find_imdbid(dir_name, input_name, omdb_api_key):
|
||||||
m = regex.match(dnzb_more_info)
|
m = regex.match(dnzb_more_info)
|
||||||
if m:
|
if m:
|
||||||
imdbid = m.group(1)
|
imdbid = m.group(1)
|
||||||
logger.info(f'Found imdbID [{imdbid}] from DNZB-MoreInfo')
|
log.info(f'Found imdbID [{imdbid}] from DNZB-MoreInfo')
|
||||||
return imdbid
|
return imdbid
|
||||||
logger.info('Searching IMDB for imdbID ...')
|
log.info('Searching IMDB for imdbID ...')
|
||||||
try:
|
try:
|
||||||
guess = guessit.guessit(input_name)
|
guess = guessit.guessit(input_name)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -59,12 +61,10 @@ def find_imdbid(dir_name, input_name, omdb_api_key):
|
||||||
url = 'http://www.omdbapi.com'
|
url = 'http://www.omdbapi.com'
|
||||||
|
|
||||||
if not omdb_api_key:
|
if not omdb_api_key:
|
||||||
logger.info(
|
log.info('Unable to determine imdbID: No api key provided for omdbapi.com.')
|
||||||
'Unable to determine imdbID: No api key provided for omdbapi.com.',
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.debug(f'Opening URL: {url}')
|
log.debug(f'Opening URL: {url}')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
r = requests.get(
|
r = requests.get(
|
||||||
|
@ -74,24 +74,24 @@ def find_imdbid(dir_name, input_name, omdb_api_key):
|
||||||
timeout=(60, 300),
|
timeout=(60, 300),
|
||||||
)
|
)
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.error(f'Unable to open URL {url}')
|
log.error(f'Unable to open URL {url}')
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
results = r.json()
|
results = r.json()
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error('No json data returned from omdbapi.com')
|
log.error('No json data returned from omdbapi.com')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
imdbid = results['imdbID']
|
imdbid = results['imdbID']
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error('No imdbID returned from omdbapi.com')
|
log.error('No imdbID returned from omdbapi.com')
|
||||||
|
|
||||||
if imdbid:
|
if imdbid:
|
||||||
logger.info(f'Found imdbID [{imdbid}]')
|
log.info(f'Found imdbID [{imdbid}]')
|
||||||
return imdbid
|
return imdbid
|
||||||
|
|
||||||
logger.warning(f'Unable to find a imdbID for {input_name}')
|
log.warning(f'Unable to find a imdbID for {input_name}')
|
||||||
return imdbid
|
return imdbid
|
||||||
|
|
||||||
|
|
||||||
|
@ -106,78 +106,59 @@ def category_search(
|
||||||
pathlist = os.path.normpath(input_directory).split(os.sep)
|
pathlist = os.path.normpath(input_directory).split(os.sep)
|
||||||
|
|
||||||
if input_category and input_category in pathlist:
|
if input_category and input_category in pathlist:
|
||||||
logger.debug(
|
log.debug(f'SEARCH: Found the Category: {input_category} in directory structure')
|
||||||
f'SEARCH: Found the Category: {input_category} in directory structure',
|
|
||||||
)
|
|
||||||
elif input_category:
|
elif input_category:
|
||||||
logger.debug(
|
log.debug(f'SEARCH: Could not find the category: {input_category} in the directory structure')
|
||||||
f'SEARCH: Could not find the category: {input_category} in the directory structure',
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
input_category = list(set(pathlist) & set(categories))[
|
input_category = list(set(pathlist) & set(categories))[
|
||||||
-1
|
-1
|
||||||
] # assume last match is most relevant category.
|
] # assume last match is most relevant category.
|
||||||
logger.debug(
|
log.debug(f'SEARCH: Found Category: {input_category} in directory structure')
|
||||||
f'SEARCH: Found Category: {input_category} in directory structure',
|
|
||||||
)
|
|
||||||
except IndexError:
|
except IndexError:
|
||||||
input_category = ''
|
input_category = ''
|
||||||
logger.debug(
|
log.debug('SEARCH: Could not find a category in the directory structure')
|
||||||
'SEARCH: Could not find a category in the directory structure',
|
|
||||||
)
|
|
||||||
if not os.path.isdir(input_directory) and os.path.isfile(
|
if not os.path.isdir(input_directory) and os.path.isfile(
|
||||||
input_directory,
|
input_directory,
|
||||||
): # If the input directory is a file
|
): # If the input directory is a file
|
||||||
if not input_name:
|
if not input_name:
|
||||||
input_name = os.path.split(os.path.normpath(input_directory))[1]
|
input_name = os.path.split(os.path.normpath(input_directory))[1]
|
||||||
return input_directory, input_name, input_category, root
|
return input_directory, input_name, input_category, root
|
||||||
|
|
||||||
if input_category and os.path.isdir(
|
if input_category and os.path.isdir(
|
||||||
os.path.join(input_directory, input_category),
|
os.path.join(input_directory, input_category),
|
||||||
):
|
):
|
||||||
logger.info(
|
log.info(f'SEARCH: Found category directory {input_category} in input directory directory {input_directory}')
|
||||||
f'SEARCH: Found category directory {input_category} in input directory directory {input_directory}',
|
|
||||||
)
|
|
||||||
input_directory = os.path.join(input_directory, input_category)
|
input_directory = os.path.join(input_directory, input_category)
|
||||||
logger.info(f'SEARCH: Setting input_directory to {input_directory}')
|
log.info(f'SEARCH: Setting input_directory to {input_directory}')
|
||||||
if input_name and os.path.isdir(os.path.join(input_directory, input_name)):
|
if input_name and os.path.isdir(os.path.join(input_directory, input_name)):
|
||||||
logger.info(
|
log.info(f'SEARCH: Found torrent directory {input_name} in input directory directory {input_directory}')
|
||||||
f'SEARCH: Found torrent directory {input_name} in input directory directory {input_directory}',
|
|
||||||
)
|
|
||||||
input_directory = os.path.join(input_directory, input_name)
|
input_directory = os.path.join(input_directory, input_name)
|
||||||
logger.info(f'SEARCH: Setting input_directory to {input_directory}')
|
log.info(f'SEARCH: Setting input_directory to {input_directory}')
|
||||||
tordir = True
|
tordir = True
|
||||||
elif input_name and os.path.isdir(
|
elif input_name and os.path.isdir(
|
||||||
os.path.join(input_directory, sanitize_name(input_name)),
|
os.path.join(input_directory, sanitize_name(input_name)),
|
||||||
):
|
):
|
||||||
logger.info(
|
log.info(f'SEARCH: Found torrent directory {sanitize_name(input_name)} in input directory directory {input_directory}')
|
||||||
f'SEARCH: Found torrent directory {sanitize_name(input_name)} in input directory directory {input_directory}',
|
|
||||||
)
|
|
||||||
input_directory = os.path.join(
|
input_directory = os.path.join(
|
||||||
input_directory, sanitize_name(input_name),
|
input_directory, sanitize_name(input_name),
|
||||||
)
|
)
|
||||||
logger.info(f'SEARCH: Setting input_directory to {input_directory}')
|
log.info(f'SEARCH: Setting input_directory to {input_directory}')
|
||||||
tordir = True
|
tordir = True
|
||||||
elif input_name and os.path.isfile(
|
elif input_name and os.path.isfile(
|
||||||
os.path.join(input_directory, input_name),
|
os.path.join(input_directory, input_name),
|
||||||
):
|
):
|
||||||
logger.info(
|
log.info(f'SEARCH: Found torrent file {input_name} in input directory directory {input_directory}')
|
||||||
f'SEARCH: Found torrent file {input_name} in input directory directory {input_directory}',
|
|
||||||
)
|
|
||||||
input_directory = os.path.join(input_directory, input_name)
|
input_directory = os.path.join(input_directory, input_name)
|
||||||
logger.info(f'SEARCH: Setting input_directory to {input_directory}')
|
log.info(f'SEARCH: Setting input_directory to {input_directory}')
|
||||||
tordir = True
|
tordir = True
|
||||||
elif input_name and os.path.isfile(
|
elif input_name and os.path.isfile(
|
||||||
os.path.join(input_directory, sanitize_name(input_name)),
|
os.path.join(input_directory, sanitize_name(input_name)),
|
||||||
):
|
):
|
||||||
logger.info(
|
log.info(f'SEARCH: Found torrent file {sanitize_name(input_name)} in input directory directory {input_directory}')
|
||||||
f'SEARCH: Found torrent file {sanitize_name(input_name)} in input directory directory {input_directory}',
|
|
||||||
)
|
|
||||||
input_directory = os.path.join(
|
input_directory = os.path.join(
|
||||||
input_directory, sanitize_name(input_name),
|
input_directory, sanitize_name(input_name),
|
||||||
)
|
)
|
||||||
logger.info(f'SEARCH: Setting input_directory to {input_directory}')
|
log.info(f'SEARCH: Setting input_directory to {input_directory}')
|
||||||
tordir = True
|
tordir = True
|
||||||
elif input_name and os.path.isdir(input_directory):
|
elif input_name and os.path.isdir(input_directory):
|
||||||
for file in os.listdir(input_directory):
|
for file in os.listdir(input_directory):
|
||||||
|
@ -185,13 +166,9 @@ def category_search(
|
||||||
input_name,
|
input_name,
|
||||||
sanitize_name(input_name),
|
sanitize_name(input_name),
|
||||||
]:
|
]:
|
||||||
logger.info(
|
log.info(f'SEARCH: Found torrent file {file} in input directory directory {input_directory}')
|
||||||
f'SEARCH: Found torrent file {file} in input directory directory {input_directory}',
|
|
||||||
)
|
|
||||||
input_directory = os.path.join(input_directory, file)
|
input_directory = os.path.join(input_directory, file)
|
||||||
logger.info(
|
log.info(f'SEARCH: Setting input_directory to {input_directory}')
|
||||||
f'SEARCH: Setting input_directory to {input_directory}',
|
|
||||||
)
|
|
||||||
input_name = file
|
input_name = file
|
||||||
tordir = True
|
tordir = True
|
||||||
break
|
break
|
||||||
|
@ -210,9 +187,7 @@ def category_search(
|
||||||
index = pathlist.index(input_category)
|
index = pathlist.index(input_category)
|
||||||
if index + 1 < len(pathlist):
|
if index + 1 < len(pathlist):
|
||||||
tordir = True
|
tordir = True
|
||||||
logger.info(
|
log.info(f'SEARCH: Found a unique directory {pathlist[index + 1]} in the category directory')
|
||||||
f'SEARCH: Found a unique directory {pathlist[index + 1]} in the category directory',
|
|
||||||
)
|
|
||||||
if not input_name:
|
if not input_name:
|
||||||
input_name = pathlist[index + 1]
|
input_name = pathlist[index + 1]
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
@ -220,9 +195,7 @@ def category_search(
|
||||||
|
|
||||||
if input_name and not tordir:
|
if input_name and not tordir:
|
||||||
if input_name in pathlist or sanitize_name(input_name) in pathlist:
|
if input_name in pathlist or sanitize_name(input_name) in pathlist:
|
||||||
logger.info(
|
log.info(f'SEARCH: Found torrent directory {input_name} in the directory structure')
|
||||||
f'SEARCH: Found torrent directory {input_name} in the directory structure',
|
|
||||||
)
|
|
||||||
tordir = True
|
tordir = True
|
||||||
else:
|
else:
|
||||||
root = 1
|
root = 1
|
||||||
|
@ -230,11 +203,7 @@ def category_search(
|
||||||
root = 2
|
root = 2
|
||||||
|
|
||||||
if root > 0:
|
if root > 0:
|
||||||
logger.info(
|
log.info('SEARCH: Could not find a unique directory for this download. Assume a common directory.')
|
||||||
'SEARCH: Could not find a unique directory for this download. Assume a common directory.',
|
log.info('SEARCH: We will try and determine which files to process, individually')
|
||||||
)
|
|
||||||
logger.info(
|
|
||||||
'SEARCH: We will try and determine which files to process, individually',
|
|
||||||
)
|
|
||||||
|
|
||||||
return input_directory, input_name, input_category, root
|
return input_directory, input_name, input_category, root
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
import linktastic
|
import linktastic
|
||||||
|
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media.utils.paths import make_dir
|
from nzb2media.utils.paths import make_dir
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from jaraco.windows.filesystem import islink, readlink
|
from jaraco.windows.filesystem import islink, readlink
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -19,73 +22,55 @@ except ImportError:
|
||||||
|
|
||||||
|
|
||||||
def copy_link(src, target_link, use_link):
|
def copy_link(src, target_link, use_link):
|
||||||
logger.info(f'MEDIAFILE: [{os.path.basename(target_link)}]', 'COPYLINK')
|
log.info(f'MEDIAFILE: [{os.path.basename(target_link)}]')
|
||||||
logger.info(f'SOURCE FOLDER: [{os.path.dirname(src)}]', 'COPYLINK')
|
log.info(f'SOURCE FOLDER: [{os.path.dirname(src)}]')
|
||||||
logger.info(f'TARGET FOLDER: [{os.path.dirname(target_link)}]', 'COPYLINK')
|
log.info(f'TARGET FOLDER: [{os.path.dirname(target_link)}]')
|
||||||
|
|
||||||
if src != target_link and os.path.exists(target_link):
|
if src != target_link and os.path.exists(target_link):
|
||||||
logger.info(
|
log.info('MEDIAFILE already exists in the TARGET folder, skipping ...')
|
||||||
'MEDIAFILE already exists in the TARGET folder, skipping ...',
|
|
||||||
'COPYLINK',
|
|
||||||
)
|
|
||||||
return True
|
return True
|
||||||
elif (
|
elif (
|
||||||
src == target_link
|
src == target_link
|
||||||
and os.path.isfile(target_link)
|
and os.path.isfile(target_link)
|
||||||
and os.path.isfile(src)
|
and os.path.isfile(src)
|
||||||
):
|
):
|
||||||
logger.info(
|
log.info('SOURCE AND TARGET files are the same, skipping ...')
|
||||||
'SOURCE AND TARGET files are the same, skipping ...', 'COPYLINK',
|
|
||||||
)
|
|
||||||
return True
|
return True
|
||||||
elif src == os.path.dirname(target_link):
|
elif src == os.path.dirname(target_link):
|
||||||
logger.info(
|
log.info('SOURCE AND TARGET folders are the same, skipping ...')
|
||||||
'SOURCE AND TARGET folders are the same, skipping ...', 'COPYLINK',
|
|
||||||
)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
make_dir(os.path.dirname(target_link))
|
make_dir(os.path.dirname(target_link))
|
||||||
try:
|
try:
|
||||||
if use_link == 'dir':
|
if use_link == 'dir':
|
||||||
logger.info(
|
log.info('Directory linking SOURCE FOLDER -> TARGET FOLDER')
|
||||||
'Directory linking SOURCE FOLDER -> TARGET FOLDER', 'COPYLINK',
|
|
||||||
)
|
|
||||||
linktastic.dirlink(src, target_link)
|
linktastic.dirlink(src, target_link)
|
||||||
return True
|
return True
|
||||||
if use_link == 'junction':
|
if use_link == 'junction':
|
||||||
logger.info(
|
log.info('Directory junction linking SOURCE FOLDER -> TARGET FOLDER')
|
||||||
'Directory junction linking SOURCE FOLDER -> TARGET FOLDER',
|
|
||||||
'COPYLINK',
|
|
||||||
)
|
|
||||||
linktastic.dirlink(src, target_link)
|
linktastic.dirlink(src, target_link)
|
||||||
return True
|
return True
|
||||||
elif use_link == 'hard':
|
elif use_link == 'hard':
|
||||||
logger.info(
|
log.info('Hard linking SOURCE MEDIAFILE -> TARGET FOLDER')
|
||||||
'Hard linking SOURCE MEDIAFILE -> TARGET FOLDER', 'COPYLINK',
|
|
||||||
)
|
|
||||||
linktastic.link(src, target_link)
|
linktastic.link(src, target_link)
|
||||||
return True
|
return True
|
||||||
elif use_link == 'sym':
|
elif use_link == 'sym':
|
||||||
logger.info(
|
log.info('Sym linking SOURCE MEDIAFILE -> TARGET FOLDER')
|
||||||
'Sym linking SOURCE MEDIAFILE -> TARGET FOLDER', 'COPYLINK',
|
|
||||||
)
|
|
||||||
linktastic.symlink(src, target_link)
|
linktastic.symlink(src, target_link)
|
||||||
return True
|
return True
|
||||||
elif use_link == 'move-sym':
|
elif use_link == 'move-sym':
|
||||||
logger.info(
|
log.info('Sym linking SOURCE MEDIAFILE -> TARGET FOLDER')
|
||||||
'Sym linking SOURCE MEDIAFILE -> TARGET FOLDER', 'COPYLINK',
|
|
||||||
)
|
|
||||||
shutil.move(src, target_link)
|
shutil.move(src, target_link)
|
||||||
linktastic.symlink(target_link, src)
|
linktastic.symlink(target_link, src)
|
||||||
return True
|
return True
|
||||||
elif use_link == 'move':
|
elif use_link == 'move':
|
||||||
logger.info('Moving SOURCE MEDIAFILE -> TARGET FOLDER', 'COPYLINK')
|
log.info('Moving SOURCE MEDIAFILE -> TARGET FOLDER')
|
||||||
shutil.move(src, target_link)
|
shutil.move(src, target_link)
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as error:
|
||||||
logger.warning(f'Error: {e}, copying instead ... ', 'COPYLINK')
|
log.warning(f'Error: {error}, copying instead ... ')
|
||||||
|
|
||||||
logger.info('Copying SOURCE MEDIAFILE -> TARGET FOLDER', 'COPYLINK')
|
log.info('Copying SOURCE MEDIAFILE -> TARGET FOLDER')
|
||||||
shutil.copy(src, target_link)
|
shutil.copy(src, target_link)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -102,17 +87,12 @@ def replace_links(link, max_depth=10):
|
||||||
link_depth = attempt
|
link_depth = attempt
|
||||||
|
|
||||||
if not link_depth:
|
if not link_depth:
|
||||||
logger.debug(f'{link} is not a link')
|
log.debug(f'{link} is not a link')
|
||||||
elif link_depth > max_depth or (
|
elif link_depth > max_depth or (
|
||||||
link_depth == max_depth and islink(target)
|
link_depth == max_depth and islink(target)
|
||||||
):
|
):
|
||||||
logger.warning(
|
log.warning(f'Exceeded maximum depth {max_depth} while following link {link}')
|
||||||
f'Exceeded maximum depth {max_depth} while following link {link}',
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
logger.info(
|
log.info(f'Changing sym-link: {link} to point directly to file: {target}')
|
||||||
f'Changing sym-link: {link} to point directly to file: {target}',
|
|
||||||
'COPYLINK',
|
|
||||||
)
|
|
||||||
os.unlink(link)
|
os.unlink(link)
|
||||||
linktastic.symlink(target, link)
|
linktastic.symlink(target, link)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
import time
|
import time
|
||||||
|
@ -7,7 +8,9 @@ import time
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def make_wake_on_lan_packet(mac_address):
|
def make_wake_on_lan_packet(mac_address):
|
||||||
|
@ -29,7 +32,7 @@ def wake_on_lan(ethernet_address):
|
||||||
connection.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
connection.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
||||||
connection.sendto(magic_packet, ('<broadcast>', 9))
|
connection.sendto(magic_packet, ('<broadcast>', 9))
|
||||||
|
|
||||||
logger.info(f'WakeOnLan sent for mac: {ethernet_address}')
|
log.info(f'WakeOnLan sent for mac: {ethernet_address}')
|
||||||
|
|
||||||
|
|
||||||
def test_connection(host, port):
|
def test_connection(host, port):
|
||||||
|
@ -50,37 +53,37 @@ def wake_up():
|
||||||
mac = wol['mac']
|
mac = wol['mac']
|
||||||
max_attempts = 4
|
max_attempts = 4
|
||||||
|
|
||||||
logger.info('Trying to wake On lan.')
|
log.info('Trying to wake On lan.')
|
||||||
|
|
||||||
for attempt in range(0, max_attempts):
|
for attempt in range(0, max_attempts):
|
||||||
logger.info(f'Attempt {attempt + 1} of {max_attempts}')
|
log.info(f'Attempt {attempt + 1} of {max_attempts}')
|
||||||
if test_connection(host, port) == 'Up':
|
if test_connection(host, port) == 'Up':
|
||||||
logger.info(f'System with mac: {mac} has been woken.')
|
log.info(f'System with mac: {mac} has been woken.')
|
||||||
break
|
break
|
||||||
wake_on_lan(mac)
|
wake_on_lan(mac)
|
||||||
time.sleep(20)
|
time.sleep(20)
|
||||||
else:
|
else:
|
||||||
if test_connection(host, port) == 'Down': # final check.
|
if test_connection(host, port) == 'Down': # final check.
|
||||||
msg = 'System with mac: {0} has not woken after {1} attempts.'
|
msg = 'System with mac: {0} has not woken after {1} attempts.'
|
||||||
logger.warning(msg.format(mac, max_attempts))
|
log.warning(msg.format(mac, max_attempts))
|
||||||
|
|
||||||
logger.info('Continuing with the rest of the script.')
|
log.info('Continuing with the rest of the script.')
|
||||||
|
|
||||||
|
|
||||||
def server_responding(base_url):
|
def server_responding(base_url):
|
||||||
logger.debug(f'Attempting to connect to server at {base_url}', 'SERVER')
|
log.debug(f'Attempting to connect to server at {base_url}')
|
||||||
try:
|
try:
|
||||||
requests.get(base_url, timeout=(60, 120), verify=False)
|
requests.get(base_url, timeout=(60, 120), verify=False)
|
||||||
except (requests.ConnectionError, requests.exceptions.Timeout):
|
except (requests.ConnectionError, requests.exceptions.Timeout):
|
||||||
logger.error(f'Server failed to respond at {base_url}', 'SERVER')
|
log.error(f'Server failed to respond at {base_url}')
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
logger.debug(f'Server responded at {base_url}', 'SERVER')
|
log.debug(f'Server responded at {base_url}')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def find_download(client_agent, download_id):
|
def find_download(client_agent, download_id):
|
||||||
logger.debug(f'Searching for Download on {client_agent} ...')
|
log.debug(f'Searching for Download on {client_agent} ...')
|
||||||
if client_agent == 'utorrent':
|
if client_agent == 'utorrent':
|
||||||
torrents = nzb2media.TORRENT_CLASS.list()[1]['torrents']
|
torrents = nzb2media.TORRENT_CLASS.list()[1]['torrents']
|
||||||
for torrent in torrents:
|
for torrent in torrents:
|
||||||
|
@ -116,7 +119,7 @@ def find_download(client_agent, download_id):
|
||||||
url, params=params, verify=False, timeout=(30, 120),
|
url, params=params, verify=False, timeout=(30, 120),
|
||||||
)
|
)
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.error('Unable to open URL')
|
log.error('Unable to open URL')
|
||||||
return False # failure
|
return False # failure
|
||||||
|
|
||||||
result = r.json()
|
result = r.json()
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def get_nzoid(input_name):
|
def get_nzoid(input_name):
|
||||||
nzoid = None
|
nzoid = None
|
||||||
slots = []
|
slots = []
|
||||||
logger.debug('Searching for nzoid from SAbnzbd ...')
|
log.debug('Searching for nzoid from SAbnzbd ...')
|
||||||
if 'http' in nzb2media.SABNZBD_HOST:
|
if 'http' in nzb2media.SABNZBD_HOST:
|
||||||
base_url = f'{nzb2media.SABNZBD_HOST}:{nzb2media.SABNZBD_PORT}/api'
|
base_url = f'{nzb2media.SABNZBD_HOST}:{nzb2media.SABNZBD_PORT}/api'
|
||||||
else:
|
else:
|
||||||
|
@ -25,7 +28,7 @@ def get_nzoid(input_name):
|
||||||
try:
|
try:
|
||||||
r = requests.get(url, params=params, verify=False, timeout=(30, 120))
|
r = requests.get(url, params=params, verify=False, timeout=(30, 120))
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.error('Unable to open URL')
|
log.error('Unable to open URL')
|
||||||
return nzoid # failure
|
return nzoid # failure
|
||||||
try:
|
try:
|
||||||
result = r.json()
|
result = r.json()
|
||||||
|
@ -37,12 +40,12 @@ def get_nzoid(input_name):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.warning('Data from SABnzbd queue could not be parsed')
|
log.warning('Data from SABnzbd queue could not be parsed')
|
||||||
params['mode'] = 'history'
|
params['mode'] = 'history'
|
||||||
try:
|
try:
|
||||||
r = requests.get(url, params=params, verify=False, timeout=(30, 120))
|
r = requests.get(url, params=params, verify=False, timeout=(30, 120))
|
||||||
except requests.ConnectionError:
|
except requests.ConnectionError:
|
||||||
logger.error('Unable to open URL')
|
log.error('Unable to open URL')
|
||||||
return nzoid # failure
|
return nzoid # failure
|
||||||
try:
|
try:
|
||||||
result = r.json()
|
result = r.json()
|
||||||
|
@ -54,21 +57,21 @@ def get_nzoid(input_name):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.warning('Data from SABnzbd history could not be parsed')
|
log.warning('Data from SABnzbd history could not be parsed')
|
||||||
try:
|
try:
|
||||||
for nzo_id, name in slots:
|
for nzo_id, name in slots:
|
||||||
if name in [input_name, clean_name]:
|
if name in [input_name, clean_name]:
|
||||||
nzoid = nzo_id
|
nzoid = nzo_id
|
||||||
logger.debug(f'Found nzoid: {nzoid}')
|
log.debug(f'Found nzoid: {nzoid}')
|
||||||
break
|
break
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.warning('Data from SABnzbd could not be parsed')
|
log.warning('Data from SABnzbd could not be parsed')
|
||||||
return nzoid
|
return nzoid
|
||||||
|
|
||||||
|
|
||||||
def report_nzb(failure_link, client_agent):
|
def report_nzb(failure_link, client_agent):
|
||||||
# Contact indexer site
|
# Contact indexer site
|
||||||
logger.info('Sending failure notification to indexer site')
|
log.info('Sending failure notification to indexer site')
|
||||||
if client_agent == 'nzbget':
|
if client_agent == 'nzbget':
|
||||||
headers = {'User-Agent': 'NZBGet / nzbToMedia.py'}
|
headers = {'User-Agent': 'NZBGet / nzbToMedia.py'}
|
||||||
elif client_agent == 'sabnzbd':
|
elif client_agent == 'sabnzbd':
|
||||||
|
@ -77,6 +80,6 @@ def report_nzb(failure_link, client_agent):
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
requests.post(failure_link, headers=headers, timeout=(30, 300))
|
requests.post(failure_link, headers=headers, timeout=(30, 300))
|
||||||
except Exception as e:
|
except Exception as error:
|
||||||
logger.error(f'Unable to open URL {failure_link} due to {e}')
|
log.error(f'Unable to open URL {failure_link} due to {error}')
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def parse_other(args):
|
def parse_other(args):
|
||||||
|
@ -100,7 +103,7 @@ def parse_synods(args):
|
||||||
input_id = f'dbid_{torrent_id}'
|
input_id = f'dbid_{torrent_id}'
|
||||||
# res = nzb2media.TORRENT_CLASS.tasks_list(additional_param='detail')
|
# res = nzb2media.TORRENT_CLASS.tasks_list(additional_param='detail')
|
||||||
res = nzb2media.TORRENT_CLASS.tasks_info(input_id, additional_param='detail')
|
res = nzb2media.TORRENT_CLASS.tasks_info(input_id, additional_param='detail')
|
||||||
logger.debug(f'result from syno {res}')
|
log.debug(f'result from syno {res}')
|
||||||
if res['success']:
|
if res['success']:
|
||||||
try:
|
try:
|
||||||
tasks = res['data']['tasks']
|
tasks = res['data']['tasks']
|
||||||
|
@ -108,7 +111,7 @@ def parse_synods(args):
|
||||||
input_id = task['id']
|
input_id = task['id']
|
||||||
input_directory = task['additional']['detail']['destination']
|
input_directory = task['additional']['detail']['destination']
|
||||||
except:
|
except:
|
||||||
logger.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/']:
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
|
@ -7,7 +8,9 @@ import stat
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def onerror(func, path, exc_info):
|
def onerror(func, path, exc_info):
|
||||||
|
@ -30,11 +33,11 @@ def onerror(func, path, exc_info):
|
||||||
|
|
||||||
|
|
||||||
def remove_dir(dir_name):
|
def remove_dir(dir_name):
|
||||||
logger.info(f'Deleting {dir_name}')
|
log.info(f'Deleting {dir_name}')
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(dir_name, onerror=onerror)
|
shutil.rmtree(dir_name, onerror=onerror)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error(f'Unable to delete folder {dir_name}')
|
log.error(f'Unable to delete folder {dir_name}')
|
||||||
|
|
||||||
|
|
||||||
def make_dir(path):
|
def make_dir(path):
|
||||||
|
@ -78,7 +81,7 @@ def remove_empty_folders(path, remove_root=True):
|
||||||
return
|
return
|
||||||
|
|
||||||
# remove empty subfolders
|
# remove empty subfolders
|
||||||
logger.debug(f'Checking for empty folders in:{path}')
|
log.debug(f'Checking for empty folders in:{path}')
|
||||||
files = os.listdir(path)
|
files = os.listdir(path)
|
||||||
if len(files):
|
if len(files):
|
||||||
for f in files:
|
for f in files:
|
||||||
|
@ -89,7 +92,7 @@ def remove_empty_folders(path, remove_root=True):
|
||||||
# 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 len(files) == 0 and remove_root:
|
||||||
logger.debug(f'Removing empty folder:{path}')
|
log.debug(f'Removing empty folder:{path}')
|
||||||
os.rmdir(path)
|
os.rmdir(path)
|
||||||
|
|
||||||
|
|
||||||
|
@ -99,66 +102,51 @@ def remove_read_only(filename):
|
||||||
file_attribute = os.stat(filename)[0]
|
file_attribute = os.stat(filename)[0]
|
||||||
if not file_attribute & stat.S_IWRITE:
|
if not file_attribute & stat.S_IWRITE:
|
||||||
# File is read-only, so make it writeable
|
# File is read-only, so make it writeable
|
||||||
logger.debug(
|
log.debug(f'Read only mode on file {filename}. Attempting to make it writeable')
|
||||||
f'Read only mode on file {filename}. Attempting to make it writeable',
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
os.chmod(filename, stat.S_IWRITE)
|
os.chmod(filename, stat.S_IWRITE)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.warning(
|
log.warning(f'Cannot change permissions of {filename}')
|
||||||
f'Cannot change permissions of {filename}', logger.WARNING,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def flatten_dir(destination, files):
|
def flatten_dir(destination, files):
|
||||||
logger.info(f'FLATTEN: Flattening directory: {destination}')
|
log.info(f'FLATTEN: Flattening directory: {destination}')
|
||||||
for outputFile in files:
|
for outputFile in files:
|
||||||
dir_path = os.path.dirname(outputFile)
|
dir_path = os.path.dirname(outputFile)
|
||||||
file_name = os.path.basename(outputFile)
|
file_name = os.path.basename(outputFile)
|
||||||
|
|
||||||
if dir_path == destination:
|
if dir_path == destination:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
target = os.path.join(destination, file_name)
|
target = os.path.join(destination, file_name)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
shutil.move(outputFile, target)
|
shutil.move(outputFile, target)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error(f'Could not flatten {outputFile}', 'FLATTEN')
|
log.error(f'Could not flatten {outputFile}')
|
||||||
|
|
||||||
remove_empty_folders(destination) # Cleanup empty directories
|
remove_empty_folders(destination) # Cleanup empty directories
|
||||||
|
|
||||||
|
|
||||||
def clean_directory(path, files):
|
def clean_directory(path, files):
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
logger.info(
|
log.info(f'Directory {path} has been processed and removed ...')
|
||||||
f'Directory {path} has been processed and removed ...', 'CLEANDIR',
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if nzb2media.FORCE_CLEAN and not nzb2media.FAILED:
|
if nzb2media.FORCE_CLEAN and not nzb2media.FAILED:
|
||||||
logger.info(f'Doing Forceful Clean of {path}', 'CLEANDIR')
|
log.info(f'Doing Forceful Clean of {path}')
|
||||||
remove_dir(path)
|
remove_dir(path)
|
||||||
return
|
return
|
||||||
|
|
||||||
if files:
|
if files:
|
||||||
logger.info(
|
log.info(f'Directory {path} still contains {len(files)} unprocessed file(s), skipping ...')
|
||||||
f'Directory {path} still contains {len(files)} unprocessed file(s), skipping ...',
|
|
||||||
'CLEANDIRS',
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.info(
|
log.info(f'Directory {path} has been processed, removing ...')
|
||||||
f'Directory {path} has been processed, removing ...', 'CLEANDIRS',
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(path, onerror=onerror)
|
shutil.rmtree(path, onerror=onerror)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error(f'Unable to delete directory {path}')
|
log.error(f'Unable to delete directory {path}')
|
||||||
|
|
||||||
|
|
||||||
def rchmod(path, mod):
|
def rchmod(path, mod):
|
||||||
logger.log(f'Changing file mode of {path} to {oct(mod)}')
|
log.info(f'Changing file mode of {path} to {oct(mod)}')
|
||||||
os.chmod(path, mod)
|
os.chmod(path, mod)
|
||||||
if not os.path.isdir(path):
|
if not os.path.isdir(path):
|
||||||
return # Skip files
|
return # Skip files
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
import subprocess
|
import subprocess
|
||||||
|
@ -9,7 +10,6 @@ import typing
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import APP_FILENAME
|
from nzb2media import APP_FILENAME
|
||||||
from nzb2media import SYS_ARGV
|
from nzb2media import SYS_ARGV
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media import version_check
|
from nzb2media import version_check
|
||||||
|
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
|
@ -17,6 +17,9 @@ if os.name == 'nt':
|
||||||
from win32api import CloseHandle, GetLastError
|
from win32api import CloseHandle, GetLastError
|
||||||
from winerror import ERROR_ALREADY_EXISTS
|
from winerror import ERROR_ALREADY_EXISTS
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
class WindowsProcess:
|
class WindowsProcess:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -110,8 +113,7 @@ def restart():
|
||||||
|
|
||||||
if popen_list:
|
if popen_list:
|
||||||
popen_list += SYS_ARGV
|
popen_list += SYS_ARGV
|
||||||
logger.log(f'Restarting nzbToMedia with {popen_list}')
|
log.info(f'Restarting nzbToMedia with {popen_list}')
|
||||||
logger.close()
|
|
||||||
p = subprocess.Popen(popen_list, cwd=os.getcwd())
|
p = subprocess.Popen(popen_list, cwd=os.getcwd())
|
||||||
p.wait()
|
p.wait()
|
||||||
status = p.returncode
|
status = p.returncode
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media.torrent import deluge
|
from nzb2media.torrent import deluge
|
||||||
from nzb2media.torrent import qbittorrent
|
from nzb2media.torrent import qbittorrent
|
||||||
from nzb2media.torrent import synology
|
from nzb2media.torrent import synology
|
||||||
from nzb2media.torrent import transmission
|
from nzb2media.torrent import transmission
|
||||||
from nzb2media.torrent import utorrent
|
from nzb2media.torrent import utorrent
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
torrent_clients = {
|
torrent_clients = {
|
||||||
'deluge': deluge,
|
'deluge': deluge,
|
||||||
'qbittorrent': qbittorrent,
|
'qbittorrent': qbittorrent,
|
||||||
|
@ -32,9 +35,7 @@ def create_torrent_class(client_agent):
|
||||||
|
|
||||||
|
|
||||||
def pause_torrent(client_agent, input_hash, input_id, input_name):
|
def pause_torrent(client_agent, input_hash, input_id, input_name):
|
||||||
logger.debug(
|
log.debug(f'Stopping torrent {input_name} in {client_agent} while processing')
|
||||||
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)
|
||||||
|
@ -48,15 +49,13 @@ def pause_torrent(client_agent, input_hash, input_id, input_name):
|
||||||
nzb2media.TORRENT_CLASS.pause(input_hash)
|
nzb2media.TORRENT_CLASS.pause(input_hash)
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.warning(
|
log.warning(f'Failed to stop torrent {input_name} in {client_agent}')
|
||||||
f'Failed to stop torrent {input_name} in {client_agent}',
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def resume_torrent(client_agent, input_hash, input_id, input_name):
|
def resume_torrent(client_agent, input_hash, input_id, input_name):
|
||||||
if not nzb2media.TORRENT_RESUME == 1:
|
if not nzb2media.TORRENT_RESUME == 1:
|
||||||
return
|
return
|
||||||
logger.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)
|
||||||
|
@ -70,14 +69,12 @@ def resume_torrent(client_agent, input_hash, input_id, input_name):
|
||||||
nzb2media.TORRENT_CLASS.resume(input_hash)
|
nzb2media.TORRENT_CLASS.resume(input_hash)
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.warning(
|
log.warning(f'Failed to start torrent {input_name} in {client_agent}')
|
||||||
f'Failed to start torrent {input_name} in {client_agent}',
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def remove_torrent(client_agent, input_hash, input_id, input_name):
|
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':
|
||||||
logger.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)
|
||||||
|
@ -92,8 +89,6 @@ def remove_torrent(client_agent, input_hash, input_id, input_name):
|
||||||
nzb2media.TORRENT_CLASS.delete_permanently(input_hash)
|
nzb2media.TORRENT_CLASS.delete_permanently(input_hash)
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.warning(
|
log.warning(f'Failed to delete torrent {input_name} in {client_agent}')
|
||||||
f'Failed to delete torrent {input_name} in {client_agent}',
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
resume_torrent(client_agent, input_hash, input_id, input_name)
|
resume_torrent(client_agent, input_hash, input_id, input_name)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
# Modified by: echel0n
|
# Modified by: echel0n
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import re
|
import re
|
||||||
|
@ -14,7 +15,9 @@ from urllib.request import urlretrieve
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import github_api as github
|
from nzb2media import github_api as github
|
||||||
from nzb2media import logger
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
class CheckVersion:
|
class CheckVersion:
|
||||||
|
@ -61,15 +64,13 @@ class CheckVersion:
|
||||||
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
|
||||||
"""
|
"""
|
||||||
if not nzb2media.VERSION_NOTIFY and not force:
|
if not nzb2media.VERSION_NOTIFY and not force:
|
||||||
logger.log(
|
log.info('Version checking is disabled, not checking for the newest version')
|
||||||
'Version checking is disabled, not checking for the newest version',
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
logger.log(f'Checking if {self.install_type} needs an update')
|
log.info(f'Checking if {self.install_type} needs an update')
|
||||||
if not self.updater.need_update():
|
if not self.updater.need_update():
|
||||||
nzb2media.NEWEST_VERSION_STRING = None
|
nzb2media.NEWEST_VERSION_STRING = None
|
||||||
logger.log('No update needed')
|
log.info('No update needed')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.updater.set_newest_text()
|
self.updater.set_newest_text()
|
||||||
|
@ -105,9 +106,7 @@ class GitUpdateManager(UpdateManager):
|
||||||
self._num_commits_ahead = 0
|
self._num_commits_ahead = 0
|
||||||
|
|
||||||
def _git_error(self):
|
def _git_error(self):
|
||||||
logger.debug(
|
log.debug('Unable to find your git executable - Set git_path in your autoProcessMedia.cfg OR delete your .git folder and run from source to enable updates.')
|
||||||
'Unable to find your git executable - Set git_path in your autoProcessMedia.cfg OR delete your .git folder and run from source to enable updates.',
|
|
||||||
)
|
|
||||||
|
|
||||||
def _find_working_git(self):
|
def _find_working_git(self):
|
||||||
test_cmd = 'version'
|
test_cmd = 'version'
|
||||||
|
@ -117,19 +116,14 @@ class GitUpdateManager(UpdateManager):
|
||||||
else:
|
else:
|
||||||
main_git = 'git'
|
main_git = 'git'
|
||||||
|
|
||||||
logger.log(
|
log.debug('Checking if we can use git commands: {git} {cmd}'.format(git=main_git, cmd=test_cmd))
|
||||||
'Checking if we can use git commands: {git} {cmd}'.format(
|
|
||||||
git=main_git, cmd=test_cmd,
|
|
||||||
),
|
|
||||||
logger.DEBUG,
|
|
||||||
)
|
|
||||||
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 exit_status == 0:
|
||||||
logger.log(f'Using: {main_git}', logger.DEBUG)
|
log.debug(f'Using: {main_git}')
|
||||||
return main_git
|
return main_git
|
||||||
else:
|
else:
|
||||||
logger.log(f'Not using: {main_git}', logger.DEBUG)
|
log.debug(f'Not using: {main_git}')
|
||||||
|
|
||||||
# trying alternatives
|
# trying alternatives
|
||||||
|
|
||||||
|
@ -144,25 +138,20 @@ class GitUpdateManager(UpdateManager):
|
||||||
alternative_git.append(main_git.lower())
|
alternative_git.append(main_git.lower())
|
||||||
|
|
||||||
if alternative_git:
|
if alternative_git:
|
||||||
logger.log('Trying known alternative git locations', logger.DEBUG)
|
log.debug('Trying known alternative git locations')
|
||||||
|
|
||||||
for cur_git in alternative_git:
|
for cur_git in alternative_git:
|
||||||
logger.log(
|
log.debug('Checking if we can use git commands: {git} {cmd}'.format(git=cur_git, cmd=test_cmd))
|
||||||
'Checking if we can use git commands: {git} {cmd}'.format(
|
|
||||||
git=cur_git, cmd=test_cmd,
|
|
||||||
),
|
|
||||||
logger.DEBUG,
|
|
||||||
)
|
|
||||||
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 exit_status == 0:
|
||||||
logger.log(f'Using: {cur_git}', logger.DEBUG)
|
log.debug(f'Using: {cur_git}')
|
||||||
return cur_git
|
return cur_git
|
||||||
else:
|
else:
|
||||||
logger.log(f'Not using: {cur_git}', logger.DEBUG)
|
log.debug(f'Not using: {cur_git}')
|
||||||
|
|
||||||
# Still haven't found a working git
|
# Still haven't found a working git
|
||||||
logger.debug(
|
log.debug(
|
||||||
'Unable to find your git executable - '
|
'Unable to find your git executable - '
|
||||||
'Set git_path in your autoProcessMedia.cfg OR '
|
'Set git_path in your autoProcessMedia.cfg OR '
|
||||||
'delete your .git folder and run from source to enable updates.',
|
'delete your .git folder and run from source to enable updates.',
|
||||||
|
@ -176,21 +165,14 @@ class GitUpdateManager(UpdateManager):
|
||||||
err = None
|
err = None
|
||||||
|
|
||||||
if not git_path:
|
if not git_path:
|
||||||
logger.log(
|
log.debug('No git specified, can\'t use git commands')
|
||||||
'No git specified, can\'t use git commands', logger.DEBUG,
|
|
||||||
)
|
|
||||||
exit_status = 1
|
exit_status = 1
|
||||||
return output, err, exit_status
|
return output, err, exit_status
|
||||||
|
|
||||||
cmd = f'{git_path} {args}'
|
cmd = f'{git_path} {args}'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logger.log(
|
log.debug('Executing {cmd} with your shell in {directory}'.format(cmd=cmd, directory=nzb2media.APP_ROOT))
|
||||||
'Executing {cmd} with your shell in {directory}'.format(
|
|
||||||
cmd=cmd, directory=nzb2media.APP_ROOT,
|
|
||||||
),
|
|
||||||
logger.DEBUG,
|
|
||||||
)
|
|
||||||
p = subprocess.Popen(
|
p = subprocess.Popen(
|
||||||
cmd,
|
cmd,
|
||||||
stdin=subprocess.PIPE,
|
stdin=subprocess.PIPE,
|
||||||
|
@ -207,29 +189,21 @@ class GitUpdateManager(UpdateManager):
|
||||||
if output:
|
if output:
|
||||||
output = output.strip()
|
output = output.strip()
|
||||||
if nzb2media.LOG_GIT:
|
if nzb2media.LOG_GIT:
|
||||||
logger.log(f'git output: {output}', logger.DEBUG)
|
log.debug(f'git output: {output}')
|
||||||
|
|
||||||
except OSError:
|
except OSError:
|
||||||
logger.log(f'Command {cmd} didn\'t work')
|
log.error(f'Command {cmd} didn\'t work')
|
||||||
exit_status = 1
|
exit_status = 1
|
||||||
|
|
||||||
exit_status = 128 if ('fatal:' in output) or err else exit_status
|
exit_status = 128 if ('fatal:' in output) or err else exit_status
|
||||||
if exit_status == 0:
|
if exit_status == 0:
|
||||||
logger.log(f'{cmd} : returned successful', logger.DEBUG)
|
log.debug(f'{cmd} : returned successful')
|
||||||
exit_status = 0
|
exit_status = 0
|
||||||
elif nzb2media.LOG_GIT and exit_status in (1, 128):
|
elif nzb2media.LOG_GIT and exit_status in (1, 128):
|
||||||
logger.log(
|
log.debug(f'{cmd} returned : {output}')
|
||||||
f'{cmd} returned : {output}',
|
|
||||||
logger.DEBUG,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
if nzb2media.LOG_GIT:
|
if nzb2media.LOG_GIT:
|
||||||
logger.log(
|
log.debug('{cmd} returned : {output}, treat as error for now'.format(cmd=cmd, output=output))
|
||||||
'{cmd} returned : {output}, treat as error for now'.format(
|
|
||||||
cmd=cmd, output=output,
|
|
||||||
),
|
|
||||||
logger.DEBUG,
|
|
||||||
)
|
|
||||||
exit_status = 1
|
exit_status = 1
|
||||||
|
|
||||||
return output, err, exit_status
|
return output, err, exit_status
|
||||||
|
@ -249,10 +223,7 @@ class GitUpdateManager(UpdateManager):
|
||||||
if exit_status == 0 and output:
|
if exit_status == 0 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):
|
||||||
logger.log(
|
log.error('Output doesn\'t look like a hash, not using it')
|
||||||
'Output doesn\'t look like a hash, not using it',
|
|
||||||
logger.ERROR,
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
self._cur_commit_hash = cur_commit_hash
|
self._cur_commit_hash = cur_commit_hash
|
||||||
if self._cur_commit_hash:
|
if self._cur_commit_hash:
|
||||||
|
@ -291,10 +262,7 @@ class GitUpdateManager(UpdateManager):
|
||||||
)
|
)
|
||||||
|
|
||||||
if not exit_status == 0:
|
if not exit_status == 0:
|
||||||
logger.log(
|
log.error('Unable to contact github, can\'t check for update')
|
||||||
'Unable to contact github, can\'t check for update',
|
|
||||||
logger.ERROR,
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# get latest commit_hash from remote
|
# get latest commit_hash from remote
|
||||||
|
@ -306,16 +274,12 @@ class GitUpdateManager(UpdateManager):
|
||||||
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):
|
||||||
logger.log(
|
log.debug('Output doesn\'t look like a hash, not using it')
|
||||||
'Output doesn\'t look like a hash, not using it',
|
|
||||||
logger.DEBUG,
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self._newest_commit_hash = cur_commit_hash
|
self._newest_commit_hash = cur_commit_hash
|
||||||
else:
|
else:
|
||||||
logger.log('git didn\'t return newest commit hash', logger.DEBUG)
|
log.debug('git didn\'t return newest commit hash')
|
||||||
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)
|
||||||
|
@ -330,47 +294,22 @@ class GitUpdateManager(UpdateManager):
|
||||||
self._num_commits_ahead = int(output.count('>'))
|
self._num_commits_ahead = int(output.count('>'))
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.log(
|
log.debug('git didn\'t return numbers for behind and ahead, not using it')
|
||||||
'git didn\'t return numbers for behind and ahead, not using it',
|
|
||||||
logger.DEBUG,
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.log(
|
log.debug('cur_commit = {current} % (newest_commit)= {new}, num_commits_behind = {x}, num_commits_ahead = {y}'.format(current=self._cur_commit_hash, new=self._newest_commit_hash, x=self._num_commits_behind, y=self._num_commits_ahead))
|
||||||
'cur_commit = {current} % (newest_commit)= {new}, '
|
|
||||||
'num_commits_behind = {x}, num_commits_ahead = {y}'.format(
|
|
||||||
current=self._cur_commit_hash,
|
|
||||||
new=self._newest_commit_hash,
|
|
||||||
x=self._num_commits_behind,
|
|
||||||
y=self._num_commits_ahead,
|
|
||||||
),
|
|
||||||
logger.DEBUG,
|
|
||||||
)
|
|
||||||
|
|
||||||
def set_newest_text(self):
|
def set_newest_text(self):
|
||||||
if self._num_commits_ahead:
|
if self._num_commits_ahead:
|
||||||
logger.log(
|
log.error('Local branch is ahead of {branch}. Automatic update not possible.'.format(branch=self.branch))
|
||||||
'Local branch is ahead of {branch}. Automatic update not possible.'.format(
|
|
||||||
branch=self.branch,
|
|
||||||
),
|
|
||||||
logger.ERROR,
|
|
||||||
)
|
|
||||||
elif self._num_commits_behind:
|
elif self._num_commits_behind:
|
||||||
logger.log(
|
log.info('There is a newer version available (you\'re {x} commit{s} behind)'.format(x=self._num_commits_behind, s='s' if self._num_commits_behind > 1 else ''))
|
||||||
'There is a newer version available (you\'re {x} commit{s} behind)'.format(
|
|
||||||
x=self._num_commits_behind,
|
|
||||||
s='s' if self._num_commits_behind > 1 else '',
|
|
||||||
),
|
|
||||||
logger.MESSAGE,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
def need_update(self):
|
def need_update(self):
|
||||||
if not self._find_installed_version():
|
if not self._find_installed_version():
|
||||||
logger.error(
|
log.error('Unable to determine installed version via git, please check your logs!')
|
||||||
'Unable to determine installed version via git, please check your logs!',
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if not self._cur_commit_hash:
|
if not self._cur_commit_hash:
|
||||||
|
@ -379,10 +318,7 @@ class GitUpdateManager(UpdateManager):
|
||||||
try:
|
try:
|
||||||
self._check_github_for_update()
|
self._check_github_for_update()
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.log(
|
log.error(f'Unable to contact github, can\'t check for update: {error!r}')
|
||||||
f'Unable to contact github, can\'t check for update: {error!r}',
|
|
||||||
logger.ERROR,
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if self._num_commits_behind > 0:
|
if self._num_commits_behind > 0:
|
||||||
|
@ -429,9 +365,7 @@ class SourceUpdateManager(UpdateManager):
|
||||||
with open(version_file) as fp:
|
with open(version_file) as fp:
|
||||||
self._cur_commit_hash = fp.read().strip(' \n\r')
|
self._cur_commit_hash = fp.read().strip(' \n\r')
|
||||||
except OSError as error:
|
except OSError as error:
|
||||||
logger.log(
|
log.debug(f'Unable to open \'version.txt\': {error}')
|
||||||
f'Unable to open \'version.txt\': {error}', logger.DEBUG,
|
|
||||||
)
|
|
||||||
|
|
||||||
if not self._cur_commit_hash:
|
if not self._cur_commit_hash:
|
||||||
self._cur_commit_hash = None
|
self._cur_commit_hash = None
|
||||||
|
@ -445,10 +379,7 @@ class SourceUpdateManager(UpdateManager):
|
||||||
try:
|
try:
|
||||||
self._check_github_for_update()
|
self._check_github_for_update()
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.log(
|
log.error(f'Unable to contact github, can\'t check for update: {error!r}')
|
||||||
f'Unable to contact github, can\'t check for update: {error!r}',
|
|
||||||
logger.ERROR,
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if not self._cur_commit_hash or self._num_commits_behind > 0:
|
if not self._cur_commit_hash or self._num_commits_behind > 0:
|
||||||
|
@ -473,7 +404,8 @@ class SourceUpdateManager(UpdateManager):
|
||||||
self.github_repo_user, self.github_repo, self.branch,
|
self.github_repo_user, self.github_repo, self.branch,
|
||||||
)
|
)
|
||||||
|
|
||||||
# try to get newest commit hash and commits behind directly by comparing branch and current commit
|
# try to get newest commit hash and commits behind directly by
|
||||||
|
# comparing branch and current commit
|
||||||
if self._cur_commit_hash:
|
if self._cur_commit_hash:
|
||||||
branch_compared = gh.compare(
|
branch_compared = gh.compare(
|
||||||
base=self.branch, head=self._cur_commit_hash,
|
base=self.branch, head=self._cur_commit_hash,
|
||||||
|
@ -502,14 +434,7 @@ class SourceUpdateManager(UpdateManager):
|
||||||
# when _cur_commit_hash doesn't match anything _num_commits_behind == 100
|
# when _cur_commit_hash doesn't match anything _num_commits_behind == 100
|
||||||
self._num_commits_behind += 1
|
self._num_commits_behind += 1
|
||||||
|
|
||||||
logger.log(
|
log.debug('cur_commit = {current} % (newest_commit)= {new}, num_commits_behind = {x}'.format(current=self._cur_commit_hash, new=self._newest_commit_hash, x=self._num_commits_behind))
|
||||||
'cur_commit = {current} % (newest_commit)= {new}, num_commits_behind = {x}'.format(
|
|
||||||
current=self._cur_commit_hash,
|
|
||||||
new=self._newest_commit_hash,
|
|
||||||
x=self._num_commits_behind,
|
|
||||||
),
|
|
||||||
logger.DEBUG,
|
|
||||||
)
|
|
||||||
|
|
||||||
def set_newest_text(self):
|
def set_newest_text(self):
|
||||||
|
|
||||||
|
@ -517,29 +442,16 @@ class SourceUpdateManager(UpdateManager):
|
||||||
nzb2media.NEWEST_VERSION_STRING = None
|
nzb2media.NEWEST_VERSION_STRING = None
|
||||||
|
|
||||||
if not self._cur_commit_hash:
|
if not self._cur_commit_hash:
|
||||||
logger.log(
|
log.error('Unknown current version number, don\'t know if we should update or not')
|
||||||
'Unknown current version number, don\'t know if we should update or not',
|
|
||||||
logger.ERROR,
|
|
||||||
)
|
|
||||||
elif self._num_commits_behind > 0:
|
elif self._num_commits_behind > 0:
|
||||||
logger.log(
|
log.info('There is a newer version available (you\'re {x} commit{s} behind)'.format(x=self._num_commits_behind, s='s' if self._num_commits_behind > 1 else ''))
|
||||||
'There is a newer version available (you\'re {x} commit{s} behind)'.format(
|
|
||||||
x=self._num_commits_behind,
|
|
||||||
s='s' if self._num_commits_behind > 1 else '',
|
|
||||||
),
|
|
||||||
logger.MESSAGE,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
"""Download and install latest source tarball from github."""
|
"""Download and install latest source tarball from github."""
|
||||||
tar_download_url = (
|
tar_download_url = (
|
||||||
'https://github.com/{org}/{repo}/tarball/{branch}'.format(
|
'https://github.com/{org}/{repo}/tarball/{branch}'.format(org=self.github_repo_user, repo=self.github_repo, branch=self.branch)
|
||||||
org=self.github_repo_user,
|
|
||||||
repo=self.github_repo,
|
|
||||||
branch=self.branch,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
version_path = os.path.join(nzb2media.APP_ROOT, 'version.txt')
|
version_path = os.path.join(nzb2media.APP_ROOT, 'version.txt')
|
||||||
|
|
||||||
|
@ -548,49 +460,35 @@ class SourceUpdateManager(UpdateManager):
|
||||||
sb_update_dir = os.path.join(nzb2media.APP_ROOT, 'sb-update')
|
sb_update_dir = os.path.join(nzb2media.APP_ROOT, 'sb-update')
|
||||||
|
|
||||||
if os.path.isdir(sb_update_dir):
|
if os.path.isdir(sb_update_dir):
|
||||||
logger.log(
|
log.info(f'Clearing out update folder {sb_update_dir} before extracting')
|
||||||
f'Clearing out update folder {sb_update_dir} before extracting',
|
|
||||||
)
|
|
||||||
shutil.rmtree(sb_update_dir)
|
shutil.rmtree(sb_update_dir)
|
||||||
|
|
||||||
logger.log(
|
log.info(f'Creating update folder {sb_update_dir} before extracting')
|
||||||
f'Creating update folder {sb_update_dir} before extracting',
|
|
||||||
)
|
|
||||||
os.makedirs(sb_update_dir)
|
os.makedirs(sb_update_dir)
|
||||||
|
|
||||||
# retrieve file
|
# retrieve file
|
||||||
logger.log(f'Downloading update from {tar_download_url!r}')
|
log.info(f'Downloading update from {tar_download_url!r}')
|
||||||
tar_download_path = os.path.join(
|
tar_download_path = os.path.join(
|
||||||
sb_update_dir, 'nzbtomedia-update.tar',
|
sb_update_dir, 'nzbtomedia-update.tar',
|
||||||
)
|
)
|
||||||
urlretrieve(tar_download_url, tar_download_path)
|
urlretrieve(tar_download_url, tar_download_path)
|
||||||
|
|
||||||
if not os.path.isfile(tar_download_path):
|
if not os.path.isfile(tar_download_path):
|
||||||
logger.log(
|
log.error('Unable to retrieve new version from {url}, can\'t update'.format(url=tar_download_url))
|
||||||
'Unable to retrieve new version from {url}, can\'t update'.format(
|
|
||||||
url=tar_download_url,
|
|
||||||
),
|
|
||||||
logger.ERROR,
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if not tarfile.is_tarfile(tar_download_path):
|
if not tarfile.is_tarfile(tar_download_path):
|
||||||
logger.log(
|
log.error('Retrieved version from {url} is corrupt, can\'t update'.format(url=tar_download_url))
|
||||||
'Retrieved version from {url} is corrupt, can\'t update'.format(
|
|
||||||
url=tar_download_url,
|
|
||||||
),
|
|
||||||
logger.ERROR,
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# extract to sb-update dir
|
# extract to sb-update dir
|
||||||
logger.log(f'Extracting file {tar_download_path}')
|
log.info(f'Extracting file {tar_download_path}')
|
||||||
tar = tarfile.open(tar_download_path)
|
tar = tarfile.open(tar_download_path)
|
||||||
tar.extractall(sb_update_dir)
|
tar.extractall(sb_update_dir)
|
||||||
tar.close()
|
tar.close()
|
||||||
|
|
||||||
# delete .tar.gz
|
# delete .tar.gz
|
||||||
logger.log(f'Deleting file {tar_download_path}')
|
log.info(f'Deleting file {tar_download_path}')
|
||||||
os.remove(tar_download_path)
|
os.remove(tar_download_path)
|
||||||
|
|
||||||
# find update dir name
|
# find update dir name
|
||||||
|
@ -600,23 +498,16 @@ class SourceUpdateManager(UpdateManager):
|
||||||
if os.path.isdir(os.path.join(sb_update_dir, x))
|
if os.path.isdir(os.path.join(sb_update_dir, x))
|
||||||
]
|
]
|
||||||
if len(update_dir_contents) != 1:
|
if len(update_dir_contents) != 1:
|
||||||
logger.log(
|
log.error(f'Invalid update data, update failed: {update_dir_contents}')
|
||||||
f'Invalid update data, update failed: {update_dir_contents}',
|
|
||||||
logger.ERROR,
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
content_dir = os.path.join(sb_update_dir, update_dir_contents[0])
|
content_dir = os.path.join(sb_update_dir, update_dir_contents[0])
|
||||||
|
|
||||||
# walk temp folder and move files to main folder
|
# walk temp folder and move files to main folder
|
||||||
logger.log(
|
log.info('Moving files from {source} to {destination}'.format(source=content_dir, destination=nzb2media.APP_ROOT))
|
||||||
'Moving files from {source} to {destination}'.format(
|
|
||||||
source=content_dir, destination=nzb2media.APP_ROOT,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
for dirname, _, filenames in os.walk(
|
for dirname, _, filenames in os.walk(
|
||||||
content_dir,
|
content_dir,
|
||||||
): # @UnusedVariable
|
): # @UnusedVariable
|
||||||
dirname = dirname[len(content_dir) + 1 :]
|
dirname = dirname[len(content_dir) + 1:]
|
||||||
for curfile in filenames:
|
for curfile in filenames:
|
||||||
old_path = os.path.join(content_dir, dirname, curfile)
|
old_path = os.path.join(content_dir, dirname, curfile)
|
||||||
new_path = os.path.join(nzb2media.APP_ROOT, dirname, curfile)
|
new_path = os.path.join(nzb2media.APP_ROOT, dirname, curfile)
|
||||||
|
@ -630,15 +521,9 @@ class SourceUpdateManager(UpdateManager):
|
||||||
os.remove(new_path)
|
os.remove(new_path)
|
||||||
os.renames(old_path, new_path)
|
os.renames(old_path, new_path)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.log(
|
log.debug('Unable to update {path}: {msg}'.format(path=new_path, msg=error))
|
||||||
'Unable to update {path}: {msg}'.format(
|
# Trash the updated file without moving in new path
|
||||||
path=new_path, msg=error,
|
os.remove(old_path)
|
||||||
),
|
|
||||||
logger.DEBUG,
|
|
||||||
)
|
|
||||||
os.remove(
|
|
||||||
old_path,
|
|
||||||
) # Trash the updated file without moving in new path
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if os.path.isfile(new_path):
|
if os.path.isfile(new_path):
|
||||||
|
@ -650,20 +535,12 @@ class SourceUpdateManager(UpdateManager):
|
||||||
with open(version_path, 'w') as ver_file:
|
with open(version_path, 'w') as ver_file:
|
||||||
ver_file.write(self._newest_commit_hash)
|
ver_file.write(self._newest_commit_hash)
|
||||||
except OSError as error:
|
except OSError as error:
|
||||||
logger.log(
|
log.error('Unable to write version file, update not complete: {msg}'.format(msg=error),)
|
||||||
'Unable to write version file, update not complete: {msg}'.format(
|
|
||||||
msg=error,
|
|
||||||
),
|
|
||||||
logger.ERROR,
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
logger.log(
|
log.error(f'Error while trying to update: {error}')
|
||||||
f'Error while trying to update: {error}',
|
log.debug(f'Traceback: {traceback.format_exc()}')
|
||||||
logger.ERROR,
|
|
||||||
)
|
|
||||||
logger.log(f'Traceback: {traceback.format_exc()}', logger.DEBUG)
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -1,23 +1,26 @@
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
|
||||||
from nzb2media.processor import nzbget, sab, manual
|
from nzb2media.processor import nzbget, sab, manual
|
||||||
from nzb2media.processor.nzb import process
|
from nzb2media.processor.nzb import process
|
||||||
from nzb2media.auto_process.common import ProcessResult
|
from nzb2media.auto_process.common import ProcessResult
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
log.addHandler(logging.NullHandler())
|
||||||
|
|
||||||
|
|
||||||
def main(args, section=None):
|
def main(args, section=None):
|
||||||
# Initialize the config
|
# Initialize the config
|
||||||
nzb2media.initialize(section)
|
nzb2media.initialize(section)
|
||||||
|
|
||||||
logger.info('#########################################################')
|
log.info('#########################################################')
|
||||||
logger.info(f'## ..::[{os.path.basename(__file__)}]::.. ##')
|
log.info(f'## ..::[{os.path.basename(__file__)}]::.. ##')
|
||||||
logger.info('#########################################################')
|
log.info('#########################################################')
|
||||||
|
|
||||||
# debug command line options
|
# debug command line options
|
||||||
logger.debug(f'Options passed into nzbToMedia: {args}')
|
log.debug(f'Options passed into nzbToMedia: {args}')
|
||||||
|
|
||||||
# Post-Processing Result
|
# Post-Processing Result
|
||||||
result = ProcessResult(
|
result = ProcessResult(
|
||||||
|
@ -36,22 +39,22 @@ def main(args, section=None):
|
||||||
result = sab.process(args)
|
result = sab.process(args)
|
||||||
# Generic program
|
# Generic program
|
||||||
elif len(args) > 5 and args[5] == 'generic':
|
elif len(args) > 5 and args[5] == 'generic':
|
||||||
logger.info('Script triggered from generic program')
|
log.info('Script triggered from generic program')
|
||||||
result = process(args[1], input_name=args[2], input_category=args[3], download_id=args[4])
|
result = process(args[1], input_name=args[2], input_category=args[3], download_id=args[4])
|
||||||
elif nzb2media.NZB_NO_MANUAL:
|
elif nzb2media.NZB_NO_MANUAL:
|
||||||
logger.warning('Invalid number of arguments received from client, and no_manual set')
|
log.warning('Invalid number of arguments received from client, and no_manual set')
|
||||||
else:
|
else:
|
||||||
manual.process()
|
manual.process()
|
||||||
|
|
||||||
if result.status_code == 0:
|
if result.status_code == 0:
|
||||||
logger.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 + '!')
|
||||||
if 'NZBOP_SCRIPTDIR' in os.environ: # return code for nzbget v11
|
if 'NZBOP_SCRIPTDIR' in os.environ: # return code for nzbget v11
|
||||||
del nzb2media.MYAPP
|
del nzb2media.MYAPP
|
||||||
return nzb2media.NZBGET_POSTPROCESS_SUCCESS
|
return nzb2media.NZBGET_POSTPROCESS_SUCCESS
|
||||||
else:
|
else:
|
||||||
logger.error(f'A problem was reported in the {args[0]} script.')
|
log.error(f'A problem was reported in the {args[0]} script.')
|
||||||
if result.message:
|
if result.message:
|
||||||
print(result.message + '!')
|
print(result.message + '!')
|
||||||
if 'NZBOP_SCRIPTDIR' in os.environ: # return code for nzbget v11
|
if 'NZBOP_SCRIPTDIR' in os.environ: # return code for nzbget v11
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue