From b1e1c9ed6d0004db00146d31dae19f6894bb639a Mon Sep 17 00:00:00 2001 From: Tommy Mikkelsen Date: Sat, 27 Feb 2016 22:36:33 +0100 Subject: [PATCH] Return of Agent delete of subs, as well as changelog ;-) --- .gitignore | 4 + Contents/Code/Docs/webtools-README_DEVS.odt | Bin 96257 -> 96260 bytes Contents/Code/__init__.py | 13 +- Contents/Code/git.py | 33 ++-- Contents/Code/pms.py | 168 ++++++++++++-------- http/changelog.txt | 34 ++++ 6 files changed, 168 insertions(+), 84 deletions(-) diff --git a/.gitignore b/.gitignore index 28f597f..38eb73b 100644 --- a/.gitignore +++ b/.gitignore @@ -43,4 +43,8 @@ Icon # gedit tmp files #***************** *~ + +*.pyc +debug + diff --git a/Contents/Code/Docs/webtools-README_DEVS.odt b/Contents/Code/Docs/webtools-README_DEVS.odt index ee2fb35cce9886f803e39ab9125482222e81cd73..0953083f3925d474421fcd558e5ad542032ba4ec 100644 GIT binary patch delta 22269 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 QWsCo*9XxE3 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 delta 22163 zcmZshV{j&I6R2a`+1O4twylkA+vXG7wr$%sH@3}ijxCuDW}=d%An3YNqb# zo}gQB|66c)d1+8EG$0@-AfRM_<#>20(4VDVQ&RN5HL*mL82C1ET-1vhop&v~2 z0Yw_4EKo>8|0_@m6i8kg5(@ga{&^}85Re=&(9iLI!Jwd^{tK4qEJg$nYao2-(evM{ zw@|8$m)T^vtU0GEFH&7APp}k8X==2wVKF977(zoCgNQS(--yuw3|~)XrTVOfepY=Y zK*vH6`pak&+mk33XwoGJ5E5_l4%qGOeU0+_tbr|nMxgS;=w(x--lqo*s2slTZB;hP zvG3@tngKjNdp{X9Yd-<#9rp!Gwt)i=hUmdmUsQXwgNG44J}xbhgOy{lABWV=?3C?N zYHITs!E0)2!^>*Mv~Q%6xggiGk_Y=MRBs9QzHm0uI~~$r@&74wFZupcFe*mo){<<; z_LBAwa}B8PSa1F1Pa96{L*(z}>Xci&S~9$Qd2xR&(-8yQZ3#Kxnh9 z59pb}q0qHi`92AKUa9nIa(IsZd>X;@O)Ii(8j%0D>tSMgu_ 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

Ak6jeEirw_G__J7DsDWK14QH30CV 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 RLw$V&@RF_ioUzA({tpCovWWly diff --git a/Contents/Code/__init__.py b/Contents/Code/__init__.py index a26f917..eb4b69d 100644 --- a/Contents/Code/__init__.py +++ b/Contents/Code/__init__.py @@ -41,12 +41,11 @@ def Start(): DEBUGMODE = os.path.isfile(debugFile) if DEBUGMODE: VERSION = VERSION + ' ****** WARNING Debug mode on *********' - PLUGIN_VERSION = VERSION - print("******** Started %s on %s **********" %(NAME + ' V' + PLUGIN_VERSION, Platform.OS)) - Log.Debug("******* Started %s on %s ***********" %(NAME + ' V' + PLUGIN_VERSION, Platform.OS)) + print("******** Started %s on %s **********" %(NAME + ' V' + VERSION, Platform.OS)) + Log.Debug("******* Started %s on %s ***********" %(NAME + ' V' + VERSION, Platform.OS)) HTTP.CacheTime = 0 DirectoryObject.thumb = R(ICON) - ObjectContainer.title1 = NAME + ' V' + PLUGIN_VERSION + ObjectContainer.title1 = NAME + ' V' + VERSION Plugin.AddViewGroup('List', viewMode='List', mediaType='items') ObjectContainer.view_group = 'List' makeSettings() @@ -97,6 +96,12 @@ def makeSettings(): # Create the pwdset entry if Dict['pwdset'] == None: Dict['pwdset'] = False + # Init the installed dict + if Dict['installed'] == None: + Dict['installed'] = {} + # Init the allBundle Dict + if Dict['PMS-AllBundleInfo'] == None: + Dict['PMS-AllBundleInfo'] = {} return #################################################################################################### diff --git a/Contents/Code/git.py b/Contents/Code/git.py index c25b7c9..2e19576 100644 --- a/Contents/Code/git.py +++ b/Contents/Code/git.py @@ -101,12 +101,9 @@ def removeEmptyFolders(path, removeRoot=True): Log.Debug('Removing empty directory: ' + path) os.rmdir(path) - - # Reset dicts nukeSpecialDicts() - url= req.get_argument('debugURL', 'https://api.github.com/repos/dagalufh/WebTools.bundle/releases/latest') bundleName = Core.storage.join_path(Core.app_support_path, Core.config.bundles_dir_name, NAME + '.bundle') Log.Info('WT install dir is: ' + bundleName) @@ -174,16 +171,17 @@ def removeEmptyFolders(path, removeRoot=True): req.set_header('Content-Type', 'application/json; charset=utf-8') req.finish('Upgraded ok') except Exception, e: + Log.Critical('***************************************************************') + Log.Critical('Error when updating WebTools') + Log.Critical('The error was: ' + str(e)) Log.Critical('***************************************************************') Log.Critical('DARN....When we tried to upgrade WT, we had an error :-(') Log.Critical('Only option now might be to do a manual install, like you did the first time') - Log.Critical('The error was: ' + str(e)) Log.Critical('Do NOT FORGET!!!!') Log.Critical('We NEED this log, so please upload to Plex forums') Log.Critical('***************************************************************') return - ''' This function will return a list of bundles, where there is an update avail ''' def getUpdateList(self, req): Log.Debug('Got a call for getUpdateList') @@ -218,7 +216,6 @@ def getUpdateList(self, req): req.set_status(500) req.set_header('Content-Type', 'application/json; charset=utf-8') req.finish('Fatal error happened in getUpdateList ' + str(e)) - ''' This function will migrate bundles that has been installed without using our UAS into our UAS ''' def migrate(self, req, silent=False): @@ -259,9 +256,6 @@ def getIdentifier(pluginDir): # Main call Log.Debug('Migrate function called') try: - # Init dict, if not already so - if Dict['installed'] == None: - Dict['installed'] = {} # Let's start by getting a list of known installed bundles knownBundles = [] for installedBundles in Dict['installed']: @@ -286,6 +280,11 @@ def getIdentifier(pluginDir): uasListjson = getUASCacheList() bFound = False for git in uasListjson: + ''' + if target == 'com.plexapp.plugins.Plex2csv': + print 'GED KIG HER' + continue + ''' if target == uasListjson[git]['identifier']: Log.Debug('Found %s is part of uas' %(target)) targetGit = {} @@ -302,6 +301,8 @@ def getIdentifier(pluginDir): Log.Debug('Dict stamped with the following install entry: ' + git + ' - ' + str(targetGit)) # Now update the PMS-AllBundleInfo Dict as well Dict['PMS-AllBundleInfo'][git] = targetGit + # Update installed dict as well + Dict['installed'][git] = targetGit # If it existed as unknown as well, we need to remove that Dict['PMS-AllBundleInfo'].pop(uasListjson[git]['identifier'], None) Dict['installed'].pop(uasListjson[git]['identifier'], None) @@ -402,7 +403,15 @@ def updateUASCache(self, req): req.finish('Exception in updateUASCache: ' + errMsg) return req # Grap file from Github - zipfile = Archive.ZipFromURL(self.UAS_URL+ '/archive/master.zip') + try: + zipfile = Archive.ZipFromURL(self.UAS_URL+ '/archive/master.zip') + except Exception, e: + Log.Critical('Could not download UAS Repo from GitHub') + req.clear() + req.set_status(500) + req.set_header('Content-Type', 'application/json; charset=utf-8') + req.finish('Exception in updateUASCache while downloading UAS repo from Github: ' + str(e)) + return req for filename in zipfile: # Walk contents of the zip, and extract as needed data = zipfile[filename] @@ -549,7 +558,11 @@ def removeEmptyFolders(path, removeRoot=True): if len(files) == 0 and removeRoot: Log.Debug('Removing empty directory: ' + path) os.rmdir(path) + try: + # Get the dict with the installed bundles, and init it if it doesn't exists + if not 'installed' in Dict: + Dict['installed'] = {} zipPath = url + '/archive/' + branch + '.zip' try: # Grap file from Github diff --git a/Contents/Code/pms.py b/Contents/Code/pms.py index acb1284..e87ca47 100644 --- a/Contents/Code/pms.py +++ b/Contents/Code/pms.py @@ -9,6 +9,7 @@ import shutil, os import time, json import io +from xml.etree import ElementTree # Undate uasTypesCounters @@ -44,11 +45,40 @@ def updateUASTypesCounters(): #TODO fix updateAllBundleInfo # updateAllBundleInfo def updateAllBundleInfoFromUAS(): + def updateInstallDict(): + ''' + # Debugging stuff + print 'Ged debugging stuff' + Dict['PMS-AllBundleInfo'].pop('https://github.com/ukdtom/plex2csv.bundle', None) + Dict['installed'].clear() + Dict.Save() + #Debug end + ''' + + + + # Start by creating a fast lookup cache for all uas bundles + uasBundles = {} + bundles = Dict['PMS-AllBundleInfo'] + for bundle in bundles: + uasBundles[bundles[bundle]['identifier']] = bundle + # Now walk the installed ones + for installedBundle in Dict['installed']: + if not installedBundle.startswith('https://'): + Log.Info('Checking unknown bundle: ' + installedBundle + ' to see if it is part of UAS now') + if installedBundle in uasBundles: + # Get the installed date of the bundle formerly known as unknown :-) + installedDate = Dict['installed'][installedBundle]['date'] + # Add updated stuff to the dicts + Dict['PMS-AllBundleInfo'][uasBundles[installedBundle]]['date'] = installedDate + Dict['installed'][uasBundles[installedBundle]] = Dict['PMS-AllBundleInfo'][uasBundles[installedBundle]] + # Remove old stuff from the Ditcs + Dict['PMS-AllBundleInfo'].pop(installedBundle, None) + Dict['installed'].pop(installedBundle, None) + Dict.Save() + return + try: - # Init the Dict - if Dict['PMS-AllBundleInfo'] == None: - Dict['PMS-AllBundleInfo'] = {} - Dict.Save() # start by checking if UAS cache has been populated jsonUAS = Core.storage.join_path(Core.app_support_path, Core.config.bundles_dir_name, NAME + '.bundle', 'http', 'uas', 'Resources', 'plugin_details.json') if os.path.exists(jsonUAS): @@ -59,38 +89,29 @@ def updateAllBundleInfoFromUAS(): json_file.close() # Convert to a JSON Object gits = JSON.ObjectFromString(str(response)) - for git in gits: - # Rearrange data - key = git['repo'] - if key == 'https://github.com/ukdtom/test': - # This is out test bundle.....Only add if this is running in devmode - # meaning a file named 'devmode' is present in the root of the bundle dir - fname = Core.storage.join_path(Core.app_support_path, Core.config.bundles_dir_name, 'WebTools.bundle', 'devmode') - print 'GED Look here' - if os.path.isfile(fname): - continue - -#******************* WORK IN PROGRESS HERE **************** - - - - # Check if already present, and if an install date also is there - if key in Dict['PMS-AllBundleInfo']: - jsonPMSAllBundleInfo = Dict['PMS-AllBundleInfo'][key] - if 'date' not in jsonPMSAllBundleInfo: - installDate = "" - else: + try: + for git in gits: + # Rearrange data + key = git['repo'] + # Check if already present, and if an install date also is there + installDate = "" + if key in Dict['PMS-AllBundleInfo']: + jsonPMSAllBundleInfo = Dict['PMS-AllBundleInfo'][key] + if 'date' in jsonPMSAllBundleInfo: installDate = Dict['PMS-AllBundleInfo'][key]['date'] - del git['repo'] - # Add/Update our Dict - Dict['PMS-AllBundleInfo'][key] = git - Dict['PMS-AllBundleInfo'][key]['date'] = installDate + del git['repo'] + # Add/Update our Dict + Dict['PMS-AllBundleInfo'][key] = git + Dict['PMS-AllBundleInfo'][key]['date'] = installDate + except Exception, e: + Log.Critical('Critical error in updateInstallDict while walking the gits: ' + str(e)) Dict.Save() updateUASTypesCounters() + updateInstallDict() else: Log.Debug('UAS was sadly not present') except Exception, e: - Log.Debug('Fatal error happened in updateAllBundleInfoFromUAS: ' + str(e)) + Log.Critical('Fatal error happened in updateAllBundleInfoFromUAS: ' + str(e)) class pms(object): # Defaults used by the rest of the class @@ -168,6 +189,30 @@ def reqprocessPost(self, req): req.set_status(412) req.finish("Unknown function call") + ''' Delete from an XML file ''' + def DelFromXML(self, fileName, attribute, value): + Log.Debug('Need to delete element with an attribute named "%s" with a value of "%s" from file named "%s"' %(attribute, value, fileName)) + with io.open(fileName, 'r') as f: + tree = ElementTree.parse(f) + root = tree.getroot() + mySubtitles = root.findall('.//Subtitle') + for Subtitles in root.findall("Language[Subtitle]"): + for node in Subtitles.findall("Subtitle"): + myValue = node.attrib.get(attribute) + + print 'Ged9', myValue + + if myValue: + if '_' in myValue: + drop, myValue = myValue.split("_") + if myValue == value: + + print 'Ged10', value + + Subtitles.remove(node) + tree.write(fileName, encoding='utf-8', xml_declaration=True) + return + # getParts def getParts(self, req): Log.Debug('Got a call for getParts') @@ -234,15 +279,10 @@ def getAllBundleInfo(self, req): Log.Debug('Got a call for getAllBundleInfo') try: req.clear() - if Dict['PMS-AllBundleInfo'] == None: - Log.Debug('getAllBundleInfo has not been populated yet') - req.set_status(204) - req.finish('getAllBundleInfo has not been populated yet') - else: - Log.Debug('Returning: ' + str(len(Dict['PMS-AllBundleInfo'])) + ' items') - req.set_status(200) - req.set_header('Content-Type', 'application/json; charset=utf-8') - req.finish(json.dumps(Dict['PMS-AllBundleInfo'])) + Log.Debug('Returning: ' + str(len(Dict['PMS-AllBundleInfo'])) + ' items') + req.set_status(200) + req.set_header('Content-Type', 'application/json; charset=utf-8') + req.finish(json.dumps(Dict['PMS-AllBundleInfo'])) except Exception, e: Log.Debug('Fatal error happened in getAllBundleInfo: ' + str(e)) req.clear() @@ -393,60 +433,48 @@ def delSub(self, req): req.finish('Hmmm....This is invalid, and most likely due to trying to delete an embedded sub :-)') else: if filePath.startswith('media://'): - ''' - Here we look at an agent provided subtitle, so this part of the function - has been crippled on purpose - ''' + # Path to symblink filePath = filePath.replace('media:/', os.path.join(Core.app_support_path, 'Media', 'localhost')) # Subtitle name agent, sub = filePath.split('_') tmp, agent = agent.split('com.') # Agent used agent = 'com.' + agent - filePath2 = filePath.replace('Contents', 'Subtitle Contributions') + filePath2 = filePath.replace('Contents', os.path.join('Contents', 'Subtitle Contributions')) filePath2, language = filePath2.split('Subtitles') language = language[1:3] filePath3 = os.path.join(filePath2[:-1], agent, language, sub) - - ''' This is removed from the code, due to the fact, that Plex will re-download right after the deletion - subtitlesXMLPath, tmp = filePath.split('Contents') agentXMLPath = os.path.join(subtitlesXMLPath, 'Contents', 'Subtitle Contributions', agent + '.xml') subtitlesXMLPath = os.path.join(subtitlesXMLPath, 'Contents', 'Subtitles.xml') self.DelFromXML(agentXMLPath, 'media', sub) self.DelFromXML(subtitlesXMLPath, 'media', sub) - agentXML = XML.ElementFromURL('"' + agentXMLPath + '"') - #Let's refresh the media - url = 'http://127.0.0.1:32400/library/metadata/' + params['param2'] + '/refresh&force=1' - refresh = HTTP.Request(url, immediate=False) - # Nuke the actual file try: # Delete the actual file os.remove(filePath) - print 'Removing: ' + filePath - + # Delete the symb link os.remove(filePath3) - print 'Removing: ' + filePath3 - # Refresh the subtitles in Plex - self.getSubTitles(params) - except: - return 500 - ''' - + #TODO: Refresh is sadly not working for me, so could use some help here :-( + #Let's refresh the media + url = 'http://127.0.0.1:32400/library/metadata/' + key + '/refresh?force=1' + HTTP.Request(url, cacheTime=0, immediate=True, method="PUT") + except Exception, e: + Log.Critical('Exception while deleting an agent based sub: ' + str(e)) + req.clear() + req.set_status(404) + req.set_header('Content-Type', 'application/json; charset=utf-8') + req.finish('Exception while deleting an agent based sub: ' + str(e)) retValues = {} retValues['FilePath']=filePath3 retValues['SymbLink']=filePath - Log.Debug('Agent subtitle returning %s' %(retValues)) req.clear() req.set_status(200) req.set_header('Content-Type', 'application/json; charset=utf-8') req.finish(json.dumps(retValues)) - return req elif filePath.startswith('file://'): # We got a sidecar here, so killing time.....YES - filePath = filePath.replace('file://', '') try: # Delete the actual file @@ -458,13 +486,13 @@ def delSub(self, req): req.set_status(200) req.set_header('Content-Type', 'application/json; charset=utf-8') req.finish(json.dumps(retVal)) - except: + except Exception, e: # Could not find req. subtitle - Log.Debug('Fatal error happened in delSub, when deleting %s' %(filePath)) + Log.Debug('Fatal error happened in delSub, when deleting %s : %s' %(filePath, str(e))) req.clear() req.set_status(404) req.set_header('Content-Type', 'application/json; charset=utf-8') - req.finish('Fatal error happened in delSub, when deleting %s' %(filePath)) + req.finish('Fatal error happened in delSub, when deleting %s : %s' %(filePath, str(e))) else: # Could not find req. subtitle Log.Debug('Fatal error happened in delSub, subtitle not found') @@ -472,12 +500,12 @@ def delSub(self, req): req.set_status(404) req.set_header('Content-Type', 'application/json; charset=utf-8') req.finish('Could not find req. subtitle') - except: - Log.Debug('Fatal error happened in delSub') + except Exception, e: + Log.Debug('Fatal error happened in delSub: ' + str(e)) req.clear() req.set_status(500) req.set_header('Content-Type', 'application/json; charset=utf-8') - req.finish('Fatal error happened in delSub') + req.finish('Fatal error happened in delSub: ' + str(e)) ''' TVShow ''' def TVshow(self, req): diff --git a/http/changelog.txt b/http/changelog.txt index 2343ced..3804735 100644 --- a/http/changelog.txt +++ b/http/changelog.txt @@ -1,3 +1,37 @@ +V2.2-DEV: +Internal Note: + Here we collect stuff that needs to go into the real released changelog, aka acumulated, and only since 2.1 changes here ;-) +BACKEND: + Fix: + #115 UAS: Migration fails, if plugin directory contains hidden folder + #116 UAS: Make UAS work, even if a git is dir levels too low + #117 UAS and uninstall unknown bundle + #121 UAS: Cleanup old files/folders when updating + #122 UAS: bundle migration + #138 UAS: getAllBundleInfo is reset when UASRepo is updated + New: + #129 UAS: Alllow 3.Party devs to clear their stuff + #135 WT: Tell users, if wrong install path is used + #137 WT: Add new decorator for auth + #126 UAS: Allow WebTools to autoupdate + +FRONTEND: + Fix: + TODO + New: + #126 UAS: Allow WebTools to autoupdate +#### + +V2.2-DEV-2016-02-25: +UAS: + The return of the Uninstall-button (Issue #132) +WebTools: + Implemented update of main plugin. This however currently causes an error in the logs. + +V2.2-DEV-2016-02-19: +UAS: + Changed focus after showing channel. This should not bring up the keyboard on mobile devices anymore. + V2.2-DEV-2016-02-02: UAS: Reverting Issue #119 because of reported issue with locked interface.