mirror of
https://github.com/pablouser1/ProxiTok.git
synced 2024-12-06 19:27:30 +01:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 78fe44070c | |||
| 7d2f6e8fd6 | |||
| 32d49954f9 | |||
| 5c770def41 | |||
| d273b35e53 | |||
| faf1dcee51 | |||
| 89d9ad2f9c | |||
| 7ddf6f7738 | |||
| 059bf7208a | |||
| d5858c39fd | |||
| 76be343c13 | |||
| a7b0edf8fe | |||
| 73e9d7a1cd | |||
| 0224cd25eb | |||
| 215f984fe4 | |||
| ee6e8b0593 | |||
| fa3f1e0a7c | |||
| ce5c9e016b | |||
| 49fcc79f15 | |||
| b138f4bccc | |||
| 94da0e46ac | |||
| 1176bc35fe | |||
| 4bfc4c9434 | |||
| de85ba3e44 | |||
| 79fd699cee | |||
| 8f83a27885 | |||
| cba59e66c7 | |||
| c925ca2a41 | |||
| 32ea8b6b12 | |||
| 7d0df67ded | |||
| 23583ef7ab | |||
| 6fafcdcd11 |
@@ -3,7 +3,7 @@ name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: pablouser1
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: sigstore/cosign-installer@main
|
||||
with:
|
||||
cosign-release: 'v1.9.0'
|
||||
cosign-release: 'v2.0.0-rc.0'
|
||||
|
||||
|
||||
# Workaround: https://github.com/docker/build-push-action/issues/461
|
||||
|
||||
@@ -1 +1 @@
|
||||
web: vendor/bin/heroku-php-nginx -C setup/heroku/nginx.conf
|
||||
web: vendor/bin/heroku-php-nginx -C misc/setup/heroku/nginx.conf
|
||||
|
||||
@@ -40,7 +40,8 @@ Apply to: Main window (address bar)
|
||||
* Add custom amount of videos per page
|
||||
|
||||
## Credits
|
||||
[@TheFrenchGhosty](https://github.com/TheFrenchGhosty): Initial Dockerfile and fixes to a usable state. You can check his Docker image [here](https://github.com/PussTheCat-org/docker-proxitok-quay) on Github or [here](https://quay.io/repository/pussthecatorg/proxitok) on Quay
|
||||
[TheFrenchGhosty](https://thefrenchghosty.me) ([Github](https://github.com/TheFrenchGhosty)): Initial Dockerfile and fixes to a usable state.
|
||||
|
||||
### External libraries
|
||||
* [TikScraperPHP](https://github.com/pablouser1/TikScraperPHP)
|
||||
* [Latte](https://github.com/nette/latte)
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
"description": "Latte cache path",
|
||||
"value": "/tmp/latte"
|
||||
},
|
||||
"API_SIGNER": {
|
||||
"description": "Signer method",
|
||||
"value": "remote"
|
||||
},
|
||||
"API_SIGNER_URL": {
|
||||
"description": "Remote signer url",
|
||||
"value": "https://signtok.vercel.app/api"
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
namespace App\Cache;
|
||||
|
||||
use TikScraper\Interfaces\CacheInterface;
|
||||
|
||||
class ApcuCache implements CacheInterface {
|
||||
function __construct() {
|
||||
if (!(extension_loaded('apcu') && apcu_enabled())) {
|
||||
throw new \Exception('APCu not enabled');
|
||||
}
|
||||
}
|
||||
|
||||
public function get(string $cache_key): ?object {
|
||||
$data = apcu_fetch($cache_key);
|
||||
return $data !== false ? json_decode($data) : null;
|
||||
}
|
||||
|
||||
public function exists(string $cache_key): bool {
|
||||
return apcu_exists($cache_key);
|
||||
}
|
||||
|
||||
public function set(string $cache_key, string $data, $timeout = 3600): void {
|
||||
apcu_store($cache_key, $data, $timeout);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
<?php
|
||||
namespace App\Constants;
|
||||
|
||||
class CacheMethods {
|
||||
abstract class CacheMethods {
|
||||
const JSON = 'json';
|
||||
const APCU = 'apcu';
|
||||
const REDIS = 'redis';
|
||||
}
|
||||
|
||||
@@ -2,19 +2,17 @@
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Helpers\ErrorHandler;
|
||||
use App\Helpers\Misc;
|
||||
use App\Helpers\Wrappers;
|
||||
use App\Models\FeedTemplate;
|
||||
use App\Models\DiscoverTemplate;
|
||||
|
||||
class DiscoverController {
|
||||
static public function get() {
|
||||
$api = Wrappers::api();
|
||||
$feed = $api->discover();
|
||||
if ($feed->meta->success) {
|
||||
$latte = Wrappers::latte();
|
||||
$latte->render(Misc::getView('discover'), new FeedTemplate('Discover', $feed));
|
||||
$data = $api->discover();
|
||||
if ($data->meta->success) {
|
||||
Wrappers::latte('discover', new DiscoverTemplate($data));
|
||||
} else {
|
||||
ErrorHandler::showMeta($feed->meta);
|
||||
ErrorHandler::showMeta($data->meta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Helpers\ErrorHandler;
|
||||
use App\Helpers\Misc;
|
||||
use App\Helpers\Wrappers;
|
||||
use App\Models\VideoTemplate;
|
||||
|
||||
@@ -12,9 +11,9 @@ class EmbedController {
|
||||
$video = $api->video($id);
|
||||
$video->feed();
|
||||
if ($video->ok()) {
|
||||
$data = $video->getFull();
|
||||
$latte = Wrappers::latte();
|
||||
$latte->render(Misc::getView('video'), new VideoTemplate($data->feed->items[0], $data->info->detail, true));
|
||||
$item = $video->getFeed()->items[0];
|
||||
$info = $video->getInfo();
|
||||
Wrappers::latte('video', new VideoTemplate($item, $info, true));
|
||||
} else {
|
||||
ErrorHandler::showMeta($video->error());
|
||||
}
|
||||
|
||||
@@ -14,9 +14,9 @@ class MusicController {
|
||||
$music = $api->music($music_id);
|
||||
$music->feed($cursor);
|
||||
if ($music->ok()) {
|
||||
$data = $music->getFull();
|
||||
$latte = Wrappers::latte();
|
||||
$latte->render(Misc::getView('music'), new FullTemplate('Music', $data));
|
||||
$info = $music->getInfo();
|
||||
$feed = $music->getFeed();
|
||||
Wrappers::latte('music', new FullTemplate('Music', $info, $feed));
|
||||
} else {
|
||||
ErrorHandler::showMeta($music->error());
|
||||
}
|
||||
|
||||
@@ -2,43 +2,12 @@
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Helpers\Cookies;
|
||||
use TikScraper\Helpers\Converter;
|
||||
|
||||
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);
|
||||
$host_count = count($host_split);
|
||||
if ($host_count === 2) {
|
||||
// Using no watermark
|
||||
return in_array($host_split[0] . '.' . $host_split[1], self::VALID_TIKTOK_DOMAINS);
|
||||
} elseif ($host_count === 3) {
|
||||
return in_array($host_split[1] . '.' . $host_split[2], self::VALID_TIKTOK_DOMAINS);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static private function checkUrl() {
|
||||
if (!isset($_GET['url'])) {
|
||||
die('You need to send a URL');
|
||||
}
|
||||
|
||||
if (!filter_var($_GET['url'], FILTER_VALIDATE_URL) || !self::isValidDomain($_GET['url'])) {
|
||||
die('Not a valid URL');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static private function getFilename(string $url, string $user): string {
|
||||
$id = Converter::urlToId($url);
|
||||
$filename = 'tiktok-video-' . $id . '-' . $user;
|
||||
return $filename;
|
||||
}
|
||||
|
||||
static public function stream() {
|
||||
self::checkUrl();
|
||||
$url = $_GET['url'];
|
||||
@@ -52,12 +21,43 @@ class ProxyController {
|
||||
$downloader = new \TikScraper\Download($method);
|
||||
|
||||
// Params
|
||||
$id = $_GET['id'] ?? '';
|
||||
$watermark = isset($_GET['watermark']);
|
||||
$url = $_GET['url'];
|
||||
$user = $_GET['user'] ?? '';
|
||||
// Filename
|
||||
$filename = self::getFilename($url, $user);
|
||||
$filename = self::getFilename($id, $user);
|
||||
// Running
|
||||
$downloader->url($_GET['url'], $filename, $watermark);
|
||||
$downloader->url($url, $filename, $watermark);
|
||||
}
|
||||
|
||||
static private function isValidDomain(string $url): bool {
|
||||
$valid = false;
|
||||
$host = parse_url($url, PHP_URL_HOST);
|
||||
$host_split = explode('.', $host);
|
||||
$host_count = count($host_split);
|
||||
if ($host_count === 2) {
|
||||
// Using no watermark
|
||||
$valid = in_array($host_split[0] . '.' . $host_split[1], self::VALID_TIKTOK_DOMAINS);
|
||||
} elseif ($host_count === 3) {
|
||||
$valid = in_array($host_split[1] . '.' . $host_split[2], self::VALID_TIKTOK_DOMAINS);
|
||||
}
|
||||
return $valid;
|
||||
}
|
||||
|
||||
static private function checkUrl(): void {
|
||||
if (!isset($_GET['url'])) {
|
||||
die('You need to send a URL');
|
||||
}
|
||||
|
||||
if (!filter_var($_GET['url'], FILTER_VALIDATE_URL) || !self::isValidDomain($_GET['url'])) {
|
||||
die('Not a valid URL');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static private function getFilename(string $id, string $user): string {
|
||||
$filename = 'tiktok-video-' . $id . '-' . $user;
|
||||
return $filename;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
namespace App\Controllers;
|
||||
use App\Helpers\ErrorHandler;
|
||||
use App\Helpers\Misc;
|
||||
use App\Helpers\UrlBuilder;
|
||||
|
||||
/**
|
||||
* Used to be compatible with HTML forms
|
||||
*/
|
||||
class RedirectController {
|
||||
static public function redirect() {
|
||||
static public function search() {
|
||||
$endpoint = '/';
|
||||
if (isset($_GET['type'], $_GET['term'])) {
|
||||
$term = urlencode(trim($_GET['term']));
|
||||
$term = trim($_GET['term']);
|
||||
switch ($_GET['type']) {
|
||||
case 'url':
|
||||
$endpoint = self::to_endpoint($term);
|
||||
@@ -24,22 +25,22 @@ class RedirectController {
|
||||
if ($term[0] === '@') {
|
||||
$term = substr($term, 1);
|
||||
}
|
||||
$endpoint = '/@' . $term;
|
||||
$endpoint = '/@' . urlencode($term);
|
||||
break;
|
||||
case 'tag':
|
||||
// Remove # if sent
|
||||
if ($term[0] === '#') {
|
||||
$term = substr($term, 1);
|
||||
}
|
||||
$endpoint = '/tag/' . $term;
|
||||
$endpoint = '/tag/' . urlencode($term);
|
||||
break;
|
||||
case 'music':
|
||||
$endpoint = '/music/' . $term;
|
||||
$endpoint = '/music/' . urlencode($term);
|
||||
break;
|
||||
case 'video':
|
||||
// The @username part is not used, but
|
||||
// it is the schema that TikTok follows
|
||||
$endpoint = '/@placeholder/video/' . $term;
|
||||
$endpoint = '/@placeholder/video/' . urlencode($term);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -48,6 +49,24 @@ class RedirectController {
|
||||
header("Location: {$url}");
|
||||
}
|
||||
|
||||
static public function download() {
|
||||
if (!(isset($_GET['videoId'], $_GET['authorUsername'], $_GET['playAddr']))) {
|
||||
ErrorHandler::showText(400, 'Request incomplete');
|
||||
return;
|
||||
}
|
||||
|
||||
$watermark = isset($_GET['watermark']) && $_GET['watermark'] === 'yes' ? true : false;
|
||||
|
||||
$url = '';
|
||||
if ($watermark) {
|
||||
$url = UrlBuilder::download($_GET['playAddr'], $_GET['authorUsername'], $_GET['videoId'], true);
|
||||
} else {
|
||||
$url = UrlBuilder::download(UrlBuilder::video_external($_GET['authorUsername'], $_GET['videoId']), $_GET['authorUsername'], $_GET['videoId'], false);
|
||||
}
|
||||
|
||||
header("Location: {$url}");
|
||||
}
|
||||
|
||||
/**
|
||||
* to_endpoint maps a TikTok URL into a ProxiTok-compatible endpoint URL.
|
||||
*/
|
||||
@@ -60,17 +79,17 @@ class RedirectController {
|
||||
if (preg_match('%^(@[A-Za-z0-9_.]+)(?:/|$)(.*)%', $m[1], $u)) {
|
||||
if ($u[2] == '') {
|
||||
// User profile URL
|
||||
return '/' . $u[1];
|
||||
return '/' . urlencode($u[1]);
|
||||
} elseif (preg_match('%^video/(\d+)%', $u[2], $v)) {
|
||||
// Video URL
|
||||
return '/' . $u[1] . '/video/' . $v[1];
|
||||
return '/' . urlencode($u[1]) . '/video/' . urlencode($v[1]);
|
||||
}
|
||||
} elseif (preg_match('%^tag/([^ ]+?)(?:/|$)%', $m[1], $t)) {
|
||||
// Tag URL
|
||||
return '/tag/' . $t[1];
|
||||
return '/tag/' . urlencode($t[1]);
|
||||
} elseif (preg_match('%^music/([^ ]+?)(?:/|$)%', $m[1], $m)) {
|
||||
// Music URL
|
||||
return '/music/' . $m[1];
|
||||
return '/music/' . urlencode($m[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,7 @@ use App\Models\SettingsTemplate;
|
||||
|
||||
class SettingsController {
|
||||
static public function index() {
|
||||
$latte = Wrappers::latte();
|
||||
$latte->render(Misc::getView('settings'), new SettingsTemplate());
|
||||
Wrappers::latte('settings', new SettingsTemplate());
|
||||
}
|
||||
|
||||
static public function general() {
|
||||
@@ -19,6 +18,7 @@ class SettingsController {
|
||||
}
|
||||
self::redirect();
|
||||
}
|
||||
|
||||
static public function api() {
|
||||
// TODO, ADD COUNT
|
||||
if (isset($_POST['api-test_endpoints'])) {
|
||||
|
||||
@@ -3,6 +3,7 @@ namespace App\Controllers;
|
||||
|
||||
use App\Helpers\ErrorHandler;
|
||||
use App\Helpers\Misc;
|
||||
use App\Helpers\UrlBuilder;
|
||||
use App\Helpers\Wrappers;
|
||||
use App\Models\FullTemplate;
|
||||
use App\Models\RSSTemplate;
|
||||
@@ -14,9 +15,9 @@ class TagController {
|
||||
$hashtag = $api->hashtag($name);
|
||||
$hashtag->feed($cursor);
|
||||
if ($hashtag->ok()) {
|
||||
$data = $hashtag->getFull();
|
||||
$latte = Wrappers::latte();
|
||||
$latte->render(Misc::getView('tag'), new FullTemplate($data->info->detail->title, $data));
|
||||
$info = $hashtag->getInfo();
|
||||
$feed = $hashtag->getFeed();
|
||||
Wrappers::latte('tag', new FullTemplate($info->detail->title, $info, $feed));
|
||||
} else {
|
||||
ErrorHandler::showMeta($hashtag->error());
|
||||
}
|
||||
@@ -28,8 +29,8 @@ class TagController {
|
||||
$hashtag->feed();
|
||||
if ($hashtag->ok()) {
|
||||
$data = $hashtag->getFull();
|
||||
$latte = Wrappers::latte();
|
||||
$latte->render(Misc::getView('rss'), new RSSTemplate($name, $data->info->detail->desc, "/tag/{$name}", $data->feed->items));
|
||||
Misc::rss($name);
|
||||
Wrappers::latte('rss', new RSSTemplate($name, $data->info->detail->desc, UrlBuilder::tag($name), $data->feed->items));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,7 @@ class TrendingController {
|
||||
|
||||
$feed = $trending->getFeed();
|
||||
if ($feed && $feed->meta->success) {
|
||||
$latte = Wrappers::latte();
|
||||
$latte->render(Misc::getView('trending'), new FeedTemplate('Trending', $feed));
|
||||
Wrappers::latte('trending', new FeedTemplate('Trending', $feed));
|
||||
} else {
|
||||
ErrorHandler::showMeta($trending->error());
|
||||
}
|
||||
@@ -31,8 +30,8 @@ class TrendingController {
|
||||
|
||||
$feed = $trending->getFeed();
|
||||
if ($feed && $feed->meta->success) {
|
||||
$latte = Wrappers::latte();
|
||||
$latte->render(Misc::getView('rss'), new RSSTemplate('Trending', 'Trending on TikTok', '/trending', $feed->items));
|
||||
Misc::rss('Trending');
|
||||
Wrappers::latte('rss', new RSSTemplate('Trending', 'Trending on TikTok', Misc::url('/trending'), $feed->items));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ namespace App\Controllers;
|
||||
|
||||
use App\Helpers\ErrorHandler;
|
||||
use App\Helpers\Misc;
|
||||
use App\Helpers\UrlBuilder;
|
||||
use App\Helpers\Wrappers;
|
||||
use App\Models\FullTemplate;
|
||||
use App\Models\RSSTemplate;
|
||||
@@ -15,13 +16,13 @@ class UserController {
|
||||
$user = $api->user($username);
|
||||
$user->feed($cursor);
|
||||
if ($user->ok()) {
|
||||
$data = $user->getFull();
|
||||
if ($data->info->detail->privateAccount) {
|
||||
$info = $user->getInfo();
|
||||
$feed = $user->getFeed();
|
||||
if ($info->detail->privateAccount) {
|
||||
ErrorHandler::showText(401, "Private account detected! Not supported");
|
||||
return;
|
||||
}
|
||||
$latte = Wrappers::latte();
|
||||
$latte->render(Misc::getView('user'), new FullTemplate($data->info->detail->nickname, $data));
|
||||
Wrappers::latte('user', new FullTemplate($info->detail->nickname, $info, $feed));
|
||||
} else {
|
||||
ErrorHandler::showMeta($user->error());
|
||||
}
|
||||
@@ -32,9 +33,9 @@ class UserController {
|
||||
$video = $api->video($video_id);
|
||||
$video->feed();
|
||||
if ($video->ok()) {
|
||||
$data = $video->getFull();
|
||||
$latte = Wrappers::latte();
|
||||
$latte->render(Misc::getView('video'), new VideoTemplate($data->feed->items[0], $data->info->detail));
|
||||
$item = $video->getFeed()->items[0];
|
||||
$info = $video->getInfo();
|
||||
Wrappers::latte('video', new VideoTemplate($item, $info));
|
||||
} else {
|
||||
ErrorHandler::showMeta($video->error());
|
||||
}
|
||||
@@ -46,8 +47,8 @@ class UserController {
|
||||
$user->feed();
|
||||
if ($user->ok()) {
|
||||
$data = $user->getFull();
|
||||
$latte = Wrappers::latte();
|
||||
$latte->render(Misc::getView('rss'), new RSSTemplate($username, $data->info->detail->signature, '/@' . $username, $data->feed->items));
|
||||
Misc::rss($username);
|
||||
Wrappers::latte('rss', new RSSTemplate($username, $data->info->detail->signature, UrlBuilder::user($username), $data->feed->items));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,13 +7,11 @@ use TikScraper\Models\Meta;
|
||||
class ErrorHandler {
|
||||
static public function showMeta(Meta $meta) {
|
||||
http_response_code($meta->http_code);
|
||||
$latte = Wrappers::latte();
|
||||
$latte->render(Misc::getView('error'), new ErrorTemplate($meta->http_code, $meta->tiktok_msg, $meta->tiktok_code));
|
||||
Wrappers::latte('error', new ErrorTemplate($meta->http_code, $meta->tiktok_msg, $meta->tiktok_code));
|
||||
}
|
||||
|
||||
static public function showText(int $code, string $msg) {
|
||||
http_response_code($code);
|
||||
$latte = Wrappers::latte();
|
||||
$latte->render(Misc::getView('error'), new ErrorTemplate($code, $msg));
|
||||
Wrappers::latte('error', new ErrorTemplate($code, $msg));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,13 @@ class Misc {
|
||||
* Returns absolute path for view
|
||||
*/
|
||||
static public function getView(string $template): string {
|
||||
return __DIR__ . "/../../views/{$template}.latte";
|
||||
return __DIR__ . "/../../templates/views/{$template}.latte";
|
||||
}
|
||||
|
||||
/**
|
||||
* Common method for rss feeds
|
||||
*/
|
||||
static public function rss(string $title) {
|
||||
header('Content-Disposition: attachment; filename="' . $title . '.rss' . '"');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,8 @@ class UrlBuilder {
|
||||
return Misc::url('/stream?url=' . urlencode($url));
|
||||
}
|
||||
|
||||
static public function download(string $url, string $username, bool $watermark): string {
|
||||
// {path('/download?url=' . urlencode($playAddr) . '&id=' . $id . '&user=' . $uniqueId) . '&watermark=1'}
|
||||
$down_url = Misc::url('/download?url=' . urlencode($url) . '&user=' . $username);
|
||||
static public function download(string $url, string $username, string $id, bool $watermark): string {
|
||||
$down_url = Misc::url('/download?url=' . urlencode($url) . '&id=' . $id . '&user=' . $username);
|
||||
if ($watermark) $down_url .= '&watermark=1';
|
||||
return $down_url;
|
||||
}
|
||||
@@ -17,6 +16,10 @@ class UrlBuilder {
|
||||
return Misc::url('/@' . $username);
|
||||
}
|
||||
|
||||
static public function tag(string $tag): string {
|
||||
return Misc::url('/tag/' . $tag);
|
||||
}
|
||||
|
||||
static public function video_internal(string $username, string $id): string {
|
||||
return Misc::url('/@' . $username . "/video/" . $id);
|
||||
}
|
||||
|
||||
+54
-21
@@ -1,15 +1,17 @@
|
||||
<?php
|
||||
namespace App\Helpers;
|
||||
|
||||
use App\Cache\ApcuCache;
|
||||
use App\Cache\JSONCache;
|
||||
use App\Cache\RedisCache;
|
||||
use App\Constants\CacheMethods;
|
||||
use App\Models\BaseTemplate;
|
||||
|
||||
class Wrappers {
|
||||
/**
|
||||
* Setup of Latte template engine
|
||||
*/
|
||||
static public function latte(): \Latte\Engine {
|
||||
static public function latte(string $template, BaseTemplate $base) {
|
||||
$latte = new \Latte\Engine;
|
||||
$cache_path = Misc::env('LATTE_CACHE', __DIR__ . '/../../cache/latte');
|
||||
$latte->setTempDirectory($cache_path);
|
||||
@@ -19,6 +21,32 @@ class Wrappers {
|
||||
$latte->addFunction('path', function (string $endpoint = ''): string {
|
||||
return Misc::url($endpoint);
|
||||
});
|
||||
|
||||
// Static assets
|
||||
$latte->addFunction('static', function (string $type, string $file, bool $isVendor = false): string {
|
||||
$endpoint = '';
|
||||
switch ($type) {
|
||||
case 'js':
|
||||
$endpoint .= '/scripts';
|
||||
break;
|
||||
case 'css':
|
||||
$endpoint .= '/styles';
|
||||
break;
|
||||
default:
|
||||
throw new \Exception('Invalid static asset type');
|
||||
}
|
||||
|
||||
if ($isVendor) $endpoint .= '/vendor';
|
||||
|
||||
$endpoint .= '/' . $file;
|
||||
|
||||
return Misc::url($endpoint);
|
||||
});
|
||||
|
||||
$latte->addFunction('theme', function(): string {
|
||||
return Cookies::theme();
|
||||
});
|
||||
|
||||
// Version being used
|
||||
$latte->addFunction('version_frontend', function (): string {
|
||||
return \Composer\InstalledVersions::getVersion('pablouser1/proxitok');
|
||||
@@ -26,26 +54,7 @@ class Wrappers {
|
||||
$latte->addFunction('version_scraper', function (): string {
|
||||
return \Composer\InstalledVersions::getVersion('pablouser1/tikscraper');
|
||||
});
|
||||
$latte->addFunction('theme', function(): string {
|
||||
return Cookies::theme();
|
||||
});
|
||||
|
||||
// UrlBuilder
|
||||
$latte->addFunction('url_stream', function (string $url): string {
|
||||
return UrlBuilder::stream($url);
|
||||
});
|
||||
$latte->addFunction('url_user', function (string $username): string {
|
||||
return UrlBuilder::user($username);
|
||||
});
|
||||
$latte->addFunction('url_video_internal', function (string $username, string $id): string {
|
||||
return UrlBuilder::video_internal($username, $id);
|
||||
});
|
||||
$latte->addFunction('url_video_external', function (string $username, string $id): string {
|
||||
return UrlBuilder::video_external($username, $id);
|
||||
});
|
||||
$latte->addFunction('url_download', function (string $url, string $username, bool $watermark): string {
|
||||
return UrlBuilder::download($url, $username, $watermark);
|
||||
});
|
||||
// https://stackoverflow.com/a/36365553
|
||||
$latte->addFunction('number', function (float $x) {
|
||||
if($x > 1000) {
|
||||
@@ -60,7 +69,28 @@ class Wrappers {
|
||||
}
|
||||
return $x;
|
||||
});
|
||||
return $latte;
|
||||
|
||||
// UrlBuilder
|
||||
$latte->addFunction('url_stream', function (string $url): string {
|
||||
return UrlBuilder::stream($url);
|
||||
});
|
||||
$latte->addFunction('url_user', function (string $username): string {
|
||||
return UrlBuilder::user($username);
|
||||
});
|
||||
$latte->addFunction('url_tag', function (string $tag): string {
|
||||
return UrlBuilder::tag($tag);
|
||||
});
|
||||
$latte->addFunction('url_video_internal', function (string $username, string $id): string {
|
||||
return UrlBuilder::video_internal($username, $id);
|
||||
});
|
||||
$latte->addFunction('url_video_external', function (string $username, string $id): string {
|
||||
return UrlBuilder::video_external($username, $id);
|
||||
});
|
||||
$latte->addFunction('url_download', function (string $url, string $username, string $id, bool $watermark): string {
|
||||
return UrlBuilder::download($url, $username, $id, $watermark);
|
||||
});
|
||||
|
||||
$latte->render(Misc::getView($template), $base);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,6 +139,9 @@ class Wrappers {
|
||||
case CacheMethods::JSON:
|
||||
$cacheEngine = new JSONCache();
|
||||
break;
|
||||
case CacheMethods::APCU:
|
||||
$cacheEngine = new ApcuCache();
|
||||
break;
|
||||
case CacheMethods::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!');
|
||||
|
||||
@@ -6,7 +6,6 @@ namespace App\Models;
|
||||
*/
|
||||
class BaseTemplate {
|
||||
public string $title;
|
||||
public string $version;
|
||||
|
||||
function __construct(string $title) {
|
||||
$this->title = $title;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
namespace App\Models;
|
||||
|
||||
use TikScraper\Models\Discover;
|
||||
|
||||
class DiscoverTemplate extends BaseTemplate {
|
||||
public Discover $data;
|
||||
|
||||
function __construct(Discover $data) {
|
||||
parent::__construct("Discover");
|
||||
$this->data = $data;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
<?php
|
||||
namespace App\Models;
|
||||
|
||||
use TikScraper\Models\Feed;
|
||||
|
||||
/**
|
||||
* Base for templates with a feed
|
||||
*/
|
||||
class FeedTemplate extends BaseTemplate {
|
||||
public object $data;
|
||||
public Feed $feed;
|
||||
|
||||
function __construct(string $title, object $feed) {
|
||||
function __construct(string $title, Feed $feed) {
|
||||
parent::__construct($title);
|
||||
$this->data = (object) [
|
||||
'feed' => $feed
|
||||
];
|
||||
$this->feed = $feed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
<?php
|
||||
namespace App\Models;
|
||||
|
||||
use TikScraper\Models\Full;
|
||||
use TikScraper\Models\Feed;
|
||||
use TikScraper\Models\Info;
|
||||
|
||||
/**
|
||||
* Base for templates with both info and feed
|
||||
*/
|
||||
class FullTemplate extends BaseTemplate {
|
||||
public Full $data;
|
||||
public Info $info;
|
||||
public Feed $feed;
|
||||
|
||||
function __construct(string $title, Full $data) {
|
||||
function __construct(string $title, Info $info, Feed $feed) {
|
||||
parent::__construct($title);
|
||||
$this->data = $data;
|
||||
$this->info = $info;
|
||||
$this->feed = $feed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
<?php
|
||||
namespace App\Models;
|
||||
|
||||
/**
|
||||
* Base for templates with a feed
|
||||
*/
|
||||
class RSSTemplate {
|
||||
public string $title;
|
||||
class RSSTemplate extends BaseTemplate {
|
||||
public string $desc;
|
||||
public string $link;
|
||||
public array $items;
|
||||
|
||||
function __construct(string $title, string $desc, string $link, array $items) {
|
||||
$this->title = $title;
|
||||
parent::__construct($title);
|
||||
$this->desc = $desc;
|
||||
$this->link = $link;
|
||||
$this->items = $items;
|
||||
|
||||
@@ -6,14 +6,15 @@ use App\Helpers\Cookies;
|
||||
use TikScraper\Constants\DownloadMethods;
|
||||
|
||||
/**
|
||||
* Base for templates with a feed
|
||||
*/
|
||||
* Settings model with all possible config items
|
||||
*/
|
||||
class SettingsTemplate extends BaseTemplate {
|
||||
public array $downloaders = [];
|
||||
public array $themes = [];
|
||||
public bool $isTestEndpoints = false;
|
||||
public string $currentDownloader;
|
||||
public string $currentTheme;
|
||||
public bool $isServiceWorker = false;
|
||||
|
||||
function __construct() {
|
||||
parent::__construct("Settings");
|
||||
@@ -27,5 +28,6 @@ class SettingsTemplate extends BaseTemplate {
|
||||
$this->isTestEndpoints = Cookies::check('api-test_endpoints', 'yes');
|
||||
$this->currentDownloader = Cookies::downloader();
|
||||
$this->currentTheme = Cookies::theme();
|
||||
$this->isServiceWorker = Cookies::check('misc-sw', 'yes');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
<?php
|
||||
namespace App\Models;
|
||||
|
||||
use TikScraper\Models\Info;
|
||||
|
||||
/**
|
||||
* Base for templates with a feed
|
||||
*/
|
||||
class VideoTemplate extends BaseTemplate {
|
||||
public object $item;
|
||||
public object $detail;
|
||||
public Info $info;
|
||||
public string $layout = 'hero';
|
||||
|
||||
function __construct(object $item, object $detail, bool $isEmbed = false) {
|
||||
function __construct(object $item, Info $info, bool $isEmbed = false) {
|
||||
parent::__construct('Video');
|
||||
$this->item = $item;
|
||||
$this->detail = $detail;
|
||||
$this->info = $info;
|
||||
if ($isEmbed) {
|
||||
$this->layout = 'embed';
|
||||
} else {
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="{path('/apple-touch-icon.png')}">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="{path('/favicon-32x32.png')}">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="{path('/favicon-16x16.png')}">
|
||||
<link rel="manifest" href="{path('/site.webmanifest')}">
|
||||
<meta property="og:title" content="ProxiTok" />
|
||||
<meta property="og:description" content="Alternative frontend for TikTok" />
|
||||
<meta property="og:type" content="website" />
|
||||
{if isset($has_rss)}
|
||||
<link rel="alternate" type="application/rss+xml" title="{$title}" href="{$_SERVER['REQUEST_URI'] . '/rss'}" />
|
||||
{/if}
|
||||
<link rel="stylesheet" href="{path('/styles/vendor/cssgg.min.css')}">
|
||||
<link rel="stylesheet" href="{path('/styles/vendor/bulma.min.css')}">
|
||||
<title>{$title} - ProxiTok</title>
|
||||
</head>
|
||||
@@ -1,13 +0,0 @@
|
||||
<div class="dropdown is-hoverable">
|
||||
<div class="dropdown-trigger">
|
||||
<button class="button" aria-haspopup="true" aria-controls="dropdown-menu">
|
||||
{include '../../icon.latte', icon: 'software-download', text: 'Download'}
|
||||
</button>
|
||||
</div>
|
||||
<div class="dropdown-menu" role="menu">
|
||||
<div class="dropdown-content">
|
||||
<a target="_blank" href="{url_download($playAddr, $uniqueId, true)}" class="dropdown-item">Watermark</a>
|
||||
<a target="_blank" href="{url_download(url_video_external($uniqueId, $id), $uniqueId, false)}" class="dropdown-item">No watermark</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,5 +0,0 @@
|
||||
{do $endpoint = '/@' . $uniqueId . '/video/' . $id}
|
||||
<div class="buttons is-centered">
|
||||
<a class="button is-success is-small" href="{url_video_internal($uniqueId, $id)}">Instance Link</a>
|
||||
<a class="button is-danger is-small" href="{url_video_external($uniqueId, $id)}">Original Link</a>
|
||||
</div>
|
||||
@@ -1,5 +0,0 @@
|
||||
<div class="tags">
|
||||
{foreach $challenges as $challenge}
|
||||
<a class="tag is-rounded is-info" href="{path('/tag/' . $challenge->title)}">{$challenge->title}</a>
|
||||
{/foreach}
|
||||
</div>
|
||||
@@ -1,40 +0,0 @@
|
||||
<div class="container">
|
||||
{foreach $data->feed->items as $item}
|
||||
<article class="media">
|
||||
<figure class="media-left">
|
||||
<p class="image is-64x64">
|
||||
<img src="{url_stream($item->author->avatarThumb)}" />
|
||||
</p>
|
||||
</figure>
|
||||
<div class="media-content">
|
||||
<div class="content">
|
||||
<p>
|
||||
<strong>{$item->author->nickname}</strong>
|
||||
<small>
|
||||
<a href="{url_user($item->author->uniqueId)}">@{$item->author->uniqueId}</a>
|
||||
</small>
|
||||
<small title="{date('M d, Y H:i:s e', $item->createTime)}">{date('M d, Y', $item->createTime)}</small>
|
||||
</p>
|
||||
{if !empty($item->challenges)}
|
||||
<p>{include './common/tags.latte', challenges: $item->challenges}</p>
|
||||
{/if}
|
||||
<p n:ifcontent>{$item->desc}</p>
|
||||
{include './common/stats.latte', playCount: $item->stats->playCount, diggCount: $item->stats->diggCount, commentCount: $item->stats->commentCount, shareCount: $item->stats->shareCount}
|
||||
</div>
|
||||
<div class="has-text-centered">
|
||||
<video width="{$item->video->width}" height="{$item->video->height}" controls preload="none" poster="{url_stream($item->video->originCover)}">
|
||||
<source src="{url_stream($item->video->playAddr)}" type="video/mp4" />
|
||||
</video>
|
||||
</div>
|
||||
<div class="has-text-centered">
|
||||
{include './common/share.latte', uniqueId: $item->author->uniqueId, id: $item->id}
|
||||
{include './common/download.latte', playAddr: $item->video->playAddr, id: $item->id, uniqueId: $item->author->uniqueId}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{/foreach}
|
||||
{if empty($data->feed->items)}
|
||||
<p class="title">No items sent by TikTok!</p>
|
||||
{/if}
|
||||
</div>
|
||||
{include './common/controls.latte'}
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "pablouser1/proxitok",
|
||||
"description": "An alternative frontend for TikTok",
|
||||
"version": "2.4.2.2",
|
||||
"version": "2.4.5.0",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"type": "project",
|
||||
"authors": [
|
||||
|
||||
Generated
+34
-34
@@ -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": "cba94cb83e29611d014cde3b5d1e1e67",
|
||||
"content-hash": "818a3e623705c076822f3d895a0d99ca",
|
||||
"packages": [
|
||||
{
|
||||
"name": "bramus/router",
|
||||
@@ -117,22 +117,22 @@
|
||||
},
|
||||
{
|
||||
"name": "latte/latte",
|
||||
"version": "v2.11.5",
|
||||
"version": "v2.11.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/latte.git",
|
||||
"reference": "89e647e51213af8a270fe9903b8735a2f6c83ad1"
|
||||
"reference": "af4dbb23a6044b1cf4904830a9b00246318c93d4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/latte/zipball/89e647e51213af8a270fe9903b8735a2f6c83ad1",
|
||||
"reference": "89e647e51213af8a270fe9903b8735a2f6c83ad1",
|
||||
"url": "https://api.github.com/repos/nette/latte/zipball/af4dbb23a6044b1cf4904830a9b00246318c93d4",
|
||||
"reference": "af4dbb23a6044b1cf4904830a9b00246318c93d4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"ext-tokenizer": "*",
|
||||
"php": ">=7.1 <8.2"
|
||||
"php": ">=7.1 <8.3"
|
||||
},
|
||||
"conflict": {
|
||||
"nette/application": "<2.4.1"
|
||||
@@ -195,9 +195,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nette/latte/issues",
|
||||
"source": "https://github.com/nette/latte/tree/v2.11.5"
|
||||
"source": "https://github.com/nette/latte/tree/v2.11.6"
|
||||
},
|
||||
"time": "2022-06-26T10:12:18+00:00"
|
||||
"time": "2022-11-04T14:53:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "m1/env",
|
||||
@@ -263,16 +263,16 @@
|
||||
},
|
||||
{
|
||||
"name": "pablouser1/tikscraper",
|
||||
"version": "v2.3.1.1",
|
||||
"version": "v2.3.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pablouser1/TikScraperPHP.git",
|
||||
"reference": "5baf0106bd4b86e92f092f7d17e6fc2d24aabf8a"
|
||||
"reference": "8ee7efd58892d0a6e536b7cc29de200202916394"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pablouser1/TikScraperPHP/zipball/5baf0106bd4b86e92f092f7d17e6fc2d24aabf8a",
|
||||
"reference": "5baf0106bd4b86e92f092f7d17e6fc2d24aabf8a",
|
||||
"url": "https://api.github.com/repos/pablouser1/TikScraperPHP/zipball/8ee7efd58892d0a6e536b7cc29de200202916394",
|
||||
"reference": "8ee7efd58892d0a6e536b7cc29de200202916394",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -305,9 +305,9 @@
|
||||
"description": "Get data from TikTok API",
|
||||
"support": {
|
||||
"issues": "https://github.com/pablouser1/TikScraperPHP/issues",
|
||||
"source": "https://github.com/pablouser1/TikScraperPHP/tree/v2.3.1.1"
|
||||
"source": "https://github.com/pablouser1/TikScraperPHP/tree/v2.3.4.0"
|
||||
},
|
||||
"time": "2022-10-23T19:33:37+00:00"
|
||||
"time": "2023-01-26T18:18:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-webdriver/webdriver",
|
||||
@@ -406,16 +406,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.26.0",
|
||||
"version": "v1.27.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e"
|
||||
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
|
||||
"reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
|
||||
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -430,7 +430,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.26-dev"
|
||||
"dev-main": "1.27-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@@ -469,7 +469,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0"
|
||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -485,20 +485,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-05-24T11:49:31+00:00"
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php80",
|
||||
"version": "v1.26.0",
|
||||
"version": "v1.27.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace"
|
||||
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace",
|
||||
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
|
||||
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -507,7 +507,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.26-dev"
|
||||
"dev-main": "1.27-dev"
|
||||
},
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
@@ -552,7 +552,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0"
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -568,20 +568,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-05-10T07:21:04+00:00"
|
||||
"time": "2022-11-03T14:55:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v5.4.11",
|
||||
"version": "v5.4.19",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "6e75fe6874cbc7e4773d049616ab450eff537bf1"
|
||||
"reference": "c5ba874c9b636dbccf761e22ce750e88ec3f55e1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/6e75fe6874cbc7e4773d049616ab450eff537bf1",
|
||||
"reference": "6e75fe6874cbc7e4773d049616ab450eff537bf1",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/c5ba874c9b636dbccf761e22ce750e88ec3f55e1",
|
||||
"reference": "c5ba874c9b636dbccf761e22ce750e88ec3f55e1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -614,7 +614,7 @@
|
||||
"description": "Executes commands in sub-processes",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/process/tree/v5.4.11"
|
||||
"source": "https://github.com/symfony/process/tree/v5.4.19"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -630,7 +630,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2022-06-27T16:58:25+00:00"
|
||||
"time": "2023-01-01T08:32:19+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
|
||||
+2
@@ -13,6 +13,7 @@ $bulmaswatch-import-font: false;
|
||||
@import "./node_modules/bulma/sass/elements/box.sass";
|
||||
@import "./node_modules/bulma/sass/elements/button.sass";
|
||||
@import "./node_modules/bulma/sass/elements/container.sass";
|
||||
@import "./node_modules/bulma/sass/elements/content.sass";
|
||||
@import "./node_modules/bulma/sass/elements/icon.sass";
|
||||
@import "./node_modules/bulma/sass/elements/image.sass";
|
||||
@import "./node_modules/bulma/sass/elements/other.sass";
|
||||
@@ -27,6 +28,7 @@ $bulmaswatch-import-font: false;
|
||||
@import "./node_modules/bulma/sass/form/tools.sass";
|
||||
|
||||
// Components
|
||||
@import "./node_modules/bulma/sass/components/breadcrumb.sass";
|
||||
@import "./node_modules/bulma/sass/components/card.sass";
|
||||
@import "./node_modules/bulma/sass/components/dropdown.sass";
|
||||
@import "./node_modules/bulma/sass/components/media.sass";
|
||||
@@ -3,6 +3,7 @@
|
||||
@import "./node_modules/css.gg/icons/scss/home.scss";
|
||||
@import "./node_modules/css.gg/icons/scss/options.scss";
|
||||
@import "./node_modules/css.gg/icons/scss/info.scss";
|
||||
@import "./node_modules/css.gg/icons/scss/code-slash.scss";
|
||||
|
||||
// Home
|
||||
@import "./node_modules/css.gg/icons/scss/search.scss";
|
||||
@@ -15,5 +16,8 @@
|
||||
@import "./node_modules/css.gg/icons/scss/share.scss";
|
||||
@import "./node_modules/css.gg/icons/scss/software-download.scss";
|
||||
|
||||
@import "./node_modules/css.gg/icons/scss/lock.scss";
|
||||
@import "./node_modules/css.gg/icons/scss/lock-unlock.scss";
|
||||
|
||||
// Video
|
||||
@import "./node_modules/css.gg/icons/scss/music.scss";
|
||||
@@ -2,8 +2,8 @@
|
||||
"name": "proxitok-scss",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"bulma": "sass --style=compressed bulma.scss ../styles/vendor/bulma.min.css",
|
||||
"cssgg": "sass --style=compressed cssgg.scss ../styles/vendor/cssgg.min.css"
|
||||
"bulma": "sass --style=compressed bulma.scss ../../styles/vendor/bulma.min.css",
|
||||
"cssgg": "sass --style=compressed cssgg.scss ../../styles/vendor/cssgg.min.css"
|
||||
},
|
||||
"dependencies": {
|
||||
"bulma": "^0.9.3",
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
|
||||
anymatch@~3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
|
||||
integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
|
||||
integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
|
||||
dependencies:
|
||||
normalize-path "^3.0.0"
|
||||
picomatch "^2.0.4"
|
||||
@@ -118,9 +118,9 @@ readdirp@~3.6.0:
|
||||
picomatch "^2.2.1"
|
||||
|
||||
sass@^1.46.0:
|
||||
version "1.53.0"
|
||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.53.0.tgz#eab73a7baac045cc57ddc1d1ff501ad2659952eb"
|
||||
integrity sha512-zb/oMirbKhUgRQ0/GFz8TSAwRq2IlR29vOUJZOx0l8sV+CkHUfHa4u5nqrG+1VceZp7Jfj59SVW9ogdhTvJDcQ==
|
||||
version "1.56.1"
|
||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.56.1.tgz#94d3910cd468fd075fa87f5bb17437a0b617d8a7"
|
||||
integrity sha512-VpEyKpyBPCxE7qGDtOcdJ6fFbcpOM+Emu7uZLxVrkX8KVU/Dp5UF7WLvzqRuUhB6mqqQt1xffLoG+AndxTZrCQ==
|
||||
dependencies:
|
||||
chokidar ">=3.0.0 <4.0.0"
|
||||
immutable "^4.0.0"
|
||||
+35
-7
@@ -11,23 +11,50 @@ $router->set404(function () {
|
||||
});
|
||||
|
||||
$router->get('/', function () {
|
||||
$latte = Wrappers::latte();
|
||||
$latte->render(Misc::getView('home'), new BaseTemplate('Home'));
|
||||
Wrappers::latte('home', new BaseTemplate('Home'));
|
||||
});
|
||||
|
||||
$router->get('/about', function () {
|
||||
$latte = Wrappers::latte();
|
||||
$latte->render(Misc::getView('about'), new BaseTemplate('About'));
|
||||
Wrappers::latte('about', new BaseTemplate('About'));
|
||||
});
|
||||
|
||||
$router->get('/verify', function () {
|
||||
$latte = Wrappers::latte();
|
||||
$latte->render(Misc::getView('verify'), new BaseTemplate('Verify'));
|
||||
Wrappers::latte('verify', new BaseTemplate('verify'));
|
||||
});
|
||||
|
||||
$router->get('/manifest', function () {
|
||||
header('Content-Type: application/json');
|
||||
$data = [
|
||||
"name" => "ProxiTok",
|
||||
"short_name" => "ProxiTok",
|
||||
"description" => "Use TikTok with a privacy-friendly alternative frontend",
|
||||
"lang" => "en-US",
|
||||
"theme_color" => "#4040ff",
|
||||
"background_color" => "#ffffff",
|
||||
"display" => "standalone",
|
||||
"orientation" => "portrait-primary",
|
||||
"icons" => [
|
||||
[
|
||||
"src" => Misc::url('/android-chrome-192x192.png'),
|
||||
"sizes" => "192x192",
|
||||
"type" => "image/png"
|
||||
],
|
||||
[
|
||||
"src" => Misc::url('/android-chrome-512x512.png'),
|
||||
"sizes" => "512x512",
|
||||
"type" => "image/png"
|
||||
]
|
||||
],
|
||||
"start_url" => Misc::url('/'),
|
||||
"scope" => Misc::url('/')
|
||||
];
|
||||
echo json_encode($data, JSON_PRETTY_PRINT);
|
||||
});
|
||||
|
||||
$router->get('/stream', 'ProxyController@stream');
|
||||
$router->get('/download', 'ProxyController@download');
|
||||
$router->get('/redirect', 'RedirectController@redirect');
|
||||
$router->get('/redirect/search', 'RedirectController@search');
|
||||
$router->get('/redirect/download', 'RedirectController@download');
|
||||
|
||||
$router->mount('/trending', function () use ($router) {
|
||||
$router->get('/', 'TrendingController@get');
|
||||
@@ -57,6 +84,7 @@ $router->mount('/settings', function () use ($router) {
|
||||
$router->get('/', 'SettingsController@index');
|
||||
$router->post('/general', 'SettingsController@general');
|
||||
$router->post('/api', 'SettingsController@api');
|
||||
$router->post('/misc', 'SettingsController@misc');
|
||||
});
|
||||
|
||||
$router->get('/discover', 'DiscoverController@get');
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"name": "ProxiTok",
|
||||
"short_name": "ProxiTok",
|
||||
"description": "Use TikTok with a privacy-friendly alternative frontend",
|
||||
"orientation": "portrait-primary",
|
||||
"icons": [
|
||||
{
|
||||
"src": "./android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"id": "./",
|
||||
"start_url": "./",
|
||||
"theme_color": "#4040ff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -1 +1 @@
|
||||
{"version":3,"sourceRoot":"","sources":["../../scss/node_modules/css.gg/icons/scss/home.scss","../../scss/node_modules/css.gg/icons/scss/options.scss","../../scss/node_modules/css.gg/icons/scss/info.scss","../../scss/node_modules/css.gg/icons/scss/search.scss","../../scss/node_modules/css.gg/icons/scss/feed.scss","../../scss/node_modules/css.gg/icons/scss/eye.scss","../../scss/node_modules/css.gg/icons/scss/heart.scss","../../scss/node_modules/css.gg/icons/scss/comment.scss","../../scss/node_modules/css.gg/icons/scss/share.scss","../../scss/node_modules/css.gg/icons/scss/software-download.scss","../../scss/node_modules/css.gg/icons/scss/music.scss"],"names":[],"mappings":"AAAA,SACE,yLACA,sBACA,kBACA,cACA,+BACA,WACA,YACA,iBACA,aACA,gBACA,4BACA,2BACA,6BACA,4BACA,mBAEA,gBACE,WACA,cACA,sBACA,kBAGF,iBACE,WACA,cACA,sBACA,kBACA,qBACA,sBACA,2BACA,wBACA,SACA,kBACA,WACA,YACA,OAGF,gBACE,UACA,YACA,iBACA,oBACA,4BACA,6BACA,gBACA,SACA,SCjDJ,YACI,sBACA,kBACA,cACA,+BACA,WACA,WACA,qCAEA,mBACE,WACA,cACA,sBACA,kBACA,UACA,WACA,iBACA,mBAGF,oBACE,WACA,cACA,sBACA,kBACA,UACA,WACA,iBACA,mBACA,SACA,UAGF,mBACE,YACA,WCnCN,SACI,sBACA,kBACA,cACA,+BACA,WACA,YACA,iBACA,mBAEA,iCACE,WACA,cACA,sBACA,kBACA,kBACA,UACA,wBACA,SAGF,gBACE,WACA,WAGF,iBACE,WACA,QC5BN,WACI,sBACA,kBACA,cACA,+BACA,WACA,YACA,iBACA,mBACA,iBACA,gBAEA,kBACE,WACA,cACA,sBACA,kBACA,kBACA,UACA,WACA,wBACA,yBACA,SACA,UCvBN,SACI,cACA,sBACA,wBACA,sBASA,iBACA,gBACA,kBACA,+BACA,UACA,WACA,kBAbA,iCACE,cACA,sBACA,wBACA,sBAWF,iCACE,WACA,kBACA,kBACA,WACA,WACA,QACA,SACA,WAGF,gBACE,UACA,QACA,WCnCN,QACI,kBACA,cACA,+BACA,WACA,YACA,iCACA,gCACA,gBACA,sBAEA,+BACE,WACA,cACA,oBACA,kBACA,sBAGF,eACE,QACA,8CACA,WACA,YAGF,gBACE,UACA,WACA,iBACA,WACA,SC/BN,UACI,iBACA,6BACA,8BACA,WACA,WACA,gBAeA,sBACA,kBACA,gHACA,cAhBA,iBACE,iBACA,6BACA,8BACA,WACA,WACA,gBACA,WACA,cACA,sBACA,kBAQF,kBACE,WACA,cACA,sBACA,kBAGF,iBACE,WACA,wBACA,QAGF,kBACE,WACA,YACA,sBACA,wBACA,UACA,QC7CN,YACI,sBACA,kBACA,cACA,+BACA,WACA,YACA,iBACA,gBACA,0CAEA,mBACE,WACA,cACA,sBACA,kBACA,UAGF,oBACE,WACA,cACA,sBACA,kBACA,UACA,iBACA,+BACA,+BACA,UACA,YACA,WAGF,mBACE,WACA,wBACA,qBACA,SACA,QCtCN,UACI,sBACA,kBACA,cACA,+BACA,UACA,WACA,wBACA,oBACA,kCAEA,iBACE,WACA,cACA,sBACA,kBACA,kBACA,WACA,WACA,wBACA,SAGF,kBACE,WACA,cACA,sBACA,kBACA,kBACA,WACA,WACA,wBACA,SACA,MACA,yBAGF,iBACE,SACA,wBCvCN,sBACI,sBACA,kBACA,cACA,+BACA,WACA,WACA,iBACA,aACA,8BACA,+BACA,eAEA,6BACE,WACA,cACA,sBACA,kBACA,UACA,WACA,sBACA,wBACA,yBACA,SACA,WAGF,8BACE,WACA,cACA,sBACA,kBACA,kBACA,UACA,YACA,wBACA,SACA,WCrCN,UACI,cACA,sBACA,iBAQA,2BACA,4BACA,gBACA,gBACA,kBACA,6CACA,WACA,YAbA,mCACE,cACA,sBACA,iBAYF,mCACE,WACA,kBACA,UACA,WACA,QACA,UACA,uBACA,mBAGF,iBACE","file":"cssgg.min.css"}
|
||||
{"version":3,"sourceRoot":"","sources":["../../misc/scss/node_modules/css.gg/icons/scss/home.scss","../../misc/scss/node_modules/css.gg/icons/scss/options.scss","../../misc/scss/node_modules/css.gg/icons/scss/info.scss","../../misc/scss/node_modules/css.gg/icons/scss/code-slash.scss","../../misc/scss/node_modules/css.gg/icons/scss/search.scss","../../misc/scss/node_modules/css.gg/icons/scss/feed.scss","../../misc/scss/node_modules/css.gg/icons/scss/eye.scss","../../misc/scss/node_modules/css.gg/icons/scss/heart.scss","../../misc/scss/node_modules/css.gg/icons/scss/comment.scss","../../misc/scss/node_modules/css.gg/icons/scss/share.scss","../../misc/scss/node_modules/css.gg/icons/scss/software-download.scss","../../misc/scss/node_modules/css.gg/icons/scss/lock.scss","../../misc/scss/node_modules/css.gg/icons/scss/lock-unlock.scss","../../misc/scss/node_modules/css.gg/icons/scss/music.scss"],"names":[],"mappings":"AAAA,SACE,yLACA,sBACA,kBACA,cACA,+BACA,WACA,YACA,iBACA,aACA,gBACA,4BACA,2BACA,6BACA,4BACA,mBAEA,gBACE,WACA,cACA,sBACA,kBAGF,iBACE,WACA,cACA,sBACA,kBACA,qBACA,sBACA,2BACA,wBACA,SACA,kBACA,WACA,YACA,OAGF,gBACE,UACA,YACA,iBACA,oBACA,4BACA,6BACA,gBACA,SACA,SCjDJ,YACI,sBACA,kBACA,cACA,+BACA,WACA,WACA,qCAEA,mBACE,WACA,cACA,sBACA,kBACA,UACA,WACA,iBACA,mBAGF,oBACE,WACA,cACA,sBACA,kBACA,UACA,WACA,iBACA,mBACA,SACA,UAGF,mBACE,YACA,WCnCN,SACI,sBACA,kBACA,cACA,+BACA,WACA,YACA,iBACA,mBAEA,iCACE,WACA,cACA,sBACA,kBACA,kBACA,UACA,wBACA,SAGF,gBACE,WACA,WAGF,iBACE,WACA,QC5BN,eACI,cACA,kBACA,sBACA,6CACA,UACA,YACA,wBAEA,sBACE,WACA,cACA,sBACA,kBACA,UACA,WACA,yBAGF,uBACE,WACA,cACA,sBACA,kBACA,UACA,WACA,yBACA,sBACA,qBACA,UACA,QAGF,sBACE,uBACA,wBACA,WACA,QCrCN,WACI,sBACA,kBACA,cACA,+BACA,WACA,YACA,iBACA,mBACA,iBACA,gBAEA,kBACE,WACA,cACA,sBACA,kBACA,kBACA,UACA,WACA,wBACA,yBACA,SACA,UCvBN,SACI,cACA,sBACA,wBACA,sBASA,iBACA,gBACA,kBACA,+BACA,UACA,WACA,kBAbA,iCACE,cACA,sBACA,wBACA,sBAWF,iCACE,WACA,kBACA,kBACA,WACA,WACA,QACA,SACA,WAGF,gBACE,UACA,QACA,WCnCN,QACI,kBACA,cACA,+BACA,WACA,YACA,iCACA,gCACA,gBACA,sBAEA,+BACE,WACA,cACA,oBACA,kBACA,sBAGF,eACE,QACA,8CACA,WACA,YAGF,gBACE,UACA,WACA,iBACA,WACA,SC/BN,UACI,iBACA,6BACA,8BACA,WACA,WACA,gBAeA,sBACA,kBACA,gHACA,cAhBA,iBACE,iBACA,6BACA,8BACA,WACA,WACA,gBACA,WACA,cACA,sBACA,kBAQF,kBACE,WACA,cACA,sBACA,kBAGF,iBACE,WACA,wBACA,QAGF,kBACE,WACA,YACA,sBACA,wBACA,UACA,QC7CN,YACI,sBACA,kBACA,cACA,+BACA,WACA,YACA,iBACA,gBACA,0CAEA,mBACE,WACA,cACA,sBACA,kBACA,UAGF,oBACE,WACA,cACA,sBACA,kBACA,UACA,iBACA,+BACA,+BACA,UACA,YACA,WAGF,mBACE,WACA,wBACA,qBACA,SACA,QCtCN,UACI,sBACA,kBACA,cACA,+BACA,UACA,WACA,wBACA,oBACA,kCAEA,iBACE,WACA,cACA,sBACA,kBACA,kBACA,WACA,WACA,wBACA,SAGF,kBACE,WACA,cACA,sBACA,kBACA,kBACA,WACA,WACA,wBACA,SACA,MACA,yBAGF,iBACE,SACA,wBCvCN,sBACI,sBACA,kBACA,cACA,+BACA,WACA,WACA,iBACA,aACA,8BACA,+BACA,eAEA,6BACE,WACA,cACA,sBACA,kBACA,UACA,WACA,sBACA,wBACA,yBACA,SACA,WAGF,8BACE,WACA,cACA,sBACA,kBACA,kBACA,UACA,YACA,wBACA,SACA,WCrCN,SACI,sBACA,kBACA,cACA,+BACA,WACA,YACA,iBACA,4BACA,2BACA,4BACA,iBAEA,gBACE,WACA,cACA,sBACA,kBACA,WACA,YACA,kBACA,+BACA,qBACA,UACA,QCxBN,gBACI,sBACA,kBACA,cACA,+BACA,WACA,WACA,iBACA,8BACA,6BACA,4BACA,iBACA,iBAEA,+CACE,WACA,cACA,sBACA,kBAGF,uBACE,+BACA,qBACA,WACA,YACA,kBACA,UACA,SAGF,wBACE,UACA,WACA,wBACA,UACA,QCpCN,UACI,cACA,sBACA,iBAQA,2BACA,4BACA,gBACA,gBACA,kBACA,6CACA,WACA,YAbA,mCACE,cACA,sBACA,iBAYF,mCACE,WACA,kBACA,UACA,WACA,QACA,UACA,uBACA,mBAGF,iBACE","file":"cssgg.min.css"}
|
||||
@@ -0,0 +1,35 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="{path('/apple-touch-icon.png')}">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="{path('/favicon-32x32.png')}">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="{path('/favicon-16x16.png')}">
|
||||
<link rel="manifest" href="{path('/manifest')}">
|
||||
{if isset($og, $og_content, $og_url)}
|
||||
<!-- Using TikTok's meta config -->
|
||||
<meta property="og:title" content="{$og->title}" />
|
||||
<meta property="og:description" content="{$og->description}" />
|
||||
<meta property="og:url" content="{$og_url}" />
|
||||
<meta property="og:image" content="{url_stream($og_content)}" />
|
||||
<meta property="twitter:title" content="{$og->title}" />
|
||||
<meta property="twitter:description" content="{$og->description}" />
|
||||
<meta property="twitter:image" content="{url_stream($og_content)}" />
|
||||
{else}
|
||||
<!-- Using predifined ProxiTok config -->
|
||||
<meta property="og:title" content="{$title}" />
|
||||
<meta property="og:description" content="Alternative frontend for TikTok" />
|
||||
<meta property="twitter:title" content="{$title}" />
|
||||
<meta property="twitter:description" content="Alternative frontend for TikTok" />
|
||||
{/if}
|
||||
<meta property="og:site_name" content="ProxiTok" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="twitter:card" content="summary" />
|
||||
<meta property="twitter:site" content="ProxiTok" />
|
||||
{if isset($has_rss)}
|
||||
<link rel="alternate" type="application/rss+xml" title="{$title}" href="{$_SERVER['REQUEST_URI'] . '/rss'}" />
|
||||
{/if}
|
||||
<link rel="stylesheet" href="{static('css', 'cssgg.min.css', true)}">
|
||||
<link rel="stylesheet" href="{static('css', 'bulma.min.css', true)}">
|
||||
<title>{$title} - ProxiTok</title>
|
||||
</head>
|
||||
@@ -1,6 +1,8 @@
|
||||
<nav class="navbar" role="navigation" aria-label="main navigation">
|
||||
<div class="navbar-brand">
|
||||
<a href="{path('/')}" class="navbar-item">ProxiTok</a>
|
||||
<a href="{path('/')}" class="navbar-item">
|
||||
{include './icon.latte', icon: 'home', text: 'ProxiTok'}
|
||||
</a>
|
||||
<a role="button" id="navbar-burger" class="navbar-burger" aria-label="menu" aria-expanded="false">
|
||||
<span aria-hidden="true"></span>
|
||||
<span aria-hidden="true"></span>
|
||||
@@ -18,8 +20,10 @@
|
||||
</a>
|
||||
</div>
|
||||
<div class="navbar-end">
|
||||
<a href="https://github.com/pablouser1/ProxiTok" class="navbar-item" target="_blank">Source</a>
|
||||
<a href="https://github.com/pablouser1/ProxiTok" class="navbar-item" target="_blank">
|
||||
{include './icon.latte', icon: 'code-slash', text: 'Source'}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<script src="{path('/scripts/navbar.js')}"></script>
|
||||
<script src="{static('js', 'navbar.js')}"></script>
|
||||
@@ -1,13 +1,13 @@
|
||||
<link rel="stylesheet" href="{path('/styles/themes/card.css')}">
|
||||
<noscript>JavaScript is required for this section to work!</noscript>
|
||||
<link rel="stylesheet" href="{static('css', 'themes/card.css')}">
|
||||
<section class="section">
|
||||
<noscript>JavaScript is required for this section to work!</noscript>
|
||||
<div class="columns is-multiline is-vcentered">
|
||||
{foreach $data->feed->items as $item}
|
||||
{foreach $feed->items as $item}
|
||||
{do $share_url = url_video_external($item->author->uniqueId, $item->id)}
|
||||
<div class="column is-one-quarter clickable-img" id="{$item->id}" onclick="openVideo(this.id)"
|
||||
data-video_url="{url_stream($item->video->playAddr)}"
|
||||
data-video_download_watermark="{url_download($item->video->playAddr, $item->author->uniqueId, true)}"
|
||||
data-video_download_nowatermark="{url_download($item->video->playAddr, $item->author->uniqueId, false)}"
|
||||
data-video_download_watermark="{url_download($item->video->playAddr, $item->author->uniqueId, $item->id, true)}"
|
||||
data-video_download_nowatermark="{url_download(url_video_external($item->author->uniqueId, $item->id), $item->author->uniqueId, $item->id, false)}"
|
||||
data-video_share_url="{$share_url}"
|
||||
data-desc="{$item->desc}"
|
||||
data-createtime="{$item->createTime}"
|
||||
@@ -17,7 +17,7 @@
|
||||
<img class="hidden" loading="lazy" data-src="{url_stream($item->video->dynamicCover)}" />
|
||||
</div>
|
||||
{/foreach}
|
||||
{if empty($data->feed->items)}
|
||||
{if empty($feed->items)}
|
||||
<p class="title">No items sent by TikTok!</p>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -67,4 +67,4 @@
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<script src="{path('/scripts/themes/card.js')}"></script>
|
||||
<script src="{static('js', 'themes/card.js')}"></script>
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
<div n:ifset="$data->info" class="buttons">
|
||||
<div class="buttons">
|
||||
{* is_numeric is used to avoid having a back button with ttwid cursors *}
|
||||
{if isset($_GET['cursor']) && is_numeric($_GET['cursor']) && $_GET['cursor'] != 0}
|
||||
<a class="button is-danger" href="?cursor=0">First</a>
|
||||
{/if}
|
||||
<a n:attr="disabled => !$data->feed->hasMore" class="button is-success" href="?cursor={$data->feed->maxCursor}">Next</a>
|
||||
<a n:attr="disabled => !$feed->hasMore" class="button is-success" href="?cursor={$feed->maxCursor}">Next</a>
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
<div class="field is-grouped is-grouped-centered">
|
||||
<p class="control">
|
||||
<a target="_blank" href="{url_download($playAddr, $uniqueId, $id, true)}" class="button is-info">Watermark</a>
|
||||
</p>
|
||||
<p class="control">
|
||||
<a target="_blank" href="{url_download(url_video_external($uniqueId, $id), $uniqueId, $id, false)}" class="button is-success">No watermark</a>
|
||||
</p>
|
||||
</div>
|
||||
@@ -0,0 +1,12 @@
|
||||
<div class="field is-grouped is-grouped-centered">
|
||||
<p class="control">
|
||||
<a class="button is-success" href="{url_video_internal($uniqueId, $id)}">
|
||||
{include '../../icon.latte', icon: 'lock', text: 'Instance'}
|
||||
</a>
|
||||
</p>
|
||||
<p class="control">
|
||||
<a class="button is-warning" href="{url_video_external($uniqueId, $id)}">
|
||||
{include '../../icon.latte', icon: 'lock-unlock', text: 'Original'}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
@@ -0,0 +1,5 @@
|
||||
<div class="tags">
|
||||
{foreach $challenges as $challenge}
|
||||
<a class="tag is-rounded" href="{path('/tag/' . $challenge->title)}">#{$challenge->title}</a>
|
||||
{/foreach}
|
||||
</div>
|
||||
@@ -0,0 +1,38 @@
|
||||
<div class="container">
|
||||
{foreach $feed->items as $item}
|
||||
<article class="media">
|
||||
<figure class="media-left">
|
||||
<p class="image is-64x64">
|
||||
<img class="is-rounded" src="{url_stream($item->author->avatarThumb)}" />
|
||||
</p>
|
||||
</figure>
|
||||
<div class="media-content">
|
||||
<p>
|
||||
<strong>{$item->author->nickname}</strong>
|
||||
<small>
|
||||
<a href="{url_user($item->author->uniqueId)}">@{$item->author->uniqueId}</a>
|
||||
</small>
|
||||
<small title="{date('M d, Y H:i:s e', $item->createTime)}">{date('M d, Y', $item->createTime)}</small>
|
||||
</p>
|
||||
{if !empty($item->challenges)}
|
||||
<p>{include './common/tags.latte', challenges: $item->challenges}</p>
|
||||
{/if}
|
||||
<p n:ifcontent>{$item->desc}</p>
|
||||
{include './common/stats.latte', playCount: $item->stats->playCount, diggCount: $item->stats->diggCount, commentCount: $item->stats->commentCount, shareCount: $item->stats->shareCount}
|
||||
<div class="has-text-centered">
|
||||
<video width="{$item->video->width}" height="{$item->video->height}" controls preload="none" poster="{url_stream($item->video->originCover)}">
|
||||
<source src="{url_stream($item->video->playAddr)}" type="video/mp4" />
|
||||
</video>
|
||||
</div>
|
||||
<p class="has-text-centered"><b>Download video</b></p>
|
||||
{include './common/download.latte', playAddr: $item->video->playAddr, id: $item->id, uniqueId: $item->author->uniqueId}
|
||||
<p class="has-text-centered"><b>Share link</b></p>
|
||||
{include './common/share.latte', uniqueId: $item->author->uniqueId, id: $item->id}
|
||||
</div>
|
||||
</article>
|
||||
{/foreach}
|
||||
{if empty($feed->items)}
|
||||
<p class="title">No items sent by TikTok!</p>
|
||||
{/if}
|
||||
</div>
|
||||
{include './common/controls.latte'}
|
||||
@@ -9,7 +9,7 @@
|
||||
{include '../components/navbar.latte'}
|
||||
</div>
|
||||
<div class="hero-body">
|
||||
<div class="container has-text-centered">
|
||||
<div class="container">
|
||||
{block content}{/block}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,40 @@
|
||||
{layout '../layouts/default.latte'}
|
||||
|
||||
{block header}
|
||||
<p class="title">Welcome to ProxiTok!</p>
|
||||
<p class="subtitle">
|
||||
Made with <span style="color: #e25555;">♥</span> in <a href="https://github.com/pablouser1/ProxiTok">Github</a>
|
||||
</p>
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
<div class="content">
|
||||
<p class="title">About this instance</p>
|
||||
<p>Frontend version: <b>{version_frontend()}</b></p>
|
||||
<p>Scraper version: <b>{version_scraper()}</b></p>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p class="title">Why would I want to use ProxiTok?</p>
|
||||
<p>
|
||||
There are already
|
||||
<a rel="nofollow" href="https://penetrum.com/tiktok/Penetrum_TikTok_Security_Analysis_whitepaper.pdf">multiple</a>
|
||||
<a rel="nofollow" href="https://rufposten.de/blog/2019/12/05/privacy-analysis-of-tiktoks-app-and-website">articles</a>
|
||||
<a rel="nofollow" href="https://citizenlab.ca/2021/03/tiktok-vs-douyin-security-privacy-analysis">explaining</a>
|
||||
Tiktok's privacy issues.
|
||||
This program allows you to browse TikTok without having to worry about privacy concerns.
|
||||
</p>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p class="title">Third party</p>
|
||||
<p>
|
||||
This project wouldn't be possible without the help of the following projects:
|
||||
<ul>
|
||||
<li><a rel="nofollow" href="https://github.com/pablouser1/TikScraperPHP">TikScraperPHP</a></li>
|
||||
<li><a rel="nofollow" href="https://github.com/nette/latte">Latte</a></li>
|
||||
<li><a rel="nofollow" href="https://github.com/bramus/router">bramus/router</a></li>
|
||||
<li><a rel="nofollow" href="https://github.com/josegonzalez/php-dotenv">php-dotenv</a></li>
|
||||
<li><a rel="nofollow" href="https://github.com/jgthms/bulma">Bulma</a> and <a href="https://github.com/jenil/bulmaswatch">Bulmaswatch</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
{/block}
|
||||
@@ -5,7 +5,7 @@
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
{foreach $data->feed->items as $type => $items}
|
||||
{foreach $data->items as $type => $items}
|
||||
<p class="title">{$type|firstUpper}</p>
|
||||
<div class="columns is-multiline is-vcentered">
|
||||
{foreach $items as $item}
|
||||
@@ -1,9 +1,9 @@
|
||||
{layout '../layouts/hero.latte'}
|
||||
|
||||
{block content}
|
||||
<p class="title">Welcome to ProxiTok!</p>
|
||||
<p class="subtitle">An alternative open source frontend for TikTok</p>
|
||||
{embed '../components/form.latte', path: '/redirect', method: 'GET'}
|
||||
<p class="title has-text-centered">Welcome to ProxiTok!</p>
|
||||
<p class="subtitle has-text-centered">An alternative open source frontend for TikTok</p>
|
||||
{embed '../components/form.latte', path: '/redirect/search', method: 'GET'}
|
||||
{block fields}
|
||||
<div class="field has-addons has-addons-centered">
|
||||
<div class="control">
|
||||
@@ -0,0 +1,11 @@
|
||||
{layout '../layouts/default.latte'}
|
||||
|
||||
{block header}
|
||||
<p class="title">{$info->detail->title}</p>
|
||||
<p class="subtitle">{$info->detail->desc}</p>
|
||||
<p>Videos: {number($info->stats->videoCount)}</p>
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
{include '../components/feed.latte'}
|
||||
{/block}
|
||||
@@ -1,18 +1,16 @@
|
||||
{contentType application/rss+xml}
|
||||
{do header('Content-Disposition: attachment; filename="' . $title . '.rss' . '"')}
|
||||
{var $full_link = path($link)}
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title>{$title}</title>
|
||||
<description><![CDATA[{$desc}]]></description>
|
||||
<link>{$full_link}</link>
|
||||
<atom:link href="{$full_link . '/rss'}" rel="self" type="application/rss+xml"></atom:link>
|
||||
<link>{$link}</link>
|
||||
<atom:link href="{$link . '/rss'}" rel="self" type="application/rss+xml"></atom:link>
|
||||
{foreach $items as $item}
|
||||
<item>
|
||||
<title>{$item->desc}</title>
|
||||
<description><![CDATA[<p>{$item->desc}</p><video controls="controls" preload="auto" src="{path('/stream?url=' . urlencode($item->video->playAddr))}"></video>]]></description>
|
||||
<link>{path('/@' . $item->author->uniqueId . '/video/' . $item->id)}</link>
|
||||
<description><![CDATA[<p>{$item->desc}</p><video controls="controls" preload="auto" src="{url_stream($item->video->playAddr)}"></video>]]></description>
|
||||
<link>{url_video_internal($item->author->uniqueId, $item->id)}</link>
|
||||
<pubDate>{date('r', $item->createTime)}</pubDate>
|
||||
<guid isPermaLink="false">{$item->id}</guid>
|
||||
</item>
|
||||
@@ -0,0 +1,17 @@
|
||||
{layout '../layouts/default.latte'}
|
||||
|
||||
{block header}
|
||||
<p class="title">Settings</p>
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
<div class="content">
|
||||
<p class="title">General</p>
|
||||
{include '../components/settings/general.latte'}
|
||||
</div>
|
||||
<hr />
|
||||
<div class="content">
|
||||
<p class="title">Api</p>
|
||||
{include '../components/settings/api.latte'}
|
||||
</div>
|
||||
{/block}
|
||||
@@ -0,0 +1,22 @@
|
||||
{layout '../layouts/default.latte'}
|
||||
|
||||
{var $has_rss = true}
|
||||
|
||||
{var $og = $info->meta->og}
|
||||
{var $og_content = $info->detail->profileLarger}
|
||||
{var $og_url = url_tag($info->detail->title)}
|
||||
|
||||
{block header}
|
||||
{if $info->detail->profileLarger !== ''}
|
||||
<figure class="image is-inline-block is-128x128">
|
||||
<img class="is-rounded" src="{url_stream($info->detail->profileLarger)}" />
|
||||
</figure>
|
||||
{/if}
|
||||
<p class="title">{$info->detail->title}</p>
|
||||
<p class="subtitle">{include '../components/rss.latte'}</p>
|
||||
<p>Videos: {number($info->stats->videoCount)} / Views: {number($info->stats->viewCount)}</p>
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
{include '../components/feed.latte'}
|
||||
{/block}
|
||||
@@ -0,0 +1,22 @@
|
||||
{layout '../layouts/default.latte'}
|
||||
|
||||
{var $has_rss = true}
|
||||
|
||||
{var $og = $info->meta->og}
|
||||
{var $og_content = $info->detail->avatarLarger}
|
||||
{var $og_url = url_user($info->detail->uniqueId)}
|
||||
|
||||
{block header}
|
||||
<figure class="image is-inline-block is-128x128">
|
||||
<img class="is-rounded" src="{url_stream($info->detail->avatarLarger)}" />
|
||||
</figure>
|
||||
<p class="title">{$info->detail->uniqueId}</p>
|
||||
<p class="subtitle">{include '../components/rss.latte'}</p>
|
||||
<p>{$info->detail->signature}</p>
|
||||
<p>Following: {number($info->stats->followingCount)} / Followers: {number($info->stats->followerCount)}</p>
|
||||
<p>Hearts: {number($info->stats->heartCount)} / Videos: {$info->stats->videoCount}</p>
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
{include '../components/feed.latte'}
|
||||
{/block}
|
||||
@@ -0,0 +1,46 @@
|
||||
{layout "../layouts/{$layout}.latte"}
|
||||
|
||||
{var $og = $info->meta->og}
|
||||
{var $og_content = $item->video->originCover}
|
||||
{var $og_url = url_video_internal($info->detail->uniqueId, $item->id)}
|
||||
|
||||
{block content}
|
||||
<div class="columns is-centered is-vcentered is-gapless">
|
||||
<div class="column has-text-centered">
|
||||
<video controls autoplay poster="{url_stream($item->video->originCover)}">
|
||||
<source src="{url_stream($item->video->playAddr)}" type="video/mp4" />
|
||||
</video>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="box">
|
||||
<article class="media">
|
||||
<figure class="media-left">
|
||||
<p class="image is-64x64">
|
||||
<img src="{url_stream($info->detail->avatarThumb)}" />
|
||||
</p>
|
||||
</figure>
|
||||
<div class="media-content">
|
||||
<p>
|
||||
<strong>{$info->detail->nickname}</strong>
|
||||
<small>
|
||||
<a href="{url_user($info->detail->uniqueId)}">@{$info->detail->uniqueId}</a>
|
||||
</small>
|
||||
<small title="{date('M d, Y H:i:s e', $item->createTime)}">{date('M d, Y', $item->createTime)}</small>
|
||||
</p>
|
||||
{if !empty($item->challenges)}
|
||||
<p>{include '../components/themes/common/tags.latte', challenges: $item->challenges}</p>
|
||||
{/if}
|
||||
<div class="content">
|
||||
<p n:ifcontent>{$item->desc}</p>
|
||||
{include '../components/themes/common/stats.latte', playCount: $item->stats->playCount, diggCount: $item->stats->diggCount, commentCount: $item->stats->commentCount, shareCount: $item->stats->shareCount}
|
||||
<div class="has-text-centered">
|
||||
{include '../components/themes/common/share.latte', uniqueId: $info->detail->uniqueId, id: $item->id}
|
||||
{include '../components/themes/common/download.latte', playAddr: $item->video->playAddr, id: $item->id, uniqueId: $info->detail->uniqueId}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
@@ -1,36 +0,0 @@
|
||||
{layout '../layouts/default.latte'}
|
||||
|
||||
{block header}
|
||||
<p class="title">Welcome to ProxiTok!</p>
|
||||
<p class="subtitle">
|
||||
Made with <span style="color: #e25555;">♥</span> in <a href="https://github.com/pablouser1/ProxiTok">Github</a>
|
||||
</p>
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
<p class="title">About this instance</p>
|
||||
<p>Frontend version: {version_frontend()}</p>
|
||||
<p>Scraper version: {version_scraper()}</p>
|
||||
<hr />
|
||||
<p class="title">Why would I want to use ProxiTok?</p>
|
||||
<p>
|
||||
There are already
|
||||
<a rel="nofollow" href="https://penetrum.com/tiktok/Penetrum_TikTok_Security_Analysis_whitepaper.pdf">multiple</a>
|
||||
<a rel="nofollow" href="https://rufposten.de/blog/2019/12/05/privacy-analysis-of-tiktoks-app-and-website">articles</a>
|
||||
<a rel="nofollow" href="https://citizenlab.ca/2021/03/tiktok-vs-douyin-security-privacy-analysis">explaining</a>
|
||||
Tiktok's privacy issues.
|
||||
This program allows you to browse TikTok without having to worry about privacy concerns.
|
||||
</p>
|
||||
<hr />
|
||||
<p class="title">Third party</p>
|
||||
<p>
|
||||
This project wouldn't be possible without the help of the following projects:
|
||||
<ul>
|
||||
<li><a rel="nofollow" href="https://github.com/pablouser1/TikScraperPHP">TikScraperPHP</a></li>
|
||||
<li><a rel="nofollow" href="https://github.com/nette/latte">Latte</a></li>
|
||||
<li><a rel="nofollow" href="https://github.com/bramus/router">bramus/router</a></li>
|
||||
<li><a rel="nofollow" href="https://github.com/josegonzalez/php-dotenv">php-dotenv</a></li>
|
||||
<li><a rel="nofollow" href="https://github.com/jgthms/bulma">Bulma</a> and <a href="https://github.com/jenil/bulmaswatch">Bulmaswatch</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
{/block}
|
||||
@@ -1,11 +0,0 @@
|
||||
{layout '../layouts/default.latte'}
|
||||
|
||||
{block header}
|
||||
<p class="title">{$data->info->detail->title}</p>
|
||||
<p class="subtitle">{$data->info->detail->desc}</p>
|
||||
<p>Videos: {number($data->info->stats->videoCount)}</p>
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
{include '../components/feed.latte'}
|
||||
{/block}
|
||||
@@ -1,13 +0,0 @@
|
||||
{layout '../layouts/default.latte'}
|
||||
|
||||
{block header}
|
||||
<p class="title">Settings</p>
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
<p class="title">General</p>
|
||||
{include '../components/settings/general.latte'}
|
||||
<hr />
|
||||
<p class="title">Api</p>
|
||||
{include '../components/settings/api.latte'}
|
||||
{/block}
|
||||
@@ -1,18 +0,0 @@
|
||||
{layout '../layouts/default.latte'}
|
||||
|
||||
{var $has_rss = true}
|
||||
|
||||
{block header}
|
||||
{if $data->info->detail->profileThumb !== ''}
|
||||
<figure class="figure is-96x96">
|
||||
<img src="{path('/stream?url=' . urlencode($data->info->detail->profileThumb))}" />
|
||||
</figure>
|
||||
{/if}
|
||||
<p class="title">{$data->info->detail->title}</p>
|
||||
<p class="subtitle">{include '../components/rss.latte'}</p>
|
||||
<p>Videos: {number($data->info->stats->videoCount)} / Views: {number($data->info->stats->viewCount)}</p>
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
{include '../components/feed.latte'}
|
||||
{/block}
|
||||
@@ -1,18 +0,0 @@
|
||||
{layout '../layouts/default.latte'}
|
||||
|
||||
{var $has_rss = true}
|
||||
|
||||
{block header}
|
||||
<figure class="figure is-96x96">
|
||||
<img src="{path('/stream?url=' . urlencode($data->info->detail->avatarThumb))}" />
|
||||
</figure>
|
||||
<p class="title">{$data->info->detail->uniqueId}</p>
|
||||
<p class="subtitle">{include '../components/rss.latte'}</p>
|
||||
<p>{$data->info->detail->signature}</p>
|
||||
<p>Following: {number($data->info->stats->followingCount)} / Followers: {number($data->info->stats->followerCount)}</p>
|
||||
<p>Hearts: {number($data->info->stats->heartCount)} / Videos: {$data->info->stats->videoCount}</p>
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
{include '../components/feed.latte'}
|
||||
{/block}
|
||||
@@ -1,25 +0,0 @@
|
||||
{layout "../layouts/{$layout}.latte"}
|
||||
|
||||
{block content}
|
||||
<div class="columns has-text-centered is-centered is-vcentered is-gapless">
|
||||
<div class="column">
|
||||
<video controls autoplay poster="{url_stream($item->video->originCover)}">
|
||||
<source src="{url_stream($item->video->playAddr)}" type="video/mp4" />
|
||||
</video>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="box">
|
||||
<p class="title">Video by <a href="{url_user($detail->uniqueId)}">{$detail->uniqueId}</a></p>
|
||||
<p class="subtitle">{$item->desc}</p>
|
||||
{include '../components/themes/common/stats.latte', playCount: $item->stats->playCount, diggCount: $item->stats->diggCount, commentCount: $item->stats->commentCount, shareCount: $item->stats->shareCount}
|
||||
<div class="container mt-4">
|
||||
<p>{include '../components/icon.latte', icon: 'music', text: $item->music->title}</p>
|
||||
<audio src="{url_stream($item->music->playUrl)}" controls preload="none"></audio>
|
||||
</div>
|
||||
<hr />
|
||||
{include '../components/themes/common/share.latte', uniqueId: $detail->uniqueId, id: $item->id}
|
||||
{include '../components/themes/common/download.latte', playAddr: $item->video->playAddr, id: $item->id, uniqueId: $detail->uniqueId}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
Reference in New Issue
Block a user