From c47d6cd6d4badaed7ca718a0991d6914d753357b Mon Sep 17 00:00:00 2001 From: Pablo Ferreiro Date: Wed, 16 Feb 2022 15:20:35 +0100 Subject: [PATCH 1/3] Reverted to last usable version --- .env.example | 7 +- README.md | 2 +- app/Cache/JSONCache.php | 32 +++++---- app/Cache/RedisCache.php | 8 +-- app/Controllers/DiscoverController.php | 4 +- app/Controllers/ProxyController.php | 7 +- app/Controllers/TagController.php | 6 +- app/Controllers/TrendingController.php | 7 +- app/Controllers/UserController.php | 6 +- app/Controllers/VideoController.php | 4 +- app/Helpers/Misc.php | 17 ++--- app/Helpers/RSS.php | 2 +- app/Models/DiscoverTemplate.php | 16 ----- app/Models/FeedTemplate.php | 6 +- app/Models/ItemTemplate.php | 14 ++++ components/feed.latte | 2 +- composer.json | 10 ++- composer.lock | 97 +++++++++++++++----------- views/about.latte | 2 +- views/music.latte | 6 +- views/tag.latte | 8 +-- views/user.latte | 12 ++-- views/video.latte | 18 ++--- 23 files changed, 149 insertions(+), 144 deletions(-) delete mode 100644 app/Models/DiscoverTemplate.php create mode 100644 app/Models/ItemTemplate.php diff --git a/.env.example b/.env.example index 2e81b81..60a168d 100644 --- a/.env.example +++ b/.env.example @@ -1,12 +1,9 @@ # APP_URL="http://localhost:8000" # Full url path, PLEASE REPLACE TO YOUR OWN ONE -# LATTE_CACHE=/tmp/proxitok_api # Path for Latte cache, leave commented for ./cache/latte -# API CONFIG -# USE_TEST_ENDPOINTS=1 # Discomment for usage of t.tiktok.com -# SIGNER_URL="https://tiktok-sign.herokuapp.com/signature" # External signing service +# LATTE_CACHE=/tmp/proxitok_api # Path for Latte cache, leave commented for ./cache/latte # API_CACHE=redis # Cache engine for TikTok Api, (more info on README) -# Redis cache, used on Helpers\CacheEngines\RedisCache +# Redis cache, used on Helpers\CacheEngines\RedisCache (CHOOSE ONE) # REDIS_HOST=localhost # Host or path to unix socket # REDIS_PORT=6379 # Set to -1 to use unix socket # REDIS_PASSWORD=example # Leave commented for no password diff --git a/README.md b/README.md index 3cacf49..5bc31e9 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ location /proxitok/.env { * i18n ## Credits -* [TikScraper](https://github.com/pablouser1/TikScraperPHP) +* [TikTok-API-PHP](https://github.com/ssovit/TikTok-API-PHP) (Currently using my personal fork) * [Latte](https://github.com/nette/latte) * [bramus/router](https://github.com/bramus/router) * [PHP dotenv](https://github.com/vlucas/phpdotenv) diff --git a/app/Cache/JSONCache.php b/app/Cache/JSONCache.php index f113433..7b16c60 100644 --- a/app/Cache/JSONCache.php +++ b/app/Cache/JSONCache.php @@ -1,31 +1,33 @@ cache_path = Misc::env('API_CACHE_JSON', __DIR__ . '/../../cache/api'); + if (isset($_ENV['API_CACHE_JSON']) && !empty($_ENV['API_CACHE_JSON'])) { + $this->cache_path = $_ENV['API_CACHE_JSON']; + } } - - public function get(string $cache_key): ?object { + public function get(string $cache_key): object|false { $filename = $this->cache_path . '/' . $cache_key . '.json'; if (is_file($filename)) { + $time = time(); $json_string = file_get_contents($filename); $element = json_decode($json_string); - return $element; + if ($time < $element->expires) { + return $element->data; + } + // Remove file if expired + unlink($filename); } - return null; + return false; } - public function exists(string $cache_key): bool { - $filename = $this->cache_path . '/' . $cache_key . '.json'; - return is_file($filename); - } - - public function set(string $cache_key, string $data, $timeout = 3600) { - file_put_contents($this->cache_path . '/' . $cache_key . '.json', $data); + public function set(string $cache_key, mixed $data, $timeout = 3600) { + file_put_contents($this->cache_path . '/' . $cache_key . '.json', json_encode([ + 'data' => $data, + 'expires' => time() + $timeout + ])); } } diff --git a/app/Cache/RedisCache.php b/app/Cache/RedisCache.php index 82063a0..55a6dca 100644 --- a/app/Cache/RedisCache.php +++ b/app/Cache/RedisCache.php @@ -27,11 +27,7 @@ class RedisCache { return null; } - public function exists(string $cache_key): bool { - return $this->client->exists($cache_key); - } - - public function set(string $cache_key, string $data, $timeout = 3600) { - $this->client->set($cache_key, $data, $timeout); + public function set(string $cache_key, array $data, $timeout = 3600) { + $this->client->set($cache_key, json_encode($data), $timeout); } } diff --git a/app/Controllers/DiscoverController.php b/app/Controllers/DiscoverController.php index dbd6e70..ea564e2 100644 --- a/app/Controllers/DiscoverController.php +++ b/app/Controllers/DiscoverController.php @@ -3,7 +3,7 @@ namespace App\Controllers; use App\Helpers\ErrorHandler; use App\Helpers\Misc; -use App\Models\DiscoverTemplate; +use App\Models\FeedTemplate; class DiscoverController { static public function get() { @@ -11,7 +11,7 @@ class DiscoverController { $feed = $api->getDiscover(); if ($feed->meta->success) { $latte = Misc::latte(); - $latte->render(Misc::getView('discover'), new DiscoverTemplate($feed)); + $latte->render(Misc::getView('discover'), new FeedTemplate('Discover', $feed)); } else { ErrorHandler::show($feed->meta); } diff --git a/app/Controllers/ProxyController.php b/app/Controllers/ProxyController.php index 9b6d417..cf0ec77 100644 --- a/app/Controllers/ProxyController.php +++ b/app/Controllers/ProxyController.php @@ -40,24 +40,25 @@ class ProxyController { static public function stream() { if (isset($_GET['download'])) { - $downloader = new \TikScraper\Download(); $watermark = isset($_GET['watermark']); if ($watermark) { self::checkUrl(); $filename = self::getFileName(); + $downloader = new \Sovit\TikTok\Download(); $downloader->url($_GET['url'], $filename, true); } else { if (!isset($_GET['id'])) { die('You need to send an ID!'); } $filename = self::getFileName(); + $downloader = new \Sovit\TikTok\Download(); $downloader->url($_GET['id'], $filename, false); } } else { self::checkUrl(); $url = $_GET['url']; - $streamer = new \TikScraper\Stream(); - $streamer->url($url); + $streamer = new \Sovit\TikTok\Stream(); + $streamer->stream($url); } } } diff --git a/app/Controllers/TagController.php b/app/Controllers/TagController.php index 077b628..5ed8c26 100644 --- a/app/Controllers/TagController.php +++ b/app/Controllers/TagController.php @@ -10,7 +10,7 @@ class TagController { static public function get(string $name) { $cursor = Misc::getCursor(); $api = Misc::api(); - $feed = $api->getHashtagFeed($name, $cursor); + $feed = $api->getChallengeFeed($name, $cursor); if ($feed->meta->success) { $latte = Misc::latte(); $latte->render(Misc::getView('tag'), new FeedTemplate('Tag', $feed)); @@ -21,9 +21,9 @@ class TagController { static public function rss(string $name) { $api = Misc::api(); - $feed = $api->getHashtagFeed($name); + $feed = $api->getChallengeFeed($name); if ($feed->meta->success) { - $feed = RSS::build("/tag/{$name}", "{$name} Tag", $feed->info->detail->desc, $feed->items); + $feed = RSS::build("/tag/{$name}", "{$name} Tag", $feed->info->detail->challenge->desc, $feed->items); // Setup headers RSS::setHeaders('tag.rss'); echo $feed; diff --git a/app/Controllers/TrendingController.php b/app/Controllers/TrendingController.php index 0558488..2d1cffe 100644 --- a/app/Controllers/TrendingController.php +++ b/app/Controllers/TrendingController.php @@ -8,10 +8,9 @@ use App\Helpers\RSS; class TrendingController { static public function get() { - $cursor = Misc::getTtwid(); - $page = $_GET['page'] ?? 0; + $cursor = Misc::getCursor(); $api = Misc::api(); - $feed = $api->getTrending($cursor, $page); + $feed = $api->getTrendingFeed($cursor); if ($feed->meta->success) { $latte = Misc::latte(); $latte->render(Misc::getView('trending'), new FeedTemplate('Trending', $feed)); @@ -22,7 +21,7 @@ class TrendingController { static public function rss() { $api = Misc::api(); - $feed = $api->getTrending(); + $feed = $api->getTrendingFeed(); if ($feed->meta->success) { $feed = RSS::build('/trending', 'Trending', 'Tiktok trending', $feed->items); // Setup headers diff --git a/app/Controllers/UserController.php b/app/Controllers/UserController.php index 343eb2f..91398a9 100644 --- a/app/Controllers/UserController.php +++ b/app/Controllers/UserController.php @@ -12,12 +12,12 @@ class UserController { $api = Misc::api(); $feed = $api->getUserFeed($username, $cursor); if ($feed->meta->success) { - if ($feed->info->detail->privateAccount) { + if ($feed->info->detail->user->privateAccount) { http_response_code(400); echo 'Private account detected! Not supported'; } $latte = Misc::latte(); - $latte->render(Misc::getView('user'), new FeedTemplate($feed->info->detail->nickname, $feed)); + $latte->render(Misc::getView('user'), new FeedTemplate($feed->info->detail->user->nickname, $feed)); } else { ErrorHandler::show($feed->meta); } @@ -27,7 +27,7 @@ class UserController { $api = Misc::api(); $feed = $api->getUserFeed($username); if ($feed->meta->success) { - $feed = RSS::build('/@'.$username, $feed->info->detail->nickname, $feed->info->detail->signature, $feed->items); + $feed = RSS::build('/@'.$username, $feed->info->detail->user->nickname, $feed->info->detail->user->signature, $feed->items); // Setup headers RSS::setHeaders('user.rss'); echo $feed; diff --git a/app/Controllers/VideoController.php b/app/Controllers/VideoController.php index 3e1285a..ae1a6a6 100644 --- a/app/Controllers/VideoController.php +++ b/app/Controllers/VideoController.php @@ -3,7 +3,7 @@ namespace App\Controllers; use App\Helpers\ErrorHandler; use App\Helpers\Misc; -use App\Models\FeedTemplate; +use App\Models\ItemTemplate; class VideoController { static public function get(string $video_id) { @@ -11,7 +11,7 @@ class VideoController { $item = $api->getVideoByID($video_id); if ($item->meta->success) { $latte = Misc::latte(); - $latte->render(Misc::getView('video'), new FeedTemplate($item->info->detail->nickname, $item)); + $latte->render(Misc::getView('video'), new ItemTemplate($item->info->detail->user->nickname, $item)); } else { ErrorHandler::show($item->meta); } diff --git a/app/Helpers/Misc.php b/app/Helpers/Misc.php index 7734bfc..4bceddf 100644 --- a/app/Helpers/Misc.php +++ b/app/Helpers/Misc.php @@ -9,16 +9,12 @@ class Misc { return isset($_GET['cursor']) && is_numeric($_GET['cursor']) ? (int) $_GET['cursor'] : 0; } - static public function getTtwid(): string { - return $_GET['cursor'] ?? ''; - } - static public function url(string $endpoint = '') { return self::env('APP_URL', '') . $endpoint; } static public function env(string $key, string $default_value): string { - return $_ENV[$key] ?? $default_value; + return isset($_ENV[$key]) && !empty($_ENV[$key]) ? $_ENV[$key] : $default_value; } /** @@ -31,11 +27,8 @@ class Misc { /** * Setup of TikTok Api wrapper */ - static public function api(): \TikScraper\Api { - $options = [ - 'remote_signer' => self::env('SIGNER_URL', 'http://localhost:8080/signature'), - 'use_test_endpoints' => self::env('USE_TEST_ENDPOINTS', false) - ]; + static public function api(): \Sovit\TikTok\Api { + $options = []; $cacheEngine = false; // Proxy config foreach(Cookies::PROXY as $proxy_element) { @@ -62,13 +55,13 @@ class Misc { } else { $host = $_ENV['REDIS_HOST']; $port = (int) $_ENV['REDIS_PORT']; - $password = $_ENV['REDIS_PASSWORD'] ?? null; + $password = isset($_ENV['REDIS_PASSWORD']) ? $_ENV['REDIS_PASSWORD'] : null; } $cacheEngine = new RedisCache($host, $port, $password); break; } } - $api = new \TikScraper\Api($options, $cacheEngine); + $api = new \Sovit\TikTok\Api($options, $cacheEngine); return $api; } diff --git a/app/Helpers/RSS.php b/app/Helpers/RSS.php index ee6495c..510aa2d 100644 --- a/app/Helpers/RSS.php +++ b/app/Helpers/RSS.php @@ -2,7 +2,7 @@ namespace App\Helpers; use \FeedWriter\RSS2; -use TikScraper\Download; +use \Sovit\TikTok\Download; class RSS { static public function build(string $endpoint, string $title, string $description, array $items): string { diff --git a/app/Models/DiscoverTemplate.php b/app/Models/DiscoverTemplate.php deleted file mode 100644 index a240830..0000000 --- a/app/Models/DiscoverTemplate.php +++ /dev/null @@ -1,16 +0,0 @@ -feed = $feed; - } -} diff --git a/app/Models/FeedTemplate.php b/app/Models/FeedTemplate.php index a26e490..836fc29 100644 --- a/app/Models/FeedTemplate.php +++ b/app/Models/FeedTemplate.php @@ -1,15 +1,13 @@ feed = $feed; } diff --git a/app/Models/ItemTemplate.php b/app/Models/ItemTemplate.php new file mode 100644 index 0000000..b4b749d --- /dev/null +++ b/app/Models/ItemTemplate.php @@ -0,0 +1,14 @@ +item = $item; + } +} diff --git a/components/feed.latte b/components/feed.latte index 60e29c2..d78e4da 100644 --- a/components/feed.latte +++ b/components/feed.latte @@ -17,7 +17,7 @@ {/foreach} -
+
{if isset($_GET['cursor']) && $_GET['cursor'] != 0 } First diff --git a/composer.json b/composer.json index 5a05bb4..01de09d 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "pablouser1/proxitok", "description": "An alternative frontend for TikTok", - "version": "1.5.0", + "version": "1.4.1.4", "license": "AGPL-3.0-or-later", "type": "project", "homepage": "https://github.com/pablouser1/ProxiTok", @@ -11,10 +11,16 @@ "homepage": "https://github.com/pablouser1" } ], + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/pablouser1/TikTok-API-PHP" + } + ], "require": { "ext-redis": "^5.3.2", "ext-mbstring": "*", - "pablouser1/tikscraper": "^1.0", + "ssovit/tiktok-api": "dev-rework", "latte/latte": "^2.10", "vlucas/phpdotenv": "^5.4", "bramus/router": "^1.6", diff --git a/composer.lock b/composer.lock index ef9c7ce..8b0c8b9 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": "f5e451a254a58bf7d512421237641801", + "content-hash": "80d871b2eb1a9e28de6f38990492ab3c", "packages": [ { "name": "bramus/router", @@ -304,45 +304,6 @@ }, "time": "2016-11-19T20:47:44+00:00" }, - { - "name": "pablouser1/tikscraper", - "version": "v1.2.4", - "source": { - "type": "git", - "url": "https://github.com/pablouser1/TikScraperPHP.git", - "reference": "577e1c1d7945c87e2bad2000fec1f9a7c0b9cf68" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/pablouser1/TikScraperPHP/zipball/577e1c1d7945c87e2bad2000fec1f9a7c0b9cf68", - "reference": "577e1c1d7945c87e2bad2000fec1f9a7c0b9cf68", - "shasum": "" - }, - "require": { - "php": ">=7.3|^8.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "TikScraper\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Pablo Ferreiro" - } - ], - "description": "Get data from TikTok API", - "support": { - "issues": "https://github.com/pablouser1/TikScraperPHP/issues", - "source": "https://github.com/pablouser1/TikScraperPHP/tree/v1.2.4" - }, - "time": "2022-02-16T11:53:00+00:00" - }, { "name": "phpoption/phpoption", "version": "1.8.1", @@ -414,6 +375,58 @@ ], "time": "2021-12-04T23:24:31+00:00" }, + { + "name": "ssovit/tiktok-api", + "version": "dev-rework", + "source": { + "type": "git", + "url": "https://github.com/pablouser1/TikTok-API-PHP.git", + "reference": "60c00cfd321888b80eba93b6214c8c4003e98e57" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pablouser1/TikTok-API-PHP/zipball/60c00cfd321888b80eba93b6214c8c4003e98e57", + "reference": "60c00cfd321888b80eba93b6214c8c4003e98e57", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Sovit\\": "lib" + } + }, + "archive": { + "exclude": [ + "/example", + "/.github", + "/.editorconfig" + ] + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sovit Tamrakar", + "email": "sovit.tamrakar@gmail.com", + "homepage": "https://github.com/ssovit/", + "role": "Developer" + } + ], + "description": "Unofficial TikTok API for PHP", + "homepage": "https://github.com/ssovit/TikTok-API-PHP", + "keywords": [ + "tiktok", + "tiktok-api", + "tiktok-scraper" + ], + "support": { + "source": "https://github.com/ssovit/TikTok-API-PHP", + "issues": "https://github.com/ssovit/TikTok-API-PHP/issues", + "email": "sovit.tamrakar@gmail.com" + }, + "time": "2022-02-07T22:43:53+00:00" + }, { "name": "symfony/polyfill-ctype", "version": "v1.24.0", @@ -746,7 +759,9 @@ "packages-dev": [], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "ssovit/tiktok-api": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/views/about.latte b/views/about.latte index 46e3a56..0eca965 100644 --- a/views/about.latte +++ b/views/about.latte @@ -20,7 +20,7 @@

This project wouldn't be possible without the help of the following projects:

    -
  • TikScraper
  • +
  • TikTok-API-PHP
  • Latte
  • bramus/router
  • PHP dotenv
  • diff --git a/views/music.latte b/views/music.latte index 04b6806..99cea03 100644 --- a/views/music.latte +++ b/views/music.latte @@ -1,9 +1,9 @@ {layout '../layouts/default.latte'} {block header} -

    {$feed->info->detail->title}

    -

    {$feed->info->detail->desc}

    -

    Videos: {number($feed->info->stats->videoCount)}

    +

    {$feed->info->detail->music->title}

    +

    {$feed->info->detail->music->desc}

    +

    Videos: {number($feed->info->detail->stats->videoCount)}

    {/block} {block content} diff --git a/views/tag.latte b/views/tag.latte index fc39f04..9313214 100644 --- a/views/tag.latte +++ b/views/tag.latte @@ -1,10 +1,10 @@ {layout '../layouts/default.latte'} {block header} -

    {$feed->info->detail->title}

    -

    {$feed->info->detail->desc}

    -

    Videos: {number($feed->info->stats->videoCount)} / Views: {number($feed->info->stats->viewCount)}

    - RSS +

    {$feed->info->detail->challenge->title}

    +

    {$feed->info->detail->challenge->desc}

    +

    Videos: {number($feed->info->detail->stats->videoCount)} / Views: {number($feed->info->detail->stats->viewCount)}

    + RSS {/block} {block content} diff --git a/views/user.latte b/views/user.latte index 7e2b56c..bb47b5b 100644 --- a/views/user.latte +++ b/views/user.latte @@ -2,13 +2,13 @@ {block header}
    - +
    -

    {$feed->info->detail->uniqueId}'s profile

    -

    {$feed->info->detail->signature}

    -

    Following: {number($feed->info->stats->followingCount)} / Followers: {number($feed->info->stats->followerCount)}

    -

    Hearts: {number($feed->info->stats->heartCount)} / Videos: {$feed->info->stats->videoCount}

    - RSS +

    {$feed->info->detail->user->uniqueId}'s profile

    +

    {$feed->info->detail->user->signature}

    +

    Following: {number($feed->info->detail->stats->followingCount)} / Followers: {number($feed->info->detail->stats->followerCount)}

    +

    Hearts: {number($feed->info->detail->stats->heartCount)} / Videos: {$feed->info->detail->stats->videoCount}

    + RSS {/block} {block content} diff --git a/views/video.latte b/views/video.latte index f1fb7cb..f9cd64a 100644 --- a/views/video.latte +++ b/views/video.latte @@ -3,20 +3,20 @@ {block content}
    -
    -

    Video by {$feed->info->detail->uniqueId}

    -

    {$feed->items[0]->desc}

    -

    Played {number($feed->info->stats->playCount)} times

    -

    Shared {number($feed->info->stats->shareCount)} times / {number($feed->info->stats->commentCount)} comments

    +

    Video by {$item->info->detail->user->uniqueId}

    +

    {$item->items[0]->desc}

    +

    Played {number($item->info->detail->stats->playCount)} times

    +

    Shared {number($item->info->detail->stats->shareCount)} times / {number($item->info->detail->stats->commentCount)} comments


    - Download video -

    {$feed->items[0]->music->title}

    - + Download video +

    {$item->items[0]->music->title}

    +
    From 669c0d29d4a19b86a127e4ab4dff202a2c0f6add Mon Sep 17 00:00:00 2001 From: IronMaltese <89056889+IronMaltese@users.noreply.github.com> Date: Sat, 5 Mar 2022 16:50:47 -0500 Subject: [PATCH 2/3] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 5bc31e9..1c66465 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,9 @@ Use Tiktok with an alternative frontend, inspired by Nitter. * Create a following list, which you can later use to see all the feeds from those users * RSS Feed for user, trending and tag (just add /rss to the url) +## Extension +If you want to automatically redirect Tiktok links to ProxiTok, download [Libredirect](https://github.com/libredirect/libredirect) + ## Installation Clone the repository and fetch the requiered external packages with: ```bash From 1eb66261531a2d7977238684937824716cfa74c8 Mon Sep 17 00:00:00 2001 From: Pablo Ferreiro Date: Fri, 11 Mar 2022 16:11:56 +0100 Subject: [PATCH 3/3] Added Redirector --- README.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1c66465..a4f455d 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,23 @@ Use Tiktok with an alternative frontend, inspired by Nitter. * See tags * See video by id * Discovery -* Create a following list, which you can later use to see all the feeds from those users * RSS Feed for user, trending and tag (just add /rss to the url) ## Extension -If you want to automatically redirect Tiktok links to ProxiTok, download [Libredirect](https://github.com/libredirect/libredirect) +If you want to automatically redirect Tiktok links to ProxiTok you can use: +* [Libredirect](https://github.com/libredirect/libredirect) +* [Redirector](https://github.com/einaregilsson/Redirector) + +You can use the following config if you want to use Redirector (you can change https://proxitok.herokuapp.com with whatever instance you want to use): +``` +Description: TikTok to ProxiTok +Example URL: https://www.tiktok.com/@tiktok +Include pattern: (.*//.*)(tiktok.com)(.*) +Redirect to: https://proxitok.herokuapp.com$3 +Example result: https://proxitok.herokuapp.com/@tiktok +Pattern type: Regular Expression +Apply to: Main window (address bar) +``` ## Installation Clone the repository and fetch the requiered external packages with: