Project structure change

This commit is contained in:
Pablo Ferreiro 2022-01-31 00:02:52 +01:00
parent bd1642957c
commit 837f126021
No known key found for this signature in database
GPG key ID: 41FBCE65B779FA24
29 changed files with 298 additions and 254 deletions

View file

@ -36,17 +36,17 @@ Available cache engines:
You don't have to do anything more You don't have to do anything more
### Nginx ### Nginx
Add the following to your config (you can modify the tiktok-viewer part if you have or not a subdir): Add the following to your config (you can modify the proxitok part if you have or not a subdir):
``` ```
location /tiktok-viewer { location /proxitok {
return 302 $scheme://$host/tiktok-viewer/; return 302 $scheme://$host/proxitok/;
} }
location /tiktok-viewer/ { location /proxitok/ {
try_files $uri $uri/ /tiktok-viewer/index.php?$query_string; try_files $uri $uri/ /proxitok/index.php?$query_string;
} }
location /tiktok-viewer/.env { location /proxitok/.env {
deny all; deny all;
return 404; return 404;
} }

View file

@ -1,5 +1,5 @@
<?php <?php
namespace Helpers\CacheEngines; namespace App\Cache;
class JSONCache { class JSONCache {
private string $cache_path = __DIR__ . '/../../cache/api'; private string $cache_path = __DIR__ . '/../../cache/api';

View file

@ -1,5 +1,5 @@
<?php <?php
namespace Helpers\CacheEngines; namespace App\Cache;
class RedisCache { class RedisCache {
private \Redis $client; private \Redis $client;

View file

@ -0,0 +1,15 @@
<?php
namespace App\Controllers;
use App\Helpers\Following;
use App\Helpers\Misc;
use App\Models\FollowingTemplate;
class FollowingController {
static public function get() {
$users = Following::getUsers();
$feed = Following::getAll($users);
$latte = Misc::latte();
$latte->render(Misc::getView('following'), new FollowingTemplate($users, $feed));
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace App\Controllers;
use App\Helpers\ErrorHandler;
use App\Helpers\Misc;
use App\Models\FeedTemplate;
class MusicController {
static public function get(string $music_id) {
$cursor = Misc::getCursor();
$api = Misc::api();
$feed = $api->getMusicFeed($music_id, $cursor);
if ($feed->meta->success) {
$latte = Misc::latte();
$latte->render(Misc::getView('music'), new FeedTemplate('Music', $feed));
} else {
ErrorHandler::show($feed->meta);
}
}
}

View file

@ -0,0 +1,35 @@
<?php
namespace App\Controllers;
class ProxyController {
const VALID_TIKTOK_DOMAINS = [
"tiktokcdn.com", "tiktokcdn-us.com", "tiktok.com"
];
static private function isValidDomain(string $url) {
$host = parse_url($url, PHP_URL_HOST);
$host_split = explode('.', $host);
return count($host_split) === 3 && in_array($host_split[1] . '.' . $host_split[2], self::VALID_TIKTOK_DOMAINS);
}
static public function stream() {
if (!isset($_GET['url'])) {
die('You need to send a url!');
}
$url = $_GET['url'];
if (!filter_var($url, FILTER_VALIDATE_URL) || !self::isValidDomain($url)) {
die('Not a valid URL');
}
if (isset($_GET['download'])) {
// Download
$downloader = new \Sovit\TikTok\Download();
$downloader->url($url, "tiktok-video", 'mp4');
} else {
// Stream
$streamer = new \Sovit\TikTok\Stream();
$streamer->stream($url);
}
}
}

View file

@ -1,29 +1,29 @@
<?php <?php
namespace App\Controllers;
/**@var Bramus\Router\Router $router */ use App\Helpers\Misc;
use App\Helpers\Cookies;
use App\Helpers\Following;
use App\Models\SettingsTemplate;
use Helpers\Following; class SettingsController {
use Helpers\Settings; static public function index() {
use Helpers\Misc;
use Views\Models\SettingsTemplate;
$router->mount('/settings', function () use ($router) {
$router->get('/', function () {
$latte = Misc::latte(); $latte = Misc::latte();
$latte->render(Misc::getView('settings'), new SettingsTemplate()); $latte->render(Misc::getView('settings'), new SettingsTemplate());
}); }
$router->post('/proxy', function () { static public function proxy() {
if (in_array(Settings::PROXY, $_POST)) { if (in_array(Cookies::PROXY, $_POST)) {
foreach (Settings::PROXY as $proxy_element) { foreach (Cookies::PROXY as $proxy_element) {
Settings::set($proxy_element, $_POST[$proxy_element]); Cookies::set($proxy_element, $_POST[$proxy_element]);
} }
} }
http_response_code(302); http_response_code(302);
header('Location: ./home'); $url = Misc::env('APP_URL', '');
}); header("Location: {$url}");
}
$router->post('/following', function () { static public function following() {
$following = Following::getUsers(); $following = Following::getUsers();
if (!isset($_POST['mode']) || empty($_POST['mode'])) { if (!isset($_POST['mode']) || empty($_POST['mode'])) {
die('You need to send a mode'); die('You need to send a mode');
@ -48,7 +48,7 @@ $router->mount('/settings', function () use ($router) {
// Build string // Build string
$following_string = implode(',', $following); $following_string = implode(',', $following);
Settings::set('following', $following_string); Cookies::set('following', $following_string);
header('Location: ../settings'); header('Location: ../settings');
}); }
}); }

View file

@ -0,0 +1,32 @@
<?php
namespace App\Controllers;
use App\Helpers\ErrorHandler;
use App\Helpers\Misc;
use App\Helpers\RSS;
use App\Models\FeedTemplate;
class TagController {
static public function get(string $name) {
$cursor = Misc::getCursor();
$api = Misc::api();
$feed = $api->getChallengeFeed($name, $cursor);
if ($feed->meta->success) {
$latte = Misc::latte();
$latte->render(Misc::getView('tag'), new FeedTemplate('Tag', $feed));
} else {
ErrorHandler::show($feed->meta);
}
}
static public function rss(string $name) {
$api = Misc::api();
$feed = $api->getChallengeFeed($name);
if ($feed->meta->success) {
$feed = RSS::build("/tag/{$name}", "{$name} Tag", $feed->info->detail->challenge->desc, $feed->items);
// Setup headers
RSS::setHeaders('tag.rss');
echo $feed;
}
}
}

View file

@ -0,0 +1,32 @@
<?php
namespace App\Controllers;
use App\Helpers\Misc;
use App\Models\FeedTemplate;
use App\Helpers\ErrorHandler;
use App\Helpers\RSS;
class TrendingController {
static public function get() {
$cursor = Misc::getCursor();
$api = Misc::api();
$feed = $api->getTrendingFeed($cursor);
if ($feed->meta->success) {
$latte = Misc::latte();
$latte->render(Misc::getView('trending'), new FeedTemplate('Trending', $feed));
} else {
ErrorHandler::show($feed->meta);
}
}
static public function rss() {
$api = Misc::api();
$feed = $api->getTrendingFeed();
if ($feed->meta->success) {
$feed = RSS::build('/trending', 'Trending', 'Tiktok trending', $feed->items);
// Setup headers
RSS::setHeaders('trending.rss');
echo $feed;
}
}
}

View file

@ -0,0 +1,36 @@
<?php
namespace App\Controllers;
use App\Helpers\ErrorHandler;
use App\Helpers\Misc;
use App\Helpers\RSS;
use App\Models\FeedTemplate;
class UserController {
static public function get(string $username) {
$cursor = Misc::getCursor();
$api = Misc::api();
$feed = $api->getUserFeed($username, $cursor);
if ($feed->meta->success) {
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->user->nickname, $feed));
} else {
ErrorHandler::show($feed->meta);
}
}
static public function rss(string $username) {
$api = Misc::api();
$feed = $api->getUserFeed($username);
if ($feed->meta->success) {
$feed = RSS::build('/@'.$username, $feed->info->detail->user->nickname, $feed->info->detail->user->signature, $feed->items);
// Setup headers
RSS::setHeaders('user.rss');
echo $feed;
}
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace App\Controllers;
use App\Helpers\ErrorHandler;
use App\Helpers\Misc;
use App\Models\ItemTemplate;
class VideoController {
static public function get(string $video_id) {
$api = Misc::api();
$item = $api->getVideoByID($video_id);
if ($item->meta->success) {
$latte = Misc::latte();
$latte->render(Misc::getView('video'), new ItemTemplate($item->info->detail->user->nickname, $item));
} else {
ErrorHandler::show($item->meta);
}
}
}

View file

@ -1,7 +1,7 @@
<?php <?php
namespace Helpers; namespace App\Helpers;
class Settings { class Cookies {
const PROXY = ['proxy-host', 'proxy-port', 'proxy-username', 'proxy-password']; const PROXY = ['proxy-host', 'proxy-port', 'proxy-username', 'proxy-password'];
static public function get(string $name): string { static public function get(string $name): string {

View file

@ -1,5 +1,5 @@
<?php <?php
namespace Helpers; namespace App\Helpers;
class ErrorHandler { class ErrorHandler {
static public function show(object $meta) { static public function show(object $meta) {

View file

@ -1,9 +1,9 @@
<?php <?php
namespace Helpers; namespace App\Helpers;
class Following { class Following {
static public function getUsers (): array { static public function getUsers (): array {
$following_string = Settings::get('following'); $following_string = Cookies::get('following');
if ($following_string) { if ($following_string) {
return explode(',', $following_string); return explode(',', $following_string);
} }

View file

@ -1,12 +1,19 @@
<?php <?php
namespace Helpers; namespace App\Helpers;
use Exception; use Exception;
use Helpers\CacheEngines\JSONCache; use App\Cache\JSONCache;
use Helpers\CacheEngines\RedisCache; use App\Cache\RedisCache;
use Helpers\Settings;
class Misc { class Misc {
static public function getCursor(): int {
return isset($_GET['cursor']) && is_numeric($_GET['cursor']) ? (int) $_GET['cursor'] : 0;
}
static public function getURL(): string {
return self::env('APP_URL', '');
}
static public function env(string $key, mixed $default_value): string { static public function env(string $key, mixed $default_value): string {
return isset($_ENV[$key]) && !empty($_ENV[$key]) ? $_ENV[$key] : $default_value; return isset($_ENV[$key]) && !empty($_ENV[$key]) ? $_ENV[$key] : $default_value;
} }
@ -15,7 +22,7 @@ class Misc {
* Returns absolute path for view * Returns absolute path for view
*/ */
static public function getView(string $template): string { static public function getView(string $template): string {
return __DIR__ . "/../views/{$template}.latte"; return __DIR__ . "/../../views/{$template}.latte";
} }
/** /**
@ -25,7 +32,7 @@ class Misc {
$options = []; $options = [];
$cacheEngine = false; $cacheEngine = false;
// Proxy config // Proxy config
foreach(Settings::PROXY as $proxy_element) { foreach(Cookies::PROXY as $proxy_element) {
if (isset($_COOKIE[$proxy_element])) { if (isset($_COOKIE[$proxy_element])) {
$options['proxy'][$proxy_element] = $_COOKIE[$proxy_element]; $options['proxy'][$proxy_element] = $_COOKIE[$proxy_element];
} }
@ -58,14 +65,14 @@ class Misc {
*/ */
static public function latte(): \Latte\Engine { static public function latte(): \Latte\Engine {
// Workaround to avoid weird path issues // Workaround to avoid weird path issues
$url = self::env('APP_URL', ''); $url = self::getURL();
$latte = new \Latte\Engine; $latte = new \Latte\Engine;
$cache_path = self::env('LATTE_CACHE', __DIR__ . '/../cache/latte'); $cache_path = self::env('LATTE_CACHE', __DIR__ . '/../../cache/latte');
$latte->setTempDirectory($cache_path); $latte->setTempDirectory($cache_path);
// -- CUSTOM FUNCTIONS -- // // -- CUSTOM FUNCTIONS -- //
// Import assets // Import assets
$latte->addFunction('assets', function (string $name, string $type) use ($url) { $latte->addFunction('assets', function (string $name, string $type) use ($url) {
$path = "{$url}/{$type}/{$name}"; $path = "{$url}/{$type}/{$name}";
return $path; return $path;
}); });

View file

@ -1,5 +1,5 @@
<?php <?php
namespace Helpers; namespace App\Helpers;
use \Bhaktaraz\RSSGenerator\Feed; use \Bhaktaraz\RSSGenerator\Feed;
use \Bhaktaraz\RSSGenerator\Channel; use \Bhaktaraz\RSSGenerator\Channel;
@ -7,7 +7,7 @@ use \Bhaktaraz\RSSGenerator\Item;
use \Sovit\TikTok\Download; use \Sovit\TikTok\Download;
class RSS { class RSS {
static public function build (string $endpoint, string $title, string $description, array $items, string $image = ''): Feed { static public function build (string $endpoint, string $title, string $description, array $items): Feed {
$url = Misc::env('APP_URL', ''); $url = Misc::env('APP_URL', '');
$download = new Download(); $download = new Download();
$rss_feed = new Feed(); $rss_feed = new Feed();

View file

@ -1,5 +1,5 @@
<?php <?php
namespace Views\Models; namespace App\Models;
/** /**
* Base for all templates, needs a Title to set * Base for all templates, needs a Title to set

View file

@ -1,5 +1,5 @@
<?php <?php
namespace Views\Models; namespace App\Models;
/** /**
* Base for templates with a feed * Base for templates with a feed

View file

@ -1,5 +1,5 @@
<?php <?php
namespace Views\Models; namespace App\Models;
/** /**
* Exclusive for /following * Exclusive for /following

View file

@ -1,5 +1,5 @@
<?php <?php
namespace Views\Models; namespace App\Models;
/** /**
* Base for templates with item (only /video at the time) * Base for templates with item (only /video at the time)

View file

@ -1,8 +1,8 @@
<?php <?php
namespace Views\Models; namespace App\Models;
use \Helpers\Following; use App\Helpers\Cookies;
use \Helpers\Settings; use App\Helpers\Following;
/** /**
* Exclusive for /settings * Exclusive for /settings
@ -13,7 +13,7 @@ class SettingsTemplate extends BaseTemplate {
function __construct() { function __construct() {
parent::__construct('Settings'); parent::__construct('Settings');
$this->proxy_elements = Settings::PROXY; $this->proxy_elements = Cookies::PROXY;
$this->following = Following::getUsers(); $this->following = Following::getUsers();
} }
} }

View file

@ -1,7 +1,7 @@
{ {
"name": "pablouser1/proxitok", "name": "pablouser1/proxitok",
"description": "An alternative frontend for TikTok", "description": "An alternative frontend for TikTok",
"version": "1.3.0", "version": "1.3.1",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"repositories": [ "repositories": [
{ {
@ -19,8 +19,7 @@
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Helpers\\": "helpers/", "App\\": "app/"
"Views\\Models\\": "views/models/"
} }
} }
} }

2
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "c86d4aba41374f807418dde1044dba45", "content-hash": "1ecb565500ab6893126d60eeebcd7379",
"packages": [ "packages": [
{ {
"name": "bhaktaraz/php-rss-generator", "name": "bhaktaraz/php-rss-generator",

View file

@ -7,5 +7,8 @@ $dotenv->safeLoad();
// ROUTER // ROUTER
$router = new Bramus\Router\Router(); $router = new Bramus\Router\Router();
require __DIR__ . '/routes/index.php'; $router->setNamespace('\App\Controllers');
require __DIR__ . '/routes.php';
$router->run(); $router->run();

43
routes.php Normal file
View file

@ -0,0 +1,43 @@
<?php
use App\Helpers\Misc;
use App\Models\BaseTemplate;
$router->get('/', function () {
$latte = Misc::latte();
$latte->render(Misc::getView('home'), new BaseTemplate('Home'));
});
$router->get('/about', function () {
$latte = Misc::latte();
$latte->render(Misc::getView('about'), new BaseTemplate('About'));
});
$router->get('/stream', 'ProxyController@stream');
$router->mount('/trending', function () use ($router) {
$router->get('/', 'TrendingController@get');
$router->get('/rss', 'TrendingController@rss');
});
$router->mount('/@([^/]+)', function () use ($router) {
$router->get('/', 'UserController@get');
$router->get('/rss', 'UserController@rss');
});
$router->get('/video/(\w+)', 'VideoController@get');
$router->mount('/tag', function () use ($router) {
$router->get('/([^/]+)', 'TagController@get');
$router->get('/rss', 'TagController@rss');
});
$router->get('/music/([^/]+)', 'MusicController@get');
// -- Settings -- //
$router->mount('/settings', function () use ($router) {
$router->get('/', 'SettingsController@index');
$router->post('/proxy', 'SettingsController@proxy');
$router->post('/following', 'SettingsController@following');
});
$router->get('/following', 'FollowingController@get');

View file

@ -1,38 +0,0 @@
<?php
const VALID_TIKTOK_DOMAINS = [
"tiktokcdn.com", "tiktokcdn-us.com", "tiktok.com"
];
/**@var Bramus\Router\Router $router */
/**
* Check if an url has a valid domain
* @param string $url URL you want to check
* @return bool
*/
function isValidDomain(string $url): bool {
$host = parse_url($url, PHP_URL_HOST);
$host_split = explode('.', $host);
return count($host_split) === 3 && in_array($host_split[1] . '.' . $host_split[2], VALID_TIKTOK_DOMAINS);
}
$router->get('/stream', function () {
if (!isset($_GET['url'])) {
die('You need to send a url!');
}
$url = $_GET['url'];
if (!filter_var($url, FILTER_VALIDATE_URL) || !isValidDomain($url)) {
die('Not a valid URL');
}
if (isset($_GET['download'])) {
// Download (video only)
$downloader = new \Sovit\TikTok\Download();
$downloader->url($url, "tiktok-video", 'mp4');
} else {
// Stream
$streamer = new \Sovit\TikTok\Stream();
$streamer->stream($url);
}
});

View file

@ -1,15 +0,0 @@
<?php
/**@var Bramus\Router\Router $router */
use Helpers\Following;
use Helpers\Misc;
use Views\Models\FollowingTemplate;
// Showing
$router->get('/following', function () {
$users = Following::getUsers();
$feed = Following::getAll($users);
$latte = Misc::latte();
$latte->render(Misc::getView('following'), new FollowingTemplate($users, $feed));
});

View file

@ -1,99 +0,0 @@
<?php
require __DIR__ . '/assets.php';
require __DIR__ . '/settings.php';
require __DIR__ . '/following.php';
require __DIR__ . '/rss.php';
/**@var Bramus\Router\Router $router */
use Helpers\Misc;
use Helpers\ErrorHandler;
use Views\Models\BaseTemplate;
use Views\Models\FeedTemplate;
use Views\Models\ItemTemplate;
$router->get('/', function () {
$latte = Misc::latte();
$latte->render(Misc::getView('home'), new BaseTemplate('Home'));
});
$router->get('/about', function () {
$latte = Misc::latte();
$latte->render(Misc::getView('about'), new BaseTemplate('About'));
});
$router->get("/trending", function () {
$cursor = 0;
if (isset($_GET['cursor']) && is_numeric($_GET['cursor'])) {
$cursor = (int) $_GET['cursor'];
}
$api = Misc::api();
$feed = $api->getTrendingFeed($cursor);
if ($feed->meta->success) {
$latte = Misc::latte();
$latte->render(Misc::getView('trending'), new FeedTemplate('Trending', $feed));
} else {
ErrorHandler::show($feed->meta);
}
});
$router->get("/@([^/]+)", function (string $username) {
$cursor = 0;
if (isset($_GET['cursor']) && is_numeric($_GET['cursor'])) {
$cursor = (int) $_GET['cursor'];
}
$api = Misc::api();
$feed = $api->getUserFeed($username, $cursor);
if ($feed->meta->success) {
if ($feed->info->detail->user->privateAccount) {
http_response_code(400);
return 'Private account detected! Not supported';
}
$latte = Misc::latte();
$latte->render(Misc::getView('user'), new FeedTemplate($feed->info->detail->user->nickname, $feed));
} else {
ErrorHandler::show($feed->meta);
}
});
$router->get('/video/([^/]+)', function (string $video_id) {
$api = Misc::api();
$item = $api->getVideoByID($video_id);
if ($item->meta->success) {
$latte = Misc::latte();
$latte->render(Misc::getView('video'), new ItemTemplate($item->info->detail->user->nickname, $item));
} else {
ErrorHandler::show($item->meta);
}
});
$router->get('/music/([^/]+)', function (string $music_id) {
$cursor = 0;
if (isset($_GET['cursor']) && is_numeric($_GET['cursor'])) {
$cursor = (int) $_GET['cursor'];
}
$api = Misc::api();
$feed = $api->getMusicFeed($music_id, $cursor);
if ($feed->meta->success) {
$latte = Misc::latte();
$latte->render(Misc::getView('music'), new FeedTemplate('Music', $feed));
} else {
ErrorHandler::show($feed->meta);
}
});
$router->get('/tag/(\w+)', function (string $name) {
$cursor = 0;
if (isset($_GET['cursor']) && is_numeric($_GET['cursor'])) {
$cursor = (int) $_GET['cursor'];
}
$api = Misc::api();
$feed = $api->getChallengeFeed($name, $cursor);
if ($feed->meta->success) {
$latte = Misc::latte();
$latte->render(Misc::getView('tag'), new FeedTemplate('Tag', $feed));
} else {
ErrorHandler::show($feed->meta);
}
});

View file

@ -1,46 +0,0 @@
<?php
/**@var Bramus\Router\Router $router */
use Helpers\Misc;
use Helpers\RSS;
use Helpers\ErrorHandler;
$router->all("/@([^/]+)/rss", function (string $username) {
$api = Misc::api();
$feed = $api->getUserFeed($username);
if ($feed->meta->success) {
$feed = RSS::build('/@'.$username, $feed->info->detail->user->nickname, $feed->info->detail->user->signature, $feed->items);
// Setup headers
RSS::setHeaders('user.rss');
echo $feed;
} else {
ErrorHandler::show($feed->meta);
}
});
$router->all("/trending/rss", function () {
$api = Misc::api();
$feed = $api->getTrendingFeed();
if ($feed->meta->success) {
$feed = RSS::build('/trending', 'Trending', 'Tiktok trending', $feed->items);
// Setup headers
RSS::setHeaders('trending.rss');
echo $feed;
} else {
ErrorHandler::show($feed->meta);
}
});
$router->all("/tag/(\w+)/rss", function (string $name) {
$api = Misc::api();
$feed = $api->getChallengeFeed($name);
if ($feed->meta->success) {
$feed = RSS::build("/tag/{$name}", "{$name} Tag", $feed->info->detail->challenge->desc, $feed->items);
// Setup headers
RSS::setHeaders('tag.rss');
echo $feed;
} else {
ErrorHandler::show($feed->meta);
}
});