Skip to content

Instantly share code, notes, and snippets.

@Generator
Last active June 18, 2023 18:01
Show Gist options
  • Save Generator/9da560853ce7001e188fcfb30ea673ca to your computer and use it in GitHub Desktop.
Save Generator/9da560853ce7001e188fcfb30ea673ca to your computer and use it in GitHub Desktop.
Kill Plex Streams without Plex Pass

Inspiration

Inspiration from kill_stream.py but wihtout the need of Plex Pass.
Kill any transconding stream or paused for a long time.

Cons:

  • Client IP blocked for 2 minutes
  • Plex App could hang or crash
  • Can't send messagens to user
  • Requires root or sudo privileges

Dependencies

  • dsniff
  • root or sudo privilege user with NOPASSWD

Sudo setup
IMPORTANT: Only use this if you are NOT running Tautulil as root
Edit /etc/sudoers.d/tautulli.conf

tautulli ALL = (ALL) NOPASSWD: /usr/sbin/tcpkill  
tautulli ALL = (ALL) NOPASSWD: /usr/bin/timeout  

Replace tautulli with service username.
Find systemd service user:
$ grep 'User=' /etc/systemd/system/tautulli.service

Install

$ wget -O kill_stream.sh https://gist.githubusercontent.com/Generator/9da560853ce7001e188fcfb30ea673ca/raw/kill_stream.sh
$ chmod +x kill_stream.sh  

Tautulli Setup

Commum Scripts Settings in Tautulli:
Taultulli > Settings > Notification Agents > Add a Notification Agent > Script
Set Script Folder
Select kill_stream.sh
Script Timeout 0

Kill Transconders

Triggers: Playback Start
Conditions: [ Transcode Decision | is | transcode ]
Arguments: Playback Start: -H {ip_address} -k

Kill non-local streams paused for a long time

Triggers:

  • Playback Pause
  • Playback Resume

Arguments:

  • Playback Pause: -H {ip_address} -p
  • Playback Resume: -r

Kill streams paused for a custom time

Triggers:

  • Playback Pause
  • Playback Resume

Arguments:
Use -t <MINUTES> to specify time to wait till kill the paused stream. In this example the stream will be killed after 10 minutes.

  • Playback Pause: -H {ip_address} -t 10 -p
  • Playback Resume: -r

Usage

-H IP           - Kill selected IP  
-i dev          - Custom Network device
-G gateway      - Custom Router gateway [ exclude gateway ]
-t time         - Paused time [default 20 minutes]
-p              - Kill paused stream
-r              - Resumed stream
-h | --help     - Help
#!/bin/bash
# Get default interface and gateway
interface=$(ip route | awk '/default/ { print $5 }')
gateway=$(ip route | awk '/default/ { print $3 }')
# Help and usage
usage() {
echo "usage: kill_stream.sh [-k IP] [-p] [-r]"
}
help() {
cat <<EOF
-H IP - Kill selected IP
-i dev - Custom Network device
-G gateway - Custom Router gateway [ exclude gateway ]
-t time - Paused time [default 20 minutes]
-p - Kill paused stream
-r - Resumed stream
-h | --help - Help
EOF
exit 0; }
# If no custom argument use default
if [ -z "${G}"]; then
G=${gateway}
fi
if [ -z "${i}"]; then
i=${interface}
fi
if [ -z "${t}"]; then
t=20
fi
# Kill the stream
kill_stream() {
SUDO=''
if (( $EUID != 0 )); then
SUDO='sudo'
fi
$SUDO timeout 2m tcpkill -i "${i}" -9 host "${H}" and not "${G}"
}
# Kill stream if paused for too long
kill_pause() {
date +%s --date='${t} minutes' > /tmp/kill_pause
while [ -f /tmp/kill_pause ]; do
sleep 15
if [ $(date +%s) -ge $(cat /tmp/kill_pause) ]; then
kill_stream
if [ -f /tmp/kill_pause ]; then
rm /tmp/kill_pause
fi
fi
done
}
# If stream get resume remove timer
resume_stream() {
if [ -f /tmp/kill_pause ]; then
rm /tmp/kill_pause
fi
}
# CLI options
while getopts ":H:G:i:t:kprh" arg; do
case "${arg}" in
H)
H="$OPTARG"
;;
G)
G="$OPTARG"
;;
i)
i="$OPTARG"
;;
t)
t="$OPTARG"
;;
k)
kill_stream
;;
p)
kill_pause
;;
r)
resume_stream
;;
h|-help)
help
;;
\? )
echo "Invalid Option: -$OPTARG" 1>&2
exit 1
;;
*)
usage
;;
esac
done
shift $((OPTIND-1))
@snackle
Copy link

snackle commented Aug 22, 2018

Hey man, absolutely loving that you came up with this. As far as I can tell, it is properly setup on my end. Showing debug log entries that seem right and have these under notification logs https://i.imgur.com/anmIx7V.png

But while actively testing and playing a transcode, the stream is not killed and my client is still able to connect/use the server. What could I be doing wrong here? Any other info I can send your way to help?

Thanks in advance for your help!

EDIT:
Just dawned on me this might be a restriction of my setup using nginx and cf as a CDN? When trying to load a direct page, the host was denied.

@goozchos
Copy link

Is there any way to do this in Windows?

@fayceee
Copy link

fayceee commented Mar 31, 2020

How do you you install this? please elaborate. It sucks having to close plex in order to kill a stream.

@fayceee
Copy link

fayceee commented Mar 31, 2020

Is there any way to do this in Windows?

Hey, please let me know if you figure out how to install this.

@goozchos
Copy link

Is there any way to do this in Windows?

Hey, please let me know if you figure out how to install this.

Are you running Plex on Windows? The install instructions for Linux are right there near the top of this page, so I'm guessing by your "how do you install" question that you're trying to do this on Windows and aren't familiar with Linux.
I'm thinking there might be a way to do this with the "Windows Subsystem for Linux", but I don't know if it would be worth running an entire Linux distribution in Windows just to run this script, which is why I was wondering if there's a way to do it directly in Windows.

@goozchos
Copy link

you can download the zip file, extract it within tautulli directory (not root)> then within Tautulli you need to 'add script' to notification agents and locate the 'kill_stream.sh' files, for me the script folder is: C:\Tautulli > after this you'd select 'playback pause' under 'triggers' tab.

i'm not sure how to use this script properly but thats what i gathered after finding a tutorial for a similar script (but for plex pass users).

It would be nice if someone could clarify this because im 50% confident this worked and it was a basic method.

I don't think that would work because this is a bash script, and bash scripts don't work directly on Windows (you'd need Linux or MacOS). Let's see what the dev says though, if they ever chime in.

@KoRnEr007
Copy link

Hello,
thanks for the work.
Is it possible to use the script if tautulli and the script are not on the same server of plex ?

Rgds

@thunder2k
Copy link

Hey, am I the only one who's getting an error for every execution?
Tautulli Notifiers :: Full script is: ['/home/pi/scripts/kill_stream.sh', '-H', '192.168.1.69', '-t', '5', '-p']
Tautulli Notifiers :: Script error: date: invalid date ‘${t} minutes’ /home/pi/scripts/kill_stream.sh: line 52: [: 1638543080: unary operator expected /home/pi/scripts/kill_stream.sh: line 52: [: 1638543095: unary operator expected /home/pi/scripts/kill_stream.sh: line 52: [: 1638543110: unary operator expected /home/pi/scripts/kill_stream.sh: line 52: [: 1638543125: unary operator expected cat: /tmp/kill_pause: No such file or directory /home/pi/scripts/kill_stream.sh: line 52: [: 1638543140: unary operator expected

@origamiofficial
Copy link

Any idea what's I'm missing here ?

2022-01-23 19:27:31 DEBUG Tautulli NotificationHandler :: Custom notification conditions not satisfied, skipping notifier_id 19.
2022-01-23 19:27:31 DEBUG Tautulli NotificationHandler :: Custom conditions evaluated to 'False'. Conditions: [False, True].
2022-01-23 19:27:31 DEBUG Tautulli NotificationHandler :: Condition logic [blank]: {1} and {2} > False
2022-01-23 19:27:31 DEBUG Tautulli NotificationHandler :: {2} library_name | is | 'test videos' > 'test videos' > True
2022-01-23 19:27:31 DEBUG Tautulli NotificationHandler :: {1} transcode_decision | is | 'transcode' > 'direct play' > False
2022-01-23 19:27:31 DEBUG Tautulli NotificationHandler :: Checking custom notification conditions for notifier_id 19.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment