Some comments on the HTTP/XML interface

We’ve just finished the initial work for adding support for Plex to our CQC (www.charmedquark.com) automation platform. We posted a preview last night for users to bang on and report issues. I just wanted to make some comments on the interface and how it could be improved. Since we have interfaces to hundreds of devices and systems by now, we have a pretty well developed opinion on what works and what doesn’t.

One nit is that the ‘stopped’ state is not reported. It only reports playing/paused, but not stopped. It would be much nicer if it did. What we ended up doing was watching the current run time and, if the state is play and the time hasn’t moved in a while, we assume it’s stopped. But, this is sub-optimal because you guys don’t even update the current time but about once per ten seconds, so we obviously have to wait longer than that in order to avoid spurious triggers of a stop state.

Which brings up the fact that polling is just not optimal for this type of application. When you add in the fact that, just to get some basic info like playing state and current time for one client, you have to pull down ALL of the metadata and current info about EVERY player that’s active, then it’s a lot worse. You really need to provide a better interface for this. If you insist on sticking with HTTP, then allow the connecting controller to request async notifications on a persistent HTTP connection. Other devices use this and it works well. If the controller doesn’t request it, it’s not done, and so it’s backwards compatible.

It’s particularly piggy in that includes all of the metadata, which almost never changes, but it has to be pulled over constantly just to get some sort of reasonably low latency access to current play state and current run time. We don’t even need the metadata, since we are providing that ourselves (by pulling it from the server and storing it upon starting up a movie.) It’s pretty crazy to suck over megabytes of data that’s never changing, and to do so for every client you want to control. It’s not so great for scalability.

It’s a bit awkward that controlling a client really involves talking to the server for the most part, or at least getting status about them does (and that’s the only on-going activity.) The only way to proactively know if a client has gone away is to (again poll) the active clients list and watch for the client of interest to disappear from the list, It would be nice to have some sort of periodic ping capability straight to the clients.

In our case, since we are an automation system, we are providing the browsing of media on our own touch screens (by pulling it from the server) and invoking playback and control. The user doesn’t want to have to switch between screens, and there’s a lot more to watching movies than just selecting a movie and playing it. We provide the control over all of the hardware as well and integrate that (along now with Plex optionally) all into a single system. This is likely to be the case for most users of automation, who want a single point of control.

It would be nice, for users like ours, to just have a ‘blank screen’ mode. Some other products do this. Instead of presenting you their interface, it can just come up with a blank screen and be used as a passive media player. That would make it much more applicable to high endy automation installations.

Anyway, just some feedback. Not intended to be negative, just telling you what is missing or sub-optimal from the perspective of our customers, and hence likely to most customers looking for automated solutions.


Dean Roddey
Chairman/CTO, Charmed Quark Systems, Ltd.

Hi @droddey

If you only require playback states (including a stopped state) then a websocket connection to Plex would provide this.

Not sure how you’re currently interfacing with Plex (I’m guessing you’re polling the sessions api), but if you set up a websocket connection to ws://127.0.0.1:32400/:/websockets/notifications you can receive notification events from the Plex server which include the play states as well as some other basic info for the streams.

This might be what you’re looking for.

Is that actually documented somewhere? In terms of what’s sent?

One issue we do have is that Plex seems to be taking an all too common stance of tacitly providing access to an API, but not really supporting it formally. So products like ours get users using it, then it changes randomly in any given update, in a way that breaks our support. And we can’t complain because, well, it’s not really officially supported. Maybe I’m being unfair and they really do formally support it, but it doesn’t seem to be the case. If they don’t, then it’s sort of having their cake (getting folks like us to get them more customers) but not having to eat it, too (take responsibility to keep it working and compatible over time.)

And of course it’s the kind of thing that leads to flakey product support because there’s no documentation of all of the possible values and formats of the data that might show up, so you only figure out that this other thing happens when someone’s system in the field breaks. Doing good interfaces requires good (which includes complete) documentation.

@droddey said:
Is that actually documented somewhere? In terms of what’s sent?

One issue we do have is that Plex seems to be taking an all too common stance of tacitly providing access to an API, but not really supporting it formally. So products like ours get users using it, then it changes randomly in any given update, in a way that breaks our support. And we can’t complain because, well, it’s not really officially supported. Maybe I’m being unfair and they really do formally support it, but it doesn’t seem to be the case. If they don’t, then it’s sort of having their cake (getting folks like us to get them more customers) but not having to eat it, too (take responsibility to keep it working and compatible over time.)

And of course it’s the kind of thing that leads to flakey product support because there’s no documentation of all of the possible values and formats of the data that might show up, so you only figure out that this other thing happens when someone’s system in the field breaks. Doing good interfaces requires good (which includes complete) documentation.

Unfortunately no there is not documentation that I’m aware of for this, official or unofficial.

Official API documentation on a whole is lacking for most third party developers currently, so making use of any undocumented API calls would be equally risky from a long-term maintenance standpoint.

Unofficially this is the data the websockets connection will return for playback events:

{  
   "_elementType":"NotificationContainer",
   "type":"playing",
   "size":1,
   "_children":[  
      {  
         "_elementType":"PlaySessionStateNotification",
         "sessionKey":"1",
         "guid":"",
         "ratingKey":"46",
         "url":"",
         "key":"/library/metadata/46",
         "viewOffset":20800,
         "state":"playing"
      }
   ]
}

How would you map one of the children back to a particular client? I guess that the session key is the only thing in there that’s remotely correlatable, right? And even then I’m not sure about it. Doesn’t the session key change every time you start and stop, or at least if you start another piece of media playing? It would be a LOT more useful if it included the machine id of the client it’s referring to.

@droddey said:
How would you map one of the children back to a particular client? I guess that the session key is the only thing in there that’s remotely correlatable, right? And even then I’m not sure about it. Doesn’t the session key change every time you start and stop, or at least if you start another piece of media playing? It would be a LOT more useful if it included the machine id of the client it’s referring to.

The only way I know how to do this currently is to query the status/sessions endpoint and match the session key. And yes the session key will change on every new stream.

Ultimately, I’m not sure if that’s worth it. You’d have to fairly rapidly poll the sessions in order to know what the session id is, and you can’t risk ignoring a notification because you don’t know how to assign it because you’d get out of sync. And, if you have to do that, you already have the information you need anyway, so you might as well just stick with polling the sessions, it seems to me.

@droddey said:
Ultimately, I’m not sure if that’s worth it. You’d have to fairly rapidly poll the sessions in order to know what the session id is, and you can’t risk ignoring a notification because you don’t know how to assign it because you’d get out of sync. And, if you have to do that, you already have the information you need anyway, so you might as well just stick with polling the sessions, it seems to me.

It is a bit of extra work, but if you want your events to fire off quickly without having to set your poll interval really short then the combination of the two works well. Essentially you always have your websocket connection open listening for events and only poll the sessions endpoint when you need to (i.e. when a new session starts or the session state changes).

It would be ideal though if the websocket connection provided a bit more detail.