2021-09-21 03:57:16 +00:00
import logging , os , plexapi , requests
2021-05-27 17:40:35 +00:00
from modules import builder , util
2021-09-21 03:57:16 +00:00
from modules . library import Library
2021-06-30 15:02:55 +00:00
from modules . util import Failed , ImageData
2021-05-02 04:22:48 +00:00
from plexapi import utils
2021-01-20 21:37:59 +00:00
from plexapi . exceptions import BadRequest , NotFound , Unauthorized
2021-06-16 18:20:48 +00:00
from plexapi . collection import Collection
2021-01-20 21:37:59 +00:00
from plexapi . server import PlexServer
from retrying import retry
2021-05-02 04:22:48 +00:00
from urllib import parse
2021-06-22 20:28:12 +00:00
from xml . etree . ElementTree import ParseError
2021-01-20 21:37:59 +00:00
logger = logging . getLogger ( " Plex Meta Manager " )
2021-05-14 19:48:33 +00:00
builders = [ " plex_all " , " plex_collectionless " , " plex_search " ]
2021-03-30 05:50:53 +00:00
search_translation = {
2021-08-23 13:30:40 +00:00
" episode_title " : " episode.title " ,
" network " : " show.network " ,
2021-04-08 03:45:37 +00:00
" critic_rating " : " rating " ,
2021-08-23 13:30:40 +00:00
" audience_rating " : " audienceRating " ,
2021-05-05 18:01:41 +00:00
" user_rating " : " userRating " ,
2021-08-23 13:30:40 +00:00
" episode_user_rating " : " episode.userRating " ,
" content_rating " : " contentRating " ,
" episode_year " : " episode.year " ,
" release " : " originallyAvailableAt " ,
" episode_unmatched " : " episode.unmatched " ,
" episode_duplicate " : " episode.duplicate " ,
" added " : " addedAt " ,
2021-05-05 18:01:41 +00:00
" episode_added " : " episode.addedAt " ,
2021-05-27 17:40:35 +00:00
" episode_air_date " : " episode.originallyAvailableAt " ,
2021-08-23 13:30:40 +00:00
" plays " : " viewCount " ,
2021-08-22 21:43:26 +00:00
" episode_plays " : " episode.viewCount " ,
2021-08-23 13:30:40 +00:00
" last_played " : " lastViewedAt " ,
" episode_last_played " : " episode.lastViewedAt " ,
" unplayed " : " unwatched " ,
2021-08-22 21:43:26 +00:00
" episode_unplayed " : " episode.unwatched " ,
2021-08-23 13:30:40 +00:00
" subtitle_language " : " subtitleLanguage " ,
" audio_language " : " audioLanguage " ,
" progress " : " inProgress " ,
2021-08-22 21:43:26 +00:00
" episode_progress " : " episode.inProgress " ,
2021-08-23 13:30:40 +00:00
" unplayed_episodes " : " show.unwatchedLeaves "
2021-05-05 18:01:41 +00:00
}
2021-07-26 18:52:32 +00:00
show_translation = {
2021-08-23 13:30:40 +00:00
" title " : " show.title " ,
" studio " : " show.studio " ,
" rating " : " show.rating " ,
" audienceRating " : " show.audienceRating " ,
" userRating " : " show.userRating " ,
" contentRating " : " show.contentRating " ,
" year " : " show.year " ,
" originallyAvailableAt " : " show.originallyAvailableAt " ,
" unmatched " : " show.unmatched " ,
" genre " : " show.genre " ,
" collection " : " show.collection " ,
" actor " : " show.actor " ,
" addedAt " : " show.addedAt " ,
2021-08-22 21:43:26 +00:00
" viewCount " : " show.viewCount " ,
2021-08-23 13:30:40 +00:00
" lastViewedAt " : " show.lastViewedAt " ,
" resolution " : " episode.resolution " ,
2021-07-26 18:52:32 +00:00
" hdr " : " episode.hdr " ,
" subtitleLanguage " : " episode.subtitleLanguage " ,
2021-08-23 13:30:40 +00:00
" audioLanguage " : " episode.audioLanguage " ,
" trash " : " episode.trash " ,
" label " : " show.label " ,
2021-07-26 18:52:32 +00:00
}
2021-05-05 18:01:41 +00:00
modifier_translation = {
2021-09-13 02:42:33 +00:00
" " : " " , " .not " : " ! " , " .is " : " % 3D " , " .isnot " : " ! % 3D " , " .gt " : " %3E %3E " , " .gte " : " %3E " , " .lt " : " % 3C % 3C " , " .lte " : " % 3C " ,
2021-07-23 19:44:21 +00:00
" .before " : " % 3C % 3C " , " .after " : " %3E %3E " , " .begins " : " % 3C " , " .ends " : " %3E "
2021-03-30 05:50:53 +00:00
}
episode_sorting_options = { " default " : " -1 " , " oldest " : " 0 " , " newest " : " 1 " }
keep_episodes_options = { " all " : 0 , " 5_latest " : 5 , " 3_latest " : 3 , " latest " : 1 , " past_3 " : - 3 , " past_7 " : - 7 , " past_30 " : - 30 }
delete_episodes_options = { " never " : 0 , " day " : 1 , " week " : 7 , " refresh " : 100 }
season_display_options = { " default " : - 1 , " show " : 0 , " hide " : 1 }
2021-05-05 17:34:09 +00:00
episode_ordering_options = { " default " : None , " tmdb_aired " : " tmdbAiring " , " tvdb_aired " : " aired " , " tvdb_dvd " : " dvd " , " tvdb_absolute " : " absolute " }
2021-03-30 05:50:53 +00:00
plex_languages = [ " default " , " ar-SA " , " ca-ES " , " cs-CZ " , " da-DK " , " de-DE " , " el-GR " , " en-AU " , " en-CA " , " en-GB " , " en-US " ,
" es-ES " , " es-MX " , " et-EE " , " fa-IR " , " fi-FI " , " fr-CA " , " fr-FR " , " he-IL " , " hi-IN " , " hu-HU " , " id-ID " ,
" it-IT " , " ja-JP " , " ko-KR " , " lt-LT " , " lv-LV " , " nb-NO " , " nl-NL " , " pl-PL " , " pt-BR " , " pt-PT " , " ro-RO " ,
" ru-RU " , " sk-SK " , " sv-SE " , " th-TH " , " tr-TR " , " uk-UA " , " vi-VN " , " zh-CN " , " zh-HK " , " zh-TW " ]
metadata_language_options = { lang . lower ( ) : lang for lang in plex_languages }
metadata_language_options [ " default " ] = None
2021-04-05 22:07:44 +00:00
use_original_title_options = { " default " : - 1 , " no " : 0 , " yes " : 1 }
2021-07-21 20:59:27 +00:00
collection_mode_options = {
2021-07-23 19:44:21 +00:00
" default " : " default " , " hide " : " hide " ,
" hide_items " : " hideItems " , " hideitems " : " hideItems " ,
" show_items " : " showItems " , " showitems " : " showItems "
2021-07-21 20:59:27 +00:00
}
2021-07-29 02:26:39 +00:00
collection_order_options = [ " release " , " alpha " , " custom " ]
2021-08-22 15:54:33 +00:00
collection_level_options = [ " episode " , " season " ]
2021-05-02 04:22:48 +00:00
collection_mode_keys = { - 1 : " default " , 0 : " hide " , 1 : " hideItems " , 2 : " showItems " }
collection_order_keys = { 0 : " release " , 1 : " alpha " , 2 : " custom " }
2021-04-21 12:49:27 +00:00
item_advance_keys = {
" item_episode_sorting " : ( " episodeSort " , episode_sorting_options ) ,
" item_keep_episodes " : ( " autoDeletionItemPolicyUnwatchedLibrary " , keep_episodes_options ) ,
" item_delete_episodes " : ( " autoDeletionItemPolicyWatchedLibrary " , delete_episodes_options ) ,
" item_season_display " : ( " flattenSeasons " , season_display_options ) ,
" item_episode_ordering " : ( " showOrdering " , episode_ordering_options ) ,
" item_metadata_language " : ( " languageOverride " , metadata_language_options ) ,
" item_use_original_title " : ( " useOriginalTitle " , use_original_title_options )
}
new_plex_agents = [ " tv.plex.agents.movie " , " tv.plex.agents.series " ]
2021-03-30 05:50:53 +00:00
searches = [
2021-09-13 02:42:33 +00:00
" title " , " title.not " , " title.is " , " title.isnot " , " title.begins " , " title.ends " ,
" studio " , " studio.not " , " studio.is " , " studio.isnot " , " studio.begins " , " studio.ends " ,
2021-05-29 02:44:01 +00:00
" actor " , " actor.not " ,
" audio_language " , " audio_language.not " ,
" collection " , " collection.not " ,
" content_rating " , " content_rating.not " ,
" country " , " country.not " ,
" director " , " director.not " ,
" genre " , " genre.not " ,
" label " , " label.not " ,
" network " , " network.not " ,
" producer " , " producer.not " ,
" subtitle_language " , " subtitle_language.not " ,
" writer " , " writer.not " ,
2021-05-27 20:09:39 +00:00
" decade " , " resolution " , " hdr " , " unmatched " , " duplicate " , " unplayed " , " progress " , " trash " ,
" last_played " , " last_played.not " , " last_played.before " , " last_played.after " ,
2021-05-05 18:01:41 +00:00
" added " , " added.not " , " added.before " , " added.after " ,
2021-05-27 20:09:39 +00:00
" release " , " release.not " , " release.before " , " release.after " ,
2021-05-05 18:01:41 +00:00
" duration.gt " , " duration.gte " , " duration.lt " , " duration.lte " ,
2021-05-27 17:40:35 +00:00
" plays.gt " , " plays.gte " , " plays.lt " , " plays.lte " ,
2021-05-05 18:01:41 +00:00
" user_rating.gt " , " user_rating.gte " , " user_rating.lt " , " user_rating.lte " ,
" critic_rating.gt " , " critic_rating.gte " , " critic_rating.lt " , " critic_rating.lte " ,
2021-05-08 00:40:07 +00:00
" audience_rating.gt " , " audience_rating.gte " , " audience_rating.lt " , " audience_rating.lte " ,
2021-05-27 17:40:35 +00:00
" year " , " year.not " , " year.gt " , " year.gte " , " year.lt " , " year.lte " ,
2021-05-27 20:09:39 +00:00
" unplayed_episodes " , " episode_unplayed " , " episode_duplicate " , " episode_progress " , " episode_unmatched " ,
2021-09-13 02:42:33 +00:00
" episode_title " , " episode_title.not " , " episode_title.is " , " episode_title.isnot " , " episode_title.begins " , " episode_title.ends " ,
2021-05-27 17:40:35 +00:00
" episode_added " , " episode_added.not " , " episode_added.before " , " episode_added.after " ,
2021-05-27 20:09:39 +00:00
" episode_air_date " , " episode_air_date.not " , " episode_air_date.before " , " episode_air_date.after " ,
" episode_last_played " , " episode_last_played.not " , " episode_last_played.before " , " episode_last_played.after " ,
2021-05-27 17:40:35 +00:00
" episode_plays.gt " , " episode_plays.gte " , " episode_plays.lt " , " episode_plays.lte " ,
" episode_user_rating.gt " , " episode_user_rating.gte " , " episode_user_rating.lt " , " episode_user_rating.lte " ,
" episode_year " , " episode_year.not " , " episode_year.gt " , " episode_year.gte " , " episode_year.lt " , " episode_year.lte "
2021-03-30 05:50:53 +00:00
]
2021-05-30 02:19:38 +00:00
and_searches = [
" title.and " , " studio.and " , " actor.and " , " audio_language.and " , " collection.and " ,
" content_rating.and " , " country.and " , " director.and " , " genre.and " , " label.and " ,
" network.and " , " producer.and " , " subtitle_language.and " , " writer.and "
]
or_searches = [
" title " , " studio " , " actor " , " audio_language " , " collection " , " content_rating " ,
" country " , " director " , " genre " , " label " , " network " , " producer " , " subtitle_language " ,
" writer " , " decade " , " resolution " , " year " , " episode_title " , " episode_year "
]
2021-03-30 05:50:53 +00:00
movie_only_searches = [
2021-07-23 19:44:21 +00:00
" country " , " country.not " , " director " , " director.not " , " producer " , " producer.not " , " writer " , " writer.not " ,
2021-08-23 13:30:40 +00:00
" decade " , " duplicate " , " unplayed " , " progress " ,
2021-08-22 21:43:26 +00:00
" duration.gt " , " duration.gte " , " duration.lt " , " duration.lte "
2021-03-30 05:50:53 +00:00
]
2021-04-01 15:34:02 +00:00
show_only_searches = [
2021-05-29 02:44:01 +00:00
" network " , " network.not " ,
2021-09-13 02:42:33 +00:00
" episode_title " , " episode_title.not " , " episode_title.is " , " episode_title.isnot " , " episode_title.begins " , " episode_title.ends " ,
2021-05-27 17:40:35 +00:00
" episode_added " , " episode_added.not " , " episode_added.before " , " episode_added.after " ,
" episode_air_date " , " episode_air_date.not " ,
" episode_air_date.before " , " episode_air_date.after " ,
2021-08-23 13:30:40 +00:00
" episode_last_played " , " episode_last_played.not " , " episode_last_played.before " , " episode_last_played.after " ,
2021-05-27 17:40:35 +00:00
" episode_plays.gt " , " episode_plays.gte " , " episode_plays.lt " , " episode_plays.lte " ,
" episode_user_rating.gt " , " episode_user_rating.gte " , " episode_user_rating.lt " , " episode_user_rating.lte " ,
2021-08-23 13:30:40 +00:00
" episode_year " , " episode_year.not " , " episode_year.gt " , " episode_year.gte " , " episode_year.lt " , " episode_year.lte " ,
" unplayed_episodes " , " episode_unplayed " , " episode_duplicate " , " episode_progress " , " episode_unmatched " ,
2021-04-01 15:34:02 +00:00
]
2021-05-28 23:18:28 +00:00
float_attributes = [ " user_rating " , " episode_user_rating " , " critic_rating " , " audience_rating " ]
boolean_attributes = [
2021-05-27 20:09:39 +00:00
" hdr " , " unmatched " , " duplicate " , " unplayed " , " progress " , " trash " ,
" unplayed_episodes " , " episode_unplayed " , " episode_duplicate " , " episode_progress " , " episode_unmatched " ,
]
2021-05-28 23:18:28 +00:00
tmdb_attributes = [ " actor " , " director " , " producer " , " writer " ]
2021-08-06 23:17:19 +00:00
date_attributes = [ " added " , " episode_added " , " release " , " episode_air_date " , " last_played " , " episode_last_played " , " first_episode_aired " , " last_episode_aired " ]
2021-08-07 06:01:21 +00:00
number_attributes = [ " plays " , " episode_plays " , " duration " , " tmdb_vote_count " ] + date_attributes
2021-07-23 19:44:21 +00:00
search_display = { " added " : " Date Added " , " release " : " Release Date " , " hdr " : " HDR " , " progress " : " In Progress " , " episode_progress " : " Episode In Progress " }
2021-05-05 18:01:41 +00:00
tags = [
2021-07-23 19:44:21 +00:00
" actor " , " audio_language " , " collection " , " content_rating " , " country " , " director " , " genre " , " label " ,
" network " , " producer " , " resolution " , " studio " , " subtitle_language " , " writer "
2021-05-05 18:01:41 +00:00
]
2021-05-29 02:33:55 +00:00
movie_sorts = {
2021-05-05 18:01:41 +00:00
" title.asc " : " titleSort " , " title.desc " : " titleSort % 3Adesc " ,
" year.asc " : " year " , " year.desc " : " year % 3Adesc " ,
" originally_available.asc " : " originallyAvailableAt " , " originally_available.desc " : " originallyAvailableAt % 3Adesc " ,
2021-05-27 17:40:35 +00:00
" release.asc " : " originallyAvailableAt " , " release.desc " : " originallyAvailableAt % 3Adesc " ,
2021-05-05 18:01:41 +00:00
" critic_rating.asc " : " rating " , " critic_rating.desc " : " rating % 3Adesc " ,
" audience_rating.asc " : " audienceRating " , " audience_rating.desc " : " audienceRating % 3Adesc " ,
" user_rating.asc " : " userRating " , " user_rating.desc " : " userRating % 3Adesc " ,
" content_rating.asc " : " contentRating " , " content_rating.desc " : " contentRating % 3Adesc " ,
" duration.asc " : " duration " , " duration.desc " : " duration % 3Adesc " ,
" plays.asc " : " viewCount " , " plays.desc " : " viewCount % 3Adesc " ,
" added.asc " : " addedAt " , " added.desc " : " addedAt % 3Adesc " ,
" random " : " random "
}
2021-05-29 02:33:55 +00:00
show_sorts = {
2021-05-05 18:01:41 +00:00
" title.asc " : " titleSort " , " title.desc " : " titleSort % 3Adesc " ,
" year.asc " : " year " , " year.desc " : " year % 3Adesc " ,
" originally_available.asc " : " originallyAvailableAt " , " originally_available.desc " : " originallyAvailableAt % 3Adesc " ,
2021-05-27 17:40:35 +00:00
" release.asc " : " originallyAvailableAt " , " release.desc " : " originallyAvailableAt % 3Adesc " ,
2021-05-05 18:01:41 +00:00
" critic_rating.asc " : " rating " , " critic_rating.desc " : " rating % 3Adesc " ,
" audience_rating.asc " : " audienceRating " , " audience_rating.desc " : " audienceRating % 3Adesc " ,
" user_rating.asc " : " userRating " , " user_rating.desc " : " userRating % 3Adesc " ,
" content_rating.asc " : " contentRating " , " content_rating.desc " : " contentRating % 3Adesc " ,
" added.asc " : " addedAt " , " added.desc " : " addedAt % 3Adesc " ,
" episode_added.asc " : " episode.addedAt " , " episode_added.desc " : " episode.addedAt % 3Adesc " ,
" random " : " random "
}
2021-05-29 02:33:55 +00:00
season_sorts = {
2021-05-05 18:01:41 +00:00
" season.asc " : " season.index % 2Cseason.titleSort " , " season.desc " : " season.index % 3Adesc % 2Cseason.titleSort " ,
" show.asc " : " show.titleSort % 2Cindex " , " show.desc " : " show.titleSort % 3Adesc % 2Cindex " ,
" user_rating.asc " : " userRating " , " user_rating.desc " : " userRating % 3Adesc " ,
" added.asc " : " addedAt " , " added.desc " : " addedAt % 3Adesc " ,
" random " : " random "
}
2021-05-29 02:33:55 +00:00
episode_sorts = {
2021-05-05 18:01:41 +00:00
" title.asc " : " titleSort " , " title.desc " : " titleSort % 3Adesc " ,
" show.asc " : " show.titleSort % 2Cseason.index % 3AnullsLast % 2Cepisode.index % 3AnullsLast % 2Cepisode.originallyAvailableAt % 3AnullsLast % 2Cepisode.titleSort % 2Cepisode.id " ,
" show.desc " : " show.titleSort % 3Adesc % 2Cseason.index % 3AnullsLast % 2Cepisode.index % 3AnullsLast % 2Cepisode.originallyAvailableAt % 3AnullsLast % 2Cepisode.titleSort % 2Cepisode.id " ,
" year.asc " : " year " , " year.desc " : " year % 3Adesc " ,
" originally_available.asc " : " originallyAvailableAt " , " originally_available.desc " : " originallyAvailableAt % 3Adesc " ,
2021-05-27 17:40:35 +00:00
" release.asc " : " originallyAvailableAt " , " release.desc " : " originallyAvailableAt % 3Adesc " ,
2021-05-05 18:01:41 +00:00
" critic_rating.asc " : " rating " , " critic_rating.desc " : " rating % 3Adesc " ,
" audience_rating.asc " : " audienceRating " , " audience_rating.desc " : " audienceRating % 3Adesc " ,
" user_rating.asc " : " userRating " , " user_rating.desc " : " userRating % 3Adesc " ,
" duration.asc " : " duration " , " duration.desc " : " duration % 3Adesc " ,
" plays.asc " : " viewCount " , " plays.desc " : " viewCount % 3Adesc " ,
" added.asc " : " addedAt " , " added.desc " : " addedAt % 3Adesc " ,
" random " : " random "
}
2021-07-23 19:44:21 +00:00
sort_types = { " movies " : ( 1 , movie_sorts ) , " shows " : ( 2 , show_sorts ) , " seasons " : ( 3 , season_sorts ) , " episodes " : ( 4 , episode_sorts ) }
2021-03-30 05:50:53 +00:00
2021-09-21 03:57:16 +00:00
class Plex ( Library ) :
2021-06-02 15:18:37 +00:00
def __init__ ( self , config , params ) :
2021-09-21 03:57:16 +00:00
super ( ) . __init__ ( config , params )
2021-07-14 14:47:20 +00:00
self . plex = params [ " plex " ]
self . url = params [ " plex " ] [ " url " ]
self . token = params [ " plex " ] [ " token " ]
self . timeout = params [ " plex " ] [ " timeout " ]
2021-11-22 20:47:26 +00:00
logger . info ( " " )
2021-03-26 05:43:11 +00:00
try :
2021-07-14 14:47:20 +00:00
self . PlexServer = PlexServer ( baseurl = self . url , token = self . token , session = self . config . session , timeout = self . timeout )
2021-03-26 05:43:11 +00:00
except Unauthorized :
raise Failed ( " Plex Error: Plex token is invalid " )
except ValueError as e :
raise Failed ( f " Plex Error: { e } " )
2021-06-22 20:28:12 +00:00
except ( requests . exceptions . ConnectionError , ParseError ) :
2021-01-20 21:37:59 +00:00
util . print_stacktrace ( )
raise Failed ( " Plex Error: Plex url is invalid " )
2021-11-22 20:47:26 +00:00
self . Plex = None
library_names = [ ]
for s in self . PlexServer . library . sections ( ) :
library_names . append ( s . title )
if s . title == params [ " name " ] :
self . Plex = s
break
2021-03-26 05:43:11 +00:00
if not self . Plex :
2021-11-22 20:47:26 +00:00
raise Failed ( f " Plex Error: Plex Library { params [ ' name ' ] } not found. Options: { library_names } " )
2021-08-24 04:33:04 +00:00
if self . Plex . type in [ " movie " , " show " ] :
self . type = self . Plex . type . capitalize ( )
else :
2021-04-21 18:02:01 +00:00
raise Failed ( f " Plex Error: Plex Library must be a Movies or TV Shows library " )
2021-03-31 04:20:20 +00:00
2021-04-21 12:49:27 +00:00
self . agent = self . Plex . agent
2021-08-24 04:33:04 +00:00
self . is_movie = self . type == " Movie "
self . is_show = self . type == " Show "
self . is_other = self . agent == " com.plexapp.agents.none "
if self . is_other :
self . type = " Video "
2021-12-06 07:52:08 +00:00
if self . tmdb_collections and self . is_show :
self . tmdb_collections = None
logger . error ( " Config Error: tmdb_collections only work with Movie Libraries. " )
2021-01-20 21:37:59 +00:00
2021-12-08 03:31:20 +00:00
def set_server_preroll ( self , preroll ) :
self . PlexServer . settings . get ( ' cinemaTrailersPrerollID ' ) . set ( preroll )
self . PlexServer . settings . save ( )
2021-04-08 20:10:26 +00:00
def get_all_collections ( self ) :
return self . search ( libtype = " collection " )
2021-05-11 01:22:18 +00:00
@retry ( stop_max_attempt_number = 6 , wait_fixed = 10000 , retry_on_exception = util . retry_if_not_plex )
2021-04-08 20:10:26 +00:00
def search ( self , title = None , libtype = None , sort = None , maxresults = None , * * kwargs ) :
return self . Plex . search ( title = title , sort = sort , maxresults = maxresults , libtype = libtype , * * kwargs )
2021-01-20 21:37:59 +00:00
2021-05-11 01:22:18 +00:00
@retry ( stop_max_attempt_number = 6 , wait_fixed = 10000 , retry_on_exception = util . retry_if_not_plex )
2021-05-12 14:25:48 +00:00
def exact_search ( self , title , libtype = None , year = None ) :
if year :
terms = { " title= " : title , " year " : year }
else :
terms = { " title= " : title }
return self . Plex . search ( libtype = libtype , * * terms )
2021-05-11 01:22:18 +00:00
@retry ( stop_max_attempt_number = 6 , wait_fixed = 10000 , retry_on_exception = util . retry_if_not_plex )
2021-05-02 04:22:48 +00:00
def get_labeled_items ( self , label ) :
return self . Plex . search ( label = label )
2021-05-11 01:22:18 +00:00
@retry ( stop_max_attempt_number = 6 , wait_fixed = 10000 , retry_on_exception = util . retry_if_not_plex )
2021-01-20 21:37:59 +00:00
def fetchItem ( self , data ) :
return self . PlexServer . fetchItem ( data )
2021-04-08 20:10:26 +00:00
def get_all ( self ) :
2021-08-24 04:33:04 +00:00
logger . info ( f " Loading All { self . type } s from Library: { self . name } " )
2021-10-05 04:30:04 +00:00
key = f " /library/sections/ { self . Plex . key } /all?includeGuids=1&type= { utils . searchType ( self . Plex . TYPE ) } "
2021-06-02 17:50:11 +00:00
container_start = 0
container_size = plexapi . X_PLEX_CONTAINER_SIZE
results = [ ]
while self . Plex . _totalViewSize is None or container_start < = self . Plex . _totalViewSize :
results . extend ( self . fetchItems ( key , container_start , container_size ) )
util . print_return ( f " Loaded: { container_start } / { self . Plex . _totalViewSize } " )
container_start + = container_size
2021-08-24 04:33:04 +00:00
logger . info ( util . adjust_space ( f " Loaded { self . Plex . _totalViewSize } { self . type } s " ) )
2021-06-02 17:50:11 +00:00
return results
@retry ( stop_max_attempt_number = 6 , wait_fixed = 10000 , retry_on_exception = util . retry_if_not_plex )
def fetchItems ( self , key , container_start , container_size ) :
return self . Plex . fetchItems ( key , container_start = container_start , container_size = container_size )
2021-04-08 20:10:26 +00:00
2021-05-11 01:22:18 +00:00
@retry ( stop_max_attempt_number = 6 , wait_fixed = 10000 , retry_on_exception = util . retry_if_not_plex )
2021-05-02 04:22:48 +00:00
def query ( self , method ) :
return method ( )
2021-05-11 01:22:18 +00:00
@retry ( stop_max_attempt_number = 6 , wait_fixed = 10000 , retry_on_exception = util . retry_if_not_plex )
2021-05-02 04:22:48 +00:00
def query_data ( self , method , data ) :
return method ( data )
2021-09-30 14:22:03 +00:00
@retry ( stop_max_attempt_number = 6 , wait_fixed = 10000 , retry_on_exception = util . retry_if_not_failed )
2021-09-30 20:55:29 +00:00
def query_collection ( self , item , collection , locked = True , add = True ) :
if add :
item . addCollection ( collection , locked = locked )
else :
item . removeCollection ( collection , locked = locked )
2021-09-30 14:22:03 +00:00
2021-05-11 01:22:18 +00:00
@retry ( stop_max_attempt_number = 6 , wait_fixed = 10000 , retry_on_exception = util . retry_if_not_plex )
2021-05-02 04:22:48 +00:00
def collection_mode_query ( self , collection , data ) :
collection . modeUpdate ( mode = data )
2021-05-11 01:22:18 +00:00
@retry ( stop_max_attempt_number = 6 , wait_fixed = 10000 , retry_on_exception = util . retry_if_not_plex )
2021-05-02 04:22:48 +00:00
def collection_order_query ( self , collection , data ) :
collection . sortUpdate ( sort = data )
2021-06-02 18:41:57 +00:00
@retry ( stop_max_attempt_number = 6 , wait_fixed = 10000 , retry_on_exception = util . retry_if_not_plex )
def reload ( self , item ) :
2021-08-12 20:36:38 +00:00
try :
item . reload ( checkFiles = False , includeAllConcerts = False , includeBandwidths = False , includeChapters = False ,
includeChildren = False , includeConcerts = False , includeExternalMedia = False , includeExtras = False ,
includeFields = False , includeGeolocation = False , includeLoudnessRamps = False , includeMarkers = False ,
includeOnDeck = False , includePopularLeaves = False , includeRelated = False ,
includeRelatedCount = 0 , includeReviews = False , includeStations = False )
except ( BadRequest , NotFound ) as e :
util . print_stacktrace ( )
raise Failed ( f " Item Failed to Load: { e } " )
2021-05-08 00:40:07 +00:00
2021-05-11 01:22:18 +00:00
@retry ( stop_max_attempt_number = 6 , wait_fixed = 10000 , retry_on_exception = util . retry_if_not_plex )
2021-05-07 15:37:09 +00:00
def edit_query ( self , item , edits , advanced = False ) :
if advanced :
2021-05-03 04:10:12 +00:00
item . editAdvanced ( * * edits )
else :
item . edit ( * * edits )
2021-06-02 18:41:57 +00:00
self . reload ( item )
2021-05-02 04:22:48 +00:00
2021-05-11 01:22:18 +00:00
@retry ( stop_max_attempt_number = 6 , wait_fixed = 10000 , retry_on_exception = util . retry_if_not_plex )
2021-06-12 15:29:17 +00:00
def _upload_image ( self , item , image ) :
2021-09-21 03:57:16 +00:00
try :
if image . is_poster and image . is_url :
item . uploadPoster ( url = image . location )
elif image . is_poster :
item . uploadPoster ( filepath = image . location )
elif image . is_url :
item . uploadArt ( url = image . location )
else :
item . uploadArt ( filepath = image . location )
self . reload ( item )
except BadRequest as e :
raise Failed ( e )
2021-04-08 20:10:26 +00:00
2021-06-30 03:08:38 +00:00
@retry ( stop_max_attempt_number = 6 , wait_fixed = 10000 , retry_on_exception = util . retry_if_not_plex )
2021-07-14 14:47:20 +00:00
def upload_file_poster ( self , item , image ) :
2021-06-30 03:08:38 +00:00
item . uploadPoster ( filepath = image )
self . reload ( item )
2021-04-08 20:10:26 +00:00
@retry ( stop_max_attempt_number = 6 , wait_fixed = 10000 , retry_on_exception = util . retry_if_not_failed )
2021-05-05 18:01:41 +00:00
def get_search_choices ( self , search_name , title = True ) :
2021-06-16 03:20:45 +00:00
final_search = search_translation [ search_name ] if search_name in search_translation else search_name
2021-07-26 18:52:32 +00:00
final_search = show_translation [ final_search ] if self . is_show and final_search in show_translation else final_search
2021-04-01 15:34:02 +00:00
try :
2021-04-18 15:36:43 +00:00
choices = { }
2021-06-16 03:20:45 +00:00
for choice in self . Plex . listFilterChoices ( final_search ) :
2021-05-05 18:01:41 +00:00
choices [ choice . title . lower ( ) ] = choice . title if title else choice . key
choices [ choice . key . lower ( ) ] = choice . title if title else choice . key
2021-04-18 15:36:43 +00:00
return choices
2021-04-01 15:34:02 +00:00
except NotFound :
2021-07-26 18:52:32 +00:00
logger . debug ( f " Search Attribute: { final_search } " )
2021-12-13 07:30:19 +00:00
raise Failed ( f " Plex Error: plex_search attribute: { search_name } not supported " )
2021-03-26 05:43:11 +00:00
2021-05-11 01:22:18 +00:00
@retry ( stop_max_attempt_number = 6 , wait_fixed = 10000 , retry_on_exception = util . retry_if_not_plex )
2021-05-02 04:22:48 +00:00
def get_labels ( self ) :
return { label . title : label . key for label in self . Plex . listFilterChoices ( field = " label " ) }
2021-05-11 01:22:18 +00:00
@retry ( stop_max_attempt_number = 6 , wait_fixed = 10000 , retry_on_exception = util . retry_if_not_plex )
2021-05-02 04:22:48 +00:00
def _query ( self , key , post = False , put = False ) :
if post : method = self . Plex . _server . _session . post
elif put : method = self . Plex . _server . _session . put
else : method = None
2021-06-30 15:07:02 +00:00
return self . Plex . _server . query ( key , method = method )
2021-05-02 04:22:48 +00:00
2021-09-30 20:55:29 +00:00
def alter_collection ( self , item , collection , smart_label_collection = False , add = True ) :
2021-09-30 14:22:03 +00:00
if smart_label_collection :
2021-09-30 20:55:29 +00:00
self . query_data ( item . addLabel if add else item . removeLabel , collection )
2021-09-30 14:22:03 +00:00
else :
locked = True
if self . agent in [ " tv.plex.agents.movie " , " tv.plex.agents.series " ] :
field = next ( ( f for f in item . fields if f . name == " collection " ) , None )
locked = field is not None
2021-09-30 20:55:29 +00:00
self . query_collection ( item , collection , locked = locked , add = add )
2021-09-30 14:22:03 +00:00
2021-08-02 14:24:13 +00:00
def move_item ( self , collection , item , after = None ) :
2021-07-29 13:36:30 +00:00
key = f " { collection . key } /items/ { item } /move "
if after :
key + = f " ?after= { after } "
self . _query ( key , put = True )
2021-05-17 14:35:47 +00:00
def smart_label_url ( self , title , sort ) :
2021-05-02 04:22:48 +00:00
labels = self . get_labels ( )
if title not in labels :
raise Failed ( f " Plex Error: Label: { title } does not exist " )
2021-05-05 18:01:41 +00:00
smart_type = 1 if self . is_movie else 2
2021-05-29 02:33:55 +00:00
sort_type = movie_sorts [ sort ] if self . is_movie else show_sorts [ sort ]
2021-05-17 14:35:47 +00:00
return smart_type , f " ?type= { smart_type } &sort= { sort_type } &label= { labels [ title ] } "
2021-05-02 04:22:48 +00:00
2021-05-23 02:42:00 +00:00
def test_smart_filter ( self , uri_args ) :
logger . debug ( f " Smart Collection Test: { uri_args } " )
test_items = self . get_filter_items ( uri_args )
if len ( test_items ) < 1 :
raise Failed ( f " Plex Error: No items for smart filter: { uri_args } " )
2021-05-05 18:01:41 +00:00
def create_smart_collection ( self , title , smart_type , uri_args ) :
2021-05-23 02:42:00 +00:00
self . test_smart_filter ( uri_args )
2021-05-02 04:22:48 +00:00
args = {
2021-05-05 18:01:41 +00:00
" type " : smart_type ,
2021-05-02 04:22:48 +00:00
" title " : title ,
" smart " : 1 ,
" sectionId " : self . Plex . key ,
" uri " : self . build_smart_filter ( uri_args )
}
self . _query ( f " /library/collections { utils . joinArgs ( args ) } " , post = True )
def get_smart_filter_from_uri ( self , uri ) :
smart_filter = parse . parse_qs ( parse . urlparse ( uri . replace ( " /#!/ " , " / " ) ) . query ) [ " key " ] [ 0 ]
2021-05-05 18:01:41 +00:00
args = smart_filter [ smart_filter . index ( " ? " ) : ]
return self . build_smart_filter ( args ) , int ( args [ args . index ( " type= " ) + 5 : args . index ( " type= " ) + 6 ] )
2021-05-02 04:22:48 +00:00
def build_smart_filter ( self , uri_args ) :
return f " server:// { self . PlexServer . machineIdentifier } /com.plexapp.plugins.library/library/sections/ { self . Plex . key } /all { uri_args } "
def update_smart_collection ( self , collection , uri_args ) :
2021-05-23 02:42:00 +00:00
self . test_smart_filter ( uri_args )
2021-05-02 04:22:48 +00:00
self . _query ( f " /library/collections/ { collection . ratingKey } /items { utils . joinArgs ( { ' uri ' : self . build_smart_filter ( uri_args ) } ) } " , put = True )
def smart_filter ( self , collection ) :
2021-06-16 18:20:48 +00:00
smart_filter = self . get_collection ( collection ) . content
2021-05-02 04:22:48 +00:00
return smart_filter [ smart_filter . index ( " ? " ) : ]
2021-04-21 18:02:01 +00:00
2021-06-30 15:07:02 +00:00
def collection_visibility ( self , collection ) :
try :
attrs = self . _query ( f " /hubs/sections/ { self . Plex . key } /manage?metadataItemId= { collection . ratingKey } " ) [ 0 ] . attrib
return {
" library " : utils . cast ( bool , attrs . get ( " promotedToRecommended " , " 0 " ) ) ,
" home " : utils . cast ( bool , attrs . get ( " promotedToOwnHome " , " 0 " ) ) ,
" shared " : utils . cast ( bool , attrs . get ( " promotedToSharedHome " , " 0 " ) )
}
except IndexError :
return { " library " : False , " home " : False , " shared " : False }
def collection_visibility_update ( self , collection , visibility = None , library = None , home = None , shared = None ) :
if visibility is None :
visibility = self . collection_visibility ( collection )
key = f " /hubs/sections/ { self . Plex . key } /manage?metadataItemId= { collection . ratingKey } "
key + = f " &promotedToRecommended= { 1 if ( library is None and visibility [ ' library ' ] ) or library else 0 } "
key + = f " &promotedToOwnHome= { 1 if ( home is None and visibility [ ' home ' ] ) or home else 0 } "
key + = f " &promotedToSharedHome= { 1 if ( shared is None and visibility [ ' shared ' ] ) or shared else 0 } "
self . _query ( key , post = True )
2021-01-20 21:37:59 +00:00
def get_collection ( self , data ) :
2021-05-02 04:22:48 +00:00
if isinstance ( data , int ) :
2021-07-26 20:29:28 +00:00
return self . fetchItem ( data )
2021-06-16 18:20:48 +00:00
elif isinstance ( data , Collection ) :
2021-07-26 20:29:28 +00:00
return data
2021-05-02 04:22:48 +00:00
else :
2021-07-26 20:29:28 +00:00
for d in self . search ( title = str ( data ) , libtype = " collection " ) :
if d . title == data :
return d
2021-06-16 18:20:48 +00:00
raise Failed ( f " Plex Error: Collection { data } not found " )
2021-01-20 21:37:59 +00:00
def validate_collections ( self , collections ) :
valid_collections = [ ]
for collection in collections :
try : valid_collections . append ( self . get_collection ( collection ) )
except Failed as e : logger . error ( e )
if len ( valid_collections ) == 0 :
2021-02-24 06:44:06 +00:00
raise Failed ( f " Collection Error: No valid Plex Collections in { collections } " )
2021-01-20 21:37:59 +00:00
return valid_collections
2021-08-07 06:01:21 +00:00
def get_rating_keys ( self , method , data ) :
2021-04-03 18:00:05 +00:00
items = [ ]
if method == " plex_all " :
2021-08-24 04:33:04 +00:00
logger . info ( f " Processing Plex All { self . type } s " )
2021-04-08 20:10:26 +00:00
items = self . get_all ( )
2021-04-03 18:00:05 +00:00
elif method == " plex_search " :
2021-05-29 02:33:55 +00:00
util . print_multiline ( data [ 1 ] , info = True )
items = self . get_filter_items ( data [ 2 ] )
2021-04-03 18:00:05 +00:00
elif method == " plex_collectionless " :
good_collections = [ ]
2021-08-01 04:35:42 +00:00
logger . info ( f " Processing Plex Collectionless " )
2021-05-09 05:37:45 +00:00
logger . info ( " Collections Excluded " )
2021-04-03 18:00:05 +00:00
for col in self . get_all_collections ( ) :
keep_collection = True
for pre in data [ " exclude_prefix " ] :
if col . title . startswith ( pre ) or ( col . titleSort and col . titleSort . startswith ( pre ) ) :
keep_collection = False
2021-05-09 05:37:45 +00:00
logger . info ( f " { col . title } excluded by prefix match { pre } " )
2021-04-03 18:00:05 +00:00
break
if keep_collection :
for ext in data [ " exclude " ] :
if col . title == ext or ( col . titleSort and col . titleSort == ext ) :
keep_collection = False
2021-05-09 05:37:45 +00:00
logger . info ( f " { col . title } excluded by exact match " )
2021-04-03 18:00:05 +00:00
break
if keep_collection :
2021-05-05 14:50:40 +00:00
logger . info ( f " Collection Passed: { col . title } " )
2021-05-05 18:01:41 +00:00
good_collections . append ( col )
2021-05-09 05:37:45 +00:00
logger . info ( " " )
logger . info ( " Collections Not Excluded (Items in these collections are not added to Collectionless) " )
for col in good_collections :
logger . info ( col . title )
2021-05-05 18:01:41 +00:00
collection_indexes = [ c . index for c in good_collections ]
2021-04-08 20:10:26 +00:00
all_items = self . get_all ( )
2021-04-03 18:00:05 +00:00
for i , item in enumerate ( all_items , 1 ) :
2021-05-26 13:25:32 +00:00
util . print_return ( f " Processing: { i } / { len ( all_items ) } { item . title } " )
2021-04-03 18:00:05 +00:00
add_item = True
2021-06-02 18:41:57 +00:00
self . reload ( item )
2021-04-03 18:00:05 +00:00
for collection in item . collections :
2021-05-05 18:01:41 +00:00
if collection . id in collection_indexes :
2021-04-03 18:00:05 +00:00
add_item = False
break
if add_item :
items . append ( item )
2021-08-24 04:33:04 +00:00
logger . info ( util . adjust_space ( f " Processed { len ( all_items ) } { self . type } s " ) )
2021-04-03 18:00:05 +00:00
else :
raise Failed ( f " Plex Error: Method { method } not supported " )
if len ( items ) > 0 :
2021-12-14 05:51:36 +00:00
ids = [ ( item . ratingKey , " ratingKey " ) for item in items ]
2021-08-07 06:01:21 +00:00
logger . debug ( " " )
logger . debug ( f " { len ( ids ) } Keys Found: { ids } " )
return ids
2021-04-03 18:00:05 +00:00
else :
raise Failed ( " Plex Error: No Items found in Plex " )
2021-05-02 04:22:48 +00:00
def get_collection_items ( self , collection , smart_label_collection ) :
if smart_label_collection :
2021-06-16 18:20:48 +00:00
return self . get_labeled_items ( collection . title if isinstance ( collection , Collection ) else str ( collection ) )
elif isinstance ( collection , Collection ) :
if collection . smart :
2021-05-23 02:42:00 +00:00
return self . get_filter_items ( self . smart_filter ( collection ) )
2021-05-19 21:07:43 +00:00
else :
return self . query ( collection . items )
2021-05-02 04:22:48 +00:00
else :
return [ ]
2021-05-23 02:42:00 +00:00
def get_filter_items ( self , uri_args ) :
key = f " /library/sections/ { self . Plex . key } /all { uri_args } "
return self . Plex . _search ( key , None , 0 , plexapi . X_PLEX_CONTAINER_SIZE )
2021-05-02 04:22:48 +00:00
def get_collection_name_and_items ( self , collection , smart_label_collection ) :
2021-06-16 18:20:48 +00:00
name = collection . title if isinstance ( collection , Collection ) else str ( collection )
2021-05-02 04:22:48 +00:00
return name , self . get_collection_items ( collection , smart_label_collection )
2021-05-26 14:45:33 +00:00
def get_tmdb_from_map ( self , item ) :
return self . movie_rating_key_map [ item . ratingKey ] if item . ratingKey in self . movie_rating_key_map else None
def get_tvdb_from_map ( self , item ) :
return self . show_rating_key_map [ item . ratingKey ] if item . ratingKey in self . show_rating_key_map else None
2021-02-05 14:56:05 +00:00
def search_item ( self , data , year = None ) :
2021-04-12 04:00:03 +00:00
kwargs = { }
if year is not None :
kwargs [ " year " ] = year
2021-07-26 20:29:28 +00:00
for d in self . search ( title = str ( data ) , * * kwargs ) :
if d . title == data :
return d
return None
2021-02-05 14:56:05 +00:00
2021-04-21 18:02:01 +00:00
def edit_item ( self , item , name , item_type , edits , advanced = False ) :
if len ( edits ) > 0 :
logger . debug ( f " Details Update: { edits } " )
try :
2021-05-03 04:10:12 +00:00
self . edit_query ( item , edits , advanced = advanced )
2021-09-13 04:56:05 +00:00
if advanced and ( " languageOverride " in edits or " useOriginalTitle " in edits ) :
2021-05-02 04:22:48 +00:00
self . query ( item . refresh )
2021-04-21 18:02:01 +00:00
logger . info ( f " { item_type } : { name } { ' Advanced ' if advanced else ' ' } Details Update Successful " )
2021-05-20 19:26:56 +00:00
return True
2021-04-21 18:02:01 +00:00
except BadRequest :
util . print_stacktrace ( )
logger . error ( f " { item_type } : { name } { ' Advanced ' if advanced else ' ' } Details Update Failed " )
2021-05-20 19:26:56 +00:00
return False
2021-05-27 17:40:35 +00:00
def edit_tags ( self , attr , obj , add_tags = None , remove_tags = None , sync_tags = None ) :
2021-08-20 13:13:54 +00:00
display = " "
2021-05-27 17:40:35 +00:00
key = builder . filter_translation [ attr ] if attr in builder . filter_translation else attr
2021-12-06 07:51:06 +00:00
if add_tags or remove_tags or sync_tags is not None :
2021-06-24 05:57:55 +00:00
_add_tags = add_tags if add_tags else [ ]
2021-08-05 19:41:59 +00:00
_remove_tags = [ t . lower ( ) for t in remove_tags ] if remove_tags else [ ]
_sync_tags = [ t . lower ( ) for t in sync_tags ] if sync_tags else [ ]
2021-07-12 02:23:14 +00:00
try :
2021-08-18 16:13:41 +00:00
self . reload ( obj )
2021-07-12 02:23:14 +00:00
_item_tags = [ item_tag . tag . lower ( ) for item_tag in getattr ( obj , key ) ]
except BadRequest :
_item_tags = [ ]
_add = [ f " { t [ : 1 ] . upper ( ) } { t [ 1 : ] } " for t in _add_tags + _sync_tags if t . lower ( ) not in _item_tags ]
2021-12-03 04:23:22 +00:00
_remove = [ t for t in _item_tags if ( sync_tags is not None and t not in _sync_tags ) or t in _remove_tags ]
2021-06-24 05:57:55 +00:00
if _add :
2021-07-12 02:23:14 +00:00
self . query_data ( getattr ( obj , f " add { attr . capitalize ( ) } " ) , _add )
2021-08-20 13:13:54 +00:00
display + = f " + { ' , + ' . join ( _add ) } "
2021-07-12 02:23:14 +00:00
if _remove :
self . query_data ( getattr ( obj , f " remove { attr . capitalize ( ) } " ) , _remove )
2021-08-20 13:13:54 +00:00
display + = f " - { ' , - ' . join ( _remove ) } "
if len ( display ) > 0 :
logger . info ( f " { obj . title [ : 25 ] : <25 } | { attr . capitalize ( ) } | { display } " )
return len ( display ) > 0
2021-04-21 18:02:01 +00:00
2021-08-02 19:00:15 +00:00
def update_item_from_assets ( self , item , overlay = None , create = False ) :
2021-07-12 20:35:35 +00:00
name = os . path . basename ( os . path . dirname ( str ( item . locations [ 0 ] ) ) if self . is_movie else str ( item . locations [ 0 ] ) )
2021-07-12 19:24:31 +00:00
found_folder = False
2021-07-14 14:47:20 +00:00
poster = None
background = None
2021-06-22 20:28:12 +00:00
for ad in self . asset_directory :
item_dir = None
2021-05-02 07:40:39 +00:00
if self . asset_folders :
2021-06-22 20:28:12 +00:00
if os . path . isdir ( os . path . join ( ad , name ) ) :
item_dir = os . path . join ( ad , name )
else :
2021-12-13 04:57:38 +00:00
for n in range ( 1 , self . asset_depth + 1 ) :
new_path = ad
for i in range ( 1 , n + 1 ) :
new_path = os . path . join ( new_path , " * " )
matches = util . glob_filter ( os . path . join ( new_path , name ) )
if len ( matches ) > 0 :
item_dir = os . path . abspath ( matches [ 0 ] )
break
2021-06-22 20:28:12 +00:00
if item_dir is None :
2021-05-02 07:40:39 +00:00
continue
2021-07-12 19:24:31 +00:00
found_folder = True
2021-06-22 20:28:12 +00:00
poster_filter = os . path . join ( item_dir , " poster.* " )
background_filter = os . path . join ( item_dir , " background.* " )
2021-05-02 07:40:39 +00:00
else :
2021-08-10 15:33:32 +00:00
poster_filter = os . path . join ( ad , f " { name } .* " )
background_filter = os . path . join ( ad , f " { name } _background.* " )
matches = util . glob_filter ( poster_filter )
2021-05-02 07:40:39 +00:00
if len ( matches ) > 0 :
2021-06-30 15:02:55 +00:00
poster = ImageData ( " asset_directory " , os . path . abspath ( matches [ 0 ] ) , prefix = f " { item . title } ' s " , is_url = False )
2021-08-10 15:33:32 +00:00
matches = util . glob_filter ( background_filter )
2021-05-02 07:40:39 +00:00
if len ( matches ) > 0 :
2021-06-30 15:02:55 +00:00
background = ImageData ( " asset_directory " , os . path . abspath ( matches [ 0 ] ) , prefix = f " { item . title } ' s " , is_poster = False , is_url = False )
2021-07-01 18:21:14 +00:00
if poster or background :
self . upload_images ( item , poster = poster , background = background , overlay = overlay )
2021-06-22 20:28:12 +00:00
if self . is_show :
2021-12-08 06:23:23 +00:00
missing_assets = " "
found_season = False
2021-05-02 07:40:39 +00:00
for season in self . query ( item . seasons ) :
2021-11-12 07:38:20 +00:00
season_name = f " Season { ' 0 ' if season . seasonNumber < 10 else ' ' } { season . seasonNumber } "
2021-06-22 20:28:12 +00:00
if item_dir :
2021-11-12 07:38:20 +00:00
season_poster_filter = os . path . join ( item_dir , f " { season_name } .* " )
season_background_filter = os . path . join ( item_dir , f " { season_name } _background.* " )
2021-05-02 07:40:39 +00:00
else :
2021-11-12 07:38:20 +00:00
season_poster_filter = os . path . join ( ad , f " { name } _ { season_name } .* " )
season_background_filter = os . path . join ( ad , f " { name } _ { season_name } _background.* " )
season_poster = None
season_background = None
2021-12-08 06:23:23 +00:00
matches = util . glob_filter ( season_poster_filter )
2021-05-02 07:40:39 +00:00
if len ( matches ) > 0 :
2021-06-30 15:02:55 +00:00
season_poster = ImageData ( " asset_directory " , os . path . abspath ( matches [ 0 ] ) , prefix = f " { item . title } Season { season . seasonNumber } ' s " , is_url = False )
2021-12-08 06:23:23 +00:00
found_season = True
elif season . seasonNumber > 0 :
missing_assets + = f " \n Missing Season { season . seasonNumber } Poster "
2021-11-12 07:38:20 +00:00
matches = util . glob_filter ( season_background_filter )
if len ( matches ) > 0 :
season_background = ImageData ( " asset_directory " , os . path . abspath ( matches [ 0 ] ) , prefix = f " { item . title } Season { season . seasonNumber } ' s " , is_poster = False , is_url = False )
if season_poster or season_background :
self . upload_images ( season , poster = season_poster , background = season_background )
2021-05-02 07:40:39 +00:00
for episode in self . query ( season . episodes ) :
2021-06-22 20:28:12 +00:00
if item_dir :
episode_filter = os . path . join ( item_dir , f " { episode . seasonEpisode . upper ( ) } .* " )
2021-05-02 07:40:39 +00:00
else :
2021-08-10 15:33:32 +00:00
episode_filter = os . path . join ( ad , f " { name } _ { episode . seasonEpisode . upper ( ) } .* " )
matches = util . glob_filter ( episode_filter )
2021-05-02 07:40:39 +00:00
if len ( matches ) > 0 :
2021-06-30 15:02:55 +00:00
episode_poster = ImageData ( " asset_directory " , os . path . abspath ( matches [ 0 ] ) , prefix = f " { item . title } { episode . seasonEpisode . upper ( ) } ' s " , is_url = False )
2021-06-22 20:28:12 +00:00
self . upload_images ( episode , poster = episode_poster )
2021-12-08 06:23:23 +00:00
if self . show_missing_season_assets and found_season and missing_assets :
util . print_multiline ( f " Missing Season Posters for { item . title } { missing_assets } " , info = True )
2021-07-13 18:00:09 +00:00
if not poster and overlay :
2021-07-06 13:55:52 +00:00
self . upload_images ( item , overlay = overlay )
2021-08-02 19:00:15 +00:00
if create and self . asset_folders and not found_folder :
os . makedirs ( os . path . join ( self . asset_directory [ 0 ] , name ) , exist_ok = True )
logger . info ( f " Asset Directory Created: { os . path . join ( self . asset_directory [ 0 ] , name ) } " )
elif not overlay and self . asset_folders and not found_folder :
2021-07-01 18:21:14 +00:00
logger . error ( f " Asset Warning: No asset folder found called ' { name } ' " )
2021-11-16 15:07:09 +00:00
elif not poster and not background and self . show_missing_assets :
2021-07-13 18:00:09 +00:00
logger . error ( f " Asset Warning: No poster or background found in an assets folder for ' { name } ' " )