diff --git a/blueprints/pages/deluge.yml b/blueprints/pages/deluge.yml new file mode 100644 index 0000000..c3d92fb --- /dev/null +++ b/blueprints/pages/deluge.yml @@ -0,0 +1,71 @@ +title: Deluge Bridge + +sections: + deluge: + type: fields + fields: + delugeUrl: + label: Deluge URL + type: url + width: 1/2 + delugePassword: + label: Deluge Password + type: text + width: 1/2 + minDownSpeed: + label: Minimum Download Speed + type: number + min: 0 + default: 4096 + after: KiB/s + width: 1/2 + maxDownSpeed: + label: Maximum Download Speed + type: number + min: 0 + default: 10240 + after: KiB/s + width: 1/2 + minUpSpeed: + label: Minimum Upload Speed + type: number + min: 0 + default: 512 + after: KiB/s + width: 1/2 + maxUpSpeed: + label: Maximum Upload Speed + type: number + min: 0 + default: 4096 + after: KiB/s + width: 1/2 + maxTimeAtMin: + label: Maximum Time At Minimum Speed + type: number + min: 0 + default: 240 + after: minutes + jellyfin: + type: fields + fields: + jellyfinUrl: + label: Jellyfin URL + type: url + width: 1/2 + jellyfinApiKey: + label: Jellyfin API Key + type: text + width: 1/2 + currentStreams: + label: Current Streams + type: number + min: 0 + default: 0 + width: 1/2 + lastSeen: + label: Last Seen Stream + type: number + min: 0 + default: 0 + width: 1/2 diff --git a/controllers/deluge.php b/controllers/deluge.php new file mode 100644 index 0000000..dfa6e5e --- /dev/null +++ b/controllers/deluge.php @@ -0,0 +1,147 @@ + + * + * This file is part of Kirby Deluge. + * + * Kirby Deluge is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation. + * + * Kirby Deluge is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License along with Kirby Deluge. If not, see . + */ + +return function ($page) { + $currentStreams = $page->currentStreams()->toInt(); + $lastSeen = $page->lastSeen()->toInt(); + + $curl = curl_init($page->delugeUrl()); + $curlOptions = [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HEADER => true, + CURLOPT_HTTPHEADER => ["Accept: application/json", "Content-Type: application/json"], + CURLOPT_ENCODING => "", + CURLOPT_COOKIEJAR => "", + CURLOPT_CONNECTTIMEOUT => 10, + CURLOPT_TIMEOUT => 10, + CURLOPT_SSL_VERIFYPEER => true, + CURLINFO_HEADER_OUT => true, + ]; + curl_setopt_array($curl, $curlOptions); + + $reqId = 0; + $response = site()->makeRequest($curl, $reqId, "auth.login", [$page->delugePassword()->toString()]); + $reqId++; + + if (get("s") == "inc") { + // Increment number of streams and ensure speeds are set to minimums. + $currentStreams++; + $lastSeen = time(); + + site()->makeRequest($curl, $reqId, "core.set_config", [["max_download_speed" => $page->minDownSpeed()->toInt()]]); + $reqId++; + site()->makeRequest($curl, $reqId, "core.set_config", [["max_upload_speed" => $page->minUpSpeed()->toInt()]]); + } elseif (get("s") == "dec") { + // Decrement number of streams and, if 0 active streams, ensure speeds are set to maximum. + $currentStreams--; + + if ($lastSeen > 0) { + if ($lastSeen < time() - ($page->maxTimeAtMin()->toInt() * 60)) { + // Assume the sessions have finished and clear them. + $currentStreams = 0; + $lastSeen = 0; + } + } + + if ($currentStreams <= 0) { + site()->makeRequest($curl, $reqId, "core.set_config", [["max_download_speed" => $page->maxDownSpeed()->toInt()]]); + $reqId++; + site()->makeRequest($curl, $reqId, "core.set_config", [["max_upload_speed" => $page->maxUpSpeed()->toInt()]]); + } + } elseif (get("s") == "reset") { + // Reset streams and speeds back to 0 and maximum respectively. + $currentStreams = 0; + $lastSeen = 0; + + site()->makeRequest($curl, $reqId, "core.set_config", [["max_download_speed" => $page->maxDownSpeed()->toInt()]]); + $reqId++; + site()->makeRequest($curl, $reqId, "core.set_config", [["max_upload_speed" => $page->maxUpSpeed()->toInt()]]); + } elseif (get("s") == "update") { + // Forceably get a list of active sessions from Jellyfin and update Deluge accordingly. + $jfCurl = curl_init($page->jellyfinUrl()->toString() . "/Sessions"); + $jfCurlOptions = [ + CURLOPT_RETURNTRANSFER => true, + // CURLOPT_HEADER => true, + CURLOPT_HTTPHEADER => ["Accept: application/json", "Content-Type: application/json", "Authorization: MediaBrowser Token=\"{$page->jellyfinApiKey()->toString()}\""], + CURLOPT_ENCODING => "", + CURLOPT_COOKIEJAR => "", + CURLOPT_CONNECTTIMEOUT => 10, + CURLOPT_TIMEOUT => 10, + CURLOPT_SSL_VERIFYPEER => true, + CURLINFO_HEADER_OUT => true, + CURLOPT_VERBOSE => true, + ]; + curl_setopt_array($jfCurl, $jfCurlOptions); + + $sessions = site()->makeRequest($jfCurl, $reqId, "get"); + $reqId++; + curl_close($jfCurl); + + $sessionsActive = 0; + if (!is_null($sessions)) { + foreach ($sessions as $session) { + if (isset($session["NowPlayingItem"])) { + if ($session["NowPlayingItem"]["Type"] !== "Audio") { + $sessionsActive++; + } + } + } + + if ($sessionsActive == 0) { + // There are no sessions active. Set to maximum speed. + $currentStreams = 0; + $lastSeen = 0; + + site()->makeRequest($curl, $reqId, "core.set_config", [["max_download_speed" => $page->maxDownSpeed()->toInt()]]); + $reqId++; + site()->makeRequest($curl, $reqId, "core.set_config", [["max_upload_speed" => $page->maxUpSpeed()->toInt()]]); + } else { + // There are sessions active. Set to minimum speed. + $currentStreams = $sessionsActive; + $lastSeen = time(); + + site()->makeRequest($curl, $reqId, "core.set_config", [["max_download_speed" => $page->minDownSpeed()->toInt()]]); + $reqId++; + site()->makeRequest($curl, $reqId, "core.set_config", [["max_upload_speed" => $page->minUpSpeed()->toInt()]]); + } + } else { + // We couldn't access Jellyfin. Assume there's something wrong and that no sessions are active. + $currentStreams = 0; + $lastSeen = 0; + + site()->makeRequest($curl, $reqId, "core.set_config", [["max_download_speed" => $page->maxDownSpeed()->toInt()]]); + $reqId++; + site()->makeRequest($curl, $reqId, "core.set_config", [["max_upload_speed" => $page->maxUpSpeed()->toInt()]]); + } + } + + // We should never have less than 0 streams active. + $currentStreams = $currentStreams < 0 ? 0 : $currentStreams; + + $page = kirby()->impersonate("kirby", function () use ($page, $currentStreams, $lastSeen) { + return $page->update([ + "currentStreams" => $currentStreams, + "lastSeen" => $lastSeen, + ]); + }); + + curl_close($curl); + + if (!($user = kirby()->user() and $user->role()->isAdmin())) { + // Limit access to page to administrators only. + echo new Response(Data::encode(["currentStreams" => $currentStreams, "lastSeen" => $lastSeen], "json"), "text/json"); + exit(); + } + + return compact("page"); +}; diff --git a/index.php b/index.php index 7b5959b..5c280e5 100644 --- a/index.php +++ b/index.php @@ -14,6 +14,15 @@ Kirby::plugin( name: "hobbyhome/deluge", extends: [ + "blueprints" => [ + "pages/deluge" => __DIR__ . "/blueprints/pages/deluge.yml", + ], + "templates" => [ + "deluge" => __DIR__ . "/templates/deluge.php", + ], + "controllers" => [ + "deluge" => require __DIR__ . "/controllers/deluge.php", + ], ], info: [ "authors" => [[ diff --git a/templates/deluge.php b/templates/deluge.php new file mode 100644 index 0000000..1073e51 --- /dev/null +++ b/templates/deluge.php @@ -0,0 +1,23 @@ + + + + +
+

Current Streams: currentStreams() ?>

+ currentStreams()->toInt() > 0) : ?> +

Last Seen: lastSeen()->toInt()) ?>

+ +
+ +
+
+ Update + Reset +
+ +
+ +