def selectPList(): Log.Debug("User selected to export a playlist") # Abort if set to auto path if Prefs['Auto_Path']: message = 'Playlists can not be exported when path is set to auto. You need to specify a manual path in the prefs' oc = ObjectContainer(title1='Error!. Playlists can not be exported when path is set to auto. You need to specify a manual path in the prefs', no_cache=True, message=message) oc.add(DirectoryObject(key=Callback(MainMenu), title="Go to the Main Menu")) Log.Debug('Can not continue, since on AutoPath') return oc # Else build up a menu of the playlists oc = ObjectContainer(title1='Select Playlist to export', no_cache=True) playlists = XML.ElementFromURL(misc.GetLoopBack() + '/playlists/all', timeout=float(PMSTIMEOUT)).xpath('//Playlist') for playlist in playlists: title = playlist.get('title') try: thumb = misc.GetLoopBack() + playlist.get('composite') except: pass playListType= playlist.get('playlistType') if playListType in ['video','audio', 'photo']: key = playlist.get('key') Log.Debug("Added playlist: " + title + " to the listing with a key of: " + key) oc.add(DirectoryObject(key=Callback(backgroundScan, title=playListType, sectiontype='playlists', key=key, random=time.clock()), thumb=thumb, title='Export from "' + title + '"', summary='Export list from "' + title + '"')) oc.add(DirectoryObject(key=Callback(MainMenu), title="Go to the Main Menu")) return oc
def MainMenu(random=0): Log.Debug("********** Starting MainMenu **********") global sectiontype title = NAME + VERSION oc = ObjectContainer(title1=title, no_cache=True, no_history=True, art=R(ART)) oc.view_group = 'List' try: if ValidateExportPath(): title = 'playlists' key = '-1' thumb = R(PLAYLIST) sectiontype = title oc.add(DirectoryObject(key=Callback(selectPList), thumb=thumb, title='Export from "' + title + '"', summary='Export list from "' + title + '"')) Log.Debug('Getting section List from: ' + misc.GetLoopBack() + '/library/sections') sections = XML.ElementFromURL(misc.GetLoopBack() + '/library/sections', timeout=float(PMSTIMEOUT)).xpath('//Directory') for section in sections: sectiontype = section.get('type') if sectiontype != "photook": # ToDo: Remove artist when code is in place for it. title = section.get('title') key = section.get('key') thumb = misc.GetLoopBack() + section.get('thumb') Log.Debug('Title of section is %s with a key of %s' %(title, key)) oc.add(DirectoryObject(key=Callback(backgroundScan, title=title, sectiontype=sectiontype, key=key, random=time.clock()), thumb=thumb, title='Export from "' + title + '"', summary='Export list from "' + title + '"')) else: oc.add(DirectoryObject(key=Callback(MainMenu, random=time.clock()), title="Select Preferences to set the export path")) except: Log.Critical("Exception happened in MainMenu") raise oc.add(PrefsObject(title='Preferences', thumb=R(ICON))) Log.Debug("********** Ending MainMenu **********") return oc
def sectionList(): # Path to DefaultPrefs.json prefsFile = Core.storage.join_path(Core.app_support_path, Core.config.bundles_dir_name, APPNAME + '.bundle', 'Contents', 'DefaultPrefs.json') with io.open(prefsFile) as json_file: data = json.load(json_file) #print(json.dumps(data, indent=4, sort_keys=True)) # Get list of libraries SectionsURL = misc.GetLoopBack() + '/library/sections' SectionList = XML.ElementFromURL(SectionsURL).xpath('//Directory') LibraryValues = [] LibraryValues.append('*** Idle ***'.decode('utf-8')) LibraryValues.append('*** Reload Library List ***'.decode('utf-8')) for Section in SectionList: LibraryValues.append(Section.get('title').decode('utf-8')) for item in data: if item['id'] == 'Libraries': item['values'] = LibraryValues break with io.open(prefsFile, 'wb') as outfile: json.dump(data, outfile, indent=4) restart() return
def scanArtistDB(myMediaURL, myCSVFile): Log.Debug("******* Starting scanArtistDB with an URL of %s ***********" % (myMediaURL)) global bScanStatusCount global bScanStatusCountOf global bScanStatus bScanStatusCount = 0 try: mySepChar = Prefs['Seperator'] Log.Debug('Writing headers for Audio Export') csvfile = io.open(myCSVFile, 'wb') csvwriter = csv.DictWriter(csvfile, fieldnames=audio.getMusicHeader( Prefs['Artist_Level']), delimiter=Prefs['Delimiter'], quoting=csv.QUOTE_NONNUMERIC) csvwriter.writeheader() if Prefs['Artist_Level'] in audiofields.singleCall: bExtraInfo = False else: bExtraInfo = True Log.Debug('Starting to fetch the list of items in this section') fetchURL = myMediaURL + '?type=10&X-Plex-Container-Start=' + str( bScanStatusCount) + '&X-Plex-Container-Size=0' medias = XML.ElementFromURL(fetchURL) if bScanStatusCount == 0: bScanStatusCountOf = medias.get('totalSize') Log.Debug('Amount of items in this section is %s' % bScanStatusCountOf) Log.Debug("Walking medias") while True: fetchURL = myMediaURL + '?type=10&sort=artist.titleSort,album.titleSort:asc&X-Plex-Container-Start=' + str( bScanStatusCount) + '&X-Plex-Container-Size=' + str( consts.CONTAINERSIZEAUDIO) medias = XML.ElementFromURL(fetchURL) if medias.get('size') == '0': break # HERE WE DO STUFF tracks = medias.xpath('.//Track') for track in tracks: bScanStatusCount += 1 # Get the Audio Info myRow = {} # Was extra info needed here? if bExtraInfo: myExtendedInfoURL = misc.GetLoopBack( ) + '/library/metadata/' + misc.GetRegInfo( track, 'ratingKey') + '?includeExtras=1' if Prefs['Check_Files']: myExtendedInfoURL = myExtendedInfoURL + '&checkFiles=1' track = XML.ElementFromURL(myExtendedInfoURL).xpath( '//Track')[0] audio.getAudioInfo(track, myRow) csvwriter.writerow(myRow) csvfile.close except: Log.Critical("Detected an exception in scanArtistDB") bScanStatus = 99 raise # Dumps the error so you can see what the problem is Log.Debug("******* Ending scanArtistDB ***********")
def getOutFileName(title, skipts, level, playlist): ''' returns the name of the output file to create ''' extension = '.' + Prefs['Output_Format'] # Get current date and time if skipts: timestr = '' else: timestr = '-' + time.strftime("%Y%m%d-%H%M%S") # Generate Output FileName # Remove invalid caracters, if on Windows...... newtitle = re.sub('[\/[:#*?"<>|]', '_', title).strip() if playlist: outFile = os.path.join( Prefs['Export_Path'], APPNAME, 'Playlist-' + newtitle + '-' + level + timestr + extension) else: if Prefs['Auto_Path']: # Need to grap the first location for the section locations = XML.ElementFromURL( misc.GetLoopBack() + '/library/sections/', timeout=float(PMSTIMEOUT)).xpath('.//Directory[@title="' + title + '"]')[0] location = locations[0].get('path') outFile = os.path.join( location, APPNAME, newtitle + '-' + level + timestr + extension) else: outFile = os.path.join( Prefs['Export_Path'], APPNAME, newtitle + '-' + level + timestr + extension) return outFile
def scanMovieDB(myMediaURL, outFile): Log.Debug("******* Starting scanMovieDB with an URL of %s ***********" % (myMediaURL)) Log.Debug('Movie Export level is %s' % (Prefs['Movie_Level'])) global bScanStatusCount global bScanStatusCountOf global bScanStatus bScanStatusCount = 0 bScanStatusCountOf = 0 iCurrent = 0 try: Log.Debug("About to open file %s" % (outFile)) output.createHeader(outFile, 'movies') if Prefs['Movie_Level'] in moviefields.singleCall: bExtraInfo = False else: bExtraInfo = True while True: Log.Debug("Walking medias") fetchURL = myMediaURL + '?X-Plex-Container-Start=' + str( iCurrent) + '&X-Plex-Container-Size=' + str( CONTAINERSIZEMOVIES) iCount = bScanStatusCount partMedias = XML.ElementFromURL(fetchURL, timeout=float(PMSTIMEOUT)) if bScanStatusCount == 0: bScanStatusCountOf = partMedias.get('totalSize') Log.Debug('Amount of items in this section is %s' % bScanStatusCountOf) # HERE WE DO STUFF Log.Debug("Retrieved part of medias okay [%s of %s]" % (str(bScanStatusCount), str(bScanStatusCountOf))) medias = partMedias.xpath('.//Video') for media in medias: myRow = {} # Was extra info needed here? if bExtraInfo: myExtendedInfoURL = genParam( misc.GetLoopBack() + '/library/metadata/' + misc.GetRegInfo(media, 'ratingKey')) media = XML.ElementFromURL( myExtendedInfoURL, timeout=float(PMSTIMEOUT)).xpath('//Video')[0] # Export the info myRow = movies.getMovieInfo(media, myRow) output.writerow(myRow) iCurrent += 1 bScanStatusCount += 1 Log.Debug("Media #%s from database: '%s'" % (str(iCurrent), misc.GetRegInfo(media, 'title'))) # Got to the end of the line? if int(partMedias.get('size')) == 0: break if bScanStatus == 3: break output.closefile() except ValueError, Argument: Log.Critical('Unknown error in scanMovieDb %s' % (Argument)) bScanStatus = 99 raise
def getShowOnly(myMedia, myRow, level): prefsLevel = Prefs['TV_Level'] if prefsLevel in ['Show Only 1', 'Show Only 2', 'Show Only 3']: for key, value in tvfields.Show_1: element = myMedia.get(value[1:]) if element == None: element = 'N/A' element = misc.WrapStr(misc.fixCRLF(element).encode('utf8')) if key == 'MetaDB Link': myRow[key] = misc.metaDBLink(element) elif key in myRow: myRow[key] = myRow[key] + Prefs['Seperator'] + element else: myRow[key] = element if prefsLevel in ['Show Only 2', 'Show Only 3']: for key, value in tvfields.Show_2: myRow[key] = misc.GetArrayAsString(myMedia, value, default = consts.DEFAULT) # Additional call needed for level 3 if prefsLevel in ['Show Only 3']: directURL = misc.GetLoopBack() + '/library/metadata/' + myRow['Media ID'] directMedia = XML.ElementFromURL(directURL, timeout=float(consts.PMSTIMEOUT)) for key, value in tvfields.Show_3: if key == 'MetaDB Link': myRow[key] = misc.metaDBLink(str(directMedia.xpath('//Directory/@guid'))) else: myRow[key] = misc.GetArrayAsString(directMedia, value, default = consts.DEFAULT) return myRow
def getShowOnly(myMedia, myRow, level): ''' Export TV Show info only ''' if level: prefsLevel = level else: prefsLevel = Prefs['TV_Level'] if prefsLevel in ['Show Only 1', 'Show Only 2', 'Show Only 3']: for key, value in tvfields.Show_1: element = myMedia.get(value[1:]) if element is None: element = consts.DEFAULT element = misc.WrapStr(misc.fixCRLF(element).encode('utf8')) if key == 'MetaDB Link': myRow[key] = misc.metaDBLink(element) # Is it a dateStamp? elif value[1:] in tvfields.dateTimeFields: myRow[key] = misc.ConvertDateStamp(element) elif key in myRow: myRow[key] = myRow[key] + Prefs['Seperator'] + element else: myRow[key] = element if prefsLevel in ['Show Only 2', 'Show Only 3']: for key, value in tvfields.Show_2: myRow[key] = misc.GetArrayAsString(myMedia, value, default=consts.DEFAULT) # Additional call needed for level 3 if prefsLevel in ['Show Only 3']: directURL = misc.GetLoopBack() + '/library/metadata/' + \ myRow['Media ID'] directMedia = XML.ElementFromURL(directURL, timeout=float(consts.PMSTIMEOUT)) for key, value in tvfields.Show_3: if key == 'MetaDB Link': try: myRow[key] = misc.metaDBLink( str(directMedia.xpath('//Directory/@guid'))) except Exception, e: myRow[key] = consts.DEFAULT pass elif key == 'Delete Item Watched after days': try: deleteDays = directMedia.xpath( '//Directory/@autoDeletionItemPolicyWatchedLibrary') if deleteDays == ['100']: deleteDays = 'Next Refresh' elif deleteDays == []: deleteDays = 'Never' elif deleteDays == ['0']: deleteDays = 'Never' elif deleteDays == ['1']: deleteDays = '1 Day' elif deleteDays == ['7']: deleteDays = '7 Days' myRow[key] = deleteDays except Exception, e: myRow[key] = consts.DEFAULT pass
def scanArtistDB(myMediaURL, outFile, level=None): ''' This function will scan a Music section.''' Log.Debug("*** Starting scanArtistDB with an URL of %s ***" % myMediaURL) global bScanStatusCount global bScanStatusCountOf global bScanStatus bScanStatusCount = 0 try: Log.Debug('Writing headers for Audio Export') output.createHeader(outFile=outFile, sectionType='audio', level=level) if level in audiofields.singleCall: bExtraInfo = False else: bExtraInfo = True Log.Debug('Starting to fetch the list of items in this section') fetchURL = ''.join((myMediaURL, '?type=10&X-Plex-Container-Start=', str(bScanStatusCount), '&X-Plex-Container-Size=0')) medias = XML.ElementFromURL(fetchURL, timeout=float(PMSTIMEOUT)) if bScanStatusCount == 0: bScanStatusCountOf = medias.get('totalSize') output.setMax(int(bScanStatusCountOf)) Log.Debug('Amount of items in this section is %s' % bScanStatusCountOf) Log.Debug("Walking medias") while True: fetchURL = ''.join( (myMediaURL, '?type=10&sort=artist.titleSort,album.titleSort:', 'asc&X-Plex-Container-Start=', str(bScanStatusCount), '&X-Plex-Container-Size=', str(CONTAINERSIZEAUDIO))) medias = XML.ElementFromURL(fetchURL, timeout=float(PMSTIMEOUT)) if medias.get('size') == '0': break # HERE WE DO STUFF tracks = medias.xpath('.//Track') for track in tracks: bScanStatusCount += 1 # Get the Audio Info myRow = {} # Was extra info needed here? if bExtraInfo: myExtendedInfoURL = genParam(''.join( (misc.GetLoopBack(), '/library/metadata/', misc.GetRegInfo(track, 'ratingKey')))) track = XML.ElementFromURL( myExtendedInfoURL, timeout=float(PMSTIMEOUT)).xpath('//Track')[0] audio.getAudioInfo(track, myRow, level=level) output.writerow(myRow) output.closefile() except Exception, e: Log.Exception("Detected an exception in scanArtistDB as: %s" % str(e)) bScanStatus = 99 # Dumps the error so you can see what the problem is raise
def scanMovieDB(myMediaURL, myCSVFile): Log.Debug("******* Starting scanMovieDB with an URL of %s ***********" %(myMediaURL)) Log.Debug('Movie Export level is %s' %(Prefs['Movie_Level'])) global bScanStatusCount global bScanStatusCountOf global bScanStatus bScanStatusCount = 0 bScanStatusCountOf = 0 iCurrent = 0 try: Log.Debug("About to open file %s" %(myCSVFile)) csvfile = io.open(myCSVFile,'wb') # Create output file, and print the header csvwriter = csv.DictWriter(csvfile, fieldnames=movies.getMovieHeader(Prefs['Movie_Level']), delimiter=Prefs['Delimiter'], quoting=csv.QUOTE_NONNUMERIC) Log.Debug("Writing header") csvwriter.writeheader() if Prefs['Movie_Level'] in moviefields.singleCall: bExtraInfo = False else: bExtraInfo = True while True: Log.Debug("Walking medias") fetchURL = myMediaURL + '?X-Plex-Container-Start=' + str(iCurrent) + '&X-Plex-Container-Size=' + str(consts.CONTAINERSIZEMOVIES) iCount = bScanStatusCount partMedias = XML.ElementFromURL(fetchURL) if bScanStatusCount == 0: bScanStatusCountOf = partMedias.get('totalSize') Log.Debug('Amount of items in this section is %s' %bScanStatusCountOf) # HERE WE DO STUFF Log.Debug("Retrieved part of medias okay [%s of %s]" %(str(bScanStatusCount), str(bScanStatusCountOf))) medias = partMedias.xpath('.//Video') for media in medias: myRow = {} # Was extra info needed here? if bExtraInfo: myExtendedInfoURL = misc.GetLoopBack() + '/library/metadata/' + misc.GetRegInfo(media, 'ratingKey') + '?includeExtras=1' if Prefs['Check_Files']: myExtendedInfoURL = myExtendedInfoURL + '&checkFiles=1' media = XML.ElementFromURL(myExtendedInfoURL).xpath('//Video')[0] # Export the info myRow = movies.getMovieInfo(media, myRow, csvwriter) csvwriter.writerow(myRow) iCurrent += 1 bScanStatusCount += 1 Log.Debug("Media #%s from database: '%s'" %(str(iCurrent), misc.GetRegInfo(media, 'title'))) # Got to the end of the line? if int(partMedias.get('size')) == 0: break csvfile.close except ValueError, Argument: Log.Critical('Unknown error in scanMovieDb %s' %(Argument)) bScanStatus = 99 raise
def restart(): try: Log.Debug('Restarting plugin') pFile = Core.storage.join_path(Core.app_support_path, Core.config.bundles_dir_name, APPNAME + '.bundle', 'Contents', 'Info.plist') pl = plistlib.readPlist(pFile) url = ''.join((misc.GetLoopBack(), '/:/plugins/%s/restart')) % pl['CFBundleIdentifier'] HTTP.Request(misc.GetLoopBack() + '/:/plugins/%s/restart' % pl['CFBundleIdentifier'], cacheTime=0, immediate=True) except Exception, e: try: HTTP.Request(misc.GetLoopBack() + '/:/plugins/com.plexapp.system/restart', immediate=True) except: pass
def scanArtistDB(myMediaURL, outFile): Log.Debug("******* Starting scanArtistDB with an URL of %s ***********" % (myMediaURL)) global bScanStatusCount global bScanStatusCountOf global bScanStatus bScanStatusCount = 0 try: Log.Debug('Writing headers for Audio Export') output.createHeader(outFile, 'audio') if Prefs['Artist_Level'] in audiofields.singleCall: bExtraInfo = False else: bExtraInfo = True Log.Debug('Starting to fetch the list of items in this section') fetchURL = myMediaURL + '?type=10&X-Plex-Container-Start=' + str( bScanStatusCount) + '&X-Plex-Container-Size=0' medias = XML.ElementFromURL(fetchURL, timeout=float(PMSTIMEOUT)) if bScanStatusCount == 0: bScanStatusCountOf = medias.get('totalSize') Log.Debug('Amount of items in this section is %s' % bScanStatusCountOf) Log.Debug("Walking medias") while True: fetchURL = myMediaURL + '?type=10&sort=artist.titleSort,album.titleSort:asc&X-Plex-Container-Start=' + str( bScanStatusCount) + '&X-Plex-Container-Size=' + str( CONTAINERSIZEAUDIO) medias = XML.ElementFromURL(fetchURL, timeout=float(PMSTIMEOUT)) if medias.get('size') == '0': break # HERE WE DO STUFF tracks = medias.xpath('.//Track') for track in tracks: bScanStatusCount += 1 # Get the Audio Info myRow = {} # Was extra info needed here? if bExtraInfo: myExtendedInfoURL = genParam( misc.GetLoopBack() + '/library/metadata/' + misc.GetRegInfo(track, 'ratingKey')) track = XML.ElementFromURL( myExtendedInfoURL, timeout=float(PMSTIMEOUT)).xpath('//Track')[0] audio.getAudioInfo(track, myRow) output.writerow(myRow) output.closefile() except: Log.Critical("Detected an exception in scanArtistDB") bScanStatus = 99 raise # Dumps the error so you can see what the problem is Log.Debug("******* Ending scanArtistDB ***********")
def ResetToIdle(): ''' Reset Library Prefs to idle ''' pFile = Core.storage.join_path(Core.app_support_path, Core.config.bundles_dir_name, APPNAME + '.bundle', 'Contents', 'Info.plist') pl = plistlib.readPlist(pFile) CFBundleIdentifier = pl['CFBundleIdentifier'] url = ''.join((misc.GetLoopBack(), '/:/plugins/', CFBundleIdentifier, '/prefs/set?Libraries=***%20Idle%20***')) HTTP.Request(url, cacheTime=0, immediate=True) return
def ScanLib(title='', skipts=False, level=None): Log.Debug('Starting to scan section from prefs: %s' % title) # Get list of libraries SectionsURL = misc.GetLoopBack() + '/library/sections' Library = XML.ElementFromURL(SectionsURL).xpath('//Directory[@title="' + title + '"]') key = Library[0].get('key').decode('utf-8') sectiontype = Library[0].get('type').decode('utf-8') Log.Debug('Key detected as %s and type as %s' % (key, sectiontype)) Thread.Create(backgroundScanThread, globalize=True, title=title, key=key, sectiontype=sectiontype, skipts=skipts, level=level) return
def getPhotoItems(medias, bExtraInfo): global bScanStatusCount try: # Start by grapping pictures here et = medias.xpath('.//Photo') for element in et: myRow = {} myRow = photo.getInfo(element, myRow) bScanStatusCount += 1 output.writerow(myRow) # Elements that are directories et = medias.xpath('.//Directory') for element in et: myExtendedInfoURL = genParam(misc.GetLoopBack() + element.get('key')) # TODO: Make small steps here when req. photos elements = XML.ElementFromURL(myExtendedInfoURL, timeout=float(PMSTIMEOUT)) getPhotoItems(elements, bExtraInfo) except Exception, e: Log.Debug('Exception in getPhotoItems was %s' %(str(e))) pass
def getShowOnly(myMedia, myRow, level): prefsLevel = Prefs['TV_Level'] for key, value in tvfields.Show_1: element = myMedia.get(value[1:]) if element == None: element = 'N/A' element = misc.WrapStr(misc.fixCRLF(element).encode('utf8')) if key in myRow: myRow[key] = myRow[key] + Prefs['Seperator'] + element else: myRow[key] = element # Now we sadly needs to make a call for each show :-( if '2' in prefsLevel: myExtendedInfoURL = misc.GetLoopBack( ) + '/library/metadata/' + myMedia.get('ratingKey') for key, value in tvfields.Show_2: if key == 'MetaDB Link': myRow[key] = misc.metaDBLink( XML.ElementFromURL( myExtendedInfoURL, timeout=float(consts.PMSTIMEOUT))[0].xpath('@guid')[0]) return myRow
def getPhotoItems(medias, csvwriter, bExtraInfo): global bScanStatusCount # Start by grapping pictures here et = medias.xpath('.//Photo') for element in et: myRow = {} myRow = photo.getInfo(element, myRow) bScanStatusCount += 1 csvwriter.writerow(myRow) # Elements that are directories et = medias.xpath('.//Directory') for element in et: myExtendedInfoURL = misc.GetLoopBack() + element.get( 'key') + '?includeExtras=1' # if bExtraInfo: # if Prefs['Check_Files']: # myExtendedInfoURL = myExtendedInfoURL + '&checkFiles=1' # TODO: Make small steps here when req. photos elements = XML.ElementFromURL(myExtendedInfoURL, timeout=float(consts.PMSTIMEOUT)) # if bExtraInfo: getPhotoItems(elements, csvwriter, bExtraInfo)
def createFile(sectionKey, sectionType, title): global newtitle # Type of export global extension # Name of muFile global muFile # fileObject for 3mu file global writer3muFile global playListType extension = '.' + Prefs['Output_Format'] # Placeholder for return array retVal =[] if sectionType == 'playlists': myMediaURL = misc.GetLoopBack() + sectionKey playListType = title title = XML.ElementFromURL(myMediaURL, timeout=float(PMSTIMEOUT)).get('title') else: myMediaURL = misc.GetLoopBack() + '/library/sections/' + sectionKey + "/all" Log.Debug("Path to medias in selection is %s" %(myMediaURL)) # Get current date and time timestr = time.strftime("%Y%m%d-%H%M%S") # Generate Output FileName if sectionType == 'show': myLevel = Prefs['TV_Level'] elif sectionType == 'movie': myLevel = Prefs['Movie_Level'] elif sectionType == 'artist': myLevel = Prefs['Artist_Level'] elif sectionType == 'photo': myLevel = Prefs['Photo_Level'] elif sectionType == 'playlists': myLevel = Prefs['PlayList_Level'] else: myLevel = '' # Remove invalid caracters, if on Windows...... newtitle = re.sub('[\/[:#*?"<>|]', '_', title).strip() if sectionType == 'playlists': outFile = os.path.join(Prefs['Export_Path'], NAME, 'Playlist-' + newtitle + '-' + myLevel + '-' + timestr + extension) if Prefs['mu_Level'] != 'Disabled': muFile = os.path.join(Prefs['Export_Path'], NAME, 'Playlist-' + newtitle + '-' + Prefs['mu_Level'] + '-' + timestr + '.m3u8') writer3muFile = codecs.open(muFile,'w', encoding='utf8') if Prefs['mu_Level'] == 'Enhanced': writer3muFile.write(unicode('#EXTM3U') + '\n') writer3muFile.write(unicode('#Written by ExportTools for Plex') + '\n') writer3muFile.write(unicode('#Playlist name: ' + newtitle) + '\n') else: if Prefs['Auto_Path']: # Need to grap the first location for the section locations = XML.ElementFromURL('http://127.0.0.1:32400/library/sections/', timeout=float(PMSTIMEOUT)).xpath('.//Directory[@key="' + sectionKey + '"]')[0] location = locations[0].get('path') outFile = os.path.join(location, NAME, newtitle + '-' + myLevel + '-' + timestr + extension) if not os.path.exists(os.path.join(location, NAME)): os.makedirs(os.path.join(location, NAME)) Log.Debug('Auto Created directory named: %s' %(os.path.join(location, NAME))) else: Log.Debug('Auto directory named: %s already exists' %(os.path.join(location, NAME))) else: outFile = os.path.join(Prefs['Export_Path'], NAME, newtitle + '-' + myLevel + '-' + timestr + extension) # Add what we got to the return array retVal.append(outFile) retVal.append(myMediaURL) # Posters ? global doPosters doPosters = False if Prefs['Export_Posters']: global posterDir if sectionType == 'show': if Prefs['TV_Level'] not in ["Level 1"]: doPosters = True if sectionType == 'movie': if Prefs['Movie_Level'] not in ["Level 1","Level 2","Special Level 1"]: doPosters = True if doPosters: posterDir = os.path.join(os.path.dirname(outFile), 'posters') if not os.path.exists(posterDir): os.makedirs(posterDir) return retVal
# Write Enhanced Info writer3muFile.write(unicode(line) + '\n') # Write FileName writer3muFile.write(unicode(rowentry['File Name']) + '\n') # Write special comment, that maybe can be used for import later info = {} info['type'] = rowentry['Type'] info['id'] = rowentry['Media ID'] strInfo = '#' + str(info) writer3muFile.write(unicode(strInfo) + '\n') except Exception, e: Log.Exception('Exception writing 3mu entry was %s' % str(e)) pass if doPosters: posterUrl = ''.join((misc.GetLoopBack(), '/photo/:/transcode?width=', str(Prefs['Poster_Width']), '&height=', str(Prefs['Poster_Hight']), '&minSize=1&url=', String.Quote(rowentry['Poster url']))) try: thumbFile = os.path.join(posterDir, rowentry['Media ID'] + '.jpg') thumb = HTTP.Request(posterUrl).content with io.open(thumbFile, 'wb') as handler: handler.write(thumb) except Exception, e: Log.Exception('Exception was %s' % str(e)) def closefile(): ''' Close file again ''' global targetfile
writer3muFile.write(unicode(line) + '\n') # Write FileName writer3muFile.write(unicode(rowentry['File Name']) + '\n') # Write special comment, that maybe can be used for import later info = {} info['type'] = rowentry['Type'] info['id'] = rowentry['Media ID'] strInfo = '#' + str(info) writer3muFile.write(unicode(strInfo) + '\n') except Exception, e: Log.Exception('Exception writing 3mu entry was %s' % str(e)) pass if doPosters: posterUrl = ''.join(( misc.GetLoopBack(), '/photo/:/transcode?width=', str(Prefs['Poster_Width']), '&height=', str(Prefs['Poster_Hight']), '&minSize=1&url=', String.Quote(rowentry['Poster url']))) try: thumbFile = os.path.join(posterDir, rowentry['Media ID'] + '.jpg') thumb = HTTP.Request(posterUrl).content with io.open(thumbFile, 'wb') as handler: handler.write(thumb) except Exception, e: Log.Exception('Exception was %s' % str(e))
def scanShowDB(myMediaURL, outFile): Log.Debug("******* Starting scanShowDB with an URL of %s ***********" %(myMediaURL)) global bScanStatusCount global bScanStatusCountOf global bScanStatus bScanStatusCount = 0 bScanStatusCountOf = 0 try: Log.Debug("About to open file %s" %(outFile)) output.createHeader(outFile, 'tvseries') if Prefs['TV_Level'] in tvfields.singleCall: bExtraInfo = False else: bExtraInfo = True Log.Debug('Starting to fetch the list of items in this section') while True: Log.Debug("Walking medias") iCount = bScanStatusCount if 'Show Only' in Prefs['TV_Level']: fetchURL = myMediaURL + '?X-Plex-Container-Start=' + str(iCount) + '&X-Plex-Container-Size=1' else: fetchURL = myMediaURL + '?X-Plex-Container-Start=' + str(iCount) + '&X-Plex-Container-Size=' + str(CONTAINERSIZETV) partMedias = XML.ElementFromURL(fetchURL, timeout=float(PMSTIMEOUT)) if bScanStatusCount == 0: bScanStatusCountOf = partMedias.get('totalSize') Log.Debug('Amount of items in this section is %s' %bScanStatusCountOf) # HERE WE DO STUFF Log.Debug("Retrieved part of medias okay [%s of %s]" %(str(iCount), str(bScanStatusCountOf))) for TVShow in partMedias: bScanStatusCount += 1 iCount += 1 ratingKey = TVShow.get("ratingKey") title = TVShow.get("title") if 'Show Only' in Prefs['TV_Level']: myRow = {} # Export the info myRow = tvseries.getShowOnly(TVShow, myRow, Prefs['TV_Level']) try: output.writerow(myRow) except Exception, e: Log.Exception('Exception happend in ScanShowDB: %s' %str(e)) continue else: if Prefs['TV_Level'] in ['Level 2','Level 3', 'Level 4', 'Level 5', 'Level 6', 'Level 7', 'Level 8', 'Level 666']: myURL = misc.GetLoopBack() + '/library/metadata/' + ratingKey tvSeriesInfo = XML.ElementFromURL(myURL, timeout=float(PMSTIMEOUT)) # Getting stuff from the main TV-Show page # Grab collections serieInfo = tvSeriesInfo.xpath('//Directory/Collection') myCol = '' for collection in serieInfo: if myCol == '': myCol = collection.get('tag') else: myCol = myCol + Prefs['Seperator'] + collection.get('tag') if myCol == '': myCol = 'N/A' # Grab locked fields serieInfo = tvSeriesInfo.xpath('//Directory/Field') myField = '' for Field in serieInfo: if myField == '': myField = Field.get('name') else: myField = myField + Prefs['Seperator'] + Field.get('name') if myField == '': myField = 'N/A' # Get size of TV-Show episodeTotalSize = XML.ElementFromURL(misc.GetLoopBack() + '/library/metadata/' + ratingKey + '/allLeaves?X-Plex-Container-Start=0&X-Plex-Container-Size=0', timeout=float(PMSTIMEOUT)).xpath('@totalSize')[0] Log.Debug('Show: %s has %s episodes' %(title, episodeTotalSize)) episodeCounter = 0 baseURL = misc.GetLoopBack() + '/library/metadata/' + ratingKey + '/allLeaves' while True: myURL = baseURL + '?X-Plex-Container-Start=' + str(episodeCounter) + '&X-Plex-Container-Size=' + str(CONTAINERSIZEEPISODES) Log.Debug('Show %s of %s with a RatingKey of %s at myURL: %s with a title of "%s" episode %s of %s' %(iCount, bScanStatusCountOf, ratingKey, myURL, title, episodeCounter, episodeTotalSize)) MainEpisodes = XML.ElementFromURL(myURL, timeout=float(PMSTIMEOUT)) Episodes = MainEpisodes.xpath('//Video') for Episode in Episodes: myRow = {} # Was extra info needed here? if bExtraInfo: myExtendedInfoURL = genParam(misc.GetLoopBack() + '/library/metadata/' + misc.GetRegInfo(Episode, 'ratingKey')) Episode = XML.ElementFromURL(myExtendedInfoURL, timeout=float(PMSTIMEOUT)).xpath('//Video')[0] # Export the info myRow = tvseries.getTvInfo(Episode, myRow) if Prefs['TV_Level'] in ['Level 2','Level 3', 'Level 4', 'Level 5', 'Level 6', 'Level 7', 'Level 8', 'Level 666']: myRow['Collection'] = myCol myRow['Locked Fields'] = myField output.writerow(myRow) episodeCounter += CONTAINERSIZEEPISODES if episodeCounter > int(episodeTotalSize): break # Got to the end of the line? if int(partMedias.get('size')) == 0: break output.closefile()
def scanShowDB(myMediaURL, myCSVFile): Log.Debug("******* Starting scanShowDB with an URL of %s ***********" %(myMediaURL)) global bScanStatusCount global bScanStatusCountOf global bScanStatus bScanStatusCount = 0 bScanStatusCountOf = 0 try: Log.Debug("About to open file %s" %(myCSVFile)) csvfile = io.open(myCSVFile,'wb') # Create output file, and print the header csvwriter = csv.DictWriter(csvfile, fieldnames=tvseries.getTVHeader(Prefs['TV_Level']), delimiter=Prefs['Delimiter'], quoting=csv.QUOTE_NONNUMERIC) Log.Debug("Writing header") csvwriter.writeheader() if Prefs['TV_Level'] in tvfields.singleCall: bExtraInfo = False else: bExtraInfo = True Log.Debug('Starting to fetch the list of items in this section') while True: Log.Debug("Walking medias") iCount = bScanStatusCount fetchURL = myMediaURL + '?X-Plex-Container-Start=' + str(iCount) + '&X-Plex-Container-Size=' + str(consts.CONTAINERSIZETV) partMedias = XML.ElementFromURL(fetchURL, headers=MYHEADER) if bScanStatusCount == 0: bScanStatusCountOf = partMedias.get('totalSize') Log.Debug('Amount of items in this section is %s' %bScanStatusCountOf) # HERE WE DO STUFF Log.Debug("Retrieved part of medias okay [%s of %s]" %(str(iCount), str(bScanStatusCountOf))) AllTVShows = partMedias.xpath('.//Directory') for TVShows in AllTVShows: bScanStatusCount += 1 iCount += 1 ratingKey = TVShows.get("ratingKey") title = TVShows.get("title") if Prefs['TV_Level'] in ['Level 2','Level 3', 'Level 4', 'Level 5', 'Level 6', 'Level 7', 'Level 8', 'Level 666']: # Getting stuff from the main TV-Show page myURL = misc.GetLoopBack() + '/library/metadata/' + ratingKey # Grab collections serieInfo = XML.ElementFromURL(myURL).xpath('//Directory/Collection') myCol = '' for collection in serieInfo: if myCol == '': myCol = collection.get('tag') else: myCol = myCol + Prefs['Seperator'] + collection.get('tag') if myCol == '': myCol = 'N/A' # Grab locked fields serieInfo = XML.ElementFromURL(myURL).xpath('//Directory/Field') myField = '' for Field in serieInfo: if myField == '': myField = Field.get('name') else: myField = myField + Prefs['Seperator'] + Field.get('name') if myField == '': myField = 'N/A' myURL = misc.GetLoopBack() + '/library/metadata/' + ratingKey + '/allLeaves' Log.Debug('Show %s of %s with a RatingKey of %s at myURL: %s with a title of "%s"' %(iCount, bScanStatusCountOf, ratingKey, myURL, title)) MainEpisodes = XML.ElementFromURL(myURL) Episodes = MainEpisodes.xpath('//Video') Log.Debug('Show %s with an index of %s contains %s episodes' %(MainEpisodes.get('parentTitle'), iCount, MainEpisodes.get('size'))) for Episode in Episodes: myRow = {} # Was extra info needed here? if bExtraInfo: myExtendedInfoURL = misc.GetLoopBack() + '/library/metadata/' + misc.GetRegInfo(Episode, 'ratingKey') + '?includeExtras=1' if Prefs['Check_Files']: myExtendedInfoURL = myExtendedInfoURL + '&checkFiles=1' Episode = XML.ElementFromURL(myExtendedInfoURL).xpath('//Video')[0] # Export the info myRow = tvseries.getTvInfo(Episode, myRow) if Prefs['TV_Level'] in ['Level 2','Level 3', 'Level 4', 'Level 5', 'Level 6', 'Level 7', 'Level 8', 'Level 666']: myRow['Collection'] = myCol myRow['Locked Fields'] = myField # Log.Debug("Show %s from database: %s Season %s Episode %s title: %s" %(bScanStatusCount, misc.GetRegInfo(Episode, 'grandparentTitle'), misc.GetRegInfo(Episode, 'parentIndex'), misc.GetRegInfo(Episode, 'index'), misc.GetRegInfo(Episode, 'title'))) csvwriter.writerow(myRow) # Got to the end of the line? if int(partMedias.get('size')) == 0: break csvfile.close except ValueError as err: Log.Debug('Exception happend as %s' %err.args) Log.Debug("******* Ending scanShowDB ***********")
def backgroundScanThread(title, key, sectiontype): Log.Debug("******* Starting backgroundScanThread ***********") global bScanStatus global bScanStatusCount global bScanStatusCountOf global EXPORTPATH try: bScanStatus = 1 Log.Debug("Section type is %s" %(sectiontype)) if sectiontype == 'playlists': myMediaURL = misc.GetLoopBack() + key playListType = title title = XML.ElementFromURL(myMediaURL).get('title') else: myMediaURL = misc.GetLoopBack() + '/library/sections/' + key + "/all" Log.Debug("Path to medias in selection is %s" %(myMediaURL)) # Get current date and time timestr = time.strftime("%Y%m%d-%H%M%S") # Generate Output FileName if sectiontype == 'show': myLevel = Prefs['TV_Level'] elif sectiontype == 'movie': myLevel = Prefs['Movie_Level'] elif sectiontype == 'artist': myLevel = Prefs['Artist_Level'] elif sectiontype == 'photo': myLevel = Prefs['Photo_Level'] elif sectiontype == 'playlists': myLevel = Prefs['PlayList_Level'] else: myLevel = '' # Remove invalid caracters, if on Windows...... newtitle = re.sub('[\/[:#*?"<>|]', '_', title) if sectiontype == 'playlists': myCSVFile = os.path.join(Prefs['Export_Path'], consts.NAME, 'Playlist-' + newtitle + '-' + myLevel + '-' + timestr + '.csv') else: if Prefs['Auto_Path']: # Need to grap the first location for the section locations = XML.ElementFromURL('http://127.0.0.1:32400/library/sections/').xpath('.//Directory[@key="' + key + '"]')[0] location = locations[0].get('path') myCSVFile = os.path.join(location, consts.NAME, newtitle + '-' + myLevel + '-' + timestr + '.csv') if not os.path.exists(os.path.join(location, consts.NAME)): os.makedirs(os.path.join(location, consts.NAME)) Log.Debug('Auto Created directory named: %s' %(os.path.join(location, consts.NAME))) else: Log.Debug('Auto directory named: %s already exists' %(os.path.join(location, consts.NAME))) else: myCSVFile = os.path.join(Prefs['Export_Path'], consts.NAME, newtitle + '-' + myLevel + '-' + timestr + '.csv') EXPORTPATH = myCSVFile Log.Debug('Output file is named %s' %(myCSVFile)) # Scan the database based on the type of section if sectiontype == "movie": scanMovieDB(myMediaURL, myCSVFile) elif sectiontype == "artist": scanArtistDB(myMediaURL, myCSVFile) elif sectiontype == "show": scanShowDB(myMediaURL, myCSVFile) elif sectiontype == "playlists": scanPList(myMediaURL, playListType, myCSVFile) elif sectiontype == "photo": scanPhotoDB(myMediaURL, myCSVFile) else: Log.Debug("Error: unknown section type: %s" %(sectiontype)) bScanStatus = 91 # Stop scanner on error if bScanStatus >= 90: return Log.Debug("******* Ending backgroundScanThread ***********") bScanStatus = 2 return except: Log.Critical("Exception happened in backgroundScanThread") bScanStatus = 99 raise Log.Debug("******* Ending backgroundScanThread ***********")