Finished updating socs for client, config, exceptions

This commit is contained in:
Michael Shepanski 2017-01-23 00:15:51 -05:00
parent db18f2640f
commit 706b974b05
9 changed files with 271 additions and 262 deletions

4
docs/configuration.rst Normal file
View file

@ -0,0 +1,4 @@
Configuration
=============
dasfasd

View file

@ -1,5 +1,5 @@
Introduction
============
Getting Started
===============
.. |br| raw:: html

View file

@ -1,12 +1,14 @@
.. toctree::
:maxdepth: 2
:maxdepth: 1
:caption: Table of Contents
:titlesonly:
self
introduction
configuration
.. toctree::
:maxdepth: 2
:maxdepth: 1
:caption: Modules
modules/audio

View file

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
from plexapi import media, utils
from plexapi.utils import Playable, PlexPartialObject
@ -10,6 +9,11 @@ class Audio(PlexPartialObject):
""" Base class for audio :class:`~plexapi.audio.Artist`, :class:`~plexapi.audio.Album`
and :class:`~plexapi.audio.Track` objects.
Parameters:
server (:class:`~plexapi.server.PlexServer`): PlexServer this client is connected to (optional)
data (:class:`ElementTree`): Response from PlexServer used to build this object (optional).
initpath (str): Relative path requested when retrieving specified `data` (optional).
Attributes:
addedAt (datetime): Datetime this item was added to the library.
index (sting): Index Number (often the track number).
@ -67,6 +71,11 @@ class Audio(PlexPartialObject):
class Artist(Audio):
""" Represents a single audio artist.
Parameters:
server (:class:`~plexapi.server.PlexServer`): PlexServer this client is connected to (optional)
data (:class:`ElementTree`): Response from PlexServer used to build this object (optional).
initpath (str): Relative path requested when retrieving specified `data` (optional).
Attributes:
art (str): Artist artwork (/library/metadata/<ratingkey>/art/<artid>)
countries (list): List of :class:`~plexapi.media.Country` objects this artist respresents.
@ -76,7 +85,6 @@ class Artist(Audio):
location (str): Filepath this artist is found on disk.
similar (list): List of :class:`~plexapi.media.Similar` artists.
"""
TYPE = 'artist'
def _loadData(self, data):
@ -128,6 +136,11 @@ class Artist(Audio):
class Album(Audio):
""" Represents a single audio album.
Parameters:
server (:class:`~plexapi.server.PlexServer`): PlexServer this client is connected to (optional)
data (:class:`ElementTree`): Response from PlexServer used to build this object (optional).
initpath (str): Relative path requested when retrieving specified `data` (optional).
Attributes:
art (str): Album artwork (/library/metadata/<ratingkey>/art/<artid>)
genres (list): List of :class:`~plexapi.media.Genre` objects this album respresents.
@ -140,7 +153,6 @@ class Album(Audio):
studio (str): Studio that released this album.
year (int): Year this album was released.
"""
TYPE = 'album'
def _loadData(self, data):
@ -185,6 +197,11 @@ class Album(Audio):
class Track(Audio, Playable):
""" Represents a single audio track.
Parameters:
server (:class:`~plexapi.server.PlexServer`): PlexServer this client is connected to (optional)
data (:class:`ElementTree`): XML response from PlexServer used to build this object (optional).
initpath (str): Relative path requested when retrieving specified `data` (optional).
Attributes:
art (str): Track artwork (/library/metadata/<ratingkey>/art/<artid>)
chapterSource (TYPE): Unknown
@ -210,9 +227,9 @@ class Track(Audio, Playable):
sessionKey (int): Session Key (active sessions only).
username (str): Username of person playing this track (active sessions only).
player (str): :class:`~plexapi.client.PlexClient` for playing track (active sessions only).
transcodeSession (None): :class:`~plexapi.media.TranscodeSession` for playing track (active sessions only).
transcodeSession (None): :class:`~plexapi.media.TranscodeSession` for playing
track (active sessions only).
"""
TYPE = 'track'
def _loadData(self, data):

View file

@ -1,10 +1,4 @@
# -*- coding: utf-8 -*-
"""
PlexAPI Client
To understand how this works, read this page:
https://github.com/plexinc/plex-media-player/wiki/Remote-control-API
"""
import requests
from requests.status_codes import _codes as codes
from plexapi import BASE_HEADERS, TIMEOUT, log, utils
@ -13,40 +7,42 @@ from xml.etree import ElementTree
class PlexClient(object):
"""Main class for interacting with a client.
""" Main class for interacting with a Plex client. This class can connect
directly to the client and control it or proxy commands through your
Plex Server. To better understand the Plex client API's read this page:
https://github.com/plexinc/plex-media-player/wiki/Remote-control-API
Parameters:
baseurl (str): HTTP URL to connect dirrectly to this client.
token (str): X-Plex-Token used for authenication (optional).
session (:class:`~requests.Session`): requests.Session object if you want more control (optional).
server (:class:`~plexapi.server.PlexServer`): PlexServer this client is connected to (optional)
data (:class:`ElementTree`): Response from PlexServer used to build this object (optional).
Attributes:
baseurl (str): http adress for the client
device (None): Description
deviceClass (sting): pc, phone
machineIdentifier (str): uuid fx 5471D9EA-1467-4051-9BE7-FCBDF490ACE3
model (TYPE): Description
platform (TYPE): Description
platformVersion (TYPE): Description
product (str): plex for ios
protocol (str): plex
protocolCapabilities (list): List of what client can do
protocolVersion (str): 1
server (plexapi.server.Plexserver): PMS your connected to
session (None or requests.Session): Add your own session object to cache stuff
state (None): Description
title (str): fx Johns Iphone
token (str): X-Plex-Token, using for authenication with PMS
vendor (str): Description
version (str): fx. 4.6
baseurl (str): HTTP address of the client
device (str): Best guess on the type of device this is (PS, iPhone, Linux, etc).
deviceClass (str): Device class (pc, phone, etc).
machineIdentifier (str): Unique ID for this device.
model (str): Unknown
platform (str): Unknown
platformVersion (str): Description
product (str): Client Product (Plex for iOS, etc).
protocol (str): Always seems ot be 'plex'.
protocolCapabilities (list<str>): List of client capabilities (navigation, playback,
timeline, mirror, playqueues).
protocolVersion (str): Protocol version (1, future proofing?)
server (:class:`~plexapi.server.PlexServer`): Server this client is connected to.
session (:class:`~requests.Session`): Session object used for connection.
state (str): Unknown
title (str): Name of this client (Johns iPhone, etc).
token (str): X-Plex-Token used for authenication
vendor (str): Unknown
version (str): Device version (4.6.1, etc).
_proxyThroughServer (bool): Set to True after calling
:func:`~plexapi.client.PlexClient.proxyThroughServer()` (default False).
"""
def __init__(self, baseurl, token=None, session=None, server=None, data=None):
"""Kick shit off.
Args:
baseurl (sting): fx http://10.0.0.99:1111222
token (None, optional): X-Plex-Token, using for authenication with PMS
session (None, optional): requests.Session() or your own session
server (None, optional): PlexServer
data (None, optional): XML response from PMS as Element
or uses connect to get it
"""
self.baseurl = baseurl.strip('/')
self.token = token
self.session = session or requests.Session()
@ -56,22 +52,17 @@ class PlexClient(object):
self._commandId = 0
def _loadData(self, data):
"""Sets attrs to the class.
Args:
data (Element): XML response from PMS as a Element
"""
""" Load attribute values from Plex XML response. """
self.deviceClass = data.attrib.get('deviceClass')
self.machineIdentifier = data.attrib.get('machineIdentifier')
self.product = data.attrib.get('product')
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.platform = data.attrib.get('platform')
self.platformVersion = data.attrib.get('platformVersion')
self.title = data.attrib.get('title') or data.attrib.get('name')
# active session details
# Active session details
self.device = data.attrib.get('device')
self.model = data.attrib.get('model')
self.state = data.attrib.get('state')
@ -79,7 +70,7 @@ class PlexClient(object):
self.version = data.attrib.get('version')
def connect(self):
"""Connect"""
""" Connects to the client and reloads all class attributes. """
try:
data = self.query('/resources')[0]
self._loadData(data)
@ -88,43 +79,38 @@ class PlexClient(object):
raise NotFound('No client found at: %s' % self.baseurl)
def headers(self):
"""Default headers
Returns:
dict: default headers
"""
""" Returns a dict of all default headers for Client requests. """
headers = BASE_HEADERS
if self.token:
headers['X-Plex-Token'] = self.token
return headers
def proxyThroughServer(self, value=True):
"""Connect to the client via the server.
""" Tells this PlexClient instance to proxy all future commands through the PlexServer.
Useful if you do not wish to connect directly to the Client device itself.
Args:
value (bool, optional): Description
Parameters:
value (bool): Enable or disable proxying (optional, default True).
Raises:
Unsupported: Cannot use client proxy with unknown server.
:class:`~plexapi.exceptions.Unsupported`: Cannot use client proxy with unknown server.
"""
if value is True and not self.server:
raise Unsupported('Cannot use client proxy with unknown server.')
self._proxyThroughServer = value
def query(self, path, method=None, headers=None, **kwargs):
"""Used to fetch relative paths to pms.
""" Returns an :class:`ElementTree` object containing the response
from the specified request path.
Args:
path (str): Relative path
method (None, optional): requests.post etc
headers (None, optional): Set headers manually
**kwargs (TYPE): Passord to the http request used for filter, sorting.
Returns:
Element
Parameters:
path (str): Relative path to query.
method (func): `self.session.get` or `self.session.post`
headers (dict): Additional headers to include or override in the request.
**kwargs (TYPE): Additional arguments to inclde in the request.<method> call.
Raises:
BadRequest: Http error and code
:class:`~plexapi.exceptions.BadRequest`: When the response is not in [200, 201]
"""
url = self.url(path)
method = method or self.session.get
@ -138,24 +124,23 @@ class PlexClient(object):
return ElementTree.fromstring(data) if data else None
def sendCommand(self, command, proxy=None, **params):
"""Send a command to the client
""" Convenience wrapper around :func:`~plexapi.client.PlexClient.query()` to more easily
send simple commands to the client. Returns an :class:`ElementTree` object containing
the response.
Args:
command (str): See the commands listed below
proxy (None, optional): Description
**params (dict): Description
Returns:
Element
Parameters:
command (str): Command to be sent in for format '<controller>/<command>'.
proxy (bool): Set True to proxy this command through the PlexServer.
**params (dict): Additional GET parameters to include with the command.
Raises:
Unsupported: Unsupported clients
:class:`~plexapi.exceptions.Unsupported`: When we detect the client doesn't support this capability.
"""
command = command.strip('/')
controller = command.split('/')[0]
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))
headers = {'X-Plex-Target-Client-Identifier': self.machineIdentifier}
self._commandId += 1
@ -167,82 +152,87 @@ class PlexClient(object):
return self.query(path, headers=headers)
def url(self, path):
"""Return a full url
""" Given a path, this retuns the full PlexClient the PlexServer URL to request.
Args:
path (str): Relative path
Returns:
string: full path to PMS
Parameters:
path (str): Relative path to be converted.
"""
if self.token:
delim = '&' if '?' in path else '?'
return '%s%s%sX-Plex-Token=%s' % (self.baseurl, path, delim, self.token)
return '%s%s' % (self.baseurl, path)
#---------------------
# Navigation Commands
# These commands navigate around the user-interface.
def contextMenu(self):
"""Open the context menu on the client."""
""" Open the context menu on the client. """
self.sendCommand('navigation/contextMenu')
def goBack(self):
"""One step back"""
""" Navigate back one position. """
self.sendCommand('navigation/back')
def goToHome(self):
"""Jump to home screen."""
""" Go directly to the home screen. """
self.sendCommand('navigation/home')
def goToMusic(self):
"""Jump to music."""
""" Go directly to the playing music panel. """
self.sendCommand('navigation/music')
def moveDown(self):
"""One step down."""
""" Move selection down a position. """
self.sendCommand('navigation/moveDown')
def moveLeft(self):
""" Move selection left a position. """
self.sendCommand('navigation/moveLeft')
def moveRight(self):
""" Move selection right a position. """
self.sendCommand('navigation/moveRight')
def moveUp(self):
""" Move selection up a position. """
self.sendCommand('navigation/moveUp')
def nextLetter(self):
"""Jump to the next letter in the alphabeth."""
""" Jump to next letter in the alphabet. """
self.sendCommand('navigation/nextLetter')
def pageDown(self):
""" Move selection down a full page. """
self.sendCommand('navigation/pageDown')
def pageUp(self):
""" Move selection up a full page. """
self.sendCommand('navigation/pageUp')
def previousLetter(self):
""" Jump to previous letter in the alphabet. """
self.sendCommand('navigation/previousLetter')
def select(self):
""" Select element at the current position. """
self.sendCommand('navigation/select')
def toggleOSD(self):
""" Toggle the on screen display during playback. """
self.sendCommand('navigation/toggleOSD')
def goToMedia(self, media, **params):
"""Go to a media on the client.
""" Navigate directly to the specified media page.
Args:
media (str): movie, music, photo
**params (TYPE): Description # todo
Parameters:
media (:class:`~plexapi.media.Media`): Media object to navigate to.
**params (dict): Additional GET parameters to include with the command.
Raises:
Unsupported: Description
:class:`~plexapi.exceptions.Unsupported`: When no PlexServer specified in this object.
"""
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(':')
self.sendCommand('mirror/details', **dict({
'machineIdentifier': self.server.machineIdentifier,
@ -251,170 +241,160 @@ class PlexClient(object):
'key': media.key,
}, **params))
#-------------------
# Playback Commands
# Most of the playback commands take a mandatory mtype {'music','photo','video'} argument,
# to specify which media type to apply the command to, (except for playMedia). This
# is in case there are multiple things happening (e.g. music in the background, photo
# slideshow in the foreground).
def pause(self, mtype):
"""Pause playback
""" Pause the currently playing media type.
Args:
mtype (str): music, photo, video
Parameters:
mtype (str): Media type to take action against (music, photo, video).
"""
self.sendCommand('playback/pause', type=mtype)
def play(self, mtype):
"""Start playback
""" Start playback for the specified media type.
Args:
mtype (str): music, photo, video
Parameters:
mtype (str): Media type to take action against (music, photo, video).
"""
self.sendCommand('playback/play', type=mtype)
def refreshPlayQueue(self, playQueueID, mtype=None):
"""Summary
Args:
playQueueID (TYPE): Description
mtype (None, optional): photo, video, music
""" Refresh the specified Playqueue.
Parameters:
playQueueID (str): Playqueue ID.
mtype (str): Media type to take action against (music, photo, video).
"""
self.sendCommand(
'playback/refreshPlayQueue', playQueueID=playQueueID, type=mtype)
def seekTo(self, offset, mtype=None):
"""Seek to a time in a plaback.
Args:
offset (int): in milliseconds
mtype (None, optional): photo, video, music
""" Seek to the specified offset (ms) during playback.
Parameters:
offset (int): Position to seek to (milliseconds).
mtype (str): Media type to take action against (music, photo, video).
"""
self.sendCommand('playback/seekTo', offset=offset, type=mtype)
def skipNext(self, mtype=None):
"""Skip to next
""" Skip to the next playback item.
Args:
mtype (None, string, optional): photo, video, music
Parameters:
mtype (str): Media type to take action against (music, photo, video).
"""
self.sendCommand('playback/skipNext', type=mtype)
def skipPrevious(self, mtype=None):
"""Skip to previous
""" Skip to previous playback item.
Args:
mtype (None, optional): Description
Parameters:
mtype (str): Media type to take action against (music, photo, video).
"""
self.sendCommand('playback/skipPrevious', type=mtype)
def skipTo(self, key, mtype=None):
"""Jump to
""" Skip to the playback item with the specified key.
Args:
key (TYPE): # what is this
mtype (None, optional): photo, video, music
Returns:
TYPE: Description
Parameters:
key (str): Key of the media item to skip to.
mtype (str): Media type to take action against (music, photo, video).
"""
# skips to item with matching key
self.sendCommand('playback/skipTo', key=key, type=mtype)
def stepBack(self, mtype=None):
"""
""" Step backward a chunk of time in the current playback item.
Args:
mtype (None, optional): photo, video, music
Parameters:
mtype (str): Media type to take action against (music, photo, video).
"""
self.sendCommand('playback/stepBack', type=mtype)
def stepForward(self, mtype):
"""Summary
""" Step forward a chunk of time in the current playback item.
Args:
mtype (TYPE): Description
Returns:
TYPE: Description
Parameters:
mtype (str): Media type to take action against (music, photo, video).
"""
self.sendCommand('playback/stepForward', type=mtype)
def stop(self, mtype):
"""Stop playback
Args:
mtype (str): video, music, photo
""" Stop the currently playing item.
Parameters:
mtype (str): Media type to take action against (music, photo, video).
"""
self.sendCommand('playback/stop', type=mtype)
def setRepeat(self, repeat, mtype):
"""Summary
""" Enable repeat for the specified playback items.
Args:
repeat (int): 0=off, 1=repeatone, 2=repeatall
mtype (TYPE): video, music, photo
Parameters:
repeat (int): Repeat mode (0=off, 1=repeatone, 2=repeatall).
mtype (str): Media type to take action against (music, photo, video).
"""
self.setParameters(repeat=repeat, mtype=mtype)
def setShuffle(self, shuffle, mtype):
"""Set shuffle
""" Enable shuffle for the specified playback items.
Args:
shuffle (int): 0=off, 1=on
mtype (TYPE): Description
Parameters:
shuffle (int): Shuffle mode (0=off, 1=on)
mtype (str): Media type to take action against (music, photo, video).
"""
self.setParameters(shuffle=shuffle, mtype=mtype)
def setVolume(self, volume, mtype):
"""Change volume
""" Enable volume for the current playback item.
Args:
volume (int): 0-100
mtype (TYPE): Description
Parameters:
volume (int): Volume level (0-100).
mtype (str): Media type to take action against (music, photo, video).
"""
self.setParameters(volume=volume, mtype=mtype)
def setAudioStream(self, audioStreamID, mtype):
"""Select a audio stream
""" Select the audio stream for the current playback item (only video).
Args:
audioStreamID (TYPE): Description
mtype (str): video, music, photo
Parameters:
audioStreamID (str): ID of the audio stream from the media object.
mtype (str): Media type to take action against (music, photo, video).
"""
self.setStreams(audioStreamID=audioStreamID, mtype=mtype)
def setSubtitleStream(self, subtitleStreamID, mtype):
"""Select a subtitle
""" Select the subtitle stream for the current playback item (only video).
Args:
subtitleStreamID (TYPE): Description
mtype (str): video, music, photo
Parameters:
subtitleStreamID (str): ID of the subtitle stream from the media object.
mtype (str): Media type to take action against (music, photo, video).
"""
self.setStreams(subtitleStreamID=subtitleStreamID, mtype=mtype)
def setVideoStream(self, videoStreamID, mtype):
"""Summary
Args:
videoStreamID (TYPE): Description
mtype (str): video, music, photo
""" Select the video stream for the current playback item (only video).
Parameters:
videoStreamID (str): ID of the video stream from the media object.
mtype (str): Media type to take action against (music, photo, video).
"""
self.setStreams(videoStreamID=videoStreamID, mtype=mtype)
def playMedia(self, media, **params):
"""Start playback on a media item.
""" Start playback of the specified media item.
Args:
media (str): movie, music, photo
**params (TYPE): Description
Parameters:
media (:class:`plexapi.media.Media`): Media item to be played back (movie, music, photo).
**params (TYPE): Additional parameters to include in the request. Useful
to specify things such as offset, audio, or subtitle streams.
Raises:
Unsupported: Description
:class:`~plexapi.exceptions.Unsupported`: When no PlexServer specified in this object.
"""
if not self.server:
raise Unsupported(
@ -430,13 +410,13 @@ class PlexClient(object):
}, **params))
def setParameters(self, volume=None, shuffle=None, repeat=None, mtype=None):
"""Set params for the client
""" Set multiple playback parameters at once.
Args:
volume (None, optional): 0-100
shuffle (None, optional): 0=off, 1=on
repeat (None, optional): 0=off, 1=repeatone, 2=repeatall
mtype (None, optional): music,photo,video
Parameters:
volume (int): Volume level (0-100; optional).
shuffle (int): Shuffle mode (0=off, 1=on; optional).
repeat (int): Repeat mode (0=off, 1=repeatone, 2=repeatall; optional).
mtype (str): Media type to take action against (optional music, photo, video).
"""
params = {}
if repeat is not None:
@ -449,15 +429,14 @@ class PlexClient(object):
params['type'] = mtype
self.sendCommand('playback/setParameters', **params)
def setStreams(self, audioStreamID=None, subtitleStreamID=None,
videoStreamID=None, mtype=None):
"""Select streams.
def setStreams(self, audioStreamID=None, subtitleStreamID=None, videoStreamID=None, mtype=None):
""" Select multiple playback streams at once.
Args:
audioStreamID (None, optional): Description
subtitleStreamID (None, optional): Description
videoStreamID (None, optional): Description
mtype (None, optional): music,photo,video
Parameters:
audioStreamID (str): ID of the audio stream from the media object.
subtitleStreamID (str): ID of the subtitle stream from the media object.
videoStreamID (str): ID of the video stream from the media object.
mtype (str): Media type to take action against (optional music, photo, video).
"""
params = {}
if audioStreamID is not None:
@ -470,19 +449,18 @@ class PlexClient(object):
params['type'] = mtype
self.sendCommand('playback/setStreams', **params)
#-------------------
# Timeline Commands
def timeline(self):
"""Timeline"""
""" Poll the current timeline and return the XML response. """
return self.sendCommand('timeline/poll', **{'wait': 1, 'commandID': 4})
def isPlayingMedia(self, includePaused=False):
"""Check timeline if anything is playing
""" Returns True if any media is currently playing.
Args:
includePaused (bool, optional): Should paused be included
Returns:
bool
Parameters:
includePaused (bool): Set True to treat currently paused items
as playing (optional; default True).
"""
for mediatype in self.timeline():
if mediatype.get('state') == 'playing':

View file

@ -1,9 +1,6 @@
# -*- coding: utf-8 -*-
# flake8:noqa
"""
Python 2/3 compatability
Always try Py3 first
"""
# Python 2/3 compatability
# Always try Py3 first
import sys
try:

View file

@ -1,17 +1,17 @@
# -*- coding: utf-8 -*-
"""
PlexConfig
Settings are stored in an INI file and can be overridden after import
plexapi by simply setting the value.
"""
from collections import defaultdict
try:
from ConfigParser import ConfigParser # Python2
except ImportError:
from configparser import ConfigParser # Python3
from plexapi.compat import ConfigParser
class PlexConfig(ConfigParser):
""" PlexAPI configuration object. Settings are stored in an INI file within the
user's home directory and can be overridden after importing plexapi by simply
setting the value. See the documentation section 'Configuration' for more
details on available options.
Parameters:
path (str): Path of the configuration file to load.
"""
def __init__(self, path):
ConfigParser.__init__(self)
@ -27,6 +27,13 @@ class PlexConfig(ConfigParser):
raise Exception('Config attr not found: %s' % attr)
def get(self, key, default=None, cast=None):
""" Returns the specified configuration value or <default> if not found.
Parameters:
key (str): Configuration variable to load in the format '<section>.<variable>'.
default: Default value to use if key not found.
cast (func): Cast the value to the specified type before returning.
"""
try:
section, name = key.split('.')
value = self.data.get(section.lower(), {}).get(name.lower(), default)
@ -35,6 +42,7 @@ class PlexConfig(ConfigParser):
return default
def _asDict(self):
""" Returns all configuration values as a dictionary. """
config = defaultdict(dict)
for section in self._sections:
for name, value in self._sections[section].items():
@ -44,6 +52,7 @@ class PlexConfig(ConfigParser):
def reset_base_headers():
""" Convenience function returns a dict of all base X-Plex-* headers for session requests. """
import plexapi
return {
'X-Plex-Platform': plexapi.X_PLEX_PLATFORM,

View file

@ -1,23 +1,25 @@
# -*- coding: utf-8 -*-
# flake8:noqa
"""
PlexAPI Exceptions
"""
class PlexApiException(Exception):
""" Base class for all PlexAPI exceptions. """
pass
class BadRequest(PlexApiException):
""" An invalid request, generally a user error. """
pass
class NotFound(PlexApiException):
""" Request media item or device is not found. """
pass
class UnknownType(PlexApiException):
""" Unknown library type. """
pass
class Unsupported(PlexApiException):
""" Unsupported client request. """
pass
class Unauthorized(PlexApiException):
""" Invalid username or password. """
pass

View file

@ -124,8 +124,8 @@ class MyPlexAccount(object):
password (str): Your MyPlex.tv password.
Raises:
Unauthorized: (401) If the username or password are invalid.
BadRequest: If any other errors occured not allowing us to log into MyPlex.tv.
:class:`~plexapi.exceptions.Unauthorized`: (401) If the username or password are invalid.
:class:`~plexapi.exceptions.BadRequest`: If any other errors occured not allowing us to log into MyPlex.tv.
"""
if 'X-Plex-Token' in plexapi.BASE_HEADERS:
del plexapi.BASE_HEADERS['X-Plex-Token']
@ -254,7 +254,7 @@ class MyPlexResource(object):
HTTP or HTTPS connection.
Raises:
NotFound: When unable to connect to any addresses for this resource.
:class:`~plexapi.exceptions.NotFound`: When unable to connect to any addresses for this resource.
"""
# Sort connections from (https, local) to (http, remote)
# Only check non-local connections unless we own the resource
@ -371,7 +371,7 @@ class MyPlexDevice(object):
successful, the PlexClient object is built and returned.
Raises:
NotFound: When unable to connect to any addresses for this device.
:class:`~plexapi.exceptions.NotFound`: When unable to connect to any addresses for this device.
"""
# Try connecting to all known resource connections in parellel, but
# only return the first server (in order) that provides a response.