import json
from urllib.parse import quote
from lib.api.trakt.trakt_utils import add_trakt_watched_context_menu, is_trakt_auth
from lib.clients.tmdb.utils.utils import (
add_tmdb_episode_context_menu,
add_tmdb_show_context_menu,
tmdb_get,
)
from lib.utils.general.utils import (
execute_thread_pool_collection,
get_fanart_details,
set_content_type,
set_media_infoTag,
)
from lib.utils.kodi.utils import (
add_directory_items_batch,
apply_section_view,
build_url,
end_of_directory,
get_setting,
kodilog,
make_list_item,
)
def show_seasons_details(params):
set_content_type("season")
ids = json.loads(params.get("ids", "{}"))
mode = params.get("mode", "")
media_type = params.get("media_type", "")
show_season_info(ids, mode, media_type)
end_of_directory()
apply_section_view("view.seasons", content_type="seasons")
def show_season_info(ids, mode, media_type):
tmdb_id = ids.get("tmdb_id")
tvdb_id = ids.get("tvdb_id")
imdb_id = ids.get("imdb_id")
if imdb_id:
res = tmdb_get("find_by_imdb_id", imdb_id)
if res and res.get("tv_results"):
tmdb_id = res["tv_results"][0]["id"]
ids = {"tmdb_id": tmdb_id, "tvdb_id": tvdb_id, "imdb_id": imdb_id}
details = tmdb_get("tv_details", tmdb_id)
name = details.name
seasons = details.seasons
fanart_details = get_fanart_details(tvdb_id=tvdb_id, mode=mode)
results = execute_thread_pool_collection(
seasons,
_process_season,
details,
name,
ids,
mode,
media_type,
fanart_details,
)
# Sort by season number
results.sort(key=lambda x: x[0])
add_directory_items_batch(
[(url, list_item, True) for _, url, list_item in results if list_item is not None]
)
def _process_season(season, details, name, ids, mode, media_type, fanart_details):
season_name = season.name
overview = season.overview
if not overview:
season.update({"overview": getattr(details, "overview", "")})
if "Miniseries" in season_name:
season_name = "Season 1"
season_number = season.season_number
if season_number == 0 and not get_setting("include_tvshow_specials"):
return # skip specials if disabled
list_item = make_list_item(label=season_name)
set_media_infoTag(list_item, data=season, fanart_data=fanart_details, mode="season")
list_item.setProperty("IsPlayable", "false")
context_menu = add_tmdb_show_context_menu(mode, ids)
if is_trakt_auth():
context_menu += add_trakt_watched_context_menu("shows", season=season_number, ids=ids)
list_item.addContextMenuItems(context_menu)
url = build_url(
"show_episodes_details",
tv_name=name,
ids=ids,
mode=mode,
media_type=media_type,
season=season_number,
)
return (season_number, url, list_item)
def show_episodes_details(params):
set_content_type("episode")
tv_name = params.get("tv_name", "")
season = int(params.get("season", 1))
ids = json.loads(params.get("ids", "{}"))
mode = params.get("mode", "")
media_type = params.get("media_type", "")
kodilog(
f"[EPISODES] show_episodes_details: tv_name={tv_name!r}, season={season}, "
f"mode={mode!r}, media_type={media_type!r}, ids={ids}"
)
item_count = show_episode_info(tv_name, season, ids, mode, media_type)
kodilog(f"[EPISODES] show_episodes_details: added item_count={item_count}")
end_of_directory()
kodilog("[EPISODES] show_episodes_details: end_of_directory called")
apply_section_view("view.episodes", content_type="episodes")
def show_episode_info(tv_name, season, ids, mode, media_type):
season_details = tmdb_get("season_details", {"id": ids.get("tmdb_id"), "season": season})
if not season_details:
kodilog(
f"[EPISODES] show_episode_info: no season_details for "
f"tmdb_id={ids.get('tmdb_id')}, season={season}"
)
return 0
episodes = getattr(season_details, "episodes", []) or []
kodilog(
f"[EPISODES] show_episode_info: fetched episodes_count={len(episodes)} "
f"for tmdb_id={ids.get('tmdb_id')}, season={season}"
)
fanart_details = get_fanart_details(tvdb_id=ids.get("tvdb_id"), mode=mode)
results = execute_thread_pool_collection(
episodes,
_process_episode,
tv_name,
season,
ids,
mode,
media_type,
fanart_details,
)
# Sort by episode number
results.sort(key=lambda x: x[0])
item_count = len([list_item for _, _, list_item in results if list_item is not None])
kodilog(
f"[EPISODES] show_episode_info: processed results_count={len(results)}, "
f"item_count={item_count}"
)
add_directory_items_batch(
[(url, list_item, False) for _, url, list_item in results if list_item is not None]
)
return item_count
def _process_episode(episode, tv_name, season, ids, mode, media_type, fanart_details):
ep_name = episode.name
episode_number = episode.episode_number
tv_data = {"name": quote(ep_name), "episode": episode_number, "season": season}
list_item = make_list_item(label=f"{season}x{episode_number}. {ep_name}")
list_item.setProperty("IsPlayable", "true")
set_media_infoTag(list_item, data=episode, fanart_data=fanart_details, mode="episode")
context_menu = add_tmdb_episode_context_menu(mode, tv_name, tv_data, ids)
if is_trakt_auth():
context_menu += add_trakt_watched_context_menu(
"shows", season=season, episode=episode_number, ids=ids
)
list_item.addContextMenuItems(context_menu)
url = build_url(
"search",
mode=mode,
media_type=media_type,
query=tv_name,
ids=ids,
tv_data=tv_data,
)
return (episode_number, url, list_item)