diff --git a/addons.xml b/addons.xml index 7110cc97..2d1a0a51 100644 --- a/addons.xml +++ b/addons.xml @@ -1,6 +1,6 @@ - + diff --git a/addons.xml.md5 b/addons.xml.md5 index 61c9e7a4..e031e354 100644 --- a/addons.xml.md5 +++ b/addons.xml.md5 @@ -1 +1 @@ -a3abfbe736a27b47783daeab4dcbd30c \ No newline at end of file +b3595896623cfbf05b58126ffae488a2 \ No newline at end of file diff --git a/language_report.txt b/language_report.txt index fb45a354..2002bb64 100644 --- a/language_report.txt +++ b/language_report.txt @@ -1,6 +1,4 @@ Language IDS w\empty strings: { - "32024": "", - "32197": "", "33085": "", "33130": "" } @@ -171,7 +169,6 @@ Language IDS not found in py files, possibly only in xml: { "32011": "Music Genres", "32012": "Recommended", "32013": "Services", - "32024": "", "32033": "Offline", "32048": "Select Servers", "32049": "Restarting...", @@ -210,7 +207,6 @@ Language IDS not found in py files, possibly only in xml: { "32170": "- Delete Path", "32177": "Finish Configuring channel first", "32182": "ZeroConf Status:", - "32197": "", "32208": "Parsing Trailer", "32210": "Parsing Details", "32218": "Not Needed...", diff --git a/plugin.video.pseudotv.live/addon.xml b/plugin.video.pseudotv.live/addon.xml index 412fbece..83285f4b 100644 --- a/plugin.video.pseudotv.live/addon.xml +++ b/plugin.video.pseudotv.live/addon.xml @@ -1,5 +1,5 @@ - + diff --git a/plugin.video.pseudotv.live/resources/language/resource.language.en_gb/strings.po b/plugin.video.pseudotv.live/resources/language/resource.language.en_gb/strings.po index 1cbdc5cd..3cd35433 100644 --- a/plugin.video.pseudotv.live/resources/language/resource.language.en_gb/strings.po +++ b/plugin.video.pseudotv.live/resources/language/resource.language.en_gb/strings.po @@ -916,7 +916,7 @@ msgid "Channel" msgstr "" msgctxt "#32024" -msgid "" +msgid "Autotuning available via Misc. Utilities" msgstr "" msgctxt "#32025" @@ -1608,7 +1608,7 @@ msgid "Video" msgstr "" msgctxt "#32197" -msgid "" +msgid "Currently Supported!" msgstr "" msgctxt "#32198" diff --git a/plugin.video.pseudotv.live/resources/lib/autotune.py b/plugin.video.pseudotv.live/resources/lib/autotune.py index c9f0a3de..974f3426 100644 --- a/plugin.video.pseudotv.live/resources/lib/autotune.py +++ b/plugin.video.pseudotv.live/resources/lib/autotune.py @@ -21,7 +21,6 @@ from globals import * from library import Library from channels import Channels -from backup import Backup class Autotune: def __init__(self, sysARG=sys.argv, service=None): @@ -50,21 +49,24 @@ def getAutotuned(self) -> dict: def _runTune(self, samples: bool=False, rebuild: bool=False, dia=None): + autoEnabled = [] customChannels = self.getCustom() autoChannels = self.getAutotuned() - self.log('_runTune, custom channels = %s, autotune channels = %s'%(len(customChannels),len(autoChannels))) + hasAutotuned = SETTINGS.hasAutotuned() + self.log('_runTune, custom channels = %s, autotune channels = %s, has autotuned = %s'%(len(customChannels),len(autoChannels),hasAutotuned)) - if len(autoChannels) > 0: #rebuild existing autotune + if len(autoChannels) > 0: #rebuild existing autotune, no samples needed rebuild = True PROPERTIES.setEXTPropertyBool('%s.has.Predefined'%(ADDON_ID),True) - elif len(customChannels) == 0 and not PROPERTIES.hasAutotuned(): - autoEnabled = [] + elif len(customChannels) == 0 and not hasAutotuned: #begin check if samples needed [autoEnabled.extend(self.library.getEnabled(type)) for type in AUTOTUNE_TYPES] if len(autoEnabled) > 0: self.log('_runTune, library enabled items = %s; recovering enabled items'%(len(autoEnabled))) - rebuild = True #recover empty channels.json with enabled library.json items. - elif isCenterlized(): return True - else: samples = True #create sample channels "autotune". + rebuild = True #recover empty channels.json with enabled library.json items. + elif hasAutotuned: # autotune already ran once, manual only going forward + return DIALOG.notificationDialog(LANGUAGE(32024)) + else: + samples = True #create sample channels "autotune". if samples: hasBackup = PROPERTIES.hasBackup() @@ -82,11 +84,12 @@ def _runTune(self, samples: bool=False, rebuild: bool=False, dia=None): msg = (LANGUAGE(32042)%ADDON_NAME) retval = DIALOG.yesnoDialog(message=msg,customlabel=opt) - if retval == 1: dia = DIALOG.progressBGDialog(header='%s, %s'%(ADDON_NAME,'%s %s'%(LANGUAGE(32021),LANGUAGE(30038)))) - elif retval == 2: - if hasBackup: return Backup().recoverChannels() + if retval == 1: dia = DIALOG.progressBGDialog(header='%s, %s'%(ADDON_NAME,'%s %s'%(LANGUAGE(32021),LANGUAGE(30038)))) #Yes + elif retval == 2: #Custom + if hasBackup: return BUILTIN.executebuiltin('RunScript(special://home/addons/%s/resources/lib/backup.py, Recover_Channels)'%(ADDON_ID)) elif hasServers: return BUILTIN.executebuiltin('RunScript(special://home/addons/%s/resources/lib/multiroom.py, Select_Server)'%(ADDON_ID)) - elif not hasChannels: return openAddonSettings() + elif not hasChannels: return openAddonSettings() #No w/exception + else: return True #No else: return True for idx, ATtype in enumerate(AUTOTUNE_TYPES): @@ -137,10 +140,9 @@ def buildAUTOTUNE(self, ATtype: str, items: list=[]): if not list: return def buildAvailableRange(existing): # create number array for given type, excluding existing channel numbers. - if existing: - existingNUMBERS = [eitem.get('number') for eitem in existing if eitem.get('number',0) > 0] # existing channel numbers - else: - existingNUMBERS = [] + if existing: existingNUMBERS = [eitem.get('number') for eitem in existing if eitem.get('number',0) > 0] # existing channel numbers + else: existingNUMBERS = [] + start = ((CHANNEL_LIMIT+1)*(AUTOTUNE_TYPES.index(ATtype)+1)) stop = (start + CHANNEL_LIMIT) self.log('buildAUTOTUNE, ATtype = %s, range = %s-%s, existingNUMBERS = %s'%(ATtype,start,stop,existingNUMBERS)) @@ -173,7 +175,7 @@ def buildAvailableRange(existing): citem['logo'] = eitem.get('logo',citem.get('logo',LOGO)) citem['favorite'] = eitem.get('favorite',False) self.channels.addChannel(citem) - PROPERTIES.setUpdateChannels(citem['id']) + SETTINGS.setUpdateChannels(citem['id']) return self.channels.setChannels() diff --git a/plugin.video.pseudotv.live/resources/lib/builder.py b/plugin.video.pseudotv.live/resources/lib/builder.py index 7c354b14..b2278936 100644 --- a/plugin.video.pseudotv.live/resources/lib/builder.py +++ b/plugin.video.pseudotv.live/resources/lib/builder.py @@ -465,7 +465,7 @@ def buildList(self, citem: dict, path: str, media: str='video', page: int=SETTIN fileList = randomShuffle(fileList) self.kodiTrailers(trailersdict) - self.log("buildList, id: %s returning (%s) files, (%s) dirs."%(citem['id'],len(fileList),len(dirList))) + self.log("buildList, [%s] returning (%s) files, (%s) dirs."%(citem['id'],len(fileList),len(dirList))) return fileList, dirList diff --git a/plugin.video.pseudotv.live/resources/lib/context_create.py b/plugin.video.pseudotv.live/resources/lib/context_create.py index 94e2f104..61542060 100644 --- a/plugin.video.pseudotv.live/resources/lib/context_create.py +++ b/plugin.video.pseudotv.live/resources/lib/context_create.py @@ -46,7 +46,7 @@ def add(self): channelData['id'] = getChannelID(channelData['name'], channelData['path'], channelData['number']) manager.channels.addChannel(channelData) manager.channels.setChannels() - PROPERTIES.setUpdateChannels(channelData['id']) + SETTINGS.setUpdateChannels(channelData['id']) manager.closeManager() del manager manager = Manager(MANAGER_XML, ADDON_PATH, "default", channel=channelData['number']) diff --git a/plugin.video.pseudotv.live/resources/lib/default.py b/plugin.video.pseudotv.live/resources/lib/default.py index ef107287..5757aac4 100644 --- a/plugin.video.pseudotv.live/resources/lib/default.py +++ b/plugin.video.pseudotv.live/resources/lib/default.py @@ -33,10 +33,11 @@ def run(sysARG, fitem: dict={}, nitem: dict={}): params['name'] = (unquoteString(params.get("name",'')) or BUILTIN.getInfoLabel('ChannelName')) params['isPlaylist'] = bool(SETTINGS.getSettingInt('Playback_Method')) log("Default: run, params = %s"%(params)) - if PROPERTIES.isRunning('togglePVR'): DIALOG.notificationDialog(LANGUAGE(32000)) - elif params.get('start') == '{utc}': DIALOG.okDialog(LANGUAGE(32129)%(PVR_CLIENT_NAME)) + + if PROPERTIES.isRunning('togglePVR'): DIALOG.notificationDialog(LANGUAGE(32000)) elif mode == 'live': - if params['isPlaylist']: threadit(Plugin(sysARG, sysInfo=params).playPlaylist)(params["name"],params["chid"]) + if params.get('start') == '{utc}':DIALOG.okDialog(LANGUAGE(32129)%(PVR_CLIENT_NAME)) + elif params['isPlaylist']: threadit(Plugin(sysARG, sysInfo=params).playPlaylist)(params["name"],params["chid"]) elif params['vid'] : threadit(Plugin(sysARG, sysInfo=params).playLive)(params["name"],params["chid"],params["vid"]) else: threadit(Plugin(sysARG, sysInfo=params).playTV)(params["name"],params["chid"]) elif mode in ['vod','dvr']: threadit(Plugin(sysARG, sysInfo=params).playVOD)(params["title"],params["vid"]) @@ -46,5 +47,6 @@ def run(sysARG, fitem: dict={}, nitem: dict={}): elif mode == 'guide' and hasAddon(PVR_CLIENT_ID,install=True,enable=True): SETTINGS.openGuide() elif mode == 'settings' and hasAddon(PVR_CLIENT_ID,install=True,enable=True): openAddonSettings() else: DIALOG.notificationDialog(LANGUAGE(32000)) + MONITOR().waitForAbort(float(SETTINGS.getSettingInt('RPC_Delay')/1000)) if __name__ == '__main__': run(sys.argv,fitem=decodePlot(BUILTIN.getInfoLabel('Plot')),nitem=decodePlot(BUILTIN.getInfoLabel('NextPlot'))) \ No newline at end of file diff --git a/plugin.video.pseudotv.live/resources/lib/globals.py b/plugin.video.pseudotv.live/resources/lib/globals.py index d38b55c5..04ba1161 100644 --- a/plugin.video.pseudotv.live/resources/lib/globals.py +++ b/plugin.video.pseudotv.live/resources/lib/globals.py @@ -232,12 +232,6 @@ def openAddonSettings(ctl=(0,1),id=ADDON_ID): BUILTIN.executebuiltin('SetFocus(%i)'%(ctl[1]-180)) return True -def startChannelBuild(): - PROPERTIES.setAutotuned(False) - PROPERTIES.setEpochTimer('chkAutoTune') - BUILTIN.closeBusyDialog() - return BUILTIN.executebuiltin('ActivateWindow(home)') - def diffRuntime(dur, roundto=15): def ceil_dt(dt, delta): return dt + (datetime.datetime.min - dt) % delta diff --git a/plugin.video.pseudotv.live/resources/lib/kodi.py b/plugin.video.pseudotv.live/resources/lib/kodi.py index d8296bec..c85d597b 100644 --- a/plugin.video.pseudotv.live/resources/lib/kodi.py +++ b/plugin.video.pseudotv.live/resources/lib/kodi.py @@ -246,6 +246,49 @@ def getCacheSetting(self, key, checksum=1, json_data=False, revive=True): else: return self.cacheDB.get(key, checksum, json_data) + def getEXTMeta(self, id): + addon = xbmcaddon.Addon(id) + properties = ['name', 'version', 'summary', 'description', 'path', 'author', 'icon', 'disclaimer', 'fanart', 'changelog', 'id', 'profile', 'stars', 'type'] + for property in properties: yield (property, addon.getAddonInfo(property)) + + + def getEXTSetting(self, id, key): + return xbmcaddon.Addon(id).getSetting(key) + + + def getFriendlyName(self): + from jsonrpc import JSONRPC + return JSONRPC().inputFriendlyName() + + + def getMYUUID(self): + friendly = self.getFriendlyName() + uuid = self.getCacheSetting('MY_UUID', checksum=friendly) + if not uuid: uuid = self.setCacheSetting('MY_UUID', genUUID(seed=self.getFriendlyName()), checksum=friendly) + return uuid + + + def getResetChannels(self): + ids = (self.getCacheSetting('clearChannels') or []) + self.clrCacheSetting('clearChannels') + return ids + + + def getUpdateChannels(self): + ids = (self.getCacheSetting('updateChannels') or []) + self.clrCacheSetting('updateChannels') + return ids + + + def hasAutotuned(self): + return self.getCacheSetting('has.Autotuned') == True + + + #CLR + def clrCacheSetting(self, key, checksum=1, life=datetime.timedelta(days=84), json_data=False): + self.setCacheSetting(key, None, checksum, life, json_data) + + #SET def _setSetting(self, func, key, value): try: @@ -306,30 +349,24 @@ def setCacheSetting(self, key, value, checksum=1, life=datetime.timedelta(days=8 return self.cacheDB.set(key, value, checksum, life, json_data) - def getEXTMeta(self, id): - addon = xbmcaddon.Addon(id) - properties = ['name', 'version', 'summary', 'description', 'path', 'author', 'icon', 'disclaimer', 'fanart', 'changelog', 'id', 'profile', 'stars', 'type'] - for property in properties: yield (property, addon.getAddonInfo(property)) - - - def getEXTSetting(self, id, key): - return xbmcaddon.Addon(id).getSetting(key) - - def setEXTSetting(self, id, key, value): return xbmcaddon.Addon(id).setSetting(key,value) - def getFriendlyName(self): - from jsonrpc import JSONRPC - return JSONRPC().inputFriendlyName() + def setUpdateChannels(self, id): + ids = self.getUpdateChannels() + ids.append(id) + return self.setCacheSetting('updateChannels',list(set(ids))) + + + def setResetChannels(self, id): + ids = self.getResetChannels() + ids.append(id) + return self.setCacheSetting('clearChannels',list(set(ids))) - def getMYUUID(self): - friendly = self.getFriendlyName() - uuid = self.getCacheSetting('MY_UUID', checksum=friendly) - if not uuid: uuid = self.setCacheSetting('MY_UUID', genUUID(seed=self.getFriendlyName()), checksum=friendly) - return uuid + def setAutotuned(self, state=True): + return self.setCacheSetting('has.Autotuned',state) @cacheit(expiration=datetime.timedelta(minutes=5), json_data=True) @@ -609,7 +646,7 @@ def log(self, msg, level=xbmc.LOGDEBUG): def clrInstanceID(self): instanceID = self.getEXTProperty('%s.InstanceID'%(ADDON_ID)) if instanceID: self.clearTrash(instanceID) - self.clearEXTProperty('%s.InstanceID'%(ADDON_ID)) + self.clrEXTProperty('%s.InstanceID'%(ADDON_ID)) def setInstanceID(self): @@ -643,42 +680,12 @@ def getLegacy(self): def forceUpdateTime(self, key): return self.setPropertyInt(key,0) - - - def getUpdateChannels(self): - ids = self.getPropertyList('updateChannels') - self.clearProperty('updateChannels') - return ids - - - def setUpdateChannels(self, id): - ids = self.getPropertyList('updateChannels') - ids.append(id) - self.setPropertyList('updateChannels',list(set(ids))) - return self.setEpochTimer('chkChannels') - - - def getClearChannels(self): - ids = self.getPropertyList('clearChannels') - self.clearProperty('clearChannels') - return ids - - - def setClearChannels(self, id): - ids = self.getPropertyList('clearChannels') - ids.append(id) - self.setPropertyList('clearChannels',list(set(ids))) - return self.setEpochTimer('chkChannels') def setEpochTimer(self, key, state=True): return self.setEXTPropertyBool('%s.%s'%(ADDON_ID,key),state) - def setAutotuned(self, state=True): - return self.setEXTPropertyBool('%s.has.Autotuned'%(ADDON_ID),state) - - def setChannels(self, state=True): return self.setEXTPropertyBool('%s.has.Channels'%(ADDON_ID),state) @@ -752,10 +759,6 @@ def suspendActivity(self): #suspend/quit running background task. else: yield - def hasAutotuned(self): - return self.getEXTPropertyBool('%s.has.Autotuned'%(ADDON_ID)) - - def hasChannels(self): return self.getEXTPropertyBool('%s.has.Channels'%(ADDON_ID)) @@ -805,19 +808,19 @@ def getKey(self, key, instanceID=True): #CLEAR - def clearEXTProperty(self, key): - self.log('clearEXTProperty, id = %s, key = %s'%(10000,key)) + def clrEXTProperty(self, key): + self.log('clrEXTProperty, id = %s, key = %s'%(10000,key)) return xbmcgui.Window(10000).clearProperty(key) - def clearProperties(self): - self.log('clearProperties') + def clrProperties(self): + self.log('clrProperties') return self.window.clearProperties() - def clearProperty(self, key): + def clrProperty(self, key): key = self.getKey(key) - self.log('clearProperty, id = %s, key = %s'%(self.winID,key)) + self.log('clrProperty, id = %s, key = %s'%(self.winID,key)) return self.window.clearProperty(key) @@ -912,7 +915,7 @@ def setTrash(self, key): #catalog instance properties that may become abandoned. def clearTrash(self, instanceID=None): #clear abandoned properties after instanceID change self.log('clearTrash, instanceID = %s'%(instanceID)) tmpDCT = loadJSON(self.getEXTProperty('%s.TRASH'%(ADDON_ID))) - for prop in tmpDCT.get(instanceID,[]): self.clearEXTProperty(prop) + for prop in tmpDCT.get(instanceID,[]): self.clrEXTProperty(prop) def __exit__(self): @@ -1126,7 +1129,7 @@ def log(self, msg, level=xbmc.LOGDEBUG): def toggleInfoMonitor(self, state, wait=0.1): self.log('toggleInfoMonitor, state = %s'%(state)) if self.properties.setPropertyBool('chkInfoMonitor',state): - self.properties.clearProperty('monitor.montiorList') + self.properties.clrProperty('monitor.montiorList') timerit(self.doInfoMonitor)(0.1) diff --git a/plugin.video.pseudotv.live/resources/lib/manager.py b/plugin.video.pseudotv.live/resources/lib/manager.py index 7b3d1865..4887bc8e 100644 --- a/plugin.video.pseudotv.live/resources/lib/manager.py +++ b/plugin.video.pseudotv.live/resources/lib/manager.py @@ -709,11 +709,12 @@ def saveChannels(self): elif not DIALOG.yesnoDialog(LANGUAGE(32076)): return with self.toggleSpinner(self.chanList): if self.server: - payload = {'uuid':SETTINGS.getMYUUID(),'name':self.friendly,'channels':self.validateChannels(self.newChannels)} - requestURL('http://%s/%s'%(self.server.get('host'),CHANNELFLE), data=dumpJSON(payload), header=HEADER, json_data=True) + return DIALOG.notificationDialog(LANGUAGE(32197)) + # payload = {'uuid':SETTINGS.getMYUUID(),'name':self.friendly,'channels':self.validateChannels(self.newChannels)} + # requestURL('http://%s/%s'%(self.server.get('host'),CHANNELFLE), data=dumpJSON(payload), header=HEADER, json_data=True) #todo write tmp file if post fails, add to que to repost when url online. else: - [(PROPERTIES.setUpdateChannels(citem.get('id')),PROPERTIES.setClearChannels(citem.get('id'))) for citem in self.validateChannels(diffLSTDICT(self.channelList,self.newChannels))] + [(SETTINGS.setUpdateChannels(citem.get('id')),SETTINGS.setResetChannels(citem.get('id'))) for citem in self.validateChannels(diffLSTDICT(self.channelList,self.newChannels))] self.channels.setChannels(self.validateChannels(self.newChannels)) self.closeManager() diff --git a/plugin.video.pseudotv.live/resources/lib/plugin.py b/plugin.video.pseudotv.live/resources/lib/plugin.py index fdb0b9c7..cf4c6da4 100644 --- a/plugin.video.pseudotv.live/resources/lib/plugin.py +++ b/plugin.video.pseudotv.live/resources/lib/plugin.py @@ -168,21 +168,19 @@ def __buildfItem(idx, item): liz.setProperty('sysInfo',encodeString(dumpJSON(sysInfo))) return liz - with PROPERTIES.suspendActivity(): - from rules import RulesList - nextitems = RulesList().runActions(RULES_ACTION_PLAYBACK_RESUME, self.sysInfo.get('citem',{'name':name,'id':chid})) - if nextitems: - self.IDXModifier = 0 - del nextitems[self.pageLimit-1:]# list of upcoming items, truncate for speed - self.log('getPausedItems, building nextitems (%s)'%(len(nextitems))) - return [__buildfItem(idx, nextitem) for idx, nextitem in enumerate(nextitems)] - else: DIALOG.notificationDialog(LANGUAGE(32000)) - return [] - + from rules import RulesList + nextitems = RulesList().runActions(RULES_ACTION_PLAYBACK_RESUME, self.sysInfo.get('citem',{'name':name,'id':chid})) + if nextitems: + self.IDXModifier = 0 + del nextitems[self.pageLimit-1:]# list of upcoming items, truncate for speed + self.log('getPausedItems, building nextitems (%s)'%(len(nextitems))) + return [__buildfItem(idx, nextitem) for idx, nextitem in enumerate(nextitems)] + else: DIALOG.notificationDialog(LANGUAGE(32000)) + return [] + def getRadioItems(self, name, chid, vid, limit=RADIO_ITEM_LIMIT): - with PROPERTIES.suspendActivity(): - return interleave([self.jsonRPC.requestList({'id':chid}, path, 'music', page=limit, sort={"method":"random"})[0] for path in vid.split('|')], SETTINGS.getSettingInt('Interleave_Value')) + return interleave([self.jsonRPC.requestList({'id':chid}, path, 'music', page=limit, sort={"method":"random"})[0] for path in vid.split('|')], SETTINGS.getSettingInt('Interleave_Value')) def getPVRItems(self, name: str, chid: str) -> list: @@ -210,54 +208,53 @@ def __buildfItem(idx, item): liz.setProperty('sysInfo',encodeString(dumpJSON(sysInfo))) return liz - with PROPERTIES.suspendActivity(): - found = False - pvritem = self._matchChannel(name,chid,radio=False) - if pvritem: - pastItems = pvritem.get('broadcastpast',[]) - nowitem = pvritem.get('broadcastnow',{}) - nextitems = pvritem.get('broadcastnext',[]) # upcoming items - nextitems.insert(0,nowitem) - nextitems = pastItems + nextitems + found = False + pvritem = self._matchChannel(name,chid,radio=False) + if pvritem: + pastItems = pvritem.get('broadcastpast',[]) + nowitem = pvritem.get('broadcastnow',{}) + nextitems = pvritem.get('broadcastnext',[]) # upcoming items + nextitems.insert(0,nowitem) + nextitems = pastItems + nextitems + + if (self.sysInfo.get('fitem') or self.sysInfo.get('vid')): + for pos, nextitem in enumerate(nextitems): + fitem = decodePlot(nextitem.get('plot',{})) + file = self.sysInfo.get('fitem',{}).get('file') if self.sysInfo.get('fitem') else self.sysInfo.get('vid') + if file == fitem.get('file') and self.sysInfo.get('citem',{}).get('id') == fitem.get('citem',{}).get('id',str(random.random())): + found = True + self.log('getPVRItems, id = %s found matching fitem'%(chid)) + del nextitems[0:pos] # start array at correct position + break + + elif self.sysInfo.get('now'): + for pos, nextitem in enumerate(nextitems): + fitem = decodePlot(nextitem.get('plot',{})) + ntime = datetime.datetime.fromtimestamp(float(self.sysInfo.get('now'))) + if ntime >= strpTime(nextitem.get('starttime')) and ntime < strpTime(nextitem.get('endtime')) and chid == fitem.get('citem',{}).get('id',str(random.random())): + found = True + self.log('getPVRItems, id = %s found matching starttime'%(chid)) + del nextitems[0:pos] # start array at correct position + break - if (self.sysInfo.get('fitem') or self.sysInfo.get('vid')): - for pos, nextitem in enumerate(nextitems): - fitem = decodePlot(nextitem.get('plot',{})) - file = self.sysInfo.get('fitem',{}).get('file') if self.sysInfo.get('fitem') else self.sysInfo.get('vid') - if file == fitem.get('file') and self.sysInfo.get('citem',{}).get('id') == fitem.get('citem',{}).get('id',str(random.random())): - found = True - self.log('getPVRItems, id = %s found matching fitem'%(chid)) - del nextitems[0:pos] # start array at correct position - break - - elif self.sysInfo.get('now'): - for pos, nextitem in enumerate(nextitems): - fitem = decodePlot(nextitem.get('plot',{})) - ntime = datetime.datetime.fromtimestamp(float(self.sysInfo.get('now'))) - if ntime >= strpTime(nextitem.get('starttime')) and ntime < strpTime(nextitem.get('endtime')) and chid == fitem.get('citem',{}).get('id',str(random.random())): - found = True - self.log('getPVRItems, id = %s found matching starttime'%(chid)) - del nextitems[0:pos] # start array at correct position - break - - if found: + if found: + nowitem = nextitems.pop(0) + if round(nowitem['progresspercentage']) > self.seekTHD: + self.log('getPVRItems, progress past threshold advance to nextitem') nowitem = nextitems.pop(0) - if round(nowitem['progresspercentage']) > self.seekTHD: - self.log('getPVRItems, progress past threshold advance to nextitem') - nowitem = nextitems.pop(0) - - if round(nowitem['progress']) < self.seekTOL: - self.log('getPVRItems, progress start at the beginning') - nowitem['progress'] = 0 - nowitem['progresspercentage'] = 0 + + if round(nowitem['progress']) < self.seekTOL: + self.log('getPVRItems, progress start at the beginning') + nowitem['progress'] = 0 + nowitem['progresspercentage'] = 0 - del nextitems[self.pageLimit-1:]# list of upcoming items, truncate for speed - nextitems.insert(0,nowitem) - self.log('getPVRItems, building nextitems (%s)'%(len(nextitems))) - return [__buildfItem(idx, item) for idx, item in enumerate(nextitems)] - else: DIALOG.notificationDialog(LANGUAGE(32164)) - else: DIALOG.notificationDialog(LANGUAGE(32000)) - return [] + del nextitems[self.pageLimit-1:]# list of upcoming items, truncate for speed + nextitems.insert(0,nowitem) + self.log('getPVRItems, building nextitems (%s)'%(len(nextitems))) + return [__buildfItem(idx, item) for idx, item in enumerate(nextitems)] + else: DIALOG.notificationDialog(LANGUAGE(32164)) + else: DIALOG.notificationDialog(LANGUAGE(32000)) + return [] def playTV(self, name: str, chid: str): @@ -322,23 +319,26 @@ def playVOD(self, title: str, vid: str): #-> catchup-id def playRadio(self, name: str, chid: str, vid: str): self.log('playRadio, id = %s'%(chid)) def __buildfItem(idx, item: dict={}): return LISTITEMS.buildItemListItem(item, 'music') - listitems = [__buildfItem(idx, item) for idx, item in enumerate(randomShuffle(self.getRadioItems(name, chid, vid)))] - if len(listitems) > 0: PLAYER().play(self._quePlaylist(listitems, pltype=xbmc.PLAYLIST_MUSIC, shuffle=True),windowed=True) - self._resolveURL(False, xbmcgui.ListItem()) + with self.preparingPlayback(), PROPERTIES.suspendActivity(): + listitems = [__buildfItem(idx, item) for idx, item in enumerate(randomShuffle(self.getRadioItems(name, chid, vid)))] + if len(listitems) > 0: PLAYER().play(self._quePlaylist(listitems, pltype=xbmc.PLAYLIST_MUSIC, shuffle=True),windowed=True) + self._resolveURL(False, xbmcgui.ListItem()) def playPlaylist(self, name: str, chid: str): self.log('playPlaylist, id = %s'%(chid)) - listitems = self.getPVRItems(name, chid) - if len(listitems) > 0: PLAYER().play(self._quePlaylist(listitems),windowed=True) - self._resolveURL(False, xbmcgui.ListItem()) + with self.preparingPlayback(), PROPERTIES.suspendActivity(): + listitems = self.getPVRItems(name, chid) + if len(listitems) > 0: PLAYER().play(self._quePlaylist(listitems),windowed=True) + self._resolveURL(False, xbmcgui.ListItem()) def playPaused(self, name: str, chid: str): self.log('playPaused, id = %s'%(chid)) - listitems = self.getPausedItems(name, chid) - if len(listitems) > 0: PLAYER().play(self._quePlaylist(listitems),windowed=True) - self._resolveURL(False, xbmcgui.ListItem()) + with self.preparingPlayback(), PROPERTIES.suspendActivity(): + listitems = self.getPausedItems(name, chid) + if len(listitems) > 0: PLAYER().play(self._quePlaylist(listitems),windowed=True) + self._resolveURL(False, xbmcgui.ListItem()) def playCheck(self, oldInfo: dict={}) -> bool: diff --git a/plugin.video.pseudotv.live/resources/lib/rules.py b/plugin.video.pseudotv.live/resources/lib/rules.py index fef469fe..6ffae731 100644 --- a/plugin.video.pseudotv.live/resources/lib/rules.py +++ b/plugin.video.pseudotv.live/resources/lib/rules.py @@ -370,7 +370,7 @@ def getPosition(self, optionindex): overlaytool = OverlayTool(OVERLAYTOOL_XML, ADDON_PATH, "default", ADV_RULES=True, Focus_IDX=1, Channel_Bug_Position_XY=self.optionValues[optionindex], ChannelBug_Color=self.optionValues[3]) del overlaytool value = PROPERTIES.getProperty("Channel_Bug_Position_XY") - PROPERTIES.clearProperty("Channel_Bug_Position_XY") + PROPERTIES.clrProperty("Channel_Bug_Position_XY") if value: self.optionValues[optionindex] = value else: self.optionValues[optionindex] = orgvalue elif self.optionValues[optionindex] != self.selectBoxOptions[optionindex][0]: @@ -446,7 +446,7 @@ def getPosition(self, optionindex): overlaytool = OverlayTool(OVERLAYTOOL_XML, ADDON_PATH, "default", ADV_RULES=True, Focus_IDX=0, OnNext_Position_XY=self.optionValues[optionindex], OnNext_Color=self.optionValues[2]) del overlaytool value = PROPERTIES.getProperty("OnNext_Position_XY") - PROPERTIES.clearProperty("OnNext_Position_XY") + PROPERTIES.clrProperty("OnNext_Position_XY") if value: self.optionValues[optionindex] = value else: self.optionValues[optionindex] = orgvalue elif self.optionValues[optionindex] != self.selectBoxOptions[optionindex][0]: @@ -1670,7 +1670,7 @@ def runAction(self, actionid, citem, parameter, inherited): self.log("runAction, restoring last resume point = %s"%(resume)) item['resume'] = resume self.storedValues[1].insert(0,item) - if self._getTotDuration(self.storedValues[1]) < (MIN_GUIDEDAYS * 86400) : PROPERTIES.setUpdateChannels(citem.get('id')) + if self._getTotDuration(self.storedValues[1]) < (MIN_GUIDEDAYS * 86400) : SETTINGS.setUpdateChannels(citem.get('id')) return self.storedValues[1] return [] diff --git a/plugin.video.pseudotv.live/resources/lib/service.py b/plugin.video.pseudotv.live/resources/lib/service.py index 70644186..a19fe192 100644 --- a/plugin.video.pseudotv.live/resources/lib/service.py +++ b/plugin.video.pseudotv.live/resources/lib/service.py @@ -180,7 +180,7 @@ def setTrakt(self, state: bool=SETTINGS.getSettingBool('Disable_Trakt')): self.log('setTrakt, state = %s'%(state)) # https://github.com/trakt/script.trakt/blob/d45f1363c49c3e1e83dabacb70729cc3dec6a815/resources/lib/kodiUtilities.py#L104 if state: PROPERTIES.setEXTPropertyBool('script.trakt.paused',state) - else: PROPERTIES.clearEXTProperty('script.trakt.paused') + else: PROPERTIES.clrEXTProperty('script.trakt.paused') def setSubtitles(self, state: bool=True): diff --git a/plugin.video.pseudotv.live/resources/lib/tasks.py b/plugin.video.pseudotv.live/resources/lib/tasks.py index 965be124..b91fd438 100644 --- a/plugin.video.pseudotv.live/resources/lib/tasks.py +++ b/plugin.video.pseudotv.live/resources/lib/tasks.py @@ -133,7 +133,7 @@ def _chkPropTimer(self, key, func, priority=-1, *args, **kwargs): key = '%s.%s'%(ADDON_ID,key) if PROPERTIES.getEXTPropertyBool(key): self.log('_chkPropTimer, key = %s'%(key)) - PROPERTIES.clearEXTProperty(key) + PROPERTIES.clrEXTProperty(key) self._que(func, priority , *args, **kwargs) @@ -216,7 +216,7 @@ def __match(id, channels): try: builder = Builder(self.service) if not channels: - ids = PROPERTIES.getUpdateChannels() + ids = SETTINGS.getUpdateChannels() if ids and not proper: channels = list(builder.sortChannels([__match(id,builder.verify()) for id in ids])) else: @@ -296,10 +296,7 @@ def chkFillers(self, channels=None): def chkAutoTune(self): self.log('chkAutoTune') - try: - autotune = Autotune(service=self.service) - if autotune._runTune(): PROPERTIES.setAutotuned() - del autotune + try: SETTINGS.setAutotuned(Autotune(service=self.service)._runTune()) except Exception as e: self.log('chkAutoTune failed! %s'%(e), xbmc.LOGERROR) diff --git a/plugin.video.pseudotv.live/resources/lib/utilities.py b/plugin.video.pseudotv.live/resources/lib/utilities.py index 7a60c380..51471e30 100644 --- a/plugin.video.pseudotv.live/resources/lib/utilities.py +++ b/plugin.video.pseudotv.live/resources/lib/utilities.py @@ -149,13 +149,13 @@ def _togglePVR(self): def buildMenu(self, select=None): - items = [{'label':LANGUAGE(32117),'label2':LANGUAGE(32120),'icon':COLOR_LOGO,'func':self.deleteFiles ,'args':(LANGUAGE(32120),False) , 'hide':False},#"Rebuild M3U/XMLTV" - {'label':LANGUAGE(32118),'label2':LANGUAGE(32119),'icon':COLOR_LOGO,'func':self.deleteFiles ,'args':(LANGUAGE(32119),True) , 'hide':False},#"Clean Start" - {'label':LANGUAGE(32121)%(PVR_CLIENT_NAME),'label2':LANGUAGE(32122) ,'icon':COLOR_LOGO,'func':self._togglePVR , 'hide':False},#"Force PVR reload" - {'label':LANGUAGE(32123),'label2':LANGUAGE(32124),'icon':COLOR_LOGO,'func':PROPERTIES.setPendingRestart , 'hide':False},#"Force PTVL reload" - {'label':LANGUAGE(32159),'label2':LANGUAGE(33159),'icon':COLOR_LOGO,'func':PROPERTIES.setEXTPropertyBool ,'args':('%s.chkLibrary'%(ADDON_ID),True), 'hide':False}, #Rescan library - {'label':LANGUAGE(32180),'label2':LANGUAGE(33180),'icon':COLOR_LOGO,'func':PROPERTIES.setEpochTimer ,'args':('chkFillers',) , 'hide':False}, #Rescan library - {'label':LANGUAGE(32181),'label2':LANGUAGE(33181),'icon':COLOR_LOGO,'func':startChannelBuild , 'hide':False}] #Run Autotune + items = [{'label':LANGUAGE(32117),'label2':LANGUAGE(32120),'icon':COLOR_LOGO,'func':self.deleteFiles ,'args':(LANGUAGE(32120),False) , 'hide':False},#"Rebuild M3U/XMLTV" + {'label':LANGUAGE(32118),'label2':LANGUAGE(32119),'icon':COLOR_LOGO,'func':self.deleteFiles ,'args':(LANGUAGE(32119),True) , 'hide':False},#"Clean Start" + {'label':LANGUAGE(32121)%(PVR_CLIENT_NAME),'label2':LANGUAGE(32122) ,'icon':COLOR_LOGO,'func':self._togglePVR , 'hide':False},#"Force PVR reload" + {'label':LANGUAGE(32123),'label2':LANGUAGE(32124),'icon':COLOR_LOGO,'func':PROPERTIES.setPendingRestart , 'hide':False},#"Force PTVL reload" + {'label':LANGUAGE(32159),'label2':LANGUAGE(33159),'icon':COLOR_LOGO,'func':PROPERTIES.forceUpdateTime ,'args':('chkLibrary',) , 'hide':False}, #Rescan library + {'label':LANGUAGE(32180),'label2':LANGUAGE(33180),'icon':COLOR_LOGO,'func':PROPERTIES.setEpochTimer ,'args':('chkFillers',) , 'hide':False}, #Rescan library + {'label':LANGUAGE(32181),'label2':LANGUAGE(33181),'icon':COLOR_LOGO,'func':self._runAutotune , 'hide':False}] #Run Autotune with BUILTIN.busy_dialog(): listItems = [LISTITEMS.buildMenuListItem(item.get('label'),item.get('label2'),item.get('icon')) for item in sorted(items,key=itemgetter('label')) if not (item.get('hide'))] @@ -172,7 +172,19 @@ def buildMenu(self, select=None): self.log("buildMenu, failed! %s"%(e), xbmc.LOGERROR) return DIALOG.notificationDialog(LANGUAGE(32000)) else: openAddonSettings((6,1)) - + + + def _runAutotune(self): + SETTINGS.setAutotuned(False) + PROPERTIES.setEpochTimer('chkAutoTune') + + + def _runUpdate(self, full=False): + if full: + SETTINGS.setAutotuned(False) + PROPERTIES.forceUpdateTime('chkLibrary') + PROPERTIES.forceUpdateTime('chkChannels') + def deleteFiles(self, msg, full: bool=False): self.log('deleteFiles, full = %s'%(full)) @@ -188,8 +200,7 @@ def deleteFiles(self, msg, full: bool=False): with BUILTIN.busy_dialog(): for key in keys: if FileAccess.delete(files[key]): DIALOG.notificationDialog(LANGUAGE(32127)%(key.replace(':',''))) - if full: startChannelBuild() - else: PROPERTIES.forceUpdateTime('chkChannels') + self._runUpdate(full) def sortMethod(self): diff --git a/plugin.video.pseudotv.live/resources/lib/xmltvs.py b/plugin.video.pseudotv.live/resources/lib/xmltvs.py index ac76c2cf..565899de 100644 --- a/plugin.video.pseudotv.live/resources/lib/xmltvs.py +++ b/plugin.video.pseudotv.live/resources/lib/xmltvs.py @@ -97,7 +97,16 @@ def _error(self, name, file, e): else: raise Exception('no parser match %s'%(str(e))) except Exception as en: self.log('%s, failed! %s\n%s'%(name,e,en), xbmc.LOGERROR) - + + def resetData(self): + self.log('resetData') + return {'date' : datetime.datetime.fromtimestamp(float(time.time())).strftime(DTFORMAT), + 'generator-info-name' : self.cleanString('%s Guidedata'%(ADDON_NAME)), + 'generator-info-url' : self.cleanString(ADDON_ID), + 'source-info-name' : self.cleanString(ADDON_NAME), + 'source-info-url' : self.cleanString(ADDON_ID)} + + def loadData(self, file: str=XMLTVFLEPATH) -> dict: self.log('loadData, file = %s'%file) try: @@ -151,31 +160,21 @@ def loadStopTimes(self, channels: list=[], programmes: list=[], fallback=None): yield channel['id'],datetime.datetime.timestamp(strpTime(fallback, DTFORMAT)) - def hasProgrammes(self, channels: list=[], programmes: list=[], fallback=None): + def hasProgrammes(self, channels: list=[], programmes: list=[], now=None): if not channels: channels = self.getChannels() if not programmes: programmes = self.getProgrammes() - if not fallback: fallback = datetime.datetime.fromtimestamp(roundTimeDown(getUTCstamp(),offset=60)).strftime(DTFORMAT) + if not now: now = datetime.datetime.fromtimestamp(roundTimeDown(getUTCstamp(),offset=60)).strftime(DTFORMAT) for channel in channels: try: valid = False - firstStart = min([program['start'] for program in programmes if program['channel'] == channel['id']], default=fallback) - lastStop = max([program['stop'] for program in programmes if program['channel'] == channel['id']], default=fallback) + lastStop = max([program['stop'] for program in programmes if program['channel'] == channel['id']], default=now) + if lastStop > now: valid = True self.log('hasProgrammes, channel = %s, valid = %s'%(channel['id'],valid)) - if lastStop > fallback: valid = True yield channel['id'],valid except Exception as e: self.log("hasProgrammes, channel = %s failed!\nMalformed XMLTV channel/programmes %s! valid = False %s"%(channel.get('id'),e), xbmc.LOGWARNING) yield channel['id'],False - - - def resetData(self): - self.log('resetData') - return {'date' : datetime.datetime.fromtimestamp(float(time.time())).strftime(DTFORMAT), - 'generator-info-name' : self.cleanString('%s Guidedata'%(ADDON_NAME)), - 'generator-info-url' : self.cleanString(ADDON_ID), - 'source-info-name' : self.cleanString(ADDON_NAME), - 'source-info-url' : self.cleanString(ADDON_ID)} def cleanString(self, text: str) -> str: @@ -206,7 +205,7 @@ def cleanChannels(self, channels: list, programmes: list) -> list: # remove stat def cleanProgrammes(self, programmes: list) -> list: now = (datetime.datetime.fromtimestamp(float(getUTCstamp())) - datetime.timedelta(days=MIN_GUIDEDAYS)) #allow some old programmes to avoid empty cells holiday = Seasonal().getHoliday() - clrIDS = PROPERTIES.getClearChannels() + clrIDS = SETTINGS.getResetChannels() def __filterProgrammes(program): citem = decodePlot(program.get('desc',([{}],''))[0][0]).get('citem',{}) @@ -283,8 +282,10 @@ def getProgramItem(self, citem: dict, fItem: dict) -> dict: item['categories'] = (fItem.get('genre') or ['Undefined'])[:5]#trim list to five item['type'] = fItem.get('type','video') item['new'] = int(fItem.get('playcount','1')) == 0 + item['thumb'] = cleanImage(getThumb(fItem,EPG_ARTWORK)) #unify thumbnail by user preference fItem.get('art',{})['thumb'] = getThumb(fItem,{0:1,1:0}[EPG_ARTWORK]) #unify thumbnail artwork, opposite of EPG_Artwork + item['date'] = fItem.get('premiered','') item['catchup-id'] = VOD_URL.format(addon=ADDON_ID,title=quoteString(item['title']),chid=quoteString(citem['id']),vid=quoteString(encodeString((fItem.get('originalfile') or fItem.get('file','')))),name=quoteString(citem['name'])) fItem['catchup-id'] = item['catchup-id'] @@ -557,5 +558,4 @@ def matchGenres(programmes): xmlData.write(doc.toprettyxml(indent=' ',encoding=DEFAULT_ENCODING)) xmlData.close() except Exception as e: self.log("buildGenres failed! %s"%(e), xbmc.LOGERROR) - except Exception as e: self.log("buildGenres failed! %s"%(e), xbmc.LOGERROR) - + except Exception as e: self.log("buildGenres failed! %s"%(e), xbmc.LOGERROR) \ No newline at end of file diff --git a/zips/plugin.video.pseudotv.live/plugin.video.pseudotv.live-0.5.7j.zip b/zips/plugin.video.pseudotv.live/plugin.video.pseudotv.live-0.5.7j.zip new file mode 100644 index 00000000..c744511a Binary files /dev/null and b/zips/plugin.video.pseudotv.live/plugin.video.pseudotv.live-0.5.7j.zip differ