# -*- coding: utf-8 -*-
# plugin.video.alkoflix
# resources/lib/windows/extras.py

import json
from datetime import datetime, timedelta
from windows import BaseDialog, location, videoplayer
from caches import watched_cache as ws
from caches.favourites_cache import favourite_type_from_context
from indexers import metadata, tmdb_api, imdb_api, mdblist_api
from menus import images
from modules import settings, dialogs, user_ratings
from modules.info_windows import extras_window_xml, person_window_xml, log_info_window_event, log_info_window_error, start_info_window_task
from modules.downloader import runner
from modules.meta_lists import networks
from modules.utils import get_datetime
from modules.kodi_utils import media_path, notification, close_all_dialog, hide_busy_dialog, ok_dialog, fetch_kodi_imagecache, local_string as ls

fanart_empty = media_path('transparent.png')
poster_empty = media_path('box_office.png')
backup_thumbnail = media_path('box_office.png')
backup_cast_thumbnail = media_path('people.png')
tmdb_image_base = tmdb_api.tmdb_image_base
button_ids = 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
playbrowse_id, trailer_id, keywords_id, images_id, extrainfo_id, genre_id, director_id, favourites_id, trakt_id, mdbl_id, tmdbl_id = button_ids
actions_id, cast_id, recommended_id, reviews_id, trivia_id, blunders_id, parentsguide_id = 2049, 2050, 2051, 2052, 2053, 2054, 2055
videos_id, posters_id, backdrops_id, year_id, genres_id, networks_id, collection_id = 2056, 2057, 2058, 2059, 2060, 2061, 2062
tmdb_list_ids = (recommended_id, year_id, genres_id, networks_id, collection_id)
imdb_list_ids = (reviews_id, trivia_id, blunders_id, parentsguide_id)
art_ids = (posters_id, backdrops_id)
parentsguide_dict = {
	'Sex & Nudity': (ls(32990), 'porn.png'), 'Violence & Gore': (ls(32991), 'war.png'), 'Profanity': (ls(32992), 'bad_languages.png'),
	'Alcohol, Drugs & Smoking': (ls(32993), 'drugs_alcohol.png'), 'Frightening & Intense Scenes': (ls(32994), 'horror.png'),
	'mild': ls(32996), 'moderate': ls(32997), 'severe': ls(32998)
}

status_translation = {
	'Released': ls(33171), 'Returning': ls(33172), 'Ended': ls(33173), 'Canceled': ls(33174), 'Cancelled': ls(33174),
	'In Production': ls(33175), 'Pilot': ls(33181), 'Planned': ls(33180)
}

def translate_status(value):
	try:
		value = (value or '').replace('Series', '').strip()
		return status_translation.get(value, value)
	except:
		return value or ''


media_type_translation = {
	'movie': 'Film', 'movies': 'Films', 'film': 'Film', 'films': 'Films',
	'tvshow': 'Série', 'tvshows': 'Séries', 'show': 'Série', 'shows': 'Séries', 'series': 'Séries',
	'season': 'Saison', 'seasons': 'Saisons',
	'episode': 'Épisode', 'episodes': 'Épisodes',
	'person': 'Personne', 'people': 'Personnes',
	'collection': 'Saga', 'collections': 'Sagas', 'set': 'Saga', 'sets': 'Sagas',
	'list': 'Liste', 'lists': 'Listes'
}

def translate_media_type(value):
	try:
		value = (value or '').strip()
		return media_type_translation.get(value.lower(), value)
	except:
		return value or ''


def is_collection_type(value):
	try: return str(value or '').lower() in ('collection', 'collections', 'set', 'sets', 'saga', 'sagas')
	except: return False

class Extras(BaseDialog):
	def __init__(self, *args, **kwargs):
		BaseDialog.__init__(self, args)
		self.control_id = None
		self.focus_id = 2049
		self.after_close = None
		self.set_starting_constants(kwargs)
		self.set_properties()

	def onInit(self):
		self.start_background_sections()
		self.make_options()
		self.safe_set_focus(self.focus_id)

	def start_background_sections(self):
		# Les sections désactivées dans les réglages ne sont plus lancées inutilement.
		# Le visuel reste identique, mais l'ouverture des fiches évite plusieurs
		# threads/cache/API inutiles.
		start_info_window_task('Extras', 'poster', self.set_poster)
		if is_collection_type(self.media_type):
			start_info_window_task('Extras', 'collection_parts', self.make_collection_parts)
			return
		loaders = (
			(cast_id, 'cast', self.make_cast, ()),
			(recommended_id, 'recommended', self.make_recommended, ()),
			(reviews_id, 'reviews', self.make_reviews, ()),
			(trivia_id, 'trivia', self.make_trivia, ()),
			(blunders_id, 'blunders', self.make_blunders, ()),
			(parentsguide_id, 'parentsguide', self.make_parentsguide, ()),
			(videos_id, 'videos', self.make_videos, ()),
			(year_id, 'year', self.make_year, ()),
			(genres_id, 'genres', self.make_genres, ()),
			(networks_id, 'networks', self.make_network, ())
		)
		for control_id, label, target, args in loaders:
			if control_id in self.enabled_lists:
				start_info_window_task('Extras', label, target, *args)
		if posters_id in self.enabled_lists or backdrops_id in self.enabled_lists:
			start_info_window_task('Extras', 'artwork', self.make_artwork_sections)
		if self.media_type == 'movie':
			if collection_id in self.enabled_lists:
				start_info_window_task('Extras', 'collection', self.make_collection)
		else:
			self.setProperty('alkoskins.extras.make.collection', 'false')

	def run(self):
		self.doModal()
		after_close = self.after_close
		selected = self.selected
		self.after_close = None
		self.clearProperties()
		hide_busy_dialog()
		if callable(after_close): return after_close()
		if selected: self.execute_code(selected)

	def make_return_kwargs(self):
		return {'meta': self.meta, 'is_widget': self.is_widget, 'is_home': self.is_home}

	def onClick(self, controlID):
		self.control_id = controlID

	def open_text_media_with_return(self, text, poster=None, title=None, subtitle='', source='text'):
		# Les fenêtres XML empilées sont instables sur certains skins/appareils Kodi.
		# Pour un retour fiable, la fiche est fermée avant le texte, puis rouverte
		# avec les métadonnées déjà chargées lorsque le lecteur de texte est fermé.
		media_type = self.media_type
		return_kwargs = self.make_return_kwargs()
		text_kwargs = {'text': text, 'poster': poster, 'title': title, 'subtitle': subtitle}
		def callback():
			try:
				log_info_window_event('Extras', 'open text viewer source=%s tmdb_id=%s' % (source, self.tmdb_id))
				ShowTextMedia('textviewer_media.xml', location, **text_kwargs).run()
			except Exception as exc:
				log_info_window_error('Extras', 'text viewer source=%s' % source, exc)
			try:
				log_info_window_event('Extras', 'return to info window source=%s tmdb_id=%s' % (source, self.tmdb_id))
				type(self)(extras_window_xml(media_type), location, **return_kwargs).run()
			except Exception as exc:
				log_info_window_error('Extras', 'return to info window source=%s' % source, exc)
		self.after_close = callback
		self.close()

	def open_person_info_with_return(self, query, source='person'):
		# Une fiche Personne ouverte depuis une fiche Film/Série ne doit pas rester
		# empilée au-dessus de la fiche parente. Sinon les listes Films/Séries/
		# Réalisations tentent d'ouvrir Videos alors qu'un dialogue modal est encore actif.
		media_type = self.media_type
		return_kwargs = self.make_return_kwargs()
		person_kwargs = {
			'query': query,
			'actor_id': None,
			'actor_name': query,
			'actor_image': None,
			'return_to_extras': return_kwargs,
			'return_media_type': media_type
		}
		def callback():
			try:
				log_info_window_event('Extras', 'open person info source=%s query=%s tmdb_id=%s' % (source, query, self.tmdb_id))
				self.open_window(('windows.people', 'People'), person_window_xml(), **person_kwargs)
			except Exception as exc:
				log_info_window_error('Extras', 'open person info source=%s' % source, exc)
		self.after_close = callback
		self.close()


	def _genre_ids_for_action(self):
		genre_ids = self.meta.get('genre_ids')
		if genre_ids: return genre_ids
		try:
			# Certains anciens caches de métadonnées n'ont pas encore le champ genre_ids.
			# Le bouton Genres reste donc capable de fonctionner à partir du libellé affiché.
			return self.meta.get('genres_ids') or self.meta.get('genre_id') or []
		except Exception:
			return []

	def open_genres_action(self):
		if not self.genre:
			log_info_window_event('Extras', 'genres button skipped: empty genre for tmdb_id=%s' % self.tmdb_id)
			return
		base_media = 'movies' if self.media_type == 'movie' else 'tv'
		genre_ids = self._genre_ids_for_action()
		log_info_window_event('Extras', 'genres button media=%s tmdb_id=%s genre_ids=%s genre=%s' % (self.media_type, self.tmdb_id, genre_ids, self.genre))
		genre_options = dialogs.genres_choice(base_media, self.genre, self.poster, return_genres=True, genre_ids=genre_ids)
		if not genre_options:
			log_info_window_event('Extras', 'genres button found no matching TMDb genres for tmdb_id=%s' % self.tmdb_id)
			return notification(32760, 1500)
		genre_params = dialogs.genres_choice(base_media, self.genre, self.poster, genre_ids=genre_ids)
		if genre_params is None:
			log_info_window_event('Extras', 'genres dialog closed without selection for tmdb_id=%s' % self.tmdb_id)
			return
		close_all_dialog()
		self.selected = self.folder_runner % self.build_url(genre_params)
		self.close()

	def onAction(self, action):
		if action in self.closing_actions: self.close()
		if action in self.context_actions:
			focus_id = self.getFocusId()
			if focus_id == actions_id and self.media_type == 'movie':
				chosen_listitem = self.get_listitem(focus_id)
				params = int(chosen_listitem.getProperty('alkoskins.extras.actions'))
				if not params == playbrowse_id: return
				dialogs.playback_choice('movie', self.poster, self.meta)
			elif focus_id in (posters_id, backdrops_id):
				chosen_listitem = self.get_listitem(focus_id)
				image = chosen_listitem.getProperty('alkoskins.extras.thumbnail')
				params = {
					'action': 'image', 'media_type': 'image', 'image': BaseDialog.icon,
					'name': '%s %s' % (self.rootname, chosen_listitem.getProperty('alkoskins.extras.name')),
					'thumb_url': image.replace('w780', {posters_id: 'w185', backdrops_id: 'w300'}[focus_id]),
					'image_url': image.replace('w780', 'original')
				}
				return runner(params)
		if not self.control_id or not action in self.selection_actions: return
		if self.control_id == actions_id:
			try: chosen_var = int(self.get_listitem(self.control_id).getProperty('alkoskins.extras.actions'))
			except Exception as exc:
				log_info_window_error('Extras', 'actions control=%s' % self.control_id, exc)
				return
			if chosen_var == playbrowse_id:
				if is_collection_type(self.media_type):
					close_all_dialog()
					url_params = {'mode': 'build_movie_list', 'action': 'tmdb_movies_collection', 'collection_id': self.tmdb_id, 'name': self.title, 'fav_type': self.fav_type}
					self.selected = self.folder_runner % self.build_url(url_params)
					self.close()
				elif self.media_type == 'movie':
					close_all_dialog()
					url_params = {'mode': 'play_media', 'media_type': 'movie', 'tmdb_id': self.tmdb_id}
					self.selected = self.plugin_runner % self.build_url(url_params)
					self.close()
				else:
					close_all_dialog()
					url_params = self.make_tvshow_browse_params()
					self.selected = self.folder_runner % self.build_url(url_params)
					self.close()
			elif chosen_var == trailer_id:
				chosen = dialogs.trailer_choice(self.media_type, self.poster, self.tmdb_id, self.meta['trailer'], self.meta['all_trailers'])
				if not chosen: return ok_dialog()
				elif chosen == 'canceled': return
				media_type = self.media_type
				kwargs = self.make_return_kwargs()
				# La bande-annonce ferme maintenant la fiche avant de lancer le lecteur, puis
				# rouvre une fiche neuve au retour. Le lambda est volontaire : la nouvelle
				# fenêtre ne doit pas être créée avant la fin de la bande-annonce, sinon
				# close_custom_dialogs peut la fermer avant son affichage et vider Actions.
				def callback():
					try:
						log_info_window_event('Extras', 'play trailer source=actions tmdb_id=%s' % self.tmdb_id)
						videoplayer(chosen, close_all_dialog, lambda: type(self)(extras_window_xml(media_type), location, **kwargs).run())
					except Exception as exc:
						log_info_window_error('Extras', 'play trailer source=actions', exc)
				self.after_close = callback
				self.close()
				return
			elif chosen_var == extrainfo_id:
				text = media_extra_info(self.media_type, self.meta)
				return self.open_text_media_with_return(text=text, poster=self.poster, title=self.title, subtitle='Info & Extra', source='extra_info')
			elif chosen_var == genre_id:
				return self.open_genres_action()
			elif chosen_var == director_id:
				if not self.media_type == 'movie': return
				director = self.meta.get('director')
				if not director: return
				return self.open_person_info_with_return(director, 'director_button')
			elif chosen_var == favourites_id:
				params = {'tmdb_id': self.tmdb_id, 'imdb_id': self.imdb_id, 'tvdb_id': self.meta.get('tvdb_id'),
						'media_type': self.media_type, 'title': self.title, 'fav_type': self.fav_type, 'icon': self.poster}
				return dialogs.favourites_choice(params)
			elif chosen_var == trakt_id:
				params = {'tmdb_id': self.tmdb_id, 'imdb_id': self.imdb_id, 'tvdb_id': self.meta['tvdb_id'],
						'media_type': self.media_type, 'icon': self.poster}
				return dialogs.trakt_manager_choice(params)
			elif chosen_var == mdbl_id:
				params = {'tmdb_id': self.tmdb_id, 'imdb_id': self.imdb_id, 'tvdb_id': self.meta['tvdb_id'],
						'media_type': self.media_type, 'icon': self.poster}
				return dialogs.mdbl_manager_choice(params)
			elif chosen_var == tmdbl_id:
				params = {'tmdb_id': self.tmdb_id, 'imdb_id': self.imdb_id, 'tvdb_id': self.meta['tvdb_id'],
						'media_type': self.media_type, 'icon': self.poster}
				return dialogs.tmdb_manager_choice(params)
		else:
			try: chosen_var = self.get_listitem(self.control_id).getProperty(self.item_action_dict[self.control_id])
			except Exception as exc:
				log_info_window_error('Extras', 'list control=%s' % self.control_id, exc)
				return
			if self.control_id == cast_id:
				if is_collection_type(self.media_type):
					params = {'mode': 'extras_menu_choice', 'tmdb_id': chosen_var, 'media_type': 'movie', 'is_widget': self.is_widget, 'is_home': self.is_home}
					return dialogs.extras_menu(params)
				return self.open_person_info_with_return(chosen_var, 'cast_list')
			elif self.control_id == videos_id:
				chosen = dialogs.imdb_videos_choice(chosen_var, self.poster)
				if not chosen: return
				self.open_window(('windows.videoplayer', 'VideoPlayer'), 'videoplayer.xml', meta=self.meta, video=chosen)
			elif self.control_id in tmdb_list_ids:
				target_media_type = 'movie' if is_collection_type(self.media_type) else self.media_type
				function = metadata.movie_meta if target_media_type == 'movie' else metadata.tvshow_meta
				meta = function('tmdb_id', chosen_var, settings.metadata_user_info(), get_datetime())
				if not meta: return
				params = {'mode': 'extras_menu_choice', 'tmdb_id': chosen_var, 'media_type': target_media_type, 'is_widget': self.is_widget, 'is_home': self.is_home}
				return dialogs.extras_menu(params)
			elif self.control_id in imdb_list_ids:
				if self.control_id == parentsguide_id:
					listings = json.loads(chosen_var)
					if not listings: return
					chosen_var = '\n\n'.join(['%02d. %s' % (count, i) for count, i in enumerate(listings, 1)])
				return self.open_text_media_with_return(text=chosen_var, poster=self.poster, title=self.title, subtitle='Info & Extra', source='imdb_list_%s' % self.control_id)
			elif self.control_id in art_ids:
				slideshow_params = {'mode': 'slideshow_image', 'all_images': chosen_var, 'current_index': self.get_position(self.control_id)}
				ending_position = images.Images().run(slideshow_params)
				self.getControl(self.control_id).selectItem(ending_position)

	def make_options(self):
		def builder():
			if is_collection_type(self.media_type):
				localized_options = [
					(extrainfo_id, ls(32605), 'information.png'),
					(favourites_id, 'Favori', 'favourites.png'),
					(playbrowse_id, 'Parcourir', 'sets.png')
				]
			else:
				localized_options = [
					(extrainfo_id, ls(32605), 'information.png'),
					(playbrowse_id, ls(32174), 'player.png')
					if self.media_type == 'movie' else
					(playbrowse_id, ls(32652), 'in_progress_tvshow.png'),
					(trailer_id, ls(32606), 'watched.png'),
					(genre_id, ls(32470), 'genres.png')
				]
				if self.media_type == 'movie':
					localized_options.append((director_id, ls(32627), 'movies.png'))
				localized_options.extend([
					(favourites_id, 'Favoris', 'favourites.png'),
					(trakt_id, 'Trakt', 'trakt-color.png'),
					(mdbl_id, 'MDBList', 'mdblist-color.png'),
					(tmdbl_id, 'TMDbList', 'tmdb.png')
				])
			for action_id, label, icon_name in localized_options:
				try:
					name = '[B]%s[/B]' % label.upper()
					icon = '%s%s' % (icon_path, icon_name)
					listitem = self.make_listitem()
					listitem.setProperty('alkoskins.extras.name', name)
					listitem.setProperty('alkoskins.extras.actions', str(action_id))
					listitem.setProperty('alkoskins.extras.thumbnail', icon)
					yield listitem
				except: pass
		try:
			icon_path = media_path()
			item_list = list(builder())
			self.add_items(actions_id, item_list)
		except Exception as exc:
			log_info_window_error('Extras', 'make_options', exc)


	def make_collection_parts(self):
		def builder():
			for item in self.meta.get('parts', []) or []:
				try:
					tmdb_id = item.get('id')
					if not tmdb_id: continue
					title = item.get('title') or item.get('name') or item.get('original_title') or ''
					poster_path = item.get('poster_path')
					thumbnail = tmdb_image_base % (self.poster_resolution, poster_path) if poster_path else poster_empty
					year = self.get_release_year(item.get('release_date') or item.get('first_air_date') or '')
					listitem = self.make_listitem()
					listitem.setProperty('alkoskins.extras.name', title)
					listitem.setProperty('alkoskins.extras.role', year)
					listitem.setProperty('alkoskins.extras.thumbnail', thumbnail)
					listitem.setProperty('alkoskins.extras.tmdb_id', str(tmdb_id))
					yield listitem
				except: pass
		try:
			item_list = list(builder())
			self.setProperty('alkoskins.extras.cast.number', '(x%02d)' % len(item_list))
			self.item_action_dict[cast_id] = 'alkoskins.extras.tmdb_id'
			self.add_items(cast_id, item_list)
		except Exception as exc:
			log_info_window_error('Extras', 'make_collection_parts', exc)

	def _aggregate_tvshow_cast(self):
		# Fallback pour les séries dont /credits.cast est vide mais dont
		# /aggregate_credits contient bien une distribution (cas fréquent sur les
		# anthologies et certaines séries à distribution variable).
		try:
			if self.media_type != 'tvshow': return []
			language = self.meta.get('meta_language') or settings.metadata_user_info().get('language', 'fr')
			data = tmdb_api.tvshow_aggregate_credits(self.tmdb_id, language) or {}
			profile_resolution = settings.get_resolution().get('profile', 'h632')
			items = []
			for item in data.get('cast') or []:
				try:
					roles = item.get('roles') or []
					characters = []
					for role in roles:
						character = role.get('character') or ''
						if character and character not in characters: characters.append(character)
					role_label = ' / '.join(characters[:2])
					thumbnail = tmdb_image_base % (profile_resolution, item['profile_path']) if item.get('profile_path') else ''
					items.append({'name': item.get('name', ''), 'role': role_label, 'thumbnail': thumbnail})
				except: pass
			if items:
				self.meta['cast'] = items
				log_info_window_event('Extras', 'tvshow aggregate cast fallback tmdb_id=%s count=%s' % (self.tmdb_id, len(items)))
			return items
		except Exception as exc:
			log_info_window_error('Extras', 'aggregate tvshow cast fallback', exc)
		return []

	def make_cast(self):
		if cast_id not in self.enabled_lists: return
		cast_items = self.meta.get('cast') or []
		if not cast_items: cast_items = self._aggregate_tvshow_cast()
		def builder():
			for item in cast_items:
				try:
					thumbnail = item.get('thumbnail') or backup_cast_thumbnail
					listitem = self.make_listitem()
					listitem.setProperty('alkoskins.extras.name', item.get('name', ''))
					listitem.setProperty('alkoskins.extras.role', item.get('role', ''))
					listitem.setProperty('alkoskins.extras.thumbnail', thumbnail)
					yield listitem
				except: pass
		try:
			item_list = list(builder())
			self.setProperty('alkoskins.extras.cast.number', '(x%02d)' % len(item_list))
			self.item_action_dict[cast_id] = 'alkoskins.extras.name'
			self.add_items(cast_id, item_list)
		except Exception as exc:
			log_info_window_error('Extras', 'make_cast', exc)

	def make_recommended(self):
		if recommended_id not in self.enabled_lists: return
		try:
			function = tmdb_api.tmdb_movies_recommendations if self.media_type == 'movie' else tmdb_api.tmdb_tv_recommendations
			data = function(self.tmdb_id, 1)['results']
			item_list = list(self.make_tmdb_listitems(data))
			self.setProperty('alkoskins.extras.recommended.number', '(x%02d)' % len(item_list))
			self.item_action_dict[recommended_id] = 'alkoskins.extras.tmdb_id'
			self.add_items(recommended_id, item_list)
		except Exception as exc:
			log_info_window_error('Extras', 'make_recommended', exc)

	def make_reviews(self):
		if reviews_id not in self.enabled_lists: return
		def builder():
			for count, item in enumerate(reviews, 1):
				try:
					provider = mdblist_api.review_provider_id.get(item['provider_id'], 'mdblist').upper()
					updated_at = item['updated_at'] or 'NA'
					rating = item['rating'] or 'NA'
					content = (
						'[B][COLOR red][%s][/COLOR][CR]%02d. %s - %s - %s[/B]\n\n%s'
						% (spoiler, count, provider, rating, updated_at, item['content'])
					) if 'spoiler' in item and item['spoiler'] else (
						'[B]%02d. %s - %s - %s[/B]\n\n%s'
						% (count, provider, rating, updated_at, item['content'])
					)
					listitem = self.make_listitem()
					listitem.setProperty('alkoskins.extras.text', content)
					yield listitem
				except: pass
		try:
			spoiler = ls(32985).upper()
			data = mdblist_api.mdbl_media_info(self.imdb_id, self.media_type)
			if not data is None:
				ratings, reviews = data['ratings'], data['reviews']
				reviews.sort(key=lambda k: k['updated_at'] or '', reverse=True)
				sources = ('imdb', 'metacritic', 'mdblist', 'tomatoes', 'trakt', 'tmdb')
				if 'score' in data: ratings.append({'source': 'mdblist', 'value': data['score']})
				ratings = ((i['source'], str(i['value'])) for i in ratings if i['source'] in sources and i['value'])
				for k, v in ratings: self.setProperty('alkoskins.extras.rating.%s' % k, v)
			else: reviews = [{'content': ls(33183), 'provider_id': '', 'updated_at': '', 'rating': ''}]
			item_list = list(builder())
			self.setProperty('alkoskins.extras.imdb_reviews.number', '(x%02d)' % len(item_list))
			self.item_action_dict[reviews_id] = 'alkoskins.extras.text'
			self.add_items(reviews_id, item_list)
		except Exception as exc:
			log_info_window_error('Extras', 'make_reviews', exc)

	def make_trivia(self):
		if trivia_id not in self.enabled_lists: return
		def builder():
			for count, item in enumerate(data, 1):
				try:
					listitem = self.make_listitem()
					listitem.setProperty('alkoskins.extras.text', '[B]%s %02d.[/B][CR][CR]%s' % (trivia, count, item))
					yield listitem
				except: pass
		try:
			trivia = ls(32984).upper()
			data = imdb_api.imdb_trivia(self.imdb_id)
			item_list = list(builder())
			self.setProperty('alkoskins.extras.imdb_trivia.number', '(x%02d)' % len(item_list))
			self.item_action_dict[trivia_id] = 'alkoskins.extras.text'
			self.add_items(trivia_id, item_list)
		except Exception as exc:
			log_info_window_error('Extras', 'make_trivia', exc)

	def make_blunders(self):
		if blunders_id not in self.enabled_lists: return
		def builder():
			for count, item in enumerate(data, 1):
				try:
					listitem = self.make_listitem()
					listitem.setProperty('alkoskins.extras.text', '[B]%s %02d.[/B][CR][CR]%s' % (blunders, count, item))
					yield listitem
				except: pass
		try:
			blunders = ls(32986).upper()
			data = imdb_api.imdb_blunders(self.imdb_id)
			item_list = list(builder())
			self.setProperty('alkoskins.extras.imdb_blunders.number', '(x%02d)' % len(item_list))
			self.item_action_dict[blunders_id] = 'alkoskins.extras.text'
			self.add_items(blunders_id, item_list)
		except Exception as exc:
			log_info_window_error('Extras', 'make_blunders', exc)

	def make_parentsguide(self):
		if parentsguide_id not in self.enabled_lists: return
		def builder():
			for item in data:
				try:
					name, icon = parentsguide_dict[item['title']]
					icon = '%s%s' % (icon_path, icon)
					ranking = parentsguide_dict[item['ranking']].upper()
					if item['listings']: ranking += ' (x%02d)' % len(item['listings'])
					listitem = self.make_listitem()
					listitem.setProperty('alkoskins.extras.name', name)
					listitem.setProperty('alkoskins.extras.ranking', ranking)
					listitem.setProperty('alkoskins.extras.thumbnail', icon)
					listitem.setProperty('alkoskins.extras.listings', json.dumps(item['listings']))
					yield listitem
				except: pass
		try:
			icon_path = media_path()
			data = mdblist_api.mdbl_parentsguide(self.imdb_id, self.media_type)
			item_list = list(builder())
			self.setProperty('alkoskins.extras.imdb_parentsguide.number', '(x%02d)' % len(item_list))
			self.item_action_dict[parentsguide_id] = 'alkoskins.extras.listings'
			self.add_items(parentsguide_id, item_list)
		except Exception as exc:
			log_info_window_error('Extras', 'make_parentsguide', exc)

	def make_videos(self):
		if videos_id not in self.enabled_lists: return
		def builder():
			for count, item in enumerate(data, 1):
				try:
					listitem = self.make_listitem()
					listitem.setProperty('alkoskins.extras.name', '%01d. %s' % (count, item['title']))
					listitem.setProperty('alkoskins.extras.thumbnail', item['poster'])
					listitem.setProperty('alkoskins.extras.qualities', json.dumps(item['videos']))
					yield listitem
				except: pass
		try:
			data = imdb_api.imdb_videos(self.imdb_id)
			item_list = list(builder())
			self.setProperty('alkoskins.extras.imdb_videos.number', '(x%02d)' % len(item_list))
			self.item_action_dict[videos_id] = 'alkoskins.extras.qualities'
			self.add_items(videos_id, item_list)
		except Exception as exc:
			log_info_window_error('Extras', 'make_videos', exc)

	def make_artwork_sections(self):
		# TMDb retourne posters et backdrops dans la même réponse. Avant, chaque
		# section relançait son propre appel API/cache. On récupère donc le bloc
		# d'images une seule fois, puis on alimente les deux listes au besoin.
		try:
			dbtype = 'movie' if self.media_type == 'movie' else 'tv'
			image_data = tmdb_api.tmdb_media_images(dbtype, self.tmdb_id)
			if posters_id in self.enabled_lists:
				self.populate_artwork_list('posters', image_data.get('posters', []))
			if backdrops_id in self.enabled_lists:
				self.populate_artwork_list('backdrops', image_data.get('backdrops', []))
		except Exception as exc:
			log_info_window_error('Extras', 'make_artwork_sections', exc)

	def populate_artwork_list(self, image_type, data):
		_id = posters_id if image_type == 'posters' else backdrops_id
		def builder():
			for count, item in enumerate(data, 1):
				try:
					thumb_url = tmdb_image_base % ('w780', item['file_path'])
					name = '%sx%s' % (item['height'], item['width'])
					listitem = self.make_listitem()
					listitem.setProperty('alkoskins.extras.name', '%01d. %s' % (count, name))
					listitem.setProperty('alkoskins.extras.thumbnail', thumb_url)
					listitem.setProperty('alkoskins.extras.all_images', json_all_images)
					yield listitem
				except: pass
		try:
			data.sort(key=lambda x: x['file_path'])
			json_all_images = json.dumps([(tmdb_image_base % ('original', i['file_path']), '%sx%s' % (i['height'], i['width'])) for i in data])
			item_list = list(builder())
			self.setProperty('alkoskins.extras.tmdb_artwork.%s.number' % image_type, '(x%02d)' % len(item_list))
			self.item_action_dict[_id] = 'alkoskins.extras.all_images'
			self.add_items(_id, item_list)
		except Exception as exc:
			log_info_window_error('Extras', 'populate_artwork_list(%s)' % image_type, exc)

	def make_year(self):
		if year_id not in self.enabled_lists: return
		try:
			function = tmdb_api.tmdb_movies_year if self.media_type == 'movie' else tmdb_api.tmdb_tv_year
			data = self.remove_current_tmdb_mediaitem(function(self.year, 1)['results'])
			item_list = list(self.make_tmdb_listitems(data))
			self.setProperty('alkoskins.extras.more_from_year.number', '(x%02d)' % len(item_list))
			self.item_action_dict[year_id] = 'alkoskins.extras.tmdb_id'
			self.add_items(year_id, item_list)
		except Exception as exc:
			log_info_window_error('Extras', 'make_year', exc)

	def make_genres(self):
		if genres_id not in self.enabled_lists: return
		try:
			function = tmdb_api.tmdb_movies_genres if self.media_type == 'movie' else tmdb_api.tmdb_tv_genres
			genre_dict = dialogs.genres_choice(self.media_type, self.genre, '', return_genres=True, genre_ids=self.meta.get('genre_ids'))
			genre_list = ','.join([i['value'][0] for i in genre_dict])
			log_info_window_event('Extras', 'make_genres tmdb_id=%s genre_ids=%s resolved=%s' % (self.tmdb_id, self.meta.get('genre_ids'), genre_list))
			if not genre_list: return
			data = self.remove_current_tmdb_mediaitem(function(genre_list, 1)['results'])
			item_list = list(self.make_tmdb_listitems(data))
			self.setProperty('alkoskins.extras.more_from_genres.number', '(x%02d)' % len(item_list))
			self.item_action_dict[genres_id] = 'alkoskins.extras.tmdb_id'
			self.add_items(genres_id, item_list)
		except Exception as exc:
			log_info_window_error('Extras', 'make_genres', exc)

	def make_network(self):
		if networks_id not in self.enabled_lists: return
		try:
			network = self.meta['studio']
			if self.media_type == 'movie': network_id = [i['id'] for i in tmdb_api.tmdb_company_id(network)['results'] if i['name'] == network][0]
			else: network_id = [item['id'] for item in networks if 'name' in item and item['name'] == network][0]
			function = tmdb_api.tmdb_movies_networks if self.media_type == 'movie' else tmdb_api.tmdb_tv_networks
			data = self.remove_current_tmdb_mediaitem(function(network_id, 1)['results'])
			item_list = list(self.make_tmdb_listitems(data))
			self.setProperty('alkoskins.extras.more_from_networks.number', '(x%02d)' % len(item_list))
			self.item_action_dict[networks_id] = 'alkoskins.extras.tmdb_id'
			self.add_items(networks_id, item_list)
		except Exception as exc:
			log_info_window_error('Extras', 'make_network', exc)

	def make_collection(self):
		if collection_id not in self.enabled_lists: return
		try: coll_id = self.meta['extra_info']['collection_id']
		except: coll_id = self.meta['extra_info']['ei_collection_id']
		if not coll_id: return
		try:
			data = tmdb_api.tmdb_movies_collection(coll_id)
			poster_path = data['poster_path']
			if poster_path: poster = tmdb_image_base % (self.poster_resolution, poster_path)
			else: poster = poster_empty
			self.setProperty('alkoskins.extras.more_from_collection.name', data['name'])
			self.setProperty('alkoskins.extras.more_from_collection.overview', data['overview'])
			self.setProperty('alkoskins.extras.more_from_collection.poster', poster)
			item_list = list(self.make_tmdb_listitems(sorted(data['parts'], key=lambda k: k['release_date'] or '2050')))
			self.setProperty('alkoskins.extras.more_from_collection.number', '(x%02d)' % len(item_list))
			self.item_action_dict[collection_id] = 'alkoskins.extras.tmdb_id'
			self.add_items(collection_id, item_list)
		except Exception as exc:
			log_info_window_error('Extras', 'make_collection', exc)

	def get_release_year(self, release_data):
		try:
			if release_data in ('', None): release_data = 'N/A'
			else: release_data = release_data.split('-')[0]
		except: pass
		return release_data

	def get_user_rating_display(self):
		def _format_rating(value):
			try:
				value = int(float(value) + 0.5)
			except:
				return ''
			if value < 1 or value > 10: return ''
			return '%s' % value
		try:
			value = self.meta.get('userrating') or self.meta.get('user_rating')
			value = _format_rating(value)
			if value: return value
		except: pass
		try:
			media_type = 'tvshow' if self.media_type in ('tvshow', 'show') else self.media_type
			if media_type not in ('movie', 'tvshow'): return ''
			index = user_ratings.get_active_ratings_index()
			rating = user_ratings.get_user_rating(
				index,
				media_type,
				tmdb_id=self.tmdb_id,
				imdb_id=self.imdb_id,
				tvdb_id=self.meta.get('tvdb_id')
			)
			return _format_rating(rating)
		except:
			return ''

	def get_finish(self):
		if self.percent_watched in ('0', '100') and self.listitem_check():
			finished = self.get_infolabel('ListItem.EndTime')
		else:
			kodi_clock = self.get_infolabel('System.Time')
			if any(i in kodi_clock for i in ['AM', 'PM']): _format = '%I:%M %p'
			else: _format = '%H:%M'
			current_time = datetime.now()
			remaining_time = ((100 - int(self.percent_watched))/100) * self.duration_data
			finish_time = current_time + timedelta(minutes=remaining_time)
			finished = finish_time.strftime(_format)
		return '%s: %s' % (ls(32791), finished)

	def get_duration(self):
		if is_collection_type(self.media_type):
			count = self.meta.get('parts_count') or len(self.meta.get('parts', []) or [])
			return '%s films' % count if count else 'N/A'
		if self.media_type == 'movie':
			return ls(32788) % self.duration_data if self.duration_data else 'N/A'
		try:
			total_seasons = int(self.meta.get('total_seasons') or 0)
		except:
			total_seasons = 0
		try:
			total_episodes = int(self.meta.get('total_aired_eps') or self.meta.get('total_episodes') or 0)
		except:
			total_episodes = 0
		if total_seasons:
			label = ls(32636).lower()
			if total_seasons == 1 and label.endswith('s'): label = label[:-1]
			return '%s %s' % (total_seasons, label)
		if total_episodes:
			label = ls(32506).lower()
			if total_episodes == 1 and label.endswith('s'): label = label[:-1]
			return '%s %s' % (total_episodes, label)
		return 'N/A'

	def get_progress(self):
		try: resume_point, curr_time, resume_id = ws.detect_bookmark(ws.get_bookmarks(self.watched_indicators, 'movie'), self.tmdb_id)
		except: resume_point = 0
		if resume_point in (0, '0', 0.0, '0.0'):
			watched_info = ws.get_watched_info_movie(self.watched_indicators)
			playcount, overlay = ws.get_watched_status_movie(watched_info, str(self.tmdb_id))
			self.meta.update({'playcount': playcount, 'overlay': overlay})
			if playcount == 1: self.percent_watched = '100'
			else: self.percent_watched = '0'
		else: self.percent_watched = str(int(float(resume_point)))
		progress_status = '%s%% %s' % (self.percent_watched, ls(32475))
		return progress_status

	def get_last_aired(self):
		extra_info = self.meta['extra_info']
		if extra_info.get('last_episode_to_air', False):
			last_ep = extra_info['last_episode_to_air']
			last_aired = 'S%.2dE%.2d' % (last_ep['season_number'], last_ep['episode_number'])
		else: return ''
		return '%s: %s' % (ls(32634), last_aired)

	def get_next_aired(self):
		extra_info = self.meta['extra_info']
		if extra_info.get('next_episode_to_air', False):
			next_ep = extra_info['next_episode_to_air']
			next_aired = 'S%.2dE%.2d' % (next_ep['season_number'], next_ep['episode_number'])
		else: return ''
		return '%s: %s' % (ls(32635), next_aired)

	def get_next_episode(self):
		watched_info = ws.get_watched_info_tv(self.watched_indicators)
		ep_list = ws.get_next_episodes(watched_info)
		try: info = [i for i in ep_list if i['media_ids']['tmdb'] == self.tmdb_id][0]
		except: return ''
		current_season = info['season']
		current_episode = info['episode']
		season_data = self.meta['season_data']
		curr_season_data = [i for i in season_data if i['season_number'] == current_season][0]
		season = current_season if current_episode < curr_season_data['episode_count'] else current_season + 1
		episode = current_episode + 1 if current_episode < curr_season_data['episode_count'] else 1
		try: info = [i for i in season_data if i['season_number'] == season][0]
		except: return ''
		if info['episode_count'] >= episode:
			next_episode = 'S%.2dE%.2d' % (season, episode)
			return '%s: %s' % (ls(32999), next_episode)
		else: return ''

	def get_stingers(self):
		if not self.tmdb_id: return ''
		stingers = {'duringcreditsstinger': ls(33176), 'aftercreditsstinger': ls(33177)}
		keywords = tmdb_api.movie_keywords(self.tmdb_id) or []
		keywords = [str(i['name']) for i in keywords]
		if all((i in keywords for i in stingers.keys())): stinger = ls(33178)
		else: stinger = next((v for k, v in stingers.items() if k in keywords), None)
		return stinger if stinger else ''

	def make_tvshow_browse_params(self):
		total_seasons = self.meta['total_seasons']
		all_episodes = settings.default_all_episodes()
		show_all_episodes = True if all_episodes in (1, 2) else False
		if show_all_episodes:
			if all_episodes == 1 and total_seasons > 1: url_params = {'mode': 'build_season_list', 'tmdb_id': self.tmdb_id}
			else: url_params = {'mode': 'build_episode_list', 'tmdb_id': self.tmdb_id, 'season': 'all'}
		else: url_params = {'mode': 'build_season_list', 'tmdb_id': self.tmdb_id}
		return url_params

	def original_poster(self):
		poster = settings.resolve_poster_art(self.meta, backup_thumbnail)
		self.current_poster = poster
		if 'image.tmdb' in self.current_poster:
			try: poster = self.current_poster.replace('w185', 'original').replace('w342', 'original').replace('w780', 'original')
			except: pass
		elif 'fanart.tv' in self.current_poster:
			if not self.check_poster_cached(self.current_poster): self.current_poster = self.meta.get(self.poster_backup) or backup_thumbnail
		return poster

	def original_fanart(self):
		fanart = self.meta.get(self.fanart_main) or self.meta.get(self.fanart_backup) or fanart_empty
		return fanart

	def remove_current_tmdb_mediaitem(self, data):
		return [i for i in data if int(i['id']) != self.tmdb_id]

	def make_tmdb_listitems(self, data):
		name_key = 'title' if self.media_type == 'movie' else 'name'
		release_key = 'release_date' if self.media_type == 'movie' else 'first_air_date'
		for item in data:
			try:
				poster_path = item['poster_path']
				if poster_path: thumbnail = tmdb_image_base % (self.poster_resolution, poster_path)
				else: thumbnail = poster_empty
				year = self.get_release_year(item[release_key])
				listitem = self.make_listitem()
				listitem.setProperty('alkoskins.extras.name', item[name_key])
				listitem.setProperty('alkoskins.extras.release_date', year)
				listitem.setProperty('alkoskins.extras.vote_average', '%.1f' % item['vote_average'])
				listitem.setProperty('alkoskins.extras.thumbnail', thumbnail)
				listitem.setProperty('alkoskins.extras.tmdb_id', str(item['id']))
				yield listitem
			except: pass

	def listitem_check(self):
		return self.get_infolabel('ListItem.Title') == self.meta['title']

	def add_items(self, _id, items):
		if self.is_closing(): return
		try:
			control = self.getControl(_id)
			if items: control.addItems(items)
		except Exception as exc:
			log_info_window_error('Extras', 'add_items control=%s' % _id, exc)


	def set_poster(self):
		if self.is_closing(): return
		try:
			if self.current_poster:
				poster_control = self.getControl(200)
				fallback_control = self.getControl(201)
				poster_control.setImage(self.current_poster)
				fallback_control.setImage(self.poster)
				total_time = 0
				while not self.check_poster_cached(self.poster):
					if self.is_closing() or total_time >= 200: break
					total_time += 1
					self.sleep(50)
				if not self.is_closing(): poster_control.setImage(self.poster)
			else: self.setProperty('alkoskins.extras.active_poster', 'false')
		except Exception as exc:
			log_info_window_error('Extras', 'set_poster', exc)

	def check_poster_cached(self, poster):
		try:
			if poster == backup_thumbnail: return True
			if fetch_kodi_imagecache(poster): return True
			return False
		except: return True

	def set_starting_constants(self, kwargs):
		self.item_action_dict = {}
		self.selected = None
		self.is_widget = kwargs['is_widget'].lower()
		self.is_home = kwargs['is_home'].lower()
		self.meta = kwargs['meta']
		self.media_type = self.meta['mediatype']#movie, tvshow, collection
		self.fav_type = self.meta.get('fav_type') or favourite_type_from_context(self.media_type, {}, '', self.meta)
		self.tmdb_id = self.meta['tmdb_id']
		self.imdb_id = self.meta.get('imdb_id', 'None')
		if self.is_widget == 'true' or self.is_home == 'true': self.folder_runner = 'ActivateWindow(Videos,%s,return)'
		else: self.folder_runner = 'Container.Update(%s)'
		self.plugin_runner = 'RunPlugin(%s)'
		self.enabled_lists = settings.extras_enabled_menus()
		self.enable_scrollbars = settings.extras_enable_scrollbars()
		self.poster_resolution = settings.get_resolution()['poster']
		self.watched_indicators = settings.watched_indicators()
		self.poster_main, self.poster_backup, self.fanart_main, self.fanart_backup = settings.get_art_provider()
		self.title = self.meta['title']
		self.year = str(self.meta['year'])
		self.rootname = self.meta['rootname']
		self.poster = self.original_poster()
		self.fanart = self.original_fanart()
		self.clearlogo = self.meta['clearlogo'] if settings.get_fanart_data() else self.meta['tmdblogo'] or ''
		self.plot = self.meta['tvshow_plot'] if 'tvshow_plot' in self.meta else self.meta['plot']
		if not self.plot: self.plot = ''
		self.rating = '%.2f' % self.meta['rating']
		self.user_rating = self.get_user_rating_display()
		self.mpaa = self.meta['mpaa']
		self.status_raw = self.meta['extra_info'].get('status', '').replace('Series', '')
		self.status = translate_status(self.status_raw)
		self.genre = self.meta['genre']
		self.network = self.meta['studio'] or 'N/A'
		if not self.network: self.network = ''
		try: self.duration_data = int(float(self.meta.get('duration', 0))/60)
		except: self.duration_data = 0
		self.duration = self.get_duration()
		if is_collection_type(self.media_type):
			self.progress, self.finish_watching = '', ''
			self.last_aired_episode, self.next_aired_episode, self.next_episode = '', '', ''
			self.stingers = ''
		elif self.media_type == 'movie':
			self.progress = self.get_progress()
			self.finish_watching = self.get_finish()
			self.last_aired_episode, self.next_aired_episode, self.next_episode = '', '', ''
			self.stingers = self.get_stingers()
		else:
			self.progress, self.finish_watching = '', ''
			self.last_aired_episode = self.get_last_aired()
			if self.status_raw not in ('', 'Ended', 'Canceled', 'Cancelled'): self.next_aired_episode = self.get_next_aired()
			else: self.next_aired_episode = ''
			self.next_episode = self.get_next_episode()
			self.stingers = ''

	def set_properties(self):
		self.setProperty('alkoskins.extras.media_type', translate_media_type(self.media_type))
		self.setProperty('alkoskins.extras.fanart', self.fanart)
		self.setProperty('alkoskins.extras.poster', self.poster)
		self.setProperty('alkoskins.extras.clearlogo', self.clearlogo)
		self.setProperty('alkoskins.extras.title', self.title)
		self.setProperty('alkoskins.extras.plot', self.plot)
		self.setProperty('alkoskins.extras.year', self.year)
		self.setProperty('alkoskins.extras.rating', self.rating)
		self.setProperty('alkoskins.extras.user_rating', self.user_rating)
		self.setProperty('alkoskins.extras.label.year', ls(32543))
		self.setProperty('alkoskins.extras.label.duration', ls(32622))
		self.setProperty('alkoskins.extras.label.tmdb_rating', 'TMDb')
		self.setProperty('alkoskins.extras.label.user_rating', ls(33213))
		self.setProperty('alkoskins.extras.label.mpaa', ls(32632))
		self.setProperty('alkoskins.extras.label.status', ls(32630))
		self.setProperty('alkoskins.extras.mpaa', self.mpaa)
		self.setProperty('alkoskins.extras.status', self.status)
		self.setProperty('alkoskins.extras.genre', self.genre)
		self.setProperty('alkoskins.extras.network', self.network)
		self.setProperty('alkoskins.extras.duration', self.duration)
		self.setProperty('alkoskins.extras.progress', self.progress)
		self.setProperty('alkoskins.extras.finish_watching', self.finish_watching)
		self.setProperty('alkoskins.extras.last_aired_episode', self.last_aired_episode)
		self.setProperty('alkoskins.extras.next_aired_episode', self.next_aired_episode)
		self.setProperty('alkoskins.extras.next_episode', self.next_episode)
		self.setProperty('alkoskins.extras.stingers', self.stingers)
		self.setProperty('alkoskins.extras.enable_scrollbars', self.enable_scrollbars)

class ShowTextMedia(BaseDialog):
	def __init__(self, *args, **kwargs):
		BaseDialog.__init__(self, args)
		self.text = kwargs.get('text')
		self.poster = kwargs.get('poster')
		self.title = kwargs.get('title') or 'Info & Extra'
		self.subtitle = kwargs.get('subtitle') or ''
		self.focus_id = 2060
		self.set_properties()

	def onInit(self):
		self.safe_set_focus(self.focus_id)

	def run(self):
		self.doModal()
		self.clearProperties()




	def onAction(self, action):
		if action in self.closing_actions: return self.close()

	def set_properties(self):
		self.setProperty('alkoskins.text_media.text', self.text)
		self.setProperty('alkoskins.text_media.poster', self.poster)
		self.setProperty('alkoskins.text_media.title', self.title)
		self.setProperty('alkoskins.text_media.subtitle', self.subtitle)

def media_extra_info(media_type, meta):
	extra_info = meta.get('extra_info')
	body = []
	append = body.append
	tagline_str, plot_str, premiered_str, rating_str, votes_str, runtime_str = ls(32619), ls(33168), ls(32620), ls(32621), ls(32623), ls(32622)
	genres_str, budget_str, revenue_str, director_str, writer_str = ls(32624), ls(32625), ls(32626), ls(32627), ls(32628)
	studio_str, collection_str, homepage_str, status_str, type_str, classification_str = ls(32615), ls(32499), ls(32629), ls(32630), ls(32631), ls(32632)
	network_str, created_by_str, last_aired_str, next_aired_str, seasons_str, episodes_str = ls(32480), ls(32633), ls(32634), ls(32635), ls(32636), ls(32506)
	try:
		if is_collection_type(media_type):
			if 'plot' in meta and meta['plot']: append('[B]%s:[/B] %s' % (plot_str, meta['plot']))
			append('[B]Type:[/B] Saga')
			append('[B]Films:[/B] %s' % (meta.get('parts_count') or len(meta.get('parts', []) or [])))
			if meta.get('year') not in ('', 'N/A', None): append('[B]%s:[/B] %s' % (premiered_str, meta.get('year')))
			parts = []
			for item in meta.get('parts', []) or []:
				title = item.get('title') or item.get('name') or item.get('original_title') or ''
				year = str(item.get('release_date') or '')[:4]
				if title: parts.append('%s%s' % (title, ' (%s)' % year if year else ''))
			if parts: append('[B]Contenu:[/B] %s' % ', '.join(parts))
		elif media_type == 'movie':
			def _process_budget_revenue(info):
				if isinstance(info, int): info = '${:,}'.format(info)
				return info
			if 'tagline' in meta and meta['tagline']: append('[B]%s:[/B] %s' % (tagline_str, meta['tagline']))
			if 'plot' in meta and meta['plot']: append('[B]%s:[/B] %s' % (plot_str, meta['plot']))
			if 'alternative_titles' in meta and meta['alternative_titles']: append('[B]%s:[/B] %s' % (ls(33169), ', '.join(meta['alternative_titles'])))
			if 'status' in extra_info: append('[B]%s:[/B] %s' % (status_str, translate_status(extra_info['status'])))
			append('[B]%s:[/B] %s' % (premiered_str, meta['premiered']))
			append('[B]%s:[/B] %s (%s %s)' % (rating_str, meta['rating'], meta['votes'], votes_str))
			append('[B]%s:[/B] %d %s' % (runtime_str, int(float(meta['duration'])/60), ls(33170)))
			append('[B]%s:[/B] %s' % (genres_str, meta['genre']))
			if 'budget' in extra_info: append('[B]%s:[/B] %s' % (budget_str, _process_budget_revenue(extra_info['budget'])))
			if 'revenue' in extra_info: append('[B]%s:[/B] %s' % (revenue_str, _process_budget_revenue(extra_info['revenue'])))
			append('[B]%s:[/B] %s' % (director_str, meta['director']))
			append('[B]%s:[/B] %s' % (writer_str, meta['writer'] or 'N/A'))
			append('[B]%s:[/B] %s' % (studio_str, meta['studio'] or 'N/A'))
			if extra_info.get('collection_name'): append('[B]%s:[/B] %s' % (collection_str, extra_info['collection_name']))
			if extra_info.get('homepage'): append('[B]%s:[/B] %s' % (homepage_str, extra_info['homepage']))
		else:
			if 'plot' in meta and meta['plot']: append('[B]%s:[/B] %s' % (plot_str, meta['plot']))
			if 'type' in extra_info: append('[B]%s:[/B] %s' % (type_str, extra_info['type']))
			if 'alternative_titles' in meta and meta['alternative_titles']: append('[B]%s:[/B] %s' % (ls(33169), ', '.join(meta['alternative_titles'])))
			if 'status' in extra_info: append('[B]%s:[/B] %s' % (status_str, translate_status(extra_info['status'])))
			append('[B]%s:[/B] %s' % (premiered_str, meta['premiered']))
			append('[B]%s:[/B] %s (%s %s)' % (rating_str, meta['rating'], meta['votes'], votes_str))
			append('[B]%s:[/B] %d %s' % (runtime_str, int(float(meta['duration'])/60), ls(33170)))
			append('[B]%s:[/B] %s' % (classification_str, meta['mpaa']))
			append('[B]%s:[/B] %s' % (genres_str, meta['genre']))
			append('[B]%s:[/B] %s' % (network_str, meta['studio']))
			if 'created_by' in extra_info: append('[B]%s:[/B] %s' % (created_by_str, extra_info['created_by']))
			if extra_info.get('last_episode_to_air', False):
				last_ep = extra_info['last_episode_to_air']
				lastep_str = '[%s] S%.2dE%.2d - %s' % (last_ep['air_date'], last_ep['season_number'], last_ep['episode_number'], last_ep['name'])
				append('[B]%s:[/B] %s' % (last_aired_str, lastep_str))
			if extra_info.get('next_episode_to_air', False):
				next_ep = extra_info['next_episode_to_air']
				nextep_str = '[%s] S%.2dE%.2d - %s' % (next_ep['air_date'], next_ep['season_number'], next_ep['episode_number'], next_ep['name'])
				append('[B]%s:[/B] %s' % (next_aired_str, nextep_str))
			append('[B]%s:[/B] %s' % (seasons_str, meta['total_seasons']))
			append('[B]%s:[/B] %s' % (episodes_str, meta['total_aired_eps']))
			if 'homepage' in extra_info: append('[B]%s:[/B] %s' % (homepage_str, extra_info['homepage']))
	except: return notification(32574)
	return '\n\n'.join(body)

