mirror of
https://github.com/pablouser1/ProxiTok.git
synced 2024-12-06 19:27:30 +01:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ec611478e3 | |||
| 96aa2803b2 | |||
| 9f63fecc18 | |||
| a27d6ca767 | |||
| 2aab1bfe24 | |||
| bc9ff0100e | |||
| c4f3a80c3e | |||
| 3b441c2683 | |||
| 03002ba835 | |||
| 76d4a581f3 | |||
| 36d9902c73 | |||
| 98405545e7 | |||
| 9ac169d480 | |||
| b63a0b2755 | |||
| 1427a94810 | |||
| 547f8460b3 | |||
| 4610a89810 | |||
| 70161ec0d6 | |||
| 2592f2087c | |||
| a033682dfb | |||
| 01c39fbc0e | |||
| 086c206920 | |||
| 3eebeb0369 | |||
| f203dca5a2 | |||
| db1de45ee1 | |||
| fe80102212 | |||
| a99b8ebd54 | |||
| d33e9d119a | |||
| 7c51b63660 | |||
| 13e686bb5a | |||
| 250bbedc1d |
@@ -42,9 +42,9 @@ jobs:
|
||||
# https://github.com/sigstore/cosign-installer
|
||||
- name: Install cosign
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: sigstore/cosign-installer@v3.1.1
|
||||
uses: sigstore/cosign-installer@v3.6.0
|
||||
with:
|
||||
cosign-release: 'v2.1.1'
|
||||
cosign-release: 'v2.4.0'
|
||||
|
||||
|
||||
# Workaround: https://github.com/docker/build-push-action/issues/461
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
# ProxiTok
|
||||
Use Tiktok with an alternative frontend, inspired by Nitter.
|
||||
|
||||
## WARNING
|
||||
THE LATEST VERSION **v2.5.0.0** INCLUDES BREAKING CHANGES, CHECK THE [PULL REQUEST](https://github.com/pablouser1/ProxiTok/pull/224) FOR MORE INFO
|
||||
|
||||
## Features
|
||||
* Privacy: All requests made to TikTok are server-side, so you will never connect to their servers
|
||||
* See user's feed
|
||||
@@ -15,6 +18,8 @@ Please check [this](https://github.com/pablouser1/ProxiTok/wiki/Self-hosting) wi
|
||||
## Public instances
|
||||
[This](https://github.com/pablouser1/ProxiTok/wiki/Public-instances) wiki article contains a list with all the known public instances.
|
||||
|
||||
Instances list in JSON format can be found in [instances.json](instances.json) file.
|
||||
|
||||
## Extensions
|
||||
If you want to automatically redirect Tiktok links to ProxiTok you can use:
|
||||
* [Libredirect](https://github.com/libredirect/libredirect)
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Helpers\ErrorHandler;
|
||||
use App\Helpers\Misc;
|
||||
use App\Helpers\Wrappers;
|
||||
use App\Models\FeedTemplate;
|
||||
|
||||
class FollowingController {
|
||||
public static function get() {
|
||||
$cursor = Misc::getCursor();
|
||||
|
||||
$api = Wrappers::api();
|
||||
$following = $api->following();
|
||||
$following->feed($cursor);
|
||||
if ($following->ok()) {
|
||||
$feed = $following->getFeed();
|
||||
Wrappers::latte('following', new FeedTemplate('Following / Discover', $feed));
|
||||
} else {
|
||||
ErrorHandler::showMeta($following->error());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Helpers\ErrorHandler;
|
||||
use App\Helpers\Misc;
|
||||
use App\Helpers\Wrappers;
|
||||
use App\Models\FeedTemplate;
|
||||
use App\Models\RSSTemplate;
|
||||
|
||||
class ForYouController {
|
||||
public static function get() {
|
||||
$api = Wrappers::api();
|
||||
$fyp = $api->foryou();
|
||||
$fyp->feed();
|
||||
if ($fyp->ok()) {
|
||||
$feed = $fyp->getFeed();
|
||||
Wrappers::latte('foryou', new FeedTemplate('For you', $feed));
|
||||
} else {
|
||||
ErrorHandler::showMeta($fyp->error());
|
||||
}
|
||||
}
|
||||
|
||||
public static function rss() {
|
||||
$api = Wrappers::api();
|
||||
$fyp = $api->foryou();
|
||||
$fyp->feed();
|
||||
if ($fyp->ok()) {
|
||||
$feed = $fyp->getFeed();
|
||||
Misc::rss('For you');
|
||||
Wrappers::latte('rss', new RSSTemplate('For you', 'For you Page', '', Misc::url('/foryou'), $feed->items));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,7 +71,7 @@ class RedirectController {
|
||||
* to_endpoint maps a TikTok URL into a ProxiTok-compatible endpoint URL.
|
||||
*/
|
||||
static private function to_endpoint(string $url): string {
|
||||
if (preg_match('%^(?:https?://)?(?:www\.)?(?:vm\.|vt\.)?tiktok\.com/(?:t/)?([A-Za-z0-9]+)%', $url, $m)) {
|
||||
if (preg_match('%^(?:https?://)?(?:www\.)?(?:vm\.|vt\.|lite\.)?tiktok\.com/(?:t/)?([A-Za-z0-9]+)%', $url, $m)) {
|
||||
// Short video URL
|
||||
return '/@placeholder/video/' . $m[1];
|
||||
} elseif (preg_match('%^https://www\.tiktok\.com/(.+)%', $url, $m)) {
|
||||
|
||||
@@ -12,6 +12,6 @@ class ErrorHandler {
|
||||
|
||||
public static function showText(int $code, string $msg) {
|
||||
http_response_code($code);
|
||||
Wrappers::latte('error', new ErrorTemplate($code, $msg));
|
||||
Wrappers::latte('error', new ErrorTemplate($code, $msg, null, null));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,12 +26,14 @@ class Misc {
|
||||
}
|
||||
|
||||
public static function getScraperOptions(): array {
|
||||
$debug = self::env('APP_DEBUG', false);
|
||||
$url = self::env('API_CHROMEDRIVER', 'http://localhost:4444');
|
||||
$verifyFp = self::env('API_VERIFYFP', '');
|
||||
$device_id = self::env('API_DEVICE_ID', '');
|
||||
$ua = self::env('USER_AGENT', '');
|
||||
|
||||
$options = [
|
||||
'debug' => $debug,
|
||||
'browser' => [
|
||||
'url' => $url,
|
||||
'close_when_done' => false
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ class ErrorTemplate extends BaseTemplate {
|
||||
public ?Response $response = null;
|
||||
|
||||
|
||||
function __construct(int $http_code, string $msg, ?int $tiktok_code = null, ?Response $response) {
|
||||
function __construct(int $http_code, string $msg, ?int $tiktok_code, ?Response $response) {
|
||||
parent::__construct('Error');
|
||||
$this->http_code = $http_code;
|
||||
$this->msg = $msg;
|
||||
|
||||
Generated
+8
-39
@@ -589,23 +589,22 @@
|
||||
},
|
||||
{
|
||||
"name": "pablouser1/tikscraper",
|
||||
"version": "v2.6.0.2",
|
||||
"version": "v2.6.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/pablouser1/TikScraperPHP.git",
|
||||
"reference": "b13a1a0ffd108651d5b54008941d9405db8bf873"
|
||||
"reference": "051f3b4dd5debc05b1d49ab21e6ab831ed04ed9a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/pablouser1/TikScraperPHP/zipball/b13a1a0ffd108651d5b54008941d9405db8bf873",
|
||||
"reference": "b13a1a0ffd108651d5b54008941d9405db8bf873",
|
||||
"url": "https://api.github.com/repos/pablouser1/TikScraperPHP/zipball/051f3b4dd5debc05b1d49ab21e6ab831ed04ed9a",
|
||||
"reference": "051f3b4dd5debc05b1d49ab21e6ab831ed04ed9a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"guzzlehttp/guzzle": "^7.8",
|
||||
"guzzlehttp/guzzle": "^7.9",
|
||||
"php": "^8.1",
|
||||
"php-webdriver/webdriver": "^1.12",
|
||||
"sapistudio/seleniumstealth": "^1.0"
|
||||
"php-webdriver/webdriver": "^1.12"
|
||||
},
|
||||
"require-dev": {
|
||||
"pestphp/pest": "^1.22"
|
||||
@@ -629,9 +628,9 @@
|
||||
"description": "Get data from TikTok API",
|
||||
"support": {
|
||||
"issues": "https://github.com/pablouser1/TikScraperPHP/issues",
|
||||
"source": "https://github.com/pablouser1/TikScraperPHP/tree/v2.6.0.2"
|
||||
"source": "https://github.com/pablouser1/TikScraperPHP/tree/v2.6.2.0"
|
||||
},
|
||||
"time": "2024-08-20T20:46:45+00:00"
|
||||
"time": "2024-08-28T12:27:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "php-webdriver/webdriver",
|
||||
@@ -903,36 +902,6 @@
|
||||
},
|
||||
"time": "2019-03-08T08:55:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sapistudio/seleniumstealth",
|
||||
"version": "1.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Sapistudio/SeleniumStealth.git",
|
||||
"reference": "4b392077e3d609fed564b78ae2e8becb98f01957"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Sapistudio/SeleniumStealth/zipball/4b392077e3d609fed564b78ae2e8becb98f01957",
|
||||
"reference": "4b392077e3d609fed564b78ae2e8becb98f01957",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"SapiStudio\\SeleniumStealth\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Sapistudio/SeleniumStealth/issues",
|
||||
"source": "https://github.com/Sapistudio/SeleniumStealth/tree/1.0.3"
|
||||
},
|
||||
"time": "2022-01-10T20:04:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
"version": "v3.5.0",
|
||||
|
||||
+8
-6
@@ -12,6 +12,8 @@ services:
|
||||
- API_CHROMEDRIVER=http://proxitok-chromedriver:9515
|
||||
# - API_VERIFYFP=verify_...
|
||||
# - API_DEVICE_ID=4586...
|
||||
labels:
|
||||
- "io.containers.autoupdate=registry"
|
||||
volumes:
|
||||
- proxitok-cache:/cache
|
||||
depends_on:
|
||||
@@ -30,17 +32,17 @@ services:
|
||||
# Redis, used for caching
|
||||
redis:
|
||||
container_name: proxitok-redis
|
||||
image: redis:7.4-alpine
|
||||
command: redis-server --save 60 1 --loglevel warning
|
||||
image: docker.io/library/redis:7.4-alpine
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "io.containers.autoupdate=registry"
|
||||
networks:
|
||||
- proxitok
|
||||
init: true
|
||||
user: nobody
|
||||
read_only: true
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
tmpfs:
|
||||
- /data:size=10M,mode=0770,uid=65534,gid=65534,noexec,nosuid,nodev
|
||||
cap_drop:
|
||||
- ALL
|
||||
# Chromedriver instance, used for sending requests to TikTok
|
||||
@@ -48,13 +50,13 @@ services:
|
||||
container_name: proxitok-chromedriver
|
||||
image: zenika/alpine-chrome:with-chromedriver
|
||||
init: true
|
||||
labels:
|
||||
- "io.containers.autoupdate=registry"
|
||||
shm_size: 1g
|
||||
networks:
|
||||
- proxitok
|
||||
security_opt:
|
||||
- seccomp:./misc/setup/docker/chrome.json
|
||||
ports:
|
||||
- 9515:9515
|
||||
volumes:
|
||||
proxitok-cache:
|
||||
|
||||
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
[
|
||||
{
|
||||
"clearnet": "https://proxitok.pabloferreiro.es/",
|
||||
"cdn": false,
|
||||
"country": "AT"
|
||||
},
|
||||
{
|
||||
"clearnet": "https://proxitok.pussthecat.org/",
|
||||
"cdn": false,
|
||||
"country": "DE"
|
||||
},
|
||||
{
|
||||
"clearnet": "https://proxitok.esmailelbob.xyz/",
|
||||
"tor": "http://proxitok.esmail5pdn24shtvieloeedh7ehz3nrwcdivnfhfcedl7gf4kwddhkqd.onion/",
|
||||
"cdn": false,
|
||||
"country": "CA"
|
||||
},
|
||||
{
|
||||
"clearnet": "https://proxitok.privacydev.net/",
|
||||
"tor": "http://proxitok.g4c3eya4clenolymqbpgwz3q3tawoxw56yhzk4vugqrl6dtu3ejvhjid.onion/",
|
||||
"cdn": false,
|
||||
"country": "FR"
|
||||
},
|
||||
{
|
||||
"clearnet": "https://tok.artemislena.eu/",
|
||||
"tor": "http://tok.lpoaj7z2zkajuhgnlltpeqh3zyq7wk2iyeggqaduhgxhyajtdt2j7wad.onion/",
|
||||
"cdn": false,
|
||||
"country": "DE"
|
||||
},
|
||||
{
|
||||
"clearnet": "https://tok.adminforge.de/",
|
||||
"cdn": false,
|
||||
"country": "DE"
|
||||
},
|
||||
{
|
||||
"clearnet": "https://tik.hostux.net/",
|
||||
"cdn": false,
|
||||
"country": "FR"
|
||||
},
|
||||
{
|
||||
"clearnet": "https://tt.vern.cc/",
|
||||
"tor": "http://tt.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion/",
|
||||
"i2p": "http://vern2gwxbtxzhb3rgchv4kbhlqppijhjqg7rmgvp4c5bxihxcm3a.b32.i2p/",
|
||||
"cdn": false,
|
||||
"country": "US"
|
||||
},
|
||||
{
|
||||
"clearnet": "https://cringe.whatever.social/",
|
||||
"cdn": false,
|
||||
"country": "US"
|
||||
},
|
||||
{
|
||||
"clearnet": "https://proxitok.lunar.icu/",
|
||||
"cdn": true,
|
||||
"country": "DE"
|
||||
},
|
||||
{
|
||||
"clearnet": "https://proxitok.privacy.com.de/",
|
||||
"cdn": false,
|
||||
"country": "DE"
|
||||
},
|
||||
{
|
||||
"clearnet": "https://cringe.whateveritworks.org/",
|
||||
"cdn": true,
|
||||
"country": "DE"
|
||||
},
|
||||
{
|
||||
"clearnet": "https://cringe.seitan-ayoub.lol/",
|
||||
"cdn": false,
|
||||
"country": "DE"
|
||||
},
|
||||
{
|
||||
"clearnet": "https://proxitok.kyun.li/",
|
||||
"cdn": false,
|
||||
"country": "RO"
|
||||
},
|
||||
{
|
||||
"clearnet": "https://cringe.datura.network/",
|
||||
"tor": "http://cringe.daturab6drmkhyeia4ch5gvfc2f3wgo6bhjrv3pz6n7kxmvoznlkq4yd.onion/",
|
||||
"cdn": false,
|
||||
"country": "DE"
|
||||
},
|
||||
{
|
||||
"clearnet": "https://tt.opnxng.com/",
|
||||
"cdn": false,
|
||||
"country": "SG"
|
||||
},
|
||||
{
|
||||
"clearnet": "https://proxitok.tinfoil-hat.net/",
|
||||
"cdn": false,
|
||||
"country": "DE"
|
||||
},
|
||||
{
|
||||
"clearnet": "https://tiktok.wpme.pl/",
|
||||
"cdn": true,
|
||||
"country": "DE"
|
||||
},
|
||||
{
|
||||
"clearnet": "https://proxitok.r4fo.com/",
|
||||
"tor": "http://proxitok.r4focoma7gu2zdwwcjjad47ysxt634lg73sxmdbkdozanwqslho5ohyd.onion/",
|
||||
"cdn": true,
|
||||
"country": "NL"
|
||||
},
|
||||
{
|
||||
"clearnet": "https://proxitok.belloworld.it/",
|
||||
"cdn": false,
|
||||
"country": "DE"
|
||||
},
|
||||
{
|
||||
"clearnet": "https://tok.habedieeh.re/",
|
||||
"tor": "http://tok.habeehrhadazsw3izbrbilqajalfyqqln54mrja3iwpqxgcuxnus7eid.onion/",
|
||||
"cdn": false,
|
||||
"country": "CA"
|
||||
},
|
||||
{
|
||||
"tor": "http://pt.skunky7dhv7nohsoalpwe3sxfz3fbkad7r3wk632riye25vqm3meqead.onion/",
|
||||
"i2p": "http://hm4d5t5jeycvraam3ptvmhlegfttjmxpxgl4lou2hibde7gzfsvq.b32.i2p/",
|
||||
"cdn": false
|
||||
}
|
||||
]
|
||||
@@ -72,6 +72,14 @@ $router->mount('/tag/([^/]+)', function () use ($router) {
|
||||
|
||||
$router->get('/music/([^/]+)', 'MusicController@get');
|
||||
|
||||
// For you
|
||||
$router->mount('/foryou', function () use ($router) {
|
||||
$router->get('/', 'ForYouController@get');
|
||||
$router->get('/rss', 'ForYouController@rss');
|
||||
});
|
||||
|
||||
$router->get('/following', 'FollowingController@get');
|
||||
|
||||
// -- Settings -- //
|
||||
$router->mount('/settings', function () use ($router) {
|
||||
$router->get('/', 'SettingsController@index');
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
{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 => !$feed->hasMore" class="button is-success" href="?cursor={$feed->maxCursor}">Next</a>
|
||||
<a n:attr="disabled => !$feed->hasMore" class="button is-success" href="?cursor={$feed->cursor}">Next</a>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +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>
|
||||
<a target="_blank" href="{url_download($downloadAddr, $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>
|
||||
<a target="_blank" href="{url_download($playAddr, $uniqueId, $id, false)}" class="button is-success">No watermark</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
{if isset($item->video->playAddr) && $item->video->playAddr !== ""}
|
||||
<!-- Download links, not shown if item is a gallery -->
|
||||
<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}
|
||||
{include './common/download.latte', id: $item->id, uniqueId: $item->author->uniqueId, playAddr: $item->video->playAddr, downloadAddr: isset($item->video->downloadAddr) ? $item->video->downloadAddr : $item->video->playAddr}
|
||||
{/if}
|
||||
<p class="has-text-centered"><b>Share link</b></p>
|
||||
{include './common/share.latte', uniqueId: $item->author->uniqueId, id: $item->id}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
{layout '../layouts/default.latte'}
|
||||
|
||||
{block header}
|
||||
<p class="title">Discover</p>
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
<div class="columns is-multiline is-vcentered">
|
||||
{foreach $feed->items as $item}
|
||||
<div class="column is-one-quarter">
|
||||
{embed '../components/card.latte'}
|
||||
{block content}
|
||||
<div class="media">
|
||||
<!-- Show image if exists -->
|
||||
{if !empty($item->info->detail->avatarLarger)}
|
||||
<div class="media-left">
|
||||
<figure class="image is-96x96">
|
||||
<img loading="lazy" width="96" height="96" src="{url_stream($item->info->detail->avatarLarger)}" />
|
||||
</figure>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="media-content">
|
||||
<p class="title">{$item->info->detail->nickname}</p>
|
||||
<p class="subtitle">{$item->info->detail->uniqueId}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>{$item->info->detail->signature}</p>
|
||||
</div>
|
||||
{/block}
|
||||
{block footer}
|
||||
<a href="{url_user($item->info->detail->uniqueId)}" class="card-footer-item">Go</a>
|
||||
{/block}
|
||||
{/embed}
|
||||
</div>
|
||||
{/foreach}
|
||||
</div>
|
||||
{include '../components/themes/common/controls.latte', feed: $feed}
|
||||
{/block}
|
||||
@@ -0,0 +1,12 @@
|
||||
{layout '../layouts/default.latte'}
|
||||
|
||||
{var $has_rss = true}
|
||||
|
||||
{block header}
|
||||
<p class="title">For you</p>
|
||||
<p class="subtitle">{include '../components/rss.latte'}</p>
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
{include '../components/feed.latte'}
|
||||
{/block}
|
||||
@@ -28,4 +28,14 @@
|
||||
</div>
|
||||
{/block}
|
||||
{/embed}
|
||||
<div class="columns is-centered is-mobile mt-2">
|
||||
<div class="column is-narrow">
|
||||
<p>For you</p>
|
||||
<a class="button is-success" href="{path('/foryou')}">Go</a>
|
||||
</div>
|
||||
<div class="column is-narrow">
|
||||
<p>Following</p>
|
||||
<a class="button is-success" href="{path('/following')}">Go</a>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
|
||||
@@ -31,7 +31,9 @@
|
||||
<p>Hearts: {number($info->stats->heartCount)} / Videos: {$info->stats->videoCount}</p>
|
||||
{embed '../components/details.latte', title: "Details"}
|
||||
{block content}
|
||||
<p>Region: {$info->detail->region}</p>
|
||||
{if isset($info->detail->region)}
|
||||
<p>Region: {$info->detail->region}</p>
|
||||
{/if}
|
||||
{if $info->detail->commerceUserInfo->commerceUser}
|
||||
<p>Category: {$info->detail->commerceUserInfo->category}</p>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user