Removed home.js

Added Discover
This commit is contained in:
Pablo Ferreiro 2022-02-06 00:58:30 +01:00
parent df052dab36
commit 8816f4a1a1
No known key found for this signature in database
GPG key ID: 41FBCE65B779FA24
25 changed files with 213 additions and 145 deletions

View file

@ -7,6 +7,7 @@ Use Tiktok with an alternative frontend, inspired by Nitter.
* See trending
* See tags
* See video by id
* Discovery
* Create a following list, which you can later use to see all the feeds from those users
* RSS Feed for user, trending and tag (just add /rss to the url)
@ -56,6 +57,7 @@ location /proxitok/.env {
* Add a NoJS version / Make the whole program without required JS
* Better error handling
* Make video on /video fit screen and don't overflow
* Allow custom Region/Language
## Credits
* [TikTok-API-PHP](https://github.com/ssovit/TikTok-API-PHP) (Currently using my personal fork)

View file

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

View file

@ -0,0 +1,24 @@
<?php
namespace App\Controllers;
use App\Helpers\Misc;
/**
* Used to be compatible with HTML forms
*/
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'])) {
$endpoint = '/video/' . $_GET['video'];
}
$url = Misc::url($endpoint);
header("Location: {$url}");
}
}

View file

@ -18,8 +18,7 @@ class SettingsController {
Cookies::set($proxy_element, $_POST[$proxy_element]);
}
}
http_response_code(302);
$url = Misc::env('APP_URL', '');
$url = Misc::url('/settings');
header("Location: {$url}");
}
@ -49,6 +48,7 @@ class SettingsController {
// Build string
$following_string = implode(',', $following);
Cookies::set('following', $following_string);
header('Location: ../settings');
$url = Misc::url('/settings');
header("Location: {$url}");
}
}

View file

@ -1,10 +1,12 @@
<?php
namespace App\Helpers;
use App\Models\ErrorTemplate;
class ErrorHandler {
static public function show(object $meta) {
http_response_code($meta->http_code);
$latte = Misc::latte();
$latte->render(Misc::getView('error'), ['error' => $meta]);
$latte->render(Misc::getView('error'), new ErrorTemplate($meta));
}
}

View file

@ -1,7 +1,6 @@
<?php
namespace App\Helpers;
use Exception;
use App\Cache\JSONCache;
use App\Cache\RedisCache;
@ -10,11 +9,11 @@ class Misc {
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 url(string $endpoint = '') {
return self::env('APP_URL', '') . $endpoint;
}
static public function env(string $key, mixed $default_value): string {
static public function env(string $key, string $default_value): string {
return isset($_ENV[$key]) && !empty($_ENV[$key]) ? $_ENV[$key] : $default_value;
}
@ -45,7 +44,7 @@ class Misc {
break;
case 'redis':
if (!isset($_ENV['REDIS_URL'])) {
throw new Exception('You need to set REDIS_URL to use Redis Cache!');
throw new \Exception('You need to set REDIS_URL to use Redis Cache!');
}
$url = parse_url($_ENV['REDIS_URL']);
@ -64,24 +63,17 @@ class Misc {
* Setup of Latte template engine
*/
static public function latte(): \Latte\Engine {
// Workaround to avoid weird path issues
$url = self::getURL();
$latte = new \Latte\Engine;
$cache_path = self::env('LATTE_CACHE', __DIR__ . '/../../cache/latte');
$latte->setTempDirectory($cache_path);
// -- CUSTOM FUNCTIONS -- //
// Import assets
$latte->addFunction('assets', function (string $name, string $type) use ($url) {
$path = "{$url}/{$type}/{$name}";
return $path;
});
// Get base URL
$latte->addFunction('path', function (string $path = '') use ($url) {
return "{$url}/{$path}";
// Get URL with optional endpoint
$latte->addFunction('path', function (string $endpoint = ''): string {
return self::url($endpoint);
});
// Version being used
$latte->addFunction('version', function () {
$latte->addFunction('version', function (): string {
return \Composer\InstalledVersions::getVersion('pablouser1/proxitok');
});
// https://stackoverflow.com/a/36365553
@ -98,10 +90,6 @@ class Misc {
}
return $x;
});
$latte->addFunction('size', function (string $url) {
$download = new \Sovit\TikTok\Download();
return $download->file_size($url);
});
return $latte;
}
}

View file

@ -0,0 +1,11 @@
<?php
namespace App\Models;
class ErrorTemplate extends BaseTemplate {
public object $error;
function __construct(object $error) {
parent::__construct('Error');
$this->error = $error;
}
}

View file

@ -0,0 +1,34 @@
<?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

@ -1,16 +1,17 @@
<link rel="stylesheet" href="{assets('feed.css', 'styles')}">
<link rel="stylesheet" href="{path('/styles/feed.css')}">
<noscript>JavaScript is required for this section to work!</noscript>
<section class="section">
<div class="columns is-multiline is-vcentered">
{foreach $feed->items as $item}
<div class="column is-one-quarter">
<a class="clickable-img" id="{$item->id}" href="#{$item->id}"
data-video_url="{path('stream?url=' . urlencode($item->video->playAddr))}"
data-video_download="{path('stream?url=' . urlencode($item->video->playAddr) . '&download=1')}"
data-video_url="{path('/stream?url=' . urlencode($item->video->playAddr))}"
data-video_download="{path('/stream?url=' . urlencode($item->video->playAddr) . '&download=1')}"
data-desc="{$item->desc}"
data-music_title="{$item->music->title}"
data-music_url="{path('stream?url=' . urlencode($item->music->playUrl))}">
<img loading="lazy" src="{path('stream?url=' . urlencode($item->video->originCover))}" />
<img class="hidden" loading="lazy" data-src="{path('stream?url=' . urlencode($item->video->dynamicCover))}" />
data-music_url="{path('/stream?url=' . urlencode($item->music->playUrl))}">
<img loading="lazy" src="{path('/stream?url=' . urlencode($item->video->originCover))}" />
<img class="hidden" loading="lazy" data-src="{path('/stream?url=' . urlencode($item->video->dynamicCover))}" />
</a>
</div>
{/foreach}
@ -50,4 +51,4 @@
</footer>
</div>
</div>
<script src="{assets('feed.js', 'scripts')}"></script>
<script src="{path('/scripts/feed.js')}"></script>

View file

@ -2,6 +2,6 @@
<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="stylesheet" href="{assets('bulma.min.css', 'styles')}">
<link rel="stylesheet" href="{path('/styles/bulma.min.css')}">
<title>{$title} - ProxiTok</title>
</head>

View file

@ -9,11 +9,11 @@
<div id="navbar-menu" class="navbar-menu">
<div class="navbar-start">
<a href="{path('')}" class="navbar-item">Home</a>
<a href="{path('following')}" class="navbar-item">Following</a>
<a href="{path('settings')}" class="navbar-item">Settings</a>
<a href="{path('about')}" class="navbar-item">About</a>
<a href="{path('/')}" class="navbar-item">Home</a>
<a href="{path('/following')}" class="navbar-item">Following</a>
<a href="{path('/settings')}" class="navbar-item">Settings</a>
<a href="{path('/about')}" class="navbar-item">About</a>
</div>
</div>
</nav>
<script src="{assets('navbar.js', 'scripts')}"></script>
<script src="{path('/scripts/navbar.js')}"></script>

View file

@ -1,5 +1,5 @@
{include '../following_tags.latte'}
<form action="./settings/following" method="POST">
<form action="{path('/settings/following')}" method="POST">
<div class="field">
<label class="label">Add / Remove user</label>
<div class="control">

View file

@ -1,4 +1,4 @@
<form action="./settings/proxy" method="POST">
<form action="{path('/settings/proxy')}" method="POST">
{foreach $proxy_elements as $proxy_element}
<div class="field">
<label class="label">{$proxy_element}</label>

View file

@ -1,8 +1,16 @@
{
"name": "pablouser1/proxitok",
"description": "An alternative frontend for TikTok",
"version": "1.3.2",
"version": "1.4.0",
"license": "AGPL-3.0-or-later",
"type": "project",
"homepage": "https://github.com/pablouser1/ProxiTok",
"authors": [
{
"name": "Pablo Ferreiro",
"homepage": "https://github.com/pablouser1"
}
],
"repositories": [
{
"type": "vcs",

16
composer.lock generated
View file

@ -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": "bf98cf536ad098372082ff5899967548",
"content-hash": "b5edb25fa0c50e39f24197b895670cc3",
"packages": [
{
"name": "bramus/router",
@ -381,12 +381,12 @@
"source": {
"type": "git",
"url": "https://github.com/pablouser1/TikTok-API-PHP.git",
"reference": "672e26d461804923324782c40c4e2d650fd01c6a"
"reference": "26e3c089bc409a324136cd4465d5489210cb73c3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pablouser1/TikTok-API-PHP/zipball/672e26d461804923324782c40c4e2d650fd01c6a",
"reference": "672e26d461804923324782c40c4e2d650fd01c6a",
"url": "https://api.github.com/repos/pablouser1/TikTok-API-PHP/zipball/26e3c089bc409a324136cd4465d5489210cb73c3",
"reference": "26e3c089bc409a324136cd4465d5489210cb73c3",
"shasum": ""
},
"type": "library",
@ -425,7 +425,7 @@
"issues": "https://github.com/ssovit/TikTok-API-PHP/issues",
"email": "sovit.tamrakar@gmail.com"
},
"time": "2022-01-22T19:37:07+00:00"
"time": "2022-02-05T23:47:32+00:00"
},
{
"name": "symfony/polyfill-ctype",
@ -620,12 +620,12 @@
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Php80\\": ""
},
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php80\\": ""
},
"classmap": [
"Resources/stubs"
]

View file

@ -1,10 +1,11 @@
<?php
use App\Helpers\Misc;
use App\Models\BaseTemplate;
use App\Models\HomeTemplate;
$router->get('/', function () {
$latte = Misc::latte();
$latte->render(Misc::getView('home'), new BaseTemplate('Home'));
$latte->render(Misc::getView('home'), new HomeTemplate);
});
$router->get('/about', function () {
@ -13,6 +14,7 @@ $router->get('/about', function () {
});
$router->get('/stream', 'ProxyController@stream');
$router->get('/redirect', 'RedirectController@redirect');
$router->mount('/trending', function () use ($router) {
$router->get('/', 'TrendingController@get');
@ -40,4 +42,5 @@ $router->mount('/settings', function () use ($router) {
$router->post('/following', 'SettingsController@following');
});
$router->get('/discover', 'DiscoverController@get');
$router->get('/following', 'FollowingController@get');

View file

@ -1,32 +0,0 @@
const goToUser = e => {
e.preventDefault()
const formData = new FormData(e.target)
const username = formData.get('username')
window.location.href = `./@${username}`
}
const goToTag = e => {
e.preventDefault()
const formData = new FormData(e.target)
const tag = formData.get('tag')
window.location.href = `./tag/${tag}`
}
const goToVideo = e => {
e.preventDefault()
const formData = new FormData(e.target)
const video_id = formData.get('video_id')
window.location.href = `./video/${video_id}`
}
const goToMusic = e => {
e.preventDefault()
const formData = new FormData(e.target)
const video_id = formData.get('music_id')
window.location.href = `./music/${video_id}`
}
document.getElementById('username_form').addEventListener('submit', goToUser, false)
document.getElementById('tag_form').addEventListener('submit', goToTag, false)
document.getElementById('video_form').addEventListener('submit', goToVideo, false)
document.getElementById('music_form').addEventListener('submit', goToMusic, false)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -24,8 +24,10 @@ $bulmaswatch-import-font: false;
@import "./node_modules/bulma/sass/form/tools.sass";
// Components
@import "./node_modules/bulma/sass/components/card.sass";
@import "./node_modules/bulma/sass/components/modal.sass";
@import "./node_modules/bulma/sass/components/navbar.sass";
@import "./node_modules/bulma/sass/components/media.sass";
// Grids
@import "./node_modules/bulma/sass/grid/columns.sass";

View file

@ -113,9 +113,9 @@ readdirp@~3.6.0:
picomatch "^2.2.1"
sass@^1.46.0:
version "1.49.0"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.49.0.tgz#65ec1b1d9a6bc1bae8d2c9d4b392c13f5d32c078"
integrity sha512-TVwVdNDj6p6b4QymJtNtRS2YtLJ/CqZriGg0eIAbAKMlN8Xy6kbv33FsEZSF7FufFFM705SQviHjjThfaQ4VNw==
version "1.49.7"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.49.7.tgz#22a86a50552b9b11f71404dfad1b9ff44c6b0c49"
integrity sha512-13dml55EMIR2rS4d/RDHHP0sXMY3+30e1TKsyXaSz3iLWVoDWEoboY8WzJd5JMnxrRHffKO3wq2mpJ0jxRJiEQ==
dependencies:
chokidar ">=3.0.0 <4.0.0"
immutable "^4.0.0"

43
views/discover.latte Normal file
View file

@ -0,0 +1,43 @@
{layout '../layouts/default.latte'}
{block header}
<p class="title">Discover</p>
{/block}
{block content}
{foreach $feed->items as $type => $items}
<p class="title">{$type|firstUpper}</p>
<div class="columns is-multiline is-vcentered">
{foreach $items as $item}
<div class="column is-one-quarter">
<a href="{path($item->cardItem->link)}">
<div class="card">
<div class="card-content">
<div class="media">
<!-- Show image if exists -->
{if !empty($item->cardItem->cover)}
<div class="media-left">
<figure class="image is-96x96">
<img width="96" height="96" src="{path('/stream?url=' . urlencode($item->cardItem->cover))}" />
</figure>
</div>
{/if}
<div class="media-content">
<p class="title">{$item->cardItem->title}</p>
<p class="subtitle">{$item->cardItem->subTitle}</p>
</div>
</div>
<div class="content">
<p>{$item->cardItem->description}</p>
</div>
</div>
</div>
</a>
</div>
{/foreach}
</div>
{if !$iterator->last}
<hr />
{/if}
{/foreach}
{/block}

View file

@ -5,9 +5,6 @@
{/block}
{block content}
<p class="title">Following:</p>
{include '../components/following_tags.latte'}
<p>You can add/remove follows on settings</p>
<hr />
<p>{include '../components/following_tags.latte'}</p>
{include '../components/feed.latte'}
{/block}

View file

@ -3,58 +3,24 @@
{block content}
<p class="title">Welcome to ProxiTok!</p>
<p class="subtitle">An alternative open source frontend for TikTok</p>
<p>Search user:</p>
<form id="username_form">
<div class="field has-addons has-addons-centered">
<div class="control">
<input name="username" class="input" type="text" placeholder="Type username" required />
</div>
<div class="control">
<button class="button is-success" type="submit">Go</button>
</div>
</div>
</form>
<!-- Create forms from App\Models\HomeTemplate -->
{foreach $forms as $form}
<p>{$form['title']}</p>
<form action="{path('/redirect')}">
<div class="field has-addons has-addons-centered">
<div class="control">
<input name="{$form['input']}" class="input" type="text" placeholder="{$form['placeholder']}" required />
</div>
<div class="control">
<button class="button is-success" type="submit">Go</button>
</div>
</div>
</form>
<hr />
{/foreach}
<p>Discover</p>
<a class="button is-success" href="{path('/discover')}">Go</a>
<hr />
<p>Search video by id:</p>
<form id="video_form">
<div class="field has-addons has-addons-centered">
<div class="control">
<input name="video_id" class="input" type="text" placeholder="Type video ID" required />
</div>
<div class="control">
<button class="button is-success" type="submit">Go</button>
</div>
</div>
</form>
<hr />
<p>Search tag:</p>
<form id="tag_form">
<div class="field has-addons has-addons-centered">
<div class="control">
<input name="tag" class="input" type="text" placeholder="Type tag" required />
</div>
<div class="control">
<button class="button is-success" type="submit">Go</button>
</div>
</div>
</form>
<hr />
<p>Search music videos by id:</p>
<form id="music_form">
<div class="field has-addons has-addons-centered">
<div class="control">
<input name="music_id" class="input" type="text" placeholder="Type music id" required />
</div>
<div class="control">
<button class="button is-success" type="submit">Go</button>
</div>
</div>
</form>
<hr />
<p>Trending:</p>
<a class="button is-success" href="./trending">Go</a>
{/block}
{block extra}
<script src="{assets('home.js', 'scripts')}"></script>
<p>Trending</p>
<a class="button is-success" href="{path('/trending')}">Go</a>
{/block}

View file

@ -2,13 +2,13 @@
{block header}
<figure class="figure is-96x96">
<img src="{path('stream?url=' . urlencode($feed->info->detail->user->avatarThumb))}" />
<img src="{path('/stream?url=' . urlencode($feed->info->detail->user->avatarThumb))}" />
</figure>
<p class="title">{$feed->info->detail->user->uniqueId}'s profile</p>
<p class="subtitle">{$feed->info->detail->user->signature}</p>
<p>Following: {number($feed->info->detail->stats->followingCount)} / Followers: {number($feed->info->detail->stats->followerCount)}</p>
<p>Hearts: {number($feed->info->detail->stats->heartCount)} / Videos: {$feed->info->detail->stats->videoCount}</p>
<a href="{path('@' . $feed->info->detail->user->uniqueId . '/rss')}">RSS</a>
<a href="{path('/@' . $feed->info->detail->user->uniqueId . '/rss')}">RSS</a>
{/block}
{block content}