2025-07-29 16:24:44 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
# Module: default
|
|
|
|
|
# Created on: 10.5.2020
|
|
|
|
|
# License: AGPL v.3 https://www.gnu.org/licenses/agpl-3.0.html
|
|
|
|
|
|
|
|
|
|
import io
|
|
|
|
|
import os
|
|
|
|
|
import sys
|
|
|
|
|
import xbmc
|
|
|
|
|
import xbmcgui
|
|
|
|
|
import xbmcplugin
|
|
|
|
|
import xbmcaddon
|
|
|
|
|
import xbmcvfs
|
|
|
|
|
import requests.cookies
|
|
|
|
|
from xml.etree import ElementTree as ET
|
|
|
|
|
import hashlib
|
|
|
|
|
from md5crypt import md5crypt
|
|
|
|
|
import traceback
|
|
|
|
|
import json
|
|
|
|
|
import unidecode
|
|
|
|
|
import re
|
|
|
|
|
import zipfile
|
|
|
|
|
import uuid
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
from urllib import urlencode
|
|
|
|
|
from urlparse import parse_qsl, urlparse
|
|
|
|
|
except ImportError:
|
|
|
|
|
from urllib.parse import urlencode
|
|
|
|
|
from urllib.parse import parse_qsl, urlparse
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
from xbmc import translatePath
|
|
|
|
|
except ImportError:
|
|
|
|
|
from xbmcvfs import translatePath
|
|
|
|
|
|
|
|
|
|
BASE = 'https://webshare.cz'
|
|
|
|
|
API = BASE + '/api/'
|
|
|
|
|
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"
|
|
|
|
|
HEADERS = {'User-Agent': UA, 'Referer':BASE}
|
|
|
|
|
REALM = ':Webshare:'
|
|
|
|
|
CATEGORIES = ['','video','images','audio','archives','docs','adult']
|
|
|
|
|
SORTS = ['','recent','rating','largest','smallest']
|
|
|
|
|
SEARCH_HISTORY = 'search_history'
|
|
|
|
|
NONE_WHAT = '%#NONE#%'
|
|
|
|
|
BACKUP_DB = 'D1iIcURxlR'
|
|
|
|
|
|
|
|
|
|
_url = sys.argv[0]
|
|
|
|
|
_handle = int(sys.argv[1])
|
|
|
|
|
_addon = xbmcaddon.Addon()
|
|
|
|
|
_session = requests.Session()
|
|
|
|
|
_session.headers.update(HEADERS)
|
|
|
|
|
_profile = translatePath( _addon.getAddonInfo('profile'))
|
|
|
|
|
try:
|
|
|
|
|
_profile = _profile.decode("utf-8")
|
|
|
|
|
except:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def get_url(**kwargs):
|
|
|
|
|
return '{0}?{1}'.format(_url, urlencode(kwargs, 'utf-8'))
|
|
|
|
|
|
|
|
|
|
def api(fnct, data):
|
|
|
|
|
response = _session.post(API + fnct + "/", data=data)
|
|
|
|
|
return response
|
|
|
|
|
|
|
|
|
|
def is_ok(xml):
|
|
|
|
|
status = xml.find('status').text
|
|
|
|
|
return status == 'OK'
|
|
|
|
|
|
|
|
|
|
def popinfo(message, heading=_addon.getAddonInfo('name'), icon=xbmcgui.NOTIFICATION_INFO, time=3000, sound=False): #NOTIFICATION_WARNING NOTIFICATION_ERROR
|
|
|
|
|
xbmcgui.Dialog().notification(heading, message, icon, time, sound=sound)
|
|
|
|
|
|
|
|
|
|
def login():
|
|
|
|
|
username = _addon.getSetting('wsuser')
|
|
|
|
|
password = _addon.getSetting('wspass')
|
|
|
|
|
if username == '' or password == '':
|
|
|
|
|
popinfo(_addon.getLocalizedString(30101), sound=True)
|
|
|
|
|
_addon.openSettings()
|
|
|
|
|
return
|
|
|
|
|
response = api('salt', {'username_or_email': username})
|
|
|
|
|
xml = ET.fromstring(response.content)
|
|
|
|
|
if is_ok(xml):
|
|
|
|
|
salt = xml.find('salt').text
|
|
|
|
|
try:
|
|
|
|
|
encrypted_pass = hashlib.sha1(md5crypt(password.encode('utf-8'), salt.encode('utf-8'))).hexdigest()
|
|
|
|
|
pass_digest = hashlib.md5(username.encode('utf-8') + REALM + encrypted_pass.encode('utf-8')).hexdigest()
|
|
|
|
|
except TypeError:
|
|
|
|
|
encrypted_pass = hashlib.sha1(md5crypt(password.encode('utf-8'), salt.encode('utf-8')).encode('utf-8')).hexdigest()
|
|
|
|
|
pass_digest = hashlib.md5(username.encode('utf-8') + REALM.encode('utf-8') + encrypted_pass.encode('utf-8')).hexdigest()
|
|
|
|
|
response = api('login', {'username_or_email': username, 'password': encrypted_pass, 'digest': pass_digest, 'keep_logged_in': 1})
|
|
|
|
|
xml = ET.fromstring(response.content)
|
|
|
|
|
if is_ok(xml):
|
|
|
|
|
token = xml.find('token').text
|
|
|
|
|
_addon.setSetting('token', token)
|
|
|
|
|
return token
|
|
|
|
|
else:
|
|
|
|
|
popinfo(_addon.getLocalizedString(30102), icon=xbmcgui.NOTIFICATION_ERROR, sound=True)
|
|
|
|
|
_addon.openSettings()
|
|
|
|
|
else:
|
|
|
|
|
popinfo(_addon.getLocalizedString(30102), icon=xbmcgui.NOTIFICATION_ERROR, sound=True)
|
|
|
|
|
_addon.openSettings()
|
|
|
|
|
|
|
|
|
|
def revalidate():
|
|
|
|
|
token = _addon.getSetting('token')
|
|
|
|
|
if len(token) == 0:
|
|
|
|
|
if login():
|
|
|
|
|
return revalidate()
|
|
|
|
|
else:
|
|
|
|
|
response = api('user_data', { 'wst': token })
|
|
|
|
|
xml = ET.fromstring(response.content)
|
|
|
|
|
status = xml.find('status').text
|
|
|
|
|
if is_ok(xml):
|
|
|
|
|
vip = xml.find('vip').text
|
|
|
|
|
if vip != '1':
|
|
|
|
|
popinfo(_addon.getLocalizedString(30103), icon=xbmcgui.NOTIFICATION_WARNING)
|
|
|
|
|
return token
|
|
|
|
|
else:
|
|
|
|
|
if login():
|
|
|
|
|
return revalidate()
|
|
|
|
|
|
|
|
|
|
def todict(xml, skip=[]):
|
|
|
|
|
result = {}
|
|
|
|
|
for e in xml:
|
|
|
|
|
if e.tag not in skip:
|
|
|
|
|
value = e.text if len(list(e)) == 0 else todict(e,skip)
|
|
|
|
|
if e.tag in result:
|
|
|
|
|
if isinstance(result[e.tag], list):
|
|
|
|
|
result[e.tag].append(value)
|
|
|
|
|
else:
|
|
|
|
|
result[e.tag] = [result[e.tag],value]
|
|
|
|
|
else:
|
|
|
|
|
result[e.tag] = value
|
|
|
|
|
#result = {e.tag:(e.text if len(list(e)) == 0 else todict(e,skip)) for e in xml if e.tag not in skip}
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
def sizelize(txtsize, units=['B','KB','MB','GB']):
|
|
|
|
|
if txtsize:
|
|
|
|
|
size = float(txtsize)
|
|
|
|
|
if size < 1024:
|
|
|
|
|
size = str(size) + units[0]
|
|
|
|
|
else:
|
|
|
|
|
size = size / 1024
|
|
|
|
|
if size < 1024:
|
|
|
|
|
size = str(int(round(size))) + units[1]
|
|
|
|
|
else:
|
|
|
|
|
size = size / 1024
|
|
|
|
|
if size < 1024:
|
|
|
|
|
size = str(round(size,2)) + units[2]
|
|
|
|
|
else:
|
|
|
|
|
size = size / 1024
|
|
|
|
|
size = str(round(size,2)) + units[3]
|
|
|
|
|
return size
|
|
|
|
|
return str(txtsize)
|
|
|
|
|
|
|
|
|
|
def labelize(file):
|
|
|
|
|
if 'size' in file:
|
|
|
|
|
size = sizelize(file['size'])
|
|
|
|
|
elif 'sizelized' in file:
|
|
|
|
|
size = file['sizelized']
|
|
|
|
|
else:
|
|
|
|
|
size = '?'
|
|
|
|
|
label = file['name'] + ' (' + size + ')'
|
|
|
|
|
return label
|
|
|
|
|
|
|
|
|
|
def tolistitem(file, addcommands=[]):
|
|
|
|
|
label = labelize(file)
|
|
|
|
|
listitem = xbmcgui.ListItem(label=label)
|
|
|
|
|
if 'img' in file:
|
|
|
|
|
listitem.setArt({'thumb': file['img']})
|
|
|
|
|
listitem.setInfo('video', {'title': label})
|
|
|
|
|
listitem.setProperty('IsPlayable', 'true')
|
|
|
|
|
commands = []
|
|
|
|
|
commands.append(( _addon.getLocalizedString(30211), 'RunPlugin(' + get_url(action='info',ident=file['ident']) + ')'))
|
|
|
|
|
commands.append(( _addon.getLocalizedString(30212), 'RunPlugin(' + get_url(action='download',ident=file['ident']) + ')'))
|
|
|
|
|
if addcommands:
|
|
|
|
|
commands = commands + addcommands
|
|
|
|
|
listitem.addContextMenuItems(commands)
|
|
|
|
|
return listitem
|
|
|
|
|
|
|
|
|
|
def ask(what):
|
|
|
|
|
if what is None:
|
|
|
|
|
what = ''
|
|
|
|
|
kb = xbmc.Keyboard(what, _addon.getLocalizedString(30007))
|
|
|
|
|
kb.doModal() # Onscreen keyboard appears
|
|
|
|
|
if kb.isConfirmed():
|
|
|
|
|
return kb.getText() # User input
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def loadsearch():
|
|
|
|
|
history = []
|
|
|
|
|
try:
|
|
|
|
|
if not os.path.exists(_profile):
|
|
|
|
|
os.makedirs(_profile)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
traceback.print_exc()
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
with io.open(os.path.join(_profile, SEARCH_HISTORY), 'r', encoding='utf8') as file:
|
|
|
|
|
fdata = file.read()
|
|
|
|
|
file.close()
|
|
|
|
|
try:
|
|
|
|
|
history = json.loads(fdata, "utf-8")
|
|
|
|
|
except TypeError:
|
|
|
|
|
history = json.loads(fdata)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
traceback.print_exc()
|
|
|
|
|
|
|
|
|
|
return history
|
|
|
|
|
|
|
|
|
|
def storesearch(what):
|
|
|
|
|
if what:
|
|
|
|
|
size = int(_addon.getSetting('shistory'))
|
|
|
|
|
|
|
|
|
|
history = loadsearch()
|
|
|
|
|
|
|
|
|
|
if what in history:
|
|
|
|
|
history.remove(what)
|
|
|
|
|
|
|
|
|
|
history = [what] + history
|
|
|
|
|
|
|
|
|
|
if len(history)>size:
|
|
|
|
|
history = history[:size]
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
with io.open(os.path.join(_profile, SEARCH_HISTORY), 'w', encoding='utf8') as file:
|
|
|
|
|
try:
|
|
|
|
|
data = json.dumps(history).decode('utf8')
|
|
|
|
|
except AttributeError:
|
|
|
|
|
data = json.dumps(history)
|
|
|
|
|
file.write(data)
|
|
|
|
|
file.close()
|
|
|
|
|
except Exception as e:
|
|
|
|
|
traceback.print_exc()
|
|
|
|
|
|
|
|
|
|
def removesearch(what):
|
|
|
|
|
if what:
|
|
|
|
|
history = loadsearch()
|
|
|
|
|
if what in history:
|
|
|
|
|
history.remove(what)
|
|
|
|
|
try:
|
|
|
|
|
with io.open(os.path.join(_profile, SEARCH_HISTORY), 'w', encoding='utf8') as file:
|
|
|
|
|
try:
|
|
|
|
|
data = json.dumps(history).decode('utf8')
|
|
|
|
|
except AttributeError:
|
|
|
|
|
data = json.dumps(history)
|
|
|
|
|
file.write(data)
|
|
|
|
|
file.close()
|
|
|
|
|
except Exception as e:
|
|
|
|
|
traceback.print_exc()
|
|
|
|
|
|
|
|
|
|
def dosearch(token, what, category, sort, limit, offset, action):
|
|
|
|
|
response = api('search',{'what':'' if what == NONE_WHAT else what, 'category':category, 'sort':sort, 'limit': limit, 'offset': offset, 'wst':token, 'maybe_removed':'true'})
|
|
|
|
|
xml = ET.fromstring(response.content)
|
|
|
|
|
if is_ok(xml):
|
|
|
|
|
|
|
|
|
|
if offset > 0: #prev page
|
|
|
|
|
listitem = xbmcgui.ListItem(label=_addon.getLocalizedString(30206))
|
|
|
|
|
listitem.setArt({'icon': 'DefaultAddonsSearch.png'})
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action=action, what=what, category=category, sort=sort, limit=limit, offset=offset - limit if offset > limit else 0), listitem, True)
|
|
|
|
|
|
|
|
|
|
for file in xml.iter('file'):
|
|
|
|
|
item = todict(file)
|
|
|
|
|
commands = []
|
|
|
|
|
commands.append(( _addon.getLocalizedString(30214), 'Container.Update(' + get_url(action='search',toqueue=item['ident'], what=what, offset=offset) + ')'))
|
|
|
|
|
listitem = tolistitem(item,commands)
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='play',ident=item['ident'],name=item['name']), listitem, False)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
total = int(xml.find('total').text)
|
|
|
|
|
except:
|
|
|
|
|
total = 0
|
|
|
|
|
|
|
|
|
|
if offset + limit < total: #next page
|
|
|
|
|
listitem = xbmcgui.ListItem(label=_addon.getLocalizedString(30207))
|
|
|
|
|
listitem.setArt({'icon': 'DefaultAddonsSearch.png'})
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action=action, what=what, category=category, sort=sort, limit=limit, offset=offset+limit), listitem, True)
|
|
|
|
|
else:
|
|
|
|
|
popinfo(_addon.getLocalizedString(30107), icon=xbmcgui.NOTIFICATION_WARNING)
|
|
|
|
|
|
|
|
|
|
def search(params):
|
|
|
|
|
xbmcplugin.setPluginCategory(_handle, _addon.getAddonInfo('name') + " \\ " + _addon.getLocalizedString(30201))
|
|
|
|
|
token = revalidate()
|
|
|
|
|
|
|
|
|
|
updateListing=False
|
|
|
|
|
|
|
|
|
|
if 'remove' in params:
|
|
|
|
|
removesearch(params['remove'])
|
|
|
|
|
updateListing=True
|
|
|
|
|
|
|
|
|
|
if 'toqueue' in params:
|
|
|
|
|
toqueue(params['toqueue'],token)
|
|
|
|
|
updateListing=True
|
|
|
|
|
|
|
|
|
|
what = None
|
|
|
|
|
|
|
|
|
|
if 'what' in params:
|
|
|
|
|
what = params['what']
|
|
|
|
|
|
|
|
|
|
if 'ask' in params:
|
|
|
|
|
slast = _addon.getSetting('slast')
|
|
|
|
|
if slast != what:
|
|
|
|
|
what = ask(what)
|
|
|
|
|
if what is not None:
|
|
|
|
|
storesearch(what)
|
|
|
|
|
else:
|
|
|
|
|
updateListing=True
|
|
|
|
|
|
|
|
|
|
if what is not None:
|
|
|
|
|
if 'offset' not in params:
|
|
|
|
|
_addon.setSetting('slast',what)
|
|
|
|
|
else:
|
|
|
|
|
_addon.setSetting('slast',NONE_WHAT)
|
|
|
|
|
updateListing=True
|
|
|
|
|
|
|
|
|
|
category = params['category'] if 'category' in params else CATEGORIES[int(_addon.getSetting('scategory'))]
|
|
|
|
|
sort = params['sort'] if 'sort' in params else SORTS[int(_addon.getSetting('ssort'))]
|
|
|
|
|
limit = int(params['limit']) if 'limit' in params else int(_addon.getSetting('slimit'))
|
|
|
|
|
offset = int(params['offset']) if 'offset' in params else 0
|
|
|
|
|
dosearch(token, what, category, sort, limit, offset, 'search')
|
|
|
|
|
else:
|
|
|
|
|
_addon.setSetting('slast',NONE_WHAT)
|
|
|
|
|
history = loadsearch()
|
|
|
|
|
listitem = xbmcgui.ListItem(label=_addon.getLocalizedString(30205))
|
|
|
|
|
listitem.setArt({'icon': 'DefaultSource.png'})
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='search',ask=1), listitem, True)
|
|
|
|
|
|
|
|
|
|
#newest
|
|
|
|
|
listitem = xbmcgui.ListItem(label=_addon.getLocalizedString(30208))
|
|
|
|
|
listitem.setArt({'icon': 'DefaultAddonsRecentlyUpdated.png'})
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='search',what=NONE_WHAT,sort=SORTS[1]), listitem, True)
|
|
|
|
|
|
|
|
|
|
#biggest
|
|
|
|
|
listitem = xbmcgui.ListItem(label=_addon.getLocalizedString(30209))
|
|
|
|
|
listitem.setArt({'icon': 'DefaultHardDisk.png'})
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='search',what=NONE_WHAT,sort=SORTS[3]), listitem, True)
|
|
|
|
|
|
|
|
|
|
for search in history:
|
|
|
|
|
listitem = xbmcgui.ListItem(label=search)
|
|
|
|
|
listitem.setArt({'icon': 'DefaultAddonsSearch.png'})
|
|
|
|
|
commands = []
|
|
|
|
|
commands.append(( _addon.getLocalizedString(30213), 'Container.Update(' + get_url(action='search',remove=search) + ')'))
|
|
|
|
|
listitem.addContextMenuItems(commands)
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='search',what=search,ask=1), listitem, True)
|
|
|
|
|
xbmcplugin.endOfDirectory(_handle, updateListing=updateListing)
|
|
|
|
|
|
|
|
|
|
def queue(params):
|
|
|
|
|
xbmcplugin.setPluginCategory(_handle, _addon.getAddonInfo('name') + " \\ " + _addon.getLocalizedString(30202))
|
|
|
|
|
token = revalidate()
|
|
|
|
|
updateListing=False
|
|
|
|
|
|
|
|
|
|
if 'dequeue' in params:
|
|
|
|
|
response = api('dequeue_file',{'ident':params['dequeue'],'wst':token})
|
|
|
|
|
xml = ET.fromstring(response.content)
|
|
|
|
|
if is_ok(xml):
|
|
|
|
|
popinfo(_addon.getLocalizedString(30106))
|
|
|
|
|
else:
|
|
|
|
|
popinfo(_addon.getLocalizedString(30107), icon=xbmcgui.NOTIFICATION_WARNING)
|
|
|
|
|
updateListing=True
|
|
|
|
|
|
|
|
|
|
response = api('queue',{'wst':token})
|
|
|
|
|
xml = ET.fromstring(response.content)
|
|
|
|
|
if is_ok(xml):
|
|
|
|
|
for file in xml.iter('file'):
|
|
|
|
|
item = todict(file)
|
|
|
|
|
commands = []
|
|
|
|
|
commands.append(( _addon.getLocalizedString(30215), 'Container.Update(' + get_url(action='queue',dequeue=item['ident']) + ')'))
|
|
|
|
|
listitem = tolistitem(item,commands)
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='play',ident=item['ident'],name=item['name']), listitem, False)
|
|
|
|
|
else:
|
|
|
|
|
popinfo(_addon.getLocalizedString(30107), icon=xbmcgui.NOTIFICATION_WARNING)
|
|
|
|
|
xbmcplugin.endOfDirectory(_handle,updateListing=updateListing)
|
|
|
|
|
|
|
|
|
|
def toqueue(ident,token):
|
|
|
|
|
response = api('queue_file',{'ident':ident,'wst':token})
|
|
|
|
|
xml = ET.fromstring(response.content)
|
|
|
|
|
if is_ok(xml):
|
|
|
|
|
popinfo(_addon.getLocalizedString(30105))
|
|
|
|
|
else:
|
|
|
|
|
popinfo(_addon.getLocalizedString(30107), icon=xbmcgui.NOTIFICATION_WARNING)
|
|
|
|
|
|
|
|
|
|
def history(params):
|
|
|
|
|
xbmcplugin.setPluginCategory(_handle, _addon.getAddonInfo('name') + " \\ " + _addon.getLocalizedString(30203))
|
|
|
|
|
token = revalidate()
|
|
|
|
|
updateListing=False
|
|
|
|
|
|
|
|
|
|
if 'remove' in params:
|
|
|
|
|
remove = params['remove']
|
|
|
|
|
updateListing=True
|
|
|
|
|
response = api('history',{'wst':token})
|
|
|
|
|
xml = ET.fromstring(response.content)
|
|
|
|
|
ids = []
|
|
|
|
|
if is_ok(xml):
|
|
|
|
|
for file in xml.iter('file'):
|
|
|
|
|
if remove == file.find('ident').text:
|
|
|
|
|
ids.append(file.find('download_id').text)
|
|
|
|
|
else:
|
|
|
|
|
popinfo(_addon.getLocalizedString(30107), icon=xbmcgui.NOTIFICATION_WARNING)
|
|
|
|
|
if ids:
|
|
|
|
|
rr = api('clear_history',{'ids[]':ids,'wst':token})
|
|
|
|
|
xml = ET.fromstring(rr.content)
|
|
|
|
|
if is_ok(xml):
|
|
|
|
|
popinfo(_addon.getLocalizedString(30104))
|
|
|
|
|
else:
|
|
|
|
|
popinfo(_addon.getLocalizedString(30107), icon=xbmcgui.NOTIFICATION_WARNING)
|
|
|
|
|
|
|
|
|
|
if 'toqueue' in params:
|
|
|
|
|
toqueue(params['toqueue'],token)
|
|
|
|
|
updateListing=True
|
|
|
|
|
|
|
|
|
|
response = api('history',{'wst':token})
|
|
|
|
|
xml = ET.fromstring(response.content)
|
|
|
|
|
files = []
|
|
|
|
|
if is_ok(xml):
|
|
|
|
|
for file in xml.iter('file'):
|
|
|
|
|
item = todict(file, ['ended_at', 'download_id', 'started_at'])
|
|
|
|
|
if item not in files:
|
|
|
|
|
files.append(item)
|
|
|
|
|
for file in files:
|
|
|
|
|
commands = []
|
|
|
|
|
commands.append(( _addon.getLocalizedString(30213), 'Container.Update(' + get_url(action='history',remove=file['ident']) + ')'))
|
|
|
|
|
commands.append(( _addon.getLocalizedString(30214), 'Container.Update(' + get_url(action='history',toqueue=file['ident']) + ')'))
|
|
|
|
|
listitem = tolistitem(file, commands)
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='play',ident=file['ident'],name=file['name']), listitem, False)
|
|
|
|
|
else:
|
|
|
|
|
popinfo(_addon.getLocalizedString(30107), icon=xbmcgui.NOTIFICATION_WARNING)
|
|
|
|
|
xbmcplugin.endOfDirectory(_handle,updateListing=updateListing)
|
|
|
|
|
|
|
|
|
|
def settings(params):
|
|
|
|
|
_addon.openSettings()
|
|
|
|
|
xbmcplugin.setResolvedUrl(_handle, False, xbmcgui.ListItem())
|
|
|
|
|
|
|
|
|
|
def infonize(data,key,process=str,showkey=True,prefix='',suffix='\n'):
|
|
|
|
|
if key in data:
|
|
|
|
|
return prefix + (key.capitalize() + ': ' if showkey else '') + process(data[key]) + suffix
|
|
|
|
|
return ''
|
|
|
|
|
|
|
|
|
|
def fpsize(fps):
|
|
|
|
|
x = round(float(fps),3)
|
|
|
|
|
if int(x) == x:
|
|
|
|
|
return str(int(x))
|
|
|
|
|
return str(x)
|
|
|
|
|
|
|
|
|
|
def getinfo(ident,wst):
|
|
|
|
|
response = api('file_info',{'ident':ident,'wst': wst})
|
|
|
|
|
xml = ET.fromstring(response.content)
|
|
|
|
|
ok = is_ok(xml)
|
|
|
|
|
if not ok:
|
|
|
|
|
response = api('file_info',{'ident':ident,'wst': wst, 'maybe_removed':'true'})
|
|
|
|
|
xml = ET.fromstring(response.content)
|
|
|
|
|
ok = is_ok(xml)
|
|
|
|
|
if ok:
|
|
|
|
|
return xml
|
|
|
|
|
else:
|
|
|
|
|
popinfo(_addon.getLocalizedString(30107), icon=xbmcgui.NOTIFICATION_WARNING)
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def info(params):
|
|
|
|
|
token = revalidate()
|
|
|
|
|
xml = getinfo(params['ident'],token)
|
|
|
|
|
|
|
|
|
|
if xml is not None:
|
|
|
|
|
info = todict(xml)
|
|
|
|
|
text = ''
|
|
|
|
|
text += infonize(info, 'name')
|
|
|
|
|
text += infonize(info, 'size', sizelize)
|
|
|
|
|
text += infonize(info, 'type')
|
|
|
|
|
text += infonize(info, 'width')
|
|
|
|
|
text += infonize(info, 'height')
|
|
|
|
|
text += infonize(info, 'format')
|
|
|
|
|
text += infonize(info, 'fps', fpsize)
|
|
|
|
|
text += infonize(info, 'bitrate', lambda x:sizelize(x,['bps','Kbps','Mbps','Gbps']))
|
|
|
|
|
if 'video' in info and 'stream' in info['video']:
|
|
|
|
|
streams = info['video']['stream']
|
|
|
|
|
if isinstance(streams, dict):
|
|
|
|
|
streams = [streams]
|
|
|
|
|
for stream in streams:
|
|
|
|
|
text += 'Video stream: '
|
|
|
|
|
text += infonize(stream, 'width', showkey=False, suffix='')
|
|
|
|
|
text += infonize(stream, 'height', showkey=False, prefix='x', suffix='')
|
|
|
|
|
text += infonize(stream,'format', showkey=False, prefix=', ', suffix='')
|
|
|
|
|
text += infonize(stream,'fps', fpsize, showkey=False, prefix=', ', suffix='')
|
|
|
|
|
text += '\n'
|
|
|
|
|
if 'audio' in info and 'stream' in info['audio']:
|
|
|
|
|
streams = info['audio']['stream']
|
|
|
|
|
if isinstance(streams, dict):
|
|
|
|
|
streams = [streams]
|
|
|
|
|
for stream in streams:
|
|
|
|
|
text += 'Audio stream: '
|
|
|
|
|
text += infonize(stream, 'format', showkey=False, suffix='')
|
|
|
|
|
text += infonize(stream,'channels', prefix=', ', showkey=False, suffix='')
|
|
|
|
|
text += infonize(stream,'bitrate', lambda x:sizelize(x,['bps','Kbps','Mbps','Gbps']), prefix=', ', showkey=False, suffix='')
|
|
|
|
|
text += '\n'
|
|
|
|
|
text += infonize(info, 'removed', lambda x:'Yes' if x=='1' else 'No')
|
|
|
|
|
xbmcgui.Dialog().textviewer(_addon.getAddonInfo('name'), text)
|
|
|
|
|
|
|
|
|
|
def getlink(ident,wst,dtype='video_stream'):
|
|
|
|
|
#uuid experiment
|
|
|
|
|
duuid = _addon.getSetting('duuid')
|
|
|
|
|
if not duuid:
|
|
|
|
|
duuid = str(uuid.uuid4())
|
|
|
|
|
_addon.setSetting('duuid',duuid)
|
|
|
|
|
data = {'ident':ident,'wst': wst,'download_type':dtype,'device_uuid':duuid}
|
|
|
|
|
#TODO password protect
|
|
|
|
|
#response = api('file_protected',data) #protected
|
|
|
|
|
#xml = ET.fromstring(response.content)
|
|
|
|
|
#if is_ok(xml) and xml.find('protected').text != 0:
|
|
|
|
|
# pass #ask for password
|
|
|
|
|
response = api('file_link',data)
|
|
|
|
|
xml = ET.fromstring(response.content)
|
|
|
|
|
if is_ok(xml):
|
|
|
|
|
return xml.find('link').text
|
|
|
|
|
else:
|
|
|
|
|
popinfo(_addon.getLocalizedString(30107), icon=xbmcgui.NOTIFICATION_WARNING)
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def play(params):
|
|
|
|
|
token = revalidate()
|
|
|
|
|
link = getlink(params['ident'],token)
|
|
|
|
|
if link is not None:
|
|
|
|
|
#headers experiment
|
|
|
|
|
headers = _session.headers
|
|
|
|
|
if headers:
|
|
|
|
|
headers.update({'Cookie':'wst='+token})
|
|
|
|
|
link = link + '|' + urlencode(headers)
|
|
|
|
|
listitem = xbmcgui.ListItem(label=params['name'],path=link)
|
|
|
|
|
listitem.setProperty('mimetype', 'application/octet-stream')
|
|
|
|
|
xbmcplugin.setResolvedUrl(_handle, True, listitem)
|
|
|
|
|
else:
|
|
|
|
|
popinfo(_addon.getLocalizedString(30107), icon=xbmcgui.NOTIFICATION_WARNING)
|
|
|
|
|
xbmcplugin.setResolvedUrl(_handle, False, xbmcgui.ListItem())
|
|
|
|
|
|
|
|
|
|
def verify_ident(ident, token):
|
|
|
|
|
"""Ověří, zda je ident platný a soubor existuje"""
|
|
|
|
|
response = api('file_info', {'ident': ident, 'wst': token})
|
|
|
|
|
xml = ET.fromstring(response.content)
|
|
|
|
|
if is_ok(xml):
|
|
|
|
|
return True
|
|
|
|
|
else:
|
|
|
|
|
popinfo(f"Neplatný ident: {ident}", icon=xbmcgui.NOTIFICATION_ERROR)
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def join(path, file):
|
|
|
|
|
if path.endswith('/') or path.endswith('\\'):
|
|
|
|
|
return path + file
|
|
|
|
|
else:
|
|
|
|
|
return path + '/' + file
|
|
|
|
|
|
|
|
|
|
def download(params):
|
|
|
|
|
token = revalidate()
|
|
|
|
|
where = _addon.getSetting('dfolder')
|
|
|
|
|
if not where or not xbmcvfs.exists(where):
|
|
|
|
|
popinfo('set folder!', sound=True)#_addon.getLocalizedString(30101)
|
|
|
|
|
_addon.openSettings()
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
local = os.path.exists(where)
|
|
|
|
|
|
|
|
|
|
normalize = 'true' == _addon.getSetting('dnormalize')
|
|
|
|
|
notify = 'true' == _addon.getSetting('dnotify')
|
|
|
|
|
every = _addon.getSetting('dnevery')
|
|
|
|
|
try:
|
|
|
|
|
every = int(re.sub(r'[^\d]+', '', every))
|
|
|
|
|
except:
|
|
|
|
|
every = 10
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
link = getlink(params['ident'],token,'file_download')
|
|
|
|
|
info = getinfo(params['ident'],token)
|
|
|
|
|
name = info.find('name').text
|
|
|
|
|
if normalize:
|
|
|
|
|
name = unidecode.unidecode(name)
|
|
|
|
|
bf = io.open(os.path.join(where,name), 'wb') if local else xbmcvfs.File(join(where,name), 'w')
|
|
|
|
|
response = _session.get(link, stream=True)
|
|
|
|
|
total = response.headers.get('content-length')
|
|
|
|
|
if total is None:
|
|
|
|
|
popinfo(_addon.getLocalizedString(30301) + name, icon=xbmcgui.NOTIFICATION_WARNING, sound=True)
|
|
|
|
|
bf.write(response.content)
|
|
|
|
|
elif not notify:
|
|
|
|
|
popinfo(_addon.getLocalizedString(30302) + name)
|
|
|
|
|
bf.write(response.content)
|
|
|
|
|
else:
|
|
|
|
|
popinfo(_addon.getLocalizedString(30302) + name)
|
|
|
|
|
dl = 0
|
|
|
|
|
total = int(total)
|
|
|
|
|
pct = total / 100
|
|
|
|
|
lastpop=0
|
|
|
|
|
for data in response.iter_content(chunk_size=4096):
|
|
|
|
|
dl += len(data)
|
|
|
|
|
bf.write(data)
|
|
|
|
|
done = int(dl / pct)
|
|
|
|
|
if done % every == 0 and lastpop != done:
|
|
|
|
|
popinfo(str(done) + '% - ' + name)
|
|
|
|
|
lastpop = done
|
|
|
|
|
bf.close()
|
|
|
|
|
popinfo(_addon.getLocalizedString(30303) + name, sound=True)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
#TODO - remove unfinished file?
|
|
|
|
|
traceback.print_exc()
|
|
|
|
|
popinfo(_addon.getLocalizedString(30304) + name, icon=xbmcgui.NOTIFICATION_ERROR, sound=True)
|
|
|
|
|
|
|
|
|
|
def loaddb(dbdir,file):
|
|
|
|
|
try:
|
|
|
|
|
data = {}
|
|
|
|
|
with io.open(os.path.join(dbdir, file), 'r', encoding='utf8') as file:
|
|
|
|
|
fdata = file.read()
|
|
|
|
|
file.close()
|
|
|
|
|
try:
|
|
|
|
|
data = json.loads(fdata, "utf-8")['data']
|
|
|
|
|
except TypeError:
|
|
|
|
|
data = json.loads(fdata)['data']
|
|
|
|
|
return data
|
|
|
|
|
except Exception as e:
|
|
|
|
|
traceback.print_exc()
|
|
|
|
|
return {}
|
|
|
|
|
|
|
|
|
|
def db(params):
|
|
|
|
|
token = revalidate()
|
|
|
|
|
updateListing=False
|
|
|
|
|
|
|
|
|
|
dbdir = os.path.join(_profile,'db')
|
|
|
|
|
if not os.path.exists(dbdir):
|
|
|
|
|
link = getlink(BACKUP_DB,token)
|
|
|
|
|
dbfile = os.path.join(_profile,'db.zip')
|
|
|
|
|
with io.open(dbfile, 'wb') as bf:
|
|
|
|
|
response = _session.get(link, stream=True)
|
|
|
|
|
bf.write(response.content)
|
|
|
|
|
bf.flush()
|
|
|
|
|
bf.close()
|
|
|
|
|
with zipfile.ZipFile(dbfile, 'r') as zf:
|
|
|
|
|
zf.extractall(_profile)
|
|
|
|
|
os.unlink(dbfile)
|
|
|
|
|
|
|
|
|
|
if 'toqueue' in params:
|
|
|
|
|
toqueue(params['toqueue'],token)
|
|
|
|
|
updateListing=True
|
|
|
|
|
|
|
|
|
|
if 'file' in params and 'key' in params:
|
|
|
|
|
data = loaddb(dbdir,params['file'])
|
|
|
|
|
item = next((x for x in data if x['id'] == params['key']), None)
|
|
|
|
|
if item is not None:
|
|
|
|
|
for stream in item['streams']:
|
|
|
|
|
commands = []
|
|
|
|
|
commands.append(( _addon.getLocalizedString(30214), 'Container.Update(' + get_url(action='db',file=params['file'],key=params['key'],toqueue=stream['ident']) + ')'))
|
|
|
|
|
listitem = tolistitem({'ident':stream['ident'],'name':stream['quality'] + ' - ' + stream['lang'] + stream['ainfo'],'sizelized':stream['size']},commands)
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='play',ident=stream['ident'],name=item['title']), listitem, False)
|
|
|
|
|
elif 'file' in params:
|
|
|
|
|
data = loaddb(dbdir,params['file'])
|
|
|
|
|
for item in data:
|
|
|
|
|
listitem = xbmcgui.ListItem(label=item['title'])
|
|
|
|
|
if 'plot' in item:
|
|
|
|
|
listitem.setInfo('video', {'title': item['title'],'plot': item['plot']})
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='db',file=params['file'],key=item['id']), listitem, True)
|
|
|
|
|
else:
|
|
|
|
|
if os.path.exists(dbdir):
|
|
|
|
|
dbfiles = [f for f in os.listdir(dbdir) if os.path.isfile(os.path.join(dbdir, f))]
|
|
|
|
|
for dbfile in dbfiles:
|
|
|
|
|
listitem = xbmcgui.ListItem(label=os.path.splitext(dbfile)[0])
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='db',file=dbfile), listitem, True)
|
|
|
|
|
xbmcplugin.addSortMethod(_handle,xbmcplugin.SORT_METHOD_LABEL)
|
|
|
|
|
xbmcplugin.endOfDirectory(_handle, updateListing=updateListing)
|
|
|
|
|
|
|
|
|
|
def mojedb(params):
|
|
|
|
|
xbmc.log("Debug: mojedb funkce spuštěna", xbmc.LOGDEBUG)
|
|
|
|
|
popinfo("Debug: mojedb funkce spuštěna")
|
2025-07-29 19:23:05 +02:00
|
|
|
|
|
|
|
|
# Funkce pro stahování JSON souborů z GITu
|
|
|
|
|
def update_json_db():
|
|
|
|
|
try:
|
|
|
|
|
import urllib.request
|
|
|
|
|
import re
|
|
|
|
|
|
|
|
|
|
def get_json_files_from_folder(folder):
|
|
|
|
|
base_url = "https://git.gald.site/gald/galdistream/src/branch/main/resources/"
|
|
|
|
|
url = base_url + folder
|
|
|
|
|
|
|
|
|
|
req = urllib.request.Request(url)
|
|
|
|
|
req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36')
|
|
|
|
|
|
|
|
|
|
with urllib.request.urlopen(req, timeout=10) as response:
|
|
|
|
|
html_content = response.read().decode('utf-8')
|
|
|
|
|
|
|
|
|
|
json_pattern = r'href="(/gald/galdistream/src/branch/main/resources/[^"]*\.json)"'
|
|
|
|
|
matches = re.findall(json_pattern, html_content)
|
|
|
|
|
|
|
|
|
|
files = []
|
|
|
|
|
for match in matches:
|
|
|
|
|
file_name = match.split("/")[-1]
|
|
|
|
|
files.append(file_name)
|
|
|
|
|
return files
|
|
|
|
|
|
|
|
|
|
base_url_raw = "https://git.gald.site/gald/galdistream/raw/branch/main/resources/"
|
|
|
|
|
folders = ["movies", "series"]
|
|
|
|
|
all_files = []
|
|
|
|
|
|
|
|
|
|
for folder in folders:
|
|
|
|
|
try:
|
|
|
|
|
files = get_json_files_from_folder(folder)
|
|
|
|
|
all_files += [f"{folder}/{file}" for file in files]
|
|
|
|
|
except Exception as e:
|
|
|
|
|
xbmc.log(f"Chyba při získávání souborů ze složky {folder}: {e}", xbmc.LOGERROR)
|
|
|
|
|
|
|
|
|
|
for file in all_files:
|
|
|
|
|
url = base_url_raw + file
|
|
|
|
|
local_path = os.path.join(_addon.getAddonInfo('path'), 'resources', file)
|
|
|
|
|
try:
|
|
|
|
|
req = urllib.request.Request(url)
|
|
|
|
|
req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36')
|
|
|
|
|
|
|
|
|
|
with urllib.request.urlopen(req, timeout=10) as response:
|
|
|
|
|
content = response.read()
|
|
|
|
|
|
|
|
|
|
os.makedirs(os.path.dirname(local_path), exist_ok=True)
|
|
|
|
|
with open(local_path, "wb") as f:
|
|
|
|
|
f.write(content)
|
|
|
|
|
xbmc.log(f"Staženo: {file}", xbmc.LOGDEBUG)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
xbmc.log(f"Chyba při stahování {file}: {e}", xbmc.LOGERROR)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
xbmc.log(f"Chyba při stahování JSON souborů: {e}", xbmc.LOGERROR)
|
|
|
|
|
|
|
|
|
|
# Stáhni aktuální JSON soubory z GITu
|
|
|
|
|
update_json_db()
|
|
|
|
|
|
2025-07-29 16:24:44 +02:00
|
|
|
xbmcplugin.setPluginCategory(_handle, _addon.getAddonInfo('name') + " \\ " + _addon.getLocalizedString(30220))
|
|
|
|
|
token = revalidate()
|
|
|
|
|
updateListing=False
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
# Načti seznam dostupných seriálů a filmů
|
|
|
|
|
series_dir = xbmcvfs.translatePath(os.path.join(_addon.getAddonInfo('path'), 'resources', 'series'))
|
|
|
|
|
movies_dir = xbmcvfs.translatePath(os.path.join(_addon.getAddonInfo('path'), 'resources', 'movies'))
|
|
|
|
|
|
|
|
|
|
xbmc.log(f"Debug: Načítám seriály z: {series_dir}", xbmc.LOGDEBUG)
|
|
|
|
|
popinfo(f"Debug: Načítám seriály z: {series_dir}")
|
|
|
|
|
|
|
|
|
|
# Načti seznam souborů seriálů
|
|
|
|
|
series_files = []
|
|
|
|
|
xbmc.log(f"Debug: Kontroluji existenci složky: {series_dir}", xbmc.LOGDEBUG)
|
|
|
|
|
|
|
|
|
|
# Zkusíme načíst soubory pomocí os.path
|
|
|
|
|
try:
|
|
|
|
|
# Použijeme os.path místo xbmcvfs pro načítání souborů
|
|
|
|
|
if os.path.exists(series_dir):
|
|
|
|
|
files = os.listdir(series_dir)
|
|
|
|
|
xbmc.log(f"Debug: Úspěšně načteno {len(files)} souborů z {series_dir}", xbmc.LOGDEBUG)
|
|
|
|
|
popinfo(f"Debug: Úspěšně načteno {len(files)} souborů")
|
|
|
|
|
for file in files:
|
|
|
|
|
xbmc.log(f"Debug: Kontroluji soubor: {file}", xbmc.LOGDEBUG)
|
|
|
|
|
if file.endswith('.json'):
|
|
|
|
|
series_files.append(file)
|
|
|
|
|
xbmc.log(f"Debug: Přidán JSON soubor: {file}", xbmc.LOGDEBUG)
|
|
|
|
|
else:
|
|
|
|
|
xbmc.log(f"Debug: Složka neexistuje (os.path): {series_dir}", xbmc.LOGDEBUG)
|
|
|
|
|
popinfo(f"Debug: Složka neexistuje (os.path): {series_dir}")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
xbmc.log(f"Debug: Chyba při načítání složky {series_dir}: {str(e)}", xbmc.LOGDEBUG)
|
|
|
|
|
popinfo(f"Debug: Chyba při načítání složky: {str(e)}")
|
|
|
|
|
|
|
|
|
|
xbmc.log(f"Debug: Nalezeno {len(series_files)} JSON souborů seriálů", xbmc.LOGDEBUG)
|
|
|
|
|
popinfo(f"Debug: Nalezeno {len(series_files)} JSON souborů seriálů")
|
|
|
|
|
for file in series_files:
|
|
|
|
|
xbmc.log(f"Debug: Seriál soubor: {file}", xbmc.LOGDEBUG)
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
xbmc.log(f"Chyba při načítání databáze: {str(e)}", xbmc.LOGERROR)
|
|
|
|
|
popinfo(f"Chyba při načítání databáze: {str(e)}", icon=xbmcgui.NOTIFICATION_ERROR, sound=True)
|
|
|
|
|
xbmcplugin.endOfDirectory(_handle, updateListing=updateListing)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# Hlavní rozcestník: seriály/filmy
|
|
|
|
|
if not params.get('type'):
|
|
|
|
|
# Seriály
|
|
|
|
|
listitem = xbmcgui.ListItem(label=_addon.getLocalizedString(30221) if _addon.getLocalizedString(30221) else 'Seriály')
|
|
|
|
|
listitem.setArt({'icon': 'DefaultTVShows.png'})
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='mojedb', type='series'), listitem, True)
|
|
|
|
|
# Filmy
|
|
|
|
|
listitem = xbmcgui.ListItem(label=_addon.getLocalizedString(30222) if _addon.getLocalizedString(30222) else 'Filmy')
|
|
|
|
|
listitem.setArt({'icon': 'DefaultMovies.png'})
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='mojedb', type='movies'), listitem, True)
|
|
|
|
|
|
|
|
|
|
# Výpis seriálů
|
|
|
|
|
elif params.get('type') == 'series' and not params.get('series_idx'):
|
|
|
|
|
xbmc.log(f"Debug: Zobrazuji seriály, nalezeno {len(series_files)} souborů", xbmc.LOGDEBUG)
|
|
|
|
|
popinfo(f"Debug: Zobrazuji seriály, nalezeno {len(series_files)} souborů")
|
|
|
|
|
for idx, file in enumerate(series_files):
|
|
|
|
|
try:
|
|
|
|
|
xbmc.log(f"Debug: Načítám seriál: {file}", xbmc.LOGDEBUG)
|
|
|
|
|
# Načti data seriálu z JSON souboru
|
|
|
|
|
series_path = xbmcvfs.translatePath(os.path.join(_addon.getAddonInfo('path'), 'resources', 'series', file))
|
|
|
|
|
xbmc.log(f"Debug: Cesta k souboru: {series_path}", xbmc.LOGDEBUG)
|
|
|
|
|
with xbmcvfs.File(series_path, 'r') as f:
|
|
|
|
|
content = f.read()
|
|
|
|
|
xbmc.log(f"Debug: Přečteno {len(content)} znaků", xbmc.LOGDEBUG)
|
|
|
|
|
serie_data = json.loads(content)
|
|
|
|
|
|
|
|
|
|
# Vytvoř název seriálu z názvu souboru
|
|
|
|
|
series_name = file.replace('.json', '').replace('-', ' ').title()
|
|
|
|
|
if 'title' in serie_data:
|
|
|
|
|
series_name = serie_data['title']
|
|
|
|
|
|
|
|
|
|
xbmc.log(f"Debug: Vytvářím položku pro seriál: {series_name}", xbmc.LOGDEBUG)
|
|
|
|
|
# Použijeme číselný index místo názvu souboru
|
|
|
|
|
url = get_url(action='mojedb', type='series', series_idx=idx)
|
|
|
|
|
xbmc.log(f"Debug: URL pro seriál: {url}", xbmc.LOGDEBUG)
|
|
|
|
|
listitem = xbmcgui.ListItem(label=series_name)
|
|
|
|
|
listitem.setArt({'icon': serie_data.get('icon', 'DefaultTVShows.png')})
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, url, listitem, True)
|
|
|
|
|
xbmc.log(f"Debug: Přidána položka pro seriál: {series_name}", xbmc.LOGDEBUG)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
xbmc.log(f"Chyba při načítání seriálu {file}: {str(e)}", xbmc.LOGERROR)
|
|
|
|
|
popinfo(f"Chyba při načítání seriálu {file}: {str(e)}", icon=xbmcgui.NOTIFICATION_ERROR)
|
|
|
|
|
|
|
|
|
|
# Výpis sezón daného seriálu
|
|
|
|
|
elif params.get('type') == 'series' and params.get('series_idx') is not None and not params.get('season_idx'):
|
|
|
|
|
try:
|
|
|
|
|
series_idx = int(params['series_idx'])
|
|
|
|
|
series_file = series_files[series_idx]
|
|
|
|
|
popinfo(f"Debug: Zpracovávám seriál: {series_file}")
|
|
|
|
|
|
|
|
|
|
# Načti data seriálu
|
|
|
|
|
series_path = xbmcvfs.translatePath(os.path.join(_addon.getAddonInfo('path'), 'resources', 'series', series_file))
|
|
|
|
|
with xbmcvfs.File(series_path, 'r') as f:
|
|
|
|
|
content = f.read()
|
|
|
|
|
serie_data = json.loads(content)
|
|
|
|
|
|
|
|
|
|
for idx, season in enumerate(serie_data.get('seasons', [])):
|
|
|
|
|
label = f"{serie_data['title']} - Sezóna {season['season']}"
|
|
|
|
|
listitem = xbmcgui.ListItem(label=label)
|
|
|
|
|
listitem.setArt({'icon': serie_data.get('icon', 'DefaultTVShows.png')})
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='mojedb', type='series', series_idx=series_idx, season_idx=idx), listitem, True)
|
|
|
|
|
popinfo(f"Debug: Přidáno {len(serie_data.get('seasons', []))} sezón")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
popinfo(f"Chyba při zpracování sezón: {str(e)}", icon=xbmcgui.NOTIFICATION_ERROR, sound=True)
|
|
|
|
|
|
|
|
|
|
# Výpis epizod dané sezóny
|
|
|
|
|
elif params.get('type') == 'series' and params.get('series_idx') is not None and params.get('season_idx') is not None and not params.get('episode_idx'):
|
|
|
|
|
xbmc.log("Debug: Zpracovávám seznam epizod", xbmc.LOGDEBUG)
|
|
|
|
|
popinfo("Debug: Zpracovávám seznam epizod")
|
|
|
|
|
try:
|
|
|
|
|
series_idx = int(params['series_idx'])
|
|
|
|
|
series_file = series_files[series_idx]
|
|
|
|
|
season_idx = int(params['season_idx'])
|
|
|
|
|
|
|
|
|
|
# Načti data seriálu
|
|
|
|
|
series_path = xbmcvfs.translatePath(os.path.join(_addon.getAddonInfo('path'), 'resources', 'series', series_file))
|
|
|
|
|
with xbmcvfs.File(series_path, 'r') as f:
|
|
|
|
|
content = f.read()
|
|
|
|
|
serie_data = json.loads(content)
|
|
|
|
|
|
|
|
|
|
season = serie_data['seasons'][season_idx]
|
|
|
|
|
xbmc.log(f"Debug: Sezóna {season['season']}, {len(season.get('episodes', []))} epizod", xbmc.LOGDEBUG)
|
|
|
|
|
popinfo(f"Debug: Sezóna {season['season']}, {len(season.get('episodes', []))} epizod")
|
|
|
|
|
for idx, episode in enumerate(season.get('episodes', [])):
|
|
|
|
|
listitem = xbmcgui.ListItem(label=episode['title'])
|
|
|
|
|
listitem.setArt({'icon': serie_data.get('icon', 'DefaultTVShows.png')})
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='mojedb', type='series', series_idx=series_idx, season_idx=params['season_idx'], episode_idx=idx), listitem, True)
|
|
|
|
|
popinfo(f"Debug: Přidáno {len(season.get('episodes', []))} epizod")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
xbmc.log(f"Chyba při zpracování epizod: {str(e)}", xbmc.LOGERROR)
|
|
|
|
|
popinfo(f"Chyba při zpracování epizod: {str(e)}", icon=xbmcgui.NOTIFICATION_ERROR, sound=True)
|
|
|
|
|
|
|
|
|
|
# Vyhledání konkrétní epizody
|
|
|
|
|
elif params.get('type') == 'series' and params.get('series_idx') is not None and params.get('season_idx') is not None and params.get('episode_idx') is not None:
|
|
|
|
|
xbmc.log("Debug: Zpracovávám epizodu", xbmc.LOGDEBUG)
|
|
|
|
|
popinfo("Debug: Zpracovávám epizodu")
|
|
|
|
|
try:
|
|
|
|
|
series_idx = int(params['series_idx'])
|
|
|
|
|
series_file = series_files[series_idx]
|
|
|
|
|
season_idx = int(params['season_idx'])
|
|
|
|
|
episode_idx = int(params['episode_idx'])
|
|
|
|
|
|
|
|
|
|
# Načti data seriálu
|
|
|
|
|
series_path = xbmcvfs.translatePath(os.path.join(_addon.getAddonInfo('path'), 'resources', 'series', series_file))
|
|
|
|
|
with xbmcvfs.File(series_path, 'r') as f:
|
|
|
|
|
content = f.read()
|
|
|
|
|
serie_data = json.loads(content)
|
|
|
|
|
|
|
|
|
|
season = serie_data['seasons'][season_idx]
|
|
|
|
|
episode = season['episodes'][episode_idx]
|
|
|
|
|
xbmc.log(f"Debug: Epizoda: {episode['title']}", xbmc.LOGDEBUG)
|
|
|
|
|
popinfo(f"Debug: Epizoda: {episode['title']}")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
xbmc.log(f"Chyba při zpracování epizody: {str(e)}", xbmc.LOGERROR)
|
|
|
|
|
popinfo(f"Chyba při zpracování epizody: {str(e)}", icon=xbmcgui.NOTIFICATION_ERROR, sound=True)
|
|
|
|
|
xbmcplugin.endOfDirectory(_handle, updateListing=updateListing)
|
|
|
|
|
return
|
|
|
|
|
if 'ident' in episode:
|
|
|
|
|
xbmc.log(f"Debug: Nalezen ident: {episode['ident']}", xbmc.LOGDEBUG)
|
|
|
|
|
popinfo(f"Debug: Nalezen ident: {episode['ident']}")
|
|
|
|
|
if verify_ident(episode['ident'], token):
|
|
|
|
|
xbmc.log("Debug: Ident je platný, vytvářím přehrávatelnou položku", xbmc.LOGDEBUG)
|
|
|
|
|
popinfo("Debug: Ident je platný, vytvářím přehrávatelnou položku")
|
|
|
|
|
# Vytvoř přehrávatelnou položku
|
|
|
|
|
listitem = xbmcgui.ListItem(label=episode['title'])
|
|
|
|
|
listitem.setArt({'icon': serie_data.get('icon', 'DefaultTVShows.png')})
|
|
|
|
|
listitem.setInfo('video', {'title': episode['title']})
|
|
|
|
|
listitem.setProperty('IsPlayable', 'true')
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='play', ident=episode['ident'], name=episode['title']), listitem, False)
|
|
|
|
|
# Ukonči adresář bez volání endOfDirectory na konci
|
|
|
|
|
xbmcplugin.addSortMethod(_handle, xbmcplugin.SORT_METHOD_LABEL)
|
|
|
|
|
popinfo("Debug: Ukončuji mojedb funkci")
|
|
|
|
|
xbmcplugin.endOfDirectory(_handle, updateListing=updateListing)
|
|
|
|
|
return
|
|
|
|
|
else:
|
|
|
|
|
xbmc.log("Debug: Ident není platný, zobrazuji výsledky vyhledávání", xbmc.LOGDEBUG)
|
|
|
|
|
popinfo("Debug: Ident není platný, zobrazuji výsledky vyhledávání")
|
|
|
|
|
# Pokud ident není platný, použij vyhledávání
|
|
|
|
|
what = episode['search']
|
|
|
|
|
category = 'video'
|
|
|
|
|
sort = 'recent'
|
|
|
|
|
limit = 20 # Zobraz více výsledků
|
|
|
|
|
offset = 0
|
|
|
|
|
dosearch(token, what, category, sort, limit, offset, 'search')
|
|
|
|
|
else:
|
|
|
|
|
popinfo("Debug: Není ident, zobrazuji výsledky vyhledávání")
|
|
|
|
|
what = episode['search']
|
|
|
|
|
category = 'video'
|
|
|
|
|
sort = 'recent'
|
|
|
|
|
limit = 20 # Zobraz více výsledků
|
|
|
|
|
offset = 0
|
|
|
|
|
dosearch(token, what, category, sort, limit, offset, 'search')
|
|
|
|
|
|
|
|
|
|
# Výpis filmů
|
|
|
|
|
elif params.get('type') == 'movies':
|
|
|
|
|
for idx, movie in enumerate(dbdata.get('movies', [])):
|
|
|
|
|
listitem = xbmcgui.ListItem(label=movie['title'])
|
|
|
|
|
listitem.setArt({'icon': movie.get('icon', 'DefaultMovies.png')})
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='mojedb', type='movies', movie_idx=idx), listitem, True)
|
|
|
|
|
|
|
|
|
|
# Vyhledání konkrétního filmu
|
|
|
|
|
elif params.get('type') == 'movies' and params.get('movie_idx') is not None:
|
|
|
|
|
movie = dbdata['movies'][int(params['movie_idx'])]
|
|
|
|
|
if 'ident' in movie:
|
|
|
|
|
if verify_ident(movie['ident'], token):
|
|
|
|
|
# Vytvoř přehrávatelnou položku
|
|
|
|
|
listitem = xbmcgui.ListItem(label=movie['title'])
|
|
|
|
|
listitem.setArt({'icon': movie.get('icon', 'DefaultMovies.png')})
|
|
|
|
|
listitem.setInfo('video', {'title': movie['title']})
|
|
|
|
|
listitem.setProperty('IsPlayable', 'true')
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='play', ident=movie['ident'], name=movie['title']), listitem, False)
|
|
|
|
|
# Ukonči adresář bez volání endOfDirectory na konci
|
|
|
|
|
xbmcplugin.addSortMethod(_handle, xbmcplugin.SORT_METHOD_LABEL)
|
|
|
|
|
popinfo("Debug: Ukončuji mojedb funkci")
|
|
|
|
|
xbmcplugin.endOfDirectory(_handle, updateListing=updateListing)
|
|
|
|
|
return
|
|
|
|
|
else:
|
|
|
|
|
popinfo("Debug: Ident filmu není platný, zobrazuji výsledky vyhledávání")
|
|
|
|
|
# Pokud ident není platný, použij vyhledávání
|
|
|
|
|
what = movie['search']
|
|
|
|
|
category = 'video'
|
|
|
|
|
sort = 'recent'
|
|
|
|
|
limit = 20 # Zobraz více výsledků
|
|
|
|
|
offset = 0
|
|
|
|
|
dosearch(token, what, category, sort, limit, offset, 'search')
|
|
|
|
|
else:
|
|
|
|
|
popinfo("Debug: Film nemá ident, zobrazuji výsledky vyhledávání")
|
|
|
|
|
what = movie['search']
|
|
|
|
|
category = 'video'
|
|
|
|
|
sort = 'recent'
|
|
|
|
|
limit = 20 # Zobraz více výsledků
|
|
|
|
|
offset = 0
|
|
|
|
|
dosearch(token, what, category, sort, limit, offset, 'search')
|
|
|
|
|
|
|
|
|
|
xbmcplugin.addSortMethod(_handle, xbmcplugin.SORT_METHOD_LABEL)
|
|
|
|
|
popinfo("Debug: Ukončuji mojedb funkci")
|
|
|
|
|
xbmcplugin.endOfDirectory(_handle, updateListing=updateListing)
|
|
|
|
|
|
|
|
|
|
def menu():
|
|
|
|
|
revalidate()
|
|
|
|
|
xbmcplugin.setPluginCategory(_handle, _addon.getAddonInfo('name'))
|
|
|
|
|
listitem = xbmcgui.ListItem(label=_addon.getLocalizedString(30201))
|
|
|
|
|
listitem.setArt({'icon': 'DefaultAddonsSearch.png'})
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='search'), listitem, True)
|
|
|
|
|
|
|
|
|
|
listitem = xbmcgui.ListItem(label=_addon.getLocalizedString(30202))
|
|
|
|
|
listitem.setArt({'icon': 'DefaultPlaylist.png'})
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='queue'), listitem, True)
|
|
|
|
|
|
|
|
|
|
listitem = xbmcgui.ListItem(label=_addon.getLocalizedString(30203))
|
|
|
|
|
listitem.setArt({'icon': 'DefaultAddonsUpdates.png'})
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='history'), listitem, True)
|
|
|
|
|
|
|
|
|
|
listitem = xbmcgui.ListItem(label=_addon.getLocalizedString(30220))
|
|
|
|
|
listitem.setArt({'icon': 'DefaultFavourites.png'})
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='mojedb'), listitem, True)
|
|
|
|
|
|
|
|
|
|
if 'true' == _addon.getSetting('experimental'):
|
|
|
|
|
listitem = xbmcgui.ListItem(label='Backup DB')
|
|
|
|
|
listitem.setArt({'icon': 'DefaultAddonsZip.png'})
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='db'), listitem, True)
|
|
|
|
|
|
|
|
|
|
listitem = xbmcgui.ListItem(label=_addon.getLocalizedString(30204))
|
|
|
|
|
listitem.setArt({'icon': 'DefaultAddonService.png'})
|
|
|
|
|
xbmcplugin.addDirectoryItem(_handle, get_url(action='settings'), listitem, False)
|
|
|
|
|
|
|
|
|
|
xbmcplugin.endOfDirectory(_handle)
|
|
|
|
|
|
|
|
|
|
def router(paramstring):
|
|
|
|
|
xbmc.log(f"Debug: Router - paramstring: {paramstring}", xbmc.LOGDEBUG)
|
|
|
|
|
params = dict(parse_qsl(paramstring))
|
|
|
|
|
xbmc.log(f"Debug: Router - params: {params}", xbmc.LOGDEBUG)
|
|
|
|
|
if params:
|
|
|
|
|
action = params.get('action', 'none')
|
|
|
|
|
xbmc.log(f"Debug: Router - action: {action}", xbmc.LOGDEBUG)
|
|
|
|
|
popinfo(f"Debug: Router - action: {action}")
|
|
|
|
|
|
|
|
|
|
if action == 'search':
|
|
|
|
|
search(params)
|
|
|
|
|
elif action == 'queue':
|
|
|
|
|
queue(params)
|
|
|
|
|
elif action == 'history':
|
|
|
|
|
history(params)
|
|
|
|
|
elif action == 'settings':
|
|
|
|
|
settings(params)
|
|
|
|
|
elif action == 'info':
|
|
|
|
|
info(params)
|
|
|
|
|
elif action == 'play':
|
|
|
|
|
play(params)
|
|
|
|
|
elif action == 'download':
|
|
|
|
|
download(params)
|
|
|
|
|
elif action == 'db':
|
|
|
|
|
db(params)
|
|
|
|
|
elif action == 'mojedb':
|
|
|
|
|
xbmc.log(f"Debug: Router - volám mojedb s parametry: {params}", xbmc.LOGDEBUG)
|
|
|
|
|
popinfo(f"Debug: Router - volám mojedb")
|
|
|
|
|
mojedb(params)
|
|
|
|
|
else:
|
|
|
|
|
xbmc.log(f"Debug: Router - neznámá akce: {action}, volám menu", xbmc.LOGDEBUG)
|
|
|
|
|
menu()
|
|
|
|
|
else:
|
|
|
|
|
xbmc.log(f"Debug: Router - žádné parametry, volám menu", xbmc.LOGDEBUG)
|
|
|
|
|
menu()
|