Traduzioni Specials
This commit is contained in:
@@ -8,12 +8,9 @@ from builtins import range
|
||||
|
||||
import os
|
||||
|
||||
from core import channeltools
|
||||
from core import jsontools
|
||||
from core import channeltools, jsontools
|
||||
from core.item import Item
|
||||
from platformcode import config, logger
|
||||
from platformcode import platformtools
|
||||
from platformcode import launcher
|
||||
from platformcode import config, logger, platformtools, launcher
|
||||
from time import sleep
|
||||
from platformcode.config import get_setting
|
||||
|
||||
@@ -28,7 +25,7 @@ colorKOD = '0xFF65B3DA'
|
||||
|
||||
def context():
|
||||
'''
|
||||
Agrega la opcion Configurar AutoPlay al menu contextual
|
||||
Add the Configure AutoPlay option to the context menu
|
||||
|
||||
:return:
|
||||
'''
|
||||
@@ -47,12 +44,12 @@ context = context()
|
||||
|
||||
def show_option(channel, itemlist, text_color=colorKOD, thumbnail=None, fanart=None):
|
||||
'''
|
||||
Agrega la opcion Configurar AutoPlay en la lista recibida
|
||||
Add the option Configure AutoPlay in the received list
|
||||
|
||||
: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)
|
||||
:param text_color: str (color for the text of the option Configure Autoplay)
|
||||
:param thumbnail: str (address where the thumbnail is for the Configure Autoplay option)
|
||||
:return:
|
||||
'''
|
||||
from channelselector import get_thumb
|
||||
@@ -85,13 +82,13 @@ def show_option(channel, itemlist, text_color=colorKOD, thumbnail=None, fanart=N
|
||||
|
||||
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.
|
||||
Main method from which the links are automatically reproduced
|
||||
- In case the option to activate it will use the options defined by the user.
|
||||
- Otherwise it will try to reproduce any link that has the preferred language.
|
||||
|
||||
: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
|
||||
:param itemlist: list (list of items ready to play, ie with action = 'play')
|
||||
:param item: item (the main item of the channel)
|
||||
:return: try to auto-reproduce, in case of failure it returns the itemlist that it received in the beginning
|
||||
'''
|
||||
logger.info()
|
||||
|
||||
@@ -103,11 +100,11 @@ def start(itemlist, item):
|
||||
|
||||
|
||||
if not config.is_xbmc():
|
||||
#platformtools.dialog_notification('AutoPlay ERROR', 'Sólo disponible para XBMC/Kodi')
|
||||
# platformtools.dialog_notification('AutoPlay ERROR', 'Sólo disponible para XBMC/Kodi')
|
||||
return itemlist
|
||||
|
||||
if not autoplay_node:
|
||||
# Obtiene el nodo AUTOPLAY desde el json
|
||||
# Get AUTOPLAY node from json
|
||||
autoplay_node = jsontools.get_node_from_file('autoplay', 'AUTOPLAY')
|
||||
|
||||
channel_id = item.channel
|
||||
@@ -122,12 +119,12 @@ def start(itemlist, item):
|
||||
if not channel_id in autoplay_node: # or not active:
|
||||
return itemlist
|
||||
|
||||
# Agrega servidores y calidades que no estaban listados a autoplay_node
|
||||
# Add servers and qualities not listed to autoplay_node
|
||||
new_options = check_value(channel_id, itemlist)
|
||||
|
||||
# Obtiene el nodo del canal desde autoplay_node
|
||||
# Get the channel node from autoplay_node
|
||||
channel_node = autoplay_node.get(channel_id, {})
|
||||
# Obtiene los ajustes des autoplay para este canal
|
||||
# Get the autoplay settings for this channel
|
||||
settings_node = channel_node.get('settings', {})
|
||||
|
||||
if get_setting('autoplay') or settings_node['active']:
|
||||
@@ -138,66 +135,65 @@ def start(itemlist, item):
|
||||
favorite_servers = []
|
||||
favorite_quality = []
|
||||
|
||||
#2nd lang, vemos si se quiere o no filtrar
|
||||
# 2nd lang, see if you want to filter or not
|
||||
status_language = config.get_setting("filter_languages", channel_id)
|
||||
|
||||
|
||||
# Guarda el valor actual de "Accion y Player Mode" en preferencias
|
||||
# Save the current value of "Action and Player Mode" in preferences
|
||||
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)
|
||||
# Enable the "View in high quality" action (if the server returns more than one quality, eg 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)
|
||||
# Report that AutoPlay is active
|
||||
# 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
|
||||
# Priorities when ordering itemlist:
|
||||
# 0: Servers and qualities
|
||||
# 1: Qualities and servers
|
||||
# 2: Servers only
|
||||
# 3: Only qualities
|
||||
# 4: Do not order
|
||||
if (settings_node['custom_servers'] and settings_node['custom_quality']) or get_setting('autoplay'):
|
||||
priority = settings_node['priority'] # 0: Servidores y calidades o 1: Calidades y servidores
|
||||
priority = settings_node['priority'] # 0: Servers and qualities or 1: Qualities and servers
|
||||
elif settings_node['custom_servers']:
|
||||
priority = 2 # Solo servidores
|
||||
priority = 2 # Servers only
|
||||
elif settings_node['custom_quality']:
|
||||
priority = 3 # Solo calidades
|
||||
priority = 3 # Only qualities
|
||||
else:
|
||||
priority = 4 # No ordenar
|
||||
priority = 4 # Do not order
|
||||
|
||||
# Obtiene las listas servidores, calidades disponibles desde el nodo del json de AutoPlay
|
||||
# Get server lists, qualities available from AutoPlay json node
|
||||
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 no qualities are defined, default is assigned as unique quality.
|
||||
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']
|
||||
# The texts of each server and quality are stored in lists, e.g. 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
|
||||
# Itemlist links are filtered and correspond to autoplay values
|
||||
for n, item in enumerate(itemlist):
|
||||
autoplay_elem = dict()
|
||||
b_dict = dict()
|
||||
|
||||
# Comprobamos q se trata de un item de video
|
||||
# We check that it is a video item
|
||||
if 'server' not in item:
|
||||
continue
|
||||
#2nd lang lista idiomas
|
||||
# 2nd lang language list
|
||||
if item.language not in favorite_langs:
|
||||
favorite_langs.append(item.language)
|
||||
|
||||
# Agrega la opcion configurar AutoPlay al menu contextual
|
||||
# Add the option to configure AutoPlay to the context menu
|
||||
if 'context' not in item:
|
||||
item.context = list()
|
||||
if not [x for x in context if x['action'] == 'autoplay_config']:
|
||||
@@ -206,15 +202,14 @@ def start(itemlist, item):
|
||||
"channel": "autoplay",
|
||||
"from_channel": channel_id})
|
||||
|
||||
# Si no tiene calidad definida le asigna calidad 'default'
|
||||
# If it does not have a defined quality, it assigns a 'default' quality.
|
||||
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
|
||||
# The list for custom settings is created
|
||||
if priority < 2: # 0: Servers and qualities or 1: Qualities and servers
|
||||
|
||||
# si el servidor y la calidad no se encuentran en las listas de favoritos o la url esta repetida,
|
||||
# descartamos el item
|
||||
# if the server and the quality are not in the favorites lists or the url is repeated, we discard the 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
|
||||
@@ -225,10 +220,9 @@ def start(itemlist, item):
|
||||
autoplay_elem["indice_server"] = favorite_servers.index(item.server.lower())
|
||||
autoplay_elem["indice_quality"] = favorite_quality.index(item.quality)
|
||||
|
||||
elif priority == 2: # Solo servidores
|
||||
elif priority == 2: # Servers only
|
||||
|
||||
# si el servidor no se encuentra en la lista de favoritos o la url esta repetida,
|
||||
# descartamos el item
|
||||
# if the server is not in the favorites list or the url is repeated, we discard the item
|
||||
if item.server.lower() not in favorite_servers or item.url in url_list_valid:
|
||||
item.type_b = True
|
||||
b_dict['videoitem'] = item
|
||||
@@ -239,8 +233,7 @@ def start(itemlist, item):
|
||||
|
||||
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 the quality is not in the favorites list or the url is repeated, we discard the item
|
||||
if item.quality not in favorite_quality or item.url in url_list_valid:
|
||||
item.type_b = True
|
||||
b_dict['videoitem'] = item
|
||||
@@ -249,13 +242,13 @@ def start(itemlist, item):
|
||||
autoplay_elem["indice_lang"] = favorite_langs.index(item.language)
|
||||
autoplay_elem["indice_quality"] = favorite_quality.index(item.quality)
|
||||
|
||||
else: # No ordenar
|
||||
else: # Do not order
|
||||
|
||||
# si la url esta repetida, descartamos el item
|
||||
# if the url is repeated, we discard the 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
|
||||
# If the item reaches here we add it to the list of valid urls and to autoplay_list
|
||||
url_list_valid.append(item.url)
|
||||
item.plan_b=True
|
||||
autoplay_elem['videoitem'] = item
|
||||
@@ -263,20 +256,20 @@ def start(itemlist, item):
|
||||
# autoplay_elem['quality'] = item.quality
|
||||
autoplay_list.append(autoplay_elem)
|
||||
|
||||
# Ordenamos segun la prioridad
|
||||
if priority == 0: # Servidores y calidades
|
||||
# We order according to priority
|
||||
if priority == 0: # Servers and qualities
|
||||
autoplay_list.sort(key=lambda orden: (orden['indice_lang'], orden['indice_server'], orden['indice_quality']))
|
||||
|
||||
elif priority == 1: # Calidades y servidores
|
||||
elif priority == 1: # Qualities and servers
|
||||
autoplay_list.sort(key=lambda orden: (orden['indice_lang'], orden['indice_quality'], orden['indice_server']))
|
||||
|
||||
elif priority == 2: # Solo servidores
|
||||
elif priority == 2: # Servers only
|
||||
autoplay_list.sort(key=lambda orden: (orden['indice_lang'], orden['indice_server']))
|
||||
|
||||
elif priority == 3: # Solo calidades
|
||||
elif priority == 3: # Only qualities
|
||||
autoplay_list.sort(key=lambda orden: (orden['indice_lang'], orden['indice_quality']))
|
||||
|
||||
# Se prepara el plan b, en caso de estar activo se agregan los elementos no favoritos al final
|
||||
# Plan b is prepared, in case it is active the non-favorite elements are added at the end
|
||||
try:
|
||||
plan_b = settings_node['plan_b']
|
||||
except:
|
||||
@@ -284,23 +277,22 @@ def start(itemlist, item):
|
||||
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 there are elements in the autoplay list, an attempt is made to reproduce each element, until one is found or all fail.
|
||||
|
||||
if autoplay_list or (plan_b and autoplay_b):
|
||||
|
||||
#played = False
|
||||
# played = False
|
||||
max_intentos = 5
|
||||
max_intentos_servers = {}
|
||||
|
||||
# Si se esta reproduciendo algo detiene la reproduccion
|
||||
# If something is playing it stops playing
|
||||
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 it is not a favorite element if you add the text plan b
|
||||
if autoplay_elem['videoitem'].type_b:
|
||||
text_b = '(Plan B)'
|
||||
if not platformtools.is_playing() and not PLAYED:
|
||||
@@ -308,7 +300,7 @@ def start(itemlist, item):
|
||||
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 the maximum number of attempts of this server have been reached, we jump to the next
|
||||
if max_intentos_servers[videoitem.server.lower()] == 0:
|
||||
continue
|
||||
|
||||
@@ -318,10 +310,9 @@ def start(itemlist, item):
|
||||
|
||||
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!!!
|
||||
# TODO videoitem.server is the id of the server, but it might not be the name !!!
|
||||
|
||||
# Intenta reproducir los enlaces
|
||||
# Si el canal tiene metodo play propio lo utiliza
|
||||
# Try to play the links If the channel has its own play method, use it
|
||||
try:
|
||||
channel = __import__('channels.%s' % channel_id, None, None, ["channels.%s" % channel_id])
|
||||
except:
|
||||
@@ -334,19 +325,19 @@ def start(itemlist, item):
|
||||
else:
|
||||
videoitem = resolved_item[0]
|
||||
|
||||
# Si no directamente reproduce y marca como visto
|
||||
# If not directly reproduce and mark as seen
|
||||
|
||||
# Verifica si el item viene de la videoteca
|
||||
#Check if the item comes from the video library
|
||||
try:
|
||||
if base_item.contentChannel =='videolibrary':
|
||||
# Marca como visto
|
||||
# Mark as seen
|
||||
from platformcode import xbmc_videolibrary
|
||||
xbmc_videolibrary.mark_auto_as_watched(base_item)
|
||||
# Rellena el video con los datos del item principal y reproduce
|
||||
# Fill the video with the data of the main item and play
|
||||
play_item = base_item.clone(url=videoitem)
|
||||
platformtools.play_video(play_item.url, autoplay=True)
|
||||
else:
|
||||
# Si no viene de la videoteca solo reproduce
|
||||
# If it doesn't come from the video library, just play
|
||||
platformtools.play_video(videoitem, autoplay=True)
|
||||
except:
|
||||
pass
|
||||
@@ -358,18 +349,16 @@ def start(itemlist, item):
|
||||
except:
|
||||
logger.debug(str(len(autoplay_list)))
|
||||
|
||||
# Si hemos llegado hasta aqui es por q no se ha podido reproducir
|
||||
# If we have come this far, it is because it could not be reproduced
|
||||
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 the maximum number of attempts of this server has been reached, ask if we want to continue testing or ignore it.
|
||||
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)):
|
||||
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 there are no items in the list, it is reported
|
||||
if autoplay_elem == autoplay_list[-1]:
|
||||
platformtools.dialog_notification('AutoPlay', config.get_localized_string(60072) % videoitem.server.upper())
|
||||
|
||||
@@ -378,7 +367,7 @@ def start(itemlist, item):
|
||||
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
|
||||
# Restore if necessary the previous value of "Action and Player Mode" in preferences
|
||||
if user_config_setting_action != 2:
|
||||
config.set_setting("default_action", user_config_setting_action)
|
||||
if user_config_setting_player != 0:
|
||||
@@ -389,15 +378,15 @@ def start(itemlist, item):
|
||||
|
||||
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.
|
||||
Check the existence of a channel in the Autoplay configuration file and if it does not exist, add it.
|
||||
It is necessary to call this function when entering any channel that includes the Autoplay function.
|
||||
|
||||
: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.
|
||||
:param channel: (str) channel id
|
||||
:param list_servers: (list) initial list of valid servers for the channel. It is not necessary to include them all,
|
||||
since the list of valid servers will be updated dynamically.
|
||||
:param list_quality: (list) initial list of valid qualities for the channel. It is not necessary to include them all,
|
||||
since the list of valid qualities will be updated dynamically.
|
||||
:return: (bool) True if the initialization was successful.
|
||||
'''
|
||||
logger.info()
|
||||
change = False
|
||||
@@ -418,13 +407,13 @@ def init(channel, list_servers, list_quality, reset=False):
|
||||
if channel not in autoplay_node or reset:
|
||||
change = True
|
||||
|
||||
# Se comprueba que no haya calidades ni servidores duplicados
|
||||
# It is verified that there are no duplicate qualities or servers
|
||||
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
|
||||
# We create the channel node and add it
|
||||
channel_node = {"servers": list_servers,
|
||||
"quality": list_quality,
|
||||
"settings": {
|
||||
@@ -458,11 +447,11 @@ def init(channel, list_servers, list_quality, reset=False):
|
||||
|
||||
|
||||
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
|
||||
'''
|
||||
checks the existence of a value in the list of servers or qualities if it does not exist adds them to the list in the json
|
||||
|
||||
:param channel: str
|
||||
:param values: list (una de servidores o calidades)
|
||||
:param values: list (one of servers or qualities)
|
||||
:param value_type: str (server o quality)
|
||||
:return: list
|
||||
'''
|
||||
@@ -471,7 +460,7 @@ def check_value(channel, itemlist):
|
||||
change = False
|
||||
|
||||
if not autoplay_node:
|
||||
# Obtiene el nodo AUTOPLAY desde el json
|
||||
# Get AUTOPLAY node from json
|
||||
autoplay_node = jsontools.get_node_from_file('autoplay', 'AUTOPLAY')
|
||||
|
||||
channel_node = autoplay_node.get(channel)
|
||||
@@ -507,7 +496,7 @@ def autoplay_config(item):
|
||||
channel_name = channel_parameters['title']
|
||||
|
||||
if not autoplay_node:
|
||||
# Obtiene el nodo AUTOPLAY desde el json
|
||||
# Get AUTOPLAY node from json
|
||||
autoplay_node = jsontools.get_node_from_file('autoplay', 'AUTOPLAY')
|
||||
|
||||
channel_node = autoplay_node.get(item.from_channel, {})
|
||||
@@ -515,21 +504,19 @@ def autoplay_config(item):
|
||||
|
||||
allow_option = True
|
||||
|
||||
active_settings = {"id": "active", "label": config.get_localized_string(60079),
|
||||
"type": "bool", "default": False, "enabled": allow_option,
|
||||
"visible": allow_option}
|
||||
active_settings = {"id": "active", "label": config.get_localized_string(60079), "type": "bool",
|
||||
"default": False, "enabled": allow_option, "visible": allow_option}
|
||||
|
||||
list_controls.append(active_settings)
|
||||
dict_values['active'] = settings_node.get('active', False)
|
||||
|
||||
hide_servers = {"id": "hide_servers", "label": config.get_localized_string(70747),
|
||||
"type": "bool", "default": False, "enabled": "eq(-" + str(len(list_controls)) + ",true)",
|
||||
"visible": allow_option}
|
||||
hide_servers = {"id": "hide_servers", "label": config.get_localized_string(70747), "type": "bool",
|
||||
"default": False, "enabled": "eq(-" + str(len(list_controls)) + ",true)", "visible": allow_option}
|
||||
|
||||
list_controls.append(hide_servers)
|
||||
dict_values['hide_servers'] = settings_node.get('hide_servers', False)
|
||||
|
||||
# Idioma
|
||||
# Language
|
||||
status_language = config.get_setting("filter_languages", item.from_channel)
|
||||
if not status_language:
|
||||
status_language = 0
|
||||
@@ -546,7 +533,7 @@ def autoplay_config(item):
|
||||
"type": "label", "enabled": True, "visible": True}
|
||||
list_controls.append(separador)
|
||||
|
||||
# Seccion servidores favoritos
|
||||
# Favorite servers section
|
||||
server_list = channel_node.get("servers", [])
|
||||
if not server_list:
|
||||
enabled = False
|
||||
@@ -578,7 +565,7 @@ def autoplay_config(item):
|
||||
if settings_node.get("server_%s" % num, 0) > len(server_list) - 1:
|
||||
dict_values["server_%s" % num] = 0
|
||||
|
||||
# Seccion Calidades favoritas
|
||||
# Favorite Qualities Section
|
||||
quality_list = channel_node.get("quality", [])
|
||||
if not quality_list:
|
||||
enabled = False
|
||||
@@ -586,8 +573,7 @@ def autoplay_config(item):
|
||||
else:
|
||||
enabled = "eq(-" + str(len(list_controls)) + ",true)"
|
||||
|
||||
custom_quality_settings = {"id": "custom_quality", "label": config.get_localized_string(60083),
|
||||
"type": "bool", "default": False, "enabled": enabled, "visible": True}
|
||||
custom_quality_settings = {"id": "custom_quality", "label": config.get_localized_string(60083), "type": "bool", "default": False, "enabled": enabled, "visible": True}
|
||||
custom_quality_pos = len(list_controls)
|
||||
list_controls.append(custom_quality_settings)
|
||||
if dict_values['active'] and enabled:
|
||||
@@ -617,7 +603,7 @@ def autoplay_config(item):
|
||||
list_controls.append(plan_b)
|
||||
|
||||
|
||||
# Seccion Prioridades
|
||||
# Priorities Section
|
||||
priority_list = [config.get_localized_string(70174), config.get_localized_string(70175)]
|
||||
set_priority = {"id": "priority", "label": config.get_localized_string(60085), "type": "list", "default": 0,
|
||||
"enabled": True, "visible": "eq(-5,true)+eq(-9,true)+eq(-12,true)", "lvalues": priority_list}
|
||||
@@ -626,7 +612,7 @@ def autoplay_config(item):
|
||||
|
||||
|
||||
|
||||
# Abrir cuadro de dialogo
|
||||
# Open dialog box
|
||||
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,
|
||||
@@ -637,7 +623,7 @@ def autoplay_config(item):
|
||||
|
||||
def save(item, dict_data_saved):
|
||||
'''
|
||||
Guarda los datos de la ventana de configuracion
|
||||
Save the data from the configuration window
|
||||
|
||||
:param item: item
|
||||
:param dict_data_saved: dict
|
||||
@@ -647,7 +633,7 @@ def save(item, dict_data_saved):
|
||||
global autoplay_node
|
||||
|
||||
if not autoplay_node:
|
||||
# Obtiene el nodo AUTOPLAY desde el json
|
||||
# Get AUTOPLAY node from json
|
||||
autoplay_node = jsontools.get_node_from_file('autoplay', 'AUTOPLAY')
|
||||
|
||||
new_config = dict_data_saved
|
||||
@@ -665,7 +651,7 @@ def save(item, dict_data_saved):
|
||||
|
||||
def get_languages(channel):
|
||||
'''
|
||||
Obtiene los idiomas desde el json del canal
|
||||
Get the languages from the channel's json
|
||||
|
||||
:param channel: str
|
||||
:return: list
|
||||
@@ -685,9 +671,9 @@ def get_languages(channel):
|
||||
|
||||
def is_active(channel):
|
||||
'''
|
||||
Devuelve un booleano q indica si esta activo o no autoplay en el canal desde el que se llama
|
||||
Returns a boolean that indicates whether or not autoplay is active on the channel from which it is called
|
||||
|
||||
:return: True si esta activo autoplay para el canal desde el que se llama, False en caso contrario.
|
||||
:return:True if autoplay is active for the channel from which it is called, False otherwise.
|
||||
'''
|
||||
logger.info()
|
||||
global autoplay_node
|
||||
@@ -696,18 +682,18 @@ def is_active(channel):
|
||||
return False
|
||||
|
||||
if not autoplay_node:
|
||||
# Obtiene el nodo AUTOPLAY desde el json
|
||||
# Get AUTOPLAY node from json
|
||||
autoplay_node = jsontools.get_node_from_file('autoplay', 'AUTOPLAY')
|
||||
|
||||
# Obtine el canal desde el q se hace la llamada
|
||||
# Get the channel from which the call is made
|
||||
#import inspect
|
||||
#module = inspect.getmodule(inspect.currentframe().f_back)
|
||||
#canal = module.__name__.split('.')[1]
|
||||
canal = channel
|
||||
|
||||
# Obtiene el nodo del canal desde autoplay_node
|
||||
# Get the channel node from autoplay_node
|
||||
channel_node = autoplay_node.get(canal, {})
|
||||
# Obtiene los ajustes des autoplay para este canal
|
||||
# Get the autoplay settings for this channel
|
||||
settings_node = channel_node.get('settings', {})
|
||||
|
||||
return settings_node.get('active', False) or get_setting('autoplay')
|
||||
@@ -727,7 +713,7 @@ def reset(item, dict):
|
||||
|
||||
# def set_status(status):
|
||||
# logger.info()
|
||||
# # Obtiene el nodo AUTOPLAY desde el json
|
||||
# # Get AUTOPLAY node from json
|
||||
# autoplay_node = jsontools.get_node_from_file('autoplay', 'AUTOPLAY')
|
||||
# autoplay_node['status'] = status
|
||||
#
|
||||
@@ -737,7 +723,7 @@ def reset(item, dict):
|
||||
def get_channel_AP_HS(item):
|
||||
autoplay_node = jsontools.get_node_from_file('autoplay', 'AUTOPLAY')
|
||||
channel_node = autoplay_node.get(item.channel, {})
|
||||
if not channel_node: # non ha mai aperto il menu del canale quindi in autoplay_data.json non c'e la key
|
||||
if not channel_node: # never opened the channel menu so in autoplay_data.json there is no key
|
||||
try:
|
||||
channelFile = __import__('channels.' + item.channel, fromlist=["channels.%s" % item.channel])
|
||||
except:
|
||||
|
||||
@@ -18,7 +18,7 @@ addonid = addon.getAddonInfo('id')
|
||||
|
||||
LIST_SITE = ['http://www.ansa.it/', 'https://www.google.it']#, 'https://www.google.com']
|
||||
|
||||
# lista di siti che non verranno raggiunti con i DNS del gestore
|
||||
# list of sites that will not be reached with the manager's DNS
|
||||
|
||||
LST_SITE_CHCK_DNS = ['https://www.casacinema.me/', 'https://cb01-nuovo-indirizzo.info/']
|
||||
#'https://www.italia-film.pw', 'https://www.cb01.uno/',] # tolti
|
||||
@@ -41,13 +41,8 @@ class Kdicc():
|
||||
|
||||
def check_Ip(self):
|
||||
"""
|
||||
controllo l'ip
|
||||
se ip_addr = 127.0.0.1 o ip_addr = '' allora il device non
|
||||
e' connesso al modem/router
|
||||
|
||||
check the ip
|
||||
if ip_addr = 127.0.0.1 or ip_addr = '' then the device does not
|
||||
is connected to the modem/router
|
||||
if ip_addr = 127.0.0.1 or ip_addr = '' then the device does not is connected to the modem/router
|
||||
|
||||
return: bool
|
||||
"""
|
||||
@@ -59,7 +54,7 @@ class Kdicc():
|
||||
|
||||
def check_Adsl(self):
|
||||
"""
|
||||
controllo se il device raggiunge i siti
|
||||
check if the device reaches the sites
|
||||
"""
|
||||
|
||||
urls = LIST_SITE
|
||||
@@ -67,8 +62,8 @@ class Kdicc():
|
||||
http_errr = 0
|
||||
for rslt in r:
|
||||
xbmc.log("check_Adsl rslt: %s" % rslt['code'], level=xbmc.LOGNOTICE)
|
||||
# Errno -2 potrebbe essere mancanza di connessione adsl o sito non raggiungibile....
|
||||
# anche nei casi in cui ci sia il cambio gestore.
|
||||
# Errno -2 could be lack of adsl connection or unreachable site ....
|
||||
# even in cases where there is a change of manager.
|
||||
if rslt['code'] == '111' or '[Errno -3]' in str(rslt['code']) or 'Errno -2' in str(rslt['code']):
|
||||
http_errr +=1
|
||||
|
||||
@@ -80,7 +75,7 @@ class Kdicc():
|
||||
|
||||
def check_Dns(self):
|
||||
"""
|
||||
Controllo se i DNS raggiungono certi siti
|
||||
Control if DNS reaches certain sites
|
||||
"""
|
||||
if self.lst_site_check_dns == []:
|
||||
urls = LST_SITE_CHCK_DNS
|
||||
@@ -88,7 +83,7 @@ class Kdicc():
|
||||
urls = self.lst_site_check_dns
|
||||
|
||||
r = self.rqst(urls)
|
||||
xbmc.log("check_Dns risultato: %s" % r, level=xbmc.LOGNOTICE)
|
||||
xbmc.log("check_Dns result: %s" % r, level=xbmc.LOGNOTICE)
|
||||
http_errr = 0
|
||||
for rslt in r:
|
||||
xbmc.log("check_Dns rslt: %s" % rslt['code'], level=xbmc.LOGNOTICE)
|
||||
@@ -103,7 +98,7 @@ class Kdicc():
|
||||
|
||||
def rqst(self, lst_urls):
|
||||
"""
|
||||
url deve iniziare con http(s):'
|
||||
url must start with http(s):'
|
||||
return : (esito, sito, url, code, reurl)
|
||||
"""
|
||||
rslt_final = []
|
||||
@@ -114,7 +109,7 @@ class Kdicc():
|
||||
for sito in lst_urls:
|
||||
rslt = {}
|
||||
try:
|
||||
r = requests.head(sito, allow_redirects = True)#, timeout=7) # da errore dopo l'inserimento in lib di httplib2
|
||||
r = requests.head(sito, allow_redirects = True) #, timeout=7) # from error after lib insertion of httplib2
|
||||
if r.url.endswith('/'):
|
||||
r.url = r.url[:-1]
|
||||
if str(sito) != str(r.url):
|
||||
@@ -130,17 +125,17 @@ class Kdicc():
|
||||
xbmc.log("Risultato nel try: %s" % (r,), level=xbmc.LOGNOTICE)
|
||||
|
||||
except requests.exceptions.ConnectionError as conn_errr:
|
||||
# Errno 10061 per s.o. win
|
||||
# gli Errno 10xxx e 11xxx saranno da compattare in qualche modo?
|
||||
# gli errori vengono inglobati in code = '111' in quanto in quel momento
|
||||
# non vengono raggiunti per una qualsiasi causa
|
||||
# Errno 10061 for s.o. win
|
||||
# will the Errno 10xxx and 11xxx be to be compacted in any way?
|
||||
# the errors are incorporated in code = '111' since at that moment
|
||||
# they are not reached for any reason
|
||||
if '[Errno 111]' in str(conn_errr) or 'Errno 10060' in str(conn_errr) \
|
||||
or 'Errno 10061' in str(conn_errr) \
|
||||
or '[Errno 110]' in str(conn_errr) \
|
||||
or 'ConnectTimeoutError' in str(conn_errr) \
|
||||
or 'Errno 11002' in str(conn_errr) or 'ReadTimeout' in str(conn_errr) \
|
||||
or 'Errno 11001' in str(conn_errr) \
|
||||
or 'Errno -2' in str(conn_errr): # questo errore è anche nel code: -2
|
||||
or 'Errno -2' in str(conn_errr): # this error is also in the code: -2
|
||||
rslt['code'] = '111'
|
||||
rslt['url'] = str(sito)
|
||||
rslt['http_err'] = 'Connection error'
|
||||
@@ -169,11 +164,11 @@ class Kdicc():
|
||||
else:
|
||||
rslt['code'] = code.status
|
||||
except httplib2.ServerNotFoundError as msg:
|
||||
# sia per mancanza di ADSL che per i siti non esistenti
|
||||
# both for lack of ADSL and for non-existent sites
|
||||
rslt['code'] = -2
|
||||
except socket.error as msg:
|
||||
# per siti irraggiungibili senza DNS corretti
|
||||
#[Errno 111] Connection refused
|
||||
# for unreachable sites without correct DNS
|
||||
# [Errno 111] Connection refused
|
||||
rslt['code'] = 111
|
||||
except:
|
||||
rslt['code'] = 'Connection error'
|
||||
@@ -181,8 +176,7 @@ class Kdicc():
|
||||
|
||||
def view_Advise(self, txt = '' ):
|
||||
"""
|
||||
Avviso per utente
|
||||
testConnected
|
||||
Notice per user testConnected
|
||||
"""
|
||||
ip = self.check_Ip()
|
||||
if ip:
|
||||
@@ -201,37 +195,36 @@ class Kdicc():
|
||||
txt = config.get_localized_string(707402)
|
||||
dialog.notification(addonname, txt, xbmcgui.NOTIFICATION_INFO, 10000)
|
||||
"""
|
||||
def richiamato in launcher.py
|
||||
def called in launcher.py
|
||||
"""
|
||||
def test_conn(is_exit, check_dns, view_msg,
|
||||
lst_urls, lst_site_check_dns, in_addon):
|
||||
|
||||
ktest = Kdicc(is_exit, check_dns, view_msg, lst_urls, lst_site_check_dns, in_addon)
|
||||
# se non ha l'ip lo comunico all'utente
|
||||
# if it does not have the IP, I will communicate it to the user
|
||||
if not ktest.check_Ip():
|
||||
# non permetto di entrare nell'addon
|
||||
# I don't let you get into the addon
|
||||
# inserire codice lingua
|
||||
# enter language code
|
||||
if view_msg == True:
|
||||
ktest.view_Advise(config.get_localized_string(70720))
|
||||
if ktest.is_exit == True:
|
||||
exit()
|
||||
# se non ha connessione ADSL lo comunico all'utente
|
||||
# if it has no ADSL connection, I will communicate it to the user
|
||||
if not ktest.check_Adsl():
|
||||
if view_msg == True:
|
||||
ktest.view_Advise(config.get_localized_string(70721))
|
||||
if ktest.is_exit == True:
|
||||
exit()
|
||||
# se ha i DNS filtrati lo comunico all'utente
|
||||
# if it has DNS filtered, I will communicate it to the user
|
||||
if check_dns == True:
|
||||
if not ktest.check_Dns():
|
||||
if view_msg == True:
|
||||
ktest.view_Advise(config.get_localized_string(70722))
|
||||
|
||||
xbmc.log("############ Inizio Check DNS ############", level=xbmc.LOGNOTICE)
|
||||
xbmc.log("############ Start Check DNS ############", level=xbmc.LOGNOTICE)
|
||||
xbmc.log("## IP: %s" % (ktest.ip_addr), level=xbmc.LOGNOTICE)
|
||||
xbmc.log("## DNS: %s" % (ktest.dns), level=xbmc.LOGNOTICE)
|
||||
xbmc.log("############ Fine Check DNS ############", level=xbmc.LOGNOTICE)
|
||||
xbmc.log("############# End Check DNS #############", level=xbmc.LOGNOTICE)
|
||||
# if check_dns == True:
|
||||
# if ktest.check_Ip() == True and ktest.check_Adsl() == True and ktest.check_Dns() == True:
|
||||
# return True
|
||||
@@ -243,21 +236,17 @@ def test_conn(is_exit, check_dns, view_msg,
|
||||
# else:
|
||||
# return False
|
||||
|
||||
# def per la creazione del file channels.json
|
||||
# def for creating the channels.json file
|
||||
def check_channels(inutile=''):
|
||||
"""
|
||||
leggo gli host dei canali dal file channels.json
|
||||
li controllo
|
||||
scrivo il file channels-test.json
|
||||
con il codice di errore e il nuovio url in caso di redirect
|
||||
I read the channel hosts from the channels.json file, I check them,
|
||||
I write the channels-test.json file with the error code and the new url in case of redirect
|
||||
|
||||
gli url DEVONO avere http(s)
|
||||
urls MUST have http (s)
|
||||
|
||||
Durante il controllo degli urls vengono rieffettuati
|
||||
i controlli di ip, asdl e dns.
|
||||
Questo perchè può succedere che in un qualsiasi momento
|
||||
la connessione possa avere problemi. Nel caso accada, il controllo e
|
||||
relativa scrittura del file viene interrotto con messaggio di avvertimento
|
||||
During the urls check the ip, asdl and dns checks are carried out.
|
||||
This is because it can happen that at any time the connection may have problems. If it does, check it
|
||||
relative writing of the file is interrupted with a warning message
|
||||
"""
|
||||
logger.info()
|
||||
|
||||
@@ -272,37 +261,37 @@ def check_channels(inutile=''):
|
||||
for chann, host in sorted(data.items()):
|
||||
|
||||
ris = []
|
||||
# per avere un'idea della tempistica
|
||||
# utile solo se si controllano tutti i canali
|
||||
# per i canali con error 522 si perdono circa 40 sec...
|
||||
# to get an idea of the timing
|
||||
# useful only if you control all channels
|
||||
# for channels with error 522 about 40 seconds are lost ...
|
||||
logger.info("check #### INIZIO #### channel - host :%s - %s " % (chann, host))
|
||||
|
||||
rslt = Kdicc(lst_urls = [host]).http_Resp()
|
||||
|
||||
# tutto ok
|
||||
# all right
|
||||
if rslt['code'] == 200:
|
||||
risultato[chann] = host
|
||||
# redirect
|
||||
elif str(rslt['code']).startswith('3'):
|
||||
#risultato[chann] = str(rslt['code']) +' - '+ rslt['redirect'][:-1]
|
||||
# risultato[chann] = str(rslt['code']) +' - '+ rslt['redirect'][:-1]
|
||||
if rslt['redirect'].endswith('/'):
|
||||
rslt['redirect'] = rslt['redirect'][:-1]
|
||||
risultato[chann] = rslt['redirect']
|
||||
# sito inesistente
|
||||
# non-existent site
|
||||
elif rslt['code'] == -2:
|
||||
risultato[chann] = 'Host Sconosciuto - '+ str(rslt['code']) +' - '+ host
|
||||
# sito non raggiungibile - probabili dns non settati
|
||||
# site not reachable - probable dns not set
|
||||
elif rslt['code'] == 111:
|
||||
risultato[chann] = ['Host non raggiungibile - '+ str(rslt['code']) +' - '+ host]
|
||||
else:
|
||||
# altri tipi di errore
|
||||
#risultato[chann] = 'Errore Sconosciuto - '+str(rslt['code']) +' - '+ host
|
||||
# other types of errors
|
||||
# risultato[chann] = 'Errore Sconosciuto - '+str(rslt['code']) +' - '+ host
|
||||
risultato[chann] = host
|
||||
|
||||
logger.info("check #### FINE #### rslt :%s " % (rslt))
|
||||
|
||||
fileJson_test = 'channels-test.json'
|
||||
# scrivo il file aggiornato
|
||||
# I write the updated file
|
||||
with open(folderJson+'/'+fileJson_test, 'w') as f:
|
||||
data = json.dump(risultato, f, sort_keys=True, indent=4)
|
||||
logger.info(data)
|
||||
|
||||
@@ -11,17 +11,13 @@ if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int
|
||||
from future.builtins import filter
|
||||
from past.utils import old_div
|
||||
|
||||
import re
|
||||
import time
|
||||
import unicodedata
|
||||
import xbmc
|
||||
import re, time, unicodedata, xbmc
|
||||
|
||||
from channelselector import get_thumb
|
||||
from core import filetools, jsontools, scraper, scrapertools, servertools, videolibrarytools, support
|
||||
from core.downloader import Downloader
|
||||
from core.item import Item
|
||||
from platformcode import config, logger
|
||||
from platformcode import platformtools
|
||||
from platformcode import config, logger, platformtools
|
||||
from core.support import log, dbg, typo
|
||||
from servers import torrent
|
||||
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ------------------------------------------------------------
|
||||
# Lista de vídeos favoritos
|
||||
# List of favorite videos
|
||||
# ------------------------------------------------------------
|
||||
|
||||
import os
|
||||
import time
|
||||
import os, time
|
||||
|
||||
from core import filetools
|
||||
from core import scrapertools
|
||||
from core import filetools, scrapertools
|
||||
from core.item import Item
|
||||
from platformcode import config, logger
|
||||
from platformcode import platformtools
|
||||
from platformcode import config, logger, platformtools
|
||||
|
||||
try:
|
||||
# Fijamos la ruta a favourites.xml
|
||||
# We set the path to favorites.xml
|
||||
if config.is_xbmc():
|
||||
import xbmc
|
||||
|
||||
@@ -32,8 +29,7 @@ def mainlist(item):
|
||||
|
||||
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(""", "")
|
||||
url = scrapertools.find_single_match(data, 'plugin://plugin.video.%s/\?([^;]*)' % config.PLUGIN_NAME).replace(""", "")
|
||||
|
||||
item = Item().fromurl(url)
|
||||
item.title = name
|
||||
@@ -45,7 +41,7 @@ def mainlist(item):
|
||||
elif type(item.context) != list:
|
||||
item.context = []
|
||||
|
||||
item.context.extend([{"title": config.get_localized_string(30154), # "Quitar de favoritos"
|
||||
item.context.extend([{"title": config.get_localized_string(30154), # "Remove from favorites "
|
||||
"action": "delFavourite",
|
||||
"channel": "favorites",
|
||||
"from_title": item.title},
|
||||
@@ -88,7 +84,7 @@ 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 you get here through the context menu, you must retrieve the action and channel parameters
|
||||
if item.from_action:
|
||||
item.__dict__["action"] = item.__dict__.pop("from_action")
|
||||
if item.from_channel:
|
||||
@@ -100,8 +96,7 @@ def addFavourite(item):
|
||||
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'
|
||||
platformtools.dialog_ok(config.get_localized_string(30102), titulo, config.get_localized_string(30108)) # 'added to favorites'
|
||||
|
||||
|
||||
def delFavourite(item):
|
||||
@@ -117,8 +112,7 @@ def delFavourite(item):
|
||||
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.dialog_ok(config.get_localized_string(30102), item.title, config.get_localized_string(30105).lower()) # 'Removed from favorites'
|
||||
platformtools.itemlist_refresh()
|
||||
break
|
||||
|
||||
@@ -127,22 +121,21 @@ def renameFavourite(item):
|
||||
logger.info()
|
||||
# logger.debug(item.tostring('\n'))
|
||||
|
||||
# Buscar el item q queremos renombrar en favourites.xml
|
||||
# Find the item we want to rename in favorites.xml
|
||||
favourites_list = read_favourites()
|
||||
for i, fav in enumerate(favourites_list):
|
||||
if fav[0] == item.from_title:
|
||||
# abrir el teclado
|
||||
# open keyboard
|
||||
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.dialog_ok(config.get_localized_string(30102), item.from_title, config.get_localized_string(60086) + ' ', new_title) # 'Removed from favorites'
|
||||
platformtools.itemlist_refresh()
|
||||
|
||||
|
||||
##################################################
|
||||
# Funciones para migrar favoritos antiguos (.txt)
|
||||
# Features to migrate old favorites (.txt)
|
||||
def readbookmark(filepath):
|
||||
logger.info()
|
||||
import urllib
|
||||
@@ -176,7 +169,7 @@ def readbookmark(filepath):
|
||||
except:
|
||||
plot = lines[4].strip()
|
||||
|
||||
# Campos contentTitle y canal añadidos
|
||||
# ContentTitle and channel fields added
|
||||
if len(lines) >= 6:
|
||||
try:
|
||||
contentTitle = urllib.unquote_plus(lines[5].strip())
|
||||
@@ -199,7 +192,7 @@ def readbookmark(filepath):
|
||||
|
||||
|
||||
def check_bookmark(readpath):
|
||||
# Crea un listado con las entradas de favoritos
|
||||
# Create a list with favorite entries
|
||||
itemlist = []
|
||||
|
||||
if readpath.startswith("special://") and config.is_xbmc():
|
||||
@@ -207,12 +200,12 @@ def check_bookmark(readpath):
|
||||
readpath = xbmc.translatePath(readpath)
|
||||
|
||||
for fichero in sorted(filetools.listdir(readpath)):
|
||||
# Ficheros antiguos (".txt")
|
||||
# Old files (".txt")
|
||||
if fichero.endswith(".txt"):
|
||||
# Esperamos 0.1 segundos entre ficheros, para que no se solapen los nombres de archivo
|
||||
# We wait 0.1 seconds between files, so that the file names do not overlap
|
||||
time.sleep(0.1)
|
||||
|
||||
# Obtenemos el item desde el .txt
|
||||
# We get the item from the .txt
|
||||
canal, titulo, thumbnail, plot, server, url, contentTitle = readbookmark(filetools.join(readpath, fichero))
|
||||
if canal == "":
|
||||
canal = "favorites"
|
||||
@@ -222,21 +215,21 @@ def check_bookmark(readpath):
|
||||
filetools.rename(filetools.join(readpath, fichero), fichero[:-4] + ".old")
|
||||
itemlist.append(item)
|
||||
|
||||
# Si hay Favoritos q guardar
|
||||
# If there are Favorites to save
|
||||
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")
|
||||
logger.debug("Correct txt to xml conversion")
|
||||
|
||||
|
||||
# Esto solo funcionara al migrar de versiones anteriores, ya no existe "bookmarkpath"
|
||||
# This will only work when migrating from previous versions, there is no longer a "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")
|
||||
logger.info("No path to old version favorites")
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ------------------------------------------------------------
|
||||
# filtertools - se encarga de filtrar resultados
|
||||
# filtertools - is responsible for filtering results
|
||||
# ------------------------------------------------------------
|
||||
|
||||
from builtins import object
|
||||
@@ -27,7 +27,7 @@ filter_global = None
|
||||
__channel__ = "filtertools"
|
||||
|
||||
|
||||
# TODO echar un ojo a https://pyformat.info/, se puede formatear el estilo y hacer referencias directamente a elementos
|
||||
# TODO take a look at https://pyformat.info/, you can format the style and make references directly to elements
|
||||
|
||||
|
||||
class ResultFilter(object):
|
||||
@@ -37,8 +37,7 @@ class ResultFilter(object):
|
||||
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)
|
||||
return "{active: '%s', language: '%s', quality_allowed: '%s'}" % (self.active, self.language, self.quality_allowed)
|
||||
|
||||
|
||||
class Filter(object):
|
||||
@@ -59,7 +58,7 @@ class Filter(object):
|
||||
TAG_LANGUAGE: dict_filtered_shows[tvshow][TAG_LANGUAGE],
|
||||
TAG_QUALITY_ALLOWED: dict_filtered_shows[tvshow][TAG_QUALITY_ALLOWED]})
|
||||
|
||||
# opcion general "no filtrar"
|
||||
# general option "do not filter"
|
||||
elif global_filter_language != 0:
|
||||
from core import channeltools
|
||||
list_controls, dict_settings = channeltools.get_channel_controls_settings(item.channel)
|
||||
@@ -71,8 +70,7 @@ class Filter(object):
|
||||
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))
|
||||
logger.error("The value associated with the code was not found '%s': %s" % (global_filter_lang_id, global_filter_language))
|
||||
break
|
||||
|
||||
self.result = ResultFilter({TAG_ACTIVE: True, TAG_LANGUAGE: language, TAG_QUALITY_ALLOWED: []})
|
||||
@@ -84,7 +82,7 @@ class Filter(object):
|
||||
|
||||
def access():
|
||||
"""
|
||||
Devuelve si se puede usar o no filtertools
|
||||
Returns whether or not filtertools can be used
|
||||
"""
|
||||
allow = False
|
||||
|
||||
@@ -96,24 +94,23 @@ def access():
|
||||
|
||||
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-.
|
||||
For xbmc / kodi and mediaserver since they can show the contextual menu, a filter option is added to the configuration menu, only if it is for series.
|
||||
Depending on the place and if there is a filter, more options will be added to show.
|
||||
The context -is shown only for series-.
|
||||
|
||||
@param item: elemento para obtener la información y ver que contexto añadir
|
||||
@param item: eelement to get the information and see what context to add
|
||||
@type item: item
|
||||
param list_language: listado de idiomas posibles
|
||||
param list_language: list of possible languages
|
||||
@type list_language: list[str]
|
||||
@param list_quality: listado de calidades posibles
|
||||
@param list_quality: list of possible qualities
|
||||
@type list_quality: list[str]
|
||||
@param exist: si existe el filtro
|
||||
@param exist: if the filter exists
|
||||
@type exist: bool
|
||||
@return: lista de opciones a mostrar en el menú contextual
|
||||
@return: list of options to display in the context menu
|
||||
@rtype: list
|
||||
"""
|
||||
|
||||
# Dependiendo de como sea el contexto lo guardamos y añadimos las opciones de filtertools.
|
||||
# Depending on how the context is, we save it and add the filtertools options.
|
||||
if isinstance(item.context, str):
|
||||
_context = item.context.split("|")
|
||||
elif isinstance(item.context, list):
|
||||
@@ -152,10 +149,8 @@ def context(item, list_language=None, list_quality=None, exist=False):
|
||||
|
||||
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))
|
||||
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
|
||||
|
||||
@@ -169,14 +164,14 @@ def check_conditions(_filter, list_item, item, list_language, list_quality, qual
|
||||
|
||||
if _filter.language:
|
||||
# logger.debug("title es %s" % item.title)
|
||||
#2nd lang
|
||||
# 2nd lang
|
||||
|
||||
from platformcode import unify
|
||||
_filter.language = unify.set_lang(_filter.language).upper()
|
||||
|
||||
# viene de episodios
|
||||
# comes from episodes
|
||||
if isinstance(item.language, list):
|
||||
#2nd lang
|
||||
# 2nd lang
|
||||
for n, lang in enumerate(item.language):
|
||||
item.language[n] = unify.set_lang(lang).upper()
|
||||
|
||||
@@ -184,9 +179,9 @@ def check_conditions(_filter, list_item, item, list_language, list_quality, qual
|
||||
language_count += 1
|
||||
else:
|
||||
is_language_valid = False
|
||||
# viene de findvideos
|
||||
# comes from findvideos
|
||||
else:
|
||||
#2nd lang
|
||||
# 2nd lang
|
||||
item.language = unify.set_lang(item.language).upper()
|
||||
|
||||
if item.language.lower() == _filter.language.lower():
|
||||
@@ -198,7 +193,7 @@ def check_conditions(_filter, list_item, item, list_language, list_quality, qual
|
||||
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 hasattr (item, 'quality'): # this validation is not necessary because the empty attribute is ALWAYS returned
|
||||
if item.quality.lower() in _filter.quality_allowed:
|
||||
quality = item.quality.lower()
|
||||
quality_count += 1
|
||||
@@ -206,7 +201,7 @@ def check_conditions(_filter, list_item, item, list_language, list_quality, qual
|
||||
is_quality_valid = False
|
||||
|
||||
if is_language_valid and is_quality_valid:
|
||||
#TODO 2nd lang: habría que ver si conviene unificar el idioma aqui o no
|
||||
#TODO 2nd lang: we should see if it is convenient to unify the language here or not
|
||||
item.list_language = list_language
|
||||
if list_quality:
|
||||
item.list_quality = list_quality
|
||||
@@ -216,34 +211,32 @@ def check_conditions(_filter, list_item, item, list_language, list_quality, qual
|
||||
# logger.debug(" -Enlace añadido")
|
||||
elif not item.language:
|
||||
list_item.append(item)
|
||||
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))
|
||||
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, _filter.language
|
||||
|
||||
|
||||
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.
|
||||
Returns a list of links, if the item is correctly filtered it is added to the received list.
|
||||
|
||||
@param list_item: lista de enlaces
|
||||
@param list_item: list of links
|
||||
@type list_item: list[Item]
|
||||
@param item: elemento a filtrar
|
||||
@param item: element to filter
|
||||
@type item: Item
|
||||
@param list_language: listado de idiomas posibles
|
||||
@param list_language: list of possible languages
|
||||
@type list_language: list[str]
|
||||
@param list_quality: listado de calidades posibles
|
||||
@param list_quality: list of possible qualities
|
||||
@type list_quality: list[str]
|
||||
@param global_filter_lang_id: id de la variable de filtrado por idioma que está en settings
|
||||
@param global_filter_lang_id: id of the filtering variable by language that is in settings
|
||||
@type global_filter_lang_id: str
|
||||
@return: lista de Item
|
||||
@return: Item list
|
||||
@rtype: list[Item]
|
||||
"""
|
||||
logger.info()
|
||||
|
||||
# si los campos obligatorios son None salimos
|
||||
# if the required fields are None we leave
|
||||
if list_item is None or item is None:
|
||||
return []
|
||||
|
||||
@@ -256,8 +249,7 @@ def get_link(list_item, item, list_language, list_quality=None, global_filter_la
|
||||
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)[:3]
|
||||
list_item, quality_count, language_count = check_conditions(filter_global, list_item, item, list_language, list_quality)[:3]
|
||||
else:
|
||||
item.context = context(item)
|
||||
list_item.append(item)
|
||||
@@ -267,17 +259,17 @@ def get_link(list_item, item, list_language, list_quality=None, global_filter_la
|
||||
|
||||
def get_links(list_item, item, list_language, list_quality=None, global_filter_lang_id="filter_languages"):
|
||||
"""
|
||||
Devuelve una lista de enlaces filtrados.
|
||||
Returns a list of filtered links.
|
||||
|
||||
@param list_item: lista de enlaces
|
||||
@param list_item: list of links
|
||||
@type list_item: list[Item]
|
||||
@param item: elemento a filtrar
|
||||
@param item: element to filter
|
||||
@type item: item
|
||||
@param list_language: listado de idiomas posibles
|
||||
@param list_language: list of possible languages
|
||||
@type list_language: list[str]
|
||||
@param list_quality: listado de calidades posibles
|
||||
@param list_quality: list of possible qualities
|
||||
@type list_quality: list[str]
|
||||
@param global_filter_lang_id: id de la variable de filtrado por idioma que está en settings
|
||||
@param global_filter_lang_id: id of the filtering variable by language that is in settings
|
||||
@type global_filter_lang_id: str
|
||||
@return: lista de Item
|
||||
@rtype: list[Item]
|
||||
@@ -285,18 +277,18 @@ def get_links(list_item, item, list_language, list_quality=None, global_filter_l
|
||||
logger.info()
|
||||
|
||||
|
||||
# si los campos obligatorios son None salimos
|
||||
# if the required fields are None we leave
|
||||
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 list_item is empty we go back, no platform validation is added so Plex can do global filter
|
||||
if len(list_item) == 0:
|
||||
return list_item
|
||||
|
||||
|
||||
second_lang = config.get_setting('second_language')
|
||||
|
||||
#Ordena segun servidores favoritos, elima servers de blacklist y desactivados
|
||||
# Sort by favorite servers, delete blacklist servers and disabled
|
||||
from core import servertools
|
||||
list_item= servertools.filter_servers(list_item)
|
||||
|
||||
@@ -313,8 +305,7 @@ def get_links(list_item, item, list_language, list_quality=None, global_filter_l
|
||||
if _filter and _filter.active:
|
||||
|
||||
for item in list_item:
|
||||
new_itemlist, quality_count, language_count, first_lang = check_conditions(_filter, new_itemlist, item, list_language,
|
||||
list_quality, quality_count, language_count)
|
||||
new_itemlist, quality_count, language_count, first_lang = check_conditions(_filter, new_itemlist, item, list_language, list_quality, quality_count, language_count)
|
||||
|
||||
#2nd lang
|
||||
if second_lang and second_lang != 'No' and first_lang.lower() != second_lang.lower() :
|
||||
@@ -322,7 +313,6 @@ def get_links(list_item, item, list_language, list_quality=None, global_filter_l
|
||||
_filter2 = _filter
|
||||
_filter2.language = second_lang
|
||||
for it in new_itemlist:
|
||||
|
||||
if isinstance(it.language, list):
|
||||
if not second_lang in it.language:
|
||||
second_list.append(it)
|
||||
@@ -330,32 +320,27 @@ def get_links(list_item, item, list_language, list_quality=None, global_filter_l
|
||||
second_list = new_itemlist
|
||||
break
|
||||
for item in list_item:
|
||||
new_itemlist, quality_count, language_count, second_lang = check_conditions(_filter2, second_list, item, list_language,
|
||||
list_quality, quality_count, language_count)
|
||||
new_itemlist, quality_count, language_count, second_lang = check_conditions(_filter2, second_list, item, list_language, list_quality, quality_count, language_count)
|
||||
|
||||
|
||||
logger.debug("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))
|
||||
logger.debug("FILTERED ITEMS: %s/%s, language [%s]: %s, allowed quality %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": config.get_localized_string(60430) % _filter.language, "action": "delete_from_context",
|
||||
"channel": "filtertools", "to_channel": item.channel}]
|
||||
_context = [{"title": config.get_localized_string(60430) % _filter.language, "action": "delete_from_context", "channel": "filtertools", "to_channel": item.channel}]
|
||||
|
||||
if _filter.quality_allowed:
|
||||
msg_quality_allowed = " y calidad %s" % _filter.quality_allowed
|
||||
else:
|
||||
msg_quality_allowed = ""
|
||||
|
||||
|
||||
msg_lang = ' %s' % first_lang.upper()
|
||||
if second_lang and second_lang != 'No':
|
||||
msg_lang = 's %s ni %s' % (first_lang.upper(), second_lang.upper())
|
||||
|
||||
|
||||
new_itemlist.append(Item(channel=__channel__, action="no_filter", list_item_all=list_item_all,
|
||||
show=item.show,
|
||||
title=config.get_localized_string(60432) % (_filter.language, msg_quality_allowed),
|
||||
@@ -392,15 +377,15 @@ def no_filter(item):
|
||||
|
||||
def mainlist(channel, list_language, list_quality):
|
||||
"""
|
||||
Muestra una lista de las series filtradas
|
||||
Shows a list of the leaked series
|
||||
|
||||
@param channel: nombre del canal para obtener las series filtradas
|
||||
@param channel: channel name to get filtered series
|
||||
@type channel: str
|
||||
@param list_language: lista de idiomas del canal
|
||||
@param list_language: channel language list
|
||||
@type list_language: list[str]
|
||||
@param list_quality: lista de calidades del canal
|
||||
@param list_quality: channel quality list
|
||||
@type list_quality: list[str]
|
||||
@return: lista de Item
|
||||
@return: Item list
|
||||
@rtype: list[Item]
|
||||
"""
|
||||
logger.info()
|
||||
@@ -439,7 +424,7 @@ def mainlist(channel, list_language, list_quality):
|
||||
|
||||
def config_item(item):
|
||||
"""
|
||||
muestra una serie filtrada para su configuración
|
||||
displays a filtered series for your setup
|
||||
|
||||
@param item: item
|
||||
@type item: Item
|
||||
@@ -447,7 +432,7 @@ def config_item(item):
|
||||
logger.info()
|
||||
logger.info("item %s" % item.tostring())
|
||||
|
||||
# OBTENEMOS LOS DATOS DEL JSON
|
||||
# WE GET THE JSON DATA
|
||||
dict_series = jsontools.get_node_from_file(item.from_channel, TAG_TVSHOW_FILTER)
|
||||
|
||||
tvshow = item.show.lower().strip()
|
||||
@@ -462,7 +447,7 @@ def config_item(item):
|
||||
pass
|
||||
|
||||
if default_lang == '':
|
||||
platformtools.dialog_notification("FilterTools", "No hay idiomas definidos")
|
||||
platformtools.dialog_notification("FilterTools", "There are no defined languages")
|
||||
return
|
||||
else:
|
||||
lang_selected = dict_series.get(tvshow, {}).get(TAG_LANGUAGE, default_lang)
|
||||
@@ -525,7 +510,7 @@ def config_item(item):
|
||||
"visible": True,
|
||||
})
|
||||
|
||||
# concatenamos list_controls con list_controls_calidad
|
||||
# we concatenate list_controls with list_controls_quality
|
||||
list_controls.extend(list_controls_calidad)
|
||||
|
||||
title = config.get_localized_string(60441) % (COLOR.get("selected", "auto"), item.show)
|
||||
@@ -566,11 +551,11 @@ def delete(item, dict_values):
|
||||
|
||||
def save(item, dict_data_saved):
|
||||
"""
|
||||
Guarda los valores configurados en la ventana
|
||||
Save the configured values in the window
|
||||
|
||||
@param item: item
|
||||
@type item: Item
|
||||
@param dict_data_saved: diccionario con los datos salvados
|
||||
@param dict_data_saved: dictionary with saved data
|
||||
@type dict_data_saved: dict
|
||||
"""
|
||||
logger.info()
|
||||
@@ -583,7 +568,7 @@ def save(item, dict_data_saved):
|
||||
dict_series = jsontools.get_node_from_file(item.from_channel, TAG_TVSHOW_FILTER)
|
||||
tvshow = item.show.strip().lower()
|
||||
|
||||
logger.info("Se actualiza los datos")
|
||||
logger.info("Data is updated")
|
||||
|
||||
list_quality = []
|
||||
for _id, value in list(dict_data_saved.items()):
|
||||
@@ -613,7 +598,7 @@ def save(item, dict_data_saved):
|
||||
|
||||
def save_from_context(item):
|
||||
"""
|
||||
Salva el filtro a través del menú contextual
|
||||
Save the filter through the context menu
|
||||
|
||||
@param item: item
|
||||
@type item: item
|
||||
@@ -630,9 +615,9 @@ def save_from_context(item):
|
||||
|
||||
sound = False
|
||||
if result:
|
||||
message = "FILTRO GUARDADO"
|
||||
message = "SAVED FILTER"
|
||||
else:
|
||||
message = "Error al guardar en disco"
|
||||
message = "Error saving to disk"
|
||||
sound = True
|
||||
|
||||
heading = "%s [%s]" % (item.show.strip(), item.language)
|
||||
@@ -644,14 +629,14 @@ def save_from_context(item):
|
||||
|
||||
def delete_from_context(item):
|
||||
"""
|
||||
Elimina el filtro a través del menú contextual
|
||||
Delete the filter through the context menu
|
||||
|
||||
@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
|
||||
# We come from get_links and no result has been obtained, in context menu and we delete
|
||||
if item.to_channel != "":
|
||||
item.from_channel = item.to_channel
|
||||
|
||||
@@ -665,9 +650,9 @@ def delete_from_context(item):
|
||||
|
||||
sound = False
|
||||
if result:
|
||||
message = "FILTRO ELIMINADO"
|
||||
message = "FILTER REMOVED"
|
||||
else:
|
||||
message = "Error al guardar en disco"
|
||||
message = "Error saving to disk"
|
||||
sound = True
|
||||
|
||||
heading = "%s [%s]" % (item.show.strip(), lang_selected)
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ------------------------------------------------------------
|
||||
# Alfa favoritos
|
||||
# KoD favorites
|
||||
# ==============
|
||||
# - 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: kodfavourites-default.json
|
||||
# - Se puede copiar kodfavourites-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 kodfavourites- y terminar en .json
|
||||
# - List of links saved as favorites, only in Alpha, not Kodi.
|
||||
# - Links are organized in (virtual) folders that can be defined by the user.
|
||||
# - A single file is used to save all folders and links: kodfavourites-default.json
|
||||
# - kodfavourites-default.json can be copied to other devices since the only local dependency is the thumbnail associated with the links,
|
||||
# but it is detected by code and adjusts to the current device.
|
||||
# - You can have different alphabet files and alternate between them, but only one of them is the "active list".
|
||||
# - Files must be in config.get_data_path () and start with kodfavourites- and end in .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
|
||||
# Requirements in other modules to run this channel:
|
||||
# - Add a link to this channel in channelselector.py
|
||||
# - Modify platformtools.py to control the context menu and add "Save link" in set_context_commands
|
||||
# ------------------------------------------------------------
|
||||
|
||||
#from builtins import str
|
||||
# from builtins import str
|
||||
import sys
|
||||
PY3 = False
|
||||
if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int
|
||||
@@ -32,35 +32,34 @@ from core import filetools, jsontools
|
||||
def fechahora_actual():
|
||||
return datetime.now().strftime('%Y-%m-%d %H:%M')
|
||||
|
||||
# Helpers para listas
|
||||
# -------------------
|
||||
# List Helpers
|
||||
|
||||
PREFIJO_LISTA = 'kodfavorites-'
|
||||
|
||||
# Devuelve el nombre de la lista activa (Ej: kodfavourites-default.json)
|
||||
# Returns the name of the active list (Ex: kodfavourites-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: kodfavourites-Prueba.json => Prueba)
|
||||
# Extract list name from file, removing prefix and suffix (Ex: kodfavourites-Test.json => Test)
|
||||
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 => kodfavourites-Prueba.json)
|
||||
# Compose the list file from a name, adding prefix and suffix (Ex: Test => kodfavourites-Test.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
|
||||
# Record the codes of the files that have been shared in a log file
|
||||
def save_log_lista_shared(msg):
|
||||
msg = fechahora_actual() + ': ' + msg + os.linesep
|
||||
fullfilename = os.path.join(config.get_data_path(), 'kodfavorites_shared.log')
|
||||
with open(fullfilename, 'a') as f: f.write(msg); f.close()
|
||||
|
||||
# Limpiar texto para usar como nombre de fichero
|
||||
# Clean text to use as file name
|
||||
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
|
||||
except NameError: # unicode is a default on python 3
|
||||
pass
|
||||
txt = unicodedata.normalize('NFKD', txt).encode('ascii', 'ignore')
|
||||
txt = txt.decode('utf-8').strip()
|
||||
@@ -70,13 +69,12 @@ def text_clean(txt, disallowed_chars = '[^a-zA-Z0-9\-_()\[\]. ]+', blank_char =
|
||||
|
||||
|
||||
|
||||
# Clase para cargar y guardar en el fichero de Alfavoritos
|
||||
# --------------------------------------------------------
|
||||
# Class to load and save in the KoDFavorites file
|
||||
class KodfavouritesData(object):
|
||||
|
||||
def __init__(self, filename = None):
|
||||
|
||||
# Si no se especifica ningún fichero se usa la lista_activa (si no la hay se crea)
|
||||
# If no file is specified, the active_list is used (if not, it is created)
|
||||
if filename == None:
|
||||
filename = get_lista_activa()
|
||||
|
||||
@@ -84,7 +82,7 @@ class KodfavouritesData(object):
|
||||
|
||||
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)
|
||||
if os.path.exists(fichero_anterior): # old format, convert (to delete after some versions)
|
||||
jsondata = jsontools.load(filetools.read(fichero_anterior))
|
||||
self.user_favorites = jsondata
|
||||
self.info_lista = {}
|
||||
@@ -94,7 +92,7 @@ class KodfavouritesData(object):
|
||||
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
|
||||
if not 'user_favorites' in jsondata or not 'info_lista' in jsondata: # incorrect format
|
||||
self.user_favorites = []
|
||||
else:
|
||||
self.user_favorites = jsondata['user_favorites']
|
||||
@@ -103,8 +101,8 @@ class KodfavouritesData(object):
|
||||
|
||||
if len(self.user_favorites) == 0:
|
||||
self.info_lista = {}
|
||||
|
||||
# Crear algunas carpetas por defecto
|
||||
|
||||
# Create some default folders
|
||||
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': [] })
|
||||
@@ -112,7 +110,7 @@ class KodfavouritesData(object):
|
||||
self.save()
|
||||
|
||||
def save(self):
|
||||
if 'created' not in self.info_lista:
|
||||
if 'created' not in self.info_lista:
|
||||
self.info_lista['created'] = fechahora_actual()
|
||||
self.info_lista['updated'] = fechahora_actual()
|
||||
|
||||
@@ -120,34 +118,34 @@ class KodfavouritesData(object):
|
||||
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))
|
||||
platformtools.dialog_ok('KoD', config.get_localized_string(70614), os.path.basename(self.user_favorites_file))
|
||||
|
||||
|
||||
# ============================
|
||||
# Añadir desde menú contextual
|
||||
# Add from context menu
|
||||
# ============================
|
||||
|
||||
def addFavourite(item):
|
||||
logger.info()
|
||||
alfav = KodfavouritesData()
|
||||
|
||||
# Si se llega aquí mediante el menú contextual, hay que recuperar los parámetros action y channel
|
||||
# If you get here through the context menu, you must retrieve the action and channel parameters
|
||||
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
|
||||
#Clear title
|
||||
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
|
||||
# Dialog to choose / create folder
|
||||
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
|
||||
# Detect that the same link does not already exist in the folder
|
||||
campos = ['channel','action','url','extra','list_type'] # if all these fields match the link is considered to already exist
|
||||
for enlace in alfav.user_favorites[i_perfil]['items']:
|
||||
it = Item().fromurl(enlace)
|
||||
repe = True
|
||||
@@ -159,25 +157,25 @@ def addFavourite(item):
|
||||
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 it is a movie / series, fill in tmdb information if tmdb_plus_info is not activated (for season / episode it is not necessary because the "second pass" will have already been done)
|
||||
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, ...)
|
||||
tmdb.set_infoLabels(item, True) # get more data in "second pass" (actors, duration, ...)
|
||||
|
||||
# Añadir fecha en que se guarda
|
||||
# Add date saved
|
||||
item.date_added = fechahora_actual()
|
||||
|
||||
# Guardar
|
||||
# save
|
||||
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
|
||||
# NAVIGATION
|
||||
# ====================
|
||||
|
||||
def mainlist(item):
|
||||
@@ -211,7 +209,7 @@ def mainlist(item):
|
||||
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
|
||||
@@ -240,15 +238,15 @@ def mostrar_perfil(item):
|
||||
it.plot += '[CR][COLOR blue]Url:[/COLOR] ' + it.url if isinstance(it.url, str) else '...'
|
||||
if it.date_added != '': it.plot += '[CR][COLOR blue]' + config.get_localized_string(70469) + ':[/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 is not a url, nor does it have the system path, convert the path since it will have been copied from another device.
|
||||
# It would be more optimal if the conversion was done with an import menu, but at the moment it is controlled in 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
|
||||
if ruta == '' and fichero == it.thumbnail: # in linux the split with a windows path does not separate correctly
|
||||
ruta, fichero = filetools.split(it.thumbnail.replace('\\','/'))
|
||||
if 'channels' in ruta and 'thumb' in ruta:
|
||||
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:
|
||||
elif 'themes' in ruta and 'default' in ruta:
|
||||
it.thumbnail = filetools.join(ruta_runtime, 'resources', 'media', 'themes', 'default', fichero)
|
||||
|
||||
itemlist.append(it)
|
||||
@@ -256,28 +254,27 @@ def mostrar_perfil(item):
|
||||
return itemlist
|
||||
|
||||
|
||||
# Rutinas internas compartidas
|
||||
# ----------------------------
|
||||
# Shared internal routines
|
||||
|
||||
# Diálogo para seleccionar/crear una carpeta. Devuelve índice de la carpeta en user_favorites (-1 si cancel)
|
||||
# Dialog to select / create a folder. Returns index of folder on user_favorites (-1 if 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
|
||||
while i_perfil == -1: # repeat until a folder is selected or cancel
|
||||
ret = platformtools.dialog_select(titulo, acciones)
|
||||
if ret == -1: return -1 # pedido cancel
|
||||
if ret == -1: return -1 # order cancel
|
||||
if ret < len(alfav.user_favorites):
|
||||
i_perfil = ret
|
||||
else: # crear nueva carpeta
|
||||
else: # create new folder
|
||||
if _crea_perfil(alfav):
|
||||
i_perfil = len(alfav.user_favorites) - 1
|
||||
|
||||
return i_perfil
|
||||
|
||||
|
||||
# Diálogo para crear una carpeta
|
||||
# Dialog to create a folder
|
||||
def _crea_perfil(alfav):
|
||||
titulo = platformtools.dialog_input(default='', heading=config.get_localized_string(70551))
|
||||
if titulo is None or titulo == '':
|
||||
@@ -289,8 +286,7 @@ def _crea_perfil(alfav):
|
||||
return True
|
||||
|
||||
|
||||
# Gestión de perfiles y enlaces
|
||||
# -----------------------------
|
||||
# Profile and link management
|
||||
|
||||
def crear_perfil(item):
|
||||
logger.info()
|
||||
@@ -325,7 +321,7 @@ def eliminar_perfil(item):
|
||||
|
||||
if not alfav.user_favorites[item.i_perfil]: return False
|
||||
|
||||
# Pedir confirmación
|
||||
# Ask for confirmation
|
||||
if not platformtools.dialog_yesno(config.get_localized_string(70618), config.get_localized_string(70619)): return False
|
||||
|
||||
del alfav.user_favorites[item.i_perfil]
|
||||
@@ -342,9 +338,9 @@ def acciones_enlace(item):
|
||||
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
|
||||
ret = platformtools.dialog_select('Action to execute', acciones)
|
||||
if ret == -1:
|
||||
return False # order cancel
|
||||
elif ret == 0:
|
||||
return editar_enlace_titulo(item)
|
||||
elif ret == 1:
|
||||
@@ -375,11 +371,11 @@ def editar_enlace_titulo(item):
|
||||
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')
|
||||
|
||||
titulo = platformtools.dialog_input(default=it.title, heading='Change link title')
|
||||
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()
|
||||
@@ -397,13 +393,13 @@ def editar_enlace_color(item):
|
||||
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)
|
||||
ret = platformtools.dialog_select('Select color:', opciones)
|
||||
|
||||
if ret == -1: return False # pedido cancel
|
||||
if ret == -1: return False # order cancel
|
||||
it.text_color = colores[ret]
|
||||
|
||||
alfav.user_favorites[item.i_perfil]['items'][item.i_enlace] = it.tourl()
|
||||
@@ -421,13 +417,13 @@ def editar_enlace_thumbnail(item):
|
||||
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)
|
||||
|
||||
# Starting with Kodi 17, you can use xbmcgui.Dialog (). Select with 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)
|
||||
# Dialog to choose thumbnail (the channel or predefined icons)
|
||||
opciones = []
|
||||
ids = []
|
||||
try:
|
||||
@@ -444,7 +440,7 @@ def editar_enlace_thumbnail(item):
|
||||
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':
|
||||
@@ -458,11 +454,11 @@ def editar_enlace_thumbnail(item):
|
||||
ids.append(os.path.join(resource_path, f))
|
||||
|
||||
if is_kodi17:
|
||||
ret = xbmcgui.Dialog().select('Seleccionar thumbnail:', opciones, useDetails=True)
|
||||
ret = xbmcgui.Dialog().select('Select thumbnail:', opciones, useDetails=True)
|
||||
else:
|
||||
ret = platformtools.dialog_select('Seleccionar thumbnail:', opciones)
|
||||
ret = platformtools.dialog_select('Select thumbnail:', opciones)
|
||||
|
||||
if ret == -1: return False # pedido cancel
|
||||
if ret == -1: return False # order cancel
|
||||
|
||||
it.thumbnail = ids[ret]
|
||||
|
||||
@@ -480,8 +476,8 @@ def editar_enlace_carpeta(item):
|
||||
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)
|
||||
# Dialog to choose / create folder
|
||||
i_perfil = _selecciona_perfil(alfav, 'Move link to:', 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])
|
||||
@@ -499,26 +495,26 @@ def editar_enlace_lista(item):
|
||||
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
|
||||
# Dialog to choose list
|
||||
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
|
||||
if it.lista != '' and '[<---]' not in it.title: # discard item create and active list
|
||||
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')
|
||||
platformtools.dialog_ok('KoD', 'There are no other lists where to move the link.', 'You can create them from the Manage link lists menu')
|
||||
return False
|
||||
|
||||
ret = platformtools.dialog_select('Seleccionar lista destino', opciones)
|
||||
ret = platformtools.dialog_select('Select destination list', opciones)
|
||||
|
||||
if ret == -1:
|
||||
return False # pedido cancel
|
||||
if ret == -1:
|
||||
return False # order cancel
|
||||
|
||||
alfav_destino = KodfavouritesData(opciones[ret])
|
||||
|
||||
# Diálogo para escoger/crear carpeta en la lista de destino
|
||||
i_perfil = _selecciona_perfil(alfav_destino, 'Seleccionar carpeta destino', -1)
|
||||
# Dialog to choose / create folder in the destination list
|
||||
i_perfil = _selecciona_perfil(alfav_destino, 'Select destination folder', -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])
|
||||
@@ -544,8 +540,7 @@ def eliminar_enlace(item):
|
||||
return True
|
||||
|
||||
|
||||
# Mover perfiles y enlaces (arriba, abajo, top, bottom)
|
||||
# ------------------------
|
||||
# Move profiles and links (up, down, top, bottom)
|
||||
def mover_perfil(item):
|
||||
logger.info()
|
||||
alfav = KodfavouritesData()
|
||||
@@ -568,28 +563,28 @@ def mover_enlace(item):
|
||||
return True
|
||||
|
||||
|
||||
# Mueve un item determinado (numérico) de una lista (arriba, abajo, top, bottom) y devuelve la lista modificada
|
||||
# Move a certain item (numeric) from a list (up, down, top, bottom) and return the modified list
|
||||
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 i_selected > last_i or i_selected < 0: return lista # non-existent index in list
|
||||
|
||||
if direccion == 'arriba':
|
||||
if i_selected == 0: # Ya está arriba de todo
|
||||
if i_selected == 0: # It's already on top of everything
|
||||
return lista
|
||||
lista.insert(i_selected - 1, lista.pop(i_selected))
|
||||
|
||||
elif direccion == 'abajo':
|
||||
if i_selected == last_i: # Ya está abajo de todo
|
||||
if i_selected == last_i: # It's already down
|
||||
return lista
|
||||
lista.insert(i_selected + 1, lista.pop(i_selected))
|
||||
|
||||
elif direccion == 'top':
|
||||
if i_selected == 0: # Ya está arriba de todo
|
||||
if i_selected == 0: # It's already on top of everything
|
||||
return lista
|
||||
lista.insert(0, lista.pop(i_selected))
|
||||
|
||||
elif direccion == 'bottom':
|
||||
if i_selected == last_i: # Ya está abajo de todo
|
||||
if i_selected == last_i: # It's already down
|
||||
return lista
|
||||
lista.insert(last_i, lista.pop(i_selected))
|
||||
|
||||
@@ -598,7 +593,7 @@ def _mover_item(lista, i_selected, direccion):
|
||||
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
# Gestionar diferentes listas de alfavoritos
|
||||
# Manage different alphabetical lists
|
||||
# ------------------------------------------
|
||||
|
||||
def mainlist_listas(item):
|
||||
@@ -607,19 +602,19 @@ def mainlist_listas(item):
|
||||
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
|
||||
|
||||
titulo = nombre if lista != lista_activa else 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
|
||||
|
||||
|
||||
@@ -631,7 +626,7 @@ def acciones_lista(item):
|
||||
|
||||
ret = platformtools.dialog_select(item.lista, acciones)
|
||||
|
||||
if ret == -1:
|
||||
if ret == -1:
|
||||
return False # pedido cancel
|
||||
elif ret == 0:
|
||||
return activar_lista(item)
|
||||
@@ -650,7 +645,7 @@ def activar_lista(item):
|
||||
|
||||
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)
|
||||
platformtools.dialog_ok('KoD', config.get_localized_string(70630), item.lista)
|
||||
return False
|
||||
|
||||
config.set_setting('lista_activa', item.lista)
|
||||
@@ -668,9 +663,9 @@ def renombrar_lista(item):
|
||||
|
||||
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)
|
||||
platformtools.dialog_ok('KoD', 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:
|
||||
@@ -680,17 +675,17 @@ def renombrar_lista(item):
|
||||
filename = get_filename_from_name(titulo)
|
||||
fullfilename = os.path.join(config.get_data_path(), filename)
|
||||
|
||||
# Comprobar que el nuevo nombre no exista
|
||||
# Check that the new name does not exist
|
||||
if os.path.exists(fullfilename):
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70613), fullfilename)
|
||||
platformtools.dialog_ok('KoD', config.get_localized_string(70613), fullfilename)
|
||||
return False
|
||||
|
||||
# Rename del fichero
|
||||
# Rename the file
|
||||
if not filetools.rename(fullfilename_current, filename):
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70631), fullfilename)
|
||||
platformtools.dialog_ok('KoD', config.get_localized_string(70631), fullfilename)
|
||||
return False
|
||||
|
||||
# Update settings si es la lista activa
|
||||
# Update settings if it is the active list
|
||||
if item.lista == get_lista_activa():
|
||||
config.set_setting('lista_activa', filename)
|
||||
|
||||
@@ -704,11 +699,11 @@ def eliminar_lista(item):
|
||||
|
||||
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)
|
||||
platformtools.dialog_ok('KoD', 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)
|
||||
platformtools.dialog_ok('KoD', 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
|
||||
@@ -720,15 +715,15 @@ def eliminar_lista(item):
|
||||
|
||||
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)
|
||||
platformtools.dialog_ok('KoD', config.get_localized_string(70630), item.lista)
|
||||
return False
|
||||
|
||||
alfav = KodfavouritesData(item.lista)
|
||||
|
||||
txt = 'Lista: [COLOR gold]%s[/COLOR]' % item.lista
|
||||
|
||||
txt = 'Lista: %s' % 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:
|
||||
@@ -736,7 +731,7 @@ def informacion_lista(item):
|
||||
|
||||
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) + ' ' + str(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))
|
||||
@@ -750,21 +745,21 @@ def compartir_lista(item):
|
||||
|
||||
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)
|
||||
platformtools.dialog_ok('KoD', 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
|
||||
|
||||
# Access to the tinyupload home page to obtain necessary data
|
||||
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
|
||||
# Sending the file to tinyupload using multipart / form-data
|
||||
from future import standard_library
|
||||
standard_library.install_aliases()
|
||||
from lib import MultipartPostHandler
|
||||
@@ -773,31 +768,31 @@ def compartir_lista(item):
|
||||
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))
|
||||
platformtools.dialog_ok('KoD', 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)
|
||||
platformtools.dialog_ok('KoD', config.get_localized_string(70647), item.lista)
|
||||
return False
|
||||
|
||||
# Apuntar código en fichero de log y dentro de la lista
|
||||
# Point code in log file and inside the list
|
||||
save_log_lista_shared(config.get_localized_string(70648) + ' ' + item.lista + ' ' + codigo + ' ' + config.get_localized_string(70649))
|
||||
|
||||
|
||||
alfav = KodfavouritesData(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)
|
||||
platformtools.dialog_ok('KoD', config.get_localized_string(70650), codigo)
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
||||
def acciones_nueva_lista(item):
|
||||
@@ -810,8 +805,8 @@ def acciones_nueva_lista(item):
|
||||
|
||||
ret = platformtools.dialog_select(config.get_localized_string(70608), acciones)
|
||||
|
||||
if ret == -1:
|
||||
return False # pedido cancel
|
||||
if ret == -1:
|
||||
return False # order cancel
|
||||
|
||||
elif ret == 0:
|
||||
return crear_lista(item)
|
||||
@@ -845,12 +840,12 @@ def crear_lista(item):
|
||||
filename = get_filename_from_name(titulo)
|
||||
fullfilename = os.path.join(config.get_data_path(), filename)
|
||||
|
||||
# Comprobar que el fichero no exista ya
|
||||
# Check that the file does not already exist
|
||||
if os.path.exists(fullfilename):
|
||||
platformtools.dialog_ok('Alfa', config.get_localized_string(70613), fullfilename)
|
||||
platformtools.dialog_ok('KoD', config.get_localized_string(70613), fullfilename)
|
||||
return False
|
||||
|
||||
# Provocar que se guarde con las carpetas vacías por defecto
|
||||
# Cause it to be saved with empty folders by default
|
||||
alfav = KodfavouritesData(filename)
|
||||
|
||||
platformtools.itemlist_refresh()
|
||||
@@ -860,7 +855,7 @@ def crear_lista(item):
|
||||
def descargar_lista(item, url):
|
||||
logger.info()
|
||||
from core import httptools, scrapertools
|
||||
|
||||
|
||||
if 'tinyupload.com/' in url:
|
||||
try:
|
||||
from urllib.parse import urlparse
|
||||
@@ -869,15 +864,15 @@ def descargar_lista(item, url):
|
||||
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)
|
||||
platformtools.dialog_ok('KoD', 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)
|
||||
platformtools.dialog_ok('KoD', config.get_localized_string(70655), motivo)
|
||||
return False
|
||||
url_json = video_urls[0][1] # https://www58.zippyshare.com/d/qPzzQ0UM/25460/kodfavourites-testeanding.json
|
||||
url_name = url_json[url_json.rfind('/')+1:]
|
||||
@@ -893,19 +888,19 @@ def descargar_lista(item, url):
|
||||
|
||||
# Download json
|
||||
data = httptools.downloadpage(url_json).data
|
||||
|
||||
# Verificar formato json de kodfavourites y añadir info de la descarga
|
||||
|
||||
# Verify ksonfavourites json format and add download info
|
||||
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))
|
||||
platformtools.dialog_ok('KoD', 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
|
||||
# Ask for name for downloaded list
|
||||
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 == '':
|
||||
@@ -915,14 +910,14 @@ def descargar_lista(item, url):
|
||||
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 the new name already exists ask for confirmation to overwrite
|
||||
if os.path.exists(fullfilename):
|
||||
if not platformtools.dialog_yesno('Alfa', config.get_localized_string(70613), config.get_localized_string(70658), filename):
|
||||
if not platformtools.dialog_yesno('KoD', 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)
|
||||
if not filetools.write(fullfilename, data):
|
||||
platformtools.dialog_ok('KoD', config.get_localized_string(70659), filename)
|
||||
|
||||
platformtools.dialog_ok('KoD', config.get_localized_string(70660), filename)
|
||||
platformtools.itemlist_refresh()
|
||||
return True
|
||||
|
||||
@@ -11,25 +11,19 @@ from core.support import typo
|
||||
PY3 = False
|
||||
if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int
|
||||
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import glob, os, re, time
|
||||
from threading import Thread
|
||||
|
||||
from channelselector import get_thumb, auto_filter
|
||||
from core import channeltools
|
||||
from core import jsontools
|
||||
from core import scrapertools, support
|
||||
from core import channeltools, jsontools, scrapertools, support
|
||||
from core.item import Item
|
||||
from platformcode import config, logger
|
||||
from platformcode import platformtools
|
||||
from platformcode import config, logger, platformtools
|
||||
|
||||
THUMBNAILS = {'0': 'posters', '1': 'banners', '2': 'squares'}
|
||||
|
||||
__perfil__ = config.get_setting('perfil', "news")
|
||||
|
||||
# Fijar perfil de color
|
||||
# Set color profile
|
||||
perfil = [['0xFF0B7B92', '0xFF89FDFB', '0xFFACD5D4'],
|
||||
['0xFFB31313', '0xFFFF9000', '0xFFFFEE82'],
|
||||
['0xFF891180', '0xFFCB22D7', '0xFFEEA1EB'],
|
||||
@@ -141,7 +135,7 @@ def get_channels_list():
|
||||
list_canales = {'peliculas': [], 'series': [],'anime': [], 'italiano':[], 'documentales': []}
|
||||
|
||||
any_active = False
|
||||
# Rellenar listas de canales disponibles
|
||||
# Fill available channel lists
|
||||
channels_path = os.path.join(config.get_runtime_path(), "channels", '*.json')
|
||||
channel_language = config.get_setting("channel_language", default="all")
|
||||
if channel_language =="auto":
|
||||
@@ -151,16 +145,16 @@ def get_channels_list():
|
||||
channel_id = os.path.basename(infile)[:-5]
|
||||
channel_parameters = channeltools.get_channel_parameters(channel_id)
|
||||
|
||||
# No incluir si es un canal inactivo
|
||||
# Do not include if it is an inactive channel
|
||||
if not channel_parameters["active"]:
|
||||
continue
|
||||
|
||||
# No incluir si el canal es en un idioma filtrado
|
||||
# Do not include if the channel is in a filtered language
|
||||
if channel_language != "all" and channel_language not in str(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
|
||||
# Include in each category, if in your configuration the channel is activated to show news
|
||||
|
||||
for categoria in list_canales:
|
||||
include_in_newest = config.get_setting("include_in_newest_" + categoria, channel_id)
|
||||
@@ -267,7 +261,7 @@ def novedades(item):
|
||||
|
||||
if any_active and len(list_canales[item.extra])>0:
|
||||
import math
|
||||
# fix float porque la division se hace mal en python 2.x
|
||||
# fix float because division is done poorly in python 2.x
|
||||
number_of_channels = float(100) / len(list_canales[item.extra])
|
||||
|
||||
for index, channel in enumerate(list_canales[item.extra]):
|
||||
@@ -294,7 +288,7 @@ def novedades(item):
|
||||
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
|
||||
# Multi Thread mode: wait for all threads to finish
|
||||
if multithread:
|
||||
pendent = [a for a in threads if a.isAlive()]
|
||||
t = float(100) / len(pendent)
|
||||
@@ -326,15 +320,15 @@ def novedades(item):
|
||||
if mode != 'normal':
|
||||
result_mode=0
|
||||
|
||||
if result_mode == 0: # Agrupados por contenido
|
||||
if result_mode == 0: # Grouped by content
|
||||
ret = group_by_content(list_newest)
|
||||
elif result_mode == 1: # Agrupados por canales
|
||||
elif result_mode == 1: # Grouped by channels
|
||||
ret = group_by_channel(list_newest)
|
||||
else: # Sin agrupar
|
||||
else: # Ungrouped
|
||||
ret = no_group(list_newest)
|
||||
|
||||
while time.time() - start_time < 2:
|
||||
# mostrar cuadro de progreso con el tiempo empleado durante almenos 2 segundos
|
||||
# show progress chart with time spent for at least 2 seconds
|
||||
time.sleep(0.5)
|
||||
if mode == 'normal':
|
||||
progreso.close()
|
||||
@@ -356,8 +350,8 @@ def get_newest(channel_id, 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
|
||||
# We request the news of the category (item.extra) searched in the channel channel
|
||||
# If there are no news for that category in the channel, it returns an empty list
|
||||
try:
|
||||
|
||||
puede = True
|
||||
@@ -381,7 +375,7 @@ def get_newest(channel_id, categoria):
|
||||
exist=True
|
||||
else:
|
||||
cache_node = {}
|
||||
#logger.debug('cache node: %s' % cache_node)
|
||||
# logger.debug('cache node: %s' % cache_node)
|
||||
for item in list_result:
|
||||
# logger.info("item="+item.tostring())
|
||||
item.channel = channel_id
|
||||
@@ -399,11 +393,11 @@ def get_newest(channel_id, categoria):
|
||||
|
||||
|
||||
def get_title(item):
|
||||
#support.log("ITEM NEWEST ->", item)
|
||||
# support.log("ITEM NEWEST ->", item)
|
||||
# item.contentSerieName c'è anche se è un film
|
||||
if item.contentSerieName and item.contentType != 'movie': # Si es una serie
|
||||
title = item.contentSerieName
|
||||
#title = re.compile("\[.*?\]", re.DOTALL).sub("", item.contentSerieName)
|
||||
# title = re.compile("\[.*?\]", re.DOTALL).sub("", item.contentSerieName)
|
||||
if not scrapertools.get_season_and_episode(title) and item.contentEpisodeNumber:
|
||||
# contentSeason non c'è in support
|
||||
if not item.contentSeason:
|
||||
@@ -414,14 +408,14 @@ def get_title(item):
|
||||
if seas:
|
||||
title = "%s - %s" % (seas, title)
|
||||
|
||||
elif item.contentTitle: # Si es una pelicula con el canal adaptado
|
||||
elif item.contentTitle: # If it is a movie with the adapted channel
|
||||
title = item.contentTitle
|
||||
elif item.contentTitle: # Si el canal no esta adaptado
|
||||
elif item.contentTitle: # If the channel is not adapted
|
||||
title = item.contentTitle
|
||||
else: # Como ultimo recurso
|
||||
else: # As a last resort
|
||||
title = item.title
|
||||
|
||||
# Limpiamos el titulo de etiquetas de formato anteriores
|
||||
# We clean the title of previous format labels
|
||||
title = re.compile("\[/*COLO.*?\]", re.DOTALL).sub("", title)
|
||||
title = re.compile("\[/*B\]", re.DOTALL).sub("", title)
|
||||
title = re.compile("\[/*I\]", re.DOTALL).sub("", title)
|
||||
@@ -452,9 +446,9 @@ def no_group(list_result_canal):
|
||||
global channels_id_name
|
||||
|
||||
for i in list_result_canal:
|
||||
#support.log("NO GROUP i -> ", i)
|
||||
# support.log("NO GROUP i -> ", i)
|
||||
canale = channels_id_name[i.channel]
|
||||
canale = canale # per differenziarlo dal colore delle altre voci
|
||||
canale = canale # to differentiate it from the color of the other items
|
||||
i.title = get_title(i) + " [" + canale + "]"
|
||||
# i.text_color = color3
|
||||
|
||||
@@ -471,12 +465,12 @@ def group_by_channel(list_result_canal):
|
||||
for i in list_result_canal:
|
||||
if i.channel not in dict_canales:
|
||||
dict_canales[i.channel] = []
|
||||
# Formatear titulo
|
||||
# Format title
|
||||
i.title = get_title(i)
|
||||
# Añadimos el contenido al listado de cada canal
|
||||
# We add the content to the list of each channel
|
||||
dict_canales[i.channel].append(i)
|
||||
|
||||
# Añadimos el contenido encontrado en la lista list_result
|
||||
# We add the content found in the list_result list
|
||||
for c in sorted(dict_canales):
|
||||
itemlist.append(Item(channel="news", title=channels_id_name[c] + ':', text_color=color1, text_bold=True))
|
||||
|
||||
@@ -498,10 +492,10 @@ def group_by_content(list_result_canal):
|
||||
list_result = []
|
||||
|
||||
for i in list_result_canal:
|
||||
# Formatear titulo
|
||||
# Format title
|
||||
i.title = get_title(i)
|
||||
|
||||
# Eliminar tildes y otros caracteres especiales para la key
|
||||
# Remove tildes and other special characters for the key
|
||||
import unicodedata
|
||||
try:
|
||||
new_key = i.title.lower().strip().decode("UTF-8")
|
||||
@@ -511,16 +505,16 @@ def group_by_content(list_result_canal):
|
||||
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...
|
||||
#If the content was already in the dictionary add it to the list of options ...
|
||||
dict_contenidos[new_key].append(i)
|
||||
else: # ...sino añadirlo al diccionario
|
||||
else: # ...but add it to the dictionary
|
||||
dict_contenidos[new_key] = [i]
|
||||
|
||||
# Añadimos el contenido encontrado en la lista list_result
|
||||
# We add the content found in the list_result list
|
||||
for v in list(dict_contenidos.values()):
|
||||
title = v[0].title
|
||||
if len(v) > 1:
|
||||
# Eliminar de la lista de nombres de canales los q esten duplicados
|
||||
# Remove duplicate q's from the channel names list
|
||||
canales_no_duplicados = []
|
||||
for i in v:
|
||||
if i.channel not in canales_no_duplicados:
|
||||
@@ -622,16 +616,16 @@ def setting_channel(item):
|
||||
channel_id = os.path.basename(infile)[:-5]
|
||||
channel_parameters = channeltools.get_channel_parameters(channel_id)
|
||||
|
||||
# No incluir si es un canal inactivo
|
||||
# Do not include if it is an inactive channel
|
||||
if not channel_parameters["active"]:
|
||||
continue
|
||||
|
||||
# No incluir si el canal es en un idioma filtrado
|
||||
# Do not include if the channel is in a filtered language
|
||||
if channel_language != "all" and channel_language not in str(channel_parameters["language"]) \
|
||||
and "*" not in channel_parameters["language"]:
|
||||
continue
|
||||
|
||||
# No incluir si en su configuracion el canal no existe 'include_in_newest'
|
||||
# Do not include if the channel does not exist 'include_in_newest' in your configuration
|
||||
include_in_newest = config.get_setting("include_in_newest_" + item.extra, channel_id)
|
||||
if include_in_newest is None:
|
||||
continue
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,11 +12,9 @@ from builtins import range
|
||||
from past.utils import old_div
|
||||
|
||||
from channelselector import get_thumb
|
||||
from core import filetools
|
||||
from core import servertools
|
||||
from core import filetools, servertools
|
||||
from core.item import Item
|
||||
from platformcode import config, logger
|
||||
from platformcode import platformtools
|
||||
from platformcode import config, logger, platformtools
|
||||
import xbmcgui
|
||||
|
||||
CHANNELNAME = "setting"
|
||||
@@ -73,7 +71,7 @@ def menu_channels(item):
|
||||
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
|
||||
# Home - Configurable channels
|
||||
import channelselector
|
||||
from core import channeltools
|
||||
channel_list = channelselector.filterchannels("all")
|
||||
@@ -85,7 +83,7 @@ def menu_channels(item):
|
||||
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
|
||||
# End - Configurable channels
|
||||
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")))
|
||||
@@ -98,7 +96,7 @@ def channel_config(item):
|
||||
return platformtools.show_channel_settings(channelpath=filetools.join(config.get_runtime_path(), "channels", item.config))
|
||||
|
||||
|
||||
def autostart(item): # item necessario launcher.py linea 265
|
||||
def autostart(item): # item required launcher.py line 265
|
||||
if config.enable_disable_autorun(AUTOSTART):
|
||||
logger.info('AUTOSTART ENABLED')
|
||||
# xbmcgui.Dialog().ok(config.get_localized_string(20000), config.get_localized_string(70709))
|
||||
@@ -126,7 +124,7 @@ def autostart(item): # item necessario launcher.py linea 265
|
||||
|
||||
# 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 = [
|
||||
# {
|
||||
@@ -257,7 +255,7 @@ def menu_servers(item):
|
||||
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
|
||||
# Home - Configurable servers
|
||||
|
||||
server_list = list(servertools.get_debriders_list().keys())
|
||||
for server in server_list:
|
||||
@@ -280,7 +278,7 @@ def menu_servers(item):
|
||||
Item(channel=CHANNELNAME, title=". " + config.get_localized_string(60553) % server_parameters["name"],
|
||||
action="server_config", config=server, folder=False, thumbnail=""))
|
||||
|
||||
# Fin - Servidores configurables
|
||||
# End - Configurable servers
|
||||
|
||||
return itemlist
|
||||
|
||||
@@ -332,13 +330,13 @@ def cb_servers_blacklist(item, dict_values):
|
||||
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
|
||||
if v: # If the server is blacklisted it cannot be in the favorites list
|
||||
config.set_setting("favorites_servers_list", 100, server=k)
|
||||
f = True
|
||||
progreso.update(old_div((i * 100), n), config.get_localized_string(60559) % k)
|
||||
i += 1
|
||||
|
||||
if not f: # Si no hay ningun servidor en la lista, desactivarla
|
||||
if not f: # If there is no server in the list, deactivate it
|
||||
config.set_setting('filter_servers', False)
|
||||
|
||||
progreso.close()
|
||||
@@ -406,7 +404,7 @@ def cb_servers_favorites(server_names, dict_values):
|
||||
progreso.update(old_div((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
|
||||
if not dict_name: # If there is no server in the list, deactivate it
|
||||
config.set_setting("favorites_servers", False)
|
||||
|
||||
progreso.close()
|
||||
@@ -420,7 +418,7 @@ def submenu_tools(item):
|
||||
logger.info()
|
||||
itemlist = list()
|
||||
|
||||
# Herramientas personalizadas
|
||||
# Custom tools
|
||||
import os
|
||||
channel_custom = os.path.join(config.get_runtime_path(), 'channels', 'custom.py')
|
||||
if not filetools.exists(channel_custom):
|
||||
@@ -483,9 +481,9 @@ def check_quickfixes(item):
|
||||
def conf_tools(item):
|
||||
logger.info()
|
||||
|
||||
# Activar o desactivar canales
|
||||
# Enable or disable channels
|
||||
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
|
||||
if config.get_platform(True)['num_version'] >= 17.0: # From Kodi 16 you can use multiselect, and from 17 with preselect
|
||||
return channels_onoff(item)
|
||||
|
||||
import channelselector
|
||||
@@ -515,14 +513,14 @@ def conf_tools(item):
|
||||
config.get_localized_string(60593)]})
|
||||
|
||||
for channel in channel_list:
|
||||
# Si el canal esta en la lista de exclusiones lo saltamos
|
||||
# If the channel is on the exclusion list, we skip it
|
||||
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 does not exist, there is NO value in _data.json
|
||||
if status is None:
|
||||
status = channel_parameters["active"]
|
||||
logger.debug("%s | Status (XML): %s" % (channel.channel, status))
|
||||
@@ -552,15 +550,14 @@ def conf_tools(item):
|
||||
callback="channel_status",
|
||||
custom_button={"visible": False})
|
||||
|
||||
# Comprobacion de archivos channel_data.json
|
||||
# Checking channel_data.json files
|
||||
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
|
||||
# Having an exclusion list doesn't make much sense because it checks if channel.json has "settings", but just in case it is left
|
||||
excluded_channels = ['url',
|
||||
'setting',
|
||||
'help']
|
||||
@@ -573,9 +570,9 @@ def conf_tools(item):
|
||||
list_status = None
|
||||
default_settings = None
|
||||
|
||||
# Se comprueba si el canal esta en la lista de exclusiones
|
||||
# It is checked if the channel is in the exclusion list
|
||||
if channel.channel not in excluded_channels:
|
||||
# Se comprueba que tenga "settings", sino se salta
|
||||
# It is checked that it has "settings", otherwise it skips
|
||||
list_controls, dict_settings = channeltools.get_channel_controls_settings(channel.channel)
|
||||
|
||||
if not list_controls:
|
||||
@@ -586,23 +583,22 @@ def conf_tools(item):
|
||||
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")
|
||||
# The json file settings of the channel are loaded
|
||||
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")
|
||||
# logger.info(channel.channel + " Has _data.json file")
|
||||
channeljson_exists = True
|
||||
# Obtenemos configuracion guardada de ../settings/channel_data.json
|
||||
# We get saved settings from ../settings/channel_data.json
|
||||
try:
|
||||
dict_file = jsontools.load(filetools.read(file_settings))
|
||||
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)
|
||||
logger.error("ERROR when reading the file: %s" % file_settings)
|
||||
else:
|
||||
# logger.info(channel.channel + " No tiene archivo _data.json")
|
||||
# logger.info(channel.channel + " No _data.json file")
|
||||
channeljson_exists = False
|
||||
|
||||
if channeljson_exists:
|
||||
@@ -614,12 +610,12 @@ def conf_tools(item):
|
||||
else:
|
||||
datajson_size = None
|
||||
|
||||
# Si el _data.json esta vacio o no existe...
|
||||
# If the _data.json is empty or does not exist ...
|
||||
if (len(dict_settings) and datajson_size) == 0 or not channeljson_exists:
|
||||
# Obtenemos controles del archivo ../channels/channel.json
|
||||
# We get controls from the file ../channels/channel.json
|
||||
needsfix = True
|
||||
try:
|
||||
# Se cargan los ajustes por defecto
|
||||
# Default settings are loaded
|
||||
list_controls, default_settings = channeltools.get_channel_controls_settings(
|
||||
channel.channel)
|
||||
# logger.info(channel.title + " | Default: %s" % default_settings)
|
||||
@@ -628,26 +624,26 @@ def conf_tools(item):
|
||||
logger.error(channel.title + config.get_localized_string(60570) % traceback.format_exc())
|
||||
# default_settings = {}
|
||||
|
||||
# Si _data.json necesita ser reparado o no existe...
|
||||
# If _data.json needs to be repaired or doesn't exist ...
|
||||
if needsfix or not channeljson_exists:
|
||||
if default_settings is not None:
|
||||
# Creamos el channel_data.json
|
||||
# We create the channel_data.json
|
||||
default_settings.update(dict_settings)
|
||||
dict_settings = default_settings
|
||||
dict_file['settings'] = dict_settings
|
||||
# Creamos el archivo ../settings/channel_data.json
|
||||
# We create the file ../settings/channel_data.json
|
||||
if not filetools.write(file_settings, jsontools.dump(dict_file), silent=True):
|
||||
logger.error("ERROR al salvar el archivo: %s" % file_settings)
|
||||
logger.error("ERROR saving file: %s" % file_settings)
|
||||
list_status = config.get_localized_string(60560)
|
||||
else:
|
||||
if default_settings is None:
|
||||
list_status = config.get_localized_string(60571)
|
||||
|
||||
else:
|
||||
# logger.info(channel.channel + " - NO necesita correccion!")
|
||||
# logger.info(channel.channel + " - NO correction needed!")
|
||||
needsfix = False
|
||||
|
||||
# Si se ha establecido el estado del canal se añade a la lista
|
||||
# If the channel status has been set it is added to the list
|
||||
if needsfix is not None:
|
||||
if needsfix:
|
||||
if not channeljson_exists:
|
||||
@@ -657,8 +653,7 @@ def conf_tools(item):
|
||||
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 "needsfix" is "false" and "datjson_size" is None, an error will have occurred
|
||||
if datajson_size is None:
|
||||
list_status = config.get_localized_string(60590)
|
||||
list_colour = "red"
|
||||
@@ -673,9 +668,9 @@ def conf_tools(item):
|
||||
thumbnail=channel.thumbnail,
|
||||
text_color=list_colour))
|
||||
else:
|
||||
logger.error("Algo va mal con el canal %s" % channel.channel)
|
||||
logger.error("Something is wrong with the channel %s" % channel.channel)
|
||||
|
||||
# Si el canal esta en la lista de exclusiones lo saltamos
|
||||
# If the channel is on the exclusion list, we skip it
|
||||
else:
|
||||
continue
|
||||
except:
|
||||
@@ -689,7 +684,7 @@ def channels_onoff(item):
|
||||
import channelselector, xbmcgui
|
||||
from core import channeltools
|
||||
|
||||
# Cargar lista de opciones
|
||||
# Load list of options
|
||||
# ------------------------
|
||||
lista = []; ids = []
|
||||
channels_list = channelselector.filterchannels('allchannelstatus')
|
||||
@@ -704,11 +699,11 @@ def channels_onoff(item):
|
||||
lista.append(it)
|
||||
ids.append(channel.channel)
|
||||
|
||||
# Diálogo para pre-seleccionar
|
||||
# Dialog to pre-select
|
||||
# ----------------------------
|
||||
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 == -1: return False # order cancel
|
||||
if ret == 2: preselect = []
|
||||
elif ret == 1: preselect = list(range(len(ids)))
|
||||
else:
|
||||
@@ -719,13 +714,13 @@ def channels_onoff(item):
|
||||
if channel_status:
|
||||
preselect.append(i)
|
||||
|
||||
# Diálogo para seleccionar
|
||||
# Dialog to select
|
||||
# ------------------------
|
||||
ret = xbmcgui.Dialog().multiselect(config.get_localized_string(60545), lista, preselect=preselect, useDetails=True)
|
||||
if ret == None: return False # pedido cancel
|
||||
if ret == None: return False # order cancel
|
||||
seleccionados = [ids[i] for i in ret]
|
||||
|
||||
# Guardar cambios en canales activados
|
||||
# Save changes to activated channels
|
||||
# ------------------------------------
|
||||
for canal in ids:
|
||||
channel_status = config.get_setting('enabled', canal)
|
||||
@@ -744,7 +739,7 @@ def channel_status(item, dict_values):
|
||||
for k in dict_values:
|
||||
|
||||
if k == "all_channels":
|
||||
logger.info("Todos los canales | Estado seleccionado: %s" % dict_values[k])
|
||||
logger.info("All channels | Selected state: %s" % dict_values[k])
|
||||
if dict_values[k] != 0:
|
||||
excluded_channels = ['url', 'search',
|
||||
'videolibrary', 'setting',
|
||||
@@ -759,25 +754,25 @@ def channel_status(item, dict_values):
|
||||
new_status_all = None
|
||||
new_status_all_default = channel_parameters["active"]
|
||||
|
||||
# Opcion Activar todos
|
||||
# Option Activate all
|
||||
if dict_values[k] == 1:
|
||||
new_status_all = True
|
||||
|
||||
# Opcion Desactivar todos
|
||||
# Option Deactivate all
|
||||
if dict_values[k] == 2:
|
||||
new_status_all = False
|
||||
|
||||
# Opcion Recuperar estado por defecto
|
||||
# Retrieve default status option
|
||||
if dict_values[k] == 3:
|
||||
# Si tiene "enabled" en el _data.json es porque el estado no es el del channel.json
|
||||
# If you have "enabled" in the _data.json, it is because the state is not that of the 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
|
||||
# If the channel does not have "enabled" in the _data.json it is not saved, it goes to the next
|
||||
else:
|
||||
continue
|
||||
|
||||
# Se guarda el estado del canal
|
||||
# Channel status is saved
|
||||
if new_status_all is not None:
|
||||
config.set_setting("enabled", new_status_all, channel.channel)
|
||||
break
|
||||
@@ -785,15 +780,15 @@ def channel_status(item, dict_values):
|
||||
continue
|
||||
|
||||
else:
|
||||
logger.info("Canal: %s | Estado: %s" % (k, dict_values[k]))
|
||||
logger.info("Channel: %s | State: %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))
|
||||
logger.info("the value is like %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())
|
||||
logger.error("Error detail: %s" % traceback.format_exc())
|
||||
platformtools.dialog_notification(config.get_localized_string(60579), config.get_localized_string(60580))
|
||||
|
||||
|
||||
@@ -823,15 +818,15 @@ def restore_tools(item):
|
||||
path = filetools.dirname(tvshow_file)
|
||||
|
||||
if not serie.active:
|
||||
# si la serie no esta activa descartar
|
||||
# if the series is not active discard
|
||||
continue
|
||||
|
||||
# Eliminamos la carpeta con la serie ...
|
||||
# We delete the folder with the series ...
|
||||
if tvshow_file.endswith('.strm') or tvshow_file.endswith('.json') or tvshow_file.endswith('.nfo'):
|
||||
os.remove(os.path.join(path, tvshow_file))
|
||||
# filetools.rmdirtree(path)
|
||||
|
||||
# ... y la volvemos a añadir
|
||||
# ... and we add it again
|
||||
service.update(path, p_dialog, i, t, serie, 3)
|
||||
p_dialog.close()
|
||||
|
||||
@@ -855,7 +850,7 @@ def restore_tools(item):
|
||||
path = filetools.dirname(movie_json)
|
||||
movie = Item().fromjson(filetools.read(movie_json))
|
||||
|
||||
# Eliminamos la carpeta con la pelicula ...
|
||||
# We delete the folder with the movie ...
|
||||
filetools.rmdirtree(path)
|
||||
|
||||
import math
|
||||
@@ -863,69 +858,69 @@ def restore_tools(item):
|
||||
|
||||
p_dialog2.update(int(math.ceil((i + 1) * t)), heading, config.get_localized_string(60389) % (movie.contentTitle,
|
||||
movie.channel.capitalize()))
|
||||
# ... y la volvemos a añadir
|
||||
# ... and we add it again
|
||||
videolibrarytools.save_movie(movie)
|
||||
except Exception as ex:
|
||||
logger.error("Error al crear de nuevo la película")
|
||||
logger.error("Error creating movie again")
|
||||
template = "An exception of type %s occured. Arguments:\n%r"
|
||||
message = template % (type(ex).__name__, ex.args)
|
||||
logger.error(message)
|
||||
|
||||
p_dialog2.close()
|
||||
|
||||
|
||||
|
||||
def report_menu(item):
|
||||
logger.info('URL: ' + item.url)
|
||||
|
||||
|
||||
from channelselector import get_thumb
|
||||
|
||||
|
||||
thumb_debug = get_thumb("update.png")
|
||||
thumb_error = get_thumb("error.png")
|
||||
thumb_next = get_thumb("next.png")
|
||||
itemlist = []
|
||||
paso = 1
|
||||
|
||||
# Crea un menú de opciones para permitir al usuario reportar un fallo de Alfa a través de un servidor "pastebin"
|
||||
# Para que el informe sea completo el usuario debe tener la opción de DEBUG=ON
|
||||
# Los servidores "pastbin" gratuitos tienen limitación de capacidad, por lo que el tamaño del log es importante
|
||||
# Al final de la operación de upload, se pasa al usuario la dirección de log en el servidor para que los reporte
|
||||
|
||||
# Create a menu of options to allow the user to report an Alpha failure through a "pastebin" server
|
||||
# For the report to be complete, the user must have the option DEBUG = ON
|
||||
# Free pastbin servers have capacity limitations, so the size of the log is important
|
||||
# At the end of the upload operation, the user is passed the log address on the server to report them
|
||||
|
||||
itemlist.append(Item(channel=item.channel, action="", title=config.get_localized_string(707418),
|
||||
thumbnail=thumb_next, folder=False))
|
||||
#if not config.get_setting('debug'):
|
||||
itemlist.append(Item(channel=item.channel, action="activate_debug", extra=True,
|
||||
# if not config.get_setting('debug'):
|
||||
itemlist.append(Item(channel=item.channel, action="activate_debug", extra=True,
|
||||
title=config.get_localized_string(707419) %
|
||||
str(paso), thumbnail=thumb_debug, folder=False))
|
||||
paso += 1
|
||||
itemlist.append(Item(channel="channelselector", action="getmainlist",
|
||||
itemlist.append(Item(channel="channelselector", action="getmainlist",
|
||||
title=config.get_localized_string(707420) %
|
||||
str(paso), thumbnail=thumb_debug))
|
||||
paso += 1
|
||||
itemlist.append(Item(channel=item.channel, action="report_send",
|
||||
itemlist.append(Item(channel=item.channel, action="report_send",
|
||||
title=config.get_localized_string(707421) %
|
||||
str(paso), thumbnail=thumb_error, folder=False))
|
||||
paso += 1
|
||||
#if config.get_setting('debug'):
|
||||
itemlist.append(Item(channel=item.channel, action="activate_debug", extra=False,
|
||||
# if config.get_setting('debug'):
|
||||
itemlist.append(Item(channel=item.channel, action="activate_debug", extra=False,
|
||||
title=config.get_localized_string(707422) % str(paso),
|
||||
thumbnail=thumb_debug, folder=False))
|
||||
paso += 1
|
||||
|
||||
|
||||
if item.url:
|
||||
itemlist.append(Item(channel=item.channel, action="", title="", folder=False))
|
||||
|
||||
itemlist.append(Item(channel=item.channel, action="",
|
||||
|
||||
itemlist.append(Item(channel=item.channel, action="",
|
||||
title=config.get_localized_string(707423),
|
||||
thumbnail=thumb_next, folder=False))
|
||||
|
||||
|
||||
if item.one_use:
|
||||
action = ''
|
||||
url = ''
|
||||
else:
|
||||
action = 'call_browser'
|
||||
url = item.url
|
||||
itemlist.append(Item(channel=item.channel, action=action,
|
||||
title="**- LOG: [COLOR gold]%s[/COLOR] -**" % item.url, url=url,
|
||||
itemlist.append(Item(channel=item.channel, action=action,
|
||||
title="**- LOG: [COLOR gold]%s[/COLOR] -**" % item.url, url=url,
|
||||
thumbnail=thumb_next, unify=False, folder=False))
|
||||
|
||||
itemlist.append(Item(channel=item.channel, action="call_browser",
|
||||
@@ -935,24 +930,24 @@ def report_menu(item):
|
||||
itemlist.append(Item(channel=item.channel, action="call_browser",
|
||||
url='https://t.me/kodiondemand', title="Su telegram",
|
||||
thumbnail=thumb_next, unify=False, folder=False))
|
||||
|
||||
|
||||
if item.one_use:
|
||||
itemlist.append(Item(channel=item.channel, action="",
|
||||
title="[COLOR orange]NO ACCEDA al INFORME: se BORRARÁ[/COLOR]",
|
||||
itemlist.append(Item(channel=item.channel, action="",
|
||||
title="[COLOR orange]NO ACCEDA al INFORME: se BORRARÁ[/COLOR]",
|
||||
thumbnail=thumb_next, folder=False))
|
||||
itemlist.append(Item(channel=item.channel, action="",
|
||||
title="[COLOR orange]ya que es de un solo uso[/COLOR]",
|
||||
itemlist.append(Item(channel=item.channel, action="",
|
||||
title="[COLOR orange]ya que es de un solo uso[/COLOR]",
|
||||
thumbnail=thumb_next, folder=False))
|
||||
|
||||
|
||||
return itemlist
|
||||
|
||||
|
||||
|
||||
|
||||
def activate_debug(item):
|
||||
logger.info(item.extra)
|
||||
from platformcode import platformtools
|
||||
|
||||
# Activa/Desactiva la opción de DEBUB en settings.xml
|
||||
|
||||
|
||||
#Enable / disable DEBUB option in settings.xml
|
||||
|
||||
if isinstance(item.extra, str):
|
||||
return report_menu(item)
|
||||
if item.extra:
|
||||
@@ -961,20 +956,20 @@ def activate_debug(item):
|
||||
else:
|
||||
config.set_setting('debug', False)
|
||||
platformtools.dialog_notification(config.get_localized_string(707430), config.get_localized_string(707432))
|
||||
|
||||
|
||||
|
||||
|
||||
def report_send(item, description='', fatal=False):
|
||||
import xbmc
|
||||
import random
|
||||
import traceback
|
||||
|
||||
if PY3:
|
||||
#from future import standard_library
|
||||
#standard_library.install_aliases()
|
||||
import urllib.parse as urlparse # Es muy lento en PY2. En PY3 es nativo
|
||||
# from future import standard_library
|
||||
# standard_library.install_aliases()
|
||||
import urllib.parse as urlparse # It is very slow in PY2. In PY3 it is native
|
||||
import urllib.parse as urllib
|
||||
else:
|
||||
import urllib # Usamos el nativo de PY2 que es más rápido
|
||||
import urllib # We use the native of PY2 which is faster
|
||||
import urlparse
|
||||
|
||||
try:
|
||||
@@ -983,149 +978,149 @@ def report_send(item, description='', fatal=False):
|
||||
except:
|
||||
requests_status = False
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
from core import jsontools, httptools, scrapertools
|
||||
from platformcode import envtal
|
||||
|
||||
# Esta función realiza la operación de upload del LOG. El tamaño del archivo es de gran importacia porque
|
||||
# los servicios de "pastebin" gratuitos tienen limitaciones, a veces muy bajas.
|
||||
# Hay un ervicio, File.io, que permite subida directa de "achivos binarios" a través de la función "request"
|
||||
# Esto aumenta dráticamente la capacidad del envío del log, muy por encima de lo necesitado
|
||||
# Por ello es necesario contar con una lista de servicios "pastebin" que puedan realizar la operación de upload,
|
||||
# ya sea por capacidad disponible o por disponibilidad.
|
||||
# Para poder usar los servidores "pastebin" con un código común, se ha creado un diccionario con los servidores
|
||||
# y sus características. En cada entrada se recogen las peculiaridades de cada servidor, tanto para formar
|
||||
# la petición consu POST como para la forma de recibir el código del upload en la respuesta (json, header, regex
|
||||
# en datos,...).
|
||||
# Al iniciar este método se aleatoriza la lista de servidores "pastebin" para evitar que todos los usuarios hagan
|
||||
# uploads contra el mismo servidor y puedan ocasionar sobrecargas.
|
||||
# Se lee el arcivo de log y se compara su tamaño con la capacidad del servidor (parámetro 10 de cada entrada
|
||||
# (empezando desde 0), expresado en MB, hasta que se encuentra uno capacitado. Si el upload falla se sigue intentado
|
||||
# con los siguientes servidores que tengan la capacidad requerida.
|
||||
# Si no se encuentra ningun servidor disponible se pide al usuario que lo intente más tarde, o que suba el log
|
||||
# directamente en el foro. Si es un problema de tamaño, se le pide que reicinie Kodi y reporducza el fallo, para
|
||||
# que el LOG sea más pequeño.
|
||||
|
||||
|
||||
|
||||
# This function performs the LOG upload operation. The file size is of great importance because
|
||||
# Free pastebin services have limitations, sometimes very low.
|
||||
# There is an ervice, File.io, that allows direct upload of "binary files" through the "request" function
|
||||
# This dramatically increases the ability to send the log, well above what is needed.
|
||||
# Therefore it is necessary to have a list of "pastebin" services that can perform the upload operation,
|
||||
# either by available capacity or by availability.
|
||||
# In order to use the "pastebin" servers with a common code, a dictionary has been created with the servers
|
||||
# and their characteristics. In each entry the peculiarities of each server are collected, both to form
|
||||
# the request with POST as for the way to receive the upload code in the response (json, header, regex
|
||||
# in data, ...).
|
||||
# Starting this method randomizes the list of "pastebin" servers to prevent all users from doing
|
||||
# uploads against the same server and may cause overloads.
|
||||
# The log file is read and its size is compared with the server capacity (parameter 10 of each entry
|
||||
# (starting from 0), expressed in MB, until a qualified one is found. If the upload fails, it continues trying
|
||||
# with the following servers that have the required capacity.
|
||||
# If no available server is found, the user is asked to try again later, or to upload the log.
|
||||
# directly on the forum. If it is a size problem, you are asked to reset Kodi and redo the fault, to
|
||||
# that the LOG is smaller.
|
||||
|
||||
|
||||
pastebin_list = {
|
||||
'hastebin': ('1', 'https://hastebin.com/', 'documents', 'random', '', '',
|
||||
'data', 'json', 'key', '', '0.29', '10', True, 'raw/', '', ''),
|
||||
'dpaste': ('1', 'http://dpaste.com/', 'api/v2/', 'random', 'content=',
|
||||
'&syntax=text&title=%s&poster=alfa&expiry_days=7',
|
||||
'hastebin': ('1', 'https://hastebin.com/', 'documents', 'random', '', '',
|
||||
'data', 'json', 'key', '', '0.29', '10', True, 'raw/', '', ''),
|
||||
'dpaste': ('1', 'http://dpaste.com/', 'api/v2/', 'random', 'content=',
|
||||
'&syntax=text&title=%s&poster=alfa&expiry_days=7',
|
||||
'headers', '', '', 'location', '0.23', '15', True, '', '.txt', ''),
|
||||
'ghostbin': ('1', 'https://ghostbin.com/', 'paste/new', 'random', 'lang=text&text=',
|
||||
'&expire=2d&password=&title=%s',
|
||||
'data', 'regex', '<title>(.*?)\s*-\s*Ghostbin<\/title>', '',
|
||||
'ghostbin': ('1', 'https://ghostbin.com/', 'paste/new', 'random', 'lang=text&text=',
|
||||
'&expire=2d&password=&title=%s',
|
||||
'data', 'regex', '<title>(.*?)\s*-\s*Ghostbin<\/title>', '',
|
||||
'0.49', '15', False, 'paste/', '', ''),
|
||||
'write.as': ('1', 'https://write.as/', 'api/posts', 'random', 'body=', '&title=%s',
|
||||
'write.as': ('1', 'https://write.as/', 'api/posts', 'random', 'body=', '&title=%s',
|
||||
'data', 'json', 'data', 'id', '0.018', '15', True, '', '', ''),
|
||||
'oneclickpaste': ('1', 'http://oneclickpaste.com/', 'index.php', 'random', 'paste_data=',
|
||||
'&title=%s&format=text&paste_expire_date=1W&visibility=0&pass=&submit=Submit',
|
||||
'data', 'regex', '<a class="btn btn-primary" href="[^"]+\/(\d+\/)">\s*View\s*Paste\s*<\/a>',
|
||||
'oneclickpaste': ('1', 'http://oneclickpaste.com/', 'index.php', 'random', 'paste_data=',
|
||||
'&title=%s&format=text&paste_expire_date=1W&visibility=0&pass=&submit=Submit',
|
||||
'data', 'regex', '<a class="btn btn-primary" href="[^"]+\/(\d+\/)">\s*View\s*Paste\s*<\/a>',
|
||||
'', '0.060', '5', True, '', '', ''),
|
||||
'bpaste': ('1', 'https://bpaste.net/', '', 'random', 'code=', '&lexer=text&expiry=1week',
|
||||
'data', 'regex', 'View\s*<a\s*href="[^*]+/(.*?)">raw<\/a>', '',
|
||||
'bpaste': ('1', 'https://bpaste.net/', '', 'random', 'code=', '&lexer=text&expiry=1week',
|
||||
'data', 'regex', 'View\s*<a\s*href="[^*]+/(.*?)">raw<\/a>', '',
|
||||
'0.79', '15', True, 'raw/', '', ''),
|
||||
'dumpz': ('0', 'http://dumpz.org/', 'api/dump', 'random', 'code=', '&lexer=text&comment=%s&password=',
|
||||
'dumpz': ('0', 'http://dumpz.org/', 'api/dump', 'random', 'code=', '&lexer=text&comment=%s&password=',
|
||||
'headers', '', '', 'location', '0.99', '15', False, '', '', ''),
|
||||
'file.io': ('1', 'https://file.io/', '', 'random', '', 'expires=1w',
|
||||
'requests', 'json', 'key', '', '99.0', '30', False, '', '.log', ''),
|
||||
'uploadfiles': ('1', 'https://up.uploadfiles.io/upload', '', 'random', '', '',
|
||||
'requests', 'json', 'url', '', '99.0', '30', False, None, '', '')
|
||||
'file.io': ('1', 'https://file.io/', '', 'random', '', 'expires=1w',
|
||||
'requests', 'json', 'key', '', '99.0', '30', False, '', '.log', ''),
|
||||
'uploadfiles': ('1', 'https://up.uploadfiles.io/upload', '', 'random', '', '',
|
||||
'requests', 'json', 'url', '', '99.0', '30', False, None, '', '')
|
||||
}
|
||||
pastebin_list_last = ['hastebin', 'ghostbin', 'file.io'] # Estos servicios los dejamos los últimos
|
||||
pastebin_one_use = ['file.io'] # Servidores de un solo uso y se borra
|
||||
pastebin_list_last = ['hastebin', 'ghostbin', 'file.io'] # We leave these services the last
|
||||
pastebin_one_use = ['file.io'] # Single-use servers and deletes
|
||||
pastebin_dir = []
|
||||
paste_file = {}
|
||||
paste_params = ()
|
||||
paste_post = ''
|
||||
status = False
|
||||
msg = config.get_localized_string(707424)
|
||||
|
||||
# Se verifica que el DEBUG=ON, si no está se rechaza y se pide al usuario que lo active y reproduzca el fallo
|
||||
|
||||
# DEBUG = ON is verified, if it is not it is rejected and the user is asked to activate it and reproduce the fault
|
||||
if not config.get_setting('debug'):
|
||||
platformtools.dialog_notification(config.get_localized_string(707425), config.get_localized_string(707426))
|
||||
return report_menu(item)
|
||||
|
||||
# De cada al futuro se permitira al usuario que introduzca una breve descripción del fallo que se añadirá al LOG
|
||||
|
||||
# From each to the future the user will be allowed to enter a brief description of the fault that will be added to the LOG
|
||||
if description == 'OK':
|
||||
description = platformtools.dialog_input('', 'Introduzca una breve descripción del fallo')
|
||||
|
||||
# Escribimos en el log algunas variables de Kodi y Alfa que nos ayudarán en el diagnóstico del fallo
|
||||
# We write in the log some Kodi and Alpha variables that will help us diagnose the failure
|
||||
environment = envtal.list_env()
|
||||
if not environment['log_path']:
|
||||
environment['log_path'] = str(filetools.join(xbmc.translatePath("special://logpath/"), 'kodi.log'))
|
||||
environment['log_size_bytes'] = str(filetools.getsize(environment['log_path']))
|
||||
environment['log_size'] = str(round(float(environment['log_size_bytes']) / (1024*1024), 3))
|
||||
|
||||
# Se lee el archivo de LOG
|
||||
|
||||
# LOG file is read
|
||||
log_path = environment['log_path']
|
||||
if filetools.exists(log_path):
|
||||
log_size_bytes = int(environment['log_size_bytes']) # Tamaño del archivivo en Bytes
|
||||
log_size = float(environment['log_size']) # Tamaño del archivivo en MB
|
||||
log_data = filetools.read(log_path) # Datos del archivo
|
||||
if not log_data: # Algún error?
|
||||
log_size_bytes = int(environment['log_size_bytes']) # File size in Bytes
|
||||
log_size = float(environment['log_size']) # File size in MB
|
||||
log_data = filetools.read(log_path) # File data
|
||||
if not log_data: # Some mistake?
|
||||
platformtools.dialog_notification(config.get_localized_string(707427), '', 2)
|
||||
return report_menu(item)
|
||||
else: # Log no existe o path erroneo?
|
||||
else: # Log no existe or erroneous path?
|
||||
platformtools.dialog_notification(config.get_localized_string(707427), '', 2)
|
||||
return report_menu(item)
|
||||
|
||||
# Si se ha introducido la descripción del fallo, se inserta la principio de los datos del LOG
|
||||
# log_title = '***** DESCRIPCIÓN DEL FALLO *****'
|
||||
# If the fault description has been entered, the beginning of the LOG data is inserted
|
||||
# log_title = '***** FAULT DESCRIPTION *****'
|
||||
# if description:
|
||||
# log_data = '%s\n%s\n\n%s' %(log_title, description, log_data)
|
||||
|
||||
# Se aleatorizan los nombre de los servidores "patebin"
|
||||
|
||||
# Server names "patebin" are scrambled
|
||||
for label_a, value_a in list(pastebin_list.items()):
|
||||
if label_a not in pastebin_list_last:
|
||||
pastebin_dir.append(label_a)
|
||||
random.shuffle(pastebin_dir)
|
||||
pastebin_dir.extend(pastebin_list_last) # Estos servicios los dejamos los últimos
|
||||
|
||||
#pastebin_dir = ['uploadfiles'] # Para pruebas de un servicio
|
||||
#log_data = 'TEST PARA PRUEBAS DEL SERVICIO'
|
||||
|
||||
# Se recorre la lista de servidores "pastebin" hasta localizar uno activo, con capacidad y disponibilidad
|
||||
pastebin_dir.extend(pastebin_list_last) # We leave these services the last
|
||||
|
||||
#pastebin_dir = ['uploadfiles'] # For testing a service
|
||||
#log_data = 'TEST FOR SERVICE TESTS'
|
||||
|
||||
# The list of "pastebin" servers is scrolled to locate an active one, with capacity and availability
|
||||
for paste_name in pastebin_dir:
|
||||
if pastebin_list[paste_name][0] != '1': # Si no esta activo el servidore, pasamos
|
||||
if pastebin_list[paste_name][0] != '1': # If the server is not active, we pass
|
||||
continue
|
||||
if pastebin_list[paste_name][6] == 'requests' and not requests_status: # Si "requests" no esta activo, pasamos
|
||||
if pastebin_list[paste_name][6] == 'requests' and not requests_status: # If "requests" is not active, we pass
|
||||
continue
|
||||
|
||||
paste_host = pastebin_list[paste_name][1] # URL del servidor "pastebin"
|
||||
paste_sufix = pastebin_list[paste_name][2] # sufijo del API para el POST
|
||||
paste_host = pastebin_list[paste_name][1] # Server URL "pastebin"
|
||||
paste_sufix = pastebin_list[paste_name][2] # API suffix for POST
|
||||
paste_title = ''
|
||||
if pastebin_list[paste_name][3] == 'random':
|
||||
paste_title = "LOG" + str(random.randrange(1, 999999999)) # Título del LOG
|
||||
paste_post1 = pastebin_list[paste_name][4] # Parte inicial del POST
|
||||
paste_post2 = pastebin_list[paste_name][5] # Parte secundaria del POST
|
||||
paste_type = pastebin_list[paste_name][6] # Tipo de downloadpage: DATA o HEADERS
|
||||
paste_resp = pastebin_list[paste_name][7] # Tipo de respuesta: JSON o datos con REGEX
|
||||
paste_resp_key = pastebin_list[paste_name][8] # Si es JSON, etiqueta `primaria con la CLAVE
|
||||
paste_url = pastebin_list[paste_name][9] # Etiqueta primaria para HEADER y sec. para JSON
|
||||
paste_file_size = float(pastebin_list[paste_name][10]) # Capacidad en MB del servidor
|
||||
if paste_file_size > 0: # Si es 0, la capacidad es ilimitada
|
||||
if log_size > paste_file_size: # Verificación de capacidad y tamaño
|
||||
msg = 'Archivo de log demasiado grande. Reinicie Kodi y reinténtelo'
|
||||
paste_title = "LOG" + str(random.randrange(1, 999999999)) # LOG title
|
||||
paste_post1 = pastebin_list[paste_name][4] # Initial part of the POST
|
||||
paste_post2 = pastebin_list[paste_name][5] # Secondary part of POST
|
||||
paste_type = pastebin_list[paste_name][6] # Type of downloadpage: DATE HEADERS
|
||||
paste_resp = pastebin_list[paste_name][7] # Response type: JSON or data with REGEX
|
||||
paste_resp_key = pastebin_list[paste_name][8] # If JSON, label `primary with KEY
|
||||
paste_url = pastebin_list[paste_name][9] # Primary label for HEADER and sec. for JSON
|
||||
paste_file_size = float(pastebin_list[paste_name][10]) # Server capacity in MB
|
||||
if paste_file_size > 0: # If it is 0, the capacity is unlimited
|
||||
if log_size > paste_file_size: # Capacity and size verification
|
||||
msg = 'Log file too large. Restart Kodi and retry'
|
||||
continue
|
||||
paste_timeout = int(pastebin_list[paste_name][11]) # Timeout para el servidor
|
||||
paste_random_headers = pastebin_list[paste_name][12] # Utiliza RAMDOM headers para despistar el serv.?
|
||||
paste_host_return = pastebin_list[paste_name][13] # Parte de url para componer la clave para usuario
|
||||
paste_host_return_tail = pastebin_list[paste_name][14] # Sufijo de url para componer la clave para usuario
|
||||
paste_timeout = int(pastebin_list[paste_name][11]) # Timeout for the server
|
||||
paste_random_headers = pastebin_list[paste_name][12] # Do you use RAMDOM headers to mislead the serv?
|
||||
paste_host_return = pastebin_list[paste_name][13] # Part of url to compose the key for user
|
||||
paste_host_return_tail = pastebin_list[paste_name][14] # Url suffix to compose user key
|
||||
paste_headers = {}
|
||||
if pastebin_list[paste_name][15]: # Headers requeridas por el servidor
|
||||
if pastebin_list[paste_name][15]: # Headers required by the server
|
||||
paste_headers.update(jsontools.load((pastebin_list[paste_name][15])))
|
||||
|
||||
if paste_name in pastebin_one_use:
|
||||
pastebin_one_use_msg = '[COLOR red]NO ACCEDA al INFORME: se BORRARÁ[/COLOR]'
|
||||
pastebin_one_use_msg = 'DO NOT ACCESS THE REPORT: it will be DELETED'
|
||||
item.one_use = True
|
||||
else:
|
||||
pastebin_one_use_msg = ''
|
||||
|
||||
|
||||
try:
|
||||
# Se crea el POST con las opciones del servidor "pastebin"
|
||||
# Se trata el formato de "requests"
|
||||
# POST is created with server options "pastebin"
|
||||
# This is the "requests" format
|
||||
if paste_type == 'requests':
|
||||
paste_file = {'file': (paste_title+'.log', log_data)}
|
||||
if paste_post1:
|
||||
@@ -1135,14 +1130,14 @@ def report_send(item, description='', fatal=False):
|
||||
paste_params = paste_post2 % (paste_title+'.log', log_size_bytes)
|
||||
else:
|
||||
paste_params = paste_post2
|
||||
|
||||
#Se trata el formato de downloads
|
||||
|
||||
# This is the download format
|
||||
else:
|
||||
#log_data = 'Test de Servidor para ver su viabilidad (áéíóúñ¿?)'
|
||||
if paste_name in ['hastebin']: # Hay algunos servicios que no necesitan "quote"
|
||||
# log_data = 'Server Test to see its viability (áéíóúñ¿?)'
|
||||
if paste_name in ['hastebin']: # There are some services that do not need "quote"
|
||||
paste_post = log_data
|
||||
else:
|
||||
paste_post = urllib.quote_plus(log_data) # Se hace un "quote" de los datos del LOG
|
||||
paste_post = urllib.quote_plus(log_data) # A "quote" is made from the LOG data
|
||||
if paste_post1:
|
||||
paste_post = '%s%s' % (paste_post1, paste_post)
|
||||
if paste_post2:
|
||||
@@ -1151,104 +1146,101 @@ def report_send(item, description='', fatal=False):
|
||||
else:
|
||||
paste_post += paste_post2
|
||||
|
||||
# Se hace la petición en downloadpage con HEADERS o DATA, con los parámetros del servidor
|
||||
# Request is made on downloadpage with HEADERS or DATA, with server parameters
|
||||
if paste_type == 'headers':
|
||||
data = httptools.downloadpage(paste_host+paste_sufix, post=paste_post,
|
||||
timeout=paste_timeout, random_headers=paste_random_headers,
|
||||
data = httptools.downloadpage(paste_host+paste_sufix, post=paste_post,
|
||||
timeout=paste_timeout, random_headers=paste_random_headers,
|
||||
headers=paste_headers).headers
|
||||
elif paste_type == 'data':
|
||||
data = httptools.downloadpage(paste_host+paste_sufix, post=paste_post,
|
||||
timeout=paste_timeout, random_headers=paste_random_headers,
|
||||
data = httptools.downloadpage(paste_host+paste_sufix, post=paste_post,
|
||||
timeout=paste_timeout, random_headers=paste_random_headers,
|
||||
headers=paste_headers).data
|
||||
|
||||
# Si la petición es con formato REQUESTS, se realiza aquí
|
||||
|
||||
# If the request is in REQUESTS format, it is made here
|
||||
elif paste_type == 'requests':
|
||||
#data = requests.post(paste_host, params=paste_params, files=paste_file,
|
||||
#data = requests.post(paste_host, params=paste_params, files=paste_file,
|
||||
# timeout=paste_timeout)
|
||||
data = httptools.downloadpage(paste_host, params=paste_params, file=log_data,
|
||||
file_name=paste_title+'.log', timeout=paste_timeout,
|
||||
data = httptools.downloadpage(paste_host, params=paste_params, file=log_data,
|
||||
file_name=paste_title+'.log', timeout=paste_timeout,
|
||||
random_headers=paste_random_headers, headers=paste_headers)
|
||||
except:
|
||||
msg = 'Inténtelo más tarde'
|
||||
logger.error('Fallo al guardar el informe. ' + msg)
|
||||
logger.error('Failed to save report. ' + msg)
|
||||
logger.error(traceback.format_exc())
|
||||
continue
|
||||
|
||||
# Se analiza la respuesta del servidor y se localiza la clave del upload para formar la url a pasar al usuario
|
||||
# The server response is analyzed and the upload key is located to form the url to pass to the user
|
||||
if data:
|
||||
paste_host_resp = paste_host
|
||||
if paste_host_return == None: # Si devuelve la url completa, no se compone
|
||||
if paste_host_return == None: # If you return the full url, it is not composed
|
||||
paste_host_resp = ''
|
||||
paste_host_return = ''
|
||||
|
||||
# Respuestas a peticiones REQUESTS
|
||||
if paste_type == 'requests': # Respuesta de petición tipo "requests"?
|
||||
if paste_resp == 'json': # Respuesta en formato JSON?
|
||||
|
||||
# Responses to REQUESTS requests
|
||||
if paste_type == 'requests': # Response of request type "requests"?
|
||||
if paste_resp == 'json': # Answer in JSON format?
|
||||
if paste_resp_key in data.data:
|
||||
if not paste_url:
|
||||
key = jsontools.load(data.data)[paste_resp_key] # con una etiqueta
|
||||
key = jsontools.load(data.data)[paste_resp_key] # with a label
|
||||
else:
|
||||
key = jsontools.load(data.data)[paste_resp_key][paste_url] # con dos etiquetas anidadas
|
||||
item.url = "%s%s%s" % (paste_host_resp+paste_host_return, key,
|
||||
key = jsontools.load(data.data)[paste_resp_key][paste_url] # with two nested tags
|
||||
item.url = "%s%s%s" % (paste_host_resp+paste_host_return, key,
|
||||
paste_host_return_tail)
|
||||
else:
|
||||
logger.error('ERROR en formato de retorno de datos. data.data=' +
|
||||
str(data.data))
|
||||
logger.error('ERROR in data return format. data.data=' + str(data.data))
|
||||
continue
|
||||
|
||||
# Respuestas a peticiones DOWNLOADPAGE
|
||||
elif paste_resp == 'json': # Respuesta en formato JSON?
|
||||
|
||||
# Responses to DOWNLOADPAGE requests
|
||||
elif paste_resp == 'json': # Answer in JSON format?
|
||||
if paste_resp_key in data:
|
||||
if not paste_url:
|
||||
key = jsontools.load(data)[paste_resp_key] # con una etiqueta
|
||||
key = jsontools.load(data)[paste_resp_key] # with a label
|
||||
else:
|
||||
key = jsontools.load(data)[paste_resp_key][paste_url] # con dos etiquetas anidadas
|
||||
item.url = "%s%s%s" % (paste_host_resp+paste_host_return, key,
|
||||
key = jsontools.load(data)[paste_resp_key][paste_url] # con two nested tags
|
||||
item.url = "%s%s%s" % (paste_host_resp+paste_host_return, key,
|
||||
paste_host_return_tail)
|
||||
else:
|
||||
logger.error('ERROR en formato de retorno de datos. data=' + str(data))
|
||||
logger.error('ERROR in data return format. data=' + str(data))
|
||||
continue
|
||||
elif paste_resp == 'regex': # Respuesta en DATOS, a buscar con un REGEX?
|
||||
elif paste_resp == 'regex': # Answer in DATA, to search with a REGEX?
|
||||
key = scrapertools.find_single_match(data, paste_resp_key)
|
||||
if key:
|
||||
item.url = "%s%s%s" % (paste_host_resp+paste_host_return, key,
|
||||
item.url = "%s%s%s" % (paste_host_resp+paste_host_return, key,
|
||||
paste_host_return_tail)
|
||||
else:
|
||||
logger.error('ERROR en formato de retorno de datos. data=' + str(data))
|
||||
logger.error('ERROR in data return format. data=' + str(data))
|
||||
continue
|
||||
elif paste_type == 'headers': # Respuesta en HEADERS, a buscar en "location"?
|
||||
elif paste_type == 'headers': # Answer in HEADERS, to search in "location"?
|
||||
if paste_url in data:
|
||||
item.url = data[paste_url] # Etiqueta de retorno de la clave
|
||||
item.url = urlparse.urljoin(paste_host_resp + paste_host_return,
|
||||
item.url = data[paste_url] # Key return label
|
||||
item.url = urlparse.urljoin(paste_host_resp + paste_host_return,
|
||||
item.url + paste_host_return_tail)
|
||||
else:
|
||||
logger.error('ERROR en formato de retorno de datos. response.headers=' +
|
||||
str(data))
|
||||
logger.error('ERROR in data return format. response.headers=' + str(data))
|
||||
continue
|
||||
else:
|
||||
logger.error('ERROR en formato de retorno de datos. paste_type=' +
|
||||
str(paste_type) + ' / DATA: ' + data)
|
||||
logger.error('ERROR in data return format. paste_type=' + str(paste_type) + ' / DATA: ' + data)
|
||||
continue
|
||||
|
||||
status = True # Operación de upload terminada con éxito
|
||||
logger.info('Report created: ' + str(item.url)) #Se guarda la URL del informe a usuario
|
||||
# if fatal: # De uso futuro, para logger.crash
|
||||
# platformtools.dialog_ok('Informe de ERROR en Alfa CREADO', 'Repórtelo en el foro agregando ERROR FATAL y esta URL: ', '[COLOR gold]%s[/COLOR]' % item.url, pastebin_one_use_msg)
|
||||
# else: # Se pasa la URL del informe a usuario
|
||||
# platformtools.dialog_ok('Informe de Fallo en Alfa CREADO', 'Repórtelo en el foro agregando una descripcion del fallo y esta URL: ', '[COLOR gold]%s[/COLOR]' % item.url, pastebin_one_use_msg)
|
||||
status = True # Upload operation completed successfully
|
||||
logger.info('Report created: ' + str(item.url)) # The URL of the user report is saved
|
||||
# if fatal: # For future use, for logger.crash
|
||||
# platformtools.dialog_ok('KoD CREATED ERROR report', 'Report it in the forum by adding FATAL ERROR and this URL: ', '[COLOR gold]%s[/COLOR]' % item.url, pastebin_one_use_msg)
|
||||
# else: # Report URL passed to user
|
||||
# platformtools.dialog_ok('KoD Crash Report CREATED', 'Report it on the forum by adding a bug description and this URL: ', '[COLOR gold]%s[/COLOR]' % item.url, pastebin_one_use_msg)
|
||||
|
||||
break # Operación terminado, no seguimos buscando
|
||||
|
||||
if not status and not fatal: # Operación fracasada...
|
||||
platformtools.dialog_notification(config.get_localized_string(707428), msg) #... se notifica la causa
|
||||
break # Operation finished, we don't keep looking
|
||||
|
||||
if not status and not fatal: # Operation failed ...
|
||||
platformtools.dialog_notification(config.get_localized_string(707428), msg) #... cause is reported
|
||||
logger.error(config.get_localized_string(707428) + msg)
|
||||
|
||||
# Se devuelve control con item.url actualizado, así aparecerá en el menú la URL del informe
|
||||
|
||||
# Control is returned with updated item.url, so the report URL will appear in the menu
|
||||
item.action = 'report_menu'
|
||||
platformtools.itemlist_update(item, True)
|
||||
# return report_menu(item)
|
||||
|
||||
|
||||
|
||||
|
||||
def call_browser(item):
|
||||
import webbrowser
|
||||
if not webbrowser.open(item.url):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ------------------------------------------------------------
|
||||
|
||||
#from builtins import str
|
||||
# from builtins import str
|
||||
import sys
|
||||
PY3 = False
|
||||
if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int
|
||||
@@ -9,8 +9,7 @@ if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int
|
||||
import os
|
||||
from core.item import Item
|
||||
from core import jsontools
|
||||
from platformcode import config, logger
|
||||
from platformcode import launcher
|
||||
from platformcode import config, logger, launcher
|
||||
import xbmc, xbmcgui, xbmcplugin, xbmcaddon
|
||||
|
||||
media_path = os.path.join(config.get_runtime_path(), "resources/skins/Default/media/side_menu/")
|
||||
@@ -113,7 +112,7 @@ class Main(xbmcgui.WindowXMLDialog):
|
||||
self.items = []
|
||||
|
||||
def onInit(self):
|
||||
#### Compatibilidad con Kodi 18 ####
|
||||
#### Kodi 18 compatibility ####
|
||||
if config.get_platform(True)['num_version'] < 18:
|
||||
self.setCoordinateResolution(2)
|
||||
|
||||
|
||||
@@ -16,10 +16,10 @@ from past.utils import old_div
|
||||
if PY3:
|
||||
#from future import standard_library
|
||||
#standard_library.install_aliases()
|
||||
import urllib.parse as urllib # Es muy lento en PY2. En PY3 es nativo
|
||||
import urllib.parse as urllib # It is very slow in PY2. In PY3 it is native
|
||||
import urllib.parse as urlparse
|
||||
else:
|
||||
import urllib # Usamos el nativo de PY2 que es más rápido
|
||||
import urllib # We use the native of PY2 which is faster
|
||||
import urlparse
|
||||
|
||||
import re
|
||||
@@ -37,7 +37,7 @@ def_lang = info_language[config.get_setting("info_language", "videolibrary")]
|
||||
|
||||
result = None
|
||||
window_select = []
|
||||
# Para habilitar o no la opción de búsqueda manual
|
||||
# To enable or disable the manual search option
|
||||
if config.get_platform() != "plex":
|
||||
keyboard = True
|
||||
else:
|
||||
@@ -47,14 +47,14 @@ else:
|
||||
def buscartrailer(item, trailers=[]):
|
||||
logger.info()
|
||||
|
||||
# Lista de acciones si se ejecuta desde el menú contextual
|
||||
# List of actions if run from context menu
|
||||
if item.action == "manual_search" and item.contextual:
|
||||
itemlist = manual_search(item)
|
||||
item.contentTitle = itemlist[0].contentTitle
|
||||
elif 'search' in item.action and item.contextual:
|
||||
itemlist = globals()[item.action](item)
|
||||
else:
|
||||
# Se elimina la opción de Buscar Trailer del menú contextual para evitar redundancias
|
||||
# Remove Trailer Search option from context menu to avoid redundancies
|
||||
if isinstance(item.context, str) and "buscar_trailer" in item.context:
|
||||
item.context = item.context.replace("buscar_trailer", "")
|
||||
elif isinstance(item.context, list) and "buscar_trailer" in item.context:
|
||||
@@ -80,8 +80,8 @@ def buscartrailer(item, trailers=[]):
|
||||
|
||||
item.year = item.infoLabels['year']
|
||||
|
||||
logger.info("Búsqueda: %s" % item.contentTitle)
|
||||
logger.info("Año: %s" % item.year)
|
||||
logger.info("Search: %s" % item.contentTitle)
|
||||
logger.info("Year: %s" % item.year)
|
||||
if item.infoLabels['trailer'] and not trailers:
|
||||
url = item.infoLabels['trailer']
|
||||
if "youtube" in url:
|
||||
@@ -98,8 +98,7 @@ def buscartrailer(item, trailers=[]):
|
||||
itemlist.extend(tmdb_trailers(item, tipo))
|
||||
else:
|
||||
for trailer in trailers:
|
||||
title = trailer['name'] + " [" + trailer['size'] + "p] (" + trailer['language'].replace("en", "ING") \
|
||||
.replace("it", "ITA") + ") [tmdb/youtube]"
|
||||
title = trailer['name'] + " [" + trailer['size'] + "p] (" + trailer['language'].replace("en", "ING").replace("it", "ITA") + ") [tmdb/youtube]"
|
||||
itemlist.append(item.clone(action="play", title=title, url=trailer['url'], server="youtube"))
|
||||
except:
|
||||
import traceback
|
||||
@@ -111,7 +110,7 @@ def buscartrailer(item, trailers=[]):
|
||||
title = "%s"
|
||||
itemlist.append(item.clone(title=title % config.get_localized_string(70507), action="youtube_search"))
|
||||
itemlist.append(item.clone(title=title % config.get_localized_string(70024), action="filmaffinity_search"))
|
||||
# Si se trata de una serie, no se incluye la opción de buscar en Abandomoviez
|
||||
# If it is a series, the option to search in Abandomoviez is not included
|
||||
if not item.show and not item.infoLabels['tvshowtitle']:
|
||||
itemlist.append(item.clone(title=title % config.get_localized_string(70508), action="abandomoviez_search"))
|
||||
|
||||
@@ -152,8 +151,7 @@ def tmdb_trailers(item, tipo="movie"):
|
||||
|
||||
if tmdb_search:
|
||||
for result in tmdb_search.get_videos():
|
||||
title = result['name'] + " [" + result['size'] + "p] (" + result['language'].replace("en", "ING") \
|
||||
.replace("it", "ITA") + ") [tmdb/youtube]"
|
||||
title = result['name'] + " [" + result['size'] + "p] (" + result['language'].replace("en", "ING").replace("it", "ITA") + ") [tmdb/youtube]"
|
||||
itemlist.append(item.clone(action="play", title=title, url=result['url'], server="youtube"))
|
||||
|
||||
return itemlist
|
||||
@@ -165,7 +163,7 @@ def youtube_search(item):
|
||||
titulo = item.contentTitle
|
||||
if item.extra != "youtube":
|
||||
titulo += " trailer"
|
||||
# Comprueba si es una búsqueda de cero o viene de la opción Siguiente
|
||||
# Check if it is a zero search or comes from the Next option
|
||||
if item.page != "":
|
||||
data = httptools.downloadpage(item.page).data
|
||||
else:
|
||||
@@ -183,8 +181,7 @@ def youtube_search(item):
|
||||
if item.contextual:
|
||||
scrapedtitle = "%s" % scrapedtitle
|
||||
url = urlparse.urljoin('https://www.youtube.com/', scrapedurl)
|
||||
itemlist.append(item.clone(title=scrapedtitle, action="play", server="youtube", url=url,
|
||||
thumbnail=scrapedthumbnail))
|
||||
itemlist.append(item.clone(title=scrapedtitle, action="play", server="youtube", url=url, thumbnail=scrapedthumbnail))
|
||||
next_page = scrapertools.find_single_match(data, '<a href="([^"]+)"[^>]+><span class="yt-uix-button-content">'
|
||||
'Siguiente')
|
||||
if next_page != "":
|
||||
@@ -207,7 +204,7 @@ def youtube_search(item):
|
||||
def abandomoviez_search(item):
|
||||
logger.info()
|
||||
|
||||
# Comprueba si es una búsqueda de cero o viene de la opción Siguiente
|
||||
# Check if it is a zero search or comes from the Next option
|
||||
if item.page != "":
|
||||
data = httptools.downloadpage(item.page).data
|
||||
else:
|
||||
@@ -226,7 +223,7 @@ def abandomoviez_search(item):
|
||||
patron = '(?:<td width="85"|<div class="col-md-2 col-sm-2 col-xs-3">).*?<img src="([^"]+)"' \
|
||||
'.*?href="([^"]+)">(.*?)(?:<\/td>|<\/small>)'
|
||||
matches = scrapertools.find_multiple_matches(data, patron)
|
||||
# Si solo hay un resultado busca directamente los trailers, sino lista todos los resultados
|
||||
# If there is only one result, search directly for the trailers, but list all the results
|
||||
if len(matches) == 1:
|
||||
item.url = urlparse.urljoin("http://www.abandomoviez.net/%s" % item.prefix, matches[0][1])
|
||||
item.thumbnail = matches[0][0]
|
||||
@@ -235,26 +232,22 @@ def abandomoviez_search(item):
|
||||
for scrapedthumbnail, scrapedurl, scrapedtitle in matches:
|
||||
scrapedurl = urlparse.urljoin("http://www.abandomoviez.net/%s" % item.prefix, scrapedurl)
|
||||
scrapedtitle = scrapertools.htmlclean(scrapedtitle)
|
||||
itemlist.append(item.clone(title=scrapedtitle, action="search_links_abando",
|
||||
url=scrapedurl, thumbnail=scrapedthumbnail))
|
||||
itemlist.append(item.clone(title=scrapedtitle, action="search_links_abando", url=scrapedurl, thumbnail=scrapedthumbnail))
|
||||
|
||||
next_page = scrapertools.find_single_match(data, '<a href="([^"]+)">Siguiente')
|
||||
if next_page != "":
|
||||
next_page = urlparse.urljoin("http://www.abandomoviez.net/%s" % item.prefix, next_page)
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70502), action="abandomoviez_search", page=next_page, thumbnail="",
|
||||
text_color=""))
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70502), action="abandomoviez_search", page=next_page, thumbnail="", text_color=""))
|
||||
|
||||
if not itemlist:
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70501), action="", thumbnail="",
|
||||
text_color=""))
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70501), action="", thumbnail="", text_color=""))
|
||||
|
||||
if keyboard:
|
||||
if item.contextual:
|
||||
title = "%s"
|
||||
else:
|
||||
title = "%s"
|
||||
itemlist.append(item.clone(title=title % config.get_localized_string(70511),
|
||||
action="manual_search", thumbnail="", extra="abandomoviez"))
|
||||
itemlist.append(item.clone(title=title % config.get_localized_string(70511), action="manual_search", thumbnail="", extra="abandomoviez"))
|
||||
|
||||
return itemlist
|
||||
|
||||
@@ -321,7 +314,7 @@ def filmaffinity_search(item):
|
||||
item.url = item.filmaffinity
|
||||
return search_links_filmaff(item)
|
||||
|
||||
# Comprueba si es una búsqueda de cero o viene de la opción Siguiente
|
||||
# Check if it is a zero search or comes from the Next option
|
||||
if item.page != "":
|
||||
data = httptools.downloadpage(item.page).data
|
||||
else:
|
||||
@@ -334,7 +327,7 @@ def filmaffinity_search(item):
|
||||
patron = '<div class="mc-poster">.*?<img.*?src="([^"]+)".*?' \
|
||||
'<div class="mc-title"><a href="/es/film(\d+).html"[^>]+>(.*?)<img'
|
||||
matches = scrapertools.find_multiple_matches(data, patron)
|
||||
# Si solo hay un resultado, busca directamente los trailers, sino lista todos los resultados
|
||||
# If there is only one result, search directly for the trailers, but list all the results
|
||||
if len(matches) == 1:
|
||||
item.url = "http://www.filmaffinity.com/es/evideos.php?movie_id=%s" % matches[0][1]
|
||||
item.thumbnail = matches[0][0]
|
||||
@@ -349,26 +342,22 @@ def filmaffinity_search(item):
|
||||
if PY3:
|
||||
scrapedtitle = unicode(scrapedtitle, encoding="utf-8", errors="ignore")
|
||||
scrapedtitle = scrapertools.htmlclean(scrapedtitle)
|
||||
itemlist.append(item.clone(title=scrapedtitle, url=scrapedurl,
|
||||
action="search_links_filmaff", thumbnail=scrapedthumbnail))
|
||||
itemlist.append(item.clone(title=scrapedtitle, url=scrapedurl, action="search_links_filmaff", thumbnail=scrapedthumbnail))
|
||||
|
||||
next_page = scrapertools.find_single_match(data, '<a href="([^"]+)">>></a>')
|
||||
if next_page != "":
|
||||
next_page = urlparse.urljoin("http://www.filmaffinity.com/es/", next_page)
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70502), page=next_page, action="filmaffinity_search", thumbnail="",
|
||||
text_color=""))
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70502), page=next_page, action="filmaffinity_search", thumbnail="", text_color=""))
|
||||
|
||||
if not itemlist:
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70501) % item.contentTitle,
|
||||
action="", thumbnail="", text_color=""))
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70501) % item.contentTitle, action="", thumbnail="", text_color=""))
|
||||
|
||||
if keyboard:
|
||||
if item.contextual:
|
||||
title = "%s"
|
||||
else:
|
||||
title = "%s"
|
||||
itemlist.append(item.clone(title=title % config.get_localized_string(70513),
|
||||
action="manual_search", thumbnail="", extra="filmaffinity"))
|
||||
itemlist.append(item.clone(title=title % config.get_localized_string(70513), action="manual_search", thumbnail="", extra="filmaffinity"))
|
||||
|
||||
return itemlist
|
||||
|
||||
@@ -400,8 +389,7 @@ def search_links_filmaff(item):
|
||||
scrapedtitle += " [" + server + "]"
|
||||
if item.contextual:
|
||||
scrapedtitle = "%s" % scrapedtitle
|
||||
itemlist.append(item.clone(title=scrapedtitle, url=trailer_url, server=server, action="play",
|
||||
thumbnail=thumbnail))
|
||||
itemlist.append(item.clone(title=scrapedtitle, url=trailer_url, server=server, action="play", thumbnail=thumbnail))
|
||||
|
||||
itemlist = servertools.get_servers_itemlist(itemlist)
|
||||
if keyboard:
|
||||
@@ -409,8 +397,7 @@ def search_links_filmaff(item):
|
||||
title = "%s"
|
||||
else:
|
||||
title = "%s"
|
||||
itemlist.append(item.clone(title=title % config.get_localized_string(70513),
|
||||
action="manual_search", thumbnail="", extra="filmaffinity"))
|
||||
itemlist.append(item.clone(title=title % config.get_localized_string(70513), action="manual_search", thumbnail="", extra="filmaffinity"))
|
||||
|
||||
return itemlist
|
||||
|
||||
@@ -451,7 +438,7 @@ try:
|
||||
self.control_list.addItems(self.items)
|
||||
self.setFocus(self.control_list)
|
||||
def onClick(self, id):
|
||||
# Boton Cancelar y [X]
|
||||
# Cancel button y [X]
|
||||
if id == 5:
|
||||
global window_select, result
|
||||
self.result = "_no_video"
|
||||
|
||||
@@ -1,22 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import re
|
||||
import urllib
|
||||
import re, urllib, xbmcaddon
|
||||
from base64 import b64decode as bdec
|
||||
|
||||
import xbmcaddon
|
||||
|
||||
from channelselector import get_thumb
|
||||
from core import filetools
|
||||
from core import httptools
|
||||
from core import jsontools
|
||||
from core import scrapertools
|
||||
from core import filetools, httptools, jsontools, scrapertools, trakt_tools
|
||||
from core.item import Item
|
||||
from core.support import typo
|
||||
from core.tmdb import Tmdb
|
||||
from core import trakt_tools
|
||||
from platformcode import config, logger
|
||||
from platformcode import platformtools
|
||||
from platformcode import config, logger, platformtools
|
||||
|
||||
info_language = ["de", "en", "es", "fr", "it", "pt"] # from videolibrary.json
|
||||
def_lang = info_language[config.get_setting("info_language", "videolibrary")]
|
||||
@@ -102,8 +94,7 @@ def search_(item):
|
||||
return listado_fa(item)
|
||||
if "myanimelist" in item.url:
|
||||
item.url += texto.replace(" ", "%20")
|
||||
item.url += "&type=0&score=0&status=0&p=0&r=0&sm=0&sd=0&sy=0&em=0&ed=0&ey=0&c[0]=a" \
|
||||
"&c[1]=b&c[2]=c&c[3]=d&c[4]=f&gx=0"
|
||||
item.url += "&type=0&score=0&status=0&p=0&r=0&sm=0&sd=0&sy=0&em=0&ed=0&ey=0&c[0]=a&c[1]=b&c[2]=c&c[3]=d&c[4]=f&gx=0"
|
||||
item.action = "busqueda_mal"
|
||||
return busqueda_mal(item)
|
||||
|
||||
@@ -125,8 +116,7 @@ def search_(item):
|
||||
def busqueda(item):
|
||||
logger.info()
|
||||
|
||||
new_item = Item(title=item.contentTitle, text=item.contentTitle.replace("+", " "), mode=item.contentType,
|
||||
infoLabels=item.infoLabels)
|
||||
new_item = Item(title=item.contentTitle, text=item.contentTitle.replace("+", " "), mode=item.contentType, infoLabels=item.infoLabels)
|
||||
|
||||
from specials import search
|
||||
return search.channel_search(new_item)
|
||||
@@ -278,35 +268,26 @@ def trakt(item):
|
||||
itemlist.append(item.clone(title=typo(config.get_localized_string(70048), 'color kod bold'), extra="cuenta"))
|
||||
else:
|
||||
item.extra = "movie"
|
||||
# Se comprueba si existe un token guardado y sino se ejecuta el proceso de autentificación
|
||||
# A saved token is checked and the authentication process is executed
|
||||
if not token_auth:
|
||||
#folder = (config.get_platform() == "plex")
|
||||
# folder = (config.get_platform() == "plex")
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70054), action="auth_trakt", folder=folder))
|
||||
else:
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70055), action="", ))
|
||||
itemlist.append(
|
||||
item.clone(title=config.get_localized_string(60651), action="acciones_trakt", url="users/me/watchlist/movies%s" % page,
|
||||
order="added", how="desc"))
|
||||
item.clone(title=config.get_localized_string(60651), action="acciones_trakt", url="users/me/watchlist/movies%s" % page, order="added", how="desc"))
|
||||
itemlist.append(
|
||||
item.clone(title=config.get_localized_string(60652), action="acciones_trakt", url="users/me/watchlist/shows%s" % page,
|
||||
extra="show",
|
||||
order="added", how="desc"))
|
||||
item.clone(title=config.get_localized_string(60652), action="acciones_trakt", url="users/me/watchlist/shows%s" % page, extra="show", order="added", how="desc"))
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70056), action="", ))
|
||||
itemlist.append(
|
||||
item.clone(title=config.get_localized_string(60651), action="acciones_trakt", url="users/me/watched/movies%s" % page,
|
||||
order="added", how="desc"))
|
||||
item.clone(title=config.get_localized_string(60651), action="acciones_trakt", url="users/me/watched/movies%s" % page, order="added", how="desc"))
|
||||
itemlist.append(
|
||||
item.clone(title=config.get_localized_string(60652), action="acciones_trakt", url="users/me/watched/shows%s" % page,
|
||||
extra="show",
|
||||
order="added", how="desc"))
|
||||
item.clone(title=config.get_localized_string(60652), action="acciones_trakt", url="users/me/watched/shows%s" % page, extra="show", order="added", how="desc"))
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70068), action="", ))
|
||||
itemlist.append(
|
||||
item.clone(title=config.get_localized_string(60651), action="acciones_trakt", url="users/me/collection/movies%s" % page,
|
||||
order="added", how="desc"))
|
||||
item.clone(title=config.get_localized_string(60651), action="acciones_trakt", url="users/me/collection/movies%s" % page, order="added", how="desc"))
|
||||
itemlist.append(
|
||||
item.clone(title=config.get_localized_string(60652), action="acciones_trakt", url="users/me/collection/shows%s" % page,
|
||||
extra="show",
|
||||
order="added", how="desc"))
|
||||
item.clone(title=config.get_localized_string(60652), action="acciones_trakt", url="users/me/collection/shows%s" % page, extra="show", order="added", how="desc"))
|
||||
itemlist.append(
|
||||
item.clone(title=config.get_localized_string(70057), action="acciones_trakt", url="users/me/lists", ))
|
||||
|
||||
@@ -320,24 +301,17 @@ def mal(item):
|
||||
item.login = True
|
||||
|
||||
itemlist.append(
|
||||
item.clone(title=config.get_localized_string(70058), url="https://myanimelist.net/topanime.php?type=tv&limit=0", action="top_mal",
|
||||
contentType="tvshow", extra="tv"))
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70059), url="https://myanimelist.net/topanime.php?type=movie&limit=0",
|
||||
action="top_mal",
|
||||
contentType="movie", extra="movie"))
|
||||
item.clone(title=config.get_localized_string(70058), url="https://myanimelist.net/topanime.php?type=tv&limit=0", action="top_mal", contentType="tvshow", extra="tv"))
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70059), url="https://myanimelist.net/topanime.php?type=movie&limit=0", action="top_mal", contentType="movie", extra="movie"))
|
||||
itemlist.append(
|
||||
item.clone(title=config.get_localized_string(70061), url="https://myanimelist.net/topanime.php?type=ova&limit=0", action="top_mal",
|
||||
contentType="tvshow", extra="tv", tipo="ova"))
|
||||
item.clone(title=config.get_localized_string(70061), url="https://myanimelist.net/topanime.php?type=ova&limit=0", action="top_mal", contentType="tvshow", extra="tv", tipo="ova"))
|
||||
itemlist.append(
|
||||
item.clone(title=config.get_localized_string(70028), url="https://myanimelist.net/topanime.php?type=bypopularity&limit=0",
|
||||
action="top_mal"))
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70060), url="https://myanimelist.net/topanime.php?type=upcoming&limit=0",
|
||||
action="top_mal"))
|
||||
item.clone(title=config.get_localized_string(70028), url="https://myanimelist.net/topanime.php?type=bypopularity&limit=0", action="top_mal"))
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70060), url="https://myanimelist.net/topanime.php?type=upcoming&limit=0", action="top_mal"))
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70062), url="", action="indices_mal"))
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70063), url="", action="indices_mal"))
|
||||
if config.get_platform() != "plex":
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70064), url="https://myanimelist.net/anime.php?q=",
|
||||
action="search_"))
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70064), url="https://myanimelist.net/anime.php?q=", action="search_"))
|
||||
itemlist.append(item.clone(title=typo(config.get_localized_string(70038), 'bold submenu'), action="filtro_mal"))
|
||||
|
||||
itemlist.append(item.clone(title=typo(config.get_localized_string(70057), 'bold submenu'), action="cuenta_mal"))
|
||||
@@ -345,15 +319,15 @@ def mal(item):
|
||||
return itemlist
|
||||
|
||||
|
||||
##-------------------- SECCION TMDB ------------------------##
|
||||
##-------------------- SECTION TMDB ------------------------##
|
||||
def listado_tmdb(item):
|
||||
# Listados principales de la categoría Tmdb (Más populares, más vistas, etc...)
|
||||
# Main listings of the Tmdb category (Most popular, Most viewed, etc ...)
|
||||
itemlist = []
|
||||
item.fanart = default_fan
|
||||
if not item.pagina:
|
||||
item.pagina = 1
|
||||
|
||||
# Listado de actores
|
||||
# List of actors
|
||||
if 'nm' in item.infoLabels['imdb_id']:
|
||||
try:
|
||||
|
||||
@@ -370,7 +344,7 @@ def listado_tmdb(item):
|
||||
else:
|
||||
ob_tmdb = Tmdb(discover=item.search, tipo=item.extra, idioma_busqueda=langt)
|
||||
|
||||
# Sagas y colecciones
|
||||
# Sagas and collections
|
||||
if "collection" in item.search["url"]:
|
||||
try:
|
||||
new_item = item.clone(action="", url='')
|
||||
@@ -394,7 +368,7 @@ def listado_tmdb(item):
|
||||
else:
|
||||
try:
|
||||
orden = False
|
||||
# Si se hace una búsqueda por actores o directores, se extraen esos resultados
|
||||
# If you do a search for actors or directors, those results are extracted
|
||||
if "cast" in ob_tmdb.result and not item.crew:
|
||||
ob_tmdb.results = ob_tmdb.result["cast"]
|
||||
orden = True
|
||||
@@ -404,7 +378,7 @@ def listado_tmdb(item):
|
||||
for i in range(0, len(ob_tmdb.results)):
|
||||
new_item = item.clone(action="detalles", url='', infoLabels={'mediatype': item.contentType})
|
||||
new_item.infoLabels = ob_tmdb.get_infoLabels(new_item.infoLabels, origen=ob_tmdb.results[i])
|
||||
# Si no hay sinopsis en idioma elegido, buscar en el alternativo
|
||||
# If there is no synopsis in the chosen language, search in the alternative
|
||||
if not new_item.infoLabels["plot"] and not 'person' in item.search["url"]:
|
||||
ob_tmdb2 = Tmdb(id_Tmdb=new_item.infoLabels["tmdb_id"], tipo=item.extra, idioma_busqueda=langt_alt)
|
||||
new_item.infoLabels["plot"] = ob_tmdb2.get_sinopsis()
|
||||
@@ -443,7 +417,7 @@ def listado_tmdb(item):
|
||||
% (typo(new_item.contentTitle,'bold'),
|
||||
typo(new_item.infoLabels['rating'].replace("0.0", ""),'color kod bold'))
|
||||
else:
|
||||
# Si es una búsqueda de personas se incluye en el título y fanart una película por la que es conocido
|
||||
# If it is a search for people, a film for which it is known is included in the title and fanart
|
||||
known_for = ob_tmdb.results[i].get("known_for")
|
||||
type=item.type
|
||||
if known_for:
|
||||
@@ -475,7 +449,7 @@ def detalles(item):
|
||||
itemlist = []
|
||||
images = {}
|
||||
data = ""
|
||||
# Si viene de seccion imdb
|
||||
# If it comes from imdb section
|
||||
if not item.infoLabels["tmdb_id"]:
|
||||
headers = [['Accept-Language', langi]]
|
||||
#data = httptools.downloadpage("http://www.imdb.com/title/" + item.infoLabels['imdb_id'], headers=headers,
|
||||
@@ -483,7 +457,7 @@ def detalles(item):
|
||||
data = httptools.downloadpage("http://www.imdb.com/title/" + item.infoLabels['imdb_id'], headers=headers).data
|
||||
|
||||
pics = scrapertools.find_single_match(data, 'showAllVidsAndPics.*?href=".*?(tt\d+)')
|
||||
# Imágenes imdb
|
||||
# Imdb images
|
||||
if pics:
|
||||
images["imdb"] = {'url': 'http://www.imdb.com/_json/title/%s/mediaviewer' % pics}
|
||||
|
||||
@@ -495,7 +469,7 @@ def detalles(item):
|
||||
|
||||
try:
|
||||
item.infoLabels = ob_tmdb.get_infoLabels(item.infoLabels)
|
||||
# Si no hay sinopsis en idioma elegido, buscar en el alternativo
|
||||
# If there is no synopsis in the chosen language, search in the alternative
|
||||
if not item.infoLabels["plot"]:
|
||||
item.infoLabels["plot"] = ob_tmdb.get_sinopsis(idioma_alternativo=langt_alt)
|
||||
except:
|
||||
@@ -505,7 +479,7 @@ def detalles(item):
|
||||
if item.infoLabels['thumbnail']:
|
||||
item.thumbnail = item.infoLabels['thumbnail']
|
||||
|
||||
# Sinopsis, votos de imdb
|
||||
# Synopsis, votes from imdb
|
||||
if data:
|
||||
plot = scrapertools.find_single_match(data, 'class="inline canwrap" itemprop="description">(.*?)</div>')
|
||||
plot = scrapertools.htmlclean(plot)
|
||||
@@ -525,29 +499,24 @@ def detalles(item):
|
||||
itemlist.append(item.clone(title="--- %s ---" % item.infoLabels['tagline'], action=""))
|
||||
|
||||
title = item.contentType.replace("movie", config.get_localized_string(70283)).replace("tvshow", "serie")
|
||||
# Búsqueda por títulos idioma elegido y/o versión original y español
|
||||
# Search by titles chosen language and / or original version and Spanish
|
||||
itemlist.append(item.clone(action="busqueda", title=config.get_localized_string(70069) % (title, item.contentTitle)))
|
||||
if item.infoLabels['originaltitle'] and item.contentTitle != item.infoLabels['originaltitle']:
|
||||
itemlist.append(item.clone(action="busqueda", contentTitle=item.infoLabels['originaltitle'],
|
||||
title=config.get_localized_string(70070) % item.infoLabels['originaltitle']))
|
||||
itemlist.append(item.clone(action="busqueda", contentTitle=item.infoLabels['originaltitle'], title=config.get_localized_string(70070) % item.infoLabels['originaltitle']))
|
||||
|
||||
if langt != "es" and langt != "en" and item.infoLabels["tmdb_id"]:
|
||||
tmdb_lang = Tmdb(id_Tmdb=item.infoLabels["tmdb_id"], tipo=item.extra, idioma_busqueda=def_lang)
|
||||
if tmdb_lang.result.get("title") and tmdb_lang.result["title"] != item.contentTitle \
|
||||
and tmdb_lang.result["title"] != item.infoLabels['originaltitle']:
|
||||
tmdb_lang = tmdb_lang.result["title"]
|
||||
itemlist.append(item.clone(action="busqueda", title=config.get_localized_string(70066) % tmdb_lang,
|
||||
contentTitle=tmdb_lang))
|
||||
itemlist.append(item.clone(action="busqueda", title=config.get_localized_string(70066) % tmdb_lang, contentTitle=tmdb_lang))
|
||||
|
||||
# En caso de serie, opción de info por temporadas
|
||||
# In case of series, option of info by seasons
|
||||
if item.contentType == "tvshow" and item.infoLabels['tmdb_id']:
|
||||
itemlist.append(item.clone(action="info_seasons",
|
||||
title=config.get_localized_string(70067) % item.infoLabels["number_of_seasons"]))
|
||||
# Opción de ver el reparto y navegar por sus películas/series
|
||||
itemlist.append(item.clone(action="info_seasons", title=config.get_localized_string(70067) % item.infoLabels["number_of_seasons"]))
|
||||
# Option to watch the cast and browse their movies / series
|
||||
if item.infoLabels['tmdb_id']:
|
||||
itemlist.append(item.clone(action="reparto", title=config.get_localized_string(70071),
|
||||
infoLabels={'tmdb_id': item.infoLabels['tmdb_id'],
|
||||
'mediatype': item.contentType}))
|
||||
itemlist.append(item.clone(action="reparto", title=config.get_localized_string(70071), infoLabels={'tmdb_id': item.infoLabels['tmdb_id'], 'mediatype': item.contentType}))
|
||||
|
||||
if config.is_xbmc():
|
||||
item.contextual = True
|
||||
@@ -556,8 +525,7 @@ def detalles(item):
|
||||
|
||||
try:
|
||||
images['tmdb'] = ob_tmdb.result["images"]
|
||||
itemlist.append(item.clone(action="imagenes", title=config.get_localized_string(70316), images=images,
|
||||
extra="menu"))
|
||||
itemlist.append(item.clone(action="imagenes", title=config.get_localized_string(70316), images=images, extra="menu"))
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -580,9 +548,7 @@ def detalles(item):
|
||||
url_album = scrapertools.find_single_match(data_music, 'album(?:|s) on request.*?href="([^"]+)"')
|
||||
if url_album:
|
||||
url_album = "https://nl.hideproxy.me" + url_album
|
||||
itemlist.append(
|
||||
item.clone(action="musica_movie", title=config.get_localized_string(70317), url=url_album,
|
||||
))
|
||||
itemlist.append(item.clone(action="musica_movie", title=config.get_localized_string(70317), url=url_album))
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -591,7 +557,7 @@ def detalles(item):
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70318), action="menu_trakt"))
|
||||
|
||||
itemlist.append(item.clone(title="", action=""))
|
||||
# Es parte de una colección
|
||||
# It is part of a collection
|
||||
try:
|
||||
if ob_tmdb.result.get("belongs_to_collection"):
|
||||
new_item = item.clone(search='', infoLabels={'mediatype': item.contentType})
|
||||
@@ -602,12 +568,11 @@ def detalles(item):
|
||||
if saga["backdrop_path"]:
|
||||
new_item.fanart = 'http://image.tmdb.org/t/p/original' + saga["backdrop_path"]
|
||||
new_item.search = {'url': 'collection/%s' % saga['id'], 'language': langt}
|
||||
itemlist.append(new_item.clone(title=config.get_localized_string(70327) % saga["name"], action="listado_tmdb",
|
||||
))
|
||||
itemlist.append(new_item.clone(title=config.get_localized_string(70327) % saga["name"], action="listado_tmdb"))
|
||||
except:
|
||||
pass
|
||||
|
||||
# Películas/Series similares y recomendaciones
|
||||
# Similar Movies / Series and Recommendations
|
||||
if item.infoLabels['tmdb_id']:
|
||||
item.extra = item.contentType.replace('tvshow', 'tv')
|
||||
title = title.replace("película", config.get_localized_string(70137)).replace("serie", config.get_localized_string(30123))
|
||||
@@ -624,7 +589,7 @@ def detalles(item):
|
||||
|
||||
|
||||
def reparto(item):
|
||||
# Actores y equipo de rodaje de una película/serie
|
||||
# Actors and film crew for a movie / series
|
||||
itemlist = []
|
||||
item.extra=item.contentType.replace('tvshow','tv')
|
||||
item.search = {'url': '%s/%s/credits' % (item.extra, item.infoLabels['tmdb_id'])}
|
||||
@@ -672,7 +637,7 @@ def reparto(item):
|
||||
|
||||
|
||||
def info_seasons(item):
|
||||
# Info de temporadas y episodios
|
||||
# Season and episode info
|
||||
itemlist = []
|
||||
ob_tmdb = Tmdb(id_Tmdb=item.infoLabels["tmdb_id"], tipo="tv", idioma_busqueda=langt)
|
||||
|
||||
@@ -719,7 +684,7 @@ def info_seasons(item):
|
||||
|
||||
|
||||
def indices_tmdb(item):
|
||||
# Indices por genero y año
|
||||
# Indices by gender and year
|
||||
itemlist = []
|
||||
from datetime import datetime
|
||||
if config.get_localized_string(70032) in item.title:
|
||||
@@ -835,7 +800,7 @@ def filtro(item):
|
||||
|
||||
def filtrado(item, values):
|
||||
values_copy = values.copy()
|
||||
# Guarda el filtro para que sea el que se cargue por defecto
|
||||
# Save the filter to be the one loaded by default
|
||||
if "save" in values and values["save"]:
|
||||
values_copy.pop("save")
|
||||
config.set_setting("filtro_defecto_" + item.extra, values_copy, item.channel)
|
||||
@@ -882,24 +847,24 @@ def musica_movie(item):
|
||||
return itemlist
|
||||
|
||||
|
||||
##-------------------- SECCION IMDB ------------------------##
|
||||
##-------------------- SECTION IMDB ------------------------##
|
||||
def listado_imdb(item):
|
||||
# Método principal para secciones de imdb
|
||||
# Main method for imdb sections
|
||||
itemlist = []
|
||||
|
||||
headers = [['Accept-Language', langi]]
|
||||
if "www.imdb.com" in item.url:
|
||||
#data = httptools.downloadpage(item.url, headers=headers, replace_headers=True).data
|
||||
# data = httptools.downloadpage(item.url, headers=headers, replace_headers=True).data
|
||||
data = httptools.downloadpage(item.url, headers=headers).data
|
||||
else:
|
||||
url = 'http://www.imdb.com/search/title?' + item.url
|
||||
#data = httptools.downloadpage(url, headers=headers, replace_headers=True).data
|
||||
# data = httptools.downloadpage(url, headers=headers, replace_headers=True).data
|
||||
data = httptools.downloadpage(url, headers=headers).data
|
||||
|
||||
data = re.sub(r"\n|\r|\t| ", "", data)
|
||||
data = re.sub(r"\s{2}", " ", data)
|
||||
|
||||
# Listado de actores
|
||||
# List of actors
|
||||
if 'search/name' in item.url:
|
||||
patron = '<td class="image">.*?src="([^"]+)".*?href="/name/(nm\d+).*?>([^<]+)<.*?href.*?>([^<]+)</a>' \
|
||||
'</span>(.*?)</td>'
|
||||
@@ -996,7 +961,7 @@ def filtro_imdb(item):
|
||||
valores = {}
|
||||
|
||||
dict_values = None
|
||||
# Se utilizan los valores por defecto/guardados
|
||||
# Default / saved values are used
|
||||
valores_guardados = config.get_setting("filtro_defecto_imdb_" + item.extra, item.channel)
|
||||
if valores_guardados:
|
||||
dict_values = valores_guardados
|
||||
@@ -1086,7 +1051,7 @@ def filtro_imdb(item):
|
||||
|
||||
def filtrado_imdb(item, values):
|
||||
values_copy = values.copy()
|
||||
# Guarda el filtro para que sea el que se cargue por defecto
|
||||
# Save the filter to be the one loaded by default
|
||||
if "save" in values and values["save"]:
|
||||
values_copy.pop("save")
|
||||
config.set_setting("filtro_defecto_imdb_" + item.extra, values_copy, item.channel)
|
||||
@@ -1119,7 +1084,7 @@ def filtrado_imdb(item, values):
|
||||
|
||||
|
||||
def indices_imdb(item):
|
||||
# Índices imdb por año y genero
|
||||
# Imdb indices by year and gender
|
||||
itemlist = []
|
||||
from datetime import datetime
|
||||
if config.get_localized_string(70032) in item.title:
|
||||
@@ -1149,12 +1114,12 @@ def indices_imdb(item):
|
||||
return itemlist
|
||||
|
||||
|
||||
##-------------------- SECCION FILMAFFINITY ------------------------##
|
||||
##-------------------- FILMAFFINITY SECTION ------------------------##
|
||||
def listado_fa(item):
|
||||
# Método para listados principales de filmaffinity
|
||||
# Filmaffinity main listing method
|
||||
itemlist = []
|
||||
|
||||
# Listados con paginación por post
|
||||
# Listings with pagination per post
|
||||
if item.extra == "top":
|
||||
if item.page_fa:
|
||||
post = "from=%s" % item.page_fa
|
||||
@@ -1176,7 +1141,7 @@ def listado_fa(item):
|
||||
data = re.sub(r"\s{2}", " ", data)
|
||||
|
||||
votaciones = []
|
||||
# Si es la sección de estrenos cambia la estructura del scraper
|
||||
# If it is the premiere section, change the structure of the scraper
|
||||
if item.extra == "estrenos":
|
||||
patron = '<i class="fa fa-calendar"></i>\s*(\d+[^<]+)<(.*?)(?:<div class="panel panel-default">|' \
|
||||
'<div class="text-center")'
|
||||
@@ -1269,7 +1234,7 @@ def listado_fa(item):
|
||||
|
||||
|
||||
def indices_fa(item):
|
||||
# Índices por genero, año, temas y sagas/colecciones
|
||||
# Indexes by gender, year, themes and sagas / collections
|
||||
itemlist = []
|
||||
if item.url:
|
||||
data = httptools.downloadpage(item.url).data
|
||||
@@ -1357,7 +1322,7 @@ def indices_fa(item):
|
||||
|
||||
|
||||
def temas_fa(item):
|
||||
# Películas y series por temas
|
||||
# Movies and series by themes
|
||||
itemlist = []
|
||||
|
||||
data = httptools.downloadpage(item.url).data
|
||||
@@ -1402,7 +1367,7 @@ def detalles_fa(item):
|
||||
data = re.sub(r"\n|\r|\t| ", "", data)
|
||||
data = re.sub(r"\s{2}", " ", data)
|
||||
|
||||
# Se extrae el título original para posibles búsquedas en tmdb posteriores
|
||||
# The original title is extracted for possible searches in later tmdb
|
||||
orig_title = scrapertools.find_single_match(data, 'itemprop="datePublished">.*?<dd>([^<]+)</dd>').strip()
|
||||
if item.contentType == "movie":
|
||||
item.infoLabels['originaltitle'] = re.sub(r"(?i)\(TV Series\)|\(S\)|\(TV\)", "", orig_title)
|
||||
@@ -1426,11 +1391,11 @@ def detalles_fa(item):
|
||||
ob_tmdb = Tmdb(id_Tmdb=ob_tmdb.get_id(), tipo=item_tmdb.extra, idioma_busqueda=langt)
|
||||
item.infoLabels = ob_tmdb.get_infoLabels(item.infoLabels)
|
||||
|
||||
# Si no hay sinopsis en idioma elegido, buscar en el alternativo
|
||||
# If there is no synopsis in the chosen language, search in the alternative
|
||||
if not item.infoLabels["plot"]:
|
||||
item.infoLabels["plot"] = ob_tmdb.get_sinopsis(idioma_alternativo=langt_alt)
|
||||
|
||||
# Se concatena el plot de filmaffinity al de tmdb si lo hay
|
||||
# The filmaffinity plot is concatenated to the tmdb plot if any
|
||||
plot = scrapertools.find_single_match(data, '<dd itemprop="description">(.*?)</dd>')
|
||||
plot = plot.replace("<br><br />", "\n")
|
||||
plot = scrapertools.decodeHtmlentities(plot).replace(" (FILMAFFINITY)", "")
|
||||
@@ -1439,7 +1404,7 @@ def detalles_fa(item):
|
||||
elif plot and not item.infoLabels['plot']:
|
||||
item.infoLabels['plot'] = plot
|
||||
|
||||
# Se busca y rellena con la info de filmaffinity para diferenciarla de tmdb
|
||||
# It is searched and filled with the filmaffinity info to differentiate it from tmdb
|
||||
if not item.infoLabels['duration']:
|
||||
duration = scrapertools.find_single_match(data, '<dd itemprop="duration">(\d+)')
|
||||
if duration:
|
||||
@@ -1544,7 +1509,7 @@ def detalles_fa(item):
|
||||
token_auth = config.get_setting("token_trakt", "trakt")
|
||||
if token_auth and ob_tmdb.result:
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70323), action="menu_trakt"))
|
||||
# Acciones si se configura cuenta en FA (Votar y añadir/quitar en listas)
|
||||
# Actions if account is configured in FA (Vote and add / remove in lists)
|
||||
mivoto = scrapertools.find_single_match(data, 'bg-my-rating.*?>\s*(\d+)')
|
||||
itk = scrapertools.find_single_match(data, 'data-itk="([^"]+)"')
|
||||
folder = not config.is_xbmc()
|
||||
@@ -1568,7 +1533,7 @@ def detalles_fa(item):
|
||||
new_item.infoLabels["duration"] = ""
|
||||
itemlist.append(new_item)
|
||||
|
||||
# Si pertenece a una saga/colección
|
||||
# If you belong to a saga / collection
|
||||
if ob_tmdb.result:
|
||||
itemlist.append(item.clone(title="", action="", infoLabels={}))
|
||||
if ob_tmdb.result.get("belongs_to_collection"):
|
||||
@@ -1603,7 +1568,7 @@ def filtro_fa(item):
|
||||
valores = {}
|
||||
|
||||
dict_values = None
|
||||
# Se utilizan los valores por defecto/guardados
|
||||
# Default / saved values are used
|
||||
valores_guardados = config.get_setting("filtro_defecto_filmaf_" + item.extra, item.channel)
|
||||
if valores_guardados:
|
||||
dict_values = valores_guardados
|
||||
@@ -1675,7 +1640,7 @@ def filtro_fa(item):
|
||||
|
||||
def filtrado_fa(item, values):
|
||||
values_copy = values.copy()
|
||||
# Guarda el filtro para que sea el que se cargue por defecto
|
||||
# Save the filter to be the one loaded by default
|
||||
if "save" in values and values["save"]:
|
||||
values_copy.pop("save")
|
||||
config.set_setting("filtro_defecto_filmaf_" + item.extra, values_copy, item.channel)
|
||||
@@ -1732,7 +1697,7 @@ def login_fa():
|
||||
|
||||
|
||||
def cuenta_fa(item):
|
||||
# Menú de cuenta filmaffinity
|
||||
# Filmaffinity account menu
|
||||
itemlist = []
|
||||
login, message = login_fa()
|
||||
if not login:
|
||||
@@ -1748,7 +1713,7 @@ def cuenta_fa(item):
|
||||
|
||||
|
||||
def acciones_fa(item):
|
||||
# Acciones cuenta filmaffinity, votar, ver listas o añadir/quitar de lista
|
||||
# Actions account filmaffinity, vote, view lists or add / remove from list
|
||||
itemlist = []
|
||||
|
||||
if item.accion == "votos" or item.accion == "lista":
|
||||
@@ -1847,7 +1812,7 @@ def acciones_fa(item):
|
||||
|
||||
|
||||
def votar_fa(item):
|
||||
# Ventana para seleccionar el voto
|
||||
# Window to select the vote
|
||||
logger.info()
|
||||
|
||||
list_controls = []
|
||||
@@ -1889,7 +1854,7 @@ def callback_voto(item, values):
|
||||
|
||||
|
||||
def newlist(item):
|
||||
# Creación de nueva lista en filmaffinity
|
||||
# Creation of new list in filmaffinity
|
||||
itemlist = []
|
||||
if item.accion == "lista":
|
||||
location = httptools.downloadpage(item.url, only_headers=True).headers["location"]
|
||||
@@ -1910,7 +1875,7 @@ def newlist(item):
|
||||
return itemlist
|
||||
|
||||
|
||||
##-------------------- LISTADOS DE IMAGENES ------------------------##
|
||||
##-------------------- IMAGE LISTINGS ------------------------##
|
||||
def imagenes(item):
|
||||
itemlist = []
|
||||
|
||||
@@ -2055,13 +2020,13 @@ def fanartv(item):
|
||||
return item, resultado
|
||||
|
||||
|
||||
##-------------------- SECCION TRAKT.TV ------------------------##
|
||||
##-------------------- SECTION TRAKT.TV ------------------------##
|
||||
def auth_trakt(item):
|
||||
return trakt_tools.auth_trakt()
|
||||
|
||||
|
||||
def menu_trakt(item):
|
||||
# Menú con acciones de cuenta trakt (vistas, watchlist, coleccion)
|
||||
# Menu with trakt account actions (views, watchlist, collection)
|
||||
itemlist = []
|
||||
token_auth = config.get_setting("token_trakt", "trakt")
|
||||
tipo = item.extra.replace("tv", "show") + "s"
|
||||
@@ -2279,9 +2244,9 @@ def order_trakt(item, values):
|
||||
return acciones_trakt(item)
|
||||
|
||||
|
||||
##-------------------- SECCION MYANIMELIST ------------------------##
|
||||
##-------------------- MYANIMELIST SECTION ------------------------##
|
||||
def top_mal(item):
|
||||
# Para los menús principales de tops pelícuas/series/ovas
|
||||
# For the main menus of movie tops / series / ova
|
||||
itemlist = []
|
||||
data = httptools.downloadpage(item.url, cookies=False).data
|
||||
data = re.sub(r"\n|\r|\t| ", "", data)
|
||||
@@ -2388,7 +2353,7 @@ def detalles_mal(item):
|
||||
ob_tmdb = Tmdb(id_Tmdb=ob_tmdb.get_id(), tipo=item_tmdb.extra, idioma_busqueda=langt)
|
||||
item.infoLabels = ob_tmdb.get_infoLabels(item.infoLabels)
|
||||
|
||||
# Se concatena sinopsis myanimelist con la de tmdb si la hubiese
|
||||
# Myanimelist synopsis is concatenated with that of tmdb if any
|
||||
plot = scrapertools.find_single_match(data, '<span itemprop="description">(.*?)</span>')
|
||||
plot = plot.replace("<br />", "\n").replace("<i>", "[I]").replace("</i>", "[/I]")
|
||||
plot = scrapertools.decodeHtmlentities(plot)
|
||||
@@ -2411,7 +2376,7 @@ def detalles_mal(item):
|
||||
except:
|
||||
pass
|
||||
|
||||
# Se sobreescribe la info de myanimelist sobre la de tmdb
|
||||
# Myanimelist info overwrites tmdb info
|
||||
generos = scrapertools.find_single_match(data, 'Genres:</span>(.*?)</div>')
|
||||
if generos:
|
||||
item.infoLabels['genre'] = scrapertools.htmlclean(generos)
|
||||
@@ -2445,7 +2410,7 @@ def detalles_mal(item):
|
||||
itemlist.append(item.clone(action="videos_mal", title=config.get_localized_string(70353),
|
||||
url=item.url + "/video"))
|
||||
|
||||
# Opción para ver la info de personajes y dobladores/equipo de rodaje
|
||||
# Option to see the info of characters and voiceovers / filming equipment
|
||||
if not "No characters or voice actors" in data and not "No staff for this anime" in data:
|
||||
itemlist.append(item.clone(action="staff_mal", title=config.get_localized_string(70354),
|
||||
url=item.url + "/characters"))
|
||||
@@ -2497,7 +2462,7 @@ def detalles_mal(item):
|
||||
if token_auth and ob_tmdb.result:
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70323), action="menu_trakt"))
|
||||
|
||||
# Se listan precuelas, secuelas y series alternativas
|
||||
# Prequels, sequels and alternative series are listed
|
||||
prequel = scrapertools.find_single_match(data, 'Prequel:</td>(.*?)</td>')
|
||||
if prequel:
|
||||
matches = scrapertools.find_multiple_matches(prequel, 'href="([^"]+)">(.*?)</a>')
|
||||
@@ -2550,7 +2515,7 @@ def detalles_mal(item):
|
||||
search={'url': '%s/%s/recommendations' % (item.extra, item.infoLabels['tmdb_id']),
|
||||
'language': langt, 'page': 1}, ))
|
||||
|
||||
# Recomendaciones myanimelist y búsqueda de info en anidb (fansubs en español)
|
||||
# Myanimelist recommendations and info search on anidb (fansubs in Spanish)
|
||||
itemlist.append(item.clone(title=config.get_localized_string(70359), action="reco_mal"))
|
||||
anidb_link = scrapertools.find_single_match(data,
|
||||
'<a href="(http://anidb.info/perl-bin/animedb.pl\?show=anime&aid=\d+)')
|
||||
@@ -2562,7 +2527,7 @@ def detalles_mal(item):
|
||||
|
||||
|
||||
def videos_mal(item):
|
||||
# Método para episodios en crunchyroll y trailer/promocionales
|
||||
# Method for crunchyroll and trailer / promotional episodes
|
||||
itemlist = []
|
||||
|
||||
data = httptools.downloadpage(item.url, cookies=False).data
|
||||
@@ -2604,7 +2569,7 @@ def videos_mal(item):
|
||||
|
||||
|
||||
def reco_mal(item):
|
||||
# Recomendaciones de myanimelist
|
||||
# Myanimelist recommendations
|
||||
itemlist = []
|
||||
|
||||
data = httptools.downloadpage(item.url + "/userrecs", cookies=False).data
|
||||
@@ -2628,7 +2593,7 @@ def reco_mal(item):
|
||||
|
||||
|
||||
def indices_mal(item):
|
||||
# Índices por temporadas y generos
|
||||
# Seasonal and gender indices
|
||||
itemlist = []
|
||||
url_base = ""
|
||||
if "Temporadas" in item.title:
|
||||
@@ -2664,7 +2629,7 @@ def indices_mal(item):
|
||||
|
||||
|
||||
def season_mal(item):
|
||||
# Scraper para temporadas de anime
|
||||
# Scraper for anime seasons
|
||||
itemlist = []
|
||||
|
||||
cookie_session = get_cookie_value()
|
||||
@@ -2758,7 +2723,7 @@ def season_mal(item):
|
||||
|
||||
|
||||
def staff_mal(item):
|
||||
# Dobladores/Equipo de rodaje
|
||||
# Benders / Filming Equipment
|
||||
itemlist = []
|
||||
data = httptools.downloadpage(item.url, cookies=False).data
|
||||
data = re.sub(r"\n|\r|\t| ", "", data)
|
||||
@@ -2869,7 +2834,7 @@ def detail_staff(item):
|
||||
|
||||
|
||||
def busqueda_mal(item):
|
||||
# Scraper para búsquedas en myanimelist
|
||||
# Scraper for myanimelist searches
|
||||
itemlist = []
|
||||
|
||||
cookie_session = get_cookie_value()
|
||||
@@ -2942,7 +2907,7 @@ def busqueda_mal(item):
|
||||
|
||||
|
||||
def info_anidb(item, itemlist, url):
|
||||
# Extrae info, puntuación y fansubs en anidb
|
||||
# Extract info, score and fansubs on anidb
|
||||
data = httptools.downloadpage(url).data
|
||||
data = re.sub(r"\n|\r|\t| ", "", data)
|
||||
data = re.sub(r"\s{2}", " ", data)
|
||||
@@ -2994,7 +2959,7 @@ def filtro_mal(item):
|
||||
list_controls = []
|
||||
valores = {}
|
||||
dict_values = None
|
||||
# Se utilizan los valores por defecto/guardados
|
||||
# Default / saved values are used
|
||||
valores_guardados = config.get_setting("filtro_defecto_mal", item.channel)
|
||||
if valores_guardados:
|
||||
dict_values = valores_guardados
|
||||
@@ -3044,7 +3009,7 @@ def filtro_mal(item):
|
||||
|
||||
def callback_mal(item, values):
|
||||
values_copy = values.copy()
|
||||
# Guarda el filtro para que sea el que se cargue por defecto
|
||||
# Save the filter to be the one loaded by default
|
||||
if "save" in values and values["save"]:
|
||||
values_copy.pop("save")
|
||||
config.set_setting("filtro_defecto_mal", values_copy, item.channel)
|
||||
@@ -3072,7 +3037,7 @@ def callback_mal(item, values):
|
||||
|
||||
|
||||
def musica_anime(item):
|
||||
# Lista los animes y canciones disponibles similares al título del anime
|
||||
# List available anime and songs similar to the anime title
|
||||
logger.info()
|
||||
itemlist = []
|
||||
|
||||
@@ -3145,7 +3110,7 @@ def login_mal(from_list=False):
|
||||
|
||||
|
||||
def cuenta_mal(item):
|
||||
# Menú de cuenta myanimelist
|
||||
# Myanimelist account menu
|
||||
itemlist = []
|
||||
login, message, user = login_mal(True)
|
||||
if not login:
|
||||
@@ -3167,7 +3132,7 @@ def cuenta_mal(item):
|
||||
|
||||
|
||||
def items_mal(item):
|
||||
# Scraper para las listas personales
|
||||
# Scraper for personal lists
|
||||
logger.info()
|
||||
itemlist = []
|
||||
data = httptools.downloadpage(item.url).data
|
||||
@@ -3213,7 +3178,7 @@ def items_mal(item):
|
||||
|
||||
|
||||
def menu_mal(item):
|
||||
# Opciones cuenta MAL, añadir a lista/votar
|
||||
# Options BAD account, add to list / vote
|
||||
itemlist = []
|
||||
|
||||
data = httptools.downloadpage(item.url).data
|
||||
@@ -3271,7 +3236,7 @@ def addlist_mal(item):
|
||||
url = "https://myanimelist.net/ownlist/anime/add.json"
|
||||
if item.lista:
|
||||
url = "https://myanimelist.net/ownlist/anime/edit.json"
|
||||
#data = httptools.downloadpage(url, post=jsontools.dump(post), headers=headers_mal, replace_headers=True).data
|
||||
# data = httptools.downloadpage(url, post=jsontools.dump(post), headers=headers_mal, replace_headers=True).data
|
||||
data = httptools.downloadpage(url, post=jsontools.dump(post), headers=headers_mal).data
|
||||
item.title = "En tu lista"
|
||||
if config.is_xbmc():
|
||||
|
||||
@@ -17,7 +17,7 @@ def mainlist(item):
|
||||
return itemlist
|
||||
|
||||
|
||||
# Al llamarse "search" la función, el launcher pide un text a buscar y lo añade como parámetro
|
||||
# When the function "search" is called, the launcher asks for a text to search for and adds it as a parameter
|
||||
def search(item, text):
|
||||
log(text)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user