Powershell based Plex “Local Player”

So, imagine a scenario where you’re trying to give a presentation on a customer’s PC, what you are trying to show is a video on a remote Plex server, but the customer’s PC is so locked down (whitelisted apps only) that whilst vlc will work, a web browser won’t! Seriously!!!

However, powershell did work and that gave me a way in.

So, what I thought wouldtake just a few simple lines to download the file from the plex server and play it through vlc, actually became a bit of an epic.

Therefore, in case anybody ever gets stuck in the same hole or wants some sample code demonstrating to do take “streamed” content and convert it back into something a media player will play locally. The code is now on github at https://github.com/glennpegden/PlexLocalPlayer

To use it just pass in the URL of the video details page in Plex, your plex username andpassword and the foldername to dump the video into (also optionally the paths to ffmpeg and vlc, or you can redefine these at the top of the script)

.\PlexLocalPlay.ps1 “http://app.plex.tv/web/app#!/server/01380a5c2c9b4290-9c1136b6882a65c1/details/%2Flibrary%2Fmetadata%2F12345” “user@email.com” “yourplexpasswrd” “G:\Users\Glenn\Downloads”

Disclaimer: I’ve no idea if interacting with Plex is this way is against their terms and conditions. I’m also not sure any of how I’m doing it is “the right way” because it was reverse engineered by examining how the Plex Web Player works on a laptop rather than from any official documentation. I’m also not responsible for how you use it. My use case was to download marketing material that I was allowed to distribute, I imagine doing this with your family’s blu ray connection may be illegal in many places.

For anyone writing your own version of this, a few things about the design.

The convoluted background download. This is to address two problema.

  1. The Plex server seems to time out connections, even if they are happily delivering content. Their own web player gets around this by hitting a “ping” end point as a keep alive, we have to emulate that.
  2. Invoke-Webrequest is nice and simple, but it loads the entire downloaded content into memory and saves it upon completion. Fine for tiny webpages, a disaster waiting to happen for huge files. BITS would normally be my go to alternative (BITS support in powershell is great), but it needs a Content-Length header from the server, which we’re not going to get from a stream.

    So, we have to use .net functions to stream the content into a file, in a background task, so the foreground task can hand the keep alive.

    Potions of the stream downloading code are based on this blog post – https://blogs.msdn.microsoft.com/jasonn/2008/06/13/downloading-files-from-the-internet-in-powershell-with-progress/

I also added some hokey support for roughly passing back the progress, but as we only know the size of the file on the remote OS and who knows what the transfer/transcode is going to do with it, it’s far from accurate. It also only updates once every 15 seconds (which is how often the keep alive is sent). Really, only consider this as an indicator something is still happening, not a real estimate of progress.

Obviously simply saving the stream to a file doesn’t generate valid video file, however ffmpeg does a brilliant job or repairing it (or has done in all my tests at least, your mileage may vary).


Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.