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))
@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