-
-
Save aksiksi/34178962254fb73a8920d8b5e6650f98 to your computer and use it in GitHub Desktop.
Determine protonvpn port via gluetun and update qbittorrent
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ pkgs, ... }: | |
let | |
update-qbittorrent-port = pkgs.stdenv.mkDerivation rec { | |
name = "update-qbittorrent-port"; | |
src = pkgs.fetchurl { | |
url = "https://gist.githubusercontent.com/aksiksi/34178962254fb73a8920d8b5e6650f98/raw/7917342ff0088fb58ed829571f7bc3f65108fc31/update_qbit_port.sh"; | |
hash = "sha256-35eodSANzs/ycDPeoy70NhFsgnDOxmJTka/WJ6j6gKY="; | |
}; | |
dontUnpack = true; | |
installPhase = '' | |
mkdir -p $out/bin | |
ln -s ${pkgs.coreutils}/bin/date $out/bin/date | |
ln -s ${pkgs.curl}/bin/curl $out/bin/curl | |
ln -s ${pkgs.gnugrep}/bin/grep $out/bin/grep | |
ln -s ${pkgs.podman}/bin/podman $out/bin/podman | |
ln -s ${pkgs.netcat}/bin/netcat $out/bin/netcat | |
cp ${src} $out/run.sh | |
chmod +x $out/run.sh | |
''; | |
buildInputs = [ | |
pkgs.coreutils # date | |
pkgs.curl | |
pkgs.gnugrep | |
pkgs.podman | |
pkgs.netcat | |
]; | |
}; | |
in | |
{ | |
systemd.services.update-qbittorrent-port = { | |
serviceConfig.Type = "oneshot"; | |
path = [ update-qbittorrent-port ]; | |
script = '' | |
.${update-qbittorrent-port}/run.sh | |
''; | |
environment = { | |
DOCKER_CMD = "podman"; | |
DISCORD_WEBHOOK_URL = "my-url"; | |
QBITTORRENT_USER = "admin"; | |
QBITTORRENT_PASS = "adminadmin"; | |
QBITTORRENT_PORT = "8888"; | |
QBITTORRENT_SERVER = "localhost"; | |
GLUETUN_SERVER = "localhost"; | |
GLUETUN_PORT = "8000"; | |
VPN_CT_NAME = "gluetun"; | |
}; | |
}; | |
systemd.timers.update-qbittorrent-port = { | |
timerConfig = { | |
# Every 5 minutes. | |
OnUnitActiveSec = 300; | |
# 5 second jitter. | |
RandomizedDelaySec = "5s"; | |
# Last run is persisted across reboots. | |
Persistent = true; | |
Unit = "update-qbittorrent-port.service"; | |
}; | |
partOf = [ "update-qbittorrent-port.service" ]; | |
wantedBy = [ "timers.target" ]; | |
}; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# Determine protonvpn port via gluetun and update qbittorrent | |
# Variables: | |
# QBITTORRENT_USER # qbittorrent username | |
# QBITTORRENT_PASS # qbittorrent password | |
# DISCORD_WEBHOOK_URL # Discord webhook URL for port change notifications | |
QBITTORRENT_PORT=${QBITTORRENT_PORT:-8080} | |
QBITTORRENT_SERVER=${QBITTORRENT_SERVER:-localhost} | |
GLUETUN_SERVER=${GLUETUN_SERVER:-localhost} | |
GLUETUN_PORT=${GLUETUN_PORT:-8000} | |
VPN_CT_NAME=${VPN_CT_NAME:-gluetun} | |
DOCKER_CMD=${DOCKER_CMD:-docker} | |
timestamp() { | |
date '+%Y-%m-%d %H:%M:%S' | |
} | |
findconfiguredport() { | |
curl -s -i --header "Referer: http://${QBITTORRENT_SERVER}:${QBITTORRENT_PORT}" --cookie "$1" "http://${QBITTORRENT_SERVER}:${QBITTORRENT_PORT}/api/v2/app/preferences" | grep -oP '(?<=\"listen_port\"\:)(\d{1,5})' | |
} | |
findactiveport() { | |
curl -s -i "http://${GLUETUN_SERVER}:${GLUETUN_PORT}/v1/openvpn/portforwarded" | grep -oP '(?<=\"port\"\:)(\d{1,5})' | |
} | |
getpublicip() { | |
curl -s -i "http://${GLUETUN_SERVER}:${GLUETUN_PORT}/v1/publicip/ip" | grep -oP '(?<="public_ip":.)(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' | |
} | |
qbt_login() { | |
qbt_sid=$(curl -s -i --header "Referer: http://${QBITTORRENT_SERVER}:${QBITTORRENT_PORT}" --data "username=${QBITTORRENT_USER}" --data-urlencode "password=${QBITTORRENT_PASS}" "http://${QBITTORRENT_SERVER}:${QBITTORRENT_PORT}/api/v2/auth/login" | grep -oP '(?!set-cookie:.)SID=.*(?=\;.HttpOnly\;)') | |
return $? | |
} | |
qbt_changeport() { | |
curl -s -i --header "Referer: http://${QBITTORRENT_SERVER}:${QBITTORRENT_PORT}" --cookie "$1" --data-urlencode "json={\"listen_port\":$2,\"random_port\":false,\"upnp\":false}" "http://${QBITTORRENT_SERVER}:${QBITTORRENT_PORT}/api/v2/app/setPreferences" >/dev/null 2>&1 | |
return $? | |
} | |
qbt_checksid() { | |
if curl -s --header "Referer: http://${QBITTORRENT_SERVER}:${QBITTORRENT_PORT}" --cookie "${qbt_sid}" "http://${QBITTORRENT_SERVER}:${QBITTORRENT_PORT}/api/v2/app/version" | grep -qi forbidden; then | |
return 1 | |
else | |
return 0 | |
fi | |
} | |
qbt_isreachable() { | |
nc -4 -vw 5 ${QBITTORRENT_SERVER} ${QBITTORRENT_PORT} &>/dev/null 2>&1 | |
} | |
check_vpn_ct_health() { | |
while true; | |
do | |
if ! ${DOCKER_CMD} inspect "${VPN_CT_NAME}" --format='{{json .State.Status}}' | grep -q '"running"'; then | |
echo "$(timestamp) | Waiting for ${VPN_CT_NAME} healthy state.." | |
sleep 3 | |
else | |
echo "$(timestamp) | VPN container ${VPN_CT_NAME} in healthy state!" | |
break | |
fi | |
done | |
} | |
get_portmap() { | |
res=0 | |
public_ip=$(getpublicip) | |
if ! qbt_checksid; then | |
echo "$(timestamp) | qBittorrent Cookie invalid, getting new SessionID" | |
if ! qbt_login; then | |
echo "$(timestamp) | Failed getting new SessionID from qBittorrent" | |
return 1 | |
fi | |
else | |
echo "$(timestamp) | qBittorrent SessionID Ok!" | |
fi | |
configured_port=$(findconfiguredport "${qbt_sid}") | |
active_port=$(findactiveport) | |
echo "$(timestamp) | Public IP: ${public_ip}" | |
echo "$(timestamp) | Configured Port: ${configured_port}" | |
echo "$(timestamp) | Active Port: ${active_port}" | |
if [ ${configured_port} != ${active_port} ]; then | |
if qbt_changeport "${qbt_sid}" ${active_port}; then | |
echo "$(timestamp) | Port Changed to: $(findconfiguredport ${qbt_sid})" | |
else | |
echo "$(timestamp) | Port Change failed." | |
res=1 | |
fi | |
curl -H "Content-Type: application/json" -d "{\"username\": \"qBittorrent Port\", \"content\": \"qBittorrent forwarded port changed from ${configured_port} to ${active_port} with result=${res}\"}" ${DISCORD_WEBHOOK_URL} | |
else | |
echo "$(timestamp) | Port OK (Act: ${active_port} Cfg: ${configured_port})" | |
fi | |
return $res | |
} | |
public_ip= | |
configured_port= | |
active_port= | |
qbt_sid= | |
# Wait for a healthy state on the VPN container | |
check_vpn_ct_health | |
# check and possibly update the port | |
get_portmap | |
exit $? |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Modified/fixed to support Podman which does not expose the State.