diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index d34ee40f..bf462757 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -181,14 +181,16 @@ jobs: env: PLEXAPI_PLEXAPI_TIMEOUT: "60" id: bootstrap - uses: LizardByte/plexhints@v2023.1226.203406 + uses: LizardByte/plexhints@v2024.129.31313 with: - additional_server_queries_put: >- - /system/agents/com.plexapp.agents.imdb/config/1?order=com.plexapp.agents.imdb%2Cdev.lizardbyte.themerr-plex - /system/agents/com.plexapp.agents.themoviedb/config/1?order=com.plexapp.agents.themoviedb%2Cdev.lizardbyte.themerr-plex + additional_server_queries: >- + put|/system/agents/com.plexapp.agents.imdb/config/1?order=com.plexapp.agents.imdb%2Cdev.lizardbyte.themerr-plex + put|/system/agents/com.plexapp.agents.themoviedb/config/1?order=com.plexapp.agents.themoviedb%2Cdev.lizardbyte.themerr-plex + put|/system/agents/com.plexapp.agents.themoviedb/config/2?order=com.plexapp.agents.themoviedb%2Cdev.lizardbyte.themerr-plex + put|/system/agents/com.plexapp.agents.thetvdb/config/2?order=com.plexapp.agents.thetvdb%2Cdev.lizardbyte.themerr-plex + get|/:/plugins/dev.lizardbyte.themerr-plex/prefs/set?bool_overwrite_plex_provided_themes=true plugin_bundles_to_install: >- Themerr-plex.bundle - without_shows: true without_music: true without_photos: true @@ -211,7 +213,6 @@ jobs: run: | python -m pytest \ -rxXs \ - --maxfail=1 \ --tb=native \ --verbose \ --cov=Contents/Code \ diff --git a/Contents/Code/__init__.py b/Contents/Code/__init__.py index 90199529..f56d677d 100644 --- a/Contents/Code/__init__.py +++ b/Contents/Code/__init__.py @@ -18,12 +18,12 @@ from plexhints.decorator_kit import handler # decorator kit from plexhints.locale_kit import Locale from plexhints.log_kit import Log # log kit - from plexhints.model_kit import Movie # model kit + from plexhints.model_kit import MetadataModel # model kit from plexhints.object_kit import MessageContainer, MetadataSearchResult, SearchResult # object kit from plexhints.prefs_kit import Prefs # prefs kit # imports from Libraries\Shared -from typing import Optional +from typing import Optional, Union try: # get the original Python builtins module @@ -195,9 +195,9 @@ def Start(): start_queue_threads() # start queue threads Log.Debug('queue threads started.') - if Prefs['bool_plex_movie_support']: + if Prefs['bool_plex_movie_support'] or Prefs['bool_plex_series_support']: plex_listener() # start watching plex - Log.Debug('plex_listener started, watching for activity from new Plex Movie agent.') + Log.Debug('plex_listener started, watching for activity from new Plex agents.') setup_scheduling() # start scheduled tasks Log.Debug('scheduled tasks started.') @@ -216,9 +216,9 @@ def main(): pass -class Themerr(Agent.Movies): +class Themerr(object): """ - Class representing the Themerr-plex Movie Agent. + Class representing the Themerr-plex Agent. This class defines the metadata agent. See the archived Plex documentation `Defining an agent class @@ -270,9 +270,12 @@ class Themerr(Agent.Movies): accepts_from = [] contributes_to = contributes_to - @staticmethod - def search(results, media, lang, manual): - # type: (SearchResult, Media.Movie, str, bool) -> Optional[SearchResult] + def __init__(self, *args, **kwargs): + super(Themerr, self).__init__(*args, **kwargs) + self.agent_type = "movies" if isinstance(self, Agent.Movies) else "tv_shows" + + def search(self, results, media, lang, manual): + # type: (SearchResult, Union[Media.Movie, Media.TV_Show], str, bool) -> Optional[SearchResult] """ Search for an item. @@ -286,7 +289,7 @@ def search(results, media, lang, manual): ---------- results : SearchResult An empty container that the developer should populate with potential matches. - media : Media.Movie + media : Union[Media.Movie, Media.TV_Show] An object containing hints to be used when performing the search. lang : str A string identifying the user’s currently selected language. This will be one of the constants added to the @@ -319,14 +322,18 @@ def search(results, media, lang, manual): if media.primary_agent == 'dev.lizardbyte.retroarcher-plex': media_id = 'games-%s' % re.search(r'((igdb)-(\d+))', media.primary_metadata.id).group(1) else: - media_id = 'movies-%s-%s' % (media.primary_agent.rsplit('.', 1)[-1], media.primary_metadata.id) + media_id = '{}-{}-{}'.format( + self.agent_type, + media.primary_agent.rsplit('.', 1)[-1], + media.primary_metadata.id + ) # e.g. = 'movies-imdb-tt0113189' # e.g. = 'movies-themoviedb-710' results.Append(MetadataSearchResult( id=media_id, name=media.primary_metadata.title, - year=media.primary_metadata.year, + year=getattr(media.primary_metadata, 'year', None), # TV Shows don't have a year attribute score=100, lang=lang, # no lang to get from db thumb=None # no point in adding thumb since plex won't show it anywhere @@ -339,7 +346,7 @@ def search(results, media, lang, manual): @staticmethod def update(metadata, media, lang, force): - # type: (Movie, Media.Movie, str, bool) -> Optional[Movie] + # type: (MetadataModel, Union[Media.Movie, Media.TV_Show], str, bool) -> MetadataModel """ Update metadata for an item. @@ -351,10 +358,10 @@ def update(metadata, media, lang, force): Parameters ---------- - metadata : object + metadata : MetadataModel A pre-initialized metadata object if this is the first time the item is being updated, or the existing metadata object if the item is being refreshed. - media : object + media : Union[Media.Movie, Media.TV_Show] An object containing information about the media hierarchy in the database. lang : str A string identifying which language should be used for the metadata. This will be one of the constants @@ -363,6 +370,11 @@ def update(metadata, media, lang, force): A boolean value identifying whether the user forced a full refresh of the metadata. If this argument is ``True``, all metadata should be refreshed, regardless of whether it has been populated previously. + Returns + ------- + MetadataModel + The metadata object. + Examples -------- >>> Themerr().update(metadata=..., media=..., lang='en', force=True) @@ -375,3 +387,11 @@ def update(metadata, media, lang, force): update_plex_item(rating_key=rating_key) return metadata + + +class ThemerrMovies(Themerr, Agent.Movies): + agent_type_verbose = "Movies" + + +class ThemerrTvShows(Themerr, Agent.TV_Shows): + agent_type_verbose = "TV" diff --git a/Contents/Code/constants.py b/Contents/Code/constants.py index b5ae204f..98e28b9f 100644 --- a/Contents/Code/constants.py +++ b/Contents/Code/constants.py @@ -41,11 +41,12 @@ themerr_data_directory = os.path.join(plugin_support_data_directory, plugin_identifier, 'DataItems') contributes_to = [ - 'tv.plex.agents.movie', - 'com.plexapp.agents.imdb', - 'com.plexapp.agents.themoviedb', - # 'com.plexapp.agents.thetvdb', # not available as movie agent - 'dev.lizardbyte.retroarcher-plex' + 'tv.plex.agents.movie', # new movie agent + 'tv.plex.agents.series', # new tv show agent + 'com.plexapp.agents.imdb', # legacy movie agent + 'com.plexapp.agents.themoviedb', # legacy movie and tv show agent + 'com.plexapp.agents.thetvdb', # legacy tv show agent + 'dev.lizardbyte.retroarcher-plex' # retroarcher plugin ] guid_map = dict( @@ -85,6 +86,7 @@ game_franchises='[GAME FRANCHISE]: ', movies='[MOVIE]: ', movie_collections='[MOVIE COLLECTION]: ', + tv_shows='[TV SHOW]: ', ) url_prefix = dict( games='https://www.igdb.com/games/', @@ -92,6 +94,7 @@ game_franchises='https://www.igdb.com/franchises/', movies='https://www.themoviedb.org/movie/', movie_collections='https://www.themoviedb.org/collection/', + tv_shows='https://www.themoviedb.org/tv/', ) # two additional strings to fill in later, item title and item url @@ -109,6 +112,8 @@ movie_collections='{}&labels={}&template={}&title={}{}&{}={}{}'.format( base_url, issue_label, issue_template, title_prefix['movie_collections'], '{}', url_name, url_prefix['movie_collections'], '{}'), + tv_shows='{}&labels={}&template={}&title={}{}&{}={}{}'.format( + base_url, issue_label, issue_template, title_prefix['tv_shows'], '{}', url_name, url_prefix['tv_shows'], '{}'), ) media_type_dict = dict( diff --git a/Contents/Code/default_prefs.py b/Contents/Code/default_prefs.py index 360079df..abc561ac 100644 --- a/Contents/Code/default_prefs.py +++ b/Contents/Code/default_prefs.py @@ -2,12 +2,15 @@ default_prefs = dict( bool_plex_movie_support='True', + bool_plex_series_support='True', + bool_overwrite_plex_provided_themes='False', bool_prefer_mp4a_codec='True', bool_remove_unused_theme_songs='True', bool_remove_unused_art='False', bool_remove_unused_posters='False', bool_auto_update_items='True', bool_auto_update_movie_themes='True', + bool_auto_update_tv_themes='True', bool_auto_update_collection_themes='True', bool_update_collection_metadata_plex_movie='False', bool_update_collection_metadata_legacy='True', diff --git a/Contents/Code/general_helper.py b/Contents/Code/general_helper.py index c42f98ad..e252962c 100644 --- a/Contents/Code/general_helper.py +++ b/Contents/Code/general_helper.py @@ -17,6 +17,9 @@ from plexhints.parse_kit import XML # parse kit from plexhints.prefs_kit import Prefs # prefs kit +# imports from Libraries\Shared +from plexapi.base import PlexPartialObject +from typing import Optional # local imports from constants import ( @@ -34,6 +37,36 @@ ] +def _get_metadata_path(item): + # type: (PlexPartialObject) -> str + """ + Get the metadata path of the item. + + Get the hashed path of the metadata directory for the item specified by the ``item``. + + Parameters + ---------- + item : PlexPartialObject + The item to get the theme upload path for. + + Returns + ------- + str + The path to the metadata directory. + + Examples + -------- + >>> _get_metadata_path(item=...) + "...bundle" + """ + guid = item.guid + full_hash = hashlib.sha1(guid).hexdigest() + metadata_path = os.path.join( + metadata_base_directory, metadata_type_map[item.type], + full_hash[0], full_hash[1:] + '.bundle') + return metadata_path + + def agent_enabled(item_agent, item_type): # type: (str, str) -> bool """ @@ -102,6 +135,8 @@ def continue_update(item_agent, item_type): -------- >>> continue_update(item_agent='tv.plex.agents.movie', item_type='movie') True + >>> continue_update(item_agent='tv.plex.agents.series', item_type='show') + True >>> continue_update(item_agent='com.plexapp.agents.imdb', item_type='movie') True >>> continue_update(item_agent='com.plexapp.agents.themoviedb', item_type='movie') @@ -115,6 +150,8 @@ def continue_update(item_agent, item_type): """ if item_agent == 'tv.plex.agents.movie': return Prefs['bool_plex_movie_support'] + elif item_agent == 'tv.plex.agents.series': + return Prefs['bool_plex_series_support'] elif item_agent in contributes_to: return agent_enabled(item_agent=item_agent, item_type=item_type) else: @@ -122,7 +159,7 @@ def continue_update(item_agent, item_type): def get_media_upload_path(item, media_type): - # type: (any, str) -> str + # type: (PlexPartialObject, str) -> str """ Get the path to the theme upload directory. @@ -130,7 +167,7 @@ def get_media_upload_path(item, media_type): Parameters ---------- - item : any + item : PlexPartialObject The item to get the theme upload path for. media_type : str The media type to get the theme upload path for. Must be one of 'art', 'posters', or 'themes'. @@ -161,16 +198,73 @@ def get_media_upload_path(item, media_type): 'media_type must be one of: {}'.format(allowed_media_types) ) - guid = item.guid - full_hash = hashlib.sha1(guid).hexdigest() - theme_upload_path = os.path.join( - metadata_base_directory, metadata_type_map[item.type], - full_hash[0], full_hash[1:] + '.bundle', 'Uploads', media_type) + theme_upload_path = os.path.join(_get_metadata_path(item=item), 'Uploads', media_type) return theme_upload_path +def get_theme_provider(item): + # type: (PlexPartialObject) -> Optional[str] + """ + Get the theme provider. + + Get the theme provider for the item specified by the ``item``. + + Parameters + ---------- + item : PlexPartialObject + The item to get the theme provider for. + + Returns + ------- + str + The theme provider. + + Examples + -------- + >>> get_theme_provider(item=...) + ... + """ + provider_map = { + 'local': 'user', # new agents, local media + 'com.plexapp.agents.localmedia': 'user', # legacy agents, local media + 'com.plexapp.agents.plexthememusic': 'plex', # legacy agents + } + + rating_key_map = { + 'metadata://themes/tv.plex.agents.movies_': 'plex', # new movie agent (placeholder if Plex adds theme support) + 'metadata://themes/tv.plex.agents.series_': 'plex', # new tv agent + 'metadata://themes/com.plexapp.agents.plexthememusic_': 'plex', # legacy agents + } + + if not item.themes(): + return + + provider = None + + selected = (theme for theme in item.themes() if theme.selected).next() + + if selected.provider in provider_map.keys(): + provider = provider_map[selected.provider] + elif selected.ratingKey.startswith(tuple(rating_key_map.keys())): + # new agents do not list a provider, so must match with rating keys if the theme + + # find the rating key prefix in the rating key map + for rating_key_prefix in rating_key_map.keys(): + if selected.ratingKey.startswith(rating_key_prefix): + provider = rating_key_map[rating_key_prefix] + break + else: + provider = selected.provider + + if not provider: + themerr_data = get_themerr_json_data(item=item) + provider = 'themerr' if themerr_data else None + + return provider + + def get_themerr_json_path(item): - # type: (any) -> str + # type: (PlexPartialObject) -> str """ Get the path to the Themerr data file. @@ -178,7 +272,7 @@ def get_themerr_json_path(item): Parameters ---------- - item : any + item : PlexPartialObject The item to get the Themerr data file path for. Returns @@ -197,7 +291,7 @@ def get_themerr_json_path(item): def get_themerr_json_data(item): - # type: (any) -> dict + # type: (PlexPartialObject) -> dict """ Get the Themerr data for the specified item. @@ -206,7 +300,7 @@ def get_themerr_json_data(item): Parameters ---------- - item : any + item : PlexPartialObject The item to get the Themerr data for. Returns @@ -249,7 +343,7 @@ def get_themerr_settings_hash(): def remove_uploaded_media(item, media_type): - # type: (any, str) -> None + # type: (PlexPartialObject, str) -> None """ Remove themes for the specified item. @@ -257,7 +351,7 @@ def remove_uploaded_media(item, media_type): Parameters ---------- - item : any + item : PlexPartialObject The item to remove the themes from. media_type : str The media type to remove the themes from. Must be one of 'art', 'posters', or 'themes'. @@ -297,7 +391,7 @@ def remove_uploaded_media_error_handler(func, path, exc_info): def update_themerr_data_file(item, new_themerr_data): - # type: (any, dict) -> None + # type: (PlexPartialObject, dict) -> None """ Update the Themerr data file for the specified item. @@ -305,7 +399,7 @@ def update_themerr_data_file(item, new_themerr_data): Parameters ---------- - item : any + item : PlexPartialObject The item to update the Themerr data file for. new_themerr_data : dict The Themerr data to update the Themerr data file with. diff --git a/Contents/Code/plex_api_helper.py b/Contents/Code/plex_api_helper.py index 08460b0b..3ea0fd47 100644 --- a/Contents/Code/plex_api_helper.py +++ b/Contents/Code/plex_api_helper.py @@ -183,6 +183,11 @@ def update_plex_item(rating_key): if item.isLocked(field='theme') and not Prefs['bool_ignore_locked_fields']: Log.Debug('Not overwriting locked theme for {}: {}'.format(item.type, item.title)) + elif ( + not Prefs['bool_overwrite_plex_provided_themes'] and + general_helper.get_theme_provider(item=item) == 'plex' + ): + Log.Debug('Not overwriting Plex provided theme for {}: {}'.format(item.type, item.title)) else: # get youtube_url try: @@ -195,7 +200,7 @@ def update_plex_item(rating_key): try: skip = themerr_data['settings_hash'] == settings_hash \ - and themerr_data[media_type_dict['themes']['themerr_data_key']] == yt_video_url + and themerr_data[media_type_dict['themes']['themerr_data_key']] == yt_video_url except KeyError: skip = False @@ -414,7 +419,7 @@ def upload_media(item, method, filepath=None, url=None): else: method(url=url) except BadRequest as e: - sleep_time = 2**count + sleep_time = 2 ** count Log.Error('%s: Error uploading media: %s' % (item.ratingKey, e)) Log.Error('%s: Trying again in : %s' % (item.ratingKey, sleep_time)) time.sleep(sleep_time) @@ -491,6 +496,48 @@ def get_database_info(item): database = 'imdb' database_id = item.guid.split('://')[1].split('?')[0] + elif item.type == 'show': + database_type = 'tv_shows' + + if item.guids: # guids is a blank list for items from legacy agents, only available for new agent items + agent = 'tv.plex.agents.series' + for guid in item.guids: + split_guid = guid.id.split('://') + temp_database = guid_map[split_guid[0]] + temp_database_id = split_guid[1] + + if temp_database == 'imdb' or temp_database == 'thetvdb': + database_id = tmdb_helper.get_tmdb_id_from_external_id( + external_id=temp_database_id, + database=split_guid[0], + item_type='tv', + ) + if database_id: + database = 'themoviedb' + break + + if temp_database == 'themoviedb': # tmdb is our prefered db, so we break if found + database_id = temp_database_id + database = temp_database + break + elif item.guid: + split_guid = item.guid.split('://') + agent = split_guid[0] + if agent == 'com.plexapp.agents.themoviedb': + database = 'themoviedb' + database_id = item.guid.split('://')[1].split('?')[0] + elif agent == 'com.plexapp.agents.thetvdb': + temp_database = 'thetvdb' + temp_database_id = item.guid.split('://')[1].split('?')[0] + + # ThemerrDB does not have TVDB IDs, so we need to convert it to TMDB ID + database_id = tmdb_helper.get_tmdb_id_from_external_id( + external_id=temp_database_id, + database='tvdb', + item_type='tv', + ) + database = 'themoviedb' if database_id else None + elif item.type == 'collection': # this is tricky since collections don't match up with any of the databases # we'll use the collection title and try to find a match @@ -635,11 +682,16 @@ def plex_listener_handler(data): # known search types: # https://github.com/pkkid/python-plexapi/blob/8b3235445f6b3051c39ff6d6fc5d49f4e674d576/plexapi/utils.py#L35-L55 - if (reverseSearchType(libtype=entry['type']) == 'movie' - and entry['state'] == 5 - and entry['identifier'] == 'com.plexapp.plugins.library'): + if ( + ( + (reverseSearchType(libtype=entry['type']) == 'movie' and Prefs['bool_plex_movie_support']) or + (reverseSearchType(libtype=entry['type']) == 'show' and Prefs['bool_plex_series_support']) + ) and + entry['state'] == 5 and + entry['identifier'] == 'com.plexapp.plugins.library' + ): # identifier always appears to be `com.plexapp.plugins.library` for updating library metadata - # entry['title'] = movie title + # entry['title'] = item title # entry['itemID'] = rating key rating_key = int(entry['itemID']) @@ -689,15 +741,20 @@ def scheduled_update(): Log.Debug('Themerr-plex is disabled for agent "{}"'.format(section.agent)) continue + all_items = [] + # get all the items in the section - media_items = section.all() if Prefs['bool_auto_update_movie_themes'] else [] + if section.type == 'movie': + media_items = section.all() if Prefs['bool_auto_update_movie_themes'] else [] - # get all collections in the section - collections = section.collections() if Prefs['bool_auto_update_collection_themes'] else [] + # get all collections in the section + collections = section.collections() if Prefs['bool_auto_update_collection_themes'] else [] - # combine the items and collections into one list - # this is done so that we can process both items and collections in the same loop - all_items = media_items + collections + # combine the items and collections into one list + # this is done so that we can process both items and collections in the same loop + all_items = media_items + collections + elif section.type == 'show': + all_items = section.all() if Prefs['bool_auto_update_tv_themes'] else [] for item in all_items: if item.ratingKey not in q.queue: diff --git a/Contents/Code/themerr_db_helper.py b/Contents/Code/themerr_db_helper.py index 46822e63..535857f2 100644 --- a/Contents/Code/themerr_db_helper.py +++ b/Contents/Code/themerr_db_helper.py @@ -25,6 +25,7 @@ game_franchises={'igdb': 'id'}, movies={'themoviedb': 'id', 'imdb': 'imdb_id'}, movie_collections={'themoviedb': 'id'}, + tv_shows={'themoviedb': 'id'}, ) lock = Lock() diff --git a/Contents/Code/tmdb_helper.py b/Contents/Code/tmdb_helper.py index 0b2515ca..e4ae9874 100644 --- a/Contents/Code/tmdb_helper.py +++ b/Contents/Code/tmdb_helper.py @@ -12,14 +12,14 @@ from plexhints.util_kit import String # util kit # imports from Libraries\Shared -from typing import Optional +from typing import Optional, Union # url borrowed from TheMovieDB.bundle tmdb_base_url = 'http://127.0.0.1:32400/services/tmdb?uri=' -def get_tmdb_id_from_imdb_id(imdb_id): - # type: (str) -> Optional[int] +def get_tmdb_id_from_external_id(external_id, database, item_type): + # type: (Union[int, str], str, str) -> Optional[int] """ Convert IMDB ID to TMDB ID. @@ -27,8 +27,12 @@ def get_tmdb_id_from_imdb_id(imdb_id): Parameters ---------- - imdb_id : str - IMDB ID to convert. + external_id : Union[int, str] + External ID to convert. + database : str + Database to search. Must be one of 'imdb' or 'tvdb'. + item_type : str + Item type to search. Must be one of 'movie' or 'tv'. Returns ------- @@ -37,25 +41,38 @@ def get_tmdb_id_from_imdb_id(imdb_id): Examples -------- - >>> get_tmdb_id_from_imdb_id(imdb_id='tt1254207') + >>> get_tmdb_id_from_external_id(imdb_id='tt1254207', database='imdb', item_type='movie') 10378 + >>> get_tmdb_id_from_external_id(imdb_id='268592', database='tvdb', item_type='tv') + 48866 """ - # according to https://www.themoviedb.org/talk/5f6a0500688cd000351c1712 we can search by imdb id + if database.lower() not in ['imdb', 'tvdb']: + Log.Exception('Invalid database: {}'.format(database)) + return + if item_type.lower() not in ['movie', 'tv']: + Log.Exception('Invalid item type: {}'.format(item_type)) + return + + # according to https://www.themoviedb.org/talk/5f6a0500688cd000351c1712 we can search by external id # https://api.themoviedb.org/3/find/tt0458290?api_key=###&external_source=imdb_id - find_imdb_item = 'find/{}?external_source=imdb_id' + find_url_suffix = 'find/{}?external_source={}_id' - url = '{}/{}'.format(tmdb_base_url, find_imdb_item.format(String.Quote(s=imdb_id, usePlus=True))) + url = '{}/{}'.format( + tmdb_base_url, + find_url_suffix.format(String.Quote(s=str(external_id), usePlus=True), database.lower()) + ) try: tmdb_data = JSON.ObjectFromURL( url=url, sleep=2.0, headers=dict(Accept='application/json'), cacheTime=CACHE_1DAY, errors='strict') except Exception as e: - Log.Debug('Error converting IMDB ID to TMDB ID: {}'.format(e)) + Log.Debug('Error converting external ID to TMDB ID: {}'.format(e)) else: Log.Debug('TMDB data: {}'.format(tmdb_data)) try: - tmdb_id = int(tmdb_data['movie_results'][0]['id']) # this is already an integer, but let's force it + # this is already an integer, but let's force it + tmdb_id = int(tmdb_data['{}_results'.format(item_type.lower())][0]['id']) except (IndexError, KeyError, ValueError): - Log.Debug('Error converting IMDB ID to TMDB ID: {}'.format(tmdb_data)) + Log.Debug('Error converting external ID to TMDB ID: {}'.format(tmdb_data)) else: return tmdb_id diff --git a/Contents/Code/webapp.py b/Contents/Code/webapp.py index 1998970f..a07f30e6 100644 --- a/Contents/Code/webapp.py +++ b/Contents/Code/webapp.py @@ -268,7 +268,8 @@ def cache_data(): or database_id.startswith('tt') ): # try to get tmdb id from imdb id - tmdb_id = tmdb_helper.get_tmdb_id_from_imdb_id(imdb_id=database_id) + tmdb_id = tmdb_helper.get_tmdb_id_from_external_id( + external_id=database_id, database='imdb', item_type='movie') database_id = tmdb_id if tmdb_id else None item_issue_url = None @@ -297,6 +298,8 @@ def cache_data(): database_id = db_data['slug'] else: issue_title = '{} ({})'.format(getattr(item, "originalTitle", None) or item.title, year) + elif item.type == 'show': + issue_title = '{} ({})'.format(item.title, year) else: # collections issue_title = item.title @@ -334,24 +337,12 @@ def cache_data(): if item.theme: theme_status = 'complete' - - selected = (theme for theme in item.themes() if theme.selected).next() - user_provided = (getattr(selected, 'provider', None) == 'local') - - if user_provided: - themerr_provided = False - else: - themerr_data = general_helper.get_themerr_json_data(item=item) - themerr_provided = True if themerr_data else False else: if issue_action == 'edit': theme_status = 'failed' else: theme_status = 'missing' - user_provided = False - themerr_provided = False - items[section.key]['items'].append(dict( title=item.title, agent=item_agent, @@ -361,10 +352,9 @@ def cache_data(): issue_action=issue_action, issue_url=item_issue_url, theme=True if item.theme else False, + theme_provider=general_helper.get_theme_provider(item=item), theme_status=theme_status, - themerr_provided=themerr_provided, type=item.type, - user_provided=user_provided, year=year, )) diff --git a/Contents/DefaultPrefs.json b/Contents/DefaultPrefs.json index 9ccf787c..deaec6b7 100644 --- a/Contents/DefaultPrefs.json +++ b/Contents/DefaultPrefs.json @@ -6,6 +6,20 @@ "default": "True", "secure": "false" }, + { + "id": "bool_plex_series_support", + "type": "bool", + "label": "Plex Series agent support (Add themes to the updated Plex Series agent)", + "default": "True", + "secure": "false" + }, + { + "id": "bool_overwrite_plex_provided_themes", + "type": "bool", + "label": "Overwrite Plex provided themes", + "default": "False", + "secure": "false" + }, { "id": "bool_prefer_mp4a_codec", "type": "bool", @@ -48,6 +62,13 @@ "default": "True", "secure": "false" }, + { + "id": "bool_auto_update_tv_themes", + "type": "bool", + "label": "Update tv show themes during automatic update", + "default": "True", + "secure": "false" + }, { "id": "bool_auto_update_collection_themes", "type": "bool", diff --git a/Contents/Resources/web/templates/home.html b/Contents/Resources/web/templates/home.html index f32c5350..4c5ba1f5 100644 --- a/Contents/Resources/web/templates/home.html +++ b/Contents/Resources/web/templates/home.html @@ -136,10 +136,14 @@