Skip to content

Commit

Permalink
v.0.4.8p
Browse files Browse the repository at this point in the history
  • Loading branch information
Lunatixz committed Apr 10, 2024
1 parent 728b0be commit 286f588
Show file tree
Hide file tree
Showing 17 changed files with 110 additions and 117 deletions.
2 changes: 1 addition & 1 deletion addons.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addons>
<addon id="plugin.video.pseudotv.live" version="0.4.8o" name="PseudoTV Live" provider-name="Lunatixz">
<addon id="plugin.video.pseudotv.live" version="0.4.8p" name="PseudoTV Live" provider-name="Lunatixz">
<requires>
<import addon="xbmc.python" version="3.0.1"/>
<import addon="pvr.iptvsimple" version="21.8.0"/>
Expand Down
2 changes: 1 addition & 1 deletion addons.xml.md5
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3aa881372ca99713693d604665c17224
c877216d79f7c2973414fd7618c5d37a
2 changes: 1 addition & 1 deletion plugin.video.pseudotv.live/addon.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<addon id="plugin.video.pseudotv.live" version="0.4.8o" name="PseudoTV Live" provider-name="Lunatixz">
<addon id="plugin.video.pseudotv.live" version="0.4.8p" name="PseudoTV Live" provider-name="Lunatixz">
<requires>
<import addon="xbmc.python" version="3.0.1"/>
<import addon="pvr.iptvsimple" version="21.8.0"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,9 @@ msgctxt "#30135"
msgid "Include"
msgstr ""

msgctxt "#30136"
msgid "Include iSpot Adverts"
msgstr ""



Expand Down
16 changes: 14 additions & 2 deletions plugin.video.pseudotv.live/resources/lib/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def __init__(self, service=None):

self.incAdverts = SETTINGS.getSettingInt('Fillers_Commercials')
self.srcAdverts = {"resource":SETTINGS.getSetting('Resource_Commericals').split('|'),
"paths":[]}
"paths":[self.getAdvertPath()]}

self.incTrailer = SETTINGS.getSettingInt('Fillers_Trailers')
self.srcTrailer = {"resource":SETTINGS.getSetting('Resource_Trailers').split('|'),
Expand Down Expand Up @@ -107,6 +107,7 @@ def verify(self, channels=None):

@timeit
def build(self):
PROPERTIES.setEXTProperty('PseudoTVRunning','True')
channels = sorted(self.verify(self.channels.getChannels()), key=lambda k: k['number'])
if not channels:
self.log('build, no verified channels found!')
Expand Down Expand Up @@ -149,6 +150,7 @@ def build(self):

self.pDialog = DIALOG.progressBGDialog(100, self.pDialog, message='%s %s'%(self.pMSG,LANGUAGE(32025) if self.completeBuild else LANGUAGE(32135)))
self.log('build, completeBuild = %s, saved = %s'%(self.completeBuild,self.saveChannelLineups()))
PROPERTIES.setEXTProperty('PseudoTVRunning','False')
return self.completeBuild


Expand Down Expand Up @@ -497,4 +499,14 @@ def getTrailers(self):
def setTrailers(self, nitems={}):
items = mergeDictLST(self.getTrailers(),nitems)
self.log('setTrailers, trailers: %s'%(len(items)))
self.cache.set('getTrailers', items, expiration=datetime.timedelta(days=28), json_data=True)
self.cache.set('getTrailers', items, expiration=datetime.timedelta(days=28), json_data=True)


def getAdvertPath(self):
if bool(self.incAdverts) and SETTINGS.getSettingBool('Include_Adverts'):
if hasAddon('plugin.video.ispot.tv'):
try: folder = os.path.join(xbmcaddon.Addon('plugin.video.ispot.tv').getSetting('Download_Folder'),'')
except: folder = 'special://profile/addon_data/plugin.video.ispot.tv/resources/'
self.log('getAdvertPath, folder: %s'%(folder))
return folder
return ''
2 changes: 2 additions & 0 deletions plugin.video.pseudotv.live/resources/lib/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@
VIDEO_EXTS = xbmc.getSupportedMedia('video').split('|')
MUSIC_EXTS = xbmc.getSupportedMedia('music').split('|')
IMAGE_EXTS = xbmc.getSupportedMedia('picture').split('|')
IMG_EXTS = ['.png','.jpg','.gif']
TEXTURES = 'Textures.xbt'

#file paths
SETTINGS_FLE = os.path.join(SETTINGS_LOC,'settings.xml')
Expand Down
52 changes: 28 additions & 24 deletions plugin.video.pseudotv.live/resources/lib/fillers.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def __init__(self, builder):
"adverts" :{"max":builder.incAdverts,"auto":builder.incAdverts == 1,"enabled":bool(builder.incAdverts),"sources":builder.srcAdverts,"items":{}},
"trailers" :{"max":builder.incTrailer,"auto":builder.incTrailer == 1,"enabled":bool(builder.incTrailer),"sources":builder.srcTrailer,"items":{}}}
self.fillSources()
print('self.bctTypes',self.bctTypes)



Expand All @@ -48,38 +49,37 @@ def log(self, msg, level=xbmc.LOGDEBUG):
def fillSources(self):
if self.bctTypes['trailers'].get('enabled',False) and SETTINGS.getSettingInt('Include_Trailers') < 2:
self.bctTypes['trailers']['items'] = mergeDictLST(self.bctTypes['trailers']['items'],self.builder.getTrailers())

for ftype, values in list(self.bctTypes.items()):
for id in values.get("sources",{}).get("resource",[]): values['items'] = mergeDictLST(values['items'],self.buildSource(ftype,id)) #parse resource packs
for path in values.get("sources",{}).get("paths",[]): values['items'] = mergeDictLST(values['items'],self.buildSource(ftype,path)) #parse vfs paths
for id in values.get("sources",{}).get("resource",[]):
if self.bctTypes[ftype].get('enabled',False): values['items'] = mergeDictLST(values['items'],self.buildSource(ftype,id)) #parse resource packs
for path in values.get("sources",{}).get("paths",[]):
if self.bctTypes[ftype].get('enabled',False): values['items'] = mergeDictLST(values['items'],self.buildSource(ftype,path)) #parse vfs paths


@cacheit(expiration=datetime.timedelta(minutes=15),json_data=False)
def buildSource(self, ftype, path):
self.log('buildSource, type = %s, path = %s'%(ftype, path))
def _parseVFS(path):
tmpDCT = {}
if not hasAddon(path, install=True): return {}
for url, items in list(self.jsonRPC.walkFileDirectory(path,retItem=True).items()):
for item in items:
for key in (item.get('genre',[]) or ['resources']): tmpDCT.setdefault(key.lower(),[]).append(item)
if hasAddon(path, install=True):
for url, items in list(self.jsonRPC.walkFileDirectory(path,chkDuration=True,retItem=True).items()):
for item in items:
for key in (item.get('genre',[]) or ['resources']): tmpDCT.setdefault(key.lower(),[]).append(item)
return tmpDCT

def _parseLocal(path):
tmpDCT = {}
print('_parseLocal',self.jsonRPC.walkListDirectory(path,appendPath=True))
# dirs, files = self.jsonRPC.walkListDirectory(path,appendPath=True)
# for idx, dir in enumerate(dirs):
# for file in files[idx]
# tmpDCT.setdefault(os.path.basename(dir).lower(),[]).append([ for file in])


# dur = self.jsonRPC.getDuration(item.get('file'),item, accurate=True)
# tmpDCT.setdefault('resources',[]).append([(item.get('file'),item.get('duration')) for item in items if item.get('duration',0) > 0])
print('_parseLocal',path,FileAccess.exists(path))
if FileAccess.exists(path):
for paths, items in list(self.jsonRPC.walkListDirectory(path, exts=VIDEO_EXTS, depth=50, chkDuration=True).items()):
print('_parseLocal',path,items)
for item in items:
for key in (item.get('genre',[]) or ['resources']): tmpDCT.setdefault(key.lower(),[]).append(item)
return tmpDCT

def _parseResource(path):
if not hasAddon(path, install=True): return {}
if not hasAddon(path, install=True): return [],[]
return self.resources.walkResource(path,exts=VIDEO_EXTS)

def _sortbyfile(data):
Expand All @@ -92,18 +92,22 @@ def _sortbyfile(data):

def _sortbyfolder(data):
tmpDCT = {}
print('_sortbyfolder',data)
for path, files in list(data.items()):
for file in files:
dur = self.jsonRPC.getDuration(os.path.join(path,file), accurate=True)
if dur > 0: tmpDCT.setdefault(os.path.basename(path).lower(),[]).append({'file':os.path.join(path,file),'duration':dur,'label':os.path.basename(path)})
return tmpDCT

if path.startswith('plugin://'): return _parseVFS(path)
if ftype == 'ratings': return _sortbyfile(_parseResource(path))
elif ftype == 'bumpers': return _sortbyfolder(_parseResource(path))
elif ftype == 'adverts': return _sortbyfolder(_parseResource(path))
elif ftype == 'trailers': return _sortbyfolder(_parseResource(path))
else: return {}
if not path: return {}
elif path.startswith('resource.'):
if ftype == 'ratings': return _sortbyfile(_parseResource(path))
elif ftype == 'bumpers': return _sortbyfolder(_parseResource(path))
elif ftype == 'adverts': return _sortbyfolder(_parseResource(path))
elif ftype == 'trailers': return _sortbyfolder(_parseResource(path))
elif path.startswith('plugin://'): return _parseVFS(path)
elif not path.startswith(tuple(VFS_TYPES)): return _sortbyfolder(_parseLocal(path))
else: return {}


def convertMPAA(self, ompaa):
Expand Down
2 changes: 1 addition & 1 deletion plugin.video.pseudotv.live/resources/lib/globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ def setFirstrun(state=True):
return PROPERTIES.setPropertyBool('hasFirstrun',state)

def isClient(silent=True):
state = (SETTINGS.getSettingBool('Client_Mode') or False)
state = SETTINGS.getSettingInt('Client_Mode') > 0
PROPERTIES.setEXTProperty('%s.isClient'%(ADDON_ID),str(state).lower())
if state and not silent: DIALOG.notificationWait(LANGUAGE(32115))
return state
Expand Down
60 changes: 29 additions & 31 deletions plugin.video.pseudotv.live/resources/lib/jsonrpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,16 @@ def cacheJSON(self, param, life=datetime.timedelta(minutes=15), checksum=ADDON_V
return cacheResponse


def walkFileDirectory(self, path, depth=3, chkDuration=True, retItem=False):
def walkFileDirectory(self, path, exts=VIDEO_EXTS, depth=3, chkDuration=False, retItem=False, checksum=ADDON_VERSION, expiration=datetime.timedelta(minutes=15)):
self.log('walkFileDirectory, path = %s, exts = %s'%(path,exts))
walk = dict()
dirs = [path]
for idx, dir in enumerate(dirs):
if MONITOR.waitForAbort(0.001) or idx > depth: break
else:
for item in self.getDirectory(param={"directory":dir}, expiration=datetime.timedelta(days=MAX_GUIDEDAYS)).get('files',[]):
if not item.get('file'): continue
self.log('walkFileDirectory, walking %s/%s directory'%(idx,len(dirs)))
for item in self.getDirectory(param={"directory":dir}).get('files',[]):
if not item.get('file') or not item.get('file','').endswith(tuple(exts)): continue
elif item.get('filetype') == 'directory': dirs.append(item.get('file'))
elif item.get('filetype') == 'file':
if chkDuration:
Expand All @@ -109,29 +111,33 @@ def walkFileDirectory(self, path, depth=3, chkDuration=True, retItem=False):
return walk


def walkListDirectory(self, path, depth=3, hasruntime=False, appendPath=False, checksum=ADDON_VERSION, expiration=datetime.timedelta(days=MAX_GUIDEDAYS)):
def chkruntime(file):
return self.getDuration(file) > 0

dirs = [path]
files = []
for idx, dir in enumerate(dirs):
def walkListDirectory(self, path, exts=VIDEO_EXTS, depth=3, chkDuration=False, appendPath=True, checksum=ADDON_VERSION, expiration=datetime.timedelta(minutes=15)):
def _chkfile(path, f):
if appendPath: f = os.path.join(path,f)
if chkDuration:
if self.getDuration(f, accurate=True) == 0: return
return f

def _parseXBT():
resource = path.replace('/resources','').replace('special://home/addons/','resource://')
walk.setdefault(resource,[]).extend(self.getListDirectory(resource,checksum,expiration)[1])
return walk

self.log('walkListDirectory, path = %s, exts = %s'%(path,exts))
walk = dict()
path = path.replace('\\','/')
dirs, files = self.getListDirectory(path,checksum,expiration)
if TEXTURES in files: return _parseXBT()
else: walk.setdefault(path,[]).extend(list(filter(None,[_chkfile(path, f) for f in files if f.endswith(tuple(exts))])))
for idx, dir in enumerate(dirs):
if MONITOR.waitForAbort(0.001) or idx > depth: break
else:
ndirs, nfiles = self.getListDirectory(dir, checksum, expiration)
if hasruntime: nfiles = [file for file in nfiles if chkruntime(file)]
if appendPath:
dirs.extend([os.path.join(path,dir) for dir in ndirs])
files.extend([os.path.join(path,fle) for fle in nfiles])
else:
dirs.extend(ndirs)
files.extend(nfiles)

self.log('walkListDirectory, return dirs = %s, files = %s\npath = %s'%(len(dirs), len(files),path))
return dirs, files

self.log('walkListDirectory, walking %s/%s directory'%(idx,len(dirs)))
walk.update(self.walkListDirectory(os.path.join(path, dir),exts,checksum))
return walk

def getListDirectory(self, path, checksum=ADDON_VERSION, expiration=datetime.timedelta(days=MAX_GUIDEDAYS)):

def getListDirectory(self, path, checksum=ADDON_VERSION, expiration=datetime.timedelta(minutes=15)):
cacheName = 'getListDirectory.%s'%(getMD5(path))
results = self.cache.get(cacheName, checksum)
if not results:
Expand Down Expand Up @@ -535,11 +541,3 @@ def padItems(self, items, page=SETTINGS.getSettingInt('Page_Limit')):
items.append(item)
self.log("padItems; items Out = %s"%(len(items)))
return items


def hasPVRSource(self):
for item in self.getSources():
if item.get('file','').lower().startswith('pvr://'):
return True
return False

5 changes: 3 additions & 2 deletions plugin.video.pseudotv.live/resources/lib/kodi.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,11 @@ def closeBusyDialog():

@contextmanager
def busy_dialog():
if not isBusyDialog(): Builtin().executebuiltin('ActivateWindow(busydialognocancel)')
# if not isBusyDialog(): Builtin().executebuiltin('ActivateWindow(busydialognocancel)')
try: yield
finally: #todo debug kodi crashing.
if isBusyDialog(): Builtin().executebuiltin('Dialog.Close(busydialognocancel)')
pass
# if isBusyDialog(): Builtin().executebuiltin('Dialog.Close(busydialognocancel)')

@contextmanager
def sudo_dialog(msg):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,4 @@ def readBlock(self):
except:
pass

return box
return box
24 changes: 5 additions & 19 deletions plugin.video.pseudotv.live/resources/lib/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ class Plugin:
@contextmanager
def preparingPlayback(self):
if self.playCheck(loadJSON(PROPERTIES.getEXTProperty('%s.lastPlayed.sysInfo'%(ADDON_ID)))):
PROPERTIES.setEXTProperty('PseudoTVRunning','True')
self.preparingPlayback = True
try: yield
finally:
PROPERTIES.setEXTProperty('PseudoTVRunning','False')
PROPERTIES.setEXTProperty('%s.lastPlayed.sysInfo'%(ADDON_ID),dumpJSON(self.sysInfo))
self.preparingPlayback = False
else:
Expand Down Expand Up @@ -203,20 +205,6 @@ def matchChannel(self, chname, id, radio=False, isPlaylist=False):
self.log('matchChannel, id = %s, chname = %s, radio = %s, isPlaylist = %s'%(id,chname,radio,isPlaylist))
def getCallback(chname, id, radio=False, isPlaylist=False):
self.log('getCallback, id = %s, radio = %s, isPlaylist = %s'%(id,radio,isPlaylist))
def _matchVFS():
pvrRoot = "pvr://channels/{dir}/".format(dir={True:'radio',False:'tv'}[radio])
results = jsonRPC.walkListDirectory(pvrRoot,checksum=getInstanceID(),expiration=datetime.timedelta(minutes=OVERLAY_DELAY))[0]
for dir in [ADDON_NAME,'All channels']: #todo "All channels" may not work with non-English translations!
for result in results:
if result.lower().startswith(quoteString(dir.lower())):
self.log('getCallback: _matchVFS, found dir = %s'%(os.path.join(pvrRoot,result)))
response = jsonRPC.walkListDirectory(os.path.join(pvrRoot,result),appendPath=True,checksum=getInstanceID(),expiration=datetime.timedelta(minutes=OVERLAY_DELAY))[1]
for pvr in response:
if pvr.lower().endswith('%s.pvr'%(id)):
self.log('getCallback: _matchVFS, found file = %s'%(pvr))
return pvr
self.log('getCallback: _matchVFS, no callback found!\nresults = %s'%(results))

def _matchJSON():
results = jsonRPC.getDirectory(param={"directory":"pvr://channels/{dir}/".format(dir={True:'radio',False:'tv'}[radio])}, cache=True).get('files',[])
for dir in [ADDON_NAME,'All channels']: #todo "All channels" may not work with non-English translations!
Expand All @@ -232,8 +220,6 @@ def _matchJSON():

if (isPlaylist or radio) and len(self.sysARG) > 2:
callback = '%s%s'%(self.sysARG[0],self.sysARG[2])
elif isLowPower() or not PROPERTIES.getPropertyBool('hasPVRSource'):
callback = _matchVFS()
else:
callback = _matchJSON() #use faster jsonrpc on high power devices. requires 'pvr://' json whitelisting.
if callback is None: return DIALOG.okDialog(LANGUAGE(32133))
Expand Down Expand Up @@ -285,10 +271,10 @@ def playCheck(self, oldInfo={}):
self.log('playCheck, id = %s\noldInfo = %s'%(oldInfo.get('chid','-1'),oldInfo))
def _chkPath():
if self.sysInfo.get('vid','').startswith(tuple(VFS_TYPES+["special://"])):
if hasAddon(getIDbyPath(self.sysInfo.get('vid','')),install=True,enable=True): return False
elif FileAccess.exists(self.sysInfo.get('vid','')): return False
if hasAddon(getIDbyPath(self.sysInfo.get('vid','')),install=True,enable=True): return True
elif FileAccess.exists(self.sysInfo.get('vid','')): return True
self.log('playCheck _chkPath, failed! path (%s) not found.'%(self.sysInfo.get('vid','')))
return True
return False

def _chkGuide():
if (self.sysInfo.get('chid') == self.sysInfo.get('citem',{}).get('id',random.random()) and self.sysInfo.get('title') != self.sysInfo.get('fitem',{}).get('label',self.sysInfo.get('title'))):
Expand Down
Loading

0 comments on commit 286f588

Please sign in to comment.