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

'''
    Descent Add-on
'''

import os, re, imp, json, urlparse
import time, threading, xbmc

from resources.lib.modules import cache
from resources.lib.modules import control
from resources.lib.modules import cleandate
from resources.lib.modules import client
from resources.lib.modules import utils
from resources.lib.modules import database


BASE_URL = 'http://api.trakt.tv'
V2_BASE_URL = 'http://api-v2launch.trakt.tv'
V2_API_KEY = '935d1a0c207c52baea061ee7a63870b2790ecd92fa36c7cc9190d2849f804b27'
CLIENT_SECRET = 'fba887a210dcb36136a8e1aa0879d0b82497c067d67121a48575c31d2e6b668a'
REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob'

databaseName = control.cacheFile
databaseTable = 'trakt'



def getTrakt(url, post = None, cache = True, check = True, timestamp = None, extended = False, direct = False, authentication = None):
    try:
        if not url.startswith(BASE_URL):
            url = urlparse.urljoin(BASE_URL, url)

        if authentication:
            valid = True
            token = authentication['token']
            refresh = authentication['refresh']
        else:
            valid = getTraktCredentialsInfo() is True
            token = control.setting('trakt.token')
            refresh = control.setting('trakt.refresh')

        headers = {'Content-Type': 'application/json', 'trakt-api-key': V2_API_KEY, 'trakt-api-version': '2'}

        if not post is None: post = json.dumps(post)

        if direct or not valid:
            result = client.request(url, post = post, headers = headers)
            return result

        headers['Authorization'] = 'Bearer %s' % token
        result = client.request(url, post = post, headers = headers, output = 'extended', error = True)
        if result and not (result[1] == '401' or result[1] == '405'):
            if check: _cacheCheck()
            if extended: return result[0], result[2]
            else: return result[0]

        try: code = str(result[1])
        except: code = ''

        if code.startswith('5') or (result and isinstance(result, basestring) and '<html' in result) or not result:
            return _error(url = url, post = post, timestamp = timestamp, message = 33676)

        oauth = urlparse.urljoin(BASE_URL, '/oauth/token')
        opost = {'client_id': V2_API_KEY, 'client_secret': CLIENT_SECRET, 'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob', 'grant_type': 'refresh_token', 'refresh_token': refresh}

        result = client.request(oauth, post = json.dumps(opost), headers = headers, error = True)

        try: code = str(result[1])
        except: code = ''

        if code.startswith('5') or not result or (result and isinstance(result, basestring) and '<html' in result):
            return _error(url = url, post = post, timestamp = timestamp, message = 33676)
        elif result and code in ['404']:
            return _error(url = url, post = post, timestamp = timestamp, message = 33786)
        elif result and code in ['401', '405']:
            return _error(url = url, post = post, timestamp = timestamp, message = 33677)

        result = json.loads(result)

        token, refresh = result['access_token'], result['refresh_token']
        control.setSetting('trakt.token', token)
        control.setSetting('trakt.refresh', refresh)

        headers['Authorization'] = 'Bearer %s' % token

        result = client.request(url, post = post, headers = headers, output = 'extended')
        if check: _cacheCheck()

        if extended: return result[0], result[2]
        else: return result[0]
    except:
        import traceback
        traceback.print_exc()

    return None


def getTraktAsJson(url, post = None, authentication = None):
    try:
        res_headers = {}
        r = getTrakt(url = url, post = post, extended = True, authentication = authentication)
        if isinstance(r, tuple) and len(r) == 2:
            res_headers = r[1]
            r = r[0]
        r = utils.json_loads_as_str(r)
        res_headers = dict((k.lower(), v) for k, v in res_headers.iteritems())
        if 'x-sort-by' in res_headers and 'x-sort-how' in res_headers:
            r = sort_list(res_headers['x-sort-by'], res_headers['x-sort-how'], r)
        return r
    except:
        pass


def _error(url, post, timestamp, message):
    _cache(url = url, post = post, timestamp = timestamp)
    if control.setting('trakt.notifications'):
        control.notification(title = 32315, message = message, icon = 'ERROR', sound = True)
    control.hide()
    return None


def _cache(url, post = None, timestamp = None):
    try:
        if post is None:
            return None
        data = database.Database(databaseName, connect = True)
        _cacheCreate(data)
        post = ('"%s"' % post.replace('"', '""').replace("'", "''")) if not post is None else data._null()
        if timestamp is None:
            timestamp = int(time.time())
        data._insert('''
            INSERT INTO %s (time, link, data)
            VALUES (%d, "%s", %s);
            ''' % (databaseTable, timestamp, url, post)
            , commit = True
        )
        data._close()
    except:
        import traceback
        traceback.print_exc()


def _cacheCreate(data):
    try:
        data._create('''
        CREATE TABLE IF NOT EXISTS %s
        (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            time INTEGER,
            link TEXT,
            data TEXT
            );
            ''' % (databaseTable)
        )
    except: pass


def _cacheCheck():
    thread = threading.Thread(target = _cacheProcess)
    thread.start()


def _cacheProcess():
    data = database.Database(databaseName, connect = True)
    data._lock()
    _cacheCreate(data)
    data._unlock()
    try:
        while True:
            data._lock()
            result = data._selectSingle('SELECT id, time, link, data FROM %s ORDER BY time ASC LIMIT 1;' % (databaseTable))
            if not result: raise Exception()
            data._delete('DELETE FROM %s WHERE id IS %d;' % (databaseTable, result[0]), commit = True)
            data._unlock()
            result = getTrakt(url = result[2], post = json.loads(result[3]) if result[3] else None, cache = True, check = False, timestamp = result[1])
    except:
        data._unlock()
    data._close()


def _cacheClear():
    try:
        data = database.Database(databaseName, connect = True)
        data._drop(databaseTable, commit = True)
        data._close()
    except:
        import traceback
        traceback.print_exc()


def authTrakt():
    try:
        if getTraktCredentialsInfo() is True:
            if control.yesnoDialog(control.lang(32511).encode('utf-8'), control.lang(32512).encode('utf-8'), '', 'Trakt'):
                control.setSetting(id='trakt.user', value='')
                control.setSetting(id='trakt.userHidden', value='')
                control.setSetting(id='trakt.token', value='')
                control.setSetting(id='trakt.refresh', value='')
            raise Exception()
        result = getTraktAsJson('/oauth/device/code', {'client_id': V2_API_KEY})
        verification_url = (control.lang(32513) % result['verification_url']).encode('utf-8')
        user_code = (control.lang(32514) % result['user_code']).encode('utf-8')
        expires_in = int(result['expires_in'])
        device_code = result['device_code']
        interval = result['interval']
        progressDialog = control.progressDialog
        progressDialog.create('Trakt', verification_url, user_code)
        for i in range(0, expires_in):
            try:
                if progressDialog.iscanceled(): break
                time.sleep(1)
                if not float(i) % interval == 0: raise Exception()
                r = getTraktAsJson('/oauth/device/token', {'client_id': V2_API_KEY, 'client_secret': CLIENT_SECRET, 'code': device_code})
                if 'access_token' in r: break
            except:
                pass
        try: progressDialog.close()
        except: pass
        token, refresh = r['access_token'], r['refresh_token']
        headers = {'Content-Type': 'application/json', 'trakt-api-key': V2_API_KEY, 'trakt-api-version': 2, 'Authorization': 'Bearer %s' % token}
        result = client.request(urlparse.urljoin(BASE_URL, '/users/me'), headers=headers)
        result = utils.json_loads_as_str(result)
        user = result['username']
        control.setSetting(id='trakt.user', value=user)
        control.setSetting(id='trakt.userHidden', value=user)
        control.setSetting(id='trakt.token', value=token)
        control.setSetting(id='trakt.refresh', value=refresh)
        raise Exception()
    except:
        pass


def getTraktCredentialsInfo():
    user = control.setting('trakt.user').strip()
    token = control.setting('trakt.token')
    refresh = control.setting('trakt.refresh')
    if (user == '' or token == '' or refresh == ''):
        return False
    return True


def getTraktIndicatorsInfo():
    indicators = control.setting('indicators') if getTraktCredentialsInfo() is False else control.setting('indicators.alt')
    indicators = True if indicators == '1' else False
    return indicators


def getTraktAddonMovieInfo():
    try:
        scrobble = control.addon('script.trakt').getSetting('scrobble_movie')
    except:
        scrobble = ''
    try:
        ExcludeHTTP = control.addon('script.trakt').getSetting('ExcludeHTTP')
    except:
        ExcludeHTTP = ''
    try:
        authorization = control.addon('script.trakt').getSetting('authorization')
    except:
        authorization = ''
    if scrobble == 'true' and ExcludeHTTP == 'false' and not authorization == '':
        return True
    else:
        return False


def getTraktAddonEpisodeInfo():
    try:
        scrobble = control.addon('script.trakt').getSetting('scrobble_episode')
    except:
        scrobble = ''
    try:
        ExcludeHTTP = control.addon('script.trakt').getSetting('ExcludeHTTP')
    except:
        ExcludeHTTP = ''
    try:
        authorization = control.addon('script.trakt').getSetting('authorization')
    except:
        authorization = ''
    if scrobble == 'true' and ExcludeHTTP == 'false' and not authorization == '':
        return True
    else:
        return False


def watch(imdb = None, tvdb = None, season = None, episode = None, refresh = True, notification = False):
    if tvdb is None:
        markMovieAsWatched(imdb)
        cachesyncMovies()
    elif not episode is None:
        markEpisodeAsWatched(imdb, tvdb, season, episode)
        cachesyncTV(imdb)
    elif not season is None:
        markSeasonAsWatched(imdb, tvdb, season)
        cachesyncTV(imdb)
    elif not tvdb is None:
        markTVShowAsWatched(imdb, tvdb)
        cachesyncTV(imdb)
    else:
        markMovieAsWatched(imdb)
        cachesyncMovies()
    if refresh:
        control.refresh()
    if notification:
        control.notification(title = 32315, message = 35502, icon = 'INFO', sound = False)


def unwatch(imdb = None, tvdb = None, season = None, episode = None, refresh = True, notification = False):
    if tvdb is None:
        markMovieAsNotWatched(imdb)
        cachesyncMovies()
    elif not episode is None:
        markEpisodeAsNotWatched(imdb, tvdb, season, episode)
        cachesyncTV(imdb)
    elif not season is None:
        markSeasonAsNotWatched(imdb, tvdb, season)
        cachesyncTV(imdb)
    elif not tvdb is None:
        markTVShowAsNotWatched(imdb, tvdb)
        cachesyncTV(imdb)
    else:
        markMovieAsNotWatched(imdb)
        cachesyncMovies()
    if refresh:
        control.refresh()
    if notification:
        control.notification(title = 32315, message = 35503, icon = 'INFO', sound = False)


def rate(imdb = None, tvdb = None, season = None, episode = None):
    return _rating(action = 'rate', imdb = imdb, tvdb = tvdb, season = season, episode = episode)


def unrate(imdb = None, tvdb = None, season = None, episode = None):
    return _rating(action = 'unrate', imdb = imdb, tvdb = tvdb, season = season, episode = episode)


def rateShow(imdb = None, tvdb = None, season = None, episode = None):
    if control.setting('trakt.rating') == 1:
        rate(imdb = imdb, tvdb = tvdb, season = season, episode = episode)


def _rating(action, imdb = None, tvdb = None, season = None, episode = None):
    try:
        addon = 'script.trakt'
        if control.condVisibility('System.HasAddon(%s)' % addon):
            data = {}
            data['action'] = action
            if not tvdb is None:
                data['video_id'] = tvdb
                if not episode is None:
                    data['media_type'] = 'episode'
                    data['dbid'] = 1
                    data['season'] = int(season)
                    data['episode'] = int(episode)
                elif not season is None:
                    data['media_type'] = 'season'
                    data['dbid'] = 5
                    data['season'] = int(season)
                else:
                    data['media_type'] = 'show'
                    data['dbid'] = 2
            else:
                data['video_id'] = imdb
                data['media_type'] = 'movie'
                data['dbid'] = 4
            script = os.path.join(control.addonPath(addon), 'resources', 'lib', 'sqlitequeue.py')
            sqlitequeue = imp.load_source('sqlitequeue', script)
            data = {'action': 'manualRating', 'ratingData': data}
            sqlitequeue.SqliteQueue().append(data)
        else:
            control.notification(title = 32315, message = 33659, icon = 'INFO', sound = False)
    except:
        pass


def manager(name, imdb = None, tvdb = None, season = None, episode = None, refresh = True):
    lists = []
    try:
        if not season is None: season = int(season)
        if not episode is None: episode = int(episode)

        items = [(control.lang(33651).encode('utf-8'), 'watch')]
        items += [(control.lang(33652).encode('utf-8'), 'unwatch')]
        items += [(control.lang(33653).encode('utf-8'), 'rate')]
        items += [(control.lang(33654).encode('utf-8'), 'unrate')]
        items += [(control.lang(33575).encode('utf-8'), '/sync/collection')]
        items += [(control.lang(33576).encode('utf-8'), '/sync/collection/remove')]
        items += [(control.lang(33577).encode('utf-8'), '/sync/watchlist')]
        items += [(control.lang(33578).encode('utf-8'), '/sync/watchlist/remove')]
        items += [(control.lang(33579).encode('utf-8'), '/users/me/lists/%s/items')]

        result = getTraktAsJson('/users/me/lists')
        lists = [(i['name'], i['ids']['slug']) for i in result]
        lists = [lists[i//2] for i in range(len(lists)*2)]

        control.hide()
        select = control.selectDialog([i[0] for i in items], heading = control.addonInfo('name') + ' - ' + control.lang(32515).encode('utf-8'))

        if select == -1:
            return
        if select >= 0:
            if select == 0:
                control.busy()
                watch(imdb = imdb, tvdb = tvdb, season = season, episode = episode, refresh = refresh, notification = False)
                control.hide()
            elif select == 1:
                control.busy()
                unwatch(imdb = imdb, tvdb = tvdb, season = season, episode = episode, refresh = refresh, notification = False)
                control.hide()
            elif select == 2:
                control.busy()
                rate(imdb = imdb, tvdb = tvdb, season = season, episode = episode)
                control.hide()
            elif select == 3:
                control.busy()
                unrate(imdb = imdb, tvdb = tvdb, season = season, episode = episode)
                control.hide()
            else:
                if tvdb is None:
                    post = {"movies": [{"ids": {"imdb": imdb}}]}
                else:
                    if not episode is None:
                        post = {"shows": [{"ids": {"tvdb": tvdb}, "seasons": [{"number": season, "episodes": [{"number": episode}]}]}]}
                        name = name + ' - ' + '%sx%02d' % (season, episode)
                    elif not season is None:
                        post = {"shows": [{"ids": {"tvdb": tvdb}, "seasons": [{"number": season}]}]}
                        name = name + ' - ' + 'Season %s' % season
                    else:
                        post = {"shows": [{"ids": {"tvdb": tvdb}}]}

                if select == 8:
                    slug = listAdd(successNotification = True)
                    if not slug is None: getTrakt(items[select][1] % slug, post = post)[0]
                else:
                    getTrakt(items[select][1], post = post)[0]

                control.hide()
                message = 33583 if (select % 2) != 0 else 33582
                if select >= 9:
                    message = 33583 if (select % 2) == 0 else 33582
                control.notification(title = name, message = message, icon = 'INFO', sound = False)
    except:
        import traceback
        traceback.print_exc()
        control.hide()


def listAdd(successNotification = True):
    t = control.lang(32520).encode('utf-8')
    k = control.keyboard('', t) ; k.doModal()
    new = k.getText() if k.isConfirmed() else None
    if (new is None or new == ''): return
    result = getTrakt('/users/me/lists', post = {"name" : new, "privacy" : "private"})
    try:
        slug = json.loads(result)['ids']['slug']
        if successNotification:
            control.notification(title = 32070, message = 33661, icon = 'INFO', sound = False)
        return slug
    except:
        control.notification(title = 32070, message = 33584, icon = 'iNFO', sound = False)
        return None


def lists(id = None):
    return cache.get(getTraktAsJson, 48, 'https://api.trakt.tv/users/me/lists' + ('' if id is None else ('/' + str(id))))


def list(id):
    return lists(id = id)


def slug(name):
    name = name.strip()
    name = name.lower()
    name = re.sub('[^a-z0-9_]', '-', name)
    name = re.sub('--+', '-', name)
    return name


def verify(authentication = None):
    try:
        if getTraktAsJson('/sync/last_activities', authentication = authentication):
            return True
    except: pass
    return False


def getActivity():
    try:
        i = getTraktAsJson('/sync/last_activities')
        activity = []
        activity.append(i['movies']['collected_at'])
        activity.append(i['episodes']['collected_at'])
        activity.append(i['movies']['watchlisted_at'])
        activity.append(i['shows']['watchlisted_at'])
        activity.append(i['seasons']['watchlisted_at'])
        activity.append(i['episodes']['watchlisted_at'])
        activity.append(i['lists']['updated_at'])
        activity.append(i['lists']['liked_at'])
        activity = [int(cleandate.iso_2_utc(i)) for i in activity]
        activity = sorted(activity, key=int)[-1]
        return activity
    except:
        pass


def getWatchedActivity():
    try:
        i = getTraktAsJson('/sync/last_activities')
        activity = []
        activity.append(i['movies']['watched_at'])
        activity.append(i['episodes']['watched_at'])
        activity = [int(cleandate.iso_2_utc(i)) for i in activity]
        activity = sorted(activity, key=int)[-1]
        return activity
    except:
        pass


def cachesyncMovies(timeout=0):
    indicators = cache.get(syncMovies, timeout)
    return indicators


def timeoutsyncMovies():
    timeout = cache.timeout(syncMovies)
    return timeout


def syncMovies():
    try:
        if getTraktCredentialsInfo() is False: return
        indicators = getTraktAsJson('/users/me/watched/movies')
        indicators = [i['movie']['ids'] for i in indicators]
        indicators = [str(i['imdb']) for i in indicators if 'imdb' in i]
        return indicators
    except:
        pass


def watchedMovies():
    try:
        if getTraktCredentialsInfo() is False:
            return
        return getTraktAsJson('/users/me/watched/movies?extended=full')
    except:
        pass


def watchedMoviesTime(imdb):
    try:
        imdb = str(imdb)
        items = watchedMovies()
        for item in items:
            if str(item['movie']['ids']['imdb']) == imdb:
                return item['last_watched_at']
    except:
        pass


def cachesyncTV(imdb):
    threads = [threading.Thread(target = cachesyncTVShows), threading.Thread(target = cachesyncSeason, args = (imdb,))]
    [i.start() for i in threads]
    [i.join() for i in threads]


def cachesyncTVShows(timeout=0):
    indicators = cache.get(syncTVShows, timeout)
    return indicators


def timeoutsyncTVShows():
    timeout = cache.timeout(syncTVShows)
    return timeout


def syncTVShows():
    try:
        if getTraktCredentialsInfo() is False: return
        indicators = getTraktAsJson('/users/me/watched/shows?extended=full')
        indicators = [(i['show']['ids']['tvdb'], i['show']['aired_episodes'], sum([[(s['number'], e['number']) for e in s['episodes']] for s in i['seasons']], [])) for i in indicators]
        indicators = [(str(i[0]), int(i[1]), i[2]) for i in indicators]
        return indicators
    except:
        pass


def watchedShows():
    try:
        if getTraktCredentialsInfo() is False: return
        return getTraktAsJson('/users/me/watched/shows?extended=full')
    except:
        pass


def watchedShowsTime(tvdb, season, episode):
    try:
        tvdb = str(tvdb)
        season = int(season)
        episode = int(episode)
        items = watchedShows()
        for item in items:
            if str(item['show']['ids']['tvdb']) == tvdb:
                seasons = item['seasons']
                for s in seasons:
                    if s['number'] == season:
                        episodes = s['episodes']
                        for e in episodes:
                            if e['number'] == episode:
                                return e['last_watched_at']
    except:
        pass


def cachesyncSeason(imdb, timeout=0):
    indicators = cache.get(syncSeason, timeout, imdb)
    return indicators


def timeoutsyncSeason(imdb):
    timeout = cache.timeout(syncSeason, imdb)
    return timeout


def syncSeason(imdb):
    try:
        if getTraktCredentialsInfo() is False: return

        if control.setting('tv.specials') == 'true':
            indicators = getTraktAsJson('/shows/%s/progress/watched?specials=true&hidden=true' % imdb)
        else:
            indicators = getTraktAsJson('/shows/%s/progress/watched?specials=false&hidden=false' % imdb)

        indicators = indicators['seasons']
        indicators = [(i['number'], [x['completed'] for x in i['episodes']]) for i in indicators]
        indicators = ['%01d' % int(i[0]) for i in indicators if not False in i[1]]
        return indicators
    except:
        pass


def showCount(imdb, refresh = True, wait = False):
    try:
        if not imdb:
            return None
        result = {'total': 0, 'watched': 0, 'unwatched': 0}
        indicators = seasonCount(imdb = imdb, refresh = refresh, wait = wait)
        for indicator in indicators:
            result['total'] += indicator['total']
            result['watched'] += indicator['watched']
            result['unwatched'] += indicator['unwatched']
        return result
    except:
        return None


def seasonCount(imdb, refresh = True, wait = False):
    try:
        if not imdb:
            return None

        if not imdb.startswith('tt'):
            imdb = 'tt' + imdb
        indicators = cache.cache_existing(_seasonCountRetrieve, imdb)

        if refresh:
            thread = threading.Thread(target = _seasonCountCache, args = (imdb,))
            thread.start()
            if wait:
                thread.join()
                indicators = cache.cache_existing(_seasonCountRetrieve, imdb)
        return indicators
    except:
        return None


def _seasonCountCache(imdb):
    return cache.get(_seasonCountRetrieve, 0, imdb)


def _seasonCountRetrieve(imdb):
    try:
        if getTraktCredentialsInfo() is False:
            return

        if control.setting('tv.specials') == 'true':
            indicators = getTraktAsJson('/shows/%s/progress/watched?specials=true&hidden=false&count_specials=true' % imdb)
        else:
            indicators = getTraktAsJson('/shows/%s/progress/watched?specials=false&hidden=false' % imdb)

        seasons = indicators['seasons']
        return [{'total': season['aired'], 'watched': season['completed'], 'unwatched': season['aired'] - season['completed']} for season in seasons]
    except:
        import traceback
        traceback.print_exc()
        return None


def markMovieAsWatched(imdb):
    if not imdb.startswith('tt'):
        imdb = 'tt' + imdb
    return getTrakt('/sync/history', {"movies": [{"ids": {"imdb": imdb}}]})[0]


def markMovieAsNotWatched(imdb):
    if not imdb.startswith('tt'):
        imdb = 'tt' + imdb
    return getTrakt('/sync/history/remove', {"movies": [{"ids": {"imdb": imdb}}]})[0]


def markTVShowAsWatched(imdb, tvdb):
    if imdb and not imdb.startswith('tt'):
        imdb = 'tt' + imdb
    result = getTrakt('/sync/history', {"shows": [{"ids": {"tvdb": tvdb}}]})[0]
    seasonCount(imdb)
    return result


def markTVShowAsNotWatched(imdb, tvdb):
    if imdb and not imdb.startswith('tt'):
        imdb = 'tt' + imdb
    result = getTrakt('/sync/history/remove', {"shows": [{"ids": {"tvdb": tvdb}}]})[0]
    seasonCount(imdb)
    return result


def markSeasonAsWatched(imdb, tvdb, season):
    if imdb and not imdb.startswith('tt'):
        imdb = 'tt' + imdb
    season = int('%01d' % int(season))
    result = getTrakt('/sync/history', {"shows": [{"seasons": [{"number": season}], "ids": {"tvdb": tvdb}}]})[0]
    seasonCount(imdb)
    return result


def markSeasonAsNotWatched(imdb, tvdb, season):
    if imdb and not imdb.startswith('tt'):
        imdb = 'tt' + imdb
    season = int('%01d' % int(season))
    result = getTrakt('/sync/history/remove', {"shows": [{"seasons": [{"number": season}], "ids": {"tvdb": tvdb}}]})[0]
    seasonCount(imdb)
    return result


def markEpisodeAsWatched(imdb, tvdb, season, episode):
    if imdb and not imdb.startswith('tt'):
        imdb = 'tt' + imdb
    season, episode = int('%01d' % int(season)), int('%01d' % int(episode))
    result = getTrakt('/sync/history', {"shows": [{"seasons": [{"episodes": [{"number": episode}], "number": season}], "ids": {"tvdb": tvdb}}]})[0]
    seasonCount(imdb)
    return result


def markEpisodeAsNotWatched(imdb, tvdb, season, episode):
    if imdb and not imdb.startswith('tt'):
        imdb = 'tt' + imdb
    season, episode = int('%01d' % int(season)), int('%01d' % int(episode))
    result = getTrakt('/sync/history/remove', {"shows": [{"seasons": [{"episodes": [{"number": episode}], "number": season}], "ids": {"tvdb": tvdb}}]})[0]
    seasonCount(imdb)
    return result


def getMovieTranslation(id, lang, full=False):
    url = '/movies/%s/translations/%s' % (id, lang)
    try:
        item = cache.get(getTraktAsJson, 48, url)[0]
        result = item if full else item.get('title')
        return None if result == 'none' else result
    except:
        pass


def getTVShowTranslation(id, lang, season=None, episode=None, full=False):
    if season and episode:
        url = '/shows/%s/seasons/%s/episodes/%s/translations/%s' % (id, season, episode, lang)
    else:
        url = '/shows/%s/translations/%s' % (id, lang)
    try:
        item = cache.get(getTraktAsJson, 48, url)[0]
        result = item if full else item.get('title')
        return None if result == 'none' else result
    except:
        pass


def getMovieSummary(id, full=True):
    try:
        url = '/movies/%s' % id
        if full: url += '?extended=full'
        return cache.get(getTraktAsJson, 48, url)
    except:
        return


def getTVShowSummary(id, full=True):
    try:
        url = '/shows/%s' % id
        if full: url += '?extended=full'
        return cache.get(getTraktAsJson, 48, url)
    except:
        return


def getEpisodeSummary(id, season, episode, full=True):
    try:
        url = '/shows/%s/seasons/%s/episodes/%s' % (id, season, episode)
        if full:
            url += '&extended=full'
        return cache.get(getTraktAsJson, 48, url)
    except:
        import traceback
        traceback.print_exc()


def getSeasons(id, full=True):
    try:
        url = '/shows/%s/seasons' % (id)
        if full:
            url += '&extended=full'
        return cache.get(getTraktAsJson, 48, url)
    except:
        import traceback
        traceback.print_exc()


def sort_list(sort_key, sort_direction, list_data):
    reverse = False if sort_direction == 'asc' else True
    if sort_key == 'rank':
        return sorted(list_data, key=lambda x: x['rank'], reverse=reverse)
    elif sort_key == 'added':
        return sorted(list_data, key=lambda x: x['listed_at'], reverse=reverse)
    elif sort_key == 'title':
        return sorted(list_data, key=lambda x: utils.title_key(x[x['type']].get('title')), reverse=reverse)
    elif sort_key == 'released':
        return sorted(list_data, key=lambda x: _released_key(x[x['type']]), reverse=reverse)
    elif sort_key == 'runtime':
        return sorted(list_data, key=lambda x: x[x['type']].get('runtime', 0), reverse=reverse)
    elif sort_key == 'popularity':
        return sorted(list_data, key=lambda x: x[x['type']].get('votes', 0), reverse=reverse)
    elif sort_key == 'percentage':
        return sorted(list_data, key=lambda x: x[x['type']].get('rating', 0), reverse=reverse)
    elif sort_key == 'votes':
        return sorted(list_data, key=lambda x: x[x['type']].get('votes', 0), reverse=reverse)
    else:
        return list_data


def getMovieAliases(id):
    try: return cache.get(getTraktAsJson, 48, '/movies/%s/aliases' % id)
    except: return []


def getTVShowAliases(id):
    try: return cache.get(getTraktAsJson, 48, '/shows/%s/aliases' % id)
    except: return []


def getPeople(id, content_type, full=True):
    try:
        url = '/%s/%s/people' % (content_type, id)
        if full: url += '?extended=full'
        return cache.get(getTraktAsJson, 48, url)
    except:
        return


def SearchAll(title, year, full=True):
    try:
        return SearchMovie(title, year, full) + SearchTVShow(title, year, full)
    except:
        return


def SearchMovie(title, year, full=True):
    try:
        url = '/search/movie?query=%s' % title
        if year: url += '&year=%s' % year
        if full: url += '&extended=full'
        return getTraktAsJson(url)
    except:
        return


def SearchTVShow(title, year, full=True):
    try:
        url = '/search/show?query=%s' % title
        if year: url += '&year=%s' % year
        if full: url += '&extended=full'
        return getTraktAsJson(url)
    except:
        return


def getGenre(content, type, type_id):
    try:
        r = '/search/%s/%s?type=%s&extended=full' % (type, type_id, content)
        r = cache.get(getTraktAsJson, 48, r)
        r = r[0].get(content, {}).get('genres', [])
        return r
    except:
        return []


def _scrobbleType(type):
    if type == 'show' or type == 'season' or type == 'episode':
        return 'episode'
    else:
        return 'movie'


def scrobbleProgress(type, imdb = None, tvdb = None, season = None, episode = None):
    try:
        type = _scrobbleType(type)
        if not imdb is None: imdb = str(imdb)
        if not tvdb is None: tvdb = int(tvdb)
        if not episode is None: episode = int(episode)
        if not episode is None: episode = int(episode)
        link = '/sync/playback/type'
        items = getTraktAsJson(link)

        if type == 'episode':
            if imdb and items:
                for item in items:
                    if 'show' in item and 'imdb' in item['show']['ids'] and item['show']['ids']['imdb'] == imdb:
                        if item['episode']['season'] == season and item['episode']['number'] == episode:
                            return item['progress']
            if tvdb:
                for item in items:
                    if 'show' in item and 'tvdb' in item['show']['ids'] and item['show']['ids']['tvdb'] == tvdb:
                        if item['episode']['season'] == season and item['episode']['number'] == episode:
                            return item['progress']
        else:
            if imdb and items:
                for item in items:
                    if 'movie' in item and 'imdb' in item['movie']['ids'] and item['movie']['ids']['imdb'] == imdb:
                        return item['progress']
    except:
        import traceback
        traceback.print_exc()
    return 0


def scrobbleUpdate(action, type, imdb = None, tvdb = None, season = None, episode = None, progress = 0):
    try:
        if action:
            type = _scrobbleType(type)
            if not imdb is None: imdb = str(imdb)
            if not tvdb is None: tvdb = int(tvdb)
            if not season is None: season = int(season)
            if not episode is None: episode = int(episode)

            if imdb: link = '/search/imdb/' + str(imdb)
            elif tvdb: link = '/search/tvdb/' + str(tvdb)
            if type == 'episode': link += '?type=show'
            else: link += '?type=movie'
            items = cache.get(getTraktAsJson, 760, link)

            if len(items) > 0:
                item = items[0]
                if type == 'episode':
                    slug = item['show']['ids']['slug']
                    link = '/shows/%s/seasons/%d/episodes/%d' % (slug, season, episode)
                    item = cache.get(getTraktAsJson, 760, link)
                else:
                    item = item['movie']

                if item:
                    link = '/scrobble/' + action
                    data = {
                        type : item,
                        'progress': progress,
                        'app_version': control.addonVersion(addon='plugin.video.descent'),
                    }
                    result = getTrakt(url = link, post = data)
                    return 'progress' in result
    except:
        pass
    return False


def IdLookup(content, type, type_id):
    try:
        r = getTraktAsJson('/search/%s/%s?type=%s' % (type, type_id, content))
        return r[0].get(content, {}).get('ids', [])
    except:
        return {}


def _released_key(item):
    if 'released' in item:
        return item['released']
    elif 'first_aired' in item:
        return item['first_aired']
    else:
        return 0

