Working on a Python PlexAPI

Thought I might post this here to see what interest there is to develop this API. I started it because I simply wanted a programmable way to mark a series as always watched so it wouldn't show up in my onDeck queue.  After realizing there wasn't much out there for an API, I thought I would contribute. -- Let me know if there is interest, and what areas you would like to see filled out.

  • Currently supports Library navigation & maintenance and Client playback.
  • I don't support Playlists, Browsing from off site, or shared libraries yet.
  • I didn't attempt any Music or Photo browsing yet.
  • Source is here: https://github.com/mjs7231/plexapi (its also in pip).

Some Examples:

# Mark All Conan (2010) Episodes Watched
from plexapi.server import PlexServer
server = PlexServer()
server.library.find('Conan (2010)').markWatched()
# Play the Movie Avatar on my iPhone
from plexapi.server import PlexServer
server = PlexServer()
avatar = server.library.section('Movies').find('Avatar')
client = server.client("Michael's iPhone")
client.playMedia(avatar)
--
2 Likes

Surprised nobody answered. It's a great idea, and the API looks neat and clean. Good job!

Good stuff!

Can I humbly ask why you are using above?

99,9 of all devs coding towards Plex are on GitHub, and Plex Inc. included.

Would make life a lot more easy, if some of the devs out there wanted to participate

but when said....

Not tried it, but might when starting a new project, but it does indeed looks so cool.....Congratz and Huge Kudo

/Tommy

Can I humbly ask why you are using above?

All my other projects are on Bitbucket as well.  My brain works better thinking about code in the terms Mercurial uses, so that what I went with.  If it's really an issue, I could switch it.  Just a personal preference; not to mention free for all my private repos.

On a side note: I noticed with the latest release of Plex Server that we can no longer hit the localhost Plex Server without first logging in.  I updated the examples and tests to show how to do this.

Can I humbly ask why you are using above?

99,9 of all devs coding towards Plex are on GitHub, and Plex Inc. included.

Would make life a lot more easy, if some of the devs out there wanted to participate

but when said....

Not tried it, but might when starting a new project, but it does indeed looks so cool.....Congratz and Huge Kudo

/Tommy

I've begun using bitbucket as well, for a free account you get unlimited private repos and you can create an organization for free too.

So I'm using it for work related repos that needs to be private.

I anticipate continuing with github for anything public/open-source.

Awesome API, I wish I had seen this before!  I had to change example 7 a bit to get it to execute (added the .section() call):

# Example 7: List files for the latest episode of Friends.
the_last_one = plex.library.section('TV Shows').get('Friends').episodes()[-1]
for part in the_last_one.iter_parts():
    print part.file

Because I was getting this error:

Traceback (most recent call last):
  File "./testplexapi.py", line 7, in 
    the_last_one = plex.library.get('Friends').episodes()[-1]
  File "/usr/local/lib/python2.7/dist-packages/plexapi/library.py", line 47, in get
    return video.find_item(self.server, '/library/all', title)
  File "/usr/local/lib/python2.7/dist-packages/plexapi/video.py", line 195, in find_item
    raise NotFound('Unable to find title: %s' % title)

Going off of what Dane touched on, I'd definitely be willing to contribute to this API if it was publicly hosted on Github.

Awesome API, I wish I had seen this before!  I had to change example 7 a bit to get it to execute (added the .section() call):

Thanks for the report, I'll take a look at it tonight and fix. It should work both with and without the section('TV Shows') part, perhaps you have an item in another section titled "Friends" as well and it got confused?

Going off of what Dane touched on, I'd definitely be willing to contribute to this API if it was publicly hosted on Github.

I find it interesting that this is the common mentality. It feels like a turf war when people see I'm using BitBucket (not just you two, I never hear the end of it from pretty much everyone). Isn't it 99% identical once you clone the repo to your local machine? You and Dane convinced me. I'll switch someday in the near future simply for the fact that its not a fight I find worth fighting. I just preferred the ability to make my repos private, a feature I'll evidently lose.

EDIT: Just moved this over to https://github.com/mjs7231/plexapi

FYI https://github.com/fuzeman/plex.py

(a bit late I know)

It should work both with and without the section('TV Shows') part, perhaps you have an item in another section titled "Friends" as well and it got confused?

It doesn't work with the section('TV Shows) bit for me because I have movies with the word "Friends" in them.  This returns multiple results in the call to .search() and calling .get() returns a NotFound exception when in reality, it found multiple results.  I haven't looked into it much more than that, I just thought I'd report that one of the examples wasn't working for me and was returning a misleading exception.

I find it interesting that this is the common mentality. It feels like a turf war when people see I'm using BitBucket (not just you two, I never hear the end of it from pretty much everyone). Isn't it 99% identical once you clone the repo to your local machine? You and Dane convinced me. I'll switch someday in the near future simply for the fact that its not a fight I find worth fighting. I just preferred the ability to make my repos private, a feature I'll evidently lose.

Heh, turf war indeed.  People get touchy about this topic but I'll say that I personally like being able to have private repos so I have a BitBucket for personal use and I have a few GitHub accounts for things that are going to be publicly available or that are going to be contributed to by others.  The primary reason that I wanted a Python Plex API on GitHub is because I wanted to contribute to it, but the secondary reason is because virtually all Plex code is on GitHub.

Just looking for a handy way to access the plex API easily. Hope you continue working on this! the ability to control clients easily is very useful (Know its a bit late, but hoping for a future update!) Specifically playing trailers/extras on clients as i currently can't find a way to do this

Excellent job. Examples are really straight forward.
Will use the part to check “watched” status from an agent (if i can) so i can sync with Simkl api.

PKKid,
I just came across this API. Very interesting. I’ve been wanting to use an API call to my plex server and a player to start a music playlist as an alarm clock. It has been pretty straight forward although I have one problem. When I try to set client parameters I get an exception. Strangely I see the volume on the client go to 100% although it does not shuffle the playlist. Right now I just ignore the exception and play but it does not shuffle. I’m a bit new to python coming from java so I may be doing something dumb.

-- snip --
#!/usr/local/bin/python

from plexapi.server import PlexServer
from plexapi.playqueue import PlayQueue
from plexapi.playlist import Playlist

baseurl = 'http://myserver:32400'
token = 'T0k3n!@#!@#$#!@!$#'
plex = PlexServer(baseurl, token)
client = plex.client("Android Player")


for playlist in plex.playlists():
    if playlist.title == "Oldies":
        print ("Play this one")
        try:
	        client.setParameters(100, 1, 1, 'music')
        except:
	        pass
        client.playMedia(playlist)
-- snip --

$ python test.py
Play this one
Traceback (most recent call last):
File “test.py”, line 20, in
client.playMedia(playlist)
File “/usr/local/lib/python2.7/site-packages/plexapi/client.py”, line 154, in playMedia
}, **params))
File “/usr/local/lib/python2.7/site-packages/plexapi/client.py”, line 85, in sendCommand
return self.query(path, headers=headers)
File “/usr/local/lib/python2.7/site-packages/plexapi/client.py”, line 71, in query
return ElementTree.fromstring(data) if data else None
File “/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/etree/ElementTree.py”, line 1300, in XML
parser.feed(text)
File “/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/etree/ElementTree.py”, line 1642, in feed
self._raiseerror(v)
File “/usr/local/Cellar/python/2.7.11/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/etree/ElementTree.py”, line 1506, in _raiseerror
raise err
xml.etree.ElementTree.ParseError: syntax error: line 1, column 0

Quick and dirty M3U8 music playlist importer:

from collections import OrderedDict
from plexapi.myplex import MyPlexAccount
from plexapi.audio import Track

PLEX_USERNAME = 'myusername'
PLEX_PASSWORD = 'mypassword'
PLEX_SERVERNAME = 'myervername'

account = MyPlexAccount(PLEX_USERNAME, PLEX_PASSWORD)
plex = account.resource(PLEX_SERVERNAME).connect()

PL_TITLE = 'Playlist1'
M3U8_FILENAME = PL_TITLE + '.m3u8'

print("Connected to Plex Server", plex)

def get_m3u8_playlist_items():
    file_path = '/home/christian/Downloads/' + M3U8_FILENAME
    filename_tracks = OrderedDict()
    trackname = None
    trackpath = None
    with open(file_path, 'r') as fobj:
        for line in fobj.readlines():
            line = line.replace("\n", '')
            if line.startswith('#EXTINF'):
                trackname = line[12:] # ist der wert fix?
                # trackname = ",".join(line.split(",")[1:])  # alternative aber untested
            else:
                trackpath = line.split('/')[-1]

            if trackname and trackpath:
                filename_tracks[trackpath] = trackname.split(' - ') # 0=Artist 1=Title
                trackname = None
                trackpath = None

    return filename_tracks

m3u8_playlist_items = get_m3u8_playlist_items()
print("PLAYLIST")
playlist_items = []
not_found = []

for pik, piv in m3u8_playlist_items.items():
    print("Looking up path=" + pik, " artist=" + piv[0], " track=" + piv[1])
    item_found = False
    items = plex.library.search(title=piv[1], artist=piv[0])
    for item in items:
        if isinstance(item, Track):
            print("  - Item ", item, item.artist())
            for media in item.media:
                print("   - Media", "Container=" + str(media.container), "Title=" + str(media.title))
                for part in media.parts:
                    print("     - ", part, part.file)
                    if pik in part.file:
                        print("       - ", "!!!!!!!!!! Found Matched File", pik)
                        playlist_items.append(item)
                        item_found = True
    if not item_found:
        not_found.append(pik)


playlist = plex.createPlaylist("Deezer: " + PL_TITLE, items=playlist_items)
print("Created Playlist", playlist)
#playlist.addItems(items)

if not_found:
    print("======= Not found Items: =======")
    for nf in not_found:
        print(" - ", nf)
1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.