Icons, themes, removed instance proxy and more

This commit is contained in:
Pablo Ferreiro 2022-03-29 19:30:31 +02:00
parent 9a35c61023
commit 44ee065ec6
No known key found for this signature in database
GPG key ID: 41FBCE65B779FA24
52 changed files with 476 additions and 511 deletions

View file

@ -3,14 +3,15 @@ namespace App\Controllers;
use App\Helpers\ErrorHandler;
use App\Helpers\Misc;
use App\Helpers\Wrappers;
use App\Models\FeedTemplate;
class DiscoverController {
static public function get() {
$api = Misc::api();
$api = Wrappers::api();
$feed = $api->getDiscover();
if ($feed->meta->success) {
$latte = Misc::latte();
$latte = Wrappers::latte();
$latte->render(Misc::getView('discover'), new FeedTemplate('Discover', $feed));
} else {
ErrorHandler::show($feed->meta);

View file

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

View file

@ -7,17 +7,25 @@ use App\Helpers\Misc;
*/
class RedirectController {
static public function redirect() {
$endpoint = '';
if (isset($_GET['user'])) {
$endpoint = '/@' . $_GET['user'];
} else if (isset($_GET['tag'])) {
$endpoint = '/tag/' . $_GET['tag'];
} else if (isset($_GET['music'])) {
$endpoint = '/music/' . $_GET['music'];
} else if (isset($_GET['video'])) {
// The @username part is not used, but
// it is the schema that TikTok follows
$endpoint = '/@placeholder/video/' . $_GET['video'];
$endpoint = '/';
if (isset($_GET['type'], $_GET['term'])) {
$term = $_GET['term'];
switch ($_GET['type']) {
case 'user':
$endpoint = '/@' . $term;
break;
case 'tag':
$endpoint = '/tag/' . $term;
break;
case 'music':
$endpoint = '/music/' . $term;
break;
case 'video':
// The @username part is not used, but
// it is the schema that TikTok follows
$endpoint = '/@placeholder/video/' . $term;
break;
}
}
$url = Misc::url($endpoint);

View file

@ -3,12 +3,13 @@ namespace App\Controllers;
use App\Helpers\Misc;
use App\Helpers\Cookies;
use App\Models\SettingsTemplate;
use App\Helpers\Wrappers;
use App\Models\BaseTemplate;
class SettingsController {
static public function index() {
$latte = Misc::latte();
$latte->render(Misc::getView('settings'), new SettingsTemplate);
$latte = Wrappers::latte();
$latte->render(Misc::getView('settings'), new BaseTemplate('Settings'));
}
static private function redirect() {
@ -16,19 +17,16 @@ class SettingsController {
header("Location: {$url}");
}
static public function proxy() {
if (in_array(Cookies::PROXY, $_POST)) {
foreach (Cookies::PROXY as $proxy_element) {
Cookies::set($proxy_element, $_POST[$proxy_element]);
}
static public function general() {
if (isset($_POST['theme'])) {
$theme = $_POST['theme'];
Cookies::set('theme', $theme);
}
self::redirect();
}
static public function api() {
$legacy = 'off';
if (isset($_POST['api-legacy'])) {
$legacy = 'on';
$legacy = $_POST['api-legacy'];
}
Cookies::set('api-legacy', $legacy);
self::redirect();

View file

@ -3,16 +3,17 @@ namespace App\Controllers;
use App\Helpers\ErrorHandler;
use App\Helpers\Misc;
use App\Helpers\RSS;
use App\Helpers\Wrappers;
use App\Models\FeedTemplate;
use App\Models\RSSTemplate;
class TagController {
static public function get(string $name) {
$cursor = Misc::getCursor();
$api = Misc::api();
$api = Wrappers::api();
$feed = $api->getHashtagFeed($name, $cursor);
if ($feed->meta->success) {
$latte = Misc::latte();
$latte = Wrappers::latte();
$latte->render(Misc::getView('tag'), new FeedTemplate('Tag', $feed));
} else {
ErrorHandler::show($feed->meta);
@ -20,13 +21,11 @@ class TagController {
}
static public function rss(string $name) {
$api = Misc::api();
$api = Wrappers::api();
$feed = $api->getHashtagFeed($name);
if ($feed->meta->success) {
$feed = RSS::build("/tag/{$name}", "{$name} Tag", $feed->info->detail->desc, $feed->items);
// Setup headers
RSS::setHeaders('tag.rss');
echo $feed;
$latte = Wrappers::latte();
$latte->render(Misc::getView('rss'), new RSSTemplate($name, $feed->info->detail->desc, "/tag/{$name}", $feed->items));
}
}
}

View file

@ -4,11 +4,12 @@ namespace App\Controllers;
use App\Helpers\Misc;
use App\Models\FeedTemplate;
use App\Helpers\ErrorHandler;
use App\Helpers\RSS;
use App\Helpers\Wrappers;
use App\Models\RSSTemplate;
class TrendingController {
static public function get() {
$api = Misc::api();
$api = Wrappers::api();
// Ttwid if normal, cursor if legacy
if ($api::class === 'TikScraper\Api') {
@ -18,7 +19,7 @@ class TrendingController {
}
$feed = $api->getTrending($cursor);
if ($feed->meta->success) {
$latte = Misc::latte();
$latte = Wrappers::latte();
$latte->render(Misc::getView('trending'), new FeedTemplate('Trending', $feed));
} else {
ErrorHandler::show($feed->meta);
@ -26,13 +27,11 @@ class TrendingController {
}
static public function rss() {
$api = Misc::api();
$api = Wrappers::api();
$feed = $api->getTrending();
if ($feed->meta->success) {
$feed = RSS::build('/trending', 'Trending', 'Tiktok trending', $feed->items);
// Setup headers
RSS::setHeaders('trending.rss');
echo $feed;
$latte = Wrappers::latte();
$latte->render(Misc::getView('rss'), new RSSTemplate('Trending', 'Trending on TikTok', '/trending', $feed->items));
}
}
}

View file

@ -3,13 +3,14 @@ namespace App\Controllers;
use App\Helpers\ErrorHandler;
use App\Helpers\Misc;
use App\Helpers\RSS;
use App\Helpers\Wrappers;
use App\Models\FeedTemplate;
use App\Models\RSSTemplate;
class UserController {
static public function get(string $username) {
$cursor = Misc::getCursor();
$api = Misc::api();
$api = Wrappers::api();
$feed = $api->getUserFeed($username, $cursor);
if ($feed->meta->success) {
if ($feed->info->detail->privateAccount) {
@ -17,7 +18,7 @@ class UserController {
echo 'Private account detected! Not supported';
exit;
}
$latte = Misc::latte();
$latte = Wrappers::latte();
$latte->render(Misc::getView('user'), new FeedTemplate($feed->info->detail->nickname, $feed));
} else {
ErrorHandler::show($feed->meta);
@ -25,10 +26,10 @@ class UserController {
}
static public function video(string $username, string $video_id) {
$api = Misc::api();
$api = Wrappers::api();
$feed = $api->getVideoByID($video_id);
if ($feed->meta->success) {
$latte = Misc::latte();
$latte = Wrappers::latte();
$latte->render(Misc::getView('video'), new FeedTemplate('Video', $feed));
} else {
ErrorHandler::show($feed->meta);
@ -36,13 +37,11 @@ class UserController {
}
static public function rss(string $username) {
$api = Misc::api();
$api = Wrappers::api();
$feed = $api->getUserFeed($username);
if ($feed->meta->success) {
$feed = RSS::build('/@'.$username, $feed->info->detail->nickname, $feed->info->detail->signature, $feed->items);
// Setup headers
RSS::setHeaders('user.rss');
echo $feed;
$latte = Wrappers::latte();
$latte->render(Misc::getView('rss'), new RSSTemplate($username, $feed->info->detail->signature, '/@' . $username, $feed->items));
}
}
}

View file

@ -2,13 +2,21 @@
namespace App\Helpers;
class Cookies {
const PROXY = ['host', 'port', 'user', 'password'];
const ALLOWED_THEMES = ['default', 'card'];
static public function get(string $name): ?string {
static public function get(string $name, string $default_value = ''): string {
if (isset($_COOKIE[$name]) && !empty($_COOKIE[$name])) {
return $_COOKIE[$name];
}
return null;
return $default_value;
}
static public function theme(): string {
$theme = self::get('theme');
if ($theme && in_array($theme, self::ALLOWED_THEMES)) {
return $theme;
}
return 'default';
}
static public function exists(string $name): bool {

View file

@ -6,7 +6,7 @@ use App\Models\ErrorTemplate;
class ErrorHandler {
static public function show(object $meta) {
http_response_code($meta->http_code);
$latte = Misc::latte();
$latte = Wrappers::latte();
$latte->render(Misc::getView('error'), new ErrorTemplate($meta));
}
}

View file

@ -1,9 +1,6 @@
<?php
namespace App\Helpers;
use App\Cache\JSONCache;
use App\Cache\RedisCache;
class Misc {
static public function getCursor(): int {
return isset($_GET['cursor']) && is_numeric($_GET['cursor']) ? (int) $_GET['cursor'] : 0;
@ -13,8 +10,10 @@ class Misc {
return isset($_GET['cursor']) ? $_GET['cursor'] : '';
}
static public function url(string $endpoint = '') {
return self::env('APP_URL', '') . $endpoint;
static public function url(string $endpoint = ''): string {
$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http";
$root = $protocol . '://' . $_SERVER['HTTP_HOST'];
return $root . self::env('APP_PATH', '') . $endpoint;
}
static public function env(string $key, $default_value) {
@ -27,97 +26,4 @@ class Misc {
static public function getView(string $template): string {
return __DIR__ . "/../../views/{$template}.latte";
}
/**
* Setup of TikTok Api wrapper
* @return \TikScraper\Api|\TikScraper\Legacy
*/
static public function api() {
$options = [
'use_test_endpoints' => self::env('API_TEST_ENDPOINTS', false),
// Instance level proxy config
'proxy' => [
'host' => self::env('PROXY_HOST', null),
'port' => self::env('PROXY_PORT', null),
'user' => self::env('PROXY_USER', null),
'password' => self::env('PROXY_PASSWORD', null)
],
'signer' => [
'remote_url' => self::env('API_SIGNER_URL', ''),
'browser_url' => self::env('API_BROWSER_URL', ''),
'close_when_done' => false
]
];
// User level proxy config, will overwrite instance config
foreach(Cookies::PROXY as $proxy_element) {
if (isset($_COOKIE[$proxy_element])) {
$options['proxy'][$proxy_element] = $_COOKIE[$proxy_element];
}
}
// Cache config
$cacheEngine = false;
if (isset($_ENV['API_CACHE'])) {
switch ($_ENV['API_CACHE']) {
case 'json':
$cacheEngine = new JSONCache();
break;
case 'redis':
if (!(isset($_ENV['REDIS_URL']) || isset($_ENV['REDIS_HOST'], $_ENV['REDIS_PORT']))) {
throw new \Exception('You need to set REDIS_URL or REDIS_HOST and REDIS_PORT to use Redis Cache!');
}
if (isset($_ENV['REDIS_URL'])) {
$url = parse_url($_ENV['REDIS_URL']);
$host = $url['host'];
$port = $url['port'];
$password = $url['pass'] ?? null;
} else {
$host = $_ENV['REDIS_HOST'];
$port = (int) $_ENV['REDIS_PORT'];
$password = isset($_ENV['REDIS_PASSWORD']) ? $_ENV['REDIS_PASSWORD'] : null;
}
$cacheEngine = new RedisCache($host, $port, $password);
break;
}
}
// Legacy mode
$legacy = self::env('API_FORCE_LEGACY', false) || isset($_COOKIE['api-legacy']) && $_COOKIE['api-legacy'] === 'on';
return $legacy === false ? new \TikScraper\Api($options, $cacheEngine) : new \TikScraper\Legacy($options, $cacheEngine);
}
/**
* Setup of Latte template engine
*/
static public function latte(): \Latte\Engine {
$latte = new \Latte\Engine;
$cache_path = self::env('LATTE_CACHE', __DIR__ . '/../../cache/latte');
$latte->setTempDirectory($cache_path);
// -- CUSTOM FUNCTIONS -- //
// Get URL with optional endpoint
$latte->addFunction('path', function (string $endpoint = ''): string {
return self::url($endpoint);
});
// Version being used
$latte->addFunction('version', function (): string {
return \Composer\InstalledVersions::getVersion('pablouser1/proxitok');
});
// https://stackoverflow.com/a/36365553
$latte->addFunction('number', function (float $x) {
if($x > 1000) {
$x_number_format = number_format($x);
$x_array = explode(',', $x_number_format);
$x_parts = array('K', 'M', 'B', 'T');
$x_count_parts = count($x_array) - 1;
$x_display = $x;
$x_display = $x_array[0] . ((int) $x_array[1][0] !== 0 ? '.' . $x_array[1][0] : '');
$x_display .= $x_parts[$x_count_parts - 1];
return $x_display;
}
return $x;
});
return $latte;
}
}

View file

@ -1,34 +0,0 @@
<?php
namespace App\Helpers;
use \FeedWriter\RSS2;
use \TikScraper\Download;
class RSS {
static public function build(string $endpoint, string $title, string $description, array $items): string {
$url = Misc::env('APP_URL', '');
$download = new Download();
$rss = new RSS2();
$rss->setTitle($title);
$rss->setDescription($description);
$rss->setLink($url . $endpoint);
$rss->setSelfLink($url . $endpoint . '/rss');
foreach ($items as $item) {
$item_rss = $rss->createNewItem();
$video = $item->video->playAddr;
$item_rss->setTitle($item->desc);
$item_rss->setDescription($item->desc);
$item_rss->setLink($url . '/video/' . $item->id);
$item_rss->setDate((int) $item->createTime);
$item_rss->setId($item->id, false);
$item_rss->addEnclosure($url . '/stream?url=' . urlencode($video), $download->file_size($video), 'video/mp4');
$rss->addItem($item_rss);
}
return $rss->generateFeed();
}
static public function setHeaders (string $filename) {
header('Content-Type: application/rss+xml');
header('Content-Disposition: attachment; filename="' . $filename . '"');
}
}

90
app/Helpers/Wrappers.php Normal file
View file

@ -0,0 +1,90 @@
<?php
namespace App\Helpers;
use App\Cache\JSONCache;
use App\Cache\RedisCache;
class Wrappers {
/**
* Setup of Latte template engine
*/
static public function latte(): \Latte\Engine {
$latte = new \Latte\Engine;
$cache_path = Misc::env('LATTE_CACHE', __DIR__ . '/../../cache/latte');
$latte->setTempDirectory($cache_path);
// -- CUSTOM FUNCTIONS -- //
// Get URL with optional endpoint
$latte->addFunction('path', function (string $endpoint = ''): string {
return Misc::url($endpoint);
});
// Version being used
$latte->addFunction('version', function (): string {
return \Composer\InstalledVersions::getVersion('pablouser1/proxitok');
});
$latte->addFunction('theme', function(): string {
return Cookies::theme();
});
// https://stackoverflow.com/a/36365553
$latte->addFunction('number', function (float $x) {
if($x > 1000) {
$x_number_format = number_format($x);
$x_array = explode(',', $x_number_format);
$x_parts = array('K', 'M', 'B', 'T');
$x_count_parts = count($x_array) - 1;
$x_display = $x;
$x_display = $x_array[0] . ((int) $x_array[1][0] !== 0 ? '.' . $x_array[1][0] : '');
$x_display .= $x_parts[$x_count_parts - 1];
return $x_display;
}
return $x;
});
return $latte;
}
/**
* Setup of TikTok Api wrapper
* @return \TikScraper\Api|\TikScraper\Legacy
*/
static public function api() {
$options = [
'use_test_endpoints' => Misc::env('API_TEST_ENDPOINTS', false),
'signer' => [
'remote_url' => Misc::env('API_SIGNER_URL', ''),
'browser_url' => Misc::env('API_BROWSER_URL', ''),
'close_when_done' => false
]
];
// Cache config
$cacheEngine = false;
if (isset($_ENV['API_CACHE'])) {
switch ($_ENV['API_CACHE']) {
case 'json':
$cacheEngine = new JSONCache();
break;
case 'redis':
if (!(isset($_ENV['REDIS_URL']) || isset($_ENV['REDIS_HOST'], $_ENV['REDIS_PORT']))) {
throw new \Exception('You need to set REDIS_URL or REDIS_HOST and REDIS_PORT to use Redis Cache!');
}
if (isset($_ENV['REDIS_URL'])) {
$url = parse_url($_ENV['REDIS_URL']);
$host = $url['host'];
$port = $url['port'];
$password = $url['pass'] ?? null;
} else {
$host = $_ENV['REDIS_HOST'];
$port = (int) $_ENV['REDIS_PORT'];
$password = isset($_ENV['REDIS_PASSWORD']) ? $_ENV['REDIS_PASSWORD'] : null;
}
$cacheEngine = new RedisCache($host, $port, $password);
break;
}
}
// Legacy mode
$legacy = Misc::env('API_FORCE_LEGACY', false) || isset($_COOKIE['api-legacy']) && $_COOKIE['api-legacy'] === 'on';
return $legacy === false ? new \TikScraper\Api($options, $cacheEngine) : new \TikScraper\Legacy($options, $cacheEngine);
}
}

View file

@ -1,34 +0,0 @@
<?php
namespace App\Models;
/**
* Exclusive for /
*/
class HomeTemplate extends BaseTemplate {
public array $forms = [
[
'title' => 'Search by user',
'input' => 'user',
'placeholder' => 'Type username'
],
[
'title' => 'Search by video ID',
'input' => 'video',
'placeholder' => 'Type video ID'
],
[
'title' => 'Search by tag',
'input' => 'tag',
'placeholder' => 'Type tag'
],
[
'title' => 'Search by music ID',
'input' => 'music',
'placeholder' => 'Type music'
]
];
function __construct() {
parent::__construct('Home');
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace App\Models;
/**
* Base for templates with a feed
*/
class RSSTemplate {
public string $title;
public string $desc;
public string $link;
public array $items;
function __construct(string $title, string $desc, string $link, array $items) {
$this->title = $title;
$this->desc = $desc;
$this->link = $link;
$this->items = $items;
}
}

View file

@ -1,16 +0,0 @@
<?php
namespace App\Models;
use App\Helpers\Cookies;
/**
* Exclusive for /settings
*/
class SettingsTemplate extends BaseTemplate {
public array $proxy_elements = [];
function __construct() {
parent::__construct('Settings');
$this->proxy_elements = Cookies::PROXY;
}
}