Reorganized channels and support moved to core
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Appends the main plugin dir to the PYTHONPATH if an internal package cannot be imported.
|
||||
# Examples: In Plex Media Server all modules are under "Code.*" package, and in Enigma2 under "Plugins.Extensions.*"
|
||||
try:
|
||||
# from core import logger
|
||||
import core
|
||||
except:
|
||||
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||
@@ -0,0 +1,724 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
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 = {}
|
||||
|
||||
|
||||
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='yellow', 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,
|
||||
thumbnail=thumbnail,
|
||||
fanart=fanart,
|
||||
plot=plot_autoplay,
|
||||
from_channel=channel
|
||||
))
|
||||
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_servers = []
|
||||
favorite_quality = []
|
||||
|
||||
# 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']):
|
||||
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 item in itemlist:
|
||||
autoplay_elem = dict()
|
||||
b_dict = dict()
|
||||
|
||||
# Comprobamos q se trata de un item de video
|
||||
if 'server' not in item:
|
||||
continue
|
||||
|
||||
# Agrega la opcion configurar AutoPlay al menu contextual
|
||||
if 'context' not in item:
|
||||
item.context = list()
|
||||
if not filter(lambda x: x['action'] == 'autoplay_config', context):
|
||||
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_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_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_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_server'], orden['indice_quality']))
|
||||
|
||||
elif priority == 1: # Calidades y servidores
|
||||
autoplay_list.sort(key=lambda orden: (orden['indice_quality'], orden['indice_server']))
|
||||
|
||||
elif priority == 2: # Solo servidores
|
||||
autoplay_list.sort(key=lambda orden: orden['indice_server'])
|
||||
|
||||
elif priority == 3: # Solo calidades
|
||||
autoplay_list.sort(key=lambda orden: 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
|
||||
channel = __import__('channels.%s' % channel_id, None, None, ["channels.%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))
|
||||
|
||||
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,
|
||||
"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)
|
||||
icon = 1
|
||||
|
||||
platformtools.dialog_notification(heading, msj, icon, 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),
|
||||
"color": "0xffffff99", "type": "bool", "default": False, "enabled": allow_option,
|
||||
"visible": allow_option}
|
||||
list_controls.append(active_settings)
|
||||
dict_values['active'] = settings_node.get('active', 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), "color": "0xffffff99",
|
||||
"type": "list", "default": 0, "enabled": "eq(-1,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(-3,true)"
|
||||
|
||||
custom_servers_settings = {"id": "custom_servers", "label": config.get_localized_string(60081), "color": "0xff66ffcc",
|
||||
"type": "bool", "default": False, "enabled": enabled, "visible": True}
|
||||
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 + 3
|
||||
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,
|
||||
"color": "0xfffcab14", "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(-7,true)"
|
||||
|
||||
custom_quality_settings = {"id": "custom_quality", "label": config.get_localized_string(60083), "color": "0xff66ffcc",
|
||||
"type": "bool", "default": False, "enabled": enabled, "visible": True}
|
||||
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 + 7
|
||||
default = num - 1
|
||||
if default > len(quality_list) - 1:
|
||||
default = 0
|
||||
|
||||
set_quality = {"id": "quality_%s" % num, "label": u" \u2665 Calidad Favorita %s" % num,
|
||||
"color": "0xfff442d9", "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(-4,true)|eq(-8,true)"
|
||||
plan_b = {"id": "plan_b", "label": config.get_localized_string(70172),
|
||||
"color": "0xffffff99",
|
||||
"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),
|
||||
"color": "0xffffff99", "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 = ['No filtrar']
|
||||
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
|
||||
actual_channel = ''
|
||||
channel_videos = []
|
||||
video_dict = dict()
|
||||
set_status(True)
|
||||
|
||||
for video_item in itemlist:
|
||||
if video_item.contentChannel != actual_channel:
|
||||
actual_channel = video_item.contentChannel
|
||||
elif is_active(actual_channel):
|
||||
channel_videos.append(video_item)
|
||||
video_dict[actual_channel] = channel_videos
|
||||
|
||||
for channel, videos in video_dict.items():
|
||||
item.contentChannel = channel
|
||||
if not PLAYED:
|
||||
start(videos, item)
|
||||
else:
|
||||
break
|
||||
@@ -0,0 +1,167 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# --------------------------------------------------------------------------------
|
||||
# autorenumber - Rinomina Automaticamente gli Episodi
|
||||
# --------------------------------------------------------------------------------
|
||||
|
||||
import os
|
||||
|
||||
try:
|
||||
import xbmcgui
|
||||
except:
|
||||
xbmcgui = None
|
||||
|
||||
from platformcode import config
|
||||
from core import jsontools, tvdb
|
||||
from core.item import Item
|
||||
from platformcode import platformtools
|
||||
from core.support import typo, log
|
||||
|
||||
TAG_TVSHOW_RENUMERATE = "TVSHOW_AUTORENUMBER"
|
||||
TAG_SEASON_EPISODE = "season_episode"
|
||||
__channel__ = "autorenumber"
|
||||
|
||||
|
||||
def access():
|
||||
allow = False
|
||||
|
||||
if config.is_xbmc():
|
||||
allow = True
|
||||
|
||||
return allow
|
||||
|
||||
|
||||
def context():
|
||||
if access():
|
||||
_context = [{"title": config.get_localized_string(70585),
|
||||
"action": "config_item",
|
||||
"channel": "autorenumber"}]
|
||||
|
||||
return _context
|
||||
|
||||
|
||||
def config_item(item):
|
||||
log(item)
|
||||
tvdb.find_and_set_infoLabels(item)
|
||||
data = ''
|
||||
data = add_season(data)
|
||||
title = item.show
|
||||
count = 0
|
||||
|
||||
while not item.infoLabels['tvdb_id']:
|
||||
try:
|
||||
item.show = platformtools.dialog_input(default=item.show, heading=config.get_localized_string(30112))
|
||||
tvdb.find_and_set_infoLabels(item)
|
||||
count = count + 1
|
||||
except:
|
||||
heading = config.get_localized_string(70704)
|
||||
item.infoLabels['tvdb_id'] = platformtools.dialog_numeric(0, heading)
|
||||
data.append(item.infoLabels['tvdb_id'])
|
||||
if item.infoLabels['tvdb_id'] != 0:
|
||||
write_data(item.from_channel, title, data)
|
||||
else:
|
||||
message = config.get_localized_string(60444)
|
||||
heading = item.show.strip()
|
||||
platformtools.dialog_notification(heading, message)
|
||||
|
||||
|
||||
|
||||
def add_season(data=None):
|
||||
log("data= ", data)
|
||||
heading = config.get_localized_string(70686)
|
||||
season = platformtools.dialog_numeric(0, heading)
|
||||
|
||||
if season != "":
|
||||
heading = config.get_localized_string(70687)
|
||||
episode = platformtools.dialog_numeric(0, heading)
|
||||
|
||||
if episode == "0":
|
||||
heading = config.get_localized_string(70688)
|
||||
special = platformtools.dialog_numeric(0, heading)
|
||||
return [int(season), int(episode), int(special)]
|
||||
elif episode != '':
|
||||
return [int(season), int(episode), '']
|
||||
|
||||
|
||||
def write_data(channel, show, data):
|
||||
log()
|
||||
dict_series = jsontools.get_node_from_file(channel, TAG_TVSHOW_RENUMERATE)
|
||||
tvshow = show.strip()
|
||||
# list_season_episode = dict_series.get(tvshow, {}).get(TAG_SEASON_EPISODE, [])
|
||||
|
||||
if data:
|
||||
dict_renumerate = {TAG_SEASON_EPISODE: data}
|
||||
dict_series[tvshow] = dict_renumerate
|
||||
else:
|
||||
dict_series.pop(tvshow, None)
|
||||
|
||||
result = jsontools.update_node(dict_series, channel, TAG_TVSHOW_RENUMERATE)[0]
|
||||
|
||||
if result:
|
||||
if data:
|
||||
message = config.get_localized_string(60446)
|
||||
else:
|
||||
message = config.get_localized_string(60444)
|
||||
else:
|
||||
message = config.get_localized_string(70593)
|
||||
|
||||
heading = show.strip()
|
||||
platformtools.dialog_notification(heading, message)
|
||||
|
||||
|
||||
|
||||
def renumber(itemlist, item='', typography=''):
|
||||
log()
|
||||
|
||||
if item:
|
||||
try:
|
||||
dict_series = jsontools.get_node_from_file(item.channel, TAG_TVSHOW_RENUMERATE)
|
||||
SERIES = dict_series[item.show.rstrip()]['season_episode']
|
||||
S = SERIES[0]
|
||||
E = SERIES[1]
|
||||
SP = SERIES[2]
|
||||
ID = SERIES[3]
|
||||
|
||||
page = 1
|
||||
epList = []
|
||||
exist = True
|
||||
item.infoLabels['tvdb_id'] = ID
|
||||
tvdb.set_infoLabels_item(item)
|
||||
|
||||
while exist:
|
||||
data = tvdb.otvdb_global.get_list_episodes(ID,page)
|
||||
if data:
|
||||
for episodes in data['data']:
|
||||
if episodes['airedSeason'] >= S:
|
||||
if E == 0:
|
||||
epList.append([0, SP])
|
||||
E = 1
|
||||
if episodes['airedEpisodeNumber'] >= E or episodes['airedSeason'] > S:
|
||||
epList.append([episodes['airedSeason'], episodes['airedEpisodeNumber']])
|
||||
page = page + 1
|
||||
else:
|
||||
exist = False
|
||||
|
||||
epList.sort()
|
||||
ep = 0
|
||||
|
||||
for item in itemlist:
|
||||
s = str(epList[ep][0])
|
||||
e = str(epList[ep][1])
|
||||
item.title = typo(s + 'x'+ e + ' - ', typography) + item.title
|
||||
ep = ep + 1
|
||||
|
||||
except:
|
||||
return itemlist
|
||||
else:
|
||||
for item in itemlist:
|
||||
if item.contentType != 'movie':
|
||||
if item.context:
|
||||
context2 = item.context
|
||||
item.context = context() + context2
|
||||
else:
|
||||
item.context = context()
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
{
|
||||
"id": "downloads",
|
||||
"name": "Descargas",
|
||||
"active": false,
|
||||
"adult": false,
|
||||
"language": ["*"],
|
||||
"categories": [
|
||||
"movie"
|
||||
],
|
||||
"settings": [
|
||||
{
|
||||
"type": "label",
|
||||
"label": "@70229",
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "library_add",
|
||||
"type": "bool",
|
||||
"label": "@70230",
|
||||
"default": false,
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "library_move",
|
||||
"type": "bool",
|
||||
"label": "@70231",
|
||||
"default": false,
|
||||
"enabled": "eq(-1,true)",
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "browser",
|
||||
"type": "bool",
|
||||
"label": "@70232",
|
||||
"default": true,
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "@70243",
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "block_size",
|
||||
"type": "list",
|
||||
"label": "@70233",
|
||||
"lvalues": [
|
||||
"128 KB",
|
||||
"256 KB",
|
||||
"512 KB",
|
||||
"1 MB",
|
||||
"2 MB"
|
||||
],
|
||||
"default": 1,
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "part_size",
|
||||
"type": "list",
|
||||
"label": "@70234",
|
||||
"lvalues": [
|
||||
"1 MB",
|
||||
"2 MB",
|
||||
"4 MB",
|
||||
"8 MB",
|
||||
"16 MB",
|
||||
"32 MB"
|
||||
],
|
||||
"default": 1,
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "max_connections",
|
||||
"type": "list",
|
||||
"label": "@70235",
|
||||
"lvalues": [
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
"10"
|
||||
],
|
||||
"default": 4,
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "max_buffer",
|
||||
"type": "list",
|
||||
"label": "@70236",
|
||||
"lvalues": [
|
||||
"0",
|
||||
"2",
|
||||
"4",
|
||||
"6",
|
||||
"8",
|
||||
"10",
|
||||
"12",
|
||||
"14",
|
||||
"16",
|
||||
"18",
|
||||
"20"
|
||||
],
|
||||
"default": 5,
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"label": "@70237",
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "server_reorder",
|
||||
"type": "list",
|
||||
"label": "@70238",
|
||||
"lvalues": [
|
||||
"@70244",
|
||||
"@70245"
|
||||
],
|
||||
"default": 0,
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "language",
|
||||
"type": "list",
|
||||
"label": "@70246",
|
||||
"lvalues": [
|
||||
"Ita, Sub, Eng, Vos, Vosi",
|
||||
"Eng, Ita, Sub, Vos, Vosi",
|
||||
"Sub, Ita, Eng, Vos, Vosi",
|
||||
"Eng, Sub, Ita, Vos, Vosi"
|
||||
],
|
||||
"default": 0,
|
||||
"enabled": "eq(-1,'@70245')",
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "quality",
|
||||
"type": "list",
|
||||
"label": "@70240",
|
||||
"lvalues": [
|
||||
"@70241",
|
||||
"HD 1080",
|
||||
"HD 720",
|
||||
"SD"
|
||||
],
|
||||
"default": 0,
|
||||
"enabled": "eq(-2,'Reordenar')",
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "server_speed",
|
||||
"type": "bool",
|
||||
"label": "@70242",
|
||||
"default": true,
|
||||
"enabled": "eq(-3,'Reordenar')",
|
||||
"visible": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,863 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ------------------------------------------------------------
|
||||
# Gestor de descargas
|
||||
# ------------------------------------------------------------
|
||||
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import unicodedata
|
||||
|
||||
|
||||
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
|
||||
from platformcode import platformtools
|
||||
|
||||
STATUS_COLORS = {0: "orange", 1: "orange", 2: "green", 3: "red"}
|
||||
STATUS_CODES = type("StatusCode", (), {"stoped": 0, "canceled": 1, "completed": 2, "error": 3})
|
||||
DOWNLOAD_LIST_PATH = config.get_setting("downloadlistpath")
|
||||
DOWNLOAD_PATH = config.get_setting("downloadpath")
|
||||
STATS_FILE = os.path.join(config.get_data_path(), "servers.json")
|
||||
|
||||
TITLE_FILE = "[COLOR %s][%i%%][/COLOR] %s"
|
||||
TITLE_TVSHOW = "[COLOR %s][%i%%][/COLOR] %s [%s]"
|
||||
|
||||
|
||||
def mainlist(item):
|
||||
logger.info()
|
||||
itemlist = []
|
||||
|
||||
# Lista de archivos
|
||||
for file in sorted(filetools.listdir(DOWNLOAD_LIST_PATH)):
|
||||
# Saltamos todos los que no sean JSON
|
||||
if not file.endswith(".json"): continue
|
||||
|
||||
# cargamos el item
|
||||
file = os.path.join(DOWNLOAD_LIST_PATH, file)
|
||||
i = Item(path=file).fromjson(filetools.read(file))
|
||||
i.thumbnail = i.contentThumbnail
|
||||
|
||||
# Listado principal
|
||||
if not item.contentType == "tvshow":
|
||||
# Series
|
||||
if i.contentType == "episode":
|
||||
# Comprobamos que la serie no este ya en el itemlist
|
||||
if not filter(
|
||||
lambda x: x.contentSerieName == i.contentSerieName and x.contentChannel == i.contentChannel,
|
||||
itemlist):
|
||||
|
||||
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 = \
|
||||
filter(
|
||||
lambda x: x.contentSerieName == i.contentSerieName and x.contentChannel == i.contentChannel,
|
||||
itemlist)[0]
|
||||
s.downloadProgress.append(i.downloadProgress)
|
||||
downloadProgress = 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)
|
||||
|
||||
# Peliculas
|
||||
elif i.contentType == "movie" or i.contentType == "video":
|
||||
i.title = TITLE_FILE % (STATUS_COLORS[i.downloadStatus], i.downloadProgress, i.contentTitle)
|
||||
itemlist.append(i)
|
||||
|
||||
# Listado dentro de una serie
|
||||
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]
|
||||
|
||||
# Si hay alguno completado
|
||||
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,
|
||||
contentSerieName=item.contentSerieName, text_color="sandybrown"))
|
||||
|
||||
# Si hay alguno con 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,
|
||||
contentSerieName=item.contentSerieName, text_color="orange"))
|
||||
|
||||
# Si hay alguno pendiente
|
||||
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,
|
||||
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,
|
||||
contentSerieName=item.contentSerieName))
|
||||
|
||||
if not item.contentType == "tvshow" and config.get_setting("browser", "downloads") == True:
|
||||
itemlist.insert(0, Item(channel=item.channel, action="browser", title=support.typo(config.get_localized_string(70222),'bold'),url=DOWNLOAD_PATH))
|
||||
|
||||
if not item.contentType == "tvshow":
|
||||
itemlist.insert(0, Item(channel=item.channel, action="settings", title= support.typo(config.get_localized_string(70223),'bold color kod')))
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def settings(item):
|
||||
ret = platformtools.show_channel_settings(caption=config.get_localized_string(70224))
|
||||
platformtools.itemlist_refresh()
|
||||
return ret
|
||||
|
||||
|
||||
def browser(item):
|
||||
logger.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)))
|
||||
else:
|
||||
itemlist.append(Item(channel=item.channel, title=file, action="play", url=filetools.join(item.url, file)))
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def clean_all(item):
|
||||
logger.info()
|
||||
|
||||
for fichero in sorted(filetools.listdir(DOWNLOAD_LIST_PATH)):
|
||||
if fichero.endswith(".json"):
|
||||
download_item = Item().fromjson(filetools.read(os.path.join(DOWNLOAD_LIST_PATH, fichero)))
|
||||
if not item.contentType == "tvshow" or (
|
||||
item.contentSerieName == download_item.contentSerieName and item.contentChannel == download_item.contentChannel):
|
||||
filetools.remove(os.path.join(DOWNLOAD_LIST_PATH, fichero))
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
|
||||
|
||||
def clean_ready(item):
|
||||
logger.info()
|
||||
for fichero in sorted(filetools.listdir(DOWNLOAD_LIST_PATH)):
|
||||
if fichero.endswith(".json"):
|
||||
download_item = Item().fromjson(filetools.read(os.path.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(os.path.join(DOWNLOAD_LIST_PATH, fichero))
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
|
||||
|
||||
def restart_error(item):
|
||||
logger.info()
|
||||
for fichero in sorted(filetools.listdir(DOWNLOAD_LIST_PATH)):
|
||||
if fichero.endswith(".json"):
|
||||
download_item = Item().fromjson(filetools.read(os.path.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(
|
||||
os.path.join(config.get_setting("downloadpath"), download_item.downloadFilename)):
|
||||
filetools.remove(
|
||||
os.path.join(config.get_setting("downloadpath"), 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)
|
||||
for fichero in sorted(filetools.listdir(DOWNLOAD_LIST_PATH)):
|
||||
if fichero.endswith(".json"):
|
||||
download_item = Item(path=os.path.join(DOWNLOAD_LIST_PATH, fichero)).fromjson(
|
||||
filetools.read(os.path.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()
|
||||
# Si se ha cancelado paramos
|
||||
if res == STATUS_CODES.canceled: break
|
||||
|
||||
|
||||
def menu(item):
|
||||
logger.info()
|
||||
if item.downloadServer:
|
||||
servidor = item.downloadServer.get("server", "Auto")
|
||||
else:
|
||||
servidor = "Auto"
|
||||
# Opciones disponibles para el menu
|
||||
op = [config.get_localized_string(70225), config.get_localized_string(70226), config.get_localized_string(70227),
|
||||
"Modificar servidor: %s" % (servidor.capitalize())]
|
||||
|
||||
opciones = []
|
||||
|
||||
# Opciones para el menu
|
||||
if item.downloadStatus == 0: # Sin descargar
|
||||
opciones.append(op[0]) # Descargar
|
||||
if not item.server: opciones.append(op[3]) # Elegir Servidor
|
||||
opciones.append(op[1]) # Eliminar de la lista
|
||||
|
||||
if item.downloadStatus == 1: # descarga parcial
|
||||
opciones.append(op[0]) # Descargar
|
||||
if not item.server: opciones.append(op[3]) # Elegir Servidor
|
||||
opciones.append(op[2]) # Reiniciar descarga
|
||||
opciones.append(op[1]) # Eliminar de la lista
|
||||
|
||||
if item.downloadStatus == 2: # descarga completada
|
||||
opciones.append(op[1]) # Eliminar de la lista
|
||||
opciones.append(op[2]) # Reiniciar descarga
|
||||
|
||||
if item.downloadStatus == 3: # descarga con error
|
||||
opciones.append(op[2]) # Reiniciar descarga
|
||||
opciones.append(op[1]) # Eliminar de la lista
|
||||
|
||||
# Mostramos el dialogo
|
||||
seleccion = platformtools.dialog_select(config.get_localized_string(30163), opciones)
|
||||
|
||||
# -1 es cancelar
|
||||
if seleccion == -1: return
|
||||
|
||||
logger.info("opcion=%s" % (opciones[seleccion]))
|
||||
# Opcion Eliminar
|
||||
if opciones[seleccion] == op[1]:
|
||||
filetools.remove(item.path)
|
||||
|
||||
# Opcion inicaiar descarga
|
||||
if opciones[seleccion] == op[0]:
|
||||
start_download(item)
|
||||
|
||||
# Elegir Servidor
|
||||
if opciones[seleccion] == op[3]:
|
||||
select_server(item)
|
||||
|
||||
# Reiniciar descarga
|
||||
if opciones[seleccion] == op[2]:
|
||||
if filetools.isfile(os.path.join(config.get_setting("downloadpath"), item.downloadFilename)):
|
||||
filetools.remove(os.path.join(config.get_setting("downloadpath"), item.downloadFilename))
|
||||
|
||||
update_json(item.path, {"downloadStatus": STATUS_CODES.stoped, "downloadComplete": 0, "downloadProgress": 0,
|
||||
"downloadServer": {}})
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
|
||||
|
||||
def move_to_libray(item):
|
||||
download_path = filetools.join(config.get_setting("downloadpath"), item.downloadFilename)
|
||||
library_path = filetools.join(config.get_videolibrary_path(), *filetools.split(item.downloadFilename))
|
||||
final_path = download_path
|
||||
|
||||
if config.get_setting("library_add", "downloads") == True and config.get_setting("library_move", "downloads") == True:
|
||||
if not filetools.isdir(filetools.dirname(library_path)):
|
||||
filetools.mkdir(filetools.dirname(library_path))
|
||||
|
||||
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):
|
||||
final_path = library_path
|
||||
|
||||
if len(filetools.listdir(filetools.dirname(download_path))) == 0:
|
||||
filetools.rmdir(filetools.dirname(download_path))
|
||||
|
||||
if config.get_setting("library_add", "downloads") == True:
|
||||
if filetools.isfile(final_path):
|
||||
if item.contentType == "movie" and item.infoLabels["tmdb_id"]:
|
||||
library_item = Item(title=config.get_localized_string(70228) % item.downloadFilename, channel="downloads",
|
||||
action="findvideos", infoLabels=item.infoLabels, url=final_path)
|
||||
videolibrarytools.save_movie(library_item)
|
||||
|
||||
elif item.contentType == "episode" and item.infoLabels["tmdb_id"]:
|
||||
library_item = Item(title=config.get_localized_string(70228) % item.downloadFilename, channel="downloads",
|
||||
action="findvideos", infoLabels=item.infoLabels, url=final_path)
|
||||
tvshow = Item(channel="downloads", contentType="tvshow",
|
||||
infoLabels={"tmdb_id": item.infoLabels["tmdb_id"]})
|
||||
videolibrarytools.save_tvshow(tvshow, [library_item])
|
||||
|
||||
|
||||
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 os.path.isfile(STATS_FILE):
|
||||
servers = jsontools.load(open(STATS_FILE, "rb").read())
|
||||
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:]
|
||||
|
||||
open(STATS_FILE, "wb").write(jsontools.dump(servers))
|
||||
return
|
||||
|
||||
|
||||
def get_server_position(server):
|
||||
if os.path.isfile(STATS_FILE):
|
||||
servers = jsontools.load(open(STATS_FILE, "rb").read())
|
||||
else:
|
||||
servers = {}
|
||||
|
||||
if server in servers:
|
||||
pos = [s for s in sorted(servers, key=lambda x: (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):
|
||||
"""
|
||||
Busca coincidencias en una cadena de texto, con un diccionario de "ID" / "Listado de cadenas de busqueda":
|
||||
{ "ID1" : ["Cadena 1", "Cadena 2", "Cadena 3"],
|
||||
"ID2" : ["Cadena 4", "Cadena 5", "Cadena 6"]
|
||||
}
|
||||
|
||||
El diccionario no pude contener una misma cadena de busqueda en varías IDs.
|
||||
|
||||
La busqueda se realiza por orden de tamaño de cadena de busqueda (de mas larga a mas corta) si una cadena coincide,
|
||||
se elimina de la cadena a buscar para las siguientes, para que no se detecten dos categorias si una cadena es parte de otra:
|
||||
por ejemplo: "Idioma Español" y "Español" si la primera aparece en la cadena "Pablo sabe hablar el Idioma Español"
|
||||
coincidira con "Idioma Español" pero no con "Español" ya que la coincidencia mas larga tiene prioridad.
|
||||
|
||||
"""
|
||||
match_dict = dict()
|
||||
matches = []
|
||||
|
||||
# Pasamos la cadena a unicode
|
||||
data = unicode(data, "utf8")
|
||||
|
||||
# Pasamos el diccionario a {"Cadena 1": "ID1", "Cadena 2", "ID1", "Cadena 4", "ID2"} y los pasamos a 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)
|
||||
match_dict[unicode(value, "utf8")] = key
|
||||
|
||||
# Si ignorecase = True, lo pasamos todo a mayusculas
|
||||
if ignorecase:
|
||||
data = data.upper()
|
||||
match_dict = dict((key.upper(), match_dict[key]) for key in match_dict)
|
||||
|
||||
# Si ascii = True, eliminamos todos los accentos y Ñ
|
||||
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)
|
||||
|
||||
# Ordenamos el listado de mayor tamaño a menor y buscamos.
|
||||
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):
|
||||
"""
|
||||
Puntua cada item en funcion de varios parametros:
|
||||
@type item: item
|
||||
@param item: elemento que se va a valorar.
|
||||
@return: puntuacion otenida
|
||||
@rtype: int
|
||||
"""
|
||||
lang_orders = {}
|
||||
lang_orders[0] = ["ES", "LAT", "SUB", "ENG", "VOSE"]
|
||||
lang_orders[1] = ["ES", "SUB", "LAT", "ENG", "VOSE"]
|
||||
lang_orders[2] = ["ENG", "SUB", "VOSE", "ESP", "LAT"]
|
||||
lang_orders[3] = ["VOSE", "ENG", "SUB", "ESP", "LAT"]
|
||||
|
||||
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[int(config.get_setting("language", "downloads"))]
|
||||
match_list_idimas = {"ES": ["CAST", "ESP", "Castellano", "Español", "Audio Español"],
|
||||
"LAT": ["LAT", "Latino"],
|
||||
"SUB": ["Subtitulo Español", "Subtitulado", "SUB"],
|
||||
"ENG": ["EN", "ENG", "Inglés", "Ingles", "English"],
|
||||
"VOSE": ["VOSE"]}
|
||||
|
||||
order_list_calidad = ["BLURAY", "FULLHD", "HD", "480P", "360P", "240P"]
|
||||
order_list_calidad = quality_orders[int(config.get_setting("quality", "downloads"))]
|
||||
match_list_calidad = {"BLURAY": ["BR", "BLURAY"],
|
||||
"FULLHD": ["FULLHD", "FULL HD", "1080", "HD1080", "HD 1080"],
|
||||
"HD": ["HD", "HD REAL", "HD 720", "720", "HDTV"],
|
||||
"480P": ["SD", "480P"],
|
||||
"360P": ["360P"],
|
||||
"240P": ["240P"]}
|
||||
|
||||
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", "downloads"):
|
||||
value += tuple([get_server_position(item.server)])
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def download_from_url(url, item):
|
||||
logger.info("Intentando descargar: %s" % (url))
|
||||
if url.lower().endswith(".m3u8") or url.lower().startswith("rtmp"):
|
||||
save_server_statistics(item.server, 0, False)
|
||||
return {"downloadStatus": STATUS_CODES.error}
|
||||
|
||||
# Obtenemos la ruta de descarga y el nombre del archivo
|
||||
item.downloadFilename = item.downloadFilename.replace('/','-')
|
||||
download_path = filetools.dirname(filetools.join(DOWNLOAD_PATH, item.downloadFilename))
|
||||
file_name = filetools.basename(filetools.join(DOWNLOAD_PATH, item.downloadFilename))
|
||||
|
||||
# Creamos la carpeta si no existe
|
||||
|
||||
if not filetools.exists(download_path):
|
||||
filetools.mkdir(download_path)
|
||||
|
||||
# Lanzamos la descarga
|
||||
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")))
|
||||
d.start_dialog(config.get_localized_string(60332))
|
||||
|
||||
# Descarga detenida. Obtenemos el estado:
|
||||
# Se ha producido un error en la descarga
|
||||
if d.state == d.states.error:
|
||||
logger.info("Error al intentar descargar %s" % (url))
|
||||
status = STATUS_CODES.error
|
||||
|
||||
# La descarga se ha detenifdo
|
||||
elif d.state == d.states.stopped:
|
||||
logger.info("Descarga detenida")
|
||||
status = STATUS_CODES.canceled
|
||||
|
||||
# La descarga ha finalizado
|
||||
elif d.state == d.states.completed:
|
||||
logger.info("Descargado correctamente")
|
||||
status = STATUS_CODES.completed
|
||||
|
||||
if item.downloadSize and item.downloadSize != d.size[0]:
|
||||
status = STATUS_CODES.error
|
||||
|
||||
save_server_statistics(item.server, d.speed[0], d.state != d.states.error)
|
||||
|
||||
dir = os.path.dirname(item.downloadFilename)
|
||||
file = filetools.join(dir, d.filename)
|
||||
|
||||
if status == STATUS_CODES.completed:
|
||||
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):
|
||||
logger.info(item.tostring())
|
||||
unsupported_servers = ["torrent"]
|
||||
|
||||
progreso = platformtools.dialog_progress(config.get_localized_string(30101), config.get_localized_string(70178) % item.server)
|
||||
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, config.get_localized_string(60003) % item.contentChannel)
|
||||
try:
|
||||
itemlist = getattr(channel, "play")(item.clone(channel=item.contentChannel, action=item.contentAction))
|
||||
except:
|
||||
logger.error("Error en el canal %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:
|
||||
logger.info("No hay nada que reproducir")
|
||||
return {"downloadStatus": STATUS_CODES.error}
|
||||
progreso.close()
|
||||
logger.info("contentAction: %s | contentChannel: %s | server: %s | url: %s" % (
|
||||
item.contentAction, item.contentChannel, item.server, item.url))
|
||||
|
||||
if not item.server or not item.url or not item.contentAction == "play" or item.server in unsupported_servers:
|
||||
logger.error("El Item no contiene los parametros necesarios.")
|
||||
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)
|
||||
else:
|
||||
video_urls, puedes, motivo = item.video_urls, True, ""
|
||||
|
||||
# Si no esta disponible, salimos
|
||||
if not puedes:
|
||||
logger.info("El vídeo **NO** está disponible")
|
||||
return {"downloadStatus": STATUS_CODES.error}
|
||||
|
||||
else:
|
||||
logger.info("El vídeo **SI** está disponible")
|
||||
|
||||
result = {}
|
||||
|
||||
# Recorre todas las opciones hasta que consiga descargar una correctamente
|
||||
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
|
||||
|
||||
# Error en la descarga, continuamos con la siguiente opcion
|
||||
if result["downloadStatus"] == STATUS_CODES.error:
|
||||
continue
|
||||
|
||||
# Devolvemos el estado
|
||||
return result
|
||||
|
||||
|
||||
def download_from_best_server(item):
|
||||
logger.info(
|
||||
"contentAction: %s | contentChannel: %s | url: %s" % (item.contentAction, item.contentChannel, item.url))
|
||||
|
||||
result = {"downloadStatus": STATUS_CODES.error}
|
||||
|
||||
progreso = platformtools.dialog_progress(config.get_localized_string(30101), config.get_localized_string(70179))
|
||||
channel = __import__('channels.%s' % item.contentChannel, None, None, ["channels.%s" % item.contentChannel])
|
||||
|
||||
progreso.update(50, config.get_localized_string(70184), 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 = filter(lambda x: x.action == "play" and not "trailer" in x.title.lower(), play_items)
|
||||
|
||||
progreso.update(100, config.get_localized_string(70183), config.get_localized_string(70181) % len(play_items),
|
||||
config.get_localized_string(70182))
|
||||
|
||||
if config.get_setting("server_reorder", "downloads") == 1:
|
||||
play_items.sort(key=sort_method)
|
||||
|
||||
if progreso.iscanceled():
|
||||
return {"downloadStatus": STATUS_CODES.canceled}
|
||||
|
||||
progreso.close()
|
||||
|
||||
# Recorremos el listado de servers, hasta encontrar uno que funcione
|
||||
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
|
||||
|
||||
# Tanto si se cancela la descarga como si se completa dejamos de probar mas opciones
|
||||
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):
|
||||
logger.info(
|
||||
"contentAction: %s | contentChannel: %s | url: %s" % (item.contentAction, item.contentChannel, item.url))
|
||||
|
||||
progreso = platformtools.dialog_progress(config.get_localized_string(30101), config.get_localized_string(70179))
|
||||
channel = __import__('channels.%s' % item.contentChannel, None, None, ["channels.%s" % item.contentChannel])
|
||||
progreso.update(50, config.get_localized_string(70184), 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 = filter(lambda x: x.action == "play" and not "trailer" in x.title.lower(), play_items)
|
||||
|
||||
progreso.update(100, config.get_localized_string(70183), config.get_localized_string(70181) % len(play_items),
|
||||
config.get_localized_string(70182))
|
||||
|
||||
for x, i in enumerate(play_items):
|
||||
if not i.server and hasattr(channel, "play"):
|
||||
play_items[x] = getattr(channel, "play")(i)
|
||||
|
||||
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}})
|
||||
elif seleccion == 0:
|
||||
update_json(item.path, {"downloadServer": {}})
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
|
||||
|
||||
def start_download(item):
|
||||
logger.info(
|
||||
"contentAction: %s | contentChannel: %s | url: %s" % (item.contentAction, item.contentChannel, item.url))
|
||||
|
||||
# Ya tenemnos server, solo falta descargar
|
||||
if item.contentAction == "play":
|
||||
ret = download_from_server(item)
|
||||
update_json(item.path, ret)
|
||||
return ret["downloadStatus"]
|
||||
|
||||
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"))
|
||||
update_json(item.path, ret)
|
||||
return ret["downloadStatus"]
|
||||
# No tenemos server, necesitamos buscar el mejor
|
||||
else:
|
||||
ret = download_from_best_server(item)
|
||||
update_json(item.path, ret)
|
||||
return ret["downloadStatus"]
|
||||
|
||||
|
||||
def get_episodes(item):
|
||||
logger.info("contentAction: %s | contentChannel: %s | contentType: %s" % (
|
||||
item.contentAction, item.contentChannel, item.contentType))
|
||||
|
||||
# El item que pretendemos descargar YA es un episodio
|
||||
if item.contentType == "episode":
|
||||
episodes = [item.clone()]
|
||||
|
||||
# El item es uma serie o temporada
|
||||
elif item.contentType in ["tvshow", "season"]:
|
||||
# importamos el canal
|
||||
channel = __import__('channels.%s' % item.contentChannel, None, None, ["channels.%s" % item.contentChannel])
|
||||
# Obtenemos el listado de episodios
|
||||
episodes = getattr(channel, item.contentAction)(item)
|
||||
|
||||
itemlist = []
|
||||
|
||||
# Tenemos las lista, ahora vamos a comprobar
|
||||
for episode in episodes:
|
||||
|
||||
# Si partiamos de un item que ya era episodio estos datos ya están bien, no hay que modificarlos
|
||||
if item.contentType != "episode":
|
||||
episode.contentAction = episode.action
|
||||
episode.contentChannel = episode.channel
|
||||
|
||||
# Si el resultado es una temporada, no nos vale, tenemos que descargar los episodios de cada temporada
|
||||
if episode.contentType == "season":
|
||||
itemlist.extend(get_episodes(episode))
|
||||
|
||||
# Si el resultado es un episodio ya es lo que necesitamos, lo preparamos para añadirlo a la descarga
|
||||
if episode.contentType == "episode":
|
||||
|
||||
# Pasamos el id al episodio
|
||||
if not episode.infoLabels["tmdb_id"]:
|
||||
episode.infoLabels["tmdb_id"] = item.infoLabels["tmdb_id"]
|
||||
|
||||
# Episodio, Temporada y Titulo
|
||||
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]
|
||||
|
||||
# Buscamos en tmdb
|
||||
if item.infoLabels["tmdb_id"]:
|
||||
scraper.find_and_set_infoLabels(episode)
|
||||
|
||||
# Episodio, Temporada y Titulo
|
||||
if not episode.contentTitle:
|
||||
episode.contentTitle = re.sub("\[[^\]]+\]|\([^\)]+\)|\d*x\d*\s*-", "", episode.title).strip()
|
||||
|
||||
episode.downloadFilename = filetools.validate_path(os.path.join(item.downloadFilename, "%dx%0.2d - %s" % (
|
||||
episode.contentSeason, episode.contentEpisodeNumber, episode.contentTitle.strip())))
|
||||
|
||||
itemlist.append(episode)
|
||||
# Cualquier otro resultado no nos vale, lo ignoramos
|
||||
else:
|
||||
logger.info("Omitiendo item no válido: %s" % episode.tostring())
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def write_json(item):
|
||||
logger.info()
|
||||
|
||||
item.action = "menu"
|
||||
item.channel = "downloads"
|
||||
item.downloadStatus = STATUS_CODES.stoped
|
||||
item.downloadProgress = 0
|
||||
item.downloadSize = 0
|
||||
item.downloadCompleted = 0
|
||||
if not item.contentThumbnail:
|
||||
item.contentThumbnail = item.thumbnail
|
||||
|
||||
for name in ["text_bold", "text_color", "text_italic", "context", "totalItems", "viewmode", "title", "fulltitle",
|
||||
"thumbnail"]:
|
||||
if item.__dict__.has_key(name):
|
||||
item.__dict__.pop(name)
|
||||
|
||||
path = os.path.join(config.get_setting("downloadlistpath"), str(time.time()) + ".json")
|
||||
filetools.write(path, item.tojson())
|
||||
item.path = path
|
||||
time.sleep(0.1)
|
||||
|
||||
|
||||
def save_download(item):
|
||||
logger.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.channel
|
||||
item.contentAction = item.action
|
||||
|
||||
if item.contentType in ["tvshow", "episode", "season"]:
|
||||
save_download_tvshow(item)
|
||||
|
||||
elif item.contentType == "movie":
|
||||
save_download_movie(item)
|
||||
|
||||
else:
|
||||
save_download_video(item)
|
||||
|
||||
|
||||
def save_download_video(item):
|
||||
logger.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,
|
||||
config.get_localized_string(30109))
|
||||
else:
|
||||
start_download(item)
|
||||
|
||||
|
||||
def save_download_movie(item):
|
||||
logger.info("contentAction: %s | contentChannel: %s | contentTitle: %s" % (
|
||||
item.contentAction, item.contentChannel, item.contentTitle))
|
||||
|
||||
progreso = platformtools.dialog_progress(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.contentChannel))
|
||||
|
||||
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,
|
||||
config.get_localized_string(30109))
|
||||
else:
|
||||
start_download(item)
|
||||
|
||||
|
||||
def save_download_tvshow(item):
|
||||
logger.info("contentAction: %s | contentChannel: %s | contentType: %s | contentSerieName: %s" % (
|
||||
item.contentAction, item.contentChannel, item.contentType, item.contentSerieName))
|
||||
|
||||
progreso = platformtools.dialog_progress(config.get_localized_string(30101), config.get_localized_string(70188))
|
||||
|
||||
scraper.find_and_set_infoLabels(item)
|
||||
|
||||
item.downloadFilename = filetools.validate_path("%s [%s]" % (item.contentSerieName, item.contentChannel))
|
||||
|
||||
progreso.update(0, config.get_localized_string(70186), config.get_localized_string(70187) % item.contentChannel)
|
||||
|
||||
episodes = get_episodes(item)
|
||||
|
||||
progreso.update(0, config.get_localized_string(70190), " ")
|
||||
|
||||
for x, i in enumerate(episodes):
|
||||
progreso.update(x * 100 / len(episodes),
|
||||
"%dx%0.2d: %s" % (i.contentSeason, i.contentEpisodeNumber, i.contentTitle))
|
||||
write_json(i)
|
||||
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)) + " capitulos de: " + item.contentSerieName,
|
||||
config.get_localized_string(30109))
|
||||
else:
|
||||
for i in episodes:
|
||||
res = start_download(i)
|
||||
if res == STATUS_CODES.canceled:
|
||||
break
|
||||
|
||||
|
||||
def set_movie_title(item):
|
||||
if not item.contentTitle:
|
||||
item.contentTitle = re.sub("\[[^\]]+\]|\([^\)]+\)", "", item.fulltitle).strip()
|
||||
|
||||
if not item.contentTitle:
|
||||
item.contentTitle = re.sub("\[[^\]]+\]|\([^\)]+\)", "", item.title).strip()
|
||||
@@ -0,0 +1,242 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ------------------------------------------------------------
|
||||
# Lista de vídeos favoritos
|
||||
# ------------------------------------------------------------
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
from core import filetools
|
||||
from core import scrapertools
|
||||
from core.item import Item
|
||||
from platformcode import config, logger
|
||||
from platformcode import platformtools
|
||||
|
||||
try:
|
||||
# Fijamos la ruta a favourites.xml
|
||||
if config.is_xbmc():
|
||||
import xbmc
|
||||
|
||||
FAVOURITES_PATH = xbmc.translatePath("special://profile/favourites.xml")
|
||||
else:
|
||||
FAVOURITES_PATH = os.path.join(config.get_data_path(), "favourites.xml")
|
||||
except:
|
||||
import traceback
|
||||
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
def mainlist(item):
|
||||
logger.info()
|
||||
itemlist = []
|
||||
|
||||
for name, thumb, data in read_favourites():
|
||||
if "plugin://plugin.video.%s/?" % config.PLUGIN_NAME in data:
|
||||
url = scrapertools.find_single_match(data, 'plugin://plugin.video.%s/\?([^;]*)' % config.PLUGIN_NAME) \
|
||||
.replace(""", "")
|
||||
|
||||
item = Item().fromurl(url)
|
||||
item.title = name
|
||||
item.thumbnail = thumb
|
||||
item.isFavourite = True
|
||||
|
||||
if type(item.context) == str:
|
||||
item.context = item.context.split("|")
|
||||
elif type(item.context) != list:
|
||||
item.context = []
|
||||
|
||||
item.context.extend([{"title": config.get_localized_string(30154), # "Quitar de favoritos"
|
||||
"action": "delFavourite",
|
||||
"channel": "favorites",
|
||||
"from_title": item.title},
|
||||
{"title": "Renombrar",
|
||||
"action": "renameFavourite",
|
||||
"channel": "favorites",
|
||||
"from_title": item.title}
|
||||
])
|
||||
# logger.debug(item.tostring('\n'))
|
||||
itemlist.append(item)
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def read_favourites():
|
||||
favourites_list = []
|
||||
if filetools.exists(FAVOURITES_PATH):
|
||||
data = filetools.read(FAVOURITES_PATH)
|
||||
|
||||
matches = scrapertools.find_multiple_matches(data, "<favourite([^<]*)</favourite>")
|
||||
for match in matches:
|
||||
name = scrapertools.find_single_match(match, 'name="([^"]*)')
|
||||
thumb = scrapertools.find_single_match(match, 'thumb="([^"]*)')
|
||||
data = scrapertools.find_single_match(match, '[^>]*>([^<]*)')
|
||||
favourites_list.append((name, thumb, data))
|
||||
|
||||
return favourites_list
|
||||
|
||||
|
||||
def save_favourites(favourites_list):
|
||||
raw = '<favourites>' + chr(10)
|
||||
for name, thumb, data in favourites_list:
|
||||
raw += ' <favourite name="%s" thumb="%s">%s</favourite>' % (name, thumb, data) + chr(10)
|
||||
raw += '</favourites>' + chr(10)
|
||||
|
||||
return filetools.write(FAVOURITES_PATH, raw)
|
||||
|
||||
|
||||
def addFavourite(item):
|
||||
logger.info()
|
||||
# logger.debug(item.tostring('\n'))
|
||||
|
||||
# Si se llega aqui mediante el menu contextual, hay que recuperar los parametros action y channel
|
||||
if item.from_action:
|
||||
item.__dict__["action"] = item.__dict__.pop("from_action")
|
||||
if item.from_channel:
|
||||
item.__dict__["channel"] = item.__dict__.pop("from_channel")
|
||||
|
||||
favourites_list = read_favourites()
|
||||
data = "ActivateWindow(10025,"plugin://plugin.video.%s/?" % config.PLUGIN_NAME + item.tourl() + "",return)"
|
||||
titulo = item.title.replace('"', "'")
|
||||
favourites_list.append((titulo, item.thumbnail, data))
|
||||
|
||||
if save_favourites(favourites_list):
|
||||
platformtools.dialog_ok(config.get_localized_string(30102), titulo,
|
||||
config.get_localized_string(30108)) # 'se ha añadido a favoritos'
|
||||
|
||||
|
||||
def delFavourite(item):
|
||||
logger.info()
|
||||
# logger.debug(item.tostring('\n'))
|
||||
|
||||
if item.from_title:
|
||||
item.title = item.from_title
|
||||
|
||||
favourites_list = read_favourites()
|
||||
for fav in favourites_list[:]:
|
||||
if fav[0] == item.title:
|
||||
favourites_list.remove(fav)
|
||||
|
||||
if save_favourites(favourites_list):
|
||||
platformtools.dialog_ok(config.get_localized_string(30102), item.title,
|
||||
config.get_localized_string(30105).lower()) # 'Se ha quitado de favoritos'
|
||||
platformtools.itemlist_refresh()
|
||||
break
|
||||
|
||||
|
||||
def renameFavourite(item):
|
||||
logger.info()
|
||||
# logger.debug(item.tostring('\n'))
|
||||
|
||||
# Buscar el item q queremos renombrar en favourites.xml
|
||||
favourites_list = read_favourites()
|
||||
for i, fav in enumerate(favourites_list):
|
||||
if fav[0] == item.from_title:
|
||||
# abrir el teclado
|
||||
new_title = platformtools.dialog_input(item.from_title, item.title)
|
||||
if new_title:
|
||||
favourites_list[i] = (new_title, fav[1], fav[2])
|
||||
if save_favourites(favourites_list):
|
||||
platformtools.dialog_ok(config.get_localized_string(30102), item.from_title,
|
||||
"se ha renombrado como:", new_title) # 'Se ha quitado de favoritos'
|
||||
platformtools.itemlist_refresh()
|
||||
|
||||
|
||||
##################################################
|
||||
# Funciones para migrar favoritos antiguos (.txt)
|
||||
def readbookmark(filepath):
|
||||
logger.info()
|
||||
import urllib
|
||||
|
||||
bookmarkfile = filetools.file_open(filepath)
|
||||
|
||||
lines = bookmarkfile.readlines()
|
||||
|
||||
try:
|
||||
titulo = urllib.unquote_plus(lines[0].strip())
|
||||
except:
|
||||
titulo = lines[0].strip()
|
||||
|
||||
try:
|
||||
url = urllib.unquote_plus(lines[1].strip())
|
||||
except:
|
||||
url = lines[1].strip()
|
||||
|
||||
try:
|
||||
thumbnail = urllib.unquote_plus(lines[2].strip())
|
||||
except:
|
||||
thumbnail = lines[2].strip()
|
||||
|
||||
try:
|
||||
server = urllib.unquote_plus(lines[3].strip())
|
||||
except:
|
||||
server = lines[3].strip()
|
||||
|
||||
try:
|
||||
plot = urllib.unquote_plus(lines[4].strip())
|
||||
except:
|
||||
plot = lines[4].strip()
|
||||
|
||||
# Campos fulltitle y canal añadidos
|
||||
if len(lines) >= 6:
|
||||
try:
|
||||
fulltitle = urllib.unquote_plus(lines[5].strip())
|
||||
except:
|
||||
fulltitle = lines[5].strip()
|
||||
else:
|
||||
fulltitle = titulo
|
||||
|
||||
if len(lines) >= 7:
|
||||
try:
|
||||
canal = urllib.unquote_plus(lines[6].strip())
|
||||
except:
|
||||
canal = lines[6].strip()
|
||||
else:
|
||||
canal = ""
|
||||
|
||||
bookmarkfile.close()
|
||||
|
||||
return canal, titulo, thumbnail, plot, server, url, fulltitle
|
||||
|
||||
|
||||
def check_bookmark(readpath):
|
||||
# Crea un listado con las entradas de favoritos
|
||||
itemlist = []
|
||||
|
||||
if readpath.startswith("special://") and config.is_xbmc():
|
||||
import xbmc
|
||||
readpath = xbmc.translatePath(readpath)
|
||||
|
||||
for fichero in sorted(filetools.listdir(readpath)):
|
||||
# Ficheros antiguos (".txt")
|
||||
if fichero.endswith(".txt"):
|
||||
# Esperamos 0.1 segundos entre ficheros, para que no se solapen los nombres de archivo
|
||||
time.sleep(0.1)
|
||||
|
||||
# Obtenemos el item desde el .txt
|
||||
canal, titulo, thumbnail, plot, server, url, fulltitle = readbookmark(filetools.join(readpath, fichero))
|
||||
if canal == "":
|
||||
canal = "favorites"
|
||||
item = Item(channel=canal, action="play", url=url, server=server, title=fulltitle, thumbnail=thumbnail,
|
||||
plot=plot, fanart=thumbnail, fulltitle=fulltitle, folder=False)
|
||||
|
||||
filetools.rename(filetools.join(readpath, fichero), fichero[:-4] + ".old")
|
||||
itemlist.append(item)
|
||||
|
||||
# Si hay Favoritos q guardar
|
||||
if itemlist:
|
||||
favourites_list = read_favourites()
|
||||
for item in itemlist:
|
||||
data = "ActivateWindow(10025,"plugin://plugin.video.kod/?" + item.tourl() + "",return)"
|
||||
favourites_list.append((item.title, item.thumbnail, data))
|
||||
if save_favourites(favourites_list):
|
||||
logger.debug("Conversion de txt a xml correcta")
|
||||
|
||||
|
||||
# Esto solo funcionara al migrar de versiones anteriores, ya no existe "bookmarkpath"
|
||||
try:
|
||||
if config.get_setting("bookmarkpath") != "":
|
||||
check_bookmark(config.get_setting("bookmarkpath"))
|
||||
else:
|
||||
logger.info("No existe la ruta a los favoritos de versiones antiguas")
|
||||
except:
|
||||
pass
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": "filmontv",
|
||||
"name": "Film in tv",
|
||||
"language": ["ita"],
|
||||
"active": false,
|
||||
"adult": false,
|
||||
"thumbnail": null,
|
||||
"banner": null,
|
||||
"categories": [],
|
||||
"settings": [],
|
||||
"channel": false
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ------------------------------------------------------------
|
||||
# Canale film in tv
|
||||
# Ringraziamo Icarus crew
|
||||
# ------------------------------------------------------------
|
||||
|
||||
import re
|
||||
import urllib
|
||||
|
||||
from core import httptools, scrapertools, tmdb, support
|
||||
from core.item import Item
|
||||
from platformcode import logger
|
||||
|
||||
host = "https://www.comingsoon.it"
|
||||
|
||||
TIMEOUT_TOTAL = 60
|
||||
|
||||
|
||||
def mainlist(item):
|
||||
logger.info(" mainlist")
|
||||
itemlist = [Item(channel=item.channel,
|
||||
title=support.typo("IN ONDA ADESSO bold"),
|
||||
action="tvoggi",
|
||||
url="%s/filmtv/" % host,
|
||||
thumbnail=item.thumbnail),
|
||||
Item(channel=item.channel,
|
||||
title="Mattina",
|
||||
action="tvoggi",
|
||||
url="%s/filmtv/oggi/mattina/" % host,
|
||||
thumbnail=item.thumbnail),
|
||||
Item(channel=item.channel,
|
||||
title="Pomeriggio",
|
||||
action="tvoggi",
|
||||
url="%s/filmtv/oggi/pomeriggio/" % host,
|
||||
thumbnail=item.thumbnail),
|
||||
Item(channel=item.channel,
|
||||
title="Sera",
|
||||
action="tvoggi",
|
||||
url="%s/filmtv/oggi/sera/" % host,
|
||||
thumbnail=item.thumbnail),
|
||||
Item(channel=item.channel,
|
||||
title="Notte",
|
||||
action="tvoggi",
|
||||
url="%s/filmtv/oggi/notte/" % host,
|
||||
thumbnail=item.thumbnail)]
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def tvoggi(item):
|
||||
logger.info("filmontv tvoggi")
|
||||
itemlist = []
|
||||
|
||||
# Carica la pagina
|
||||
data = httptools.downloadpage(item.url).data
|
||||
|
||||
# Estrae i contenuti
|
||||
patron = r'<div class="col-xs-5 box-immagine">[^<]+<img src="([^"]+)[^<]+<[^<]+<[^<]+<[^<]+<[^<]+<.*?titolo">(.*?)<[^<]+<[^<]+<[^<]+<[^>]+><br />(.*?)<[^<]+</div>[^<]+<[^<]+<[^<]+<[^>]+>[^<]+<[^<]+<[^<]+<[^>]+><[^<]+<[^>]+>:\s*([^<]+)[^<]+<[^<]+[^<]+<[^<]+[^<]+<[^<]+[^<]+[^>]+>:\s*([^<]+)'
|
||||
# patron = r'<div class="col-xs-5 box-immagine">[^<]+<img src="([^"]+)[^<]+<[^<]+<[^<]+<[^<]+<[^<]+<.*?titolo">(.*?)<[^<]+<[^<]+<[^<]+<[^>]+><br />(.*?)<[^<]+</div>'
|
||||
matches = re.compile(patron, re.DOTALL).findall(data)
|
||||
|
||||
for scrapedthumbnail, scrapedtitle, scrapedtv, scrapedgender, scrapedyear in matches:
|
||||
# for scrapedthumbnail, scrapedtitle, scrapedtv in matches:
|
||||
scrapedurl = ""
|
||||
scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle).strip()
|
||||
infoLabels = {}
|
||||
infoLabels["year"] = scrapedyear
|
||||
itemlist.append(
|
||||
Item(channel=item.channel,
|
||||
action="do_search",
|
||||
extra=urllib.quote_plus(scrapedtitle) + '{}' + 'movie',
|
||||
title=scrapedtitle + "[COLOR yellow] " + scrapedtv + "[/COLOR]",
|
||||
fulltitle=scrapedtitle,
|
||||
url=scrapedurl,
|
||||
thumbnail=scrapedthumbnail,
|
||||
contentTitle=scrapedtitle,
|
||||
contentType='movie',
|
||||
infoLabels=infoLabels,
|
||||
folder=True))
|
||||
|
||||
tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True)
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def do_search(item):
|
||||
from specials import search
|
||||
return search.do_search(item)
|
||||
@@ -0,0 +1,632 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ------------------------------------------------------------
|
||||
# filtertools - se encarga de filtrar resultados
|
||||
# ------------------------------------------------------------
|
||||
|
||||
from core import jsontools
|
||||
from core.item import Item
|
||||
from platformcode import config, logger
|
||||
from platformcode import platformtools
|
||||
from core import channeltools
|
||||
|
||||
TAG_TVSHOW_FILTER = "TVSHOW_FILTER"
|
||||
TAG_NAME = "name"
|
||||
TAG_ACTIVE = "active"
|
||||
TAG_LANGUAGE = "language"
|
||||
TAG_QUALITY_ALLOWED = "quality_allowed"
|
||||
|
||||
COLOR = {"parent_item": "yellow", "error": "red", "striped_even_active": "blue",
|
||||
"striped_even_inactive": "0xff00bfff", "striped_odd_active": "0xff008000",
|
||||
"striped_odd_inactive": "0xff00fa9a", "selected": "blue"
|
||||
}
|
||||
|
||||
filter_global = None
|
||||
|
||||
__channel__ = "filtertools"
|
||||
|
||||
|
||||
# TODO echar un ojo a https://pyformat.info/, se puede formatear el estilo y hacer referencias directamente a elementos
|
||||
|
||||
|
||||
class ResultFilter:
|
||||
def __init__(self, dict_filter):
|
||||
self.active = dict_filter[TAG_ACTIVE]
|
||||
self.language = dict_filter[TAG_LANGUAGE]
|
||||
self.quality_allowed = dict_filter[TAG_QUALITY_ALLOWED]
|
||||
|
||||
def __str__(self):
|
||||
return "{active: '%s', language: '%s', quality_allowed: '%s'}" % \
|
||||
(self.active, self.language, self.quality_allowed)
|
||||
|
||||
|
||||
class Filter:
|
||||
def __init__(self, item, global_filter_lang_id):
|
||||
self.result = None
|
||||
self.__get_data(item, global_filter_lang_id)
|
||||
|
||||
def __get_data(self, item, global_filter_lang_id):
|
||||
|
||||
dict_filtered_shows = jsontools.get_node_from_file(item.channel, TAG_TVSHOW_FILTER)
|
||||
tvshow = item.show.lower().strip()
|
||||
|
||||
global_filter_language = config.get_setting(global_filter_lang_id, item.channel)
|
||||
|
||||
if tvshow in dict_filtered_shows.keys():
|
||||
|
||||
self.result = ResultFilter({TAG_ACTIVE: dict_filtered_shows[tvshow][TAG_ACTIVE],
|
||||
TAG_LANGUAGE: dict_filtered_shows[tvshow][TAG_LANGUAGE],
|
||||
TAG_QUALITY_ALLOWED: dict_filtered_shows[tvshow][TAG_QUALITY_ALLOWED]})
|
||||
|
||||
# opcion general "no filtrar"
|
||||
elif global_filter_language != 0:
|
||||
from core import channeltools
|
||||
list_controls, dict_settings = channeltools.get_channel_controls_settings(item.channel)
|
||||
|
||||
for control in list_controls:
|
||||
if control["id"] == global_filter_lang_id:
|
||||
|
||||
try:
|
||||
language = control["lvalues"][global_filter_language]
|
||||
# logger.debug("language %s" % language)
|
||||
except:
|
||||
logger.error("No se ha encontrado el valor asociado al codigo '%s': %s" %
|
||||
(global_filter_lang_id, global_filter_language))
|
||||
break
|
||||
|
||||
self.result = ResultFilter({TAG_ACTIVE: True, TAG_LANGUAGE: language, TAG_QUALITY_ALLOWED: []})
|
||||
break
|
||||
|
||||
def __str__(self):
|
||||
return "{'%s'}" % self.result
|
||||
|
||||
|
||||
def access():
|
||||
"""
|
||||
Devuelve si se puede usar o no filtertools
|
||||
"""
|
||||
allow = False
|
||||
|
||||
if config.is_xbmc() or config.get_platform() == "mediaserver":
|
||||
allow = True
|
||||
|
||||
return allow
|
||||
|
||||
|
||||
def context(item, list_language=None, list_quality=None, exist=False):
|
||||
"""
|
||||
Para xbmc/kodi y mediaserver ya que pueden mostrar el menú contextual, se añade un menu para configuración
|
||||
la opción de filtro, sólo si es para series.
|
||||
Dependiendo del lugar y si existe filtro se añadirán más opciones a mostrar.
|
||||
El contexto -solo se muestra para series-.
|
||||
|
||||
@param item: elemento para obtener la información y ver que contexto añadir
|
||||
@type item: item
|
||||
param list_language: listado de idiomas posibles
|
||||
@type list_language: list[str]
|
||||
@param list_quality: listado de calidades posibles
|
||||
@type list_quality: list[str]
|
||||
@param exist: si existe el filtro
|
||||
@type exist: bool
|
||||
@return: lista de opciones a mostrar en el menú contextual
|
||||
@rtype: list
|
||||
"""
|
||||
|
||||
# Dependiendo de como sea el contexto lo guardamos y añadimos las opciones de filtertools.
|
||||
if type(item.context) == str:
|
||||
_context = item.context.split("|")
|
||||
elif type(item.context) == list:
|
||||
_context = item.context
|
||||
else:
|
||||
_context = []
|
||||
|
||||
if access():
|
||||
dict_data = {"title": config.get_localized_string(60426), "action": "config_item", "channel": "filtertools"}
|
||||
if list_language:
|
||||
dict_data["list_language"] = list_language
|
||||
if list_quality:
|
||||
dict_data["list_quality"] = list_quality
|
||||
|
||||
added = False
|
||||
if type(_context) == list:
|
||||
for x in _context:
|
||||
if x and type(x) == dict:
|
||||
if x["channel"] == "filtertools":
|
||||
added = True
|
||||
break
|
||||
|
||||
if not added:
|
||||
_context.append(dict_data)
|
||||
|
||||
if item.action == "play":
|
||||
if not exist:
|
||||
_context.append({"title": config.get_localized_string(60427) % item.language, "action": "save_from_context",
|
||||
"channel": "filtertools", "from_channel": item.channel})
|
||||
else:
|
||||
_context.append({"title": config.get_localized_string(60428) % item.language, "action": "delete_from_context",
|
||||
"channel": "filtertools", "from_channel": item.channel})
|
||||
|
||||
return _context
|
||||
|
||||
|
||||
def show_option(itemlist, channel, list_language, list_quality):
|
||||
if access():
|
||||
itemlist.append(Item(channel=__channel__, title=config.get_localized_string(60429) %
|
||||
COLOR.get("parent_item", "auto"), action="load",
|
||||
list_language=list_language,
|
||||
list_quality=list_quality, from_channel=channel))
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def load(item):
|
||||
return mainlist(channel=item.from_channel, list_language=item.list_language, list_quality=item.list_quality)
|
||||
|
||||
|
||||
def check_conditions(_filter, list_item, item, list_language, list_quality, quality_count=0, language_count=0):
|
||||
is_language_valid = True
|
||||
if _filter.language:
|
||||
# logger.debug("title es %s" % item.title)
|
||||
|
||||
# viene de episodios
|
||||
if isinstance(item.language, list):
|
||||
if _filter.language in item.language:
|
||||
language_count += 1
|
||||
else:
|
||||
is_language_valid = False
|
||||
# viene de findvideos
|
||||
else:
|
||||
if item.language.lower() == _filter.language.lower():
|
||||
language_count += 1
|
||||
else:
|
||||
is_language_valid = False
|
||||
|
||||
is_quality_valid = True
|
||||
quality = ""
|
||||
|
||||
if _filter.quality_allowed and item.quality != "":
|
||||
# if hasattr(item, 'quality'): # esta validación no hace falta por que SIEMPRE se devuelve el atributo vacío
|
||||
if item.quality.lower() in _filter.quality_allowed:
|
||||
quality = item.quality.lower()
|
||||
quality_count += 1
|
||||
else:
|
||||
is_quality_valid = False
|
||||
|
||||
if is_language_valid and is_quality_valid:
|
||||
item.list_language = list_language
|
||||
if list_quality:
|
||||
item.list_quality = list_quality
|
||||
item.context = context(item, exist=True)
|
||||
list_item.append(item)
|
||||
# logger.debug("{0} | context: {1}".format(item.title, item.context))
|
||||
# logger.debug(" -Enlace añadido")
|
||||
|
||||
logger.debug(" idioma valido?: %s, item.language: %s, filter.language: %s" %
|
||||
(is_language_valid, item.language, _filter.language))
|
||||
logger.debug(" calidad valida?: %s, item.quality: %s, filter.quality_allowed: %s"
|
||||
% (is_quality_valid, quality, _filter.quality_allowed))
|
||||
|
||||
return list_item, quality_count, language_count
|
||||
|
||||
|
||||
def get_link(list_item, item, list_language, list_quality=None, global_filter_lang_id="filter_languages"):
|
||||
"""
|
||||
Devuelve una lista de enlaces, si el item está filtrado correctamente se agrega a la lista recibida.
|
||||
|
||||
@param list_item: lista de enlaces
|
||||
@type list_item: list[Item]
|
||||
@param item: elemento a filtrar
|
||||
@type item: Item
|
||||
@param list_language: listado de idiomas posibles
|
||||
@type list_language: list[str]
|
||||
@param list_quality: listado de calidades posibles
|
||||
@type list_quality: list[str]
|
||||
@param global_filter_lang_id: id de la variable de filtrado por idioma que está en settings
|
||||
@type global_filter_lang_id: str
|
||||
@return: lista de Item
|
||||
@rtype: list[Item]
|
||||
"""
|
||||
logger.info()
|
||||
|
||||
# si los campos obligatorios son None salimos
|
||||
if list_item is None or item is None:
|
||||
return []
|
||||
|
||||
logger.debug("total de items : %s" % len(list_item))
|
||||
|
||||
global filter_global
|
||||
|
||||
if not filter_global:
|
||||
filter_global = Filter(item, global_filter_lang_id).result
|
||||
logger.debug("filter: '%s' datos: '%s'" % (item.show, filter_global))
|
||||
|
||||
if filter_global and filter_global.active:
|
||||
list_item, quality_count, language_count = \
|
||||
check_conditions(filter_global, list_item, item, list_language, list_quality)
|
||||
else:
|
||||
item.context = context(item)
|
||||
list_item.append(item)
|
||||
|
||||
return list_item
|
||||
|
||||
|
||||
def get_links(list_item, item, list_language, list_quality=None, global_filter_lang_id="filter_languages"):
|
||||
"""
|
||||
Devuelve una lista de enlaces filtrados.
|
||||
|
||||
@param list_item: lista de enlaces
|
||||
@type list_item: list[Item]
|
||||
@param item: elemento a filtrar
|
||||
@type item: item
|
||||
@param list_language: listado de idiomas posibles
|
||||
@type list_language: list[str]
|
||||
@param list_quality: listado de calidades posibles
|
||||
@type list_quality: list[str]
|
||||
@param global_filter_lang_id: id de la variable de filtrado por idioma que está en settings
|
||||
@type global_filter_lang_id: str
|
||||
@return: lista de Item
|
||||
@rtype: list[Item]
|
||||
"""
|
||||
logger.info()
|
||||
|
||||
# si los campos obligatorios son None salimos
|
||||
if list_item is None or item is None:
|
||||
return []
|
||||
|
||||
# si list_item está vacío volvemos, no se añade validación de plataforma para que Plex pueda hacer filtro global
|
||||
if len(list_item) == 0:
|
||||
return list_item
|
||||
|
||||
logger.debug("total de items : %s" % len(list_item))
|
||||
|
||||
new_itemlist = []
|
||||
quality_count = 0
|
||||
language_count = 0
|
||||
|
||||
_filter = Filter(item, global_filter_lang_id).result
|
||||
logger.debug("filter: '%s' datos: '%s'" % (item.show, _filter))
|
||||
|
||||
if _filter and _filter.active:
|
||||
|
||||
for item in list_item:
|
||||
new_itemlist, quality_count, language_count = check_conditions(_filter, new_itemlist, item, list_language,
|
||||
list_quality, quality_count, language_count)
|
||||
|
||||
logger.info("ITEMS FILTRADOS: %s/%s, idioma [%s]: %s, calidad_permitida %s: %s"
|
||||
% (len(new_itemlist), len(list_item), _filter.language, language_count, _filter.quality_allowed,
|
||||
quality_count))
|
||||
|
||||
if len(new_itemlist) == 0:
|
||||
list_item_all = []
|
||||
for i in list_item:
|
||||
list_item_all.append(i.tourl())
|
||||
|
||||
_context = [{"title": "FILTRO: Borrar '%s'" % _filter.language, "action": "delete_from_context",
|
||||
"channel": "filtertools", "to_channel": "seriesdanko"}]
|
||||
|
||||
if _filter.quality_allowed:
|
||||
msg_quality_allowed = " y calidad %s" % _filter.quality_allowed
|
||||
else:
|
||||
msg_quality_allowed = ""
|
||||
|
||||
new_itemlist.append(Item(channel=__channel__, action="no_filter", list_item_all=list_item_all,
|
||||
show=item.show,
|
||||
title="[COLOR %s]No hay elementos con idioma '%s'%s, pulsa para mostrar "
|
||||
"sin filtro[/COLOR]"
|
||||
% (COLOR.get("error", "auto"), _filter.language, msg_quality_allowed),
|
||||
context=_context))
|
||||
|
||||
else:
|
||||
for item in list_item:
|
||||
item.list_language = list_language
|
||||
if list_quality:
|
||||
item.list_quality = list_quality
|
||||
item.context = context(item)
|
||||
new_itemlist = list_item
|
||||
|
||||
return new_itemlist
|
||||
|
||||
|
||||
def no_filter(item):
|
||||
"""
|
||||
Muestra los enlaces sin filtrar
|
||||
|
||||
@param item: item
|
||||
@type item: Item
|
||||
@return: lista de enlaces
|
||||
@rtype: list[Item]
|
||||
"""
|
||||
logger.info()
|
||||
|
||||
itemlist = []
|
||||
for i in item.list_item_all:
|
||||
itemlist.append(Item().fromurl(i))
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def mainlist(channel, list_language, list_quality):
|
||||
"""
|
||||
Muestra una lista de las series filtradas
|
||||
|
||||
@param channel: nombre del canal para obtener las series filtradas
|
||||
@type channel: str
|
||||
@param list_language: lista de idiomas del canal
|
||||
@type list_language: list[str]
|
||||
@param list_quality: lista de calidades del canal
|
||||
@type list_quality: list[str]
|
||||
@return: lista de Item
|
||||
@rtype: list[Item]
|
||||
"""
|
||||
logger.info()
|
||||
itemlist = []
|
||||
dict_series = jsontools.get_node_from_file(channel, TAG_TVSHOW_FILTER)
|
||||
|
||||
idx = 0
|
||||
for tvshow in sorted(dict_series):
|
||||
|
||||
if idx % 2 == 0:
|
||||
if dict_series[tvshow][TAG_ACTIVE]:
|
||||
tag_color = COLOR.get("striped_even_active", "auto")
|
||||
else:
|
||||
tag_color = COLOR.get("striped_even_inactive", "auto")
|
||||
else:
|
||||
if dict_series[tvshow][TAG_ACTIVE]:
|
||||
tag_color = COLOR.get("striped_odd_active", "auto")
|
||||
else:
|
||||
tag_color = COLOR.get("striped_odd_inactive", "auto")
|
||||
|
||||
idx += 1
|
||||
name = dict_series.get(tvshow, {}).get(TAG_NAME, tvshow)
|
||||
activo = config.get_localized_string(60433)
|
||||
if dict_series[tvshow][TAG_ACTIVE]:
|
||||
activo = ""
|
||||
title = config.get_localized_string(60434) % (tag_color, name, activo)
|
||||
|
||||
itemlist.append(Item(channel=__channel__, action="config_item", title=title, show=name,
|
||||
list_language=list_language, list_quality=list_quality, from_channel=channel))
|
||||
|
||||
if len(itemlist) == 0:
|
||||
itemlist.append(Item(channel=channel, action="mainlist", title=config.get_localized_string(60435)))
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def config_item(item):
|
||||
"""
|
||||
muestra una serie filtrada para su configuración
|
||||
|
||||
@param item: item
|
||||
@type item: Item
|
||||
"""
|
||||
logger.info()
|
||||
logger.info("item %s" % item.tostring())
|
||||
|
||||
# OBTENEMOS LOS DATOS DEL JSON
|
||||
dict_series = jsontools.get_node_from_file(item.from_channel, TAG_TVSHOW_FILTER)
|
||||
|
||||
tvshow = item.show.lower().strip()
|
||||
default_lang = ''
|
||||
|
||||
channel_parameters = channeltools.get_channel_parameters(item.from_channel)
|
||||
list_language = channel_parameters["filter_languages"]
|
||||
try:
|
||||
if channel_parameters["filter_languages"] != '' and len(list_language) > 0:
|
||||
default_lang = list_language[1]
|
||||
except:
|
||||
pass
|
||||
|
||||
if default_lang == '':
|
||||
platformtools.dialog_notification("FilterTools", "No hay idiomas definidos")
|
||||
return
|
||||
else:
|
||||
lang_selected = dict_series.get(tvshow, {}).get(TAG_LANGUAGE, default_lang)
|
||||
list_quality = dict_series.get(tvshow, {}).get(TAG_QUALITY_ALLOWED, [x.lower() for x in item.list_quality])
|
||||
# logger.info("lang selected {}".format(lang_selected))
|
||||
# logger.info("list quality {}".format(list_quality))
|
||||
|
||||
active = True
|
||||
custom_button = {'visible': False}
|
||||
allow_option = False
|
||||
if item.show.lower().strip() in dict_series:
|
||||
allow_option = True
|
||||
active = dict_series.get(item.show.lower().strip(), {}).get(TAG_ACTIVE, False)
|
||||
custom_button = {'label': 'Borrar', 'function': 'delete', 'visible': True, 'close': True}
|
||||
|
||||
list_controls = []
|
||||
|
||||
if allow_option:
|
||||
active_control = {
|
||||
"id": "active",
|
||||
"type": "bool",
|
||||
"label": "¿Activar/Desactivar filtro?",
|
||||
"color": "",
|
||||
"default": active,
|
||||
"enabled": allow_option,
|
||||
"visible": allow_option,
|
||||
}
|
||||
list_controls.append(active_control)
|
||||
|
||||
language_option = {
|
||||
"id": "language",
|
||||
"type": "list",
|
||||
"label": "Idioma",
|
||||
"color": "0xFFee66CC",
|
||||
"default": item.list_language.index(lang_selected),
|
||||
"enabled": True,
|
||||
"visible": True,
|
||||
"lvalues": item.list_language
|
||||
}
|
||||
list_controls.append(language_option)
|
||||
|
||||
if item.list_quality:
|
||||
list_controls_calidad = [
|
||||
{
|
||||
"id": "textoCalidad",
|
||||
"type": "label",
|
||||
"label": "Calidad permitida",
|
||||
"color": "0xffC6C384",
|
||||
"enabled": True,
|
||||
"visible": True,
|
||||
},
|
||||
]
|
||||
for element in sorted(item.list_quality, key=str.lower):
|
||||
list_controls_calidad.append({
|
||||
"id": element,
|
||||
"type": "bool",
|
||||
"label": element,
|
||||
"default": (False, True)[element.lower() in list_quality],
|
||||
"enabled": True,
|
||||
"visible": True,
|
||||
})
|
||||
|
||||
# concatenamos list_controls con list_controls_calidad
|
||||
list_controls.extend(list_controls_calidad)
|
||||
|
||||
title = "Filtrado de enlaces para: [COLOR %s]%s[/COLOR]" % (COLOR.get("selected", "auto"), item.show)
|
||||
|
||||
platformtools.show_channel_settings(list_controls=list_controls, callback='save', item=item,
|
||||
caption=title, custom_button=custom_button)
|
||||
|
||||
|
||||
def delete(item, dict_values):
|
||||
logger.info()
|
||||
|
||||
if item:
|
||||
dict_series = jsontools.get_node_from_file(item.from_channel, TAG_TVSHOW_FILTER)
|
||||
tvshow = item.show.strip().lower()
|
||||
|
||||
heading = "¿Está seguro que desea eliminar el filtro?"
|
||||
line1 = "Pulse 'Si' para eliminar el filtro de [COLOR %s]%s[/COLOR], pulse 'No' o cierre la ventana para " \
|
||||
"no hacer nada." % (COLOR.get("selected", "auto"), item.show.strip())
|
||||
|
||||
if platformtools.dialog_yesno(heading, line1) == 1:
|
||||
lang_selected = dict_series.get(tvshow, {}).get(TAG_LANGUAGE, "")
|
||||
dict_series.pop(tvshow, None)
|
||||
|
||||
result, json_data = jsontools.update_node(dict_series, item.from_channel, TAG_TVSHOW_FILTER)
|
||||
|
||||
sound = False
|
||||
if result:
|
||||
message = "FILTRO ELIMINADO"
|
||||
else:
|
||||
message = "Error al guardar en disco"
|
||||
sound = True
|
||||
|
||||
heading = "%s [%s]" % (item.show.strip(), lang_selected)
|
||||
platformtools.dialog_notification(heading, message, sound=sound)
|
||||
|
||||
if item.action in ["findvideos", "play"]:
|
||||
platformtools.itemlist_refresh()
|
||||
|
||||
|
||||
def save(item, dict_data_saved):
|
||||
"""
|
||||
Guarda los valores configurados en la ventana
|
||||
|
||||
@param item: item
|
||||
@type item: Item
|
||||
@param dict_data_saved: diccionario con los datos salvados
|
||||
@type dict_data_saved: dict
|
||||
"""
|
||||
logger.info()
|
||||
|
||||
if item and dict_data_saved:
|
||||
logger.debug('item: %s\ndatos: %s' % (item.tostring(), dict_data_saved))
|
||||
|
||||
if item.from_channel == "videolibrary":
|
||||
item.from_channel = item.contentChannel
|
||||
dict_series = jsontools.get_node_from_file(item.from_channel, TAG_TVSHOW_FILTER)
|
||||
tvshow = item.show.strip().lower()
|
||||
|
||||
logger.info("Se actualiza los datos")
|
||||
|
||||
list_quality = []
|
||||
for _id, value in dict_data_saved.items():
|
||||
if _id in item.list_quality and value:
|
||||
list_quality.append(_id.lower())
|
||||
|
||||
lang_selected = item.list_language[dict_data_saved[TAG_LANGUAGE]]
|
||||
dict_filter = {TAG_NAME: item.show, TAG_ACTIVE: dict_data_saved.get(TAG_ACTIVE, True),
|
||||
TAG_LANGUAGE: lang_selected, TAG_QUALITY_ALLOWED: list_quality}
|
||||
dict_series[tvshow] = dict_filter
|
||||
|
||||
result, json_data = jsontools.update_node(dict_series, item.from_channel, TAG_TVSHOW_FILTER)
|
||||
|
||||
sound = False
|
||||
if result:
|
||||
message = "FILTRO GUARDADO"
|
||||
else:
|
||||
message = "Error al guardar en disco"
|
||||
sound = True
|
||||
|
||||
heading = "%s [%s]" % (item.show.strip(), lang_selected)
|
||||
platformtools.dialog_notification(heading, message, sound=sound)
|
||||
|
||||
if item.from_action in ["findvideos", "play"]:
|
||||
platformtools.itemlist_refresh()
|
||||
|
||||
|
||||
def save_from_context(item):
|
||||
"""
|
||||
Salva el filtro a través del menú contextual
|
||||
|
||||
@param item: item
|
||||
@type item: item
|
||||
"""
|
||||
logger.info()
|
||||
|
||||
dict_series = jsontools.get_node_from_file(item.from_channel, TAG_TVSHOW_FILTER)
|
||||
tvshow = item.show.strip().lower()
|
||||
|
||||
dict_filter = {TAG_NAME: item.show, TAG_ACTIVE: True, TAG_LANGUAGE: item.language, TAG_QUALITY_ALLOWED: []}
|
||||
dict_series[tvshow] = dict_filter
|
||||
|
||||
result, json_data = jsontools.update_node(dict_series, item.from_channel, TAG_TVSHOW_FILTER)
|
||||
|
||||
sound = False
|
||||
if result:
|
||||
message = "FILTRO GUARDADO"
|
||||
else:
|
||||
message = "Error al guardar en disco"
|
||||
sound = True
|
||||
|
||||
heading = "%s [%s]" % (item.show.strip(), item.language)
|
||||
platformtools.dialog_notification(heading, message, sound=sound)
|
||||
|
||||
if item.from_action in ["findvideos", "play"]:
|
||||
platformtools.itemlist_refresh()
|
||||
|
||||
|
||||
def delete_from_context(item):
|
||||
"""
|
||||
Elimina el filtro a través del menú contextual
|
||||
|
||||
@param item: item
|
||||
@type item: item
|
||||
"""
|
||||
logger.info()
|
||||
|
||||
# venimos desde get_links y no se ha obtenido ningún resultado, en menu contextual y damos a borrar
|
||||
if item.to_channel != "":
|
||||
item.from_channel = item.to_channel
|
||||
|
||||
dict_series = jsontools.get_node_from_file(item.from_channel, TAG_TVSHOW_FILTER)
|
||||
tvshow = item.show.strip().lower()
|
||||
|
||||
lang_selected = dict_series.get(tvshow, {}).get(TAG_LANGUAGE, "")
|
||||
dict_series.pop(tvshow, None)
|
||||
|
||||
result, json_data = jsontools.update_node(dict_series, item.from_channel, TAG_TVSHOW_FILTER)
|
||||
|
||||
sound = False
|
||||
if result:
|
||||
message = "FILTRO ELIMINADO"
|
||||
else:
|
||||
message = "Error al guardar en disco"
|
||||
sound = True
|
||||
|
||||
heading = "%s [%s]" % (item.show.strip(), lang_selected)
|
||||
platformtools.dialog_notification(heading, message, sound=sound)
|
||||
|
||||
if item.from_action in ["findvideos", "play", "no_filter"]: # 'no_filter' es el mismo caso que L#601
|
||||
platformtools.itemlist_refresh()
|
||||
@@ -0,0 +1,921 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ------------------------------------------------------------
|
||||
# Alfa favoritos
|
||||
# ==============
|
||||
# - Lista de enlaces guardados como favoritos, solamente en Alfa, no Kodi.
|
||||
# - Los enlaces se organizan en carpetas (virtuales) que puede definir el usuario.
|
||||
# - Se utiliza un sólo fichero para guardar todas las carpetas y enlaces: alfavorites-default.json
|
||||
# - Se puede copiar alfavorites-default.json a otros dispositivos ya que la única dependencia local es el thumbnail asociado a los enlaces,
|
||||
# pero se detecta por código y se ajusta al dispositivo actual.
|
||||
# - Se pueden tener distintos ficheros de alfavoritos y alternar entre ellos, pero solamente uno de ellos es la "lista activa".
|
||||
# - Los ficheros deben estar en config.get_data_path() y empezar por alfavorites- y terminar en .json
|
||||
|
||||
# Requerimientos en otros módulos para ejecutar este canal:
|
||||
# - Añadir un enlace a este canal en channelselector.py
|
||||
# - Modificar platformtools.py para controlar el menú contextual y añadir "Guardar enlace" en set_context_commands
|
||||
# ------------------------------------------------------------
|
||||
|
||||
import os, re
|
||||
from datetime import datetime
|
||||
|
||||
from core.item import Item
|
||||
from platformcode import config, logger, platformtools
|
||||
|
||||
from core import filetools, jsontools
|
||||
|
||||
|
||||
def fechahora_actual():
|
||||
return datetime.now().strftime('%Y-%m-%d %H:%M')
|
||||
|
||||
# Helpers para listas
|
||||
# -------------------
|
||||
|
||||
PREFIJO_LISTA = 'kodfavorites-'
|
||||
|
||||
# Devuelve el nombre de la lista activa (Ej: alfavorites-default.json)
|
||||
def get_lista_activa():
|
||||
return config.get_setting('lista_activa', default = PREFIJO_LISTA + 'default.json')
|
||||
|
||||
# Extrae nombre de la lista del fichero, quitando prefijo y sufijo (Ej: alfavorites-Prueba.json => Prueba)
|
||||
def get_name_from_filename(filename):
|
||||
return filename.replace(PREFIJO_LISTA, '').replace('.json', '')
|
||||
|
||||
# Componer el fichero de lista a partir de un nombre, añadiendo prefijo y sufijo (Ej: Prueba => alfavorites-Prueba.json)
|
||||
def get_filename_from_name(name):
|
||||
return PREFIJO_LISTA + name + '.json'
|
||||
|
||||
# Apuntar en un fichero de log los códigos de los ficheros que se hayan compartido
|
||||
def save_log_lista_shared(msg):
|
||||
msg = fechahora_actual() + ': ' + msg + os.linesep
|
||||
fullfilename = os.path.join(config.get_data_path(), 'alfavorites_shared.log')
|
||||
with open(fullfilename, 'a') as f: f.write(msg); f.close()
|
||||
|
||||
# Limpiar texto para usar como nombre de fichero
|
||||
def text_clean(txt, disallowed_chars = '[^a-zA-Z0-9\-_()\[\]. ]+', blank_char = ' '):
|
||||
import unicodedata
|
||||
try:
|
||||
txt = unicode(txt, 'utf-8')
|
||||
except NameError: # unicode is a default on python 3
|
||||
pass
|
||||
txt = unicodedata.normalize('NFKD', txt).encode('ascii', 'ignore')
|
||||
txt = txt.decode('utf-8').strip()
|
||||
if blank_char != ' ': txt = txt.replace(' ', blank_char)
|
||||
txt = re.sub(disallowed_chars, '', txt)
|
||||
return str(txt)
|
||||
|
||||
|
||||
|
||||
# Clase para cargar y guardar en el fichero de Alfavoritos
|
||||
# --------------------------------------------------------
|
||||
class AlfavoritesData:
|
||||
|
||||
def __init__(self, filename = None):
|
||||
|
||||
# Si no se especifica ningún fichero se usa la lista_activa (si no la hay se crea)
|
||||
if filename == None:
|
||||
filename = get_lista_activa()
|
||||
|
||||
self.user_favorites_file = os.path.join(config.get_data_path(), filename)
|
||||
|
||||
if not os.path.exists(self.user_favorites_file):
|
||||
fichero_anterior = os.path.join(config.get_data_path(), 'user_favorites.json')
|
||||
if os.path.exists(fichero_anterior): # formato anterior, convertir (a eliminar después de algunas versiones)
|
||||
jsondata = jsontools.load(filetools.read(fichero_anterior))
|
||||
self.user_favorites = jsondata
|
||||
self.info_lista = {}
|
||||
self.save()
|
||||
filetools.remove(fichero_anterior)
|
||||
else:
|
||||
self.user_favorites = []
|
||||
else:
|
||||
jsondata = jsontools.load(filetools.read(self.user_favorites_file))
|
||||
if not 'user_favorites' in jsondata or not 'info_lista' in jsondata: # formato incorrecto
|
||||
self.user_favorites = []
|
||||
else:
|
||||
self.user_favorites = jsondata['user_favorites']
|
||||
self.info_lista = jsondata['info_lista']
|
||||
|
||||
|
||||
if len(self.user_favorites) == 0:
|
||||
self.info_lista = {}
|
||||
|
||||
# Crear algunas carpetas por defecto
|
||||
self.user_favorites.append({ 'title': config.get_localized_string(30122), 'items': [] })
|
||||
self.user_favorites.append({ 'title': config.get_localized_string(30123), 'items': [] })
|
||||
self.user_favorites.append({ 'title': config.get_localized_string(70149), 'items': [] })
|
||||
|
||||
self.save()
|
||||
|
||||
def save(self):
|
||||
if 'created' not in self.info_lista:
|
||||
self.info_lista['created'] = fechahora_actual()
|
||||
self.info_lista['updated'] = fechahora_actual()
|
||||
|
||||
jsondata = {}
|
||||
jsondata['user_favorites'] = self.user_favorites
|
||||
jsondata['info_lista'] = self.info_lista
|
||||
if not filetools.write(self.user_favorites_file, jsontools.dump(jsondata)):
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70614), os.path.basename(self.user_favorites_file))
|
||||
|
||||
|
||||
# ============================
|
||||
# Añadir desde menú contextual
|
||||
# ============================
|
||||
|
||||
def addFavourite(item):
|
||||
logger.info()
|
||||
alfav = AlfavoritesData()
|
||||
|
||||
# Si se llega aquí mediante el menú contextual, hay que recuperar los parámetros action y channel
|
||||
if item.from_action:
|
||||
item.__dict__['action'] = item.__dict__.pop('from_action')
|
||||
if item.from_channel:
|
||||
item.__dict__['channel'] = item.__dict__.pop('from_channel')
|
||||
|
||||
# Limpiar título
|
||||
item.title = re.sub(r'\[COLOR [^\]]*\]', '', item.title.replace('[/COLOR]', '')).strip()
|
||||
if item.text_color:
|
||||
item.__dict__.pop('text_color')
|
||||
|
||||
# Diálogo para escoger/crear carpeta
|
||||
i_perfil = _selecciona_perfil(alfav, config.get_localized_string(70546))
|
||||
if i_perfil == -1: return False
|
||||
|
||||
# Detectar que el mismo enlace no exista ya en la carpeta
|
||||
campos = ['channel','action','url','extra','list_type'] # si todos estos campos coinciden se considera que el enlace ya existe
|
||||
for enlace in alfav.user_favorites[i_perfil]['items']:
|
||||
it = Item().fromurl(enlace)
|
||||
repe = True
|
||||
for prop in campos:
|
||||
if prop in it.__dict__ and prop in item.__dict__ and it.__dict__[prop] != item.__dict__[prop]:
|
||||
repe = False
|
||||
break
|
||||
if repe:
|
||||
platformtools.dialog_notification(config.get_localized_string(70615), config.get_localized_string(70616))
|
||||
return False
|
||||
|
||||
# Si es una película/serie, completar información de tmdb si no se tiene activado tmdb_plus_info (para season/episodio no hace falta pq ya se habrá hecho la "segunda pasada")
|
||||
if (item.contentType == 'movie' or item.contentType == 'tvshow') and not config.get_setting('tmdb_plus_info', default=False):
|
||||
from core import tmdb
|
||||
tmdb.set_infoLabels(item, True) # obtener más datos en "segunda pasada" (actores, duración, ...)
|
||||
|
||||
# Añadir fecha en que se guarda
|
||||
item.date_added = fechahora_actual()
|
||||
|
||||
# Guardar
|
||||
alfav.user_favorites[i_perfil]['items'].append(item.tourl())
|
||||
alfav.save()
|
||||
|
||||
platformtools.dialog_notification(config.get_localized_string(70531), config.get_localized_string(70532) % alfav.user_favorites[i_perfil]['title'])
|
||||
|
||||
return True
|
||||
|
||||
|
||||
# ====================
|
||||
# NAVEGACIÓN
|
||||
# ====================
|
||||
|
||||
def mainlist(item):
|
||||
logger.info()
|
||||
alfav = AlfavoritesData()
|
||||
item.category = get_name_from_filename(os.path.basename(alfav.user_favorites_file))
|
||||
|
||||
itemlist = []
|
||||
last_i = len(alfav.user_favorites) - 1
|
||||
|
||||
for i_perfil, perfil in enumerate(alfav.user_favorites):
|
||||
context = []
|
||||
|
||||
context.append({'title': config.get_localized_string(70533), 'channel': item.channel, 'action': 'editar_perfil_titulo',
|
||||
'i_perfil': i_perfil})
|
||||
context.append({'title': config.get_localized_string(70534), 'channel': item.channel, 'action': 'eliminar_perfil',
|
||||
'i_perfil': i_perfil})
|
||||
|
||||
if i_perfil > 0:
|
||||
context.append({'title': config.get_localized_string(70535), 'channel': item.channel, 'action': 'mover_perfil',
|
||||
'i_perfil': i_perfil, 'direccion': 'top'})
|
||||
context.append({'title': config.get_localized_string(70536), 'channel': item.channel, 'action': 'mover_perfil',
|
||||
'i_perfil': i_perfil, 'direccion': 'arriba'})
|
||||
if i_perfil < last_i:
|
||||
context.append({'title': config.get_localized_string(70537), 'channel': item.channel, 'action': 'mover_perfil',
|
||||
'i_perfil': i_perfil, 'direccion': 'abajo'})
|
||||
context.append({'title': config.get_localized_string(70538), 'channel': item.channel, 'action': 'mover_perfil',
|
||||
'i_perfil': i_perfil, 'direccion': 'bottom'})
|
||||
|
||||
plot = '%d enlaces en la carpeta' % len(perfil['items'])
|
||||
itemlist.append(Item(channel=item.channel, action='mostrar_perfil', title=perfil['title'], plot=plot, i_perfil=i_perfil, context=context))
|
||||
|
||||
itemlist.append(item.clone(action='crear_perfil', title=config.get_localized_string(70542), folder=False))
|
||||
|
||||
itemlist.append(item.clone(action='mainlist_listas', title=config.get_localized_string(70603)))
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def mostrar_perfil(item):
|
||||
logger.info()
|
||||
alfav = AlfavoritesData()
|
||||
|
||||
itemlist = []
|
||||
|
||||
i_perfil = item.i_perfil
|
||||
if not alfav.user_favorites[i_perfil]: return itemlist
|
||||
last_i = len(alfav.user_favorites[i_perfil]['items']) - 1
|
||||
|
||||
ruta_runtime = config.get_runtime_path()
|
||||
|
||||
for i_enlace, enlace in enumerate(alfav.user_favorites[i_perfil]['items']):
|
||||
|
||||
it = Item().fromurl(enlace)
|
||||
it.context = [ {'title': '[COLOR blue]'+config.get_localized_string(70617)+'[/COLOR]', 'channel': item.channel, 'action': 'acciones_enlace',
|
||||
'i_enlace': i_enlace, 'i_perfil': i_perfil} ]
|
||||
|
||||
it.plot += '[CR][CR][COLOR blue]Canal:[/COLOR] ' + it.channel + ' [COLOR blue]Action:[/COLOR] ' + it.action
|
||||
if it.extra != '': it.plot += ' [COLOR blue]Extra:[/COLOR] ' + it.extra
|
||||
it.plot += '[CR][COLOR blue]Url:[/COLOR] ' + it.url if isinstance(it.url, str) else '...'
|
||||
if it.date_added != '': it.plot += '[CR][COLOR blue]Added:[/COLOR] ' + it.date_added
|
||||
|
||||
# Si no es una url, ni tiene la ruta del sistema, convertir el path ya que se habrá copiado de otro dispositivo.
|
||||
# Sería más óptimo que la conversión se hiciera con un menú de importar, pero de momento se controla en run-time.
|
||||
if it.thumbnail and '://' not in it.thumbnail and not it.thumbnail.startswith(ruta_runtime):
|
||||
ruta, fichero = filetools.split(it.thumbnail)
|
||||
if ruta == '' and fichero == it.thumbnail: # en linux el split con un path de windows no separa correctamente
|
||||
ruta, fichero = filetools.split(it.thumbnail.replace('\\','/'))
|
||||
if 'channels' in ruta and 'thumb' in ruta:
|
||||
it.thumbnail = filetools.join(ruta_runtime, 'resources', 'media', 'channels', 'thumb', fichero)
|
||||
elif 'themes' in ruta and 'default' in ruta:
|
||||
it.thumbnail = filetools.join(ruta_runtime, 'resources', 'media', 'themes', 'default', fichero)
|
||||
|
||||
itemlist.append(it)
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
# Rutinas internas compartidas
|
||||
# ----------------------------
|
||||
|
||||
# Diálogo para seleccionar/crear una carpeta. Devuelve índice de la carpeta en user_favorites (-1 si cancel)
|
||||
def _selecciona_perfil(alfav, titulo='Seleccionar carpeta', i_actual=-1):
|
||||
acciones = [(perfil['title'] if i_p != i_actual else '[I][COLOR pink]%s[/COLOR][/I]' % perfil['title']) for i_p, perfil in enumerate(alfav.user_favorites)]
|
||||
acciones.append('Crear nueva carpeta')
|
||||
|
||||
i_perfil = -1
|
||||
while i_perfil == -1: # repetir hasta seleccionar una carpeta o cancelar
|
||||
ret = platformtools.dialog_select(titulo, acciones)
|
||||
if ret == -1: return -1 # pedido cancel
|
||||
if ret < len(alfav.user_favorites):
|
||||
i_perfil = ret
|
||||
else: # crear nueva carpeta
|
||||
if _crea_perfil(alfav):
|
||||
i_perfil = len(alfav.user_favorites) - 1
|
||||
|
||||
return i_perfil
|
||||
|
||||
|
||||
# Diálogo para crear una carpeta
|
||||
def _crea_perfil(alfav):
|
||||
titulo = platformtools.dialog_input(default='', heading=config.get_localized_string(70551))
|
||||
if titulo is None or titulo == '':
|
||||
return False
|
||||
|
||||
alfav.user_favorites.append({'title': titulo, 'items': []})
|
||||
alfav.save()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
# Gestión de perfiles y enlaces
|
||||
# -----------------------------
|
||||
|
||||
def crear_perfil(item):
|
||||
logger.info()
|
||||
alfav = AlfavoritesData()
|
||||
|
||||
if not _crea_perfil(alfav): return False
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
return True
|
||||
|
||||
|
||||
def editar_perfil_titulo(item):
|
||||
logger.info()
|
||||
alfav = AlfavoritesData()
|
||||
|
||||
if not alfav.user_favorites[item.i_perfil]: return False
|
||||
|
||||
titulo = platformtools.dialog_input(default=alfav.user_favorites[item.i_perfil]['title'], heading=config.get_localized_string(70533))
|
||||
if titulo is None or titulo == '' or titulo == alfav.user_favorites[item.i_perfil]['title']:
|
||||
return False
|
||||
|
||||
alfav.user_favorites[item.i_perfil]['title'] = titulo
|
||||
alfav.save()
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
return True
|
||||
|
||||
|
||||
def eliminar_perfil(item):
|
||||
logger.info()
|
||||
alfav = AlfavoritesData()
|
||||
|
||||
if not alfav.user_favorites[item.i_perfil]: return False
|
||||
|
||||
# Pedir confirmación
|
||||
if not platformtools.dialog_yesno(config.get_localized_string(70618), config.get_localized_string(70619)): return False
|
||||
|
||||
del alfav.user_favorites[item.i_perfil]
|
||||
alfav.save()
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
return True
|
||||
|
||||
|
||||
def acciones_enlace(item):
|
||||
logger.info()
|
||||
|
||||
acciones = [config.get_localized_string(70620), config.get_localized_string(70621), config.get_localized_string(70622), config.get_localized_string(70623),
|
||||
config.get_localized_string(70624), config.get_localized_string(70548), config.get_localized_string(70625),
|
||||
config.get_localized_string(70626), config.get_localized_string(70627), config.get_localized_string(70628)]
|
||||
|
||||
ret = platformtools.dialog_select('Acción a ejecutar', acciones)
|
||||
if ret == -1:
|
||||
return False # pedido cancel
|
||||
elif ret == 0:
|
||||
return editar_enlace_titulo(item)
|
||||
elif ret == 1:
|
||||
return editar_enlace_color(item)
|
||||
elif ret == 2:
|
||||
return editar_enlace_thumbnail(item)
|
||||
elif ret == 3:
|
||||
return editar_enlace_carpeta(item)
|
||||
elif ret == 4:
|
||||
return editar_enlace_lista(item)
|
||||
elif ret == 5:
|
||||
return eliminar_enlace(item)
|
||||
elif ret == 6:
|
||||
return mover_enlace(item.clone(direccion='top'))
|
||||
elif ret == 7:
|
||||
return mover_enlace(item.clone(direccion='arriba'))
|
||||
elif ret == 8:
|
||||
return mover_enlace(item.clone(direccion='abajo'))
|
||||
elif ret == 9:
|
||||
return mover_enlace(item.clone(direccion='bottom'))
|
||||
|
||||
|
||||
def editar_enlace_titulo(item):
|
||||
logger.info()
|
||||
alfav = AlfavoritesData()
|
||||
|
||||
if not alfav.user_favorites[item.i_perfil]: return False
|
||||
if not alfav.user_favorites[item.i_perfil]['items'][item.i_enlace]: return False
|
||||
|
||||
it = Item().fromurl(alfav.user_favorites[item.i_perfil]['items'][item.i_enlace])
|
||||
|
||||
titulo = platformtools.dialog_input(default=it.title, heading='Cambiar título del enlace')
|
||||
if titulo is None or titulo == '' or titulo == it.title:
|
||||
return False
|
||||
|
||||
it.title = titulo
|
||||
|
||||
alfav.user_favorites[item.i_perfil]['items'][item.i_enlace] = it.tourl()
|
||||
alfav.save()
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
return True
|
||||
|
||||
|
||||
def editar_enlace_color(item):
|
||||
logger.info()
|
||||
alfav = AlfavoritesData()
|
||||
|
||||
if not alfav.user_favorites[item.i_perfil]: return False
|
||||
if not alfav.user_favorites[item.i_perfil]['items'][item.i_enlace]: return False
|
||||
|
||||
it = Item().fromurl(alfav.user_favorites[item.i_perfil]['items'][item.i_enlace])
|
||||
|
||||
colores = ['green','yellow','red','blue','white','orange','lime','aqua','pink','violet','purple','tomato','olive','antiquewhite','gold']
|
||||
opciones = ['[COLOR %s]%s[/COLOR]' % (col, col) for col in colores]
|
||||
|
||||
ret = platformtools.dialog_select('Seleccionar color:', opciones)
|
||||
|
||||
if ret == -1: return False # pedido cancel
|
||||
it.text_color = colores[ret]
|
||||
|
||||
alfav.user_favorites[item.i_perfil]['items'][item.i_enlace] = it.tourl()
|
||||
alfav.save()
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
return True
|
||||
|
||||
|
||||
def editar_enlace_thumbnail(item):
|
||||
logger.info()
|
||||
alfav = AlfavoritesData()
|
||||
|
||||
if not alfav.user_favorites[item.i_perfil]: return False
|
||||
if not alfav.user_favorites[item.i_perfil]['items'][item.i_enlace]: return False
|
||||
|
||||
it = Item().fromurl(alfav.user_favorites[item.i_perfil]['items'][item.i_enlace])
|
||||
|
||||
# A partir de Kodi 17 se puede usar xbmcgui.Dialog().select con thumbnails (ListItem & useDetails=True)
|
||||
is_kodi17 = (config.get_platform(True)['num_version'] >= 17.0)
|
||||
if is_kodi17:
|
||||
import xbmcgui
|
||||
|
||||
# Diálogo para escoger thumbnail (el del canal o iconos predefinidos)
|
||||
opciones = []
|
||||
ids = []
|
||||
try:
|
||||
from core import channeltools
|
||||
channel_parameters = channeltools.get_channel_parameters(it.channel)
|
||||
if channel_parameters['thumbnail'] != '':
|
||||
nombre = 'Canal %s' % it.channel
|
||||
if is_kodi17:
|
||||
it_thumb = xbmcgui.ListItem(nombre)
|
||||
it_thumb.setArt({ 'thumb': channel_parameters['thumbnail'] })
|
||||
opciones.append(it_thumb)
|
||||
else:
|
||||
opciones.append(nombre)
|
||||
ids.append(channel_parameters['thumbnail'])
|
||||
except:
|
||||
pass
|
||||
|
||||
resource_path = os.path.join(config.get_runtime_path(), 'resources', 'media', 'themes', 'default')
|
||||
for f in sorted(os.listdir(resource_path)):
|
||||
if f.startswith('thumb_') and not f.startswith('thumb_intervenido') and f != 'thumb_back.png':
|
||||
nombre = f.replace('thumb_', '').replace('_', ' ').replace('.png', '')
|
||||
if is_kodi17:
|
||||
it_thumb = xbmcgui.ListItem(nombre)
|
||||
it_thumb.setArt({ 'thumb': os.path.join(resource_path, f) })
|
||||
opciones.append(it_thumb)
|
||||
else:
|
||||
opciones.append(nombre)
|
||||
ids.append(os.path.join(resource_path, f))
|
||||
|
||||
if is_kodi17:
|
||||
ret = xbmcgui.Dialog().select('Seleccionar thumbnail:', opciones, useDetails=True)
|
||||
else:
|
||||
ret = platformtools.dialog_select('Seleccionar thumbnail:', opciones)
|
||||
|
||||
if ret == -1: return False # pedido cancel
|
||||
|
||||
it.thumbnail = ids[ret]
|
||||
|
||||
alfav.user_favorites[item.i_perfil]['items'][item.i_enlace] = it.tourl()
|
||||
alfav.save()
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
return True
|
||||
|
||||
|
||||
def editar_enlace_carpeta(item):
|
||||
logger.info()
|
||||
alfav = AlfavoritesData()
|
||||
|
||||
if not alfav.user_favorites[item.i_perfil]: return False
|
||||
if not alfav.user_favorites[item.i_perfil]['items'][item.i_enlace]: return False
|
||||
|
||||
# Diálogo para escoger/crear carpeta
|
||||
i_perfil = _selecciona_perfil(alfav, 'Mover enlace a:', item.i_perfil)
|
||||
if i_perfil == -1 or i_perfil == item.i_perfil: return False
|
||||
|
||||
alfav.user_favorites[i_perfil]['items'].append(alfav.user_favorites[item.i_perfil]['items'][item.i_enlace])
|
||||
del alfav.user_favorites[item.i_perfil]['items'][item.i_enlace]
|
||||
alfav.save()
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
return True
|
||||
|
||||
|
||||
def editar_enlace_lista(item):
|
||||
logger.info()
|
||||
alfav = AlfavoritesData()
|
||||
|
||||
if not alfav.user_favorites[item.i_perfil]: return False
|
||||
if not alfav.user_favorites[item.i_perfil]['items'][item.i_enlace]: return False
|
||||
|
||||
# Diálogo para escoger lista
|
||||
opciones = []
|
||||
itemlist_listas = mainlist_listas(item)
|
||||
for it in itemlist_listas:
|
||||
if it.lista != '' and '[<---]' not in it.title: # descarta item crear y lista activa
|
||||
opciones.append(it.lista)
|
||||
|
||||
if len(opciones) == 0:
|
||||
platformtools.dialog_ok('Alfa', 'No hay otras listas dónde mover el enlace.', 'Puedes crearlas desde el menú Gestionar listas de enlaces')
|
||||
return False
|
||||
|
||||
ret = platformtools.dialog_select('Seleccionar lista destino', opciones)
|
||||
|
||||
if ret == -1:
|
||||
return False # pedido cancel
|
||||
|
||||
alfav_destino = AlfavoritesData(opciones[ret])
|
||||
|
||||
# Diálogo para escoger/crear carpeta en la lista de destino
|
||||
i_perfil = _selecciona_perfil(alfav_destino, 'Seleccionar carpeta destino', -1)
|
||||
if i_perfil == -1: return False
|
||||
|
||||
alfav_destino.user_favorites[i_perfil]['items'].append(alfav.user_favorites[item.i_perfil]['items'][item.i_enlace])
|
||||
del alfav.user_favorites[item.i_perfil]['items'][item.i_enlace]
|
||||
alfav_destino.save()
|
||||
alfav.save()
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
return True
|
||||
|
||||
|
||||
def eliminar_enlace(item):
|
||||
logger.info()
|
||||
alfav = AlfavoritesData()
|
||||
|
||||
if not alfav.user_favorites[item.i_perfil]: return False
|
||||
if not alfav.user_favorites[item.i_perfil]['items'][item.i_enlace]: return False
|
||||
|
||||
del alfav.user_favorites[item.i_perfil]['items'][item.i_enlace]
|
||||
alfav.save()
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
return True
|
||||
|
||||
|
||||
# Mover perfiles y enlaces (arriba, abajo, top, bottom)
|
||||
# ------------------------
|
||||
def mover_perfil(item):
|
||||
logger.info()
|
||||
alfav = AlfavoritesData()
|
||||
|
||||
alfav.user_favorites = _mover_item(alfav.user_favorites, item.i_perfil, item.direccion)
|
||||
alfav.save()
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
return True
|
||||
|
||||
def mover_enlace(item):
|
||||
logger.info()
|
||||
alfav = AlfavoritesData()
|
||||
|
||||
if not alfav.user_favorites[item.i_perfil]: return False
|
||||
alfav.user_favorites[item.i_perfil]['items'] = _mover_item(alfav.user_favorites[item.i_perfil]['items'], item.i_enlace, item.direccion)
|
||||
alfav.save()
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
return True
|
||||
|
||||
|
||||
# Mueve un item determinado (numérico) de una lista (arriba, abajo, top, bottom) y devuelve la lista modificada
|
||||
def _mover_item(lista, i_selected, direccion):
|
||||
last_i = len(lista) - 1
|
||||
if i_selected > last_i or i_selected < 0: return lista # índice inexistente en lista
|
||||
|
||||
if direccion == 'arriba':
|
||||
if i_selected == 0: # Ya está arriba de todo
|
||||
return lista
|
||||
lista.insert(i_selected - 1, lista.pop(i_selected))
|
||||
|
||||
elif direccion == 'abajo':
|
||||
if i_selected == last_i: # Ya está abajo de todo
|
||||
return lista
|
||||
lista.insert(i_selected + 1, lista.pop(i_selected))
|
||||
|
||||
elif direccion == 'top':
|
||||
if i_selected == 0: # Ya está arriba de todo
|
||||
return lista
|
||||
lista.insert(0, lista.pop(i_selected))
|
||||
|
||||
elif direccion == 'bottom':
|
||||
if i_selected == last_i: # Ya está abajo de todo
|
||||
return lista
|
||||
lista.insert(last_i, lista.pop(i_selected))
|
||||
|
||||
return lista
|
||||
|
||||
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
# Gestionar diferentes listas de alfavoritos
|
||||
# ------------------------------------------
|
||||
|
||||
def mainlist_listas(item):
|
||||
logger.info()
|
||||
itemlist = []
|
||||
item.category = 'Listas'
|
||||
|
||||
lista_activa = get_lista_activa()
|
||||
|
||||
import glob
|
||||
|
||||
path = os.path.join(config.get_data_path(), PREFIJO_LISTA+'*.json')
|
||||
for fichero in glob.glob(path):
|
||||
lista = os.path.basename(fichero)
|
||||
nombre = get_name_from_filename(lista)
|
||||
titulo = nombre if lista != lista_activa else '[COLOR gold]%s[/COLOR] [<---]' % nombre
|
||||
|
||||
itemlist.append(item.clone(action='acciones_lista', lista=lista, title=titulo, folder=False))
|
||||
|
||||
itemlist.append(item.clone(action='acciones_nueva_lista', title=config.get_localized_string(70642), folder=False))
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def acciones_lista(item):
|
||||
logger.info()
|
||||
|
||||
acciones = [config.get_localized_string(70604), config.get_localized_string(70629),
|
||||
config.get_localized_string(70605), config.get_localized_string(70606), config.get_localized_string(70607)]
|
||||
|
||||
ret = platformtools.dialog_select(item.lista, acciones)
|
||||
|
||||
if ret == -1:
|
||||
return False # pedido cancel
|
||||
elif ret == 0:
|
||||
return activar_lista(item)
|
||||
elif ret == 1:
|
||||
return renombrar_lista(item)
|
||||
elif ret == 2:
|
||||
return compartir_lista(item)
|
||||
elif ret == 3:
|
||||
return eliminar_lista(item)
|
||||
elif ret == 4:
|
||||
return informacion_lista(item)
|
||||
|
||||
|
||||
def activar_lista(item):
|
||||
logger.info()
|
||||
|
||||
fullfilename = os.path.join(config.get_data_path(), item.lista)
|
||||
if not os.path.exists(fullfilename):
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70630), item.lista)
|
||||
return False
|
||||
|
||||
config.set_setting('lista_activa', item.lista)
|
||||
|
||||
from channelselector import get_thumb
|
||||
item_inicio = Item(title=config.get_localized_string(70527), channel="alfavorites", action="mainlist",
|
||||
thumbnail=get_thumb("mylink.png"),
|
||||
category=config.get_localized_string(70527), viewmode="thumbnails")
|
||||
platformtools.itemlist_update(item_inicio, replace=True)
|
||||
return True
|
||||
|
||||
|
||||
def renombrar_lista(item):
|
||||
logger.info()
|
||||
|
||||
fullfilename_current = os.path.join(config.get_data_path(), item.lista)
|
||||
if not os.path.exists(fullfilename_current):
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70630), fullfilename_current)
|
||||
return False
|
||||
|
||||
nombre = get_name_from_filename(item.lista)
|
||||
titulo = platformtools.dialog_input(default=nombre, heading=config.get_localized_string(70612))
|
||||
if titulo is None or titulo == '' or titulo == nombre:
|
||||
return False
|
||||
titulo = text_clean(titulo, blank_char='_')
|
||||
|
||||
filename = get_filename_from_name(titulo)
|
||||
fullfilename = os.path.join(config.get_data_path(), filename)
|
||||
|
||||
# Comprobar que el nuevo nombre no exista
|
||||
if os.path.exists(fullfilename):
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70613), fullfilename)
|
||||
return False
|
||||
|
||||
# Rename del fichero
|
||||
if not filetools.rename(fullfilename_current, filename):
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70631), fullfilename)
|
||||
return False
|
||||
|
||||
# Update settings si es la lista activa
|
||||
if item.lista == get_lista_activa():
|
||||
config.set_setting('lista_activa', filename)
|
||||
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
return True
|
||||
|
||||
|
||||
def eliminar_lista(item):
|
||||
logger.info()
|
||||
|
||||
fullfilename = os.path.join(config.get_data_path(), item.lista)
|
||||
if not os.path.exists(fullfilename):
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70630), item.lista)
|
||||
return False
|
||||
|
||||
if item.lista == get_lista_activa():
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70632), item.lista)
|
||||
return False
|
||||
|
||||
if not platformtools.dialog_yesno(config.get_localized_string(70606), config.get_localized_string(70633) + ' %s ?' % item.lista): return False
|
||||
filetools.remove(fullfilename)
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
return True
|
||||
|
||||
|
||||
def informacion_lista(item):
|
||||
logger.info()
|
||||
|
||||
fullfilename = os.path.join(config.get_data_path(), item.lista)
|
||||
if not os.path.exists(fullfilename):
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70630), item.lista)
|
||||
return False
|
||||
|
||||
alfav = AlfavoritesData(item.lista)
|
||||
|
||||
txt = 'Lista: [COLOR gold]%s[/COLOR]' % item.lista
|
||||
txt += '[CR]' + config.get_localized_string(70634) + ' ' + alfav.info_lista['created'] + ' ' + config.get_localized_string(70635) + ' ' + alfav.info_lista['updated']
|
||||
|
||||
if 'downloaded_date' in alfav.info_lista:
|
||||
txt += '[CR]' + config.get_localized_string(70636) + ' ' + alfav.info_lista['downloaded_date'] + ' ' + alfav.info_lista['downloaded_from'] + ' ' + config.get_localized_string(70637)
|
||||
|
||||
if 'tinyupload_date' in alfav.info_lista:
|
||||
txt += '[CR]' + config.get_localized_string(70638) + ' ' + alfav.info_lista['tinyupload_date'] + ' ' + config.get_localized_string(70639) + ' [COLOR blue]' + alfav.info_lista['tinyupload_code'] + '[/COLOR]'
|
||||
|
||||
txt += '[CR]' + config.get_localized_string(70640) + ' ' + len(alfav.user_favorites)
|
||||
for perfil in alfav.user_favorites:
|
||||
txt += '[CR]- %s (%d %s)' % (perfil['title'], len(perfil['items']), config.get_localized_string(70641))
|
||||
|
||||
platformtools.dialog_textviewer(config.get_localized_string(70607), txt)
|
||||
return True
|
||||
|
||||
|
||||
def compartir_lista(item):
|
||||
logger.info()
|
||||
|
||||
fullfilename = os.path.join(config.get_data_path(), item.lista)
|
||||
if not os.path.exists(fullfilename):
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70630), fullfilename)
|
||||
return False
|
||||
|
||||
try:
|
||||
progreso = platformtools.dialog_progress_bg(config.get_localized_string(70643), config.get_localized_string(70644))
|
||||
|
||||
# Acceso a la página principal de tinyupload para obtener datos necesarios
|
||||
from core import httptools, scrapertools
|
||||
data = httptools.downloadpage('http://s000.tinyupload.com/index.php').data
|
||||
upload_url = scrapertools.find_single_match(data, 'form action="([^"]+)')
|
||||
sessionid = scrapertools.find_single_match(upload_url, 'sid=(.+)')
|
||||
|
||||
progreso.update(10, config.get_localized_string(70645), config.get_localized_string(70646))
|
||||
|
||||
# Envío del fichero a tinyupload mediante multipart/form-data
|
||||
from lib import MultipartPostHandler
|
||||
import urllib2
|
||||
opener = urllib2.build_opener(MultipartPostHandler.MultipartPostHandler)
|
||||
params = { 'MAX_FILE_SIZE' : '52428800', 'file_description' : '', 'sessionid' : sessionid, 'uploaded_file' : open(fullfilename, 'rb') }
|
||||
handle = opener.open(upload_url, params)
|
||||
data = handle.read()
|
||||
|
||||
progreso.close()
|
||||
|
||||
if not 'File was uploaded successfuly' in data:
|
||||
logger.debug(data)
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70647))
|
||||
return False
|
||||
|
||||
codigo = scrapertools.find_single_match(data, 'href="index\.php\?file_id=([^"]+)')
|
||||
|
||||
except:
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70647), item.lista)
|
||||
return False
|
||||
|
||||
# Apuntar código en fichero de log y dentro de la lista
|
||||
save_log_lista_shared(config.get_localized_string(70648) + ' ' + item.lista + ' ' + codigo + ' ' + config.get_localized_string(70649))
|
||||
|
||||
alfav = AlfavoritesData(item.lista)
|
||||
alfav.info_lista['tinyupload_date'] = fechahora_actual()
|
||||
alfav.info_lista['tinyupload_code'] = codigo
|
||||
alfav.save()
|
||||
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70650), codigo)
|
||||
return True
|
||||
|
||||
|
||||
|
||||
def acciones_nueva_lista(item):
|
||||
logger.info()
|
||||
|
||||
acciones = [config.get_localized_string(70651),
|
||||
config.get_localized_string(70652),
|
||||
config.get_localized_string(70653),
|
||||
config.get_localized_string(70654)]
|
||||
|
||||
ret = platformtools.dialog_select(config.get_localized_string(70608), acciones)
|
||||
|
||||
if ret == -1:
|
||||
return False # pedido cancel
|
||||
|
||||
elif ret == 0:
|
||||
return crear_lista(item)
|
||||
|
||||
elif ret == 1:
|
||||
codigo = platformtools.dialog_input(default='', heading=config.get_localized_string(70609)) # 05370382084539519168
|
||||
if codigo is None or codigo == '':
|
||||
return False
|
||||
return descargar_lista(item, 'http://s000.tinyupload.com/?file_id=' + codigo)
|
||||
|
||||
elif ret == 2:
|
||||
url = platformtools.dialog_input(default='https://', heading=config.get_localized_string(70610))
|
||||
if url is None or url == '':
|
||||
return False
|
||||
return descargar_lista(item, url)
|
||||
|
||||
elif ret == 3:
|
||||
txt = config.get_localized_string(70611)
|
||||
platformtools.dialog_textviewer(config.get_localized_string(70607), txt)
|
||||
return False
|
||||
|
||||
|
||||
def crear_lista(item):
|
||||
logger.info()
|
||||
|
||||
titulo = platformtools.dialog_input(default='', heading=config.get_localized_string(70612))
|
||||
if titulo is None or titulo == '':
|
||||
return False
|
||||
titulo = text_clean(titulo, blank_char='_')
|
||||
|
||||
filename = get_filename_from_name(titulo)
|
||||
fullfilename = os.path.join(config.get_data_path(), filename)
|
||||
|
||||
# Comprobar que el fichero no exista ya
|
||||
if os.path.exists(fullfilename):
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70613), fullfilename)
|
||||
return False
|
||||
|
||||
# Provocar que se guarde con las carpetas vacías por defecto
|
||||
alfav = AlfavoritesData(filename)
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
return True
|
||||
|
||||
|
||||
def descargar_lista(item, url):
|
||||
logger.info()
|
||||
from core import httptools, scrapertools
|
||||
|
||||
if 'tinyupload.com/' in url:
|
||||
try:
|
||||
from urlparse import urlparse
|
||||
data = httptools.downloadpage(url).data
|
||||
logger.debug(data)
|
||||
down_url, url_name = scrapertools.find_single_match(data, ' href="(download\.php[^"]*)"><b>([^<]*)')
|
||||
url_json = '{uri.scheme}://{uri.netloc}/'.format(uri=urlparse(url)) + down_url
|
||||
except:
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70655), url)
|
||||
return False
|
||||
|
||||
elif 'zippyshare.com/' in url:
|
||||
from core import servertools
|
||||
video_urls, puedes, motivo = servertools.resolve_video_urls_for_playing('zippyshare', url)
|
||||
|
||||
if not puedes:
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70655), motivo)
|
||||
return False
|
||||
url_json = video_urls[0][1] # https://www58.zippyshare.com/d/qPzzQ0UM/25460/alfavorites-testeanding.json
|
||||
url_name = url_json[url_json.rfind('/')+1:]
|
||||
|
||||
elif 'friendpaste.com/' in url:
|
||||
url_json = url if url.endswith('/raw') else url + '/raw'
|
||||
url_name = 'friendpaste'
|
||||
|
||||
else:
|
||||
url_json = url
|
||||
url_name = url[url.rfind('/')+1:]
|
||||
|
||||
|
||||
# Download json
|
||||
data = httptools.downloadpage(url_json).data
|
||||
|
||||
# Verificar formato json de alfavorites y añadir info de la descarga
|
||||
jsondata = jsontools.load(data)
|
||||
if 'user_favorites' not in jsondata or 'info_lista' not in jsondata:
|
||||
logger.debug(data)
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70656))
|
||||
return False
|
||||
|
||||
jsondata['info_lista']['downloaded_date'] = fechahora_actual()
|
||||
jsondata['info_lista']['downloaded_from'] = url
|
||||
data = jsontools.dump(jsondata)
|
||||
|
||||
# Pedir nombre para la lista descargada
|
||||
nombre = get_name_from_filename(url_name)
|
||||
titulo = platformtools.dialog_input(default=nombre, heading=config.get_localized_string(70657))
|
||||
if titulo is None or titulo == '':
|
||||
return False
|
||||
titulo = text_clean(titulo, blank_char='_')
|
||||
|
||||
filename = get_filename_from_name(titulo)
|
||||
fullfilename = os.path.join(config.get_data_path(), filename)
|
||||
|
||||
# Si el nuevo nombre ya existe pedir confirmación para sobrescribir
|
||||
if os.path.exists(fullfilename):
|
||||
if not platformtools.dialog_yesno('Alfa', config.get_localized_string(70613), config.get_localized_string(70658), filename):
|
||||
return False
|
||||
|
||||
if not filetools.write(fullfilename, data):
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70659), filename)
|
||||
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70660), filename)
|
||||
platformtools.itemlist_refresh()
|
||||
return True
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"id": "news",
|
||||
"name": "Novedades",
|
||||
"active": false,
|
||||
"adult": false,
|
||||
"language": ["*"],
|
||||
"categories": [
|
||||
"movie"
|
||||
],
|
||||
"settings": [
|
||||
{
|
||||
"id": "multithread",
|
||||
"type": "bool",
|
||||
"label": "@60656",
|
||||
"default": true,
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "result_mode",
|
||||
"type": "list",
|
||||
"label": "@60657",
|
||||
"default": 2,
|
||||
"enabled": true,
|
||||
"visible": true,
|
||||
"lvalues": [
|
||||
"@60658",
|
||||
"@60659",
|
||||
"@60660"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "perfil",
|
||||
"type": "list",
|
||||
"label": "@60666",
|
||||
"default": 0,
|
||||
"enabled": true,
|
||||
"visible": true,
|
||||
"lvalues": [
|
||||
"@60667",
|
||||
"@60668",
|
||||
"@60669",
|
||||
"@60670",
|
||||
"@60671"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,656 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ------------------------------------------------------------
|
||||
# Channel for recent videos on several channels
|
||||
# ------------------------------------------------------------
|
||||
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
from threading import Thread
|
||||
|
||||
from channelselector import get_thumb, auto_filter
|
||||
from core import channeltools
|
||||
from core import scrapertools
|
||||
from core.item import Item
|
||||
from platformcode import config, logger
|
||||
from platformcode import platformtools
|
||||
from core import jsontools
|
||||
|
||||
|
||||
THUMBNAILS = {'0': 'posters', '1': 'banners', '2': 'squares'}
|
||||
|
||||
__perfil__ = config.get_setting('perfil', "news")
|
||||
|
||||
# Fijar perfil de color
|
||||
perfil = [['0xFF0B7B92', '0xFF89FDFB', '0xFFACD5D4'],
|
||||
['0xFFB31313', '0xFFFF9000', '0xFFFFEE82'],
|
||||
['0xFF891180', '0xFFCB22D7', '0xFFEEA1EB'],
|
||||
['0xFFA5DEE5', '0xFFE0F9B5', '0xFFFEFDCA'],
|
||||
['0xFFF23557', '0xFF22B2DA', '0xFFF0D43A']]
|
||||
|
||||
#color1, color2, color3 = ["white", "white", "white"]
|
||||
color1, color2, color3 = perfil[__perfil__]
|
||||
|
||||
list_newest = []
|
||||
list_newest_tourl = []
|
||||
channels_id_name = {}
|
||||
|
||||
menu_cache_path = os.path.join(config.get_data_path(), "settings_channels", 'menu_cache_data.json')
|
||||
menu_settings_path = os.path.join(config.get_data_path(), "settings_channels", 'menu_settings_data.json')
|
||||
|
||||
|
||||
def mainlist(item):
|
||||
logger.info()
|
||||
|
||||
itemlist = []
|
||||
list_canales, any_active = get_channels_list()
|
||||
channel_language = config.get_setting("channel_language", default="all")
|
||||
|
||||
#if list_canales['peliculas']:
|
||||
thumbnail = get_thumb("channels_movie.png")
|
||||
new_item = Item(channel=item.channel, action="novedades", extra="peliculas", title=config.get_localized_string(30122),
|
||||
thumbnail=thumbnail)
|
||||
|
||||
set_category_context(new_item)
|
||||
itemlist.append(new_item)
|
||||
|
||||
# thumbnail = get_thumb("channels_movie_4k.png")
|
||||
# new_item = Item(channel=item.channel, action="novedades", extra="4k", title=config.get_localized_string(70208), thumbnail=thumbnail)
|
||||
#
|
||||
# set_category_context(new_item)
|
||||
# itemlist.append(new_item)
|
||||
|
||||
#if list_canales['terror']:
|
||||
# thumbnail = get_thumb("channels_horror.png")
|
||||
# new_item = Item(channel=item.channel, action="novedades", extra="terror", title=config.get_localized_string(70209),
|
||||
# thumbnail=thumbnail)
|
||||
# set_category_context(new_item)
|
||||
# itemlist.append(new_item)
|
||||
|
||||
#if list_canales['infantiles']:
|
||||
# thumbnail = get_thumb("channels_children.png")
|
||||
# new_item = Item(channel=item.channel, action="novedades", extra="infantiles", title=config.get_localized_string(60510),
|
||||
# thumbnail=thumbnail)
|
||||
# set_category_context(new_item)
|
||||
# itemlist.append(new_item)
|
||||
|
||||
#if list_canales['series']:
|
||||
thumbnail = get_thumb("channels_tvshow.png")
|
||||
new_item = Item(channel=item.channel, action="novedades", extra="series", title=config.get_localized_string(60511),
|
||||
thumbnail=thumbnail)
|
||||
set_category_context(new_item)
|
||||
itemlist.append(new_item)
|
||||
|
||||
#if list_canales['anime']:
|
||||
thumbnail = get_thumb("channels_anime.png")
|
||||
new_item = Item(channel=item.channel, action="novedades", extra="anime", title=config.get_localized_string(60512),
|
||||
thumbnail=thumbnail)
|
||||
set_category_context(new_item)
|
||||
itemlist.append(new_item)
|
||||
|
||||
if channel_language == "all" or channel_language == "esp":
|
||||
# if list_canales['Castellano']:
|
||||
thumbnail = get_thumb("channels_spanish.png")
|
||||
new_item = Item(channel=item.channel, action="novedades", extra="castellano", title=config.get_localized_string(70014),
|
||||
thumbnail=thumbnail)
|
||||
set_category_context(new_item)
|
||||
itemlist.append(new_item)
|
||||
|
||||
# if list_canales['Latino']:
|
||||
thumbnail = get_thumb("channels_latino.png")
|
||||
new_item = Item(channel=item.channel, action="novedades", extra="latino", title=config.get_localized_string(59976),
|
||||
thumbnail=thumbnail)
|
||||
set_category_context(new_item)
|
||||
itemlist.append(new_item)
|
||||
if channel_language == "all":
|
||||
# if list_canales['Italiano']:
|
||||
thumbnail = get_thumb("channels_italian.png")
|
||||
new_item = Item(channel=item.channel, action="novedades", extra="italiano", title=config.get_localized_string(70563),
|
||||
thumbnail=thumbnail)
|
||||
set_category_context(new_item)
|
||||
itemlist.append(new_item)
|
||||
|
||||
# if list_canales['Torrent']:
|
||||
# thumbnail = get_thumb("channels_torrent.png")
|
||||
# new_item = Item(channel=item.channel, action="novedades", extra="torrent", title=config.get_localized_string(70171), thumbnail=thumbnail)
|
||||
# set_category_context(new_item)
|
||||
# itemlist.append(new_item)
|
||||
|
||||
#if list_canales['documentales']:
|
||||
thumbnail = get_thumb("channels_documentary.png")
|
||||
new_item = Item(channel=item.channel, action="novedades", extra="documentales", title=config.get_localized_string(60513),
|
||||
thumbnail=thumbnail)
|
||||
set_category_context(new_item)
|
||||
itemlist.append(new_item)
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def set_category_context(item):
|
||||
item.context = [{"title": config.get_localized_string(60514) % item.title,
|
||||
"extra": item.extra,
|
||||
"action": "setting_channel",
|
||||
"channel": item.channel}]
|
||||
item.category = config.get_localized_string(60679) % item.extra
|
||||
|
||||
|
||||
def get_channels_list():
|
||||
logger.info()
|
||||
|
||||
list_canales = {'peliculas': [], '4k': [], 'terror': [], 'infantiles': [], 'series': [], 'anime': [],
|
||||
'castellano': [], 'latino':[], 'italiano':[], 'torrent':[], 'documentales': []}
|
||||
any_active = False
|
||||
# Rellenar listas de canales disponibles
|
||||
channels_path = os.path.join(config.get_runtime_path(), "channels", '*.json')
|
||||
channel_language = config.get_setting("channel_language", default="all")
|
||||
if channel_language =="auto":
|
||||
channel_language = auto_filter()
|
||||
|
||||
for infile in sorted(glob.glob(channels_path)):
|
||||
channel_id = os.path.basename(infile)[:-5]
|
||||
channel_parameters = channeltools.get_channel_parameters(channel_id)
|
||||
|
||||
# No incluir si es un canal inactivo
|
||||
if not channel_parameters["active"]:
|
||||
continue
|
||||
|
||||
# No incluir si es un canal para adultos, y el modo adulto está desactivado
|
||||
if channel_parameters["adult"] and config.get_setting("adult_mode") == 0:
|
||||
continue
|
||||
|
||||
# No incluir si el canal es en un idioma filtrado
|
||||
if channel_language != "all" and channel_language not in channel_parameters["language"] \
|
||||
and "*" not in channel_parameters["language"]:
|
||||
continue
|
||||
|
||||
# Incluir en cada categoria, si en su configuracion el canal esta activado para mostrar novedades
|
||||
|
||||
for categoria in list_canales:
|
||||
include_in_newest = config.get_setting("include_in_newest_" + categoria, channel_id)
|
||||
if include_in_newest:
|
||||
channels_id_name[channel_id] = channel_parameters["title"]
|
||||
list_canales[categoria].append((channel_id, channel_parameters["title"]))
|
||||
any_active = True
|
||||
|
||||
return list_canales, any_active
|
||||
|
||||
def set_cache(item):
|
||||
logger.info()
|
||||
item.mode = 'set_cache'
|
||||
t = Thread(target=novedades, args=[item])
|
||||
t.start()
|
||||
#t.join()
|
||||
|
||||
def get_from_cache(item):
|
||||
logger.info()
|
||||
itemlist=[]
|
||||
cache_node = jsontools.get_node_from_file('menu_cache_data.json', 'cached')
|
||||
first=item.last
|
||||
last = first+40
|
||||
#if last >=len(cache_node[item.extra]):
|
||||
# last = len(cache_node[item.extra])
|
||||
|
||||
for cached_item in cache_node[item.extra][first:last]:
|
||||
new_item= Item()
|
||||
new_item = new_item.fromurl(cached_item)
|
||||
itemlist.append(new_item)
|
||||
if item.mode == 'silent':
|
||||
set_cache(item)
|
||||
if last >= len(cache_node[item.extra]):
|
||||
item.mode='finish'
|
||||
itemlist = add_menu_items(item, itemlist)
|
||||
else:
|
||||
item.mode='get_cached'
|
||||
item.last =last
|
||||
itemlist = add_menu_items(item, itemlist)
|
||||
|
||||
return itemlist
|
||||
|
||||
def add_menu_items(item, itemlist):
|
||||
logger.info()
|
||||
|
||||
menu_icon = get_thumb('menu.png')
|
||||
menu = Item(channel="channelselector", action="getmainlist", viewmode="movie", thumbnail=menu_icon, title='Menu')
|
||||
itemlist.insert(0, menu)
|
||||
if item.mode != 'finish':
|
||||
if item.mode == 'get_cached':
|
||||
last=item.last
|
||||
else:
|
||||
last = len(itemlist)
|
||||
refresh_icon = get_thumb('more.png')
|
||||
refresh = item.clone(thumbnail=refresh_icon, mode='get_cached',title='Mas', last=last)
|
||||
itemlist.insert(len(itemlist), refresh)
|
||||
|
||||
return itemlist
|
||||
|
||||
def novedades(item):
|
||||
logger.info()
|
||||
|
||||
global list_newest
|
||||
threads = []
|
||||
list_newest = []
|
||||
start_time = time.time()
|
||||
|
||||
mode = item.mode
|
||||
if mode == '':
|
||||
mode = 'normal'
|
||||
|
||||
if mode=='get_cached':
|
||||
if os.path.exists(menu_cache_path):
|
||||
return get_from_cache(item)
|
||||
|
||||
multithread = config.get_setting("multithread", "news")
|
||||
logger.info("multithread= " + str(multithread))
|
||||
|
||||
if not multithread:
|
||||
if platformtools.dialog_yesno(config.get_localized_string(60515),
|
||||
config.get_localized_string(60516),
|
||||
config.get_localized_string(60517),
|
||||
config.get_localized_string(60518)):
|
||||
if config.set_setting("multithread", True, "news"):
|
||||
multithread = True
|
||||
|
||||
if mode == 'normal':
|
||||
progreso = platformtools.dialog_progress(item.category, config.get_localized_string(60519))
|
||||
|
||||
list_canales, any_active = get_channels_list()
|
||||
|
||||
if config.is_xbmc():
|
||||
from specials import side_menu
|
||||
if mode=='silent' and any_active and len(list_canales[item.extra]) > 0:
|
||||
side_menu.set_menu_settings(item)
|
||||
aux_list=[]
|
||||
for canal in list_canales[item.extra]:
|
||||
if len(aux_list)<2:
|
||||
aux_list.append(canal)
|
||||
list_canales[item.extra]=aux_list
|
||||
|
||||
if mode == 'set_cache':
|
||||
list_canales[item.extra] = list_canales[item.extra][2:]
|
||||
|
||||
if any_active and len(list_canales[item.extra])>0:
|
||||
import math
|
||||
# fix float porque la division se hace mal en python 2.x
|
||||
number_of_channels = float(100) / len(list_canales[item.extra])
|
||||
|
||||
for index, channel in enumerate(list_canales[item.extra]):
|
||||
channel_id, channel_title = channel
|
||||
percentage = int(math.ceil((index + 1) * number_of_channels))
|
||||
|
||||
# if progreso.iscanceled():
|
||||
# progreso.close()
|
||||
# logger.info("Búsqueda cancelada")
|
||||
# return itemlist
|
||||
|
||||
# Modo Multi Thread
|
||||
if multithread:
|
||||
t = Thread(target=get_newest, args=[channel_id, item.extra], name=channel_title)
|
||||
t.start()
|
||||
threads.append(t)
|
||||
if mode == 'normal':
|
||||
progreso.update(percentage, "", config.get_localized_string(60520) % channel_title)
|
||||
|
||||
# Modo single Thread
|
||||
else:
|
||||
if mode == 'normal':
|
||||
logger.info("Obteniendo novedades de channel_id=" + channel_id)
|
||||
progreso.update(percentage, "", config.get_localized_string(60520) % channel_title)
|
||||
get_newest(channel_id, item.extra)
|
||||
|
||||
# Modo Multi Thread: esperar q todos los hilos terminen
|
||||
if multithread:
|
||||
pendent = [a for a in threads if a.isAlive()]
|
||||
t = float(100) / len(pendent)
|
||||
while pendent:
|
||||
index = (len(threads) - len(pendent)) + 1
|
||||
percentage = int(math.ceil(index * t))
|
||||
|
||||
list_pendent_names = [a.getName() for a in pendent]
|
||||
if mode == 'normal':
|
||||
mensaje = config.get_localized_string(30994) % (", ".join(list_pendent_names))
|
||||
progreso.update(percentage, config.get_localized_string(60521) % (len(threads) - len(pendent), len(threads)),
|
||||
mensaje)
|
||||
logger.debug(mensaje)
|
||||
|
||||
if progreso.iscanceled():
|
||||
logger.info("Busqueda de novedades cancelada")
|
||||
break
|
||||
|
||||
time.sleep(0.5)
|
||||
pendent = [a for a in threads if a.isAlive()]
|
||||
if mode == 'normal':
|
||||
mensaje = config.get_localized_string(60522) % (len(list_newest), time.time() - start_time)
|
||||
progreso.update(100, mensaje, " ", " ")
|
||||
logger.info(mensaje)
|
||||
start_time = time.time()
|
||||
# logger.debug(start_time)
|
||||
|
||||
result_mode = config.get_setting("result_mode", "news")
|
||||
if mode != 'normal':
|
||||
result_mode=0
|
||||
|
||||
if result_mode == 0: # Agrupados por contenido
|
||||
ret = group_by_content(list_newest)
|
||||
elif result_mode == 1: # Agrupados por canales
|
||||
ret = group_by_channel(list_newest)
|
||||
else: # Sin agrupar
|
||||
ret = no_group(list_newest)
|
||||
|
||||
while time.time() - start_time < 2:
|
||||
# mostrar cuadro de progreso con el tiempo empleado durante almenos 2 segundos
|
||||
time.sleep(0.5)
|
||||
if mode == 'normal':
|
||||
progreso.close()
|
||||
if mode == 'silent':
|
||||
set_cache(item)
|
||||
item.mode = 'set_cache'
|
||||
ret = add_menu_items(item, ret)
|
||||
if mode != 'set_cache':
|
||||
return ret
|
||||
else:
|
||||
if mode != 'set_cache':
|
||||
no_channels = platformtools.dialog_ok(config.get_localized_string(30130) + ' - ' + item.extra, config.get_localized_string(70661), config.get_localized_string(70662))
|
||||
return
|
||||
|
||||
|
||||
def get_newest(channel_id, categoria):
|
||||
logger.info("channel_id=" + channel_id + ", categoria=" + categoria)
|
||||
|
||||
global list_newest
|
||||
global list_newest_tourl
|
||||
|
||||
# Solicitamos las novedades de la categoria (item.extra) buscada en el canal channel
|
||||
# Si no existen novedades para esa categoria en el canal devuelve una lista vacia
|
||||
try:
|
||||
|
||||
puede = True
|
||||
try:
|
||||
modulo = __import__('channels.%s' % channel_id, fromlist=["channels.%s" % channel_id])
|
||||
except:
|
||||
try:
|
||||
exec "import channels." + channel_id + " as modulo"
|
||||
except:
|
||||
puede = False
|
||||
|
||||
if not puede:
|
||||
return
|
||||
|
||||
logger.info("running channel " + modulo.__name__ + " " + modulo.__file__)
|
||||
list_result = modulo.newest(categoria)
|
||||
logger.info("canal= %s %d resultados" % (channel_id, len(list_result)))
|
||||
exist=False
|
||||
if os.path.exists(menu_cache_path):
|
||||
cache_node = jsontools.get_node_from_file('menu_cache_data.json', 'cached')
|
||||
exist=True
|
||||
else:
|
||||
cache_node = {}
|
||||
#logger.debug('cache node: %s' % cache_node)
|
||||
for item in list_result:
|
||||
# logger.info("item="+item.tostring())
|
||||
item.channel = channel_id
|
||||
list_newest.append(item)
|
||||
list_newest_tourl.append(item.tourl())
|
||||
|
||||
cache_node[categoria] = list_newest_tourl
|
||||
|
||||
jsontools.update_node(cache_node, 'menu_cache_data.json', "cached")
|
||||
|
||||
except:
|
||||
logger.error("No se pueden recuperar novedades de: " + channel_id)
|
||||
import traceback
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
def get_title(item):
|
||||
if item.contentSerieName: # Si es una serie
|
||||
title = item.contentSerieName
|
||||
if not scrapertools.get_season_and_episode(title) and item.contentEpisodeNumber:
|
||||
if not item.contentSeason:
|
||||
item.contentSeason = '1'
|
||||
title = "%s - %sx%s" % (title, item.contentSeason, str(item.contentEpisodeNumber).zfill(2))
|
||||
|
||||
elif item.contentTitle: # Si es una pelicula con el canal adaptado
|
||||
title = item.contentTitle
|
||||
elif item.fulltitle: # Si el canal no esta adaptado
|
||||
title = item.fulltitle
|
||||
else: # Como ultimo recurso
|
||||
title = item.title
|
||||
|
||||
# Limpiamos el titulo de etiquetas de formato anteriores
|
||||
title = re.compile("\[/*COLO.*?\]", re.DOTALL).sub("", title)
|
||||
title = re.compile("\[/*B\]", re.DOTALL).sub("", title)
|
||||
title = re.compile("\[/*I\]", re.DOTALL).sub("", title)
|
||||
|
||||
return title
|
||||
|
||||
|
||||
def no_group(list_result_canal):
|
||||
itemlist = []
|
||||
global channels_id_name
|
||||
|
||||
for i in list_result_canal:
|
||||
i.title = get_title(i) + " [" + channels_id_name[i.channel] + "]"
|
||||
i.text_color = color3
|
||||
|
||||
itemlist.append(i.clone())
|
||||
|
||||
return sorted(itemlist, key=lambda it: it.title.lower())
|
||||
|
||||
|
||||
def group_by_channel(list_result_canal):
|
||||
global channels_id_name
|
||||
dict_canales = {}
|
||||
itemlist = []
|
||||
|
||||
for i in list_result_canal:
|
||||
if i.channel not in dict_canales:
|
||||
dict_canales[i.channel] = []
|
||||
# Formatear titulo
|
||||
i.title = get_title(i)
|
||||
# Añadimos el contenido al listado de cada canal
|
||||
dict_canales[i.channel].append(i)
|
||||
|
||||
# Añadimos el contenido encontrado en la lista list_result
|
||||
for c in sorted(dict_canales):
|
||||
itemlist.append(Item(channel="news", title=channels_id_name[c] + ':', text_color=color1, text_bold=True))
|
||||
|
||||
for i in dict_canales[c]:
|
||||
if i.contentQuality:
|
||||
i.title += ' (%s)' % i.contentQuality
|
||||
if i.language:
|
||||
i.title += ' [%s]' % i.language
|
||||
i.title = ' %s' % i.title
|
||||
i.text_color = color3
|
||||
itemlist.append(i.clone())
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def group_by_content(list_result_canal):
|
||||
global channels_id_name
|
||||
dict_contenidos = {}
|
||||
list_result = []
|
||||
|
||||
for i in list_result_canal:
|
||||
# Formatear titulo
|
||||
i.title = get_title(i)
|
||||
|
||||
# Eliminar tildes y otros caracteres especiales para la key
|
||||
import unicodedata
|
||||
try:
|
||||
new_key = i.title.lower().strip().decode("UTF-8")
|
||||
new_key = ''.join((c for c in unicodedata.normalize('NFD', new_key) if unicodedata.category(c) != 'Mn'))
|
||||
|
||||
except:
|
||||
new_key = i.title
|
||||
|
||||
if new_key in dict_contenidos:
|
||||
# Si el contenido ya estaba en el diccionario añadirlo a la lista de opciones...
|
||||
dict_contenidos[new_key].append(i)
|
||||
else: # ...sino añadirlo al diccionario
|
||||
dict_contenidos[new_key] = [i]
|
||||
|
||||
# Añadimos el contenido encontrado en la lista list_result
|
||||
for v in dict_contenidos.values():
|
||||
title = v[0].title
|
||||
if len(v) > 1:
|
||||
# Eliminar de la lista de nombres de canales los q esten duplicados
|
||||
canales_no_duplicados = []
|
||||
for i in v:
|
||||
if i.channel not in canales_no_duplicados:
|
||||
canales_no_duplicados.append(channels_id_name[i.channel])
|
||||
|
||||
if len(canales_no_duplicados) > 1:
|
||||
canales = ', '.join([i for i in canales_no_duplicados[:-1]])
|
||||
title += config.get_localized_string(70210) % (canales, canales_no_duplicados[-1])
|
||||
else:
|
||||
title += config.get_localized_string(70211) % (', '.join([i for i in canales_no_duplicados]))
|
||||
|
||||
new_item = v[0].clone(channel="news", title=title, action="show_channels",
|
||||
sub_list=[i.tourl() for i in v], extra=channels_id_name)
|
||||
else:
|
||||
new_item = v[0].clone(title=title)
|
||||
|
||||
new_item.text_color = color3
|
||||
list_result.append(new_item)
|
||||
|
||||
return sorted(list_result, key=lambda it: it.title.lower())
|
||||
|
||||
|
||||
def show_channels(item):
|
||||
logger.info()
|
||||
global channels_id_name
|
||||
channels_id_name = item.extra
|
||||
itemlist = []
|
||||
|
||||
for i in item.sub_list:
|
||||
new_item = Item()
|
||||
new_item = new_item.fromurl(i)
|
||||
# logger.debug(new_item.tostring())
|
||||
if new_item.contentQuality:
|
||||
new_item.title += ' (%s)' % new_item.contentQuality
|
||||
if new_item.language:
|
||||
new_item.title += ' [%s]' % new_item.language
|
||||
new_item.title += ' (%s)' % channels_id_name[new_item.channel]
|
||||
new_item.text_color = color1
|
||||
|
||||
itemlist.append(new_item.clone())
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def menu_opciones(item):
|
||||
itemlist = list()
|
||||
itemlist.append(Item(channel=item.channel, title=config.get_localized_string(60525),
|
||||
text_bold = True, thumbnail=get_thumb("setting_0.png"),
|
||||
folder=False))
|
||||
itemlist.append(Item(channel=item.channel, action="setting_channel", extra="peliculas", title=config.get_localized_string(60526),
|
||||
thumbnail=get_thumb("channels_movie.png"),
|
||||
folder=False))
|
||||
# itemlist.append(Item(channel=item.channel, action="setting_channel", extra="4K", title=config.get_localized_string(70207),
|
||||
# thumbnail=get_thumb("channels_movie.png"), folder=False))
|
||||
# itemlist.append(Item(channel=item.channel, action="setting_channel", extra="infantiles", title=config.get_localized_string(60527),
|
||||
# thumbnail=get_thumb("channels_children.png"),
|
||||
# folder=False))
|
||||
itemlist.append(Item(channel=item.channel, action="setting_channel", extra="series",
|
||||
title=config.get_localized_string(60528),
|
||||
thumbnail=get_thumb("channels_tvshow.png"),
|
||||
folder=False))
|
||||
itemlist.append(Item(channel=item.channel, action="setting_channel", extra="anime",
|
||||
title=config.get_localized_string(60529),
|
||||
thumbnail=get_thumb("channels_anime.png"),
|
||||
folder=False))
|
||||
# itemlist.append(
|
||||
# Item(channel=item.channel, action="setting_channel", extra="castellano", title=config.get_localized_string(70212),
|
||||
# thumbnail=get_thumb("channels_documentary.png"), folder=False))
|
||||
|
||||
# itemlist.append(Item(channel=item.channel, action="setting_channel", extra="latino", title=config.get_localized_string(70213),
|
||||
# thumbnail=get_thumb("channels_documentary.png"), folder=False))
|
||||
|
||||
itemlist.append(Item(channel=item.channel, action="setting_channel", extra="Torrent", title=config.get_localized_string(70214),
|
||||
thumbnail=get_thumb("channels_documentary.png"), folder=False))
|
||||
|
||||
itemlist.append(Item(channel=item.channel, action="setting_channel", extra="documentales",
|
||||
title=config.get_localized_string(60530),
|
||||
thumbnail=get_thumb("channels_documentary.png"),
|
||||
folder=False))
|
||||
itemlist.append(Item(channel=item.channel, action="settings", title=config.get_localized_string(60531),
|
||||
thumbnail=get_thumb("setting_0.png"),
|
||||
folder=False))
|
||||
return itemlist
|
||||
|
||||
|
||||
def settings(item):
|
||||
return platformtools.show_channel_settings(caption=config.get_localized_string(60532))
|
||||
|
||||
|
||||
def setting_channel(item):
|
||||
channels_path = os.path.join(config.get_runtime_path(), "channels", '*.json')
|
||||
channel_language = config.get_setting("channel_language", default="all")
|
||||
|
||||
list_controls = []
|
||||
for infile in sorted(glob.glob(channels_path)):
|
||||
channel_id = os.path.basename(infile)[:-5]
|
||||
channel_parameters = channeltools.get_channel_parameters(channel_id)
|
||||
|
||||
# No incluir si es un canal inactivo
|
||||
if not channel_parameters["active"]:
|
||||
continue
|
||||
|
||||
# No incluir si es un canal para adultos, y el modo adulto está desactivado
|
||||
if channel_parameters["adult"] and config.get_setting("adult_mode") == 0:
|
||||
continue
|
||||
|
||||
# No incluir si el canal es en un idioma filtrado
|
||||
if channel_language != "all" and channel_language not in channel_parameters["language"] \
|
||||
and "*" not in channel_parameters["language"]:
|
||||
continue
|
||||
|
||||
# No incluir si en su configuracion el canal no existe 'include_in_newest'
|
||||
include_in_newest = config.get_setting("include_in_newest_" + item.extra, channel_id)
|
||||
if include_in_newest is None:
|
||||
continue
|
||||
|
||||
control = {'id': channel_id,
|
||||
'type': "bool",
|
||||
'label': channel_parameters["title"],
|
||||
'default': include_in_newest,
|
||||
'enabled': True,
|
||||
'visible': True}
|
||||
|
||||
list_controls.append(control)
|
||||
|
||||
caption = config.get_localized_string(60533) + item.title.replace(config.get_localized_string(60525), "- ").strip()
|
||||
if config.get_setting("custom_button_value_news", item.channel):
|
||||
custom_button_label = config.get_localized_string(59992)
|
||||
else:
|
||||
custom_button_label = config.get_localized_string(59991)
|
||||
|
||||
return platformtools.show_channel_settings(list_controls=list_controls,
|
||||
caption=caption,
|
||||
callback="save_settings", item=item,
|
||||
custom_button={'visible': True,
|
||||
'function': "cb_custom_button",
|
||||
'close': False,
|
||||
'label': custom_button_label})
|
||||
|
||||
|
||||
def save_settings(item, dict_values):
|
||||
for v in dict_values:
|
||||
config.set_setting("include_in_newest_" + item.extra, dict_values[v], v)
|
||||
|
||||
|
||||
def cb_custom_button(item, dict_values):
|
||||
value = config.get_setting("custom_button_value_news", item.channel)
|
||||
if value == "":
|
||||
value = False
|
||||
|
||||
for v in dict_values.keys():
|
||||
dict_values[v] = not value
|
||||
|
||||
if config.set_setting("custom_button_value_news", not value, item.channel) == True:
|
||||
return {"label": "Ninguno"}
|
||||
else:
|
||||
return {"label": "Todos"}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"id": "search",
|
||||
"name": "@60672",
|
||||
"active": false,
|
||||
"adult": false,
|
||||
"language": ["ita"],
|
||||
"categories": ["movie"],
|
||||
"settings": [
|
||||
{
|
||||
"id": "multithread",
|
||||
"type": "bool",
|
||||
"label": "@60673",
|
||||
"default": true,
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "result_mode",
|
||||
"type": "list",
|
||||
"label": "@60674",
|
||||
"default": 0,
|
||||
"enabled": true,
|
||||
"visible": true,
|
||||
"lvalues": ["@60675","@60676"]
|
||||
},
|
||||
{
|
||||
"id": "saved_searches_limit",
|
||||
"type": "list",
|
||||
"label": "@60677",
|
||||
"default": 0,
|
||||
"enabled": true,
|
||||
"visible": true,
|
||||
"lvalues": ["10","20","30","40"]
|
||||
},
|
||||
{
|
||||
"id": "last_search",
|
||||
"type": "bool",
|
||||
"label": "@60678",
|
||||
"default": true,
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,783 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
from threading import Thread
|
||||
|
||||
from channelselector import get_thumb, auto_filter
|
||||
from core import channeltools
|
||||
from core import scrapertools
|
||||
from core.item import Item
|
||||
from platformcode import config, logger
|
||||
from platformcode import platformtools
|
||||
from core import tmdb
|
||||
import xbmc, xbmcaddon
|
||||
addon = xbmcaddon.Addon('metadata.themoviedb.org')
|
||||
def_lang = addon.getSetting('language')
|
||||
|
||||
link_list = []
|
||||
max_links = 30
|
||||
|
||||
|
||||
def mainlist(item):
|
||||
logger.info()
|
||||
item.channel = "search"
|
||||
|
||||
itemlist = []
|
||||
context = [{"title": config.get_localized_string(60412), "action": "setting_channel", "channel": item.channel}]
|
||||
itemlist.append(Item(channel=item.channel, action="sub_menu", title=config.get_localized_string(70305), context=context,
|
||||
thumbnail=get_thumb("search.png")))
|
||||
|
||||
itemlist.append(Item(channel=item.channel, action='genres_menu', title=config.get_localized_string(70306), type='movie',
|
||||
thumbnail=get_thumb("genres.png")))
|
||||
|
||||
itemlist.append (Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70307),
|
||||
context=context, search_type='list', list_type='movie/popular',
|
||||
thumbnail=get_thumb("popular.png")))
|
||||
|
||||
itemlist.append(Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70308),
|
||||
context=context, search_type='list', list_type='movie/top_rated',
|
||||
thumbnail=get_thumb("top_rated.png")))
|
||||
|
||||
itemlist.append(
|
||||
Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70309), context=context,
|
||||
search_type='list', list_type='movie/now_playing',
|
||||
thumbnail=get_thumb("now_playing.png")))
|
||||
|
||||
itemlist.append(Item(channel=item.channel, action='genres_menu', title=config.get_localized_string(70310), type='tv',
|
||||
thumbnail=get_thumb("genres.png")))
|
||||
|
||||
itemlist.append(
|
||||
Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70311), context=context,
|
||||
search_type='list',list_type='tv/popular', thumbnail=get_thumb("popular.png")))
|
||||
|
||||
itemlist.append(Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70312), context=context,
|
||||
search_type='list', list_type='tv/on_the_air', thumbnail=get_thumb("on_the_air.png")))
|
||||
|
||||
|
||||
itemlist.append(Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70313), context=context,
|
||||
search_type='list', list_type='tv/top_rated', thumbnail=get_thumb("top_rated.png")))
|
||||
|
||||
itemlist.append(Item(channel="filmontv", action="mainlist", title=config.get_localized_string(50001),
|
||||
thumbnail=get_thumb("on_the_air.png"), viewmode="thumbnails"))
|
||||
|
||||
|
||||
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def genres_menu(item):
|
||||
|
||||
itemlist = []
|
||||
|
||||
genres = tmdb.get_genres(item.type)
|
||||
|
||||
logger.debug(genres)
|
||||
logger.debug(genres[item.type])
|
||||
|
||||
for key, value in genres[item.type].items():
|
||||
itemlist.append(item.clone(title=value, action='discover_list', search_type='discover',
|
||||
list_type=key, page='1'))
|
||||
return sorted(itemlist, key=lambda it: it.title)
|
||||
|
||||
def sub_menu(item):
|
||||
logger.info()
|
||||
item.channel = "search"
|
||||
|
||||
itemlist = list()
|
||||
context = [{"title": config.get_localized_string(70273),
|
||||
"action": "setting_channel",
|
||||
"channel": item.channel}]
|
||||
itemlist.append(Item(channel=item.channel, action="search",
|
||||
title=config.get_localized_string(30980), context=context,
|
||||
thumbnail=get_thumb("search.png")))
|
||||
|
||||
thumbnail = get_thumb("search_star.png")
|
||||
|
||||
itemlist.append(Item(channel='tvmoviedb', title=config.get_localized_string(70036), action="search_",
|
||||
search={'url': 'search/person', 'language': def_lang, 'page': 1}, star=True,
|
||||
thumbnail=thumbnail))
|
||||
|
||||
itemlist.append(Item(channel=item.channel, action="search",
|
||||
title=config.get_localized_string(59998), extra="categorias",
|
||||
context=context,
|
||||
thumbnail=get_thumb("search.png")))
|
||||
itemlist.append(Item(channel=item.channel, action="opciones", title=config.get_localized_string(59997),
|
||||
thumbnail=get_thumb("search.png")))
|
||||
|
||||
itemlist.append(Item(channel="tvmoviedb", action="mainlist", title=config.get_localized_string(70274),
|
||||
thumbnail=get_thumb("search.png")))
|
||||
|
||||
saved_searches_list = get_saved_searches()
|
||||
context2 = context[:]
|
||||
context2.append({"title": config.get_localized_string(59996),
|
||||
"action": "clear_saved_searches",
|
||||
"channel": item.channel})
|
||||
logger.info("saved_searches_list=%s" % saved_searches_list)
|
||||
|
||||
if saved_searches_list:
|
||||
itemlist.append(Item(channel=item.channel, action="",
|
||||
title=config.get_localized_string(59995), context=context2,
|
||||
thumbnail=get_thumb("search.png")))
|
||||
for saved_search_text in saved_searches_list:
|
||||
itemlist.append(Item(channel=item.channel, action="do_search",
|
||||
title=' "' + saved_search_text + '"',
|
||||
extra=saved_search_text, context=context2,
|
||||
category=saved_search_text,
|
||||
thumbnail=get_thumb("search.png")))
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def opciones(item):
|
||||
itemlist = list()
|
||||
itemlist.append(Item(channel=item.channel, action="setting_channel",
|
||||
title=config.get_localized_string(59994), folder=False,
|
||||
thumbnail=get_thumb("search.png")))
|
||||
itemlist.append(Item(channel=item.channel, action="clear_saved_searches", title=config.get_localized_string(59996),
|
||||
folder=False, thumbnail=get_thumb("search.png")))
|
||||
itemlist.append(Item(channel=item.channel, action="settings", title=config.get_localized_string(60531), folder=False,
|
||||
thumbnail=get_thumb("search.png")))
|
||||
return itemlist
|
||||
|
||||
|
||||
def settings(item):
|
||||
return platformtools.show_channel_settings(caption=config.get_localized_string(59993))
|
||||
|
||||
|
||||
def setting_channel(item):
|
||||
if config.get_platform(True)['num_version'] >= 17.0: # A partir de Kodi 16 se puede usar multiselect, y de 17 con preselect
|
||||
return setting_channel_new(item)
|
||||
else:
|
||||
return setting_channel_old(item)
|
||||
|
||||
def setting_channel_new(item):
|
||||
import channelselector, xbmcgui
|
||||
from core import channeltools
|
||||
|
||||
# Cargar lista de opciones (canales activos del usuario y que permitan búsqueda global)
|
||||
# ------------------------
|
||||
lista = []; ids = []; lista_lang = []; lista_ctgs = []
|
||||
channels_list = channelselector.filterchannels('all')
|
||||
for channel in channels_list:
|
||||
channel_parameters = channeltools.get_channel_parameters(channel.channel)
|
||||
|
||||
# No incluir si en la configuracion del canal no existe "include_in_global_search"
|
||||
if not channel_parameters['include_in_global_search']:
|
||||
continue
|
||||
|
||||
lbl = '%s' % channel_parameters['language']
|
||||
lbl += ' %s' % ', '.join(config.get_localized_category(categ) for categ in channel_parameters['categories'])
|
||||
|
||||
it = xbmcgui.ListItem(channel.title, lbl)
|
||||
it.setArt({ 'thumb': channel.thumbnail, 'fanart': channel.fanart })
|
||||
lista.append(it)
|
||||
ids.append(channel.channel)
|
||||
lista_lang.append(channel_parameters['language'])
|
||||
lista_ctgs.append(channel_parameters['categories'])
|
||||
|
||||
# Diálogo para pre-seleccionar
|
||||
# ----------------------------
|
||||
preselecciones = [
|
||||
config.get_localized_string(70570),
|
||||
config.get_localized_string(70571),
|
||||
config.get_localized_string(70572),
|
||||
config.get_localized_string(70573),
|
||||
# config.get_localized_string(70574),
|
||||
# config.get_localized_string(70575),
|
||||
config.get_localized_string(70576)
|
||||
]
|
||||
presel_values = ['skip', 'actual', 'all', 'none', 'cast', 'lat', 'ita']
|
||||
|
||||
categs = ['movie', 'tvshow', 'documentary', 'anime', 'vos', 'direct', 'torrent']
|
||||
if config.get_setting('adult_mode') > 0: categs.append('adult')
|
||||
for c in categs:
|
||||
preselecciones.append(config.get_localized_string(70577) + config.get_localized_category(c))
|
||||
presel_values.append(c)
|
||||
|
||||
if item.action == 'setting_channel': # Configuración de los canales incluídos en la búsqueda
|
||||
del preselecciones[0]
|
||||
del presel_values[0]
|
||||
#else: # Llamada desde "buscar en otros canales" (se puede saltar la selección e ir directo a la búsqueda)
|
||||
|
||||
ret = platformtools.dialog_select(config.get_localized_string(59994), preselecciones)
|
||||
if ret == -1: return False # pedido cancel
|
||||
if presel_values[ret] == 'skip': return True # continuar sin modificar
|
||||
elif presel_values[ret] == 'none': preselect = []
|
||||
elif presel_values[ret] == 'all': preselect = range(len(ids))
|
||||
elif presel_values[ret] in ['cast', 'lat']:
|
||||
preselect = []
|
||||
for i, lg in enumerate(lista_lang):
|
||||
if presel_values[ret] in lg or '*' in lg:
|
||||
preselect.append(i)
|
||||
elif presel_values[ret] in ['ita']:
|
||||
preselect = []
|
||||
for i, lg in enumerate(lista_lang):
|
||||
if presel_values[ret] in lg or '*' in lg:
|
||||
preselect.append(i)
|
||||
elif presel_values[ret] == 'actual':
|
||||
preselect = []
|
||||
for i, canal in enumerate(ids):
|
||||
channel_status = config.get_setting('include_in_global_search', canal)
|
||||
if channel_status:
|
||||
preselect.append(i)
|
||||
else:
|
||||
preselect = []
|
||||
for i, ctgs in enumerate(lista_ctgs):
|
||||
if presel_values[ret] in ctgs:
|
||||
preselect.append(i)
|
||||
|
||||
# Diálogo para seleccionar
|
||||
# ------------------------
|
||||
ret = xbmcgui.Dialog().multiselect(config.get_localized_string(59994), lista, preselect=preselect, useDetails=True)
|
||||
if ret == None: return False # pedido cancel
|
||||
seleccionados = [ids[i] for i in ret]
|
||||
|
||||
# Guardar cambios en canales para la búsqueda
|
||||
# -------------------------------------------
|
||||
for canal in ids:
|
||||
channel_status = config.get_setting('include_in_global_search', canal)
|
||||
if channel_status is None: channel_status = True
|
||||
|
||||
if channel_status and canal not in seleccionados:
|
||||
config.set_setting('include_in_global_search', False, canal)
|
||||
elif not channel_status and canal in seleccionados:
|
||||
config.set_setting('include_in_global_search', True, canal)
|
||||
|
||||
return True
|
||||
|
||||
def setting_channel_old(item):
|
||||
channels_path = os.path.join(config.get_runtime_path(), "channels", '*.json')
|
||||
# channel_language = config.get_setting("channel_language", default="all")
|
||||
channel_language = auto_filter()
|
||||
|
||||
list_controls = []
|
||||
for infile in sorted(glob.glob(channels_path)):
|
||||
channel_name = os.path.basename(infile)[:-5]
|
||||
channel_parameters = channeltools.get_channel_parameters(channel_name)
|
||||
|
||||
# No incluir si es un canal inactivo
|
||||
if not channel_parameters["active"]:
|
||||
continue
|
||||
|
||||
# No incluir si es un canal para adultos, y el modo adulto está desactivado
|
||||
if channel_parameters["adult"] and config.get_setting("adult_mode") == 0:
|
||||
continue
|
||||
|
||||
# No incluir si el canal es en un idioma filtrado
|
||||
if channel_language != "all" and channel_language not in channel_parameters["language"] \
|
||||
and "*" not in channel_parameters["language"]:
|
||||
continue
|
||||
|
||||
# No incluir si en la configuracion del canal no existe "include_in_global_search"
|
||||
include_in_global_search = channel_parameters["include_in_global_search"]
|
||||
|
||||
if not include_in_global_search:
|
||||
continue
|
||||
else:
|
||||
# Se busca en la configuración del canal el valor guardado
|
||||
include_in_global_search = config.get_setting("include_in_global_search", channel_name)
|
||||
|
||||
control = {'id': channel_name,
|
||||
'type': "bool",
|
||||
'label': channel_parameters["title"],
|
||||
'default': include_in_global_search,
|
||||
'enabled': True,
|
||||
'visible': True}
|
||||
|
||||
list_controls.append(control)
|
||||
|
||||
if config.get_setting("custom_button_value", item.channel):
|
||||
custom_button_label = config.get_localized_string(59992)
|
||||
else:
|
||||
custom_button_label = config.get_localized_string(59991)
|
||||
|
||||
return platformtools.show_channel_settings(list_controls=list_controls,
|
||||
caption=config.get_localized_string(59990),
|
||||
callback="save_settings", item=item,
|
||||
custom_button={'visible': True,
|
||||
'function': "cb_custom_button",
|
||||
'close': False,
|
||||
'label': custom_button_label})
|
||||
|
||||
|
||||
def save_settings(item, dict_values):
|
||||
progreso = platformtools.dialog_progress(config.get_localized_string(59988), config.get_localized_string(59989))
|
||||
n = len(dict_values)
|
||||
for i, v in enumerate(dict_values):
|
||||
progreso.update((i * 100) / n, config.get_localized_string(59988))
|
||||
config.set_setting("include_in_global_search", dict_values[v], v)
|
||||
|
||||
progreso.close()
|
||||
return True
|
||||
|
||||
|
||||
def cb_custom_button(item, dict_values):
|
||||
value = config.get_setting("custom_button_value", item.channel)
|
||||
if value == "":
|
||||
value = False
|
||||
|
||||
for v in dict_values.keys():
|
||||
dict_values[v] = not value
|
||||
|
||||
if config.set_setting("custom_button_value", not value, item.channel) == True:
|
||||
return {"label": config.get_localized_string(59992)}
|
||||
else:
|
||||
return {"label": config.get_localized_string(59991)}
|
||||
|
||||
|
||||
def searchbycat(item):
|
||||
# Only in xbmc/kodi
|
||||
# Abre un cuadro de dialogo con las categorías en las que hacer la búsqueda
|
||||
|
||||
categories = [config.get_localized_string(30122), config.get_localized_string(30123), config.get_localized_string(30124), config.get_localized_string(30125), config.get_localized_string(59975), config.get_localized_string(59976)]
|
||||
categories_id = ["movie", "tvshow", "anime", "documentary", "vos", "latino"]
|
||||
list_controls = []
|
||||
for i, category in enumerate(categories):
|
||||
control = {'id': categories_id[i],
|
||||
'type': "bool",
|
||||
'label': category,
|
||||
'default': False,
|
||||
'enabled': True,
|
||||
'visible': True}
|
||||
|
||||
list_controls.append(control)
|
||||
control = {'id': "separador",
|
||||
'type': "label",
|
||||
'label': '',
|
||||
'default': "",
|
||||
'enabled': True,
|
||||
'visible': True}
|
||||
list_controls.append(control)
|
||||
control = {'id': "torrent",
|
||||
'type': "bool",
|
||||
'label': config.get_localized_string(70275),
|
||||
'default': True,
|
||||
'enabled': True,
|
||||
'visible': True}
|
||||
list_controls.append(control)
|
||||
|
||||
return platformtools.show_channel_settings(list_controls=list_controls, caption=config.get_localized_string(59974),
|
||||
callback="search_cb", item=item)
|
||||
|
||||
|
||||
def search_cb(item, values=""):
|
||||
cat = []
|
||||
for c in values:
|
||||
if values[c]:
|
||||
cat.append(c)
|
||||
|
||||
if not len(cat):
|
||||
return None
|
||||
else:
|
||||
logger.info(item.tostring())
|
||||
logger.info(str(cat))
|
||||
return do_search(item, cat)
|
||||
|
||||
|
||||
# Al llamar a esta función, el sistema pedirá primero el texto a buscar
|
||||
# y lo pasará en el parámetro "tecleado"
|
||||
def search(item, tecleado):
|
||||
logger.info()
|
||||
tecleado = tecleado.replace("+", " ")
|
||||
item.category = tecleado
|
||||
|
||||
if tecleado != "":
|
||||
save_search(tecleado)
|
||||
|
||||
if item.extra == "categorias":
|
||||
item.extra = tecleado
|
||||
itemlist = searchbycat(item)
|
||||
else:
|
||||
item.extra = tecleado
|
||||
itemlist = do_search(item, [])
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def show_result(item):
|
||||
tecleado = None
|
||||
if item.adult and config.get_setting("adult_request_password"):
|
||||
# Solicitar contraseña
|
||||
tecleado = platformtools.dialog_input("", config.get_localized_string(60334), True)
|
||||
if tecleado is None or tecleado != config.get_setting("adult_password"):
|
||||
return []
|
||||
|
||||
item.channel = item.__dict__.pop('from_channel')
|
||||
item.action = item.__dict__.pop('from_action')
|
||||
if item.__dict__.has_key('tecleado'):
|
||||
tecleado = item.__dict__.pop('tecleado')
|
||||
|
||||
try:
|
||||
channel = __import__('channels.%s' % item.channel, fromlist=["channels.%s" % item.channel])
|
||||
except:
|
||||
import traceback
|
||||
logger.error(traceback.format_exc())
|
||||
return []
|
||||
|
||||
if tecleado:
|
||||
# Mostrar resultados: agrupados por canales
|
||||
return channel.search(item, tecleado)
|
||||
else:
|
||||
# Mostrar resultados: todos juntos
|
||||
if item.infoPlus: #Si viene de una ventana de InfoPlus, hay que salir de esta forma...
|
||||
del item.infoPlus #si no, se mete en un bucle mostrando la misma pantalla,
|
||||
item.title = item.title.strip() #dando error en "handle -1"
|
||||
return getattr(channel, item.action)(item)
|
||||
try:
|
||||
from platformcode import launcher
|
||||
launcher.run(item)
|
||||
except ImportError:
|
||||
return getattr(channel, item.action)(item)
|
||||
|
||||
|
||||
def channel_search(search_results, channel_parameters, tecleado):
|
||||
try:
|
||||
exec("from specials import " + channel_parameters["channel"] + " as module")
|
||||
mainlist = module.mainlist(Item(channel=channel_parameters["channel"]))
|
||||
search_items = [item for item in mainlist if item.action == "search"]
|
||||
if not search_items:
|
||||
search_items = [Item(channel=channel_parameters["channel"], action="search")]
|
||||
|
||||
for item in search_items:
|
||||
result = module.search(item.clone(), tecleado)
|
||||
if result is None:
|
||||
result = []
|
||||
if len(result):
|
||||
if not channel_parameters["title"].capitalize() in search_results:
|
||||
search_results[channel_parameters["title"].capitalize()] = []
|
||||
search_results[channel_parameters["title"].capitalize()].append({"item": item,
|
||||
"itemlist": result,
|
||||
"adult": channel_parameters["adult"]})
|
||||
|
||||
except:
|
||||
logger.error("No se puede buscar en: %s" % channel_parameters["title"])
|
||||
import traceback
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
# Esta es la función que realmente realiza la búsqueda
|
||||
def do_search(item, categories=None):
|
||||
logger.info("blaa categorias %s" % categories)
|
||||
|
||||
if item.contextual==True:
|
||||
categories = ["Películas"]
|
||||
setting_item = Item(channel=item.channel, title=config.get_localized_string(59994), folder=False,
|
||||
thumbnail=get_thumb("search.png"))
|
||||
if not setting_channel(setting_item):
|
||||
return False
|
||||
|
||||
if categories is None:
|
||||
categories = []
|
||||
|
||||
multithread = config.get_setting("multithread", "search")
|
||||
result_mode = config.get_setting("result_mode", "search")
|
||||
|
||||
if item.wanted!='':
|
||||
tecleado=item.wanted
|
||||
else:
|
||||
tecleado = item.extra
|
||||
|
||||
itemlist = []
|
||||
|
||||
channels_path = os.path.join(config.get_runtime_path(), "channels", '*.json')
|
||||
logger.info("channels_path=%s" % channels_path)
|
||||
|
||||
# channel_language = config.get_setting("channel_language", default="all")
|
||||
channel_language = auto_filter()
|
||||
logger.info("channel_language=%s" % channel_language)
|
||||
|
||||
# Para Kodi es necesario esperar antes de cargar el progreso, de lo contrario
|
||||
# el cuadro de progreso queda "detras" del cuadro "cargando..." y no se le puede dar a cancelar
|
||||
time.sleep(0.5)
|
||||
progreso = platformtools.dialog_progress(config.get_localized_string(30993) % tecleado, "")
|
||||
channel_files = sorted(glob.glob(channels_path), key=lambda x: os.path.basename(x))
|
||||
import math
|
||||
|
||||
threads = []
|
||||
search_results = {}
|
||||
start_time = time.time()
|
||||
list_channels_search = []
|
||||
|
||||
# Extrae solo los canales a buscar
|
||||
for index, infile in enumerate(channel_files):
|
||||
try:
|
||||
basename = os.path.basename(infile)
|
||||
basename_without_extension = basename[:-5]
|
||||
logger.info("%s..." % basename_without_extension)
|
||||
|
||||
channel_parameters = channeltools.get_channel_parameters(basename_without_extension)
|
||||
|
||||
# No busca si es un canal inactivo
|
||||
if not channel_parameters["active"]:
|
||||
logger.info("%s -no activo-" % basename_without_extension)
|
||||
continue
|
||||
|
||||
# En caso de búsqueda por categorias
|
||||
if categories:
|
||||
|
||||
# Si no se ha seleccionado torrent no se muestra
|
||||
#if "torrent" not in categories and "infoPlus" not in categories:
|
||||
# if "torrent" in channel_parameters["categories"]:
|
||||
# logger.info("%s -torrent-" % basename_without_extension)
|
||||
# continue
|
||||
|
||||
for cat in categories:
|
||||
if cat not in channel_parameters["categories"]:
|
||||
logger.info("%s -no en %s-" % (basename_without_extension, cat))
|
||||
continue
|
||||
|
||||
# No busca si es un canal para adultos, y el modo adulto está desactivado
|
||||
if channel_parameters["adult"] and config.get_setting("adult_mode") == 0:
|
||||
logger.info("%s -adulto-" % basename_without_extension)
|
||||
continue
|
||||
|
||||
# No busca si el canal es en un idioma filtrado
|
||||
if channel_language != "all" and channel_language not in channel_parameters["language"] \
|
||||
and "*" not in channel_parameters["language"]:
|
||||
logger.info("%s -idioma no válido-" % basename_without_extension)
|
||||
continue
|
||||
|
||||
# No busca si es un canal excluido de la búsqueda global
|
||||
include_in_global_search = channel_parameters["include_in_global_search"]
|
||||
if include_in_global_search:
|
||||
# Buscar en la configuracion del canal
|
||||
include_in_global_search = config.get_setting("include_in_global_search", basename_without_extension)
|
||||
|
||||
if not include_in_global_search:
|
||||
logger.info("%s -no incluido en lista a buscar-" % basename_without_extension)
|
||||
continue
|
||||
list_channels_search.append(infile)
|
||||
except:
|
||||
logger.error("No se puede buscar en: %s" % channel_parameters["title"])
|
||||
import traceback
|
||||
logger.error(traceback.format_exc())
|
||||
continue
|
||||
|
||||
|
||||
for index, infile in enumerate(list_channels_search):
|
||||
try:
|
||||
# fix float porque la division se hace mal en python 2.x
|
||||
percentage = int(float((index+1))/len(list_channels_search)*float(100))
|
||||
basename = os.path.basename(infile)
|
||||
basename_without_extension = basename[:-5]
|
||||
logger.info("%s..." % basename_without_extension)
|
||||
channel_parameters = channeltools.get_channel_parameters(basename_without_extension)
|
||||
# Movido aqui el progreso, para que muestre el canal exacto que está buscando
|
||||
progreso.update(percentage,
|
||||
config.get_localized_string(60520) % (channel_parameters["title"]))
|
||||
# Modo Multi Thread
|
||||
if progreso.iscanceled():
|
||||
progreso.close()
|
||||
logger.info("Búsqueda cancelada")
|
||||
return itemlist
|
||||
if multithread:
|
||||
t = Thread(target=channel_search, args=[search_results, channel_parameters, tecleado],
|
||||
name=channel_parameters["title"])
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
threads.append(t)
|
||||
# Modo single Thread
|
||||
else:
|
||||
logger.info("Intentado búsqueda en %s de %s " % (basename_without_extension, tecleado))
|
||||
channel_search(search_results, channel_parameters, tecleado)
|
||||
except:
|
||||
logger.error("No se puede buscar en: %s" % channel_parameters["title"])
|
||||
import traceback
|
||||
logger.error(traceback.format_exc())
|
||||
continue
|
||||
|
||||
# Modo Multi Thread
|
||||
# Usando isAlive() no es necesario try-except,
|
||||
# ya que esta funcion (a diferencia de is_alive())
|
||||
# es compatible tanto con versiones antiguas de python como nuevas
|
||||
if multithread:
|
||||
pendent = [a for a in threads if a.isAlive()]
|
||||
if len(pendent) > 0: t = float(100) / len(pendent)
|
||||
while len(pendent) > 0:
|
||||
index = (len(threads) - len(pendent)) + 1
|
||||
percentage = int(math.ceil(index * t))
|
||||
|
||||
list_pendent_names = [a.getName() for a in pendent]
|
||||
mensaje = config.get_localized_string(70282) % (", ".join(list_pendent_names))
|
||||
progreso.update(percentage, config.get_localized_string(60521) % (len(threads) - len(pendent) + 1, len(threads)),
|
||||
mensaje)
|
||||
if progreso.iscanceled():
|
||||
logger.info("Búsqueda cancelada")
|
||||
break
|
||||
time.sleep(0.5)
|
||||
pendent = [a for a in threads if a.isAlive()]
|
||||
total = 0
|
||||
for channel in sorted(search_results.keys()):
|
||||
for element in search_results[channel]:
|
||||
total += len(element["itemlist"])
|
||||
title = channel
|
||||
# resultados agrupados por canales
|
||||
if item.contextual == True or item.action == 'search_tmdb':
|
||||
result_mode = 1
|
||||
if result_mode == 0:
|
||||
if len(search_results[channel]) > 1:
|
||||
title += " -%s" % element["item"].title.strip()
|
||||
title += " (%s)" % len(element["itemlist"])
|
||||
title = re.sub("\[COLOR [^\]]+\]", "", title)
|
||||
title = re.sub("\[/COLOR]", "", title)
|
||||
itemlist.append(Item(title=title, channel="search", action="show_result", url=element["item"].url,
|
||||
extra=element["item"].extra, folder=True, adult=element["adult"],
|
||||
from_action="search", from_channel=element["item"].channel, tecleado=tecleado))
|
||||
# todos los resultados juntos, en la misma lista
|
||||
else:
|
||||
title = config.get_localized_string(70697) % channel
|
||||
itemlist.append(Item(title=title, channel="search", action="",
|
||||
folder=False, text_bold=True, from_channel=channel))
|
||||
for i in element["itemlist"]:
|
||||
if i.action:
|
||||
title = " " + i.title
|
||||
if "infoPlus" in categories: #Se manrca vi viene de una ventana de InfoPlus
|
||||
i.infoPlus = True
|
||||
itemlist.append(i.clone(title=title, from_action=i.action, from_channel=i.channel,
|
||||
channel="search", action="show_result", adult=element["adult"]))
|
||||
title = config.get_localized_string(59972) % (
|
||||
tecleado, total, time.time() - start_time)
|
||||
itemlist.insert(0, Item(title=title, text_color='yellow'))
|
||||
progreso.close()
|
||||
#Para opcion Buscar en otros canales
|
||||
if item.contextual == True:
|
||||
return exact_results(itemlist, tecleado)
|
||||
else:
|
||||
return itemlist
|
||||
|
||||
|
||||
def exact_results(results, wanted):
|
||||
logger.info()
|
||||
itemlist =[]
|
||||
|
||||
for item in results:
|
||||
if item.action=='':
|
||||
channel=item.from_channel
|
||||
if item.action != '' and item.contentTitle==wanted:
|
||||
item.title = '%s [%s]' % (item.title, channel)
|
||||
itemlist.append(item)
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def save_search(text):
|
||||
saved_searches_limit = int((10, 20, 30, 40,)[int(config.get_setting("saved_searches_limit", "search"))])
|
||||
|
||||
current_saved_searches_list = config.get_setting("saved_searches_list", "search")
|
||||
if current_saved_searches_list is None:
|
||||
saved_searches_list = []
|
||||
else:
|
||||
saved_searches_list = list(current_saved_searches_list)
|
||||
|
||||
if text in saved_searches_list:
|
||||
saved_searches_list.remove(text)
|
||||
|
||||
saved_searches_list.insert(0, text)
|
||||
|
||||
config.set_setting("saved_searches_list", saved_searches_list[:saved_searches_limit], "search")
|
||||
|
||||
|
||||
def clear_saved_searches(item):
|
||||
config.set_setting("saved_searches_list", list(), "search")
|
||||
platformtools.dialog_ok(config.get_localized_string(60329), config.get_localized_string(60424))
|
||||
|
||||
|
||||
def get_saved_searches():
|
||||
current_saved_searches_list = config.get_setting("saved_searches_list", "search")
|
||||
if current_saved_searches_list is None:
|
||||
saved_searches_list = []
|
||||
else:
|
||||
saved_searches_list = list(current_saved_searches_list)
|
||||
|
||||
return saved_searches_list
|
||||
|
||||
|
||||
def discover_list(item):
|
||||
from platformcode import unify
|
||||
itemlist = []
|
||||
|
||||
result = tmdb.discovery(item)
|
||||
|
||||
tvshow = False
|
||||
|
||||
logger.debug(item)
|
||||
|
||||
for elem in result:
|
||||
elem['tmdb_id']=elem['id']
|
||||
if 'title' in elem:
|
||||
title = unify.normalize(elem['title']).capitalize()
|
||||
elem['year'] = scrapertools.find_single_match(elem['release_date'], '(\d{4})-\d+-\d+')
|
||||
else:
|
||||
title = unify.normalize(elem['name']).capitalize()
|
||||
tvshow = True
|
||||
|
||||
new_item = Item(channel='search', title=title, infoLabels=elem, action='do_search', extra=title,
|
||||
category=config.get_localized_string(70695), context ='')
|
||||
|
||||
if tvshow:
|
||||
new_item.contentSerieName = title
|
||||
else:
|
||||
new_item.contentTitle = title
|
||||
|
||||
itemlist.append(new_item)
|
||||
|
||||
tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True)
|
||||
|
||||
if item.page != '' and len(itemlist)>0:
|
||||
next_page = str(int(item.page)+1)
|
||||
#if not 'similar' in item.list_type:
|
||||
# itemlist.append(item.clone(title='Pagina Siguente', page=next_page))
|
||||
#else:
|
||||
itemlist.append(Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70065),
|
||||
search_type=item.search_type, list_type=item.list_type, type=item.type, page=next_page))
|
||||
|
||||
return itemlist
|
||||
|
||||
def search_tmdb(item):
|
||||
logger.debug(item)
|
||||
|
||||
itemlist = []
|
||||
threads = []
|
||||
logger.debug(item)
|
||||
wanted = item.contentTitle
|
||||
|
||||
search = do_search(item)
|
||||
|
||||
if item.contentSerieName == '':
|
||||
results = exact_results(search, wanted)
|
||||
for result in results:
|
||||
logger.debug(result)
|
||||
t = Thread(target=get_links, args=[result])
|
||||
t.start()
|
||||
threads.append(t)
|
||||
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
# try:
|
||||
# get_links(result)
|
||||
# except:
|
||||
# pass
|
||||
|
||||
for link in link_list:
|
||||
if link.action == 'play' and not 'trailer' in link.title.lower() and len(itemlist) < max_links:
|
||||
itemlist.append(link)
|
||||
|
||||
return sorted(itemlist, key=lambda it: it.server)
|
||||
else:
|
||||
for item in search:
|
||||
if item.contentSerieName != '' and item.contentSerieName == wanted:
|
||||
logger.debug(item)
|
||||
itemlist.append(item)
|
||||
return itemlist
|
||||
|
||||
def get_links (item):
|
||||
logger.info()
|
||||
results =[]
|
||||
channel = __import__('channels.%s' % item.from_channel, None, None, ["channels.%s" % item.from_channel])
|
||||
if len(link_list) <= max_links:
|
||||
link_list.extend(getattr(channel, item.from_action)(item))
|
||||
@@ -0,0 +1,866 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import Queue
|
||||
import datetime
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import threading
|
||||
import time
|
||||
import urllib
|
||||
from threading import Thread
|
||||
from unicodedata import normalize
|
||||
|
||||
import xbmc
|
||||
|
||||
from core import channeltools, httptools, tmdb, servertools
|
||||
from lib.fuzzywuzzy import fuzz
|
||||
from platformcode import platformtools
|
||||
|
||||
try:
|
||||
import json
|
||||
except:
|
||||
import simplejson as json
|
||||
|
||||
from platformcode import config
|
||||
from platformcode import logger
|
||||
from core.item import Item
|
||||
|
||||
TMDB_KEY = tmdb.tmdb_auth_key ######TMDB_KEY = '92db8778ccb39d825150332b0a46061d'
|
||||
# TMDB_KEY = '92db8778ccb39d825150332b0a46061d'
|
||||
|
||||
|
||||
TMDB_URL_BASE = 'http://api.themoviedb.org/3/'
|
||||
TMDB_IMAGES_BASEURL = 'http://image.tmdb.org/t/p/'
|
||||
INCLUDE_ADULT = True if config.get_setting("enableadultmode") else False
|
||||
LANGUAGE_ID = 'it'
|
||||
|
||||
DTTIME = (datetime.datetime.utcnow() - datetime.timedelta(hours=5))
|
||||
SYSTIME = DTTIME.strftime('%Y%m%d%H%M%S%f')
|
||||
TODAY_TIME = DTTIME.strftime('%Y-%m-%d')
|
||||
MONTH_TIME = (DTTIME - datetime.timedelta(days=30)).strftime('%Y-%m-%d')
|
||||
MONTH2_TIME = (DTTIME - datetime.timedelta(days=60)).strftime('%Y-%m-%d')
|
||||
YEAR_DATE = (DTTIME - datetime.timedelta(days=365)).strftime('%Y-%m-%d')
|
||||
|
||||
TIMEOUT_TOTAL = config.get_setting("timeout")
|
||||
MAX_THREADS = config.get_setting("maxthreads")
|
||||
|
||||
# TIMEOUT_TOTAL = config.get_setting("timeout", default=90)
|
||||
# MAX_THREADS = config.get_setting("maxthreads", default=24)
|
||||
|
||||
NLS_Search_by_Channel = config.get_localized_string(30974)
|
||||
NLS_Alternative_Search = config.get_localized_string(70021)
|
||||
NLS_Search_by_Title = config.get_localized_string(30980)
|
||||
NLS_Search_by_Person = config.get_localized_string(30981)
|
||||
NLS_Search_by_Company = config.get_localized_string(30982)
|
||||
NLS_Now_Playing = config.get_localized_string(30983)
|
||||
NLS_Popular = config.get_localized_string(30984)
|
||||
NLS_Top_Rated = config.get_localized_string(30985)
|
||||
NLS_Search_by_Collection = config.get_localized_string(30986)
|
||||
NLS_List_by_Genre = config.get_localized_string(30987)
|
||||
NLS_Search_by_Year = config.get_localized_string(30988)
|
||||
NLS_Search_Similar_by_Title = config.get_localized_string(30989)
|
||||
NLS_Search_Tvshow_by_Title = config.get_localized_string(30990)
|
||||
NLS_Most_Voted = config.get_localized_string(30996)
|
||||
NLS_Oscar = config.get_localized_string(30997)
|
||||
NLS_Last_2_months = config.get_localized_string(60534)
|
||||
NLS_Library = config.get_localized_string(30991)
|
||||
NLS_Next_Page = config.get_localized_string(30992)
|
||||
NLS_Looking_For = config.get_localized_string(30993)
|
||||
NLS_Searching_In = config.get_localized_string(30994)
|
||||
NLS_Found_So_Far = config.get_localized_string(30995)
|
||||
NLS_Info_Title = config.get_localized_string(30975)
|
||||
NLS_Info_Person = config.get_localized_string(30979)
|
||||
NLS_New_TVShow = config.get_localized_string(30978)
|
||||
NLS_TVShow_onair = config.get_localized_string(30977)
|
||||
NLS_TVShow_airing_today = config.get_localized_string(30976)
|
||||
|
||||
TMDb_genres = {}
|
||||
|
||||
|
||||
def mainlist(item):
|
||||
logger.info(" mainlist")
|
||||
itemlist = [Item(channel="search",
|
||||
title="[COLOR lightgreen]%s[/COLOR]" % NLS_Search_by_Channel,
|
||||
action="mainlist",
|
||||
thumbnail="http://i.imgur.com/pE5WSZp.png"),
|
||||
Item(channel="tvmoviedb",
|
||||
title="[COLOR yellow]%s[/COLOR]" % NLS_Alternative_Search,
|
||||
action="mainlist",
|
||||
url="search_movie_by_title",
|
||||
thumbnail="https://s6.postimg.cc/6lll9b8c1/searching.png"),
|
||||
Item(channel=item.channel,
|
||||
title="[COLOR yellow]%s[/COLOR]" % NLS_Search_by_Title,
|
||||
action="search",
|
||||
url="search_movie_by_title",
|
||||
thumbnail="http://i.imgur.com/B1H1G8U.png"),
|
||||
Item(channel=item.channel,
|
||||
title="[COLOR yellow]%s[/COLOR]" % NLS_Search_by_Person,
|
||||
action="search",
|
||||
url="search_person_by_name",
|
||||
thumbnail="http://i.imgur.com/efuEeNu.png"),
|
||||
Item(channel=item.channel,
|
||||
title="[COLOR yellow]%s[/COLOR]" % NLS_Search_by_Year,
|
||||
action="search_movie_by_year",
|
||||
url="search_movie_by_year",
|
||||
thumbnail="https://d1kz0yd1invg7i.cloudfront.net/uploads/app/icon/1/calendar-icon-big.png"),
|
||||
Item(channel=item.channel,
|
||||
title="[COLOR yellow]%s[/COLOR]" % NLS_Search_by_Collection,
|
||||
action="search",
|
||||
url="search_collection_by_name",
|
||||
thumbnail="http://i.imgur.com/JmcvZDL.png"),
|
||||
Item(channel=item.channel,
|
||||
title="[COLOR yellow]%s[/COLOR]" % NLS_Search_Similar_by_Title,
|
||||
action="search",
|
||||
url="search_similar_movie_by_title",
|
||||
thumbnail="http://i.imgur.com/JmcvZDL.png"),
|
||||
Item(channel=item.channel,
|
||||
title="[COLOR lime]%s[/COLOR]" % NLS_Search_Tvshow_by_Title,
|
||||
action="search",
|
||||
url="search_tvshow_by_title",
|
||||
thumbnail="https://i.imgur.com/2ZWjLn5.jpg?1"),
|
||||
Item(channel=item.channel,
|
||||
title="(TV Shows) [COLOR lime]%s[/COLOR]" % NLS_New_TVShow,
|
||||
action="list_tvshow",
|
||||
url='discover/tv?sort_by=popularity.desc&first_air_date.gte=%s&first_air_date.lte=%s&' % (
|
||||
MONTH2_TIME, TODAY_TIME),
|
||||
plot="1",
|
||||
type="tvshow",
|
||||
thumbnail="https://i.imgur.com/2ZWjLn5.jpg?1"),
|
||||
Item(channel=item.channel,
|
||||
title="(TV Shows) [COLOR lime]%s[/COLOR]" % NLS_TVShow_onair,
|
||||
action="list_tvshow",
|
||||
url="tv/on_the_air?",
|
||||
plot="1",
|
||||
type="tvshow",
|
||||
thumbnail="https://i.imgur.com/2ZWjLn5.jpg?1"),
|
||||
Item(channel=item.channel,
|
||||
title="(TV Shows) [COLOR lime]%s[/COLOR]" % NLS_Popular,
|
||||
action="list_tvshow",
|
||||
url="tv/popular?",
|
||||
plot="1",
|
||||
type="tvshow",
|
||||
thumbnail="https://i.imgur.com/2ZWjLn5.jpg?1"),
|
||||
Item(channel=item.channel,
|
||||
title="(TV Shows) [COLOR lime]%s[/COLOR]" % NLS_Top_Rated,
|
||||
action="list_tvshow",
|
||||
url="tv/top_rated?",
|
||||
plot="1",
|
||||
type="tvshow",
|
||||
thumbnail="https://i.imgur.com/2ZWjLn5.jpg?1"),
|
||||
Item(channel=item.channel,
|
||||
title="(TV Shows) [COLOR lime]%s[/COLOR]" % NLS_TVShow_airing_today,
|
||||
action="list_tvshow",
|
||||
url="tv/airing_today?",
|
||||
plot="1",
|
||||
type="tvshow",
|
||||
thumbnail="https://i.imgur.com/2ZWjLn5.jpg?1"),
|
||||
Item(channel=item.channel,
|
||||
title="(Movies) [COLOR yellow]%s[/COLOR]" % NLS_Now_Playing,
|
||||
action="list_movie",
|
||||
url="movie/now_playing?",
|
||||
plot="1",
|
||||
type="movie",
|
||||
thumbnail="http://i.imgur.com/B16HnVh.png"),
|
||||
Item(channel=item.channel,
|
||||
title="(Movies) [COLOR yellow]%s[/COLOR]" % NLS_Popular,
|
||||
action="list_movie",
|
||||
url="movie/popular?",
|
||||
plot="1",
|
||||
type="movie",
|
||||
thumbnail="http://i.imgur.com/8IBjyzw.png"),
|
||||
Item(channel=item.channel,
|
||||
title="(Movies) [COLOR yellow]%s[/COLOR]" % NLS_Top_Rated,
|
||||
action="list_movie",
|
||||
url="movie/top_rated?",
|
||||
plot="1",
|
||||
type="movie",
|
||||
thumbnail="http://www.clipartbest.com/cliparts/RiG/6qn/RiG6qn79T.png"),
|
||||
Item(channel=item.channel,
|
||||
title="(Movies) [COLOR yellow]%s[/COLOR]" % NLS_Most_Voted,
|
||||
action="list_movie",
|
||||
url='discover/movie?certification_country=US&sort_by=vote_count.desc&',
|
||||
plot="1",
|
||||
type="movie",
|
||||
thumbnail="http://i.imgur.com/5ShnO8w.png"),
|
||||
Item(channel=item.channel,
|
||||
title="(Movies) [COLOR yellow]%s[/COLOR]" % NLS_Oscar,
|
||||
action="list_movie",
|
||||
url='list/509ec17b19c2950a0600050d?',
|
||||
plot="1",
|
||||
type="movie",
|
||||
thumbnail="http://i.imgur.com/5ShnO8w.png"),
|
||||
Item(channel=item.channel,
|
||||
title="(Movies) [COLOR yellow]%s[/COLOR]" % NLS_Last_2_months,
|
||||
action="list_movie",
|
||||
url='discover/movie?primary_release_date.gte=%s&primary_release_date.lte=%s&' % (
|
||||
YEAR_DATE, MONTH2_TIME),
|
||||
plot="1",
|
||||
type="movie",
|
||||
thumbnail="http://i.imgur.com/CsizqUI.png"),
|
||||
Item(channel=item.channel,
|
||||
title="(Movies) [COLOR yellow]%s[/COLOR]" % NLS_List_by_Genre,
|
||||
action="list_genres",
|
||||
type="movie",
|
||||
thumbnail="http://i.imgur.com/uotyBbU.png")]
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def list_movie(item):
|
||||
logger.info(" list_movie '%s/%s'" % (item.url, item.plot))
|
||||
|
||||
results = [0, 0]
|
||||
page = int(item.plot)
|
||||
itemlist = build_movie_list(item, tmdb_get_data('%s&page=%d&' % (item.url, page), results=results))
|
||||
if page < results[0]:
|
||||
itemlist.append(Item(
|
||||
channel=item.channel,
|
||||
title="[COLOR orange]%s (%d/%d)[/COLOR]" % (NLS_Next_Page, page * len(itemlist), results[1]),
|
||||
action="list_movie",
|
||||
url=item.url,
|
||||
plot="%d" % (page + 1),
|
||||
type=item.type,
|
||||
viewmode="" if page <= 1 else "paged_list"))
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def list_tvshow(item):
|
||||
logger.info(" list_tvshow '%s/%s'" % (item.url, item.plot))
|
||||
|
||||
results = [0, 0]
|
||||
page = int(item.plot)
|
||||
itemlist = build_movie_list(item, tmdb_get_data('%spage=%d&' % (item.url, page), results=results))
|
||||
if page < results[0]:
|
||||
itemlist.append(Item(
|
||||
channel=item.channel,
|
||||
title="[COLOR orange]%s (%d/%d)[/COLOR]" % (NLS_Next_Page, page * len(itemlist), results[1]),
|
||||
action="list_tvshow",
|
||||
url=item.url,
|
||||
plot="%d" % (page + 1),
|
||||
type=item.type,
|
||||
viewmode="" if page <= 1 else "paged_list"))
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def list_genres(item):
|
||||
logger.info(" list_genres")
|
||||
|
||||
tmdb_genre(1)
|
||||
itemlist = []
|
||||
for genre_id, genre_name in TMDb_genres.iteritems():
|
||||
itemlist.append(
|
||||
Item(channel=item.channel,
|
||||
title=genre_name,
|
||||
action="list_movie",
|
||||
url='genre/%d/movies?primary_release_date.gte=%s&primary_release_date.lte=%s&language=it' % (
|
||||
genre_id, YEAR_DATE, TODAY_TIME),
|
||||
plot="1"))
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def discover_list(item):
|
||||
from platformcode import unify
|
||||
from core import scrapertools
|
||||
itemlist = []
|
||||
|
||||
result = tmdb.discovery(item)
|
||||
|
||||
tvshow = False
|
||||
|
||||
logger.debug(item)
|
||||
|
||||
for elem in result:
|
||||
elem['tmdb_id'] = elem['id']
|
||||
if 'title' in elem:
|
||||
title = unify.normalize(elem['title']).capitalize()
|
||||
elem['year'] = scrapertools.find_single_match(elem['release_date'], '(\d{4})-\d+-\d+')
|
||||
else:
|
||||
title = unify.normalize(elem['name']).capitalize()
|
||||
tvshow = True
|
||||
|
||||
new_item = Item(channel='searchall', title=title, infoLabels=elem, action='search_tmdb', extra=title,
|
||||
category=config.get_localized_string(70695), context='')
|
||||
|
||||
if tvshow:
|
||||
new_item.contentSerieName = title
|
||||
else:
|
||||
new_item.contentTitle = title
|
||||
|
||||
itemlist.append(new_item)
|
||||
|
||||
tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True)
|
||||
|
||||
if item.page != '' and len(itemlist) > 0:
|
||||
next_page = str(int(item.page) + 1)
|
||||
# if not 'similar' in item.list_type:
|
||||
# itemlist.append(item.clone(title='Pagina Siguente', page=next_page))
|
||||
# else:
|
||||
itemlist.append(Item(channel=item.channel, action='discover_list', title=config.get_localized_string(30992),
|
||||
text_color="orange", search_type=item.search_type, list_type=item.list_type,
|
||||
type=item.type, page=next_page))
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
# Do not change the name of this function otherwise launcher.py won't create the keyboard dialog required to enter the search terms
|
||||
def search(item, search_terms):
|
||||
if item.url == '': return []
|
||||
|
||||
return globals()[item.url](item, search_terms) if item.url in globals() else []
|
||||
|
||||
|
||||
def search_tvshow_by_title(item, search_terms):
|
||||
logger.info(" search_tvshow_by_title '%s'" % (search_terms))
|
||||
|
||||
return list_movie(
|
||||
Item(channel=item.channel,
|
||||
url='search/tv?query=%s&' % search_terms,
|
||||
plot="1",
|
||||
type="tvshow"))
|
||||
|
||||
|
||||
def search_movie_by_title(item, search_terms):
|
||||
logger.info(" search_movie_by_title '%s'" % (search_terms))
|
||||
|
||||
return list_movie(
|
||||
Item(channel=item.channel,
|
||||
url='search/movie?query=%s&' % search_terms,
|
||||
plot="1",
|
||||
type="movie"))
|
||||
|
||||
|
||||
def search_similar_movie_by_title(item, search_terms):
|
||||
logger.info(" search_similar_movie_by_title '%s'" % (search_terms))
|
||||
|
||||
return list_movie(
|
||||
Item(channel=item.channel,
|
||||
url='search/movie?append_to_response=similar_movies,alternative_title&query=%s&' % search_terms,
|
||||
plot="1",
|
||||
type='movie'))
|
||||
|
||||
|
||||
def search_movie_by_year(item):
|
||||
logger.info(" search_movie_by_year")
|
||||
now = datetime.datetime.now()
|
||||
year = int(now.year)
|
||||
result = []
|
||||
for i in range(150):
|
||||
year_to_search = year - i
|
||||
result.append(Item(channel=item.channel,
|
||||
url='discover/movie?primary_release_year=%s&' % year_to_search,
|
||||
plot="1",
|
||||
type="movie",
|
||||
title="%s" % year_to_search,
|
||||
action="list_movie"))
|
||||
return result
|
||||
|
||||
|
||||
def search_person_by_name(item, search_terms):
|
||||
logger.info(" search_person_by_name '%s'" % (search_terms))
|
||||
|
||||
persons = tmdb_get_data("search/person?query=%s&" % search_terms)
|
||||
|
||||
itemlist = []
|
||||
for person in persons:
|
||||
name = normalize_unicode(tmdb_tag(person, 'name'))
|
||||
poster = tmdb_image(person, 'profile_path')
|
||||
fanart = ''
|
||||
for movie in tmdb_tag(person, 'known_for', []):
|
||||
if tmdb_tag_exists(movie, 'backdrop_path'):
|
||||
fanart = tmdb_image(movie, 'backdrop_path', 'w1280')
|
||||
break
|
||||
|
||||
# extracmds = [
|
||||
# (NLS_Info_Person, "RunScript(script.extendedinfo,info=extendedactorinfo,id=%s)" % str(tmdb_tag(person, 'id')))] \
|
||||
# if xbmc.getCondVisibility('System.HasAddon(script.extendedinfo)') else []
|
||||
|
||||
itemlist.append(Item(
|
||||
channel=item.channel,
|
||||
action='search_movie_by_person',
|
||||
extra=str(tmdb_tag(person, 'id')),
|
||||
title=name,
|
||||
thumbnail=poster,
|
||||
viewmode='list',
|
||||
fanart=fanart,
|
||||
type='movie'
|
||||
# extracmds=extracmds
|
||||
))
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def search_movie_by_person(item):
|
||||
logger.info(" search_movie_by_person '%s'" % (item.extra))
|
||||
|
||||
# return list_movie(
|
||||
# Item(channel=item.channel,
|
||||
# url="discover/movie?with_people=%s&primary_release_date.lte=%s&sort_by=primary_release_date.desc&" % (
|
||||
# item.extra, TODAY_TIME),
|
||||
# plot="1"))
|
||||
|
||||
person_movie_credits = tmdb_get_data(
|
||||
"person/%s/movie_credits?primary_release_date.lte=%s&sort_by=primary_release_date.desc&" % (
|
||||
item.extra, TODAY_TIME))
|
||||
movies = []
|
||||
if person_movie_credits:
|
||||
movies.extend(tmdb_tag(person_movie_credits, 'cast', []))
|
||||
movies.extend(tmdb_tag(person_movie_credits, 'crew', []))
|
||||
|
||||
# Movie person list is not paged
|
||||
return build_movie_list(item, movies)
|
||||
|
||||
|
||||
def search_collection_by_name(item, search_terms):
|
||||
logger.info(" search_collection_by_name '%s'" % (search_terms))
|
||||
|
||||
collections = tmdb_get_data("search/collection?query=%s&" % search_terms)
|
||||
|
||||
itemlist = []
|
||||
for collection in collections:
|
||||
name = normalize_unicode(tmdb_tag(collection, 'name'))
|
||||
poster = tmdb_image(collection, 'poster_path')
|
||||
fanart = tmdb_image(collection, 'backdrop_path', 'w1280')
|
||||
|
||||
itemlist.append(Item(
|
||||
channel=item.channel,
|
||||
action='search_movie_by_collection',
|
||||
extra=str(tmdb_tag(collection, 'id')),
|
||||
title=name,
|
||||
thumbnail=poster,
|
||||
viewmode='list',
|
||||
fanart=fanart,
|
||||
type='movie'
|
||||
))
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def search_movie_by_collection(item):
|
||||
logger.info(" search_movie_by_collection '%s'" % (item.extra))
|
||||
|
||||
collection = tmdb_get_data("collection/%s?" % item.extra)
|
||||
|
||||
# Movie collection list is not paged
|
||||
return build_movie_list(item, collection['parts']) if 'parts' in collection else []
|
||||
|
||||
|
||||
def build_movie_list(item, movies):
|
||||
if movies is None: return []
|
||||
|
||||
itemlist = []
|
||||
for movie in movies:
|
||||
t = tmdb_tag(movie, 'title')
|
||||
if t == '':
|
||||
t = re.sub('\s(|[(])(UK|US|AU|\d{4})(|[)])$', '', tmdb_tag(movie, 'name'))
|
||||
title = normalize_unicode(t)
|
||||
title_search = normalize_unicode(t, encoding='ascii')
|
||||
if not all(ord(char) < 128 for char in title): continue
|
||||
poster = tmdb_image(movie, 'poster_path')
|
||||
fanart = tmdb_image(movie, 'backdrop_path', 'w1280')
|
||||
jobrole = normalize_unicode(
|
||||
' [COLOR yellow][' + tmdb_tag(movie, 'job') + '][/COLOR]' if tmdb_tag_exists(movie, 'job') else '')
|
||||
genres = normalize_unicode(
|
||||
' / '.join([tmdb_genre(genre).upper() for genre in tmdb_tag(movie, 'genre_ids', [])]))
|
||||
year = tmdb_tag(movie, 'release_date')[0:4] if tmdb_tag_exists(movie, 'release_date') else ''
|
||||
plot = normalize_unicode(tmdb_tag(movie, 'overview'))
|
||||
rating = tmdb_tag(movie, 'vote_average')
|
||||
votes = tmdb_tag(movie, 'vote_count')
|
||||
|
||||
extrameta = {'plot': plot}
|
||||
if year != "": extrameta["Year"] = year
|
||||
if genres != "": extrameta["Genre"] = genres
|
||||
if votes:
|
||||
extrameta["Rating"] = rating
|
||||
extrameta["Votes"] = "%d" % votes
|
||||
|
||||
# extracmds = [(NLS_Info_Title, "RunScript(script.extendedinfo,info=extendedinfo,id=%s)" % str(tmdb_tag(movie, 'id')))] \
|
||||
# if xbmc.getCondVisibility('System.HasAddon(script.extendedinfo)') else [('Movie/Show Info', 'XBMC.Action(Info)')]
|
||||
|
||||
found = False
|
||||
kodi_db_movies = kodi_database_movies(title)
|
||||
for kodi_db_movie in kodi_db_movies:
|
||||
logger.info('Kod.database set for local playing(%s):\n%s' % (title, str(kodi_db_movie)))
|
||||
if year == str(kodi_db_movie["year"]):
|
||||
found = True
|
||||
|
||||
# If some, less relevant, keys are missing locally
|
||||
# try to get them through TMDB anyway.
|
||||
try:
|
||||
poster = kodi_db_movie["art"]["poster"]
|
||||
fanart = kodi_db_movie["art"]["fanart"]
|
||||
except KeyError:
|
||||
poster = poster
|
||||
fanart = fanart
|
||||
|
||||
itemlist.append(Item(
|
||||
channel=item.channel,
|
||||
action='play',
|
||||
url=kodi_db_movie["file"],
|
||||
title='[COLOR orange][%s][/COLOR] ' % NLS_Library + kodi_db_movie["title"] + jobrole,
|
||||
thumbnail=poster,
|
||||
category=genres,
|
||||
plot=plot,
|
||||
viewmode='movie_with_plot',
|
||||
fanart=fanart,
|
||||
infoLabels=extrameta,
|
||||
folder=False,
|
||||
))
|
||||
|
||||
if not found:
|
||||
logger.info('Kod.database set for channels search(%s)' % title)
|
||||
itemlist.append(Item(
|
||||
channel=item.channel,
|
||||
action='do_channels_search',
|
||||
extra=url_quote_plus(title_search) + '{}' + item.type + '{}' + year,
|
||||
title=title + jobrole,
|
||||
thumbnail=poster,
|
||||
category=genres,
|
||||
plot=plot,
|
||||
viewmode='movie_with_plot',
|
||||
fanart=fanart,
|
||||
infoLabels=extrameta,
|
||||
))
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def normalize_unicode(string, encoding='utf-8'):
|
||||
if string is None: string = ''
|
||||
return normalize('NFKD', string if isinstance(string, unicode) else unicode(string, encoding, 'ignore')).encode(
|
||||
encoding, 'ignore')
|
||||
|
||||
|
||||
def tmdb_get_data(url="", results=[0, 0], language=True):
|
||||
url = TMDB_URL_BASE + "%sinclude_adult=%s&api_key=%s" % (url, INCLUDE_ADULT, TMDB_KEY)
|
||||
# Temporary fix until tmdb fixes the issue with getting the genres by language!
|
||||
if language: url += "&language=%s" % LANGUAGE_ID
|
||||
response = get_json_response(url)
|
||||
results[0] = response['total_pages'] if 'total_pages' in response else 0
|
||||
results[1] = response['total_results'] if 'total_results' in response else 0
|
||||
|
||||
if response:
|
||||
if "results" in response:
|
||||
return response["results"]
|
||||
elif "items" in response:
|
||||
return response["items"]
|
||||
elif "tv_credits" in response:
|
||||
return response["tv_credits"]["cast"]
|
||||
else:
|
||||
return response
|
||||
|
||||
|
||||
def tmdb_tag_exists(entry, tag):
|
||||
return isinstance(entry, dict) and tag in entry and entry[tag] is not None
|
||||
|
||||
|
||||
def tmdb_tag(entry, tag, default=""):
|
||||
return entry[tag] if isinstance(entry, dict) and tag in entry else default
|
||||
|
||||
|
||||
def tmdb_image(entry, tag, width='original'):
|
||||
return TMDB_IMAGES_BASEURL + width + '/' + tmdb_tag(entry, tag) if tmdb_tag_exists(entry, tag) else ''
|
||||
|
||||
|
||||
def tmdb_genre(id):
|
||||
if id not in TMDb_genres:
|
||||
genres = tmdb_get_data("genre/list?", language="it")
|
||||
for genre in tmdb_tag(genres, 'genres', []):
|
||||
TMDb_genres[tmdb_tag(genre, 'id')] = tmdb_tag(genre, 'name')
|
||||
|
||||
return TMDb_genres[id] if id in TMDb_genres and TMDb_genres[id] != None else str(id)
|
||||
|
||||
|
||||
def kodi_database_movies(title):
|
||||
json_query = \
|
||||
'{"jsonrpc": "2.0",\
|
||||
"params": {\
|
||||
"sort": {"order": "ascending", "method": "title"},\
|
||||
"filter": {"operator": "is", "field": "title", "value": "%s"},\
|
||||
"properties": ["title", "art", "file", "year"]\
|
||||
},\
|
||||
"method": "VideoLibrary.GetMovies",\
|
||||
"id": "libMovies"\
|
||||
}' % title
|
||||
response = get_xbmc_jsonrpc_response(json_query)
|
||||
return response["result"]["movies"] if response and "result" in response and "movies" in response["result"] else []
|
||||
|
||||
|
||||
def get_xbmc_jsonrpc_response(json_query=""):
|
||||
try:
|
||||
response = xbmc.executeJSONRPC(json_query)
|
||||
response = unicode(response, 'utf-8', errors='ignore')
|
||||
response = json.loads(response)
|
||||
logger.info(" jsonrpc %s" % response)
|
||||
except Exception, e:
|
||||
logger.info(" jsonrpc error: %s" % str(e))
|
||||
response = None
|
||||
return response
|
||||
|
||||
|
||||
def url_quote_plus(input_string):
|
||||
try:
|
||||
return urllib.quote_plus(input_string.encode('utf8', 'ignore'))
|
||||
except:
|
||||
return urllib.quote_plus(unicode(input_string, "utf-8").encode("utf-8"))
|
||||
|
||||
|
||||
def get_json_response(url=""):
|
||||
response = httptools.downloadpage(url).data
|
||||
try:
|
||||
results = json.loads(response)
|
||||
except:
|
||||
logger.info(" Exception: Could not get new JSON data from %s" % url)
|
||||
results = []
|
||||
return results
|
||||
|
||||
|
||||
def channel_search(queue, channel_parameters, category, title_year, tecleado):
|
||||
try:
|
||||
search_results = []
|
||||
|
||||
title_search = urllib.unquote_plus(tecleado)
|
||||
|
||||
exec "from specials import " + channel_parameters["channel"] + " as module"
|
||||
mainlist = module.mainlist(Item(channel=channel_parameters["channel"]))
|
||||
|
||||
for item in mainlist:
|
||||
if item.action != "search" or category and item.extra != category:
|
||||
continue
|
||||
|
||||
for res_item in module.search(item.clone(), tecleado):
|
||||
title = res_item.fulltitle
|
||||
|
||||
# If the release year is known, check if it matches the year found in the title
|
||||
if title_year > 0:
|
||||
year_match = re.search('\(.*(\d{4}).*\)', title)
|
||||
if year_match and abs(int(year_match.group(1)) - title_year) > 1:
|
||||
continue
|
||||
|
||||
# Clean up a bit the returned title to improve the fuzzy matching
|
||||
title = re.sub(r'\(.*\)', '', title) # Anything within ()
|
||||
title = re.sub(r'\[.*\]', '', title) # Anything within []
|
||||
|
||||
# Check if the found title fuzzy matches the searched one
|
||||
if fuzz.token_sort_ratio(title_search, title) > 85:
|
||||
res_item.title = "[COLOR azure]" + res_item.title + "[/COLOR][COLOR orange] su [/COLOR][COLOR green]" + \
|
||||
channel_parameters["title"] + "[/COLOR]"
|
||||
search_results.append(res_item)
|
||||
|
||||
queue.put(search_results)
|
||||
|
||||
except:
|
||||
logger.error("No se puede buscar en: " + channel_parameters["title"])
|
||||
import traceback
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
def do_channels_search(item):
|
||||
logger.info(" do_channels_search")
|
||||
|
||||
tecleado, category, title_year = item.extra.split('{}')
|
||||
|
||||
try:
|
||||
title_year = int(title_year)
|
||||
except:
|
||||
title_year = 0
|
||||
|
||||
itemlist = []
|
||||
|
||||
channels_path = os.path.join(config.get_runtime_path(), "channels", '*.json')
|
||||
logger.info(" channels_path=" + channels_path)
|
||||
|
||||
# channel_language = config.get_setting("channel_language")
|
||||
channel_language = auto_filter()
|
||||
logger.info(" channel_language=" + channel_language)
|
||||
if channel_language == "":
|
||||
channel_language = "all"
|
||||
logger.info(" channel_language=" + channel_language)
|
||||
|
||||
progreso = platformtools.dialog_progress_bg(NLS_Looking_For % urllib.unquote_plus(tecleado))
|
||||
|
||||
channel_files = sorted(glob.glob(channels_path))
|
||||
|
||||
search_results = Queue.Queue()
|
||||
completed_channels = 0
|
||||
number_of_channels = 0
|
||||
|
||||
start_time = int(time.time())
|
||||
|
||||
for infile in channel_files:
|
||||
|
||||
basename_without_extension = os.path.basename(infile)[:-5]
|
||||
|
||||
channel_parameters = channeltools.get_channel_parameters(basename_without_extension)
|
||||
|
||||
# No busca si es un canal inactivo
|
||||
if channel_parameters["active"] != True:
|
||||
continue
|
||||
|
||||
# En caso de busqueda por categorias
|
||||
if category and category not in channel_parameters["categories"]:
|
||||
continue
|
||||
|
||||
# No busca si el canal es en un idioma filtrado
|
||||
if channel_language != "all" and channel_parameters["language"] != channel_language:
|
||||
continue
|
||||
|
||||
# No busca si es un canal excluido de la busqueda global
|
||||
include_in_global_search = channel_parameters["include_in_global_search"]
|
||||
if include_in_global_search == True:
|
||||
# Buscar en la configuracion del canal
|
||||
include_in_global_search = config.get_setting("include_in_global_search", basename_without_extension)
|
||||
if include_in_global_search == False:
|
||||
continue
|
||||
|
||||
t = Thread(target=channel_search, args=[search_results, channel_parameters, category, title_year, tecleado])
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
number_of_channels += 1
|
||||
|
||||
while threading.active_count() >= MAX_THREADS:
|
||||
|
||||
delta_time = int(time.time()) - start_time
|
||||
if len(itemlist) <= 0:
|
||||
timeout = None # No result so far,lets the thread to continue working until a result is returned
|
||||
elif delta_time >= TIMEOUT_TOTAL:
|
||||
progreso.close()
|
||||
itemlist = sorted(itemlist, key=lambda item: item.fulltitle)
|
||||
return itemlist
|
||||
else:
|
||||
timeout = TIMEOUT_TOTAL - delta_time # Still time to gather other results
|
||||
|
||||
progreso.update(completed_channels * 100 / number_of_channels)
|
||||
|
||||
try:
|
||||
itemlist.extend(search_results.get(timeout=timeout))
|
||||
completed_channels += 1
|
||||
except:
|
||||
progreso.close()
|
||||
itemlist = sorted(itemlist, key=lambda item: item.fulltitle)
|
||||
return itemlist
|
||||
|
||||
while completed_channels < number_of_channels:
|
||||
|
||||
delta_time = int(time.time()) - start_time
|
||||
if len(itemlist) <= 0:
|
||||
timeout = None # No result so far,lets the thread to continue working until a result is returned
|
||||
elif delta_time >= TIMEOUT_TOTAL:
|
||||
break # At least a result matching the searched title has been found, lets stop the search
|
||||
else:
|
||||
timeout = TIMEOUT_TOTAL - delta_time # Still time to gather other results
|
||||
|
||||
progreso.update(completed_channels * 100 / number_of_channels)
|
||||
|
||||
try:
|
||||
itemlist.extend(search_results.get(timeout=timeout))
|
||||
completed_channels += 1
|
||||
except:
|
||||
# Expired timeout raise an exception
|
||||
break
|
||||
|
||||
progreso.close()
|
||||
|
||||
# todo 1 : impostare una visualizzazione % di avanzamento (serve?)
|
||||
# todo 2 : verificare la formattazione dei titoli estratti
|
||||
# todo 3 : gestione numero threads e timeout
|
||||
if config.get_setting("findlinks") == True and "{}movie{}" in item.extra:
|
||||
itemlist = links_list(itemlist)
|
||||
itemlist = sorted(itemlist, key=lambda item: item.title.lower())
|
||||
else:
|
||||
itemlist = sorted(itemlist, key=lambda item: item.fulltitle)
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def links_list(itemlist):
|
||||
logger.info(" links_list")
|
||||
itemlistresults = []
|
||||
itemlistlist = []
|
||||
allthreads = []
|
||||
global_search_results = Queue.Queue()
|
||||
|
||||
# create and collect threads
|
||||
for item in itemlist:
|
||||
t = Thread(target=list_single_site, args=[global_search_results, item])
|
||||
t.setDaemon(True)
|
||||
allthreads.append(t)
|
||||
|
||||
# start threads
|
||||
for thread in allthreads:
|
||||
try:
|
||||
thread.start()
|
||||
except:
|
||||
logger.error("thread error !")
|
||||
|
||||
# join threads, to wait all threads end before going on
|
||||
for thread in allthreads:
|
||||
thread.join()
|
||||
|
||||
# collect results
|
||||
while not global_search_results.empty():
|
||||
for item in global_search_results.get():
|
||||
if not item_url_in_itemlist(item, itemlistresults):
|
||||
channelformatteditem = rewrite_item_title(item)
|
||||
if channelformatteditem is not None:
|
||||
itemlistresults.append(channelformatteditem)
|
||||
|
||||
return itemlistresults
|
||||
|
||||
|
||||
def list_single_site(queue, item):
|
||||
logger.info(" list_single_site")
|
||||
channelitemlist = []
|
||||
try:
|
||||
# logger.info(item.channel + " start channel search " + time.strftime("%Y-%m-%d %H:%M:%S"))
|
||||
module_to_call = getattr(__import__("channels"), item.channel)
|
||||
channelitemlist = module_to_call.findvideos(item)
|
||||
queue.put(channelitemlist)
|
||||
# logger.info(item.channel + " end channel search " + time.strftime("%Y-%m-%d %H:%M:%S"))
|
||||
except:
|
||||
try:
|
||||
# logger.info(item.channel + " start servertools search " + time.strftime("%Y-%m-%d %H:%M:%S"))
|
||||
# logger.info("no findvideos defined in channel functions, calling servertools.findvideos to find links")
|
||||
servertools_itemlist = []
|
||||
headers = [['Referer', item.channel]]
|
||||
data = httptools.downloadpage(item.url, headers=headers).data
|
||||
list_servertools = servertools.findvideos(data)
|
||||
for item_servertools in list_servertools:
|
||||
servertools_itemlist.append(Item(channel=item.channel,
|
||||
action="play",
|
||||
fulltitle=item.title,
|
||||
server=item_servertools[0],
|
||||
thumbnail=item_servertools[3],
|
||||
title=item.title,
|
||||
url=item_servertools[1]))
|
||||
queue.put(servertools_itemlist)
|
||||
# logger.info(item.channel + " end servertools search " + time.strftime("%Y-%m-%d %H:%M:%S"))
|
||||
except Exception, e:
|
||||
logger.error('exception in list_single_site: ' + str(e))
|
||||
return channelitemlist
|
||||
|
||||
|
||||
# utility function
|
||||
def item_url_in_itemlist(item, itemlist):
|
||||
logger.info(" item_url_in_itemlist")
|
||||
i = 0
|
||||
while i < len(itemlist):
|
||||
if itemlist[i].url == item.url:
|
||||
# logger.info("elemento eliminato : " + item.url)
|
||||
return True
|
||||
i = i + 1
|
||||
return False
|
||||
|
||||
|
||||
# utility function, optional
|
||||
def rewrite_item_title(item):
|
||||
logger.info(" rewrite_item_title")
|
||||
if "download" not in item.title.lower():
|
||||
item.title = "[COLOR yellow][%s][/COLOR][COLOR orange][%s][/COLOR] %s" % (
|
||||
item.server, item.channel, item.fulltitle)
|
||||
else:
|
||||
return None
|
||||
return item
|
||||
@@ -0,0 +1,745 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ------------------------------------------------------------
|
||||
# Configuracion
|
||||
# ------------------------------------------------------------
|
||||
|
||||
from channelselector import get_thumb
|
||||
from core import filetools
|
||||
from core import servertools
|
||||
from core.item import Item
|
||||
from platformcode import config, logger
|
||||
from platformcode import platformtools
|
||||
|
||||
CHANNELNAME = "setting"
|
||||
|
||||
|
||||
def mainlist(item):
|
||||
logger.info()
|
||||
|
||||
itemlist = list()
|
||||
itemlist.append(Item(channel=CHANNELNAME, title=config.get_localized_string(60535), action="settings", folder=False,
|
||||
thumbnail=get_thumb("setting_0.png")))
|
||||
|
||||
itemlist.append(Item(channel=CHANNELNAME, title="", action="", folder=False, thumbnail=get_thumb("setting_0.png")))
|
||||
|
||||
itemlist.append(Item(channel=CHANNELNAME, title=config.get_localized_string(60536) + ":", text_bold=True, action="", folder=False,
|
||||
thumbnail=get_thumb("setting_0.png")))
|
||||
itemlist.append(Item(channel=CHANNELNAME, title=" " + config.get_localized_string(60537), action="menu_channels", folder=True,
|
||||
thumbnail=get_thumb("channels.png")))
|
||||
itemlist.append(Item(channel=CHANNELNAME, title=" " + config.get_localized_string(60538), action="menu_servers", folder=True,
|
||||
thumbnail=get_thumb("channels.png")))
|
||||
itemlist.append(Item(channel="news", title=" " + config.get_localized_string(60539), action="menu_opciones",
|
||||
folder=True, thumbnail=get_thumb("news.png")))
|
||||
itemlist.append(Item(channel="search", title=" " + config.get_localized_string(60540), action="opciones", folder=True,
|
||||
thumbnail=get_thumb("search.png")))
|
||||
itemlist.append(Item(channel=CHANNELNAME, title=" " + config.get_localized_string(60541), action="channel_config",
|
||||
config="downloads", folder=True, thumbnail=get_thumb("downloads.png")))
|
||||
|
||||
if config.get_videolibrary_support():
|
||||
itemlist.append(Item(channel="videolibrary", title=" " + config.get_localized_string(60542), action="channel_config",
|
||||
folder=True, thumbnail=get_thumb("videolibrary.png")))
|
||||
|
||||
if config.is_xbmc():
|
||||
itemlist.append(Item(channel=CHANNELNAME, title=" " + config.get_localized_string(70253), action="setting_torrent",
|
||||
folder=True, thumbnail=get_thumb("channels_torrent.png")))
|
||||
|
||||
itemlist.append(Item(channel=CHANNELNAME, action="", title="", folder=False, thumbnail=get_thumb("setting_0.png")))
|
||||
itemlist.append(Item(channel=CHANNELNAME, title=config.get_localized_string(60544), action="submenu_tools", folder=True,
|
||||
thumbnail=get_thumb("setting_0.png")))
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def menu_channels(item):
|
||||
logger.info()
|
||||
itemlist = list()
|
||||
|
||||
itemlist.append(Item(channel=CHANNELNAME, title=config.get_localized_string(60545), action="conf_tools", folder=False,
|
||||
extra="channels_onoff", thumbnail=get_thumb("setting_0.png")))
|
||||
|
||||
itemlist.append(Item(channel=CHANNELNAME, title=config.get_localized_string(60546) + ":", action="", folder=False,
|
||||
text_bold = True, thumbnail=get_thumb("setting_0.png")))
|
||||
|
||||
# Inicio - Canales configurables
|
||||
import channelselector
|
||||
from core import channeltools
|
||||
channel_list = channelselector.filterchannels("all")
|
||||
for channel in channel_list:
|
||||
channel_parameters = channeltools.get_channel_parameters(channel.channel)
|
||||
if channel_parameters["has_settings"]:
|
||||
itemlist.append(Item(channel=CHANNELNAME, title=". " + config.get_localized_string(60547) % channel.title,
|
||||
action="channel_config", config=channel.channel, folder=False,
|
||||
thumbnail=channel.thumbnail))
|
||||
# Fin - Canales configurables
|
||||
itemlist.append(Item(channel=CHANNELNAME, action="", title="", folder=False, thumbnail=get_thumb("setting_0.png")))
|
||||
itemlist.append(Item(channel=CHANNELNAME, title=config.get_localized_string(60548) + ":", action="", folder=False,
|
||||
text_bold=True, thumbnail=get_thumb("channels.png")))
|
||||
itemlist.append(Item(channel=CHANNELNAME, title=". " + config.get_localized_string(60549), action="conf_tools",
|
||||
folder=True, extra="lib_check_datajson", thumbnail=get_thumb("channels.png")))
|
||||
return itemlist
|
||||
|
||||
|
||||
def channel_config(item):
|
||||
return platformtools.show_channel_settings(channelpath=filetools.join(config.get_runtime_path(), "channels",
|
||||
item.config))
|
||||
|
||||
|
||||
def setting_torrent(item):
|
||||
logger.info()
|
||||
|
||||
default = config.get_setting("torrent_client", server="torrent", default=0)
|
||||
|
||||
torrent_options = [config.get_localized_string(30006), config.get_localized_string(70254), config.get_localized_string(70255)]
|
||||
torrent_options.extend(platformtools.torrent_client_installed())
|
||||
|
||||
list_controls = [
|
||||
{
|
||||
"id": "list_torrent",
|
||||
"type": "list",
|
||||
"label": config.get_localized_string(70256),
|
||||
"default": default,
|
||||
"enabled": True,
|
||||
"visible": True,
|
||||
"lvalues": torrent_options
|
||||
}
|
||||
]
|
||||
|
||||
platformtools.show_channel_settings(list_controls=list_controls, callback='save_setting_torrent', item=item,
|
||||
caption=config.get_localized_string(70257), custom_button={'visible': False})
|
||||
|
||||
|
||||
def save_setting_torrent(item, dict_data_saved):
|
||||
if dict_data_saved and "list_torrent" in dict_data_saved:
|
||||
config.set_setting("torrent_client", dict_data_saved["list_torrent"], server="torrent")
|
||||
|
||||
def menu_servers(item):
|
||||
logger.info()
|
||||
itemlist = list()
|
||||
|
||||
itemlist.append(Item(channel=CHANNELNAME, title=config.get_localized_string(60550), action="servers_blacklist", folder=False,
|
||||
thumbnail=get_thumb("setting_0.png")))
|
||||
|
||||
itemlist.append(Item(channel=CHANNELNAME, title=config.get_localized_string(60551),
|
||||
action="servers_favorites", folder=False, thumbnail=get_thumb("setting_0.png")))
|
||||
|
||||
itemlist.append(Item(channel=CHANNELNAME, title=config.get_localized_string(60552),
|
||||
action="", folder=False, text_bold = True, thumbnail=get_thumb("setting_0.png")))
|
||||
|
||||
# Inicio - Servidores configurables
|
||||
|
||||
server_list = servertools.get_debriders_list().keys()
|
||||
for server in server_list:
|
||||
server_parameters = servertools.get_server_parameters(server)
|
||||
if server_parameters["has_settings"]:
|
||||
itemlist.append(
|
||||
Item(channel=CHANNELNAME, title = ". " + config.get_localized_string(60553) % server_parameters["name"],
|
||||
action="server_config", config=server, folder=False, thumbnail=""))
|
||||
|
||||
itemlist.append(Item(channel=CHANNELNAME, title=config.get_localized_string(60554),
|
||||
action="", folder=False, text_bold = True, thumbnail=get_thumb("setting_0.png")))
|
||||
|
||||
server_list = servertools.get_servers_list().keys()
|
||||
|
||||
for server in sorted(server_list):
|
||||
server_parameters = servertools.get_server_parameters(server)
|
||||
logger.info(server_parameters)
|
||||
if server_parameters["has_settings"] and filter(lambda x: x["id"] not in ["black_list", "white_list"],
|
||||
server_parameters["settings"]):
|
||||
itemlist.append(
|
||||
Item(channel=CHANNELNAME, title=". " + config.get_localized_string(60553) % server_parameters["name"],
|
||||
action="server_config", config=server, folder=False, thumbnail=""))
|
||||
|
||||
# Fin - Servidores configurables
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def server_config(item):
|
||||
return platformtools.show_channel_settings(channelpath=filetools.join(config.get_runtime_path(), "servers",
|
||||
item.config))
|
||||
|
||||
|
||||
def servers_blacklist(item):
|
||||
server_list = servertools.get_servers_list()
|
||||
dict_values = {}
|
||||
|
||||
list_controls = [{"id": "filter_servers",
|
||||
"type": "bool",
|
||||
"label": "@30068",
|
||||
"default": False,
|
||||
"enabled": True,
|
||||
"visible": True}]
|
||||
dict_values['filter_servers'] = config.get_setting('filter_servers')
|
||||
if dict_values['filter_servers'] == None:
|
||||
dict_values['filter_servers'] = False
|
||||
for i, server in enumerate(sorted(server_list.keys())):
|
||||
server_parameters = server_list[server]
|
||||
controls, defaults = servertools.get_server_controls_settings(server)
|
||||
dict_values[server] = config.get_setting("black_list", server=server)
|
||||
|
||||
control = {"id": server,
|
||||
"type": "bool",
|
||||
"label": ' %s' % server_parameters["name"],
|
||||
"default": defaults.get("black_list", False),
|
||||
"enabled": "eq(-%s,True)" % (i + 1),
|
||||
"visible": True}
|
||||
list_controls.append(control)
|
||||
|
||||
return platformtools.show_channel_settings(list_controls=list_controls, dict_values=dict_values,
|
||||
caption=config.get_localized_string(60550), callback="cb_servers_blacklist")
|
||||
|
||||
|
||||
def cb_servers_blacklist(item, dict_values):
|
||||
f = False
|
||||
progreso = platformtools.dialog_progress(config.get_localized_string(60557), config.get_localized_string(60558))
|
||||
n = len(dict_values)
|
||||
i = 1
|
||||
for k, v in dict_values.items():
|
||||
if k == 'filter_servers':
|
||||
config.set_setting('filter_servers', v)
|
||||
else:
|
||||
config.set_setting("black_list", v, server=k)
|
||||
if v: # Si el servidor esta en la lista negra no puede estar en la de favoritos
|
||||
config.set_setting("favorites_servers_list", 100, server=k)
|
||||
f = True
|
||||
progreso.update((i * 100) / n, config.get_localized_string(60559) % k)
|
||||
i += 1
|
||||
|
||||
if not f: # Si no hay ningun servidor en la lista, desactivarla
|
||||
config.set_setting('filter_servers', False)
|
||||
|
||||
progreso.close()
|
||||
|
||||
|
||||
def servers_favorites(item):
|
||||
server_list = servertools.get_servers_list()
|
||||
dict_values = {}
|
||||
|
||||
list_controls = [{'id': 'favorites_servers',
|
||||
'type': "bool",
|
||||
'label': config.get_localized_string(60577),
|
||||
'default': False,
|
||||
'enabled': True,
|
||||
'visible': True}]
|
||||
dict_values['favorites_servers'] = config.get_setting('favorites_servers')
|
||||
if dict_values['favorites_servers'] == None:
|
||||
dict_values['favorites_servers'] = False
|
||||
|
||||
server_names = [config.get_localized_string(59992)]
|
||||
|
||||
for server in sorted(server_list.keys()):
|
||||
if config.get_setting("black_list", server=server):
|
||||
continue
|
||||
|
||||
server_names.append(server_list[server]['name'])
|
||||
|
||||
orden = config.get_setting("favorites_servers_list", server=server)
|
||||
|
||||
if orden > 0:
|
||||
dict_values[orden] = len(server_names) - 1
|
||||
|
||||
for x in range(1, 6):
|
||||
control = {'id': x,
|
||||
'type': "list",
|
||||
'label': config.get_localized_string(60597) % x,
|
||||
'lvalues': server_names,
|
||||
'default': 0,
|
||||
'enabled': "eq(-%s,True)" % x,
|
||||
'visible': True}
|
||||
list_controls.append(control)
|
||||
|
||||
return platformtools.show_channel_settings(list_controls=list_controls, dict_values=dict_values, item=server_names,
|
||||
caption=config.get_localized_string(60551), callback="cb_servers_favorites")
|
||||
|
||||
|
||||
def cb_servers_favorites(server_names, dict_values):
|
||||
dict_name = {}
|
||||
progreso = platformtools.dialog_progress(config.get_localized_string(60557), config.get_localized_string(60558))
|
||||
|
||||
for i, v in dict_values.items():
|
||||
if i == "favorites_servers":
|
||||
config.set_setting("favorites_servers", v)
|
||||
elif int(v) > 0:
|
||||
dict_name[server_names[v]] = int(i)
|
||||
|
||||
servers_list = servertools.get_servers_list().items()
|
||||
n = len(servers_list)
|
||||
i = 1
|
||||
for server, server_parameters in servers_list:
|
||||
if server_parameters['name'] in dict_name.keys():
|
||||
config.set_setting("favorites_servers_list", dict_name[server_parameters['name']], server=server)
|
||||
else:
|
||||
config.set_setting("favorites_servers_list", 0, server=server)
|
||||
progreso.update((i * 100) / n, config.get_localized_string(60559) % server_parameters['name'])
|
||||
i += 1
|
||||
|
||||
if not dict_name: # Si no hay ningun servidor en lalista desactivarla
|
||||
config.set_setting("favorites_servers", False)
|
||||
|
||||
progreso.close()
|
||||
|
||||
|
||||
def settings(item):
|
||||
config.open_settings()
|
||||
|
||||
|
||||
def submenu_tools(item):
|
||||
logger.info()
|
||||
itemlist = list()
|
||||
|
||||
# Herramientas personalizadas
|
||||
import os
|
||||
channel_custom = os.path.join(config.get_runtime_path(), 'channels', 'custom.py')
|
||||
if not filetools.exists(channel_custom):
|
||||
user_custom = os.path.join(config.get_data_path(), 'custom.py')
|
||||
if filetools.exists(user_custom):
|
||||
filetools.copy(user_custom, channel_custom, silent=True)
|
||||
if filetools.exists(channel_custom):
|
||||
itemlist.append(Item(channel='custom', action='mainlist', title='Custom Channel'))
|
||||
|
||||
|
||||
#Disabilitato il menu degli aggiornamenti
|
||||
#itemlist.append(Item(channel=CHANNELNAME, action="check_quickfixes", folder=False,
|
||||
# title=config.get_localized_string(30001), plot="Versión actual: %s" % config.get_addon_version() ))
|
||||
itemlist.append(Item(channel=CHANNELNAME, action="update_quasar", folder=False,
|
||||
title=config.get_localized_string(70569)))
|
||||
itemlist.append(Item(channel=CHANNELNAME, action="", title="", folder=False,
|
||||
thumbnail=get_thumb("setting_0.png")))
|
||||
|
||||
itemlist.append(Item(channel=CHANNELNAME, title=config.get_localized_string(60564) + ":", action="", folder=False,
|
||||
text_bold=True, thumbnail=get_thumb("channels.png")))
|
||||
itemlist.append(Item(channel=CHANNELNAME, title=config.get_localized_string(60565), action="conf_tools",
|
||||
folder=True, extra="lib_check_datajson", thumbnail=get_thumb("channels.png")))
|
||||
|
||||
if config.get_videolibrary_support():
|
||||
itemlist.append(Item(channel=CHANNELNAME, action="", title="", folder=False,
|
||||
thumbnail=get_thumb("setting_0.png")))
|
||||
itemlist.append(Item(channel=CHANNELNAME, title=config.get_localized_string(60566) + ":", action="", folder=False,
|
||||
text_bold=True, thumbnail=get_thumb("videolibrary.png")))
|
||||
itemlist.append(Item(channel=CHANNELNAME, action="overwrite_tools", folder=False,
|
||||
thumbnail=get_thumb("videolibrary.png"),
|
||||
title="- " + config.get_localized_string(60567)))
|
||||
itemlist.append(Item(channel="videolibrary", action="update_videolibrary", folder=False,
|
||||
thumbnail=get_thumb("videolibrary.png"),
|
||||
title="- " + config.get_localized_string(60568)))
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def check_quickfixes(item):
|
||||
logger.info()
|
||||
|
||||
if not os.path.isfile(config.get_runtime_path() + '/.dev'):
|
||||
logger.info("DEV MODE OFF")
|
||||
from platformcode import updater
|
||||
return updater.check_addon_updates(verbose=True)
|
||||
else:
|
||||
logger.info("DEV MODE ON")
|
||||
|
||||
|
||||
def update_quasar(item):
|
||||
logger.info()
|
||||
|
||||
from platformcode import custom_code, platformtools
|
||||
stat = False
|
||||
stat = custom_code.update_external_addon("quasar")
|
||||
if stat:
|
||||
platformtools.dialog_notification("Actualización Quasar", "Realizada con éxito")
|
||||
else:
|
||||
platformtools.dialog_notification("Actualización Quasar", "Ha fallado. Consulte el log")
|
||||
|
||||
|
||||
def conf_tools(item):
|
||||
logger.info()
|
||||
|
||||
# Activar o desactivar canales
|
||||
if item.extra == "channels_onoff":
|
||||
if config.get_platform(True)['num_version'] >= 17.0: # A partir de Kodi 16 se puede usar multiselect, y de 17 con preselect
|
||||
return channels_onoff(item)
|
||||
|
||||
import channelselector
|
||||
from core import channeltools
|
||||
|
||||
channel_list = channelselector.filterchannels("allchannelstatus")
|
||||
|
||||
excluded_channels = ['url',
|
||||
'search',
|
||||
'videolibrary',
|
||||
'setting',
|
||||
'news',
|
||||
# 'help',
|
||||
'downloads']
|
||||
|
||||
list_controls = []
|
||||
try:
|
||||
list_controls.append({'id': "all_channels",
|
||||
'type': "list",
|
||||
'label': config.get_localized_string(60594),
|
||||
'default': 0,
|
||||
'enabled': True,
|
||||
'visible': True,
|
||||
'lvalues': ['',
|
||||
config.get_localized_string(60591),
|
||||
config.get_localized_string(60592),
|
||||
config.get_localized_string(60593)]})
|
||||
|
||||
for channel in channel_list:
|
||||
# Si el canal esta en la lista de exclusiones lo saltamos
|
||||
if channel.channel not in excluded_channels:
|
||||
|
||||
channel_parameters = channeltools.get_channel_parameters(channel.channel)
|
||||
|
||||
status_control = ""
|
||||
status = config.get_setting("enabled", channel.channel)
|
||||
# si status no existe es que NO HAY valor en _data.json
|
||||
if status is None:
|
||||
status = channel_parameters["active"]
|
||||
logger.debug("%s | Status (XML): %s" % (channel.channel, status))
|
||||
if not status:
|
||||
status_control = config.get_localized_string(60595)
|
||||
else:
|
||||
logger.debug("%s | Status: %s" % (channel.channel, status))
|
||||
|
||||
control = {'id': channel.channel,
|
||||
'type': "bool",
|
||||
'label': channel_parameters["title"] + status_control,
|
||||
'default': status,
|
||||
'enabled': True,
|
||||
'visible': True}
|
||||
list_controls.append(control)
|
||||
|
||||
else:
|
||||
continue
|
||||
|
||||
except:
|
||||
import traceback
|
||||
logger.error("Error: %s" % traceback.format_exc())
|
||||
else:
|
||||
return platformtools.show_channel_settings(list_controls=list_controls,
|
||||
item=item.clone(channel_list=channel_list),
|
||||
caption=config.get_localized_string(60596),
|
||||
callback="channel_status",
|
||||
custom_button={"visible": False})
|
||||
|
||||
# Comprobacion de archivos channel_data.json
|
||||
elif item.extra == "lib_check_datajson":
|
||||
itemlist = []
|
||||
import channelselector
|
||||
from core import channeltools
|
||||
channel_list = channelselector.filterchannels("allchannelstatus")
|
||||
|
||||
# Tener una lista de exclusion no tiene mucho sentido por que se comprueba si channel.json tiene "settings",
|
||||
# pero por si acaso se deja
|
||||
excluded_channels = ['url',
|
||||
'setting',
|
||||
'help']
|
||||
|
||||
try:
|
||||
import os
|
||||
from core import jsontools
|
||||
for channel in channel_list:
|
||||
|
||||
list_status = None
|
||||
default_settings = None
|
||||
|
||||
# Se comprueba si el canal esta en la lista de exclusiones
|
||||
if channel.channel not in excluded_channels:
|
||||
# Se comprueba que tenga "settings", sino se salta
|
||||
list_controls, dict_settings = channeltools.get_channel_controls_settings(channel.channel)
|
||||
|
||||
if not list_controls:
|
||||
itemlist.append(Item(channel=CHANNELNAME,
|
||||
title=channel.title + config.get_localized_string(60569),
|
||||
action="", folder=False,
|
||||
thumbnail=channel.thumbnail))
|
||||
continue
|
||||
# logger.info(channel.channel + " SALTADO!")
|
||||
|
||||
# Se cargan los ajustes del archivo json del canal
|
||||
file_settings = os.path.join(config.get_data_path(), "settings_channels",
|
||||
channel.channel + "_data.json")
|
||||
dict_settings = {}
|
||||
dict_file = {}
|
||||
if filetools.exists(file_settings):
|
||||
# logger.info(channel.channel + " Tiene archivo _data.json")
|
||||
channeljson_exists = True
|
||||
# Obtenemos configuracion guardada de ../settings/channel_data.json
|
||||
try:
|
||||
dict_file = jsontools.load(open(file_settings, "rb").read())
|
||||
if isinstance(dict_file, dict) and 'settings' in dict_file:
|
||||
dict_settings = dict_file['settings']
|
||||
except EnvironmentError:
|
||||
logger.error("ERROR al leer el archivo: %s" % file_settings)
|
||||
else:
|
||||
# logger.info(channel.channel + " No tiene archivo _data.json")
|
||||
channeljson_exists = False
|
||||
|
||||
if channeljson_exists:
|
||||
try:
|
||||
datajson_size = filetools.getsize(file_settings)
|
||||
except:
|
||||
import traceback
|
||||
logger.error(channel.title + config.get_localized_string(60570) % traceback.format_exc())
|
||||
else:
|
||||
datajson_size = None
|
||||
|
||||
# Si el _data.json esta vacio o no existe...
|
||||
if (len(dict_settings) and datajson_size) == 0 or not channeljson_exists:
|
||||
# Obtenemos controles del archivo ../channels/channel.json
|
||||
needsfix = True
|
||||
try:
|
||||
# Se cargan los ajustes por defecto
|
||||
list_controls, default_settings = channeltools.get_channel_controls_settings(
|
||||
channel.channel)
|
||||
# logger.info(channel.title + " | Default: %s" % default_settings)
|
||||
except:
|
||||
import traceback
|
||||
logger.error(channel.title + config.get_localized_string(60570) % traceback.format_exc())
|
||||
# default_settings = {}
|
||||
|
||||
# Si _data.json necesita ser reparado o no existe...
|
||||
if needsfix or not channeljson_exists:
|
||||
if default_settings is not None:
|
||||
# Creamos el channel_data.json
|
||||
default_settings.update(dict_settings)
|
||||
dict_settings = default_settings
|
||||
dict_file['settings'] = dict_settings
|
||||
# Creamos el archivo ../settings/channel_data.json
|
||||
json_data = jsontools.dump(dict_file)
|
||||
try:
|
||||
open(file_settings, "wb").write(json_data)
|
||||
# logger.info(channel.channel + " - Archivo _data.json GUARDADO!")
|
||||
# El channel_data.json se ha creado/modificado
|
||||
list_status = config.get_localized_string(60560)
|
||||
except EnvironmentError:
|
||||
logger.error("ERROR al salvar el archivo: %s" % file_settings)
|
||||
else:
|
||||
if default_settings is None:
|
||||
list_status = config.get_localized_string(60571)
|
||||
|
||||
else:
|
||||
# logger.info(channel.channel + " - NO necesita correccion!")
|
||||
needsfix = False
|
||||
|
||||
# Si se ha establecido el estado del canal se añade a la lista
|
||||
if needsfix is not None:
|
||||
if needsfix:
|
||||
if not channeljson_exists:
|
||||
list_status = config.get_localized_string(60588)
|
||||
list_colour = "red"
|
||||
else:
|
||||
list_status = config.get_localized_string(60589)
|
||||
list_colour = "green"
|
||||
else:
|
||||
# Si "needsfix" es "false" y "datjson_size" es None habra
|
||||
# ocurrido algun error
|
||||
if datajson_size is None:
|
||||
list_status = config.get_localized_string(60590)
|
||||
list_colour = "red"
|
||||
else:
|
||||
list_status = config.get_localized_string(60589)
|
||||
list_colour = "green"
|
||||
|
||||
if list_status is not None:
|
||||
itemlist.append(Item(channel=CHANNELNAME,
|
||||
title=channel.title + list_status,
|
||||
action="", folder=False,
|
||||
thumbnail=channel.thumbnail,
|
||||
text_color=list_colour))
|
||||
else:
|
||||
logger.error("Algo va mal con el canal %s" % channel.channel)
|
||||
|
||||
# Si el canal esta en la lista de exclusiones lo saltamos
|
||||
else:
|
||||
continue
|
||||
except:
|
||||
import traceback
|
||||
logger.error("Error: %s" % traceback.format_exc())
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def channels_onoff(item):
|
||||
import channelselector, xbmcgui
|
||||
from core import channeltools
|
||||
|
||||
# Cargar lista de opciones
|
||||
# ------------------------
|
||||
lista = []; ids = []
|
||||
channels_list = channelselector.filterchannels('allchannelstatus')
|
||||
for channel in channels_list:
|
||||
channel_parameters = channeltools.get_channel_parameters(channel.channel)
|
||||
lbl = '%s' % channel_parameters['language']
|
||||
# ~ lbl += ' %s' % [config.get_localized_category(categ) for categ in channel_parameters['categories']]
|
||||
lbl += ' %s' % ', '.join(config.get_localized_category(categ) for categ in channel_parameters['categories'])
|
||||
|
||||
it = xbmcgui.ListItem(channel.title, lbl)
|
||||
it.setArt({ 'thumb': channel.thumbnail, 'fanart': channel.fanart })
|
||||
lista.append(it)
|
||||
ids.append(channel.channel)
|
||||
|
||||
# Diálogo para pre-seleccionar
|
||||
# ----------------------------
|
||||
preselecciones = [config.get_localized_string(70517), config.get_localized_string(70518), config.get_localized_string(70519)]
|
||||
ret = platformtools.dialog_select(config.get_localized_string(60545), preselecciones)
|
||||
if ret == -1: return False # pedido cancel
|
||||
if ret == 2: preselect = []
|
||||
elif ret == 1: preselect = range(len(ids))
|
||||
else:
|
||||
preselect = []
|
||||
for i, canal in enumerate(ids):
|
||||
channel_status = config.get_setting('enabled', canal)
|
||||
if channel_status is None: channel_status = True
|
||||
if channel_status:
|
||||
preselect.append(i)
|
||||
|
||||
# Diálogo para seleccionar
|
||||
# ------------------------
|
||||
ret = xbmcgui.Dialog().multiselect(config.get_localized_string(60545), lista, preselect=preselect, useDetails=True)
|
||||
if ret == None: return False # pedido cancel
|
||||
seleccionados = [ids[i] for i in ret]
|
||||
|
||||
# Guardar cambios en canales activados
|
||||
# ------------------------------------
|
||||
for canal in ids:
|
||||
channel_status = config.get_setting('enabled', canal)
|
||||
if channel_status is None: channel_status = True
|
||||
|
||||
if channel_status and canal not in seleccionados:
|
||||
config.set_setting('enabled', False, canal)
|
||||
elif not channel_status and canal in seleccionados:
|
||||
config.set_setting('enabled', True, canal)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def channel_status(item, dict_values):
|
||||
try:
|
||||
for k in dict_values:
|
||||
|
||||
if k == "all_channels":
|
||||
logger.info("Todos los canales | Estado seleccionado: %s" % dict_values[k])
|
||||
if dict_values[k] != 0:
|
||||
excluded_channels = ['url', 'search',
|
||||
'videolibrary', 'setting',
|
||||
'news',
|
||||
'help',
|
||||
'downloads']
|
||||
|
||||
for channel in item.channel_list:
|
||||
if channel.channel not in excluded_channels:
|
||||
from core import channeltools
|
||||
channel_parameters = channeltools.get_channel_parameters(channel.channel)
|
||||
new_status_all = None
|
||||
new_status_all_default = channel_parameters["active"]
|
||||
|
||||
# Opcion Activar todos
|
||||
if dict_values[k] == 1:
|
||||
new_status_all = True
|
||||
|
||||
# Opcion Desactivar todos
|
||||
if dict_values[k] == 2:
|
||||
new_status_all = False
|
||||
|
||||
# Opcion Recuperar estado por defecto
|
||||
if dict_values[k] == 3:
|
||||
# Si tiene "enabled" en el _data.json es porque el estado no es el del channel.json
|
||||
if config.get_setting("enabled", channel.channel):
|
||||
new_status_all = new_status_all_default
|
||||
|
||||
# Si el canal no tiene "enabled" en el _data.json no se guarda, se pasa al siguiente
|
||||
else:
|
||||
continue
|
||||
|
||||
# Se guarda el estado del canal
|
||||
if new_status_all is not None:
|
||||
config.set_setting("enabled", new_status_all, channel.channel)
|
||||
break
|
||||
else:
|
||||
continue
|
||||
|
||||
else:
|
||||
logger.info("Canal: %s | Estado: %s" % (k, dict_values[k]))
|
||||
config.set_setting("enabled", dict_values[k], k)
|
||||
logger.info("el valor esta como %s " % config.get_setting("enabled", k))
|
||||
|
||||
platformtools.itemlist_update(Item(channel=CHANNELNAME, action="mainlist"))
|
||||
|
||||
except:
|
||||
import traceback
|
||||
logger.error("Detalle del error: %s" % traceback.format_exc())
|
||||
platformtools.dialog_notification(config.get_localized_string(60579), config.get_localized_string(60580))
|
||||
|
||||
|
||||
def overwrite_tools(item):
|
||||
import videolibrary_service
|
||||
from core import videolibrarytools
|
||||
|
||||
seleccion = platformtools.dialog_yesno(config.get_localized_string(60581),
|
||||
config.get_localized_string(60582),
|
||||
config.get_localized_string(60583))
|
||||
if seleccion == 1:
|
||||
# tvshows
|
||||
heading = config.get_localized_string(60584)
|
||||
p_dialog = platformtools.dialog_progress_bg(config.get_localized_string(60585), heading)
|
||||
p_dialog.update(0, '')
|
||||
|
||||
show_list = []
|
||||
for path, folders, files in filetools.walk(videolibrarytools.TVSHOWS_PATH):
|
||||
show_list.extend([filetools.join(path, f) for f in files if f == "tvshow.nfo"])
|
||||
|
||||
if show_list:
|
||||
t = float(100) / len(show_list)
|
||||
|
||||
for i, tvshow_file in enumerate(show_list):
|
||||
head_nfo, serie = videolibrarytools.read_nfo(tvshow_file)
|
||||
path = filetools.dirname(tvshow_file)
|
||||
|
||||
if not serie.active:
|
||||
# si la serie no esta activa descartar
|
||||
continue
|
||||
|
||||
# Eliminamos la carpeta con la serie ...
|
||||
filetools.rmdirtree(path)
|
||||
|
||||
# ... y la volvemos a añadir
|
||||
videolibrary_service.update(path, p_dialog, i, t, serie, 3)
|
||||
p_dialog.close()
|
||||
|
||||
# movies
|
||||
heading = config.get_localized_string(60586)
|
||||
p_dialog2 = platformtools.dialog_progress_bg(config.get_localized_string(60585), heading)
|
||||
p_dialog2.update(0, '')
|
||||
|
||||
movies_list = []
|
||||
for path, folders, files in filetools.walk(videolibrarytools.MOVIES_PATH):
|
||||
movies_list.extend([filetools.join(path, f) for f in files if f.endswith(".json")])
|
||||
|
||||
logger.debug("movies_list %s" % movies_list)
|
||||
|
||||
if movies_list:
|
||||
t = float(100) / len(movies_list)
|
||||
|
||||
for i, movie_json in enumerate(movies_list):
|
||||
try:
|
||||
from core import jsontools
|
||||
path = filetools.dirname(movie_json)
|
||||
movie = Item().fromjson(filetools.read(movie_json))
|
||||
|
||||
# Eliminamos la carpeta con la pelicula ...
|
||||
filetools.rmdirtree(path)
|
||||
|
||||
import math
|
||||
heading = config.get_localized_string(60587)
|
||||
|
||||
p_dialog2.update(int(math.ceil((i + 1) * t)), heading, "%s: %s" % (movie.contentTitle,
|
||||
movie.channel.capitalize()))
|
||||
# ... y la volvemos a añadir
|
||||
videolibrarytools.save_movie(movie)
|
||||
except Exception, ex:
|
||||
logger.error("Error al crear de nuevo la película")
|
||||
template = "An exception of type %s occured. Arguments:\n%r"
|
||||
message = template % (type(ex).__name__, ex.args)
|
||||
logger.error(message)
|
||||
|
||||
p_dialog2.close()
|
||||
@@ -0,0 +1,361 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ------------------------------------------------------------
|
||||
|
||||
import os
|
||||
from core.item import Item
|
||||
from core import jsontools
|
||||
from platformcode import config, logger
|
||||
from platformcode import launcher
|
||||
import xbmc, xbmcgui, xbmcplugin, xbmcaddon, channelselector
|
||||
|
||||
import xbmc, xbmcaddon
|
||||
addon = xbmcaddon.Addon('metadata.themoviedb.org')
|
||||
def_lang = addon.getSetting('language')
|
||||
|
||||
media_path = os.path.join(config.get_runtime_path(), "resources/skins/Default/media/side_menu/")
|
||||
menu_settings_path = os.path.join(config.get_data_path(), "settings_channels", 'menu_settings_data.json')
|
||||
|
||||
if os.path.exists(menu_settings_path):
|
||||
menu_node = jsontools.get_node_from_file('menu_setting_data.json', 'menu')
|
||||
else:
|
||||
menu_node = {'categoria actual':config.get_setting('category')}
|
||||
jsontools.update_node(menu_node, 'menu_settings_data.json', "menu")
|
||||
|
||||
|
||||
|
||||
ACTION_SHOW_FULLSCREEN = 36
|
||||
ACTION_GESTURE_SWIPE_LEFT = 511
|
||||
ACTION_SELECT_ITEM = 7
|
||||
ACTION_PREVIOUS_MENU = 10
|
||||
ACTION_MOVE_LEFT = 1
|
||||
ACTION_MOVE_RIGHT = 2
|
||||
ACTION_MOVE_DOWN = 4
|
||||
ACTION_MOVE_UP = 3
|
||||
|
||||
def set_menu_settings(item):
|
||||
if os.path.exists(menu_settings_path):
|
||||
menu_node = jsontools.get_node_from_file('menu_settings_data.json', 'menu')
|
||||
else:
|
||||
menu_node = {}
|
||||
menu_node['categoria actual'] = item.extra
|
||||
|
||||
jsontools.update_node(menu_node, 'menu_settings_data.json', "menu")
|
||||
|
||||
def check_user_home(item):
|
||||
logger.info()
|
||||
if os.path.exists(menu_settings_path):
|
||||
menu_node = jsontools.get_node_from_file('menu_settings_data.json', 'menu')
|
||||
if 'user_home' in menu_node:
|
||||
item = Item().fromurl(menu_node['user_home'])
|
||||
else:
|
||||
item = Item(channel="channelselector", action="getmainlist", viewmode="movie")
|
||||
from platformcode import platformtools
|
||||
undefined_start = platformtools.dialog_ok(config.get_localized_string(70664), config.get_localized_string(70665),
|
||||
config.get_localized_string(70666))
|
||||
return item
|
||||
|
||||
def set_custom_start(item):
|
||||
logger.info()
|
||||
if os.path.exists(menu_settings_path):
|
||||
menu_node = jsontools.get_node_from_file('menu_settings_data.json', 'menu')
|
||||
else:
|
||||
menu_node={}
|
||||
parent_item= Item().fromurl(item.parent)
|
||||
parent_item.start=True
|
||||
config.set_setting("custom_start",True)
|
||||
if config.get_setting("news_start"):
|
||||
config.set_setting("news_start", False)
|
||||
menu_node['user_home']=parent_item.tourl()
|
||||
jsontools.update_node(menu_node, 'menu_settings_data.json', "menu")
|
||||
|
||||
def get_start_page():
|
||||
logger.info()
|
||||
|
||||
dictCategory = {
|
||||
config.get_localized_string(70137): 'peliculas',
|
||||
config.get_localized_string(30123): 'series',
|
||||
config.get_localized_string(30124): 'anime',
|
||||
config.get_localized_string(70018): 'infantiles',
|
||||
config.get_localized_string(60513): 'documentales',
|
||||
config.get_localized_string(70013): 'terror',
|
||||
config.get_localized_string(30124): 'castellano',
|
||||
config.get_localized_string(59976): 'latino',
|
||||
config.get_localized_string(70171): 'torrent',
|
||||
}
|
||||
category = dictCategory[config.get_setting("category")]
|
||||
|
||||
custom_start= config.get_setting("custom_start")
|
||||
#if category != 'definido':
|
||||
if custom_start == False:
|
||||
item = Item(channel="news", action="novedades", extra=category, mode='silent')
|
||||
else:
|
||||
from specials import side_menu
|
||||
item = Item()
|
||||
item = side_menu.check_user_home(item)
|
||||
return item
|
||||
|
||||
|
||||
|
||||
def open_menu(item):
|
||||
main = Main('side_menu.xml', config.get_runtime_path())
|
||||
main.doModal()
|
||||
del main
|
||||
|
||||
|
||||
class Main(xbmcgui.WindowXMLDialog):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.items = []
|
||||
|
||||
def onInit(self):
|
||||
#### Compatibilidad con Kodi 18 ####
|
||||
if config.get_platform(True)['num_version'] < 18:
|
||||
self.setCoordinateResolution(2)
|
||||
|
||||
self.focus = -1
|
||||
self.buttons = []
|
||||
posx= 0
|
||||
posy= 145
|
||||
space = 30
|
||||
|
||||
selected = 'selected0.png'
|
||||
width = 260
|
||||
height = 30
|
||||
textcolor = "0xFFCCCCCC"
|
||||
conditional_textcolor = "0xFF0081C2"
|
||||
shadow = "0x00000000"
|
||||
offsetx = 30
|
||||
offsety = 5
|
||||
font = 'font25_title'
|
||||
|
||||
if config.get_setting('start_page'):
|
||||
label = config.get_localized_string(70663)
|
||||
self.button_start = xbmcgui.ControlButton(posx, posy, width, height, label, font=font, alignment=0x00000000,
|
||||
noFocusTexture='', focusTexture=media_path + selected,
|
||||
textColor=textcolor, shadowColor=shadow, textOffsetX=offsetx,
|
||||
textOffsetY=offsety)
|
||||
self.addControl(self.button_start)
|
||||
self.buttons.append(self.button_start)
|
||||
|
||||
posy += space * 2
|
||||
label = config.get_localized_string(70009)
|
||||
self.button_alfa = xbmcgui.ControlButton(posx, posy, width, height, label, font=font, alignment=0x00000000,
|
||||
noFocusTexture='', focusTexture=media_path+selected,
|
||||
textColor=textcolor, shadowColor=shadow, textOffsetX=offsetx,
|
||||
textOffsetY=offsety)
|
||||
self.addControl(self.button_alfa)
|
||||
self.buttons.append(self.button_alfa)
|
||||
|
||||
|
||||
posy += space
|
||||
label = config.get_localized_string(30100)
|
||||
self.button_config = xbmcgui.ControlButton(posx, posy, width, height, label, font=font, alignment=0x00000000,
|
||||
noFocusTexture='', focusTexture=media_path + selected,
|
||||
textColor=textcolor, shadowColor=shadow, textOffsetX=offsetx,
|
||||
textOffsetY=offsety)
|
||||
self.addControl(self.button_config)
|
||||
self.buttons.append(self.button_config)
|
||||
posy += space*2
|
||||
label = config.get_localized_string(30122)
|
||||
self.button_peliculas = xbmcgui.ControlButton(posx, posy, width, height, label, font=font,
|
||||
alignment=0x00000000, noFocusTexture='',
|
||||
focusTexture=media_path+selected, textColor=textcolor,
|
||||
shadowColor=shadow, textOffsetX=offsetx, textOffsetY=offsety)
|
||||
self.addControl(self.button_peliculas)
|
||||
self.buttons.append(self.button_peliculas)
|
||||
posy += space
|
||||
label = config.get_localized_string(70017)
|
||||
self.button_series = xbmcgui.ControlButton(posx, posy, width, height, label, font=font,
|
||||
alignment=0x00000000, noFocusTexture='',
|
||||
focusTexture=media_path+selected, textColor=textcolor,
|
||||
shadowColor=shadow, textOffsetX=offsetx, textOffsetY=offsety)
|
||||
self.addControl(self.button_series)
|
||||
self.buttons.append(self.button_series)
|
||||
posy += space
|
||||
label = config.get_localized_string(30124)
|
||||
self.button_anime = xbmcgui.ControlButton(posx, posy, width, height, label, font=font, alignment=0x00000000,
|
||||
noFocusTexture='', focusTexture=media_path+selected,
|
||||
textColor=textcolor, shadowColor=shadow, textOffsetX=offsetx,
|
||||
textOffsetY=offsety)
|
||||
self.addControl(self.button_anime)
|
||||
self.buttons.append(self.button_anime)
|
||||
# posy += space
|
||||
# label = config.get_localized_string(70018)
|
||||
# self.button_infantil = xbmcgui.ControlButton(posx, posy, width, height, label, font=font,
|
||||
# alignment=0x00000000, noFocusTexture='',
|
||||
# focusTexture=media_path+selected, textColor=textcolor,
|
||||
# shadowColor=shadow, textOffsetX=offsetx, textOffsetY=offsety)
|
||||
# self.addControl(self.button_infantil)
|
||||
# self.buttons.append(self.button_infantil)
|
||||
posy += space
|
||||
label = config.get_localized_string(70019)
|
||||
self.button_docu = xbmcgui.ControlButton(posx, posy, width, height, label, font=font,
|
||||
alignment=0x00000000, noFocusTexture='',
|
||||
focusTexture=media_path + selected, textColor=textcolor,
|
||||
shadowColor=shadow, textOffsetX=offsetx, textOffsetY=offsety)
|
||||
self.addControl(self.button_docu)
|
||||
self.buttons.append(self.button_docu)
|
||||
posy += space
|
||||
|
||||
# label = config.get_localized_string(70013)
|
||||
# self.button_terror = xbmcgui.ControlButton(posx, posy, width, height, label, font=font,
|
||||
# alignment=0x00000000, noFocusTexture='',
|
||||
# focusTexture=media_path+selected, textColor=textcolor,
|
||||
# shadowColor=shadow, textOffsetX=offsetx, textOffsetY=offsety)
|
||||
# self.addControl(self.button_terror)
|
||||
# self.buttons.append(self.button_terror)
|
||||
|
||||
# if channelselector.auto_filter() == 'esp':
|
||||
# posy += space
|
||||
# label = config.get_localized_string(59981)
|
||||
# self.button_lat = xbmcgui.ControlButton(posx, posy, width, height, label, font=font, alignment=0x00000000,
|
||||
# noFocusTexture='', focusTexture=media_path+selected,
|
||||
# textColor=textcolor, shadowColor=shadow, textOffsetX=offsetx,
|
||||
# textOffsetY=offsety)
|
||||
# self.addControl(self.button_lat)
|
||||
# self.buttons.append(self.button_lat)
|
||||
# posy += space
|
||||
# label = config.get_localized_string(70014)
|
||||
# self.button_cast = xbmcgui.ControlButton(posx, posy, width, height, label, font=font, alignment=0x00000000,
|
||||
# noFocusTexture='', focusTexture=media_path + selected,
|
||||
# textColor=textcolor, shadowColor=shadow, textOffsetX=offsetx,
|
||||
# textOffsetY=offsety)
|
||||
# self.addControl(self.button_cast)
|
||||
# self.buttons.append(self.button_cast)
|
||||
# posy += space
|
||||
# label = config.get_localized_string(70015)
|
||||
# self.button_torrent = xbmcgui.ControlButton(posx, posy, width, height, label, font=font,
|
||||
# alignment=0x00000000, noFocusTexture='',
|
||||
# focusTexture=media_path+selected, textColor=textcolor,
|
||||
# shadowColor=shadow, textOffsetX=offsetx, textOffsetY=offsety)
|
||||
# self.addControl(self.button_torrent)
|
||||
# self.buttons.append(self.button_torrent)
|
||||
|
||||
start_page_item = get_start_page()
|
||||
if config.get_setting('start_page') and start_page_item.channel == 'news':
|
||||
posy += space
|
||||
label = config.get_localized_string(70016)
|
||||
self.button_config = xbmcgui.ControlButton(posx, posy, width, height, label, font=font,
|
||||
alignment=0x00000000, noFocusTexture='',
|
||||
focusTexture=media_path+selected, textColor=conditional_textcolor,
|
||||
shadowColor=shadow, textOffsetX=offsetx, textOffsetY=offsety)
|
||||
self.addControl(self.button_config)
|
||||
self.buttons.append(self.button_config)
|
||||
|
||||
posy += space*2
|
||||
label = config.get_localized_string(60423)
|
||||
self.button_buscar = xbmcgui.ControlButton(posx, posy, width, height, label, font=font, alignment=0x00000000,
|
||||
noFocusTexture='', focusTexture=media_path + selected,
|
||||
textColor=textcolor, shadowColor=shadow, textOffsetX=offsetx,
|
||||
textOffsetY=offsety)
|
||||
self.addControl(self.button_buscar)
|
||||
self.buttons.append(self.button_buscar)
|
||||
posy += space
|
||||
label = config.get_localized_string(70036)
|
||||
self.button_actor = xbmcgui.ControlButton(posx, posy, width, height, label, font=font, alignment=0x00000000,
|
||||
noFocusTexture='', focusTexture=media_path + selected,
|
||||
textColor=textcolor, shadowColor=shadow, textOffsetX=offsetx,
|
||||
textOffsetY=offsety)
|
||||
self.addControl(self.button_actor)
|
||||
self.buttons.append(self.button_actor)
|
||||
|
||||
posy += space
|
||||
label = config.get_localized_string(70010)
|
||||
self.button_config_search = xbmcgui.ControlButton(posx, posy, width, height, label, font=font,
|
||||
alignment=0x00000000,
|
||||
noFocusTexture='', focusTexture=media_path + selected,
|
||||
textColor=conditional_textcolor, shadowColor=shadow,
|
||||
textOffsetX=offsetx, textOffsetY=offsety)
|
||||
self.addControl(self.button_config_search)
|
||||
self.buttons.append(self.button_config_search)
|
||||
|
||||
|
||||
label=''
|
||||
self.button_close = xbmcgui.ControlButton(260, 0, 1020, 725, label, noFocusTexture='', focusTexture='')
|
||||
self.addControl(self.button_close)
|
||||
|
||||
|
||||
|
||||
def onClick(self, control):
|
||||
new_item=''
|
||||
|
||||
control = self.getControl(control).getLabel()
|
||||
|
||||
if control == config.get_localized_string(70663):
|
||||
new_item = get_start_page()
|
||||
elif control == config.get_localized_string(70009):
|
||||
new_item = Item(channel='', action='getmainlist', title='Menú Alfa')
|
||||
elif control == config.get_localized_string(30100):
|
||||
new_item = Item(channel='setting', action="settings")
|
||||
elif control == config.get_localized_string(30122):
|
||||
new_item = Item(channel='news', action="novedades", extra="peliculas", mode='silent')
|
||||
elif control == config.get_localized_string(70017):
|
||||
new_item = Item(channel='news', action="novedades", extra="series", mode='silent')
|
||||
elif control == config.get_localized_string(30124):
|
||||
new_item = Item(channel='news', action="novedades", extra="anime", mode='silent')
|
||||
elif control == config.get_localized_string(70018):
|
||||
new_item = Item(channel='news', action="novedades", extra="infantiles", mode='silent')
|
||||
elif control == config.get_localized_string(70019):
|
||||
new_item = Item(channel='news', action="novedades", extra="documentales", mode='silent')
|
||||
elif control == config.get_localized_string(70013):
|
||||
new_item = Item(channel='news', action="novedades", extra="terror", mode='silent')
|
||||
elif control == config.get_localized_string(59981):
|
||||
new_item = Item(channel='news', action="novedades", extra="castellano", mode='silent')
|
||||
elif control == config.get_localized_string(70014):
|
||||
new_item = Item(channel='news', action="novedades", extra="latino", mode='silent')
|
||||
elif control == config.get_localized_string(70015):
|
||||
new_item = Item(channel='news', action="novedades", extra="torrent", mode='silent')
|
||||
elif control == config.get_localized_string(70016):
|
||||
menu_node = jsontools.get_node_from_file('menu_settings_data.json', 'menu')
|
||||
if 'categoria actual' in menu_node:
|
||||
category = menu_node['categoria actual']
|
||||
new_item = Item(channel='news', action="setting_channel", extra=category, menu=True)
|
||||
elif control == config.get_localized_string(60423):
|
||||
new_item = Item(channel='search', action="search")
|
||||
elif control == config.get_localized_string(70036):
|
||||
new_item = Item(channel='tvmoviedb', title="Buscar actor/actriz", action="search_",
|
||||
search={'url': 'search/person', 'language': def_lang, 'page': 1}, star=True)
|
||||
elif control == config.get_localized_string(70010):
|
||||
new_item = Item(channel='search', action="setting_channel")
|
||||
elif control == '':
|
||||
self.close()
|
||||
if new_item !='':
|
||||
self.run_action(new_item)
|
||||
|
||||
|
||||
def onAction(self, action):
|
||||
|
||||
|
||||
if action == ACTION_PREVIOUS_MENU or action == ACTION_GESTURE_SWIPE_LEFT or action == 110 or action == 92:
|
||||
self.close()
|
||||
|
||||
if action == ACTION_MOVE_RIGHT or action == ACTION_MOVE_DOWN:
|
||||
self.focus += 1
|
||||
if self.focus > len(self.buttons)-1:
|
||||
self.focus = 0
|
||||
while True:
|
||||
id_focus = str(self.buttons[self.focus].getId())
|
||||
|
||||
if xbmc.getCondVisibility('[Control.IsVisible(' + id_focus + ')]'):
|
||||
self.setFocus(self.buttons[self.focus])
|
||||
break
|
||||
self.focus += 1
|
||||
|
||||
if action == ACTION_MOVE_LEFT or action == ACTION_MOVE_UP:
|
||||
self.focus -= 1
|
||||
if self.focus < 0:
|
||||
self.focus = len(self.buttons) - 1
|
||||
while True:
|
||||
id_focus = str(self.buttons[self.focus].getId())
|
||||
if xbmc.getCondVisibility('[Control.IsVisible(' + id_focus + ')]'):
|
||||
self.setFocus(self.buttons[self.focus])
|
||||
break
|
||||
self.focus -= 1
|
||||
|
||||
def run_action(self, item):
|
||||
logger.info()
|
||||
if item.menu != True:
|
||||
self.close()
|
||||
xbmc.executebuiltin("Container.update(%s)"%launcher.run(item))
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
{
|
||||
"id": "tvmoviedb",
|
||||
"name": "TvMovieDB",
|
||||
"active": false,
|
||||
"adult": false,
|
||||
"language": ["*"],
|
||||
"thumbnail": "http://i.imgur.com/HA7fvgD.png",
|
||||
"categories": [
|
||||
"movie",
|
||||
"tvshow",
|
||||
"anime"
|
||||
],
|
||||
"settings": [
|
||||
{
|
||||
"id": "tmdb",
|
||||
"type": "list",
|
||||
"label": "@70418",
|
||||
"default": 0,
|
||||
"enabled": true,
|
||||
"visible": true,
|
||||
"lvalues": [
|
||||
"auto",
|
||||
"@70419",
|
||||
"@70420",
|
||||
"@70421",
|
||||
"@70422",
|
||||
"@70423",
|
||||
"@70424",
|
||||
"@70425",
|
||||
"@70014"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "tmdb_alternativo",
|
||||
"type": "list",
|
||||
"label": "@70426",
|
||||
"default": 6,
|
||||
"enabled": true,
|
||||
"visible": true,
|
||||
"lvalues": [
|
||||
"@70419",
|
||||
"@70420",
|
||||
"@70421",
|
||||
"@70422",
|
||||
"@70423",
|
||||
"@70424",
|
||||
"@70425",
|
||||
"@70014"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "imdb",
|
||||
"type": "list",
|
||||
"label": "@70427",
|
||||
"color": "0xFFE0F04B",
|
||||
"default": 0,
|
||||
"enabled": true,
|
||||
"visible": true,
|
||||
"lvalues": [
|
||||
"auto",
|
||||
"@70419",
|
||||
"@70420",
|
||||
"@70421",
|
||||
"@70422",
|
||||
"@70423",
|
||||
"@70424",
|
||||
"@70425",
|
||||
"@70014"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "label1",
|
||||
"type": "label",
|
||||
"label": "",
|
||||
"enabled": false,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "filmaff",
|
||||
"type": "list",
|
||||
"label": "@70428",
|
||||
"color": "0xFF25AA48",
|
||||
"default": 0,
|
||||
"enabled": true,
|
||||
"visible": true,
|
||||
"lvalues": [
|
||||
"auto",
|
||||
"@70429",
|
||||
"@70430",
|
||||
"@70431",
|
||||
"@70432",
|
||||
"@70433",
|
||||
"@70434"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "usuariofa",
|
||||
"type": "text",
|
||||
"label": "@70435",
|
||||
"color": "0xFFd50b0b",
|
||||
"default": "",
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "passfa",
|
||||
"type": "text",
|
||||
"label": "@70436",
|
||||
"color": "0xFFd50b0b",
|
||||
"default": "",
|
||||
"enabled": "!eq(-1,'')",
|
||||
"hidden": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "orderfa",
|
||||
"type": "list",
|
||||
"label": "@70437",
|
||||
"color": "0xFF25AA48",
|
||||
"default": 0,
|
||||
"enabled": "!eq(-1,'')",
|
||||
"visible": true,
|
||||
"lvalues": [
|
||||
"@70438",
|
||||
"@60230",
|
||||
"@70042",
|
||||
"@70439",
|
||||
"@70440"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "label2",
|
||||
"type": "label",
|
||||
"label": "",
|
||||
"enabled": false,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "usuariomal",
|
||||
"type": "text",
|
||||
"label": "@70441",
|
||||
"color": "0xFF25AA48",
|
||||
"default": "",
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "passmal",
|
||||
"type": "text",
|
||||
"label": "@70442",
|
||||
"color": "0xFF25AA48",
|
||||
"default": "",
|
||||
"enabled": "!eq(-1,'')",
|
||||
"hidden": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "adult_mal",
|
||||
"type": "bool",
|
||||
"label": "@70443",
|
||||
"color": "0xFFd50b0b",
|
||||
"default": false,
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "perfil",
|
||||
"type": "list",
|
||||
"label": "@60666",
|
||||
"default": 2,
|
||||
"enabled": true,
|
||||
"visible": true,
|
||||
"lvalues": [
|
||||
"@70444",
|
||||
"@70445",
|
||||
"@70446",
|
||||
"@59992"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"id": "url",
|
||||
"name": "URL",
|
||||
"active": false,
|
||||
"adult": false,
|
||||
"thumbnail": "url.png",
|
||||
"banner": "url.png"
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from core import httptools
|
||||
from core import scrapertools
|
||||
from core import servertools
|
||||
from core.item import Item
|
||||
from platformcode import config, logger
|
||||
|
||||
|
||||
def mainlist(item):
|
||||
logger.info()
|
||||
|
||||
itemlist = []
|
||||
itemlist.append(Item(channel=item.channel, action="search", title=config.get_localized_string(60089)))
|
||||
itemlist.append(Item(channel=item.channel, action="search", title=config.get_localized_string(60090)))
|
||||
itemlist.append(Item(channel=item.channel, action="search", title=config.get_localized_string(60091)))
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
# Al llamarse "search" la función, el launcher pide un texto a buscar y lo añade como parámetro
|
||||
def search(item, texto):
|
||||
logger.info("texto=" + texto)
|
||||
|
||||
if not texto.startswith("http"):
|
||||
texto = "http://" + texto
|
||||
|
||||
itemlist = []
|
||||
|
||||
if "servidor" in item.title:
|
||||
itemlist = servertools.find_video_items(data=texto)
|
||||
for item in itemlist:
|
||||
item.channel = "url"
|
||||
item.action = "play"
|
||||
elif "directo" in item.title:
|
||||
itemlist.append(Item(channel=item.channel, action="play", url=texto, server="directo", title=config.get_localized_string(60092)))
|
||||
else:
|
||||
data = httptools.downloadpage(texto).data
|
||||
itemlist = servertools.find_video_items(data=data)
|
||||
for item in itemlist:
|
||||
item.channel = "url"
|
||||
item.action = "play"
|
||||
|
||||
if len(itemlist) == 0:
|
||||
itemlist.append(Item(channel=item.channel, action="search", title=config.get_localized_string(60093)))
|
||||
|
||||
return itemlist
|
||||
@@ -0,0 +1,326 @@
|
||||
{
|
||||
"id": "videolibrary",
|
||||
"name": "Videoteca",
|
||||
"active": false,
|
||||
"adult": false,
|
||||
"language": ["*"],
|
||||
"settings": [
|
||||
{
|
||||
"id": "update",
|
||||
"type": "list",
|
||||
"label": "@60601",
|
||||
"default": 1,
|
||||
"visible": true,
|
||||
"lvalues": [
|
||||
"@60602",
|
||||
"@60603",
|
||||
"@60604",
|
||||
"@60605"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "update_wait",
|
||||
"type": "list",
|
||||
"label": "@60606",
|
||||
"default": 0,
|
||||
"visible": true,
|
||||
"enabled": "eq(-1,@60603)|eq(-1,@60605)",
|
||||
"lvalues": [
|
||||
"No",
|
||||
"@60609",
|
||||
"@60610",
|
||||
"@60611",
|
||||
"@60612"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "everyday_delay",
|
||||
"type": "list",
|
||||
"label": "@60613",
|
||||
"default": 1,
|
||||
"visible": true,
|
||||
"enabled": "eq(-2,@60604)|eq(-2,@60605)",
|
||||
"lvalues": [
|
||||
"00:00",
|
||||
"04:00",
|
||||
"08:00",
|
||||
"12:00",
|
||||
"16:00",
|
||||
"20:00"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "updatetvshows_interval",
|
||||
"type": "list",
|
||||
"label": "@60614",
|
||||
"default": 0,
|
||||
"visible": true,
|
||||
"enabled": "!eq(-3,@60615)",
|
||||
"lvalues": [
|
||||
"@60616",
|
||||
"@60617"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "search_new_content",
|
||||
"type": "list",
|
||||
"label": "@60618",
|
||||
"default": 0,
|
||||
"enabled": "!eq(-4,@60615)",
|
||||
"lvalues": [
|
||||
"@60619",
|
||||
"@60620"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "addition",
|
||||
"type": "label",
|
||||
"label": "@70092",
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "enable_filter",
|
||||
"type": "bool",
|
||||
"label": "@70090",
|
||||
"enabled": true,
|
||||
"visible": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"id": "filters",
|
||||
"type": "text",
|
||||
"label": "@70091",
|
||||
"visible": true,
|
||||
"enabled": "eq(-1,true)"
|
||||
},
|
||||
|
||||
{
|
||||
"id": "window_type",
|
||||
"type": "list",
|
||||
"label": "@60621",
|
||||
"default": 0,
|
||||
"enabled": true,
|
||||
"visible": true,
|
||||
"lvalues": [
|
||||
"@60622",
|
||||
"@60623"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "max_links",
|
||||
"type": "list",
|
||||
"label": "@60624",
|
||||
"default": 0,
|
||||
"enabled": true,
|
||||
"visible": true,
|
||||
"lvalues": [
|
||||
"@60625",
|
||||
"30",
|
||||
"60",
|
||||
"90",
|
||||
"120",
|
||||
"150",
|
||||
"180",
|
||||
"210"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "white_list_order",
|
||||
"type": "bool",
|
||||
"label": "@60626",
|
||||
"enabled": true,
|
||||
"visible": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"id": "quit_channel_name",
|
||||
"type": "bool",
|
||||
"label": "@60627",
|
||||
"enabled": true,
|
||||
"visible": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"id": "replace_VD",
|
||||
"type": "bool",
|
||||
"label": "@60628",
|
||||
"enabled": true,
|
||||
"visible": true,
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"id": "db_mode",
|
||||
"type": "list",
|
||||
"label": "@60629",
|
||||
"default": 0,
|
||||
"enabled": true,
|
||||
"visible": true,
|
||||
"lvalues": [
|
||||
"@60630",
|
||||
"@60631"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "xbmc_host",
|
||||
"type": "text",
|
||||
"label": "@60632",
|
||||
"visible": true,
|
||||
"enabled": "eq(-1,Remota)"
|
||||
},
|
||||
{
|
||||
"id": "xbmc_puerto",
|
||||
"type": "text",
|
||||
"label": "@60633",
|
||||
"enabled": "!eq(-1,'')",
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "mark_as_watched",
|
||||
"type": "bool",
|
||||
"label": "@60634",
|
||||
"default": true,
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "watched_setting",
|
||||
"type": "list",
|
||||
"label": "@60635",
|
||||
"default": 3,
|
||||
"visible": true,
|
||||
"enabled": "eq(-1,true)",
|
||||
"lvalues": [
|
||||
"5 min",
|
||||
"30%",
|
||||
"50%",
|
||||
"80%",
|
||||
"@60636"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "sync_trakt",
|
||||
"type": "label",
|
||||
"label": "@60637",
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "sync_trakt_watched",
|
||||
"type": "bool",
|
||||
"label": "@60638",
|
||||
"default": false,
|
||||
"visible": true,
|
||||
"enabled": "eq(-3,true)"
|
||||
},
|
||||
{
|
||||
"id": "sync_trakt_notification",
|
||||
"type": "bool",
|
||||
"label": "@60639",
|
||||
"default": true,
|
||||
"visible": true,
|
||||
"enabled": "eq(-1,true)"
|
||||
},
|
||||
{
|
||||
"id": "sync_trakt_new_tvshow",
|
||||
"type": "bool",
|
||||
"label": "@60640",
|
||||
"default": false,
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "sync_trakt_new_tvshow_wait",
|
||||
"type": "bool",
|
||||
"label": "@60641",
|
||||
"default": true,
|
||||
"visible": true,
|
||||
"enabled": "eq(-1,true)"
|
||||
},
|
||||
{
|
||||
"id": "show_all_seasons",
|
||||
"type": "bool",
|
||||
"label": "@60642",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"id": "no_pile_on_seasons",
|
||||
"type": "list",
|
||||
"label": "@60643",
|
||||
"default": 1,
|
||||
"lvalues": [
|
||||
"@60648",
|
||||
"@60644",
|
||||
"@60616"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "ask_channel",
|
||||
"type": "bool",
|
||||
"label": "@60645",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"id": "original_title_folder",
|
||||
"type": "list",
|
||||
"label": "@60646",
|
||||
"default": 0,
|
||||
"lvalues": [
|
||||
"@60647",
|
||||
"@60649"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "lowerize_title",
|
||||
"type": "list",
|
||||
"label": "@70703",
|
||||
"default": 0,
|
||||
"lvalues": [
|
||||
"Si",
|
||||
"No"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "lab_1",
|
||||
"type": "label",
|
||||
"label": "@60650",
|
||||
"enabled": true,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "scraper_movies",
|
||||
"type": "list",
|
||||
"label": "@60651",
|
||||
"enabled": false,
|
||||
"default": 0,
|
||||
"lvalues": [
|
||||
"TheMovieDB.org",
|
||||
"None"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "scraper_tvshows",
|
||||
"type": "list",
|
||||
"label": "@60652",
|
||||
"default": 0,
|
||||
"lvalues": [
|
||||
"TheMovieDB.org",
|
||||
"TheTvDB.com"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "tvdb_retry_eng",
|
||||
"type": "bool",
|
||||
"label": "@60653",
|
||||
"default": true,
|
||||
"enabled": "eq(-1,TheTvDB.com)",
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"id": "verify_playcount",
|
||||
"type": "bool",
|
||||
"label": "@70526",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,981 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os, traceback
|
||||
|
||||
from channelselector import get_thumb
|
||||
from core import filetools
|
||||
from core import scrapertools
|
||||
from core import videolibrarytools
|
||||
from core.item import Item
|
||||
from platformcode import config, logger
|
||||
from platformcode import platformtools
|
||||
from lib import generictools
|
||||
|
||||
|
||||
def mainlist(item):
|
||||
logger.info()
|
||||
|
||||
itemlist = list()
|
||||
itemlist.append(Item(channel=item.channel, action="list_movies", title=config.get_localized_string(60509),
|
||||
category=config.get_localized_string(70270),
|
||||
thumbnail=get_thumb("videolibrary_movie.png")))
|
||||
itemlist.append(Item(channel=item.channel, action="list_tvshows", title=config.get_localized_string(60600),
|
||||
category=config.get_localized_string(70271),
|
||||
thumbnail=get_thumb("videolibrary_tvshow.png")))
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def channel_config(item):
|
||||
return platformtools.show_channel_settings(channelpath=os.path.join(config.get_runtime_path(), "channels",
|
||||
item.channel),
|
||||
caption=config.get_localized_string(60598))
|
||||
|
||||
|
||||
def list_movies(item, silent=False):
|
||||
logger.info()
|
||||
itemlist = []
|
||||
dead_list = []
|
||||
zombie_list = []
|
||||
for raiz, subcarpetas, ficheros in filetools.walk(videolibrarytools.MOVIES_PATH):
|
||||
for f in ficheros:
|
||||
if f.endswith(".nfo"):
|
||||
nfo_path = filetools.join(raiz, f)
|
||||
|
||||
#Sincronizamos las películas vistas desde la videoteca de Kodi con la de Alfa
|
||||
try:
|
||||
if config.is_xbmc(): #Si es Kodi, lo hacemos
|
||||
from platformcode import xbmc_videolibrary
|
||||
xbmc_videolibrary.mark_content_as_watched_on_alfa(nfo_path)
|
||||
except:
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
head_nfo, new_item = videolibrarytools.read_nfo(nfo_path)
|
||||
|
||||
if not new_item: #Si no ha leído bien el .nfo, pasamos a la siguiente
|
||||
continue
|
||||
|
||||
if len(new_item.library_urls) > 1:
|
||||
multicanal = True
|
||||
else:
|
||||
multicanal = False
|
||||
|
||||
## verifica la existencia de los canales, en caso de no existir el canal se pregunta si se quieren
|
||||
## eliminar los enlaces de dicho canal
|
||||
|
||||
for canal_org in new_item.library_urls:
|
||||
canal = generictools.verify_channel(canal_org)
|
||||
try:
|
||||
channel_verify = __import__('channels.%s' % canal, fromlist=["channels.%s" % canal])
|
||||
logger.debug('El canal %s parece correcto' % channel_verify)
|
||||
except:
|
||||
dead_item = Item(multicanal=multicanal,
|
||||
contentType='movie',
|
||||
dead=canal,
|
||||
path=raiz,
|
||||
nfo=nfo_path,
|
||||
library_urls=new_item.library_urls,
|
||||
infoLabels={'title': new_item.contentTitle})
|
||||
if canal not in dead_list and canal not in zombie_list:
|
||||
confirm = platformtools.dialog_yesno('Videoteca',
|
||||
'Parece que el canal [COLOR red]%s[/COLOR] ya no existe.' % canal.upper(),
|
||||
'Deseas eliminar los enlaces de este canal?')
|
||||
|
||||
elif canal in zombie_list:
|
||||
confirm = False
|
||||
else:
|
||||
confirm = True
|
||||
|
||||
if confirm:
|
||||
delete(dead_item)
|
||||
if canal not in dead_list:
|
||||
dead_list.append(canal)
|
||||
continue
|
||||
else:
|
||||
if canal not in zombie_list:
|
||||
zombie_list.append(canal)
|
||||
|
||||
if len(dead_list) > 0:
|
||||
for canal in dead_list:
|
||||
if canal in new_item.library_urls:
|
||||
del new_item.library_urls[canal]
|
||||
|
||||
|
||||
new_item.nfo = nfo_path
|
||||
new_item.path = raiz
|
||||
new_item.thumbnail = new_item.contentThumbnail
|
||||
new_item.text_color = "blue"
|
||||
strm_path = new_item.strm_path.replace("\\", "/").rstrip("/")
|
||||
if '/' in new_item.path:
|
||||
new_item.strm_path = strm_path
|
||||
|
||||
if not filetools.exists(filetools.join(new_item.path, filetools.basename(strm_path))):
|
||||
# Si se ha eliminado el strm desde la bilbioteca de kodi, no mostrarlo
|
||||
continue
|
||||
|
||||
# Menu contextual: Marcar como visto/no visto
|
||||
visto = new_item.library_playcounts.get(os.path.splitext(f)[0], 0)
|
||||
new_item.infoLabels["playcount"] = visto
|
||||
if visto > 0:
|
||||
texto_visto = config.get_localized_string(60016)
|
||||
contador = 0
|
||||
else:
|
||||
texto_visto = config.get_localized_string(60017)
|
||||
contador = 1
|
||||
|
||||
# Menu contextual: Eliminar serie/canal
|
||||
num_canales = len(new_item.library_urls)
|
||||
if "downloads" in new_item.library_urls:
|
||||
num_canales -= 1
|
||||
if num_canales > 1:
|
||||
texto_eliminar = config.get_localized_string(60018)
|
||||
else:
|
||||
texto_eliminar = config.get_localized_string(60019)
|
||||
|
||||
new_item.context = [{"title": texto_visto,
|
||||
"action": "mark_content_as_watched",
|
||||
"channel": "videolibrary",
|
||||
"playcount": contador},
|
||||
{"title": texto_eliminar,
|
||||
"action": "delete",
|
||||
"channel": "videolibrary",
|
||||
"multicanal": multicanal}]
|
||||
# ,{"title": "Cambiar contenido (PENDIENTE)",
|
||||
# "action": "",
|
||||
# "channel": "videolibrary"}]
|
||||
# logger.debug("new_item: " + new_item.tostring('\n'))
|
||||
itemlist.append(new_item)
|
||||
|
||||
if silent == False:
|
||||
return sorted(itemlist, key=lambda it: it.title.lower())
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
def list_tvshows(item):
|
||||
logger.info()
|
||||
itemlist = []
|
||||
dead_list = []
|
||||
zombie_list = []
|
||||
# Obtenemos todos los tvshow.nfo de la videoteca de SERIES recursivamente
|
||||
for raiz, subcarpetas, ficheros in filetools.walk(videolibrarytools.TVSHOWS_PATH):
|
||||
for f in ficheros:
|
||||
|
||||
if f == "tvshow.nfo":
|
||||
tvshow_path = filetools.join(raiz, f)
|
||||
# logger.debug(tvshow_path)
|
||||
|
||||
#Sincronizamos los episodios vistos desde la videoteca de Kodi con la de Alfa
|
||||
try:
|
||||
if config.is_xbmc(): #Si es Kodi, lo hacemos
|
||||
from platformcode import xbmc_videolibrary
|
||||
xbmc_videolibrary.mark_content_as_watched_on_alfa(tvshow_path)
|
||||
except:
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
head_nfo, item_tvshow = videolibrarytools.read_nfo(tvshow_path)
|
||||
|
||||
if len(item_tvshow.library_urls) > 1:
|
||||
multicanal = True
|
||||
else:
|
||||
multicanal = False
|
||||
|
||||
## verifica la existencia de los canales, en caso de no existir el canal se pregunta si se quieren
|
||||
## eliminar los enlaces de dicho canal
|
||||
|
||||
for canal in item_tvshow.library_urls:
|
||||
canal = generictools.verify_channel(canal)
|
||||
try:
|
||||
channel_verify = __import__('channels.%s' % canal, fromlist=["channels.%s" % canal])
|
||||
logger.debug('El canal %s parece correcto' % channel_verify)
|
||||
except:
|
||||
dead_item = Item(multicanal=multicanal,
|
||||
contentType='tvshow',
|
||||
dead=canal,
|
||||
path=raiz,
|
||||
nfo=tvshow_path,
|
||||
library_urls=item_tvshow.library_urls,
|
||||
infoLabels={'title': item_tvshow.contentTitle})
|
||||
if canal not in dead_list and canal not in zombie_list:
|
||||
confirm = platformtools.dialog_yesno('Videoteca',
|
||||
'Parece que el canal [COLOR red]%s[/COLOR] ya no existe.' % canal.upper(),
|
||||
'Deseas eliminar los enlaces de este canal?')
|
||||
|
||||
elif canal in zombie_list:
|
||||
confirm = False
|
||||
else:
|
||||
confirm = True
|
||||
|
||||
if confirm:
|
||||
delete(dead_item)
|
||||
if canal not in dead_list:
|
||||
dead_list.append(canal)
|
||||
continue
|
||||
else:
|
||||
if canal not in zombie_list:
|
||||
zombie_list.append(canal)
|
||||
|
||||
if len(dead_list) > 0:
|
||||
for canal in dead_list:
|
||||
if canal in item_tvshow.library_urls:
|
||||
del item_tvshow.library_urls[canal]
|
||||
|
||||
### continua la carga de los elementos de la videoteca
|
||||
|
||||
try: #A veces da errores aleatorios, por no encontrar el .nfo. Probablemente problemas de timing
|
||||
item_tvshow.title = item_tvshow.contentTitle
|
||||
item_tvshow.path = raiz
|
||||
item_tvshow.nfo = tvshow_path
|
||||
# Menu contextual: Marcar como visto/no visto
|
||||
visto = item_tvshow.library_playcounts.get(item_tvshow.contentTitle, 0)
|
||||
item_tvshow.infoLabels["playcount"] = visto
|
||||
if visto > 0:
|
||||
texto_visto = config.get_localized_string(60020)
|
||||
contador = 0
|
||||
else:
|
||||
texto_visto = config.get_localized_string(60021)
|
||||
contador = 1
|
||||
|
||||
except:
|
||||
logger.error('No encuentra: ' + str(tvshow_path))
|
||||
logger.error(traceback.format_exc())
|
||||
continue
|
||||
|
||||
# Menu contextual: Buscar automáticamente nuevos episodios o no
|
||||
if item_tvshow.active and int(item_tvshow.active) > 0:
|
||||
texto_update = config.get_localized_string(60022)
|
||||
value = 0
|
||||
item_tvshow.text_color = "green"
|
||||
else:
|
||||
texto_update = config.get_localized_string(60023)
|
||||
value = 1
|
||||
item_tvshow.text_color = "0xFFDF7401"
|
||||
|
||||
# Menu contextual: Eliminar serie/canal
|
||||
num_canales = len(item_tvshow.library_urls)
|
||||
if "downloads" in item_tvshow.library_urls:
|
||||
num_canales -= 1
|
||||
if num_canales > 1:
|
||||
texto_eliminar = config.get_localized_string(60024)
|
||||
else:
|
||||
texto_eliminar = config.get_localized_string(60025)
|
||||
|
||||
item_tvshow.context = [{"title": texto_visto,
|
||||
"action": "mark_content_as_watched",
|
||||
"channel": "videolibrary",
|
||||
"playcount": contador},
|
||||
{"title": texto_update,
|
||||
"action": "mark_tvshow_as_updatable",
|
||||
"channel": "videolibrary",
|
||||
"active": value},
|
||||
{"title": texto_eliminar,
|
||||
"action": "delete",
|
||||
"channel": "videolibrary",
|
||||
"multicanal": multicanal},
|
||||
{"title": config.get_localized_string(70269),
|
||||
"action": "update_tvshow",
|
||||
"channel": "videolibrary"}]
|
||||
# ,{"title": "Cambiar contenido (PENDIENTE)",
|
||||
# "action": "",
|
||||
# "channel": "videolibrary"}]
|
||||
|
||||
# logger.debug("item_tvshow:\n" + item_tvshow.tostring('\n'))
|
||||
|
||||
## verifica la existencia de los canales ##
|
||||
if len(item_tvshow.library_urls) > 0:
|
||||
itemlist.append(item_tvshow)
|
||||
|
||||
|
||||
|
||||
if itemlist:
|
||||
itemlist = sorted(itemlist, key=lambda it: it.title.lower())
|
||||
|
||||
itemlist.append(Item(channel=item.channel, action="update_videolibrary", thumbnail=item.thumbnail,
|
||||
title=config.get_localized_string(60026), folder=False))
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def get_seasons(item):
|
||||
logger.info()
|
||||
# logger.debug("item:\n" + item.tostring('\n'))
|
||||
itemlist = []
|
||||
dict_temp = {}
|
||||
|
||||
raiz, carpetas_series, ficheros = filetools.walk(item.path).next()
|
||||
|
||||
# Menu contextual: Releer tvshow.nfo
|
||||
head_nfo, item_nfo = videolibrarytools.read_nfo(item.nfo)
|
||||
|
||||
if config.get_setting("no_pile_on_seasons", "videolibrary") == 2: # Siempre
|
||||
return get_episodes(item)
|
||||
|
||||
for f in ficheros:
|
||||
if f.endswith('.json'):
|
||||
season = f.split('x')[0]
|
||||
dict_temp[season] = config.get_localized_string(60027) % season
|
||||
|
||||
if config.get_setting("no_pile_on_seasons", "videolibrary") == 1 and len(
|
||||
dict_temp) == 1: # Sólo si hay una temporada
|
||||
return get_episodes(item)
|
||||
else:
|
||||
|
||||
# TODO mostrar los episodios de la unica temporada "no vista", en vez de mostrar el Item "temporada X" previo
|
||||
# si está marcado "ocultar los vistos" en el skin, se ejecutaria esto
|
||||
# se comprueba cada temporada en dict_temp si está visto.
|
||||
# si hay una sola temporada y no_pile_on_seasons == 1, se devuelve get(episodios)
|
||||
# si está todo visto, hacemos como actualmente <-- el else no se hace nada.. CREO
|
||||
# if config.get_setting("no_pile_on_seasons", "videolibrary") == 1 and len(dict_temp_Visible) == 1: # Sólo si hay una temporada
|
||||
|
||||
# Creamos un item por cada temporada
|
||||
for season, title in dict_temp.items():
|
||||
new_item = item.clone(action="get_episodes", title=title, contentSeason=season,
|
||||
filtrar_season=True)
|
||||
|
||||
# Menu contextual: Marcar la temporada como vista o no
|
||||
visto = item_nfo.library_playcounts.get("season %s" % season, 0)
|
||||
new_item.infoLabels["playcount"] = visto
|
||||
if visto > 0:
|
||||
texto = config.get_localized_string(60028)
|
||||
value = 0
|
||||
else:
|
||||
texto = config.get_localized_string(60029)
|
||||
value = 1
|
||||
new_item.context = [{"title": texto,
|
||||
"action": "mark_season_as_watched",
|
||||
"channel": "videolibrary",
|
||||
"playcount": value}]
|
||||
|
||||
# logger.debug("new_item:\n" + new_item.tostring('\n'))
|
||||
itemlist.append(new_item)
|
||||
|
||||
if len(itemlist) > 1:
|
||||
itemlist = sorted(itemlist, key=lambda it: int(it.contentSeason))
|
||||
|
||||
if config.get_setting("show_all_seasons", "videolibrary"):
|
||||
new_item = item.clone(action="get_episodes", title=config.get_localized_string(60030))
|
||||
new_item.infoLabels["playcount"] = 0
|
||||
itemlist.insert(0, new_item)
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def get_episodes(item):
|
||||
logger.info()
|
||||
# logger.debug("item:\n" + item.tostring('\n'))
|
||||
itemlist = []
|
||||
|
||||
# Obtenemos los archivos de los episodios
|
||||
raiz, carpetas_series, ficheros = filetools.walk(item.path).next()
|
||||
|
||||
# Menu contextual: Releer tvshow.nfo
|
||||
head_nfo, item_nfo = videolibrarytools.read_nfo(item.nfo)
|
||||
|
||||
# Crear un item en la lista para cada strm encontrado
|
||||
for i in ficheros:
|
||||
if i.endswith('.strm'):
|
||||
season_episode = scrapertools.get_season_and_episode(i)
|
||||
if not season_episode:
|
||||
# El fichero no incluye el numero de temporada y episodio
|
||||
continue
|
||||
season, episode = season_episode.split("x")
|
||||
# Si hay q filtrar por temporada, ignoramos los capitulos de otras temporadas
|
||||
if item.filtrar_season and int(season) != int(item.contentSeason):
|
||||
continue
|
||||
|
||||
# Obtener los datos del season_episode.nfo
|
||||
nfo_path = filetools.join(raiz, i).replace('.strm', '.nfo')
|
||||
head_nfo, epi = videolibrarytools.read_nfo(nfo_path)
|
||||
|
||||
# Fijar el titulo del capitulo si es posible
|
||||
if epi.contentTitle:
|
||||
title_episodie = epi.contentTitle.strip()
|
||||
else:
|
||||
title_episodie = config.get_localized_string(60031) % \
|
||||
(epi.contentSeason, str(epi.contentEpisodeNumber).zfill(2))
|
||||
|
||||
epi.contentTitle = "%sx%s" % (epi.contentSeason, str(epi.contentEpisodeNumber).zfill(2))
|
||||
epi.title = "%sx%s - %s" % (epi.contentSeason, str(epi.contentEpisodeNumber).zfill(2), title_episodie)
|
||||
|
||||
if item_nfo.library_filter_show:
|
||||
epi.library_filter_show = item_nfo.library_filter_show
|
||||
|
||||
# Menu contextual: Marcar episodio como visto o no
|
||||
visto = item_nfo.library_playcounts.get(season_episode, 0)
|
||||
epi.infoLabels["playcount"] = visto
|
||||
if visto > 0:
|
||||
texto = config.get_localized_string(60032)
|
||||
value = 0
|
||||
else:
|
||||
texto = config.get_localized_string(60033)
|
||||
value = 1
|
||||
epi.context = [{"title": texto,
|
||||
"action": "mark_content_as_watched",
|
||||
"channel": "videolibrary",
|
||||
"playcount": value,
|
||||
"nfo": item.nfo}]
|
||||
|
||||
# logger.debug("epi:\n" + epi.tostring('\n'))
|
||||
itemlist.append(epi)
|
||||
|
||||
return sorted(itemlist, key=lambda it: (int(it.contentSeason), int(it.contentEpisodeNumber)))
|
||||
|
||||
|
||||
def findvideos(item):
|
||||
from specials import autoplay
|
||||
logger.info()
|
||||
# logger.debug("item:\n" + item.tostring('\n'))
|
||||
|
||||
itemlist = []
|
||||
list_canales = {}
|
||||
item_local = None
|
||||
|
||||
# Desactiva autoplay
|
||||
autoplay.set_status(False)
|
||||
|
||||
if not item.contentTitle or not item.strm_path:
|
||||
logger.debug("No se pueden buscar videos por falta de parametros")
|
||||
return []
|
||||
|
||||
content_title = filter(lambda c: c not in ":*?<>|\/", item.contentTitle.strip().lower())
|
||||
|
||||
if item.contentType == 'movie':
|
||||
item.strm_path = filetools.join(videolibrarytools.MOVIES_PATH, item.strm_path)
|
||||
path_dir = os.path.dirname(item.strm_path)
|
||||
item.nfo = filetools.join(path_dir, os.path.basename(path_dir) + ".nfo")
|
||||
else:
|
||||
item.strm_path = filetools.join(videolibrarytools.TVSHOWS_PATH, item.strm_path)
|
||||
path_dir = os.path.dirname(item.strm_path)
|
||||
item.nfo = filetools.join(path_dir, 'tvshow.nfo')
|
||||
|
||||
for fd in filetools.listdir(path_dir):
|
||||
if fd.endswith('.json'):
|
||||
contenido, nom_canal = fd[:-6].split('[')
|
||||
if (contenido.startswith(content_title) or item.contentType == 'movie') and nom_canal not in \
|
||||
list_canales.keys():
|
||||
list_canales[nom_canal] = filetools.join(path_dir, fd)
|
||||
|
||||
num_canales = len(list_canales)
|
||||
|
||||
if 'downloads' in list_canales:
|
||||
json_path = list_canales['downloads']
|
||||
item_json = Item().fromjson(filetools.read(json_path))
|
||||
|
||||
item_json.contentChannel = "local"
|
||||
# Soporte para rutas relativas en descargas
|
||||
if filetools.is_relative(item_json.url):
|
||||
item_json.url = filetools.join(videolibrarytools.VIDEOLIBRARY_PATH, item_json.url)
|
||||
|
||||
del list_canales['downloads']
|
||||
|
||||
# Comprobar q el video no haya sido borrado
|
||||
if filetools.exists(item_json.url):
|
||||
item_local = item_json.clone(action='play')
|
||||
itemlist.append(item_local)
|
||||
else:
|
||||
num_canales -= 1
|
||||
|
||||
filtro_canal = ''
|
||||
if num_canales > 1 and config.get_setting("ask_channel", "videolibrary"):
|
||||
opciones = [config.get_localized_string(70089) % k.capitalize() for k in list_canales.keys()]
|
||||
opciones.insert(0, config.get_localized_string(70083))
|
||||
if item_local:
|
||||
opciones.append(item_local.title)
|
||||
|
||||
from platformcode import platformtools
|
||||
index = platformtools.dialog_select(config.get_localized_string(30163), opciones)
|
||||
if index < 0:
|
||||
return []
|
||||
|
||||
elif item_local and index == len(opciones) - 1:
|
||||
filtro_canal = 'downloads'
|
||||
platformtools.play_video(item_local)
|
||||
|
||||
elif index > 0:
|
||||
filtro_canal = opciones[index].replace(config.get_localized_string(70078), "").strip()
|
||||
itemlist = []
|
||||
|
||||
for nom_canal, json_path in list_canales.items():
|
||||
if filtro_canal and filtro_canal != nom_canal.capitalize():
|
||||
continue
|
||||
|
||||
item_canal = Item()
|
||||
item_canal.channel = nom_canal
|
||||
|
||||
nom_canal = item_canal.channel
|
||||
|
||||
# Importamos el canal de la parte seleccionada
|
||||
try:
|
||||
channel = __import__('channels.%s' % nom_canal, fromlist=["channels.%s" % nom_canal])
|
||||
except ImportError:
|
||||
exec "import channels." + nom_canal + " as channel"
|
||||
|
||||
item_json = Item().fromjson(filetools.read(json_path))
|
||||
|
||||
list_servers = []
|
||||
|
||||
try:
|
||||
# FILTERTOOLS
|
||||
# si el canal tiene filtro se le pasa el nombre que tiene guardado para que filtre correctamente.
|
||||
if "list_language" in item_json:
|
||||
# si se viene desde la videoteca del addon
|
||||
if "library_filter_show" in item:
|
||||
item_json.show = item.library_filter_show.get(nom_canal, "")
|
||||
|
||||
# Ejecutamos find_videos, del canal o común
|
||||
item_json.contentChannel = 'videolibrary'
|
||||
if hasattr(channel, 'findvideos'):
|
||||
from core import servertools
|
||||
list_servers = getattr(channel, 'findvideos')(item_json)
|
||||
list_servers = servertools.filter_servers(list_servers)
|
||||
else:
|
||||
from core import servertools
|
||||
list_servers = servertools.find_video_items(item_json)
|
||||
except Exception, ex:
|
||||
logger.error("Ha fallado la funcion findvideos para el canal %s" % nom_canal)
|
||||
template = "An exception of type %s occured. Arguments:\n%r"
|
||||
message = template % (type(ex).__name__, ex.args)
|
||||
logger.error(message)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
# Cambiarle el titulo a los servers añadiendoles el nombre del canal delante y
|
||||
# las infoLabels y las imagenes del item si el server no tiene
|
||||
for server in list_servers:
|
||||
#if not server.action: # Ignorar/PERMITIR las etiquetas
|
||||
# continue
|
||||
|
||||
server.contentChannel = server.channel
|
||||
server.channel = "videolibrary"
|
||||
server.nfo = item.nfo
|
||||
server.strm_path = item.strm_path
|
||||
|
||||
#### Compatibilidad con Kodi 18: evita que se quede la ruedecedita dando vueltas en enlaces Directos
|
||||
if server.action == 'play':
|
||||
server.folder = False
|
||||
|
||||
# Se añade el nombre del canal si se desea
|
||||
if config.get_setting("quit_channel_name", "videolibrary") == 0:
|
||||
server.title = "%s: %s" % (nom_canal.capitalize(), server.title)
|
||||
|
||||
#server.infoLabels = item_json.infoLabels
|
||||
if not server.thumbnail:
|
||||
server.thumbnail = item.thumbnail
|
||||
|
||||
# logger.debug("server:\n%s" % server.tostring('\n'))
|
||||
itemlist.append(server)
|
||||
|
||||
# return sorted(itemlist, key=lambda it: it.title.lower())
|
||||
autoplay.play_multi_channel(item, itemlist)
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def play(item):
|
||||
logger.info()
|
||||
# logger.debug("item:\n" + item.tostring('\n'))
|
||||
|
||||
if not item.contentChannel == "local":
|
||||
channel = __import__('channels.%s' % item.contentChannel, fromlist=["channels.%s" % item.contentChannel])
|
||||
if hasattr(channel, "play"):
|
||||
itemlist = getattr(channel, "play")(item)
|
||||
|
||||
else:
|
||||
itemlist = [item.clone()]
|
||||
else:
|
||||
itemlist = [item.clone(url=item.url, server="local")]
|
||||
|
||||
# Para enlaces directo en formato lista
|
||||
if isinstance(itemlist[0], list):
|
||||
item.video_urls = itemlist
|
||||
itemlist = [item]
|
||||
|
||||
# Esto es necesario por si el play del canal elimina los datos
|
||||
for v in itemlist:
|
||||
if isinstance(v, Item):
|
||||
v.nfo = item.nfo
|
||||
v.strm_path = item.strm_path
|
||||
v.infoLabels = item.infoLabels
|
||||
if item.contentTitle:
|
||||
v.title = item.contentTitle
|
||||
else:
|
||||
if item.contentType == "episode":
|
||||
v.title = config.get_localized_string(60036) % item.contentEpisodeNumber
|
||||
v.thumbnail = item.thumbnail
|
||||
v.contentThumbnail = item.thumbnail
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
def update_videolibrary(item):
|
||||
logger.info()
|
||||
|
||||
# Actualizar las series activas sobreescribiendo
|
||||
import videolibrary_service
|
||||
videolibrary_service.check_for_update(overwrite=True)
|
||||
|
||||
# Eliminar las carpetas de peliculas que no contengan archivo strm
|
||||
for raiz, subcarpetas, ficheros in filetools.walk(videolibrarytools.MOVIES_PATH):
|
||||
strm = False
|
||||
for f in ficheros:
|
||||
if f.endswith(".strm"):
|
||||
strm = True
|
||||
break
|
||||
|
||||
if ficheros and not strm:
|
||||
logger.debug("Borrando carpeta de pelicula eliminada: %s" % raiz)
|
||||
filetools.rmdirtree(raiz)
|
||||
|
||||
|
||||
# metodos de menu contextual
|
||||
def update_tvshow(item):
|
||||
logger.info()
|
||||
# logger.debug("item:\n" + item.tostring('\n'))
|
||||
|
||||
heading = config.get_localized_string(60037)
|
||||
p_dialog = platformtools.dialog_progress_bg(config.get_localized_string(20000), heading)
|
||||
p_dialog.update(0, heading, item.contentSerieName)
|
||||
|
||||
import videolibrary_service
|
||||
if videolibrary_service.update(item.path, p_dialog, 1, 1, item, False) and config.is_xbmc():
|
||||
from platformcode import xbmc_videolibrary
|
||||
xbmc_videolibrary.update(folder=filetools.basename(item.path))
|
||||
|
||||
p_dialog.close()
|
||||
|
||||
|
||||
def verify_playcount_series(item, path):
|
||||
logger.info()
|
||||
|
||||
"""
|
||||
Este método revisa y repara el PlayCount de una serie que se haya desincronizado de la lista real de episodios en su carpeta. Las entradas de episodios, temporadas o serie que falten, son creado con la marca de "no visto". Posteriormente se envia a verificar los contadores de Temporadas y Serie
|
||||
|
||||
En el retorno envía de estado de True si se actualizado o False si no, normalmente por error. Con este estado, el caller puede actualizar el estado de la opción "verify_playcount" en "videolibrary.py". La intención de este método es la de dar una pasada que repare todos los errores y luego desactivarse. Se puede volver a activar en el menú de Videoteca de Alfa.
|
||||
|
||||
"""
|
||||
#logger.debug("item:\n" + item.tostring('\n'))
|
||||
|
||||
#Si no ha hecho nunca la verificación, lo forzamos
|
||||
estado = config.get_setting("verify_playcount", "videolibrary")
|
||||
if not estado or estado == False:
|
||||
estado = True #Si no ha hecho nunca la verificación, lo forzamos
|
||||
else:
|
||||
estado = False
|
||||
|
||||
if item.contentType == 'movie': #Esto es solo para Series
|
||||
return (item, False)
|
||||
if filetools.exists(path):
|
||||
nfo_path = filetools.join(path, "tvshow.nfo")
|
||||
head_nfo, it = videolibrarytools.read_nfo(nfo_path) #Obtenemos el .nfo de la Serie
|
||||
if not hasattr(it, 'library_playcounts') or not it.library_playcounts: #Si el .nfo no tiene library_playcounts se lo creamos
|
||||
logger.error('** No tiene PlayCount')
|
||||
it.library_playcounts = {}
|
||||
|
||||
# Obtenemos los archivos de los episodios
|
||||
raiz, carpetas_series, ficheros = filetools.walk(path).next()
|
||||
# Crear un item en la lista para cada strm encontrado
|
||||
estado_update = False
|
||||
for i in ficheros:
|
||||
if i.endswith('.strm'):
|
||||
season_episode = scrapertools.get_season_and_episode(i)
|
||||
if not season_episode:
|
||||
# El fichero no incluye el numero de temporada y episodio
|
||||
continue
|
||||
season, episode = season_episode.split("x")
|
||||
if season_episode not in it.library_playcounts: #No está incluido el episodio
|
||||
it.library_playcounts.update({season_episode: 0}) #actualizamos el playCount del .nfo
|
||||
estado_update = True #Marcamos que hemos actualizado algo
|
||||
|
||||
if 'season %s' % season not in it.library_playcounts: #No está incluida la Temporada
|
||||
it.library_playcounts.update({'season %s' % season: 0}) #actualizamos el playCount del .nfo
|
||||
estado_update = True #Marcamos que hemos actualizado algo
|
||||
|
||||
if it.contentSerieName not in it.library_playcounts: #No está incluida la Serie
|
||||
it.library_playcounts.update({item.contentSerieName: 0}) #actualizamos el playCount del .nfo
|
||||
estado_update = True #Marcamos que hemos actualizado algo
|
||||
|
||||
if estado_update:
|
||||
logger.error('** Estado de actualización: ' + str(estado) + ' / PlayCount: ' + str(it.library_playcounts))
|
||||
estado = estado_update
|
||||
# se comprueba que si todos los episodios de una temporada están marcados, se marque tb la temporada
|
||||
for key, value in it.library_playcounts.iteritems():
|
||||
if key.startswith("season"):
|
||||
season = scrapertools.find_single_match(key, 'season (\d+)') #Obtenemos en núm. de Temporada
|
||||
it = check_season_playcount(it, season)
|
||||
# Guardamos los cambios en item.nfo
|
||||
if filetools.write(nfo_path, head_nfo + it.tojson()):
|
||||
return (it, estado)
|
||||
return (item, False)
|
||||
|
||||
|
||||
def mark_content_as_watched2(item):
|
||||
logger.info()
|
||||
# logger.debug("item:\n" + item.tostring('\n'))
|
||||
|
||||
if filetools.exists(item.nfo):
|
||||
head_nfo, it = videolibrarytools.read_nfo(item.nfo)
|
||||
#logger.debug(it)
|
||||
|
||||
if item.contentType == 'movie':
|
||||
name_file = os.path.splitext(os.path.basename(item.nfo))[0]
|
||||
|
||||
if name_file != 'tvshow' :
|
||||
it.library_playcounts.update({name_file: item.playcount})
|
||||
|
||||
if item.contentType == 'episode' or item.contentType == 'list' or name_file == 'tvshow':
|
||||
# elif item.contentType == 'episode':
|
||||
name_file = os.path.splitext(os.path.basename(item.strm_path))[0]
|
||||
num_season = name_file [0]
|
||||
item.__setattr__('contentType', 'episode')
|
||||
item.__setattr__('contentSeason', num_season)
|
||||
#logger.debug(name_file)
|
||||
|
||||
else:
|
||||
name_file = item.contentTitle
|
||||
# logger.debug(name_file)
|
||||
|
||||
if not hasattr(it, 'library_playcounts'):
|
||||
it.library_playcounts = {}
|
||||
it.library_playcounts.update({name_file: item.playcount})
|
||||
|
||||
# se comprueba que si todos los episodios de una temporada están marcados, se marque tb la temporada
|
||||
if item.contentType != 'movie':
|
||||
it = check_season_playcount(it, item.contentSeason)
|
||||
#logger.debug(it)
|
||||
|
||||
# Guardamos los cambios en item.nfo
|
||||
if filetools.write(item.nfo, head_nfo + it.tojson()):
|
||||
item.infoLabels['playcount'] = item.playcount
|
||||
#logger.debug(item.playcount)
|
||||
|
||||
# if item.contentType == 'episodesss':
|
||||
# Actualizar toda la serie
|
||||
#new_item = item.clone(contentSeason=-1)
|
||||
#mark_season_as_watched(new_item)
|
||||
|
||||
if config.is_xbmc():
|
||||
from platformcode import xbmc_videolibrary
|
||||
xbmc_videolibrary.mark_content_as_watched_on_kodi(item , item.playcount)
|
||||
# logger.debug(item)
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
|
||||
|
||||
def mark_content_as_watched(item):
|
||||
logger.info()
|
||||
#logger.debug("item:\n" + item.tostring('\n'))
|
||||
|
||||
if filetools.exists(item.nfo):
|
||||
head_nfo, it = videolibrarytools.read_nfo(item.nfo)
|
||||
|
||||
if item.contentType == 'movie':
|
||||
name_file = os.path.splitext(os.path.basename(item.nfo))[0]
|
||||
elif item.contentType == 'episode':
|
||||
name_file = "%sx%s" % (item.contentSeason, str(item.contentEpisodeNumber).zfill(2))
|
||||
else:
|
||||
name_file = item.contentTitle
|
||||
|
||||
if not hasattr(it, 'library_playcounts'):
|
||||
it.library_playcounts = {}
|
||||
it.library_playcounts.update({name_file: item.playcount})
|
||||
|
||||
# se comprueba que si todos los episodios de una temporada están marcados, se marque tb la temporada
|
||||
if item.contentType != 'movie':
|
||||
it = check_season_playcount(it, item.contentSeason)
|
||||
|
||||
# Guardamos los cambios en item.nfo
|
||||
if filetools.write(item.nfo, head_nfo + it.tojson()):
|
||||
item.infoLabels['playcount'] = item.playcount
|
||||
|
||||
if item.contentType == 'tvshow' and item.type != 'episode' :
|
||||
# Actualizar toda la serie
|
||||
new_item = item.clone(contentSeason=-1)
|
||||
mark_season_as_watched(new_item)
|
||||
|
||||
if config.is_xbmc(): #and item.contentType == 'episode':
|
||||
from platformcode import xbmc_videolibrary
|
||||
xbmc_videolibrary.mark_content_as_watched_on_kodi(item, item.playcount)
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
|
||||
|
||||
def mark_season_as_watched(item):
|
||||
logger.info()
|
||||
# logger.debug("item:\n" + item.tostring('\n'))
|
||||
|
||||
# Obtener el diccionario de episodios marcados
|
||||
f = filetools.join(item.path, 'tvshow.nfo')
|
||||
head_nfo, it = videolibrarytools.read_nfo(f)
|
||||
if not hasattr(it, 'library_playcounts'):
|
||||
it.library_playcounts = {}
|
||||
|
||||
# Obtenemos los archivos de los episodios
|
||||
raiz, carpetas_series, ficheros = filetools.walk(item.path).next()
|
||||
|
||||
# Marcamos cada uno de los episodios encontrados de esta temporada
|
||||
episodios_marcados = 0
|
||||
for i in ficheros:
|
||||
if i.endswith(".strm"):
|
||||
season_episode = scrapertools.get_season_and_episode(i)
|
||||
if not season_episode:
|
||||
# El fichero no incluye el numero de temporada y episodio
|
||||
continue
|
||||
season, episode = season_episode.split("x")
|
||||
|
||||
if int(item.contentSeason) == -1 or int(season) == int(item.contentSeason):
|
||||
name_file = os.path.splitext(os.path.basename(i))[0]
|
||||
it.library_playcounts[name_file] = item.playcount
|
||||
episodios_marcados += 1
|
||||
|
||||
if episodios_marcados:
|
||||
if int(item.contentSeason) == -1:
|
||||
# Añadimos todas las temporadas al diccionario item.library_playcounts
|
||||
for k in it.library_playcounts.keys():
|
||||
if k.startswith("season"):
|
||||
it.library_playcounts[k] = item.playcount
|
||||
else:
|
||||
# Añadimos la temporada al diccionario item.library_playcounts
|
||||
it.library_playcounts["season %s" % item.contentSeason] = item.playcount
|
||||
|
||||
# se comprueba que si todas las temporadas están vistas, se marque la serie como vista
|
||||
it = check_tvshow_playcount(it, item.contentSeason)
|
||||
|
||||
# Guardamos los cambios en tvshow.nfo
|
||||
filetools.write(f, head_nfo + it.tojson())
|
||||
item.infoLabels['playcount'] = item.playcount
|
||||
|
||||
if config.is_xbmc():
|
||||
# Actualizamos la BBDD de Kodi
|
||||
from platformcode import xbmc_videolibrary
|
||||
xbmc_videolibrary.mark_season_as_watched_on_kodi(item, item.playcount)
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
|
||||
|
||||
def mark_tvshow_as_updatable(item):
|
||||
logger.info()
|
||||
head_nfo, it = videolibrarytools.read_nfo(item.nfo)
|
||||
it.active = item.active
|
||||
filetools.write(item.nfo, head_nfo + it.tojson())
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
|
||||
|
||||
def delete(item):
|
||||
def delete_all(_item):
|
||||
for file in filetools.listdir(_item.path):
|
||||
if file.endswith(".strm") or file.endswith(".nfo") or file.endswith(".json")or file.endswith(".torrent"):
|
||||
filetools.remove(filetools.join(_item.path, file))
|
||||
raiz, carpeta_serie, ficheros = filetools.walk(_item.path).next()
|
||||
if ficheros == []:
|
||||
filetools.rmdir(_item.path)
|
||||
|
||||
if config.is_xbmc():
|
||||
import xbmc
|
||||
# esperamos 3 segundos para dar tiempo a borrar los ficheros
|
||||
xbmc.sleep(3000)
|
||||
# TODO mirar por qué no funciona al limpiar en la videoteca de Kodi al añadirle un path
|
||||
# limpiamos la videoteca de Kodi
|
||||
from platformcode import xbmc_videolibrary
|
||||
xbmc_videolibrary.clean()
|
||||
|
||||
logger.info("Eliminados todos los enlaces")
|
||||
platformtools.itemlist_refresh()
|
||||
|
||||
# logger.info(item.contentTitle)
|
||||
# logger.debug(item.tostring('\n'))
|
||||
|
||||
if item.contentType == 'movie':
|
||||
heading = config.get_localized_string(70084)
|
||||
else:
|
||||
heading = config.get_localized_string(70085)
|
||||
if item.multicanal:
|
||||
# Obtener listado de canales
|
||||
if item.dead == '':
|
||||
opciones = [config.get_localized_string(70086) % k.capitalize() for k in item.library_urls.keys() if
|
||||
k != "downloads"]
|
||||
opciones.insert(0, heading)
|
||||
|
||||
index = platformtools.dialog_select(config.get_localized_string(30163), opciones)
|
||||
|
||||
if index == 0:
|
||||
# Seleccionado Eliminar pelicula/serie
|
||||
delete_all(item)
|
||||
|
||||
elif index > 0:
|
||||
# Seleccionado Eliminar canal X
|
||||
canal = opciones[index].replace(config.get_localized_string(70079), "").lower()
|
||||
else:
|
||||
return
|
||||
else:
|
||||
canal = item.dead
|
||||
|
||||
num_enlaces = 0
|
||||
for fd in filetools.listdir(item.path):
|
||||
if fd.endswith(canal + '].json') or scrapertools.find_single_match(fd, '%s]_\d+.torrent' % canal):
|
||||
if filetools.remove(filetools.join(item.path, fd)):
|
||||
num_enlaces += 1
|
||||
|
||||
if num_enlaces > 0:
|
||||
# Actualizar .nfo
|
||||
head_nfo, item_nfo = videolibrarytools.read_nfo(item.nfo)
|
||||
del item_nfo.library_urls[canal]
|
||||
if item_nfo.emergency_urls and item_nfo.emergency_urls.get(canal, False):
|
||||
del item_nfo.emergency_urls[canal]
|
||||
filetools.write(item.nfo, head_nfo + item_nfo.tojson())
|
||||
|
||||
msg_txt = config.get_localized_string(70087) % (num_enlaces, canal)
|
||||
logger.info(msg_txt)
|
||||
platformtools.dialog_notification(heading, msg_txt)
|
||||
platformtools.itemlist_refresh()
|
||||
|
||||
else:
|
||||
if platformtools.dialog_yesno(heading,
|
||||
config.get_localized_string(70088) % item.infoLabels['title']):
|
||||
delete_all(item)
|
||||
|
||||
|
||||
def check_season_playcount(item, season):
|
||||
logger.info()
|
||||
|
||||
if season:
|
||||
episodios_temporada = 0
|
||||
episodios_vistos_temporada = 0
|
||||
for key, value in item.library_playcounts.iteritems():
|
||||
if key.startswith("%sx" % season):
|
||||
episodios_temporada += 1
|
||||
if value > 0:
|
||||
episodios_vistos_temporada += 1
|
||||
|
||||
if episodios_temporada == episodios_vistos_temporada:
|
||||
# se comprueba que si todas las temporadas están vistas, se marque la serie como vista
|
||||
item.library_playcounts.update({"season %s" % season: 1})
|
||||
else:
|
||||
# se comprueba que si todas las temporadas están vistas, se marque la serie como vista
|
||||
item.library_playcounts.update({"season %s" % season: 0})
|
||||
|
||||
return check_tvshow_playcount(item, season)
|
||||
|
||||
|
||||
def check_tvshow_playcount(item, season):
|
||||
logger.info()
|
||||
if season:
|
||||
temporadas_serie = 0
|
||||
temporadas_vistas_serie = 0
|
||||
for key, value in item.library_playcounts.iteritems():
|
||||
#if key.startswith("season %s" % season):
|
||||
if key.startswith("season" ):
|
||||
temporadas_serie += 1
|
||||
if value > 0:
|
||||
temporadas_vistas_serie += 1
|
||||
#logger.debug(temporadas_serie)
|
||||
|
||||
if temporadas_serie == temporadas_vistas_serie:
|
||||
item.library_playcounts.update({item.title: 1})
|
||||
else:
|
||||
item.library_playcounts.update({item.title: 0})
|
||||
|
||||
else:
|
||||
playcount = item.library_playcounts.get(item.title, 0)
|
||||
item.library_playcounts.update({item.title: playcount})
|
||||
|
||||
return item
|
||||
Reference in New Issue
Block a user