mirror of
https://github.com/jellyfin/jellyfin-kodi.git
synced 2025-01-23 16:36:12 +00:00
work in progress - move home videos to plugin listing
This commit is contained in:
parent
b7f0f869eb
commit
ee9f08080e
9 changed files with 172 additions and 398 deletions
|
@ -41,7 +41,7 @@ if __name__ == '__main__':
|
||||||
if not itemtype and xbmc.getCondVisibility("Container.Content(artists)"): itemtype = "artist"
|
if not itemtype and xbmc.getCondVisibility("Container.Content(artists)"): itemtype = "artist"
|
||||||
if not itemtype and xbmc.getCondVisibility("Container.Content(songs)"): itemtype = "song"
|
if not itemtype and xbmc.getCondVisibility("Container.Content(songs)"): itemtype = "song"
|
||||||
|
|
||||||
logMsg("Contextmenu opened for itemid: %s - itemtype: %s" %(itemid,itemtype),0)
|
logMsg("Contextmenu opened for itemid: %s - itemtype: %s" %(itemid,itemtype))
|
||||||
|
|
||||||
userid = utils.window('emby_currUser')
|
userid = utils.window('emby_currUser')
|
||||||
server = utils.window('emby_server%s' % userid)
|
server = utils.window('emby_server%s' % userid)
|
||||||
|
|
|
@ -58,6 +58,7 @@ class Main:
|
||||||
'thememedia': entrypoint.getThemeMedia,
|
'thememedia': entrypoint.getThemeMedia,
|
||||||
'channels': entrypoint.BrowseChannels,
|
'channels': entrypoint.BrowseChannels,
|
||||||
'channelsfolder': entrypoint.BrowseChannels,
|
'channelsfolder': entrypoint.BrowseChannels,
|
||||||
|
'browsecontent': entrypoint.BrowseContent,
|
||||||
'nextup': entrypoint.getNextUpEpisodes,
|
'nextup': entrypoint.getNextUpEpisodes,
|
||||||
'inprogressepisodes': entrypoint.getInProgressEpisodes,
|
'inprogressepisodes': entrypoint.getInProgressEpisodes,
|
||||||
'recentepisodes': entrypoint.getRecentEpisodes,
|
'recentepisodes': entrypoint.getRecentEpisodes,
|
||||||
|
@ -79,6 +80,9 @@ class Main:
|
||||||
|
|
||||||
elif mode == "channels":
|
elif mode == "channels":
|
||||||
modes[mode](itemid)
|
modes[mode](itemid)
|
||||||
|
|
||||||
|
elif mode == "browsecontent":
|
||||||
|
modes[mode]( itemid, params.get('type',[""])[0], params.get('folderid',[""])[0], params.get('filter',[""])[0] )
|
||||||
|
|
||||||
elif mode == "channelsfolder":
|
elif mode == "channelsfolder":
|
||||||
folderid = params['folderid'][0]
|
folderid = params['folderid'][0]
|
||||||
|
|
|
@ -122,6 +122,7 @@ class API():
|
||||||
media_streams = item['MediaSources'][0]['MediaStreams']
|
media_streams = item['MediaSources'][0]['MediaStreams']
|
||||||
|
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
if not item.get("MediaStreams"): return None
|
||||||
media_streams = item['MediaStreams']
|
media_streams = item['MediaStreams']
|
||||||
|
|
||||||
for media_stream in media_streams:
|
for media_stream in media_streams:
|
||||||
|
@ -134,11 +135,11 @@ class API():
|
||||||
# Height, Width, Codec, AspectRatio, AspectFloat, 3D
|
# Height, Width, Codec, AspectRatio, AspectFloat, 3D
|
||||||
track = {
|
track = {
|
||||||
|
|
||||||
'videocodec': codec,
|
'codec': codec,
|
||||||
'height': media_stream.get('Height'),
|
'height': media_stream.get('Height'),
|
||||||
'width': media_stream.get('Width'),
|
'width': media_stream.get('Width'),
|
||||||
'video3DFormat': item.get('Video3DFormat'),
|
'video3DFormat': item.get('Video3DFormat'),
|
||||||
'aspectratio': 1.85
|
'aspect': 1.85
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -148,47 +149,50 @@ class API():
|
||||||
|
|
||||||
# Sort codec vs container/profile
|
# Sort codec vs container/profile
|
||||||
if "msmpeg4" in codec:
|
if "msmpeg4" in codec:
|
||||||
track['videocodec'] = "divx"
|
track['codec'] = "divx"
|
||||||
elif "mpeg4" in codec:
|
elif "mpeg4" in codec:
|
||||||
if "simple profile" in profile or not profile:
|
if "simple profile" in profile or not profile:
|
||||||
track['videocodec'] = "xvid"
|
track['codec'] = "xvid"
|
||||||
elif "h264" in codec:
|
elif "h264" in codec:
|
||||||
if container in ("mp4", "mov", "m4v"):
|
if container in ("mp4", "mov", "m4v"):
|
||||||
track['videocodec'] = "avc1"
|
track['codec'] = "avc1"
|
||||||
|
|
||||||
# Aspect ratio
|
# Aspect ratio
|
||||||
if item.get('AspectRatio'):
|
if item.get('AspectRatio'):
|
||||||
# Metadata AR
|
# Metadata AR
|
||||||
aspectratio = item['AspectRatio']
|
aspect = item['AspectRatio']
|
||||||
else: # File AR
|
else: # File AR
|
||||||
aspectratio = media_stream.get('AspectRatio', "0")
|
aspect = media_stream.get('AspectRatio', "0")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
aspectwidth, aspectheight = aspectratio.split(':')
|
aspectwidth, aspectheight = aspect.split(':')
|
||||||
track['aspectratio'] = round(float(aspectwidth) / float(aspectheight), 6)
|
track['aspect'] = round(float(aspectwidth) / float(aspectheight), 6)
|
||||||
|
|
||||||
except (ValueError, ZeroDivisionError):
|
except (ValueError, ZeroDivisionError):
|
||||||
width = track.get('width')
|
width = track.get('width')
|
||||||
height = track.get('height')
|
height = track.get('height')
|
||||||
|
|
||||||
if width and height:
|
if width and height:
|
||||||
track['aspectratio'] = round(float(width / height), 6)
|
track['aspect'] = round(float(width / height), 6)
|
||||||
else:
|
else:
|
||||||
track['aspectratio'] = 1.85
|
track['aspect'] = 1.85
|
||||||
|
|
||||||
|
if item.get("RunTimeTicks"):
|
||||||
|
track['duration'] = item.get("RunTimeTicks") / 10000000.0
|
||||||
|
|
||||||
videotracks.append(track)
|
videotracks.append(track)
|
||||||
|
|
||||||
elif stream_type == "Audio":
|
elif stream_type == "Audio":
|
||||||
# Codec, Channels, language
|
# Codec, Channels, language
|
||||||
track = {
|
track = {
|
||||||
|
|
||||||
'audiocodec': codec,
|
'codec': codec,
|
||||||
'channels': media_stream.get('Channels'),
|
'channels': media_stream.get('Channels'),
|
||||||
'audiolanguage': media_stream.get('Language')
|
'language': media_stream.get('Language')
|
||||||
}
|
}
|
||||||
|
|
||||||
if "dca" in codec and "dts-hd ma" in profile:
|
if "dca" in codec and "dts-hd ma" in profile:
|
||||||
track['audiocodec'] = "dtshd_ma"
|
track['codec'] = "dtshd_ma"
|
||||||
|
|
||||||
audiotracks.append(track)
|
audiotracks.append(track)
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@ def doMainListing():
|
||||||
path = utils.window('Emby.nodes.%s.content' % i)
|
path = utils.window('Emby.nodes.%s.content' % i)
|
||||||
label = utils.window('Emby.nodes.%s.title' % i)
|
label = utils.window('Emby.nodes.%s.title' % i)
|
||||||
if path:
|
if path:
|
||||||
|
print path
|
||||||
addDirectoryItem(label, path)
|
addDirectoryItem(label, path)
|
||||||
|
|
||||||
# some extra entries for settings and stuff. TODO --> localize the labels
|
# some extra entries for settings and stuff. TODO --> localize the labels
|
||||||
|
@ -400,6 +401,99 @@ def refreshPlaylist():
|
||||||
time=1000,
|
time=1000,
|
||||||
sound=False)
|
sound=False)
|
||||||
|
|
||||||
|
##### BROWSE EMBY HOMEVIDEOS AND PICTURES #####
|
||||||
|
def BrowseContent(viewname, type="", folderid=None, filter=None):
|
||||||
|
|
||||||
|
_addon_id = int(sys.argv[1])
|
||||||
|
_addon_url = sys.argv[0]
|
||||||
|
doUtils = downloadutils.DownloadUtils()
|
||||||
|
emby = embyserver.Read_EmbyServer()
|
||||||
|
art = artwork.Artwork()
|
||||||
|
utils.logMsg("BrowseHomeVideos","viewname: %s - type: %s - folderid: %s - filter: %s" %(viewname, type, folderid, filter),0)
|
||||||
|
|
||||||
|
if type.lower() == "homevideos":
|
||||||
|
xbmcplugin.setContent(int(sys.argv[1]), 'episodes')
|
||||||
|
itemtype = "Video"
|
||||||
|
elif type.lower() == "photos":
|
||||||
|
xbmcplugin.setContent(int(sys.argv[1]), 'pictures')
|
||||||
|
itemtype = "Photo"
|
||||||
|
else:
|
||||||
|
itemtype = ""
|
||||||
|
|
||||||
|
if not folderid:
|
||||||
|
views = emby.getViews(type)
|
||||||
|
for view in views:
|
||||||
|
if view.get("name") == viewname:
|
||||||
|
folderid = view.get("id")
|
||||||
|
print view
|
||||||
|
|
||||||
|
if folderid:
|
||||||
|
listing = emby.getSection(folderid).get("Items",[])
|
||||||
|
for item in listing:
|
||||||
|
if item.get("Type") == itemtype or item.get("IsFolder") == True:
|
||||||
|
API = api.API(item)
|
||||||
|
itemid = item['Id']
|
||||||
|
title = item.get('Name')
|
||||||
|
li = xbmcgui.ListItem(title)
|
||||||
|
|
||||||
|
premieredate = API.getPremiereDate()
|
||||||
|
genre = API.getGenres()
|
||||||
|
overlay = 0
|
||||||
|
userdata = API.getUserData()
|
||||||
|
seektime = userdata['Resume']
|
||||||
|
if seektime:
|
||||||
|
li.setProperty("resumetime", seektime)
|
||||||
|
li.setProperty("totaltime", item.get("RunTimeTicks")/ 10000000.0)
|
||||||
|
|
||||||
|
played = userdata['Played']
|
||||||
|
if played: overlay = 7
|
||||||
|
else: overlay = 6
|
||||||
|
|
||||||
|
favorite = userdata['Favorite']
|
||||||
|
if favorite: overlay = 5
|
||||||
|
|
||||||
|
playcount = userdata['PlayCount']
|
||||||
|
if playcount is None:
|
||||||
|
playcount = 0
|
||||||
|
|
||||||
|
rating = item.get('CommunityRating')
|
||||||
|
if not rating: rating = userdata['UserRating']
|
||||||
|
|
||||||
|
# Populate the extradata list and artwork
|
||||||
|
pbutils.PlaybackUtils(item).setArtwork(li)
|
||||||
|
extradata = {
|
||||||
|
|
||||||
|
'id': itemid,
|
||||||
|
'rating': rating,
|
||||||
|
'year': item.get('ProductionYear'),
|
||||||
|
'premieredate': premieredate,
|
||||||
|
'genre': genre,
|
||||||
|
'playcount': str(playcount),
|
||||||
|
'title': title,
|
||||||
|
'plot': API.getOverview(),
|
||||||
|
'Overlay': str(overlay),
|
||||||
|
}
|
||||||
|
li.setInfo('video', infoLabels=extradata)
|
||||||
|
li.setThumbnailImage(art.getAllArtwork(item)['Primary'])
|
||||||
|
li.setIconImage('DefaultTVShows.png')
|
||||||
|
|
||||||
|
if item.get("IsFolder") == True:
|
||||||
|
path = "%s?id=%s&mode=browsecontent&type=%s&folderid=%s" % (_addon_url, viewname, type, itemid)
|
||||||
|
xbmcplugin.addDirectoryItem(handle=_addon_id, url=path, listitem=li, isFolder=True)
|
||||||
|
else:
|
||||||
|
path = "%s?id=%s&mode=play" % (_addon_url, itemid)
|
||||||
|
li.setProperty('IsPlayable', 'true')
|
||||||
|
|
||||||
|
mediastreams = API.getMediaStreams()
|
||||||
|
if mediastreams:
|
||||||
|
for key, value in mediastreams.iteritems():
|
||||||
|
if value: li.addStreamInfo(key, value[0])
|
||||||
|
|
||||||
|
xbmcplugin.addDirectoryItem(handle=_addon_id, url=path, listitem=li)
|
||||||
|
|
||||||
|
|
||||||
|
xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))
|
||||||
|
|
||||||
##### BROWSE EMBY CHANNELS #####
|
##### BROWSE EMBY CHANNELS #####
|
||||||
def BrowseChannels(itemid, folderid=None):
|
def BrowseChannels(itemid, folderid=None):
|
||||||
|
|
||||||
|
|
|
@ -61,15 +61,13 @@ class Items(object):
|
||||||
|
|
||||||
'Movie': Movies,
|
'Movie': Movies,
|
||||||
'BoxSet': Movies,
|
'BoxSet': Movies,
|
||||||
'MusicVideo': MusicVideos,
|
|
||||||
'Series': TVShows,
|
'Series': TVShows,
|
||||||
'Season': TVShows,
|
'Season': TVShows,
|
||||||
'Episode': TVShows,
|
'Episode': TVShows,
|
||||||
'MusicAlbum': Music,
|
'MusicAlbum': Music,
|
||||||
'MusicArtist': Music,
|
'MusicArtist': Music,
|
||||||
'AlbumArtist': Music,
|
'AlbumArtist': Music,
|
||||||
'Audio': Music,
|
'Audio': Music
|
||||||
'Video': HomeVideos
|
|
||||||
}
|
}
|
||||||
|
|
||||||
total = 0
|
total = 0
|
||||||
|
@ -169,13 +167,6 @@ class Items(object):
|
||||||
'userdata': items_process.updateUserdata,
|
'userdata': items_process.updateUserdata,
|
||||||
'remove': items_process.remove
|
'remove': items_process.remove
|
||||||
}
|
}
|
||||||
elif itemtype == "Video":
|
|
||||||
actions = {
|
|
||||||
'added': items_process.added,
|
|
||||||
'update': items_process.add_update,
|
|
||||||
'userdata': items_process.updateUserdata,
|
|
||||||
'remove': items_process.remove
|
|
||||||
}
|
|
||||||
else:
|
else:
|
||||||
self.logMsg("Unsupported itemtype: %s." % itemtype, 1)
|
self.logMsg("Unsupported itemtype: %s." % itemtype, 1)
|
||||||
actions = {}
|
actions = {}
|
||||||
|
@ -624,257 +615,6 @@ class Movies(Items):
|
||||||
|
|
||||||
self.logMsg("Deleted %s %s from kodi database" % (mediatype, itemid), 1)
|
self.logMsg("Deleted %s %s from kodi database" % (mediatype, itemid), 1)
|
||||||
|
|
||||||
class HomeVideos(Items):
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, embycursor, kodicursor):
|
|
||||||
Items.__init__(self, embycursor, kodicursor)
|
|
||||||
|
|
||||||
def added(self, items, pdialog):
|
|
||||||
|
|
||||||
total = len(items)
|
|
||||||
count = 0
|
|
||||||
for hvideo in items:
|
|
||||||
|
|
||||||
title = hvideo['Name']
|
|
||||||
if pdialog:
|
|
||||||
percentage = int((float(count) / float(total))*100)
|
|
||||||
pdialog.update(percentage, message=title)
|
|
||||||
count += 1
|
|
||||||
self.add_update(hvideo)
|
|
||||||
if not pdialog and self.contentmsg:
|
|
||||||
self.contentPop(title)
|
|
||||||
|
|
||||||
|
|
||||||
def add_update(self, item, viewtag=None, viewid=None):
|
|
||||||
# Process single movie
|
|
||||||
kodicursor = self.kodicursor
|
|
||||||
emby_db = self.emby_db
|
|
||||||
kodi_db = self.kodi_db
|
|
||||||
artwork = self.artwork
|
|
||||||
API = api.API(item)
|
|
||||||
|
|
||||||
# If the item already exist in the local Kodi DB we'll perform a full item update
|
|
||||||
# If the item doesn't exist, we'll add it to the database
|
|
||||||
update_item = True
|
|
||||||
itemid = item['Id']
|
|
||||||
emby_dbitem = emby_db.getItem_byId(itemid)
|
|
||||||
try:
|
|
||||||
hmovieid = emby_dbitem[0]
|
|
||||||
fileid = emby_dbitem[1]
|
|
||||||
pathid = emby_dbitem[2]
|
|
||||||
self.logMsg("hmovieid: %s fileid: %s pathid: %s" % (hmovieid, fileid, pathid), 1)
|
|
||||||
|
|
||||||
except TypeError:
|
|
||||||
update_item = False
|
|
||||||
self.logMsg("hmovieid: %s not found." % itemid, 2)
|
|
||||||
# movieid
|
|
||||||
kodicursor.execute("select coalesce(max(idMovie),0) from movie")
|
|
||||||
hmovieid = kodicursor.fetchone()[0] + 1
|
|
||||||
|
|
||||||
if not viewtag or not viewid:
|
|
||||||
# Get view tag from emby
|
|
||||||
viewtag, viewid, mediatype = self.emby.getView_embyId(itemid)
|
|
||||||
self.logMsg("View tag found: %s" % viewtag, 2)
|
|
||||||
|
|
||||||
# fileId information
|
|
||||||
checksum = API.getChecksum()
|
|
||||||
dateadded = API.getDateCreated()
|
|
||||||
userdata = API.getUserData()
|
|
||||||
playcount = userdata['PlayCount']
|
|
||||||
dateplayed = userdata['LastPlayedDate']
|
|
||||||
|
|
||||||
# item details
|
|
||||||
people = API.getPeople()
|
|
||||||
title = item['Name']
|
|
||||||
year = item.get('ProductionYear')
|
|
||||||
sorttitle = item['SortName']
|
|
||||||
runtime = API.getRuntime()
|
|
||||||
genre = "HomeVideos"
|
|
||||||
|
|
||||||
|
|
||||||
##### GET THE FILE AND PATH #####
|
|
||||||
playurl = API.getFilePath()
|
|
||||||
|
|
||||||
if "\\" in playurl:
|
|
||||||
# Local path
|
|
||||||
filename = playurl.rsplit("\\", 1)[1]
|
|
||||||
else: # Network share
|
|
||||||
filename = playurl.rsplit("/", 1)[1]
|
|
||||||
|
|
||||||
if self.directpath:
|
|
||||||
# Direct paths is set the Kodi way
|
|
||||||
if utils.window('emby_pathverified') != "true" and not xbmcvfs.exists(playurl):
|
|
||||||
# Validate the path is correct with user intervention
|
|
||||||
utils.window('emby_directPath', clear=True)
|
|
||||||
resp = xbmcgui.Dialog().yesno(
|
|
||||||
heading="Can't validate path",
|
|
||||||
line1=(
|
|
||||||
"Kodi can't locate file: %s. Verify the path. "
|
|
||||||
"You may to verify your network credentials in the "
|
|
||||||
"add-on settings or use the emby path substitution "
|
|
||||||
"to format your path correctly. Stop syncing?"
|
|
||||||
% playurl))
|
|
||||||
if resp:
|
|
||||||
utils.window('emby_shouldStop', value="true")
|
|
||||||
return False
|
|
||||||
|
|
||||||
path = playurl.replace(filename, "")
|
|
||||||
utils.window('emby_pathverified', value="true")
|
|
||||||
else:
|
|
||||||
# Set plugin path and media flags using real filename
|
|
||||||
path = "plugin://plugin.video.emby.movies/"
|
|
||||||
params = {
|
|
||||||
|
|
||||||
'filename': filename.encode('utf-8'),
|
|
||||||
'id': itemid,
|
|
||||||
'dbid': hmovieid,
|
|
||||||
'mode': "play"
|
|
||||||
}
|
|
||||||
filename = "%s?%s" % (path, urllib.urlencode(params))
|
|
||||||
|
|
||||||
|
|
||||||
##### UPDATE THE MOVIE #####
|
|
||||||
if update_item:
|
|
||||||
self.logMsg("UPDATE homemovie itemid: %s - Title: %s" % (itemid, title), 1)
|
|
||||||
|
|
||||||
# Update the movie entry
|
|
||||||
query = ' '.join((
|
|
||||||
|
|
||||||
"UPDATE movie",
|
|
||||||
"SET c00 = ?, c07 = ?, c10 = ?, c11 = ?, c14 = ?, c16 = ?",
|
|
||||||
"WHERE idMovie = ?"
|
|
||||||
))
|
|
||||||
kodicursor.execute(query, (title, year, sorttitle, runtime, genre, title, hmovieid))
|
|
||||||
|
|
||||||
# Update the checksum in emby table
|
|
||||||
emby_db.updateReference(itemid, checksum)
|
|
||||||
|
|
||||||
##### OR ADD THE MOVIE #####
|
|
||||||
else:
|
|
||||||
self.logMsg("ADD homemovie itemid: %s - Title: %s" % (itemid, title), 1)
|
|
||||||
|
|
||||||
# Add path
|
|
||||||
pathid = kodi_db.addPath(path)
|
|
||||||
# Add the file
|
|
||||||
fileid = kodi_db.addFile(filename, pathid)
|
|
||||||
|
|
||||||
# Create the movie entry
|
|
||||||
query = (
|
|
||||||
'''
|
|
||||||
INSERT INTO movie(
|
|
||||||
idMovie, idFile, c00, c07, c10, c11, c14, c16)
|
|
||||||
|
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
kodicursor.execute(query, (hmovieid, fileid, title, year, sorttitle, runtime,
|
|
||||||
genre, title))
|
|
||||||
|
|
||||||
# Create the reference in emby table
|
|
||||||
emby_db.addReference(itemid, hmovieid, "Video", "movie", fileid, pathid,
|
|
||||||
None, checksum, viewid)
|
|
||||||
|
|
||||||
# Update the path
|
|
||||||
query = ' '.join((
|
|
||||||
|
|
||||||
"UPDATE path",
|
|
||||||
"SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?",
|
|
||||||
"WHERE idPath = ?"
|
|
||||||
))
|
|
||||||
kodicursor.execute(query, (path, "movies", "metadata.local", 1, pathid))
|
|
||||||
|
|
||||||
# Update the file
|
|
||||||
query = ' '.join((
|
|
||||||
|
|
||||||
"UPDATE files",
|
|
||||||
"SET idPath = ?, strFilename = ?, dateAdded = ?",
|
|
||||||
"WHERE idFile = ?"
|
|
||||||
))
|
|
||||||
kodicursor.execute(query, (pathid, filename, dateadded, fileid))
|
|
||||||
|
|
||||||
|
|
||||||
# Process artwork
|
|
||||||
artwork.addArtwork(artwork.getAllArtwork(item), hmovieid, "movie", kodicursor)
|
|
||||||
# Process stream details
|
|
||||||
streams = API.getMediaStreams()
|
|
||||||
kodi_db.addStreams(fileid, streams, runtime)
|
|
||||||
# Process tags: view, emby tags
|
|
||||||
tags = [viewtag]
|
|
||||||
tags.extend(item['Tags'])
|
|
||||||
if userdata['Favorite']:
|
|
||||||
tags.append("Favorite homemovies")
|
|
||||||
kodi_db.addTags(hmovieid, tags, "movie")
|
|
||||||
# Process playstates
|
|
||||||
resume = API.adjustResume(userdata['Resume'])
|
|
||||||
total = round(float(runtime), 6)
|
|
||||||
kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
|
|
||||||
|
|
||||||
def updateUserdata(self, item):
|
|
||||||
# This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
|
|
||||||
# Poster with progress bar
|
|
||||||
emby_db = self.emby_db
|
|
||||||
kodi_db = self.kodi_db
|
|
||||||
API = api.API(item)
|
|
||||||
|
|
||||||
# Get emby information
|
|
||||||
itemid = item['Id']
|
|
||||||
checksum = API.getChecksum()
|
|
||||||
userdata = API.getUserData()
|
|
||||||
runtime = API.getRuntime()
|
|
||||||
|
|
||||||
# Get Kodi information
|
|
||||||
emby_dbitem = emby_db.getItem_byId(itemid)
|
|
||||||
try:
|
|
||||||
movieid = emby_dbitem[0]
|
|
||||||
fileid = emby_dbitem[1]
|
|
||||||
self.logMsg(
|
|
||||||
"Update playstate for homemovie: %s fileid: %s"
|
|
||||||
% (item['Name'], fileid), 1)
|
|
||||||
except TypeError:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Process favorite tags
|
|
||||||
if userdata['Favorite']:
|
|
||||||
kodi_db.addTag(movieid, "Favorite homemovies", "movie")
|
|
||||||
else:
|
|
||||||
kodi_db.removeTag(movieid, "Favorite homemovies", "movie")
|
|
||||||
|
|
||||||
# Process playstates
|
|
||||||
playcount = userdata['PlayCount']
|
|
||||||
dateplayed = userdata['LastPlayedDate']
|
|
||||||
resume = API.adjustResume(userdata['Resume'])
|
|
||||||
total = round(float(runtime), 6)
|
|
||||||
|
|
||||||
kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
|
|
||||||
emby_db.updateReference(itemid, checksum)
|
|
||||||
|
|
||||||
def remove(self, itemid):
|
|
||||||
# Remove movieid, fileid, emby reference
|
|
||||||
emby_db = self.emby_db
|
|
||||||
kodicursor = self.kodicursor
|
|
||||||
artwork = self.artwork
|
|
||||||
|
|
||||||
emby_dbitem = emby_db.getItem_byId(itemid)
|
|
||||||
try:
|
|
||||||
hmovieid = emby_dbitem[0]
|
|
||||||
fileid = emby_dbitem[1]
|
|
||||||
self.logMsg("Removing hmovieid: %s fileid: %s" % (hmovieid, fileid), 1)
|
|
||||||
except TypeError:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Remove artwork
|
|
||||||
artwork.deleteArtwork(hmovieid, "movie", kodicursor)
|
|
||||||
|
|
||||||
# Delete kodi movie and file
|
|
||||||
kodicursor.execute("DELETE FROM movie WHERE idMovie = ?", (hmovieid,))
|
|
||||||
kodicursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,))
|
|
||||||
|
|
||||||
# Remove the emby reference
|
|
||||||
emby_db.removeItem(itemid)
|
|
||||||
|
|
||||||
self.logMsg("Deleted homemovie %s from kodi database" % itemid, 1)
|
|
||||||
|
|
||||||
class MusicVideos(Items):
|
class MusicVideos(Items):
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -640,8 +640,8 @@ class Kodidb_Functions():
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
'''
|
'''
|
||||||
)
|
)
|
||||||
cursor.execute(query, (fileid, 0, videotrack['videocodec'],
|
cursor.execute(query, (fileid, 0, videotrack['codec'],
|
||||||
videotrack['aspectratio'], videotrack['width'], videotrack['height'],
|
videotrack['aspect'], videotrack['width'], videotrack['height'],
|
||||||
runtime ,videotrack['video3DFormat']))
|
runtime ,videotrack['video3DFormat']))
|
||||||
|
|
||||||
# Audio details
|
# Audio details
|
||||||
|
@ -654,8 +654,8 @@ class Kodidb_Functions():
|
||||||
VALUES (?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?)
|
||||||
'''
|
'''
|
||||||
)
|
)
|
||||||
cursor.execute(query, (fileid, 1, audiotrack['audiocodec'],
|
cursor.execute(query, (fileid, 1, audiotrack['codec'],
|
||||||
audiotrack['channels'], audiotrack['audiolanguage']))
|
audiotrack['channels'], audiotrack['language']))
|
||||||
|
|
||||||
# Subtitles details
|
# Subtitles details
|
||||||
for subtitletrack in streamdetails['subtitle']:
|
for subtitletrack in streamdetails['subtitle']:
|
||||||
|
|
|
@ -230,8 +230,7 @@ class LibrarySync(threading.Thread):
|
||||||
|
|
||||||
'movies': self.movies,
|
'movies': self.movies,
|
||||||
'musicvideos': self.musicvideos,
|
'musicvideos': self.musicvideos,
|
||||||
'tvshows': self.tvshows,
|
'tvshows': self.tvshows
|
||||||
'homevideos': self.homevideos
|
|
||||||
}
|
}
|
||||||
for itemtype in process:
|
for itemtype in process:
|
||||||
startTime = datetime.now()
|
startTime = datetime.now()
|
||||||
|
@ -343,7 +342,7 @@ class LibrarySync(threading.Thread):
|
||||||
totalnodes = 0
|
totalnodes = 0
|
||||||
|
|
||||||
# Set views for supported media type
|
# Set views for supported media type
|
||||||
mediatypes = ['movies', 'tvshows', 'musicvideos', 'homevideos', 'music']
|
mediatypes = ['movies', 'tvshows', 'musicvideos', 'homevideos', 'music', 'photos']
|
||||||
for mediatype in mediatypes:
|
for mediatype in mediatypes:
|
||||||
|
|
||||||
# Get media folders from server
|
# Get media folders from server
|
||||||
|
@ -447,7 +446,6 @@ class LibrarySync(threading.Thread):
|
||||||
# Save total
|
# Save total
|
||||||
utils.window('Emby.nodes.total', str(totalnodes))
|
utils.window('Emby.nodes.total', str(totalnodes))
|
||||||
|
|
||||||
|
|
||||||
def movies(self, embycursor, kodicursor, pdialog, compare=False):
|
def movies(self, embycursor, kodicursor, pdialog, compare=False):
|
||||||
# Get movies from emby
|
# Get movies from emby
|
||||||
emby = self.emby
|
emby = self.emby
|
||||||
|
@ -709,99 +707,6 @@ class LibrarySync(threading.Thread):
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def homevideos(self, embycursor, kodicursor, pdialog, compare=False):
|
|
||||||
# Get homevideos from emby
|
|
||||||
emby = self.emby
|
|
||||||
emby_db = embydb.Embydb_Functions(embycursor)
|
|
||||||
hvideos = itemtypes.HomeVideos(embycursor, kodicursor)
|
|
||||||
|
|
||||||
views = emby_db.getView_byType('homevideos')
|
|
||||||
self.logMsg("Media folders: %s" % views, 1)
|
|
||||||
|
|
||||||
if compare:
|
|
||||||
# Pull the list of homevideos in Kodi
|
|
||||||
try:
|
|
||||||
all_kodihvideos = dict(emby_db.getChecksum('Video'))
|
|
||||||
except ValueError:
|
|
||||||
all_kodihvideos = {}
|
|
||||||
|
|
||||||
all_embyhvideosIds = set()
|
|
||||||
updatelist = []
|
|
||||||
|
|
||||||
for view in views:
|
|
||||||
|
|
||||||
if self.shouldStop():
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Get items per view
|
|
||||||
viewId = view['id']
|
|
||||||
viewName = view['name']
|
|
||||||
|
|
||||||
if pdialog:
|
|
||||||
pdialog.update(
|
|
||||||
heading="Emby for Kodi",
|
|
||||||
message="Gathering homevideos from view: %s..." % viewName)
|
|
||||||
|
|
||||||
all_embyhvideos = emby.getHomeVideos(viewId)
|
|
||||||
|
|
||||||
if compare:
|
|
||||||
# Manual sync
|
|
||||||
if pdialog:
|
|
||||||
pdialog.update(
|
|
||||||
heading="Emby for Kodi",
|
|
||||||
message="Comparing homevideos from view: %s..." % viewName)
|
|
||||||
|
|
||||||
for embyhvideo in all_embyhvideos['Items']:
|
|
||||||
|
|
||||||
if self.shouldStop():
|
|
||||||
return False
|
|
||||||
|
|
||||||
API = api.API(embyhvideo)
|
|
||||||
itemid = embyhvideo['Id']
|
|
||||||
all_embyhvideosIds.add(itemid)
|
|
||||||
|
|
||||||
|
|
||||||
if all_kodihvideos.get(itemid) != API.getChecksum():
|
|
||||||
# Only update if homemovie is not in Kodi or checksum is different
|
|
||||||
updatelist.append(itemid)
|
|
||||||
|
|
||||||
self.logMsg("HomeVideos to update for %s: %s" % (viewName, updatelist), 1)
|
|
||||||
embyhvideos = emby.getFullItems(updatelist)
|
|
||||||
total = len(updatelist)
|
|
||||||
del updatelist[:]
|
|
||||||
else:
|
|
||||||
total = all_embyhvideos['TotalRecordCount']
|
|
||||||
embyhvideos = all_embyhvideos['Items']
|
|
||||||
|
|
||||||
if pdialog:
|
|
||||||
pdialog.update(heading="Processing %s / %s items" % (viewName, total))
|
|
||||||
|
|
||||||
count = 0
|
|
||||||
for embyhvideo in embyhvideos:
|
|
||||||
# Process individual homemovies
|
|
||||||
if self.shouldStop():
|
|
||||||
return False
|
|
||||||
|
|
||||||
title = embyhvideo['Name']
|
|
||||||
if pdialog:
|
|
||||||
percentage = int((float(count) / float(total))*100)
|
|
||||||
pdialog.update(percentage, message=title)
|
|
||||||
count += 1
|
|
||||||
hvideos.add_update(embyhvideo, viewName, viewId)
|
|
||||||
else:
|
|
||||||
self.logMsg("HomeVideos finished.", 2)
|
|
||||||
|
|
||||||
##### PROCESS DELETES #####
|
|
||||||
if compare:
|
|
||||||
# Manual sync, process deletes
|
|
||||||
for kodihvideo in all_kodihvideos:
|
|
||||||
if kodihvideo not in all_embyhvideosIds:
|
|
||||||
hvideos.remove(kodihvideo)
|
|
||||||
else:
|
|
||||||
self.logMsg("HomeVideos compare finished.", 1)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def tvshows(self, embycursor, kodicursor, pdialog, compare=False):
|
def tvshows(self, embycursor, kodicursor, pdialog, compare=False):
|
||||||
# Get shows from emby
|
# Get shows from emby
|
||||||
emby = self.emby
|
emby = self.emby
|
||||||
|
|
|
@ -61,7 +61,7 @@ def getSongTags(file):
|
||||||
comment = ""
|
comment = ""
|
||||||
|
|
||||||
isTemp,filename = getRealFileName(file)
|
isTemp,filename = getRealFileName(file)
|
||||||
logMsg( "getting song ID3 tags for " + filename, 0)
|
logMsg( "getting song ID3 tags for " + filename)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if filename.lower().endswith(".flac"):
|
if filename.lower().endswith(".flac"):
|
||||||
|
@ -82,7 +82,7 @@ def getSongTags(file):
|
||||||
#POPM rating is 0-255 and needs to be converted to 0-5 range
|
#POPM rating is 0-255 and needs to be converted to 0-5 range
|
||||||
if rating > 5: rating = (rating / 255) * 5
|
if rating > 5: rating = (rating / 255) * 5
|
||||||
else:
|
else:
|
||||||
logMsg( "Not supported fileformat or unable to access file: %s" %(filename), 0)
|
logMsg( "Not supported fileformat or unable to access file: %s" %(filename))
|
||||||
rating = int(round(rating,0))
|
rating = int(round(rating,0))
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -98,7 +98,7 @@ def updateRatingToFile(rating, file):
|
||||||
#update the rating from Emby to the file
|
#update the rating from Emby to the file
|
||||||
|
|
||||||
isTemp,filename = getRealFileName(file)
|
isTemp,filename = getRealFileName(file)
|
||||||
logMsg( "setting song rating: %s for filename: %s" %(rating,filename), 0)
|
logMsg( "setting song rating: %s for filename: %s" %(rating,filename))
|
||||||
|
|
||||||
if not filename:
|
if not filename:
|
||||||
return
|
return
|
||||||
|
@ -115,7 +115,7 @@ def updateRatingToFile(rating, file):
|
||||||
audio.add(id3.POPM(email="Windows Media Player 9 Series", rating=calcrating, count=1))
|
audio.add(id3.POPM(email="Windows Media Player 9 Series", rating=calcrating, count=1))
|
||||||
audio.save()
|
audio.save()
|
||||||
else:
|
else:
|
||||||
logMsg( "Not supported fileformat: %s" %(filename), 0)
|
logMsg( "Not supported fileformat: %s" %(filename))
|
||||||
|
|
||||||
#remove tempfile if needed....
|
#remove tempfile if needed....
|
||||||
if isTemp:
|
if isTemp:
|
||||||
|
|
|
@ -56,10 +56,6 @@ class VideoNodes(object):
|
||||||
|
|
||||||
kodiversion = self.kodiversion
|
kodiversion = self.kodiversion
|
||||||
|
|
||||||
if mediatype == "homevideos":
|
|
||||||
# Treat homevideos as movies
|
|
||||||
mediatype = "movies"
|
|
||||||
|
|
||||||
cleantagname = utils.normalize_nodes(tagname.encode('utf-8'))
|
cleantagname = utils.normalize_nodes(tagname.encode('utf-8'))
|
||||||
if viewtype == "mixed":
|
if viewtype == "mixed":
|
||||||
dirname = "%s - %s" % (cleantagname, mediatype)
|
dirname = "%s - %s" % (cleantagname, mediatype)
|
||||||
|
@ -78,7 +74,7 @@ class VideoNodes(object):
|
||||||
xbmcvfs.exists(path)
|
xbmcvfs.exists(path)
|
||||||
|
|
||||||
# Create the node directory
|
# Create the node directory
|
||||||
if not xbmcvfs.exists(nodepath):
|
if not xbmcvfs.exists(nodepath) and not mediatype=="photos":
|
||||||
# We need to copy over the default items
|
# We need to copy over the default items
|
||||||
xbmcvfs.mkdirs(nodepath)
|
xbmcvfs.mkdirs(nodepath)
|
||||||
else:
|
else:
|
||||||
|
@ -99,14 +95,18 @@ class VideoNodes(object):
|
||||||
if utils.window('Emby.nodes.%s.index' % i) == path:
|
if utils.window('Emby.nodes.%s.index' % i) == path:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if mediatype=="photos":
|
||||||
|
path = "plugin://plugin.video.emby/?id=%s&mode=browsecontent&type=photos&filter=index" % tagname
|
||||||
|
|
||||||
utils.window('Emby.nodes.%s.index' % indexnumber, value=path)
|
utils.window('Emby.nodes.%s.index' % indexnumber, value=path)
|
||||||
|
|
||||||
# Root
|
# Root
|
||||||
root = self.commonRoot(order=0, label=tagname, tagname=tagname, roottype=0)
|
if not mediatype=="photos":
|
||||||
try:
|
root = self.commonRoot(order=0, label=tagname, tagname=tagname, roottype=0)
|
||||||
utils.indent(root)
|
try:
|
||||||
except: pass
|
utils.indent(root)
|
||||||
etree.ElementTree(root).write(nodeXML)
|
except: pass
|
||||||
|
etree.ElementTree(root).write(nodeXML)
|
||||||
|
|
||||||
nodetypes = {
|
nodetypes = {
|
||||||
|
|
||||||
|
@ -144,6 +144,14 @@ class VideoNodes(object):
|
||||||
'9': 135,
|
'9': 135,
|
||||||
'10': 30229,
|
'10': 30229,
|
||||||
'11': 30230},
|
'11': 30230},
|
||||||
|
|
||||||
|
'homevideos': {
|
||||||
|
'1': tagname,
|
||||||
|
'2': 30170},
|
||||||
|
|
||||||
|
'photos': {
|
||||||
|
'1': tagname,
|
||||||
|
'2': 30170},
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes = mediatypes[mediatype]
|
nodes = mediatypes[mediatype]
|
||||||
|
@ -161,7 +169,19 @@ class VideoNodes(object):
|
||||||
label = stringid
|
label = stringid
|
||||||
|
|
||||||
# Set window properties
|
# Set window properties
|
||||||
if nodetype == "nextepisodes":
|
if mediatype == "homevideos" and nodetype == "all":
|
||||||
|
# Custom query
|
||||||
|
path = "plugin://plugin.video.emby/?id=%s&mode=browsecontent&type=homevideos" % tagname
|
||||||
|
elif mediatype == "homevideos" and nodetype == "recent":
|
||||||
|
# Custom query
|
||||||
|
path = "plugin://plugin.video.emby/?id=%s&mode=browsecontent&type=homevideos&filter=recent" % tagname
|
||||||
|
elif mediatype == "photos" and nodetype == "all":
|
||||||
|
# Custom query
|
||||||
|
path = "plugin://plugin.video.emby/?id=%s&mode=browsecontent&type=photos" % tagname
|
||||||
|
elif mediatype == "photos" and nodetype == "recent":
|
||||||
|
# Custom query
|
||||||
|
path = "plugin://plugin.video.emby/?id=%s&mode=browsecontent&type=photos&filter=recent" % tagname
|
||||||
|
elif nodetype == "nextepisodes":
|
||||||
# Custom query
|
# Custom query
|
||||||
path = "plugin://plugin.video.emby/?id=%s&mode=nextup&limit=25" % tagname
|
path = "plugin://plugin.video.emby/?id=%s&mode=nextup&limit=25" % tagname
|
||||||
elif kodiversion == 14 and nodetype == "recentepisodes":
|
elif kodiversion == 14 and nodetype == "recentepisodes":
|
||||||
|
@ -172,7 +192,11 @@ class VideoNodes(object):
|
||||||
path = "plugin://plugin.video.emby/?id=%s&mode=inprogressepisodes&limit=25"% tagname
|
path = "plugin://plugin.video.emby/?id=%s&mode=inprogressepisodes&limit=25"% tagname
|
||||||
else:
|
else:
|
||||||
path = "library://video/Emby - %s/%s_%s.xml" % (dirname, cleantagname, nodetype)
|
path = "library://video/Emby - %s/%s_%s.xml" % (dirname, cleantagname, nodetype)
|
||||||
windowpath = "ActivateWindow(Video,%s,return)" % path
|
|
||||||
|
if mediatype == "photos":
|
||||||
|
windowpath = "ActivateWindow(Pictures,%s,return)" % path
|
||||||
|
else:
|
||||||
|
windowpath = "ActivateWindow(Video,%s,return)" % path
|
||||||
|
|
||||||
if nodetype == "all":
|
if nodetype == "all":
|
||||||
|
|
||||||
|
@ -192,14 +216,17 @@ class VideoNodes(object):
|
||||||
utils.window('%s.path' % embynode, value=windowpath)
|
utils.window('%s.path' % embynode, value=windowpath)
|
||||||
utils.window('%s.content' % embynode, value=path)
|
utils.window('%s.content' % embynode, value=path)
|
||||||
|
|
||||||
|
if mediatype=="photos":
|
||||||
|
#for photos we do not create a node in videos but we do want the window props to be created
|
||||||
|
#todo: add our photos nodes to kodi picture sources somehow
|
||||||
|
continue
|
||||||
|
|
||||||
if xbmcvfs.exists(nodeXML):
|
if xbmcvfs.exists(nodeXML):
|
||||||
# Don't recreate xml if already exists
|
# Don't recreate xml if already exists
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
||||||
# Create the root
|
# Create the root
|
||||||
if nodetype == "nextepisodes" or (kodiversion == 14 and
|
if nodetype == "nextepisodes" or (kodiversion == 14 and nodetype in ('recentepisodes', 'inprogressepisodes')) or mediatype=="homevideos":
|
||||||
nodetype in ('recentepisodes', 'inprogressepisodes')):
|
|
||||||
# Folder type with plugin path
|
# Folder type with plugin path
|
||||||
root = self.commonRoot(order=node, label=label, tagname=tagname, roottype=2)
|
root = self.commonRoot(order=node, label=label, tagname=tagname, roottype=2)
|
||||||
etree.SubElement(root, 'path').text = path
|
etree.SubElement(root, 'path').text = path
|
||||||
|
|
Loading…
Reference in a new issue