From 5c56f3e6f00a61af2ccf50811c155c325f2b10fa Mon Sep 17 00:00:00 2001
From: Yassine Doghri <yassine@doghri.fr>
Date: Tue, 26 Oct 2021 15:54:56 +0000
Subject: [PATCH] feat(settings): add general config for instance (site name,
 description and icon)

---
 .gitignore                                    |   2 +
 app/Config/App.php                            |  20 +++
 app/Config/Routes.php                         |   6 +-
 app/Controllers/WebmanifestController.php     |  45 ++++++
 app/Database/Seeds/AuthSeeder.php             |  12 ++
 app/Helpers/media_helper.php                  |   3 +
 composer.json                                 |   8 +-
 composer.lock                                 | 153 ++++++++++++++----
 ecs.php                                       |   1 -
 modules/Admin/Config/Routes.php               |  15 ++
 .../Admin/Controllers/SettingsController.php  | 105 ++++++++++++
 modules/Admin/Language/en/AdminNavigation.php |   2 +
 modules/Admin/Language/en/Breadcrumb.php      |   1 +
 modules/Admin/Language/en/Settings.php        |  23 +++
 modules/Admin/Language/fr/AdminNavigation.php |   2 +
 modules/Admin/Language/fr/Settings.php        |  24 +++
 .../Install/Controllers/InstallController.php |   2 +
 public/favicon.ico                            | Bin 16958 -> 21238 bytes
 public/icon-180.png                           | Bin 0 -> 17522 bytes
 public/icon-192.png                           | Bin 0 -> 5913 bytes
 public/icon-512.png                           | Bin 0 -> 7340 bytes
 public/icon-64.png                            | Bin 0 -> 738 bytes
 public/icon.png                               | Bin 0 -> 7027 bytes
 themes/cp_admin/_layout.php                   |   5 +-
 themes/cp_admin/_sidebar.php                  |   4 +
 themes/cp_admin/person/edit.php               |   1 +
 themes/cp_admin/settings/general.php          |  59 +++++++
 themes/cp_app/_layout.php                     |  15 +-
 themes/cp_app/embed.php                       |   5 +-
 themes/cp_app/episode/_layout.php             |   5 +-
 themes/cp_app/home.php                        |  19 ++-
 themes/cp_app/map.php                         |   5 +-
 themes/cp_app/page.php                        |   5 +-
 themes/cp_app/podcast/_layout.php             |   5 +-
 themes/cp_app/podcast/about.php               |   5 +-
 themes/cp_app/podcast/activity.php            |   5 +-
 themes/cp_app/podcast/episodes.php            |   5 +-
 themes/cp_app/podcast/follow.php              |   6 +-
 themes/cp_app/post/remote_action.php          |   5 +-
 themes/cp_auth/_layout.php                    |   2 +-
 themes/cp_install/_layout.php                 |   5 +-
 41 files changed, 533 insertions(+), 52 deletions(-)
 create mode 100644 app/Controllers/WebmanifestController.php
 create mode 100644 modules/Admin/Controllers/SettingsController.php
 create mode 100644 modules/Admin/Language/en/Settings.php
 create mode 100644 modules/Admin/Language/fr/Settings.php
 create mode 100644 public/icon-180.png
 create mode 100644 public/icon-192.png
 create mode 100644 public/icon-512.png
 create mode 100644 public/icon-64.png
 create mode 100644 public/icon.png
 create mode 100644 themes/cp_admin/settings/general.php

diff --git a/.gitignore b/.gitignore
index 47f4c37308..4ed935bc0b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -137,9 +137,11 @@ node_modules
 
 # public folder
 public/*
+public/media/site
 !public/media
 !public/.htaccess
 !public/favicon.ico
+!public/icon*
 !public/index.php
 !public/robots.txt
 
diff --git a/app/Config/App.php b/app/Config/App.php
index df445db0ed..4d2227c087 100644
--- a/app/Config/App.php
+++ b/app/Config/App.php
@@ -427,4 +427,24 @@ class App extends BaseConfig
      * Defines the root folder for media files storage
      */
     public string $mediaRoot = 'media';
+
+    /**
+     * --------------------------------------------------------------------------
+     * Instance / Site Config
+     * --------------------------------------------------------------------------
+     */
+    public string $siteName = 'Castopod';
+
+    public string $siteDescription = 'Castopod Host is an open-source hosting platform made for podcasters who want engage and interact with their audience.';
+
+    /**
+     * @var array<int|string, string>
+     */
+    public array $siteIcon = [
+        'ico' => '/favicon.ico',
+        '64' => '/icon-64.png',
+        '180' => '/icon-180.png',
+        '192' => '/icon-192.png',
+        '512' => '/icon-512.png',
+    ];
 }
diff --git a/app/Config/Routes.php b/app/Config/Routes.php
index 45eff6b951..7d2ca19f73 100644
--- a/app/Config/Routes.php
+++ b/app/Config/Routes.php
@@ -48,9 +48,13 @@ $routes->addPlaceholder(
  * --------------------------------------------------------------------
  */
 
+$routes->get('manifest.webmanifest', 'WebmanifestController', [
+    'as' => 'webmanifest',
+]);
+
 // We get a performance increase by specifying the default
 // route since we don't have to scan directories.
-$routes->get('/', 'HomeController::index', [
+$routes->get('/', 'HomeController', [
     'as' => 'home',
 ]);
 
diff --git a/app/Controllers/WebmanifestController.php b/app/Controllers/WebmanifestController.php
new file mode 100644
index 0000000000..dd320e440e
--- /dev/null
+++ b/app/Controllers/WebmanifestController.php
@@ -0,0 +1,45 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright  2020 Podlibre
+ * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
+ * @link       https://castopod.org/
+ */
+
+namespace App\Controllers;
+
+use CodeIgniter\Controller;
+use CodeIgniter\HTTP\ResponseInterface;
+
+class WebmanifestController extends Controller
+{
+    public function index(): ResponseInterface
+    {
+        $webmanifest = [
+            'name' => service('settings')
+                ->get('App.siteName'),
+            'description' => service('settings')
+                ->get('App.siteDescription'),
+            'display' => 'minimal-ui',
+            'theme_color' => '#009486',
+            'icons' => [
+                [
+                    'src' => service('settings')
+                        ->get('App.siteIcon')['192'],
+                    'type' => 'image/png',
+                    'sizes' => '192x192',
+                ],
+                [
+                    'src' => service('settings')
+                        ->get('App.siteIcon')['512'],
+                    'type' => 'image/png',
+                    'sizes' => '512x512',
+                ],
+            ],
+        ];
+
+        return $this->response->setJSON($webmanifest);
+    }
+}
diff --git a/app/Database/Seeds/AuthSeeder.php b/app/Database/Seeds/AuthSeeder.php
index 2fb6fb6a28..eb9af6a760 100644
--- a/app/Database/Seeds/AuthSeeder.php
+++ b/app/Database/Seeds/AuthSeeder.php
@@ -40,6 +40,18 @@ class AuthSeeder extends Seeder
      * @var array<string, array<string, string|array>[]>
      */
     protected array $permissions = [
+        'settings' => [
+            [
+                'name' => 'view',
+                'description' => 'View settings options',
+                'has_permission' => ['superadmin'],
+            ],
+            [
+                'name' => 'manage',
+                'description' => 'Update general settings',
+                'has_permission' => ['superadmin'],
+            ],
+        ],
         'users' => [
             [
                 'name' => 'create',
diff --git a/app/Helpers/media_helper.php b/app/Helpers/media_helper.php
index 312af42a3b..b9a1c65bf7 100644
--- a/app/Helpers/media_helper.php
+++ b/app/Helpers/media_helper.php
@@ -29,6 +29,9 @@ if (! function_exists('save_media')) {
 
         if (! file_exists($mediaRoot)) {
             mkdir($mediaRoot, 0777, true);
+        }
+
+        if (! file_exists($mediaRoot . '/index.html')) {
             touch($mediaRoot . '/index.html');
         }
 
diff --git a/composer.json b/composer.json
index 3ca24a4fc5..b7dffcaf40 100644
--- a/composer.json
+++ b/composer.json
@@ -12,15 +12,17 @@
     "geoip2/geoip2": "^v2.11.0",
     "myth/auth": "dev-develop",
     "codeigniter4/codeigniter4": "dev-develop",
-    "league/commonmark": "^1.6.6",
+    "league/commonmark": "^v1.6.6",
     "vlucas/phpdotenv": "^v5.3.0",
-    "league/html-to-markdown": "^5.0.0",
+    "league/html-to-markdown": "^v5.0.1",
     "opawg/user-agents-php": "^v1.0",
     "podlibre/ipcat": "^v1.0",
     "podlibre/podcast-namespace": "^v1.0.6",
     "phpseclib/phpseclib": "~2.0.30",
     "michalsn/codeigniter4-uuid": "dev-develop",
-    "essence/essence": "^3.5.4"
+    "essence/essence": "^3.5.4",
+    "codeigniter4/settings": "dev-develop",
+    "chrisjean/php-ico": "^1.0"
   },
   "require-dev": {
     "mikey179/vfsstream": "^v1.6.8",
diff --git a/composer.lock b/composer.lock
index 03baaec32b..82b1287a71 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
     "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
     "This file is @generated automatically"
   ],
-  "content-hash": "af4a438816f7adbbd6950d93ed333e9f",
+  "content-hash": "f35a050323bdc632cd550f9d13f0679c",
   "packages": [
     {
       "name": "brick/math",
@@ -60,6 +60,46 @@
       ],
       "time": "2021-01-20T22:51:39+00:00"
     },
+    {
+      "name": "chrisjean/php-ico",
+      "version": "1.0.4",
+      "source": {
+        "type": "git",
+        "url": "https://github.com/chrisbliss18/php-ico.git",
+        "reference": "ccd5c0d56554f3ddcd7a823e695be83e0d1e43b6"
+      },
+      "dist": {
+        "type": "zip",
+        "url": "https://api.github.com/repos/chrisbliss18/php-ico/zipball/ccd5c0d56554f3ddcd7a823e695be83e0d1e43b6",
+        "reference": "ccd5c0d56554f3ddcd7a823e695be83e0d1e43b6",
+        "shasum": ""
+      },
+      "require": {
+        "ext-gd": "*",
+        "php": ">=5.2.4"
+      },
+      "type": "library",
+      "autoload": {
+        "classmap": ["class-php-ico.php"]
+      },
+      "notification-url": "https://packagist.org/downloads/",
+      "license": ["GPL-2.0+"],
+      "authors": [
+        {
+          "name": "Chris Jean",
+          "homepage": "https://chrisjean.com",
+          "role": "Developer"
+        }
+      ],
+      "description": "An easy-to-use library to generate valid ICO files.",
+      "homepage": "https://github.com/chrisbliss18/php-ico",
+      "keywords": ["favicon", "ico"],
+      "support": {
+        "issues": "https://github.com/chrisbliss18/php-ico/issues",
+        "source": "https://github.com/chrisbliss18/php-ico"
+      },
+      "time": "2016-09-27T22:00:56+00:00"
+    },
     {
       "name": "codeigniter4/codeigniter4",
       "version": "dev-develop",
@@ -137,6 +177,59 @@
       },
       "time": "2021-06-10T06:40:05+00:00"
     },
+    {
+      "name": "codeigniter4/settings",
+      "version": "dev-develop",
+      "source": {
+        "type": "git",
+        "url": "https://github.com/codeigniter4/settings.git",
+        "reference": "5d758e5e0a3f9dda9f66303d82ccfbb82e979577"
+      },
+      "dist": {
+        "type": "zip",
+        "url": "https://api.github.com/repos/codeigniter4/settings/zipball/5d758e5e0a3f9dda9f66303d82ccfbb82e979577",
+        "reference": "5d758e5e0a3f9dda9f66303d82ccfbb82e979577",
+        "shasum": ""
+      },
+      "require": {
+        "php": "^7.3 || ^8.0"
+      },
+      "require-dev": {
+        "codeigniter4/codeigniter4": "dev-develop",
+        "fakerphp/faker": "^1.9",
+        "mockery/mockery": "^1.0",
+        "nexusphp/tachycardia": "^1.0",
+        "php-coveralls/php-coveralls": "^2.4",
+        "phpstan/phpstan": "^0.12",
+        "phpunit/phpunit": "^9.0",
+        "squizlabs/php_codesniffer": "^3.3"
+      },
+      "default-branch": true,
+      "type": "library",
+      "autoload": {
+        "psr-4": {
+          "Sparks\\Settings\\": "src"
+        },
+        "exclude-from-classmap": ["**/Database/Migrations/**"]
+      },
+      "notification-url": "https://packagist.org/downloads/",
+      "license": ["MIT"],
+      "authors": [
+        {
+          "name": "Lonnie Ezell",
+          "email": "lonnieje@gmail.com",
+          "role": "Developer"
+        }
+      ],
+      "description": "Settings library for CodeIgniter 4",
+      "homepage": "https://github.com/codeigniter4/settings",
+      "keywords": ["Settings", "codeigniter", "codeigniter4"],
+      "support": {
+        "issues": "https://github.com/codeigniter4/settings/issues",
+        "source": "https://github.com/codeigniter4/settings/tree/develop"
+      },
+      "time": "2021-08-16T05:07:59+00:00"
+    },
     {
       "name": "composer/ca-bundle",
       "version": "1.2.10",
@@ -494,16 +587,16 @@
     },
     {
       "name": "james-heinrich/getid3",
-      "version": "2.0.x-dev",
+      "version": "v2.0.0-beta4",
       "source": {
         "type": "git",
         "url": "https://github.com/JamesHeinrich/getID3.git",
-        "reference": "ee238d552571c6029898b087d5fc95df826418d6"
+        "reference": "5ad79104e937e7d9c8a9141a97e1f063dd1123f8"
       },
       "dist": {
         "type": "zip",
-        "url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/ee238d552571c6029898b087d5fc95df826418d6",
-        "reference": "ee238d552571c6029898b087d5fc95df826418d6",
+        "url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/5ad79104e937e7d9c8a9141a97e1f063dd1123f8",
+        "reference": "5ad79104e937e7d9c8a9141a97e1f063dd1123f8",
         "shasum": ""
       },
       "require": {
@@ -562,9 +655,9 @@
       "keywords": ["audio", "codecs", "id3", "metadata", "tags", "video"],
       "support": {
         "issues": "https://github.com/JamesHeinrich/getID3/issues",
-        "source": "https://github.com/JamesHeinrich/getID3/tree/2.0"
+        "source": "https://github.com/JamesHeinrich/getID3/tree/v2.0.0-beta4"
       },
-      "time": "2021-12-15T17:29:14+00:00"
+      "time": "2021-10-06T16:23:45+00:00"
     },
     {
       "name": "kint-php/kint",
@@ -745,16 +838,16 @@
     },
     {
       "name": "league/commonmark",
-      "version": "1.6.2",
+      "version": "1.6.6",
       "source": {
         "type": "git",
         "url": "https://github.com/thephpleague/commonmark.git",
-        "reference": "7d70d2f19c84bcc16275ea47edabee24747352eb"
+        "reference": "c4228d11e30d7493c6836d20872f9582d8ba6dcf"
       },
       "dist": {
         "type": "zip",
-        "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/7d70d2f19c84bcc16275ea47edabee24747352eb",
-        "reference": "7d70d2f19c84bcc16275ea47edabee24747352eb",
+        "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/c4228d11e30d7493c6836d20872f9582d8ba6dcf",
+        "reference": "c4228d11e30d7493c6836d20872f9582d8ba6dcf",
         "shasum": ""
       },
       "require": {
@@ -772,7 +865,7 @@
         "github/gfm": "0.29.0",
         "michelf/php-markdown": "~1.4",
         "mikehaertl/php-shellcommand": "^1.4",
-        "phpstan/phpstan": "^0.12",
+        "phpstan/phpstan": "^0.12.90",
         "phpunit/phpunit": "^7.5 || ^8.5 || ^9.2",
         "scrutinizer/ocular": "^1.5",
         "symfony/finder": "^4.2"
@@ -838,37 +931,40 @@
           "type": "tidelift"
         }
       ],
-      "time": "2021-05-12T11:39:41+00:00"
+      "time": "2021-07-17T17:13:23+00:00"
     },
     {
       "name": "league/html-to-markdown",
-      "version": "4.10.0",
+      "version": "5.0.1",
       "source": {
         "type": "git",
         "url": "https://github.com/thephpleague/html-to-markdown.git",
-        "reference": "0868ae7a552e809e5cd8f93ba022071640408e88"
+        "reference": "e5600a2c5ce7b7571b16732c7086940f56f7abec"
       },
       "dist": {
         "type": "zip",
-        "url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/0868ae7a552e809e5cd8f93ba022071640408e88",
-        "reference": "0868ae7a552e809e5cd8f93ba022071640408e88",
+        "url": "https://api.github.com/repos/thephpleague/html-to-markdown/zipball/e5600a2c5ce7b7571b16732c7086940f56f7abec",
+        "reference": "e5600a2c5ce7b7571b16732c7086940f56f7abec",
         "shasum": ""
       },
       "require": {
         "ext-dom": "*",
         "ext-xml": "*",
-        "php": ">=5.3.3"
+        "php": "^7.2.5 || ^8.0"
       },
       "require-dev": {
-        "mikehaertl/php-shellcommand": "~1.1.0",
-        "phpunit/phpunit": "^4.8|^5.7",
-        "scrutinizer/ocular": "~1.1"
+        "mikehaertl/php-shellcommand": "^1.1.0",
+        "phpstan/phpstan": "^0.12.82",
+        "phpunit/phpunit": "^8.5 || ^9.2",
+        "scrutinizer/ocular": "^1.6",
+        "unleashedtech/php-coding-standard": "^2.7",
+        "vimeo/psalm": "^4.6"
       },
       "bin": ["bin/html-to-markdown"],
       "type": "library",
       "extra": {
         "branch-alias": {
-          "dev-master": "4.10-dev"
+          "dev-master": "5.1-dev"
         }
       },
       "autoload": {
@@ -897,7 +993,7 @@
       "keywords": ["html", "markdown"],
       "support": {
         "issues": "https://github.com/thephpleague/html-to-markdown/issues",
-        "source": "https://github.com/thephpleague/html-to-markdown/tree/4.10.0"
+        "source": "https://github.com/thephpleague/html-to-markdown/tree/5.0.1"
       },
       "funding": [
         {
@@ -913,11 +1009,11 @@
           "type": "github"
         },
         {
-          "url": "https://www.patreon.com/colinodell",
-          "type": "patreon"
+          "url": "https://tidelift.com/funding/github/packagist/league/html-to-markdown",
+          "type": "tidelift"
         }
       ],
-      "time": "2020-07-01T00:34:03+00:00"
+      "time": "2021-09-17T20:00:27+00:00"
     },
     {
       "name": "maxmind-db/reader",
@@ -7457,7 +7553,8 @@
     "james-heinrich/getid3": 20,
     "myth/auth": 20,
     "codeigniter4/codeigniter4": 20,
-    "michalsn/codeigniter4-uuid": 20
+    "michalsn/codeigniter4-uuid": 20,
+    "codeigniter4/settings": 20
   },
   "prefer-stable": true,
   "prefer-lowest": false,
@@ -7465,5 +7562,5 @@
     "php": "^8.0"
   },
   "platform-dev": [],
-  "plugin-api-version": "2.0.0"
+  "plugin-api-version": "2.1.0"
 }
diff --git a/ecs.php b/ecs.php
index 939cae297d..a7d4071516 100644
--- a/ecs.php
+++ b/ecs.php
@@ -17,7 +17,6 @@ return static function (ContainerConfigurator $containerConfigurator): void {
         __DIR__ . '/themes',
         __DIR__ . '/tests',
         __DIR__ . '/public',
-        __DIR__ . '/public',
     ]);
 
     $parameters->set(Option::SKIP, [
diff --git a/modules/Admin/Config/Routes.php b/modules/Admin/Config/Routes.php
index d259ce905c..edda5e8152 100644
--- a/modules/Admin/Config/Routes.php
+++ b/modules/Admin/Config/Routes.php
@@ -18,6 +18,21 @@ $routes->group(
             'as' => 'admin',
         ]);
 
+        $routes->group('settings', function ($routes): void {
+            $routes->get('/', 'SettingsController', [
+                'as' => 'settings-general',
+                'filter' => 'permission:settings-manage',
+            ]);
+            $routes->post('instance', 'SettingsController::attemptInstanceEdit', [
+                'as' => 'settings-instance',
+                'filter' => 'permission:settings-manage',
+            ]);
+            $routes->get('instance-delete-icon', 'SettingsController::deleteIcon', [
+                'as' => 'settings-instance-delete-icon',
+                'filter' => 'permission:settings-manage',
+            ]);
+        });
+
         $routes->group('persons', function ($routes): void {
             $routes->get('/', 'PersonController', [
                 'as' => 'person-list',
diff --git a/modules/Admin/Controllers/SettingsController.php b/modules/Admin/Controllers/SettingsController.php
new file mode 100644
index 0000000000..1308df71f5
--- /dev/null
+++ b/modules/Admin/Controllers/SettingsController.php
@@ -0,0 +1,105 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright  2020 Podlibre
+ * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
+ * @link       https://castopod.org/
+ */
+
+namespace Modules\Admin\Controllers;
+
+use CodeIgniter\HTTP\RedirectResponse;
+use PHP_ICO;
+
+class SettingsController extends BaseController
+{
+    public function index(): string
+    {
+        helper('form');
+        return view('settings/general');
+    }
+
+    public function attemptInstanceEdit(): RedirectResponse
+    {
+        $rules = [
+            'site_icon' =>
+                'is_image[site_icon]|ext_in[site_icon,png,jpeg]|is_image_squared[site_icon]|min_dims[image,512,512]|permit_empty',
+        ];
+
+        if (! $this->validate($rules)) {
+            return redirect()
+                ->back()
+                ->withInput()
+                ->with('errors', $this->validator->getErrors());
+        }
+
+        $siteName = $this->request->getPost('site_name');
+        if ($siteName !== service('settings')->get('App.siteName')) {
+            service('settings')->set('App.siteName', $siteName);
+        }
+
+        $siteDescription = $this->request->getPost('site_description');
+        if ($siteDescription !== service('settings')->get('App.siteDescription')) {
+            service('settings')->set('App.siteDescription', $siteDescription);
+        }
+
+        $siteIconFile = $this->request->getFile('site_icon');
+        if ($siteIconFile !== null && $siteIconFile->isValid()) {
+            helper(['filesystem', 'media']);
+
+            // delete site folder in media before repopulating it
+            delete_files(ROOTPATH . 'public/media/site/');
+
+            // save original in disk
+            $originalFilename = save_media($siteIconFile, 'site', 'icon');
+
+            // convert jpeg image to png if not
+            if ($siteIconFile->getClientMimeType() !== 'image/png') {
+                service('image')->withFile(ROOTPATH . 'public/media/' . $originalFilename)
+                    ->convert(IMAGETYPE_JPEG)
+                    ->save(ROOTPATH . 'public/media/site/icon.png');
+            }
+
+            // generate random hash to use as a suffix to renew browser cache
+            $randomHash = substr(bin2hex(random_bytes(18)), 0, 8);
+
+            // generate ico
+            $ico_lib = new PHP_ICO();
+            $ico_lib->add_image(ROOTPATH . 'public/media/site/icon.png', [[32, 32], [64, 64]]);
+            $ico_lib->save_ico(ROOTPATH . "public/media/site/favicon.{$randomHash}.ico");
+
+            // resize original to needed sizes
+            foreach ([64, 180, 192, 512] as $size) {
+                service('image')
+                    ->withFile(ROOTPATH . 'public/media/site/icon.png')
+                    ->resize($size, $size)
+                    ->save(ROOTPATH . "public/media/site/icon-{$size}.{$randomHash}.png");
+            }
+
+            service('settings')
+                ->set('App.siteIcon', [
+                    'ico' => "/media/site/favicon.{$randomHash}.ico",
+                    '64' => "/media/site/icon-64.{$randomHash}.png",
+                    '180' => "/media/site/icon-180.{$randomHash}.png",
+                    '192' => "/media/site/icon-192.{$randomHash}.png",
+                    '512' => "/media/site/icon-512.{$randomHash}.png",
+                ]);
+        }
+
+        return redirect()->back();
+    }
+
+    public function deleteIcon(): RedirectResponse
+    {
+        helper('filesystem');
+        // delete site folder in media
+        delete_files(ROOTPATH . 'public/media/site/');
+
+        service('settings')
+            ->forget('App.siteIcon');
+
+        return redirect()->back();
+    }
+}
diff --git a/modules/Admin/Language/en/AdminNavigation.php b/modules/Admin/Language/en/AdminNavigation.php
index 68cbefb3eb..c2e8e4b696 100644
--- a/modules/Admin/Language/en/AdminNavigation.php
+++ b/modules/Admin/Language/en/AdminNavigation.php
@@ -29,6 +29,8 @@ return [
     'pages' => 'Pages',
     'page-list' => 'All pages',
     'page-create' => 'New Page',
+    'settings' => 'Settings',
+    'settings-general' => 'General',
     'account' => [
         'my-account' => 'My account',
         'change-password' => 'Change password',
diff --git a/modules/Admin/Language/en/Breadcrumb.php b/modules/Admin/Language/en/Breadcrumb.php
index 9a1ef1c2f9..63564f79d9 100644
--- a/modules/Admin/Language/en/Breadcrumb.php
+++ b/modules/Admin/Language/en/Breadcrumb.php
@@ -16,6 +16,7 @@ return [
     'episodes' => 'episodes',
     'contributors' => 'contributors',
     'pages' => 'pages',
+    'settings' => 'settings',
     'add' => 'add',
     'new' => 'new',
     'edit' => 'edit',
diff --git a/modules/Admin/Language/en/Settings.php b/modules/Admin/Language/en/Settings.php
new file mode 100644
index 0000000000..8864c87fdb
--- /dev/null
+++ b/modules/Admin/Language/en/Settings.php
@@ -0,0 +1,23 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright  2020 Podlibre
+ * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
+ * @link       https://castopod.org/
+ */
+
+return [
+    'title' => 'General settings',
+    'form' => [
+        'site_section_title' => 'Instance',
+        'site_icon' => 'Site icon',
+        'site_icon_delete' => 'Delete site icon',
+        'site_icon_hint' => 'Site icons are what you see on your browser tabs, bookmarks bar, and when you add a website as a shortcut on mobile devices.',
+        'site_icon_helper' => 'Icon must be squared with at least 512px wide and tall.',
+        'site_name' => 'Site name',
+        'site_description' => 'Site description',
+        'submit' => 'Save',
+    ],
+];
diff --git a/modules/Admin/Language/fr/AdminNavigation.php b/modules/Admin/Language/fr/AdminNavigation.php
index 357b64ffab..b85b1a3025 100644
--- a/modules/Admin/Language/fr/AdminNavigation.php
+++ b/modules/Admin/Language/fr/AdminNavigation.php
@@ -28,6 +28,8 @@ return [
     'pages' => 'Pages',
     'page-list' => 'Toutes les pages',
     'page-create' => 'Créer une page',
+    'settings' => 'Paramètres',
+    'settings-general' => 'Général',
     'account' => [
         'my-account' => 'Mon compte',
         'change-password' => 'Modifier le mot de passe',
diff --git a/modules/Admin/Language/fr/Settings.php b/modules/Admin/Language/fr/Settings.php
new file mode 100644
index 0000000000..e68c87c7a2
--- /dev/null
+++ b/modules/Admin/Language/fr/Settings.php
@@ -0,0 +1,24 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright  2020 Podlibre
+ * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
+ * @link       https://castopod.org/
+ */
+
+return [
+    'title' => 'Paramètres généraux',
+    'form' => [
+        'site_section_title' => 'Instance',
+        'site_section_subtitle' => 'configuration de l’instance',
+        'site_icon' => 'Favicon du site',
+        'site_icon_delete' => 'Supprimer la favicon du site',
+        'site_icon_hint' => 'Les favicons sont ce que vous voyez sur les onglets de votre navigateur, dans votre barre de favoris, et lorsque vous ajoutez un site web en raccourci sur des appareils mobiles.',
+        'site_icon_helper' => 'La favicon doit être carrée et avoir au moins 512px de largeur et de hauteur.',
+        'site_name' => 'Titre du site',
+        'site_description' => 'Description du site',
+        'submit' => 'Save',
+    ],
+];
diff --git a/modules/Install/Controllers/InstallController.php b/modules/Install/Controllers/InstallController.php
index 59bad8c901..5a65ce4475 100644
--- a/modules/Install/Controllers/InstallController.php
+++ b/modules/Install/Controllers/InstallController.php
@@ -243,6 +243,8 @@ class InstallController extends Controller
     {
         $migrations = Services::migrations();
 
+        $migrations->setNamespace('Sparks\Settings')
+            ->latest();
         $migrations->setNamespace('Myth\Auth')
             ->latest();
         $migrations->setNamespace('Modules\Fediverse')
diff --git a/public/favicon.ico b/public/favicon.ico
index b844d1d06dc8c533874fdb40bdb0701700dda75f..9bf9b97aa31acf5e8dc1c93087eaa79b80d60396 100644
GIT binary patch
literal 21238
zcmZQzU}RuoP*4ET3Jfa*7#P$T7#JKJAbbrc28MG23=A3!3=9e&aR!Ju0}jwOh2j4w
z9u0%hG%%V5M$^D(8UUq%dFyQcAG$jA|HY>}|6hK#mm&-@<It5U|L3l?BBGvQ{J-aX
z`~Sy3p8bFF^Ep*9$jsemoAA0}<Do37+KJ5%>kp)2bwk$-uK)Kw--6qJ<IU;+C+{r%
z|LEJJ{|~<2`+xAt<o~zcorB9`GaDp!_2rTON3YNR|M1(x{|~=C_<!u?y#IGTT!HJm
z`|0}s&gmQ&ZdkCv39bfY&bAZfU^VSing6#>WdgHzooPT(15$^MHy_CdtA*%e2DA5F
z=t9vqf4wbO9F*2zc-8JG6g4pWVe%k)*O^8XHRyJO_%QoH>R}k&{*^n!FzjEl#S_Ks
z8*fhj@1Ds6SJyLJ;Qy_6=TX#v>_f+(@b8?#3D?&*M+7DOLFyN6c8ANu+}Jxu2prcS
zc^JO(eE<J7d*lDF-Iw?uWG+mc5Pj*{?*D7{#QtBmKl%Ul*T+%Z3`$QRyI}Sr(|gXf
zp{ONf4>|IC&v#(>9p(m5xSf5lj%IE+_i)pHP(Fj%hmG!-#`+&r4qSV6<p1LzPbqc_
zsNA{s>e&BHNAmu6Ok>08cWiC}<sp!JD8V2zu$et7Hd@z@rh(BkfMZyIZo;5(3I_%T
zhKA8`3X<xE(Y!mFcSqB}Xc`zz1EXnRG!2ZVfzdQDng&MGz-Ss6O#`E8U^ESkrh(Bk
zFq#HN)4*sN7)=ACX<#I#fvHQ>{;%7g^ncH}*8c~uO!|N5%H#pXAUA;AvUXp>|0#==
zX*SkBf4$xR^N+VsJa0|T+&-~-Ky%{f9&Y?UcdaGW!T~f#4qE2{GMiX;4756sTX&yr
z{@*^8g`#i(`5m-YXrTQ=uKh=E%=u5rIt9?05_0VxEc$kyt|KcA%v)zoll5}+4j0f`
zn^~)jNe+W^k2d2h>p*7W^T)kUH~v5R{sgCfe0s6T-T!hMyygy@97qi09#EbKv9aOP
z_g0bQ|7puK@w$Ec$;$t8R-64lczF_h4I0RP(0ZipCo2E<&Jq4k&AhYWVEX?_3+4as
zIp2n|R_^B8GvIo7>QeRppuCRF?;tUd+a@nkBsvU0YpOu{aN$V{<xtG(nZ^IV3u$d0
zs9iL3g+AUe#AP<RI4B)~)(C>kgkjM7K@f)VLG;3nsOv1z&B3)k6r>j&AGtmYr`thm
zNzv6~<AdrBbT^R0zy9VVN?2pF3nbP*PaLP4LH2^uDo7nM7+>DM|M?bC?g6dI1KCR{
zrk4LnDFZG%-i9|UCoPmE7zQ&}8sIg9*l+=-|5^M5?L%K@jBY+?{U<ST4^ngT&N94i
z-+rQkpnE`VMszoj%LkQzAa~)z_{u+!y~l6PC+KFF`GnR(gVuk~T4{*WyagK^|3Cgg
zz4{MS=79QLF!!O;%eDm&Y^&@zRfE&L=;kfj<cc@`LE#B<)5=}pDD6v7nFs0{KKOc{
zpni}Uq+rlm`=wib{<lqGg!==u-hR{J-2achKO$(~!i~;wedzv0=Y#xl=fh=!W`f)g
zQU}T}r|z!!5849&5~C#st(6D$NkHWpC=Q6R3lw&s@)+Hp`1qi3CC2Qbpa#^Q!RJ?O
za-i_K^5OtdX<#si!PS?C|94JjCpzsThsBg7D*x|(yf$RR0F*zbE!8B;@33%~v0MkG
z%{`do8rf~2JWo!)59V)Vx^J%Ne^8qk)Q>>6W3aN1-&**8!hA`J;vL!lF!uCi+W$f0
zN>^SSB&yD#SNJ^o{`mjZmxuoEJ>UKx)b512m$oz`c+U@L-_JnfwkeQ(bhP#F=zPa$
z_>QK5(KIlc21e7sXc`zz1EXnRG!2ZVfzdQDng&MGz-Ss6O#?$S4bbgCf>DbGWe5NO
D0pgQO

literal 16958
zcmZQzU}RuqaBu+83Je-f3=Con3=A3!3=9qo3=9nn5OD?&aAIH(=7wMp7lhlUF#I3I
zqhT<b21e7sXc`zz1EXnRG!2ZVfzdQDng&MGz-Ss6O#`E8U^ESkrh(BkFq#HN)4*sN
z7)=ACX<%fhftf4x{%<~#|Nro{Y5z~&S@!?zgLMOnPu*Sd|LFBu|F<41{y%56>HoGV
zj5L|gn7`is|D|WU|3CTpd{E=7FAx1+vc;2XVbDI6`Tw4CErZ(6*y7~y)v5oxW^hs%
z4vhan=3p~_D2Sc8zxsd2G*+_1V9T+hAs6rH@v`qiCt3cVwp9K9;~!6ky#GPrF>kFE
z$zgEh`pjYBcaZ<jJ={Q&|9fW({D1uY@v!kfC=8}7Rwg<OmTmJR==W={j{FDZtp{K4
zVyM0ReDD9wNAoenLGB<2?>*oC|MvR}Sj>C&|M;y1|8KrKi$xB#o?d?-m1zHOKUqQ0
zyp_Ac!RB>NXa7HMo%R1!yCVKC-x2hG%3>w3IH;X`>h5xa<`4>x^N%)z%>&iLAbU0(
z$^eJ$iXB1!`{#*)<<{(tBWTaT%M-wALGB`i4_=-~&^%;+;xcdD{$zsY5c2=l<0S;$
zJ#m2yL3==Pfy<rf;>7rW@*+io?pm=Un4r4|`5zSD=<Y-3gX(xf=A6E_lAwEG=I%b*
zOwirSwg(V2j~ea91DARU+B1E*HbM6ux;mAhIWYgP*&9pHybDjZ{|Dtsm>zVxZ?5S7
zd!KI-G>1^Ufz0TgBZ$}SpmLayIhzjW;57r;{gW3d5an)A++Yg>Q2lxS(I%qIAmnb4
zJgA@9Ih_rw`<HI@`TykSGlF)_SgwOrKeE4(*`RV4WH%vv`PrWTt9D2JpRru~|EyI;
z|2H1W`hWZVMS|`jWG=e=rDuEoFWThxzjFo$*dJ4usQ%w`uJ!-pA5RI|1*(sc{YDHM
zWEZ*{1`Geu_eTW%jO<oW8X?Bd=xUDNoKKQH$aW4E_Q^X-!083uZ^ZC>X7m3Cwetpx
zUr2SwwO2>~6Dm6ig~NpT68}MYk5sz{TK(nc`~FXuFG+UXBZmv9%-MCO@jt2gZXm({
z<VKKNL2gF&12xza=S%$uwMQ>J+4le8*ZYH}Yyi0h<R*~YKyIXlUx_gT)b8w=#rJ<8
zF~|+XxOG&`$ey<tjsMa3A58<JX<#%BjHZFnG%%V5M$^D(8W>FjqiJ9?4UDFNk(>rV
LX8?@iksAU4@Y2ij

diff --git a/public/icon-180.png b/public/icon-180.png
new file mode 100644
index 0000000000000000000000000000000000000000..937c4c6c80ad0926a8fbfc1783d26c76e0698072
GIT binary patch
literal 17522
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
Uo8|nIfq{X+)78&qol`;+0RI5sUH||9

literal 0
HcmV?d00001

diff --git a/public/icon-192.png b/public/icon-192.png
new file mode 100644
index 0000000000000000000000000000000000000000..7864f7e9495a68e5e5bc6958d602bab2c4733a2c
GIT binary patch
literal 5913
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

literal 0
HcmV?d00001

diff --git a/public/icon-512.png b/public/icon-512.png
new file mode 100644
index 0000000000000000000000000000000000000000..9998e36ae442c3aa2a55834aa093163d5dd05dbd
GIT binary patch
literal 7340
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

literal 0
HcmV?d00001

diff --git a/public/icon-64.png b/public/icon-64.png
new file mode 100644
index 0000000000000000000000000000000000000000..cf8d2cf1cc1cb9704de282006a76a1ce86568be7
GIT binary patch
literal 738
zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4rT@hhPm4t-!L#RS_k-qxH3#>W1ZH)H>*c#
z{=|~wTem&AaR2MW=Rcot%;;=9v+L3KM-uZV?0I%+-}B3o^C$4n?m6=6+R<0n1n2b5
zzj=Jgos({x7Wr&ly7|%hJ<l#j?p~$6e1_4gSy_iRUVMLBb;;D$b9<itc)a)dWranP
zdoLYep4u)jyLZ#0^ULm>WSidk?B^4m<uhXUuG#+Ng6Q17o1gD>Uf7p&cvJJ)-2vN|
zwVd0dy?pxAtA{3DKB%~8a`2878HYBkymwk@@s#BK>tq&8Tz>ad#mVjAyH>JK@3dYw
zFJjlKpdHKek8Tdyu|jNKf85?R6D}Y0+qUfP*9YzA_g;8^d%>;aXW!jSJ+S`q_s7bM
zr_8*5WW&RA>Px3R`SI9l?YyF6TNtObO}%<}_5CxPGrH{8&)@y*(xI1EJ+~~;TQM{L
z$mVI+4zGJ~cE#OOv#uX4KDO0#^_+F9=7PePv%n*=n1O-s2naJy)#j6CU|{t1ba4!c
zXni{+Jou1<h?}|4jfNEw47-&ak2t;QVii4l&-%vh|Nq5LoQiptW<KdnbAGklp(i=#
zzE3#m(BZT&;E!-rGk4V78_Rz)Uzyqv|K0MLo57Q~a86d<jrly)XC-~l*4!7G_);@B
z_c7b8r&V6oZ)&eZx84srV<xcv=ec$7=H0VfZY5*t@&ACr9kl}ckZP^WO~0>fxUt;5
zPQEwQp=VK};e^L&p*|@;?YQ&LG8uQWEpzZ|p81e{Qh^b78XxbO<`{;}C-|Q{aADs3
z#AE|cTC4nphbf{ya=dFAW7MTv&#pb?Gf%!lc=H79y!R7g4XQH|<Wr7VCD?Z=-4Cv+
zII?c$V_|{i849IpZ0qJc=6~q4Z~qb7ox7&V?bygWA^PUMP2ZP<Ond#lWxrYQk8iI6
z_dWm3#or(Id3k#KoR6P=O{*(^`1ted-Cx|-2WW_J9pyhCVEfnX)VBEy3=9mOu6{1-
HoD!M<ysCpf

literal 0
HcmV?d00001

diff --git a/public/icon.png b/public/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..3c182ad441f3c993ef0d680db2293ebe0018bcb3
GIT binary patch
literal 7027
zcmeAS@N?(olHy`uVBq!ia0y~yU}6Aa4mJh`hA$OYelajGa29w(7Bet#3xhBt!>l<H
z3=9m6#X;^)4C~IxykuZtU`coMb!1@J*w6hZk(Gf#n#0q@F{Fa=?cMwp^Pbio_;@<%
zv03sQ_1NB|pmwvlr(Z^CO;bx;z4XWWA6^Hy@R&uVB^m^5c+a-&bE`qegBj~XqK?Jo
zaE3^1oskt;s-wPi?Lm9>TW)WY{0t_}6z-XJ*5moR`;%>?lKswA{+suFSN(i`nR9_F
z&Dx*uTmQZ`_ImC8^r^q!S8iuuSXr}#f#D?w1A~VL1A~JT69a>g5Cg-62@DJkEi4QS
zDk=;N3W|&j44j;!N=Czl;>2JVl`(hg^Yu3WYM*|5zdCG<hPX*QgZIZ{8<U@Ad@lWT
zzBqqhXofgrz{1ey>t67@yBr++^wQ_^uX%n*hxwPX{oHysp1H@V<-kAl`pcb-JGbA{
zVxRTCnonMH^XJb`U)(;<RVv6J+QC?Nd6sGFV^#4|wqGx=ii<TAcHcbm@~XC9HD8y)
zjM~2*H%mVRsB@*wdhfGs^Qphz_e9UoC~U2NysLCB<Nsr)ua)sxHQYM0=U3FtkEi~r
zvBhOCO4w%*d4|EKL*mQ!nopmK4yV38wX9oTi(%{SD=|logm*|baWuWHjyJP5P&~t+
zqugvaA@In7#lN4Oa^9?eBW6br%K@VsB_C%M)f#X8fA#D1+4tCkx+5EN_4i$wDVeZ`
z<$%P|1NF~C=NE3}FX);fdgIp><J9X1ub<)S>12>-);&A*-`dyf4L&gIDCL><JZ-El
zw^wFy^I_<@z<bu@|6S?zb?+N(7<BG#ON(^i=;_<d;C3Ly{=kEzZzk`QZv0z4{q!|8
z770CL24@leH#^^V&*uHZ;C$__a>C{ZA2=Eme})wwt-t+cYS~xjo(ZXq4+R;RyI%hL
zz3yhpT=|5ace!cII@~;N3|}<m9(`VWUUvU0_Jlu4kq@T1%Na{wSl%yEC6@j7{{EL%
z&GrY3x@KNKp1<$p&K>?t3*7JL*k#z~*%f@$ies1-zK6{=Z+jo_jc*BG-57KNeSRKq
zfAfBpzPwSxNuljL|9(uHZDqVgr<WmuDfl15<n_B%3J$AZ6BAQs5Hs9cwaWO%>`&}7
zYBs8T*!z0lm77b>&a4!AAbDg;&>C&Vfaw)d**e$neZ4$i-0wWk0j5U>?bzxYs_uS!
zseQV9{oZ5y*0ORmT<$pd-|w<J!`0m%H<iv!jS>8i$n-#jt-hhGb8pN$fgc8p1wzgC
z4%SCynGA&$nC_`F_!<0Q-V*K7V9WSknBnLH{t2$%ujL6UF!20iIO)Q2=lfA#)!kPZ
z1<rpp|H1r3xSajY-`3UMX_?FlTn6)A^E>!`oYQc|pT|d%VI%jK-PdD-8BXZVlbG@K
zF5^okg?q2A?-Wg08turS@pNCd+44QM2C)oBX7wMGZ&+8+7;wy*If&Ka&5wTZKMV&>
zK00J@yRN~6QQ)$5*&pT&6K;r9-2O6EwOfSoLhN_;2IEfO#>j8XOE?;4T-*4L|3Ffb
z{ejy0X^#~h*YY<+d_Hfol=(n{S?ngYqdP9XVtBFUcYNwy`G$Kb5nLIi3@!&}{$gJc
zE;)@UN}3@sZ`nV_7vVarTYhRbuH|Le{f|-N%H7%P^4>BxMM*Mj{CNI~JwtQX#wBYv
zpIpn$ApM^~Vp)YlfOI-zlsLn>e~c2#ZU|JAbH~fyU&ZiYM?8bu!s5c4n{G2ji!!j)
zGq^3yP4>xVQaE*H_CE%RsoTynZBb*0`O9pOl`EAUB?va4T_XEdk-LL7(}4&42X<_E
zx|3loM?*9#14HtqY0sHL<Qd-mW>1*&XeUGNjLLO(40*Bju8a+ZS%<xw?4q>9X8$*f
ztqDy0^6XyCY8l(IHD~1Jz5nx7`s{i4`*q7df4=qky!FT0)a5<qYvySkD3GcB9Wk@|
z_1bfW631g_RDU*~`+oH~+vUY)O7neZ&zqI?FU~qX#yInlZ=>PAGcq-6udI5-Q1JSG
z#u3iv7sJ0zw_Pu<Y23~?SK`n8moM*cO#Iq9cj?UD=`kT@@q64v4hS9DC_d4)_(Q<W
z;vXI}=g!w>_v88Iy*2Bo<=n@*Ne|lWW3;*4GLnn)R$DTh)B1k@bKc4;=l7Lu{`z0B
z)3NUMz3Eo+&tjE-IINGYj0--UeQNFeU3)&uTC9`4bNk!AJ3PNW+aCWGl#{bAB>AjW
z-`;Ju=gKUP_MDObdwKt~s8DH!jsHIFeZ4P4;>_aT-=?#t$4i`Cuzx~F<BsCw)4#Om
z^mt@HyXu^JeBaJZZ;wuQGkT$)a#~$q{E>6XX=VFWWnv3%G3<EXJ^Swe`^$Gcsz~_u
z^V|XZbHe9e9yzHIcVCC)gc94owY%p_W|z$O)46=~@0;kHC2}X2&sKi9y}K?hD<qfU
z&nx}?w@!UG?vL{MeE;_q<J5O+?_Cph_vN@yw((5a@5$EFYaiH$o;gwbf7xr<>e^M6
zk`LZ|nyO#FJVb5T|IqCGM^8R~JzgIqH|y`yP4QpnpPTnn`E1FHf9KMcW=gYVPMlHr
z`*`|1?fVsfI*Sqx9kM?1Qz4C+-{g764V#Ka-e%jMb2p#QTlDV2k=PJj*Qtyj%;*2z
z;<$+2@b3TX|NqH9eQMq}%~MQ$k?i_2mVy_hHZHcm)=|EvXn~KF;Jy7jbc-*gl}%f8
zieX3f<*Re6<1IJ83;l1u|3gyc@9qD?vo6{S9-Z<;bbq~Lqm*mK@zDP&=XU5Wk$(7e
zO?j@+n~UGX<Mp<#eCOFvnEK+{{-dSqZL-!}61bchpYJy>y4*f?ftumd`rniPNABDE
zT6}5Pce}4SJHI`YFVRzqh_Mk_am+UJDr<xKe_cJZUq>IrKc01E<s+Ap@TJx{C)L@`
zSbW>|{%`5ZyKf#UA3v|Gl;D|FV^UDcxZ$JF<)Cz-=Kr$(=R!>1?wE07LCNvS*4#du
z-aW9tt&_ObHOA%0{LJ&6?hTta@XD{wzwc7YxZx(xfu?PCUrW+I<S(x9n#GY2RLcI}
z?98sYuPRt<)R@FJR{GW^2Zu5Wy#D|0ul?S0fB){DubZpJG{YrV?$7Q=ao^Y5e-l2<
zm@Z(<u(j7el=Z-uSKQq4V$%O^RXwd=)xl8BG(%+L!}rpL2HPq=ynm&~-qFx{)yyqa
zltKFLv`>nK2FExxCf^YL@Zim7)@jjqmR?$B`v0g4OU>htG0$hmUHNt`*qC8z_U|i?
zo!;I0%AGw)XZ4NZ&kx?{dz%%OH$?8ZEX<(%WbP+<5%mQ<&Gq4HJmqq)sU_Y?dbaj$
zb>2CZw1<xpV{0yanWEY-(cnjYz@9*z&zu@Ae{yPH&18BkW}JWX=sxA&jCL<Bg_hbb
zSvQNJ!#u1oCdX!z^uHZDgl1Y+tT?bEWq#%BE^B5T)|vpDMgJ~!-CLExw!rCQPoesP
z?{_~Q@$+Wvas9UPfAG<2W|kl9SGVv4oabpM4=uM~tc^Hwf%&WtL(eSL<^0_Y&udL>
zxg8inj&Z*DB3Jc}bu&Xx$eZ0OKlbJ?7Gr$3?aueBCSjq%4B~4nmZyk^|MzoPF8+FA
z8l%M0wY!ggcY3rmmg$cLqXAPIL(E_OV>%3rg~I=D-4|6Yqjcc0=G-Gf4z}W}Ls=Z&
ztU2?Kk0Jbjw=wsD6%u#Ep6_HhzBW3OEn!92+}ErQeh%J`RgP@ve7|&NW}3$x!GP-(
zp{@*T)~;CLmiqhNbgu5(#XmYG3pjs$p<Ud%^yWY9g(?gZt0L-4?*G5^_Qvy;vmb1}
z%#nTPEqb2y#6JG#Oxqdx!hL6JxgGpcpTF&Qt)WVF+<fu-wjH$=*16NxxS7soFutAY
zwOhSVXcNx?gEuxQ2CuL7|2u6rC(3MXG}DZNbq>FbA8WNJZdkdc-1^PT6>0Jf3^NKg
zf4*0Fzdv^UEXIU_cYoi<o;gtIogm9{pk?#Iwf2SP4ed;Z9g>1K%{McY3NQ%gz0*~_
z%O9@DlU4T5W1;=Vl9Nw_8HDxLrMx`9=DsZRhMp_-A4Av~4GxBUN%$u7?f2sP{0OI4
zw;P{q&fogy=W33IHSCY-F8^n?{IyNk;;-@VYx^zIZ#NtNT*c9_`1n0d$(?`m4VEcN
zwlL-xe0$(yXUrgcM)Xa>oC7bXAIvVuPuW|r`o-qplROURgm+H9kia7H_tQ<um}{TI
zedo`$VmffpLq6xxqIf&&FRPcG_cQfoSXRt9ql77e<(>gI!-1C7nV-u{857*i878k=
zmaY&Y%<zqo;qj!uqEEh@k7ZDv@Ns2c_WAh87xVAS|6TR8blqf~*B`?#|BgPx;A5b^
z@Zg$QO@<f!6-(kxZ5=nwVwhn$<^A3}%M=rTt||J%n^N_)Rdx2Qd-sEU8IJ7o+7`{Y
zeEBC?hr?SGA98j)jI91w+4}FuQSW07tKR<A4c*IYaC`Dnz1UQ#B7tRvl1JKBu5_w5
zTXXK`?$vKugF;yywte62?i!yZ@H+b1WP!sQA12$`|2<_@9dtYG>nbLN$8#BGUyBKO
z;eX83qwTm*%zv}EJ<C#57~C?RCG6{MSm*RhIQ+j^p<#!`x0<$JlMVMJckbF2z9Zb6
zc|xx8gWmZO(J$^U>pnZjU`9lfarc$oH>xKW{><HWNb=PxCWR|MyyaYEe7-S$dDnLO
znyAE;uXgUXr={*&e>*$%R){!*>Ay+rsbUMv3!kR3H6#|i`Kp&~@^+><vq6#Mcg8yp
zRIW^x*8BWB$s&o(&qpuzNcpjhuCM=Z<uUTe>rQ?7j`_qE%k;~t*;c0+9@m`?ne*q-
zcN<&NtAD<qw|-pv^)9>V*}Xq!pWD3QarRER`#HC!C3c;^TohYz<ne*W6R#EWth4$)
z=iJ8~7YZfbFYHg&V_Re)mOfkiQlWfv<m2jR4;BV3e#NAabNhGE&fH(8CY_w-9~bxT
z?q46tsTLP=qBbwf+4E$P(cY?6n}23rIMMao><Fg@UtjE5&Jr2*B^H*mwx!P4wkE%C
z@A7$)KiQsGu;s^WU-#$ZaXpz^h7yW)zkf}9_QU!LXLBHb$o6&n7o~)}zEm=maYOR`
ze<h3sx0kQi;Xk*};L79+%et?dY~~g(eRos#s7ZP`d+8tZU1@Q(Z}%!l96fpBi~V7-
z%eOx6ymc?8f+v{gM`3Dx?dSLVJ_^5f`}ASX4BL+N(*9O@k0kDVJoWEccHRpA@Uy#O
zgpBn+?p_l(mGQ#dN2j*%7_6Bb!1Jr{(9f*m(9JUY_jfer2^_iVIj2V{r|m04Z%*Qg
ziX%LCHZUpl9gLp+SfB0bQyaGT_bN)COVn)HS=DQQd%^JsbLao|Ihpb7s@3xUha;c<
ztG=fzy6b)SZ0q3SnMV%(`dMGO<4e{~_P<Lz>~CL7n`N5D_G_<J=XvKEy#$fG$|vr%
z?^!!m|IIfmlxn<nEZJb)zxr=iXM4MCx8Jxqr@nB<X6MI2xeP}_E`QJ8wJ)U@)B-6{
z6;hwGBdhcG!|d79x^3k)-d}iq@`dyJ%8Ju>3A-t-`;zzbVY2Pte5HNw_q;N`D%*TF
zvN1v{qN_(dMRD2x$BWinW4{u*lSN?Bk<GfyE%~PElW!Dky1=gIWy5#GbKj*1pFjWm
z*T*?2)akR;yJ@~V*4bF2xtU=r-=ElxHiGfqGeuv_D>mx-n_+4{_ZzhF^Xl>b@4KI_
z>i_R}Qso=dp1-&6m+_sLe3bL~zHGDdYhNEdFFtR#`-)zfllzGyoN4F(Of+`$|Fcv7
z!<{lW9VLZBCVdAl|NAU_JW<^v`UA`PbG3iZ>O7j+ci7_FvdQ}@Kd+0m*JszN{`ddn
zD!v8_j_oRY-m1g}eahc|@4BVH?Xp9bbMrXng!=tgSdsVTzzSWF2Ze9`Ivex;+dlt)
z%<KNclbsdT{ds(6a^RVcn%~R!YnZMs<9E3JJ%5+p)06evK07QazjU|k^4v*p-ZgLd
z*k9OPdOusf?#W)wk2mg!U;cY@nsTz5$~(0ayS{{dezt$zs&s}!k?)_?eDv0--}2S#
zvCppHNgx02|Np%H^!@)Y#eM!7hwZ<tvp#pmt_^RjzC``JR~oNXU-<M_n9k0xT4^js
z^40hAmi>RMv?lH9d4?nG24(ft`Q{9dH{`zee%hy=?)7$6wd94BNmlO~Z;Ep<^f=o{
z?c!a<-|*o=v3^LcHXB1}$8*Osp?g06Pg%>su$h6O=kT?=Z+HCSU(3;uAjZ%T*tPn9
z?CCFAF9I`s8D_9DBuu$g@>M=cnBkxf1H<AA+gAU-u!;dxifi2Y_~hIrv$b4cZHZmK
z|J~jMGL*Yv2J4Mmld4S^BkFQ@zW*Pxmb>9Y!e$<W;tv6g4URdruU>}5{cR6pbI8cv
z$Y>z<@zC<>a{K68tF|%<tnaNY`1X^D;qQ*Ut<wMfuH9nb_-^<0P4)UWEDcM$dh2s{
zzkMIFmapN4z>Q<k<_r>Z&t0i+N_`T>?yy0G!9hRi)&8|0ZNC^erZF)@blv!R|J%y{
z>qHm@ycxIKd{XA;U`lYzz5lg-l?bCilGSnMCI*YS5`P{$8BR7~6nMnw_>GyNVAbxj
zzcxpA{XZGR>d^6*p_=c!I0MJVcl#et-8sp37emKihWPq7>SnA=0cCG)&(FI1KjkHp
z!V#16=5qf#eH$4%kG3Y<p8u^}O_N#SjGSFiUi~5GCI+KddB3cy-prj8dW(T$<1=At
zdxjH>t$(E7{!+f`3ZuZIa}8^E&(~wva{uD?e#t-n9`X!|?|1|l8Q!LS_^-fN(8R%z
zvHslyd+Yio1#=iIIyo3J<eUG$tljc~QIPRr^!(pBj0^J2{^*|JIgshXa%bX?djSn*
z20!M{WQaJhZLj|HZ25nU>TFCQ8Q(taIan{q^nmA4qT^it2^<V7j&0kkFZpM>1A~r|
zox^pzKOWC3FEaRS+g<i|P2{1uo_|~RFBM|&zEIhC;j#Y?XNCl)qdsrXo(=uqym`Nl
zPA|g?#~i*bDhvjZX>qn!EY06r{fJ6@$>PwTHj6)^=0Z|0XTwv`;D6iyd@y|dx7K2J
z&C}EOHNU7_oA$`niG9}02Hw@nPq98<r@_$U|K`*G&+hei=5+Im{Ce!@z<lG|qtj=5
z4lFEs9y(t$`dWM-gT&g3Rri@UpPvp&FA`@UWhGC}X?6YgEeCFW4i{r+)4%rXv10DB
z-|fx}JU8ct|Lr`^!ORnwvuEF4$sf6&r1cmLn6ks?rAIO(INW{tk3BuUApSoGM}wdc
z6T@EP5B=>763mJW8!VXrS8z5MzG^$Lto!;69gYI0oOic3=C8}C{;10QUxKqCRj8cz
z&aaiHtqmC__{O|_Z&R_Ncx!&~{Z9f6r*+a;|Gl~#K26$w<GD2q7pm5MQ*UROp&%U=
zACVVZUwQM+8LlJ3Y>Zjr;lDm!v1|VKM36yPD~&Cw@<H3_Yh_6X-Y^7o+n#NZzx><q
z#qslOe^06~XbCzBC~o*TsryvP=h~{QRck)+F(u4A>RgpHVSeS;twz@N`3Kf_Fs!(-
zO7ywReA$Sdn~a?|eEaj+>b`!&#zjBVwfpMDIUVLF{rcCNe0&z;--z@D{qw)?seAI{
zd)kKn{plOlPoK^hs>8SEhVAavI=Sp`m-;F&=%}#OFjvVjDNJO}uWDptI9@wCU_Lra
jFgi8DNtOAazxH*1gKz9zvA2kUfq}u()z4*}Q$iB}^e~5!

literal 0
HcmV?d00001

diff --git a/themes/cp_admin/_layout.php b/themes/cp_admin/_layout.php
index 3b673615ab..17274d51df 100644
--- a/themes/cp_admin/_layout.php
+++ b/themes/cp_admin/_layout.php
@@ -7,7 +7,10 @@
     <title><?= $this->renderSection('title') ?> | Castopod Admin</title>
     <meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
-    <link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+    <link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
 
     <?= service('vite')
         ->asset('styles/index.css', 'css') ?>
diff --git a/themes/cp_admin/_sidebar.php b/themes/cp_admin/_sidebar.php
index 0a1a7f410a..dd8cb12a4d 100644
--- a/themes/cp_admin/_sidebar.php
+++ b/themes/cp_admin/_sidebar.php
@@ -22,6 +22,10 @@ $navigation = [
         'items' => ['page-list', 'page-create'],
 
     ],
+    'settings' => [
+        'icon' => 'settings',
+        'items' => ['settings-general'],
+    ],
 ]; ?>
 
 <nav class="flex flex-col flex-1 py-4 overflow-y-auto gap-y-4">
diff --git a/themes/cp_admin/person/edit.php b/themes/cp_admin/person/edit.php
index 49c2ca484d..7ce8966e79 100644
--- a/themes/cp_admin/person/edit.php
+++ b/themes/cp_admin/person/edit.php
@@ -35,6 +35,7 @@
     label="<?= lang('Person.form.unique_name') ?>"
     hint="<?= lang('Person.form.unique_name_hint') ?>"
     required="true" />
+
 <Forms.Field
     name="information_url"
     label="<?= lang('Person.form.information_url') ?>"
diff --git a/themes/cp_admin/settings/general.php b/themes/cp_admin/settings/general.php
new file mode 100644
index 0000000000..f48bc58136
--- /dev/null
+++ b/themes/cp_admin/settings/general.php
@@ -0,0 +1,59 @@
+<?= $this->extend('_layout') ?>
+
+<?= $this->section('title') ?>
+<?= lang('Settings.title') ?>
+<?= $this->endSection() ?>
+
+<?= $this->section('pageTitle') ?>
+<?= lang('Settings.title') ?>
+<?= $this->endSection() ?>
+
+<?= $this->section('content') ?>
+
+<form action="<?= route_to('settings-instance') ?>" method="POST" class="flex flex-col max-w-sm gap-y-4" enctype="multipart/form-data">
+<?= csrf_field() ?>
+
+<Forms.Section
+    title="<?= lang('Settings.form.site_section_title') ?>">
+
+    <Forms.Field
+        name="site_name"
+        label="<?= lang('Settings.form.site_name') ?>"
+        value="<?= service('settings')
+    ->get('App.siteName') ?>"
+        required="true" />
+
+    <Forms.Field
+        as="Textarea"
+        name="site_description"
+        label="<?= lang('Settings.form.site_description') ?>"
+        value="<?= service('settings')
+    ->get('App.siteDescription') ?>"
+        required="true"
+        rows="4" />
+
+    <div class="flex items-center">
+        <Forms.Field
+            name="site_icon"
+            type="file"
+            label="<?= lang('Settings.form.site_icon') ?>"
+            hint="<?= lang('Settings.form.site_icon_hint') ?>"
+            helper="<?= lang('Settings.form.site_icon_helper') ?>"
+            accept=".png,.jpeg"
+            class="flex-1"
+            />
+        <?php if (config('App')->siteIcon['ico'] !== service('settings')->get('App.siteIcon')['ico']): ?>
+        <div class="relative ml-2">
+            <a href="<?= route_to('settings-instance-delete-icon') ?>" class="absolute p-1 text-white bg-red-600 border-2 border-black rounded-full hover:bg-red-800 -top-3 -right-3 focus:ring-castopod" title="<?= lang('Settings.form.site_icon_delete') ?>"><?= icon('delete-bin') ?></a>
+            <img src="<?= service('settings')->get('App.siteIcon')['64'] ?>" alt="<?= service('settings')->get('App.siteName') ?> Favicon" class="w-10 h-10" />
+        </div>
+        <?php endif; ?>
+    </div>
+
+    <Button variant="primary" type="submit" class="self-end"><?= lang('Settings.form.submit') ?></Button>
+
+</Forms.Section>
+
+</form>
+
+<?= $this->endSection() ?>
diff --git a/themes/cp_app/_layout.php b/themes/cp_app/_layout.php
index eda77ca644..54afb9f285 100644
--- a/themes/cp_app/_layout.php
+++ b/themes/cp_app/_layout.php
@@ -6,9 +6,20 @@
 <head>
     <meta charset="UTF-8"/>
     <title><?= $this->renderSection('title') ?></title>
-    <meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/>
+    <meta name="description" content="<?= service('settings')
+    ->get('App.siteDescription') ?>"/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
-    <link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+    <link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
+
+    <meta property="og:title" content="<?= service('settings')
+    ->get('App.siteName') ?>" />
+    <meta property="og:description" content="<?= service('settings')
+    ->get('App.siteDescription') ?>" />
+    <meta property="og:site_name" content="<?= service('settings')
+    ->get('App.siteName') ?>" />
 
     <?= service('vite')
         ->asset('styles/index.css', 'css') ?>
diff --git a/themes/cp_app/embed.php b/themes/cp_app/embed.php
index 2817de36ac..612a5f1f03 100644
--- a/themes/cp_app/embed.php
+++ b/themes/cp_app/embed.php
@@ -8,7 +8,10 @@
     <meta name="description" content="<?= htmlspecialchars(
         $episode->description,
     ) ?>" />
-    <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
+    <link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
     <link rel="canonical" href="<?= $episode->link ?>" />
     <?= service('vite')
         ->asset('styles/index.css', 'css') ?>
diff --git a/themes/cp_app/episode/_layout.php b/themes/cp_app/episode/_layout.php
index 8eb6efd872..813c198387 100644
--- a/themes/cp_app/episode/_layout.php
+++ b/themes/cp_app/episode/_layout.php
@@ -7,7 +7,10 @@
 <head>
     <meta charset="UTF-8"/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
-    <link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+    <link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
 
     <?= $this->renderSection('meta-tags') ?>
     <?php if ($podcast->payment_pointer): ?>
diff --git a/themes/cp_app/home.php b/themes/cp_app/home.php
index 310f50539e..0852e85c05 100644
--- a/themes/cp_app/home.php
+++ b/themes/cp_app/home.php
@@ -5,10 +5,23 @@
 
 <head>
     <meta charset="UTF-8"/>
-    <title>Castopod</title>
-    <meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/>
+    <title><?= service('settings')
+    ->get('App.siteName') ?></title>
+    <meta name="description" content="<?= service('settings')
+    ->get('App.siteDescription') ?>"/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
-    <link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+    <link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
+
+    <meta property="og:title" content="<?= service('settings')
+    ->get('App.siteName') ?>" />
+    <meta property="og:description" content="<?= service('settings')
+    ->get('App.siteDescription') ?>" />
+    <meta property="og:site_name" content="<?= service('settings')
+    ->get('App.siteName') ?>" />
+
     <?= service('vite')
         ->asset('styles/index.css', 'css') ?>
     <?= service('vite')
diff --git a/themes/cp_app/map.php b/themes/cp_app/map.php
index e59fcd0168..2838dcea8d 100644
--- a/themes/cp_app/map.php
+++ b/themes/cp_app/map.php
@@ -8,7 +8,10 @@
     <title><?= lang('Page.map') ?></title>
     <meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
-    <link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+    <link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
     <?= service('vite')
         ->asset('styles/index.css', 'css') ?>
     <?= service('vite')
diff --git a/themes/cp_app/page.php b/themes/cp_app/page.php
index b8c0f8e7f4..84399887f1 100644
--- a/themes/cp_app/page.php
+++ b/themes/cp_app/page.php
@@ -7,7 +7,10 @@
     <meta charset="UTF-8"/>
     <title><?= $page->title ?></title>
     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
-    <link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+    <link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
     <?= service('vite')
         ->asset('styles/index.css', 'css') ?>
     <?= service('vite')
diff --git a/themes/cp_app/podcast/_layout.php b/themes/cp_app/podcast/_layout.php
index 487a58abcf..8a9c9eea16 100644
--- a/themes/cp_app/podcast/_layout.php
+++ b/themes/cp_app/podcast/_layout.php
@@ -7,7 +7,10 @@
 <head>
     <meta charset="UTF-8"/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
-    <link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+    <link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
 
     <?= $this->renderSection('meta-tags') ?>
     <?php if ($podcast->payment_pointer): ?>
diff --git a/themes/cp_app/podcast/about.php b/themes/cp_app/podcast/about.php
index 7383c93cd0..1c80116ca4 100644
--- a/themes/cp_app/podcast/about.php
+++ b/themes/cp_app/podcast/about.php
@@ -9,7 +9,10 @@
 <meta name="description" content="<?= htmlspecialchars(
     $podcast->description,
 ) ?>" />
-<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+<link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+<link rel="manifest" href="<?= route_to('webmanifest') ?>">
 <link rel="canonical" href="<?= current_url() ?>" />
 <meta property="og:title" content="<?= $podcast->title ?>" />
 <meta property="og:description" content="<?= $podcast->description ?>" />
diff --git a/themes/cp_app/podcast/activity.php b/themes/cp_app/podcast/activity.php
index f291f25794..3743d8859b 100644
--- a/themes/cp_app/podcast/activity.php
+++ b/themes/cp_app/podcast/activity.php
@@ -7,7 +7,10 @@
 <meta name="description" content="<?= htmlspecialchars(
     $podcast->description,
 ) ?>" />
-<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+<link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+<link rel="manifest" href="<?= route_to('webmanifest') ?>">
 <link rel="canonical" href="<?= current_url() ?>" />
 <meta property="og:title" content="<?= $podcast->title ?>" />
 <meta property="og:description" content="<?= $podcast->description ?>" />
diff --git a/themes/cp_app/podcast/episodes.php b/themes/cp_app/podcast/episodes.php
index c5a97c9aee..8b6bae0fe4 100644
--- a/themes/cp_app/podcast/episodes.php
+++ b/themes/cp_app/podcast/episodes.php
@@ -7,7 +7,10 @@
 <meta name="description" content="<?= htmlspecialchars(
     $podcast->description,
 ) ?>" />
-<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+<link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+<link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+<link rel="manifest" href="<?= route_to('webmanifest') ?>">
 <link rel="canonical" href="<?= current_url() ?>" />
 <meta property="og:title" content="<?= $podcast->title ?>" />
 <meta property="og:description" content="<?= $podcast->description ?>" />
diff --git a/themes/cp_app/podcast/follow.php b/themes/cp_app/podcast/follow.php
index 473980cf75..abd8888d77 100644
--- a/themes/cp_app/podcast/follow.php
+++ b/themes/cp_app/podcast/follow.php
@@ -7,8 +7,10 @@
 <head>
     <meta charset="UTF-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <link rel="shortcut icon" type="image/png" href="/favicon.ico" />
-    <?= service('vite')->asset('styles/index.css', 'css') ?>
+    <link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
     
     <title><?= lang('Podcast.followTitle', [
         'actorDisplayName' => $actor->display_name,
diff --git a/themes/cp_app/post/remote_action.php b/themes/cp_app/post/remote_action.php
index 3a885e9ee1..6914f04bee 100644
--- a/themes/cp_app/post/remote_action.php
+++ b/themes/cp_app/post/remote_action.php
@@ -5,7 +5,10 @@
 <head>
     <meta charset="UTF-8"/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
-    <link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+    <link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
 
     <title><?= lang('Fediverse.' . $action . '.title', [
         'actorDisplayName' => $post->actor->display_name,
diff --git a/themes/cp_auth/_layout.php b/themes/cp_auth/_layout.php
index b22e49856d..9ac33873f9 100644
--- a/themes/cp_auth/_layout.php
+++ b/themes/cp_auth/_layout.php
@@ -7,7 +7,7 @@
 	<title>Castopod Auth</title>
 	<meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/>
 	<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
-	<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+	<link rel="icon" type="image/x-icon" href="/favicon.ico" />
     <?= service('vite')
         ->asset('styles/index.css', 'css') ?>
 </head>
diff --git a/themes/cp_install/_layout.php b/themes/cp_install/_layout.php
index a3ed84c476..affa0827c6 100644
--- a/themes/cp_install/_layout.php
+++ b/themes/cp_install/_layout.php
@@ -6,7 +6,10 @@
     <title>Castopod</title>
     <meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience."/>
     <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
-    <link rel="shortcut icon" type="image/png" href="/favicon.ico" />
+    <link rel="icon" type="image/x-icon" href="<?= service('settings')
+    ->get('App.siteIcon')['ico'] ?>" />
+    <link rel="apple-touch-icon" href="<?= service('settings')->get('App.siteIcon')['180'] ?>">
+    <link rel="manifest" href="<?= route_to('webmanifest') ?>">
     <?= service('vite')
         ->asset('styles/index.css', 'css') ?>
     <?= service('vite')
-- 
GitLab