Redesign playlists
This commit is contained in:
parent
5d79bcf1c2
commit
8a58c885e9
6 changed files with 276 additions and 134 deletions
|
@ -14,7 +14,10 @@ from plexbmchelper import listener, plexgdm, subscribers, functions, \
|
|||
@utils.ThreadMethodsAdditionalSuspend('plex_serverStatus')
|
||||
@utils.ThreadMethods
|
||||
class PlexCompanion(threading.Thread):
|
||||
def __init__(self):
|
||||
"""
|
||||
Initialize with a Queue for callbacks
|
||||
"""
|
||||
def __init__(self, queue):
|
||||
self.logMsg("----===## Starting PlexCompanion ##===----", 1)
|
||||
self.settings = settings.getSettings()
|
||||
|
||||
|
@ -24,6 +27,8 @@ class PlexCompanion(threading.Thread):
|
|||
self.logMsg("Registration string is: %s "
|
||||
% self.client.getClientDetails(), 2)
|
||||
|
||||
self.queue = queue
|
||||
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
def run(self):
|
||||
|
@ -51,6 +56,7 @@ class PlexCompanion(threading.Thread):
|
|||
subscriptionManager,
|
||||
jsonClass,
|
||||
self.settings,
|
||||
self.queue,
|
||||
('', self.settings['myport']),
|
||||
listener.MyHandler)
|
||||
httpd.timeout = 0.95
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from urllib import urlencode
|
||||
from ast import literal_eval
|
||||
from urlparse import urlparse, parse_qs
|
||||
from urlparse import urlparse, parse_qsl
|
||||
import re
|
||||
from copy import deepcopy
|
||||
|
||||
|
@ -86,13 +86,13 @@ def GetPlexKeyNumber(plexKey):
|
|||
def ParseContainerKey(containerKey):
|
||||
"""
|
||||
Parses e.g. /playQueues/3045?own=1&repeat=0&window=200 to:
|
||||
'playQueues', '3045', {'window': ['200'], 'own': ['1'], 'repeat': ['0']}
|
||||
'playQueues', '3045', {'window': '200', 'own': '1', 'repeat': '0'}
|
||||
|
||||
Output hence: library, key, query (query as a special dict)
|
||||
Output hence: library, key, query (str, str, dict)
|
||||
"""
|
||||
result = urlparse(containerKey)
|
||||
library, key = GetPlexKeyNumber(result.path)
|
||||
query = parse_qs(result.query)
|
||||
query = dict(parse_qsl(result.query))
|
||||
return library, key, query
|
||||
|
||||
|
||||
|
|
|
@ -24,22 +24,37 @@ class Playlist():
|
|||
def __init__(self, typus=None):
|
||||
self.userid = utils.window('currUserId')
|
||||
self.server = utils.window('pms_server')
|
||||
# Construct the Kodi playlist instance
|
||||
if typus == 'video':
|
||||
self.playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
|
||||
self.typus = 'video'
|
||||
self.logMsg('Initiated video playlist', 1)
|
||||
elif typus == 'music':
|
||||
self.playlist = xbmc.PlayList(xbmc.PLAYLIST_MUSIC)
|
||||
self.typus = 'music'
|
||||
self.logMsg('Initiated music playlist', 1)
|
||||
else:
|
||||
self.playlist = None
|
||||
self.typus = None
|
||||
if self.playlist is not None:
|
||||
self.playlistId = self.playlist.getPlayListId()
|
||||
# "interal" PKC playlist
|
||||
self.items = []
|
||||
|
||||
def _initiatePlaylist(self, itemids):
|
||||
def clear(self):
|
||||
"""
|
||||
Empties current Kodi playlist and internal self.items list
|
||||
"""
|
||||
self.logMsg('Clearing playlist', 1)
|
||||
self.playlist.clear()
|
||||
self.items = []
|
||||
|
||||
def _initiatePlaylist(self):
|
||||
self.logMsg('Initiating playlist', 1)
|
||||
playlist = None
|
||||
with embydb.GetEmbyDB() as emby_db:
|
||||
for itemid in itemids:
|
||||
for item in self.items:
|
||||
itemid = item['plexId']
|
||||
embydb_item = emby_db.getItem_byId(itemid)
|
||||
try:
|
||||
mediatype = embydb_item[4]
|
||||
|
@ -54,63 +69,95 @@ class Playlist():
|
|||
if PlexAPI.API(item[0]).getType() == 'track':
|
||||
playlist = xbmc.PlayList(xbmc.PLAYLIST_MUSIC)
|
||||
self.logMsg('Music playlist initiated', 1)
|
||||
self.typus = 'music'
|
||||
else:
|
||||
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
|
||||
self.logMsg('Video playlist initiated', 1)
|
||||
self.typus = 'video'
|
||||
else:
|
||||
if mediatype == 'song':
|
||||
playlist = xbmc.PlayList(xbmc.PLAYLIST_MUSIC)
|
||||
self.logMsg('Music playlist initiated', 1)
|
||||
self.typus = 'music'
|
||||
else:
|
||||
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
|
||||
self.logMsg('Video playlist initiated', 1)
|
||||
self.typus = 'video'
|
||||
break
|
||||
self.playlist = playlist
|
||||
if self.playlist is not None:
|
||||
self.playlistId = self.playlist.getPlayListId()
|
||||
|
||||
def _addToPlaylist(self, itemids, startPlayer=False):
|
||||
def _addToPlaylist(self, startitem, startPlayer=False):
|
||||
started = False
|
||||
with embydb.GetEmbyDB() as emby_db:
|
||||
for itemid in itemids:
|
||||
embydb_item = emby_db.getItem_byId(itemid)
|
||||
for pos, item in enumerate(self.items):
|
||||
kodiId = None
|
||||
plexId = item['plexId']
|
||||
embydb_item = emby_db.getItem_byId(plexId)
|
||||
try:
|
||||
dbid = embydb_item[0]
|
||||
kodiId = embydb_item[0]
|
||||
mediatype = embydb_item[4]
|
||||
except TypeError:
|
||||
self.logMsg('Couldnt find item %s in Kodi db' % itemid, 1)
|
||||
item = PlexFunctions.GetPlexMetadata(itemid)
|
||||
if item in (None, 401):
|
||||
self.logMsg('Could not download itemid %s'
|
||||
% itemid, -1)
|
||||
self.logMsg('Couldnt find item %s in Kodi db' % plexId, 1)
|
||||
xml = PlexFunctions.GetPlexMetadata(plexId)
|
||||
if xml in (None, 401):
|
||||
self.logMsg('Could not download plexId %s'
|
||||
% plexId, -1)
|
||||
else:
|
||||
self.logMsg('Downloaded item metadata, adding now', 1)
|
||||
self._addtoPlaylist_xbmc(item[0])
|
||||
self.logMsg('Downloaded xml metadata, adding now', 1)
|
||||
self._addtoPlaylist_xbmc(xml[0])
|
||||
else:
|
||||
# Add to playlist
|
||||
self.logMsg("Adding %s PlexId %s, KodiId %s to playlist."
|
||||
% (mediatype, itemid, dbid), 1)
|
||||
self.addtoPlaylist(dbid, mediatype)
|
||||
if started is False and startPlayer is True:
|
||||
% (mediatype, plexId, kodiId), 1)
|
||||
self.addtoPlaylist(kodiId, mediatype)
|
||||
# Add the kodiId
|
||||
if kodiId is not None:
|
||||
item['kodiId'] = str(kodiId)
|
||||
if (started is False and
|
||||
startPlayer is True and
|
||||
startitem[1] == item[startitem[0]]):
|
||||
started = True
|
||||
xbmc.Player().play(self.playlist, startpos=pos)
|
||||
if (started is False and
|
||||
startPlayer is True and
|
||||
len(self.playlist) > 0):
|
||||
self.logMsg('Never received a starting item for playlist, '
|
||||
'starting with the first entry', 1)
|
||||
xbmc.Player().play(self.playlist)
|
||||
|
||||
def playAll(self, itemids, startat):
|
||||
self.logMsg("---*** PLAY ALL ***---", 1)
|
||||
self.logMsg("Items: %s and start at: %s" % (itemids, startat), 1)
|
||||
def playAll(self, items, startitem, offset):
|
||||
"""
|
||||
items: list of dicts of the form
|
||||
{
|
||||
'queueId': Plex playQueueItemID, e.g. '29175'
|
||||
'plexId': Plex ratingKey, e.g. '125'
|
||||
'kodiId': Kodi's db id of the same item
|
||||
}
|
||||
|
||||
startitem: tuple (typus, id), where typus is either 'queueId' or
|
||||
'plexId' and id is the corresponding id as a string
|
||||
offset: First item's time offset to play in Kodi time (an int)
|
||||
"""
|
||||
self.logMsg("---*** PLAY ALL ***---", 1)
|
||||
self.logMsg('Startitem: %s, offset: %s, items: %s'
|
||||
% (startitem, offset, items), 1)
|
||||
self.items = items
|
||||
if self.playlist is None:
|
||||
self._initiatePlaylist(itemids)
|
||||
self._initiatePlaylist()
|
||||
if self.playlist is None:
|
||||
self.logMsg('Could not create playlist, abort', -1)
|
||||
return
|
||||
|
||||
utils.window('plex_customplaylist', value="true")
|
||||
if startat != 0:
|
||||
if offset != 0:
|
||||
# Seek to the starting position
|
||||
utils.window('plex_customplaylist.seektime', str(startat))
|
||||
self._addToPlaylist(itemids, startPlayer=True)
|
||||
utils.window('plex_customplaylist.seektime', str(offset))
|
||||
self._addToPlaylist(startitem, startPlayer=True)
|
||||
# Log playlist
|
||||
self.verifyPlaylist()
|
||||
self.logMsg('Internal playlist: %s' % self.items, 2)
|
||||
|
||||
def modifyPlaylist(self, itemids):
|
||||
self.logMsg("---*** ADD TO PLAYLIST ***---", 1)
|
||||
|
@ -126,7 +173,6 @@ class Playlist():
|
|||
mediatype: Kodi type: 'movie', 'episode', 'musicvideo', 'artist',
|
||||
'album', 'song', 'genre'
|
||||
"""
|
||||
|
||||
pl = {
|
||||
'jsonrpc': "2.0",
|
||||
'id': 1,
|
||||
|
|
|
@ -106,11 +106,6 @@ class jsonClass():
|
|||
"id": 1,
|
||||
"method": "JSONRPC.Ping"
|
||||
})
|
||||
elif action.lower() == "playmedia":
|
||||
xbmc.Player().play("plugin://plugin.video.plexkodiconnect/"
|
||||
"?mode=companion&arguments=%s"
|
||||
% arguments)
|
||||
return True
|
||||
elif arguments:
|
||||
request = json.dumps({
|
||||
"id": 1,
|
||||
|
|
|
@ -73,9 +73,10 @@ class MyHandler(BaseHTTPRequestHandler):
|
|||
|
||||
def answer_request(self, sendData):
|
||||
self.serverlist = self.server.client.getServerList()
|
||||
self.subMgr = self.server.subscriptionManager
|
||||
self.js = self.server.jsonClass
|
||||
self.settings = self.server.settings
|
||||
subMgr = self.server.subscriptionManager
|
||||
js = self.server.jsonClass
|
||||
settings = self.server.settings
|
||||
queue = self.server.queue
|
||||
|
||||
try:
|
||||
request_path = self.path[1:]
|
||||
|
@ -87,17 +88,17 @@ class MyHandler(BaseHTTPRequestHandler):
|
|||
params[key] = paramarrays[key][0]
|
||||
self.logMsg("remote request_path: %s" % request_path, 2)
|
||||
self.logMsg("params received from remote: %s" % params, 2)
|
||||
self.subMgr.updateCommandID(self.headers.get(
|
||||
subMgr.updateCommandID(self.headers.get(
|
||||
'X-Plex-Client-Identifier',
|
||||
self.client_address[0]),
|
||||
params.get('commandID', False))
|
||||
if request_path == "version":
|
||||
self.response(
|
||||
"PlexKodiConnect Plex Companion: Running\r\nVersion: %s"
|
||||
% self.settings['version'])
|
||||
% settings['version'])
|
||||
elif request_path == "verify":
|
||||
self.response("XBMC JSON connection test:\r\n" +
|
||||
self.js.jsonrpc("ping"))
|
||||
js.jsonrpc("ping"))
|
||||
elif "resources" == request_path:
|
||||
resp = ('%s'
|
||||
'<MediaContainer>'
|
||||
|
@ -114,20 +115,20 @@ class MyHandler(BaseHTTPRequestHandler):
|
|||
'/>'
|
||||
'</MediaContainer>'
|
||||
% (getXMLHeader(),
|
||||
self.settings['client_name'],
|
||||
self.settings['uuid'],
|
||||
self.settings['platform'],
|
||||
self.settings['plexbmc_version']))
|
||||
settings['client_name'],
|
||||
settings['uuid'],
|
||||
settings['platform'],
|
||||
settings['plexbmc_version']))
|
||||
self.logMsg("crafted resources response: %s" % resp, 2)
|
||||
self.response(resp, self.js.getPlexHeaders())
|
||||
self.response(resp, js.getPlexHeaders())
|
||||
elif "/subscribe" in request_path:
|
||||
self.response(getOKMsg(), self.js.getPlexHeaders())
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
protocol = params.get('protocol', False)
|
||||
host = self.client_address[0]
|
||||
port = params.get('port', False)
|
||||
uuid = self.headers.get('X-Plex-Client-Identifier', "")
|
||||
commandID = params.get('commandID', 0)
|
||||
self.subMgr.addSubscriber(protocol,
|
||||
subMgr.addSubscriber(protocol,
|
||||
host,
|
||||
port,
|
||||
uuid,
|
||||
|
@ -139,28 +140,28 @@ class MyHandler(BaseHTTPRequestHandler):
|
|||
self.response(
|
||||
re.sub(r"INSERTCOMMANDID",
|
||||
str(commandID),
|
||||
self.subMgr.msg(self.js.getPlayers())),
|
||||
subMgr.msg(js.getPlayers())),
|
||||
{
|
||||
'X-Plex-Client-Identifier': self.settings['uuid'],
|
||||
'X-Plex-Client-Identifier': settings['uuid'],
|
||||
'Access-Control-Expose-Headers':
|
||||
'X-Plex-Client-Identifier',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Content-Type': 'text/xml'
|
||||
})
|
||||
elif "/unsubscribe" in request_path:
|
||||
self.response(getOKMsg(), self.js.getPlexHeaders())
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
uuid = self.headers.get('X-Plex-Client-Identifier', False) \
|
||||
or self.client_address[0]
|
||||
self.subMgr.removeSubscriber(uuid)
|
||||
subMgr.removeSubscriber(uuid)
|
||||
elif request_path == "player/playback/setParameters":
|
||||
self.response(getOKMsg(), self.js.getPlexHeaders())
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
if 'volume' in params:
|
||||
volume = int(params['volume'])
|
||||
self.logMsg("adjusting the volume to %s%%" % volume, 2)
|
||||
self.js.jsonrpc("Application.SetVolume",
|
||||
js.jsonrpc("Application.SetVolume",
|
||||
{"volume": volume})
|
||||
elif "/playMedia" in request_path:
|
||||
self.response(getOKMsg(), self.js.getPlexHeaders())
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
offset = params.get('viewOffset', params.get('offset', "0"))
|
||||
protocol = params.get('protocol', "http")
|
||||
address = params.get('address', self.client_address[0])
|
||||
|
@ -174,90 +175,93 @@ class MyHandler(BaseHTTPRequestHandler):
|
|||
playQueueID = self.regex.findall(containerKey)[0]
|
||||
except IndexError:
|
||||
playQueueID = ''
|
||||
|
||||
self.js.jsonrpc("playmedia", params)
|
||||
self.subMgr.lastkey = params['key']
|
||||
self.subMgr.containerKey = containerKey
|
||||
self.subMgr.playQueueID = playQueueID
|
||||
self.subMgr.server = server.get('server', 'localhost')
|
||||
self.subMgr.port = port
|
||||
self.subMgr.protocol = protocol
|
||||
self.subMgr.notify()
|
||||
# We need to tell service.py
|
||||
queue.put({
|
||||
'action': 'playlist',
|
||||
'data': params
|
||||
})
|
||||
subMgr.lastkey = params['key']
|
||||
subMgr.containerKey = containerKey
|
||||
subMgr.playQueueID = playQueueID
|
||||
subMgr.server = server.get('server', 'localhost')
|
||||
subMgr.port = port
|
||||
subMgr.protocol = protocol
|
||||
subMgr.notify()
|
||||
elif request_path == "player/playback/play":
|
||||
self.response(getOKMsg(), self.js.getPlexHeaders())
|
||||
for playerid in self.js.getPlayerIds():
|
||||
self.js.jsonrpc("Player.PlayPause",
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
for playerid in js.getPlayerIds():
|
||||
js.jsonrpc("Player.PlayPause",
|
||||
{"playerid": playerid, "play": True})
|
||||
elif request_path == "player/playback/pause":
|
||||
self.response(getOKMsg(), self.js.getPlexHeaders())
|
||||
for playerid in self.js.getPlayerIds():
|
||||
self.js.jsonrpc("Player.PlayPause",
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
for playerid in js.getPlayerIds():
|
||||
js.jsonrpc("Player.PlayPause",
|
||||
{"playerid": playerid, "play": False})
|
||||
elif request_path == "player/playback/stop":
|
||||
self.response(getOKMsg(), self.js.getPlexHeaders())
|
||||
for playerid in self.js.getPlayerIds():
|
||||
self.js.jsonrpc("Player.Stop", {"playerid": playerid})
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
for playerid in js.getPlayerIds():
|
||||
js.jsonrpc("Player.Stop", {"playerid": playerid})
|
||||
elif request_path == "player/playback/seekTo":
|
||||
self.response(getOKMsg(), self.js.getPlexHeaders())
|
||||
for playerid in self.js.getPlayerIds():
|
||||
self.js.jsonrpc("Player.Seek",
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
for playerid in js.getPlayerIds():
|
||||
js.jsonrpc("Player.Seek",
|
||||
{"playerid": playerid,
|
||||
"value": millisToTime(
|
||||
params.get('offset', 0))})
|
||||
self.subMgr.notify()
|
||||
subMgr.notify()
|
||||
elif request_path == "player/playback/stepForward":
|
||||
self.response(getOKMsg(), self.js.getPlexHeaders())
|
||||
for playerid in self.js.getPlayerIds():
|
||||
self.js.jsonrpc("Player.Seek",
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
for playerid in js.getPlayerIds():
|
||||
js.jsonrpc("Player.Seek",
|
||||
{"playerid": playerid,
|
||||
"value": "smallforward"})
|
||||
self.subMgr.notify()
|
||||
subMgr.notify()
|
||||
elif request_path == "player/playback/stepBack":
|
||||
self.response(getOKMsg(), self.js.getPlexHeaders())
|
||||
for playerid in self.js.getPlayerIds():
|
||||
self.js.jsonrpc("Player.Seek",
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
for playerid in js.getPlayerIds():
|
||||
js.jsonrpc("Player.Seek",
|
||||
{"playerid": playerid,
|
||||
"value": "smallbackward"})
|
||||
self.subMgr.notify()
|
||||
subMgr.notify()
|
||||
elif request_path == "player/playback/skipNext":
|
||||
self.response(getOKMsg(), self.js.getPlexHeaders())
|
||||
for playerid in self.js.getPlayerIds():
|
||||
self.js.jsonrpc("Player.GoTo",
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
for playerid in js.getPlayerIds():
|
||||
js.jsonrpc("Player.GoTo",
|
||||
{"playerid": playerid,
|
||||
"to": "next"})
|
||||
self.subMgr.notify()
|
||||
subMgr.notify()
|
||||
elif request_path == "player/playback/skipPrevious":
|
||||
self.response(getOKMsg(), self.js.getPlexHeaders())
|
||||
for playerid in self.js.getPlayerIds():
|
||||
self.js.jsonrpc("Player.GoTo",
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
for playerid in js.getPlayerIds():
|
||||
js.jsonrpc("Player.GoTo",
|
||||
{"playerid": playerid,
|
||||
"to": "previous"})
|
||||
self.subMgr.notify()
|
||||
subMgr.notify()
|
||||
elif request_path == "player/playback/skipTo":
|
||||
self.js.skipTo(params.get('key').rsplit('/', 1)[1],
|
||||
js.skipTo(params.get('key').rsplit('/', 1)[1],
|
||||
params.get('type'))
|
||||
self.subMgr.notify()
|
||||
subMgr.notify()
|
||||
elif request_path == "player/navigation/moveUp":
|
||||
self.response(getOKMsg(), self.js.getPlexHeaders())
|
||||
self.js.jsonrpc("Input.Up")
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
js.jsonrpc("Input.Up")
|
||||
elif request_path == "player/navigation/moveDown":
|
||||
self.response(getOKMsg(), self.js.getPlexHeaders())
|
||||
self.js.jsonrpc("Input.Down")
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
js.jsonrpc("Input.Down")
|
||||
elif request_path == "player/navigation/moveLeft":
|
||||
self.response(getOKMsg(), self.js.getPlexHeaders())
|
||||
self.js.jsonrpc("Input.Left")
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
js.jsonrpc("Input.Left")
|
||||
elif request_path == "player/navigation/moveRight":
|
||||
self.response(getOKMsg(), self.js.getPlexHeaders())
|
||||
self.js.jsonrpc("Input.Right")
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
js.jsonrpc("Input.Right")
|
||||
elif request_path == "player/navigation/select":
|
||||
self.response(getOKMsg(), self.js.getPlexHeaders())
|
||||
self.js.jsonrpc("Input.Select")
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
js.jsonrpc("Input.Select")
|
||||
elif request_path == "player/navigation/home":
|
||||
self.response(getOKMsg(), self.js.getPlexHeaders())
|
||||
self.js.jsonrpc("Input.Home")
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
js.jsonrpc("Input.Home")
|
||||
elif request_path == "player/navigation/back":
|
||||
self.response(getOKMsg(), self.js.getPlexHeaders())
|
||||
self.js.jsonrpc("Input.Back")
|
||||
self.response(getOKMsg(), js.getPlexHeaders())
|
||||
js.jsonrpc("Input.Back")
|
||||
else:
|
||||
self.logMsg('Unknown request path: %s' % request_path, -1)
|
||||
# elif 'player/mirror/details' in request_path:
|
||||
|
@ -290,7 +294,7 @@ class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
|
|||
daemon_threads = True
|
||||
|
||||
def __init__(self, client, subscriptionManager, jsonClass, settings,
|
||||
*args, **kwargs):
|
||||
queue, *args, **kwargs):
|
||||
"""
|
||||
client: Class handle to plexgdm.plexgdm. We can thus ask for an up-to-
|
||||
date serverlist without instantiating anything
|
||||
|
@ -301,4 +305,5 @@ class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
|
|||
self.subscriptionManager = subscriptionManager
|
||||
self.jsonClass = jsonClass
|
||||
self.settings = settings
|
||||
self.queue = queue
|
||||
HTTPServer.__init__(self, *args, **kwargs)
|
||||
|
|
98
service.py
98
service.py
|
@ -43,9 +43,11 @@ import player
|
|||
import videonodes
|
||||
import websocket_client as wsc
|
||||
import downloadutils
|
||||
import playlist
|
||||
|
||||
import PlexAPI
|
||||
import PlexCompanion
|
||||
import PlexFunctions as PF
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
@ -109,6 +111,10 @@ class Service():
|
|||
# Set the minimum database version
|
||||
window('plex_minDBVersion', value="1.1.5")
|
||||
|
||||
# Initialize playlist/queue stuff
|
||||
self.queueId = None
|
||||
self.playlist = None
|
||||
|
||||
def getLogLevel(self):
|
||||
try:
|
||||
logLevel = int(utils.settings('logLevel'))
|
||||
|
@ -116,6 +122,79 @@ class Service():
|
|||
logLevel = 0
|
||||
return logLevel
|
||||
|
||||
def _getStartItem(self, string):
|
||||
"""
|
||||
Grabs the Plex id from e.g. '/library/metadata/12987'
|
||||
|
||||
and returns the tuple (typus, id) where typus is either 'queueId' or
|
||||
'plexId' and id is the corresponding id as a string
|
||||
"""
|
||||
typus = 'plexId'
|
||||
if string.startswith('/library/metadata'):
|
||||
try:
|
||||
string = string.split('/')[3]
|
||||
except IndexError:
|
||||
string = ''
|
||||
else:
|
||||
self.logMsg('Unknown string! %s' % string, -1)
|
||||
return typus, string
|
||||
|
||||
def processTasks(self, task):
|
||||
"""
|
||||
Processes tasks picked up e.g. by Companion listener
|
||||
|
||||
task = {
|
||||
'action': 'playlist'
|
||||
'data': as received from Plex companion
|
||||
}
|
||||
"""
|
||||
self.logMsg('Processing: %s' % task, 2)
|
||||
data = task['data']
|
||||
|
||||
if task['action'] == 'playlist':
|
||||
try:
|
||||
_, queueId, query = PF.ParseContainerKey(data['containerKey'])
|
||||
except Exception as e:
|
||||
self.logMsg('Exception while processing: %s' % e, -1)
|
||||
import traceback
|
||||
self.logMsg("Traceback:\n%s" % traceback.format_exc(), -1)
|
||||
return
|
||||
if self.playlist is not None:
|
||||
if self.playlist.typus != data.get('type'):
|
||||
self.logMsg('Switching to Kodi playlist of type %s'
|
||||
% data.get('type'), 1)
|
||||
self.playlist = None
|
||||
self.queueId = None
|
||||
if self.playlist is None:
|
||||
if data.get('type') == 'music':
|
||||
self.playlist = playlist.Playlist('music')
|
||||
elif data.get('type') == 'video':
|
||||
self.playlist = playlist.Playlist('video')
|
||||
else:
|
||||
self.playlist = playlist.Playlist()
|
||||
if queueId != self.queueId:
|
||||
self.logMsg('New playlist received, updating!', 1)
|
||||
self.queueId = queueId
|
||||
xml = PF.GetPlayQueue(queueId)
|
||||
if xml in (None, 401):
|
||||
self.logMsg('Could not download Plex playlist.', -1)
|
||||
return
|
||||
# Clear existing playlist on the Kodi side
|
||||
self.playlist.clear()
|
||||
items = []
|
||||
for item in xml:
|
||||
items.append({
|
||||
'queueId': item.get('playQueueItemID'),
|
||||
'plexId': item.get('ratingKey'),
|
||||
'kodiId': None
|
||||
})
|
||||
self.playlist.playAll(
|
||||
items,
|
||||
startitem=self._getStartItem(data.get('key', '')),
|
||||
offset=PF.ConvertPlexToKodiTime(data.get('offset', 0)))
|
||||
else:
|
||||
self.logMsg('This has never happened before!', -1)
|
||||
|
||||
def ServiceEntryPoint(self):
|
||||
|
||||
log = self.logMsg
|
||||
|
@ -132,6 +211,8 @@ class Service():
|
|||
|
||||
# Queue for background sync
|
||||
queue = Queue.Queue(maxsize=200)
|
||||
# Queue for PlexCompanion listener
|
||||
companionQueue = Queue.Queue(maxsize=100)
|
||||
|
||||
connectMsg = True if utils.settings('connectMsg') == 'true' else False
|
||||
|
||||
|
@ -195,7 +276,15 @@ class Service():
|
|||
except Exception as e:
|
||||
log("Exception in Playback Monitor Service: %s" % e, 1)
|
||||
pass
|
||||
try:
|
||||
task = companionQueue.get(block=False)
|
||||
except Queue.Empty:
|
||||
pass
|
||||
else:
|
||||
# Got instructions from Plex Companions, process them
|
||||
self.processTasks(task)
|
||||
companionQueue.task_done()
|
||||
if not self.kodimonitor_running:
|
||||
# Start up events
|
||||
self.warn_auth = True
|
||||
if connectMsg and self.welcome_msg:
|
||||
|
@ -208,8 +297,8 @@ class Service():
|
|||
time=2000,
|
||||
sound=False)
|
||||
# Start monitoring kodi events
|
||||
if not self.kodimonitor_running:
|
||||
self.kodimonitor_running = kodimonitor.KodiMonitor()
|
||||
self.kodimonitor_running = True
|
||||
kodimonitor.KodiMonitor()
|
||||
|
||||
# Start the Websocket Client
|
||||
if not self.websocket_running:
|
||||
|
@ -222,7 +311,8 @@ class Service():
|
|||
# Start the Plex Companion thread
|
||||
if not self.plexCompanion_running:
|
||||
self.plexCompanion_running = True
|
||||
plexCompanion = PlexCompanion.PlexCompanion()
|
||||
plexCompanion = PlexCompanion.PlexCompanion(
|
||||
companionQueue)
|
||||
plexCompanion.start()
|
||||
else:
|
||||
if (user.currUser is None) and self.warn_auth:
|
||||
|
@ -313,7 +403,7 @@ class Service():
|
|||
# Abort was requested while waiting.
|
||||
break
|
||||
|
||||
if monitor.waitForAbort(1):
|
||||
if monitor.waitForAbort(0.05):
|
||||
# Abort was requested while waiting. We should exit
|
||||
break
|
||||
|
||||
|
|
Loading…
Reference in a new issue