including some more dashboard components

This commit is contained in:
2026-03-05 06:34:27 +01:00
parent f03ec900c6
commit 7d8c36a771
57 changed files with 1694 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
APP_NAME=Heimdall
APP_ENV=local
APP_KEY=base64:iovIUyf+fbX/1gbhrxHIr/58SLI1F3u/GGVd60r4WpQ=
APP_DEBUG=false
APP_URL=http://localhost
APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US
APP_MAINTENANCE_DRIVER=file
APP_MAINTENANCE_STORE=database
BCRYPT_ROUNDS=12
LOG_CHANNEL=daily
LOG_STACK=single
DB_CONNECTION=sqlite
DB_DATABASE=app.sqlite
#DB_CONNECTION=<mysql | pgsql>
#DB_HOST=<hostname | ip>
#DB_PORT=<port number>
#DB_DATABASE=<database>
#DB_USERNAME=<user>
#DB_PASSWORD=<password>
BROADCAST_CONNECTION=log
CACHE_STORE=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null
QUEUE_DRIVER=database
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
AUTH_ROLES_ENABLE=false
AUTH_ROLES_HEADER="remote-groups"
AUTH_ROLES_HTTP_HEADER="HTTP_REMOTE_GROUPS"
AUTH_ROLES_ADMIN="admin"
AUTH_ROLES_DELIMITER=","
ALLOW_INTERNAL_REQUESTS=false

View File

@@ -0,0 +1,83 @@
<?php
namespace App\SupportedApps\Bookstack;
class Bookstack extends \App\SupportedApps implements \App\EnhancedApps
{
public $config;
//protected $login_first = true; // Uncomment if api requests need to be authed first
//protected $method = 'POST'; // Uncomment if requests to the API should be set by POST
public function __construct()
{
//$this->jar = new \GuzzleHttp\Cookie\CookieJar; // Uncomment if cookies need to be set
}
public function getHeaders()
{
$api_token = $this->config->api_token . ":" . $this->config->api_secret;
$attrs["headers"] = ["Authorization" => "Token " . $api_token];
return $attrs;
}
public function test()
{
$test = parent::appTest(
$this->url("api/shelves?count=0"),
$this->getHeaders()
);
echo $test->status;
}
public function livestats()
{
$status = "inactive";
$attrs = $this->getHeaders();
$data = ["visiblestats" => []];
foreach ($this->config->availablestats as $stat) {
if (!isset(self::getAvailableStats()[$stat])) {
continue;
}
$res = parent::execute(
$this->url("api/" . $stat . "?count=0"),
$attrs
);
$details = json_decode($res->getBody());
$newstat = new \stdClass();
$newstat->title = self::getAvailableStats()[$stat];
$newstat->value = isset($details->total)
? number_format($details->total)
: "N/A";
$data["visiblestats"][] = $newstat;
}
return parent::getLiveStats($status, $data);
}
public function url($endpoint)
{
$api_url =
rtrim(parent::normaliseurl($this->config->url), "/") .
"/" .
ltrim($endpoint, "/");
return $api_url;
}
public static function getAvailableStats()
{
return [
"shelves" => "Shelves",
"books" => "Books",
"chapters" => "Chapters",
"pages" => "Pages",
];
}
}

View File

@@ -0,0 +1,10 @@
{
"appid": "348c49dd03dddd418929316668d2e67bf2d9ae88",
"name": "Bookstack",
"website": "https://www.bookstackapp.com",
"license": "MIT License",
"description": "BookStack is a simple, self-hosted, easy-to-use platform for organising and storing information.",
"enhanced": true,
"tile_background": "dark",
"icon": "bookstack.svg"
}

View File

@@ -0,0 +1,22 @@
<h2>{{ __('app.apps.config') }} ({{ __('app.optional') }}) @include('items.enable')</h2>
<div class="items">
<div class="input">
<label>{{ strtoupper(__('app.url')) }}</label>
{!! Form::text('config[override_url]', isset($item) ? $item->getConfig()->override_url ?? null : null, ['placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control']) !!}
</div>
<div class="input">
<label>Token ID</label>
{!! Form::text('config[api_token]', isset($item) ? $item->getconfig()->api_token : null, ['placeholder' => 'Token ID', 'data-config' => 'api_token', 'class' => 'form-control config-item']) !!}
</div>
<div class="input">
<label>Token Secret</label>
{!! Form::text('config[api_secret]', isset($item) ? $item->getconfig()->api_secret : null, ['placeholder' => 'Token Secret', 'data-config' => 'api_secret', 'class' => 'form-control config-item']) !!}
</div>
<div class="input">
<label>Stats to show</label>
{!! Form::select('config[availablestats][]', App\SupportedApps\Bookstack\Bookstack::getAvailableStats(), isset($item) ? $item->getConfig()->availablestats ?? null : null, ['multiple' => 'multiple']) !!}
</div>
<div class="input">
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
</div>
</div>

View File

@@ -0,0 +1,8 @@
<ul class="livestats">
@foreach ($visiblestats as $stat)
<li>
<span class="title">{!! $stat->title !!}</span>
<strong>{!! $stat->value !!}</strong>
</li>
@endforeach
</ul>

View File

@@ -0,0 +1,7 @@
<?php
namespace App\SupportedApps\Dockge;
class Dockge extends \App\SupportedApps
{
}

View File

@@ -0,0 +1,10 @@
{
"appid": "0bafb882c9d2c034ca5333367f8ccc90f4ae85e4",
"name": "Dockge",
"website": "https://github.com/louislam/dockge",
"license": "MIT License",
"description": "A fancy, easy-to-use and reactive self-hosted docker compose.yaml stack-oriented manager.",
"enhanced": false,
"tile_background": "dark",
"icon": "dockge.svg"
}

View File

@@ -0,0 +1,7 @@
<?php
namespace App\SupportedApps\Dozzle;
class Dozzle extends \App\SupportedApps
{
}

View File

@@ -0,0 +1,10 @@
{
"appid": "176d99d897dbd7c02b1a1db4142054f74a76aa47",
"name": "Dozzle",
"website": "https://dozzle.dev",
"license": "MIT License",
"description": "Dozzle is a real-time log viewer for docker containers.",
"enhanced": false,
"tile_background": "dark",
"icon": "dozzle.svg"
}

View File

@@ -0,0 +1,101 @@
<?php
namespace App\SupportedApps\FileBrowser;
class FileBrowser extends \App\SupportedApps implements \App\EnhancedApps
{
public $config;
//protected $login_first = true; // Uncomment if api requests need to be authed first
//protected $method = 'POST'; // Uncomment if requests to the API should be set by POST
public function __construct()
{
//$this->jar = new \GuzzleHttp\Cookie\CookieJar; // Uncomment if cookies need to be set
}
private function getToken()
{
$username = $this->config->username;
$password = $this->config->password;
$authHeader = $this->config->authHeader;
$attrs = [
"headers" => [
"Content-Type" => "application/json"
],
"body" => json_encode([
"username" => $username,
"password" => $password
])
];
if ($authHeader !== null) {
$attrs["headers"][$authHeader] = $username;
}
$res = parent::execute($this->url("api/login"), $attrs, null, "POST");
switch ($res->getStatusCode()) {
case 200:
return $res->getBody()->getContents();
case 403:
throw new \Exception("Invalid username/password");
default:
throw new \Exception("Could not connect to FileBrowser");
}
}
private function formatBytes($bytes, $precision = 2) {
$units = array('B', 'KB', 'MB', 'GB', 'TB');
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);
$bytes /= pow(1024, $pow);
$value = round($bytes, $precision);
$unit = $units[$pow];
return [
"value" => $value,
"unit" => $unit
];
}
public function test()
{
try {
$token = $this->getToken();
echo "Successfully communicated with the API";
} catch (Exception $err) {
echo $err->getMessage();
}
}
public function livestats()
{
$status = "inactive";
$token = $this->getToken();
$attrs = [
"headers" => [
"X-AUTH" => $token
],
];
$res = parent::execute($this->url("api/usage"), $attrs);
$details = json_decode($res->getBody());
if ($details != null) {
$data["used"] = $this->formatBytes($details->used);
$data["total"] = $this->formatBytes($details->total);
}
return parent::getLiveStats($status, $data);
}
public function url($endpoint)
{
$api_url = parent::normaliseurl($this->config->url) . $endpoint;
return $api_url;
}
}

View File

@@ -0,0 +1,10 @@
{
"appid": "ba05dd8e070851895ee6184eb9778cfa0753a490",
"name": "FileBrowser",
"website": "https://github.com/filebrowser/filebrowser",
"license": "Apache License 2.0",
"description": "filebrowser provides a file managing interface within a specified directory and it can be used to upload, delete, preview, rename and edit your files. It allows the creation of multiple users and each user can have its own directory. It can be used as a standalone app or as a middleware.",
"enhanced": true,
"tile_background": "dark",
"icon": "filebrowser.svg"
}

View File

@@ -0,0 +1,29 @@
<h2>{{ __('app.apps.config') }} ({{ __('app.optional') }}) @include('items.enable')</h2>
<div class="items" style="flex-direction:column">
<div style="display:flex;flex-direction:row;">
<div class="input">
<label>{{ strtoupper(__('app.url')) }}</label>
{!! Form::text('config[override_url]', isset($item) ? $item->getconfig()->override_url : null, ['placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control']) !!}
</div>
</div>
<div style="display:flex;flex-direction:row;">
<div class="input">
<label>{{ __('app.apps.username') }}</label>
{!! Form::text('config[username]', isset($item) ? $item->getconfig()->username : null, ['placeholder' => __('app.apps.username'), 'data-config' => 'username', 'class' => 'form-control config-item']) !!}
</div>
<div class="input">
<label>{{ __('app.apps.password') }}</label>
{!! Form::input('password', 'config[password]', '', ['placeholder' => __('app.apps.password'), 'data-config' => 'password', 'class' => 'form-control config-item']) !!}
</div>
</div>
<div style="display:flex;flex-direction:row;">
<div class="input">
<label>Proxy Header (<a href="https://filebrowser.org/configuration/authentication-method#proxy-header" target="_blank">help?</a>)</label>
{!! Form::text('config[authHeader]', isset($item) ? $item->getconfig()->authHeader : null, ['placeholder' => 'X-My-Header', 'data-config' => 'authHeader', 'class' => 'form-control config-item']) !!}
<small>Also fill {{ __('app.apps.username') }}</small>
</div>
</div>
<div class="input">
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
</div>
</div>

View File

@@ -0,0 +1,10 @@
<ul class="livestats">
<li>
<span class="title">Used</span>
<strong>{!! $used["value"] !!}<span>{!! $used["unit"] !!}</span></strong>
</li>
<li>
<span class="title">Total</span>
<strong>{!! $total["value"] !!}<span>{!! $total["unit"] !!}</span></strong>
</li>
</ul>

View File

@@ -0,0 +1,7 @@
<?php
namespace App\SupportedApps\ITTools;
class ITTools extends \App\SupportedApps
{
}

View File

@@ -0,0 +1,10 @@
{
"appid": "b5f16344632fdfe68391a2dc3816ee0edbb1813c",
"name": "IT-Tools",
"website": "https://it-tools.tech/",
"license": "GNU General Public License v3.0 only",
"description": "Useful tools for developer and people working in IT.",
"enhanced": false,
"tile_background": "light",
"icon": "ittools.png"
}

View File

@@ -0,0 +1,7 @@
<?php
namespace App\SupportedApps\JDownloader;
class JDownloader extends \App\SupportedApps
{
}

View File

@@ -0,0 +1,10 @@
{
"appid": "af7b37e2841d9150f6abd5a936b32a1f681d6bda",
"name": "JDownloader",
"website": "http://jdownloader.org",
"license": "Creative Commons Attribution Non Commercial Share Alike 2.0 Generic",
"description": "JDownloader is a free, open-source download management tool with a huge community of developers that makes downloading as easy and fast as it should be.",
"enhanced": false,
"tile_background": "dark",
"icon": "jdownloader.png"
}

View File

@@ -0,0 +1,71 @@
<?php
namespace App\SupportedApps\Jellyfin;
class Jellyfin extends \App\SupportedApps implements \App\EnhancedApps
{
public $config;
public function __construct()
{
}
public function test()
{
$test = parent::appTest(
$this->url("System/Info"),
$this->getAttrs()
);
echo $test->status;
}
public function livestats()
{
$status = "inactive";
$res = parent::execute($this->url("Items/Counts"), $this->getAttrs());
$result = json_decode($res->getBody());
$details = ["visiblestats" => []];
foreach ($this->config->availablestats as $stat) {
$newstat = new \stdClass();
$newstat->title = self::getAvailableStats()[$stat];
$newstat->value = $result->{$stat};
$details["visiblestats"][] = $newstat;
}
return parent::getLiveStats($status, $details);
}
public function url($endpoint)
{
$api_url = parent::normaliseurl($this->config->url) . $endpoint;
return $api_url;
}
private function getAttrs()
{
$authorizationHeader = "MediaBrowser " .
"Token=\"" . urlencode($this->config->password) . "\", " .
"Client=\"Heimdall\"";
return [
"headers" => [
"Authorization" => $authorizationHeader,
],
];
}
public static function getAvailableStats()
{
return [
"MovieCount" => "Movies",
"SeriesCount" => "Series",
"EpisodeCount" => "Episodes",
"ArtistCount" => "Artists",
"ProgramCount" => "Programs",
"TrailerCount" => "Trailers",
"SongCount" => "Songs",
"AlbumCount" => "Albums",
"MusicVideoCount" => "MusicVideos",
"BoxSetCount" => "BoxSets",
"BookCount" => "Books",
"ItemCount" => "Items",
];
}
}

View File

@@ -0,0 +1,10 @@
{
"appid": "3e0a7f109bd760b9474c78cb652e8c3e82669226",
"name": "Jellyfin",
"website": "https://jellyfin.github.io",
"license": "GNU General Public License v2.0 only",
"description": "Jellyfin is the Free Software Media System that puts you in control of managing and streaming your media. There are no strings attached, no premium licenses or features, and no hidden agendas.",
"enhanced": true,
"tile_background": "dark",
"icon": "jellyfin.svg"
}

View File

@@ -0,0 +1,18 @@
<h2>{{ __('app.apps.config') }} ({{ __('app.optional') }}) @include('items.enable')</h2>
<div class="items">
<div class="input">
<label>{{ strtoupper(__('app.url')) }}</label>
{!! Form::text('config[override_url]', isset($item) ? $item->getconfig()->override_url : null, ['placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control']) !!}
</div>
<div class="input">
<label>{{ __('app.apps.password') }} (secret token)</label>
{!! Form::input('password', 'config[password]', '', ['placeholder' => __('app.apps.password'), 'data-config' => 'password', 'class' => 'form-control config-item']) !!}
</div>
<div class="input">
<label>Stats to show</label>
{!! Form::select('config[availablestats][]', App\SupportedApps\Jellyfin\Jellyfin::getAvailableStats(), isset($item) ? $item->getConfig()->availablestats ?? null : null, ['multiple' => 'multiple']) !!}
</div>
<div class="input">
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
</div>
</div>

View File

@@ -0,0 +1,8 @@
<ul class="livestats">
@foreach ($visiblestats as $stat)
<li>
<span class="title">{!! $stat->title !!}</span>
<strong>{!! $stat->value !!}</strong>
</li>
@endforeach
</ul>

View File

@@ -0,0 +1,61 @@
<?php
namespace App\SupportedApps\NginxProxyManager;
class NginxProxyManager extends \App\SupportedApps implements \App\EnhancedApps
{
public $config;
//protected $login_first = true; // Uncomment if api requests need to be authed first
//protected $method = 'POST'; // Uncomment if requests to the API should be set by POST
public function __construct()
{
//$this->jar = new \GuzzleHttp\Cookie\CookieJar; // Uncomment if cookies need to be set
}
public function test()
{
$test = parent::appTest($this->url("api"));
echo $test->status;
}
public function livestats()
{
$status = "inactive";
$auth_attrs = [
"headers" => [
"Accept" => "application/json",
"Content-Type" => "application/json",
],
"body" => json_encode([
"identity" => $this->config->email,
"secret" => $this->config->password,
]),
];
$auth_res = parent::execute(
$this->url("api/tokens"),
$auth_attrs,
null,
"POST"
);
$auth_data = json_decode($auth_res->getBody(), true);
$token = $auth_data["token"];
$attrs = [
"headers" => [
"Accept" => "application/json",
"Authorization" => "Bearer " . $token,
],
];
$res = parent::execute($this->url("api/reports/hosts"), $attrs);
$data = json_decode($res->getBody(), true);
return parent::getLiveStats($status, $data);
}
public function url($endpoint)
{
$api_url = parent::normaliseurl($this->config->url) . $endpoint;
return $api_url;
}
}

View File

@@ -0,0 +1,10 @@
{
"appid": "cbfad988a16a9fbcc1812bc206afcc1f73dd36de",
"name": "Nginx Proxy Manager",
"website": "https://nginxproxymanager.jc21.com",
"license": "MIT License",
"description": "This project comes as a pre-built docker image that enables you to easily forward to your websites running at home or otherwise, including free SSL, without having to know too much about Nginx or Letsencrypt.",
"enhanced": true,
"tile_background": "light",
"icon": "nginxproxymanager.png"
}

View File

@@ -0,0 +1,18 @@
<h2>{{ __('app.apps.config') }} ({{ __('app.optional') }}) @include('items.enable')</h2>
<div class="items">
<div class="input">
<label>{{ strtoupper(__('app.url')) }}</label>
{!! Form::text('config[override_url]', isset($item) ? $item->getconfig()->override_url : null, ['placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control']) !!}
</div>
<div class="input">
<label>Email address</label>
{!! Form::text('config[email]', isset($item) ? $item->getconfig()->email : null, ['placeholder' => __('Email address'), 'data-config' => 'email', 'class' => 'form-control config-item']) !!}
</div>
<div class="input">
<label>{{ __('app.apps.password') }}</label>
{!! Form::input('password', 'config[password]', '', ['placeholder' => __('app.apps.password'), 'data-config' => 'password', 'class' => 'form-control config-item']) !!}
</div>
<div class="input">
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
</div>
</div>

View File

@@ -0,0 +1,10 @@
<ul class="livestats">
<li>
<span class="title">Proxy Hosts</span>
<strong>{!! $proxy !!}</strong>
</li>
<li>
<span class="title">Redirection Hosts</span>
<strong>{!! $redirection !!}</strong>
</li>
</ul>

View File

@@ -0,0 +1,7 @@
<?php
namespace App\SupportedApps\OnlyOffice;
class OnlyOffice extends \App\SupportedApps
{
}

View File

@@ -0,0 +1,10 @@
{
"appid": "fc4e407d69510b855b678aa4fba6083fbbfc5383",
"name": "OnlyOffice",
"website": "https://www.onlyoffice.com",
"license": "GNU Affero General Public License v3.0 or later",
"description": "ONLYOFFICE online editors for text documents, spreadsheets, and presentations with access to pro features and connect them to the platform of your choice with ready-to-use connectors: https://www.onlyoffice.com/download.aspx#connectors",
"enhanced": false,
"tile_background": "light",
"icon": "onlyoffice.png"
}

View File

@@ -0,0 +1,184 @@
<?php
namespace App\SupportedApps\Pihole;
use Illuminate\Support\Facades\Log;
class Pihole extends \App\SupportedApps implements \App\EnhancedApps
{
public $config;
//protected $login_first = true; // Uncomment if api requests need to be authed first
//protected $method = 'POST'; // Uncomment if requests to the API should be set by POST
public function __construct()
{
$this->jar = new \GuzzleHttp\Cookie\CookieJar(); // Uncomment if cookies need to be set
}
public function test()
{
$version = $this->config->version;
if ($version == 5) {
$test = parent::appTest($this->url("api.php?summaryRaw"));
echo $test->status;
}
if ($version == 6) {
$test = $this->getInfo();
if ($test["valid"]) {
echo "Successfully communicated with the API";
} else {
echo "Error while communicating with the API: " . $test["message"];
}
}
}
public function livestats()
{
$data = [];
$status = "inactive";
$version = $this->config->version;
if ($version == 5) {
$res = parent::execute($this->url("api.php?summaryRaw"));
$details = json_decode($res->getBody());
if ($details) {
$data["ads_blocked"] = number_format(
$details->ads_blocked_today
);
$data["ads_percentage"] = number_format(
$details->ads_percentage_today,
1
);
$status = "active";
}
}
if ($version == 6) {
$results = $this->getInfo();
if ($results["valid"]) {
$data["ads_blocked"] = $results["queries"];
$data["ads_percentage"] = $results["percent"];
$status = "active";
}
}
return parent::getLiveStats($status, $data);
}
public function url($endpoint)
{
$version = $this->config->version;
if ($version == 5) {
$apikey = $this->config->apikey;
$api_url = parent::normaliseurl($this->config->url) . $endpoint;
if ($apikey) {
$api_url .= "&auth=" . $apikey;
}
}
if ($version == 6) {
$api_url = parent::normaliseurl($this->config->url) . $endpoint;
}
return $api_url;
}
public function getInfo()
{
$ignoreTls = $this->getConfigValue("ignore_tls", false);
if ($ignoreTls) {
$attrs = [
"body" => json_encode(['password' => $this->config->apikey]),
"cookies" => $this->jar,
"verify" => false,
"headers" => [
"Content-Type" => "application/json",
"Accept" => "application/json",
],
];
$attrsid["verify"] = false;
} else {
$attrs = [
"body" => json_encode(['password' => $this->config->apikey]),
"cookies" => $this->jar,
"headers" => [
"Content-Type" => "application/json",
"Accept" => "application/json",
],
];
}
// Create session and retrieve data
$response = parent::execute($this->url("api/auth"), $attrs, null, "POST");
$auth = json_decode($response->getBody());
if (!$auth->session->valid) {
$data = [
'valid' => false,
'validity' => -1,
'message' => $auth->session->message,
'queries' => 0,
'percent' => 0
];
return $data;
}
if ($ignoreTls) {
$attrsid = [
"body" => json_encode(['sid' => $auth->session->sid]),
"cookies" => $this->jar,
"verify" => false,
"headers" => [
"Content-Type" => "application/json",
"Accept" => "application/json",
],
];
} else {
$attrsid = [
"body" => json_encode(['sid' => $auth->session->sid]),
"cookies" => $this->jar,
"headers" => [
"Content-Type" => "application/json",
"Accept" => "application/json",
],
];
}
// Get queries data
$responsesummary = parent::execute($this->url("api/stats/summary"), $attrsid, null, "GET");
$datasummary = json_decode($responsesummary->getBody());
// After retrieving the data the session is closed to declutter
parent::execute($this->url("api/auth"), $attrsid, null, "DELETE");
// Extract data from the response
$valid = $auth->session->valid;
$validity = $auth->session->validity;
$message = $auth->session->message;
if (!$auth->session->valid) {
$queriesblocked = 0;
$percentblocked = 0;
} else {
$queriesblocked = $datasummary->queries->blocked;
$percentblocked = round($datasummary->queries->percent_blocked, 2);
}
$data = [
'valid' => $valid,
'validity' => $validity,
'message' => $message,
'queries' => $queriesblocked,
'percent' => $percentblocked
];
return $data;
}
public function getConfigValue($key, $default = null)
{
return isset($this->config) && isset($this->config->$key)
? $this->config->$key
: $default;
}
}

View File

@@ -0,0 +1,10 @@
{
"appid": "b89920409bdce40e08ba1023480b0546061cd577",
"name": "Pi-hole",
"website": "https://pi-hole.net",
"license": "European Union Public License 1.2",
"description": "Pi-hole is a Linux network-level advertisement and internet tracker blocking application which acts as a DNS sinkhole, intended for use on a private network.",
"enhanced": true,
"tile_background": "dark",
"icon": "pihole.svg"
}

View File

@@ -0,0 +1,43 @@
<h2>{{ __('app.apps.config') }} ({{ __('app.optional') }}) @include('items.enable')</h2>
<div class="items">
<input type="hidden" data-config="dataonly" class="config-item" name="config[dataonly]" value="1" />
<div class="input">
<label>{{ strtoupper(__('app.url')) }}</label>
{!! Form::text('config[override_url]', isset($item) ? $item->getconfig()->override_url : null, ['placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control']) !!}
</div>
<div class="input">
<label>Api Key(v5)/App Password(v6)</label>
{!! Form::text('config[apikey]', isset($item) && property_exists($item->getconfig(), 'apikey') ? $item->getconfig()->apikey : null, ['placeholder' => __('app.apps.apikey'), 'data-config' => 'apikey', 'class' => 'form-control config-item']) !!}
</div>
<div class="items" style="max-width: 100px;">
<div class="input">
<label>Version</label>
{!! Form::select(
'config[version]',
['5' => 'v5', '6' => 'v6'],
isset($item) ? $item->getconfig()->version : null,
['data-config' => 'version', 'class' => 'form-control config-item'],
) !!}
</div>
</div>
<div class="input" style="max-width: 150px;">
<label>Skip TLS verification</label>
<div class="toggleinput" style="margin-top: 26px; padding-left: 15px;">
{!! Form::hidden('config[ignore_tls]', 0, ['class' => 'config-item', 'data-config' => 'ignore_tls']) !!}
<label class="switch">
<?php
$checked = false;
if (isset($item) && !empty($item) && isset($item->getconfig()->ignore_tls)) {
$checked = $item->getconfig()->ignore_tls;
}
$set_checked = $checked ? ' checked="checked"' : '';
?>
<input type="checkbox" class="config-item" data-config="ignore_tls" name="config[ignore_tls]" value="1" <?php echo $set_checked; ?> />
<span class="slider round"></span>
</label>
</div>
</div>
<div class="input">
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
</div>
</div>

View File

@@ -0,0 +1,10 @@
<ul class="livestats">
<li>
<span class="title">Queries<br />Blocked</span>
<strong>{!! $ads_blocked !!}</strong>
</li>
<li>
<span class="title">Percent<br /> Blocked</span>
<strong>{!! $ads_percentage !!}</strong>
</li>
</ul>

View File

@@ -0,0 +1,95 @@
<?php
namespace App\SupportedApps\UptimeKuma;
class UptimeKuma extends \App\SupportedApps implements \App\EnhancedApps
{
public $config;
private $mapping = [
0 => "down",
1 => "up",
2 => "pending",
3 => "maintenance",
];
public function __construct()
{
}
private function getAttrs()
{
if (empty($this->config->apikey)) {
return [];
}
$basicAuthValue = base64_encode(":" . $this->config->apikey);
return [
"headers" => [
"Authorization" => "Basic " . $basicAuthValue,
]
];
}
public function test()
{
$test = parent::appTest($this->url("metrics"), $this->getAttrs());
echo $test->status;
}
public function livestats()
{
$status = "inactive";
$response = parent::execute($this->url("metrics"), $this->getAttrs());
$body = $response->getBody();
$lines = explode("\n", $body);
$data = [
"up" => 0,
"down" => 0,
"pending" => 0,
"maintenance" => 0,
"unknown" => 0,
];
foreach ($lines as $line) {
if (strlen($line) === 0 || strpos($line, '#') === 0) {
// If the line is empty or is a comment we can skip it
continue;
}
if (strpos($line, 'monitor_status') !== 0) {
// If the line is a metric but not a monitor we can ignore it
continue;
}
// We only really care about the state, which is the integer at the end
// of the line.
//
// This can be 0 (Down), 1 (Up), 2 (Pending), 3 (Maintenance)
//
// We only care about the down or up but let's translate all of them.
$state = intval(substr($line, strrpos($line, ' ')));
$data[$this->mapping[$state] ?? 'unknown']++;
}
if ($data["down"] > 0) {
$status = "active";
}
return parent::getLiveStats($status, $data);
}
public function url($endpoint)
{
$api_url = parent::normaliseurl($this->config->url) .
$endpoint;
return $api_url;
}
}

View File

@@ -0,0 +1,10 @@
{
"appid": "366c6646eedab83cc4b349f198424d2291cbfa76",
"name": "Uptime Kuma",
"website": "https://uptime.kuma.pet",
"license": "MIT License",
"description": "It is a self-hosted monitoring tool like \"Uptime Robot\".",
"enhanced": true,
"tile_background": "dark",
"icon": "uptimekuma.svg"
}

View File

@@ -0,0 +1,32 @@
<h2>{{ __('app.apps.config') }} ({{ __('app.optional') }}) @include('items.enable')</h2>
<div class="items">
<input type="hidden" data-config="dataonly" class="config-item" name="config[dataonly]" value="1" />
<div class="input">
<label>{{ strtoupper(__('app.url')) }}</label>
{!! Form::text('config[override_url]', isset($item) ? $item->getconfig()->override_url : null, ['placeholder' => __('app.apps.override'), 'id' => 'override_url', 'class' => 'form-control']) !!}
</div>
<div class="input">
<label>{{ __('app.apps.apikey') }}</label>
{!! Form::text('config[apikey]', isset($item) ? ($item->getconfig()->apikey ?? null) : null, ['placeholder' => __('app.apps.apikey'), 'data-config' => 'apikey', 'class' => 'form-control config-item']) !!}
</div>
<div class="input">
<label>Skip TLS verification</label>
<div class="toggleinput" style="margin-top: 26px; padding-left: 15px;">
{!! Form::hidden('config[ignore_tls]', 0, ['class' => 'config-item', 'data-config' => 'ignore_tls']) !!}
<label class="switch">
<?php
$checked = false;
if (isset($item) && !empty($item) && isset($item->getconfig()->ignore_tls)) {
$checked = $item->getconfig()->ignore_tls;
}
$set_checked = $checked ? ' checked="checked"' : '';
?>
<input type="checkbox" class="config-item" data-config="ignore_tls" name="config[ignore_tls]" value="1" <?php echo $set_checked; ?> />
<span class="slider round"></span>
</label>
</div>
</div>
<div class="input">
<button style="margin-top: 32px;" class="btn test" id="test_config">Test</button>
</div>
</div>

View File

@@ -0,0 +1,10 @@
<ul class="livestats">
<li>
<span class="title">Up</span>
<strong>{!! $up ?? 0 !!}</strong>
</li>
<li>
<span class="title">Down</span>
<strong>{!! $down ?? 0 !!}</strong>
</li>
</ul>

View File

@@ -0,0 +1,7 @@
<?php
namespace App\SupportedApps\Vaultwarden;
class Vaultwarden extends \App\SupportedApps
{
}

View File

@@ -0,0 +1,10 @@
{
"appid": "ddf4f264320af1347ef54d424c60fae3b4fcc448",
"name": "Vaultwarden",
"website": "https://github.com/dani-garcia/vaultwarden",
"license": "GNU Affero General Public License v3.0",
"description": "Alternative implementation of the Bitwarden server API written in Rust and compatible with upstream Bitwarden clients*, perfect for self-hosted deployment where running the official resource-heavy service might not be ideal.",
"enhanced": false,
"tile_background": "light",
"icon": "vaultwarden.png"
}

View File

@@ -0,0 +1,7 @@
<?php
namespace App\SupportedApps\WireGuard;
class WireGuard extends \App\SupportedApps
{
}

View File

@@ -0,0 +1,10 @@
{
"appid": "afef2217e82ee20638490bb102605f6e09789093",
"name": "WireGuard",
"website": "https://www.wireguard.com",
"license": "CNRI Python Open Source GPL Compatible License Agreement",
"description": "WireGuard® is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPsec, while avoiding the massive headache. It intends to be considerably more performant than OpenVPN. WireGuard is designed as a general purpose VPN for running on embedded interfaces and super computers alike, fit for many different circumstances. Initially released for the Linux kernel, it is now cross-platform (Windows, macOS, BSD, iOS, Android) and widely deployable. It is currently under heavy development, but already it might be regarded as the most secure, easiest to use, and simplest VPN solution in the industry.",
"enhanced": false,
"tile_background": "dark",
"icon": "wireguard.png"
}

View File

@@ -0,0 +1,10 @@
{
"appid": "668b5fcda851fe516fef14e82973beffe32f385a",
"name": "ownCloud",
"website": "https://owncloud.org",
"license": "GNU Affero General Public License v3.0 or later",
"description": "ownCloud is a free and open source file hosting service. It also supports extensions for online document editing, calendar and contact synchronization. It's a safe home for all your data.",
"enhanced": false,
"tile_background": "dark",
"icon": "owncloud.png"
}

View File

@@ -0,0 +1,7 @@
<?php
namespace App\SupportedApps\ownCloud;
class ownCloud extends \App\SupportedApps // phpcs:ignore
{
}

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 230.397 218.62">
<g fill="#fff" fill-rule="evenodd" stroke="#0288d1" stroke-linejoin="round" stroke-width="6">
<g stroke-linecap="round">
<path d="m98.52 180.166 128.88-74.409-92.058-53.15-128.88 74.409z"></path>
<path d="M6.46 127.016v21.26l92.058 53.15 128.88-74.409v-21.26"></path>
<path d="m98.52 215.596-92.058-53.15s-7.5-16.918 0-28.346l92.058 53.15 128.88-74.409v28.346L98.52 215.596"></path>
<path d="m98.52 130.556 128.88-74.41L135.34 3 6.46 77.406z"></path>
<path d="M98.52 130.556 227.4 56.147v28.346L98.52 158.902l-92.058-53.15s-6.071-17.632 0-28.346z"></path>
<path d="m98.52 187.256-92.058-53.15s-7.5-16.918 0-28.346l92.058 53.15L227.4 84.501v28.346L98.52 187.256"></path>
</g>
<path d="m156.82 15.402-55.234 31.89 21.48 1.772 3.069 12.402 55.235-31.89z"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 933 B

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640">
<g transform="translate(320 325.566) scale(.9545)">
<linearGradient id="a" x1="259.78" x2="463.85" y1="261.15" y2="456.49" gradientTransform="translate(-236.647 -213.944)" gradientUnits="userSpaceOnUse">
<stop offset="0%" style="stop-color:#74c2ff;stop-opacity:1"></stop>
<stop offset="100%" style="stop-color:#86e6a9;stop-opacity:1"></stop>
</linearGradient>
<path stroke-linecap="round" d="M131.867-139.049c27.143 27.84 38.257 39.595 71.251 87.328 32.995 47.734 61.323 135.705-15.778 195.772-9.613 7.489-20.602 14.76-32.68 21.607-84.805 48.066-223.333 75.128-316.453 8.625-106.383-75.974-98.31-242.949 17.442-344.789 115.752-101.84 249.074 3.618 276.217 31.457z" style="stroke:#f2f2f2;stroke-opacity:.51;stroke-width:190;stroke-dasharray:none;stroke-linecap:butt;stroke-dashoffset:0;stroke-linejoin:miter;stroke-miterlimit:4;fill:url(#a);fill-rule:nonzero;opacity:1"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1019 B

View File

@@ -0,0 +1,142 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.2" viewBox="0 0 1024 1024">
<defs>
<clipPath id="cp1">
<path d="M1115.21-134.62v1241.33H-126.37V-134.62z"></path>
</clipPath>
</defs>
<style>.d{fill:#eb8b00}.h{fill:#f79900}.m{fill:#fea200}.r{fill:#ea8c00}.s{fill:#f59b00}.t{fill:#fea500}.Y{fill:#ffbb14}.Z{fill:#ffa901}.a4{fill:#ffbd11}.a6{fill:#ffce2c}.at{fill:#ffaa03}.aD{fill:#ffc620}.aI{fill:#ffde3f}.aJ{fill:#ffd935}.aK{fill:#ffbc11}.aO{fill:#ffb811}.aP{fill:#ffb208}</style>
<g clip-path="url(#cp1)">
<path d="m808 677.3 94.5 55.9-143.6 56-51.7-3z" style="fill:#b60"></path>
<path d="M956.9 570.9 899 736.6l117-145.7z" style="fill:#b25b00"></path>
<path d="m806.5 683.2 14.7-131.9 140.3 20.9z" style="fill:#e08000"></path>
<path d="m753.4 572 69.8-19.8-13 127.9z" class="d"></path>
<path d="m666.8 618.2 89.2-46 56.8 111.2z" style="fill:#ef9100"></path>
<path d="m960 572.2-58.9 161-91.6-53.1z" style="fill:#c76e00"></path>
<path d="m616 711.5 92.4 74.4 102.4-107.4z" style="fill:#ce6e00"></path>
<path d="m616 714.2 50.6-104.5L812 680.1z" class="d"></path>
<path d="m507.8 653.3 109.8 61.5 49.2-99.4z" class="h"></path>
<path d="M511.6 489v166.6l155.2-38.8z" style="fill:#ffa902"></path>
<path d="m663 621.8 35.1-65.4 61.6 15.7z" style="fill:#f59900"></path>
<path d="m652 526 13.3 95.7 36.1-63.8z" style="fill:#fea400"></path>
<path d="m505.1 485 161.2 133.7-.7-11.9-11.5-79.9z" style="fill:#ffaf06"></path>
<path d="m655.7 486-7.3 40 50.1 31.9z" class="h"></path>
<path d="m668.3 420-17.1 107.4-139.6-39.9z" class="m"></path>
<path d="m1012.9 432.1-54.1 141.2 55.8 17.6z" style="fill:#be6800"></path>
<path d="m960.3 573.6 54.2-141.5-87.8 52.2z" style="fill:#dd7c00"></path>
<path d="m928.4 483.1 33.1 90.6-141.2-19.4z" style="fill:#c96b00"></path>
<path d="m894.3 438-73.1 118.5 108.4-72.8z" style="fill:#dd8200"></path>
<path d="m891.3 436.2 36.9 48.4 86.3-50.8-113.3-14.2z" class="r"></path>
<path d="m895.4 437.2 27-37.2 91.4 34.4z" class="r"></path>
<path d="m835 415.6 17.1 95.9 42.7-72.5z" class="s"></path>
<path d="m816.3 394 59.8 68.5 19.3-23.9z" class="s"></path>
<path d="m762.4 365.4 161.7 34.5-30 39.8z" class="t"></path>
<path d="M921.2 260.4v140.8l92.2 33.9z" style="fill:#ca7000"></path>
<path d="m845.1 313.7 77.3 87.5-1.2-142.2z" style="fill:#e28100"></path>
<path d="m761.3 366.5 86-54.5 76.7 89.7z" style="fill:#f49900"></path>
<path d="m627.8 340.3 136.8 27.4 85.1-55z" style="fill:#ffb10b"></path>
<path d="m631.6 340.7 36.2 78.7 36.4-32.5 62.2-20.6z" style="fill:#ffbb13"></path>
<path d="m632.6 340.6 36.4 80-157.6 70.3 1.2-8.1z" style="fill:#ffa905"></path>
<path d="m778.1 135.7 68.4 178 74.7-53.3z" style="fill:#faa100"></path>
<path d="M511.4 269.3v221.6l122.5-150z" style="fill:#ffb812"></path>
<path d="m511.6 270.5 153.8-77.6-33 148z" style="fill:#ffcb24"></path>
<path d="m663 190.3-32.1 150.6 218.4-27.2z" style="fill:#ffc31c"></path>
<path d="m665.4 192.9 114-57.2L848 315.1z" style="fill:#ffb10a"></path>
<path d="M510.3 44.4 664 195.8l117.8-58.9z" style="fill:#ffc119"></path>
<path d="m511.6 783.4 200.1 2.5-93.7-74.3z" style="fill:#bf6700"></path>
<path d="m511.5 784.1.1-128.8 107.1 57.4z" style="fill:#e68d00"></path>
<path d="m511.8 45.2-.4 226.6 154-77.4z" style="fill:#ffd027"></path>
<path d="m791.8 880.1 79.1-11-113.5-37.4z" style="fill:#cd7500"></path>
<path d="m789.1 878.6 13.7 59.7 67.5-69.8z" style="fill:#c06900"></path>
<path d="m669.9 976.8 121.9-99.2 11.6 60z" style="fill:#d47b00"></path>
<path d="m595.1 897.7 97.7 63.9 100.5-84z" style="fill:#eb8e00"></path>
<path d="m599.7 898.1 157.7-67.2 37.2 47.9z" style="fill:#c66d00"></path>
<path d="m598.9 898.7 69.1-71.8 89 4.8-140.7 61.5z" style="fill:#bd6200"></path>
<path d="m511.5 825 87.2 76.1 74.1-74.4z" style="fill:#cf7100"></path>
<path d="M506.5 1015.9 677 975.2l18.1-16.5-177.8 48.4z" style="fill:#d57500"></path>
<path d="m512 1016.2 87.3-119.3 93.8 63.6-177.3 55.4z" style="fill:#e08400"></path>
<path d="m441.2 879.5 158.1 21.1-87.3-76z" style="fill:#d87a00"></path>
<path d="m442.6 878.9 67.5 137 3.6-.2 85.6-116.9z" style="fill:#f49f00"></path>
<path d="m512 1016.2-68.4-138.1-84.3 87.5 145.8 49.8z" style="fill:#ffb308"></path>
<path d="m353.2 973 7.1-9.8 147.1 53.1z" style="fill:#ffa600"></path>
<path d="m274 829.2 17.1 76.8 153.5-25.9-9.6-4.9z" style="fill:#ffc61d"></path>
<path d="m274.7 829.8 169.9 50.7 13.4-12 54-43.6z" style="fill:#ec9300"></path>
<path d="m290.1 903.7 63.7 69.4 90.9-94.5z" class="Y"></path>
<path d="m229.7 938 62.1-33.7 67.2 70.4z" class="Z"></path>
<path d="m222.8 884.3 8.5 53.9 64.6-34.2z" style="fill:#ffc319"></path>
<path d="m156.1 869.6 77.3 69.3L224 882z" class="Z"></path>
<path d="m273.5 830 5.1 3.6 13.2 70.7-71.9-20z" style="fill:#ffd832"></path>
<path d="m155.3 869.6 119.3-40-6.9 10.8-45.2 45z" style="fill:#ffc721"></path>
<path d="m396.6 444.5 116 46.1V266z" style="fill:#ffc823"></path>
<path d="m332.1 395.5 30.2 47.4h38.8z" class="a4"></path>
<path d="m360.6 514.2 1.7-72.6 40.8-.3z" style="fill:#ffc524"></path>
<path d="m355.3 518.2-5.2 60 52.2-137z" class="a6"></path>
<path d="m348.9 577 162.7-89-112-45.1z" style="fill:#ffc016"></path>
<path d="m436.2 617 76.4 41.7V484.1z" style="fill:#ffb708"></path>
<path d="m346.6 576.8 91.8 41.4 74.2-132z" style="fill:#ffc011"></path>
<path d="m512.6 653.9.3 129.1-3.7-.5-122.3-83.7c-1.2 0 125.7-44.9 125.7-44.9" style="fill:#f59f00"></path>
<path d="m389.2 702.2 49.3-88.1 73.5 40.4-.4 2.5z" style="fill:#ffb609"></path>
<path d="m390.3 707.8-42.5-131.2 92.9 38.1z" style="fill:#ffc01a"></path>
<path d="M266.8 788.5 377.9 705l15.2-4.5 119.5 82.8z" style="fill:#d57900"></path>
<path d="m260.4 730.9 9 57.2 123.7-90.4z" style="fill:#e08500"></path>
<path d="m289.8 623.9 103.3 77.2-4.9 1.9-128.6 28.8z" style="fill:#f89f00"></path>
<path d="m350.7 576.2 42.4 126-104.6-76.6z" style="fill:#ffba0c"></path>
<path d="m301.8 571.3 50.8 6.9 7.4-64z" class="a6"></path>
<path d="m289.5 626.7 65.4-49.6-51.6-8.5z" style="fill:#ffc41f"></path>
<path d="m8.7 589.4 113.5 143.8 24.5-33.1L17.3 592.8z" style="fill:#da7f00"></path>
<path d="m143.8 700.1 127.9 89.1-150.8-56z" style="fill:#d07700"></path>
<path d="M142.8 700.5v2.8l127.3 85.1-8.5-58.1z" style="fill:#f09600"></path>
<path d="m292.9 624.1-31.3 108L144 701.8l144.3-77.6z" style="fill:#ffae05"></path>
<path d="m209.4 560-67.7 143.9 150.1-78.5z" style="fill:#ffbe1a"></path>
<path d="m207.1 558.8 83.6 67.9 14.8-59.2z" style="fill:#ffcd29"></path>
<path d="m83.4 543.5 128.3 14.8-66.5 143.3z" style="fill:#fb9c00"></path>
<path d="m84.7 544 63.2 161.6L7.4 588.8z" style="fill:#e38500"></path>
<path d="m169.6 489 41.5 72-131.4-16.2z" style="fill:#ffae07"></path>
<path d="M10.8 432.1 8 589.8l81.4-45.6z" class="m"></path>
<path d="m129.5 414.5-43.2 129-76.1-110.8z" style="fill:#ffad02"></path>
<path d="m127.5 416.5 42.1 75.2-86.3 53.4z" class="t"></path>
<path d="m126.2 416.5 59 8.7-15.7 68.1z" style="fill:#ffaf0a"></path>
<path d="m126.3 416.8 98.9-32.6-41.2 41.5-56.7-7.2z" class="at"></path>
<path d="M367.8 187.7 512.4 44.3l.4 225.4-4.8.3z" style="fill:#ffda35"></path>
<path d="m329 349.3 36.2-165.7 146.4 86.9z" style="fill:#ffcd23"></path>
<path d="m276.2 330.3 55.1 19.5L368.4 185z" style="fill:#ffce28"></path>
<path d="m327.8 347.2 184.8-78.6-114.5 176.6z" style="fill:#ffd834"></path>
<path d="m327.7 344.1 3.5 52.6 65.5 44.9z" style="fill:#ffc21b"></path>
<path d="m329.2 346.6 3.7 50.5-64.4-28.8z" class="Y"></path>
<path d="m275 328.5-3.3 41.2 60.4-21.6z" style="fill:#ffae08"></path>
<path d="m151.8 303.1 216.6-117.2 1.1 1.7-93.4 144.7z" style="fill:#ffd331"></path>
<path d="m153.8 302.1 123.8 28.5-151.8 88.8 1.1-10.3z" style="fill:#ffc722"></path>
<path d="m155.9 297.8-29.3 119.3L9.5 433.8z" style="fill:#ffb806"></path>
<path d="m10.2 435.7 91.9-172.3 53.2 37.3z" class="aD"></path>
<path d="m243.8 136.4 4.8.6-93.8 165.8-53.2-38.5z" style="fill:#ffce26"></path>
<path d="M512 45.2v5.1L369.4 187.2l-123.5-50.3z" style="fill:#ffe350"></path>
<path d="m247.8 136.4 122.8 49.9-219.3 118.4z" style="fill:#ffd839"></path>
<path d="m276.9 328.8-3.8 40.9-146.3 48.1z" style="fill:#ffb40f"></path>
<path d="m149.8 68.4 52.9 34.1L218 82.4z" class="aD"></path>
<path d="m216.8 53.3.9 29.8-69.6-13.7z" class="a6"></path>
<path d="m209.6 31.6 7.5 23.4-68.2 14.9z" class="aI"></path>
<path d="m150.9 70.4 31.9-62.2 28.3 25.6z" class="aJ"></path>
<path d="M151.6 70.4 137 7.2l46.9 1.2z" class="aJ"></path>
<path d="M153.1 69.5 137.8 6.8l-34 39z" class="aK"></path>
<path d="m156.3 70-52.7-25.7-.7 28.9z" style="fill:#ffc420"></path>
<path d="m156.7 67.7-47.4 26.1-7.2-21.5z" style="fill:#ffb910"></path>
<path d="m152.7 68.3-5.8 54.6-38.3-29.6z" style="fill:#ffad09"></path>
<path d="m178.3 121.2-26.5-53-5.5 54.7z" class="aO"></path>
<path d="m203.4 101.8-53-34.6 25.1 55.2z" class="aP"></path>
<path d="m200.4 177 1.8-75.2 43.4 35.5z" class="aP"></path>
<path d="M203.2 180 177 120.9l26.4-19.6z" class="a4"></path>
<path d="m877.8 68.7-55.9 35.1L808 83.1z" class="aD"></path>
<path d="m807.2 55.7.3 29.5 69-15z" class="a6"></path>
<path d="M813.3 33.9 807 58.1l68.7 13.1z" class="aI"></path>
<path d="M873.7 71.8 841.8 9.6l-28 25.6z" class="aJ"></path>
<path d="M872.7 73.5 889 8.2l-48.9 1.6z" class="aJ"></path>
<path d="m869.9 74.2 16.6-67 35.9 39.5z" class="aK"></path>
<path d="m871.7 71.2 49.9-25.4.2 29.4z" class="at"></path>
<path d="m869.9 70 45.4 25.2 7.2-21.4z" style="fill:#fca400"></path>
<path d="m871.9 69.8 5.8 54.5 38.7-31z" style="fill:#fb9e00"></path>
<path d="m846.3 122.5 26.9-52.9 5.1 54.7z" class="aO"></path>
<path d="m820.6 103 54.9-34.1-27.8 53.6z" class="aP"></path>
<path d="m775.7 135.7 75.2-13.3-30.3 52.1z" style="fill:#e88e00"></path>
<path d="m773 138 52.8-36.6 27.8 21.9z" style="fill:#fca500"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" id="prefix__svg44" fill-rule="evenodd" clip-rule="evenodd" image-rendering="optimizeQuality" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" version="1.1" viewBox="0 0 560 560">
<defs id="prefix__defs4">
<style id="style2" type="text/css">.prefix__fil1{fill:#fefefe}.prefix__fil6{fill:#006498}.prefix__fil5{fill:#bdeaff}</style>
</defs>
<g id="prefix__g85" transform="translate(-70 -70)">
<path id="prefix__path9" fill="#fefefe" d="M350 71c154 0 279 125 279 279S504 629 350 629 71 504 71 350 196 71 350 71z" class="prefix__fil1"></path>
<path id="prefix__path11" fill="#332c2b" fill-opacity=".149" d="m475 236 118 151c3 116-149 252-292 198l-76-99 114-156s138-95 136-94z"></path>
<path id="prefix__path13" fill="#2bbcff" d="M231 211h208l38 24v246c0 5-3 8-8 8H231c-5 0-8-3-8-8V219c0-5 3-8 8-8z"></path>
<path id="prefix__path15" fill="#53c6fc" d="M231 211h208l38 24v2l-37-23H231c-4 0-7 3-7 7v263c-1-1-1-2-1-3V219c0-5 3-8 8-8z"></path>
<path id="prefix__polygon17" fill="#bdeaff" d="M305 212h113v98H305z" class="prefix__fil5"></path>
<path id="prefix__path19" fill="#bdeaff" d="M255 363h189c3 0 5 2 5 4v116H250V367c0-2 2-4 5-4z" class="prefix__fil5"></path>
<path id="prefix__polygon21" fill="#006498" d="M250 470h199v13H250z" class="prefix__fil6"></path>
<path id="prefix__path23" fill="#006498" d="M380 226h10c3 0 6 2 6 5v40c0 3-3 6-6 6h-10c-3 0-6-3-6-6v-40c0-3 3-5 6-5z" class="prefix__fil6"></path>
<path id="prefix__path25" fill="#fefefe" d="M254 226c10 0 17 7 17 17 0 9-7 16-17 16-9 0-17-7-17-16 0-10 8-17 17-17z" class="prefix__fil1"></path>
<path id="prefix__path27" fill="#006498" d="M267 448h165c2 0 3 1 3 3 0 1-1 3-3 3H267c-2 0-3-2-3-3 0-2 1-3 3-3z" class="prefix__fil6"></path>
<path id="prefix__path29" fill="#006498" d="M267 415h165c2 0 3 1 3 3 0 1-1 2-3 2H267c-2 0-3-1-3-2 0-2 1-3 3-3z" class="prefix__fil6"></path>
<path id="prefix__path31" fill="#006498" d="M267 381h165c2 0 3 2 3 3 0 2-1 3-3 3H267c-2 0-3-1-3-3 0-1 1-3 3-3z" class="prefix__fil6"></path>
<path id="prefix__path33" fill="#fefefe" d="M236 472c3 0 5 2 5 5 0 2-2 4-5 4s-5-2-5-4c0-3 2-5 5-5z" class="prefix__fil1"></path>
<path id="prefix__path35" fill="#fefefe" d="M463 472c3 0 5 2 5 5 0 2-2 4-5 4s-5-2-5-4c0-3 2-5 5-5z" class="prefix__fil1"></path>
<path id="prefix__polygon37" fill="#006498" d="M305 212h-21v98h21z" class="prefix__fil6"></path>
<path id="prefix__path39" fill="#0ea5eb" d="M477 479v2c0 5-3 8-8 8H231c-5 0-8-3-8-8v-2c0 4 3 8 8 8h238c5 0 8-4 8-8z"></path>
<path id="prefix__path41" fill="#2979ff" d="M350 70c155 0 280 125 280 280S505 630 350 630 70 505 70 350 195 70 350 70zm0 46c129 0 234 105 234 234S479 584 350 584 116 479 116 350s105-234 234-234z"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 465.365 465.363">
<defs>
<linearGradient id="a" x1="110.25" x2="496.14" y1="213.3" y2="436.09" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#aa5cc3"></stop>
<stop offset="1" style="stop-color:#00a4dc"></stop>
</linearGradient>
<linearGradient xlink:href="#a" id="b" x1="110.25" x2="496.14" y1="213.3" y2="436.09" gradientUnits="userSpaceOnUse"></linearGradient>
<linearGradient xlink:href="#a" id="c" x1="110.25" x2="496.14" y1="213.3" y2="436.09" gradientUnits="userSpaceOnUse"></linearGradient>
</defs>
<g fill="url(#a)" transform="translate(-23.29 -23.3)">
<path d="M256 201.6c-20.4 0-86.2 119.3-76.2 139.4 10 20.1 142.5 19.9 152.4 0 9.9-19.9-55.7-139.4-76.2-139.4z" style="fill:url(#b)"></path>
<path d="M256 23.3c-61.6 0-259.8 359.4-229.6 420.1 30.2 60.7 429.3 60 459.2 0 29.9-60-168-420.1-229.6-420.1Zm150.5 367.5c-19.6 39.3-281.1 39.8-300.9 0C85.8 351 215.7 115.5 256 115.5c40.3 0 170.1 235.9 150.5 275.3z" style="fill:url(#c)"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 258.305 380">
<linearGradient id="a" x1="7.926" x2="204.053" y1="58.61" y2="58.61" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#12b212"></stop>
<stop offset="1" stop-color="#0f0"></stop>
</linearGradient>
<g stroke-width="2.925">
<path fill="url(#a)" d="M106.925 116.781C59.488 111.721 11.7 75.865 7.926 0c73.613 0 112.98 43.577 116.781 112.628 13.922-82.826 79.17-73.116 79.17-73.116 3.1 46.94-35.446 75.398-79.17 77.767C112.424 91.395 38.84 27.9 38.84 27.9a.205.205 0 0 0-.322.234s71.01 61.857 68.407 88.646"></path>
<path fill="#980200" d="M129.153 380c-4.592-.263-47.438-1.901-50.041-50.04-2.106-29.247 20.999-50.802 20.999-79.2-5.235-70.806-100.11-62.032-100.11 0a58.318 58.318 0 0 0 17.05 41.354l70.689 70.718a58.318 58.318 0 0 0 41.354 17.051"></path>
<path fill="red" d="M258.305 250.789c-.263 4.592-1.9 47.438-50.04 50.04-29.247 2.106-50.83-20.998-79.2-20.998-70.806 5.235-62.032 100.081 0 100.081a58.318 58.318 0 0 0 41.355-17.05l70.747-70.69a58.318 58.318 0 0 0 17.05-41.354"></path>
<path fill="#980200" d="M129.153 121.636c4.592.263 47.438 1.901 50.04 50.041 2.106 29.247-20.998 50.801-20.998 79.2 5.235 70.805 100.081 62.031 100.081 0a58.318 58.318 0 0 0-17.05-41.355l-70.719-70.747a58.318 58.318 0 0 0-41.354-17.051"></path>
<path fill="red" d="M.234 250.789c.263-4.592 1.901-47.438 50.04-50.04 29.247-2.107 50.831 20.998 79.2 20.998 70.806-5.323 62.032-100.081 0-100.081a58.318 58.318 0 0 0-41.354 17.05l-70.747 70.718A58.318 58.318 0 0 0 .322 250.79"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 164.179 151.11">
<defs>
<linearGradient id="a" x1="259.78" x2="463.85" y1="261.15" y2="456.49" gradientUnits="userSpaceOnUse">
<stop offset="0%" stop-color="#5cdd8b"></stop>
<stop offset="100%" stop-color="#86e6a9"></stop>
</linearGradient>
</defs>
<path d="M490.4 235.64c53.69 122.74 53.69 199.7 0 230.86-80.55 46.74-290.44 60.99-350.86-10.86-40.28-47.9-40.28-121.24 0-220 40.96-67.46 99.17-101.19 174.63-101.19 75.47 0 134.21 33.73 176.23 101.19z" style="fill:url(#a)" transform="translate(-2.685 -9.115) scale(.26458)"></path>
<path fill="none" d="M490.4 235.64c53.69 122.74 53.69 199.7 0 230.86-80.55 46.74-290.44 60.99-350.86-10.86-40.28-47.9-40.28-121.24 0-220 40.96-67.46 99.17-101.19 174.63-101.19 75.47 0 134.21 33.73 176.23 101.19z" style="fill-opacity:0;stroke:#f2f2f2;stroke-width:200;stroke-opacity:.51" transform="translate(-2.685 -9.115) scale(.26458)"></path>
</svg>

After

Width:  |  Height:  |  Size: 1003 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -0,0 +1,34 @@
<html>
<head>
<title>Welcome to our server</title>
<style>
body{
font-family: Helvetica, Arial, sans-serif;
}
.message{
width:330px;
padding:20px 40px;
margin:0 auto;
background-color:#f9f9f9;
border:1px solid #ddd;
}
center{
margin:40px 0;
}
h1{
font-size: 18px;
line-height: 26px;
}
p{
font-size: 12px;
}
</style>
</head>
<body>
<div class="message">
<h1>Welcome to our server</h1>
<p>The website is currently being setup under this address.</p>
<p>For help and support, please contact: <a href="me@example.com">me@example.com</a></p>
</div>
</body>
</html>

View File

@@ -0,0 +1,307 @@
[2026-03-05 02:13:25] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:13:25] local.DEBUG: Process Apps dispatched
[2026-03-05 02:13:25] local.DEBUG: Process Apps dispatched
[2026-03-05 02:52:38] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:52:38] local.DEBUG: Process Apps dispatched
[2026-03-05 02:52:40] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:52:40] local.DEBUG: Process Apps dispatched
[2026-03-05 02:52:42] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:52:42] local.DEBUG: Process Apps dispatched
[2026-03-05 02:52:46] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:52:46] local.DEBUG: Process Apps dispatched
[2026-03-05 02:52:46] local.DEBUG: Get app triggered for: ba05dd8e070851895ee6184eb9778cfa0753a490
[2026-03-05 02:52:46] local.DEBUG: Download triggered for stdClass Object
(
[appid] => ba05dd8e070851895ee6184eb9778cfa0753a490
[name] => FileBrowser
[website] => https://github.com/filebrowser/filebrowser
[license] => Apache License 2.0
[description] => filebrowser provides a file managing interface within a specified directory and it can be used to upload, delete, preview, rename and edit your files. It allows the creation of multiple users and each user can have its own directory. It can be used as a standalone app or as a middleware.
[enhanced] => 1
[tile_background] => dark
[icon] => filebrowser.svg
[sha] => b92328bdd28ebaf4103fa1a7ba22da49e3c263e7
[class] => App\SupportedApps\FileBrowser\FileBrowser
)
[2026-03-05 02:52:47] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:52:56] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:52:57] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:53:02] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:53:03] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:53:09] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:53:09] local.DEBUG: Get app triggered for: 668b5fcda851fe516fef14e82973beffe32f385a
[2026-03-05 02:53:09] local.DEBUG: Download triggered for stdClass Object
(
[appid] => 668b5fcda851fe516fef14e82973beffe32f385a
[name] => ownCloud
[website] => https://owncloud.org
[license] => GNU Affero General Public License v3.0 or later
[description] => ownCloud is a free and open source file hosting service. It also supports extensions for online document editing, calendar and contact synchronization. It's a safe home for all your data.
[enhanced] =>
[tile_background] => dark
[icon] => owncloud.png
[sha] => fa9bc697bec8367d9f4d4e98e9a34ea9c61d4710
[class] => App\SupportedApps\ownCloud\ownCloud
)
[2026-03-05 02:53:17] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:53:17] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:53:20] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:53:22] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:53:51] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:53:51] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:53:53] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:53:54] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:54:00] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:54:00] local.DEBUG: Get app triggered for: b89920409bdce40e08ba1023480b0546061cd577
[2026-03-05 02:54:00] local.DEBUG: Download triggered for stdClass Object
(
[appid] => b89920409bdce40e08ba1023480b0546061cd577
[name] => Pi-hole
[website] => https://pi-hole.net
[license] => European Union Public License 1.2
[description] => Pi-hole is a Linux network-level advertisement and internet tracker blocking application which acts as a DNS sinkhole, intended for use on a private network.
[enhanced] => 1
[tile_background] => dark
[icon] => pihole.svg
[sha] => 945fe7045036e17eff1d0c46be6280f207cef77a
[class] => App\SupportedApps\Pihole\Pihole
)
[2026-03-05 02:54:00] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:54:11] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:54:11] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:54:13] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:54:14] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:54:18] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:54:18] local.DEBUG: Get app triggered for: 0bafb882c9d2c034ca5333367f8ccc90f4ae85e4
[2026-03-05 02:54:18] local.DEBUG: Download triggered for stdClass Object
(
[appid] => 0bafb882c9d2c034ca5333367f8ccc90f4ae85e4
[name] => Dockge
[website] => https://github.com/louislam/dockge
[license] => MIT License
[description] => A fancy, easy-to-use and reactive self-hosted docker compose.yaml stack-oriented manager.
[enhanced] =>
[tile_background] => dark
[icon] => dockge.svg
[sha] => f4e77826a682041f4ab5e3276d3a7c1886d8095d
[class] => App\SupportedApps\Dockge\Dockge
)
[2026-03-05 02:54:27] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:54:27] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:54:29] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:54:31] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:54:34] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:54:34] local.DEBUG: Get app triggered for: 348c49dd03dddd418929316668d2e67bf2d9ae88
[2026-03-05 02:54:34] local.DEBUG: Download triggered for stdClass Object
(
[appid] => 348c49dd03dddd418929316668d2e67bf2d9ae88
[name] => Bookstack
[website] => https://www.bookstackapp.com
[license] => MIT License
[description] => BookStack is a simple, self-hosted, easy-to-use platform for organising and storing information.
[enhanced] => 1
[tile_background] => dark
[icon] => bookstack.svg
[sha] => fd57e5a47f09f6227b62b74428765dbce7f5813d
[class] => App\SupportedApps\Bookstack\Bookstack
)
[2026-03-05 02:54:34] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:54:42] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:54:42] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:54:47] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:54:49] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:54:53] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:54:53] local.DEBUG: Get app triggered for: af7b37e2841d9150f6abd5a936b32a1f681d6bda
[2026-03-05 02:54:53] local.DEBUG: Download triggered for stdClass Object
(
[appid] => af7b37e2841d9150f6abd5a936b32a1f681d6bda
[name] => JDownloader
[website] => http://jdownloader.org
[license] => Creative Commons Attribution Non Commercial Share Alike 2.0 Generic
[description] => JDownloader is a free, open-source download management tool with a huge community of developers that makes downloading as easy and fast as it should be.
[enhanced] =>
[tile_background] => dark
[icon] => jdownloader.png
[sha] => 32303a80935e2fbbecb1132e2358498ba876060b
[class] => App\SupportedApps\JDownloader\JDownloader
)
[2026-03-05 02:55:00] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:55:17] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:55:17] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:55:20] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:55:22] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:55:24] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:55:24] local.DEBUG: Get app triggered for: 176d99d897dbd7c02b1a1db4142054f74a76aa47
[2026-03-05 02:55:24] local.DEBUG: Download triggered for stdClass Object
(
[appid] => 176d99d897dbd7c02b1a1db4142054f74a76aa47
[name] => Dozzle
[website] => https://dozzle.dev
[license] => MIT License
[description] => Dozzle is a real-time log viewer for docker containers.
[enhanced] =>
[tile_background] => dark
[icon] => dozzle.svg
[sha] => 46ca9ab4e1428db7e545d09261f487b08220d28d
[class] => App\SupportedApps\Dozzle\Dozzle
)
[2026-03-05 02:55:32] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:55:32] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:55:36] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:55:37] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:55:42] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:55:42] local.DEBUG: Get app triggered for: fc4e407d69510b855b678aa4fba6083fbbfc5383
[2026-03-05 02:55:42] local.DEBUG: Download triggered for stdClass Object
(
[appid] => fc4e407d69510b855b678aa4fba6083fbbfc5383
[name] => OnlyOffice
[website] => https://www.onlyoffice.com
[license] => GNU Affero General Public License v3.0 or later
[description] => ONLYOFFICE online editors for text documents, spreadsheets, and presentations with access to pro features and connect them to the platform of your choice with ready-to-use connectors: https://www.onlyoffice.com/download.aspx#connectors
[enhanced] =>
[tile_background] => light
[icon] => onlyoffice.png
[sha] => 4b8aa18f29760fab9ce5cd94976e86e464772a85
[class] => App\SupportedApps\OnlyOffice\OnlyOffice
)
[2026-03-05 02:55:42] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:55:48] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:55:48] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:55:51] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:55:52] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:55:55] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:55:55] local.DEBUG: Get app triggered for: cbfad988a16a9fbcc1812bc206afcc1f73dd36de
[2026-03-05 02:55:55] local.DEBUG: Download triggered for stdClass Object
(
[appid] => cbfad988a16a9fbcc1812bc206afcc1f73dd36de
[name] => Nginx Proxy Manager
[website] => https://nginxproxymanager.jc21.com
[license] => MIT License
[description] => This project comes as a pre-built docker image that enables you to easily forward to your websites running at home or otherwise, including free SSL, without having to know too much about Nginx or Letsencrypt.
[enhanced] => 1
[tile_background] => light
[icon] => nginxproxymanager.png
[sha] => 0b8e03a7f9a833c0e644f401ee85926b8ba86c73
[class] => App\SupportedApps\NginxProxyManager\NginxProxyManager
)
[2026-03-05 02:55:55] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:55:55] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:56:02] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:56:02] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:56:06] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:56:07] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:56:10] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:56:10] local.DEBUG: Get app triggered for: 366c6646eedab83cc4b349f198424d2291cbfa76
[2026-03-05 02:56:10] local.DEBUG: Download triggered for stdClass Object
(
[appid] => 366c6646eedab83cc4b349f198424d2291cbfa76
[name] => Uptime Kuma
[website] => https://uptime.kuma.pet
[license] => MIT License
[description] => It is a self-hosted monitoring tool like "Uptime Robot".
[enhanced] => 1
[tile_background] => dark
[icon] => uptimekuma.svg
[sha] => 5179586b1259c3eba3fbf0c4712436110adb1885
[class] => App\SupportedApps\UptimeKuma\UptimeKuma
)
[2026-03-05 02:56:10] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:56:18] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:56:19] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:56:29] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:56:33] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:56:41] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:56:41] local.DEBUG: Get app triggered for: b5f16344632fdfe68391a2dc3816ee0edbb1813c
[2026-03-05 02:56:41] local.DEBUG: Download triggered for stdClass Object
(
[appid] => b5f16344632fdfe68391a2dc3816ee0edbb1813c
[name] => IT-Tools
[website] => https://it-tools.tech/
[license] => GNU General Public License v3.0 only
[description] => Useful tools for developer and people working in IT.
[enhanced] =>
[tile_background] => light
[icon] => ittools.png
[sha] => c42fe8dccaae8c320230a00f24771745edc8dc2d
[class] => App\SupportedApps\ITTools\ITTools
)
[2026-03-05 02:56:41] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:56:47] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:56:48] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:56:50] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:56:51] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:56:56] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:56:56] local.DEBUG: Get app triggered for: ddf4f264320af1347ef54d424c60fae3b4fcc448
[2026-03-05 02:56:56] local.DEBUG: Download triggered for stdClass Object
(
[appid] => ddf4f264320af1347ef54d424c60fae3b4fcc448
[name] => Vaultwarden
[website] => https://github.com/dani-garcia/vaultwarden
[license] => GNU Affero General Public License v3.0
[description] => Alternative implementation of the Bitwarden server API written in Rust and compatible with upstream Bitwarden clients*, perfect for self-hosted deployment where running the official resource-heavy service might not be ideal.
[enhanced] =>
[tile_background] => light
[icon] => vaultwarden.png
[sha] => fbc0ce92000160c6576cf4dc54b3859098f9faa8
[class] => App\SupportedApps\Vaultwarden\Vaultwarden
)
[2026-03-05 02:56:57] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:57:03] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:57:03] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:57:05] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:57:06] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:57:10] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:57:10] local.DEBUG: Get app triggered for: 3e0a7f109bd760b9474c78cb652e8c3e82669226
[2026-03-05 02:57:10] local.DEBUG: Download triggered for stdClass Object
(
[appid] => 3e0a7f109bd760b9474c78cb652e8c3e82669226
[name] => Jellyfin
[website] => https://jellyfin.github.io
[license] => GNU General Public License v2.0 only
[description] => Jellyfin is the Free Software Media System that puts you in control of managing and streaming your media. There are no strings attached, no premium licenses or features, and no hidden agendas.
[enhanced] => 1
[tile_background] => dark
[icon] => jellyfin.svg
[sha] => 0261afdcd2000d2ed0fddf978d364b8ffcae961d
[class] => App\SupportedApps\Jellyfin\Jellyfin
)
[2026-03-05 02:57:11] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:57:18] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:57:19] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:57:20] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:57:21] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:57:25] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:57:25] local.DEBUG: Get app triggered for: afef2217e82ee20638490bb102605f6e09789093
[2026-03-05 02:57:25] local.DEBUG: Download triggered for stdClass Object
(
[appid] => afef2217e82ee20638490bb102605f6e09789093
[name] => WireGuard
[website] => https://www.wireguard.com
[license] => CNRI Python Open Source GPL Compatible License Agreement
[description] => WireGuard® is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPsec, while avoiding the massive headache. It intends to be considerably more performant than OpenVPN. WireGuard is designed as a general purpose VPN for running on embedded interfaces and super computers alike, fit for many different circumstances. Initially released for the Linux kernel, it is now cross-platform (Windows, macOS, BSD, iOS, Android) and widely deployable. It is currently under heavy development, but already it might be regarded as the most secure, easiest to use, and simplest VPN solution in the industry.
[enhanced] =>
[tile_background] => dark
[icon] => wireguard.png
[sha] => 5c05f64749725c3179f109d21977d086101b3ee7
[class] => App\SupportedApps\WireGuard\WireGuard
)
[2026-03-05 02:57:31] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:57:32] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:57:34] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:57:35] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:57:49] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite
[2026-03-05 02:57:49] local.DEBUG: SQLite Database Path: /app/www/database/app.sqlite

View File

@@ -0,0 +1,44 @@
tiles:
id: tiles
name: Tiles
target: _blank
baidu:
id: baidu
url: https://www.baidu.com/s
name: Baidu
method: get
target: _blank
query: wd
bing:
id: bing
url: https://www.bing.com/search
name: Bing
method: get
target: _blank
query: q
ddg:
id: ddg
url: https://duckduckgo.com/
name: DuckDuckGo
method: get
target: _blank
query: q
google:
id: google
url: https://www.google.com/search
name: Google
method: get
target: _blank
query: q
startpage:
id: startpage
url: https://www.startpage.com/do/dsearch
name: Startpage
method: get
target: _blank
query: query