import argparse , logging , os , re , sys , time
from datetime import datetime
try :
import schedule
from modules import tests , util
from modules . config import Config
except ModuleNotFoundError :
print ( " Error: Requirements are not installed " )
sys . exit ( 0 )
parser = argparse . ArgumentParser ( )
parser . add_argument ( " --my-tests " , dest = " tests " , help = argparse . SUPPRESS , action = " store_true " , default = False )
parser . add_argument ( " --debug " , dest = " debug " , help = argparse . SUPPRESS , action = " store_true " , default = False )
parser . add_argument ( " -c " , " --config " , dest = " config " , help = " Run with desired *.yml file " , type = str )
parser . add_argument ( " -t " , " --time " , dest = " time " , help = " Time to update each day use format HH:MM (Default: 03:00) " , default = " 03:00 " , type = str )
parser . add_argument ( " -re " , " --resume " , dest = " resume " , help = " Resume collection run from a specific collection " , type = str )
parser . add_argument ( " -r " , " --run " , dest = " run " , help = " Run without the scheduler " , action = " store_true " , default = False )
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 )
parser . add_argument ( " -cl " , " --collection " , " --collections " , dest = " collections " , help = " Process only specified collections (comma-separated list) " , type = str )
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 ( )
def check_bool ( env_str , default ) :
env_var = os . environ . get ( env_str )
if env_var is not None :
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
else :
return default
my_tests = check_bool ( " PMM_TESTS " , args . tests )
test = check_bool ( " PMM_TEST " , args . test )
debug = check_bool ( " PMM_DEBUG " , args . debug )
run = check_bool ( " PMM_RUN " , args . run )
collections = os . environ . get ( " PMM_COLLECTIONS " ) if os . environ . get ( " PMM_COLLECTIONS " ) else args . collections
resume = os . environ . get ( " PMM_RESUME " ) if os . environ . get ( " PMM_RESUME " ) else args . resume
time_to_run = os . environ . get ( " PMM_TIME " ) if os . environ . get ( " PMM_TIME " ) else args . time
if not re . match ( " ^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$ " , time_to_run ) :
raise util . Failed ( f " Argument Error: time argument invalid: { time_to_run } must be in the HH:MM format " )
util . separating_character = os . environ . get ( " PMM_DIVIDER " ) [ 0 ] if os . environ . get ( " PMM_DIVIDER " ) else args . divider [ 0 ]
screen_width = os . environ . get ( " PMM_WIDTH " ) if os . environ . get ( " PMM_WIDTH " ) else args . width
if 90 < = screen_width < = 300 :
util . screen_width = screen_width
else :
raise util . Failed ( f " Argument Error: width argument invalid: { screen_width } must be an integer between 90 and 300 " )
config_file = os . environ . get ( " PMM_CONFIG " ) if os . environ . get ( " PMM_CONFIG " ) else args . config
default_dir = os . path . join ( os . path . dirname ( os . path . abspath ( __file__ ) ) , " config " )
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 ) : raise util . Failed ( f " Config Error: config not found at { os . path . abspath ( config_file ) } " )
elif not os . path . exists ( os . path . join ( default_dir , " config.yml " ) ) : raise util . Failed ( f " Config Error: config not found at { os . path . abspath ( default_dir ) } " )
os . makedirs ( os . path . join ( default_dir , " logs " ) , exist_ok = True )
logger = logging . getLogger ( " Plex Meta Manager " )
logger . setLevel ( logging . DEBUG )
def fmt_filter ( record ) :
record . levelname = f " [ { record . levelname } ] "
record . filename = f " [ { record . filename } : { record . lineno } ] "
return True
file_handler = logging . handlers . TimedRotatingFileHandler ( os . path . join ( default_dir , " logs " , " meta.log " ) , when = " midnight " , backupCount = 10 , encoding = " utf-8 " )
file_handler . addFilter ( fmt_filter )
file_handler . setFormatter ( logging . Formatter ( " [ %(asctime)s ] %(filename)-27s %(levelname)-10s | %(message)-100s | " ) )
cmd_handler = logging . StreamHandler ( )
cmd_handler . setFormatter ( logging . Formatter ( " | %(message)-100s | " ) )
cmd_handler . setLevel ( logging . DEBUG if my_tests or test or debug else logging . INFO )
logger . addHandler ( cmd_handler )
logger . addHandler ( file_handler )
sys . excepthook = util . my_except_hook
util . separator ( )
util . centered ( " " )
util . centered ( " ____ _ __ __ _ __ __ " )
util . centered ( " | _ \\ | | _____ __ | \\ / | ___| |_ __ _ | \\ / | __ _ _ __ __ _ __ _ ___ _ __ " )
util . centered ( " | |_) | |/ _ \\ \\ / / | | \\ /| |/ _ \\ __/ _` | | | \\ /| |/ _` | ' _ \\ / _` |/ _` |/ _ \\ ' __| " )
util . centered ( " | __/| | __/> < | | | | __/ || (_| | | | | | (_| | | | | (_| | (_| | __/ | " )
util . centered ( " |_| |_| \\ ___/_/ \\ _ \\ |_| |_| \\ ___| \\ __ \\ __,_| |_| |_| \\ __,_|_| |_| \\ __,_| \\ __, | \\ ___|_| " )
util . centered ( " |___/ " )
util . centered ( " Version: 1.7.2-Beta5 " )
util . separator ( )
if my_tests :
tests . run_tests ( default_dir )
sys . exit ( 0 )
def start ( config_path , is_test , daily , collections_to_run , resume_from ) :
if daily : start_type = " Daily "
elif is_test : start_type = " Test "
elif collections_to_run : start_type = " Collections "
else : start_type = " "
start_time = datetime . now ( )
util . separator ( f " Starting { start_type } Run " )
try :
config = Config ( default_dir , config_path )
config . update_libraries ( is_test , collections_to_run , resume_from )
except Exception as e :
util . print_stacktrace ( )
logger . critical ( e )
logger . info ( " " )
util . separator ( f " Finished { start_type } Run \n Run Time: { str ( datetime . now ( ) - start_time ) . split ( ' . ' ) [ 0 ] } " )
try :
if run or test or collections or resume :
start ( config_file , test , False , collections , resume )
else :
length = 0
schedule . every ( ) . day . at ( time_to_run ) . do ( start , config_file , False , True , None , None )
while True :
schedule . run_pending ( )
current = datetime . now ( ) . strftime ( " % H: % M " )
seconds = ( datetime . strptime ( time_to_run , " % H: % M " ) - datetime . strptime ( current , " % H: % M " ) ) . total_seconds ( )
hours = int ( seconds / / 3600 )
if hours < 0 :
hours + = 24
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 ' ' } "
length = util . print_return ( length , f " Current Time: { current } | { time_str } until the daily run at { time_to_run } " )
time . sleep ( 1 )
except KeyboardInterrupt :
util . separator ( " Exiting Plex Meta Manager " )