Redesign Kodi monitor and player

Allows now to have playback initiated by Kodi - especially when using
direct paths
This commit is contained in:
tomkat83 2016-03-16 17:02:22 +01:00
parent 68ea41fe24
commit 7f674acbac
7 changed files with 302 additions and 264 deletions

View file

@ -1981,7 +1981,7 @@ class API():
def getMediaStreams(self):
"""
Returns the media streams
Returns the media streams for metadata purposes
Output: each track contains a dictionaries
{
@ -2220,7 +2220,7 @@ class API():
kodiindex += 1
mapping = json.dumps(mapping)
utils.window('emby_%s.indexMapping' % playurl, value=mapping)
self.logMsg('Found external subs: %s' % externalsubs)
return externalsubs
def CreateListItemFromPlexItem(self, listItem=None):

View file

@ -82,6 +82,7 @@ class Items(object):
Returns True if sync should stop, else False
"""
self.logMsg('Cannot access file: %s' % url, -1)
import xbmcaddon
string = xbmcaddon.Addon().getLocalizedString
resp = xbmcgui.Dialog().yesno(

View file

@ -3,6 +3,7 @@
###############################################################################
import json
from unicodedata import normalize
import xbmc
import xbmcgui
@ -21,7 +22,8 @@ class KodiMonitor(xbmc.Monitor):
def __init__(self):
self.doUtils = downloadutils.DownloadUtils()
self.doUtils = downloadutils.DownloadUtils().downloadUrl
self.xbmcplayer = xbmc.Player()
self.logMsg("Kodi monitor started.", 1)
@ -60,68 +62,25 @@ class KodiMonitor(xbmc.Monitor):
utils.window('emby_logLevel', value=currentLog)
def onNotification(self, sender, method, data):
window = utils.window
doUtils = self.doUtils
if method not in ("Playlist.OnAdd"):
self.logMsg("Method: %s Data: %s" % (method, data), 1)
if data:
data = json.loads(data,'utf-8')
data = json.loads(data, 'utf-8')
if method == "Player.OnPlay":
# Set up report progress for emby playback
item = data.get('item')
try:
kodiid = item['id']
type = item['type']
except (KeyError, TypeError):
self.logMsg("Item is invalid for playstate update.", 1)
else:
if ((utils.settings('useDirectPaths') == "1" and not type == "song") or
(type == "song" and utils.settings('enableMusic') == "true")):
# Set up properties for player
with embydb.GetEmbyDB() as emby_db:
emby_dbitem = emby_db.getItem_byKodiId(kodiid, type)
try:
itemid = emby_dbitem[0]
except TypeError:
self.logMsg("No kodiid returned.", 1)
else:
# Tell everyone else what's going on
utils.window('Plex_currently_playing_itemid',
value=itemid)
url = "{server}/library/metadata/%s" % itemid
result = doUtils.downloadUrl(url)
try:
result.attrib
except AttributeError:
self.logMsg('Could not retrieve PMS xml for %s'
% itemid, -1)
return
playurl = None
count = 0
while not playurl and count < 2:
try:
playurl = xbmc.Player().getPlayingFile()
except RuntimeError:
count += 1
xbmc.sleep(200)
else:
listItem = xbmcgui.ListItem()
playback = pbutils.PlaybackUtils(result)
if type == "song" and utils.settings('streamMusic') == "true":
utils.window('emby_%s.playmethod' % playurl,
value="DirectStream")
else:
utils.window('emby_%s.playmethod' % playurl,
value="DirectPlay")
# Set properties for player.py
playback.setProperties(playurl, listItem)
self.PlayBackStart(data)
elif method == "Player.OnStop":
# Get rid of some values
utils.window('Plex_currently_playing_itemid', clear=True)
window('Plex_currently_playing_itemid', clear=True)
window('emby_customPlaylist', clear=True)
window('emby_customPlaylist.seektime', clear=True)
window('emby_playbackProps', clear=True)
window('suspend_LibraryThread', clear=True)
window('emby_customPlaylist.seektime', clear=True)
elif method == "VideoLibrary.OnUpdate":
# Manually marking as watched/unwatched
@ -188,7 +147,6 @@ class KodiMonitor(xbmc.Monitor):
finally:
embycursor.close()'''
elif method == "System.OnWake":
# Allow network to wake up
xbmc.sleep(10000)
@ -196,3 +154,89 @@ class KodiMonitor(xbmc.Monitor):
elif method == "Playlist.OnClear":
pass
def PlayBackStart(self, data):
"""
Called whenever a playback is started
"""
log = self.logMsg
window = utils.window
# Try to get a Kodi ID
item = data.get('item')
try:
kodiid = item['id']
type = item['type']
except (KeyError, TypeError):
log("Item is invalid for Plex playstate update.", 0)
return
# Get Plex' item id
with embydb.GetEmbyDB() as emby_db:
emby_dbitem = emby_db.getItem_byKodiId(kodiid, type)
try:
plexid = emby_dbitem[0]
except TypeError:
log("No Plex id returned for kodiid %s" % kodiid, 0)
return
log("Found Plex id %s for Kodi id %s" % (plexid, kodiid), 1)
# Get currently playing file - can take a while
try:
currentFile = self.xbmcplayer.getPlayingFile()
xbmc.sleep(300)
except:
currentFile = ""
count = 0
while not currentFile:
xbmc.sleep(100)
try:
currentFile = self.xbmcplayer.getPlayingFile()
except:
pass
if count == 20:
log("No current File - Cancelling OnPlayBackStart...", -1)
return
else:
count += 1
currentFile = currentFile.decode('utf-8')
log("Currently playing file is: %s" % currentFile, 1)
# Normalize to string, because we need to use this in WINDOW(key),
# where key can only be string
currentFile = normalize('NFKD', currentFile).encode('ascii', 'ignore')
log('Normalized filename: %s' % currentFile, 1)
# Set some stuff if Kodi initiated playback
if ((utils.settings('useDirectPaths') == "1" and not type == "song") or
(type == "song" and utils.settings('enableMusic') == "true")):
if self.StartDirectPath(plexid, type, currentFile) is False:
log('Could not initiate monitoring; aborting', -1)
return
# Save currentFile for cleanup later and to be able to access refs
window('plex_lastPlayedFiled', value=currentFile)
window('Plex_currently_playing_itemid', value=plexid)
window("emby_%s.itemid" % currentFile, value=plexid)
log('Finish playback startup', 1)
def StartDirectPath(self, plexid, type, currentFile):
"""
Set some additional stuff if playback was initiated by Kodi, not PKC
"""
result = self.doUtils('{server}/library/metadata/%s' % plexid)
try:
result[0].attrib
except:
self.logMsg('Did not receive a valid XML for plexid %s.'
% plexid, -1)
return False
# Setup stuff, because playback was started by Kodi, not PKC
pbutils.PlaybackUtils(result[0]).setProperties(
currentFile, xbmcgui.ListItem())
if type == "song" and utils.settings('streamMusic') == "true":
utils.window('emby_%s.playmethod' % currentFile,
value="DirectStream")
else:
utils.window('emby_%s.playmethod' % currentFile,
value="DirectPlay")
self.logMsg('Window properties set for direct paths!', 0)

View file

@ -278,7 +278,7 @@ class PlaybackUtils():
# Only for direct stream
if playmethod in ("DirectStream"):
# Direct play automatically appends external
subtitles = self.externalSubs(playurl)
subtitles = self.API.externalSubs(playurl)
listitem.setSubtitles(subtitles)
self.setArtwork(listitem)
@ -288,12 +288,8 @@ class PlaybackUtils():
externalsubs = []
mapping = {}
item = self.item
itemid = item['Id']
try:
mediastreams = item['MediaSources'][0]['MediaStreams']
except (TypeError, KeyError, IndexError):
return
itemid = self.API.getRatingKey()
mediastreams = self.API.getMediaStreams()
kodiindex = 0
for stream in mediastreams:

View file

@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
#################################################################################################
###############################################################################
import json
from unicodedata import normalize
import xbmc
import xbmcgui
@ -13,7 +14,7 @@ import downloadutils
from urllib import urlencode
#################################################################################################
###############################################################################
@utils.logging
@ -48,7 +49,9 @@ class Player(xbmc.Player):
return self.playStats
def onPlayBackStarted(self):
"""
Window values need to have been set in Kodimonitor.py
"""
log = self.logMsg
window = utils.window
# Will be called when xbmc starts playing a file
@ -66,35 +69,39 @@ class Player(xbmc.Player):
xbmc.sleep(100)
try:
currentFile = xbmcplayer.getPlayingFile()
except: pass
if count == 5: # try 5 times
except:
pass
if count == 20:
log("Cancelling playback report...", 1)
break
else: count += 1
if currentFile:
else:
count += 1
if not currentFile:
log('Error getting a currently playing file; abort reporting', -1)
return
currentFile = currentFile.decode('utf-8')
# Normalize to string, because we need to use this in WINDOW(key),
# where key can only be string
currentFile = normalize('NFKD', currentFile).encode('ascii', 'ignore')
log('Normalized filename: %s' % currentFile, 1)
# Save currentFile for cleanup later and for references
self.currentFile = currentFile
# Save currentFile for cleanup later
window('plex_lastPlayedFiled', value=currentFile)
# We may need to wait for info to be set in kodi monitor
itemId = window("emby_%s.itemid" % currentFile)
tryCount = 0
count = 0
while not itemId:
xbmc.sleep(200)
itemId = window("emby_%s.itemid" % currentFile)
if tryCount == 20: # try 20 times or about 10 seconds
log("Could not find itemId, cancelling playback report...", 1)
break
else: tryCount += 1
# try 20 times or about 10 seconds
if count == 20:
log("Could not find itemId, cancelling playback report...", -1)
return
count += 1
else:
window('Plex_currently_playing_itemid', value=itemId)
log("ONPLAYBACK_STARTED: %s itemid: %s" % (currentFile, itemId), 0)
# Only proceed if an itemId was found.
embyitem = "emby_%s" % currentFile
runtime = window("%s.runtime" % embyitem)
refresh_id = window("%s.refreshid" % embyitem)
@ -119,12 +126,10 @@ class Player(xbmc.Player):
# Get playback volume
volume_query = {
"jsonrpc": "2.0",
"id": 1,
"method": "Application.GetProperties",
"params": {
"properties": ["volume", "muted"]
}
}
@ -157,7 +162,6 @@ class Player(xbmc.Player):
else:
# Get the current kodi audio and subtitles and convert to Emby equivalent
tracks_query = {
"jsonrpc": "2.0",
"id": 1,
"method": "Player.GetProperties",
@ -226,12 +230,9 @@ class Player(xbmc.Player):
runtime = xbmcplayer.getTotalTime()
log("Runtime is missing, Kodi runtime: %s" % runtime, 1)
playQueueVersion = utils.window(
'playQueueVersion')
playQueueID = utils.window(
'playQueueID')
playQueueItemID = utils.window(
'plex_%s.playQueueItemID' % currentFile)
playQueueVersion = window('playQueueVersion')
playQueueID = window('playQueueID')
playQueueItemID = window('plex_%s.playQueueItemID' % currentFile)
# Save data map for updates and position calls
data = {
'playQueueVersion': playQueueVersion,
@ -281,7 +282,7 @@ class Player(xbmc.Player):
# only report playback if emby has initiated the playback (item_id has value)
if data:
# Get playback information
# Get playback inforation
itemId = data['item_id']
audioindex = data['AudioStreamIndex']
subtitleindex = data['SubtitleStreamIndex']
@ -451,18 +452,13 @@ class Player(xbmc.Player):
window = utils.window
# Will be called when user stops xbmc playing a file
log("ONPLAYBACK_STOPPED", 2)
window('emby_customPlaylist', clear=True)
window('emby_customPlaylist.seektime', clear=True)
window('emby_playbackProps', clear=True)
window('suspend_LibraryThread', clear=True)
log("Clear playlist properties.", 1)
self.stopAll()
def onPlayBackEnded(self):
# Will be called when xbmc stops playing a file
self.logMsg("ONPLAYBACK_ENDED", 2)
utils.window('emby_customPlaylist.seektime', clear=True)
utils.window('suspend_LibraryThread', clear=True)
self.stopAll()
def stopAll(self):

View file

@ -76,10 +76,10 @@ class SubscriptionManager:
keyid = None
count = 0
while not keyid:
if count > 10:
if count > 300:
break
keyid = WINDOW.getProperty('Plex_currently_playing_itemid')
xbmc.sleep(1000)
xbmc.sleep(100)
count += 1
if keyid:
self.lastkey = "/library/metadata/%s"%keyid

View file

@ -109,6 +109,7 @@ class Service():
# ws = wsc.WebSocket_Client()
library = librarysync.LibrarySync()
kplayer = player.Player()
xplayer = xbmc.Player()
plx = PlexAPI.PlexAPI()
plexCompanion = PlexCompanion.PlexCompanion()
@ -136,11 +137,11 @@ class Service():
if (user.currUser is not None) and user.HasAccess:
# If an item is playing
if xbmc.Player().isPlaying():
if xplayer.isPlaying():
try:
# Update and report progress
playtime = xbmc.Player().getTime()
totalTime = xbmc.Player().getTotalTime()
playtime = xplayer.getTime()
totalTime = xplayer.getTotalTime()
currentFile = kplayer.currentFile
# Update positionticks