# -*- coding: utf-8 -*-
# ------------------------------------------------------------
# Download manager
# ------------------------------------------------------------

from __future__ import division
#from builtins import str
import sys, os
PY3 = False
if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int
from past.utils import old_div

import re, time, unicodedata, xbmc

from channelselector import get_thumb
from core import filetools, jsontools, scraper, scrapertools, servertools, videolibrarytools, support
from core.downloader import Downloader
from core.item import Item
from platformcode import config, logger, platformtools
from core.support import info, typo
from servers import torrent

kb = '0xFF65B3DA'
kg = '0xFF65DAA8'
kr = '0xFFDA6865'
ky = '0xFFDAAB65'

STATUS_COLORS = {0: '', 1: '', 2: kg, 3: kr, 4: kb}
STATUS_CODES = type("StatusCode", (), {"stoped": 0, "canceled": 1, "completed": 2, "error": 3, "downloading": 4 })
DOWNLOAD_LIST_PATH = config.get_setting("downloadlistpath")
DOWNLOAD_PATH = config.get_setting("downloadpath")
STATS_FILE = filetools.join(config.get_data_path(), "servers.json")

FOLDER_MOVIES = config.get_setting("folder_movies")
FOLDER_TVSHOWS = config.get_setting("folder_tvshows")
TITLE_FILE = "[COLOR %s]| %i%% |[/COLOR] - %s"
TITLE_TVSHOW = "[COLOR %s]| %i%% |[/COLOR] - %s [%s]"
extensions_list = ['.aaf', '.3gp', '.asf', '.avi', '.flv', '.mpeg', '.m1v', '.m2v', '.m4v', '.mkv', '.mov', '.mpg', '.mpe', '.mp4', '.ogg', '.wmv']


def mainlist(item):
    info()
    itemlist = []

    # File list
    for file in sorted(filetools.listdir(DOWNLOAD_LIST_PATH)):
        # We skip all the non JSON
        if not file.endswith(".json"): continue

        # we load the item
        file = filetools.join(DOWNLOAD_LIST_PATH, file)
        i = Item(path=file).fromjson(filetools.read(file))
        i.thumbnail = i.contentThumbnail

        # Main listing
        if not item.contentType == "tvshow":
            # Series
            if i.contentType == "episode":
                # We check that the series is not already in the itemlist
                if not [x for x in itemlist if x.contentSerieName == i.contentSerieName and x.contentChannel == i.contentChannel]:

                    title = TITLE_TVSHOW % (STATUS_COLORS[i.downloadStatus], i.downloadProgress, i.contentSerieName, i.contentChannel)

                    itemlist.append(Item(title=title, channel="downloads", action="mainlist", contentType="tvshow",
                                         contentSerieName=i.contentSerieName, contentChannel=i.contentChannel,
                                         downloadStatus=i.downloadStatus, downloadProgress=[i.downloadProgress],
                                         fanart=i.fanart, thumbnail=i.thumbnail))

                else:
                    s = [x for x in itemlist if x.contentSerieName == i.contentSerieName and x.contentChannel == i.contentChannel][0]
                    s.downloadProgress.append(i.downloadProgress)
                    downloadProgress = old_div(sum(s.downloadProgress), len(s.downloadProgress))

                    if not s.downloadStatus in [STATUS_CODES.error, STATUS_CODES.canceled] and not i.downloadStatus in [
                        STATUS_CODES.completed, STATUS_CODES.stoped]:
                        s.downloadStatus = i.downloadStatus

                    s.title = TITLE_TVSHOW % (STATUS_COLORS[s.downloadStatus], downloadProgress, i.contentSerieName, i.contentChannel)

            # Movies
            elif i.contentType == "movie" or i.contentType == "video":
                i.title = TITLE_FILE % (STATUS_COLORS[i.downloadStatus], i.downloadProgress, i.contentTitle)
                itemlist.append(i)

        # Listed within a series
        else:
            if i.contentType == "episode" and i.contentSerieName == item.contentSerieName and i.contentChannel == item.contentChannel:
                i.title = TITLE_FILE % (STATUS_COLORS[i.downloadStatus], i.downloadProgress, "%dx%0.2d: %s" % (i.contentSeason, i.contentEpisodeNumber, i.contentTitle))
                itemlist.append(i)

    estados = [i.downloadStatus for i in itemlist]

    # If there is any completed
    if 2 in estados:
        itemlist.insert(0, Item(channel=item.channel, action="clean_ready", title=config.get_localized_string(70218),
                                contentType=item.contentType, contentChannel=item.contentChannel, thumbnail=get_thumb('delete.png'),
                                contentSerieName=item.contentSerieName, text_color=STATUS_COLORS[STATUS_CODES.completed]))

    # If there is any error
    if 3 in estados:
        itemlist.insert(0, Item(channel=item.channel, action="restart_error", title=config.get_localized_string(70219),
                                contentType=item.contentType, contentChannel=item.contentChannel, thumbnail=get_thumb('update.png'),
                                contentSerieName=item.contentSerieName, text_color=STATUS_COLORS[STATUS_CODES.error]))

    # If there is any pending
    if 1 in estados or 0 in estados:
        itemlist.insert(0, Item(channel=item.channel, action="download_all", title=support.typo(config.get_localized_string(70220),'bold'),
                                contentType=item.contentType, contentChannel=item.contentChannel, thumbnail=get_thumb('downloads.png'),
                                contentSerieName=item.contentSerieName))

    if len(itemlist):
        itemlist.insert(0, Item(channel=item.channel, action="clean_all", title=support.typo(config.get_localized_string(70221),'bold'),
                                contentType=item.contentType, contentChannel=item.contentChannel, thumbnail=get_thumb('delete.png'),
                                contentSerieName=item.contentSerieName))

    # if there's at least one downloading
    if 4 in estados:
        itemlist.insert(0, Item(channel=item.channel, action="stop_all", title=config.get_localized_string(60222),
                                contentType=item.contentType, contentChannel=item.contentChannel,
                                contentSerieName=item.contentSerieName, thumbnail=get_thumb('stop.png'),
                                text_color=STATUS_COLORS[STATUS_CODES.downloading]))

    if not item.contentType == "tvshow" and config.get_setting("browser") == True:
        itemlist.insert(0, Item(channel=item.channel, action="browser", title=support.typo(config.get_localized_string(70222),'bold'), thumbnail=get_thumb('search.png'), url=DOWNLOAD_PATH))

    if not item.contentType == "tvshow":
        itemlist.append(Item(channel='shortcuts', action="SettingOnPosition", category=6, setting=0, title= support.typo(config.get_localized_string(70288),'bold color kod'), thumbnail=get_thumb('setting_0.png')))

    # Reload
    if estados:
        itemlist.insert(0, Item(channel=item.channel, action="reload", title= support.typo(config.get_localized_string(70008),'bold color kod'),
                                contentType=item.contentType, contentChannel=item.contentChannel, thumbnail=get_thumb('update.png'),
                                contentSerieName=item.contentSerieName))

    return itemlist


def settings(item):
    ret = platformtools.show_channel_settings(caption=config.get_localized_string(70224))
    platformtools.itemlist_refresh()
    return ret


def browser(item):
    info()
    itemlist = []

    for file in filetools.listdir(item.url):
        if file == "list": continue
        if filetools.isdir(filetools.join(item.url, file)):
            itemlist.append(Item(channel=item.channel, title=file, action=item.action, url=filetools.join(item.url, file), context=[{ 'title': config.get_localized_string(30037), 'channel': 'downloads', 'action': "del_dir"}]))
        else:
            if not item.infoLabels:
                infoLabels = {"mediatype":"video"}
            else:
                infoLabels = item.infoLabels
            itemlist.append(Item(channel=item.channel, title=file, action="play", infoLabels=infoLabels, url=filetools.join(item.url, file), context=[{ 'title': config.get_localized_string(30039), 'channel': 'downloads', 'action': "del_file"}]))

    return itemlist


def del_file(item):
    ok = platformtools.dialog_yesno(config.get_localized_string(30039),config.get_localized_string(30040) % item.title)
    if ok:
        filetools.remove(item.url)
        xbmc.sleep(100)
        platformtools.itemlist_refresh()


def del_dir(item):
    ok = platformtools.dialog_yesno(config.get_localized_string(30037),config.get_localized_string(30038))
    if ok:
        filetools.rmdirtree(item.url)
        xbmc.sleep(100)
        platformtools.itemlist_refresh()


def clean_all(item):
    info()
    stop_all()
    removeFiles = False
    if platformtools.dialog_yesno(config.get_localized_string(20000), config.get_localized_string(30300)):
        removeFiles = True

    for File in sorted(filetools.listdir(DOWNLOAD_LIST_PATH)):
        if File.endswith(".json"):
            download_item = Item().fromjson(filetools.read(filetools.join(DOWNLOAD_LIST_PATH, File)))
            if not item.contentType == "tvshow" or ( item.contentSerieName == download_item.contentSerieName and item.contentChannel == download_item.contentChannel):
                filetools.remove(filetools.join(DOWNLOAD_LIST_PATH, File))
                if removeFiles:
                    filetools.remove(filetools.join(DOWNLOAD_PATH, download_item.downloadFilename))
                    dirName = filetools.join(DOWNLOAD_PATH, filetools.dirname(download_item.downloadFilename))
                    if len(filetools.listdir(dirName)) == 0:
                        filetools.rmdir(dirName)

    xbmc.sleep(100)
    platformtools.itemlist_refresh()


def reload(item):
    platformtools.itemlist_refresh()


def stop_all(item=None):
    info()

    for fichero in sorted(filetools.listdir(DOWNLOAD_LIST_PATH)):
        if fichero.endswith(".json"):
            download_item = Item().fromjson(filetools.read(filetools.join(DOWNLOAD_LIST_PATH, fichero)))
            if download_item.TorrentName:
                from inspect import stack
                if stack()[1][3] == 'clean_all': action = 'delete'
                else: action = 'pause'
                torrent.elementum_actions(action, download_item.TorrentName)
            if download_item.downloadStatus == 4:
                update_json(filetools.join(DOWNLOAD_LIST_PATH, fichero), {"downloadStatus": STATUS_CODES.stoped})
    xbmc.sleep(300)
    if item:
        platformtools.itemlist_refresh()


def clean_ready(item):
    info()
    for fichero in sorted(filetools.listdir(DOWNLOAD_LIST_PATH)):
        if fichero.endswith(".json"):
            download_item = Item().fromjson(filetools.read(filetools.join(DOWNLOAD_LIST_PATH, fichero)))
            if not item.contentType == "tvshow" or ( item.contentSerieName == download_item.contentSerieName and item.contentChannel == download_item.contentChannel):
                if download_item.downloadStatus == STATUS_CODES.completed:
                    filetools.remove(filetools.join(DOWNLOAD_LIST_PATH, fichero))

    platformtools.itemlist_refresh()


def restart_error(item):
    info()
    for fichero in sorted(filetools.listdir(DOWNLOAD_LIST_PATH)):
        if fichero.endswith(".json"):
            download_item = Item().fromjson(filetools.read(filetools.join(DOWNLOAD_LIST_PATH, fichero)))

            if not item.contentType == "tvshow" or ( item.contentSerieName == download_item.contentSerieName and item.contentChannel == download_item.contentChannel):
                if download_item.downloadStatus == STATUS_CODES.error:
                    if filetools.isfile(
                            filetools.join(DOWNLOAD_PATH, download_item.downloadFilename)):
                        filetools.remove(
                            filetools.join(DOWNLOAD_PATH, download_item.downloadFilename))

                    update_json(item.path, {"downloadStatus": STATUS_CODES.stoped, "downloadComplete": 0, "downloadProgress": 0})

    platformtools.itemlist_refresh()


def download_all(item):
    time.sleep(0.5)
    item.action = "download_all_background"
    xbmc.executebuiltin("RunPlugin(plugin://plugin.video.kod/?" + item.tourl() + ")")
    platformtools.itemlist_refresh()


def download_all_background(item):
    for fichero in sorted(filetools.listdir(DOWNLOAD_LIST_PATH)):
        if fichero.endswith(".json"):
            download_item = Item(path=filetools.join(DOWNLOAD_LIST_PATH, fichero)).fromjson(
                filetools.read(filetools.join(DOWNLOAD_LIST_PATH, fichero)))

            if not item.contentType == "tvshow" or ( item.contentSerieName == download_item.contentSerieName and item.contentChannel == download_item.contentChannel):
                if download_item.downloadStatus in [STATUS_CODES.stoped, STATUS_CODES.canceled]:
                    res = start_download(download_item)
                    # platformtools.itemlist_refresh()
                    # If canceled, we stop
                    if res == STATUS_CODES.canceled: break


def menu(item):
    info(item)
    if item.downloadServer:
        servidor = item.downloadServer.get("server", "Auto")
    else:
        servidor = "Auto"
    # Options available for the menu
    op = [config.get_localized_string(70225), config.get_localized_string(70226), config.get_localized_string(70227),
          config.get_localized_string(30165) % (servidor.capitalize()), config.get_localized_string(60220),
          config.get_localized_string(60221)]

    opciones = []

    # Options for the menu
    if item.downloadStatus == STATUS_CODES.stoped:
        opciones.append(op[0])                          # Download
        if not item.server: opciones.append(op[3])      # Choose Server
        opciones.append(op[1])                          # Remove from the list

    if item.downloadStatus == STATUS_CODES.canceled:
        opciones.append(op[0])                          # Download
        if not item.server: opciones.append(op[3])      # Choose Server
        opciones.append(op[2])                          # Restart download
        opciones.append(op[1])                          # Remove from the list

    if item.downloadStatus == STATUS_CODES.completed:
        opciones.append(op[5])                          # Play
        opciones.append(op[1])                          # Remove from the list
        opciones.append(op[2])                          # Restart download

    if item.downloadStatus == STATUS_CODES.error:       # Download with error
        opciones.append(op[2])                          # Restart download
        opciones.append(op[1])                          # Remove from the list

    if item.downloadStatus == STATUS_CODES.downloading:
        opciones.append(op[5])                          # Play
        opciones.append(op[4])                          # Pause Download
        opciones.append(op[1])                          # Remove from the list

    # Show Dialog
    seleccion = platformtools.dialog_select(config.get_localized_string(30163), opciones)
    logger.debug('SELECTION: '+ op[seleccion])

    # -1 is cancel
    if seleccion == -1: return

    # Delete
    if opciones[seleccion] == op[1]:
        filetools.remove(item.path)
        if item.TorrentName:
            torrent.elementum_actions('delete', item.TorrentName)
        else:
            if platformtools.dialog_yesno(config.get_localized_string(20000), config.get_localized_string(30300)):
                filetools.remove(filetools.join(DOWNLOAD_PATH, item.downloadFilename))

    # Start Download
    if opciones[seleccion] == op[0]:
        item.action = "start_download"
        xbmc.executebuiltin("RunPlugin(plugin://plugin.video.kod/?" + item.tourl() + ")")

    # Select Server
    if opciones[seleccion] == op[3]:
        select_server(item)

    # Restart Download
    if opciones[seleccion] == op[2]:
        if filetools.isfile(filetools.join(DOWNLOAD_PATH, item.downloadFilename)):
            filetools.remove(filetools.join(DOWNLOAD_PATH, item.downloadFilename))

        update_json(item.path, {"downloadStatus": STATUS_CODES.stoped, "downloadComplete": 0, "downloadProgress": 0, "downloadServer": {}})

    if opciones[seleccion] == op[4]:
        if item.TorrentName:
            torrent.elementum_actions('pause', item.TorrentName)
        update_json(item.path, {"downloadStatus": STATUS_CODES.stoped})

    if opciones[seleccion] == op[5]:
        path = filetools.join(DOWNLOAD_PATH, item.downloadFilename)
        if filetools.isdir(path):
            videos = []
            files = filetools.listdir(path)
            for f in files:
                if os.path.splitext(f)[-1] in extensions_list:
                    videos.append(f)
            if len(videos) > 1:
                selection = platformtools.dialog_select(config.get_localized_string(30034), files)
            else:
                selection = 0
            xbmc.executebuiltin('PlayMedia(' + filetools.join(path, files[selection]) + ',resume)')
        else:
            xbmc.executebuiltin('PlayMedia(' + path + ',resume)')

    if opciones[seleccion] != op[5]:
        platformtools.itemlist_refresh()


def move_to_libray(item):
    info()

    if item.contentType == 'movie':
        FOLDER = FOLDER_MOVIES
        path_title = "%s [%s]" % (item.contentTitle.strip() if item.contentTitle else item.fulltitle.strip() , item.infoLabels['IMDBNumber'])
        move_path = filetools.join(config.get_videolibrary_path(), FOLDER, path_title)

    else:
        FOLDER = FOLDER_TVSHOWS
        path_title = os.path.dirname(item.downloadFilename)
        move_path = filetools.join(config.get_videolibrary_path(), FOLDER)

    download_path = filetools.join(DOWNLOAD_PATH, item.downloadFilename)
    library_path = filetools.join(move_path, *filetools.split(item.downloadFilename)) 
    final_path = download_path

    if not filetools.isdir(filetools.dirname(library_path)):
        filetools.mkdir(filetools.dirname(library_path))

    if item.contentType == "movie" and item.infoLabels["tmdb_id"]:
        contentTitle = item.contentTitle if item.contentTitle else item.fulltitle
        library_item = Item(title= filetools.split(item.downloadFilename)[-1], channel="downloads", contentTitle = contentTitle,
                            fulltitle = item.fulltitle,action="findvideos", infoLabels=item.infoLabels, url=library_path)
        videolibrarytools.save_movie(library_item, silent=True)

    elif item.contentType == "episode" and item.infoLabels["tmdb_id"]:
        contentSerieName = item.contentSerieName if item.contentSerieName else item.fulltitle
        library_item = Item(title=filetools.split(item.downloadFilename)[-1], channel="downloads", contentSerieName = contentSerieName,
                            fulltitle = item.fulltitle, action="findvideos", infoLabels=item.infoLabels, url=library_path)
        tvshow = Item(channel="downloads", contentType="tvshow", contentSerieName = contentSerieName,
                        fulltitle = item.fulltitle, infoLabels={"tmdb_id": item.infoLabels["tmdb_id"]})
        videolibrarytools.save_tvshow(tvshow, [library_item], silent=True)

    if filetools.isfile(library_path) and filetools.isfile(download_path):
        filetools.remove(library_path)

    if filetools.isfile(download_path):
        if filetools.move(download_path, library_path, silent=True):
            final_path = library_path

        if len(filetools.listdir(filetools.dirname(download_path))) == 0:
            filetools.rmdir(filetools.dirname(download_path))

    name = item.contentTitle if item.contentType == 'movie' else str(item.infoLabels['season']) + 'x' + str(item.infoLabels['episode']).zfill(2)
    list_item = filetools.listdir(filetools.join(config.get_videolibrary_path(), FOLDER, path_title))

    clean = False
    for File in list_item:
        filename = File.lower()
        name = name.lower()

        if filename.startswith(name) and (filename.endswith('.strm') or (filename.endswith('.json') and 'downloads' not in filename)):
            clean = True
            file_path = filetools.join(config.get_setting("videolibrarypath"), FOLDER, path_title, File)
            info('Delete File:', str(file_path))
            filetools.remove(file_path)
            if file_path.endswith('.strm'):
                file_strm_path = file_path

    if config.is_xbmc() and config.get_setting("videolibrary_kodi"):
        from platformcode import xbmc_videolibrary
        if clean == True:
            path_list = [file_strm_path]
            xbmc_videolibrary.clean(path_list)
        xbmc_videolibrary.update(FOLDER, path_title)


def update_json(path, params):
    item = Item().fromjson(filetools.read(path))
    item.__dict__.update(params)
    filetools.write(path, item.tojson())


def save_server_statistics(server, speed, success):
    if filetools.isfile(STATS_FILE):
        servers = jsontools.load(filetools.read(STATS_FILE))
    else:
        servers = {}

    if not server in servers:
        servers[server] = {"success": [], "count": 0, "speeds": [], "last": 0}

    servers[server]["count"] += 1
    servers[server]["success"].append(bool(success))
    servers[server]["success"] = servers[server]["success"][-5:]
    servers[server]["last"] = time.time()
    if success:
        servers[server]["speeds"].append(speed)
        servers[server]["speeds"] = servers[server]["speeds"][-5:]

    filetools.write(STATS_FILE, jsontools.dump(servers))
    return


def get_server_position(server):
    if filetools.isfile(STATS_FILE):
        servers = jsontools.load(filetools.read(STATS_FILE))
    else:
        servers = {}

    if server in servers:
        pos = [s for s in sorted(servers, key=lambda x: (old_div(sum(servers[x]["speeds"]), (len(servers[x]["speeds"]) or 1)), float(sum(servers[x]["success"])) / ( len(servers[x]["success"]) or 1)), reverse=True)]
        return pos.index(server) + 1
    else:
        return 0


def get_match_list(data, match_list, order_list=None, only_ascii=False, ignorecase=False):
    """
    Search for matches in a text string, with a dictionary of "ID" / "List of search strings":
    {"ID1": ["String 1", "String 2", "String 3"],
      "ID2": ["String 4", "String 5", "String 6"]
    }

    The dictionary could not contain the same search string in several IDs.
    The search is performed in order of search string size (from longest to shortest) if a string matches,
    it is removed from the search string for the following, so that two categories are not detected if one string is part of another:
    for example: "Spanish Language" and "Spanish" if the first appears in the string "Pablo knows how to speak the Spanish Language"
    It will match "Spanish Language" but not "Spanish" since the longest match has priority.

    """
    match_dict = dict()
    matches = []

    # We pass the string to unicode
    if not PY3:
        data = unicode(data, "utf8")

    # We pass the dictionary to {"String 1": "ID1", "String 2", "ID1", "String 4", "ID2"} and we pass them to unicode
    for key in match_list:
        if order_list and not key in order_list:
            raise Exception("key '%s' not in match_list" % key)
        for value in match_list[key]:
            if value in match_dict:
                raise Exception("Duplicate word in list: '%s'" % value)
            if not PY3:
                match_dict[unicode(value, "utf8")] = key
            else:
                match_dict[value] = key

    # If ignorecase = True, we pass everything to capital letters
    if ignorecase:
        data = data.upper()
        match_dict = dict((key.upper(), match_dict[key]) for key in match_dict)

    # If ascii = True, we remove all accents and Ñ
    if only_ascii:
        data = ''.join((c for c in unicodedata.normalize('NFD', data) if unicodedata.category(c) != 'Mn'))
        match_dict = dict((''.join((c for c in unicodedata.normalize('NFD', key) if unicodedata.category(c) != 'Mn')), match_dict[key]) for key in match_dict)

    # We sort the list from largest to smallest and search.
    for match in sorted(match_dict, key=lambda x: len(x), reverse=True):
        s = data
        for a in matches:
            s = s.replace(a, "")
        if match in s:
            matches.append(match)
    if matches:
        if order_list:
            return type("Mtch_list", (), {"key": match_dict[matches[-1]], "index": order_list.index(match_dict[matches[-1]])})
        else:
            return type("Mtch_list", (), {"key": match_dict[matches[-1]], "index": None})
    else:
        if order_list:
            return type("Mtch_list", (), {"key": None, "index": len(order_list)})
        else:
            return type("Mtch_list", (), {"key": None, "index": None})


def sort_method(item):
    """
    Score each item based on various parameters:
    @type item: item
    @param item: item to be valued.
    @return:  punctuation obtained
    @rtype: int
    """
    lang_orders = {}
    lang_orders['ITA'] = ["ITA", "Sub-ITA"]
    lang_orders['Sub-ITA'] = ["ITA", "Sub-ITA"]

    quality_orders = {}
    quality_orders[0] = ["BLURAY", "FULLHD", "HD", "480P", "360P", "240P"]
    quality_orders[1] = ["FULLHD", "HD", "480P", "360P", "240P", "BLURAY"]
    quality_orders[2] = ["HD", "480P", "360P", "240P", "FULLHD", "BLURAY"]
    quality_orders[3] = ["480P", "360P", "240P", "BLURAY", "FULLHD", "HD"]

    order_list_idiomas = lang_orders[config.get_setting("language")]
    match_list_idimas = {"ITA": ["ITA", "IT", "Italiano", "italiano", "ITALIANO"],
                         "Sub-ITA": ["Sottotitolato", "SUB", "sub-ita", "SUB-ITA", "Sub-ITA", "Sub-Ita"]}

    order_list_calidad = ["BLURAY", "FULLHD", "HD", "480P", "360P", "240P"]
    order_list_calidad = quality_orders[int(config.get_setting("quality"))]
    match_list_calidad = {"BLURAY": ["BR", "BLURAY", '4K'],
                          "FULLHD": ["FULLHD", "FULL HD", "1080", "HD1080", "HD 1080", "1080p"],
                          "HD": ["HD", "HD REAL", "HD 720", "720", "HDTV", "720p"],
                          "480P": ["SD", "480P", '480', 'NORMAL'],
                          "360P": ["360P", "360", 'MOBILE'],
                          "240P": ["240P", "240"]}

    value = (get_match_list(item.title, match_list_idimas, order_list_idiomas, ignorecase=True, only_ascii=True).index, \
             get_match_list(item.title, match_list_calidad, order_list_calidad, ignorecase=True, only_ascii=True).index)

    if config.get_setting("server_speed"):
        value += tuple([get_server_position(item.server)])

    return value


def download_from_url(url, item):
    info("Attempting to download:", url)
    if '.m3u8' in url.lower().split('|')[0] or url.lower().startswith("rtmp"):
        save_server_statistics(item.server, 0, False)
        platformtools.dialog_notification('m3u8 Download',config.get_localized_string(60364), sound=False)
        return {"downloadStatus": STATUS_CODES.error}

    # We get the download path and the file name
    item.downloadFilename = item.downloadFilename
    download_path = filetools.dirname(filetools.join(DOWNLOAD_PATH, item.downloadFilename))
    file_name = filetools.basename(filetools.join(DOWNLOAD_PATH, item.downloadFilename))

    # We create the folder if it does not exist

    if not filetools.exists(download_path):
        filetools.mkdir(download_path)

    # We launch the download
    d = Downloader(url, download_path, file_name,
                   max_connections=1 + int(config.get_setting("max_connections", "downloads")),
                   block_size=2 ** (17 + int(config.get_setting("block_size", "downloads"))),
                   part_size=2 ** (20 + int(config.get_setting("part_size", "downloads"))),
                   max_buffer=2 * int(config.get_setting("max_buffer", "downloads")),
                   json_path=item.path)
    dir = filetools.dirname(item.downloadFilename)
    file = filetools.join(dir, d.filename)

    update_json(item.path, {"downloadUrl": d.download_url, "downloadStatus": STATUS_CODES.downloading, "downloadSize": d.size[0],
            "downloadProgress": d.progress, "downloadCompleted": d.downloaded[0], "downloadFilename": file})

    d.start_dialog(config.get_localized_string(60332))

    # Download stopped. We get the state:
    # Download failed
    if d.state == d.states.error:
        info("Error trying to download", url)
        status = STATUS_CODES.error

    # Download has stopped
    elif d.state == d.states.stopped:
        info("Stop download")
        status = STATUS_CODES.canceled

    # Download is complete
    elif d.state == d.states.completed:
        info("Downloaded correctly")
        status = STATUS_CODES.completed

        if (item.downloadSize and item.downloadSize != d.size[0]) or d.size[0] < 5000000:  # if size don't correspond or file is too little (gounlimited for example send a little video to say the server is overloaded)
            status = STATUS_CODES.error

    save_server_statistics(item.server, d.speed[0], d.state != d.states.error)

    if status == STATUS_CODES.completed and config.get_setting("library_move"):
        move_to_libray(item.clone(downloadFilename=file))

    return {"downloadUrl": d.download_url, "downloadStatus": status, "downloadSize": d.size[0],
            "downloadProgress": d.progress, "downloadCompleted": d.downloaded[0], "downloadFilename": file}


def download_from_server(item):
    info(item.tostring())
    unsupported_servers = ["torrent"]

    if item.contentChannel == 'local':
        return {"downloadStatus": STATUS_CODES.completed}

    progreso = platformtools.dialog_progress_bg(config.get_localized_string(30101), config.get_localized_string(70178) % item.server)

    try:
        if item.contentChannel in ['community', 'videolibrary']:
            channel = __import__('specials.%s' % item.contentChannel, None, None, ['specials.%s' % item.contentChannel])
        else:
            channel = __import__('channels.%s' % item.contentChannel, None, None, ['channels.%s' % item.contentChannel])
        if hasattr(channel, "play") and not item.play_menu:

            progreso.update(50, config.get_localized_string(70178) % item.server + '\n' + config.get_localized_string(70180) % item.contentChannel)
            try:
                itemlist = getattr(channel, "play")(item.clone(channel=item.contentChannel, action=item.contentAction))
            except:
                logger.error("Error in the channel %s" % item.contentChannel)
            else:
                if len(itemlist) and isinstance(itemlist[0], Item):
                    download_item = item.clone(**itemlist[0].__dict__)
                    download_item.contentAction = download_item.action
                    download_item.infoLabels = item.infoLabels
                    item = download_item
                elif len(itemlist) and isinstance(itemlist[0], list):
                    item.video_urls = itemlist
                    if not item.server: item.server = "directo"
                else:
                    info("There is nothing to reproduce")
                    return {"downloadStatus": STATUS_CODES.error}
    finally:
        progreso.close()
    info("contentAction: %s | contentChannel: %s | server: %s | url: %s" % (item.contentAction, item.contentChannel, item.server, item.url))

    if item.server == 'torrent':
        import xbmcgui
        xlistitem = xbmcgui.ListItem(path=item.url)
        xlistitem.setArt({'icon': item.thumbnail, 'thumb': item.thumbnail, 'poster': item.thumbnail, 'fanart': item.thumbnail})
        platformtools.set_infolabels(xlistitem, item)
        platformtools.play_torrent(item, xlistitem, item.url)

    if not item.server or not item.url or not item.contentAction == "play" or item.server in unsupported_servers:
        logger.error("The Item does not contain the necessary parameters.")
        return {"downloadStatus": STATUS_CODES.error}

    if not item.video_urls:
        video_urls, puedes, motivo = servertools.resolve_video_urls_for_playing(item.server, item.url, item.password, True, True)
    else:
        video_urls, puedes, motivo = item.video_urls, True, ""

    # If it is not available, we go out
    if not puedes:
        info("The video is NOT available")
        return {"downloadStatus": STATUS_CODES.error}

    else:
        info("YES Video is available")

        result = {}

        # Go through all the options until I can download one correctly
        for video_url in reversed(video_urls):

            result = download_from_url(video_url[1], item)

            if result["downloadStatus"] in [STATUS_CODES.canceled, STATUS_CODES.completed]:
                break

            # Download error, we continue with the next option
            if result["downloadStatus"] == STATUS_CODES.error:
                continue

        # We return the state
        return result


def download_from_best_server(item):
    info("contentAction: %s | contentChannel: %s | url: %s" % (item.contentAction, item.contentChannel, item.url))

    result = {"downloadStatus": STATUS_CODES.error}
    progreso = platformtools.dialog_progress_bg(config.get_localized_string(30101), config.get_localized_string(70179))

    try:
        if item.downloadItemlist:
            info('using cached servers')
            play_items = [Item().fromurl(i) for i in item.downloadItemlist]
        else:
            if item.contentChannel in ['community', 'videolibrary']:
                channel = __import__('specials.%s' % item.contentChannel, None, None, ['specials.%s' % item.contentChannel])
            else:
                channel = __import__('channels.%s' % item.contentChannel, None, None, ['channels.%s' % item.contentChannel])

            progreso.update(50, config.get_localized_string(70184) + '\n' + config.get_localized_string(70180) % item.contentChannel)

            if hasattr(channel, item.contentAction):
                play_items = getattr(channel, item.contentAction)(item.clone(action=item.contentAction, channel=item.contentChannel))
            else:
                play_items = servertools.find_video_items(item.clone(action=item.contentAction, channel=item.contentChannel))

        play_items = [x for x in play_items if x.action == "play" and not "trailer" in x.title.lower()]

        progreso.update(100, config.get_localized_string(70183) + '\n' + config.get_localized_string(70181) % len(play_items))

        # if config.get_setting("server_reorder", "downloads") == 1:
        play_items.sort(key=sort_method)

        # if progreso.iscanceled():
        #     return {"downloadStatus": STATUS_CODES.canceled}
    finally:
        progreso.close()

    # We go through the list of servers, until we find one that works
    for play_item in play_items:
        play_item = item.clone(**play_item.__dict__)
        play_item.contentAction = play_item.action
        play_item.infoLabels = item.infoLabels

        result = download_from_server(play_item)

        # if progreso.iscanceled():
        #     result["downloadStatus"] = STATUS_CODES.canceled

        # Whether the download is canceled or completed, we stop trying more options
        if result["downloadStatus"] in [STATUS_CODES.canceled, STATUS_CODES.completed]:
            result["downloadServer"] = {"url": play_item.url, "server": play_item.server}
            break

    return result


def select_server(item):
    if item.server:
        return "Auto"
    info("contentAction: %s | contentChannel: %s | url: %s" % (item.contentAction, item.contentChannel, item.url))
    progreso = platformtools.dialog_progress_bg(config.get_localized_string(30101), config.get_localized_string(70179))
    try:
        if item.downloadItemlist:
            info('using cached servers')
            play_items = [Item().fromurl(i) for i in item.downloadItemlist]
        else:
            if item.contentChannel in ['community', 'videolibrary']:
                channel = __import__('specials.%s' % item.contentChannel, None, None, ['specials.%s' % item.contentChannel])
            else:
                channel = __import__('channels.%s' % item.contentChannel, None, None, ['channels.%s' % item.contentChannel])
            progreso.update(50, config.get_localized_string(70184) + '\n' + config.get_localized_string(70180) % item.contentChannel)

            if hasattr(channel, item.contentAction):
                play_items = getattr(channel, item.contentAction)(
                    item.clone(action=item.contentAction, channel=item.contentChannel))
            else:
                play_items = servertools.find_video_items(item.clone(action=item.contentAction, channel=item.contentChannel))

        play_items = [x for x in play_items if x.action == "play" and not "trailer" in x.title.lower()]
        progreso.update(100, config.get_localized_string(70183) + '\n' + config.get_localized_string(70181) % len(play_items))
    finally:
        progreso.close()

    for x, i in enumerate(play_items):
        if not i.server and hasattr(channel, "play"):
            play_items[x] = getattr(channel, "play")(i)

    if len(play_items) == 1:
        # if there is only one server select it
        seleccion = 1
    else:
        # otherwise it shows the selection window
        seleccion = platformtools.dialog_select(config.get_localized_string(70192), ["Auto"] + [s.title for s in play_items])

    if seleccion >= 1:
        update_json(item.path, {
            "downloadServer": {"url": play_items[seleccion - 1].url, "server": play_items[seleccion - 1].server}})
        return play_items[seleccion - 1]
    elif seleccion == 0:
        update_json(item.path, {"downloadServer": {}})
        return 'Auto'
    # platformtools.itemlist_refresh()


def start_download(item):
    info("contentAction: %s | contentChannel: %s | url: %s" % (item.contentAction, item.contentChannel, item.url))
    # We already have a server, we just need to download
    if item.contentAction == "play":
        ret = download_from_server(item)
    elif item.downloadServer and item.downloadServer.get("server"):
        ret = download_from_server(
            item.clone(server=item.downloadServer.get("server"), url=item.downloadServer.get("url"),
                       contentAction="play"))
    # We don't have a server, we need to find the best
    else:
        ret = download_from_best_server(item)

    if ret["downloadStatus"] == STATUS_CODES.completed and config.get_setting("library_move"):
        filetools.remove(item.path)
    else:
        update_json(item.path, ret)
    return ret["downloadStatus"]


def get_episodes(item):
    info("contentAction: %s | contentChannel: %s | contentType: %s" % (item.contentAction, item.contentChannel, item.contentType))

    if 'dlseason' in item:
        season = True
        season_number = item.dlseason
    else:
        season = False
    # The item we want to download NOW is an episode
    if item.contentType == "episode":
        episodes = [item.clone()]

    # The item is a series or season
    elif item.contentType in ["tvshow", "season"]:
        if item.downloadItemlist:
            episodes = [Item().fromurl(i) for i in item.downloadItemlist]
        else:
            # The item is a series or season...
            if item.contentChannel in ['community', 'videolibrary']:
                channel = __import__('specials.%s' % item.contentChannel, None, None, ["specials.%s" % item.contentChannel])
            else:
                channel = __import__('channels.%s' % item.contentChannel, None, None, ["channels.%s" % item.contentChannel])
            # We get the list of episodes
            episodes = getattr(channel, item.contentAction)(item)

    itemlist = []
    if episodes and not scrapertools.find_single_match(episodes[0].title, r'(\d+.\d+)') and item.channel not in ['videolibrary'] and item.action != 'season':
        from platformcode.autorenumber import select_type, renumber, check
        # support.dbg()
        if not check(item):
            select_type(item)
            return get_episodes(item)
        else:
            renumber(episodes, item)

    # We get the list of episodes...
    for episode in episodes:
        # If we started from an item that was already an episode, this data is already good, it should not be modified
        if item.contentType != "episode":
            episode.contentAction = episode.action
            episode.contentChannel = episode.channel

        # If the result is a season, it is not worth it, we have to download the episodes of each season
        if episode.contentType == "season":
            itemlist.extend(get_episodes(episode))

        # If the result is an episode is already what we need, we prepare it to add it to the download
        if episode.contentType == "episode":

            # We pass the id to the episode
            if not episode.infoLabels["tmdb_id"]:
                episode.infoLabels["tmdb_id"] = item.infoLabels["tmdb_id"]

            # Episode, Season and Title
            if not episode.contentSeason or not episode.contentEpisodeNumber:
                season_and_episode = scrapertools.get_season_and_episode(episode.title)
                if season_and_episode:
                    episode.contentSeason = season_and_episode.split("x")[0]
                    episode.contentEpisodeNumber = season_and_episode.split("x")[1]

            # Episode, Season and Title...
            if item.infoLabels["tmdb_id"]:
                scraper.find_and_set_infoLabels(episode)

            # Episode, Season and Title
            if not episode.contentTitle:
                episode.contentTitle = re.sub(r"\[[^\]]+\]|\([^\)]+\)|\d*x\d*\s*-", "", episode.title).strip()

            episode.downloadFilename = filetools.validate_path(filetools.join(item.downloadFilename, "%dx%0.2d - %s" % (episode.contentSeason, episode.contentEpisodeNumber, episode.contentTitle.strip())))
            if season:
                if episode.contentSeason == int(season_number):
                    itemlist.append(episode)
            else:
                itemlist.append(episode)


        # Any other result is not worth it, we ignore it
        else:
            info("Omitiendo item no válido:", episode.tostring())

    # Any other result is not worth it, we ignore it...
    itemlist = videolibrarytools.filter_list(itemlist)

    return itemlist


def write_json(item):
    info()

    channel = item.from_channel if item.from_channel else item.channel
    item.action = "menu"
    item.channel = "downloads"
    item.downloadStatus = STATUS_CODES.stoped
    item.downloadProgress = 0
    item.downloadSize = 0
    item.downloadCompleted = 0
    title = re.sub(r'(?:\[[^\]]+\]|%s[^-]+-\s*)' %config.get_localized_string(60356), '', item.title).strip()
    if not item.contentThumbnail:
        item.contentThumbnail = item.thumbnail

    for name in ["text_bold", "text_color", "text_italic", "context", "totalItems", "viewmode", "title", "contentTitle", "thumbnail"]:
        if name in item.__dict__:
            item.__dict__.pop(name)

    if item.contentType == 'episode':
        naming = title + typo(item.infoLabels['IMDBNumber'], '_ []') + typo(channel, '_ []')
    else:
        naming =  item.fulltitle + typo(item.infoLabels['IMDBNumber'], '_ []') + typo(channel, '_ []')
    naming += typo(item.contentLanguage, '_ []') if item.contentLanguage else ''
    naming += typo(item.quality, '_ []') if item.quality else ''

    path = filetools.join(DOWNLOAD_LIST_PATH, naming + ".json")
    if filetools.isfile(path):
        filetools.remove(path)

    item.path = path
    filetools.write(path, item.tojson())
    time.sleep(0.1)


def save_download(item):
    show_disclaimer()
    if item.channel != 'downloads':
        item.from_channel = item.channel
        item.from_action = item.action

    item.channel = "downloads"
    item.action = "save_download_background"
    xbmc.executebuiltin("RunPlugin(plugin://plugin.video.kod/?" + item.tourl() + ")")


def save_download_background(item):
    info()
    # Menu contextual
    if item.from_action and item.from_channel:
        item.channel = item.from_channel
        item.action = item.from_action
        del item.from_action
        del item.from_channel

    item.contentChannel = item.from_channel if item.from_channel else item.channel
    item.contentAction = item.from_action if item.from_action else item.action

    if item.channel == 'videolibrary':
        from specials import videolibrary

        if not item.parent:
            parent = item
        else:
            parent = Item().fromurl(item.parent)
        parent.contentChannel = 'videolibrary'
        if item.downloadItemlist:  # episode
            parent.downloadItemlist = item.downloadItemlist
        elif item.unseen:  # unseen episodes
            parent.downloadItemlist = [i.tourl() for i in videolibrary.get_episodes(parent) if i.action == 'findvideos' and  parent.library_playcounts[scrapertools.get_season_and_episode(i.title)] == 0]

        else:  # tvshow or season
            parent.downloadItemlist = [i.tourl() for i in videolibrary.get_episodes(parent) if i.action == 'findvideos']
        if parent.contentType in ["tvshow", "episode", "season"]:
            if not item.unseen and parent.contentSeason:  # if no season, this is episode view, let's download entire serie
                parent.dlseason = parent.contentSeason  # this is season view, let's download season
            save_download_tvshow(parent)
        elif parent.contentType == "movie":
            save_download_movie(parent)
    else:
        if item.contentType in ["tvshow", "episode", "season"]:
            if ('download' in item and item.channel != 'community') or (item.channel == 'community' and config.get_setting('show_seasons',item.channel) == False):
                heading = config.get_localized_string(70594) # <- Enter the season number
                item.dlseason = platformtools.dialog_numeric(0, heading, '')
                if item.dlseason:
                    save_download_tvshow(item)
            else:
                save_download_tvshow(item)

        elif item.contentType == "movie":
            save_download_movie(item)
        else:
            save_download_video(item)


def save_download_videolibrary(item):
    info()
    show_disclaimer()
    item.contentChannel = 'videolibrary'
    item.channel = "downloads"
    item.action = "save_download_background"
    xbmc.executebuiltin("RunPlugin(plugin://plugin.video.kod/?" + item.tourl() + ")")


def save_download_video(item):
    info("contentAction: %s | contentChannel: %s | contentTitle: %s" % (item.contentAction, item.contentChannel, item.contentTitle))

    set_movie_title(item)

    item.downloadFilename = filetools.validate_path("%s [%s]" % (item.contentTitle.strip(), item.contentChannel))

    write_json(item)

    if not platformtools.dialog_yesno(config.get_localized_string(30101), config.get_localized_string(70189)):
        platformtools.dialog_ok(config.get_localized_string(30101), item.contentTitle + '\n' + config.get_localized_string(30109))
    else:
        start_download(item)


def save_download_movie(item):
    info("contentAction: %s | contentChannel: %s | contentTitle: %s" % ( item.contentAction, item.contentChannel, item.contentTitle))

    progreso = platformtools.dialog_progress_bg(config.get_localized_string(30101), config.get_localized_string(70191))

    set_movie_title(item)

    result = scraper.find_and_set_infoLabels(item)
    if not result:
        progreso.close()
        return save_download_video(item)

    progreso.update(0, config.get_localized_string(60062))

    item.downloadFilename = filetools.validate_path("%s [%s]" % (item.contentTitle.strip(), item.infoLabels['IMDBNumber']))
    item.backupFilename = filetools.validate_path("%s [%s]" % (item.contentTitle.strip(), item.infoLabels['IMDBNumber']))

    write_json(item)

    progreso.close()

    if not platformtools.dialog_yesno(config.get_localized_string(30101), config.get_localized_string(70189)):
        platformtools.dialog_ok(config.get_localized_string(30101), item.contentTitle + '\n' + config.get_localized_string(30109))
    else:
        # from core.support import dbg;dbg()
        play_item = select_server(item)
        if type(play_item) == str and play_item == 'Auto':
            start_download(item)
        else:
            play_item = item.clone(**play_item.__dict__)
            play_item.contentAction = play_item.action
            play_item.infoLabels = item.infoLabels
            start_download(play_item)


def save_download_tvshow(item):
    info("contentAction: %s | contentChannel: %s | contentType: %s | contentSerieName: %s" % (item.contentAction, item.contentChannel, item.contentType, item.contentSerieName))
    progreso = platformtools.dialog_progress_bg(config.get_localized_string(30101), config.get_localized_string(70188))
    try:
        item.show = item.fulltitle
        if item.channel not in ['videolibrary']:
            scraper.find_and_set_infoLabels(item)

        if not item.contentSerieName: item.contentSerieName = item.fulltitle

        if item.strm_path: item.downloadFilename = filetools.validate_path(item.strm_path.split(os.sep)[-2])
        else: item.downloadFilename = filetools.validate_path("%s [%s]" % (item.contentSerieName, item.infoLabels['IMDBNumber']))

        if config.get_setting("lowerize_title", "videolibrary"):
            item.downloadFilename = item.downloadFilename.lower()

        progreso.update(0, config.get_localized_string(70186) + '\n' + config.get_localized_string(70180) % item.contentChannel)

        episodes = get_episodes(item)

        progreso.update(0, config.get_localized_string(70190))

        for x, i in enumerate(episodes):
            progreso.update(old_div(x * 100, len(episodes)), "%dx%0.2d: %s" % (i.contentSeason, i.contentEpisodeNumber, i.contentTitle))
            write_json(i)
    finally:
        progreso.close()

    if not platformtools.dialog_yesno(config.get_localized_string(30101), config.get_localized_string(70189)):
        platformtools.dialog_ok(config.get_localized_string(30101), str(len(episodes)) + config.get_localized_string(30110) + '\n' + item.contentSerieName + '\n' + config.get_localized_string(30109))

    else:
        if len(episodes) == 1:
            play_item = select_server(episodes[0])
            if play_item:  # not pressed cancel
                if type(play_item) == str and play_item == 'Auto':
                    start_download(episodes[0])
                else:
                    play_item = episodes[0].clone(**play_item.__dict__)
                    play_item.contentAction = play_item.action
                    play_item.infoLabels = episodes[0].infoLabels
                    start_download(play_item)
        else:
            for i in episodes:
                i.contentChannel = item.contentChannel
                res = start_download(i)
                if res == STATUS_CODES.canceled:
                    break


def set_movie_title(item):
    if not item.contentTitle:
        item.contentTitle = re.sub(r"\[[^\]]+\]|\([^\)]+\)", "", item.contentTitle).strip()

    if not item.contentTitle:
        item.contentTitle = re.sub(r"\[[^\]]+\]|\([^\)]+\)", "", item.title).strip()


def show_disclaimer():
    line1 = config.get_localized_string(70690)
    line2 = config.get_localized_string(70691)
    line3 = config.get_localized_string(70692)
    platformtools.dialog_ok(config.get_localized_string(20000), line1 + '\n' + line2 + '\n' + line3)
