2022-02-13 16:33:57 +00:00
import argparse , os , sys , time , traceback
2021-02-28 03:56:49 +00:00
from datetime import datetime
2021-12-17 14:24:46 +00:00
2021-03-16 13:56:17 +00:00
try :
2022-03-15 06:47:50 +00:00
import plexapi , requests , schedule
2022-02-13 16:33:57 +00:00
from modules . logs import MyLogger
2022-01-26 14:27:22 +00:00
from plexapi . exceptions import NotFound
from plexapi . video import Show , Season
2022-01-27 15:22:58 +00:00
from ruamel import yaml
2021-03-16 13:56:17 +00:00
except ModuleNotFoundError :
2021-05-25 22:22:59 +00:00
print ( " Requirements Error: Requirements are not installed " )
sys . exit ( 0 )
if sys . version_info [ 0 ] != 3 or sys . version_info [ 1 ] < 6 :
print ( " Version Error: Version: %s . %s . %s incompatible please use Python 3.6+ " % ( sys . version_info [ 0 ] , sys . version_info [ 1 ] , sys . version_info [ 2 ] ) )
2021-03-16 13:56:17 +00:00
sys . exit ( 0 )
2021-01-20 21:37:59 +00:00
parser = argparse . ArgumentParser ( )
2021-04-22 19:24:09 +00:00
parser . add_argument ( " -db " , " --debug " , dest = " debug " , help = argparse . SUPPRESS , action = " store_true " , default = False )
2021-11-03 14:38:43 +00:00
parser . add_argument ( " -tr " , " --trace " , dest = " trace " , help = argparse . SUPPRESS , action = " store_true " , default = False )
2021-01-20 21:37:59 +00:00
parser . add_argument ( " -c " , " --config " , dest = " config " , help = " Run with desired *.yml file " , type = str )
2021-09-08 03:04:36 +00:00
parser . add_argument ( " -t " , " --time " , " --times " , dest = " times " , help = " Times to update each day use format HH:MM (Default: 03:00) (comma-separated list) " , default = " 03:00 " , type = str )
2021-03-31 04:20:20 +00:00
parser . add_argument ( " -re " , " --resume " , dest = " resume " , help = " Resume collection run from a specific collection " , type = str )
2021-01-20 21:37:59 +00:00
parser . add_argument ( " -r " , " --run " , dest = " run " , help = " Run without the scheduler " , action = " store_true " , default = False )
2022-01-02 04:23:47 +00:00
parser . add_argument ( " -is " , " --ignore-schedules " , dest = " ignore_schedules " , help = " Run ignoring collection schedules " , action = " store_true " , default = False )
2022-02-13 16:33:57 +00:00
parser . add_argument ( " -ig " , " --ignore-ghost " , dest = " ignore_ghost " , help = " Run ignoring ghost logging " , action = " store_true " , default = False )
2021-02-21 08:13:07 +00:00
parser . add_argument ( " -rt " , " --test " , " --tests " , " --run-test " , " --run-tests " , dest = " test " , help = " Run in debug mode with only collections that have test: true " , action = " store_true " , default = False )
2021-05-18 21:56:57 +00:00
parser . add_argument ( " -co " , " --collection-only " , " --collections-only " , dest = " collection_only " , help = " Run only collection operations " , action = " store_true " , default = False )
parser . add_argument ( " -lo " , " --library-only " , " --libraries-only " , dest = " library_only " , help = " Run only library operations " , action = " store_true " , default = False )
2022-01-09 00:45:42 +00:00
parser . add_argument ( " -lf " , " --library-first " , " --libraries-first " , dest = " library_first " , help = " Run library operations before collections " , action = " store_true " , default = False )
2021-05-18 21:56:57 +00:00
parser . add_argument ( " -rc " , " -cl " , " --collection " , " --collections " , " --run-collection " , " --run-collections " , dest = " collections " , help = " Process only specified collections (comma-separated list) " , type = str )
parser . add_argument ( " -rl " , " -l " , " --library " , " --libraries " , " --run-library " , " --run-libraries " , dest = " libraries " , help = " Process only specified libraries (comma-separated list) " , type = str )
2022-01-25 07:45:31 +00:00
parser . add_argument ( " -rm " , " -m " , " --metadata " , " --metadata-files " , " --run-metadata-files " , dest = " metadata " , help = " Process only specified Metadata files (comma-separated list) " , type = str )
2021-12-31 04:34:04 +00:00
parser . add_argument ( " -dc " , " --delete " , " --delete-collections " , dest = " delete " , help = " Deletes all Collections in the Plex Library before running " , action = " store_true " , default = False )
2021-05-26 06:03:00 +00:00
parser . add_argument ( " -nc " , " --no-countdown " , dest = " no_countdown " , help = " Run without displaying the countdown " , action = " store_true " , default = False )
2021-08-09 19:45:20 +00:00
parser . add_argument ( " -nm " , " --no-missing " , dest = " no_missing " , help = " Run without running the missing section " , action = " store_true " , default = False )
2021-12-26 15:48:52 +00:00
parser . add_argument ( " -ro " , " --read-only-config " , dest = " read_only_config " , help = " Run without writing to the config " , action = " store_true " , default = False )
2021-01-20 21:37:59 +00:00
parser . add_argument ( " -d " , " --divider " , dest = " divider " , help = " Character that divides the sections (Default: ' = ' ) " , default = " = " , type = str )
parser . add_argument ( " -w " , " --width " , dest = " width " , help = " Screen Width (Default: 100) " , default = 100 , type = int )
args = parser . parse_args ( )
2021-09-08 03:04:36 +00:00
def get_arg ( env_str , default , arg_bool = False , arg_int = False ) :
2021-03-16 21:00:21 +00:00
env_var = os . environ . get ( env_str )
2021-09-08 03:04:36 +00:00
if env_var :
if arg_bool :
if env_var is True or env_var is False :
return env_var
elif env_var . lower ( ) in [ " t " , " true " ] :
return True
else :
return False
elif arg_int :
return int ( env_var )
2021-03-16 21:00:21 +00:00
else :
2021-09-08 03:04:36 +00:00
return str ( env_var )
2021-03-16 21:00:21 +00:00
else :
return default
2021-12-06 22:30:38 +00:00
config_file = get_arg ( " PMM_CONFIG " , args . config )
times = get_arg ( " PMM_TIME " , args . times )
2021-09-08 03:04:36 +00:00
run = get_arg ( " PMM_RUN " , args . run , arg_bool = True )
2021-12-06 22:30:38 +00:00
test = get_arg ( " PMM_TEST " , args . test , arg_bool = True )
2022-01-02 04:23:47 +00:00
ignore_schedules = get_arg ( " PMM_IGNORE_SCHEDULES " , args . ignore_schedules , arg_bool = True )
2022-02-13 16:33:57 +00:00
ignore_ghost = get_arg ( " PMM_IGNORE_GHOST " , args . ignore_ghost , arg_bool = True )
2021-09-08 03:04:36 +00:00
collection_only = get_arg ( " PMM_COLLECTIONS_ONLY " , args . collection_only , arg_bool = True )
2021-12-06 22:30:38 +00:00
library_only = get_arg ( " PMM_LIBRARIES_ONLY " , args . library_only , arg_bool = True )
2022-01-04 16:46:56 +00:00
library_first = get_arg ( " PMM_LIBRARIES_FIRST " , args . library_first , arg_bool = True )
2021-09-08 03:04:36 +00:00
collections = get_arg ( " PMM_COLLECTIONS " , args . collections )
libraries = get_arg ( " PMM_LIBRARIES " , args . libraries )
2022-01-25 07:45:31 +00:00
metadata_files = get_arg ( " PMM_METADATA_FILES " , args . metadata )
2021-12-31 04:34:04 +00:00
delete = get_arg ( " PMM_DELETE_COLLECTIONS " , args . delete , arg_bool = True )
2021-09-08 03:04:36 +00:00
resume = get_arg ( " PMM_RESUME " , args . resume )
2021-12-06 22:30:38 +00:00
no_countdown = get_arg ( " PMM_NO_COUNTDOWN " , args . no_countdown , arg_bool = True )
no_missing = get_arg ( " PMM_NO_MISSING " , args . no_missing , arg_bool = True )
2021-12-24 00:16:46 +00:00
read_only_config = get_arg ( " PMM_READ_ONLY_CONFIG " , args . read_only_config , arg_bool = True )
2021-09-08 03:04:36 +00:00
divider = get_arg ( " PMM_DIVIDER " , args . divider )
2021-11-17 14:20:04 +00:00
screen_width = get_arg ( " PMM_WIDTH " , args . width , arg_int = True )
2021-12-06 22:30:38 +00:00
debug = get_arg ( " PMM_DEBUG " , args . debug , arg_bool = True )
trace = get_arg ( " PMM_TRACE " , args . trace , arg_bool = True )
2021-09-08 03:04:36 +00:00
if screen_width < 90 or screen_width > 300 :
print ( f " Argument Error: width argument invalid: { screen_width } must be an integer between 90 and 300 using the default 100 " )
screen_width = 100
2021-01-20 21:37:59 +00:00
default_dir = os . path . join ( os . path . dirname ( os . path . abspath ( __file__ ) ) , " config " )
2021-09-08 03:04:36 +00:00
if config_file and os . path . exists ( config_file ) :
default_dir = os . path . join ( os . path . dirname ( os . path . abspath ( config_file ) ) )
elif config_file and not os . path . exists ( config_file ) :
print ( f " Config Error: config not found at { os . path . abspath ( config_file ) } " )
sys . exit ( 0 )
elif not os . path . exists ( os . path . join ( default_dir , " config.yml " ) ) :
print ( f " Config Error: config not found at { os . path . abspath ( default_dir ) } " )
sys . exit ( 0 )
2021-01-20 21:37:59 +00:00
2022-02-13 16:33:57 +00:00
logger = MyLogger ( " Plex Meta Manager " , default_dir , screen_width , divider [ 0 ] , ignore_ghost , test or debug or trace )
2021-01-20 21:37:59 +00:00
2022-02-13 16:33:57 +00:00
from modules import util
util . logger = logger
from modules . builder import CollectionBuilder
from modules . config import ConfigFile
from modules . meta import MetadataFile
from modules . util import Failed , NotScheduled
2021-01-20 21:37:59 +00:00
2022-02-13 16:33:57 +00:00
def my_except_hook ( exctype , value , tb ) :
for _line in traceback . format_exception ( etype = exctype , value = value , tb = tb ) :
logger . critical ( _line )
2021-01-20 21:37:59 +00:00
2022-02-13 16:33:57 +00:00
sys . excepthook = my_except_hook
2021-01-20 21:37:59 +00:00
2022-03-16 21:01:39 +00:00
def get_versions ( presplit_version ) :
split_version = presplit_version . split ( " -develop " )
return presplit_version , split_version [ 0 ] , int ( split_version [ 1 ] ) if len ( split_version ) > 1 else 0
version = ( " Unknown " , " Unknown " , 0 )
2021-10-21 16:00:00 +00:00
with open ( os . path . join ( os . path . dirname ( os . path . abspath ( __file__ ) ) , " VERSION " ) ) as handle :
2021-10-19 04:23:52 +00:00
for line in handle . readlines ( ) :
line = line . strip ( )
if len ( line ) > 0 :
2022-03-16 21:01:39 +00:00
version = get_versions ( line )
2021-10-19 04:23:52 +00:00
break
2022-03-16 21:01:39 +00:00
version_url = f " https://raw.githubusercontent.com/meisnate12/Plex-Meta-Manager/ { ' develop ' if version [ 1 ] else ' master ' } /VERSION "
latest_version = get_versions ( requests . get ( version_url ) . content . decode ( ) . strip ( ) )
new_version = latest_version [ 0 ] if version [ 1 ] != latest_version [ 1 ] or ( version [ 2 ] and version [ 2 ] < latest_version [ 2 ] ) else None
2022-03-15 06:47:50 +00:00
2022-02-08 06:19:35 +00:00
plexapi . BASE_HEADERS [ ' X-Plex-Client-Identifier ' ] = " Plex-Meta-Manager "
2021-10-04 17:51:32 +00:00
def start ( attrs ) :
2022-02-13 16:33:57 +00:00
logger . add_main_handler ( )
logger . separator ( )
2021-10-19 04:23:52 +00:00
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . info_center ( " ____ _ __ __ _ __ __ " )
logger . info_center ( " | _ \\ | | _____ __ | \\ / | ___| |_ __ _ | \\ / | __ _ _ __ __ _ __ _ ___ _ __ " )
logger . info_center ( " | |_) | |/ _ \\ \\ / / | | \\ /| |/ _ \\ __/ _` | | | \\ /| |/ _` | ' _ \\ / _` |/ _` |/ _ \\ ' __| " )
logger . info_center ( " | __/| | __/> < | | | | __/ || (_| | | | | | (_| | | | | (_| | (_| | __/ | " )
logger . info_center ( " |_| |_| \\ ___/_/ \\ _ \\ |_| |_| \\ ___| \\ __ \\ __,_| |_| |_| \\ __,_|_| |_| \\ __,_| \\ __, | \\ ___|_| " )
logger . info_center ( " |___/ " )
2022-03-16 21:01:39 +00:00
logger . info ( f " Version: { version [ 0 ] } " )
if new_version :
logger . info ( f " Newest Version: { new_version } " )
2021-10-07 15:17:20 +00:00
if " time " in attrs and attrs [ " time " ] : start_type = f " { attrs [ ' time ' ] } "
elif " test " in attrs and attrs [ " test " ] : start_type = " Test "
elif " collections " in attrs and attrs [ " collections " ] : start_type = " Collections "
elif " libraries " in attrs and attrs [ " libraries " ] : start_type = " Libraries "
else : start_type = " "
2021-02-28 03:56:49 +00:00
start_time = datetime . now ( )
2021-10-04 17:51:32 +00:00
if " time " not in attrs :
attrs [ " time " ] = start_time . strftime ( " % H: % M " )
2021-12-01 05:38:20 +00:00
attrs [ " time_obj " ] = start_time
2022-03-16 21:01:39 +00:00
attrs [ " read_only " ] = read_only_config
2022-03-16 21:03:28 +00:00
attrs [ " new_version " ] = new_version
2022-02-13 16:33:57 +00:00
logger . separator ( debug = True )
2021-12-06 22:30:38 +00:00
logger . debug ( f " --config (PMM_CONFIG): { config_file } " )
logger . debug ( f " --time (PMM_TIME): { times } " )
logger . debug ( f " --run (PMM_RUN): { run } " )
logger . debug ( f " --run-tests (PMM_TEST): { test } " )
logger . debug ( f " --collections-only (PMM_COLLECTIONS_ONLY): { collection_only } " )
logger . debug ( f " --libraries-only (PMM_LIBRARIES_ONLY): { library_only } " )
2022-01-04 16:46:56 +00:00
logger . debug ( f " --libraries-first (PMM_LIBRARIES_FIRST): { library_first } " )
2021-12-06 22:30:38 +00:00
logger . debug ( f " --run-collections (PMM_COLLECTIONS): { collections } " )
logger . debug ( f " --run-libraries (PMM_LIBRARIES): { libraries } " )
2022-01-25 07:45:31 +00:00
logger . debug ( f " --run-metadata-files (PMM_METADATA_FILES): { metadata_files } " )
2022-01-02 04:23:47 +00:00
logger . debug ( f " --ignore-schedules (PMM_IGNORE_SCHEDULES): { ignore_schedules } " )
2022-02-13 16:33:57 +00:00
logger . debug ( f " --ignore-ghost (PMM_IGNORE_GHOST): { ignore_ghost } " )
2021-12-31 04:34:04 +00:00
logger . debug ( f " --delete-collections (PMM_DELETE_COLLECTIONS): { delete } " )
2021-12-06 22:30:38 +00:00
logger . debug ( f " --resume (PMM_RESUME): { resume } " )
logger . debug ( f " --no-countdown (PMM_NO_COUNTDOWN): { no_countdown } " )
logger . debug ( f " --no-missing (PMM_NO_MISSING): { no_missing } " )
2021-12-24 00:16:46 +00:00
logger . debug ( f " --read-only-config (PMM_READ_ONLY_CONFIG): { read_only_config } " )
2021-12-06 22:30:38 +00:00
logger . debug ( f " --divider (PMM_DIVIDER): { divider } " )
logger . debug ( f " --width (PMM_WIDTH): { screen_width } " )
logger . debug ( f " --debug (PMM_DEBUG): { debug } " )
logger . debug ( f " --trace (PMM_TRACE): { trace } " )
logger . debug ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " Starting { start_type } Run " )
2021-11-03 14:36:11 +00:00
config = None
2021-12-30 21:29:16 +00:00
stats = { " created " : 0 , " modified " : 0 , " deleted " : 0 , " added " : 0 , " unchanged " : 0 , " removed " : 0 , " radarr " : 0 , " sonarr " : 0 }
2021-01-20 21:37:59 +00:00
try :
2022-03-16 21:01:39 +00:00
config = ConfigFile ( default_dir , attrs )
2021-01-20 21:37:59 +00:00
except Exception as e :
2022-02-13 16:33:57 +00:00
logger . stacktrace ( )
logger . critical ( e )
2021-10-04 17:51:32 +00:00
else :
try :
2021-12-30 21:29:16 +00:00
stats = update_libraries ( config )
2021-10-04 17:51:32 +00:00
except Exception as e :
config . notify ( e )
2022-02-13 16:33:57 +00:00
logger . stacktrace ( )
logger . critical ( e )
2021-01-20 21:37:59 +00:00
logger . info ( " " )
2021-12-01 05:38:20 +00:00
end_time = datetime . now ( )
run_time = str ( end_time - start_time ) . split ( ' . ' ) [ 0 ]
2021-11-03 14:36:11 +00:00
if config :
2021-11-28 07:14:35 +00:00
try :
2022-03-16 21:03:28 +00:00
config . Webhooks . end_time_hooks ( start_time , end_time , run_time , stats , new_version )
2021-11-28 07:14:35 +00:00
except Failed as e :
2022-02-13 16:33:57 +00:00
logger . stacktrace ( )
2021-11-28 07:14:35 +00:00
logger . error ( f " Webhooks Error: { e } " )
2022-03-16 21:01:39 +00:00
version_line = f " Version: { version [ 0 ] } "
if new_version :
version_line = f " { version_line } Newest Version: { new_version } "
2022-03-15 06:47:50 +00:00
logger . separator ( f " Finished { start_type } Run \n { version_line } \n Finished: { end_time . strftime ( ' % H: % M: % S % Y- % m- %d ' ) } Run Time: { run_time } " )
2022-02-13 16:33:57 +00:00
logger . remove_main_handler ( )
2021-01-20 21:37:59 +00:00
2021-05-25 22:22:59 +00:00
def update_libraries ( config ) :
2021-05-08 02:30:28 +00:00
for library in config . libraries :
2021-12-18 03:02:24 +00:00
if library . skip_library :
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " Skipping { library . name } Library " )
2021-12-18 03:02:24 +00:00
continue
2021-10-04 17:51:32 +00:00
try :
2022-02-13 16:33:57 +00:00
logger . add_library_handler ( library . mapping_name )
2021-10-26 05:40:23 +00:00
plexapi . server . TIMEOUT = library . timeout
2021-08-12 20:37:03 +00:00
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " { library . name } Library " )
2021-12-06 07:52:08 +00:00
2022-01-04 16:46:56 +00:00
if config . library_first and library . library_operation and not config . test_mode and not collection_only :
library_operations ( config , library )
2021-12-06 07:52:08 +00:00
logger . debug ( " " )
logger . debug ( f " Mapping Name: { library . original_mapping_name } " )
logger . debug ( f " Folder Name: { library . mapping_name } " )
logger . debug ( f " Missing Path: { library . missing_path } " )
for ad in library . asset_directory :
logger . debug ( f " Asset Directory: { ad } " )
logger . debug ( f " Asset Folders: { library . asset_folders } " )
logger . debug ( f " Create Asset Folders: { library . create_asset_folders } " )
2022-01-11 01:23:56 +00:00
logger . debug ( f " Download URL Assets: { library . download_url_assets } " )
2021-12-06 07:52:08 +00:00
logger . debug ( f " Sync Mode: { library . sync_mode } " )
2022-03-10 18:28:56 +00:00
logger . debug ( f " Minimum Items: { library . minimum_items } " )
2021-12-06 07:52:08 +00:00
logger . debug ( f " Delete Below Minimum: { library . delete_below_minimum } " )
2021-12-06 22:30:38 +00:00
logger . debug ( f " Delete Not Scheduled: { library . delete_not_scheduled } " )
2022-01-11 01:23:56 +00:00
logger . debug ( f " Default Collection Order: { library . default_collection_order } " )
2021-12-06 07:52:08 +00:00
logger . debug ( f " Missing Only Released: { library . missing_only_released } " )
logger . debug ( f " Only Filter Missing: { library . only_filter_missing } " )
logger . debug ( f " Show Unmanaged: { library . show_unmanaged } " )
logger . debug ( f " Show Filtered: { library . show_filtered } " )
logger . debug ( f " Show Missing: { library . show_missing } " )
logger . debug ( f " Show Missing Assets: { library . show_missing_assets } " )
logger . debug ( f " Save Missing: { library . save_missing } " )
logger . debug ( f " Clean Bundles: { library . clean_bundles } " )
logger . debug ( f " Empty Trash: { library . empty_trash } " )
logger . debug ( f " Optimize: { library . optimize } " )
logger . debug ( f " Timeout: { library . timeout } " )
2021-12-31 04:34:04 +00:00
if config . delete_collections :
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " Deleting all Collections from the { library . name } Library " , space = False , border = False )
2021-12-31 04:34:04 +00:00
logger . info ( " " )
for collection in library . get_all_collections ( ) :
logger . info ( f " Collection { collection . title } Deleted " )
library . query ( collection . delete )
2022-02-08 22:57:36 +00:00
if not library . is_other and not library . is_music and ( library . metadata_files or library . original_mapping_name in config . library_map ) and not library_only :
2021-08-12 20:37:03 +00:00
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " Mapping { library . name } Library " , space = False , border = False )
2021-08-12 20:37:03 +00:00
logger . info ( " " )
2021-12-07 19:21:07 +00:00
library . map_guids ( )
2021-10-04 17:51:32 +00:00
for metadata in library . metadata_files :
2022-01-24 15:57:48 +00:00
metadata_name = metadata . get_file_name ( )
2022-01-25 07:45:31 +00:00
if config . requested_metadata_files and metadata_name not in config . requested_metadata_files :
2022-01-24 15:57:48 +00:00
continue
2021-05-19 19:21:22 +00:00
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " Running { metadata_name } Metadata File \n { metadata . path } " )
2021-10-04 17:51:32 +00:00
if not config . test_mode and not config . resume_from and not collection_only :
try :
metadata . update_metadata ( )
except Failed as e :
library . notify ( e )
logger . error ( e )
collections_to_run = metadata . get_collections ( config . requested_collections )
if config . resume_from and config . resume_from not in collections_to_run :
logger . info ( " " )
logger . warning ( f " Collection: { config . resume_from } not in Metadata File: { metadata . path } " )
continue
if collections_to_run and not library_only :
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " { ' Test ' if config . test_mode else ' ' } Collections " )
logger . remove_library_handler ( library . mapping_name )
2021-10-04 17:51:32 +00:00
run_collection ( config , library , metadata , collections_to_run )
2022-02-13 16:33:57 +00:00
logger . re_add_library_handler ( library . mapping_name )
2021-10-04 17:51:32 +00:00
if library . run_sort :
2021-05-19 19:21:22 +00:00
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " Sorting { library . name } Library ' s Collections " , space = False , border = False )
2021-05-24 03:38:46 +00:00
logger . info ( " " )
2021-10-04 17:51:32 +00:00
for builder in library . run_sort :
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " Sorting { builder . name } Collection " , space = False , border = False )
2021-10-04 17:51:32 +00:00
logger . info ( " " )
builder . sort_collection ( )
2021-05-19 19:21:22 +00:00
2022-01-04 16:46:56 +00:00
if not config . library_first and library . library_operation and not config . test_mode and not collection_only :
2021-12-07 19:21:07 +00:00
library_operations ( config , library )
2021-10-04 17:51:32 +00:00
2022-02-13 16:33:57 +00:00
logger . remove_library_handler ( library . mapping_name )
2021-10-04 17:51:32 +00:00
except Exception as e :
library . notify ( e )
2022-02-13 16:33:57 +00:00
logger . stacktrace ( )
logger . critical ( e )
2021-05-08 02:30:28 +00:00
2021-12-30 21:29:16 +00:00
playlist_status = { }
playlist_stats = { }
2021-12-17 14:24:46 +00:00
if config . playlist_files :
2022-02-13 16:33:57 +00:00
logger . add_playlists_handler ( )
2021-12-30 21:29:16 +00:00
playlist_status , playlist_stats = run_playlists ( config )
2022-02-13 16:33:57 +00:00
logger . remove_playlists_handler ( )
2021-12-17 14:24:46 +00:00
2021-05-08 02:30:28 +00:00
has_run_again = False
for library in config . libraries :
if library . run_again :
has_run_again = True
break
2021-12-30 21:29:16 +00:00
amount_added = 0
2021-05-18 17:41:22 +00:00
if has_run_again and not library_only :
2021-05-08 02:30:28 +00:00
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( " Run Again " )
2021-05-08 02:30:28 +00:00
logger . info ( " " )
for x in range ( 1 , config . general [ " run_again_delay " ] + 1 ) :
2022-02-13 16:33:57 +00:00
logger . ghost ( f " Waiting to run again in { config . general [ ' run_again_delay ' ] - x + 1 } minutes " )
2021-05-08 02:30:28 +00:00
for y in range ( 60 ) :
time . sleep ( 1 )
2022-02-13 16:33:57 +00:00
logger . exorcise ( )
2021-05-08 02:30:28 +00:00
for library in config . libraries :
if library . run_again :
2021-10-04 17:51:32 +00:00
try :
2022-02-13 16:33:57 +00:00
logger . re_add_library_handler ( library . mapping_name )
2021-10-04 17:51:32 +00:00
os . environ [ " PLEXAPI_PLEXAPI_TIMEOUT " ] = str ( library . timeout )
2021-05-08 02:30:28 +00:00
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " { library . name } Library Run Again " )
2021-05-08 02:30:28 +00:00
logger . info ( " " )
2021-10-04 17:51:32 +00:00
library . map_guids ( )
for builder in library . run_again :
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " { builder . name } Collection in { library . name } " )
2021-10-04 17:51:32 +00:00
logger . info ( " " )
try :
2021-12-30 21:29:16 +00:00
amount_added + = builder . run_collections_again ( )
2021-10-04 17:51:32 +00:00
except Failed as e :
library . notify ( e , collection = builder . name , critical = False )
2022-02-13 16:33:57 +00:00
logger . stacktrace ( )
logger . error ( e )
logger . remove_library_handler ( library . mapping_name )
2021-10-04 17:51:32 +00:00
except Exception as e :
library . notify ( e )
2022-02-13 16:33:57 +00:00
logger . stacktrace ( )
logger . critical ( e )
2021-05-08 02:30:28 +00:00
2021-05-12 23:19:39 +00:00
used_url = [ ]
for library in config . libraries :
if library . url not in used_url :
used_url . append ( library . url )
if library . empty_trash :
library . query ( library . PlexServer . library . emptyTrash )
2021-05-14 02:45:36 +00:00
if library . clean_bundles :
library . query ( library . PlexServer . library . cleanBundles )
2021-05-12 23:19:39 +00:00
if library . optimize :
library . query ( library . PlexServer . library . optimize )
2021-12-30 21:29:16 +00:00
longest = 20
for library in config . libraries :
for title in library . status :
if len ( title ) > longest :
longest = len ( title )
if playlist_status :
for title in playlist_status :
if len ( title ) > longest :
longest = len ( title )
2021-12-30 23:05:31 +00:00
2021-12-30 21:29:16 +00:00
def print_status ( section , status ) :
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " { section } Summary " , space = False , border = False )
2021-12-30 21:29:16 +00:00
logger . info ( " " )
2021-12-30 23:05:31 +00:00
logger . info ( f " { ' Title ' : ^ { longest } } | + | = | - | { ' Status ' : ^13 } " )
2022-02-13 16:33:57 +00:00
breaker = f " { logger . separating_character * longest } | { logger . separating_character * 5 } | { logger . separating_character * 5 } | { logger . separating_character * 5 } | "
logger . separator ( breaker , space = False , border = False , side_space = False , left = True )
2021-12-30 21:29:16 +00:00
for name , data in status . items ( ) :
2021-12-30 23:05:31 +00:00
logger . info ( f " { name : < { longest } } | { data [ ' added ' ] : ^3 } | { data [ ' unchanged ' ] : ^3 } | { data [ ' removed ' ] : ^3 } | { data [ ' status ' ] } " )
2021-12-30 21:29:16 +00:00
if data [ " errors " ] :
for error in data [ " errors " ] :
2022-02-13 16:33:57 +00:00
logger . info ( error )
2021-12-30 21:29:16 +00:00
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( " Summary " )
2021-12-30 21:29:16 +00:00
for library in config . libraries :
print_status ( library . name , library . status )
if playlist_status :
print_status ( " Playlists " , playlist_status )
2022-02-20 00:08:41 +00:00
stats = { " created " : 0 , " modified " : 0 , " deleted " : 0 , " added " : 0 , " unchanged " : 0 , " removed " : 0 , " radarr " : 0 , " sonarr " : 0 , " names " : [ ] }
2021-12-30 21:29:16 +00:00
stats [ " added " ] + = amount_added
for library in config . libraries :
stats [ " created " ] + = library . stats [ " created " ]
stats [ " modified " ] + = library . stats [ " modified " ]
stats [ " deleted " ] + = library . stats [ " deleted " ]
stats [ " added " ] + = library . stats [ " added " ]
stats [ " unchanged " ] + = library . stats [ " unchanged " ]
stats [ " removed " ] + = library . stats [ " removed " ]
stats [ " radarr " ] + = library . stats [ " radarr " ]
stats [ " sonarr " ] + = library . stats [ " sonarr " ]
2022-02-20 00:08:41 +00:00
stats [ " names " ] . extend ( [ { " name " : n , " library " : library . name } for n in library . stats [ " names " ] ] )
2021-12-30 21:29:16 +00:00
if playlist_stats :
stats [ " created " ] + = playlist_stats [ " created " ]
stats [ " modified " ] + = playlist_stats [ " modified " ]
stats [ " deleted " ] + = playlist_stats [ " deleted " ]
stats [ " added " ] + = playlist_stats [ " added " ]
stats [ " unchanged " ] + = playlist_stats [ " unchanged " ]
stats [ " removed " ] + = playlist_stats [ " removed " ]
stats [ " radarr " ] + = playlist_stats [ " radarr " ]
stats [ " sonarr " ] + = playlist_stats [ " sonarr " ]
2022-02-20 00:08:41 +00:00
stats [ " names " ] . extend ( [ { " name " : n , " library " : " PLAYLIST " } for n in playlist_stats [ " names " ] ] )
2021-12-30 21:29:16 +00:00
return stats
2021-12-07 19:21:07 +00:00
def library_operations ( config , library ) :
2021-05-08 02:30:28 +00:00
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " { library . name } Library Operations " )
2021-05-08 02:30:28 +00:00
logger . info ( " " )
2021-12-07 18:48:31 +00:00
logger . debug ( f " Assets For All: { library . assets_for_all } " )
logger . debug ( f " Delete Collections With Less: { library . delete_collections_with_less } " )
logger . debug ( f " Delete Unmanaged Collections: { library . delete_unmanaged_collections } " )
logger . debug ( f " Mass Genre Update: { library . mass_genre_update } " )
logger . debug ( f " Mass Audience Rating Update: { library . mass_audience_rating_update } " )
logger . debug ( f " Mass Critic Rating Update: { library . mass_critic_rating_update } " )
2022-02-07 22:46:24 +00:00
logger . debug ( f " Mass Content Rating Update: { library . mass_content_rating_update } " )
2022-03-14 04:53:07 +00:00
logger . debug ( f " Mass Originally Available Update: { library . mass_originally_available_update } " )
2022-03-15 15:52:55 +00:00
logger . debug ( f " Mass IMDb Parental Labels: { library . mass_imdb_parental_labels } " )
2021-12-07 18:48:31 +00:00
logger . debug ( f " Mass Trakt Rating Update: { library . mass_trakt_rating_update } " )
2021-12-19 21:02:10 +00:00
logger . debug ( f " Mass Collection Mode Update: { library . mass_collection_mode } " )
2021-12-07 18:48:31 +00:00
logger . debug ( f " Split Duplicates: { library . split_duplicates } " )
2021-12-30 18:59:54 +00:00
logger . debug ( f " Radarr Add All Existing: { library . radarr_add_all_existing } " )
2021-12-18 22:45:09 +00:00
logger . debug ( f " Radarr Remove by Tag: { library . radarr_remove_by_tag } " )
2021-12-30 18:59:54 +00:00
logger . debug ( f " Sonarr Add All Existing: { library . sonarr_add_all_existing } " )
2021-12-18 22:45:09 +00:00
logger . debug ( f " Sonarr Remove by Tag: { library . sonarr_remove_by_tag } " )
2022-02-04 22:00:38 +00:00
logger . debug ( f " Update Blank Track Titles: { library . update_blank_track_titles } " )
2021-12-07 18:48:31 +00:00
logger . debug ( f " TMDb Collections: { library . tmdb_collections } " )
2021-12-31 04:51:46 +00:00
logger . debug ( f " Genre Collections: { library . genre_collections } " )
2021-12-07 18:48:31 +00:00
logger . debug ( f " Genre Mapper: { library . genre_mapper } " )
2022-03-13 20:44:42 +00:00
logger . debug ( f " Content Rating Mapper: { library . content_rating_mapper } " )
2022-01-27 15:22:58 +00:00
logger . debug ( f " Metadata Backup: { library . metadata_backup } " )
logger . debug ( f " Item Operation: { library . items_library_operation } " )
2022-01-27 21:56:23 +00:00
logger . debug ( " " )
2021-11-06 03:54:12 +00:00
2021-07-03 02:14:36 +00:00
if library . split_duplicates :
items = library . search ( * * { " duplicate " : True } )
for item in items :
item . split ( )
2022-02-13 16:33:57 +00:00
logger . info ( f " { item . title [ : 25 ] : <25 } | Splitting " )
2021-08-02 21:01:19 +00:00
2022-02-04 22:00:38 +00:00
if library . update_blank_track_titles :
2022-02-08 13:43:31 +00:00
tracks = library . get_all ( collection_level = " track " )
2022-03-03 14:43:00 +00:00
num_edited = 0
2022-02-08 13:43:31 +00:00
for i , item in enumerate ( tracks , 1 ) :
2022-02-13 16:33:57 +00:00
logger . ghost ( f " Processing Track: { i } / { len ( tracks ) } { item . title } " )
2022-03-06 04:34:05 +00:00
if not item . title and item . titleSort :
library . edit_query ( item , { " title.locked " : 1 , " title.value " : item . titleSort } )
num_edited + = 1
logger . info ( f " Track: { item . titleSort } was updated with sort title " )
2022-03-03 14:43:00 +00:00
logger . info ( f " { len ( tracks ) } Tracks Processed; { num_edited } Blank Track Titles Updated " )
2022-02-04 22:00:38 +00:00
2021-12-31 04:51:46 +00:00
tmdb_collections = { }
2022-01-24 15:13:08 +00:00
if library . items_library_operation :
2022-02-03 23:24:35 +00:00
items = library . get_all ( load = True )
2021-11-06 03:54:12 +00:00
radarr_adds = [ ]
sonarr_adds = [ ]
trakt_ratings = config . Trakt . user_ratings ( library . is_movie ) if library . mass_trakt_rating_update else [ ]
2022-03-15 00:11:16 +00:00
reverse_anidb = { }
2022-03-16 06:19:34 +00:00
if library . mass_genre_update == " anidb " :
2022-03-16 21:01:39 +00:00
for k , v in library . anidb_map . items ( ) :
2022-03-16 06:19:34 +00:00
reverse_anidb [ v ] = k
2022-03-15 00:11:16 +00:00
2021-11-06 03:54:12 +00:00
for i , item in enumerate ( items , 1 ) :
2021-08-05 18:57:50 +00:00
try :
2021-11-06 03:54:12 +00:00
library . reload ( item )
except Failed as e :
logger . error ( e )
continue
2022-02-13 16:33:57 +00:00
logger . ghost ( f " Processing: { i } / { len ( items ) } { item . title } " )
2021-11-15 20:31:38 +00:00
if library . assets_for_all :
2021-12-19 00:48:11 +00:00
library . find_assets ( item )
2022-01-27 15:22:58 +00:00
tmdb_id , tvdb_id , imdb_id = library . get_ids ( item )
2021-11-06 03:54:12 +00:00
if library . mass_trakt_rating_update :
2021-05-08 02:30:28 +00:00
try :
2021-11-06 03:54:12 +00:00
if library . is_movie and tmdb_id in trakt_ratings :
new_rating = trakt_ratings [ tmdb_id ]
elif library . is_show and tvdb_id in trakt_ratings :
new_rating = trakt_ratings [ tvdb_id ]
else :
raise Failed
if str ( item . userRating ) != str ( new_rating ) :
library . edit_query ( item , { " userRating.value " : new_rating , " userRating.locked " : 1 } )
2022-02-13 16:33:57 +00:00
logger . info ( f " { item . title [ : 25 ] : <25 } | User Rating | { new_rating } " )
2021-11-06 03:54:12 +00:00
except Failed :
pass
2022-03-15 15:52:55 +00:00
if library . mass_imdb_parental_labels :
try :
parental_guide = config . IMDb . parental_guide ( imdb_id )
labels = [ f " { k . capitalize ( ) } : { v } " for k , v in parental_guide . items ( ) if library . mass_imdb_parental_labels == " with_none " or v != " None " ]
library . edit_tags ( " label " , item , append_tags = labels )
except Failed :
pass
2022-03-16 06:19:34 +00:00
2021-11-24 13:22:17 +00:00
path = os . path . dirname ( str ( item . locations [ 0 ] ) ) if library . is_movie else str ( item . locations [ 0 ] )
2021-12-30 18:59:54 +00:00
if library . Radarr and library . radarr_add_all_existing and tmdb_id :
2021-12-09 15:23:51 +00:00
path = path . replace ( library . Radarr . plex_path , library . Radarr . radarr_path )
path = path [ : - 1 ] if path . endswith ( ( ' / ' , ' \\ ' ) ) else path
radarr_adds . append ( ( tmdb_id , path ) )
2021-12-30 18:59:54 +00:00
if library . Sonarr and library . sonarr_add_all_existing and tvdb_id :
2021-12-09 15:23:51 +00:00
path = path . replace ( library . Sonarr . plex_path , library . Sonarr . sonarr_path )
path = path [ : - 1 ] if path . endswith ( ( ' / ' , ' \\ ' ) ) else path
sonarr_adds . append ( ( tvdb_id , path ) )
2021-11-06 03:54:12 +00:00
tmdb_item = None
2022-03-14 04:53:07 +00:00
if library . tmdb_collections or library . mass_genre_update == " tmdb " or library . mass_audience_rating_update == " tmdb " \
or library . mass_critic_rating_update == " tmdb " or library . mass_originally_available_update == " tmdb " :
2022-01-27 15:22:58 +00:00
tmdb_item = config . TMDb . get_item ( item , tmdb_id , tvdb_id , imdb_id , is_movie = library . is_movie )
2021-11-06 03:54:12 +00:00
omdb_item = None
2022-02-07 22:46:24 +00:00
if library . mass_genre_update == " omdb " or library . mass_audience_rating_update == " omdb " \
2022-03-14 04:53:07 +00:00
or library . mass_critic_rating_update == " omdb " or library . mass_content_rating_update == " omdb " \
or library . mass_originally_available_update == " omdb " :
2021-11-06 03:54:12 +00:00
if config . OMDb . limit is False :
if tmdb_id and not imdb_id :
imdb_id = config . Convert . tmdb_to_imdb ( tmdb_id )
elif tvdb_id and not imdb_id :
imdb_id = config . Convert . tvdb_to_imdb ( tvdb_id )
if imdb_id :
try :
omdb_item = config . OMDb . get_omdb ( imdb_id )
except Failed as e :
2022-02-13 16:33:57 +00:00
logger . error ( str ( e ) )
2021-11-06 03:54:12 +00:00
except Exception :
logger . error ( f " IMDb ID: { imdb_id } " )
raise
else :
2022-02-13 16:33:57 +00:00
logger . info ( f " { item . title [ : 25 ] : <25 } | No IMDb ID for Guid: { item . guid } " )
2021-11-06 03:54:12 +00:00
tvdb_item = None
2022-03-14 04:53:07 +00:00
if library . mass_genre_update == " tvdb " or library . mass_originally_available_update == " tvdb " :
2021-11-06 03:54:12 +00:00
if tvdb_id :
try :
tvdb_item = config . TVDb . get_item ( tvdb_id , library . is_movie )
except Failed as e :
2022-02-13 16:33:57 +00:00
logger . error ( str ( e ) )
2021-11-06 03:54:12 +00:00
else :
2022-02-13 16:33:57 +00:00
logger . info ( f " { item . title [ : 25 ] : <25 } | No TVDb ID for Guid: { item . guid } " )
2021-08-10 15:18:43 +00:00
2022-03-15 00:11:16 +00:00
anidb_item = None
if library . mass_genre_update == " anidb " :
if item . ratingKey in reverse_anidb :
2022-03-16 06:19:34 +00:00
anidb_id = reverse_anidb [ item . ratingKey ]
elif tvdb_id in config . Convert . _tvdb_to_anidb :
anidb_id = config . Convert . _tvdb_to_anidb [ tvdb_id ]
elif imdb_id in config . Convert . _imdb_to_anidb :
anidb_id = config . Convert . _imdb_to_anidb [ imdb_id ]
else :
anidb_id = None
logger . info ( f " { item . title [ : 25 ] : <25 } | No AniDB ID for Guid: { item . guid } " )
if anidb_id :
2022-03-15 00:11:16 +00:00
try :
2022-03-16 06:19:34 +00:00
anidb_item = config . AniDB . get_anime ( anidb_id )
2022-03-15 00:11:16 +00:00
except Failed as e :
logger . error ( str ( e ) )
2022-02-06 07:33:09 +00:00
mdb_item = None
2022-02-07 22:46:24 +00:00
if library . mass_audience_rating_update in util . mdb_types or library . mass_critic_rating_update in util . mdb_types \
2022-03-14 04:53:07 +00:00
or library . mass_content_rating_update in [ " mdb " , " mdb_commonsense " ] or library . mass_originally_available_update == " mdb " :
2022-02-06 07:33:09 +00:00
if config . Mdblist . limit is False :
if tmdb_id and not imdb_id :
imdb_id = config . Convert . tmdb_to_imdb ( tmdb_id )
elif tvdb_id and not imdb_id :
imdb_id = config . Convert . tvdb_to_imdb ( tvdb_id )
if imdb_id :
try :
mdb_item = config . Mdblist . get_imdb ( imdb_id )
except Failed as e :
2022-02-13 16:33:57 +00:00
logger . error ( str ( e ) )
2022-02-06 07:33:09 +00:00
except Exception :
logger . error ( f " IMDb ID: { imdb_id } " )
raise
else :
2022-02-13 16:33:57 +00:00
logger . info ( f " { item . title [ : 25 ] : <25 } | No IMDb ID for Guid: { item . guid } " )
2022-02-06 07:33:09 +00:00
2022-03-13 19:39:34 +00:00
if library . tmdb_collections and tmdb_item and tmdb_item . collection_id :
tmdb_collections [ tmdb_item . collection_id ] = tmdb_item . collection_name
2021-12-06 07:52:08 +00:00
2022-02-06 07:33:09 +00:00
def get_rating ( attribute ) :
if tmdb_item and attribute == " tmdb " :
return tmdb_item . vote_average
2022-02-07 22:46:24 +00:00
elif omdb_item and attribute == " omdb " :
2022-02-06 07:33:09 +00:00
return omdb_item . imdb_rating
elif mdb_item and attribute == " mdb " :
return mdb_item . score / 10 if mdb_item . score else None
elif mdb_item and attribute == " mdb_imdb " :
return mdb_item . imdb_rating if mdb_item . imdb_rating else None
elif mdb_item and attribute == " mdb_metacritic " :
return mdb_item . metacritic_rating / 10 if mdb_item . metacritic_rating else None
elif mdb_item and attribute == " mdb_metacriticuser " :
return mdb_item . metacriticuser_rating if mdb_item . metacriticuser_rating else None
elif mdb_item and attribute == " mdb_trakt " :
return mdb_item . trakt_rating / 10 if mdb_item . trakt_rating else None
elif mdb_item and attribute == " mdb_tomatoes " :
2022-02-22 16:15:37 +00:00
return mdb_item . tomatoes_rating / 10 if mdb_item . tomatoes_rating else None
2022-02-06 07:33:09 +00:00
elif mdb_item and attribute == " mdb_tomatoesaudience " :
return mdb_item . tomatoesaudience_rating / 10 if mdb_item . tomatoesaudience_rating else None
elif mdb_item and attribute == " mdb_tmdb " :
return mdb_item . tmdb_rating / 10 if mdb_item . tmdb_rating else None
elif mdb_item and attribute == " mdb_letterboxd " :
return mdb_item . letterboxd_rating * 2 if mdb_item . letterboxd_rating else None
2022-03-15 00:11:16 +00:00
elif anidb_item and attribute == " anidb_rating " :
return anidb_item . rating
elif anidb_item and attribute == " anidb_average " :
return anidb_item . average
2022-02-06 07:33:09 +00:00
else :
raise Failed
2022-03-15 02:40:09 +00:00
if library . mass_genre_update or library . genre_mapper :
2021-11-06 03:54:12 +00:00
try :
2022-03-15 02:40:09 +00:00
new_genres = [ ]
if library . mass_genre_update :
if tmdb_item and library . mass_genre_update == " tmdb " :
new_genres = tmdb_item . genres
elif omdb_item and library . mass_genre_update == " omdb " :
new_genres = omdb_item . genres
elif tvdb_item and library . mass_genre_update == " tvdb " :
new_genres = tvdb_item . genres
elif anidb_item and library . mass_genre_update == " anidb " :
new_genres = anidb_item . genres
else :
raise Failed
if not new_genres :
logger . info ( f " { item . title [ : 25 ] : <25 } | No Genres Found " )
if library . genre_mapper :
if not new_genres :
new_genres = [ g . tag for g in item . genres ]
mapped_genres = [ ]
for genre in new_genres :
if genre in library . genre_mapper :
if library . genre_mapper [ genre ] :
mapped_genres . append ( library . genre_mapper [ genre ] )
else :
mapped_genres . append ( genre )
new_genres = mapped_genres
2021-11-06 03:54:12 +00:00
library . edit_tags ( " genre " , item , sync_tags = new_genres )
except Failed :
pass
if library . mass_audience_rating_update :
try :
2022-02-06 07:33:09 +00:00
new_rating = get_rating ( library . mass_audience_rating_update )
2021-11-06 03:54:12 +00:00
if new_rating is None :
2022-02-13 16:33:57 +00:00
logger . info ( f " { item . title [ : 25 ] : <25 } | No Rating Found " )
2022-02-06 07:33:09 +00:00
elif str ( item . audienceRating ) != str ( new_rating ) :
library . edit_query ( item , { " audienceRating.value " : new_rating , " audienceRating.locked " : 1 } )
2022-02-13 16:33:57 +00:00
logger . info ( f " { item . title [ : 25 ] : <25 } | Audience Rating | { new_rating } " )
2021-11-06 03:54:12 +00:00
except Failed :
pass
if library . mass_critic_rating_update :
try :
2022-02-06 07:33:09 +00:00
new_rating = get_rating ( library . mass_critic_rating_update )
2021-11-06 03:54:12 +00:00
if new_rating is None :
2022-02-13 16:33:57 +00:00
logger . info ( f " { item . title [ : 25 ] : <25 } | No Rating Found " )
2022-02-06 07:33:09 +00:00
elif str ( item . rating ) != str ( new_rating ) :
library . edit_query ( item , { " rating.value " : new_rating , " rating.locked " : 1 } )
2022-02-13 16:33:57 +00:00
logger . info ( f " { item . title [ : 25 ] : <25 } | Critic Rating | { new_rating } " )
2021-11-06 03:54:12 +00:00
except Failed :
pass
2022-03-15 02:40:09 +00:00
if library . mass_content_rating_update or library . content_rating_mapper :
2022-02-07 22:46:24 +00:00
try :
2022-03-15 02:40:09 +00:00
new_rating = None
if library . mass_content_rating_update :
if omdb_item and library . mass_content_rating_update == " omdb " :
new_rating = omdb_item . content_rating
elif mdb_item and library . mass_content_rating_update == " mdb " :
new_rating = mdb_item . certification if mdb_item . certification else None
elif mdb_item and library . mass_content_rating_update == " mdb_commonsense " :
new_rating = mdb_item . commonsense if mdb_item . commonsense else None
else :
raise Failed
if new_rating is None :
logger . info ( f " { item . title [ : 25 ] : <25 } | No Content Rating Found " )
if library . content_rating_mapper :
if new_rating is None :
new_rating = item . contentRating
if new_rating in library . content_rating_mapper :
new_rating = library . content_rating_mapper [ new_rating ]
if str ( item . contentRating ) != str ( new_rating ) :
2022-02-07 22:46:24 +00:00
library . edit_query ( item , { " contentRating.value " : new_rating , " contentRating.locked " : 1 } )
2022-02-13 16:33:57 +00:00
logger . info ( f " { item . title [ : 25 ] : <25 } | Content Rating | { new_rating } " )
2022-02-07 22:46:24 +00:00
except Failed :
pass
2022-03-14 04:53:07 +00:00
if library . mass_originally_available_update :
try :
if omdb_item and library . mass_originally_available_update == " omdb " :
new_date = omdb_item . released
elif mdb_item and library . mass_originally_available_update == " mdb " :
new_date = mdb_item . released
2022-03-15 00:11:16 +00:00
elif tvdb_item and library . mass_originally_available_update == " tvdb " :
2022-03-14 04:53:07 +00:00
new_date = tvdb_item . released
2022-03-15 00:11:16 +00:00
elif tmdb_item and library . mass_originally_available_update == " tmdb " :
2022-03-14 04:53:07 +00:00
new_date = tmdb_item . release_date if library . is_movie else tmdb_item . first_air_date
2022-03-15 00:11:16 +00:00
elif anidb_item and library . mass_originally_available_update == " anidb " :
new_date = anidb_item . released
2022-03-14 04:53:07 +00:00
else :
raise Failed
if new_date is None :
logger . info ( f " { item . title [ : 25 ] : <25 } | No Originally Available Date Found " )
elif str ( item . rating ) != str ( new_date ) :
library . edit_query ( item , { " originallyAvailableAt.value " : new_date . strftime ( " % Y- % m- %d " ) , " originallyAvailableAt.locked " : 1 } )
logger . info ( f " { item . title [ : 25 ] : <25 } | Originally Available Date | { new_date . strftime ( ' % Y- % m- %d ' ) } " )
except Failed :
pass
2022-02-07 22:46:24 +00:00
2021-12-30 18:59:54 +00:00
if library . Radarr and library . radarr_add_all_existing :
2021-05-09 05:38:41 +00:00
try :
2021-11-06 03:54:12 +00:00
library . Radarr . add_tmdb ( radarr_adds )
except Failed as e :
logger . error ( e )
2021-12-30 18:59:54 +00:00
if library . Sonarr and library . sonarr_add_all_existing :
2021-08-02 21:01:19 +00:00
try :
2021-11-06 03:54:12 +00:00
library . Sonarr . add_tvdb ( sonarr_adds )
except Failed as e :
logger . error ( e )
2021-05-08 02:30:28 +00:00
2021-12-31 04:51:46 +00:00
if tmdb_collections or library . genre_collections :
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " Starting Automated Collections " )
2021-12-31 04:51:46 +00:00
logger . info ( " " )
new_collections = { }
templates = { }
2021-12-06 07:52:08 +00:00
if tmdb_collections :
2021-12-31 04:51:46 +00:00
templates [ " TMDb Collection " ] = library . tmdb_collections [ " template " ]
2021-12-19 01:12:04 +00:00
for _i , _n in tmdb_collections . items ( ) :
if int ( _i ) not in library . tmdb_collections [ " exclude_ids " ] :
template = { " name " : " TMDb Collection " , " collection_id " : _i }
2022-01-06 06:26:33 +00:00
for k , v in library . tmdb_collections [ " dictionary_variables " ] . items ( ) :
2021-12-19 01:12:04 +00:00
if int ( _i ) in v :
template [ k ] = v [ int ( _i ) ]
2021-12-21 18:48:27 +00:00
for suffix in library . tmdb_collections [ " remove_suffix " ] :
if _n . endswith ( suffix ) :
2021-12-28 21:23:26 +00:00
_n = _n [ : - len ( suffix ) ]
2021-12-19 01:12:04 +00:00
new_collections [ _n . strip ( ) ] = { " template " : template }
2021-12-31 04:51:46 +00:00
if library . genre_collections :
templates [ " Genre Collection " ] = library . genre_collections [ " template " ]
2022-01-28 21:59:26 +00:00
for genre in library . get_tags ( " genre " ) :
if genre . title not in library . genre_collections [ " exclude_genres " ] :
template = { " name " : " Genre Collection " , " genre " : genre . title }
2022-01-06 06:26:33 +00:00
for k , v in library . genre_collections [ " dictionary_variables " ] . items ( ) :
2022-01-28 21:59:26 +00:00
if genre . title in v :
template [ k ] = v [ genre . title ]
2021-12-31 04:51:46 +00:00
title = library . genre_collections [ " title_format " ]
2022-01-28 21:59:26 +00:00
title = title . replace ( " <<genre>> " , genre . title )
2021-12-31 04:51:46 +00:00
if " <<library_type>> " in title :
title = title . replace ( " <<library_type>> " , library . type )
new_collections [ title ] = { " template " : template }
metadata = MetadataFile ( config , library , " Data " , { " collections " : new_collections , " templates " : templates } )
2022-01-25 06:36:49 +00:00
if metadata . collections :
library . collections . extend ( [ c for c in metadata . collections ] )
2021-12-31 04:51:46 +00:00
run_collection ( config , library , metadata , metadata . get_collections ( None ) )
2021-12-06 07:52:08 +00:00
2021-12-18 22:45:09 +00:00
if library . radarr_remove_by_tag :
library . Radarr . remove_all_with_tags ( library . radarr_remove_by_tag )
if library . sonarr_remove_by_tag :
library . Sonarr . remove_all_with_tags ( library . sonarr_remove_by_tag )
2021-11-06 03:54:12 +00:00
if library . delete_collections_with_less is not None or library . delete_unmanaged_collections :
logger . info ( " " )
2021-12-15 21:19:43 +00:00
print_suffix = " "
2021-11-06 03:54:12 +00:00
unmanaged = " "
if library . delete_collections_with_less is not None and library . delete_collections_with_less > 0 :
2021-12-15 21:19:43 +00:00
print_suffix = f " with less then { library . delete_collections_with_less } item { ' s ' if library . delete_collections_with_less > 1 else ' ' } "
2021-11-06 03:54:12 +00:00
if library . delete_unmanaged_collections :
if library . delete_collections_with_less is None :
unmanaged = " Unmanaged Collections "
elif library . delete_collections_with_less > 0 :
unmanaged = " Unmanaged Collections and "
2022-02-13 16:33:57 +00:00
logger . separator ( f " Deleting All { unmanaged } Collections { print_suffix } " , space = False , border = False )
2021-11-06 03:54:12 +00:00
logger . info ( " " )
unmanaged_collections = [ ]
for col in library . get_all_collections ( ) :
2022-03-06 05:02:39 +00:00
if ( library . delete_collections_with_less and col . childCount < library . delete_collections_with_less ) \
or ( library . delete_unmanaged_collections and col . title not in library . collections ) :
2021-11-06 03:54:12 +00:00
library . query ( col . delete )
logger . info ( f " { col . title } Deleted " )
elif col . title not in library . collections :
unmanaged_collections . append ( col )
2022-02-22 20:04:04 +00:00
if library . mass_collection_mode :
logger . info ( " " )
logger . separator ( f " Mass Collection Mode for { library . name } Library " , space = False , border = False )
logger . info ( " " )
for col in library . get_all_collections ( ) :
2021-12-19 21:02:10 +00:00
library . collection_mode_query ( col , library . mass_collection_mode )
2021-11-06 03:54:12 +00:00
if library . show_unmanaged and len ( unmanaged_collections ) > 0 :
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " Unmanaged Collections in { library . name } Library " , space = False , border = False )
2021-11-06 03:54:12 +00:00
logger . info ( " " )
for col in unmanaged_collections :
logger . info ( col . title )
logger . info ( " " )
logger . info ( f " { len ( unmanaged_collections ) } Unmanaged Collection { ' s ' if len ( unmanaged_collections ) > 1 else ' ' } " )
elif library . show_unmanaged :
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " No Unmanaged Collections in { library . name } Library " , space = False , border = False )
2021-11-06 03:54:12 +00:00
logger . info ( " " )
2021-05-20 03:36:57 +00:00
2021-11-06 03:54:12 +00:00
if library . assets_for_all and len ( unmanaged_collections ) > 0 :
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " Unmanaged Collection Assets Check for { library . name } Library " , space = False , border = False )
2021-11-06 03:54:12 +00:00
logger . info ( " " )
for col in unmanaged_collections :
2021-12-19 00:48:11 +00:00
library . find_assets ( col )
2021-05-20 03:36:57 +00:00
2022-01-27 15:22:58 +00:00
if library . metadata_backup :
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " Metadata Backup for { library . name } Library " , space = False , border = False )
2022-01-27 15:22:58 +00:00
logger . info ( " " )
logger . info ( f " Metadata Backup Path: { library . metadata_backup [ ' path ' ] } " )
logger . info ( " " )
2022-03-13 20:55:48 +00:00
meta = None
2022-03-10 18:29:14 +00:00
if os . path . exists ( library . metadata_backup [ " path " ] ) :
try :
meta , _ , _ = yaml . util . load_yaml_guess_indent ( open ( library . metadata_backup [ " path " ] ) )
except yaml . scanner . ScannerError as e :
logger . error ( f " YAML Error: { util . tab_new_lines ( e ) } " )
filename , file_extension = os . path . splitext ( library . metadata_backup [ " path " ] )
i = 1
while os . path . exists ( f " { filename } { i } { file_extension } " ) :
i + = 1
os . rename ( library . metadata_backup [ " path " ] , f " { filename } { i } { file_extension } " )
logger . error ( f " Backup failed to load saving copy to { filename } { i } { file_extension } " )
2022-03-13 20:55:48 +00:00
if not meta :
meta = { }
2022-03-11 07:07:37 +00:00
if " metadata " not in meta :
meta [ " metadata " ] = { }
2022-02-03 23:24:35 +00:00
items = library . get_all ( load = True )
2022-01-27 15:22:58 +00:00
titles = [ i . title for i in items ]
for i , item in enumerate ( items , 1 ) :
2022-02-13 16:33:57 +00:00
logger . ghost ( f " Processing: { i } / { len ( items ) } { item . title } " )
2022-01-27 15:22:58 +00:00
map_key , attrs = library . get_locked_attributes ( item , titles )
if attrs or library . metadata_backup [ " add_blank_entries " ] :
2022-03-10 18:29:14 +00:00
def get_dict ( attrs_dict ) :
return { ak : get_dict ( av ) if isinstance ( av , dict ) else av for ak , av in attrs_dict . items ( ) } if isinstance ( attrs_dict , dict ) else attrs_dict
meta [ " metadata " ] [ map_key ] = get_dict ( attrs )
2022-02-13 16:33:57 +00:00
logger . exorcise ( )
2022-01-27 15:22:58 +00:00
try :
2022-02-08 14:49:42 +00:00
yaml . round_trip_dump ( meta , open ( library . metadata_backup [ " path " ] , " w " , encoding = " utf-8 " ) , block_seq_indent = 2 )
logger . info ( f " { len ( meta [ ' metadata ' ] ) } { library . type . capitalize ( ) } { ' s ' if len ( meta [ ' metadata ' ] ) > 1 else ' ' } Backed Up " )
2022-01-27 15:22:58 +00:00
except yaml . scanner . ScannerError as e :
2022-02-13 16:33:57 +00:00
logger . error ( f " YAML Error: { util . tab_new_lines ( e ) } " )
2022-01-27 15:22:58 +00:00
2021-05-26 14:45:33 +00:00
def run_collection ( config , library , metadata , requested_collections ) :
2021-05-19 17:12:34 +00:00
logger . info ( " " )
2021-05-26 04:35:54 +00:00
for mapping_name , collection_attrs in requested_collections . items ( ) :
2021-05-20 20:38:48 +00:00
collection_start = datetime . now ( )
2021-05-25 22:22:59 +00:00
if config . test_mode and ( " test " not in collection_attrs or collection_attrs [ " test " ] is not True ) :
2021-05-12 14:25:48 +00:00
no_template_test = True
if " template " in collection_attrs and collection_attrs [ " template " ] :
for data_template in util . get_list ( collection_attrs [ " template " ] , split = False ) :
if " name " in data_template \
and data_template [ " name " ] \
and metadata . templates \
and data_template [ " name " ] in metadata . templates \
and metadata . templates [ data_template [ " name " ] ] \
and " test " in metadata . templates [ data_template [ " name " ] ] \
and metadata . templates [ data_template [ " name " ] ] [ " test " ] is True :
no_template_test = False
if no_template_test :
continue
2021-05-25 22:22:59 +00:00
if config . resume_from and config . resume_from != mapping_name :
2021-05-19 17:12:34 +00:00
continue
2021-05-25 22:22:59 +00:00
elif config . resume_from == mapping_name :
config . resume_from = None
2021-05-12 14:25:48 +00:00
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " Resuming Collections " )
2021-05-19 17:12:34 +00:00
2021-05-19 21:30:20 +00:00
if " name_mapping " in collection_attrs and collection_attrs [ " name_mapping " ] :
2021-05-20 20:38:48 +00:00
collection_log_name , output_str = util . validate_filename ( collection_attrs [ " name_mapping " ] )
2021-05-19 21:30:20 +00:00
else :
2021-05-20 20:38:48 +00:00
collection_log_name , output_str = util . validate_filename ( mapping_name )
2022-02-13 16:33:57 +00:00
logger . add_collection_handler ( library . mapping_name , collection_log_name )
2021-12-30 21:29:16 +00:00
library . status [ mapping_name ] = { " status " : " " , " errors " : [ ] , " created " : False , " modified " : False , " deleted " : False , " added " : 0 , " unchanged " : 0 , " removed " : 0 , " radarr " : 0 , " sonarr " : 0 }
2021-05-19 21:30:20 +00:00
2021-05-19 17:12:34 +00:00
try :
2022-02-13 16:33:57 +00:00
logger . separator ( f " { mapping_name } Collection in { library . name } " )
2021-05-12 14:25:48 +00:00
logger . info ( " " )
2021-05-20 20:38:48 +00:00
if output_str :
logger . info ( output_str )
logger . info ( " " )
2021-05-12 14:25:48 +00:00
2022-02-13 16:33:57 +00:00
logger . separator ( f " Validating { mapping_name } Attributes " , space = False , border = False )
2021-05-24 03:38:46 +00:00
2022-02-08 22:57:36 +00:00
builder = CollectionBuilder ( config , metadata , mapping_name , no_missing , collection_attrs , library = library )
2022-02-20 00:08:41 +00:00
library . stats [ " names " ] . append ( builder . name )
2021-05-24 03:38:46 +00:00
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " Running { mapping_name } Collection " , space = False , border = False )
2021-05-12 14:25:48 +00:00
if len ( builder . schedule ) > 0 :
2022-02-13 16:33:57 +00:00
logger . info ( builder . schedule )
2021-05-12 14:25:48 +00:00
2021-05-24 03:38:46 +00:00
if len ( builder . smart_filter_details ) > 0 :
2021-05-29 02:33:55 +00:00
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . info ( builder . smart_filter_details )
2021-05-24 03:38:46 +00:00
2021-11-03 14:36:11 +00:00
items_added = 0
items_removed = 0
2022-01-27 21:24:50 +00:00
if not builder . smart_url and builder . builders and not builder . blank_collection :
2021-05-12 14:25:48 +00:00
logger . info ( " " )
2021-05-19 17:12:34 +00:00
logger . info ( f " Sync Mode: { ' sync ' if builder . sync else ' append ' } " )
2021-11-24 13:22:17 +00:00
if builder . filters or builder . tmdb_filters :
2021-05-19 17:12:34 +00:00
logger . info ( " " )
for filter_key , filter_value in builder . filters :
logger . info ( f " Collection Filter { filter_key } : { filter_value } " )
2021-11-24 13:22:17 +00:00
for filter_key , filter_value in builder . tmdb_filters :
logger . info ( f " Collection Filter { filter_key } : { filter_value } " )
2021-05-12 14:25:48 +00:00
2022-02-08 22:57:36 +00:00
for method , value in builder . builders :
logger . debug ( " " )
logger . debug ( f " Builder: { method } : { value } " )
logger . info ( " " )
builder . filter_and_save_items ( builder . gather_ids ( method , value ) )
2021-05-24 03:38:46 +00:00
2022-02-09 02:31:29 +00:00
if len ( builder . added_items ) > 0 and len ( builder . added_items ) + builder . beginning_count > = builder . minimum and builder . build_collection :
2021-12-30 21:29:16 +00:00
items_added , items_unchanged = builder . add_to_collection ( )
library . stats [ " added " ] + = items_added
library . status [ mapping_name ] [ " added " ] = items_added
library . stats [ " unchanged " ] + = items_unchanged
library . status [ mapping_name ] [ " unchanged " ] = items_unchanged
2021-11-03 14:36:11 +00:00
items_removed = 0
2021-10-20 19:58:25 +00:00
if builder . sync :
2021-11-03 14:36:11 +00:00
items_removed = builder . sync_collection ( )
2021-12-30 21:29:16 +00:00
library . stats [ " removed " ] + = items_removed
library . status [ mapping_name ] [ " removed " ] = items_removed
2021-10-20 19:58:25 +00:00
2021-08-16 05:41:04 +00:00
if builder . do_missing and ( len ( builder . missing_movies ) > 0 or len ( builder . missing_shows ) > 0 ) :
2021-11-03 14:36:11 +00:00
radarr_add , sonarr_add = builder . run_missing ( )
2021-12-30 21:29:16 +00:00
library . stats [ " radarr " ] + = radarr_add
library . status [ mapping_name ] [ " radarr " ] + = radarr_add
library . stats [ " sonarr " ] + = sonarr_add
library . status [ mapping_name ] [ " sonarr " ] + = sonarr_add
2021-05-12 14:25:48 +00:00
2022-03-14 13:29:34 +00:00
valid = True
if builder . build_collection and (
( builder . smart_url and len ( library . get_filter_items ( builder . smart_url ) ) < builder . minimum )
2022-03-15 20:53:37 +00:00
or ( not builder . smart_url and len ( builder . added_items ) + builder . beginning_count < builder . minimum )
2022-03-14 13:29:34 +00:00
) :
logger . info ( " " )
logger . info ( f " Collection Minimum: { builder . minimum } not met for { mapping_name } Collection " )
valid = False
if builder . details [ " delete_below_minimum " ] and builder . obj :
logger . info ( " " )
logger . info ( builder . delete ( ) )
builder . deleted = True
2021-09-15 03:16:59 +00:00
run_item_details = True
2022-01-27 21:24:50 +00:00
if valid and builder . build_collection and ( builder . builders or builder . smart_url or builder . blank_collection ) :
2021-09-15 03:16:59 +00:00
try :
builder . load_collection ( )
2021-11-03 14:36:11 +00:00
if builder . created :
2021-12-30 21:29:16 +00:00
library . stats [ " created " ] + = 1
library . status [ mapping_name ] [ " created " ] = True
2021-11-03 14:36:11 +00:00
elif items_added > 0 or items_removed > 0 :
2021-12-30 21:29:16 +00:00
library . stats [ " modified " ] + = 1
library . status [ mapping_name ] [ " modified " ] = True
2021-09-15 03:16:59 +00:00
except Failed :
2022-02-13 16:33:57 +00:00
logger . stacktrace ( )
2021-09-15 03:16:59 +00:00
run_item_details = False
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( " No Collection to Update " , space = False , border = False )
2021-09-15 03:16:59 +00:00
else :
builder . update_details ( )
2021-07-29 13:36:30 +00:00
2021-12-09 04:57:00 +00:00
if builder . deleted :
2021-12-30 21:29:16 +00:00
library . stats [ " deleted " ] + = 1
library . status [ mapping_name ] [ " deleted " ] = True
2021-12-09 04:57:00 +00:00
2021-12-08 03:31:20 +00:00
if builder . server_preroll is not None :
library . set_server_preroll ( builder . server_preroll )
logger . info ( " " )
logger . info ( f " Plex Server Movie pre-roll video updated to { builder . server_preroll } " )
2021-12-21 18:48:27 +00:00
if ( builder . item_details or builder . custom_sort ) and run_item_details and builder . builders :
2021-09-15 03:16:59 +00:00
try :
builder . load_collection_items ( )
except Failed :
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( " No Items Found " , space = False , border = False )
2021-09-15 03:16:59 +00:00
else :
2021-12-17 14:24:46 +00:00
if builder . item_details :
builder . update_item_details ( )
2021-12-21 18:48:27 +00:00
if builder . custom_sort :
2021-12-17 14:24:46 +00:00
library . run_sort . append ( builder )
# builder.sort_collection()
2021-05-26 19:14:51 +00:00
2021-12-13 19:43:36 +00:00
builder . send_notifications ( )
2021-05-14 19:22:59 +00:00
if builder . run_again and ( len ( builder . run_again_movies ) > 0 or len ( builder . run_again_shows ) > 0 ) :
2021-05-12 14:25:48 +00:00
library . run_again . append ( builder )
2021-12-30 21:29:16 +00:00
if library . status [ mapping_name ] [ " created " ] :
library . status [ mapping_name ] [ " status " ] = " Created "
elif library . status [ mapping_name ] [ " deleted " ] :
library . status [ mapping_name ] [ " status " ] = " Deleted "
elif library . status [ mapping_name ] [ " modified " ] :
library . status [ mapping_name ] [ " status " ] = " Modified "
else :
library . status [ mapping_name ] [ " status " ] = " Unchanged "
2021-10-21 14:00:16 +00:00
except NotScheduled as e :
2022-02-13 16:33:57 +00:00
logger . info ( e )
2021-12-30 21:29:16 +00:00
library . status [ mapping_name ] [ " status " ] = " Not Scheduled "
2021-05-12 14:25:48 +00:00
except Failed as e :
2021-10-04 17:51:32 +00:00
library . notify ( e , collection = mapping_name )
2022-02-13 16:33:57 +00:00
logger . stacktrace ( )
logger . error ( e )
2021-12-30 21:29:16 +00:00
library . status [ mapping_name ] [ " status " ] = " PMM Failure "
library . status [ mapping_name ] [ " errors " ] . append ( e )
2021-05-12 14:25:48 +00:00
except Exception as e :
2021-10-04 17:51:32 +00:00
library . notify ( f " Unknown Error: { e } " , collection = mapping_name )
2022-02-13 16:33:57 +00:00
logger . stacktrace ( )
2021-05-12 14:25:48 +00:00
logger . error ( f " Unknown Error: { e } " )
2021-12-30 21:29:16 +00:00
library . status [ mapping_name ] [ " status " ] = " Unknown Error "
library . status [ mapping_name ] [ " errors " ] . append ( e )
2021-05-19 17:12:34 +00:00
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " Finished { mapping_name } Collection \n Collection Run Time: { str ( datetime . now ( ) - collection_start ) . split ( ' . ' ) [ 0 ] } " )
logger . remove_collection_handler ( library . mapping_name , collection_log_name )
2021-05-08 02:30:28 +00:00
2021-12-23 17:02:07 +00:00
def run_playlists ( config ) :
2022-02-20 00:08:41 +00:00
stats = { " created " : 0 , " modified " : 0 , " deleted " : 0 , " added " : 0 , " unchanged " : 0 , " removed " : 0 , " radarr " : 0 , " sonarr " : 0 , " names " : [ ] }
2021-12-30 21:29:16 +00:00
status = { }
2021-12-23 17:02:07 +00:00
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( " Playlists " )
2021-12-23 17:02:07 +00:00
logger . info ( " " )
for playlist_file in config . playlist_files :
for mapping_name , playlist_attrs in playlist_file . playlists . items ( ) :
playlist_start = datetime . now ( )
if config . test_mode and ( " test " not in playlist_attrs or playlist_attrs [ " test " ] is not True ) :
no_template_test = True
if " template " in playlist_attrs and playlist_attrs [ " template " ] :
for data_template in util . get_list ( playlist_attrs [ " template " ] , split = False ) :
if " name " in data_template \
and data_template [ " name " ] \
and playlist_file . templates \
and data_template [ " name " ] in playlist_file . templates \
and playlist_file . templates [ data_template [ " name " ] ] \
and " test " in playlist_file . templates [ data_template [ " name " ] ] \
and playlist_file . templates [ data_template [ " name " ] ] [ " test " ] is True :
no_template_test = False
if no_template_test :
continue
if " name_mapping " in playlist_attrs and playlist_attrs [ " name_mapping " ] :
playlist_log_name , output_str = util . validate_filename ( playlist_attrs [ " name_mapping " ] )
else :
playlist_log_name , output_str = util . validate_filename ( mapping_name )
2022-02-13 16:33:57 +00:00
logger . add_playlist_handler ( playlist_log_name )
2021-12-30 21:29:16 +00:00
status [ mapping_name ] = { " status " : " " , " errors " : [ ] , " created " : False , " modified " : False , " deleted " : False , " added " : 0 , " unchanged " : 0 , " removed " : 0 , " radarr " : 0 , " sonarr " : 0 }
2021-12-23 17:02:07 +00:00
server_name = None
library_names = None
try :
2022-02-13 16:33:57 +00:00
logger . separator ( f " { mapping_name } Playlist " )
2021-12-23 17:02:07 +00:00
logger . info ( " " )
if output_str :
logger . info ( output_str )
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " Validating { mapping_name } Attributes " , space = False , border = False )
2021-12-23 17:02:07 +00:00
2022-02-08 22:57:36 +00:00
builder = CollectionBuilder ( config , playlist_file , mapping_name , no_missing , playlist_attrs )
2022-02-20 00:08:41 +00:00
stats [ " names " ] . append ( builder . name )
2021-12-23 17:02:07 +00:00
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " Running { mapping_name } Playlist " , space = False , border = False )
2021-12-23 17:02:07 +00:00
if len ( builder . schedule ) > 0 :
2022-02-13 16:33:57 +00:00
logger . info ( builder . schedule )
2021-12-23 17:02:07 +00:00
items_added = 0
items_removed = 0
valid = True
logger . info ( " " )
logger . info ( f " Sync Mode: { ' sync ' if builder . sync else ' append ' } " )
if builder . filters or builder . tmdb_filters :
logger . info ( " " )
for filter_key , filter_value in builder . filters :
logger . info ( f " Playlist Filter { filter_key } : { filter_value } " )
for filter_key , filter_value in builder . tmdb_filters :
logger . info ( f " Playlist Filter { filter_key } : { filter_value } " )
method , value = builder . builders [ 0 ]
logger . debug ( " " )
logger . debug ( f " Builder: { method } : { value } " )
logger . info ( " " )
2022-01-24 22:36:40 +00:00
if " plex " in method :
ids = [ ]
2022-02-08 22:57:36 +00:00
for pl_library in builder . libraries :
2022-01-24 22:36:40 +00:00
ids . extend ( pl_library . get_rating_keys ( method , value ) )
elif " tautulli " in method :
ids = [ ]
2022-02-08 22:57:36 +00:00
for pl_library in builder . libraries :
2022-01-24 22:36:40 +00:00
ids . extend ( pl_library . Tautulli . get_rating_keys ( pl_library , value , True ) )
else :
ids = builder . gather_ids ( method , value )
2021-12-23 17:02:07 +00:00
2022-02-08 22:57:36 +00:00
builder . filter_and_save_items ( ids )
2021-12-23 17:02:07 +00:00
if len ( builder . added_items ) > = builder . minimum :
2021-12-30 21:29:16 +00:00
items_added , items_unchanged = builder . add_to_collection ( )
2021-12-23 17:02:07 +00:00
stats [ " added " ] + = items_added
2021-12-30 21:29:16 +00:00
status [ mapping_name ] [ " added " ] + = items_added
stats [ " unchanged " ] + = items_unchanged
status [ mapping_name ] [ " unchanged " ] + = items_unchanged
2021-12-23 17:02:07 +00:00
items_removed = 0
if builder . sync :
items_removed = builder . sync_collection ( )
stats [ " removed " ] + = items_removed
2021-12-30 21:29:16 +00:00
status [ mapping_name ] [ " removed " ] + = items_removed
2021-12-23 17:02:07 +00:00
elif len ( builder . added_items ) < builder . minimum :
logger . info ( " " )
logger . info ( f " Playlist Minimum: { builder . minimum } not met for { mapping_name } Playlist " )
valid = False
if builder . details [ " delete_below_minimum " ] and builder . obj :
2021-12-26 15:48:52 +00:00
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . info ( builder . delete ( ) )
2021-12-23 17:02:07 +00:00
builder . deleted = True
if builder . do_missing and ( len ( builder . missing_movies ) > 0 or len ( builder . missing_shows ) > 0 ) :
radarr_add , sonarr_add = builder . run_missing ( )
stats [ " radarr " ] + = radarr_add
2021-12-30 21:29:16 +00:00
status [ mapping_name ] [ " radarr " ] + = radarr_add
2021-12-23 17:02:07 +00:00
stats [ " sonarr " ] + = sonarr_add
2021-12-30 21:29:16 +00:00
status [ mapping_name ] [ " sonarr " ] + = sonarr_add
2021-12-23 17:02:07 +00:00
run_item_details = True
try :
builder . load_collection ( )
if builder . created :
stats [ " created " ] + = 1
2021-12-30 21:29:16 +00:00
status [ mapping_name ] [ " created " ] = True
2021-12-23 17:02:07 +00:00
elif items_added > 0 or items_removed > 0 :
stats [ " modified " ] + = 1
2021-12-30 21:29:16 +00:00
status [ mapping_name ] [ " modified " ] = True
2021-12-23 17:02:07 +00:00
except Failed :
2022-02-13 16:33:57 +00:00
logger . stacktrace ( )
2021-12-23 17:02:07 +00:00
run_item_details = False
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( " No Playlist to Update " , space = False , border = False )
2021-12-23 17:02:07 +00:00
else :
builder . update_details ( )
if builder . deleted :
stats [ " deleted " ] + = 1
2021-12-30 21:29:16 +00:00
status [ mapping_name ] [ " deleted " ] = True
2021-12-23 17:02:07 +00:00
if valid and run_item_details and builder . builders and ( builder . item_details or builder . custom_sort ) :
try :
builder . load_collection_items ( )
except Failed :
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( " No Items Found " , space = False , border = False )
2021-12-23 17:02:07 +00:00
else :
if builder . item_details :
builder . update_item_details ( )
if builder . custom_sort :
builder . sort_collection ( )
if valid :
2021-12-26 15:48:52 +00:00
builder . sync_playlist ( )
2021-12-23 17:02:07 +00:00
builder . send_notifications ( playlist = True )
except NotScheduled as e :
2022-02-13 16:33:57 +00:00
logger . info ( e )
2021-12-30 21:29:16 +00:00
status [ mapping_name ] [ " status " ] = " Not Scheduled "
2021-12-23 17:02:07 +00:00
except Failed as e :
config . notify ( e , server = server_name , library = library_names , playlist = mapping_name )
2022-02-13 16:33:57 +00:00
logger . stacktrace ( )
logger . error ( e )
2021-12-30 21:29:16 +00:00
status [ mapping_name ] [ " status " ] = " PMM Failure "
status [ mapping_name ] [ " errors " ] . append ( e )
2021-12-23 17:02:07 +00:00
except Exception as e :
config . notify ( f " Unknown Error: { e } " , server = server_name , library = library_names , playlist = mapping_name )
2022-02-13 16:33:57 +00:00
logger . stacktrace ( )
2021-12-23 17:02:07 +00:00
logger . error ( f " Unknown Error: { e } " )
2021-12-30 21:29:16 +00:00
status [ mapping_name ] [ " status " ] = " Unknown Error "
status [ mapping_name ] [ " errors " ] . append ( e )
2021-12-23 17:02:07 +00:00
logger . info ( " " )
2022-02-13 16:33:57 +00:00
logger . separator ( f " Finished { mapping_name } Playlist \n Playlist Run Time: { str ( datetime . now ( ) - playlist_start ) . split ( ' . ' ) [ 0 ] } " )
logger . remove_playlist_handler ( playlist_log_name )
2021-12-30 21:29:16 +00:00
return status , stats
2021-12-23 17:02:07 +00:00
2021-01-20 21:37:59 +00:00
try :
2022-01-25 07:45:31 +00:00
if run or test or collections or libraries or metadata_files or resume :
2021-10-04 17:51:32 +00:00
start ( {
" config_file " : config_file ,
" test " : test ,
2021-12-31 04:34:04 +00:00
" delete " : delete ,
2022-01-02 04:23:47 +00:00
" ignore_schedules " : ignore_schedules ,
2021-10-04 17:51:32 +00:00
" collections " : collections ,
" libraries " : libraries ,
2022-01-25 07:45:31 +00:00
" metadata_files " : metadata_files ,
2022-01-04 16:46:56 +00:00
" library_first " : library_first ,
2021-11-03 14:38:43 +00:00
" resume " : resume ,
" trace " : trace
2021-10-04 17:51:32 +00:00
} )
2021-01-20 21:37:59 +00:00
else :
2021-09-08 03:04:36 +00:00
times_to_run = util . get_list ( times )
valid_times = [ ]
2021-05-25 22:22:59 +00:00
for time_to_run in times_to_run :
2021-09-08 03:04:36 +00:00
try :
valid_times . append ( datetime . strftime ( datetime . strptime ( time_to_run , " % H: % M " ) , " % H: % M " ) )
except ValueError :
if time_to_run :
raise Failed ( f " Argument Error: time argument invalid: { time_to_run } must be in the HH:MM format " )
else :
raise Failed ( f " Argument Error: blank time argument " )
for time_to_run in valid_times :
2022-01-04 16:46:56 +00:00
schedule . every ( ) . day . at ( time_to_run ) . do ( start , { " config_file " : config_file , " time " : time_to_run , " delete " : delete , " library_first " : library_first , " trace " : trace } )
2021-01-20 21:37:59 +00:00
while True :
schedule . run_pending ( )
2021-05-24 22:16:19 +00:00
if not no_countdown :
2021-12-15 15:50:20 +00:00
current_time = datetime . now ( ) . strftime ( " % H: % M " )
2021-05-25 22:22:59 +00:00
seconds = None
og_time_str = " "
2021-09-08 03:04:36 +00:00
for time_to_run in valid_times :
2021-12-15 15:50:20 +00:00
new_seconds = ( datetime . strptime ( time_to_run , " % H: % M " ) - datetime . strptime ( current_time , " % H: % M " ) ) . total_seconds ( )
2021-05-25 22:22:59 +00:00
if new_seconds < 0 :
new_seconds + = 86400
if ( seconds is None or new_seconds < seconds ) and new_seconds > 0 :
seconds = new_seconds
og_time_str = time_to_run
2021-09-22 12:43:21 +00:00
if seconds is not None :
hours = int ( seconds / / 3600 )
minutes = int ( ( seconds % 3600 ) / / 60 )
time_str = f " { hours } Hour { ' s ' if hours > 1 else ' ' } and " if hours > 0 else " "
time_str + = f " { minutes } Minute { ' s ' if minutes > 1 else ' ' } "
2022-02-13 16:33:57 +00:00
logger . ghost ( f " Current Time: { current_time } | { time_str } until the next run at { og_time_str } | Runs: { ' , ' . join ( times_to_run ) } " )
2021-09-22 12:43:21 +00:00
else :
logger . error ( f " Time Error: { valid_times } " )
2021-05-25 22:22:59 +00:00
time . sleep ( 60 )
2021-01-20 21:37:59 +00:00
except KeyboardInterrupt :
2022-02-13 16:33:57 +00:00
logger . separator ( " Exiting Plex Meta Manager " )