Add ability to control Deluge's upload and download speeds based on Jellyfin streams.
This commit is contained in:
71
blueprints/pages/deluge.yml
Normal file
71
blueprints/pages/deluge.yml
Normal file
@@ -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
|
||||
135
controllers/deluge.php
Normal file
135
controllers/deluge.php
Normal file
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
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");
|
||||
};
|
||||
@@ -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" => [[
|
||||
|
||||
23
templates/deluge.php
Normal file
23
templates/deluge.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?= snippet("header") ?>
|
||||
|
||||
<?= snippet("page/title") ?>
|
||||
|
||||
<div class="container">
|
||||
<p><strong>Current Streams</strong>: <?= $page->currentStreams() ?></p>
|
||||
<?php if ($page->currentStreams()->toInt() > 0) : ?>
|
||||
<p><strong>Last Seen</strong>: <?= date('l \t\h\e\ jS \of F Y \a\t g:ia', $page->lastSeen()->toInt()) ?></p>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="d-grid gap-2 col-6 mx-auto">
|
||||
<a class="btn btn-primary" href="?s=update" role="button">Update</a>
|
||||
<a class="btn btn-warning" href="?s=reset" role="button">Reset</a>
|
||||
</div>
|
||||
<div class="d-grid gap-2 col-6 mx-auto">
|
||||
<a class="btn btn-danger" href="?s=inc" role="button">Increment Streams</a>
|
||||
<a class="btn btn-danger" href="?s=dec" role="button">Decrement Streams</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= snippet("footer") ?>
|
||||
Reference in New Issue
Block a user