# -*- coding: utf-8 -*-

import datetime
import sys, requests
PY3 = False
if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int

if PY3:
    import urllib.parse as urllib                               # It is very slow in PY2. In PY3 it is native
    from concurrent import futures
else:
    import urllib                                               # We use the native of PY2 which is faster
    from concurrent_py2 import futures

from future.builtins import range
from future.builtins import object

import ast, copy, re, time

from core import filetools, httptools, jsontools, scrapertools
from core.item import InfoLabels
from platformcode import config, logger, platformtools
import threading

info_language = ["de", "en", "es", "fr", "it", "pt"] # from videolibrary.json
def_lang = info_language[config.get_setting("info_language", "videolibrary")]

host = 'https://api.themoviedb.org/3'
api = 'a1ab8b8669da03637a4b98fa39c39228'

""" 
    Set of functions related to infoLabels.
    version 1.0:
    Initial version

    Include:
    - set_infoLabels (source, seekTmdb, search_language): Gets and sets (item.infoLabels) the extra data of one or several series, chapters or movies.
    - set_infoLabels_item (item, seekTmdb, search_language): Gets and sets (item.infoLabels) the extra data of a series, chapter or movie.
    - set_infoLabels_itemlist (item_list, seekTmdb, search_language): Gets and sets (item.infoLabels) the data extras from a list of series, chapters or movies.
    - infoLabels_tostring (item): Returns a str with the list ordered with the item's infoLabels

    Usage:
    - tmdb.set_infoLabels (item, seekTmdb = True)

    Get basic data from a movie:
    Before calling the set_infoLabels method the title to search for must be in item.contentTitle and the year in item.infoLabels ['year'].

    Obtain basic data from a series:
    Before calling the set_infoLabels method the title to search for must be in item.show or in item.contentSerieName.

    Get more data from a movie or series:
    After obtaining the basic data in item.infoLabels ['tmdb'] we will have the code of the series or movie.
    We could also directly set this code, if known, or use the corresponding code of:
    IMDB (in item.infoLabels ['IMDBNumber'] or item.infoLabels ['code'] or item.infoLabels ['imdb_id']), TVDB (only series, in item.infoLabels ['tvdb_id']),
    Freebase (series only, on item.infoLabels ['freebase_mid']), TVRage (series only, on item.infoLabels ['tvrage_id'])

    Get data from a season:
    Before calling the set_infoLabels method the series title must be in item.show or in item.contentSerieName,
    the series TMDB code must be in item.infoLabels ['tmdb'] (it can be set automatically by the basic data query)
    and the season number must be in item.infoLabels ['season'].

    Get data from an episode:
    Before calling the set_infoLabels method the series title must be in item.show or in item.contentSerieName,
    the TMDB code of the series must be in item.infoLabels ['tmdb'] (it can be set automatically using the basic data query),
    the season number must be in item.infoLabels ['season'] and the episode number must be in item.infoLabels ['episode'].
"""
otmdb_global = None
from core import db


def clean_cache():
    db['tmdb_cache'].clear()


# The function name is the name of the decorator and receives the function that decorates.
def cache_response(fn):
    logger.debug()

    # import time
    # start_time = time.time()

    def wrapper(*args, **kwargs):
        def check_expired(saved_date):
            valided = False

            cache_expire = config.get_setting("tmdb_cache_expire", default=0)
            current_date = datetime.datetime.now()
            elapsed = current_date - saved_date

            # 1 day
            if cache_expire == 0:
                if elapsed > datetime.timedelta(days=1):
                    valided = False
                else:
                    valided = True
            # 7 days
            elif cache_expire == 1:
                if elapsed > datetime.timedelta(days=7):
                    valided = False
                else:
                    valided = True

            # 15 days
            elif cache_expire == 2:
                if elapsed > datetime.timedelta(days=15):
                    valided = False
                else:
                    valided = True

            # 1 month - 30 days
            elif cache_expire == 3:
                # we do not take into account February or months with 31 days
                if elapsed > datetime.timedelta(days=30):
                    valided = False
                else:
                    valided = True
            # no expire
            elif cache_expire == 4:
                valided = True

            return valided

        result = {}
        try:

            # cache is not active
            if not config.get_setting("tmdb_cache", default=False) or not kwargs.get('cache', True):
                logger.debug('no cache')
                result = fn(*args)
            else:

                url = args[0].replace('&year=-', '').replace('&primary_release_year=-', '').replace('&first_air_date_year=-', '')
                # if PY3: url = str.encode(url)

                row = db['tmdb_cache'].get(url)

                if row and check_expired(row[1]):
                    result = row[0]

                # si no se ha obtenido información, llamamos a la funcion
                if not result.get('results'):
                    result = fn(*args)
                    db['tmdb_cache'][url] = [result, datetime.datetime.now()]

            # elapsed_time = time.time() - start_time
            # logger.debug("TARDADO %s" % elapsed_time)

        # error getting data
        except Exception as ex:
            message = "An exception of type {} occured. Arguments:\n{}".format(type(ex).__name__, repr(ex.args))
            logger.error("error in:", message)

        return result

    return wrapper


def set_infoLabels(source, seekTmdb=True, search_language=def_lang, forced=False):
    """
    Depending on the data type of source, it obtains and sets (item.infoLabels) the extra data of one or more series, chapters or movies.

    @param source: variable that contains the information to set infoLabels
    @type source: list, item
    @param seekTmdb: if it is True, it searches www.themoviedb.org to obtain the data, otherwise it obtains the data of the Item itself.
    @type seekTmdb: bool
    @param search_language: set the language value in case of search at www.themoviedb.org
    @type search_language: str
    @return: a number or list of numbers with the result of the calls to set_infoLabels_item
    @rtype: int, list
    """

    if not config.get_setting('tmdb_active') and not forced:
        return

    start_time = time.time()
    if type(source) == list:
        ret = set_infoLabels_itemlist(source, seekTmdb, search_language)
        logger.debug("The data of {} links were obtained in {} seconds".format(len(source), time.time() - start_time))
    else:
        ret = set_infoLabels_item(source, seekTmdb, search_language)
        logger.debug("The data were obtained in {} seconds".format(time.time() - start_time))
    return ret


def set_infoLabels_itemlist(itemlist, seekTmdb=False, search_language=def_lang, forced=False):
    """
    Concurrently, it gets the data of the items included in the item_list.

    The API in the past had a limit of 40 requests per IP every 10 '', now there's no limit (https://developers.themoviedb.org/3/getting-started/request-rate-limiting)
    If a limit will be re-added uncomment "tmdb_threads" and related code

    @param item_list: list of Item objects that represent movies, series or chapters. The infoLabels attribute of each Item object will be modified including the extra localized data.
    @type item_list: list
    @param seekTmdb: If it is True, it searches www.themoviedb.org to obtain the data, otherwise it obtains the data of the Item itself if they exist.
    @type seekTmdb: bool
    @param search_language: Language code according to ISO 639-1, in case of search at www.themoviedb.org.
    @type search_language: str

    @return: A list of numbers whose absolute value represents the number of elements included in the infoLabels attribute of each Item. This number will be positive if the data has been obtained from www.themoviedb.org and negative otherwise.
    @rtype: list
    """

    if not config.get_setting('tmdb_active') and not forced:
        return

    r_list = list()

    def sub_thread(_item, _i, _seekTmdb):
        ret = 0
        try:
            ret = set_infoLabels_item(_item, _seekTmdb, search_language)
        except:
            import traceback
            logger.error(traceback.format_exc(1))

        return (_i, _item, ret)
    # from core.support import dbg;dbg()
    # for i, item in enumerate(itemlist):
    #     r_list.append(sub_thread(item, i, seekTmdb))
    with futures.ThreadPoolExecutor() as executor:
        searchList = [executor.submit(sub_thread, item, i, seekTmdb) for i, item in enumerate(itemlist)]
        for res in futures.as_completed(searchList):
            r_list.append(res.result())


    # Sort results list by call order to keep the same order q itemlist
    r_list.sort(key=lambda i: i[0])

    # Rebuild and return list only with results of individual calls
    return [it[2] for it in r_list]


def set_infoLabels_item(item, seekTmdb=True, search_language=def_lang):
    """
    Gets and sets (item.infoLabels) the extra data of a series, chapter or movie.

    @param item: Item object that represents a movie, series or chapter. The infoLabels attribute will be modified including the extra localized data.
    @type item: Item
    @param seekTmdb: If it is True, it searches www.themoviedb.org to obtain the data, otherwise it obtains the data of the Item itself if they exist.
    @type seekTmdb: bool
    @param search_language: Language code according to ISO 639-1, in case of search at www.themoviedb.org.
    @type search_language: str
    @return: A number whose absolute value represents the number of elements included in the item.infoLabels attribute. This number will be positive if the data has been obtained from www.themoviedb.org and negative otherwise.
    @rtype: int
    """
    global otmdb_global

    def read_data(otmdb_aux):
        # item.infoLabels = otmdb_aux.get_infoLabels(item.infoLabels)
        infoLabels = otmdb_aux.get_infoLabels(item.infoLabels)
        if not infoLabels.get('plot'): infoLabels['plot'] = otmdb_aux.get_plot('en')
        item.infoLabels = infoLabels
        if item.infoLabels.get('thumbnail'):
            item.thumbnail = item.infoLabels['thumbnail']
        if item.infoLabels.get('fanart'):
            item.fanart = item.infoLabels['fanart']

    if seekTmdb:
        def search(otmdb_global, search_type):
            if item.infoLabels.get('season'):
                try:
                    seasonNumber = int(item.infoLabels['season'])
                except ValueError:
                    logger.debug("The season number is not valid.")
                    return -1 * len(item.infoLabels)

                if not otmdb_global or (item.infoLabels['tmdb_id'] and str(otmdb_global.result.get("id")) != item.infoLabels['tmdb_id']) \
                        or (otmdb_global.searched_text and otmdb_global.searched_text != item.infoLabels['tvshowtitle']):
                    if item.infoLabels['tmdb_id']:
                        otmdb_global = Tmdb(id_Tmdb=item.infoLabels['tmdb_id'], search_type=search_type,
                                            search_language=search_language)
                    else:
                        otmdb_global = Tmdb(searched_text=scrapertools.unescape(item.infoLabels['tvshowtitle']), search_type=search_type,
                                            search_language=search_language, year=item.infoLabels['year'])

                    read_data(otmdb_global)

                if item.infoLabels['episode']:
                    try:
                        ep = int(item.infoLabels['episode'])
                    except ValueError:
                        logger.debug("The episode number ({}) is not valid".format(repr(item.infoLabels['episode'])))
                        return -1 * len(item.infoLabels)

                    # We have valid season number and episode number...
                    # ... search episode data
                    item.infoLabels['mediatype'] = 'episode'
                    episode = otmdb_global.get_episode(seasonNumber, ep)

                    if episode:
                        # Update data
                        read_data(otmdb_global)
                        item.infoLabels['mediatype'] = 'episode'
                        if episode.get('episode_title'):
                            item.infoLabels['title'] = episode['episode_title']
                        if episode.get('episode_plot'):
                            item.infoLabels['plot'] = episode['episode_plot']
                        if episode.get('episode_image'):
                            item.infoLabels['poster_path'] = episode['episode_image']
                            item.thumbnail = item.infoLabels['poster_path']
                        if episode.get('episode_air_date'):
                            item.infoLabels['aired'] = episode['episode_air_date']
                        if episode.get('episode_vote_average'):
                            item.infoLabels['rating'] = episode['episode_vote_average']
                        if episode.get('episode_vote_count'):
                            item.infoLabels['votes'] = episode['episode_vote_count']
                        if episode.get('episode_id'):
                            item.infoLabels['episode_id'] = episode['episode_id']
                        if episode.get('episode_imdb_id'):
                            item.infoLabels['episode_imdb_id'] = episode['episode_imdb_id']
                        if episode.get('episode_tvdb_id'):
                            item.infoLabels['episode_tvdb_id'] = episode['episode_tvdb_id']
                        if episode.get('episode_posters'):
                            item.infoLabels['posters'] = episode['episode_posters']

                        return len(item.infoLabels)

                else:
                    # We have a valid season number but no episode number...
                    # ... search season data
                    item.infoLabels['mediatype'] = 'season'
                    season = otmdb_global.get_season(seasonNumber)
                    # enseason = otmdb_global.get_season(seasonNumber, language='en')
                    if not isinstance(season, dict):
                        season = ast.literal_eval(season.decode('utf-8'))
                    # if not isinstance(enseason, dict):
                    #     enseason = ast.literal_eval(enseason.decode('utf-8'))

                    if season:
                        # Update data
                        read_data(otmdb_global)
                        seasonTitle = season.get("name", '')
                        seasonPlot = season.get("overview" , '')
                        seasonDate = season.get("air_date", '')
                        seasonPoster = season.get('poster_path', '')
                        seasonPosters = []
                        for image in season['images']['posters']:
                            seasonPosters.append('https://image.tmdb.org/t/p/original' + image['file_path'])

                        item.infoLabels['title'] = seasonTitle
                        item.infoLabels['plot'] = seasonPlot
                        date = seasonDate
                        if date:
                            date.split('-')
                            item.infoLabels['aired'] = date[2] + "/" + date[1] + "/" + date[0]

                        if seasonPoster:
                            item.infoLabels['poster_path'] = 'https://image.tmdb.org/t/p/original' + seasonPoster
                            item.thumbnail = item.infoLabels['poster_path']
                        if seasonPosters:
                            if seasonPoster: seasonPosters.insert(0, seasonPoster)
                            item.infoLabels['posters'] = seasonPosters

                        return len(item.infoLabels)

            # Search...
            else:
                otmdb = copy.copy(otmdb_global)
                # Search by ID...
                if item.infoLabels['tmdb_id']:
                    # ...Search for tmdb_id
                    otmdb = Tmdb(id_Tmdb=item.infoLabels['tmdb_id'], search_type=search_type,
                                 search_language=search_language)

                elif item.infoLabels['imdb_id']:
                    # ...Search by imdb code
                    otmdb = Tmdb(external_id=item.infoLabels['imdb_id'], external_source="imdb_id", search_type=search_type,
                                 search_language=search_language)

                elif search_type == 'tv':  # bsearch with other codes
                    if item.infoLabels['tvdb_id']:
                        # ...Search for tvdb_id
                        otmdb = Tmdb(external_id=item.infoLabels['tvdb_id'], external_source="tvdb_id",
                                     search_type=search_type, search_language=search_language)
                    elif item.infoLabels['freebase_mid']:
                        # ...Search for freebase_mid
                        otmdb = Tmdb(external_id=item.infoLabels['freebase_mid'], external_source="freebase_mid",
                                     search_type=search_type, search_language=search_language)
                    elif item.infoLabels['freebase_id']:
                        # ...Search by freebase_id
                        otmdb = Tmdb(external_id=item.infoLabels['freebase_id'], external_source="freebase_id",
                                     search_type=search_type, search_language=search_language)
                    elif item.infoLabels['tvrage_id']:
                        # ...Search by tvrage_id
                        otmdb = Tmdb(external_id=item.infoLabels['tvrage_id'], external_source="tvrage_id",
                                     search_type=search_type, search_language=search_language)

                # if otmdb is None:
                if not item.infoLabels['tmdb_id'] and not item.infoLabels['imdb_id'] and not item.infoLabels['tvdb_id']\
                    and not item.infoLabels['freebase_mid'] and not item.infoLabels['freebase_id'] and not item.infoLabels['tvrage_id']:
                    # Could not search by ID ...
                    # do it by title
                    if search_type == 'tv':
                        # Serial search by title and filtering your results if necessary
                        searched_title = scrapertools.unescape(item.infoLabels['tvshowtitle'])
                    else:
                        # Movie search by title ...
                        # if item.infoLabels['year'] or item.infoLabels['filtro']:
                        # ...and year or filter
                        searched_title = scrapertools.unescape(item.infoLabels['title'])
                    # from core.support import dbg;dbg()
                    otmdb = Tmdb(searched_text=searched_title, search_type=search_type, search_language=search_language,
                                    filtro=item.infoLabels.get('filtro', {}), year=item.infoLabels['year'])
                    if otmdb is not None and not otmdb.get_id():
                        otmdb = Tmdb(searched_text=searched_title, search_type=search_type, search_language=search_language,
                                    filtro=item.infoLabels.get('filtro', {}))
                    if otmdb is not None:
                        if otmdb.get_id() and config.get_setting("tmdb_plus_info", default=False):
                            # If the search has been successful and you are not looking for a list of items,
                            # carry out another search to expand the information
                            if search_type == 'multi':
                                search_type = otmdb.result.get('media_type')

                            otmdb = Tmdb(id_Tmdb=otmdb.result.get("id"), search_type=search_type,
                                         search_language=search_language)

                if otmdb is not None and otmdb.get_id():
                    # The search has found a valid result
                    read_data(otmdb)
                    return len(item.infoLabels)

        def unify():
            new_title = scrapertools.title_unify(item.fulltitle)
            if new_title != item.fulltitle:
                item.infoLabels['tvshowtitle'] = scrapertools.title_unify(item.infoLabels['tvshowtitle'])
                item.infoLabels['title'] = scrapertools.title_unify(item.infoLabels['title'])
                # item.fulltitle = new_title
                return True
        # We check what type of content it is...
        # from core.support import dbg;dbg()
        if item.contentType == 'movie':
            search_type = 'movie'
        elif item.contentType == 'undefined':  # don't know
            search_type = 'multi'
        else:
            search_type = 'tv'

        ret = search(otmdb_global, search_type)
        if not ret:  # try with unified title
            backup = [item.fulltitle, item.infoLabels['tvshowtitle'], item.infoLabels['title']]
            if unify():
                ret = search(otmdb_global, search_type)
            if not ret:
                item.fulltitle, item.infoLabels['tvshowtitle'], item.infoLabels['title'] = backup
        return ret
    # Search in tmdb is deactivated or has not given result
    # item.contentType = item.infoLabels['mediatype']
    return -1 * len(item.infoLabels)


def find_and_set_infoLabels(item):
    logger.debug()

    global otmdb_global
    tmdb_result = None

    if item.contentType == "movie":
        search_type = "movie"
        content_type = config.get_localized_string(60247)
        title = item.contentTitle
    else:
        search_type = "tv"
        content_type = config.get_localized_string(60298)
        title = item.contentSerieName

    # If the title includes the (year) we will remove it
    year = scrapertools.find_single_match(title, "^.+?\s*(\(\d{4}\))$")
    if year:
        title = title.replace(year, "").strip()
        item.infoLabels['year'] = year[1:-1]

    if not item.infoLabels.get("tmdb_id") or not item.infoLabels.get("tmdb_id")[0].isdigit():
        if item.infoLabels.get("imdb_id"): otmdb_global = Tmdb(external_id=item.infoLabels.get("imdb_id"), external_source="imdb_id", search_type=search_type)
        else: otmdb_global = Tmdb(searched_text=scrapertools.unescape(title), search_type=search_type, year=item.infoLabels['year'])

    elif not otmdb_global or str(otmdb_global.result.get("id")) != item.infoLabels['tmdb_id']:
        otmdb_global = Tmdb(id_Tmdb=item.infoLabels['tmdb_id'], search_type=search_type, search_language=def_lang)

    results = otmdb_global.get_list_results()
    if len(results) > 1:
        # select tmdb_id at the first position
        if item.infoLabels['selected_tmdb_id']:
            results.insert(0, results.pop([r.get('id') for r in results].index(int(item.infoLabels['selected_tmdb_id']))))
        tmdb_result = platformtools.show_video_info(results, item=item, caption= content_type % title)
    elif len(results) > 0:
        tmdb_result = results[0]

    if isinstance(item.infoLabels, InfoLabels):
        infoLabels = item.infoLabels
    else:
        infoLabels = InfoLabels()

    if tmdb_result:
        infoLabels['tmdb_id'] = tmdb_result['id']
        # all look if it can be removed and get only from get_nfo ()
        infoLabels['url_scraper'] = ["https://www.themoviedb.org/{}/{}".format(search_type, infoLabels['tmdb_id'])]
        if infoLabels['tvdb_id']:
            infoLabels['url_scraper'].append("http://thetvdb.com/index.php?tab=series&id=" +  infoLabels['tvdb_id'])
        item.infoLabels = infoLabels
        set_infoLabels_item(item)

        return True

    else:
        item.infoLabels = infoLabels
        return False


def get_nfo(item, search_groups=False):
    """
    Returns the information necessary for the result to be scraped into the kodi video library, for tmdb it works only by passing it the url.
    @param item: element that contains the data necessary to generate the info
    @type item: Item
    @rtype: str
    @return:
    """

    if search_groups:
        from platformcode.autorenumber import RENUMBER, GROUP
        path = filetools.join(config.get_data_path(), "settings_channels", item.channel + "_data.json")
        if filetools.exists(path): 
            g = jsontools.load(filetools.read(path)).get(RENUMBER,{}).get(item.fulltitle.strip(),{}).get(GROUP,'')
            if g:
                if type(g) == list: g = ', '.join(g)
                return g + '\n'

        groups = get_groups(item)

        if groups:
            Id = select_group(groups, item)
            if Id == 'original':
                info_nfo = ', '.join(item.infoLabels['url_scraper'])
                return info_nfo + '\n'
            elif Id :
                info_nfo = 'https://www.themoviedb.org/tv/{}/episode_group/{}'.format(item.infoLabels['tmdb_id'], Id)
                return info_nfo + '\n'
            else: return

    info_nfo = ', '.join(item.infoLabels['url_scraper'])

    return info_nfo + '\n'

def get_groups(item):
    valid_groups = []

    url = '{}/tv/{}/episode_groups?api_key={}&language={}'.format(host, item.infoLabels['tmdb_id'], api, def_lang)
    groups = requests.get(url).json().get('results',[])

    for g in groups:
        seasons = []
        add = False
        Id = g.get('id','')
        group = get_group(Id)
        for gr in group:
            if gr['episodes']:
                season = gr['episodes'][0]['season_number']
                if season not in seasons:
                    seasons.append(season)
                    add = True
                else:
                    add = False
                    break
        if add: valid_groups.append(g)
    return valid_groups

def select_group(groups, item):
    selected = -1
    url = '{}/tv/{}?api_key={}&language={}'.format(host, item.infoLabels['tmdb_id'], api, def_lang)
    res = requests.get(url).json()
    selections = [['Original',res.get('number_of_seasons',0), res.get('number_of_episodes',0), '', item.thumbnail]]
    ids = ['original']
    for group in groups:
        ID = group.get('id','')
        if ID:
            selections.append([group.get('name',''), group.get('group_count',0), group.get('episode_count',0), group.get('description',''), item.thumbnail])
            ids.append(ID)
    if selections and ids:
        selected = platformtools.dialog_select_group(config.get_localized_string(70831), selections)
    if selected > -1:
        return ids[selected]
    return ''

def get_group(Id):
    # from core.support import dbg;dbg()
    url = '{}/tv/episode_group/{}?api_key={}&language={}'.format(host, Id, api, def_lang)
    group = requests.get(url).json().get('groups',[])
    return group

def completar_codigos(item):
    """
    If necessary, check if the tvdb identifier exists and if it does not exist try to find it
    """
    if item.contentType != "movie" and not item.infoLabels['tvdb_id']:
        # Launch search for imdb_id on tvdb
        from core.tvdb import Tvdb
        ob = Tvdb(imdb_id=item.infoLabels['imdb_id'])
        item.infoLabels['tvdb_id'] = ob.get_id()
    if item.infoLabels['tvdb_id']:
        url_scraper = "http://thetvdb.com/index.php?tab=series&id=" + item.infoLabels['tvdb_id']
        if url_scraper not in item.infoLabels['url_scraper']:
            item.infoLabels['url_scraper'].append(url_scraper)


def discovery(item, dict_=False, cast=False):
    from core.item import Item

    if dict_:
        if item.page:
            if not item.discovery: item.discovery={}
            item.discovery['page'] = item.page
        listado = Tmdb(discover = dict_, cast=cast)

    elif item.search_type == 'discover':
        listado = Tmdb(discover={'url':'discover/' + item.type, 'with_genres':item.list_type, 'language':def_lang, 'page':item.page})

    elif item.search_type == 'list':
        if item.page == '':
            item.page = '1'
        listado = Tmdb(discover={'url': item.list_type, 'language':def_lang, 'page':item.page})

    return listado

def get_dic_genres(search_type):
    lang = def_lang
    # from core.support import dbg;dbg()
    genres = Tmdb(search_type=search_type)

    return genres.dic_genres[lang]


# Auxiliary class
class ResultDictDefault(dict):
    # Python 2.4
    def __getitem__(self, key):
        try:
            return super(ResultDictDefault, self).__getitem__(key)
        except:
            return self.__missing__(key)

    def __missing__(self, key):
        """
        default values in case the requested key does not exist
        """
        if key in ['genre_ids', 'genre', 'genres']:
            return list()

        elif key == 'images_posters':
            posters = dict()
            if 'images' in list(super(ResultDictDefault, self).keys()) and 'posters' in super(ResultDictDefault, self).__getitem__('images'):
                posters = super(ResultDictDefault, self).__getitem__('images')['posters']
                super(ResultDictDefault, self).__setattr__("images_posters", posters)

            return posters

        elif key == "images_backdrops":
            backdrops = dict()
            if 'images' in list(super(ResultDictDefault, self).keys()) and 'backdrops' in super(ResultDictDefault, self).__getitem__('images'):
                backdrops = super(ResultDictDefault, self).__getitem__('images')['backdrops']
                super(ResultDictDefault, self).__setattr__("images_backdrops", backdrops)

            return backdrops

        elif key == "images_profiles":
            profiles = dict()
            if 'images' in list(super(ResultDictDefault, self).keys()) and 'profiles' in super(ResultDictDefault, self).__getitem__('images'):
                profiles = super(ResultDictDefault, self).__getitem__('images')['profiles']
                super(ResultDictDefault, self).__setattr__("images_profiles", profiles)

            return profiles

        else:
            # The rest of the keys return empty strings by default
            return ""

    def __str__(self):
        return self.tostring(separador=',\n')

    def tostring(self, separador=',\n'):
        ls = []
        for i in list(super(ResultDictDefault, self).items()):
            i_str = str(i)[1:-1]
            if isinstance(i[0], str):
                old = i[0] + "',"
                new = i[0] + "':"
            else:
                old = str(i[0]) + ","
                new = str(i[0]) + ":"
            ls.append(i_str.replace(old, new, 1))

        return "{%s}" % separador.join(ls)


# ---------------------------------------------------------------------------------------------------------------
# class Tmdb:
# Scraper for the API based addon from https://www.themoviedb.org/
# version 1.4:
# - Documented limitation of API use (see below).
# - Added get_season () method
# version 1.3:
# - Fixed error when returning None the path_poster and backdrop_path
# - Fixed a bug that caused the list of genres to accumulate from one call to another
# - Added get_genres () method
# - Added optional parameters alternative_language to the get_plot () method
#
#
# Usage:
# Construction methods:
# Tmdb (search_text, type)
# Parameters:
# searched_text: (str) Text or part of the text to search
# type: ("movie" or "tv") Type of result searched for movies or series. Default "movie"
# (optional) language_search: (str) language code according to ISO 639-1
# (optional) include_adult: (bool) Adult content is included in the search or not. Default
# 'False'
# (optional) year: (str) Release year.
# (optional) page: (int) When there are many results for a search these are organized by pages.
# We can load the page we want, although by default it is always the first page.
# Return:
# This call returns a Tmdb object containing the first page of the search result 'search_text'
# on the themoviedb.org website. The more optional parameters are included, the more precise the search will be.
# Also the object is initialized with the first result of the first page of results.
# Tmdb (id_Tmdb, type)
# Parameters:
# id_Tmdb: (str) Identifier code of a certain movie or series at themoviedb.org
# type: ("movie" or "tv") Type of result searched for movies or series. Default "movie"
# (optional) language_search: (str) language code according to ISO 639-1
# Return:
# This call returns a Tmdb object that contains the result of searching for a movie or series with the
# identifier id_Tmd
# on the themoviedb.org website.
# Tmdb (external_id, external_source, type)
# Parameters:
# external_id: (str) Identifier code of a certain movie or series on the web referenced by
# 'external_source'.
# external_source: (For series: "imdb_id", "freebase_mid", "freebase_id", "tvdb_id", "tvrage_id"; For
# movies: "imdb_id")
# type: ("movie" or "tv") Type of result searched for movies or series. Default "movie"
# (optional) language_search: (str) language code according to ISO 639-1
# Return:
# This call returns a Tmdb object that contains the result of searching for a movie or series with the
# identifier 'external_id' of
# the website referenced by 'external_source' on the themoviedb.org website.
#
# Main methods:
# get_id (): Returns a str with the Tmdb identifier of the loaded movie or series or an empty string if there were no
# nothing loaded.
# get_plot (alternate_language): Returns a str with the synopsis of the series or movie loaded.
# get_poster (response_type, size): Get the poster or a list of posters.
# get_backdrop (response_type, size): Get a background image or a list of background images.
# get_season (season): Get a dictionary with season-specific data.
# get_episode (season, episode): Get a dictionary with specific data of the episode.
# get_genres (): Returns a str with the list of genres to which the movie or series belongs.
#
#
# Other methods:
# load_result (result, page): When the search returns several results we can select which result
# concrete and from which page to load the data.
#
# Limitations:
# The use of the API imposes a limit of 20 simultaneous connections (concurrency) or 30 requests in 10 seconds per IP
# Information about the api: http://docs.themoviedb.apiary.io
# -------------------------------------------------------------------------------------------------------------------


class Tmdb(object):
    # Class attribute
    dic_genres = {}
    '''
    dic_genres={"id_idioma1": {"tv": {"id1": "name1",
                                       "id2": "name2"
                                      },
                                "movie": {"id1": "name1",
                                          "id2": "name2"
                                          }
                                }
                }
    '''
    dic_country = {"AD": "Andorra", "AE": "Emiratos Árabes Unidos", "AF": "Afganistán", "AG": "Antigua y Barbuda",
                   "AI": "Anguila", "AL": "Albania", "AM": "Armenia", "AN": "Antillas Neerlandesas", "AO": "Angola",
                   "AQ": "Antártida", "AR": "Argentina", "AS": "Samoa Americana", "AT": "Austria", "AU": "Australia",
                   "AW": "Aruba", "AX": "Islas de Åland", "AZ": "Azerbayán", "BA": "Bosnia y Herzegovina",
                   "BD": "Bangladesh", "BE": "Bélgica", "BF": "Burkina Faso", "BG": "Bulgaria", "BI": "Burundi",
                   "BJ": "Benín", "BL": "San Bartolomé", "BM": "Islas Bermudas", "BN": "Brunéi", "BO": "Bolivia",
                   "BR": "Brasil", "BS": "Bahamas", "BT": "Bhután", "BV": "Isla Bouvet", "BW": "Botsuana",
                   "BY": "Bielorrusia", "BZ": "Belice", "CA": "Canadá", "CC": "Islas Cocos (Keeling)", "CD": "Congo",
                   "CF": "República Centroafricana", "CG": "Congo", "CH": "Suiza", "CI": "Costa de Marfil",
                   "CK": "Islas Cook", "CL": "Chile", "CM": "Camerún", "CN": "China", "CO": "Colombia",
                   "CR": "Costa Rica", "CU": "Cuba", "CV": "Cabo Verde", "CX": "Isla de Navidad", "CY": "Chipre",
                   "CZ": "República Checa", "DE": "Alemania", "DJ": "Yibuti", "DK": "Dinamarca", "DZ": "Algeria",
                   "EC": "Ecuador", "EE": "Estonia", "EG": "Egipto", "EH": "Sahara Occidental", "ER": "Eritrea",
                   "ES": "España", "ET": "Etiopía", "FI": "Finlandia", "FJ": "Fiyi", "FK": "Islas Malvinas",
                   "FM": "Micronesia", "FO": "Islas Feroe", "FR": "Francia", "GA": "Gabón", "GB": "Gran Bretaña",
                   "GD": "Granada", "GE": "Georgia", "GF": "Guayana Francesa", "GG": "Guernsey", "GH": "Ghana",
                   "GI": "Gibraltar", "GL": "Groenlandia", "GM": "Gambia", "GN": "Guinea", "GP": "Guadalupe",
                   "GQ": "Guinea Ecuatorial", "GR": "Grecia", "GS": "Islas Georgias del Sur y Sandwich del Sur",
                   "GT": "Guatemala", "GW": "Guinea-Bissau", "GY": "Guyana", "HK": "Hong kong",
                   "HM": "Islas Heard y McDonald", "HN": "Honduras", "HR": "Croacia", "HT": "Haití", "HU": "Hungría",
                   "ID": "Indonesia", "IE": "Irlanda", "IM": "Isla de Man", "IN": "India",
                   "IO": "Territorio Británico del Océano Índico", "IQ": "Irak", "IR": "Irán", "IS": "Islandia",
                   "IT": "Italia", "JE": "Jersey", "JM": "Jamaica", "JO": "Jordania", "JP": "Japón", "KG": "Kirgizstán",
                   "KH": "Camboya", "KM": "Comoras", "KP": "Corea del Norte", "KR": "Corea del Sur", "KW": "Kuwait",
                   "KY": "Islas Caimán", "KZ": "Kazajistán", "LA": "Laos", "LB": "Líbano", "LC": "Santa Lucía",
                   "LI": "Liechtenstein", "LK": "Sri lanka", "LR": "Liberia", "LS": "Lesoto", "LT": "Lituania",
                   "LU": "Luxemburgo", "LV": "Letonia", "LY": "Libia", "MA": "Marruecos", "MC": "Mónaco",
                   "MD": "Moldavia", "ME": "Montenegro", "MF": "San Martín (Francia)", "MG": "Madagascar",
                   "MH": "Islas Marshall", "MK": "Macedônia", "ML": "Mali", "MM": "Birmania", "MN": "Mongolia",
                   "MO": "Macao", "MP": "Islas Marianas del Norte", "MQ": "Martinica", "MR": "Mauritania",
                   "MS": "Montserrat", "MT": "Malta", "MU": "Mauricio", "MV": "Islas Maldivas", "MW": "Malawi",
                   "MX": "México", "MY": "Malasia", "NA": "Namibia", "NE": "Niger", "NG": "Nigeria", "NI": "Nicaragua",
                   "NL": "Países Bajos", "NO": "Noruega", "NP": "Nepal", "NR": "Nauru", "NU": "Niue",
                   "NZ": "Nueva Zelanda", "OM": "Omán", "PA": "Panamá", "PE": "Perú", "PF": "Polinesia Francesa",
                   "PH": "Filipinas", "PK": "Pakistán", "PL": "Polonia", "PM": "San Pedro y Miquelón",
                   "PN": "Islas Pitcairn", "PR": "Puerto Rico", "PS": "Palestina", "PT": "Portugal", "PW": "Palau",
                   "PY": "Paraguay", "QA": "Qatar", "RE": "Reunión", "RO": "Rumanía", "RS": "Serbia", "RU": "Rusia",
                   "RW": "Ruanda", "SA": "Arabia Saudita", "SB": "Islas Salomón", "SC": "Seychelles", "SD": "Sudán",
                   "SE": "Suecia", "SG": "Singapur", "SH": "Santa Elena", "SI": "Eslovenia",
                   "SJ": "Svalbard y Jan Mayen",
                   "SK": "Eslovaquia", "SL": "Sierra Leona", "SM": "San Marino", "SN": "Senegal", "SO": "Somalia",
                   "SV": "El Salvador", "SY": "Siria", "SZ": "Swazilandia", "TC": "Islas Turcas y Caicos", "TD": "Chad",
                   "TF": "Territorios Australes y Antárticas Franceses", "TG": "Togo", "TH": "Tailandia",
                   "TJ": "Tadjikistán", "TK": "Tokelau", "TL": "Timor Oriental", "TM": "Turkmenistán", "TN": "Tunez",
                   "TO": "Tonga", "TR": "Turquía", "TT": "Trinidad y Tobago", "TV": "Tuvalu", "TW": "Taiwán",
                   "TZ": "Tanzania", "UA": "Ucrania", "UG": "Uganda",
                   "UM": "Islas Ultramarinas Menores de Estados Unidos",
                   "UY": "Uruguay", "UZ": "Uzbekistán", "VA": "Ciudad del Vaticano",
                   "VC": "San Vicente y las Granadinas",
                   "VE": "Venezuela", "VG": "Islas Vírgenes Británicas", "VI": "Islas Vírgenes de los Estados Unidos",
                   "VN": "Vietnam", "VU": "Vanuatu", "WF": "Wallis y Futuna", "WS": "Samoa", "YE": "Yemen",
                   "YT": "Mayotte", "ZA": "Sudáfrica", "ZM": "Zambia", "ZW": "Zimbabue", "BB": "Barbados",
                   "BH": "Bahrein",
                   "DM": "Dominica", "DO": "República Dominicana", "GU": "Guam", "IL": "Israel", "KE": "Kenia",
                   "KI": "Kiribati", "KN": "San Cristóbal y Nieves", "MZ": "Mozambique", "NC": "Nueva Caledonia",
                   "NF": "Isla Norfolk", "PG": "Papúa Nueva Guinea", "SR": "Surinám", "ST": "Santo Tomé y Príncipe",
                   "US": "EEUU"}

    def __init__(self, **kwargs):
        self.page = kwargs.get('page', 1)
        self.index_results = 0
        self.cast = kwargs.get('cast', False)
        self.results = []
        self.result = ResultDictDefault()
        self.total_pages = 0
        self.total_results = 0

        self.season = {}
        self.searched_text = kwargs.get('searched_text', '')

        self.search_id = kwargs.get('id_Tmdb', '')
        self.search_text = re.sub('\[[^\]]+\]', '', self.searched_text).strip()
        self.search_type = kwargs.get('search_type', '')
        self.search_language = kwargs.get('search_language', def_lang)
        self.fallback_language = 'en'
        # self.search_include_adult = kwargs.get('include_adult', False)
        self.search_year = kwargs.get('year', '')
        self.search_filter = kwargs.get('filtro', {})
        self.discover = kwargs.get('discover', {})

        # Refill gender dictionary if necessary
        if (self.search_type == 'movie' or self.search_type == "tv") and (self.search_language not in Tmdb.dic_genres or self.search_type not in Tmdb.dic_genres[self.search_language]):
            self.filling_dic_genres(self.search_type, self.search_language)

        if not self.search_type:
            self.search_type = 'movie'

        if self.search_id:
            # Search by tmdb identifier
            self.__by_id()

        elif self.search_text:
            # Search by text
            self.__search(page=self.page)

        elif 'external_source' in kwargs and 'external_id' in kwargs:
            # Search by external identifier according to type.
            # TV Series: imdb_id, freebase_mid, freebase_id, tvdb_id, tvrage_id
            # Movies: imdb_id
            if (self.search_type == 'movie' and kwargs.get('external_source') == "imdb_id") or (self.search_type == 'tv' and kwargs.get('external_source') in ("imdb_id", "freebase_mid", "freebase_id", "tvdb_id", "tvrage_id")):
                self.search_id = kwargs.get('external_id')
                self.__by_id(source=kwargs.get('external_source'))

        elif self.discover:
            self.__discover()

        else:
            logger.debug("Created empty object")

    @staticmethod
    @cache_response
    def get_json(url, cache=True):
        # from core.support import dbg;dbg()
        try:
            result = httptools.downloadpage(url, cookies=False, ignore_response_code=True)

            res_headers = result.headers
            dict_data = result.json
            #logger.debug("result_data es %s" % dict_data)

            if "status_code" in dict_data:
                #logger.debug("\nError de tmdb: %s %s" % (dict_data["status_code"], dict_data["status_message"]))

                if dict_data["status_code"] == 25:
                    while "status_code" in dict_data and dict_data["status_code"] == 25:
                        wait = int(res_headers['retry-after'])
                        #logger.error("Limit reached, we wait to call back on ...%s" % wait)
                        time.sleep(wait)
                        # logger.debug("RE Call #%s" % d)
                        result = httptools.downloadpage(url, cookies=False)

                        res_headers = result.headers
                        # logger.debug("res_headers es %s" % res_headers)
                        dict_data = result.json
                        # logger.debug("result_data es %s" % dict_data)

        # error getting data
        except Exception as ex:
            message = "An exception of type %s occured. Arguments:\n%s" % (type(ex).__name__, repr(ex.args))
            logger.error("error in: %s" % message)
            dict_data = {}

        return dict_data

    @classmethod
    def filling_dic_genres(cls, search_type='movie', language=def_lang):
        # Fill dictionary of genres of the type and language passed as parameters
        if language not in cls.dic_genres:
            cls.dic_genres[language] = {}

        if search_type not in cls.dic_genres[language]:
            cls.dic_genres[language][search_type] = {}
            url = ('{}/genre/{}/list?api_key={}&language={}'.format(host, search_type, api, language))
            try:
                logger.debug("[Tmdb.py] Filling in dictionary of genres")

                result = cls.get_json(url)
                if not isinstance(result, dict):
                    result = ast.literal_eval(result.decode('utf-8'))
                list_genres = result.get("genres", {})

                for i in list_genres:
                    cls.dic_genres[language][search_type][str(i["id"])] = i["name"]
            except:
                logger.error("Error generating dictionaries")
                import traceback
                logger.error(traceback.format_exc())

    def __by_id(self, source='tmdb'):
        # from core.support import dbg;dbg()

        if self.search_id:
            if source == "tmdb":
                url = ('{}/{}/{}?api_key={}&language={}&append_to_response=images,videos,external_ids,credits&include_image_language={},en,null'.format(host, self.search_type, self.search_id, api, self.search_language, self.search_language))
                searching = "id_Tmdb: {}".format(self.search_id)
            else:
                url = ('{}/find/{}?external_source={}&api_key={}&language={}'.format(host, self.search_id, source, api, self.search_language))
                searching = "{}: {}".format(source.capitalize(), self.search_id)

            logger.debug("[Tmdb.py] Searching %s:\n%s" % (searching, url))
            result = self.get_json(url)
            if not isinstance(result, dict):
                result = ast.literal_eval(result.decode('utf-8'))

            if result:
                if source != "tmdb":
                    if self.search_type == "movie":
                        result = result["movie_results"][0]
                    else:
                        if result["tv_results"]:
                            result = result["tv_results"][0]
                        else:
                            result = result['tv_episode_results'][0]

                result = self.get_mpaa(result)

                self.results = [result]
                self.total_results = 1
                self.total_pages = 1
                self.result = ResultDictDefault(result)
                self.result['media_type'] = self.search_type.replace('tv', 'tvshow')

            else:
                # No search results
                msg = "The search of %s gave no results" % searching
                logger.debug(msg)

    def __search(self, index_results=0, page=1):
        self.result = ResultDictDefault()
        results = []
        text_simple = self.search_text.lower()
        text_quote = urllib.quote(text_simple)
        total_results = 0
        total_pages = 0
        searching = ""

        if self.search_text:
            url = ('{}/search/{}?api_key={}&query={}&language={}&include_adult={}&page={}'.format(host, self.search_type, api, text_quote, self.search_language, False, page))

            if self.search_year:
                if self.search_type == 'movie':
                    url += '&primary_release_year=%s' % self.search_year
                else:
                    url += '&first_air_date_year=%s' % self.search_year

            searching = self.search_text.capitalize()
            logger.debug("[Tmdb.py] Searching %s on page %s:\n%s" % (searching, page, url))
            result = self.get_json(url)
            if not isinstance(result, dict):
                result = ast.literal_eval(result.decode('utf-8'))

            total_results = result.get("total_results", 0)
            total_pages = result.get("total_pages", 0)

            if total_results > 0:
                results = [r for r in result["results"] if r.get('first_air_date', r.get('release_date', ''))]

            if self.search_filter and total_results > 1:
                for key, value in list(dict(self.search_filter).items()):
                    for r in results[:]:
                        if not r[key]:
                            r[key] = str(r[key])
                        if key not in r or value not in r[key]:
                            results.remove(r)
                            total_results -= 1

        if results:
            if index_results >= len(results):
                # A higher number of results has been requested than those obtained
                logger.error(
                    "The search for '%s' gave %s results for the page %s \n It is impossible to show the result number %s"
                    % (searching, len(results), page, index_results))
                return 0

            # We sort result based on fuzzy match to detect most similar
            if len(results) > 1:
                from lib.fuzzy_match import algorithims
                if self.search_type == 'multi':
                    if self.search_year:
                        for r in results:
                            if (r.get('release_date', '') and r.get('release_date', '')[:4] == self.search_year) or (r.get('first_air_date', '') and r.get('first_air_date', '')[:4] == self.search_year):
                                results = [r]
                                break
                    if len(results) > 1:
                        results.sort(key=lambda r: algorithims.trigram(text_simple, r.get('name', '') if r.get('media_type') == 'tv' else r.get('title', '')), reverse=True)
                else:
                    results.sort(key=lambda r: algorithims.trigram(text_simple, r.get('name', '') if self.search_type == 'tv' else r.get('title', '')), reverse=True)

            # We return the number of results of this page
            self.results = results
            self.total_results = total_results
            self.total_pages = total_pages
            self.result = ResultDictDefault(self.results[index_results])
            # self.result['mediatype'] = self.result['media_type']

            if not config.get_setting('tmdb_plus_info'):
                self.result = self.get_mpaa(self.result)
            return len(self.results)

        else:
            # No search results
            msg = "The search for '%s' gave no results for page %s" % (searching, page)
            logger.error(msg)
            return 0

    def __discover(self, index_results=0):
        self.result = ResultDictDefault()
        results = []
        total_results = 0
        total_pages = 0

        # Exampleself.discover: {'url': 'discover/movie', 'with_cast': '1'}
        # url: API method to run
        # rest of keys: Search parameters concatenated to the url
        type_search = self.discover.get('url', '')
        if type_search:
            params = []
            for key, value in list(self.discover.items()):
                if key != "url":
                    params.append(key + "=" + str(value))

            url = ('{}/{}?api_key={}&{}'.format(host, type_search, api, "&".join(params)))

            logger.debug("[Tmdb.py] Searching %s:\n%s" % (type_search, url))
            result = self.get_json(url, cache=False)
            if not isinstance(result, dict):
                result = ast.literal_eval(result.decode('utf-8'))

            total_results = result.get("total_results", -1)
            total_pages = result.get("total_pages", 1)

            if total_results > 0 or self.cast:
                if self.cast:
                    results = result['cast']
                    total_results = len(results)
                else:
                    results = result["results"]
                if self.search_filter and results:
                    # TODO documentar esta parte
                    for key, value in list(dict(self.search_filter).items()):
                        for r in results[:]:
                            if key not in r or r[key] != value:
                                results.remove(r)
                                total_results -= 1
            elif total_results == -1:
                results = result

            if index_results >= len(results):
                logger.error(
                    "The search for '%s' did not give %s results" % (type_search, index_results))
                return 0

        # We return the number of results of this page
        if results:
            self.results = results
            self.total_results = total_results
            self.total_pages = total_pages
            if total_results > 0:
                self.result = ResultDictDefault(self.results[index_results])

            else:
                self.result = results
            return len(self.results)
        else:
            # No search results
            logger.error("The search for '%s' gave no results" % type_search)
            return 0

    def load_result(self, index_results=0, page=1):
        # If there are no results, there is only one or if the number of results on this page is less than the index sought to exit
        self.result = ResultDictDefault()
        num_result_page = len(self.results)

        if page > self.total_pages:
            return False

        if page != self.page:
            num_result_page = self.__search(index_results, page)

        if num_result_page == 0 or num_result_page <= index_results:
            return False

        self.page = page
        self.index_results = index_results
        self.result = ResultDictDefault(self.results[index_results])
        return True

    def get_list_results(self, num_result=20):
        # logger.debug("self %s" % str(self))
        res = []

        if num_result <= 0:
            num_result = self.total_results
        num_result = min([num_result, self.total_results])

        cr = 0

        for p in range(1, self.total_pages + 1):
            for r in range(0, len(self.results)):
                try:
                    if self.load_result(r, p):
                        result = self.result.copy()

                        result['thumbnail'] = self.get_poster(size="w300")
                        result['fanart'] = self.get_backdrop()

                        res.append(result)
                        cr += 1

                        if cr >= num_result:
                            return res
                except:
                    continue

        return res

    def get_genres(self, origen=None):
        """
        :param origen: Source dictionary where the infoLabels are obtained, by default self.result
        :type origen: Dict
        :return: Returns the list of genres to which the movie or series belongs.
        :rtype: str
        """
        genre_list = []

        if not origen:
            origen = self.result

        if "genre_ids" in origen:
            # Search list of genres by IDs
            for i in origen.get("genre_ids"):
                try:
                    genre_list.append(Tmdb.dic_genres[self.search_language][self.search_type][str(i)])
                except:
                    pass

        elif "genre" in origen or "genres" in origen:
            # Search genre list (object list {id, name})
            v = origen["genre"]
            v.extend(origen["genres"])
            for i in v:
                genre_list.append(i['name'])

        return ', '.join(genre_list)

    def search_by_id(self, id, source='tmdb', search_type='movie'):
        self.search_id = id
        self.search_type = search_type
        self.__by_id(source=source)

    def get_id(self):
        """
        :return: Returns the Tmdb identifier of the loaded movie or series or an empty string in case nothing was loaded. You can use this method to find out if a search has been successful or not.
        :rtype: str
        """
        return str(self.result.get('id', ""))

    def get_plot(self, language_alternative=''):
        """

        :param language_alternative: Language code, according to ISO 639-1, if there is no synopsis in the language set for the search.
            By default, the original language is used. If None is used as the alternative_language, it will only search in the set language.
        :type language_alternative: str
        :return: Returns the synopsis of a movie or series
        :rtype: str
        """
        ret = ""
        # from core.support import dbg;dbg()

        if 'id' in self.result:
            ret = self.result.get('overview')
            if ret == "" and str(language_alternative).lower() != 'none':
                # Let's launch a search for id and reread the synopsis again
                self.search_id = str(self.result["id"])
                if language_alternative:
                    self.search_language = language_alternative
                else:
                    self.search_language = self.result['original_language']

                url = ('{}/{}/{}?api_key={}&language={}'.format(host, self.search_type, self.search_id, api, self.search_language))

                result = self.get_json(url)
                if not isinstance(result, dict):
                    result = ast.literal_eval(result.decode('utf-8'))

                if 'overview' in result:
                    self.result['overview'] = result['overview']
                    ret = self.result['overview']

        return ret

    def get_poster(self, response_type="str", size="original"):
        """

        @param response_type: Data type returned by this method. Default "str"
        @type response_type: list, str
        @param size: ("w45", "w92", "w154", "w185", "w300", "w342", "w500", "w600", "h632", "w780", "w1280", "original")
            Indicates the width (w) or height (h) of the image to download. Default "original"
        @return: If the response_type is "list" it returns a list with all the urls of the poster images of the specified size.
            If the response_type is "str" ​​it returns the url of the poster image, most valued, of the specified size.
            If the specified size does not exist, the images are returned to the original size.
        @rtype: list, str
        """
        ret = []
        if size not in ("w45", "w92", "w154", "w185", "w300", "w342", "w500", "w600", "h632", "w780", "w1280"):
            size = "original"

        if self.result["poster_path"] is None or self.result["poster_path"] == "":
            poster_path = ""
        else:
            poster_path = 'https://image.tmdb.org/t/p/' + size + self.result["poster_path"]

        if response_type == 'str':
            return poster_path
        elif not self.result["id"]:
            return []

        if len(self.result['images_posters']) == 0:
            # We are going to launch a search by id and reread again
            self.search_id = str(self.result["id"])
            self.__by_id()

        if len(self.result['images_posters']) > 0:
            for i in self.result['images_posters']:
                imagen_path = i['file_path']
                if size != "original":
                    # We cannot order sizes larger than the original
                    if size[1] == 'w' and int(imagen_path['width']) < int(size[1:]):
                        size = "original"
                    elif size[1] == 'h' and int(imagen_path['height']) < int(size[1:]):
                        size = "original"
                ret.append('https://image.tmdb.org/t/p/' + size + imagen_path)
        else:
            ret.append(poster_path)

        return ret

    def get_backdrop(self, response_type="str", size="original"):
        """
        Returns the images of type backdrop
        @param response_type: Data type returned by this method. Default "str"
        @type response_type: list, str
        @param size: ("w45", "w92", "w154", "w185", "w300", "w342", "w500", "w600", "h632", "w780", "w1280", "original")
            Indicates the width (w) or height (h) of the image to download. Default "original"
        @type size: str
        @return: If the response_type is "list" it returns a list with all the urls of the backdrop images of the specified size.
            If the response_type is "str" ​​it returns the url of the backdrop type image, most valued, of the specified size.
            If the specified size does not exist, the images are returned to the original size.
        @rtype: list, str
        """
        ret = []
        if size not in ("w45", "w92", "w154", "w185", "w300", "w342", "w500", "w600", "h632", "w780", "w1280"):
            size = "original"

        if self.result["backdrop_path"] is None or self.result["backdrop_path"] == "":
            backdrop_path = ""
        else:
            backdrop_path = 'get_posterget_poster' + size + self.result["backdrop_path"]

        if response_type == 'str':
            return backdrop_path
        elif self.result["id"] == "":
            return []

        if len(self.result['images_backdrops']) == 0:
            # Let's launch a search by id and reread everything
            self.search_id = str(self.result["id"])
            self.__by_id()

        if len(self.result['images_backdrops']) > 0:
            for i in self.result['images_backdrops']:
                imagen_path = i['file_path']
                if size != "original":
                    # We cannot order sizes larger than the original
                    if size[1] == 'w' and int(imagen_path['width']) < int(size[1:]):
                        size = "original"
                    elif size[1] == 'h' and int(imagen_path['height']) < int(size[1:]):
                        size = "original"
                ret.append('https://image.tmdb.org/t/p/' + size + imagen_path)
        else:
            ret.append(backdrop_path)

        return ret

    def get_season(self, seasonNumber=1, language=''):
        # --------------------------------------------------------------------------------------------------------------------------------------------
        # Parameters:
        # season number: (int) Season number. Default 1.
        # Return: (Dec)
        # Returns a dictionary with data about the season.
        # You can get more information about the returned data at:
        # http://docs.themoviedb.apiary.io/#reference/tv-seasons/tvidseasonseasonnumber/get
        # http://docs.themoviedb.apiary.io/#reference/tv-seasons/tvidseasonseasonnumbercredits/get
        # --------------------------------------------------------------------------------------------------------------------------------------------
        if not self.result["id"] or self.search_type != "tv":
            return {}

        seasonNumber = int(seasonNumber)
        if seasonNumber < 0:
            seasonNumber = 1
        search_language = language if language else self.search_language

        if not self.season.get(seasonNumber, {}) or language:
            # If there is no information about the requested season, check the website

            # http://api.themoviedb.org/3/tv/1407/season/1?api_key=a1ab8b8669da03637a4b98fa39c39228&language=es&
            # append_to_response=credits
            url = "{}/tv/{}/season/{}?api_key={}&language={}&append_to_response=videos,images,credits,external_ids&include_image_language={},en,null".format(host, self.result["id"], seasonNumber, api, search_language, search_language)
            # fallbackUrl = "{}/tv/{}/season/{}?api_key={}&language=en&append_to_response=videos,images,credits&include_image_language={},en,null".format(host, self.result["id"], seasonNumber, api, search_language)
            logger.debug('TMDB URL', url)

            searching = "id_Tmdb: " + str(self.result["id"]) + " season: " + str(seasonNumber) + "\nURL: " + url
            logger.debug("[Tmdb.py] Searching " + searching)
            # from core.support import dbg;dbg()
            try:
                self.season[seasonNumber] = self.get_json(url)
                if not isinstance(self.season[seasonNumber], dict):
                    self.season[seasonNumber] = ast.literal_eval(self.season[seasonNumber].decode('utf-8'))

            except:
                logger.error("Unable to get the season")
                self.season[seasonNumber] = {"status_code": 15, "status_message": "Failed"}
                self.season[seasonNumber] = {"episodes": {}}

            if "status_code" in self.season[seasonNumber]:
                # An error has occurred
                msg = config.get_localized_string(70496) + searching + config.get_localized_string(70497)
                msg += "\nTmdb error: %s %s" % (
                self.season[seasonNumber]["status_code"], self.season[seasonNumber]["status_message"])
                logger.debug(msg)
                self.season[seasonNumber] = {}

        return self.season[seasonNumber]

    def get_collection(self, _id=''):
        ret = {}
        if not _id:
            collection = self.result.get('belongs_to_collection', {})
            if collection:
                _id = collection.get('id')
        if _id:
            translation = {}
            url = '{}/collection/{}?api_key={}&language={}&append_to_response=images&include_image_language={},en,null'.format(host, _id, api, self.search_language, self.search_language)
            tanslationurl = '{}/collection/{}/translations?api_key={}'.format(host, _id, api)
            info = self.get_json(url)
            for t in self.get_json(tanslationurl).get('translations'):
                if t.get('iso_639_1') == self.fallback_language:
                    translation = t.get('data',{})
                    break
            ret['set'] = info.get('name') if info.get('name') else translation.get('name')
            ret['setid'] = _id
            ret['setoverview'] = info.get('overview') if info.get('overview') else translation.get('overview', '')
            posters = ['https://image.tmdb.org/t/p/original' + info.get('poster_path')] if info.get('poster_path') else []
            fanarts = ['https://image.tmdb.org/t/p/original' + info.get('backdrop_path')] if info.get('backdrop_path') else []
            for image in info['images']['posters']:
                posters.append('https://image.tmdb.org/t/p/original' + image['file_path'])
            for image in info['images']['backdrops']:
                fanarts.append('https://image.tmdb.org/t/p/original' + image['file_path'])
            ret['setposters'] = posters
            ret['setfanarts'] = fanarts
        return ret

    def get_episode(self, seasonNumber=1, chapter=1):
        # --------------------------------------------------------------------------------------------------------------------------------------------
        # Parameters:
        # season number (optional): (int) Season number. Default 1.
        # chapter: (int) Chapter number. Default 1.
        # Return: (Dec)
        # Returns a dictionary with the following elements:
        # "season_name", "season_synopsis", "season_poster", "season_num_ episodes" (int),
        # "season_air_date", "episode_vote_count", "episode_vote_average",
        # "episode_title", "episode_synopsis", "episode_image", "episode_air_date",
        # "episode_crew" and "episode_guest_stars",
        # With chapter == -1 the dictionary will only have the elements referring to the season
        # --------------------------------------------------------------------------------------------------------------------------------------------

        if not self.result["id"] or self.search_type != "tv":
            return {}

        try:
            chapter = int(chapter)
            season = int(seasonNumber)
        except ValueError:
            logger.debug("The episode or season number is not valid")
            return {}

        # season = self.get_season(seasonNumber)
        # # enseason = self.get_season(seasonNumber, language='en')
        # # if not isinstance(season, dict):
        # #     season = ast.literal_eval(season.decode('utf-8'))
        # # if not isinstance(enseason, dict):
        # #     enseason = ast.literal_eval(enseason.decode('utf-8'))
        # if not season:
        #     # An error has occurred
        #     return {}

        # if len(season["episodes"]) == 0:
        #     # An error has occurred
        #     logger.error("Episode %d of the season %d not found." % (chapter, seasonNumber))
        #     return {}

        # elif len(season["episodes"]) < chapter and season["episodes"][-1]['episode_number'] >= chapter:
        #     n = None
        #     for i, chapters in enumerate(season["episodes"]):
        #         if chapters['episode_number'] == chapter:
        #             n = i + 1
        #             break
        #     if n != None:
        #         chapter = n
        #     else:
        #         logger.error("Episode %d of the season %d not found." % (chapter, seasonNumber))
        #         return {}

        # elif len(season["episodes"]) < chapter:
        #     logger.error("Episode %d of the season %d not found." % (chapter, seasonNumber))
        #     return {}

        # ret_dic = get_season_dic(season)

        # if chapter == 0:
        #     # If we only look for season data, include the technical team that has intervened in any chapter
        #     dic_aux = dict((i['id'], i) for i in ret_dic["season_crew"])
        #     for e in season["episodes"]:
        #         for crew in e['crew']:
        #             if crew['id'] not in list(dic_aux.keys()):
        #                 dic_aux[crew['id']] = crew
        #     ret_dic["season_crew"] = list(dic_aux.values())


        # Obtain chapter data if applicable
        # from core.support import dbg;dbg()
        ret_dic = {}
        if chapter > 0:
            # episode = season["episodes"][chapter - 1]
            url = "{}/tv/{}/season/{}/episode/{}?api_key={}&language={}&append_to_response=videos,images,credits,external_ids&include_image_language={},en,null".format(host, self.result["id"], seasonNumber, chapter, api, self.search_language, self.search_language)
            episode = self.get_json(url)
            # logger.debug('EPISODE', url)

            episodeTitle = episode.get("name", '')
            episodeId = episode.get('id', '')
            episodePlot = episode.get('overview', '')
            episodeDate = episode.get('air_date', '')
            episodeImage =  episode.get('still_path', '')
            episodeCrew = episode.get('crew', [])
            episodeStars = episode.get('guest_stars', [])
            episodeVoteCount = episode.get('vote_count', 0)
            episodeVoteAverage = episode.get('vote_average', 0)
            externalIds = episode.get('external_ids', {})
            imdb_id = externalIds.get('imdb_id')
            tvdb_id = externalIds.get('tvdb_id')
            posters = []
            for image in episode.get('images',{}).get('stills',{}):
                posters.append('https://image.tmdb.org/t/p/original' + image['file_path'])

            ret_dic["episode_title"] = episodeTitle
            ret_dic["episode_plot"] = episodePlot

            if episodeImage:
                ret_dic["episode_image"] = 'https://image.tmdb.org/t/p/original' + episodeImage
            else:
                ret_dic["episode_image"] = ""
            if episodeDate:
                date = episodeDate.split("-")
                ret_dic["episode_air_date"] = date[2] + "/" + date[1] + "/" + date[0]
            else:
                ret_dic["episode_air_date"] = ""
            if posters:
                ret_dic['episode_posters'] = posters

            ret_dic["episode_crew"] = episodeCrew
            if episodeStars:
                ret_dic["episode_actors"] = [[k['name'], k['character'], 'https://image.tmdb.org/t/p/original/' + k['profile_path'] if k['profile_path'] else '', k['order']] for k in episodeStars]
            ret_dic["episode_vote_count"] = episodeVoteCount
            ret_dic["episode_vote_average"] = episodeVoteAverage
            ret_dic["episode_id"] = episodeId
            ret_dic["episode_imdb_id"] = imdb_id
            ret_dic["episode_tvdb_id"] = tvdb_id


        return ret_dic

    def get_list_episodes(self):
        url = '{}/tv/{}?api_key={}&language={}'.format(host, self.search_id, api, self.search_language)
        results = requests.get(url).json().get('seasons', [])
        seasons = []
        if results and 'Error' not in results:
            for season in results:
                url = '{}/tv/{}/season/{}?api_key={}&language={}'.format(host, self.search_id, season['season_number'], api, self.search_language)
                try: start_from = requests.get(url).json()['episodes'][0]['episode_number']
                except: start_from = 1
                seasons.append({'season_number':season['season_number'], 'episode_count':season['episode_count'], 'start_from':start_from})
        return seasons

    def get_videos(self):
        """
        :return: Returns an ordered list (language / resolution / type) of Dict objects in which each of its elements corresponds to a trailer, teaser or clip from youtube.
        :rtype: list of Dict
        """
        ret = []

        if self.result['id']:
            if self.result['videos']:
                self.result["videos"] = self.result["videos"]['results']
            else:
                self.result["videos"] = []
                # First video search in the search language
                url = "{}/{}/{}/videos?api_key={}&language={}".format(host, self.search_type, self.result['id'], api, self.search_language)

                dict_videos = self.get_json(url)
                if not isinstance(dict_videos, dict):
                    dict_videos = ast.literal_eval(dict_videos.decode('utf-8'))

                if dict_videos['results']:
                    dict_videos['results'] = sorted(dict_videos['results'], key=lambda x: (x['type'], x['size']))
                    self.result["videos"] = dict_videos['results']

            # If the search language is not English, do a second video search in English
            if self.search_language != 'en':
                url = "{}/{}/{}/videos?api_key={}".format(host, self.search_type, self.result['id'], api)

                dict_videos = self.get_json(url)
                if not isinstance(dict_videos, dict):
                    dict_videos = ast.literal_eval(dict_videos.decode('utf-8'))

                if dict_videos['results']:
                    dict_videos['results'] = sorted(dict_videos['results'], key=lambda x: (x['type'], x['size']))
                    self.result["videos"].extend(dict_videos['results'])

            # If the searches have obtained results, return a list of objects
            for i in self.result['videos']:
                if i['site'] == "YouTube":
                    ret.append({'name': i['name'],
                                'url': "plugin://plugin.video.youtube/play/?video_id={}".format(i['key']),
                                'size': str(i['size']),
                                'type': i['type'],
                                'language': i['iso_639_1']})

        return ret

    def get_infoLabels(self, infoLabels=None, origen=None):
        """
        :param infoLabels: Extra information about the movie, series, season or chapter.
        :type infoLabels: Dict
        :param origen: Source dictionary where the infoLabels are obtained, by default self.result
        :type origen: Dict
        :return: Returns the extra information obtained from the current object. If the infoLables parameter was passed, the returned value will be read as a duly updated parameter.
        :rtype: Dict
        """

        if infoLabels:
            ret_infoLabels = InfoLabels(infoLabels)
        else:
            ret_infoLabels = InfoLabels()
        # Start Listings
        l_country = [i.strip() for i in ret_infoLabels['country'].split(',') if ret_infoLabels['country']]
        l_director = [i.strip() for i in ret_infoLabels['director'].split(',') if ret_infoLabels['director']]
        l_director_image = ret_infoLabels.get('director_image', [])
        l_director_id = ret_infoLabels.get('director_id', [])
        l_writer = [i.strip() for i in ret_infoLabels['writer'].split(',') if ret_infoLabels['writer']]
        l_writer_image = ret_infoLabels.get('writer_image', [])
        l_writer_id = ret_infoLabels.get('writer_id', [])
        l_castandrole = ret_infoLabels.get('castandrole', [])

        if not origen:
            origen = self.result

        if 'credits' in list(origen.keys()):
            dic_origen_credits = origen['credits']
            origen['credits_cast'] = dic_origen_credits.get('cast', [])
            origen['credits_crew'] = dic_origen_credits.get('crew', [])
            del origen['credits']

        if 'images' in list(origen.keys()):
            dic_origen_credits = origen['images']
            origen['posters'] = dic_origen_credits.get('posters', [])
            origen['fanarts'] = dic_origen_credits.get('backdrops', [])
            del origen['images']

        items = list(origen.items())

        # Season / episode information
        if ret_infoLabels['season'] and self.season.get(ret_infoLabels['season']):
            # If there is data loaded for the indicated season

            episodio = -1
            if ret_infoLabels['episode']:
                episodio = ret_infoLabels['episode']

            items.extend(list(self.get_episode(ret_infoLabels['season'], episodio).items()))


        for k, v in items:
            if not v:
                continue
            elif isinstance(v, str):
                v = re.sub(r"\n|\r|\t", "", v)
                # fix
                if v == "None":
                    continue

            if k == 'media_type':
                # from core.support import dbg;dbg()
                ret_infoLabels['mediatype'] = v if v in ['tv', 'tvshow'] else 'movie'

            elif k == 'overview':
                if origen:
                    ret_infoLabels['plot'] = v
                else:
                    ret_infoLabels['plot'] = self.get_plot()

            elif k == 'runtime':                                # Duration for movies
                ret_infoLabels['duration'] = int(v) * 60

            elif k == 'episode_run_time':                       # Duration for episodes
                try:
                    for v_alt in v:                             # It comes as a list (?!)
                        ret_infoLabels['duration'] = int(v_alt) * 60
                except:
                    pass

            elif k == 'release_date':
                ret_infoLabels['year'] = int(v[:4])
                ret_infoLabels['premiered'] = v

            elif k == 'first_air_date':
                ret_infoLabels['year'] = int(v[:4])
                ret_infoLabels['aired'] = v
                ret_infoLabels['premiered'] = ret_infoLabels['aired']

            elif k == 'original_title' or k == 'original_name':
                ret_infoLabels['originaltitle'] = v

            elif k == 'vote_average':
                ret_infoLabels['rating'] = float(v)

            elif k == 'vote_count':
                ret_infoLabels['votes'] = v

            elif k in ['poster_path', 'profile_path']:
                ret_infoLabels['thumbnail'] = 'https://image.tmdb.org/t/p/original' + v

            elif k == 'backdrop_path':
                ret_infoLabels['fanart'] = 'https://image.tmdb.org/t/p/original' + v

            elif k == 'id':
                ret_infoLabels['tmdb_id'] = v

            elif k == 'imdb_id':
                ret_infoLabels['imdb_id'] = v

            elif k == 'external_ids':
                if 'tvdb_id' in v:
                    ret_infoLabels['tvdb_id'] = v['tvdb_id']
                if 'imdb_id' in v:
                    ret_infoLabels['imdb_id'] = v['imdb_id']

            elif k in ['genres', "genre_ids", "genre"]:
                ret_infoLabels['genre'] = self.get_genres(origen)

            elif k == 'name' or k == 'title':
                ret_infoLabels['title'] = v

            elif k == 'tagline':
                ret_infoLabels['tagline'] = v

            elif k == 'production_companies':
                ret_infoLabels['studio'] = ", ".join(i['name'] for i in v)

            elif k == 'credits_cast' or k == 'season_cast' or k == 'episode_guest_stars':
                dic_aux = dict((name, [character, thumb, order, id]) for (name, character, thumb, order, id) in l_castandrole)
                l_castandrole.extend([(p['name'], p.get('character', '') or p.get('character_name', ''), 'https://image.tmdb.org/t/p/original' + p.get('profile_path', '') if p.get('profile_path', '') else '', p.get('order'), p.get('id')) \
                                      for p in v if 'name' in p and p['name'] not in list(dic_aux.keys())])

            elif k == 'videos':
                if not isinstance(v, list):
                    v = v.get('results', [])
                for i in v:
                    if i.get("site", "") == "YouTube":
                        ret_infoLabels['trailer'] = "plugin://plugin.video.youtube/play/?video_id=" + v[0]["key"]
                        break

            elif k == 'posters':
                ret_infoLabels['posters'] = ['https://image.tmdb.org/t/p/original' + p["file_path"] for p in v]

            elif k == 'fanarts':
                ret_infoLabels['fanarts'] = ['https://image.tmdb.org/t/p/original' + p["file_path"] for p in v]

            elif k == 'belongs_to_collection':
                c = Tmdb.get_collection(self, v.get('id',''))
                for k, v in c.items():
                    ret_infoLabels[k] = v

            elif k == 'production_countries' or k == 'origin_country':
                # support.dbg()
                if isinstance(v, str):
                    l_country = list(set(l_country + v.split(',')))

                elif isinstance(v, list) and len(v) > 0:
                    if isinstance(v[0], str):
                        l_country = list(set(l_country + v))
                    elif isinstance(v[0], dict):
                        # {'iso_3166_1': 'FR', 'name':'France'}
                        for i in v:
                            if 'name' in i:
                                # pais = Tmdb.dic_country.get(i['iso_3166_1'], i['iso_3166_1'])
                                l_country = list(set(l_country + [i['name']]))

            elif k == 'credits_crew' or k == 'episode_crew' or k == 'season_crew':
                for crew in v:
                    if crew['job'].lower() == 'director':
                        # from core.support import dbg;dbg()
                        l_director = list(set(l_director + [crew['name']]))
                        l_director_image += ['https://image.tmdb.org/t/p/original' + crew['profile_path'] if crew['profile_path'] else '']
                        l_director_id += [crew['id']]

                    elif crew['job'].lower() in ('screenplay', 'writer'):
                        l_writer = list(set(l_writer + [crew['name']]))
                        l_writer_image += ['https://image.tmdb.org/t/p/original' + crew['profile_path'] if crew['profile_path'] else '']
                        l_writer_id += [crew['id']]

            elif k == 'created_by':
                for crew in v:
                    l_writer = list(set(l_writer + [crew['name']]))


            elif isinstance(v, str) or isinstance(v, int) or isinstance(v, float):
                ret_infoLabels[k] = v

            else:
                # logger.debug("Atributos no añadidos: " + k +'= '+ str(v))
                pass

        # Sort the lists and convert them to str if necessary
        if l_castandrole:
            ret_infoLabels['castandrole'] = sorted(l_castandrole, key=lambda tup: tup[0])
        if l_country:
            ret_infoLabels['country'] = ', '.join(sorted(l_country))
        if l_director:
            ret_infoLabels['director'] = ', '.join(l_director)
            ret_infoLabels['director_image'] = l_director_image
            ret_infoLabels['director_id'] = l_director_id
        if l_writer:
            ret_infoLabels['writer'] = ', '.join(l_writer)
            ret_infoLabels['writer_image'] = l_writer_image
            ret_infoLabels['writer_id'] = l_writer_id

        return ret_infoLabels

    def get_mpaa(self, result):
        if result.get('id'):
            Mpaaurl = '{}/{}/{}/{}?api_key={}'.format(host, self.search_type, result['id'], 'release_dates' if self.search_type == 'movie' else 'content_ratings', api)
            Mpaas = self.get_json(Mpaaurl).get('results',[])
            for m in Mpaas:
                if m.get('iso_3166_1','').lower() == 'us':
                    result['mpaa'] = m.get('rating', m.get('release_dates', [{}])[0].get('certification'))
                    break
        return result


def get_season_dic(season):
    ret_dic = dict()
    # logger.debug(jsontools.dump(season))
    # Get data for this season

    seasonTitle = season.get("name", '')
    seasonPlot = season.get("overview" , '')
    seasonId = season.get("id", '')
    seasonEpisodes = len(season.get("episodes",[]))
    seasonDate = season.get("air_date", '')
    seasonPoster = season.get('poster_path', '')
    seasonCredits = season.get('credits', {})
    seasonPosters = season.get('images',{}).get('posters',{})
    seasonFanarts = season.get('images',{}).get('backdrops',{})
    seasonTrailers = season.get('videos',{}).get('results',[])

    ret_dic["season_title"] = seasonTitle
    ret_dic["season_plot"] = seasonPlot
    ret_dic["season_id"] = seasonId
    ret_dic["season_episodes_number"] = seasonEpisodes

    if seasonDate:
        date = seasonDate.split("-")
        ret_dic["season_air_date"] = date[2] + "/" + date[1] + "/" + date[0]
    else:
        ret_dic["season_air_date"] = ''
    if seasonPoster:
        ret_dic["season_poster"] = 'https://image.tmdb.org/t/p/original' + seasonPoster
    else:
        ret_dic["season_poster"] = ''

    if seasonPosters:
        ret_dic['season_posters'] = ['https://image.tmdb.org/t/p/original' + p["file_path"] for p in seasonPosters]
    if seasonFanarts:
        ret_dic['season_fanarts'] = ['https://image.tmdb.org/t/p/original' + p["file_path"] for p in seasonFanarts]
    if seasonTrailers:
        ret_dic['season_trailer'] = []
        for i in seasonTrailers:
            if i.get("site", "") == "YouTube":
                ret_dic['season_trailer'] = "plugin://plugin.video.youtube/play/?video_id=" + seasonTrailers[0]["key"]
                break

    dic_aux = seasonCredits if seasonCredits else {}
    ret_dic["season_cast"] = dic_aux.get('cast', [])
    ret_dic["season_crew"] = dic_aux.get('crew', [])
    return ret_dic

def parse_fallback_info(info, fallbackInfo):
    info_dict = {}
    for key, value in info.items():
        if not value:
            value = fallbackInfo[key]
        info_dict[key] = value
    episodes = info_dict['episodes']

    episodes_list = []
    for i, episode in enumerate(episodes):
        episode_dict = {}
        for key, value in episode.items():
            if not value:
                value = fallbackInfo['episodes'][i][key]
            episode_dict[key] = value
        episodes_list.append(episode_dict)

    info_dict['episodes'] = episodes_list
    return info_dict