mirror of
https://github.com/jellyfin/jellyfin-kodi.git
synced 2024-11-10 04:06:11 +00:00
fix for the merge that didn't follow
Media path fix, and clean up of writeKodiVideoDB. Fix for library sync for deletes.
This commit is contained in:
parent
3589c4b05d
commit
0c54257de6
4 changed files with 1281 additions and 1300 deletions
|
@ -1,3 +1,4 @@
|
|||
# -- coding: utf-8 --
|
||||
# API.py
|
||||
# This class helps translate more complex cases from the MediaBrowser API to the XBMC API
|
||||
|
||||
|
@ -11,142 +12,157 @@ class API():
|
|||
|
||||
def getPeople(self, item):
|
||||
# Process People
|
||||
director=[]
|
||||
writer=[]
|
||||
cast=[]
|
||||
people = item.get("People")
|
||||
if(people != None):
|
||||
for person in people:
|
||||
if(person.get("Type") == "Director"):
|
||||
director.append(person.get("Name"))
|
||||
if(person.get("Type") == "Writing"):
|
||||
writer.append(person.get("Name"))
|
||||
if(person.get("Type") == "Writer"):
|
||||
writer.append(person.get("Name"))
|
||||
if(person.get("Type") == "Actor"):
|
||||
Name = person.get("Name")
|
||||
Role = person.get("Role")
|
||||
if Role == None:
|
||||
Role = ''
|
||||
cast.append(Name)
|
||||
return {'Director' : director,
|
||||
'Writer' : writer,
|
||||
'Cast' : cast
|
||||
}
|
||||
|
||||
def getTimeInfo(self, item):
|
||||
resumeTime = ''
|
||||
userData = item.get("UserData")
|
||||
PlaybackPositionTicks = '100'
|
||||
if userData.get("PlaybackPositionTicks") != None:
|
||||
PlaybackPositionTicks = str(userData.get("PlaybackPositionTicks"))
|
||||
reasonableTicks = int(userData.get("PlaybackPositionTicks")) / 1000
|
||||
resumeTime = reasonableTicks / 10000
|
||||
director = []
|
||||
writer = []
|
||||
cast = []
|
||||
|
||||
try:
|
||||
tempDuration = str(int(item.get("RunTimeTicks", "0"))/(10000000*60))
|
||||
except TypeError:
|
||||
try:
|
||||
tempDuration = str(int(item.get("CumulativeRunTimeTicks"))/(10000000*60))
|
||||
except TypeError:
|
||||
tempDuration = "0"
|
||||
cappedPercentage = None
|
||||
resume=0
|
||||
percentage=0
|
||||
if (resumeTime != "" and int(resumeTime) > 0):
|
||||
duration = float(tempDuration)
|
||||
if(duration > 0):
|
||||
resume = float(resumeTime) / 60
|
||||
percentage = int((resume / duration) * 100.0)
|
||||
return {'Duration' : tempDuration,
|
||||
'TotalTime' : tempDuration,
|
||||
'Percent' : str(percentage),
|
||||
'ResumeTime' : str(resume)
|
||||
}
|
||||
people = item['People']
|
||||
|
||||
except: pass
|
||||
|
||||
else:
|
||||
|
||||
for person in people:
|
||||
|
||||
type = person['Type']
|
||||
Name = person['Name']
|
||||
|
||||
if "Director" in type:
|
||||
director.append(Name)
|
||||
elif "Writing" in type:
|
||||
writer.append(Name)
|
||||
elif "Writer" in type:
|
||||
writer.append(Name)
|
||||
elif "Actor" in type:
|
||||
cast.append(Name)
|
||||
|
||||
return {
|
||||
|
||||
'Director': director,
|
||||
'Writer': writer,
|
||||
'Cast': cast
|
||||
}
|
||||
|
||||
def getTimeInfo(self, item):
|
||||
# Runtime and Resume point
|
||||
tempRuntime = 0
|
||||
runtime = 0
|
||||
resume = 0
|
||||
|
||||
try: # Get resume point
|
||||
userdata = item['UserData']
|
||||
playbackPosition = userdata['PlaybackPositionTicks']
|
||||
resume = playbackPosition / 10000000.0
|
||||
except: pass
|
||||
|
||||
try: # Get total runtime
|
||||
tempRuntime = item['RunTimeTicks']
|
||||
|
||||
except:
|
||||
try: tempRuntime = item['CumulativeRunTimeTicks']
|
||||
except: pass
|
||||
|
||||
finally:
|
||||
runtime = tempRuntime / 10000000.0
|
||||
|
||||
|
||||
return {
|
||||
|
||||
'ResumeTime': resume,
|
||||
'TotalTime': runtime
|
||||
}
|
||||
|
||||
def getStudios(self, item):
|
||||
# Process Studio
|
||||
studios = []
|
||||
if item.get("SeriesStudio") != None and item.get("SeriesStudio") != '':
|
||||
studios.append(item.get("SeriesStudio"))
|
||||
else:
|
||||
if(item.get("Studios") != []):
|
||||
for studio_string in item.get("Studios"):
|
||||
temp=studio_string.get("Name")
|
||||
studios.append(temp)
|
||||
studios = []
|
||||
|
||||
try:
|
||||
studio = item['SeriesStudio']
|
||||
studios.append(studio)
|
||||
except:
|
||||
try:
|
||||
studioArray = item['Studios']
|
||||
for studio in studioArray:
|
||||
studios.append(studio['Name'])
|
||||
except: pass
|
||||
|
||||
return studios
|
||||
|
||||
def getMediaStreams(self, item, mediaSources=False):
|
||||
# Process MediaStreams
|
||||
channels = ''
|
||||
videocodec = ''
|
||||
audiocodec = ''
|
||||
audiolanguage = ''
|
||||
subtitlelanguage = ''
|
||||
height = ''
|
||||
width = ''
|
||||
aspectratio = '1:1'
|
||||
aspectfloat = 1.85
|
||||
Video3DFormat = ''
|
||||
def getGenre(self,item):
|
||||
genre = ""
|
||||
genres = item.get("Genres")
|
||||
if genres != None and genres != []:
|
||||
for genre_string in genres:
|
||||
if genre == "": #Just take the first genre
|
||||
genre = genre_string
|
||||
else:
|
||||
genre = genre + " / " + genre_string
|
||||
elif item.get("SeriesGenres") != None and item.get("SeriesGenres") != '':
|
||||
genres = item.get("SeriesGenres")
|
||||
if genres != None and genres != []:
|
||||
for genre_string in genres:
|
||||
if genre == "": #Just take the first genre
|
||||
genre = genre_string
|
||||
else:
|
||||
genre = genre + " / " + genre_string
|
||||
return genre
|
||||
|
||||
if mediaSources == True:
|
||||
mediaSources = item.get("MediaSources")
|
||||
if(mediaSources != None):
|
||||
MediaStreams = mediaSources[0].get("MediaStreams")
|
||||
else:
|
||||
def getMediaStreams(self, item, mediaSources = False):
|
||||
|
||||
videotracks = [] # Height, Width, Codec, AspectRatio, AspectFloat, 3D
|
||||
audiotracks = [] # Codec, Channels, language
|
||||
subtitlelanguages = [] # Language
|
||||
|
||||
if mediaSources:
|
||||
try:
|
||||
MediaStreams = item['MediaSources'][0]['MediaStreams']
|
||||
except:
|
||||
MediaStreams = None
|
||||
else:
|
||||
MediaStreams = item.get("MediaStreams")
|
||||
if(MediaStreams != None):
|
||||
#mediaStreams = MediaStreams[0].get("MediaStreams")
|
||||
if(MediaStreams != None):
|
||||
for mediaStream in MediaStreams:
|
||||
if(mediaStream.get("Type") == "Video"):
|
||||
videocodec = mediaStream.get("Codec")
|
||||
if mediaStream.get("Height"):
|
||||
height = int(mediaStream.get("Height"))
|
||||
if mediaStream.get("Width"):
|
||||
width = int(mediaStream.get("Width"))
|
||||
aspectratio = mediaStream.get("AspectRatio")
|
||||
Video3DFormat = item.get("Video3DFormat")
|
||||
if aspectratio != None and len(aspectratio) >= 3:
|
||||
try:
|
||||
aspectwidth,aspectheight = aspectratio.split(':')
|
||||
aspectfloat = float(aspectwidth) / float(aspectheight)
|
||||
except:
|
||||
aspectfloat = 1.85
|
||||
if(mediaStream.get("Type") == "Audio"):
|
||||
isdefault = mediaStream.get("IsDefault") == "true"
|
||||
if audiocodec == '':
|
||||
audiocodec = mediaStream.get("Codec")
|
||||
if channels == '':
|
||||
channels = mediaStream.get("Channels")
|
||||
if audiolanguage == '':
|
||||
audiolanguage = mediaStream.get("Language")
|
||||
# only overwrite if default
|
||||
if isdefault:
|
||||
audiocodec = mediaStream.get("Codec")
|
||||
channels = mediaStream.get("Channels")
|
||||
audiolanguage = mediaStream.get("Language")
|
||||
if(mediaStream.get("Type") == "Subtitle"):
|
||||
isdefault = mediaStream.get("IsDefault") == "true"
|
||||
if subtitlelanguage == '':
|
||||
subtitlelanguage = mediaStream.get("Language")
|
||||
# only overwrite if default
|
||||
if isdefault:
|
||||
subtitlelanguage = mediaStream.get("Language")
|
||||
|
||||
|
||||
return {'channels' : str(channels),
|
||||
'videocodec' : videocodec,
|
||||
'audiocodec' : audiocodec,
|
||||
'audiolanguage' : audiolanguage,
|
||||
'subtitlelanguage' : subtitlelanguage,
|
||||
'height' : height,
|
||||
'width' : width,
|
||||
'aspectratio' : aspectfloat,
|
||||
'3dformat' : Video3DFormat
|
||||
}
|
||||
MediaStreams = item.get('MediaStreams')
|
||||
|
||||
if MediaStreams:
|
||||
# Sort through the Video, Audio, Subtitle tracks
|
||||
for mediaStream in MediaStreams:
|
||||
|
||||
type = mediaStream.get("Type", "")
|
||||
|
||||
if "Video" in type:
|
||||
videotrack = {}
|
||||
videotrack['videocodec'] = mediaStream.get('Codec')
|
||||
videotrack['height'] = mediaStream.get('Height')
|
||||
videotrack['width'] = mediaStream.get('Width')
|
||||
videotrack['aspectratio'] = mediaStream.get('AspectRatio')
|
||||
videotrack['Video3DFormat'] = item.get('Video3DFormat')
|
||||
if len(videotrack['aspectratio']) >= 3:
|
||||
try:
|
||||
aspectwidth, aspectheight = aspectratio.split(':')
|
||||
videotrack['aspectfloat'] = float(aspectwidth) / float(aspectheight)
|
||||
except:
|
||||
videotrack['aspectfloat'] = 1.85
|
||||
videotracks.append(videotrack)
|
||||
|
||||
elif "Audio" in type:
|
||||
audiotrack = {}
|
||||
audiotrack['audiocodec'] = mediaStream.get('Codec')
|
||||
audiotrack['channels'] = mediaStream.get('Channels')
|
||||
audiotrack['audiolanguage'] = mediaStream.get('Language')
|
||||
audiotracks.append(audiotrack)
|
||||
|
||||
elif "Subtitle" in type:
|
||||
try:
|
||||
subtitlelanguages.append(mediaStream['Language'])
|
||||
except:
|
||||
subtitlelanguages.append("Unknown")
|
||||
|
||||
return {
|
||||
|
||||
'videocodec' : videotracks,
|
||||
'audiocodec' : audiotracks,
|
||||
'subtitlelanguage' : subtitlelanguages
|
||||
}
|
||||
|
||||
|
||||
def getChecksum(self, item):
|
||||
# use the etags checksum for this if available
|
||||
|
@ -169,109 +185,62 @@ class API():
|
|||
return checksum
|
||||
|
||||
def getUserData(self, item):
|
||||
userData = item.get("UserData")
|
||||
resumeTime = 0
|
||||
if(userData != None):
|
||||
if userData.get("Played") != True:
|
||||
watched="True"
|
||||
else:
|
||||
watched="False"
|
||||
if userData.get("IsFavorite") == True:
|
||||
favorite=True
|
||||
else:
|
||||
favorite=False
|
||||
if(userData.get("Played") == True):
|
||||
# Cover the Emby scenario where item is played but playcount is 0.
|
||||
playcount = userData.get('PlayCount')
|
||||
# Default
|
||||
favorite = False
|
||||
playcount = None
|
||||
lastPlayedDate = None
|
||||
userKey = ""
|
||||
|
||||
try:
|
||||
userdata = item['UserData']
|
||||
|
||||
except: # No userdata found.
|
||||
pass
|
||||
|
||||
else:
|
||||
favorite = userdata['IsFavorite']
|
||||
userKey = userdata.get('Key', "")
|
||||
|
||||
watched = userdata['Played']
|
||||
if watched:
|
||||
# Playcount is tied to the watch status
|
||||
playcount = userdata['PlayCount']
|
||||
if playcount == 0:
|
||||
playcount = 1
|
||||
else:
|
||||
playcount="0"
|
||||
if userData.get('UnplayedItemCount') != None:
|
||||
UnplayedItemCount = userData.get('UnplayedItemCount')
|
||||
else:
|
||||
UnplayedItemCount = "0"
|
||||
if userData.get('LastPlayedDate') != None:
|
||||
#TODO--> is there some other way to do this ?
|
||||
datestring = userData.get('LastPlayedDate').split('T')[0]
|
||||
timestring = userData.get('LastPlayedDate').split('T')[1]
|
||||
timestring = timestring.split('.')[0]
|
||||
LastPlayedDate = datestring + " " + timestring
|
||||
else:
|
||||
LastPlayedDate = None
|
||||
if userData.get('PlaybackPositionTicks') != None:
|
||||
PlaybackPositionTicks = userData.get('PlaybackPositionTicks')
|
||||
else:
|
||||
PlaybackPositionTicks = ''
|
||||
userKey = userData.get("Key", "")
|
||||
return {'Watched' : watched,
|
||||
'Favorite' : favorite,
|
||||
'PlayCount': playcount,
|
||||
'LastPlayedDate': LastPlayedDate,
|
||||
'UnplayedItemCount' : UnplayedItemCount,
|
||||
'PlaybackPositionTicks' : str(PlaybackPositionTicks),
|
||||
'Key' : userKey
|
||||
}
|
||||
|
||||
def getGenre(self,item):
|
||||
genre = ""
|
||||
genres = item.get("Genres")
|
||||
if genres != None and genres != []:
|
||||
for genre_string in genres:
|
||||
if genre == "": #Just take the first genre
|
||||
genre = genre_string
|
||||
else:
|
||||
genre = genre + " / " + genre_string
|
||||
elif item.get("SeriesGenres") != None and item.get("SeriesGenres") != '':
|
||||
genres = item.get("SeriesGenres")
|
||||
if genres != None and genres != []:
|
||||
for genre_string in genres:
|
||||
if genre == "": #Just take the first genre
|
||||
genre = genre_string
|
||||
else:
|
||||
genre = genre + " / " + genre_string
|
||||
return genre
|
||||
|
||||
def getName(self, item):
|
||||
Temp = item.get("Name")
|
||||
if Temp == None:
|
||||
Temp = ""
|
||||
Name=Temp.encode('utf-8')
|
||||
return Name
|
||||
playcount = None
|
||||
|
||||
lastPlayedDate = userdata.get('LastPlayedDate', None)
|
||||
if lastPlayedDate:
|
||||
lastPlayedDate = lastPlayedDate.split('.')[0].replace('T', " ")
|
||||
|
||||
return {
|
||||
|
||||
'Favorite': favorite,
|
||||
'PlayCount': playcount,
|
||||
'LastPlayedDate': lastPlayedDate,
|
||||
'Key': userKey
|
||||
}
|
||||
|
||||
|
||||
def getRecursiveItemCount(self, item):
|
||||
if item.get("RecursiveItemCount") != None:
|
||||
return str(item.get("RecursiveItemCount"))
|
||||
else:
|
||||
return "0"
|
||||
|
||||
def getSeriesName(self, item):
|
||||
Temp = item.get("SeriesName")
|
||||
if Temp == None:
|
||||
Temp = ""
|
||||
Name=Temp.encode('utf-8')
|
||||
return Name
|
||||
return "0"
|
||||
|
||||
def getOverview(self, item):
|
||||
Temp = item.get("Overview")
|
||||
if Temp == None:
|
||||
Temp=''
|
||||
Overview1=Temp.encode('utf-8')
|
||||
Overview=str(Overview1)
|
||||
Overview=Overview.replace("\"", "\'")
|
||||
Overview=Overview.replace("\n", " ")
|
||||
Overview=Overview.replace("\r", " ")
|
||||
return Overview
|
||||
|
||||
def getPremiereDate(self, item):
|
||||
if(item.get("PremiereDate") != None):
|
||||
premieredatelist = (item.get("PremiereDate")).split("T")
|
||||
premieredate = premieredatelist[0]
|
||||
else:
|
||||
premieredate = ""
|
||||
Temp = premieredate
|
||||
premieredate = Temp.encode('utf-8')
|
||||
return premieredate
|
||||
|
||||
overview = ""
|
||||
|
||||
try:
|
||||
overview = item['Overview']
|
||||
overview = overview.replace("\"", "\'")
|
||||
overview = overview.replace("\n", " ")
|
||||
overview = overview.replace("\r", " ")
|
||||
except: pass
|
||||
|
||||
return overview
|
||||
|
||||
def getTVInfo(self, item, userData):
|
||||
TotalSeasons = 0 if item.get("ChildCount")==None else item.get("ChildCount")
|
||||
|
@ -306,15 +275,105 @@ class API():
|
|||
'Episode' : tempEpisode,
|
||||
'SeriesName' : SeriesName
|
||||
}
|
||||
|
||||
def getDateCreated(self, item):
|
||||
tempDate = item.get("DateCreated")
|
||||
if tempDate != None:
|
||||
tempDate = tempDate.split("T")[0]
|
||||
date = tempDate.split("-")
|
||||
tempDate = date[2] + "." + date[1] + "." +date[0]
|
||||
else:
|
||||
tempDate = "01.01.2000"
|
||||
return tempDate
|
||||
|
||||
dateadded = None
|
||||
|
||||
try:
|
||||
dateadded = item['DateCreated']
|
||||
dateadded = dateadded.split('.')[0].replace('T', " ")
|
||||
except: pass
|
||||
|
||||
return dateadded
|
||||
|
||||
def getPremiereDate(self, item):
|
||||
|
||||
premiere = None
|
||||
|
||||
try:
|
||||
premiere = item['PremiereDate']
|
||||
premiere = premiere.split('.')[0].replace('T', " ")
|
||||
except: pass
|
||||
|
||||
return premiere
|
||||
|
||||
def getTagline(self, item):
|
||||
|
||||
tagline = None
|
||||
|
||||
try:
|
||||
tagline = item['Taglines'][0]
|
||||
except: pass
|
||||
|
||||
return tagline
|
||||
|
||||
def getProvider(self, item, providername):
|
||||
# Provider Name: imdb or tvdb
|
||||
provider = None
|
||||
|
||||
try:
|
||||
if "imdb" in providername:
|
||||
provider = item['ProviderIds']['Imdb']
|
||||
elif "tvdb" in providername:
|
||||
provider = item['ProviderIds']['Tvdb']
|
||||
except: pass
|
||||
|
||||
return provider
|
||||
|
||||
def getCountry(self, item):
|
||||
|
||||
country = None
|
||||
|
||||
try:
|
||||
country = item['ProductionLocations'][0]
|
||||
except: pass
|
||||
|
||||
return country
|
||||
|
||||
def getArtworks(self, data, type, mediaType = "", index = "0", getAll = False):
|
||||
|
||||
"""
|
||||
Get all artwork, it will return an empty string
|
||||
for the artwork type not found.
|
||||
|
||||
Index only matters when getAll is False.
|
||||
|
||||
mediaType: movie, boxset, tvshow, episode, season
|
||||
|
||||
Artwork type: Primary, Banner, Logo, Art, Thumb,
|
||||
Disc Backdrop
|
||||
"""
|
||||
id = data['Id']
|
||||
|
||||
maxHeight = 10000
|
||||
maxWidth = 10000
|
||||
imageTag = "e3ab56fe27d389446754d0fb04910a34" # Place holder tag
|
||||
|
||||
|
||||
if getAll:
|
||||
|
||||
allartworks = {
|
||||
|
||||
'Primary': "",
|
||||
'Banner': "",
|
||||
'Logo': "",
|
||||
'Art': "",
|
||||
'Thumb': "",
|
||||
'Disc': "",
|
||||
'Backdrop': ""
|
||||
}
|
||||
|
||||
for keytype in allartworks:
|
||||
type = keytype
|
||||
url = ""
|
||||
|
||||
allartworks[keytype] = url
|
||||
|
||||
|
||||
return allartworks
|
||||
|
||||
else: pass
|
||||
|
||||
def getArtwork(self, data, type, mediaType = "", index = "0", userParentInfo = False):
|
||||
|
||||
|
@ -416,6 +475,14 @@ class API():
|
|||
artwork=''
|
||||
|
||||
return artwork
|
||||
|
||||
def imageUrl(self, id, type, index, width, height):
|
||||
|
||||
WINDOW = xbmcgui.Window(10000)
|
||||
username = WINDOW.getProperty('currUser')
|
||||
server = WINDOW.getProperty('server%s' % username)
|
||||
# For people image - actors, directors, writers
|
||||
return "%s/mediabrowser/Items/%s/Images/%s?MaxWidth=%s&MaxHeight=%s&Index=%s" % (server, id, type, width, height, index)
|
||||
|
||||
def getUserArtwork(self, data, type, index = "0"):
|
||||
|
||||
|
|
|
@ -659,61 +659,67 @@ class LibrarySync(threading.Thread):
|
|||
# Delete from Kodi before Emby
|
||||
# To be able to get mediaType
|
||||
doUtils = DownloadUtils()
|
||||
|
||||
video = []
|
||||
video = {}
|
||||
music = []
|
||||
|
||||
itemIds = ','.join(itemList)
|
||||
url = "{server}/mediabrowser/Users/{UserId}/Items?Ids=%s&format=json" % itemIds
|
||||
result = doUtils.downloadUrl(url)
|
||||
|
||||
if result is "":
|
||||
# Websocket feedback
|
||||
self.logMsg("Item %s is removed." % itemIds)
|
||||
return
|
||||
|
||||
for item in result[u'Items']:
|
||||
# Sort by type for database deletion
|
||||
itemId = item["Id"]
|
||||
mediaType = item["MediaType"]
|
||||
# Database connection to myVideosXX.db
|
||||
connectionvideo = utils.KodiSQL()
|
||||
cursorvideo = connectionvideo.cursor()
|
||||
# Database connection to myMusicXX.db
|
||||
connectionmusic = utils.KodiSQL("music")
|
||||
cursormusic = connectionmusic.cursor()
|
||||
|
||||
if "Video" in mediaType:
|
||||
video.append(itemId)
|
||||
elif "Audio" in mediaType:
|
||||
music.append(itemId)
|
||||
for item in itemList:
|
||||
# Sort by type for database deletion
|
||||
try: # Search video database
|
||||
self.logMsg("Check video database.", 1)
|
||||
cursorvideo.execute("SELECT media_type FROM emby WHERE emby_id = ?", (item,))
|
||||
mediatype = cursorvideo.fetchone()[0]
|
||||
video[item] = mediatype
|
||||
#video.append(itemtype)
|
||||
except:
|
||||
self.logMsg("Check music database.", 1)
|
||||
try: # Search music database
|
||||
cursormusic.execute("SELECT media_type FROM emby WHERE emby_id = ?", (item,))
|
||||
cursormusic.fetchone()[0]
|
||||
music.append(item)
|
||||
except: self.logMsg("Item %s is not found in Kodi database." % item, 1)
|
||||
|
||||
if len(video) > 0:
|
||||
#Process video library
|
||||
connection = utils.KodiSQL("video")
|
||||
cursor = connection.cursor()
|
||||
|
||||
connection = connectionvideo
|
||||
cursor = cursorvideo
|
||||
# Process video library
|
||||
for item in video:
|
||||
type = ReadKodiDB().getTypeByEmbyId(item, connection, cursor)
|
||||
self.logMsg("Type: %s" % type)
|
||||
self.logMsg("Message: Doing LibraryChanged: Items Removed: Calling deleteItemFromKodiLibrary: %s" % item, 0)
|
||||
|
||||
type = video[item]
|
||||
self.logMsg("Doing LibraryChanged: Items Removed: Calling deleteItemFromKodiLibrary: %s" % item, 1)
|
||||
|
||||
if "episode" in type:
|
||||
# Get the TV Show Id for reference later
|
||||
showId = ReadKodiDB().getShowIdByEmbyId(item, connection, cursor)
|
||||
self.logMsg("ShowId: %s" % showId, 0)
|
||||
self.logMsg("ShowId: %s" % showId, 1)
|
||||
WriteKodiVideoDB().deleteItemFromKodiLibrary(item, connection, cursor)
|
||||
# Verification
|
||||
if "episode" in type:
|
||||
showTotalCount = ReadKodiDB().getShowTotalCount(showId, connection, cursor)
|
||||
self.logMsg("ShowTotalCount: %s" % showTotalCount, 0)
|
||||
self.logMsg("ShowTotalCount: %s" % showTotalCount, 1)
|
||||
# If there are no episodes left
|
||||
if showTotalCount == 0 or showTotalCount == None:
|
||||
# Delete show
|
||||
embyId = ReadKodiDB().getEmbyIdByKodiId(showId, "tvshow", connection, cursor)
|
||||
self.logMsg("Message: Doing LibraryChanged: Deleting show: %s" % embyId, 0)
|
||||
self.logMsg("Message: Doing LibraryChanged: Deleting show: %s" % embyId, 1)
|
||||
WriteKodiVideoDB().deleteItemFromKodiLibrary(embyId, connection, cursor)
|
||||
|
||||
connection.commit()
|
||||
cursor.close()
|
||||
# Close connection
|
||||
cursorvideo.close()
|
||||
|
||||
if len(music) > 0:
|
||||
connection = connectionmusic
|
||||
cursor = cursormusic
|
||||
#Process music library
|
||||
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
||||
if addon.getSetting("enableMusicSync") is "true":
|
||||
addon = xbmcaddon.Addon()
|
||||
if addon.getSetting('enableMusicSync') == "true":
|
||||
connection = utils.KodiSQL("music")
|
||||
cursor = connection.cursor()
|
||||
|
||||
|
@ -722,35 +728,34 @@ class LibrarySync(threading.Thread):
|
|||
WriteKodiMusicDB().deleteItemFromKodiLibrary(item, connection, cursor)
|
||||
|
||||
connection.commit()
|
||||
cursor.close()
|
||||
# Close connection
|
||||
cursormusic.close()
|
||||
|
||||
if deleteEmbyItem:
|
||||
for item in itemList:
|
||||
url = "{server}/mediabrowser/Items/%s" % item
|
||||
self.logMsg('Deleting via URL: %s' % url)
|
||||
doUtils.downloadUrl(url, type="DELETE")
|
||||
doUtils.downloadUrl(url, type = "DELETE")
|
||||
xbmc.executebuiltin("Container.Refresh")
|
||||
|
||||
def remove_items(self, itemsRemoved):
|
||||
|
||||
# websocket client
|
||||
self.removeItems.extend(itemsRemoved)
|
||||
|
||||
def update_items(self, itemsToUpdate):
|
||||
# doing adds and updates
|
||||
# websocket client
|
||||
if(len(itemsToUpdate) > 0):
|
||||
self.logMsg("Message : Doing LibraryChanged : Processing Added and Updated : " + str(itemsToUpdate), 0)
|
||||
self.logMsg("Doing LibraryChanged : Processing Added and Updated : " + str(itemsToUpdate), 0)
|
||||
self.updateItems.extend(itemsToUpdate)
|
||||
self.doIncrementalSync = True
|
||||
|
||||
def user_data_update(self, userDataList):
|
||||
# do full playcount update for now
|
||||
# websocket client
|
||||
for userData in userDataList:
|
||||
itemId = userData.get("ItemId")
|
||||
if(itemId != None):
|
||||
self.updateItems.append(itemId)
|
||||
if(len(self.updateItems) > 0):
|
||||
self.logMsg("Message : Doing UserDataChanged : Processing Updated : " + str(self.updateItems), 0)
|
||||
self.doIncrementalSync = True
|
||||
self.logMsg("Doing UserDataChanged : Processing Updated : " + str(self.updateItems), 0)
|
||||
|
||||
def ShouldStop(self):
|
||||
|
||||
|
@ -770,32 +775,44 @@ class LibrarySync(threading.Thread):
|
|||
|
||||
while not self.KodiMonitor.abortRequested():
|
||||
|
||||
# In the event the server goes offline after
|
||||
# the thread has already been started.
|
||||
while self.suspendClient == True:
|
||||
# The service.py will change self.suspendClient to False
|
||||
if self.KodiMonitor.waitForAbort(5):
|
||||
# Abort was requested while waiting. We should exit
|
||||
break
|
||||
|
||||
# Library sync
|
||||
if not startupComplete:
|
||||
# Run full sync
|
||||
self.logMsg("Doing_Db_Sync: syncDatabase (Started)", 1)
|
||||
startTime = datetime.now()
|
||||
libSync = self.FullLibrarySync()
|
||||
self.logMsg("Doing_Db_Sync: syncDatabase (Finished) %s" % libSync, 1)
|
||||
elapsedTime = datetime.now() - startTime
|
||||
self.logMsg("Doing_Db_Sync: syncDatabase (Finished in: %s) %s" % (str(elapsedTime).split('.')[0], libSync), 1)
|
||||
|
||||
if libSync:
|
||||
startupComplete = True
|
||||
|
||||
if WINDOW.getProperty("OnWakeSync") == "true":
|
||||
# Set via Kodi Monitor event
|
||||
if WINDOW.getProperty("OnWakeSync") == "true" and WINDOW.getProperty('Server_online') == "true":
|
||||
WINDOW.clearProperty("OnWakeSync")
|
||||
if WINDOW.getProperty("SyncDatabaseRunning") != "true":
|
||||
utils.logMsg("Doing_Db_Sync Post Resume: syncDatabase (Started)",0)
|
||||
self.logMsg("Doing_Db_Sync Post Resume: syncDatabase (Started)", 0)
|
||||
libSync = self.FullLibrarySync()
|
||||
utils.logMsg("Doing_Db_Sync Post Resume: syncDatabase (Finished) " + str(libSync),0)
|
||||
self.logMsg("Doing_Db_Sync Post Resume: syncDatabase (Finished) " + str(libSync), 0)
|
||||
|
||||
if self.doIncrementalSync:
|
||||
# Add or update item to Kodi library
|
||||
if len(self.updateItems) > 0:
|
||||
# Add or update items
|
||||
self.logMsg("Processing items: %s" % (str(self.updateItems)), 1)
|
||||
listItems = self.updateItems
|
||||
self.updateItems = []
|
||||
self.doIncrementalSync = False
|
||||
self.IncrementalSync(listItems)
|
||||
|
||||
if len(self.removeItems) > 0:
|
||||
# Remove item from Kodi library
|
||||
self.logMsg("Removing items: %s" % self.removeItems, 1)
|
||||
listItems = self.removeItems
|
||||
self.removeItems = []
|
||||
self.removefromDB(listItems)
|
||||
|
@ -805,3 +822,11 @@ class LibrarySync(threading.Thread):
|
|||
break
|
||||
|
||||
self.logMsg("--- Library Sync Thread stopped ---", 0)
|
||||
|
||||
def suspendClient(self):
|
||||
self.suspendClient = True
|
||||
self.logMsg("--- Library Sync Thread paused ---", 0)
|
||||
|
||||
def resumeClient(self):
|
||||
self.suspendClient = False
|
||||
self.logMsg("--- Library Sync Thread resumed ---", 0)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
#################################################################################################
|
||||
# utils class
|
||||
#################################################################################################
|
||||
|
@ -19,8 +21,7 @@ class PlayUtils():
|
|||
clientInfo = ClientInformation()
|
||||
|
||||
addonName = clientInfo.getAddonName()
|
||||
addonId = clientInfo.getAddonId()
|
||||
addon = xbmcaddon.Addon(id=addonId)
|
||||
addon = xbmcaddon.Addon()
|
||||
|
||||
audioPref = addon.getSetting('Audiopref')
|
||||
subsPref = addon.getSetting('Subspref')
|
||||
|
@ -35,76 +36,36 @@ class PlayUtils():
|
|||
|
||||
def getPlayUrl(self, server, id, result):
|
||||
|
||||
addon = self.addon
|
||||
WINDOW = xbmcgui.Window(10000)
|
||||
username = WINDOW.getProperty('currUser')
|
||||
server = WINDOW.getProperty('server%s' % username)
|
||||
|
||||
if self.isDirectPlay(result):
|
||||
try:
|
||||
# Try direct play
|
||||
playurl = self.directPlay(result)
|
||||
if not playurl:
|
||||
# Let user know that direct play failed
|
||||
resp = xbmcgui.Dialog().select('Warning: Unable to direct play.', ['Play from HTTP', 'Play from HTTP and remember next time.'])
|
||||
if resp > -1:
|
||||
# Play from HTTP
|
||||
playurl = self.directStream(result, server, id)
|
||||
if resp == 1:
|
||||
# Remember next time
|
||||
addon.setSetting('playFromStream', "true")
|
||||
if not playurl:
|
||||
# Try transcoding
|
||||
playurl = self.transcoding(result, server, id)
|
||||
WINDOW.setProperty("transcoding%s" % id, "true")
|
||||
self.logMsg("File is transcoding.", 1)
|
||||
WINDOW.setProperty("%splaymethod" % playurl, "Transcode")
|
||||
else:
|
||||
self.logMsg("File is direct streaming.", 1)
|
||||
WINDOW.setProperty("%splaymethod" % playurl, "DirectStream")
|
||||
else:
|
||||
# User decided not to proceed.
|
||||
self.logMsg("Unable to direct play. Verify the following path is accessible by the device: %s. You might also need to add SMB credentials in the addon settings." % result[u'MediaSources'][0][u'Path'])
|
||||
return False
|
||||
else:
|
||||
self.logMsg("File is direct playing.", 1)
|
||||
WINDOW.setProperty("%splaymethod" % playurl.encode('utf-8'), "DirectPlay")
|
||||
except:
|
||||
return False
|
||||
if self.isDirectPlay(result,True):
|
||||
# Try direct play
|
||||
playurl = self.directPlay(result)
|
||||
if playurl:
|
||||
self.logMsg("File is direct playing.", 1)
|
||||
WINDOW.setProperty("%splaymethod" % playurl.encode('utf-8'), "DirectPlay")
|
||||
|
||||
elif self.isDirectStream(result):
|
||||
try:
|
||||
# Try direct stream
|
||||
playurl = self.directStream(result, server, id)
|
||||
if not playurl:
|
||||
# Try transcoding
|
||||
playurl = self.transcoding(result, server, id)
|
||||
WINDOW.setProperty("transcoding%s" % id, "true")
|
||||
self.logMsg("File is transcoding.", 1)
|
||||
WINDOW.setProperty("%splaymethod" % playurl, "Transcode")
|
||||
else:
|
||||
self.logMsg("File is direct streaming.", 1)
|
||||
WINDOW.setProperty("%splaymethod" % playurl, "DirectStream")
|
||||
except:
|
||||
return False
|
||||
# Try direct stream
|
||||
playurl = self.directStream(result, server, id)
|
||||
if playurl:
|
||||
self.logMsg("File is direct streaming.", 1)
|
||||
WINDOW.setProperty("%splaymethod" % playurl, "DirectStream")
|
||||
|
||||
elif self.isTranscoding(result):
|
||||
try:
|
||||
# Try transcoding
|
||||
playurl = self.transcoding(result, server, id)
|
||||
WINDOW.setProperty("transcoding%s" % id, "true")
|
||||
else:# Try transcoding
|
||||
playurl = self.transcoding(result, server, id)
|
||||
if playurl:
|
||||
self.logMsg("File is transcoding.", 1)
|
||||
WINDOW.setProperty("%splaymethod" % playurl, "Transcode")
|
||||
except:
|
||||
return False
|
||||
|
||||
return playurl.encode('utf-8')
|
||||
|
||||
|
||||
def isDirectPlay(self, result):
|
||||
def isDirectPlay(self, result, dialog=False):
|
||||
# Requirements for Direct play:
|
||||
# FileSystem, Accessible path
|
||||
self.addon = xbmcaddon.Addon(id=self.addonId)
|
||||
self.addon = xbmcaddon.Addon()
|
||||
|
||||
playhttp = self.addon.getSetting('playFromStream')
|
||||
# User forcing to play via HTTP instead of SMB
|
||||
|
@ -126,17 +87,30 @@ class PlayUtils():
|
|||
return True
|
||||
else:
|
||||
self.logMsg("Can't direct play: Unable to locate the content.", 1)
|
||||
if dialog:
|
||||
# Let user know that direct play failed
|
||||
resp = xbmcgui.Dialog().select('Warning: Unable to direct play.', ['Play from HTTP', 'Play from HTTP and remember next time.'])
|
||||
if resp == 1:
|
||||
# Remember next time
|
||||
addon.setSetting('playFromStream', "true")
|
||||
else:
|
||||
# User decided not to proceed.
|
||||
self.logMsg("Unable to direct play. Verify the following path is accessible by the device: %s. You might also need to add SMB credentials in the addon settings." % result[u'MediaSources'][0][u'Path'])
|
||||
return False
|
||||
|
||||
|
||||
def directPlay(self, result):
|
||||
|
||||
addon = self.addon
|
||||
|
||||
try:
|
||||
# Item can be played directly
|
||||
playurl = result[u'MediaSources'][0][u'Path']
|
||||
|
||||
try:
|
||||
playurl = result[u'MediaSources'][0][u'Path']
|
||||
except:
|
||||
playurl = result[u'Path']
|
||||
except:
|
||||
self.logMsg("Direct play failed. Trying Direct stream.", 1)
|
||||
return False
|
||||
else:
|
||||
if u'VideoType' in result:
|
||||
# Specific format modification
|
||||
if u'Dvd' in result[u'VideoType']:
|
||||
|
@ -156,19 +130,15 @@ class PlayUtils():
|
|||
playurl = playurl.replace("\\", "/")
|
||||
|
||||
if "apple.com" in playurl:
|
||||
USER_AGENT = 'QuickTime/7.7.4'
|
||||
USER_AGENT = "QuickTime/7.7.4"
|
||||
playurl += "?|User-Agent=%s" % USER_AGENT
|
||||
|
||||
if ":" not in playurl:
|
||||
self.logMsg("Path seems invalid: %s" % playurl)
|
||||
self.logMsg("Path seems invalid: %s" % playurl, 1)
|
||||
return False
|
||||
|
||||
return playurl
|
||||
|
||||
except:
|
||||
self.logMsg("Direct play failed. Trying Direct stream.", 1)
|
||||
return False
|
||||
|
||||
def isDirectStream(self, result):
|
||||
# Requirements for Direct stream:
|
||||
# FileSystem or Remote, BitRate, supported encoding
|
||||
|
@ -188,23 +158,24 @@ class PlayUtils():
|
|||
|
||||
return True
|
||||
|
||||
def directStream(self, result, server, id, type="Video"):
|
||||
def directStream(self, result, server, id, type = "Video"):
|
||||
|
||||
try:
|
||||
if type == "Video":
|
||||
# Play with Direct Stream
|
||||
if "ThemeVideo" in type:
|
||||
playurl ="%s/mediabrowser/Videos/%s/stream?static=true" % (server, id)
|
||||
|
||||
elif "Video" in type:
|
||||
playurl = "%s/mediabrowser/Videos/%s/stream?static=true" % (server, id)
|
||||
elif type == "Audio":
|
||||
# Verify audio and subtitles
|
||||
mediaSources = result[u'MediaSources']
|
||||
if mediaSources[0].get('DefaultAudioStreamIndex') != None:
|
||||
playurl = "%s&AudioStreamIndex=%s" % (playurl, mediaSources[0].get('DefaultAudioStreamIndex'))
|
||||
if mediaSources[0].get('DefaultSubtitleStreamIndex') != None:
|
||||
playurl = "%s&SubtitleStreamIndex=%s" % (playurl, mediaSources[0].get('DefaultSubtitleStreamIndex'))
|
||||
|
||||
elif "Audio" in type:
|
||||
playurl = "%s/mediabrowser/Audio/%s/stream.mp3" % (server, id)
|
||||
return playurl
|
||||
|
||||
mediaSources = result[u'MediaSources']
|
||||
if mediaSources[0].get('DefaultAudioStreamIndex') != None:
|
||||
playurl = "%s&AudioStreamIndex=%s" % (playurl, mediaSources[0].get('DefaultAudioStreamIndex'))
|
||||
if mediaSources[0].get('DefaultSubtitleStreamIndex') != None:
|
||||
playurl = "%s&SubtitleStreamIndex=%s" % (playurl, mediaSources[0].get('DefaultSubtitleStreamIndex'))
|
||||
|
||||
self.logMsg("Playurl: %s" % playurl)
|
||||
|
||||
return playurl
|
||||
|
||||
except:
|
||||
|
@ -329,7 +300,7 @@ class PlayUtils():
|
|||
# Local or Network path
|
||||
self.logMsg("Path exists.", 2)
|
||||
return True
|
||||
elif ":\\" not in path:
|
||||
elif "nfs:" in path.lower():
|
||||
# Give benefit of the doubt.
|
||||
self.logMsg("Can't verify path. Still try direct play.", 2)
|
||||
return True
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue