Giter Club home page Giter Club logo

python-plexapi's Introduction

Python-PlexAPI

image

image

image

image

image

image

Overview

Unofficial Python bindings for the Plex API. Our goal is to match all capabilities of the official Plex Web Client. A few of the many features we currently support are:

  • Navigate local or remote shared libraries.
  • Perform library actions such as scan, analyze, empty trash.
  • Remote control and play media on connected clients, including Controlling Sonos speakers
  • Listen in on all Plex Server notifications.

Installation & Documentation

pip install plexapi

Install extra features:

pip install plexapi[alert]  # Install with dependencies required for plexapi.alert

Documentation can be found at Read the Docs.

Join our Discord for support and discussion.

Getting a PlexServer Instance

There are two types of authentication. If you are running on a separate network or using Plex Users you can log into MyPlex to get a PlexServer instance. An example of this is below. NOTE: Servername below is the name of the server (not the hostname and port). If logged into Plex Web you can see the server name in the top left above your available libraries.

from plexapi.myplex import MyPlexAccount
account = MyPlexAccount('<USERNAME>', '<PASSWORD>')
plex = account.resource('<SERVERNAME>').connect()  # returns a PlexServer instance

If you want to avoid logging into MyPlex and you already know your auth token string, you can use the PlexServer object directly as above, by passing in the baseurl and auth token directly.

from plexapi.server import PlexServer
baseurl = 'http://plexserver:32400'
token = '2ffLuB84dqLswk9skLos'
plex = PlexServer(baseurl, token)

Usage Examples

# Example 1: List all unwatched movies.
movies = plex.library.section('Movies')
for video in movies.search(unwatched=True):
    print(video.title)
# Example 2: Mark all Game of Thrones episodes as played.
plex.library.section('TV Shows').get('Game of Thrones').markPlayed()
# Example 3: List all clients connected to the Server.
for client in plex.clients():
    print(client.title)
# Example 4: Play the movie Cars on another client.
# Note: Client must be on same network as server.
cars = plex.library.section('Movies').get('Cars')
client = plex.client("Michael's iPhone")
client.playMedia(cars)
# Example 5: List all content with the word 'Game' in the title.
for video in plex.search('Game'):
    print(f'{video.title} ({video.TYPE})')
# Example 6: List all movies directed by the same person as Elephants Dream.
movies = plex.library.section('Movies')
elephants_dream = movies.get('Elephants Dream')
director = elephants_dream.directors[0]
for movie in movies.search(None, director=director):
    print(movie.title)
# Example 7: List files for the latest episode of The 100.
last_episode = plex.library.section('TV Shows').get('The 100').episodes()[-1]
for part in last_episode.iterParts():
    print(part.file)
# Example 8: Get audio/video/all playlists
for playlist in plex.playlists():
    print(playlist.title)
# Example 9: Rate the 100 four stars.
plex.library.section('TV Shows').get('The 100').rate(8.0)

Controlling Sonos speakers

To control Sonos speakers directly using Plex APIs, the following requirements must be met:

  1. Active Plex Pass subscription
  2. Sonos account linked to Plex account
  3. Plex remote access enabled

Due to the design of Sonos music services, the API calls to control Sonos speakers route through https://sonos.plex.tv and back via the Plex server's remote access. Actual media playback is local unless networking restrictions prevent the Sonos speakers from connecting to the Plex server directly.

from plexapi.myplex import MyPlexAccount
from plexapi.server import PlexServer

baseurl = 'http://plexserver:32400'
token = '2ffLuB84dqLswk9skLos'

account = MyPlexAccount(token)
server = PlexServer(baseurl, token)

# List available speakers/groups
for speaker in account.sonos_speakers():
    print(speaker.title)

# Obtain PlexSonosPlayer instance
speaker = account.sonos_speaker("Kitchen")

album = server.library.section('Music').get('Stevie Wonder').album('Innervisions')

# Speaker control examples
speaker.playMedia(album)
speaker.pause()
speaker.setVolume(10)
speaker.skipNext()

Running tests over PlexAPI

Use:

tools/plex-boostraptest.py 

with appropriate arguments and add this new server to a shared user which username is defined in environment variable SHARED_USERNAME. It uses official docker image to create a proper instance.

For skipping the docker and reuse a existing server use

python plex-bootstraptest.py --no-docker --username USERNAME --password PASSWORD --server-name NAME-OF-YOUR-SEVER

Also in order to run most of the tests you have to provide some environment variables:

  • PLEXAPI_AUTH_SERVER_BASEURL containing an URL to your Plex instance, e.g. http://127.0.0.1:32400 (without trailing slash)
  • PLEXAPI_AUTH_MYPLEX_USERNAME and PLEXAPI_AUTH_MYPLEX_PASSWORD with your MyPlex username and password accordingly

After this step you can run tests with following command:

py.test tests -rxXs --ignore=tests/test_sync.py

Some of the tests in main test-suite require a shared user in your account (e.g. test_myplex_users, test_myplex_updateFriend, etc.), you need to provide a valid shared user's username to get them running you need to provide the username of the shared user as an environment variable SHARED_USERNAME. You can enable a Guest account and simply pass Guest as SHARED_USERNAME (or just create a user like plexapitest and play with it).

To be able to run tests over Mobile Sync api you have to some some more environment variables, to following values exactly:

  • PLEXAPI_HEADER_PROVIDES='controller,sync-target'
  • PLEXAPI_HEADER_PLATFORM=iOS
  • PLEXAPI_HEADER_PLATFORM_VERSION=11.4.1
  • PLEXAPI_HEADER_DEVICE=iPhone

And finally run the sync-related tests:

py.test tests/test_sync.py -rxXs

Common Questions

Why are you using camelCase and not following PEP8 guidelines?

This API reads XML documents provided by MyPlex and the Plex Server. We decided to conform to their style so that the API variable names directly match with the provided XML documents.

Why don't you offer feature XYZ?

This library is meant to be a wrapper around the XML pages the Plex server provides. If we are not providing an API that is offered in the XML pages, please let us know! -- Adding additional features beyond that should be done outside the scope of this library.

What are some helpful links if trying to understand the raw Plex API?

python-plexapi's People

Contributors

alindil avatar andrey-yantsen avatar andy-maier avatar attzonko avatar blacktwin avatar blinkystitt avatar cdce8p avatar dependabot-preview[bot] avatar dependabot[bot] avatar dirtycajunrice avatar dr-blank avatar gabrielstackhouse avatar glensc avatar havardgulldahl avatar hellowlol avatar jjlawren avatar jonnywong16 avatar meisnate12 avatar menushka avatar montellese avatar nitemare avatar nwithan8 avatar pkkid avatar reenignearcher avatar simonc56 avatar tdorsey avatar tijder avatar yosnoop avatar zacwest avatar zseriesguy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

python-plexapi's Issues

client.timeline hangs

I'm not certain this is a bug and not bad coding on my part (apologies if it is the latter), but in my usage of python-plexapi I occasionally end up with a client sitting at the user/pin screen. In this instance, if I try to access the timeline, it just seems to hang...shouldn't this connection attempt timeout? I noticed the timeline definition doesn't pass the TIMEOUT value like other calls to requests.get do:

 def timeline(self):
        url = self.url('timeline/poll')
        params = {'wait':1, 'commandID':4}
        xml_text = requests.get(url, params=params, headers=BASE_HEADERS).text
        return ElementTree.fromstring(xml_text)

Automated testing

I'd like to incorporate some automated tests into the project, especially for the code submitted for #7
In the past, i've used py.test but id be open to another framework if you are partial to one.

Question how to do `unseen with actor "name"` queries

I try to do some searches like:

  • unseen with actor "name"
  • unseen and R-rated

I figured to use the generic search method of a MovieSection def search(self, title, filter='all', vtype=None, **tags) with actor=Name tags and filter='unwatched'.
But the method expects an Actor object not a String.

Could you give an example how you would do it? I don't see the possibility to get the Actor object from a name String.

Btw great work and thanks for making it public.

plex.clients() doesn't display any clients

I have the Plex iPhone app connected to my server, and the web app connected, but even while actively streaming to my iPhone, nothing is returned by plex.clients():

In [1]: from plexapi.myplex import MyPlexUser
In [2]: user = MyPlexUser.signin('ME', 'SEKRIT')
In [3]: plex = user.getServer('MyServer').connect()
In [4]: plex.clients()
Out[4]: []

Are my expectations incorrect?

Season and Show objects now contain a method called getStreamURL

The Series and Show objects now contain a method called getStreamURL which produces an invalid URL.

Should the code be restructured to account for this? Thinking outloud, mabe the inheritance could be something like:

Video <- PlayableVideo <- Episode
and
Video <- Show

TypeError: 'NoneType' object is not callable

>>> rev = plex.library.get('Revenge')
>>> print(rev)
<Show:b'Revenge'>

>>> eps = rev.episodes()
>>> print(eps)
[<Episode:b'Pilot'>, <Episode:b'Trust'>]

>>> rev.searchEpisodes('Trust')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable

I found this: http://stackoverflow.com/questions/3283441/python-nonetype-is-not-callable-error
but i couldnt find a type = None anywhere

Am I calling searchEpisodes incorrectly or is this a python bug?

Plex search doesn't work (400) bad_request

Hello,

The search example doesn't work. (example #5)
All other examples work really well. Maybe there was an update in the latest Plex server version?

Thanks anyway for this great API :)

Document ability to playmedia action with offset

I noticed the remote control API was updated and mentions that the play media action now supports the offset argument. Is it possible to get that support added here? I find it would be nice to be able to resume something from where you left off, should the need arise.

I added a line to the setParameters function for it, and it works for me:
if offset is not None: params['offSet'] = offset # offset value in ms

Support New Hub Search

Yesterday a new PlexWeb version was released which included a new global search which is supper fast, forgiving and a bit more contextual. We should make sure the server.search() option is using this. Perhaps we can return results grouped in a dictionary or something.

Error by search Movies with ' in the titel

A search for Marvel's The Avengers return with a (500) internal_server_error

2015-07-08 14:25:44.419: test_004_search_movie
2015-07-08 14:25:44.877: โ†[91mFAIL!: (500) internal_server_errorโ†[0m
2015-07-08 14:25:44.879: Runtime: 0.460s
2015-07-08 14:25:44.880: Queries: 1
2015-07-08 14:25:44.881:
2015-07-08 14:25:44.883: Tests Run: 1
2015-07-08 14:25:44.885: Tests Passed: 0
2015-07-08 14:25:44.886: Tests Failed: 1

MOVIE_TITLE = 'Marvel's The Avengers'

Read timed out.

Hey guys,

Sometimes I get timeout exceptions:
[ERROR]: Exception: HTTPConnectionPool(host='localhost', port=32400): Read timed out. (read timeout=5)

After a quick look in the source, I think there should be a 30 second timeout, or am I wrong?

Thanks
Michael

Episode and Season numbering

The Plex XML output orders Seasons and Episodes. Plex JS uses this ordering to name episodes in the Plex GUI.

Should be able to set
episode_obj.episode_number = X
episode_obj.season_number = X
in the Episode class.

Also would be nice to have a definite integer attribute for season number as well, could be handled in the same way.

Connecting to main acount from a remote location failed

When I try to connect with the user owning the server, it doesn't work.
When I connect with a user who has it as a shared server, it works.
All of this is done from a remote location.

ERROR:plexapi:http://172.x.x.x:32400: HTTPConnectionPool(host='172.x.x.x', port=32400): Max retries exceeded with url: /?X-Plex-Token=(token) (Caused by ConnectTimeoutError(<requests.packages.urllib3.connection.HTTPConnection object at 0x10a434050>, 'Connection to 172.x.x.x timed out. (connect timeout=5)'))
ERROR:plexapi:https://10-x-x-x.somthg.plex.direct:32400: HTTPSConnectionPool(host='10-x-x-x.somthg.plex.direct', port=32400): Max retries exceeded with url: /?X-Plex-Token=(token) (Caused by ConnectTimeoutError(<requests.packages.urllib3.connection.VerifiedHTTPSConnection object at 0x10a434250>, 'Connection to 10-x-x-x.somthg.plex.direct timed out. (connect timeout=5)'))
ERROR:plexapi:https://172-x-x-x.somthg.plex.direct:32400: HTTPSConnectionPool(host='172-x-x-x.somthg.plex.direct', port=32400): Max retries exceeded with url: /?X-Plex-Token=(token) (Caused by ConnectTimeoutError(<requests.packages.urllib3.connection.VerifiedHTTPSConnection object at 0x10a4349d0>, 'Connection to 172-x-x-x.somthg.plex.direct timed out. (connect timeout=5)'))
ERROR:plexapi:http://10.x.x.x:32400: HTTPConnectionPool(host=โ€™10.x.x.x', port=32400): Max retries exceeded with url: /?X-Plex-Token=(token) (Caused by ConnectTimeoutError(<requests.packages.urllib3.connection.HTTPConnection object at 0x10a434dd0>, 'Connection to 10.90.165.4 timed out. (connect timeout=5)'))
INFO:plexapi:Testing connection: https://172-x-x-x.somthg.plex.direct:32400 ERR
INFO:plexapi:Testing connection: https://10-x-x-x.somthg.plex.direct:32400 ERR
INFO:plexapi:Testing connection: https://62-x-x-x.somthg.plex.direct:32400 OK
INFO:plexapi:Testing connection: http://172.x.x.x:32400 ERR
INFO:plexapi:Testing connection: http://10.x.x.x:32400 ERR
INFO:plexapi:Testing connection: http://62.x.x.x:32400 OK
INFO:plexapi:Connecting to server: None
Traceback (most recent call last):
File "/Users/myuser/PycharmProjects/PlexCompanion/test1.py", line 12, in
print movie.checkExisting()
File "/Users/myuser/PycharmProjects/PlexCompanion/PlexAlert/Movie.py", line 63, in checkExisting
for video in plex.search(self.name):
AttributeError: 'NoneType' object has no attribute 'search'

Displaying Photos in Nested Photoalbums

I have photo album A which has two sub albums B and C. All the jpegs are inside B and C. How do I get plexapi to display photos in nested albums. It shows up fine in plex web client.

Support Casting to Chromecast

Hi
My android smartphone client is connected to the plex media server. It is ready to display media. When I use the Python plex api to play media using client.playMedia(item), items displays correctly on my client screen.

But I am unable to cast it on another screen using Chromecast. When I try casting, it tries and gives up.
All other content like youtube etc. Iam able to cast. It is only items playing via the Python API, I am not able to cast.

Any ideas?

Several APIs returning invalid URLs

There are several APIs such as the thumbUrl propery of Video which return a URL, using an object that may or may not have been fetched at the time of the request:

https://github.com/mjs7231/python-plexapi/blob/master/plexapi/video.py#L261

This results in the URL being combined from the Plex base URL, plus a _NA object stringified, giving an invalid URL such as http://127.0.0.1:32400/__NA__. I think it's more reasonable to return either a None or _NA object in these cases.

NA when trying to get the genres and roles for a show

I'm trying to get the genres for a given show and I keep getting "NA" returned for everything I try.

I can get genres and roles for Movies without issue.

I'm wondering if I am not using this properly for shows. This what I am trying:

show = plex.library.section("TV Shows").get("Almost Human")
foundgenres = show.genres

I'm expecting foundgenres above would be a list similar to what is returned when querying the genres for a movie, though instead of a list I'm getting "NA"

I get a similar result if I replace "genres" with "roles." Summary, type, year, duration, etc are all returned as expected, however. Am I doing something wrong here?

Look into SSL (HTTPS) support

Been poking around after the SSL announcement today. We may be able to update the API to use this without much effort on our end. There are currently only 5 references to http: in the plexapi source:

plexapi/client.py:66:        return 'http://%s:%s/player/%s' % (self.address, self.port, path.lstrip('/'))
plexapi/video.py:80:        params['path'] = 'http://127.0.0.1:32400%s' % self.key
plexapi/server.py:43:        if address.startswith('http://'):
plexapi/server.py:106:        url = 'http://%s:%s/%s' % (self.address, self.port, path.lstrip('/'))
plexapi/utils.py:55:        addr = addr.replace('http://', '')

It looks like the plex web client is now loading https://plex.tv/api/resources?includeHttps=1 to find available servers, then tests and continues to communicate to these servers via HTTPS URLs that look like the following:

Testing connection to server at https://192-168-1-131.de28ba8634fc44a46.plex.direct:32400/
Testing connection to server at https://00-00-00-00.de28ba8634fc44a46.plex.direct:32400/

It doesn't appear chrome is getting the server list from https://plex.tv/pms/servers.xml?includeLite=1 anymore (which is how plexapi currently gets the server list)

Install fails

pi@zogg:~ $ cat /home/pi/.pip/pip.log
------------------------------------------------------------
/usr/bin/pip run on Mon Nov 21 05:40:41 2016
Downloading/unpacking plexapi
  Getting page https://pypi.python.org/simple/plexapi/
  URLs to search for versions for plexapi:
  * https://pypi.python.org/simple/plexapi/
  Analyzing links from page https://pypi.python.org/simple/plexapi/
    Found link https://pypi.python.org/packages/01/8e/eca1d9abe0432fef7f6a4c86af558c61631390f35b705a35628ae2bd7f84/PlexAPI-0.2.tar.gz#md5=96f5513802c24a2bc69817ffa976bf18 (from https://pypi.python.org/simple/plexapi/), version: 0.2
    Found link https://pypi.python.org/packages/06/31/0ce446d6717469c8f1cec0c40feacfb587a31d97fb4cc3c79b5a9d4de8e4/PlexAPI-0.9.1.tar.gz#md5=f8093e9ac642e18de6588e4b9fa6eda4 (from https://pypi.python.org/simple/plexapi/), version: 0.9.1
    Found link https://pypi.python.org/packages/0b/92/2c57d5e2d758d0f5f76ed72f7db0f0dad747831009a54c79991491077fa7/PlexAPI-0.2.3.tar.gz#md5=37a9855e49b345978787dd2c57de807b (from https://pypi.python.org/simple/plexapi/), version: 0.2.3
    Found link https://pypi.python.org/packages/0e/6e/56de724747eefe467c42aea34a370afa88a7e90c456eb56aa5ca785fc1ba/PlexAPI-2.0.2.tar.gz#md5=ad898641c7303757d5166df63e9bc872 (from https://pypi.python.org/simple/plexapi/), version: 2.0.2
    Found link https://pypi.python.org/packages/0f/f7/e78b6d8c7292fd64832093631125f0fe21ef9f8e72cd4745a3caa168a95d/PlexAPI-0.9.3.tar.gz#md5=020bed6427b6c5e37bed78b4fd00f3ef (from https://pypi.python.org/simple/plexapi/), version: 0.9.3
    Found link https://pypi.python.org/packages/1d/c9/ef7b641a7359cee899573c21df85028e2fc417ebef2cb96a91646e865e59/PlexAPI-1.1.0.tar.gz#md5=c310e0a3ec58b61aaeee0578b5921c25 (from https://pypi.python.org/simple/plexapi/), version: 1.1.0
    Found link https://pypi.python.org/packages/3a/d0/1a4bd779aa942b0b922981a1a72dcec7728b185cba86b4f6f0c43445f3fd/PlexAPI-0.9.4.tar.gz#md5=8b450b6db481f1174ddc8735d8c0c768 (from https://pypi.python.org/simple/plexapi/), version: 0.9.4
    Found link https://pypi.python.org/packages/45/93/5c3165d8e326ef1788f941d979c46c9267be8f7e42235ab58e8c93e1e602/PlexAPI-1.0.2.tar.gz#md5=9113ba80477ca9576d3557668c7ffbc9 (from https://pypi.python.org/simple/plexapi/), version: 1.0.2
    Found link https://pypi.python.org/packages/4a/98/6b48bfe331ab61c5ccb2d98dcdde09cbdbe5a9a97bc1b662ccd36352a0b3/PlexAPI-0.2.1.tar.gz#md5=2661674d6ee7ef568b4ab53bc24a409d (from https://pypi.python.org/simple/plexapi/), version: 0.2.1
    Found link https://pypi.python.org/packages/9e/93/9b700c5cb93b0a6c4ae6f27b9f900e79c2ef0d8dbb6cca4343e1aac17182/PlexAPI-0.9.2.tar.gz#md5=aa1bf14e2ef35b92e55e3ff4c6f3dd66 (from https://pypi.python.org/simple/plexapi/), version: 0.9.2
    Found link https://pypi.python.org/packages/bc/1a/23318d7ccd1871080e4812cb9ba5b5d2726853a4ae347fc29fb42bc8568b/PlexAPI-0.9.6.tar.gz#md5=9feaecf1abb6836def2d090c647f9424 (from https://pypi.python.org/simple/plexapi/), version: 0.9.6
    Found link https://pypi.python.org/packages/c2/95/fd31295206450678bd55103d05cacf523134f87f151ec979f098d0a345d6/PlexAPI-0.2.2.tar.gz#md5=a0807ef7c53cea582d9203606b5fefab (from https://pypi.python.org/simple/plexapi/), version: 0.2.2
    Found link https://pypi.python.org/packages/c8/5d/6c2bcd44e462a27cfe28bf09aa75236091d92009072327592e4b5eb63288/PlexAPI-1.0.1.tar.gz#md5=d04b5bd6781de6afb9e4394d94c12840 (from https://pypi.python.org/simple/plexapi/), version: 1.0.1
    Found link https://pypi.python.org/packages/c8/dc/6184288312afb6722c39b953338088c842a788348015a56f46b4aaad617c/PlexAPI-1.0.0.tar.gz#md5=8e2c115b0c5732c9f5f1bd061a92a265 (from https://pypi.python.org/simple/plexapi/), version: 1.0.0
    Found link https://pypi.python.org/packages/db/7a/60e8942d5c75b05ccb39cfb8e57f450e8e90e484b651234902e82b0350cc/PlexAPI-0.9.0.tar.gz#md5=44bc040d3b64a897796695fb296a7801 (from https://pypi.python.org/simple/plexapi/), version: 0.9.0
    Found link https://pypi.python.org/packages/e2/11/a09ae8cfb4b999b414468740492a8e033e0c4485ad229f4697fbe58f944f/PlexAPI-2.0.1.tar.gz#md5=14fef6d5a78c4e5b04491e3c65ce2ffd (from https://pypi.python.org/simple/plexapi/), version: 2.0.1
  Using version 2.0.2 (newest of versions: 2.0.2, 2.0.1, 1.1.0, 1.0.2, 1.0.1, 1.0.0, 0.9.6, 0.9.4, 0.9.3, 0.9.2, 0.9.1, 0.9.0, 0.2.3, 0.2.2, 0.2.1, 0.2)
  Downloading PlexAPI-2.0.2.tar.gz
  Downloading from URL https://pypi.python.org/packages/0e/6e/56de724747eefe467c42aea34a370afa88a7e90c456eb56aa5ca785fc1ba/PlexAPI-2.0.2.tar.gz#md5=ad898641c7303757d5166df63e9bc872 (from https://pypi.python.org/simple/plexapi/)
  Running setup.py (path:/tmp/pip-build-POcDDg/plexapi/setup.py) egg_info for package plexapi
    Warn: pypandoc not found, not converting Markdown to RST
    running egg_info
    creating pip-egg-info/PlexAPI.egg-info
    writing requirements to pip-egg-info/PlexAPI.egg-info/requires.txt
    writing pip-egg-info/PlexAPI.egg-info/PKG-INFO
    writing top-level names to pip-egg-info/PlexAPI.egg-info/top_level.txt
    writing dependency_links to pip-egg-info/PlexAPI.egg-info/dependency_links.txt
    writing manifest file 'pip-egg-info/PlexAPI.egg-info/SOURCES.txt'
    warning: manifest_maker: standard file '-c' not found
    
    reading manifest file 'pip-egg-info/PlexAPI.egg-info/SOURCES.txt'
    reading manifest template 'MANIFEST.in'
    writing manifest file 'pip-egg-info/PlexAPI.egg-info/SOURCES.txt'
  Source in /tmp/pip-build-POcDDg/plexapi has version 2.0.2, which satisfies requirement plexapi
Requirement already satisfied (use --upgrade to upgrade): requests in /usr/lib/python2.7/dist-packages (from plexapi)
  skipping extra security
  skipping extra security
  skipping extra security
Installing collected packages: plexapi
  Running setup.py install for plexapi
    Running command /usr/bin/python -c "import setuptools, tokenize;__file__='/tmp/pip-build-POcDDg/plexapi/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /tmp/pip-DPT_pI-record/install-record.txt --single-version-externally-managed --compile
    Warn: pypandoc not found, not converting Markdown to RST
    running install
    running build
    running build_py
    creating build
    creating build/lib.linux-armv7l-2.7
    creating build/lib.linux-armv7l-2.7/tests
    copying tests/examples.py -> build/lib.linux-armv7l-2.7/tests
    copying tests/utils.py -> build/lib.linux-armv7l-2.7/tests
    copying tests/tests.py -> build/lib.linux-armv7l-2.7/tests
    copying tests/__init__.py -> build/lib.linux-armv7l-2.7/tests
    copying tests/findattrs.py -> build/lib.linux-armv7l-2.7/tests
    creating build/lib.linux-armv7l-2.7/plexapi
    copying plexapi/config.py -> build/lib.linux-armv7l-2.7/plexapi
    copying plexapi/myplex.py -> build/lib.linux-armv7l-2.7/plexapi
    copying plexapi/compat.py -> build/lib.linux-armv7l-2.7/plexapi
    copying plexapi/playlist.py -> build/lib.linux-armv7l-2.7/plexapi
    copying plexapi/server.py -> build/lib.linux-armv7l-2.7/plexapi
    copying plexapi/sync.py -> build/lib.linux-armv7l-2.7/plexapi
    copying plexapi/video.py -> build/lib.linux-armv7l-2.7/plexapi
    copying plexapi/audio.py -> build/lib.linux-armv7l-2.7/plexapi
    copying plexapi/utils.py -> build/lib.linux-armv7l-2.7/plexapi
    copying plexapi/client.py -> build/lib.linux-armv7l-2.7/plexapi
    copying plexapi/__init__.py -> build/lib.linux-armv7l-2.7/plexapi
    copying plexapi/exceptions.py -> build/lib.linux-armv7l-2.7/plexapi
    copying plexapi/media.py -> build/lib.linux-armv7l-2.7/plexapi
    copying plexapi/library.py -> build/lib.linux-armv7l-2.7/plexapi
    copying plexapi/photo.py -> build/lib.linux-armv7l-2.7/plexapi
    copying plexapi/playqueue.py -> build/lib.linux-armv7l-2.7/plexapi
    running install_lib
    creating /usr/local/lib/python2.7/dist-packages/tests
    error: could not create '/usr/local/lib/python2.7/dist-packages/tests': Permission denied
    Complete output from command /usr/bin/python -c "import setuptools, tokenize;__file__='/tmp/pip-build-POcDDg/plexapi/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /tmp/pip-DPT_pI-record/install-record.txt --single-version-externally-managed --compile:
    Warn: pypandoc not found, not converting Markdown to RST

running install

running build

running build_py

creating build

creating build/lib.linux-armv7l-2.7

creating build/lib.linux-armv7l-2.7/tests

copying tests/examples.py -> build/lib.linux-armv7l-2.7/tests

copying tests/utils.py -> build/lib.linux-armv7l-2.7/tests

copying tests/tests.py -> build/lib.linux-armv7l-2.7/tests

copying tests/__init__.py -> build/lib.linux-armv7l-2.7/tests

copying tests/findattrs.py -> build/lib.linux-armv7l-2.7/tests

creating build/lib.linux-armv7l-2.7/plexapi

copying plexapi/config.py -> build/lib.linux-armv7l-2.7/plexapi

copying plexapi/myplex.py -> build/lib.linux-armv7l-2.7/plexapi

copying plexapi/compat.py -> build/lib.linux-armv7l-2.7/plexapi

copying plexapi/playlist.py -> build/lib.linux-armv7l-2.7/plexapi

copying plexapi/server.py -> build/lib.linux-armv7l-2.7/plexapi

copying plexapi/sync.py -> build/lib.linux-armv7l-2.7/plexapi

copying plexapi/video.py -> build/lib.linux-armv7l-2.7/plexapi

copying plexapi/audio.py -> build/lib.linux-armv7l-2.7/plexapi

copying plexapi/utils.py -> build/lib.linux-armv7l-2.7/plexapi

copying plexapi/client.py -> build/lib.linux-armv7l-2.7/plexapi

copying plexapi/__init__.py -> build/lib.linux-armv7l-2.7/plexapi

copying plexapi/exceptions.py -> build/lib.linux-armv7l-2.7/plexapi

copying plexapi/media.py -> build/lib.linux-armv7l-2.7/plexapi

copying plexapi/library.py -> build/lib.linux-armv7l-2.7/plexapi

copying plexapi/photo.py -> build/lib.linux-armv7l-2.7/plexapi

copying plexapi/playqueue.py -> build/lib.linux-armv7l-2.7/plexapi

running install_lib

creating /usr/local/lib/python2.7/dist-packages/tests

error: could not create '/usr/local/lib/python2.7/dist-packages/tests': Permission denied

----------------------------------------
Cleaning up...
Command /usr/bin/python -c "import setuptools, tokenize;__file__='/tmp/pip-build-POcDDg/plexapi/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /tmp/pip-DPT_pI-record/install-record.txt --single-version-externally-managed --compile failed with error code 1 in /tmp/pip-build-POcDDg/plexapi
Exception information:
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/pip/basecommand.py", line 122, in main
    status = self.run(options, args)
  File "/usr/lib/python2.7/dist-packages/pip/commands/install.py", line 295, in run
    requirement_set.install(install_options, global_options, root=options.root_path)
  File "/usr/lib/python2.7/dist-packages/pip/req.py", line 1436, in install
    requirement.install(install_options, global_options, *args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/pip/req.py", line 707, in install
    cwd=self.source_dir, filter_stdout=self._filter_install, show_stdout=False)
  File "/usr/lib/python2.7/dist-packages/pip/util.py", line 716, in call_subprocess
    % (command_desc, proc.returncode, cwd))
InstallationError: Command /usr/bin/python -c "import setuptools, tokenize;__file__='/tmp/pip-build-POcDDg/plexapi/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /tmp/pip-DPT_pI-record/install-record.txt --single-version-externally-managed --compile failed with error code 1 in /tmp/pip-build-POcDDg/plexapi

Some objects are passing the incorrect key

In some cases the Plex XML API's are passing a key of /library/metadata/<key>/children when in fact the key should really just be /library/metadata/<key> without the /children part at the end. This is causing problems in PlexPartialObject where it never thinks it has the full object, because we don't have the correct reference to the items main page. Currently we see this in the following objects from Plex.

  • Audio Artist - requires self.key.replace('/children', '')
  • Audio Album - requires self.key.replace('/children', '')
  • Playlist - requires self.key.replace('/items', '')

To get around this, we added a flag for objects: FIX_BUG_50 to note we are doing something weird to get around this issue.

How get a list of all audio albums?

Maybe I'm missing something, but I just can't figure out how to get a list all audio albums with this API. The equivalent REST API path would be:
/library/sections/<section_id>/albums

I was trying to call "searchAlbums()" with no params, but that was raising an error:

  File "./api-test.py", line 84, in <module>
    main()
  File "./api-test.py", line 79, in main
    generate_playlist("cask.local", name, list_size)
  File "./api-test.py", line 41, in generate_playlist
    all_albums = music_section.searchAlbums()
  File "/usr/local/lib/python2.7/dist-packages/PlexAPI-2.0.0a_.................................._.version.of.this.api-py2.7.egg/plexapi/library.py", line 270, in searchAlbums
    return self.search(libtype='album', **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/PlexAPI-2.0.0a_.................................._.version.of.this.api-py2.7.egg/plexapi/library.py", line 193, in search
    if libtype is not None: args['type'] = utils.searchType(libtype)
  File "/usr/local/lib/python2.7/dist-packages/PlexAPI-2.0.0a_.................................._.version.of.this.api-py2.7.egg/plexapi/utils.py", line 261, in searchType
    if libtype in SEARCHTYPES + SEARCHTYPESSTRS:
TypeError: unsupported operand type(s) for +: 'dict' and 'list'

Subsequent call to <show>.episodes() returning zero results.

Hello,
Thanks for putting the API together.
These two commands return very different results:

plex.library.get('Game of Thrones').episodes()
Out[49]: 
[<Episode:The.Red.Woman>,
 <Episode:Home>,
 <Episode:Oathbreaker>,
 <Episode:Book.of.the.Stranger>]

vs.

got = plex.library.get('Game of Thrones')
got.episodes()
Out[53]: []

How come?

PlexServer() no longer working

Hi,

I was using plexapi successfully for a while and then moved to a new place, havent touched it in a while.

Now I can no longer connect to plex server using plexapi.server.PlexServer. I get the following error:

In [1]: from plexapi.server import PlexServer

In [2]: ps = PlexServer()
---------------------------------------------------------------------------
NotFound                                  Traceback (most recent call last)
<ipython-input-2-553a4ba3c216> in <module>()
----> 1 ps = PlexServer()

/Users/eric/miniconda3/envs/plex/lib/python2.7/site-packages/plexapi/server.pyc in __init__(self, baseurl, token, session)
     25         self.token = token
     26         self.session = session or requests.Session()
---> 27         data = self._connect()
     28         self.friendlyName = data.attrib.get('friendlyName')
     29         self.machineIdentifier = data.attrib.get('machineIdentifier')

/Users/eric/miniconda3/envs/plex/lib/python2.7/site-packages/plexapi/server.pyc in _connect(self)
     48         except Exception as err:
     49             log.error('%s: %s', self.baseurl, err)
---> 50             raise NotFound('No server found at: %s' % self.baseurl)
     51
     52     @property

NotFound: No server found at: http://localhost:32400

Note however that if I'm using the MyPlexAccount method, it works. Interestingly, after I create an account with MyPlexAccount, connect through the account, then plex=PlexServer() works fine.

Any idea/suggestion?

I'm using plexapi 2.0.2 with python 2.7

Thanks!

List watched episodes by any Plex Home user

I have limited disk space, so I've been running a script that gathers all watched episodes and deletes them, then refreshes the plex media server. Works great. But then I set up Plex Home for other family members, and I still need to delete the episodes they've watched. But even though I'm the admin user, I cannot see the state of the shows they've watched. I even tried using their login/password to authenticate with my script, but then the script doesn't work at all, because they aren't the administrator.

Is there any way the API can be used to see the watched state of episodes for other Plex Home child accounts?

Better Organization of Attributes For Library Types

I'm doing some pretty basic analysis of which attributes exist on which library types. Going to use this bug as a place to take notes. It's also somewhat interesting. The code is split up into two major base classes (Audio & Video). The idea is that any attrs in all {artist, album, track} will be put in the base class for Audio. Any attrs in all {movie, show, season, episode} will be put in the base class for Video. All other attrs will be placed in their proper subclasses.

After scanning all items in my library, the following table is where I see attributes defined:
http://pastebin.com/raw/3usn8A70

Ability to Play Nested Photo Albums

Hi

I was really looking forward to using this API package (thanks a ton for creating it).
I am using WinPython and am trying some simple stuff following the examples but I am getting errors:

from plexapi.server import PlexServer
plex = PlexServer()

The above works fine. I have 1 client (my android phone) connected to the Plex server and I want to get name. I get the error:

for client in plex.clients():
    print(client.name)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-39-95657ebdc665> in <module>()
      1 for client in plex.clients():
----> 2     print(client.name)

AttributeError: 'PlexClient' object has no attribute 'name'

Doing help(client) confirms client doesn't have name attribute. So I don't know why the examples listed it. I have exactly 1 playlist containing 2 photos. This works fine:

for playlist in plex.playlists():
   for item in playlist.items():
    print(item)
<Photo:15669:b'P1050130'>
<Photo:15670:b'P1050131'>

Finally, I want to play the playlist on my phone so I do this and again get an error.

client.playMedia(playlist)
File "<string>", line unknown
ParseError: syntax error: line 1, column 0

I get the first photo on my phone and that is it. What is going on here? Am I doing something wrong? Please help.

Empty Clients

Hello there.

Thanks for this, it has been incredibly helpful.

However, the clients list (as specified in example 3) is empty, as I believe plex no longer has a '\clients' url. At least with both my PMP and mobile clients connected, that container is empty. I believe now this needs to be pulled from 'https://plex.tv/pms/resources'. Is this correct? If so, can the code be adjusted to that?

Thanks

timeline / isMediaPlaying giving parse error

When trying to use the timeline and isMediaPlaying options I get the following parse error:
requests.exceptions.InvalidURL: Failed to parse: 192-168-1-134.longstingoflettersnumberhere.plex.direct:32400timeline

I'm trying it as follows from a python console:
from plexapi.myplex import MyPlexUser
user = MyPlexUser.signin(PLEXUN, PLEXPW)
plex = user.getResource(PLEXSVR).connect()
client = plex.client(CLIENT)
client.isPlayingMedia()
(OR)
client.timeline()

and then I get the above error.
Am I doing something wrong to cause that parse error?

getStreamUrl produces a malformed URL

I cant seem to track this bug down, but the URL has an additional ? mark just before the X-Plex-Token paramater (should be an &):

plex.library.get('9').getStreamUrl()

produces:

http://localhost:10041/video/:/transcode/universal/start?path=http%3A%2F%2F127.0.0.1%3A32400%2Flibrary%2Fmetadata%2F1450&mediaIndex=0&X-Plex-Platform=Chrome&copyts=1&offset=0?X-Plex-Token=pRcNNDBmZUYkBWdAUaYa

Notice the end:

..&copyts=1&offset=0?X-Plex-Token=pRcNNDBmZUYkBWdAUaYa

Support for music

Hi mjs,

Awesome work, keep it up!

So Plex music support happened ;)

I noticed plexapi doesnt support music media, only video with many types (show, movie, episode, season, etc). Fully understand it's not an easy feat to get music support in as nice as video.

Would love it if things like sessions do show a minimal set of info though. Right now it strictly handles video only (https://github.com/mjs7231/python-plexapi/blob/master/plexapi/server.py#L102)

Non owner plex user watch status shows owners watch status

I was wondering if the API was able to handle a non-owner? I can get watch status of owner, but not another user; it returns the watch status of the owner. I am trying to get a list if watched shows from each user on the plex server, so I can delete shows that have been watched by everyone.

Maybe I'm using the API incorrectly. As a side note, when I set a breakpoint in the debugger at line 88 (if filter == 'unwatched':)and type 'show' in the debugger; they data changes every time I type show. First time itshows show object, third+ time it shows an episode object.

Here is the script I was trying to get to work.

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim: set ft=python ts=4 sw=4 sts=4 et :
"""
PlexAPI Manage

Generates a list of files which may be deleted based on being watched by all
users and matching a base path.
"""
import sys
from os.path import dirname, abspath
sys.path.append(dirname(dirname(abspath(__file__))))
from plexapi.myplex import MyPlexUser

from pprint import pprint
import plexapi
plexapi.TIMEOUT = 30

ADMIN = ( '[email protected]', 'password' )

USERS = [
    ADMIN,
    ( '[email protected]', 'password' ),
]

SECTIONS = [
    ( 'Plex', ('TV Shows',), ('/media/tv-shows', ) ),
]


class ListDiffer(object):
    """A list difference calculator.
    """
    def __init__(self, current_list, past_list):
        self.current_list, self.past_list = current_list, past_list

        try:
            self.current_set = set((current_list))
            self.past_set = set((past_list))
        except TypeError:
            self.current_set = set(map(tuple, current_list))
            self.past_set = set(map(tuple, past_list))

    def diff(self):
        '''symetric_differences lists ALL differences; both added and removed
        '''
        return self.current_set.symmetric_difference(self.past_set)

    def common(self):
        '''Contain elements that are in both; all common, added and removed
        '''
        return self.current_set.union(self.past_set)

    def added(self):
        '''Lists differences only; in this case will list all new elements in current_set
        '''
        return self.current_set.difference(self.past_set)

    def removed(self):
        '''Lists differences only; in this case will list all removed items from past_set
        '''
        return self.past_set.difference(self.current_set)

    def unchanged(self):
        '''Contains elements common to both; in this case will list unchanged elements
        '''
        return self.current_set.intersection(self.past_set)


def video_paths(plex, sections=None, paths=None, filter='unwatched'):
    '''Returns a file list of video absolute paths based on filter.

    sections: plexapi:section
    paths: list of root paths to accept
    filter: watched|unwatched
    '''
    file_list = []

    if not sections:
        sections = plex.library.sections()
    if not paths:
        paths = []

    for section_name in sections:
        section = plex.library.section(section_name)

        for show in section.all():
            if filter ==  'unwatched':
                show_filter = show.unwatched()
            elif filter ==  'watched':
                show_filter = show.watched()
            else:
                continue

            for episode in show_filter:
                print episode.title
                for media in episode.media:
                    for part in media.parts:
                        if paths:
                            for path in paths:
                                if part.file.startswith(path):
                                    print part.file
                                    file_list.append(part.file)
                                    break
                        else:
                            file_list.append(part.file)
    return file_list


class Users(object):
    def __init__(self):
        self.users = {}

    def signin(self, user_id, password, server):
        if user_id in self.users:
            user = self.users[user_id]

        else:
            user = self.users[user_id] = MyPlexUser.signin(user_id, password)

        resource = user.getResource(server)

        # XXX: Hack to allow non-owned user connections
        #resource.owned = True
        plex = resource.connect()

        return plex


def common_watched(args):
    users = Users()
    watched = []
    for user_id, password in USERS:
        for resource, sections, paths in SECTIONS:
            plex = users.signin(user_id, password, resource)
            watched.append(
                video_paths(plex,
                            sections=sections,
                            paths=paths,
                            filter='watched')
                )
    # XXX: Only works for 2 users at moment...
    if len(watched) == 2:
        diff = ListDiffer(watched[0], watched[1])
    pprint( watched )


def main(args):
    common_watched(args)


if __name__ == '__main__':
    main(args)

Support for Photos

I have a Music section and photos and I'm not getting those libraries.

<Directory allowSync="0" art="/:/resources/artist-fanart.jpg" composite="/library/sections/3/composite/1458279050" filters="1" refreshing="0" thumb="/:/resources/artist.png" key="3" type="artist" title="Music" agent="com.plexapp.agents.lastfm" scanner="Plex Music Scanner" language="en" uuid="ab1afce0-4f31-4fd5-845b-73add7bf6748" updatedAt="1458279050" createdAt="1387300385">
my sections only has my movie sections,

no errors were generated in getting sections.

The output from http://localhost:32400/library/sections has those sections as shown by the above output.

music = plex.library.section('Music')
Fails with

plexapi.exceptions.NotFound: Invalid library section: Music

Play music on clients

I was trying out Plex Api for my python Voice Assistant, and I could not get a lot of stuff to work yet.

I need just a simple thing. A user asks with voice to play some track. This track name is then passed to the PLEX api's search, and I want to play the first entry of it, or make a playlist out of all entries and play them.

Or make a random playlist out of all music entries (songs) and just switch to the one that was found by user's query.

For example, saying "AI, Play Joe Satriani", should start playing all Joe Satriani songs it found in random or alphabet order. Once it finished playing it can either just start playing them again, or switch to another random song.

These are all accepted behaviours, at the moment I'm just looking for a simpler one.

Thanks.

The problems I encountered, is that I don't understand what 'section' means? It's certainly not a library name. But I get errors when trying to pass anything like MUSIC or music or Music into it, and then 'get'.
Here is the code I tried:

for client in plex.clients():
    print(client.title)
    m = plex.library.section('Music').get(plex.search('Joe Satriani')[0])
    client.playMedia(m)

OR THIS ONE

client.playMedia(plex.search('Joe Satriani')[0])

Support for playlists

How do we get a list of playlists on the server?

Can't see anything that hits the endpoint /playlists/all

Better Documentation

I'm finding it hard to figure out what exactly this API Can do, other than the examples listed in README.md, I'm finding it pretty difficult to explore the different options.

At this point what I'm doing consists of using help() to try and figure what each object/method can do. This doesn't really seem "scalable" and is fairly time consuming.

Is there a readthedocs webpage or something?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.