Files
galdistream/galdPl.py

974 lines
42 KiB
Python
Raw Normal View History

# -*- 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")
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()