import sys
from threading import Thread
from indexers.metadata import tvshow_meta, season_episodes_meta, all_episodes_meta, tmdb_image_base
from caches.favourites_cache import favourites_context_label, favourites_cache, favourite_type_from_context, season_favourite_type_from_tv, episode_favourite_type_from_tv, tv_favourite_type_from_child
from caches.watched_cache import get_watched_info_tv, get_watched_status_season, get_bookmarks, get_resumetime, set_resumetime, get_watched_status_episode
from modules import kodi_utils, settings, user_ratings
from modules.utils import adjust_premiered_date, get_datetime
# from modules.kodi_utils import logger

tv_meta_function, season_meta_function, default_duration = tvshow_meta, season_episodes_meta, 3600
KODI_VERSION, make_cast_list = kodi_utils.get_kodi_version(), kodi_utils.make_cast_list
string, ls, build_url = str, kodi_utils.local_string, kodi_utils.build_url
remove_meta_keys, dict_removals = kodi_utils.remove_meta_keys, kodi_utils.episode_dict_removals
get_art_provider, show_specials = settings.get_art_provider, settings.show_specials
adjust_premiered_date_function, get_datetime_function = adjust_premiered_date, get_datetime
run_plugin, container_refresh, container_update = 'RunPlugin(%s)', 'Container.Refresh(%s)', 'Container.Update(%s)'
fanart_empty = ''
poster_empty = kodi_utils.media_path('box_office.png')
watched_str, unwatched_str, extras_str, options_str = ls(32642), ls(32643), 'Info & Extra', 'Options (alkoFlix)'
trailer_str = 'Bande annonce'
clearprog_str, season_str, unaired_label = ls(32651), ls(32537), '[COLOR cyan]%s[/COLOR]'

# Récupère un visuel Fanart.tv propre à une saison, si disponible.
def get_season_specific_art(meta, key, season_number):
	try:
		items = meta.get(key) or {}
		season_key = string(season_number)
		return items.get(season_key) or items.get(season_key.zfill(2)) or ''
	except:
		return ''

# Détermine les visuels à utiliser pour une saison en respectant le fournisseur choisi.
def get_season_art(meta, season_data, season_number, image_resolution, poster_main, fanart_enabled, show_poster, show_landscape, fanart):
	season_poster_fanart = get_season_specific_art(meta, 'season_posters', season_number)
	season_poster_fanart_text = get_season_specific_art(meta, 'season_posters_text', season_number)
	season_landscape_fanart = get_season_specific_art(meta, 'season_landscapes', season_number)
	season_landscape_fanart_text = get_season_specific_art(meta, 'season_landscapes_text', season_number)
	poster_path = season_data.get('poster_path')
	season_poster_tmdb = tmdb_image_base % (image_resolution, poster_path) if poster_path else ''

	# Si Fanart.tv est choisi par défaut, on privilégie d'abord les visuels
	# textuels Fanart.tv, puis TMDb textuel, avant de retomber sur les versions
	# neutres/sans texte.
	if fanart_enabled and poster_main == 'poster2':
		show_landscape_text = meta.get('landscape_text') or meta.get('landscape_tmdb_text') or ''
		show_landscape_full = settings.resolve_landscape_art(meta, fanart or show_poster)
		poster = season_poster_fanart_text or season_poster_tmdb or season_poster_fanart or show_poster
		landscape = season_landscape_fanart_text or show_landscape_text or season_landscape_fanart or show_landscape_full or fanart or poster
	else:
		poster = season_poster_tmdb or season_poster_fanart or season_poster_fanart_text or show_poster
		landscape = show_landscape or season_landscape_fanart or season_landscape_fanart_text or fanart or poster
	return poster, landscape

class Seasons:
	def __init__(self, params):
		self.params = params
		self.items = []
		self.append = self.items.append
		self.current_date = get_datetime_function()
		self.meta_user_info = settings.metadata_user_info()
		try: self.watched_indicators = int(self.params.get('watched_indicators', settings.watched_indicators()))
		except: self.watched_indicators = settings.watched_indicators()
		self.hide_watched_items = self.params.get('hide_watched_items', 'false') == 'true'
		self.watched_info = get_watched_info_tv(self.watched_indicators)
		self.watched_title = ('alkoFlix', 'Trakt', 'MDBList')[self.watched_indicators]
		self.show_unaired = settings.show_unaired()
		self.is_widget = kodi_utils.external_browse()
		self.fanart_enabled = self.meta_user_info['extra_fanart_enabled']
		self.widget_hide_watched = self.is_widget and self.meta_user_info['widget_hide_watched']
		self.menu_hide_watched = (not self.is_widget) and self.meta_user_info.get('menu_hide_watched', False) and self.params.get('ignore_menu_hide_watched') != 'true'
		self.poster_main, self.poster_backup, self.fanart_main, self.fanart_backup = get_art_provider()
		self.catalogue_id = self.params.get('catalogue_id') or self.params.get('catalog_id') or ''
		self.user_ratings = user_ratings.get_active_ratings_index()

	def build_season_list(self, params):
		def _process_season_list():
			use_season_title = settings.use_season_title()
			image_resolution = self.meta_user_info['image_resolution']['poster']
			season_data = meta_get('season_data')
			if season_data:
				if 'season' in params:
					try: selected_season = int(params['season'])
					except: selected_season = params['season']
					season_data = [i for i in season_data if i['season_number'] == selected_season]
				if not show_specials(): season_data = [i for i in season_data if not i['season_number'] == 0]
				season_data.sort(key=lambda k: k['season_number'])
			else: season_data = []
			running_ep_count = total_aired_eps
			for item in season_data:
				try:
					props = {}
					cm = []
					cm_append = cm.append
					item_get = item.get
					name, overview, rating = item_get('name'), item_get('overview'), item_get('vote_average')
					season_number, episode_count = item_get('season_number'), item_get('episode_count')
					user_rating = user_ratings.get_user_rating(self.user_ratings, 'season', tmdb_id=tmdb_id, imdb_id=imdb_id, tvdb_id=tvdb_id, season=season_number)
					air_date = item_get('air_date')
					poster, season_landscape = get_season_art(meta, item, season_number, image_resolution, self.poster_main, self.fanart_enabled, show_poster, landscape, fanart)
					if season_number == 0: unaired = False
					elif episode_count == 0: unaired = True
					elif season_number != total_seasons: unaired = False
					else:
						episode_airs = adjust_premiered_date_function(air_date, 0)[0]
						if not episode_airs or self.current_date < episode_airs: unaired = True
						else: unaired = False
					if unaired:
						if not self.show_unaired: return
						episode_count = 0
					elif season_number != 0:
						running_ep_count -= episode_count
						if running_ep_count < 0: episode_count = running_ep_count + episode_count
					try: year = air_date.split('-')[0]
					except: year = show_year
					plot = overview or show_plot
					title = name if use_season_title and name else ' '.join([season_str, string(season_number)])
					if 'season' in params: title = '%s: %s' % (show_title, title)
					if unaired: title = '%s' % (unaired_label % title)
					playcount, overlay, watched, unwatched = get_watched_status_season(self.watched_info, string(tmdb_id), season_number, episode_count)
					if (self.widget_hide_watched or self.menu_hide_watched) and watched: continue
					url_data = {'mode': 'build_episode_list', 'tmdb_id': tmdb_id, 'season': season_number}
					if self.params.get('ignore_menu_hide_watched') == 'true': url_data['ignore_menu_hide_watched'] = 'true'
					if self.catalogue_id: url_data['catalogue_id'] = self.catalogue_id
					if parent_fav_type: url_data['parent_fav_type'] = parent_fav_type
					url_params = build_url(url_data)
					options_params = build_url({'mode': 'options_menu_choice', 'content': 'season', 'tmdb_id': tmdb_id, 'is_widget': self.is_widget})
					trailer_params = build_url({'mode': 'play_trailer_choice', 'media_type': 'tvshow', 'tmdb_id': tmdb_id})
					info_extra_params = build_url({'mode': 'info_extra_choice', 'media_type': 'season', 'tmdb_id': tmdb_id, 'season': season_number})
					rating_params = build_url({'mode': 'rating_choice', 'media_type': 'season', 'tmdb_id': tmdb_id, 'imdb_id': imdb_id, 'tvdb_id': tvdb_id, 'season': season_number, 'title': show_title})
					fav_id = '%s:%s' % (tmdb_id, season_number)
					fav_params = build_url({'mode': 'favourites_choice', 'media_type': 'season', 'fav_type': season_fav_type, 'parent_fav_type': parent_fav_type, 'tmdb_id': tmdb_id, 'imdb_id': imdb_id, 'tvdb_id': tvdb_id, 'season': season_number, 'title': '%s - %s' % (show_title, title)})
					cm_append((options_str, run_plugin % options_params))
					cm_append((trailer_str, run_plugin % trailer_params))
					cm_append((extras_str, run_plugin % info_extra_params))
					if settings.context_favourites_enabled(): cm_append((favourites_context_label(season_fav_type, fav_id), run_plugin % fav_params))
					if settings.context_rating_enabled('season'): cm_append((ls(33141), run_plugin % rating_params))
					if not playcount: cm_append((watched_str % self.watched_title, run_plugin % build_url({
						'mode': 'mark_as_watched_unwatched_season', 'action': 'mark_as_watched', 'year': show_year,
						'tmdb_id': tmdb_id, 'tvdb_id': tvdb_id, 'season': season_number, 'title': show_title
					})))
					if watched: cm_append((unwatched_str % self.watched_title, run_plugin % build_url({
						'mode': 'mark_as_watched_unwatched_season', 'action': 'mark_as_unwatched', 'year': show_year,
						'tmdb_id': tmdb_id, 'tvdb_id': tvdb_id, 'season': season_number, 'title': show_title
					})))
					props['unwatchedepisodes'] = string(unwatched)
					props['totalepisodes'] = string(episode_count)
					props['alkoflix_sort_order'] = string(params.get('sort', ''))
					listitem = kodi_utils.make_listitem()
					listitem.addContextMenuItems(cm)
					listitem.setProperties(props)
					listitem.setLabel(title)
#					listitem.setContentLookup(False)
					listitem.setArt(kodi_utils.clean_art({'poster': poster, 'icon': poster, 'thumb': poster, 'fanart': fanart, 'banner': banner, 'clearart': clearart, 'clearlogo': clearlogo,
									'landscape': season_landscape, 'tvshow.poster': show_poster, 'tvshow.clearart': clearart, 'tvshow.clearlogo': clearlogo, 'tvshow.landscape': landscape, 'tvshow.banner': banner}))
					if KODI_VERSION < 20:
						listitem.setCast(show_cast)
						listitem.setUniqueIDs({'imdb': imdb_id, 'tmdb': string(tmdb_id), 'tvdb': string(tvdb_id)})
						info = {'mediatype': 'season', 'trailer': trailer, 'title': title, 'size': '0', 'duration': episode_run_time, 'plot': plot,
									'rating': rating, 'premiered': air_date, 'studio': studio, 'year': year, 'genre': genre, 'mpaa': mpaa, 'tvshowtitle': show_title,
									'imdbnumber': imdb_id, 'votes': votes, 'season': season_number, 'playcount': playcount, 'overlay': overlay}
						if user_rating: info['userrating'] = user_rating
						listitem.setInfo('video', info)
						listitem.setProperty('watchedepisodes', string(watched))
					else:
						if watched > 0: listitem.setProperty('watchedepisodes', string(watched))
						videoinfo = listitem.getVideoInfoTag(offscreen=True)
						videoinfo.setCast(make_cast_list(show_cast))
						videoinfo.setUniqueIDs({'imdb': imdb_id, 'tmdb': string(tmdb_id), 'tvdb': string(tvdb_id)})
						videoinfo.setDuration(episode_run_time)
						videoinfo.setGenres(genre.split(', '))
						videoinfo.setIMDBNumber(imdb_id)
						videoinfo.setMediaType('season')
						videoinfo.setMpaa(mpaa)
						videoinfo.setPlaycount(playcount)
						videoinfo.setPlot(plot)
						videoinfo.setPremiered(air_date)
						videoinfo.setRating(rating)
						user_ratings.apply_user_rating_to_listitem(listitem, user_rating, videoinfo)
						videoinfo.setSeason(season_number)
						videoinfo.setStudios((studio,))
						videoinfo.setTitle(title)
						videoinfo.setTrailer(trailer)
						videoinfo.setTvShowStatus(show_status)
						videoinfo.setTvShowTitle(show_title)
						videoinfo.setVotes(votes)
						videoinfo.setYear(int(year))
					self.append((url_params, listitem, True))
				except: pass
		def _process_episode_list():
			thumb_fanart = settings.thumb_fanart()
			adjust_hours = settings.date_offset()
			bookmarks = get_bookmarks(self.watched_indicators, 'episode')
			all_episodes = True if params.get('season') == 'all' else False
			if all_episodes:
				episodes_data = all_episodes_meta(meta, self.meta_user_info, Thread)
				if not show_specials(): episodes_data = [i for i in episodes_data if not i['season'] == 0]
			else: episodes_data = season_meta_function(params['season'], meta, self.meta_user_info)
			for item in episodes_data:
				try:
					props = {}
					cm = []
					cm_append = cm.append
					item_get = item.get
					season, episode, ep_name = item_get('season'), item_get('episode'), item_get('title')
					user_rating = user_ratings.get_user_rating(self.user_ratings, 'episode', tmdb_id=tmdb_id, imdb_id=imdb_id, tvdb_id=tvdb_id, season=season, episode=episode)
					if user_rating: item['userrating'] = user_rating
					premiered, cast = item_get('premiered'), show_cast + item_get('guest_stars', [])
					episode_date, premiered = adjust_premiered_date_function(premiered, adjust_hours)
					playcount, overlay = get_watched_status_episode(self.watched_info, string(tmdb_id), season, episode)
					resumetime, progress = get_resumetime(bookmarks, tmdb_id, season, episode)
					thumb = item_get('thumb') or fanart
					if thumb_fanart: background = thumb
					else: background = fanart
					item.update({'trailer': trailer, 'tvshowtitle': show_title, 'premiered': premiered, 'genre': genre, 'duration': episode_run_time, 'mpaa': mpaa, 'studio': studio,
								'playcount': playcount, 'overlay': overlay})
					options_params = build_url({'mode': 'options_menu_choice', 'content': 'episode', 'tmdb_id': tmdb_id, 'season': season, 'episode': episode, 'is_widget': self.is_widget})
					trailer_params = build_url({'mode': 'play_trailer_choice', 'media_type': 'tvshow', 'tmdb_id': tmdb_id})
					info_extra_params = build_url({'mode': 'info_extra_choice', 'media_type': 'episode', 'tmdb_id': tmdb_id, 'season': season, 'episode': episode})
					rating_params = build_url({'mode': 'rating_choice', 'media_type': 'episode', 'tmdb_id': tmdb_id, 'imdb_id': imdb_id, 'tvdb_id': tvdb_id, 'season': season, 'episode': episode, 'title': show_title})
					fav_id = '%s:%s:%s' % (tmdb_id, season, episode)
					fav_params = build_url({'mode': 'favourites_choice', 'media_type': 'episode', 'fav_type': episode_fav_type, 'parent_fav_type': parent_fav_type, 'tmdb_id': tmdb_id, 'imdb_id': imdb_id, 'tvdb_id': tvdb_id, 'season': season, 'episode': episode, 'title': '%s - S%sE%s - %s' % (show_title, string(season).zfill(1), string(episode).zfill(2), ep_name)})
					url_data = {'mode': 'play_media', 'media_type': 'episode', 'tmdb_id': tmdb_id, 'season': season, 'episode': episode}
					if self.catalogue_id: url_data['catalogue_id'] = self.catalogue_id
					play_params = build_url(url_data)
					url_params = play_params
					display = '%sx%s - %s' % (string(season).zfill(1), string(episode).zfill(2), ep_name) if self.hide_watched_items and all_episodes else ep_name
					unaired = False
					if not episode_date or self.current_date < episode_date:
						if not self.show_unaired: continue
						if season != 0:
							unaired = True
							display = '%s' % (unaired_label % ep_name)
							item['title'] = display
					if self.hide_watched_items and (playcount or unaired): continue
					if (self.widget_hide_watched or self.menu_hide_watched) and playcount and not unaired: continue
					try: year = premiered.split('-')[0]
					except: year = show_year
					cm_append((options_str, run_plugin % options_params))
					cm_append((trailer_str, run_plugin % trailer_params))
					cm_append((extras_str, run_plugin % info_extra_params))
					if settings.context_favourites_enabled(): cm_append((favourites_context_label(episode_fav_type, fav_id), run_plugin % fav_params))
					if settings.context_rating_enabled('episode'): cm_append((ls(33137), run_plugin % rating_params))
					clearprog_params, unwatched_params, watched_params = '', '', ''
					if not unaired:
						if progress != '0' or resumetime != '0': cm_append((clearprog_str, run_plugin % build_url({
							'mode': 'watched_unwatched_erase_bookmark', 'media_type': 'episode',
							'tmdb_id': tmdb_id, 'season': season, 'episode': episode, 'refresh': 'true'
						})))
						if playcount: cm_append((unwatched_str % self.watched_title, run_plugin % build_url({
							'mode': 'mark_as_watched_unwatched_episode', 'action': 'mark_as_unwatched', 'year': show_year,
							'tmdb_id': tmdb_id, 'tvdb_id': tvdb_id, 'season': season, 'episode': episode, 'title': show_title
						})))
						else: cm_append((watched_str % self.watched_title, run_plugin % build_url({
							'mode': 'mark_as_watched_unwatched_episode', 'action': 'mark_as_watched', 'year': show_year,
							'tmdb_id': tmdb_id, 'tvdb_id': tvdb_id, 'season': season, 'episode': episode, 'title': show_title
						})))
					props['episode_type'] = item_get('episode_type')
					listitem = kodi_utils.make_listitem()
					listitem.addContextMenuItems(cm)
					listitem.setProperties(props)
					listitem.setLabel(display)
#					listitem.setContentLookup(False)
					listitem.setArt(kodi_utils.clean_art({'poster': show_poster, 'fanart': background, 'thumb': thumb, 'icon': thumb, 'banner': banner, 'clearart': clearart, 'clearlogo': clearlogo,
									'landscape': thumb, 'tvshow.poster': show_poster, 'tvshow.clearart': clearart, 'tvshow.clearlogo': clearlogo, 'tvshow.landscape': thumb, 'tvshow.banner': banner}))
					if KODI_VERSION < 20:
						listitem.setCast(cast)
						listitem.setUniqueIDs({'imdb': imdb_id, 'tmdb': string(tmdb_id), 'tvdb': string(tvdb_id)})
						listitem.setInfo('video', remove_meta_keys(item, dict_removals))
						listitem.setProperty('resumetime', resumetime)
					else:
						videoinfo = listitem.getVideoInfoTag(offscreen=True)
						videoinfo.setCast(make_cast_list(cast))
						videoinfo.setUniqueIDs({'imdb': imdb_id, 'tmdb': string(tmdb_id), 'tvdb': string(tvdb_id)})
						videoinfo.setDirectors(item_get('director').split(', '))
						videoinfo.setDuration(int(item_get('duration') or default_duration))
						videoinfo.setEpisode(episode)
						videoinfo.setFirstAired(premiered)
						videoinfo.setGenres(genre.split(', '))
						videoinfo.setIMDBNumber(imdb_id)
						videoinfo.setMediaType('episode')
						videoinfo.setMpaa(mpaa)
						videoinfo.setPlaycount(playcount)
						videoinfo.setPlot(item_get('plot'))
						videoinfo.setRating(item_get('rating'))
						user_ratings.apply_user_rating_to_listitem(listitem, user_rating, videoinfo)
						videoinfo.setSeason(season)
						videoinfo.setStudios((studio,))
						videoinfo.setTitle(item_get('title'))
						videoinfo.setTrailer(trailer)
						videoinfo.setTvShowStatus(show_status)
						videoinfo.setTvShowTitle(show_title)
						videoinfo.setVotes(item_get('votes'))
						videoinfo.setWriters(item_get('writer').split(', '))
						videoinfo.setYear(int(year))
						if int(progress):
							listitem.setProperty('watchedprogress', progress)
							videoinfo.setResumePoint(*set_resumetime(resumetime, progress, videoinfo.getDuration()))
					self.append((url_params, listitem, False))
				except: pass
		meta = tv_meta_function('tmdb_id', params['tmdb_id'], self.meta_user_info, self.current_date)
		meta_get = meta.get
		tmdb_id, tvdb_id, imdb_id = meta_get('tmdb_id'), meta_get('tvdb_id'), meta_get('imdb_id')
		rootname, show_status = meta_get('rootname'), meta_get('status')
		show_title, show_year, show_plot = meta_get('title'), meta_get('year'), meta_get('plot')
		show_poster = settings.resolve_poster_art(meta, poster_empty)
		media_fanart = meta_get(self.fanart_main) or meta_get(self.fanart_backup)
		fanart = media_fanart or fanart_empty
		clearlogo = meta_get('clearlogo') or meta_get('tmdblogo') or ''
		# Fanart.tv reste optionnel, mais les landscapes TMDb sélectionnés selon la
		# langue doivent rester disponibles pour les vues paysage.
		if self.fanart_enabled:
			banner, clearart = meta_get('banner'), meta_get('clearart')
			landscape = settings.resolve_landscape_art(meta, media_fanart or show_poster)
		else:
			banner, clearart = '', ''
			landscape = meta_get('landscape_tmdb') or media_fanart or show_poster
		show_cast, mpaa, votes = meta_get('cast', []), meta_get('mpaa'), meta_get('votes')
		trailer, genre, studio = string(meta_get('trailer')), meta_get('genre'), meta_get('studio')
		episode_run_time, rating, premiered = meta_get('duration'), meta_get('rating'), meta_get('premiered')
		total_seasons, total_aired_eps = meta_get('total_seasons'), meta_get('total_aired_eps')
		parent_fav_type = self.params.get('parent_fav_type') or self.params.get('series_fav_type') or self.params.get('tv_fav_type') or ''
		if not parent_fav_type:
			parent_fav_type = favourite_type_from_context('tvshow', self.params, self.params.get('action'), meta)
		season_fav_type = season_favourite_type_from_tv(parent_fav_type)
		episode_fav_type = episode_favourite_type_from_tv(parent_fav_type)
		mode = self.params.get('mode', 'build_season_list')
		if 'episode' in mode: _process_episode_list()
		else: _process_season_list()
		self.params['show_title'] = show_title
		return self.items

	def _parse_favourite_ref(self, value):
		parts = str(value or '').split(':')
		try: return [int(i) for i in parts]
		except: return []

	def _favourite_rows_for_types(self, fav_type, kind):
		if fav_type == 'all_seasons': fav_types = ('season', 'season_family', 'season_animation', 'season_documentary')
		elif fav_type == 'all_episodes': fav_types = ('episode', 'episode_family', 'episode_animation', 'episode_documentary')
		else: fav_types = (fav_type,)
		rows = []
		for item_type in fav_types:
			for fav in favourites_cache.get_favourites(item_type) or []:
				fav = dict(fav)
				fav['_fav_type'] = item_type
				rows.append(fav)
		return rows

	def build_favourite_seasons(self, fav_type='season'):
		items = []
		for fav in self._favourite_rows_for_types(fav_type, 'season'):
			item_fav_type = fav.get('_fav_type', fav_type)
			parts = self._parse_favourite_ref(fav.get('tmdb_id'))
			if len(parts) < 2: continue
			show_id, season_no = parts[0], parts[1]
			try:
				meta = tv_meta_function('tmdb_id', show_id, self.meta_user_info, self.current_date) or {}
				show_title = meta.get('title') or fav.get('title') or str(show_id)
				season_data = next((i for i in meta.get('season_data', []) if int(i.get('season_number')) == int(season_no)), {})
				show_poster = settings.resolve_poster_art(meta, poster_empty)
				fanart = meta.get(self.fanart_main) or meta.get(self.fanart_backup) or fanart_empty
				show_landscape = settings.resolve_landscape_art(meta, fanart or show_poster)
				poster, season_landscape = get_season_art(meta, season_data, season_no, self.meta_user_info['image_resolution']['poster'], self.poster_main, self.fanart_enabled, show_poster, show_landscape, fanart)
				title = fav.get('title') or '%s - Saison %s' % (show_title, season_no)
				url = build_url({'mode': 'build_episode_list', 'tmdb_id': show_id, 'season': season_no, 'parent_fav_type': tv_favourite_type_from_child(item_fav_type)})
				fav_params = build_url({'mode': 'favourites_choice', 'media_type': 'season', 'fav_type': item_fav_type, 'tmdb_id': show_id, 'imdb_id': meta.get('imdb_id'), 'tvdb_id': meta.get('tvdb_id'), 'season': season_no, 'title': title})
				li = kodi_utils.make_listitem()
				li.setLabel(title)
				li.setArt(kodi_utils.clean_art({'poster': poster, 'icon': poster, 'thumb': poster, 'fanart': fanart, 'landscape': season_landscape}))
				li.addContextMenuItems([(favourites_context_label(item_fav_type, fav.get('tmdb_id')), run_plugin % fav_params)])
				items.append((url, li, True))
			except: pass
		return items

	def build_favourite_episodes(self, fav_type='episode'):
		items = []
		for fav in self._favourite_rows_for_types(fav_type, 'episode'):
			item_fav_type = fav.get('_fav_type', fav_type)
			parts = self._parse_favourite_ref(fav.get('tmdb_id'))
			if len(parts) < 3: continue
			show_id, season_no, episode_no = parts[0], parts[1], parts[2]
			try:
				meta = tv_meta_function('tmdb_id', show_id, self.meta_user_info, self.current_date) or {}
				show_title = meta.get('title') or str(show_id)
				episodes = season_meta_function(season_no, meta, self.meta_user_info) or []
				ep = next((i for i in episodes if int(i.get('episode')) == int(episode_no)), {})
				ep_name = ep.get('title') or ''
				title = fav.get('title') or '%s - S%sE%s - %s' % (show_title, season_no, episode_no, ep_name)
				thumb = ep.get('thumb') or meta.get(self.fanart_main) or meta.get(self.fanart_backup) or fanart_empty
				poster = settings.resolve_poster_art(meta, poster_empty)
				url = build_url({'mode': 'play_media', 'media_type': 'episode', 'tmdb_id': show_id, 'season': season_no, 'episode': episode_no})
				fav_params = build_url({'mode': 'favourites_choice', 'media_type': 'episode', 'fav_type': item_fav_type, 'tmdb_id': show_id, 'imdb_id': meta.get('imdb_id'), 'tvdb_id': meta.get('tvdb_id'), 'season': season_no, 'episode': episode_no, 'title': title})
				li = kodi_utils.make_listitem()
				li.setLabel(title)
				li.setArt(kodi_utils.clean_art({'poster': poster, 'icon': thumb, 'thumb': thumb, 'fanart': thumb, 'landscape': thumb}))
				li.addContextMenuItems([(favourites_context_label(item_fav_type, fav.get('tmdb_id')), run_plugin % fav_params)])
				items.append((url, li, False))
			except: pass
		return items


	def run(self):
		__handle__, is_widget = int(sys.argv[1]), kodi_utils.external_browse()
		mode = self.params.get('mode', 'build_season_list')
		action = self.params.get('action')
		season_actions = {
			'favourites_seasons': 'season',
			'favourites_seasons_all': 'all_seasons',
			'favourites_seasons_family': 'season_family',
			'favourites_seasons_animation': 'season_animation',
			'favourites_anime_seasons': 'anime_season',
			'favourites_seasons_documentary': 'season_documentary',
			'favourites_custom_seasons': self.params.get('fav_type', 'season')
		}
		episode_actions = {
			'favourites_episodes': 'episode',
			'favourites_episodes_all': 'all_episodes',
			'favourites_episodes_family': 'episode_family',
			'favourites_episodes_animation': 'episode_animation',
			'favourites_anime_episodes': 'anime_episode',
			'favourites_episodes_documentary': 'episode_documentary',
			'favourites_custom_episodes': self.params.get('fav_type', 'episode')
		}
		if action in season_actions:
			content_type, view_type, items = 'seasons', 'view.seasons', self.build_favourite_seasons(season_actions[action])
		elif action in episode_actions:
			content_type, view_type, items = 'episodes', 'view.episodes', self.build_favourite_episodes(episode_actions[action])
		elif 'episode' in mode:
			content_type, view_type, items = 'episodes', 'view.episodes', self.build_season_list(self.params)
		else:
			content_type, view_type, items = 'seasons', 'view.seasons', self.build_season_list(self.params)
		kodi_utils.add_items(__handle__, items)
		kodi_utils.set_category(__handle__, self.params.get('show_title'))
		kodi_utils.set_sort_method(__handle__, content_type)
		kodi_utils.set_content(__handle__, content_type)
		kodi_utils.end_directory(__handle__, False if is_widget else None)
		kodi_utils.set_view_mode(view_type, content_type)

