merged from develop

This commit is contained in:
alfa_addon_10
2017-08-13 17:07:36 +02:00
parent ebda6babdd
commit ed553f5cae
398 changed files with 10399 additions and 2029 deletions

View File

@@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------
# Módulo para acciones en el cliente HTML
# ------------------------------------------------------------
import os
from inspect import isclass
from controller import Controller
from platformcode import logger
def load_controllers():
controllers = []
path = os.path.split(__file__)[0]
for fname in os.listdir(path):
mod, ext = os.path.splitext(fname)
fname = os.path.join(path, fname)
if os.path.isfile(fname) and ext == '.py' and not mod.startswith('_'):
try:
exec "import " + mod + " as controller"
except:
import traceback
logger.error(traceback.format_exc())
for c in dir(controller):
cls = getattr(controller, c)
if not c.startswith('_') and isclass(cls) and issubclass(cls, Controller) and Controller != cls:
controllers.append(cls)
return controllers
controllers = load_controllers()
def find_controller(url):
result = []
for c in controllers:
if c().match(url):
return c

View File

@@ -0,0 +1,129 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------
# Mediaserver Base controller
# ------------------------------------------------------------
import threading
from platformcode import config, platformtools
class Controller(object):
pattern = ""
name = None
def __init__(self, handler=None, ID=None):
self.handler = handler
self.id = ID
if not self.id:
self.id = threading.current_thread().name
if self.handler:
self.platformtools = Platformtools()
self.host = "http://%s:%s" % (config.get_local_ip(), config.get_setting("server.port"))
def __setattr__(self, name, value):
super(Controller, self).__setattr__(name, value)
if name == "platformtools":
platformtools.controllers[self.id] = self.platformtools
def __del__(self):
from platformcode import platformtools
if self.id in platformtools.controllers:
del platformtools.controllers[self.id]
def run(self, path):
pass
def match(self, path):
if self.pattern.findall(path):
return True
else:
return False
class Platformtools(object):
def dialog_ok(self, heading, line1, line2="", line3=""):
pass
def dialog_notification(self, heading, message, icon=0, time=5000, sound=True):
pass
def dialog_yesno(self, heading, line1, line2="", line3="", nolabel="No", yeslabel="Si", autoclose=""):
return True
def dialog_select(self, heading, list):
pass
def dialog_progress(self, heading, line1, line2="", line3=""):
class Dialog(object):
def __init__(self, heading, line1, line2, line3, PObject):
self.PObject = PObject
self.closed = False
self.heading = heading
text = line1
if line2: text += "\n" + line2
if line3: text += "\n" + line3
def iscanceled(self):
return self.closed
def update(self, percent, line1, line2="", line3=""):
pass
def close(self):
self.closed = True
return Dialog(heading, line1, line2, line3, None)
def dialog_progress_bg(self, heading, message=""):
class Dialog(object):
def __init__(self, heading, message, PObject):
self.PObject = PObject
self.closed = False
self.heading = heading
def isFinished(self):
return not self.closed
def update(self, percent=0, heading="", message=""):
pass
def close(self):
self.closed = True
return Dialog(heading, message, None)
def dialog_input(self, default="", heading="", hidden=False):
return default
def dialog_numeric(self, type, heading, default=""):
return None
def itemlist_refresh(self):
pass
def itemlist_update(self, item):
pass
def render_items(self, itemlist, parentitem):
pass
def is_playing(self):
return False
def play_video(self, item):
pass
def show_channel_settings(self, list_controls=None, dict_values=None, caption="", callback=None, item=None,
custom_button=None, channelpath=None):
pass
def show_video_info(self, data, caption="Información del vídeo", callback=None, item=None):
pass
def show_recaptcha(self, key, url):
pass

View File

@@ -0,0 +1,104 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------
# Controlador para acceso a archivos locales
# ------------------------------------------------------------
import os
import re
import time
from controller import Controller
from platformcode import config, logger
class fileserver(Controller):
pattern = re.compile("^/(?:media/.*?)?(?:local/.*?)?$")
def run(self, path):
if path == "/":
f = open(os.path.join(config.get_runtime_path(), "platformcode", "template", "page.html"), "rb")
self.handler.send_response(200)
self.handler.send_header('Content-type', 'text/html')
self.handler.end_headers()
respuesta = f.read()
respuesta = respuesta.replace("{$WSPORT}", str(config.get_setting("websocket.port")))
self.handler.wfile.write(respuesta)
f.close()
elif path.startswith("/local/"):
import base64
import urllib
Path = path.replace("/local/", "").split("/")[0]
Path = base64.b64decode(urllib.unquote_plus(Path))
Size = int(os.path.getsize(Path.decode("utf8")))
f = open(Path.decode("utf8"), "rb")
if not self.handler.headers.get("range") == None:
if "=" in str(self.handler.headers.get("range")) and "-" in str(self.handler.headers.get("range")):
Inicio = int(self.handler.headers.get("range").split("=")[1].split("-")[0])
if self.handler.headers.get("range").split("=")[1].split("-")[1] <> "":
Fin = int(self.handler.headers.get("range").split("=")[1].split("-")[1])
else:
Fin = Size - 1
else:
Inicio = 0
Fin = Size - 1
if not Fin > Inicio: Fin = Size - 1
if self.handler.headers.get("range") == None:
logger.info("-------------------------------------------------------")
logger.info("Solicitando archivo local: " + Path)
logger.info("-------------------------------------------------------")
self.handler.send_response(200)
self.handler.send_header("Content-Disposition", "attachment; filename=video.mp4")
self.handler.send_header('Accept-Ranges', 'bytes')
self.handler.send_header('Content-Length', str(Size))
self.handler.send_header("Connection", "close")
self.handler.end_headers()
while True:
time.sleep(0.2)
buffer = f.read(1024 * 250)
if not buffer:
break
self.handler.wfile.write(buffer)
self.handler.wfile.close()
f.close()
else:
logger.info("-------------------------------------------------------")
logger.info("Solicitando archivo local: " + Path)
logger.info("Rango: " + str(Inicio) + "-" + str(Fin) + "/" + str(Size))
logger.info("-------------------------------------------------------")
f.seek(Inicio)
self.handler.send_response(206)
self.handler.send_header("Content-Disposition", "attachment; filename=video.mp4")
self.handler.send_header('Accept-Ranges', 'bytes')
self.handler.send_header('Content-Length', str(Fin - Inicio))
self.handler.send_header('Content-Range', str(Inicio) + "-" + str(Fin) + "/" + str(Size))
self.handler.send_header("Connection", "close")
self.handler.end_headers()
while True:
time.sleep(0.2)
buffer = f.read(1024 * 250)
if not buffer:
break
self.handler.wfile.write(buffer)
self.handler.wfile.close()
f.close()
elif path.startswith("/media/"):
file = os.path.join(config.get_runtime_path(), "platformcode", "template", path[7:])
from mimetypes import MimeTypes
mime = MimeTypes()
mime_type = mime.guess_type(file)
try:
mim = mime_type[0]
except:
mim = ""
f = open(file, "rb")
self.handler.send_response(200)
self.handler.send_header('Content-type', mim)
self.handler.end_headers()
self.handler.wfile.write(f.read())
f.close()

View File

@@ -0,0 +1,788 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------
# Controlador para HTML
# ------------------------------------------------------------
import json
import os
import re
import threading
import time
import channelselector
from controller import Controller
from controller import Platformtools
from platformcode import config
from core import versiontools
from core.item import Item
from core.tmdb import Tmdb
from platformcode import launcher, logger
class html(Controller):
pattern = re.compile("##")
name = "HTML"
def __init__(self, handler=None, ID=None):
super(html, self).__init__(handler, ID)
self.platformtools = platform(self)
self.data = {}
if self.handler:
self.client_ip = handler.client.getpeername()[0]
self.send_message({"action": "connect",
"data": {"version": "Alfa %s" % versiontools.get_current_plugin_version_tag(),
"date": versiontools.get_current_plugin_date()}})
t = threading.Thread(target=launcher.start, name=ID)
t.setDaemon(True)
t.start()
def run(self, path):
if path:
item = Item().fromurl(path)
else:
item = Item(channel="channelselector", action="mainlist", viewmode="banner")
launcher.run(item)
def get_data(self, id):
while not "id" in self.data or not self.data["id"] == id:
time.sleep(0.1)
data = self.data["result"]
self.data = {}
return data
def send_message(self, data):
import random
ID = "%032x" % (random.getrandbits(128))
data["id"] = ID
self.handler.sendMessage(json.dumps(data))
return ID
class platform(Platformtools):
def __init__(self, controller):
self.controller = controller
self.handler = controller.handler
self.get_data = controller.get_data
self.send_message = controller.send_message
def render_items(self, itemlist, parent_item):
"""
Función encargada de mostrar el itemlist, se pasa como parametros el itemlist y el item del que procede
@type itemlist: list
@param itemlist: lista de elementos a mostrar
@type parent_item: item
@param parent_item: elemento padre
"""
# Si el itemlist no es un list salimos
if not type(itemlist) == list:
JsonData = {}
JsonData["action"] = "HideLoading"
JsonData["data"] = {}
self.send_message(JsonData)
return
# Si no hay ningun item, mostramos un aviso
if not len(itemlist):
itemlist.append(Item(title="No hay elementos que mostrar"))
if parent_item.channel == "channelselector" and not parent_item.action == "filterchannels":
parent_item.viewmode = "banner"
elif parent_item.channel == "channelselector" and parent_item.action == "filterchannels":
parent_item.viewmode = "channel"
if not parent_item.viewmode:
parent_item.viewmode = "list"
# Item Atrás
if not (parent_item.channel == "channelselector" and parent_item.action == "mainlist") and not \
itemlist[0].action == "go_back":
if parent_item.viewmode in ["banner", "channel"]:
itemlist.insert(0, Item(title="Atrás", action="go_back",
thumbnail=channelselector.get_thumb("back.png", "banner_")))
else:
itemlist.insert(0, Item(title="Atrás", action="go_back",
thumbnail=channelselector.get_thumb("back.png")))
JsonData = {}
JsonData["action"] = "EndItems"
JsonData["data"] = {}
JsonData["data"]["itemlist"] = []
JsonData["data"]["viewmode"] = parent_item.viewmode
JsonData["data"]["category"] = parent_item.category.capitalize()
JsonData["data"]["host"] = self.controller.host
# Recorremos el itemlist
for item in itemlist:
if not item.thumbnail and item.action == "search": item.thumbnail = channelselector.get_thumb("search.png")
if not item.thumbnail and item.folder == True: item.thumbnail = channelselector.get_thumb("folder.png", "banner")
if not item.thumbnail and item.folder == False: item.thumbnail = channelselector.get_thumb("nofolder.png")
if "http://media.xxxxx/" in item.thumbnail and not item.thumbnail.startswith(
"http://media.xxxxxxxx/thumb_"):
if parent_item.viewmode in ["banner", "channel"]:
item.thumbnail = channelselector.get_thumbnail_path("banner") + os.path.basename(item.thumbnail)
else:
item.thumbnail = channelselector.get_thumbnail_path() + os.path.basename(item.thumbnail)
# Estas imagenes no estan en banner, asi que si queremos banner, para que no se vean mal las quitamos
elif parent_item.viewmode in ["banner", "channel"] and item.thumbnail.startswith(
"http://media.xxxxx/thumb_"):
item.thumbnail = ""
# Si el item no contiene categoria,le ponemos la del item padre
if item.category == "":
item.category = parent_item.category
# Si el item no contiene fanart,le ponemos la del item padre
if item.fanart == "":
item.fanart = parent_item.fanart
title = item.title.replace(item.title.lstrip(), "").replace(" ", "&nbsp;") + item.title.lstrip()
# Formatear titulo
if item.text_color:
title = '[COLOR %s]%s[/COLOR]' % (item.text_color, title)
if item.text_bold:
title = '[B]%s[/B]' % title
if item.text_italic:
title = '[I]%s[/I]' % title
title = self.kodi_labels_to_html(title)
# Añade headers a las imagenes si estan en un servidor con cloudflare
from core import httptools
item.thumbnail = httptools.get_url_headers(item.thumbnail)
item.fanart = httptools.get_url_headers(item.fanart)
JsonItem = {}
JsonItem["title"] = title
JsonItem["thumbnail"] = item.thumbnail
JsonItem["fanart"] = item.fanart
JsonItem["plot"] = item.plot
JsonItem["action"] = item.action
JsonItem["url"] = item.tourl()
JsonItem["context"] = []
if not item.action == "go_back":
for Comando in self.set_context_commands(item, parent_item):
JsonItem["context"].append({"title": Comando[0], "url": Comando[1]})
JsonData["data"]["itemlist"].append(JsonItem)
ID = self.send_message(JsonData)
self.get_data(ID)
def set_context_commands(self, item, parent_item):
"""
Función para generar los menus contextuales.
1. Partiendo de los datos de item.context
a. Metodo antiguo item.context tipo str separando las opciones por "|" (ejemplo: item.context = "1|2|3")
(solo predefinidos)
b. Metodo list: item.context es un list con las diferentes opciones del menu:
- Predefinidos: Se cargara una opcion predefinida con un nombre.
item.context = ["1","2","3"]
- dict(): Se cargara el item actual modificando los campos que se incluyan en el dict() en caso de
modificar los campos channel y action estos serán guardados en from_channel y from_action.
item.context = [{"title":"Nombre del menu", "action": "action del menu", "channel",
"channel del menu"}, {...}]
2. Añadiendo opciones segun criterios
Se pueden añadir opciones al menu contextual a items que cumplan ciertas condiciones
3. Añadiendo opciones a todos los items
Se pueden añadir opciones al menu contextual para todos los items
@param item: elemento que contiene los menu contextuales
@type item: item
@param parent_item:
@type parent_item: item
"""
context_commands = []
# Creamos un list con las diferentes opciones incluidas en item.context
if type(item.context) == str:
context = item.context.split("|")
elif type(item.context) == list:
context = item.context
else:
context = []
# Opciones segun item.context
for command in context:
# Predefinidos
if type(command) == str:
if command == "buscar_trailer":
context_commands.append(("Buscar Trailer",
item.clone(channel="trailertools", action="buscartrailer",
contextual=True).tourl()))
# Formato dict
if type(command) == dict:
# Los parametros del dict, se sobreescriben al nuevo context_item en caso de sobreescribir "action" y
# "channel", los datos originales se guardan en "from_action" y "from_channel"
if "action" in command:
command["from_action"] = item.action
if "channel" in command:
command["from_channel"] = item.channel
context_commands.append(
(command["title"], item.clone(**command).tourl()))
# Opciones segun criterios
# Ir al Menu Principal (channel.mainlist)
if parent_item.channel not in ["news",
"channelselector"] and item.action != "mainlist" and parent_item.action != "mainlist":
context_commands.append(("Ir al Menu Principal", Item(channel=item.channel, action="mainlist").tourl()))
# Añadir a Favoritos
if item.channel not in ["favorites", "videolibrary", "help", "setting",
""] and not parent_item.channel == "favorites":
context_commands.append((config.get_localized_string(30155),
item.clone(channel="favorites", action="addFavourite", from_channel=item.channel,
from_action=item.action).tourl()))
# Añadimos opción contextual para Añadir la serie completa a la videoteca
if item.channel != "videolibrary" and item.action in ["episodios", "get_episodios"] \
and (item.contentSerieName or item.show):
context_commands.append(("Añadir Serie a Videoteca",
item.clone(action="add_serie_to_library", from_action=item.action).tourl()))
# Añadir Pelicula a videoteca
if item.channel != "videolibrary" and item.action in ["detail", "findvideos"] \
and item.contentType == 'movie':
context_commands.append(("Añadir Pelicula a Videoteca",
item.clone(action="add_pelicula_to_library", from_action=item.action).tourl()))
# Descargar pelicula
if item.contentType == "movie" and not item.channel == "downloads":
context_commands.append(("Descargar Pelicula",
item.clone(channel="downloads", action="save_download", from_channel=item.channel,
from_action=item.action).tourl()))
# Descargar serie
if item.contentType == "tvshow" and not item.channel == "downloads":
context_commands.append(("Descargar Serie",
item.clone(channel="downloads", action="save_download", from_channel=item.channel,
from_action=item.action).tourl()))
# Descargar episodio
if item.contentType == "episode" and not item.channel == "downloads":
context_commands.append(("Descargar Episodio",
item.clone(channel="downloads", action="save_download", from_channel=item.channel,
from_action=item.action).tourl()))
# Descargar temporada
if item.contentType == "season" and not item.channel == "downloads":
context_commands.append(("Descargar Temporada",
item.clone(channel="downloads", action="save_download", from_channel=item.channel,
from_action=item.action).tourl()))
# Abrir configuración
if parent_item.channel not in ["setting", "news", "search"]:
context_commands.append(("Abrir Configuración", Item(channel="setting", action="mainlist").tourl()))
return sorted(context_commands, key=lambda comand: comand[0])
def dialog_ok(self, heading, line1, line2="", line3=""):
text = line1
if line2: text += "\n" + line2
if line3: text += "\n" + line3
text = self.kodi_labels_to_html(text)
JsonData = {}
JsonData["action"] = "Alert"
JsonData["data"] = {}
JsonData["data"]["title"] = heading
JsonData["data"]["text"] = unicode(text, "utf8", "ignore").encode("utf8")
ID = self.send_message(JsonData)
self.get_data(ID)
def dialog_notification(self, heading, message, icon=0, time=5000, sound=True):
JsonData = {}
JsonData["action"] = "notification"
JsonData["data"] = {}
JsonData["data"]["title"] = self.kodi_labels_to_html(heading)
JsonData["data"]["text"] = self.kodi_labels_to_html(message)
JsonData["data"]["icon"] = icon
JsonData["data"]["sound"] = sound
JsonData["data"]["time"] = time
self.send_message(JsonData)
return
def dialog_yesno(self, heading, line1, line2="", line3="", nolabel="No", yeslabel="Si", autoclose=""):
text = line1
if line2: text += "\n" + line2
if line3: text += "\n" + line3
text = self.kodi_labels_to_html(text)
heading = self.kodi_labels_to_html(heading)
JsonData = {}
JsonData["action"] = "AlertYesNo"
JsonData["data"] = {}
JsonData["data"]["title"] = heading
JsonData["data"]["text"] = text
ID = self.send_message(JsonData)
response = self.get_data(ID)
return response
def dialog_select(self, heading, list):
JsonData = {}
heading = self.kodi_labels_to_html(heading)
JsonData["action"] = "List"
JsonData["data"] = {}
JsonData["data"]["title"] = heading
JsonData["data"]["list"] = []
for Elemento in list:
JsonData["data"]["list"].append(self.kodi_labels_to_html(Elemento))
ID = self.send_message(JsonData)
response = self.get_data(ID)
return response
def dialog_progress(self, heading, line1, line2="", line3=""):
class Dialog(object):
def __init__(self, heading, line1, line2, line3, platformtools):
self.platformtools = platformtools
self.closed = False
self.heading = self.platformtools.kodi_labels_to_html(heading)
text = line1
if line2: text += "\n" + line2
if line3: text += "\n" + line3
text = self.platformtools.kodi_labels_to_html(text)
JsonData = {}
JsonData["action"] = "Progress"
JsonData["data"] = {}
JsonData["data"]["title"] = heading
JsonData["data"]["text"] = text
JsonData["data"]["percent"] = 0
ID = self.platformtools.send_message(JsonData)
self.platformtools.get_data(ID)
def iscanceled(self):
JsonData = {}
JsonData["action"] = "ProgressIsCanceled"
JsonData["data"] = {}
ID = self.platformtools.send_message(JsonData)
response = self.platformtools.get_data(ID)
return response
def update(self, percent, line1, line2="", line3=""):
text = line1
if line2: text += "\n" + line2
if line3: text += "\n" + line3
text = self.platformtools.kodi_labels_to_html(text)
JsonData = {}
JsonData["action"] = "ProgressUpdate"
JsonData["data"] = {}
JsonData["data"]["title"] = self.heading
JsonData["data"]["text"] = text
JsonData["data"]["percent"] = percent
self.platformtools.send_message(JsonData)
def close(self):
JsonData = {}
JsonData["action"] = "ProgressClose"
JsonData["data"] = {}
ID = self.platformtools.send_message(JsonData)
self.platformtools.get_data(ID)
self.closed = True
return Dialog(heading, line1, line2, line3, self)
def dialog_progress_bg(self, heading, message=""):
class Dialog(object):
def __init__(self, heading, message, platformtools):
self.platformtools = platformtools
self.closed = False
self.heading = self.platformtools.kodi_labels_to_html(heading)
message = self.platformtools.kodi_labels_to_html(message)
JsonData = {}
JsonData["action"] = "ProgressBG"
JsonData["data"] = {}
JsonData["data"]["title"] = heading
JsonData["data"]["text"] = message
JsonData["data"]["percent"] = 0
ID = self.platformtools.send_message(JsonData)
self.platformtools.get_data(ID)
def isFinished(self):
return not self.closed
def update(self, percent=0, heading="", message=""):
JsonData = {}
JsonData["action"] = "ProgressBGUpdate"
JsonData["data"] = {}
JsonData["data"]["title"] = self.platformtools.kodi_labels_to_html(heading)
JsonData["data"]["text"] = self.platformtools.kodi_labels_to_html(message)
JsonData["data"]["percent"] = percent
self.platformtools.send_message(JsonData)
def close(self):
JsonData = {}
JsonData["action"] = "ProgressBGClose"
JsonData["data"] = {}
ID = self.platformtools.send_message(JsonData)
self.platformtools.get_data(ID)
self.closed = True
return Dialog(heading, message, self)
def dialog_input(self, default="", heading="", hidden=False):
JsonData = {}
JsonData["action"] = "Keyboard"
JsonData["data"] = {}
JsonData["data"]["title"] = self.kodi_labels_to_html(heading)
JsonData["data"]["text"] = default
JsonData["data"]["password"] = hidden
ID = self.send_message(JsonData)
response = self.get_data(ID)
return response
def dialog_numeric(self, type, heading, default=""):
return self.dialog_input("", heading, False)
def itemlist_refresh(self):
JsonData = {}
JsonData["action"] = "Refresh"
JsonData["data"] = {}
ID = self.send_message(JsonData)
self.get_data(ID)
def itemlist_update(self, item):
JsonData = {}
JsonData["action"] = "Update"
JsonData["data"] = {}
JsonData["data"]["url"] = item.tourl()
ID = self.send_message(JsonData)
self.get_data(ID)
def is_playing(self):
JsonData = {}
JsonData["action"] = "isPlaying"
JsonData["data"] = {}
ID = self.send_message(JsonData)
response = self.get_data(ID)
return response
def play_video(self, item):
if item.contentTitle:
title = item.contentTitle
elif item.fulltitle:
title = item.fulltitle
else:
title = item.title
if item.contentPlot:
plot = item.contentPlot
else:
plot = item.plot
if item.server == "torrent":
self.play_torrent(item)
else:
JsonData = {}
JsonData["action"] = "Play"
JsonData["data"] = {}
JsonData["data"]["title"] = title
JsonData["data"]["plot"] = plot
JsonData["data"]["video_url"] = item.video_url
JsonData["data"]["url"] = item.url
JsonData["data"]["host"] = self.controller.host
ID = self.send_message(JsonData)
self.get_data(ID)
def play_torrent(self, item):
import time
import os
played = False
# Importamos el cliente
from btserver import Client
# Iniciamos el cliente:
c = Client(url=item.url, is_playing_fnc=self.is_playing, wait_time=None, timeout=5,
temp_path=os.path.join(config.get_data_path(), "torrent"))
# Mostramos el progreso
progreso = self.dialog_progress("Alfa - Torrent", "Iniciando...")
# Mientras el progreso no sea cancelado ni el cliente cerrado
while not progreso.iscanceled() and not c.closed:
try:
# Obtenemos el estado del torrent
s = c.status
# Montamos las tres lineas con la info del torrent
txt = '%.2f%% de %.1fMB %s | %.1f kB/s' % \
(s.progress_file, s.file_size, s.str_state, s._download_rate)
txt2 = 'S: %d(%d) P: %d(%d) | DHT:%s (%d) | Trakers: %d' % \
(
s.num_seeds, s.num_complete, s.num_peers, s.num_incomplete, s.dht_state, s.dht_nodes,
s.trackers)
txt3 = 'Origen Peers TRK: %d DHT: %d PEX: %d LSD %d ' % \
(s.trk_peers, s.dht_peers, s.pex_peers, s.lsd_peers)
progreso.update(s.buffer, txt, txt2, txt3)
time.sleep(1)
# Si el buffer se ha llenado y la reproduccion no ha sido iniciada, se inicia
if s.buffer == 100 and not played:
# Cerramos el progreso
progreso.close()
# Obtenemos el playlist del torrent
item.video_url = c.get_play_list()
item.server = "directo"
self.play_video(item)
# Marcamos como reproducido para que no se vuelva a iniciar
played = True
# Y esperamos a que el reproductor se cierre
while self.is_playing():
time.sleep(1)
# Cuando este cerrado, Volvemos a mostrar el dialogo
progreso = self.dialog_progress("Alfa - Torrent", "Iniciando...")
except:
import traceback
logger.info(traceback.format_exc())
break
progreso.update(100, "Terminando y eliminando datos", " ", " ")
# Detenemos el cliente
if not c.closed:
c.stop()
# Y cerramos el progreso
progreso.close()
return
def open_settings(self, items):
from platformcode import config
JsonData = {}
JsonData["action"] = "OpenConfig"
JsonData["data"] = {}
JsonData["data"]["title"] = "Opciones"
JsonData["data"]["items"] = []
for item in items:
if item.get('option') == 'hidden':
item['hidden'] = True
for key in item:
if key in ["lvalues", "label", "category"]:
try:
ops = item[key].split("|")
for x, op in enumerate(ops):
ops[x] = config.get_localized_string(int(ops[x]))
item[key] = "|".join(ops)
except:
pass
JsonData["data"]["items"].append(item)
ID = self.send_message(JsonData)
response = self.get_data(ID)
if response:
from platformcode import config
config.set_settings(response)
JsonData = {}
JsonData["action"] = "HideLoading"
JsonData["data"] = {}
self.send_message(JsonData)
def show_channel_settings(self, list_controls=None, dict_values=None, caption="", callback=None, item=None,
custom_button=None, channelpath=None):
from platformcode import config
from core import channeltools
from core import servertools
import inspect
if not os.path.isdir(os.path.join(config.get_data_path(), "settings_channels")):
os.mkdir(os.path.join(config.get_data_path(), "settings_channels"))
title = caption
if type(custom_button) == dict:
custom_button = {"label": custom_button.get("label", ""),
"function": custom_button.get("function", ""),
"visible": bool(custom_button.get("visible", True)),
"close": bool(custom_button.get("close", False))}
else:
custom_button = None
# Obtenemos el canal desde donde se ha echo la llamada y cargamos los settings disponibles para ese canal
if not channelpath:
channelpath = inspect.currentframe().f_back.f_back.f_code.co_filename
channelname = os.path.basename(channelpath).replace(".py", "")
ch_type = os.path.basename(os.path.dirname(channelpath))
# Si no tenemos list_controls, hay que sacarlos del json del canal
if not list_controls:
# Si la ruta del canal esta en la carpeta "channels", obtenemos los controles y valores mediante chaneltools
if os.path.join(config.get_runtime_path(), "channels") in channelpath:
# La llamada se hace desde un canal
list_controls, default_values = channeltools.get_channel_controls_settings(channelname)
kwargs = {"channel": channelname}
# Si la ruta del canal esta en la carpeta "servers", obtenemos los controles y valores mediante servertools
elif os.path.join(config.get_runtime_path(), "servers") in channelpath:
# La llamada se hace desde un server
list_controls, default_values = servertools.get_server_controls_settings(channelname)
kwargs = {"server": channelname}
# En caso contrario salimos
else:
return None
# Si no se pasan dict_values, creamos un dict en blanco
if dict_values == None:
dict_values = {}
# Ponemos el titulo
if caption == "":
caption = str(config.get_localized_string(30100)) + " -- " + channelname.capitalize()
elif caption.startswith('@') and unicode(caption[1:]).isnumeric():
caption = config.get_localized_string(int(caption[1:]))
JsonData = {}
JsonData["action"] = "OpenConfig"
JsonData["data"] = {}
JsonData["data"]["title"] = self.kodi_labels_to_html(caption)
JsonData["data"]["custom_button"] = custom_button
JsonData["data"]["items"] = []
# Añadir controles
for c in list_controls:
if not "default" in c: c["default"] = ""
if not "color" in c: c["color"] = "auto"
if not "label" in c: continue
# Obtenemos el valor
if not c["id"] in dict_values:
if not callback:
c["value"] = config.get_setting(c["id"], **kwargs)
else:
c["value"] = c["default"]
dict_values[c["id"]] = c["value"]
else:
c["value"] = dict_values[c["id"]]
# Translation
if c['label'].startswith('@') and unicode(c['label'][1:]).isnumeric():
c['label'] = str(config.get_localized_string(c['label'][1:]))
if c["label"].endswith(":"): c["label"] = c["label"][:-1]
if c['type'] == 'list':
lvalues = []
for li in c['lvalues']:
if li.startswith('@') and unicode(li[1:]).isnumeric():
lvalues.append(str(config.get_localized_string(li[1:])))
else:
lvalues.append(li)
c['lvalues'] = lvalues
c["label"] = self.kodi_labels_to_html(c["label"])
JsonData["data"]["items"].append(c)
ID = self.send_message(JsonData)
close = False
while True:
data = self.get_data(ID)
if type(data) == dict:
JsonData["action"] = "HideLoading"
JsonData["data"] = {}
self.send_message(JsonData)
for v in data:
if data[v] == "true": data[v] = True
if data[v] == "false": data[v] = False
if unicode(data[v]).isnumeric(): data[v] = int(data[v])
if callback and '.' in callback:
package, callback = callback.rsplit('.', 1)
else:
package = '%s.%s' % (ch_type, channelname)
cb_channel = None
try:
cb_channel = __import__(package, None, None, [package])
except ImportError:
logger.error('Imposible importar %s' % package)
if callback:
# Si existe una funcion callback la invocamos ...
return getattr(cb_channel, callback)(item, data)
else:
# si no, probamos si en el canal existe una funcion 'cb_validate_config' ...
try:
return getattr(cb_channel, 'cb_validate_config')(item, data)
except AttributeError:
# ... si tampoco existe 'cb_validate_config'...
for v in data:
config.set_setting(v, data[v], **kwargs)
elif data == "custom_button":
if '.' in callback:
package, callback = callback.rsplit('.', 1)
else:
package = '%s.%s' % (ch_type, channelname)
try:
cb_channel = __import__(package, None, None, [package])
except ImportError:
logger.error('Imposible importar %s' % package)
else:
return_value = getattr(cb_channel, custom_button['function'])(item, dict_values)
if custom_button["close"] == True:
return return_value
else:
JsonData["action"] = "custom_button"
JsonData["data"] = {}
JsonData["data"]["values"] = dict_values
JsonData["data"]["return_value"] = return_value
ID = self.send_message(JsonData)
elif data == False:
return None
def show_video_info(self, data, caption="", item=None, scraper=Tmdb):
from platformcode import html_info_window
return html_info_window.InfoWindow().start(self, data, caption, item, scraper)
def show_recaptcha(self, key, url):
from platformcode import html_recaptcha
return html_recaptcha.recaptcha().start(self, key, url)
def kodi_labels_to_html(self, text):
text = re.sub(r"(?:\[I\])(.*?)(?:\[/I\])", r"<i>\1</i>", text)
text = re.sub(r"(?:\[B\])(.*?)(?:\[/B\])", r"<b>\1</b>", text)
text = re.sub(r"(?:\[COLOR (?:0x)?([0-f]{2})([0-f]{2})([0-f]{2})([0-f]{2})\])(.*?)(?:\[/COLOR\])",
lambda m: "<span style='color: rgba(%s,%s,%s,%s)'>%s</span>" % (
int(m.group(2), 16), int(m.group(3), 16), int(m.group(4), 16), int(m.group(1), 16) / 255.0,
m.group(5)), text)
text = re.sub(r"(?:\[COLOR (?:0x)?([0-f]{2})([0-f]{2})([0-f]{2})\])(.*?)(?:\[/COLOR\])",
r"<span style='color: #\1\2\3'>\4</span>", text)
text = re.sub(r"(?:\[COLOR (?:0x)?([a-z|A-Z]+)\])(.*?)(?:\[/COLOR\])", r"<span style='color: \1'>\2</span>",
text)
return text

View File

@@ -0,0 +1,188 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------
# Controlador para RSS
# ------------------------------------------------------------
import json
import random
import re
import threading
import time
from controller import Controller
from controller import Platformtools
from core.item import Item
class jsonserver(Controller):
pattern = re.compile("^/json")
data = {}
def __init__(self, handler=None):
super(jsonserver, self).__init__(handler)
self.platformtools = platformtools(self)
def extract_item(self, path):
if path == "/json" or path == "/json/":
item = Item(channel="channelselector", action="mainlist")
else:
item = Item().fromurl(path.replace("/json/", ""))
return item
def run(self, path):
item = self.extract_item(path)
from platformcode import launcher
launcher.run(item)
def set_data(self, data):
self.data = data
def get_data(self, id):
if "id" in self.data and self.data["id"] == id:
data = self.data["result"]
else:
data = None
return data
def send_data(self, data, headers={}, response=200):
headers.setdefault("content-type", "application/json")
headers.setdefault("connection", "close")
self.handler.send_response(response)
for header in headers:
self.handler.send_header(header, headers[header])
self.handler.end_headers()
self.handler.wfile.write(data)
class platformtools(Platformtools):
def __init__(self, controller):
self.controller = controller
self.handler = controller.handler
def render_items(self, itemlist, parentitem):
JSONResponse = {}
JSONResponse["title"] = parentitem.title
JSONResponse["date"] = time.strftime("%x")
JSONResponse["time"] = time.strftime("%X")
JSONResponse["count"] = len(itemlist)
JSONResponse["list"] = []
for item in itemlist:
JSONItem = {}
JSONItem["title"] = item.title
JSONItem["url"] = "http://" + self.controller.host + "/json/" + item.tourl()
if item.thumbnail: JSONItem["thumbnail"] = item.thumbnail
if item.plot: JSONItem["plot"] = item.plot
JSONResponse["list"].append(JSONItem)
self.controller.send_data(json.dumps(JSONResponse, indent=4, sort_keys=True))
def dialog_select(self, heading, list):
ID = "%032x" % (random.getrandbits(128))
response = '<?xml version="1.0" encoding="UTF-8" ?>\n'
response += '<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">\n'
response += '<channel>\n'
response += '<link>/rss</link>\n'
response += '<title>' + heading + '</title>\n'
for option in list:
response += '<item>\n'
response += '<title>' + option + '</title>\n'
response += '<image>%s</image>\n'
response += '<link>http://' + self.controller.host + '/data/' + threading.current_thread().name + '/' + ID + '/' + str(
list.index(option)) + '</link>\n'
response += '</item>\n\n'
response += '</channel>\n'
response += '</rss>\n'
self.controller.send_data(response)
self.handler.server.shutdown_request(self.handler.request)
while not self.controller.get_data(ID):
continue
return int(self.controller.get_data(ID))
def dialog_ok(self, heading, line1, line2="", line3=""):
text = line1
if line2: text += "\n" + line2
if line3: text += "\n" + line3
ID = "%032x" % (random.getrandbits(128))
response = '<?xml version="1.0" encoding="UTF-8" ?>\n'
response += '<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">\n'
response += '<channel>\n'
response += '<link>/rss</link>\n'
response += '<title>' + heading + '</title>\n'
response += '<item>\n'
response += '<title>' + text + '</title>\n'
response += '<image>%s</image>\n'
response += '<link></link>\n'
response += '</item>\n\n'
response += '<item>\n'
response += '<title>Si</title>\n'
response += '<image>%s</image>\n'
response += '<link>http://' + self.controller.host + '/data/' + threading.current_thread().name + '/' + ID + '/1</link>\n'
response += '</item>\n\n'
response += '<item>\n'
response += '</channel>\n'
response += '</rss>\n'
self.controller.send_data(response)
self.handler.server.shutdown_request(self.handler.request)
while not self.controller.get_data(ID):
continue
def dialog_yesno(self, heading, line1, line2="", line3=""):
text = line1
if line2: text += "\n" + line2
if line3: text += "\n" + line3
ID = "%032x" % (random.getrandbits(128))
response = '<?xml version="1.0" encoding="UTF-8" ?>\n'
response += '<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">\n'
response += '<channel>\n'
response += '<link>/rss</link>\n'
response += '<title>' + heading + '</title>\n'
response += '<item>\n'
response += '<title>' + text + '</title>\n'
response += '<image>%s</image>\n'
response += '<link></link>\n'
response += '</item>\n\n'
response += '<item>\n'
response += '<title>Si</title>\n'
response += '<image>%s</image>\n'
response += '<link>http://' + self.controller.host + '/data/' + threading.current_thread().name + '/' + ID + '/1</link>\n'
response += '</item>\n\n'
response += '<item>\n'
response += '<title>No</title>\n'
response += '<image>%s</image>\n'
response += '<link>http://' + self.controller.host + '/data/' + threading.current_thread().name + '/' + ID + '/0</link>\n'
response += '</item>\n\n'
response += '</channel>\n'
response += '</rss>\n'
self.controller.send_data(response)
self.handler.server.shutdown_request(self.handler.request)
while not self.controller.get_data(ID):
continue
return bool(int(self.controller.get_data(ID)))
def dialog_notification(self, heading, message, icon=0, time=5000, sound=True):
# No disponible por ahora, muestra un dialog_ok
self.dialog_ok(heading, message)
def play_video(self, item):
response = '<?xml version="1.0" encoding="UTF-8" ?>\n'
response += '<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">\n'
response += '<channel>\n'
response += '<link>/rss</link>\n'
response += '<title>' + item.title + '</title>\n'
response += '<item>\n'
response += '<title>' + item.title + '</title>\n'
response += '<image>%s</image>\n'
response += '<link>' + item.video_url + '</link>\n'
response += '</item>\n\n'
response += '</channel>\n'
response += '</rss>\n'
self.controller.send_data(response)

View File

@@ -0,0 +1,58 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------
# Controlador para acceso indirecto a ficheros remotos
# ------------------------------------------------------------
import base64
import re
import urllib
import urllib2
from controller import Controller
class proxy(Controller):
pattern = re.compile("^/proxy/")
def run(self, path):
url = path.replace("/proxy/", "").split("/")[0]
url = base64.b64decode(urllib.unquote_plus(url))
request_headers = self.handler.headers.dict
if "host" in request_headers: request_headers.pop("host")
if "referer" in request_headers: request_headers.pop("referer")
if "cookie" in request_headers: request_headers.pop("cookie")
if "|" in url:
url_headers = dict(
[[header.split("=")[0].lower(), urllib.unquote_plus("=".join(header.split("=")[1:]))] for header in
url.split("|")[1].split("&")])
url = url.split("|")[0]
request_headers.update(url_headers)
req = urllib2.Request(url, headers=request_headers)
opener = urllib2.build_opener(urllib2.HTTPHandler(debuglevel=0))
try:
h = opener.open(req)
except urllib2.HTTPError, e:
h = e
except:
self.handler.send_response("503")
self.handler.wfile.close()
h.close()
self.handler.send_response(h.getcode())
for header in h.info():
self.handler.send_header(header, h.info()[header])
self.handler.end_headers()
blocksize = 1024
bloqueleido = h.read(blocksize)
while len(bloqueleido) > 0:
self.handler.wfile.write(bloqueleido)
bloqueleido = h.read(blocksize)
self.handler.wfile.close()
h.close()

View File

@@ -0,0 +1,199 @@
# -*- coding: utf-8 -*-
# ------------------------------------------------------------
# Controlador para RSS
# ------------------------------------------------------------
import random
import re
import threading
from controller import Controller
from controller import Platformtools
from core.item import Item
class rss(Controller):
pattern = re.compile("^/rss")
data = {}
def __init__(self, handler=None, ):
super(rss, self).__init__(handler)
self.platformtools = platformtools(self)
def extract_item(self, path):
if path == "/rss" or path == "/rss/":
item = Item(channel="channelselector", action="mainlist")
else:
item = Item().fromurl(path.replace("/rss/", ""))
return item
def run(self, path):
item = self.extract_item(path)
from platformcode import launcher
launcher.run(item)
def set_data(self, data):
self.data = data
def get_data(self, id):
if "id" in self.data and self.data["id"] == id:
data = self.data["result"]
else:
data = None
return data
def send_data(self, data, headers={}, response=200):
headers.setdefault("content-type", "application/rss+xml")
headers.setdefault("connection", "close")
self.handler.send_response(response)
for header in headers:
self.handler.send_header(header, headers[header])
self.handler.end_headers()
self.handler.wfile.write(data)
class platformtools(Platformtools):
def __init__(self, controller):
self.controller = controller
self.handler = controller.handler
def create_rss(self, itemlist):
resp = '<?xml version="1.0" encoding="UTF-8" ?>\n'
resp += '<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">\n'
resp += '<channel>\n'
resp += '<link>http://' + self.controller.host + '/rss</link>\n'
resp += '<title>Menú Principal</title>\n'
for item in itemlist:
resp += '<item>\n'
resp += '<title>' + item.title + '</title>\n'
resp += '<image>' + item.thumbnail + '</image>\n'
resp += '<link>' + self.controller.host + '/rss/' + item.tourl() + '</link>\n'
resp += '</item>\n\n'
resp += '</channel>\n'
resp += '</rss>\n'
return resp
def render_items(self, itemlist, parentitem):
new_itemlist = []
for item in itemlist:
# if item.action == "search": continue
# if item.channel=="search": continue
# if item.channel=="setting": continue
# if item.channel=="help": continue
new_itemlist.append(item)
response = self.create_rss(new_itemlist)
self.controller.send_data(response)
def dialog_select(self, heading, list):
ID = "%032x" % (random.getrandbits(128))
response = '<?xml version="1.0" encoding="UTF-8" ?>\n'
response += '<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">\n'
response += '<channel>\n'
response += '<link>/rss</link>\n'
response += '<title>' + heading + '</title>\n'
for option in list:
response += '<item>\n'
response += '<title>' + option + '</title>\n'
response += '<image>%s</image>\n'
response += '<link>http://' + self.controller.host + '/data/' + threading.current_thread().name + '/' + ID + '/' + str(
list.index(option)) + '</link>\n'
response += '</item>\n\n'
response += '</channel>\n'
response += '</rss>\n'
self.controller.send_data(response)
self.handler.server.shutdown_request(self.handler.request)
while not self.controller.get_data(ID):
continue
return int(self.controller.get_data(ID))
def dialog_ok(self, heading, line1, line2="", line3=""):
text = line1
if line2: text += "\n" + line2
if line3: text += "\n" + line3
ID = "%032x" % (random.getrandbits(128))
response = '<?xml version="1.0" encoding="UTF-8" ?>\n'
response += '<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">\n'
response += '<channel>\n'
response += '<link>/rss</link>\n'
response += '<title>' + heading + '</title>\n'
response += '<item>\n'
response += '<title>' + text + '</title>\n'
response += '<image>%s</image>\n'
response += '<link></link>\n'
response += '</item>\n\n'
response += '<item>\n'
response += '<title>Si</title>\n'
response += '<image>%s</image>\n'
response += '<link>http://' + self.controller.host + '/data/' + threading.current_thread().name + '/' + ID + '/1</link>\n'
response += '</item>\n\n'
response += '<item>\n'
response += '</channel>\n'
response += '</rss>\n'
self.controller.send_data(response)
self.handler.server.shutdown_request(self.handler.request)
while not self.controller.get_data(ID):
continue
def dialog_yesno(self, heading, line1, line2="", line3=""):
text = line1
if line2: text += "\n" + line2
if line3: text += "\n" + line3
ID = "%032x" % (random.getrandbits(128))
response = '<?xml version="1.0" encoding="UTF-8" ?>\n'
response += '<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">\n'
response += '<channel>\n'
response += '<link>/rss</link>\n'
response += '<title>' + heading + '</title>\n'
response += '<item>\n'
response += '<title>' + text + '</title>\n'
response += '<image>%s</image>\n'
response += '<link></link>\n'
response += '</item>\n\n'
response += '<item>\n'
response += '<title>Si</title>\n'
response += '<image>%s</image>\n'
response += '<link>http://' + self.controller.host + '/data/' + threading.current_thread().name + '/' + ID + '/1</link>\n'
response += '</item>\n\n'
response += '<item>\n'
response += '<title>No</title>\n'
response += '<image>%s</image>\n'
response += '<link>http://' + self.controller.host + '/data/' + threading.current_thread().name + '/' + ID + '/0</link>\n'
response += '</item>\n\n'
response += '</channel>\n'
response += '</rss>\n'
self.controller.send_data(response)
self.handler.server.shutdown_request(self.handler.request)
while not self.controller.get_data(ID):
continue
return bool(int(self.controller.get_data(ID)))
def dialog_notification(self, heading, message, icon=0, time=5000, sound=True):
# No disponible por ahora, muestra un dialog_ok
self.dialog_ok(heading, message)
def play_video(self, item):
response = '<?xml version="1.0" encoding="UTF-8" ?>\n'
response += '<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">\n'
response += '<channel>\n'
response += '<link>/rss</link>\n'
response += '<title>' + item.title + '</title>\n'
response += '<item>\n'
response += '<title>' + item.title + '</title>\n'
response += '<image>%s</image>\n'
response += '<link>' + item.video_url + '</link>\n'
response += '</item>\n\n'
response += '</channel>\n'
response += '</rss>\n'
self.controller.send_data(response)