This commit is contained in:
Hellowlol 2016-12-17 00:51:16 +01:00
parent 740e7a5b9b
commit 3839b9f2d8

View file

@ -4,6 +4,7 @@ PlexAPI Client
To understand how this works, read this page: To understand how this works, read this page:
https://github.com/plexinc/plex-media-player/wiki/Remote-control-API https://github.com/plexinc/plex-media-player/wiki/Remote-control-API
""" """
import requests import requests
from requests.status_codes import _codes as codes from requests.status_codes import _codes as codes
from plexapi import BASE_HEADERS, TIMEOUT, log, utils from plexapi import BASE_HEADERS, TIMEOUT, log, utils
@ -27,7 +28,8 @@ class PlexClient(object):
self.machineIdentifier = data.attrib.get('machineIdentifier') self.machineIdentifier = data.attrib.get('machineIdentifier')
self.product = data.attrib.get('product') self.product = data.attrib.get('product')
self.protocol = data.attrib.get('protocol') self.protocol = data.attrib.get('protocol')
self.protocolCapabilities = data.attrib.get('protocolCapabilities', '').split(',') self.protocolCapabilities = data.attrib.get(
'protocolCapabilities', '').split(',')
self.protocolVersion = data.attrib.get('protocolVersion') self.protocolVersion = data.attrib.get('protocolVersion')
self.platform = data.attrib.get('platform') self.platform = data.attrib.get('platform')
self.platformVersion = data.attrib.get('platformVersion') self.platformVersion = data.attrib.get('platformVersion')
@ -74,10 +76,12 @@ class PlexClient(object):
command = command.strip('/') command = command.strip('/')
controller = command.split('/')[0] controller = command.split('/')[0]
if controller not in self.protocolCapabilities: if controller not in self.protocolCapabilities:
raise Unsupported('Client %s does not support the %s controller.' % (self.title, controller)) raise Unsupported(
'Client %s does not support the %s controller.' % (self.title, controller))
path = '/player/%s%s' % (command, utils.joinArgs(params)) path = '/player/%s%s' % (command, utils.joinArgs(params))
headers = {'X-Plex-Target-Client-Identifier':self.machineIdentifier} headers = {'X-Plex-Target-Client-Identifier': self.machineIdentifier}
self._commandId += 1; params['commandID'] = self._commandId self._commandId += 1
params['commandID'] = self._commandId
proxy = self._proxyThroughServer if proxy is None else proxy proxy = self._proxyThroughServer if proxy is None else proxy
if proxy: if proxy:
return self.server.query(path, headers=headers) return self.server.query(path, headers=headers)
@ -93,23 +97,37 @@ class PlexClient(object):
# Navigation Commands # Navigation Commands
# These commands navigate around the user-interface. # These commands navigate around the user-interface.
def contextMenu(self): self.sendCommand('navigation/contextMenu') def contextMenu(self): self.sendCommand('navigation/contextMenu')
def goBack(self): self.sendCommand('navigation/back') def goBack(self): self.sendCommand('navigation/back')
def goToHome(self): self.sendCommand('navigation/home') def goToHome(self): self.sendCommand('navigation/home')
def goToMusic(self): self.sendCommand('navigation/music') def goToMusic(self): self.sendCommand('navigation/music')
def moveDown(self): self.sendCommand('navigation/moveDown') def moveDown(self): self.sendCommand('navigation/moveDown')
def moveLeft(self): self.sendCommand('navigation/moveLeft') def moveLeft(self): self.sendCommand('navigation/moveLeft')
def moveRight(self): self.sendCommand('navigation/moveRight') def moveRight(self): self.sendCommand('navigation/moveRight')
def moveUp(self): self.sendCommand('navigation/moveUp') def moveUp(self): self.sendCommand('navigation/moveUp')
def nextLetter(self): self.sendCommand('navigation/nextLetter') def nextLetter(self): self.sendCommand('navigation/nextLetter')
def pageDown(self): self.sendCommand('navigation/pageDown') def pageDown(self): self.sendCommand('navigation/pageDown')
def pageUp(self): self.sendCommand('navigation/pageUp') def pageUp(self): self.sendCommand('navigation/pageUp')
def previousLetter(self): self.sendCommand('navigation/previousLetter') def previousLetter(self): self.sendCommand('navigation/previousLetter')
def select(self): self.sendCommand('navigation/select') def select(self): self.sendCommand('navigation/select')
def toggleOSD(self): self.sendCommand('navigation/toggleOSD') def toggleOSD(self): self.sendCommand('navigation/toggleOSD')
def goToMedia(self, media, **params): def goToMedia(self, media, **params):
if not self.server: if not self.server:
raise Unsupported('A server must be specified before using this command.') raise Unsupported(
'A server must be specified before using this command.')
server_url = media.server.baseurl.split(':') server_url = media.server.baseurl.split(':')
self.sendCommand('mirror/details', **dict({ self.sendCommand('mirror/details', **dict({
'machineIdentifier': self.server.machineIdentifier, 'machineIdentifier': self.server.machineIdentifier,
@ -124,25 +142,54 @@ class PlexClient(object):
# is in case there are multiple things happening (e.g. music in the background, photo # is in case there are multiple things happening (e.g. music in the background, photo
# slideshow in the foreground). # slideshow in the foreground).
def pause(self, mtype): self.sendCommand('playback/pause', type=mtype) def pause(self, mtype): self.sendCommand('playback/pause', type=mtype)
def play(self, mtype): self.sendCommand('playback/play', type=mtype) def play(self, mtype): self.sendCommand('playback/play', type=mtype)
def refreshPlayQueue(self, playQueueID, mtype=None): self.sendCommand('playback/refreshPlayQueue', playQueueID=playQueueID, type=mtype)
def seekTo(self, offset, mtype=None): self.sendCommand('playback/seekTo', offset=offset, type=mtype) # offset in milliseconds def refreshPlayQueue(self, playQueueID, mtype=None): self.sendCommand(
def skipNext(self, mtype=None): self.sendCommand('playback/skipNext', type=mtype) 'playback/refreshPlayQueue', playQueueID=playQueueID, type=mtype)
def skipPrevious(self, mtype=None): self.sendCommand('playback/skipPrevious', type=mtype)
def skipTo(self, key, mtype=None): self.sendCommand('playback/skipTo', key=key, type=mtype) # skips to item with matching key def seekTo(self, offset, mtype=None): self.sendCommand(
def stepBack(self, mtype=None): self.sendCommand('playback/stepBack', type=mtype) 'playback/seekTo', offset=offset, type=mtype) # offset in milliseconds
def stepForward(self, mtype): self.sendCommand('playback/stepForward', type=mtype)
def skipNext(self, mtype=None): self.sendCommand(
'playback/skipNext', type=mtype)
def skipPrevious(self, mtype=None): self.sendCommand(
'playback/skipPrevious', type=mtype)
def skipTo(self, key, mtype=None): self.sendCommand(
'playback/skipTo', key=key, type=mtype) # skips to item with matching key
def stepBack(self, mtype=None): self.sendCommand(
'playback/stepBack', type=mtype)
def stepForward(self, mtype): self.sendCommand(
'playback/stepForward', type=mtype)
def stop(self, mtype): self.sendCommand('playback/stop', type=mtype) def stop(self, mtype): self.sendCommand('playback/stop', type=mtype)
def setRepeat(self, repeat, mtype): self.setParameters(repeat=repeat, mtype=mtype) # 0=off, 1=repeatone, 2=repeatall
def setShuffle(self, shuffle, mtype): self.setParameters(shuffle=shuffle, mtype=mtype) # 0=off, 1=on def setRepeat(self, repeat, mtype): self.setParameters(
def setVolume(self, volume, mtype): self.setParameters(volume=volume, mtype=mtype) # 0-100 repeat=repeat, mtype=mtype) # 0=off, 1=repeatone, 2=repeatall
def setAudioStream(self, audioStreamID, mtype): self.setStreams(audioStreamID=audioStreamID, mtype=mtype)
def setSubtitleStream(self, subtitleStreamID, mtype): self.setStreams(subtitleStreamID=subtitleStreamID, mtype=mtype) def setShuffle(self, shuffle, mtype): self.setParameters(
def setVideoStream(self, videoStreamID, mtype): self.setStreams(videoStreamID=videoStreamID, mtype=mtype) shuffle=shuffle, mtype=mtype) # 0=off, 1=on
def setVolume(self, volume, mtype): self.setParameters(
volume=volume, mtype=mtype) # 0-100
def setAudioStream(self, audioStreamID, mtype): self.setStreams(
audioStreamID=audioStreamID, mtype=mtype)
def setSubtitleStream(self, subtitleStreamID, mtype): self.setStreams(
subtitleStreamID=subtitleStreamID, mtype=mtype)
def setVideoStream(self, videoStreamID, mtype): self.setStreams(
videoStreamID=videoStreamID, mtype=mtype)
def playMedia(self, media, **params): def playMedia(self, media, **params):
if not self.server: if not self.server:
raise Unsupported('A server must be specified before using this command.') raise Unsupported(
'A server must be specified before using this command.')
server_url = media.server.baseurl.split(':') server_url = media.server.baseurl.split(':')
playqueue = self.server.createPlayQueue(media) playqueue = self.server.createPlayQueue(media)
self.sendCommand('playback/playMedia', **dict({ self.sendCommand('playback/playMedia', **dict({
@ -155,23 +202,31 @@ class PlexClient(object):
def setParameters(self, volume=None, shuffle=None, repeat=None, mtype=None): def setParameters(self, volume=None, shuffle=None, repeat=None, mtype=None):
params = {} params = {}
if repeat is not None: params['repeat'] = repeat # 0=off, 1=repeatone, 2=repeatall if repeat is not None:
if shuffle is not None: params['shuffle'] = shuffle # 0=off, 1=on params['repeat'] = repeat # 0=off, 1=repeatone, 2=repeatall
if volume is not None: params['volume'] = volume # 0-100 if shuffle is not None:
if mtype is not None: params['type'] = mtype # music,photo,video params['shuffle'] = shuffle # 0=off, 1=on
if volume is not None:
params['volume'] = volume # 0-100
if mtype is not None:
params['type'] = mtype # music,photo,video
self.sendCommand('playback/setParameters', **params) self.sendCommand('playback/setParameters', **params)
def setStreams(self, audioStreamID=None, subtitleStreamID=None, videoStreamID=None, mtype=None): def setStreams(self, audioStreamID=None, subtitleStreamID=None, videoStreamID=None, mtype=None):
params = {} params = {}
if audioStreamID is not None: params['audioStreamID'] = audioStreamID if audioStreamID is not None:
if subtitleStreamID is not None: params['subtitleStreamID'] = subtitleStreamID params['audioStreamID'] = audioStreamID
if videoStreamID is not None: params['videoStreamID'] = videoStreamID if subtitleStreamID is not None:
if mtype is not None: params['type'] = mtype # music,photo,video params['subtitleStreamID'] = subtitleStreamID
if videoStreamID is not None:
params['videoStreamID'] = videoStreamID
if mtype is not None:
params['type'] = mtype # music,photo,video
self.sendCommand('playback/setStreams', **params) self.sendCommand('playback/setStreams', **params)
# Timeline Commands # Timeline Commands
def timeline(self): def timeline(self):
return self.sendCommand('timeline/poll', **{'wait':1, 'commandID':4}) return self.sendCommand('timeline/poll', **{'wait': 1, 'commandID': 4})
def isPlayingMedia(self, includePaused=False): def isPlayingMedia(self, includePaused=False):
for mediatype in self.timeline(): for mediatype in self.timeline():