- Menu contestuale in finestra server - Piccoli fix deltabit e uqloads - Piccolo fix gestione viste - Fix gestione salva link
511 lines
19 KiB
Python
511 lines
19 KiB
Python
# -*- coding: utf-8 -*-
|
||
# --------------------------------------------------------------------------------
|
||
# Item is the object we use for representing data
|
||
# --------------------------------------------------------------------------------
|
||
|
||
#from builtins import str
|
||
from future.builtins import object
|
||
import sys
|
||
PY3 = False
|
||
if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int
|
||
|
||
if PY3:
|
||
#from future import standard_library
|
||
#standard_library.install_aliases()
|
||
import urllib.parse as urllib # It is very slow in PY2. In PY3 it is native
|
||
else:
|
||
import urllib # We use the native of PY2 which is faster
|
||
from core.scrapertools import unescape
|
||
|
||
import base64
|
||
import copy
|
||
|
||
from core import jsontools as json
|
||
|
||
|
||
class InfoLabels(dict):
|
||
def __str__(self):
|
||
return self.tostring(separador=',\r\t')
|
||
|
||
def __setitem__(self, name, value):
|
||
if name in ["season", "episode"]:
|
||
# we force int () in season and episode
|
||
try:
|
||
super(InfoLabels, self).__setitem__(name, int(value))
|
||
except:
|
||
pass
|
||
|
||
elif name in ['IMDBNumber', 'imdb_id']:
|
||
# For compatibility we have to save the value in the three fields
|
||
super(InfoLabels, self).__setitem__('IMDBNumber', str(value))
|
||
# super(InfoLabels, self).__setitem__('code', value)
|
||
super(InfoLabels, self).__setitem__('imdb_id', str(value))
|
||
|
||
elif name == "mediatype" and value not in ["list", "movie", "tvshow", "season", "episode", "music", "undefined"]:
|
||
super(InfoLabels, self).__setitem__('mediatype', 'list')
|
||
|
||
elif name in ['tmdb_id', 'tvdb_id', 'noscrap_id']:
|
||
super(InfoLabels, self).__setitem__(name, str(value))
|
||
else:
|
||
super(InfoLabels, self).__setitem__(name, value)
|
||
|
||
# Python 2.4
|
||
def __getitem__(self, key):
|
||
try:
|
||
return super(InfoLabels, self).__getitem__(key)
|
||
except:
|
||
return self.__missing__(key)
|
||
|
||
def __missing__(self, key):
|
||
"""
|
||
Valores por defecto en caso de que la clave solicitada no exista.
|
||
El parametro 'default' en la funcion obj_infoLabels.get(key,default) tiene preferencia sobre los aqui definidos.
|
||
"""
|
||
if key in ['rating']:
|
||
# Key example q returns a str formatted as float by default
|
||
return '0.0'
|
||
|
||
elif key == 'code':
|
||
code = []
|
||
# Add imdb_id to the code list
|
||
if 'imdb_id' in list(super(InfoLabels, self).keys()) and super(InfoLabels, self).__getitem__('imdb_id'):
|
||
code.append(super(InfoLabels, self).__getitem__('imdb_id'))
|
||
|
||
# Complete with the rest of the codes
|
||
for scr in ['tmdb_id', 'tvdb_id', 'noscrap_id']:
|
||
if scr in list(super(InfoLabels, self).keys()) and super(InfoLabels, self).__getitem__(scr):
|
||
value = "%s%s" % (scr[:-2], super(InfoLabels, self).__getitem__(scr))
|
||
code.append(value)
|
||
|
||
# Option to add a code of the random type
|
||
if not code:
|
||
import time
|
||
value = time.strftime("%Y%m%d%H%M%S", time.gmtime())
|
||
code.append(value)
|
||
super(InfoLabels, self).__setitem__('noscrap_id', value)
|
||
|
||
return code
|
||
|
||
elif key == 'mediatype':
|
||
# "list", "movie", "tvshow", "season", "episode"
|
||
if 'tvshowtitle' in list(super(InfoLabels, self).keys()) \
|
||
and super(InfoLabels, self).__getitem__('tvshowtitle') != "":
|
||
if 'episode' in list(super(InfoLabels, self).keys()) and super(InfoLabels, self).__getitem__('episode') != "":
|
||
return 'episode'
|
||
|
||
if 'episodeName' in list(super(InfoLabels, self).keys()) \
|
||
and super(InfoLabels, self).__getitem__('episodeName') != "":
|
||
return 'episode'
|
||
|
||
if 'season' in list(super(InfoLabels, self).keys()) and super(InfoLabels, self).__getitem__('season') != "":
|
||
return 'season'
|
||
else:
|
||
return 'tvshow'
|
||
|
||
elif 'title' in list(super(InfoLabels, self).keys()) and super(InfoLabels, self).__getitem__('title') != "":
|
||
return 'movie'
|
||
|
||
else:
|
||
return 'list'
|
||
|
||
else:
|
||
# The rest of the keys return empty strings by default
|
||
return ""
|
||
|
||
def tostring(self, separador=', '):
|
||
ls = []
|
||
dic = dict(list(super(InfoLabels, self).items()))
|
||
|
||
for i in sorted(dic.items()):
|
||
i_str = str(i)[1:-1]
|
||
if isinstance(i[0], str):
|
||
old = i[0] + "',"
|
||
new = i[0] + "':"
|
||
else:
|
||
old = str(i[0]) + ","
|
||
new = str(i[0]) + ":"
|
||
ls.append(i_str.replace(old, new, 1))
|
||
|
||
return "{%s}" % separador.join(ls)
|
||
|
||
|
||
class Item(object):
|
||
def __init__(self, **kwargs):
|
||
"""
|
||
Item initialization
|
||
"""
|
||
|
||
# Creamos el atributo infoLabels
|
||
self.__dict__["infoLabels"] = InfoLabels()
|
||
if "infoLabels" in kwargs:
|
||
if isinstance(kwargs["infoLabels"], dict):
|
||
self.__dict__["infoLabels"].update(kwargs["infoLabels"])
|
||
del kwargs["infoLabels"]
|
||
|
||
if "parentContent" in kwargs:
|
||
self.set_parent_content(kwargs["parentContent"])
|
||
del kwargs["parentContent"]
|
||
|
||
kw = copy.copy(kwargs)
|
||
for k in kw:
|
||
if k in ["contentTitle", "contentPlot", "contentSerieName", "show", "contentType", "contentEpisodeTitle",
|
||
"contentSeason", "contentEpisodeNumber", "contentThumbnail", "plot", "duration", "contentQuality",
|
||
"quality", "year"]:
|
||
self.__setattr__(k, kw[k])
|
||
del kwargs[k]
|
||
|
||
self.__dict__.update(kwargs)
|
||
self.__dict__ = self.toutf8(self.__dict__)
|
||
|
||
def __contains__(self, m):
|
||
"""
|
||
Check if an attribute exists in the item
|
||
"""
|
||
return m in self.__dict__
|
||
|
||
def __setattr__(self, name, value):
|
||
"""
|
||
Function called when modifying any attribute of the item, modifies some attributes based on the modified data.
|
||
"""
|
||
if PY3: name = self.toutf8(name)
|
||
value = self.toutf8(value)
|
||
if name == "__dict__":
|
||
for key in value:
|
||
self.__setattr__(key, value[key])
|
||
return
|
||
|
||
# We decode the HTML entities
|
||
if name in ["title", "plot", "fulltitle", "contentPlot", "contentTitle"]:
|
||
value = self.decode_html(value)
|
||
|
||
# By modifying any of these attributes content...
|
||
if name in ["contentTitle", "contentPlot", "plot", "contentSerieName", "contentType", "contentEpisodeTitle",
|
||
"contentSeason", "contentEpisodeNumber", "contentThumbnail", "show", "contentQuality", "quality", "year"]:
|
||
# ...and update infoLables
|
||
if name == "contentTitle":
|
||
self.__dict__["infoLabels"]["title"] = value
|
||
elif name == "contentPlot" or name == "plot":
|
||
self.__dict__["infoLabels"]["plot"] = value
|
||
elif name == "contentSerieName" or name == "show":
|
||
self.__dict__["infoLabels"]["tvshowtitle"] = value
|
||
elif name == "contentType":
|
||
self.__dict__["infoLabels"]["mediatype"] = value
|
||
elif name == "contentEpisodeTitle":
|
||
self.__dict__["infoLabels"]["episodeName"] = value
|
||
elif name == "contentSeason":
|
||
self.__dict__["infoLabels"]["season"] = value
|
||
elif name == "contentEpisodeNumber":
|
||
self.__dict__["infoLabels"]["episode"] = value
|
||
elif name == "contentThumbnail":
|
||
self.__dict__["infoLabels"]["thumbnail"] = value
|
||
elif name == "contentQuality" or name == "quality":
|
||
self.__dict__["infoLabels"]["quality"] = value
|
||
elif name == "year":
|
||
self.__dict__["infoLabels"]["year"] = value
|
||
|
||
elif name == "duration":
|
||
# String q represents the duration of the video in seconds
|
||
self.__dict__["infoLabels"]["duration"] = str(value)
|
||
|
||
elif name == "viewcontent" and value not in ["files", "movies", "tvshows", "seasons", "episodes"]:
|
||
super(Item, self).__setattr__("viewcontent", "files")
|
||
|
||
# When assigning a value to infoLables
|
||
elif name == "infoLabels":
|
||
if isinstance(value, dict):
|
||
value_defaultdict = InfoLabels(value)
|
||
self.__dict__["infoLabels"] = value_defaultdict
|
||
|
||
else:
|
||
super(Item, self).__setattr__(name, value)
|
||
|
||
def __getattr__(self, name):
|
||
"""
|
||
Returns the default values in case the requested attribute does not exist in the item
|
||
"""
|
||
if name.startswith("__"):
|
||
return super(Item, self).__getattribute__(name)
|
||
|
||
# default value for folder
|
||
if name == "folder":
|
||
return True
|
||
|
||
# default value for contentChannel
|
||
elif name == "contentChannel":
|
||
return "list"
|
||
|
||
# default value for viewcontent
|
||
elif name == "viewcontent":
|
||
# we try to fix it according to the type of content...
|
||
if self.__dict__["infoLabels"]["mediatype"] == 'movie':
|
||
viewcontent = 'movies'
|
||
elif self.__dict__["infoLabels"]["mediatype"] in ["tvshow", "season", "episode"]:
|
||
viewcontent = "episodes"
|
||
else:
|
||
viewcontent = "files"
|
||
|
||
self.__dict__["viewcontent"] = viewcontent
|
||
return viewcontent
|
||
|
||
# values saved in infoLabels
|
||
elif name in ["contentTitle", "contentPlot", "contentSerieName", "show", "contentType", "contentEpisodeTitle",
|
||
"contentSeason", "contentEpisodeNumber", "contentThumbnail", "plot", "duration",
|
||
"contentQuality", "quality"]:
|
||
if name == "contentTitle":
|
||
return self.__dict__["infoLabels"]["title"]
|
||
elif name == "contentPlot" or name == "plot":
|
||
return self.__dict__["infoLabels"]["plot"]
|
||
elif name == "contentSerieName" or name == "show":
|
||
return self.__dict__["infoLabels"]["tvshowtitle"]
|
||
elif name == "contentType":
|
||
ret = self.__dict__["infoLabels"]["mediatype"]
|
||
if ret == 'list' and self.__dict__.get("fulltitle", None): # backward compatibility
|
||
ret = 'movie'
|
||
self.__dict__["infoLabels"]["mediatype"] = ret
|
||
return ret
|
||
elif name == "contentEpisodeTitle":
|
||
return self.__dict__["infoLabels"]["episodeName"]
|
||
elif name == "contentSeason":
|
||
return self.__dict__["infoLabels"]["season"]
|
||
elif name == "contentEpisodeNumber":
|
||
return self.__dict__["infoLabels"]["episode"]
|
||
elif name == "contentThumbnail":
|
||
return self.__dict__["infoLabels"]["thumbnail"]
|
||
elif name == "contentQuality" or name == "quality":
|
||
return self.__dict__["infoLabels"]["quality"]
|
||
else:
|
||
return self.__dict__["infoLabels"][name]
|
||
|
||
# default value for all other attributes
|
||
else:
|
||
return ""
|
||
|
||
def __str__(self):
|
||
return '\r\t' + self.tostring('\r\t')
|
||
|
||
def __eq__(self, other):
|
||
if type(other) == Item:
|
||
return self.__dict__ == other.__dict__
|
||
else:
|
||
return False
|
||
|
||
def set_parent_content(self, parentContent):
|
||
"""
|
||
Fill the contentDetails fields with the information of the item "parent"
|
||
@param parentContent: item father
|
||
@type parentContent: item
|
||
"""
|
||
# Check that parentContent is an Item
|
||
if not type(parentContent) == type(self):
|
||
return
|
||
# Copy all the attributes that start with "content" and are declared and the infoLabels
|
||
for attr in parentContent.__dict__:
|
||
if attr.startswith("content") or attr == "infoLabels":
|
||
self.__setattr__(attr, parentContent.__dict__[attr])
|
||
|
||
def tostring(self, separator=", "):
|
||
"""
|
||
Generate a text string with the item's data for the log
|
||
Use: logger.info(item.tostring())
|
||
@param separator: string to be used as a separator
|
||
@type separator: str
|
||
'"""
|
||
dic = self.__dict__.copy()
|
||
|
||
# We add the content fields... if they have any value
|
||
for key in ["contentTitle", "contentPlot", "contentSerieName", "contentEpisodeTitle",
|
||
"contentSeason", "contentEpisodeNumber", "contentThumbnail"]:
|
||
value = self.__getattr__(key)
|
||
if value:
|
||
dic[key] = value
|
||
|
||
if 'mediatype' in self.__dict__["infoLabels"]:
|
||
dic["contentType"] = self.__dict__["infoLabels"]['mediatype']
|
||
|
||
ls = []
|
||
for var in sorted(dic):
|
||
if isinstance(dic[var], str):
|
||
valor = "'%s'" % dic[var]
|
||
elif isinstance(dic[var], InfoLabels):
|
||
if separator == '\r\t':
|
||
valor = dic[var].tostring(',\r\t\t')
|
||
else:
|
||
valor = dic[var].tostring()
|
||
elif PY3 and isinstance(dic[var], bytes):
|
||
valor = "'%s'" % dic[var].decode('utf-8')
|
||
else:
|
||
valor = str(dic[var])
|
||
|
||
if PY3 and isinstance(var, bytes):
|
||
var = var.decode('utf-8')
|
||
ls.append(var + "= " + valor)
|
||
|
||
return separator.join(ls)
|
||
|
||
def tourl(self):
|
||
"""
|
||
Generate a text string with the item data to create a url, to re-generate the Item use item.fromurl ().
|
||
|
||
Use: url = item.tourl()
|
||
"""
|
||
dump = json.dump(self.__dict__).encode("utf8")
|
||
# if empty dict
|
||
if not dump:
|
||
# set a str to avoid b64encode fails
|
||
dump = "".encode("utf8")
|
||
return str(urllib.quote(base64.b64encode(dump)))
|
||
|
||
def fromurl(self, url, silent=False):
|
||
"""
|
||
Generate an item from a text string. The string can be created by the tourl () function or have
|
||
the old format: plugin: //plugin.video.kod/? channel = ... (+ other parameters)
|
||
Use: item.fromurl("string")
|
||
|
||
@param url: url
|
||
@type url: str
|
||
"""
|
||
if "?" in url:
|
||
url = url.split("?")[1]
|
||
decoded = False
|
||
try:
|
||
str_item = base64.b64decode(urllib.unquote(url))
|
||
json_item = json.load(str_item, object_hook=self.toutf8, silent=silent)
|
||
if json_item is not None and len(json_item) > 0:
|
||
self.__dict__.update(json_item)
|
||
decoded = True
|
||
except:
|
||
pass
|
||
|
||
if not decoded:
|
||
url = urllib.unquote_plus(url)
|
||
dct = dict([[param.split("=")[0], param.split("=")[1]] for param in url.split("&") if "=" in param])
|
||
self.__dict__.update(dct)
|
||
self.__dict__ = self.toutf8(self.__dict__)
|
||
|
||
if 'infoLabels' in self.__dict__ and not isinstance(self.__dict__['infoLabels'], InfoLabels):
|
||
self.__dict__['infoLabels'] = InfoLabels(self.__dict__['infoLabels'])
|
||
|
||
return self
|
||
|
||
def tojson(self, path=""):
|
||
from core import filetools
|
||
"""
|
||
Create a JSON from the item, to save favorite files, download list, etc....
|
||
If a path is specified, it saves it in the specified path, if not, it returns the string json
|
||
Applications: item.tojson(path="path\archivo\json.json")
|
||
file.write(item.tojson())
|
||
|
||
@param path: path
|
||
@type path: str
|
||
"""
|
||
if path:
|
||
#open(path, "wb").write(json.dump(self.__dict__))
|
||
res = filetools.write(path, json.dump(self.__dict__))
|
||
else:
|
||
return json.dump(self.__dict__)
|
||
|
||
def fromjson(self, json_item=None, path=""):
|
||
from core import filetools
|
||
"""
|
||
Generate an item from a JSON file
|
||
If a path is specified, it directly reads the file, if not, it reads the passed text string.
|
||
Applications: item = Item().fromjson(path="path\archivo\json.json")
|
||
item = Item().fromjson("Cadena de texto json")
|
||
|
||
@param json_item: item
|
||
@type json_item: json
|
||
@param path: path
|
||
@type path: str
|
||
"""
|
||
if path:
|
||
if filetools.exists(path):
|
||
#json_item = open(path, "rb").read()
|
||
json_item = filetools.read(path)
|
||
else:
|
||
json_item = {}
|
||
|
||
if json_item is None:
|
||
json_item = {}
|
||
|
||
item = json.load(json_item, object_hook=self.toutf8)
|
||
self.__dict__.update(item)
|
||
|
||
if 'infoLabels' in self.__dict__ and not isinstance(self.__dict__['infoLabels'], InfoLabels):
|
||
self.__dict__['infoLabels'] = InfoLabels(self.__dict__['infoLabels'])
|
||
|
||
return self
|
||
|
||
def clone(self, **kwargs):
|
||
"""
|
||
Generate a new item by cloning the current item
|
||
Applications: NewItem = item.clone()
|
||
NuewItem = item.clone(title="New Title", action = "New Action")
|
||
"""
|
||
newitem = copy.deepcopy(self)
|
||
if "infoLabels" in kwargs:
|
||
kwargs["infoLabels"] = InfoLabels(kwargs["infoLabels"])
|
||
for kw in kwargs:
|
||
newitem.__setattr__(kw, kwargs[kw])
|
||
newitem.__dict__ = newitem.toutf8(newitem.__dict__)
|
||
|
||
return newitem
|
||
|
||
@staticmethod
|
||
def decode_html(value):
|
||
"""
|
||
Decode the HTML entities
|
||
@param value: value to decode
|
||
@type value: str
|
||
"""
|
||
try:
|
||
unicode_title = unicode(value, "utf8", "ignore")
|
||
return unescape(unicode_title).encode("utf8")
|
||
except:
|
||
if PY3 and isinstance(value, bytes):
|
||
value = value.decode("utf8")
|
||
return value
|
||
|
||
def toutf8(self, *args):
|
||
"""
|
||
Pass the item to utf8
|
||
"""
|
||
if len(args) > 0:
|
||
value = args[0]
|
||
else:
|
||
value = self.__dict__
|
||
|
||
if isinstance(value, unicode):
|
||
value = value.encode("utf8")
|
||
if PY3: value = value.decode("utf8")
|
||
return value
|
||
|
||
elif not PY3 and isinstance(value, str):
|
||
return unicode(value, "utf8", "ignore").encode("utf8")
|
||
|
||
elif PY3 and isinstance(value, bytes):
|
||
return value.decode("utf8")
|
||
|
||
elif isinstance(value, list):
|
||
for x, key in enumerate(value):
|
||
value[x] = self.toutf8(value[x])
|
||
return value
|
||
|
||
elif isinstance(value, dict):
|
||
newdct = {}
|
||
for key in value:
|
||
value_unc = self.toutf8(value[key])
|
||
key_unc = self.toutf8(key)
|
||
#if isinstance(key, unicode):
|
||
# key = key.encode("utf8")
|
||
|
||
newdct[key_unc] = value_unc
|
||
|
||
if len(args) > 0:
|
||
if isinstance(value, InfoLabels):
|
||
return InfoLabels(newdct)
|
||
else:
|
||
return newdct
|
||
|
||
else:
|
||
return value
|