Files
addon/specials/autoplay.py

754 lines
30 KiB
Python

# -*- coding: utf-8 -*-
#from builtins import str
import sys
PY3 = False
if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int
from builtins import range
import os
from core import channeltools
from core import jsontools
from core.item import Item
from platformcode import config, logger
from platformcode import platformtools
from platformcode import launcher
from time import sleep
from platformcode.config import get_setting
__channel__ = "autoplay"
PLAYED = False
autoplay_node = {}
colorKOD = '0xFF65B3DA'
def context():
'''
Agrega la opcion Configurar AutoPlay al menu contextual
:return:
'''
_context = ""
if config.is_xbmc():
_context = [{"title": config.get_localized_string(60071),
"action": "autoplay_config",
"channel": "autoplay"}]
return _context
context = context()
def show_option(channel, itemlist, text_color=colorKOD, thumbnail=None, fanart=None):
'''
Agrega la opcion Configurar AutoPlay en la lista recibida
:param channel: str
:param itemlist: list (lista donde se desea integrar la opcion de configurar AutoPlay)
:param text_color: str (color para el texto de la opcion Configurar Autoplay)
:param thumbnail: str (direccion donde se encuentra el thumbnail para la opcion Configurar Autoplay)
:return:
'''
from channelselector import get_thumb
logger.info()
if not config.is_xbmc():
return itemlist
if thumbnail == None:
thumbnail = get_thumb('autoplay.png')
# if fanart == None:
# fanart = get_thumb('autoplay.png')
plot_autoplay = config.get_localized_string(60399)
itemlist.append(
Item(channel=__channel__,
title=config.get_localized_string(60071),
action="autoplay_config",
text_color=text_color,
text_bold=True,
thumbnail=thumbnail,
# fanart=fanart,
plot=plot_autoplay,
from_channel=channel,
folder=False
))
return itemlist
def start(itemlist, item):
'''
Metodo principal desde donde se reproduce automaticamente los enlaces
- En caso la opcion de personalizar activa utilizara las opciones definidas por el usuario.
- En caso contrario intentara reproducir cualquier enlace que cuente con el idioma preferido.
:param itemlist: list (lista de items listos para reproducir, o sea con action='play')
:param item: item (el item principal del canal)
:return: intenta autoreproducir, en caso de fallar devuelve el itemlist que recibio en un principio
'''
logger.info()
global PLAYED
global autoplay_node
PLAYED = False
base_item = item
if not config.is_xbmc():
#platformtools.dialog_notification('AutoPlay ERROR', 'Sólo disponible para XBMC/Kodi')
return itemlist
if not autoplay_node:
# Obtiene el nodo AUTOPLAY desde el json
autoplay_node = jsontools.get_node_from_file('autoplay', 'AUTOPLAY')
channel_id = item.channel
if item.channel == 'videolibrary':
autoplay_node = jsontools.get_node_from_file('autoplay', 'AUTOPLAY')
channel_id = item.contentChannel
try:
active = autoplay_node['status']
except:
active = is_active(item.channel)
if not channel_id in autoplay_node or not active:
return itemlist
# Agrega servidores y calidades que no estaban listados a autoplay_node
new_options = check_value(channel_id, itemlist)
# Obtiene el nodo del canal desde autoplay_node
channel_node = autoplay_node.get(channel_id, {})
# Obtiene los ajustes des autoplay para este canal
settings_node = channel_node.get('settings', {})
if get_setting('autoplay') or settings_node['active']:
url_list_valid = []
autoplay_list = []
autoplay_b = []
favorite_langs = []
favorite_servers = []
favorite_quality = []
#2nd lang, vemos si se quiere o no filtrar
status_language = config.get_setting("filter_languages", channel_id)
# Guarda el valor actual de "Accion y Player Mode" en preferencias
user_config_setting_action = config.get_setting("default_action")
user_config_setting_player = config.get_setting("player_mode")
# Habilita la accion "Ver en calidad alta" (si el servidor devuelve más de una calidad p.e. gdrive)
if user_config_setting_action != 2:
config.set_setting("default_action", 2)
if user_config_setting_player != 0:
config.set_setting("player_mode", 0)
# Informa que AutoPlay esta activo
#platformtools.dialog_notification('AutoPlay Activo', '', sound=False)
# Prioridades a la hora de ordenar itemlist:
# 0: Servidores y calidades
# 1: Calidades y servidores
# 2: Solo servidores
# 3: Solo calidades
# 4: No ordenar
if (settings_node['custom_servers'] and settings_node['custom_quality']) or get_setting('autoplay'):
priority = settings_node['priority'] # 0: Servidores y calidades o 1: Calidades y servidores
elif settings_node['custom_servers']:
priority = 2 # Solo servidores
elif settings_node['custom_quality']:
priority = 3 # Solo calidades
else:
priority = 4 # No ordenar
# Obtiene las listas servidores, calidades disponibles desde el nodo del json de AutoPlay
server_list = channel_node.get('servers', [])
for server in server_list:
server = server.lower()
quality_list = channel_node.get('quality', [])
# Si no se definen calidades la se asigna default como calidad unica
if len(quality_list) == 0:
quality_list =['default']
# Se guardan los textos de cada servidor y calidad en listas p.e. favorite_servers = ['verystream', 'openload',
# 'streamcloud']
for num in range(1, 4):
favorite_servers.append(channel_node['servers'][settings_node['server_%s' % num]].lower())
favorite_quality.append(channel_node['quality'][settings_node['quality_%s' % num]])
# Se filtran los enlaces de itemlist y que se correspondan con los valores de autoplay
for n, item in enumerate(itemlist):
autoplay_elem = dict()
b_dict = dict()
# Comprobamos q se trata de un item de video
if 'server' not in item:
continue
#2nd lang lista idiomas
if item.language not in favorite_langs:
favorite_langs.append(item.language)
# Agrega la opcion configurar AutoPlay al menu contextual
if 'context' not in item:
item.context = list()
if not [x for x in context if x['action'] == 'autoplay_config']:
item.context.append({"title": config.get_localized_string(60071),
"action": "autoplay_config",
"channel": "autoplay",
"from_channel": channel_id})
# Si no tiene calidad definida le asigna calidad 'default'
if item.quality == '':
item.quality = 'default'
# Se crea la lista para configuracion personalizada
if priority < 2: # 0: Servidores y calidades o 1: Calidades y servidores
# si el servidor y la calidad no se encuentran en las listas de favoritos o la url esta repetida,
# descartamos el item
if item.server.lower() not in favorite_servers or item.quality not in favorite_quality \
or item.url in url_list_valid:
item.type_b = True
b_dict['videoitem']= item
autoplay_b.append(b_dict)
continue
autoplay_elem["indice_lang"] = favorite_langs.index(item.language)
autoplay_elem["indice_server"] = favorite_servers.index(item.server.lower())
autoplay_elem["indice_quality"] = favorite_quality.index(item.quality)
elif priority == 2: # Solo servidores
# si el servidor no se encuentra en la lista de favoritos o la url esta repetida,
# descartamos el item
if item.server.lower() not in favorite_servers or item.url in url_list_valid:
item.type_b = True
b_dict['videoitem'] = item
autoplay_b.append(b_dict)
continue
autoplay_elem["indice_lang"] = favorite_langs.index(item.language)
autoplay_elem["indice_server"] = favorite_servers.index(item.server.lower())
elif priority == 3: # Solo calidades
# si la calidad no se encuentra en la lista de favoritos o la url esta repetida,
# descartamos el item
if item.quality not in favorite_quality or item.url in url_list_valid:
item.type_b = True
b_dict['videoitem'] = item
autoplay_b.append(b_dict)
continue
autoplay_elem["indice_lang"] = favorite_langs.index(item.language)
autoplay_elem["indice_quality"] = favorite_quality.index(item.quality)
else: # No ordenar
# si la url esta repetida, descartamos el item
if item.url in url_list_valid:
continue
# Si el item llega hasta aqui lo añadimos al listado de urls validas y a autoplay_list
url_list_valid.append(item.url)
item.plan_b=True
autoplay_elem['videoitem'] = item
# autoplay_elem['server'] = item.server
# autoplay_elem['quality'] = item.quality
autoplay_list.append(autoplay_elem)
# Ordenamos segun la prioridad
if priority == 0: # Servidores y calidades
autoplay_list.sort(key=lambda orden: (orden['indice_lang'], orden['indice_server'], orden['indice_quality']))
elif priority == 1: # Calidades y servidores
autoplay_list.sort(key=lambda orden: (orden['indice_lang'], orden['indice_quality'], orden['indice_server']))
elif priority == 2: # Solo servidores
autoplay_list.sort(key=lambda orden: (orden['indice_lang'], orden['indice_server']))
elif priority == 3: # Solo calidades
autoplay_list.sort(key=lambda orden: (orden['indice_lang'], orden['indice_quality']))
# Se prepara el plan b, en caso de estar activo se agregan los elementos no favoritos al final
try:
plan_b = settings_node['plan_b']
except:
plan_b = True
text_b = ''
if plan_b:
autoplay_list.extend(autoplay_b)
# Si hay elementos en la lista de autoplay se intenta reproducir cada elemento, hasta encontrar uno
# funcional o fallen todos
if autoplay_list or (plan_b and autoplay_b):
#played = False
max_intentos = 5
max_intentos_servers = {}
# Si se esta reproduciendo algo detiene la reproduccion
if platformtools.is_playing():
platformtools.stop_video()
for autoplay_elem in autoplay_list:
play_item = Item
# Si no es un elemento favorito si agrega el texto plan b
if autoplay_elem['videoitem'].type_b:
text_b = '(Plan B)'
if not platformtools.is_playing() and not PLAYED:
videoitem = autoplay_elem['videoitem']
if videoitem.server.lower() not in max_intentos_servers:
max_intentos_servers[videoitem.server.lower()] = max_intentos
# Si se han alcanzado el numero maximo de intentos de este servidor saltamos al siguiente
if max_intentos_servers[videoitem.server.lower()] == 0:
continue
lang = " "
if hasattr(videoitem, 'language') and videoitem.language != "":
lang = " '%s' " % videoitem.language
platformtools.dialog_notification("AutoPlay %s" %text_b, "%s%s%s" % (
videoitem.server.upper(), lang, videoitem.quality.upper()), sound=False)
# TODO videoitem.server es el id del server, pero podria no ser el nombre!!!
# Intenta reproducir los enlaces
# Si el canal tiene metodo play propio lo utiliza
try:
channel = __import__('channels.%s' % channel_id, None, None, ["channels.%s" % channel_id])
except:
channel = __import__('specials.%s' % channel_id, None, None, ["specials.%s" % channel_id])
if hasattr(channel, 'play'):
resolved_item = getattr(channel, 'play')(videoitem)
if len(resolved_item) > 0:
if isinstance(resolved_item[0], list):
videoitem.video_urls = resolved_item
else:
videoitem = resolved_item[0]
# Si no directamente reproduce y marca como visto
# Verifica si el item viene de la videoteca
try:
if base_item.contentChannel =='videolibrary':
# Marca como visto
from platformcode import xbmc_videolibrary
xbmc_videolibrary.mark_auto_as_watched(base_item)
# Rellena el video con los datos del item principal y reproduce
play_item = base_item.clone(url=videoitem)
platformtools.play_video(play_item.url, autoplay=True)
else:
# Si no viene de la videoteca solo reproduce
platformtools.play_video(videoitem, autoplay=True)
except:
pass
sleep(3)
try:
if platformtools.is_playing():
PLAYED = True
break
except:
logger.debug(str(len(autoplay_list)))
# Si hemos llegado hasta aqui es por q no se ha podido reproducir
max_intentos_servers[videoitem.server.lower()] -= 1
# Si se han alcanzado el numero maximo de intentos de este servidor
# preguntar si queremos seguir probando o lo ignoramos
if max_intentos_servers[videoitem.server.lower()] == 0:
text = config.get_localized_string(60072) % videoitem.server.upper()
if not platformtools.dialog_yesno("AutoPlay", text,
config.get_localized_string(60073)):
max_intentos_servers[videoitem.server.lower()] = max_intentos
# Si no quedan elementos en la lista se informa
if autoplay_elem == autoplay_list[-1]:
platformtools.dialog_notification('AutoPlay', config.get_localized_string(60072) % videoitem.server.upper())
else:
platformtools.dialog_notification(config.get_localized_string(60074), config.get_localized_string(60075))
if new_options:
platformtools.dialog_notification("AutoPlay", config.get_localized_string(60076), sound=False)
# Restaura si es necesario el valor previo de "Accion y Player Mode" en preferencias
if user_config_setting_action != 2:
config.set_setting("default_action", user_config_setting_action)
if user_config_setting_player != 0:
config.set_setting("player_mode", user_config_setting_player)
return itemlist
def init(channel, list_servers, list_quality, reset=False):
'''
Comprueba la existencia de canal en el archivo de configuracion de Autoplay y si no existe lo añade.
Es necesario llamar a esta funcion al entrar a cualquier canal que incluya la funcion Autoplay.
:param channel: (str) id del canal
:param list_servers: (list) lista inicial de servidores validos para el canal. No es necesario incluirlos todos,
ya que la lista de servidores validos se ira actualizando dinamicamente.
:param list_quality: (list) lista inicial de calidades validas para el canal. No es necesario incluirlas todas,
ya que la lista de calidades validas se ira actualizando dinamicamente.
:return: (bool) True si la inicializacion ha sido correcta.
'''
logger.info()
change = False
result = True
if not config.is_xbmc():
# platformtools.dialog_notification('AutoPlay ERROR', 'Sólo disponible para XBMC/Kodi')
result = False
else:
autoplay_path = os.path.join(config.get_data_path(), "settings_channels", 'autoplay_data.json')
if os.path.exists(autoplay_path):
autoplay_node = jsontools.get_node_from_file('autoplay', "AUTOPLAY")
else:
change = True
autoplay_node = {"AUTOPLAY": {}}
if channel not in autoplay_node or reset:
change = True
# Se comprueba que no haya calidades ni servidores duplicados
if 'default' not in list_quality:
list_quality.append('default')
# list_servers = list(set(list_servers))
# list_quality = list(set(list_quality))
# Creamos el nodo del canal y lo añadimos
channel_node = {"servers": list_servers,
"quality": list_quality,
"settings": {
"active": False,
"hide_servers": False,
"plan_b": True,
"custom_servers": False,
"custom_quality": False,
"priority": 0}}
for n in range(1, 4):
s = c = 0
if len(list_servers) >= n:
s = n - 1
if len(list_quality) >= n:
c = n - 1
channel_node["settings"]["server_%s" % n] = s
channel_node["settings"]["quality_%s" % n] = c
autoplay_node[channel] = channel_node
if change:
result, json_data = jsontools.update_node(autoplay_node, 'autoplay', 'AUTOPLAY')
if not result:
heading = config.get_localized_string(60077)
msj = config.get_localized_string(60078)
platformtools.dialog_notification(heading, msj, sound=False)
return result
def check_value(channel, itemlist):
''' comprueba la existencia de un valor en la lista de servidores o calidades
si no existiera los agrega a la lista en el json
:param channel: str
:param values: list (una de servidores o calidades)
:param value_type: str (server o quality)
:return: list
'''
logger.info()
global autoplay_node
change = False
if not autoplay_node:
# Obtiene el nodo AUTOPLAY desde el json
autoplay_node = jsontools.get_node_from_file('autoplay', 'AUTOPLAY')
channel_node = autoplay_node.get(channel)
server_list = channel_node.get('servers')
if not server_list:
server_list = channel_node['servers'] = list()
quality_list = channel_node.get('quality')
if not quality_list:
quality_list = channel_node['quality'] = list()
for item in itemlist:
if item.server.lower() not in server_list and item.server !='':
server_list.append(item.server.lower())
change = True
if item.quality not in quality_list and item.quality !='':
quality_list.append(item.quality)
change = True
if change:
change, json_data = jsontools.update_node(autoplay_node, 'autoplay', 'AUTOPLAY')
return change
def autoplay_config(item):
logger.info()
global autoplay_node
dict_values = {}
list_controls = []
channel_parameters = channeltools.get_channel_parameters(item.from_channel)
channel_name = channel_parameters['title']
if not autoplay_node:
# Obtiene el nodo AUTOPLAY desde el json
autoplay_node = jsontools.get_node_from_file('autoplay', 'AUTOPLAY')
channel_node = autoplay_node.get(item.from_channel, {})
settings_node = channel_node.get('settings', {})
allow_option = True
active_settings = {"id": "active", "label": config.get_localized_string(60079),
"type": "bool", "default": False, "enabled": allow_option,
"visible": allow_option}
list_controls.append(active_settings)
dict_values['active'] = settings_node.get('active', False)
hide_servers = {"id": "hide_servers", "label": config.get_localized_string(70747),
"type": "bool", "default": False, "enabled": "eq(-" + str(len(list_controls)) + ",true)",
"visible": allow_option}
list_controls.append(hide_servers)
dict_values['hide_servers'] = settings_node.get('hide_servers', False)
# Idioma
status_language = config.get_setting("filter_languages", item.from_channel)
if not status_language:
status_language = 0
set_language = {"id": "language", "label": config.get_localized_string(60080),
"type": "list", "default": 0, "enabled": "eq(-" + str(len(list_controls)) + ",true)", "visible": True,
"lvalues": get_languages(item.from_channel)}
list_controls.append(set_language)
dict_values['language'] = status_language
separador = {"id": "label", "label": " "
"_________________________________________________________________________________________",
"type": "label", "enabled": True, "visible": True}
list_controls.append(separador)
# Seccion servidores favoritos
server_list = channel_node.get("servers", [])
if not server_list:
enabled = False
server_list = ["No disponible"]
else:
enabled = "eq(-" + str(len(list_controls)) + ",true)"
custom_servers_settings = {"id": "custom_servers", "label": config.get_localized_string(60081),
"type": "bool", "default": False, "enabled": enabled, "visible": True}
custom_servers_pos = len(list_controls)
list_controls.append(custom_servers_settings)
if dict_values['active'] and enabled:
dict_values['custom_servers'] = settings_node.get('custom_servers', False)
else:
dict_values['custom_servers'] = False
for num in range(1, 4):
pos1 = num + custom_servers_pos
default = num - 1
if default > len(server_list) - 1:
default = 0
set_servers = {"id": "server_%s" % num, "label": u" \u2665" + config.get_localized_string(60082) % num,
"type": "list", "default": default,
"enabled": "eq(-%s,true)+eq(-%s,true)" % (pos1, num), "visible": True,
"lvalues": server_list}
list_controls.append(set_servers)
dict_values["server_%s" % num] = settings_node.get("server_%s" % num, 0)
if settings_node.get("server_%s" % num, 0) > len(server_list) - 1:
dict_values["server_%s" % num] = 0
# Seccion Calidades favoritas
quality_list = channel_node.get("quality", [])
if not quality_list:
enabled = False
quality_list = ["No disponible"]
else:
enabled = "eq(-" + str(len(list_controls)) + ",true)"
custom_quality_settings = {"id": "custom_quality", "label": config.get_localized_string(60083),
"type": "bool", "default": False, "enabled": enabled, "visible": True}
custom_quality_pos = len(list_controls)
list_controls.append(custom_quality_settings)
if dict_values['active'] and enabled:
dict_values['custom_quality'] = settings_node.get('custom_quality', False)
else:
dict_values['custom_quality'] = False
for num in range(1, 4):
pos1 = num + custom_quality_pos
default = num - 1
if default > len(quality_list) - 1:
default = 0
set_quality = {"id": "quality_%s" % num, "label": u" \u2665 " + config.get_localized_string(707417) + " %s" % num,
"type": "list", "default": default,
"enabled": "eq(-%s,true)+eq(-%s,true)" % (pos1, num), "visible": True,
"lvalues": quality_list}
list_controls.append(set_quality)
dict_values["quality_%s" % num] = settings_node.get("quality_%s" % num, 0)
if settings_node.get("quality_%s" % num, 0) > len(quality_list) - 1:
dict_values["quality_%s" % num] = 0
# Plan B
dict_values['plan_b'] = settings_node.get('plan_b', False)
enabled = "eq(-" + str(custom_servers_pos) + ",true)|eq(-" + str(custom_quality_pos) + ",true)"
plan_b = {"id": "plan_b", "label": config.get_localized_string(70172),"type": "bool", "default": False, "enabled": enabled, "visible": True}
list_controls.append(plan_b)
# Seccion Prioridades
priority_list = [config.get_localized_string(70174), config.get_localized_string(70175)]
set_priority = {"id": "priority", "label": config.get_localized_string(60085), "type": "list", "default": 0,
"enabled": True, "visible": "eq(-5,true)+eq(-9,true)+eq(-12,true)", "lvalues": priority_list}
list_controls.append(set_priority)
dict_values["priority"] = settings_node.get("priority", 0)
# Abrir cuadro de dialogo
platformtools.show_channel_settings(list_controls=list_controls, dict_values=dict_values, callback='save',
item=item, caption='%s - AutoPlay' % channel_name,
custom_button={'visible': True,
'function': "reset",
'close': True,
'label': 'Reset'})
def save(item, dict_data_saved):
'''
Guarda los datos de la ventana de configuracion
:param item: item
:param dict_data_saved: dict
:return:
'''
logger.info()
global autoplay_node
if not autoplay_node:
# Obtiene el nodo AUTOPLAY desde el json
autoplay_node = jsontools.get_node_from_file('autoplay', 'AUTOPLAY')
new_config = dict_data_saved
if not new_config['active']:
new_config['language']=0
channel_node = autoplay_node.get(item.from_channel)
config.set_setting("filter_languages", dict_data_saved.pop("language"), item.from_channel)
channel_node['settings'] = dict_data_saved
result, json_data = jsontools.update_node(autoplay_node, 'autoplay', 'AUTOPLAY')
return result
def get_languages(channel):
'''
Obtiene los idiomas desde el json del canal
:param channel: str
:return: list
'''
logger.info()
list_language = ['Non filtrare']
list_controls, dict_settings = channeltools.get_channel_controls_settings(channel)
for control in list_controls:
try:
if control["id"] == 'filter_languages':
list_language = control["lvalues"]
except:
pass
return list_language
def is_active(channel):
'''
Devuelve un booleano q indica si esta activo o no autoplay en el canal desde el que se llama
:return: True si esta activo autoplay para el canal desde el que se llama, False en caso contrario.
'''
logger.info()
global autoplay_node
if not config.is_xbmc():
return False
if not autoplay_node:
# Obtiene el nodo AUTOPLAY desde el json
autoplay_node = jsontools.get_node_from_file('autoplay', 'AUTOPLAY')
# Obtine el canal desde el q se hace la llamada
#import inspect
#module = inspect.getmodule(inspect.currentframe().f_back)
#canal = module.__name__.split('.')[1]
canal = channel
# Obtiene el nodo del canal desde autoplay_node
channel_node = autoplay_node.get(canal, {})
# Obtiene los ajustes des autoplay para este canal
settings_node = channel_node.get('settings', {})
return settings_node.get('active', False) or get_setting('autoplay')
def reset(item, dict):
channel_name = item.from_channel
channel = __import__('channels.%s' % channel_name, fromlist=["channels.%s" % channel_name])
list_servers = channel.list_servers
list_quality = channel.list_quality
init(channel_name, list_servers, list_quality, reset=True)
platformtools.dialog_notification('AutoPlay', config.get_localized_string(70523) % item.category)
return
def set_status(status):
logger.info()
# Obtiene el nodo AUTOPLAY desde el json
autoplay_node = jsontools.get_node_from_file('autoplay', 'AUTOPLAY')
autoplay_node['status'] = status
result, json_data = jsontools.update_node(autoplay_node, 'autoplay', 'AUTOPLAY')
def play_multi_channel(item, itemlist):
logger.info()
global PLAYED
video_dict = dict()
set_status(True)
for video_item in itemlist:
if is_active(video_item.contentChannel):
if video_item.contentChannel not in video_dict.keys():
video_dict[video_item.contentChannel] = [video_item]
else:
video_dict[video_item.contentChannel].append(video_item)
for channel, videos in video_dict.items():
item.contentChannel = channel
if not PLAYED:
start(videos, item)
else:
break