Files
addon/core/item.py
Alhaziel01 29a5b2569e - Chiusura finestra server dopo standby
- Menu contestuale in finestra server
 - Piccoli fix deltabit e uqloads
 - Piccolo fix gestione viste
 - Fix gestione salva link
2022-01-13 13:02:01 +01:00

511 lines
19 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- 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