353 lines
14 KiB
Python
353 lines
14 KiB
Python
# -*- coding: utf-8 -*-
|
|
# -*- Tools for trakt sync -*-
|
|
# -*- Created for Alfa-addon -*-
|
|
# -*- By the Alfa Develop Group -*
|
|
|
|
import os, xbmc
|
|
from core import httptools, jsontools
|
|
from core.item import Item
|
|
from platformcode import config, logger
|
|
from threading import Thread
|
|
import sys
|
|
if sys.version_info[0] >= 3: from concurrent import futures
|
|
else: from concurrent_py2 import futures
|
|
|
|
host = 'https://api.trakt.tv'
|
|
client_id = '502bd1660b833c1ae69828163c0848e84e9850061e5529f30930e7356cae73b1'
|
|
client_secret = '1d30d5b24acf223a5e1ab6c61d08b69992d98ed5b0c7e26b052b5e6a592035a4'
|
|
token_auth = config.getSetting("token_trakt", "trakt")
|
|
|
|
|
|
def auth_trakt():
|
|
item = Item()
|
|
folder = (config.getXBMCPlatform() == 'plex')
|
|
item.folder = folder
|
|
# Autentificación de cuenta Trakt
|
|
headers = {'Content-Type': 'application/json', 'trakt-api-key': client_id, 'trakt-api-version': '2'}
|
|
try:
|
|
post = {'client_id': client_id}
|
|
post = jsontools.dump(post)
|
|
# Se solicita url y código de verificación para conceder permiso a la app
|
|
url = host + '/oauth/device/code'
|
|
data = httptools.downloadpage(url, post=post, headers=headers).json
|
|
item.verify_url = data['verification_url']
|
|
item.user_code = data['user_code']
|
|
item.device_code = data['device_code']
|
|
item.intervalo = data['interval']
|
|
if not item.folder:
|
|
token_trakt(item)
|
|
|
|
else:
|
|
itemlist = []
|
|
title = config.getLocalizedString(60248) % item.verify_url
|
|
itemlist.append(item.clone(title=title, action=''))
|
|
title = config.getLocalizedString(60249) % item.user_code
|
|
itemlist.append(item.clone(title=title, action=''))
|
|
title = config.getLocalizedString(60250)
|
|
itemlist.append(item.clone(title=title, action='token_trakt'))
|
|
return itemlist
|
|
except:
|
|
import traceback
|
|
logger.error(traceback.format_exc())
|
|
|
|
|
|
def token_trakt(item):
|
|
from platformcode import platformtools
|
|
|
|
headers = {'Content-Type': 'application/json', 'trakt-api-key': client_id, 'trakt-api-version': '2'}
|
|
try:
|
|
if item.extra == 'renew':
|
|
refresh = config.getSetting('refresh_token_trakt', 'trakt')
|
|
url = host + '/oauth/device/token'
|
|
post = {'refresh_token': refresh, 'client_id': client_id, 'client_secret': client_secret,
|
|
'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob', 'grant_type': 'refresh_token'}
|
|
post = jsontools.dump(post)
|
|
data = httptools.downloadpage(url, post=post, headers=headers).data
|
|
data = jsontools.load(data)
|
|
elif item.action == 'token_trakt':
|
|
url = host + '/oauth/device/token'
|
|
post = 'code={}&client_id={}&client_secret={}'.format(item.device_code, client_id, client_secret)
|
|
data = httptools.downloadpage(url, post=post, headers=headers).data
|
|
data = jsontools.load(data)
|
|
else:
|
|
import time
|
|
dialog_auth = platformtools.dialogProgress(config.getLocalizedString(60251),
|
|
config.getLocalizedString(60252) % item.verify_url + '\n' +
|
|
config.getLocalizedString(60253) % item.user_code + '\n' +
|
|
config.getLocalizedString(60254))
|
|
|
|
# Generalmente cada 5 segundos se intenta comprobar si el usuario ha introducido el código
|
|
while True:
|
|
time.sleep(item.intervalo)
|
|
try:
|
|
if dialog_auth.iscanceled():
|
|
config.setSetting('trakt_sync', False)
|
|
return
|
|
|
|
url = host + '/oauth/device/token'
|
|
post = {'code': item.device_code, 'client_id': client_id, 'client_secret': client_secret}
|
|
post = jsontools.dump(post)
|
|
data = httptools.downloadpage(url, post=post, headers=headers).data
|
|
data = jsontools.load(data)
|
|
if 'access_token' in data:
|
|
# Código introducido, salimos del bucle
|
|
break
|
|
except:
|
|
pass
|
|
|
|
try:
|
|
dialog_auth.close()
|
|
except:
|
|
pass
|
|
|
|
token = data['access_token']
|
|
refresh = data['refresh_token']
|
|
|
|
config.setSetting('token_trakt', token, 'trakt')
|
|
config.setSetting('refresh_token_trakt', refresh, 'trakt')
|
|
if not item.folder:
|
|
platformtools.dialogNotification(config.getLocalizedString(60255), config.getLocalizedString(60256))
|
|
if config.is_xbmc():
|
|
import xbmc
|
|
xbmc.executebuiltin('Container.Refresh')
|
|
return
|
|
|
|
except:
|
|
import traceback
|
|
logger.error(traceback.format_exc())
|
|
if not item.folder:
|
|
return platformtools.dialogNotification(config.getLocalizedString(60527), config.getLocalizedString(60258))
|
|
token = ''
|
|
|
|
itemlist = []
|
|
if token:
|
|
itemlist.append(item.clone(title=config.getLocalizedString(60256), action=''))
|
|
else:
|
|
itemlist.append(item.clone(title=config.getLocalizedString(60260), action=''))
|
|
|
|
return itemlist
|
|
|
|
|
|
def set_trakt_info(item):
|
|
logger.debug()
|
|
import xbmcgui
|
|
# Envia los datos a trakt
|
|
try:
|
|
info = item.infoLabels
|
|
ids = jsontools.dump({'tmdb': info['tmdb_id'] , 'imdb': info['imdb_id'], 'slug': info['title']})
|
|
xbmcgui.Window(10000).setProperty('script.trakt.ids', ids)
|
|
except:
|
|
pass
|
|
|
|
|
|
def get_trakt_watched(id_type, mediatype, update=False):
|
|
logger.debug()
|
|
|
|
id_list = []
|
|
id_dict = dict()
|
|
|
|
token_auth = config.getSetting('token_trakt', 'trakt')
|
|
|
|
if token_auth:
|
|
sync_path = os.path.join(config.getDataPath(), 'settings_channels', 'trakt')
|
|
|
|
if os.path.exists(sync_path) and not update:
|
|
trakt_node = jsontools.getNodeFromFile('trakt', 'TRAKT')
|
|
if mediatype == 'shows':
|
|
return trakt_node['shows']
|
|
if mediatype == 'movies':
|
|
return trakt_node['movies']
|
|
|
|
else:
|
|
token_auth = config.getSetting('token_trakt', 'trakt')
|
|
if token_auth:
|
|
try:
|
|
token_auth = config.getSetting('token_trakt', 'trakt')
|
|
headers = [['Content-Type', 'application/json'], ['trakt-api-key', client_id],
|
|
['trakt-api-version', '2']]
|
|
if token_auth:
|
|
headers.append(['Authorization', 'Bearer ' + token_auth])
|
|
url = host + '/sync/watched/' + mediatype
|
|
data = httptools.downloadpage(url, headers=headers).data
|
|
watched_dict = jsontools.load(data)
|
|
|
|
if mediatype == 'shows':
|
|
|
|
dict_show = dict()
|
|
for item in watched_dict:
|
|
temp = []
|
|
id_ = str(item['show']['ids']['tmdb'])
|
|
season_dict = dict()
|
|
for season in item['seasons']:
|
|
ep = []
|
|
number = str(season['number'])
|
|
# season_dict = dict()
|
|
for episode in season['episodes']:
|
|
ep.append(str(episode['number']))
|
|
season_dict[number] = ep
|
|
temp.append(season_dict)
|
|
dict_show[id_] = season_dict
|
|
id_dict = dict_show
|
|
return id_dict
|
|
|
|
elif mediatype == 'movies':
|
|
for item in watched_dict:
|
|
id_list.append(str(item['movie']['ids'][id_type]))
|
|
except:
|
|
pass
|
|
|
|
return id_list
|
|
|
|
|
|
def trakt_check(itemlist):
|
|
if type(itemlist) != list:
|
|
return
|
|
def sync(item, id_result):
|
|
info = item.infoLabels
|
|
try:
|
|
if info['mediatype'] == 'movie' and info['tmdb_id'] in id_result[info['mediatype']]:
|
|
item.infoLabels['playcount'] = 1
|
|
elif info['mediatype'] == 'episode' and info['tmdb_id'] in id_result[info['mediatype']]:
|
|
id = info['tmdb_id']
|
|
if info['season'] and info['episode'] and \
|
|
str(info['season']) in id_result[info['mediatype']][id] and \
|
|
str(info['episode']) in id_result[info['mediatype']][id][str(info['season'])]:
|
|
item.infoLabels['playcount'] = 1
|
|
except:
|
|
pass
|
|
|
|
if itemlist and itemlist[0].channel != 'videolibrary' \
|
|
and 'mediatype' in itemlist[0].infoLabels \
|
|
and itemlist[0].infoLabels['mediatype'] in ['movie', 'episode']:
|
|
|
|
id_result = {}
|
|
id_result['movie'] = get_trakt_watched('tmdb', 'movies', True)
|
|
id_result['episode'] = get_trakt_watched('tmdb', 'shows', True)
|
|
|
|
with futures.ThreadPoolExecutor() as executor:
|
|
[executor.submit(sync, it, id_result) for it in itemlist]
|
|
|
|
return itemlist
|
|
|
|
|
|
def get_sync_from_file():
|
|
logger.debug()
|
|
sync_path = os.path.join(config.getDataPath(), 'settings_channels', 'trakt_data.json')
|
|
trakt_node = {}
|
|
if os.path.exists(sync_path):
|
|
trakt_node = jsontools.getNodeFromFile('trakt', 'TRAKT')
|
|
|
|
trakt_node['movies'] = get_trakt_watched('tmdb', 'movies')
|
|
trakt_node['shows'] = get_trakt_watched('tmdb', 'shows')
|
|
jsontools.updateNode(trakt_node, 'trakt', 'TRAKT')
|
|
|
|
|
|
def update_trakt_data(mediatype, trakt_data):
|
|
logger.debug()
|
|
|
|
sync_path = os.path.join(config.getDataPath(), 'settings_channels', 'trakt_data.json')
|
|
if os.path.exists(sync_path):
|
|
trakt_node = jsontools.getNodeFromFile('trakt', 'TRAKT')
|
|
trakt_node[mediatype] = trakt_data
|
|
jsontools.updateNode(trakt_node, 'trakt', 'TRAKT')
|
|
|
|
|
|
def ask_install_script():
|
|
logger.debug()
|
|
|
|
from platformcode import platformtools
|
|
|
|
respuesta = platformtools.dialogYesNo(config.getLocalizedString(20000), config.getLocalizedString(70521))
|
|
if respuesta:
|
|
xbmc.executebuiltin('InstallAddon(script.trakt)')
|
|
return
|
|
else:
|
|
config.setSetting('install_trakt', False)
|
|
return
|
|
|
|
|
|
def wait_for_update_trakt():
|
|
logger.debug()
|
|
t = Thread(target=update_all)
|
|
t.setDaemon(True)
|
|
t.start()
|
|
t.is_alive()
|
|
|
|
|
|
def update_all():
|
|
from time import sleep
|
|
logger.debug()
|
|
sleep(20)
|
|
while xbmc.Player().isPlaying():
|
|
sleep(20)
|
|
for mediatype in ['movies', 'shows']:
|
|
trakt_data = get_trakt_watched('tmdb', mediatype, True)
|
|
update_trakt_data(mediatype, trakt_data)
|
|
|
|
|
|
def context(item):
|
|
Type = item.contentType.replace("tv", "") + "s"
|
|
item.action = 'traktResults'
|
|
title = config.getLocalizedString(30122 if item.contentType == 'movie' else 30123)
|
|
context = []
|
|
commands = []
|
|
condition = "'tmdb': " + item.infoLabels["tmdb_id"]
|
|
try:
|
|
result = execute(item.clone(url="/sync/watched/" + Type))
|
|
post = {Type: [{"ids": {"tmdb": item.infoLabels["tmdb_id"]}}]}
|
|
if condition in str(result):
|
|
context.append(config.getLocalizedString(60016 if item.contentType == 'movie' else 60020))
|
|
commands.append(item.clone(url="/sync/history/remove", post=post))
|
|
else:
|
|
context.append(config.getLocalizedString(60017 if item.contentType == 'movie' else 60021))
|
|
commands.append(item.clone(url="/sync/history", post=post))
|
|
except:
|
|
pass
|
|
|
|
try:
|
|
result = execute(item.clone(url="/sync/watchlist/" + Type))
|
|
post = {Type: [{"ids": {"tmdb": item.infoLabels["tmdb_id"]}}]}
|
|
if condition in str(result):
|
|
context.append(config.getLocalizedString(70343) % title)
|
|
commands.append(item.clone(url="/sync/watchlist/remove", post=post))
|
|
else:
|
|
context.append(config.getLocalizedString(70344) % title)
|
|
commands.append(item.clone(url="/sync/watchlist", post=post))
|
|
except:
|
|
pass
|
|
|
|
try:
|
|
result = execute(item.clone(url="/sync/collection/" + Type))
|
|
post = {Type: [{"ids": {"tmdb": item.infoLabels["tmdb_id"]}}]}
|
|
if condition in str(result):
|
|
context.append(config.getLocalizedString(70345) % title)
|
|
commands.append(item.clone(url="/sync/collection/remove", post=post))
|
|
else:
|
|
context.append(config.getLocalizedString(70346) % title)
|
|
commands.append(item.clone(url="/sync/collection", post=post))
|
|
except:
|
|
pass
|
|
|
|
if context:
|
|
import xbmcgui
|
|
index = xbmcgui.Dialog().contextmenu(context)
|
|
if index > -1:
|
|
execute(commands[index])
|
|
|
|
def execute(item):
|
|
from platformcode.platformtools import dialogNotification
|
|
url = host + item.url
|
|
|
|
headers = [['Content-Type', 'application/json'], ['trakt-api-key', client_id], ['trakt-api-version', '2']]
|
|
if token_auth: headers.append(['Authorization', 'Bearer {}'.format(token_auth)])
|
|
|
|
post = None
|
|
if item.post: post = jsontools.dump(item.post)
|
|
|
|
data = httptools.downloadpage(url, post=post, headers=headers).json
|
|
|
|
if not post:
|
|
return data
|
|
else:
|
|
if 'not_found' in data: return dialogNotification('Trakt', config.getLocalizedString(70347))
|
|
else: return dialogNotification('Trakt', config.getLocalizedString(70348)) |