That generated a token - THANK YOU!
Great! I'll work on an update.
EDIT:
Turns out there was a simple fix....just the instructions updated
Syntax:
USERID='[your plex email]' PASSWD='[your plex passwd]' [path_to_script/plextoken.sh]
Note that your email and passwd must be placed in single quotes to ensure correct handling of special characters
EDIT:
Also added a check for a failed attempt to obtain a token
Got the PlexIPTV.sh script working first try after you helped me with this. I just finished watching Plex for about 5 minutes - something I haven't been able to do for several days to a couple of weeks.
Thanks for testing this out! Appreciate it.
If anything else comes up i'll be periodically checking this thread.
I was thinking about Windows, and I think you could run these scripts under WSL if you have it installed.
The only thing I vaguely remember from when I was using Windows Channels and running programs in WSL is that WSL had trouble communicating with the Channels server using the localhost address. You had to use your actual network address (change in PlexIPTV.sh). You will also need to change the File names in the Channels source definition to Windows format.
I've given the @john9527 scripts (thanks!) the OliveTin-for-Channels treatment, both for generating the unique Plex token and creating the user-specific M3U/XML. One of the variations deploying this via OliveTin, is that's not necessary to have the script on the same host as your Channels DVR.
A cron job is not needed either, as the OliveTin Action will repeat at whatever interval you specify. A healthchecks.io integration is available, so you'll get notified by e-mail if the Plex data is not refreshed on the schedule set.
In addition, I've added a static-file-server to the stack, so that the resulting M3U and XML files are available by URL. Multiple DVRs are supported too, if needed, though you can share the files generated across DVRs as well.
Healthchecks.io integration if you're using Organizr for CDVR related stuff:
And, of course, the end result:
Here's the full stack (including static-file-server) to deploy via Portainer:
version: '3.9'
services:
olivetin:
image: bnhf/olivetin:${TAG} # Add the tag like latest or test to the environment variables below
container_name: olivetin
dns_search: ${DOMAIN} # For Tailscale users using Magic DNS, add your Tailnet (tailxxxxx.ts.net) to use hostnames for remote nodes
ports:
- 1337:1337
environment:
- CHANNELS_DVR=${CHANNELS_DVR} # Add your Channels DVR server in the form hostname:port or ip:port
- CHANNELS_DVR_ALTERNATES=${CHANNELS_DVR_ALTERNATES} # Space separated list of alternate Channels DVR servers to choose from in the form hostname:port or ip:port
- CHANNELS_CLIENTS=${CHANNELS_CLIENTS} # Space separated list of Channels DVR clients you'd like notifications sent to in the form hostname or IP
- UPDATE_YAMLS=${UPDATE_YAMLS} # Set this to true to update config.yaml
- UPDATE_SCRIPTS=${UPDATE_SCRIPTS} # Set this to true to update all included scripts
- TZ=${TZ} # Add your local timezone in standard linux format. E.G. US/Eastern, US/Central, US/Mountain, US/Pacific, etc
volumes:
- ${HOST_DIR}/olivetin:/config # Add the parent directory on your Docker you'd like to use
- ${DVR_SHARE}:/mnt/media-server6-8089 # This can either be a Docker volume or a host directory that's connected via Samba or NFS to your Channels DVR network share
restart: unless-stopped
#volumes: # use this section if you've setup a docker volume named channels-dvr, with CIFS or NFS, to bind to /mnt/dvr inside the container
#channels-dvr:
#external: true
static-file-server:
image: halverneus/static-file-server:${TAG}
container_name: static-file-server
dns_search: ${DOMAIN}
ports:
- 8080:8080
environment:
- FOLDER=${FOLDER}
volumes:
- ${HOST_DIR}/olivetin/local-server-8089_data:${FOLDER}
restart: unless-stopped
And some sample environment variables:
TAG=latest
DOMAIN=tailxxxxx.ts.net
CHANNELS_DVR=local-server:8089
CHANNELS_DVR_ALTERNATES=remote-server:8089
CHANNELS_CLIENTS=appletv4k-den firestick-bedroom
UPDATE_YAMLS=true
UPDATE_SCRIPTS=true
TZ=US/Mountain
HOST_DIR=/data
DVR_SHARE=/mnt/dvr
FOLDER=/web
Using the above example, the Plex M3U could be found at http://your-docker-host:8080/us.m3u8, and the XML could be found at http://your-docker-host:8080/us.xml -- and would look like this in Custom Channels:
nice! thanks for these scripts, @john9527
I do confirm that these scripts will work in WSL.
Issues I encountered:
If you cron the PlexIPTV.sh script, the cron service in WSL is disabled by default so you'd have to set up a task in task scheduler to start it on startup. but then if you ran docker in WSL for the plutotv guide container, you're probably already doing this so just add it to that. I suppose alternately, you could simply just use task scheduler to kick off the actual script in wsl instead of cron.
I'm not sure if its an IP issue or if simply the URL being referenced to in PlexIPTV.sh is not in the same place, but after fiddling with this a little, I simply circumvented it and went the local file route as my WSL mounts the C drive in /mnt/c anyway. So, I modded the scripts to create/write to /mnt/c/ChannelsDVR/IPTV/plex and referenced the same place in the source settings in the channels gui, but correcting to C:\ChannelsDVR\IPTV\plex for the relevant paths.
The plextoken.sh script did not work for me because of Special Chars being present, and yes I used the Single Quotes as advised. I had to URL encode the passwd first.
Consider updating your script to include something like:
# If receiving script errors and your passwd contains special characters,
# try using a version of your passwd that is URL ENCODEd
# ( e.g., generated with https://www.browserling.com/tools/url-encode or similar)
@john9527 I ran into the same thing when I was adapting your scripts for use with OliveTin-for-Channels. Here's the Bash function I wrote to do the URL encoding -- in case it's of any value to you:
urlencode() {
local unencodedPasswd="${1}"
local urlencodedPasswd=""
local passwdLength=${#unencodedPasswd}
for ((characterPosition = 0; characterPosition < $passwdLength; characterPosition++)); do
local passwdCharacter="${unencodedPasswd:characterPosition:1}"
case "${passwdCharacter}" in
[a-zA-Z0-9.~_-])
encodedPasswd+="${passwdCharacter}"
;;
*)
printf -v hex '%02x' "'${passwdCharacter}"
encodedPasswd+="%${hex^^}"
;;
esac
done
echo "${encodedPasswd}"
}
Okay, count me as an idiot, but I cannot figure out what "your-docker-host" is supposed to be in a Windows environment with Docker Desktop. The files are definitely in the container...
... but I have tried:
- localhost
- machine name
- machine IP address
- default switch IP address
- WSL IP address
- Docker Network IP address
All with ports 8080 and 1337, but to no avail. Is there some other path that is supposed to be used?
You pretty much covered the bases. Is it possible you have a port conflict on 8080? That's a fairly commonly used port, so you might need to map it to something else. On a Windows machine with Docker Desktop for Windows, that Windows PC is your Docker host.
In Portainer, you should see the port listed on the line for the static-file-server container -- if there's no 8080 there, then it's very likely taken by another container or something running under Windows.
EDIT: It's also possible there's something up with your volume definitions. Can you post the docker-compose you're using so I can have a look at it?
@babsonnexus For example, here's the bottom part of my OliveTin-for-Channels docker-compose, along with static-file-server in a stack:
volumes:
- ${HOST_DIR}/olivetin:/config # Add the parent directory on your Docker you'd like to use
- ${DVR_SHARE}:/mnt/media-server6-8089 # This can either be a Docker volume or a host directory that's connected via Samba or NFS to your Channels DVR network share
- ${LOGS_SHARE}:/mnt/media-server6-8089_logs # This can either be a Docker volume or a host directory that's connected via Samba or NFS to your Channels DVR logs network share
restart: unless-stopped
#volumes: # use this section if you've setup a docker volume named channels-dvr, with CIFS or NFS, to bind to /mnt/dvr inside the container
#channels-dvr:
#external: true
static-file-server:
image: halverneus/static-file-server:${TAG}
container_name: static-file-server2
dns_search: ${DOMAIN}
ports:
- 8081:8080
environment:
- FOLDER=${FOLDER}
volumes:
- ${HOST_DIR}/olivetin/media-server6-8089_data:${FOLDER}
restart: unless-stopped
And these are the relevant environment variables that I use:
HOST_DIR=/data
DVR_SHARE=/mnt/dvr
FOLDER=/web
Which results in the Plex M3U/XML files ending up here:
Not sure what combination you're using for them to end up in /tmp
I wasn't aware before this that I needed to install this separate package, too. Once I did so, I was able to make connections using the normal localhost
(and set my port to 7900 to keep it away from everything else).
I was just looking in /tmp
because I saw that it was updating files there. Once I realized the directory structure under /config
, I was able to find the files you were thinking:
This was actually different than what I saw in the OliveTin thread, so now I have the correct mount, too:
Seems to be updating regularly and correctly so far, so thanks for the clarifications! FYI, this was my first attempt at using OliveTin for Channels and learning curve was steep!
Ah OK, I figured you were a wily OliveTin veteran by now. The project has grown substantially from the early days, now with more than two dozen Actions available -- so I can see where you'd say that. Hopefully this Plex tool will work well for you, and you'll find other Actions of value, as that's where the real payoff lies.
Hmmm....seems like data-raw and quoted inputs weren't enough to prevent problems on the token generation. I updated the gist to have curl do the urlencode on the passed parms (no added function definition needed). You will still need to single quote the values on the command line.
Thanks @jsmart138 and @bnhf for letting me know.
Here's a How-To get the above Bash Shell Scripts (PlexIPTV.sh and plextoken.sh) up and running for Channels-dvr running in an existing fancybits/channels-dvr Docker Container. I already have a long Docker to-do list with all my other HomeLab Containers, so I was keen to get this up and running in the bare minimum number of steps just using the current channels-dvr Docker Container. Basic steps are:
-
Figure out what Host folder has already been mapped to your Channels-dvr Container from the Container's script (or alternatively use your own location BUT then you pick up add'l steps for mapping it to the Container). For the fancybits Container, that location is: /mnt/disk/dvr/
-
Manually (as root) create the ../iptv subfolders that the Bash Scripts intended to create in your (default Linux install) Home folder but do so in said (default Container install) Host subfolder location already accessible to the fancybits Container. (Or alternatively, as mentioned above, pick your own location, including the Home location in the Script, but then you pick up the work of setting up and maintaining the mapping of that location to the Container.) Set appropriate Permissions for those specific newly created subfolders (i.e., so the Scripts can be run as non-root, and the Results can be read by the Channels-dvr Container).
For example, whereas the plextoken.sh Script wants to create a certain additional folders in the (default Linux install) ~/channels-dvr folder:
$ mkdir -p ~/channels-dvr/iptv/plex
Instead, create these in a location where the fancybits Container already thinks its /channels-dvr folder is located:
$ sudo mkdir -p /mnt/disk/dvr/config/iptv/plex
- Patch the Bash Scripts to use the New Host Container folder location (above, or one you created/mapped) instead of the Home folder location that the Container cannot access.
For example, Replace the string:
~/channels-dvr/iptv/plex
With:
/mnt/disk/dvr/config/iptv/plex
Obviously some of the Code can now instead simply be commented out (e.g, mkdir call).
-
Run (+/- further debug/edit, as necessary) plextoken.sh Script to obtain Plex token. Unfortunately for me, 90% of my time here was spent on this step so I will elaborate to help others avoid my particular problem. The plextoken.sh Script (at the time of this posting) bombs on a '%' char in the password (regardless of how you Quote it). I therefore had to feed that Script a URL Encoded version of my password so that the Script could correctly use it as part of a URL that it ultimately sends (cleartext btw) to the Plex token server. Prior comments above elaborate on this issue. Simple non-techie solution is to just have a Password with only URL-friendly chars (e.g., Mixed-case alphanumeric). Once the correct token file is generated, you are good to go running the PlexIPTV.sh Script.
-
Create your “Plex” Source in Channels-dvr WebUI (as previously shown above). The Container can access the .m3u8 and .xml files directly from the Host File System simply using File syntax.
File | Source:
/channels-dvr/iptv/plex/us.m3u8
XMLTV Guide Data:
file:///channels-dvr/iptv/plex/us.xml
Edit: To the extent channels-dvr needs to access the XML file via HTTP protocol, I run the (built-in) Python HTTP.Server at an arbitrary Port (e.g., 8095) and feed the XMLTV Guide Data text field the URL of the Host IP (e.g., 192.168.1.99) and XML:
python3 -m http.server 8095 &
XMLTV Guide Data:
http://192.168.1.99:8095:/us.xml
BTW, any old pre-existing broken Plex Source must be either deleted or de-prioritized before you can access the individual Channels from your new working Plex Source.
- Create a user Cron job to periodically run PlexIPTV.sh, for refreshing .m3mu and .xml files.
Enjoy. The Bash Scripts nicely remove a nagging thorn from using Plex Live TV feeds. !!!BIG THANKS!!! to John9527 for creating them.
Plex is just fully un-useable to watch.
Recordings on some of the channels i have enabled seem to be ok, but i see in logs every couple min it drops connection, and re-establishes.
But live watching, some times it fails to tune immediately, sometimes, works for a few min.
I have painfully compared the channels enabled in the plex m3u,. and managed to find some of them in Pluto and Samsung m3us i also have. A few outliers though... but seems there is no easy solution for this issues of too many requests. See some Docker based solutions, and some sort of scripts., but nothing super easy for Windows... i won't waste my time tinkering with things for the few channels i rarely even watch... so, proably just gonna delete plex as a source.
I am using the https://i.mjh.nz/Plex/us.m3u8 link that was recommend on this form.
Is there any other ulr for Plex that does not have this issue?
I had this working with @john9527 scripts for a couple of months and it was awesome. Then I started getting token errors. Tried to login to plex.tv with the creds manually and it gave me a wrong password error. Odd, I didn't change it and it is strong and unique, but whatever. Changed it, updated my plextoken.sh script, and I get an unspecified error generating a token every time.
My username and password were already in single quotes. My special character is a exclamation in this case (random via password-gen tool), so shouldn't need special encoding but....it fails. I tried manually escaping with \ just in case, still fails so I set it back. Any ideas on how to workaround getting a plextoken and plexdata set up?
curl was still being picky about doing a data-urlencode.
Grab the latest version of plextoken.sh from the gist.
Also....Plex really doesn't document how they expire tokens. After not accessing a plex channel for a couple of days, I also had to generate a new token after it had been working for a month.
Appreciate the info. I realized I could go into the "failed" plextoken file and it would show me the specific error the log wasn't showing. It says "password is missing". No idea what the issue is. I've tried (with the updated script) USERID and PASSWD on the same line and on separate lines, single quotes as before, just doesn't process the password.