exit loop

This commit is contained in:
SpootDev 2016-03-31 10:55:21 -05:00
parent 2e1a2328fd
commit 065bff5215

View file

@ -1,286 +1,287 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
################################################################################################# #################################################################################################
import os import os
import xbmc import xbmc
import xbmcaddon import xbmcaddon
import xbmcvfs import xbmcvfs
from mutagen.flac import FLAC, Picture from mutagen.flac import FLAC, Picture
from mutagen.id3 import ID3 from mutagen.id3 import ID3
from mutagen import id3 from mutagen import id3
import base64 import base64
import read_embyserver as embyserver import read_embyserver as embyserver
import utils import utils
################################################################################################# #################################################################################################
# Helper for the music library, intended to fix missing song ID3 tags on Emby # Helper for the music library, intended to fix missing song ID3 tags on Emby
def logMsg(msg, lvl=1): def logMsg(msg, lvl=1):
utils.logMsg("%s %s" % ("Emby", "musictools"), msg, lvl) utils.logMsg("%s %s" % ("Emby", "musictools"), msg, lvl)
def getRealFileName(filename, isTemp=False): def getRealFileName(filename, isTemp=False):
#get the filename path accessible by python if possible... #get the filename path accessible by python if possible...
if not xbmcvfs.exists(filename): if not xbmcvfs.exists(filename):
logMsg( "File does not exist! %s" %(filename), 0) logMsg( "File does not exist! %s" %(filename), 0)
return (False, "") return (False, "")
#if we use os.path method on older python versions (sunch as some android builds), we need to pass arguments as string #if we use os.path method on older python versions (sunch as some android builds), we need to pass arguments as string
if os.path.supports_unicode_filenames: if os.path.supports_unicode_filenames:
checkfile = filename checkfile = filename
else: else:
checkfile = filename.encode("utf-8") checkfile = filename.encode("utf-8")
# determine if our python module is able to access the file directly... # determine if our python module is able to access the file directly...
if os.path.exists(checkfile): if os.path.exists(checkfile):
filename = filename filename = filename
elif os.path.exists(checkfile.replace("smb://","\\\\").replace("/","\\")): elif os.path.exists(checkfile.replace("smb://","\\\\").replace("/","\\")):
filename = filename.replace("smb://","\\\\").replace("/","\\") filename = filename.replace("smb://","\\\\").replace("/","\\")
else: else:
#file can not be accessed by python directly, we copy it for processing... #file can not be accessed by python directly, we copy it for processing...
isTemp = True isTemp = True
if "/" in filename: filepart = filename.split("/")[-1] if "/" in filename: filepart = filename.split("/")[-1]
else: filepart = filename.split("\\")[-1] else: filepart = filename.split("\\")[-1]
tempfile = "special://temp/"+filepart tempfile = "special://temp/"+filepart
xbmcvfs.copy(filename, tempfile) xbmcvfs.copy(filename, tempfile)
filename = xbmc.translatePath(tempfile).decode("utf-8") filename = xbmc.translatePath(tempfile).decode("utf-8")
return (isTemp,filename) return (isTemp,filename)
def getEmbyRatingFromKodiRating(rating): def getEmbyRatingFromKodiRating(rating):
# Translation needed between Kodi/ID3 rating and emby likes/favourites: # Translation needed between Kodi/ID3 rating and emby likes/favourites:
# 3+ rating in ID3 = emby like # 3+ rating in ID3 = emby like
# 5+ rating in ID3 = emby favourite # 5+ rating in ID3 = emby favourite
# rating 0 = emby dislike # rating 0 = emby dislike
# rating 1-2 = emby no likes or dislikes (returns 1 in results) # rating 1-2 = emby no likes or dislikes (returns 1 in results)
favourite = False favourite = False
deletelike = False deletelike = False
like = False like = False
if (rating >= 3): like = True if (rating >= 3): like = True
if (rating == 0): like = False if (rating == 0): like = False
if (rating == 1 or rating == 2): deletelike = True if (rating == 1 or rating == 2): deletelike = True
if (rating >= 5): favourite = True if (rating >= 5): favourite = True
return(like, favourite, deletelike) return(like, favourite, deletelike)
def getAdditionalSongTags(embyid, emby_rating, API, kodicursor, emby_db, enableimportsongrating, enableexportsongrating, enableupdatesongrating): def getAdditionalSongTags(embyid, emby_rating, API, kodicursor, emby_db, enableimportsongrating, enableexportsongrating, enableupdatesongrating):
emby = embyserver.Read_EmbyServer() emby = embyserver.Read_EmbyServer()
previous_values = None previous_values = None
filename = API.getFilePath() filename = API.getFilePath()
rating = 0 rating = 0
emby_rating = int(round(emby_rating, 0)) emby_rating = int(round(emby_rating, 0))
#get file rating and comment tag from file itself. #get file rating and comment tag from file itself.
if enableimportsongrating: if enableimportsongrating:
file_rating, comment, hasEmbeddedCover = getSongTags(filename) file_rating, comment, hasEmbeddedCover = getSongTags(filename)
else: else:
file_rating = 0 file_rating = 0
comment = "" comment = ""
hasEmbeddedCover = False hasEmbeddedCover = False
emby_dbitem = emby_db.getItem_byId(embyid) emby_dbitem = emby_db.getItem_byId(embyid)
try: try:
kodiid = emby_dbitem[0] kodiid = emby_dbitem[0]
except TypeError: except TypeError:
# Item is not in database. # Item is not in database.
currentvalue = None currentvalue = None
else: else:
query = "SELECT rating FROM song WHERE idSong = ?" query = "SELECT rating FROM song WHERE idSong = ?"
kodicursor.execute(query, (kodiid,)) kodicursor.execute(query, (kodiid,))
try: try:
currentvalue = int(round(float(kodicursor.fetchone()[0]),0)) currentvalue = int(round(float(kodicursor.fetchone()[0]),0))
except: currentvalue = None except: currentvalue = None
# Only proceed if we actually have a rating from the file # Only proceed if we actually have a rating from the file
if file_rating is None and currentvalue: if file_rating is None and currentvalue:
return (currentvalue, comment, False) return (currentvalue, comment, False)
elif file_rating is None and not currentvalue: elif file_rating is None and not currentvalue:
return (emby_rating, comment, False) return (emby_rating, comment, False)
logMsg("getAdditionalSongTags --> embyid: %s - emby_rating: %s - file_rating: %s - current rating in kodidb: %s" %(embyid, emby_rating, file_rating, currentvalue)) logMsg("getAdditionalSongTags --> embyid: %s - emby_rating: %s - file_rating: %s - current rating in kodidb: %s" %(embyid, emby_rating, file_rating, currentvalue))
updateFileRating = False updateFileRating = False
updateEmbyRating = False updateEmbyRating = False
if currentvalue != None: if currentvalue != None:
# we need to translate the emby values... # we need to translate the emby values...
if emby_rating == 1 and currentvalue == 2: if emby_rating == 1 and currentvalue == 2:
emby_rating = 2 emby_rating = 2
if emby_rating == 3 and currentvalue == 4: if emby_rating == 3 and currentvalue == 4:
emby_rating = 4 emby_rating = 4
#if updating rating into file is disabled, we ignore the rating in the file... #if updating rating into file is disabled, we ignore the rating in the file...
if not enableupdatesongrating: if not enableupdatesongrating:
file_rating = currentvalue file_rating = currentvalue
#if convert emby likes/favourites convert to song rating is disabled, we ignore the emby rating... #if convert emby likes/favourites convert to song rating is disabled, we ignore the emby rating...
if not enableexportsongrating: if not enableexportsongrating:
emby_rating = currentvalue emby_rating = currentvalue
if (emby_rating == file_rating) and (file_rating != currentvalue): if (emby_rating == file_rating) and (file_rating != currentvalue):
#the rating has been updated from kodi itself, update change to both emby ands file #the rating has been updated from kodi itself, update change to both emby ands file
rating = currentvalue rating = currentvalue
updateFileRating = True updateFileRating = True
updateEmbyRating = True updateEmbyRating = True
elif (emby_rating != currentvalue) and (file_rating == currentvalue): elif (emby_rating != currentvalue) and (file_rating == currentvalue):
#emby rating changed - update the file #emby rating changed - update the file
rating = emby_rating rating = emby_rating
updateFileRating = True updateFileRating = True
elif (file_rating != currentvalue) and (emby_rating == currentvalue): elif (file_rating != currentvalue) and (emby_rating == currentvalue):
#file rating was updated, sync change to emby #file rating was updated, sync change to emby
rating = file_rating rating = file_rating
updateEmbyRating = True updateEmbyRating = True
elif (emby_rating != currentvalue) and (file_rating != currentvalue): elif (emby_rating != currentvalue) and (file_rating != currentvalue):
#both ratings have changed (corner case) - the highest rating wins... #both ratings have changed (corner case) - the highest rating wins...
if emby_rating > file_rating: if emby_rating > file_rating:
rating = emby_rating rating = emby_rating
updateFileRating = True updateFileRating = True
else: else:
rating = file_rating rating = file_rating
updateEmbyRating = True updateEmbyRating = True
else: else:
#nothing has changed, just return the current value #nothing has changed, just return the current value
rating = currentvalue rating = currentvalue
else: else:
# no rating yet in DB # no rating yet in DB
if enableimportsongrating: if enableimportsongrating:
#prefer the file rating #prefer the file rating
rating = file_rating rating = file_rating
#determine if we should also send the rating to emby server #determine if we should also send the rating to emby server
if enableexportsongrating: if enableexportsongrating:
if emby_rating == 1 and file_rating == 2: if emby_rating == 1 and file_rating == 2:
emby_rating = 2 emby_rating = 2
if emby_rating == 3 and file_rating == 4: if emby_rating == 3 and file_rating == 4:
emby_rating = 4 emby_rating = 4
if emby_rating != file_rating: if emby_rating != file_rating:
updateEmbyRating = True updateEmbyRating = True
elif enableexportsongrating: elif enableexportsongrating:
#set the initial rating to emby value #set the initial rating to emby value
rating = emby_rating rating = emby_rating
if updateFileRating and enableupdatesongrating: if updateFileRating and enableupdatesongrating:
updateRatingToFile(rating, filename) updateRatingToFile(rating, filename)
if updateEmbyRating and enableexportsongrating: if updateEmbyRating and enableexportsongrating:
# sync details to emby server. Translation needed between ID3 rating and emby likes/favourites: # sync details to emby server. Translation needed between ID3 rating and emby likes/favourites:
like, favourite, deletelike = getEmbyRatingFromKodiRating(rating) like, favourite, deletelike = getEmbyRatingFromKodiRating(rating)
utils.window("ignore-update-%s" %embyid, "true") #set temp windows prop to ignore the update from webclient update utils.window("ignore-update-%s" %embyid, "true") #set temp windows prop to ignore the update from webclient update
emby.updateUserRating(embyid, like, favourite, deletelike) emby.updateUserRating(embyid, like, favourite, deletelike)
return (rating, comment, hasEmbeddedCover) return (rating, comment, hasEmbeddedCover)
def getSongTags(file): def getSongTags(file):
# Get the actual ID3 tags for music songs as the server is lacking that info # Get the actual ID3 tags for music songs as the server is lacking that info
rating = 0 rating = 0
comment = "" comment = ""
hasEmbeddedCover = False hasEmbeddedCover = False
isTemp,filename = getRealFileName(file) isTemp,filename = getRealFileName(file)
logMsg( "getting song ID3 tags for " + filename) logMsg( "getting song ID3 tags for " + filename)
try: try:
###### FLAC FILES ############# ###### FLAC FILES #############
if filename.lower().endswith(".flac"): if filename.lower().endswith(".flac"):
audio = FLAC(filename) audio = FLAC(filename)
if audio.get("comment"): if audio.get("comment"):
comment = audio.get("comment")[0] comment = audio.get("comment")[0]
for pic in audio.pictures: for pic in audio.pictures:
if pic.type == 3 and pic.data: if pic.type == 3 and pic.data:
#the file has an embedded cover #the file has an embedded cover
hasEmbeddedCover = True hasEmbeddedCover = True
if audio.get("rating"): break
rating = float(audio.get("rating")[0]) if audio.get("rating"):
#flac rating is 0-100 and needs to be converted to 0-5 range rating = float(audio.get("rating")[0])
if rating > 5: rating = (rating / 100) * 5 #flac rating is 0-100 and needs to be converted to 0-5 range
if rating > 5: rating = (rating / 100) * 5
###### MP3 FILES #############
elif filename.lower().endswith(".mp3"): ###### MP3 FILES #############
audio = ID3(filename) elif filename.lower().endswith(".mp3"):
audio = ID3(filename)
if audio.get("APIC:Front Cover"):
if audio.get("APIC:Front Cover").data: if audio.get("APIC:Front Cover"):
hasEmbeddedCover = True if audio.get("APIC:Front Cover").data:
hasEmbeddedCover = True
if audio.get("comment"):
comment = audio.get("comment")[0] if audio.get("comment"):
if audio.get("POPM:Windows Media Player 9 Series"): comment = audio.get("comment")[0]
if audio.get("POPM:Windows Media Player 9 Series").rating: if audio.get("POPM:Windows Media Player 9 Series"):
rating = float(audio.get("POPM:Windows Media Player 9 Series").rating) if audio.get("POPM:Windows Media Player 9 Series").rating:
#POPM rating is 0-255 and needs to be converted to 0-5 range rating = float(audio.get("POPM:Windows Media Player 9 Series").rating)
if rating > 5: rating = (rating / 255) * 5 #POPM rating is 0-255 and needs to be converted to 0-5 range
else: if rating > 5: rating = (rating / 255) * 5
logMsg( "Not supported fileformat or unable to access file: %s" %(filename)) else:
logMsg( "Not supported fileformat or unable to access file: %s" %(filename))
#the rating must be a round value
rating = int(round(rating,0)) #the rating must be a round value
rating = int(round(rating,0))
except Exception as e:
#file in use ? except Exception as e:
utils.logMsg("Exception in getSongTags", str(e),0) #file in use ?
rating = None utils.logMsg("Exception in getSongTags", str(e),0)
rating = None
#remove tempfile if needed....
if isTemp: xbmcvfs.delete(filename) #remove tempfile if needed....
if isTemp: xbmcvfs.delete(filename)
return (rating, comment, hasEmbeddedCover)
return (rating, comment, hasEmbeddedCover)
def updateRatingToFile(rating, file):
#update the rating from Emby to the file def updateRatingToFile(rating, file):
#update the rating from Emby to the file
f = xbmcvfs.File(file)
org_size = f.size() f = xbmcvfs.File(file)
f.close() org_size = f.size()
f.close()
#create tempfile
if "/" in file: filepart = file.split("/")[-1] #create tempfile
else: filepart = file.split("\\")[-1] if "/" in file: filepart = file.split("/")[-1]
tempfile = "special://temp/"+filepart else: filepart = file.split("\\")[-1]
xbmcvfs.copy(file, tempfile) tempfile = "special://temp/"+filepart
tempfile = xbmc.translatePath(tempfile).decode("utf-8") xbmcvfs.copy(file, tempfile)
tempfile = xbmc.translatePath(tempfile).decode("utf-8")
logMsg( "setting song rating: %s for filename: %s - using tempfile: %s" %(rating,file,tempfile))
logMsg( "setting song rating: %s for filename: %s - using tempfile: %s" %(rating,file,tempfile))
if not tempfile:
return if not tempfile:
return
try:
if tempfile.lower().endswith(".flac"): try:
audio = FLAC(tempfile) if tempfile.lower().endswith(".flac"):
calcrating = int(round((float(rating) / 5) * 100, 0)) audio = FLAC(tempfile)
audio["rating"] = str(calcrating) calcrating = int(round((float(rating) / 5) * 100, 0))
audio.save() audio["rating"] = str(calcrating)
elif tempfile.lower().endswith(".mp3"): audio.save()
audio = ID3(tempfile) elif tempfile.lower().endswith(".mp3"):
calcrating = int(round((float(rating) / 5) * 255, 0)) audio = ID3(tempfile)
audio.add(id3.POPM(email="Windows Media Player 9 Series", rating=calcrating, count=1)) calcrating = int(round((float(rating) / 5) * 255, 0))
audio.save() audio.add(id3.POPM(email="Windows Media Player 9 Series", rating=calcrating, count=1))
else: audio.save()
logMsg( "Not supported fileformat: %s" %(tempfile)) else:
logMsg( "Not supported fileformat: %s" %(tempfile))
#once we have succesfully written the flags we move the temp file to destination, otherwise not proceeding and just delete the temp
#safety check: we check the file size of the temp file before proceeding with overwite of original file #once we have succesfully written the flags we move the temp file to destination, otherwise not proceeding and just delete the temp
f = xbmcvfs.File(tempfile) #safety check: we check the file size of the temp file before proceeding with overwite of original file
checksum_size = f.size() f = xbmcvfs.File(tempfile)
f.close() checksum_size = f.size()
if checksum_size >= org_size: f.close()
xbmcvfs.delete(file) if checksum_size >= org_size:
xbmcvfs.copy(tempfile,file) xbmcvfs.delete(file)
else: xbmcvfs.copy(tempfile,file)
logMsg( "Checksum mismatch for filename: %s - using tempfile: %s - not proceeding with file overwite!" %(rating,file,tempfile)) else:
logMsg( "Checksum mismatch for filename: %s - using tempfile: %s - not proceeding with file overwite!" %(rating,file,tempfile))
#always delete the tempfile
xbmcvfs.delete(tempfile) #always delete the tempfile
xbmcvfs.delete(tempfile)
except Exception as e:
#file in use ? except Exception as e:
logMsg("Exception in updateRatingToFile %s" %e,0) #file in use ?
logMsg("Exception in updateRatingToFile %s" %e,0)