Compare commits

...

164 Commits

Author SHA1 Message Date
Pablo Ferreiro ec611478e3 implemented following (AKA discover) & fyp using new endpoints
Docker / build (push) Has been cancelled
Create Tag / build (push) Has been cancelled
2024-08-28 14:34:02 +02:00
Pablo Ferreiro 96aa2803b2 bump scraper
Docker / build (push) Has been cancelled
Create Tag / build (push) Has been cancelled
2024-08-21 19:10:32 +02:00
Pablo Ferreiro 9f63fecc18 fixed null value on download 2024-08-21 13:30:56 +02:00
Pablo Ferreiro a27d6ca767 bump scraper 2024-08-21 13:24:40 +02:00
Pablo Ferreiro 2aab1bfe24 bump scraper 2024-08-21 13:09:06 +02:00
Pablo Ferreiro bc9ff0100e region may not show 2024-08-21 03:57:26 +02:00
Pablo Ferreiro c4f3a80c3e fixed error constructor 2024-08-21 03:30:52 +02:00
Pablo Ferreiro 3b441c2683 fixed undefined addr 2024-08-21 03:28:34 +02:00
Pablo Ferreiro 03002ba835 removed redis persist storage 2024-08-21 03:26:11 +02:00
Pablo Ferreiro 76d4a581f3 init redis and no need to expose chromedriver 2024-08-21 03:15:33 +02:00
Pablo Ferreiro 36d9902c73 bump 2024-08-21 03:03:13 +02:00
Pablo Ferreiro 98405545e7 controls using cursor 2024-08-21 02:35:42 +02:00
Pablo Ferreiro 9ac169d480 download fix 2024-08-21 02:05:38 +02:00
Pablo Ferreiro b63a0b2755 official instance now in austria 2024-08-21 01:39:46 +02:00
Pablo Ferreiro 1427a94810 Merge pull request #223 from yedayak/lite-short-url
Follow lite.tiktok.com, same as v[mt].tiktok.com
2024-08-21 00:35:21 +02:00
Pablo Ferreiro 547f8460b3 Merge pull request #205 from drizzt/podman-compatibility
Podman compatibility
2024-08-21 00:00:47 +02:00
Pablo Ferreiro 4610a89810 Merge branch 'master' into podman-compatibility 2024-08-21 00:00:28 +02:00
Pablo Ferreiro 70161ec0d6 Merge pull request #209 from jamesbrown8532/instances-list-json
Add instances list in JSON format
2024-08-20 23:55:00 +02:00
Pablo Ferreiro 2592f2087c bump scraper 2024-08-20 23:50:21 +02:00
Pablo Ferreiro a033682dfb breaking changes warning 2024-08-20 23:37:21 +02:00
Pablo Ferreiro 01c39fbc0e cosign bump 2024-08-20 23:29:29 +02:00
Pablo Ferreiro 086c206920 removed discover template 2024-08-20 23:27:42 +02:00
Pablo Ferreiro 672e752841 Merge pull request #224 from pablouser1/scraper_rewrite
v2.5.0.0: "Hopefully fixing the mess" edition (BREAKING CHANGES!)
2024-08-20 23:08:43 +02:00
Pablo Ferreiro 591bb2c726 fixed download issue 2024-08-20 22:49:24 +02:00
Pablo Ferreiro 4e49badfc4 bump 2024-08-20 22:40:25 +02:00
Pablo Ferreiro 5001bf0e91 docker comments 2024-08-20 22:33:43 +02:00
Pablo Ferreiro 71931971f7 removed trending and discover 2024-08-20 22:28:58 +02:00
Pablo Ferreiro f2e3475cb9 bump tikscraper 2024-08-20 22:28:21 +02:00
Pablo Ferreiro 9536d9e78a bump latte 2024-08-20 21:08:05 +02:00
Pablo Ferreiro 86fdeff56e removed discover and trending from home 2024-08-20 21:05:06 +02:00
Pablo Ferreiro bbbe6c2dba docker 2024-08-20 21:02:34 +02:00
Pablo Ferreiro f1f69533a8 reflect scraper changes 2024-08-20 20:13:43 +02:00
Yedaya Katsman 3eebeb0369 Follow lite.tiktok.com, same as v[mt].tiktok.com
Fixes https://github.com/pablouser1/ProxiTok/issues/222
2024-08-18 22:59:09 +03:00
Pablo Ferreiro 107ca2f9e2 cache change 2024-08-14 20:01:17 +02:00
jamesbrown8532 f203dca5a2 Fix typo in instances.json 2024-02-18 12:56:03 +00:00
jamesbrown8532 db1de45ee1 Remove duplicate entry 2024-02-18 01:41:45 +00:00
jamesbrown8532 fe80102212 Put Tor instance link in correct entry 2024-02-18 01:41:28 +00:00
jamesbrown8532 a99b8ebd54 Mention instances.json in README.md 2024-02-18 01:25:11 +00:00
jamesbrown8532 d33e9d119a Add instances list in JSON format 2024-02-18 01:23:41 +00:00
Pablo Ferreiro 358c6ad08f bump scraper 2024-02-13 18:46:17 +01:00
Timothy Redaelli 7c51b63660 Add io.containers.autoupdate to tell podman to auto update containers
See https://docs.podman.io/en/latest/markdown/podman-auto-update.1.html
for more informations
2024-01-25 18:48:21 +01:00
Timothy Redaelli 13e686bb5a Add the full image: path in docker-compose.yml 2024-01-25 18:35:58 +01:00
Timothy Redaelli 250bbedc1d Remove persistent storage from redis in docker-compose.yml
This is needed to restore podman-compose compatibility, since it doesn't
support uid and gid options in tmpfs, moreover it's quite silly to have
persistent storage on a tmpfs since /data is deleted when the container
is stopped.

Fixes: 48eccbc5ec ("harden docker-compose")
Cc: admin@nullnet.services
2024-01-25 18:35:58 +01:00
Pablo Ferreiro dd377a27be bump 2024-01-25 13:20:52 +01:00
Pablo Ferreiro 79454aa9e0 Merge pull request #187 from rystaf/user-avatar-rss
rss feed: include user avatar, use nickname for title and username for item creator.
2023-11-29 16:57:55 +00:00
Pablo Ferreiro 9f1e2c44e4 Merge pull request #191 from taivlam/patch-1
Fix typo in bug report template
2023-11-28 15:18:33 +00:00
taivlam 846ab1ccae Fix typo in bug_report.md
Missing "n" in the word "environment"
2023-10-30 18:11:04 -04:00
Ryan Stafford dfe22f6a18 use user nickname for rss title, and username for item creator 2023-10-10 14:42:30 -04:00
Ryan Stafford b85b1f4148 conform image tag to atom spec 2023-10-10 14:31:28 -04:00
Ryan Stafford a573ac1990 Include user avatar in rss feed 2023-10-10 13:47:53 -04:00
Pablo Ferreiro a3b4143ab1 Show debug info when TikTok gives error 2023-10-07 00:17:11 +02:00
Pablo Ferreiro 3ba64be202 avoid crash when using user id instead of username 2023-09-29 13:52:04 +02:00
Pablo Ferreiro 80f3ca4ebb Improved description extras 2023-09-29 13:31:31 +02:00
Pablo Ferreiro 200a6fc1f8 Some UI changes 2023-09-29 13:29:20 +02:00
Pablo Ferreiro c546ed406c hotfix 2023-09-27 14:17:28 +02:00
Pablo Ferreiro 7c333b1658 wrapper 2.4, changed PROXY config, docker php82 2023-09-27 13:24:27 +02:00
Pablo Ferreiro 9d9207b05e shut down signer (way) faster 2023-07-26 22:21:06 +02:00
Pablo Ferreiro 923d42c6c1 auto yes 2023-07-26 21:56:42 +02:00
Pablo Ferreiro 5ba084dae1 bump cosign and pin php-nginx version 2023-07-26 21:51:32 +02:00
Pablo Ferreiro 4f906ef801 new docker image 2023-07-26 21:41:37 +02:00
Pablo Ferreiro 15fdd41cad small changes to UI 2023-07-04 16:39:53 +02:00
Pablo Ferreiro 34623c8e43 hotfix 2023-06-12 18:57:05 +02:00
Pablo Ferreiro 629da5f357 Fixed more crashing issues 2023-06-12 15:20:51 +02:00
Pablo Ferreiro 4a59dab75c Docker updated to PHP8.2 2023-06-12 15:20:42 +02:00
Pablo Ferreiro 8c769d89d4 Fixed isAd crash 2023-06-12 15:08:02 +02:00
Pablo Ferreiro 19a2066fc2 changed keyword order 2023-04-27 20:23:23 +02:00
Pablo Ferreiro e43580f3f9 RSS TextExtra and Gallery support 2023-04-27 20:22:55 +02:00
Pablo Ferreiro b5d034437f fix multiple carousel in one page 2023-04-08 12:03:33 +02:00
Pablo Ferreiro 4e191922fe accept both desktop and mobile user agents scraper 2023-04-05 17:09:22 +02:00
Pablo Ferreiro d09830cc89 bump scraper 2023-04-03 16:24:51 +02:00
Pablo Ferreiro 3556fef036 commerce fix 2023-04-03 14:37:04 +02:00
Pablo Ferreiro 7e65da7fe9 fixes to ttag 2023-04-02 20:37:36 +02:00
Pablo Ferreiro 3bd6c553f4 bump 2023-04-02 20:18:10 +02:00
Pablo Ferreiro aadfeccab1 Added some details 2023-04-02 20:14:48 +02:00
Pablo Ferreiro 4188fcf064 Initial URLify of vid desc and profile 2023-04-02 19:55:04 +02:00
Pablo Ferreiro 9364a2e212 hotfix 2023-04-01 18:45:10 +02:00
Pablo Ferreiro e5d416f696 pictures using carousel 2023-04-01 17:09:12 +02:00
Pablo Ferreiro 98a9ec2b65 hotfix 2023-04-01 16:35:17 +02:00
Pablo Ferreiro 33c723d786 Pictures support 2023-04-01 15:48:27 +02:00
Pablo Ferreiro faee8d58f2 bump 2023-03-29 11:23:14 +02:00
Pablo Ferreiro 75e13bc7d2 Merge pull request #140 from NoPlagiarism/www_shortened
Fix https:// + www in redirections (fixes #139)
2023-03-29 09:05:36 +00:00
Pablo Ferreiro 08145ee90b Merge pull request #135 from kuanhulio/master
harden docker-compose
2023-03-29 09:04:10 +00:00
NoPlagiarism 6194324452 Fix https:// + www in redirections (#139) 2023-03-29 07:39:36 +05:00
Nullnet Services Administrator 48eccbc5ec harden docker-compose 2023-03-18 21:10:24 -05:00
Pablo Ferreiro cac97ff05e Initial comments support 2023-03-06 21:20:14 +01:00
Pablo Ferreiro eeaa8cdf1c Random User Agent generator 2023-03-05 13:18:34 +01:00
Pablo Ferreiro ecba96eaf4 Merge pull request #131 from chrisnovakovic/video-title
Set page title to video description in video view
2023-02-28 11:40:30 +00:00
Chris Novakovic 013feeb679 Set page title to video description in video view
If the upstream video has a description set, use it as the page title in
place of "Video" in the video view. This helps to disambiguate video
pages in the browser history.
2023-02-27 23:11:36 +00:00
Pablo Ferreiro bf86e0d36a Merge pull request #125 from samip5/configureable_user_agent
Ability to pass custom user agent to the scraper and ignore .git on Docker
2023-02-19 11:08:22 +00:00
Skyler Mäntysaari 72ea5d43fd Addressing PR comments about not using hardcoded string. 2023-02-17 22:32:36 +02:00
Skyler Mäntysaari 288f87504c Add .git to dockerignore
Otherwise bad things end up in container.
2023-02-16 02:26:25 +02:00
Skyler Mäntysaari 3d5890d821 Ability to pass own user agent to the scraper. 2023-02-08 12:59:17 +02:00
Pablo Ferreiro 5dea2468f8 Better handling of private accounts 2023-02-01 15:22:53 +01:00
Pablo Ferreiro e8ec0ab293 bump 2023-01-28 17:32:07 +01:00
Pablo Ferreiro 78fe44070c Fixed Trending and normalized Discover 2023-01-26 19:21:14 +01:00
Pablo Ferreiro 7d2f6e8fd6 bump scraper 2023-01-26 17:20:38 +01:00
Pablo Ferreiro 32d49954f9 hotfix 2023-01-25 21:10:47 +01:00
Pablo Ferreiro 5c770def41 better ui 2023-01-25 21:06:59 +01:00
Pablo Ferreiro d273b35e53 Added apcu caching method and bump 2023-01-25 15:56:23 +01:00
Pablo Ferreiro faf1dcee51 bump, video showing up 2023-01-25 15:18:46 +01:00
Pablo Ferreiro 89d9ad2f9c Mobile-friendly 2023-01-25 15:00:52 +01:00
Pablo Ferreiro 7ddf6f7738 bump cosign 2023-01-25 14:10:35 +01:00
Pablo Ferreiro 059bf7208a bump 2023-01-25 13:59:59 +01:00
Pablo Ferreiro d5858c39fd Fixed undefined vars 2022-12-27 16:58:03 +01:00
Pablo Ferreiro 76be343c13 Merge pull request #114 from TheFrenchGhosty/patch-1
Update the credits, deprecate my image
2022-12-27 14:37:27 +00:00
TheFrenchGhosty a7b0edf8fe Update the credits, deprecate my image 2022-12-21 17:37:23 +01:00
Pablo Ferreiro 73e9d7a1cd Dynamically generated manifest 2022-11-27 14:26:35 +01:00
Pablo Ferreiro 0224cd25eb Added url_tag 2022-11-27 00:05:11 +01:00
Pablo Ferreiro 215f984fe4 Properly implemented OG 2022-11-26 23:51:45 +01:00
Pablo Ferreiro ee6e8b0593 Revert "Added better og support"
This reverts commit fa3f1e0a7c.
2022-11-26 23:36:20 +01:00
Pablo Ferreiro fa3f1e0a7c Added better og support 2022-11-26 23:28:59 +01:00
Pablo Ferreiro ce5c9e016b Better profile pic resolution 2022-11-26 22:25:48 +01:00
Pablo Ferreiro 49fcc79f15 bump 2022-11-22 20:45:53 +01:00
Pablo Ferreiro b138f4bccc misc folder and date on /video 2022-11-18 16:48:51 +01:00
Pablo Ferreiro 94da0e46ac Internal fixes and cleanup 2022-11-04 20:08:19 +01:00
Pablo Ferreiro 1176bc35fe web manifest tweaks and .latte structure 2022-11-04 18:02:57 +01:00
Pablo Ferreiro 4bfc4c9434 revert SW 2022-11-04 17:41:22 +01:00
Pablo Ferreiro de85ba3e44 hotfix 2022-11-04 17:36:18 +01:00
Pablo Ferreiro 79fd699cee revert auto register sw 2022-11-04 17:25:14 +01:00
Pablo Ferreiro 8f83a27885 autoregister sw 2022-11-04 17:14:21 +01:00
Pablo Ferreiro cba59e66c7 WIP PWA support 2022-11-04 17:10:51 +01:00
Pablo Ferreiro c925ca2a41 bump cosign 2022-11-03 11:27:18 +01:00
Pablo Ferreiro 32ea8b6b12 Merge pull request #91 from chrisnovakovic/redirect-selective-urlencode
Redirect: URL-encode input term after processing input
2022-11-03 09:08:05 +00:00
Chris Novakovic 7d0df67ded Redirect: URL-encode input term after processing input
In the redirect controller, rather than URL-encoding the entire input
term before processing it, only URL-encode (the relevant parts of) it in
the URL that the redirect controller generates. This ensures that the
original input term can be pattern-matched appropriately.

Fixes #90.
2022-10-29 19:35:07 +01:00
Pablo Ferreiro 23583ef7ab Fixed issue with download filename 2022-10-24 20:53:59 +02:00
Pablo Ferreiro 6fafcdcd11 Added some icons and bump scraper 2022-10-24 20:38:31 +02:00
Pablo Ferreiro 5e1b009f75 Fixed no watermark download, added settings icon 2022-10-23 21:35:04 +02:00
Pablo Ferreiro 7aa869f567 Download services, scraper bump 2022-09-25 19:53:00 +02:00
Pablo Ferreiro c076ba65a6 Merge pull request #79 from j9d3it/patch-2
Example Redirector config change
2022-09-07 16:15:03 +02:00
j9d3it 2504ba6e93 Example Redirector config change
I changed the example Redirector config to use the new official instance instead of the old Heroku one.
2022-09-06 16:00:00 +09:00
Pablo Ferreiro 38557fafa6 Nicer error display 2022-09-03 14:01:03 +02:00
Pablo Ferreiro 96fb2fd428 Proxy support 2022-09-03 13:21:43 +02:00
Pablo Ferreiro af4d98b8dd Fixed rss item link 2022-09-03 12:59:36 +02:00
Pablo Ferreiro 40e5d45956 Merge pull request #71 from NoPlagiarism/vm_t_support
vt.tiktok.com + tiktok.com/t support in TikTok URL option
2022-09-03 00:17:03 +02:00
Pablo Ferreiro 2f20cf8c02 updated wrapper 2022-08-17 14:47:32 +02:00
NoPlagiarism aa2fff2b31 www, http, + /t/ fix 2022-08-16 03:03:48 +05:00
NoPlagiarism fbc9061b21 vt.tiktok.com + tiktok.com/t support 2022-08-16 02:30:08 +05:00
Pablo Ferreiro 67c080e5f4 Funding 2022-08-13 14:47:29 +02:00
Pablo Ferreiro 086c95ca71 Added public instance template 2022-08-13 13:32:46 +02:00
Pablo Ferreiro 931191bcaf Added issue templates 2022-08-13 13:28:16 +02:00
Pablo Ferreiro ebe5941fa2 temp favicon, updated scrapper and .env changes 2022-08-13 13:09:39 +02:00
Pablo Ferreiro 574ae51582 bump 2022-08-11 23:34:16 +02:00
Pablo Ferreiro 90a2d2ec28 Updated TikScrapper 2022-08-11 23:33:16 +02:00
Pablo Ferreiro 3880da35ea Merge pull request #63 from chrisnovakovic/tiktok-url
Accept TikTok URLs as search terms
2022-08-04 14:04:04 +02:00
Chris Novakovic 8d8fe43431 Add type declarations, fix function reference 2022-07-31 17:20:38 +01:00
Chris Novakovic e7ee03e3cc Accept TikTok URLs as search terms
On the home page, allow TikTok URLs to be entered as search terms for
the new category "TikTok URL", and redirect to a ProxiTok-compatible
URL when a valid one is entered.

Closes #58.
2022-07-27 00:49:14 +01:00
Pablo Ferreiro d0057e77e3 Fixing error message 2022-07-03 18:35:30 +02:00
Pablo Ferreiro d52dc8687f Some anti-crash fixes 2022-07-03 18:19:10 +02:00
Pablo Ferreiro bc3777d74c User now can use test endpoints 2022-06-28 20:41:51 +02:00
Pablo Ferreiro 9acc40618a enclosure removed 2022-06-28 18:54:03 +02:00
Pablo Ferreiro 5e33b93031 Merge pull request #56 from konopielko/master
Add video to the feed content
2022-06-28 18:45:53 +02:00
konopielko 76bfcbe34a Add video to the feed content 2022-06-21 20:18:07 +02:00
Pablo Ferreiro e2282f9dcc New TODOS 2022-06-16 11:47:42 +02:00
Pablo Ferreiro cfe3a0c51b Some anti crash patches 2022-06-16 11:22:43 +02:00
Pablo Ferreiro 3b0ed28ad9 Creation date on both themes 2022-06-12 13:17:56 +02:00
Pablo Ferreiro 9d37bc433d rss auto discovery 2022-06-12 12:50:41 +02:00
Pablo Ferreiro 26bde1e4a8 /t endpoint 2022-06-12 12:50:16 +02:00
Pablo Ferreiro 59029e48ad Added Heroku app.json 2022-06-05 17:34:18 +02:00
Pablo Ferreiro e12d26562d RIP Legacy Mode 2022-06-04 21:04:43 +02:00
Pablo Ferreiro bdba336d3c cosign update, allow docker deploy with Dockerfile 2022-06-04 20:21:42 +02:00
Pablo Ferreiro 578277d251 Added qemu action 2022-06-04 20:03:21 +02:00
Pablo Ferreiro 240b8d7540 Merge pull request #47 from alefvanoon/patch-1
add arm64 build
2022-06-04 19:56:44 +02:00
alefvanoon 08a28ffc3a add arm64 build 2022-06-04 11:38:23 +00:00
Pablo Ferreiro e1fbf75281 Fixed Video Cache and updated Latte 2022-06-02 11:18:16 +02:00
120 changed files with 3773 additions and 843 deletions
+5 -7
View File
@@ -1,8 +1,6 @@
node_modules
/.env
/.vscode
/vendor
/cache/latte/*
!/cache/latte/.gitkeep
/cache/api/*
!/cache/api/.gitkeep
.env
.git
.vscode
vendor
cache
+1 -1
View File
@@ -22,7 +22,7 @@ indent_style = space
indent_size = 4
[**.latte]
indent_style = tab
indent_style = space
indent_size = 2
[**.html]
+10 -7
View File
@@ -1,17 +1,20 @@
# APP_PATH="/proxitok" # Relative path, PLEASE LEAVE EMPTY IF /
# APP_URL="http://localhost:8000" # Absolute path to proxitok instance
# LATTE_CACHE=/tmp/proxitok_api # Path for Latte cache, leave commented for ./cache/latte
# API CONFIG
# API_FORCE_LEGACY=true # Force legacy mode for wrapper
# API_SIGNER_URL="https://example.com" # External signing service
# API_BROWSER_URL="http://localhost:4444" # chromedriver url
# API_TEST_ENDPOINTS=true # Discomment for usage of testing TikTok endpoints, may help sometimes
# API_CHROMEDRIVER=http://localhost:4444
# API_VERIFYFP=verify_...
# API_DEVICE_ID=586094...
# API_CACHE=redis
# Redis cache, used on Helpers\CacheEngines\RedisCache (CHOOSE ONE)
# Redis cache, used on App\Cache\RedisCache (CHOOSE ONE)
# REDIS_HOST=localhost # Host or path to unix socket
# REDIS_PORT=6379 # Set to -1 to use unix socket
# REDIS_PASSWORD=example # Leave commented for no password
# JSON cache, used on Helpers\CacheEngines\JSONCache
# JSON cache, used on App\Cache\JSONCache
# API_CACHE_JSON=/tmp/proxitok_api # Path for JSON API Cache, leave commented for ./cache/api
# PROXY="https://user:password@host:port" # Host to be used as proxy, make sure to type a valid protocol. Available: http:// | https:// | socks4:// | socks5://
# USER_AGENT="Mozilla/5.0 (Android 12; Mobile; rv:109.0) Gecko/109.0 Firefox/109.0"
+2
View File
@@ -0,0 +1,2 @@
liberapay: 'pablouser1'
custom: 'https://paypal.me/pablouser1'
+12
View File
@@ -0,0 +1,12 @@
---
name: Add my instance
about: Add public instance to the list
title: "[INSTANCES] New public instance"
labels: ''
assignees: ''
---
- URL: https://proxitok.example.com
- Cloudflare: Yes / No
- Country: Type the name of the country you are hosting the instance here
+35
View File
@@ -0,0 +1,35 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
Before submitting an issue, please make sure you are using the latest version of ProxiTok.
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Logs**
If applicable, add PHP logs to help explain the issue.
**Environment (please complete the following information):**
- Deployment method (if possible): [e.g docker, heroku, manual...]
- Frontend version: [e.g. 2.2.0.0]
- Scrapper version: [e.g. 2.4.0.0]
- PHP Version: [e.g. 8.0]
You can find the frontend and scrapper version on /about
+17
View File
@@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
+16 -8
View File
@@ -35,13 +35,16 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v3
- name: Setup QEMU
uses: docker/setup-qemu-action@v2
# Install the cosign tool except on PR
# https://github.com/sigstore/cosign-installer
- name: Install cosign
if: github.event_name != 'pull_request'
uses: sigstore/cosign-installer@v2.3.0
uses: sigstore/cosign-installer@v3.6.0
with:
cosign-release: 'v1.7.1'
cosign-release: 'v2.4.0'
# Workaround: https://github.com/docker/build-push-action/issues/461
@@ -68,14 +71,20 @@ jobs:
# Build and push Docker image with Buildx (don't push on PR)
# https://github.com/docker/build-push-action
- name: Set some variables for the image
run: |
echo "IMAGE_VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_ENV
echo "IMAGE_NAME=${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@v2
with:
context: .
platforms: linux/amd64
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
tags: |
ghcr.io/${{ env.IMAGE_NAME }}:latest
ghcr.io/${{ env.IMAGE_NAME }}:${{ env.IMAGE_VERSION }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
@@ -87,7 +96,6 @@ jobs:
- name: Sign the published Docker image
if: ${{ github.event_name != 'pull_request' }}
env:
COSIGN_EXPERIMENTAL: "true"
# This step uses the identity token to provision an ephemeral certificate
# against the sigstore community Fulcio instance.
run: cosign sign ${{ steps.meta.outputs.tags }}@${{ steps.build-and-push.outputs.digest }}
DIGEST: ${{ steps.build-and-push.outputs.digest }}
TAGS: ${{ steps.meta.outputs.tags }}
run: cosign sign --yes "${TAGS}@${DIGEST}"
+18 -20
View File
@@ -1,24 +1,22 @@
FROM php:8-apache
WORKDIR /var/www/html
FROM trafex/php-nginx:3.6.0
# Add composer
COPY --from=composer /usr/bin/composer /usr/bin/composer
RUN apt update -y && apt upgrade -y \
&& apt install -y --no-install-recommends libzip-dev \
&& pecl install redis zip \
&& docker-php-ext-enable redis zip \
&& a2enmod rewrite headers \
&& mkdir /cache \
&& chown -R www-data:www-data /cache \
&& rm -rf /var/www/html/*
# Copy project to /var/www/html
COPY . .
# Copy config
COPY ./misc/setup/docker/php.ini /etc/php83/conf.d/settings.ini
# Run composer and clean
RUN composer update --no-cache \
&& composer install --no-interaction --optimize-autoloader --no-dev --no-cache \
&& apt autoclean -y \
&& apt autoremove -y \
&& rm -rf /var/lib/apt/lists/* \
&& rm -rf /usr/bin/composer
USER root
# Create cache folder
RUN mkdir /cache && chown -R nobody:nogroup /cache
# Install deps
RUN apk add --no-cache php83-redis php83-zip php83-tokenizer
EXPOSE 80
USER nobody
# Copy source
COPY --chown=nobody . /var/www/html
# Dependencies
RUN composer install --no-interaction --optimize-autoloader --no-dev --no-cache
EXPOSE 8080
+1 -1
View File
@@ -1 +1 @@
web: vendor/bin/heroku-php-nginx -C setup/nginx_heroku.conf
web: vendor/bin/heroku-php-nginx -C misc/setup/heroku/nginx.conf
+16 -6
View File
@@ -1,14 +1,16 @@
# 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
* See trending and discovery tab
* See tags
* See video by id
* Themes
* RSS Feed for user, trending and tag (just add /rss to the url)
* RSS Feed for user and tag (just add /rss to the url)
## Self-hosting
Please check [this](https://github.com/pablouser1/ProxiTok/wiki/Self-hosting) wiki article for info on how to self-host your own instance
@@ -16,28 +18,36 @@ 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)
* [Redirector](https://github.com/einaregilsson/Redirector)
You can use the following config if you want to use Redirector (you can change https://proxitok.herokuapp.com with whatever instance you want to use):
You can use the following config if you want to use Redirector (you can change https://proxitok.pabloferreiro.es with whatever instance you want to use):
```
Description: TikTok to ProxiTok
Example URL: https://www.tiktok.com/@tiktok
Include pattern: (.*//.*)(tiktok.com)(.*)
Redirect to: https://proxitok.herokuapp.com$3
Example result: https://proxitok.herokuapp.com/@tiktok
Redirect to: https://proxitok.pabloferreiro.es$3
Example result: https://proxitok.pabloferreiro.es/@tiktok
Pattern type: Regular Expression
Apply to: Main window (address bar)
```
## TODO / Known issues
* Fix Heroku, still using old signer method
* Replace placeholder favicon
* Make video on /video fit screen and don't overflow
* Fix embed styling
* Fix crash when invalid vm.tiktok.com/CODE or www.tiktok.com/t/CODE is provided
* 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.
* [Jennifer Wjertzoch](https://wjertzochjennifer.medium.com): Carousel CSS Implementation
### External libraries
* [TikScraperPHP](https://github.com/pablouser1/TikScraperPHP)
* [Latte](https://github.com/nette/latte)
Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

+43
View File
@@ -0,0 +1,43 @@
{
"name": "ProxiTok",
"description": "Open source alternative frontend for TikTok",
"keywords": [
"php",
"tiktok",
"alternative-frontends"
],
"website": "https://github.com/pablouser1/ProxiTok",
"repository": "https://github.com/pablouser1/ProxiTok",
"env": {
"APP_URL": {
"description": "Your instance url (example: https://proxitok.herokuapp.com)"
},
"API_CACHE": {
"description": "Cache system in use",
"value": "redis"
},
"LATTE_CACHE": {
"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"
}
},
"addons": [
{
"plan": "heroku-redis:hobby-dev",
"as": "REDIS"
}
],
"buildpacks": [
{
"url": "heroku/php"
}
]
}
+25
View File
@@ -0,0 +1,25 @@
<?php
namespace App\Cache;
use TikScraper\Interfaces\ICache;
class ApcuCache implements ICache {
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, int $timeout = 3600): void {
apcu_store($cache_key, $data, $timeout);
}
}
+4 -2
View File
@@ -1,7 +1,9 @@
<?php
namespace App\Cache;
class JSONCache {
use TikScraper\Interfaces\ICache;
class JSONCache implements ICache {
private string $cache_path = __DIR__ . '/../../cache/api';
function __construct() {
@@ -24,7 +26,7 @@ class JSONCache {
return is_file($filename);
}
public function set(string $cache_key, mixed $data, $timeout = 3600) {
public function set(string $cache_key, string $data, int $timeout = 3600) {
file_put_contents($this->cache_path . '/' . $cache_key . '.json', $data);
}
}
+5 -6
View File
@@ -1,7 +1,9 @@
<?php
namespace App\Cache;
class RedisCache {
use TikScraper\Interfaces\ICache;
class RedisCache implements ICache {
private \Redis $client;
function __construct(string $host, int $port, ?string $password) {
$this->client = new \Redis();
@@ -21,17 +23,14 @@ class RedisCache {
public function get(string $cache_key): ?object {
$data = $this->client->get($cache_key);
if ($data) {
return json_decode($data);
}
return null;
return $data ? json_decode($data) : null;
}
public function exists(string $cache_key): bool {
return $this->client->exists($cache_key);
}
public function set(string $cache_key, string $data, $timeout = 3600) {
public function set(string $cache_key, string $data, int $timeout = 3600) {
$this->client->set($cache_key, $data, $timeout);
}
}
+8
View File
@@ -0,0 +1,8 @@
<?php
namespace App\Constants;
abstract class CacheMethods {
const JSON = 'json';
const APCU = 'apcu';
const REDIS = 'redis';
}
+7
View File
@@ -0,0 +1,7 @@
<?php
namespace App\Constants;
abstract class TextExtras {
const USER = 0;
const HASHTAG = 1;
}
+7
View File
@@ -0,0 +1,7 @@
<?php
namespace App\Constants;
abstract class Themes {
const DEFAULT = "default";
const CARD = "card";
}
-20
View File
@@ -1,20 +0,0 @@
<?php
namespace App\Controllers;
use App\Helpers\ErrorHandler;
use App\Helpers\Misc;
use App\Helpers\Wrappers;
use App\Models\FeedTemplate;
class DiscoverController {
static public function get() {
$api = Wrappers::api();
$feed = $api->discover();
if ($feed->meta->success) {
$latte = Wrappers::latte();
$latte->render(Misc::getView('discover'), new FeedTemplate('Discover', $feed));
} else {
ErrorHandler::show($feed->meta);
}
}
}
+8 -7
View File
@@ -2,19 +2,20 @@
namespace App\Controllers;
use App\Helpers\ErrorHandler;
use App\Helpers\Misc;
use App\Helpers\Wrappers;
use App\Models\VideoTemplate;
class EmbedController {
static public function v2(int $id) {
public static function v2(int $id) {
$api = Wrappers::api();
$feed = $api->getVideoByID($id);
if ($feed->meta->success) {
$latte = Wrappers::latte();
$latte->render(Misc::getView('video'), new VideoTemplate($feed->items[0], $feed->info->detail, true));
$video = $api->video($id);
$video->feed();
if ($video->ok()) {
$item = $video->getFeed()->items[0];
$info = $video->getInfo();
Wrappers::latte('video', new VideoTemplate($item, $info, true));
} else {
ErrorHandler::show($feed->meta);
ErrorHandler::showMeta($video->error());
}
}
}
+23
View File
@@ -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());
}
}
}
+33
View File
@@ -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));
}
}
}
+5 -5
View File
@@ -7,18 +7,18 @@ use App\Helpers\Wrappers;
use App\Models\FullTemplate;
class MusicController {
static public function get(string $music_id) {
public static function get(string $music_id) {
$cursor = Misc::getCursor();
$api = Wrappers::api();
$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::show($music->error());
ErrorHandler::showMeta($music->error());
}
}
}
+36 -33
View File
@@ -1,25 +1,54 @@
<?php
namespace App\Controllers;
use App\Helpers\Cookies;
use App\Helpers\Misc;
class ProxyController {
const VALID_TIKTOK_DOMAINS = [
"tiktokcdn.com", "tiktokcdn-us.com", "tiktok.com"
];
static private function isValidDomain(string $url) {
public static function stream() {
self::checkUrl();
$url = $_GET['url'];
$options = Misc::getScraperOptions();
$streamer = new \TikScraper\Stream($options);
$streamer->url($url);
}
public static function download() {
self::checkUrl();
$method = Cookies::downloader();
$downloader = new \TikScraper\Download($method, Misc::getScraperOptions());
// Params
$id = $_GET['id'] ?? '';
$watermark = isset($_GET['watermark']);
$url = $_GET['url'];
$user = $_GET['user'] ?? '';
// Filename
$filename = self::getFilename($id, $user);
// Running
$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
return in_array($host_split[0] . '.' . $host_split[1], self::VALID_TIKTOK_DOMAINS);
$valid = 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);
$valid = in_array($host_split[1] . '.' . $host_split[2], self::VALID_TIKTOK_DOMAINS);
}
return false;
return $valid;
}
static private function checkUrl() {
static private function checkUrl(): void {
if (!isset($_GET['url'])) {
die('You need to send a URL');
}
@@ -30,34 +59,8 @@ class ProxyController {
}
static private function getFileName(): string {
$filename = 'tiktok-video';
if (isset($_GET['user'])) {
$filename .= '-' . $_GET['user'] . '-' . $_GET['id'];
}
static private function getFilename(string $id, string $user): string {
$filename = 'tiktok-video-' . $id . '-' . $user;
return $filename;
}
static public function stream() {
self::checkUrl();
$url = $_GET['url'];
$streamer = new \TikScraper\Stream();
$streamer->url($url);
}
static public function download() {
$downloader = new \TikScraper\Download();
$watermark = isset($_GET['watermark']);
if ($watermark) {
self::checkUrl();
$filename = self::getFileName();
$downloader->url($_GET['url'], $filename, true);
} else {
if (!isset($_GET['id'])) {
die('You need to send an ID!');
}
$filename = self::getFileName();
$downloader->url($_GET['id'], $filename, false);
}
}
}
+61 -5
View File
@@ -1,37 +1,46 @@
<?php
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() {
public static function search() {
$endpoint = '/';
if (isset($_GET['type'], $_GET['term'])) {
$term = trim($_GET['term']);
switch ($_GET['type']) {
case 'url':
$endpoint = self::to_endpoint($term);
if (!$endpoint) {
ErrorHandler::showText(400, 'Invalid TikTok URL');
return;
}
break;
case 'user':
// Remove @ if sent
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;
}
}
@@ -39,4 +48,51 @@ class RedirectController {
$url = Misc::url($endpoint);
header("Location: {$url}");
}
public static 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.
*/
static private function to_endpoint(string $url): string {
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)) {
// Username component (which may indicate a user profile URL or a video URL)
if (preg_match('%^(@[A-Za-z0-9_.]+)(?:/|$)(.*)%', $m[1], $u)) {
if ($u[2] == '') {
// User profile URL
return '/' . urlencode($u[1]);
} elseif (preg_match('%^video/(\d+)%', $u[2], $v)) {
// Video URL
return '/' . urlencode($u[1]) . '/video/' . urlencode($v[1]);
}
} elseif (preg_match('%^tag/([^ ]+?)(?:/|$)%', $m[1], $t)) {
// Tag URL
return '/tag/' . urlencode($t[1]);
} elseif (preg_match('%^music/([^ ]+?)(?:/|$)%', $m[1], $m)) {
// Music URL
return '/music/' . urlencode($m[1]);
}
}
return '';
}
}
+15 -14
View File
@@ -4,31 +4,32 @@ namespace App\Controllers;
use App\Helpers\Misc;
use App\Helpers\Cookies;
use App\Helpers\Wrappers;
use App\Models\BaseTemplate;
use App\Models\SettingsTemplate;
class SettingsController {
static public function index() {
$latte = Wrappers::latte();
$latte->render(Misc::getView('settings'), new BaseTemplate('Settings'));
public static function index() {
Wrappers::latte('settings', new SettingsTemplate());
}
static private function redirect() {
$url = Misc::url('/settings');
header("Location: {$url}");
}
static public function general() {
public static function general() {
if (isset($_POST['theme'])) {
$theme = $_POST['theme'];
Cookies::set('theme', $theme);
}
self::redirect();
}
static public function api() {
if (isset($_POST['api-legacy'])) {
$legacy = $_POST['api-legacy'];
public static function api() {
// TODO, ADD COUNT
if (isset($_POST['api-downloader'])) {
$downloader = $_POST['api-downloader'];
Cookies::set("api-downloader", $downloader);
}
Cookies::set('api-legacy', $legacy);
self::redirect();
}
static private function redirect() {
$url = Misc::url('/settings');
header("Location: {$url}");
}
}
+9 -8
View File
@@ -3,33 +3,34 @@ 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;
class TagController {
static public function get(string $name) {
public static function get(string $name) {
$cursor = Misc::getCursor();
$api = Wrappers::api();
$hashtag = $api->hashtag($name);
$hashtag->feed($cursor);
if ($hashtag->ok()) {
$data = $hashtag->getFull();
$latte = Wrappers::latte();
$latte->render(Misc::getView('tag'), new FullTemplate('Tag', $data));
$info = $hashtag->getInfo();
$feed = $hashtag->getFeed();
Wrappers::latte('tag', new FullTemplate($info->detail->title, $info, $feed));
} else {
ErrorHandler::show($hashtag->error());
ErrorHandler::showMeta($hashtag->error());
}
}
static public function rss(string $name) {
public static function rss(string $name) {
$api = Wrappers::api();
$hashtag = $api->hashtag($name);
$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));
}
}
}
-43
View File
@@ -1,43 +0,0 @@
<?php
namespace App\Controllers;
use App\Helpers\Misc;
use App\Models\FeedTemplate;
use App\Helpers\ErrorHandler;
use App\Helpers\Wrappers;
use App\Models\RSSTemplate;
class TrendingController {
static public function get() {
$api = Wrappers::api();
// Ttwid if standard, cursor if legacy
if ($api->isLegacy()) {
$cursor = Misc::getCursor();
} else {
$cursor = Misc::getTtwid();
}
$trending = $api->trending();
$trending->feed($cursor);
$feed = $trending->getFeed();
if ($feed && $feed->meta->success) {
$latte = Wrappers::latte();
$latte->render(Misc::getView('trending'), new FeedTemplate('Trending', $feed));
} else {
ErrorHandler::show($trending->error());
}
}
static public function rss() {
$api = Wrappers::api();
$trending = $api->trending();
$trending->feed();
$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));
}
}
}
+14 -18
View File
@@ -3,52 +3,48 @@ 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;
use App\Models\VideoTemplate;
class UserController {
static public function get(string $username) {
public static function get(string $username) {
$cursor = Misc::getCursor();
$api = Wrappers::api();
$user = $api->user($username);
$user->feed($cursor);
if ($user->ok()) {
$data = $user->getFull();
if ($data->info->detail->privateAccount) {
http_response_code(403);
echo 'Private account detected! Not supported';
exit;
}
$latte = Wrappers::latte();
$latte->render(Misc::getView('user'), new FullTemplate($data->info->detail->nickname, $data));
$info = $user->getInfo();
$feed = $user->getFeed();
Wrappers::latte('user', new FullTemplate($info->detail->nickname, $info, $feed));
} else {
ErrorHandler::show($user->error());
ErrorHandler::showMeta($user->error());
}
}
static public function video(string $username, string $video_id) {
public static function video(string $username, string $video_id) {
$api = Wrappers::api();
$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::show($video->error());
ErrorHandler::showMeta($video->error());
}
}
static public function rss(string $username) {
public static function rss(string $username) {
$api = Wrappers::api();
$user = $api->user($username);
$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($data->info->detail->nickname, $data->info->detail->signature, UrlBuilder::stream($data->info->detail->avatarLarger), UrlBuilder::user($username), $data->feed->items));
}
}
}
+1 -4
View File
@@ -1,11 +1,8 @@
<?php
namespace App\Controllers;
/**
* @deprecated Please use UserController::video instead
*/
class VideoController {
static public function get(string $video_id) {
public static function get(string $video_id) {
UserController::video('placeholder', $video_id);
}
}
+18 -7
View File
@@ -1,29 +1,40 @@
<?php
namespace App\Helpers;
class Cookies {
const ALLOWED_THEMES = ['default', 'card'];
use App\Constants\Themes;
static public function get(string $name, string $default_value = ''): string {
class Cookies {
public static function get(string $name, string $default_value = ''): string {
if (isset($_COOKIE[$name]) && !empty($_COOKIE[$name])) {
return $_COOKIE[$name];
}
return $default_value;
}
static public function theme(): string {
public static function theme(): string {
$theme = self::get('theme');
if ($theme && in_array($theme, self::ALLOWED_THEMES)) {
$ref = new \ReflectionClass(Themes::class);
$themes = $ref->getConstants();
if ($theme && in_array($theme, $themes)) {
return $theme;
}
return 'default';
}
static public function exists(string $name): bool {
public static function downloader(): string {
$downloader = self::get('api-downloader', 'default');
return $downloader;
}
public static function exists(string $name): bool {
return isset($_COOKIE[$name]);
}
static public function set(string $name, string $value) {
public static function check(string $name, string $value): bool {
return self::exists($name) && $_COOKIE[$name] === $value;
}
public static function set(string $name, string $value) {
setcookie($name, $value, time()+60*60*24*30, '/', '', isset($_SERVER['HTTPS']), true);
}
};
+8 -4
View File
@@ -5,9 +5,13 @@ use App\Models\ErrorTemplate;
use TikScraper\Models\Meta;
class ErrorHandler {
static public function show(Meta $meta) {
http_response_code($meta->http_code);
$latte = Wrappers::latte();
$latte->render(Misc::getView('error'), new ErrorTemplate($meta));
public static function showMeta(Meta $meta) {
http_response_code($meta->httpCode);
Wrappers::latte('error', new ErrorTemplate($meta->httpCode, $meta->proxitokMsg, $meta->proxitokCode, $meta->response));
}
public static function showText(int $code, string $msg) {
http_response_code($code);
Wrappers::latte('error', new ErrorTemplate($code, $msg, null, null));
}
}
+41 -6
View File
@@ -2,26 +2,61 @@
namespace App\Helpers;
class Misc {
static public function getCursor(): int {
public static function getCursor(): int {
return isset($_GET['cursor']) && is_numeric($_GET['cursor']) ? (int) $_GET['cursor'] : 0;
}
static public function getTtwid(): string {
public static function getTtwid(): string {
return isset($_GET['cursor']) ? $_GET['cursor'] : '';
}
static public function url(string $endpoint = ''): string {
public static function url(string $endpoint = ''): string {
return self::env('APP_URL', '') . $endpoint;
}
static public function env(string $key, $default_value) {
public static function env(string $key, $default_value) {
return $_ENV[$key] ?? $default_value;
}
/**
* Returns absolute path for view
*/
static public function getView(string $template): string {
return __DIR__ . "/../../views/{$template}.latte";
public static function getView(string $template): string {
return __DIR__ . "/../../templates/views/{$template}.latte";
}
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
],
'verify_fp' => $verifyFp,
'device_id' => $device_id,
'user_agent' => $ua
];
$proxy = Misc::env('PROXY', '');
if ($proxy !== '') {
$options['proxy'] = $proxy;
}
return $options;
}
/**
* Common method for rss feeds
*/
public static function rss(string $title) {
header('Content-Type: application/rss+xml');
header('Content-Disposition: attachment; filename="' . $title . '.rss' . '"');
}
}
+30
View File
@@ -0,0 +1,30 @@
<?php
namespace App\Helpers;
class UrlBuilder {
public static function stream(string $url): string {
return Misc::url('/stream?url=' . urlencode($url));
}
public static 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;
}
public static function user(string $username): string {
return Misc::url('/@' . $username);
}
public static function tag(string $tag): string {
return Misc::url('/tag/' . $tag);
}
public static function video_internal(string $username, string $id): string {
return Misc::url('/@' . $username . "/video/" . $id);
}
public static function video_external(string $username, string $id): string {
return "https://www.tiktok.com/@" . $username . "/video/" . $id;
}
}
+97 -22
View File
@@ -1,14 +1,18 @@
<?php
namespace App\Helpers;
use App\Cache\ApcuCache;
use App\Cache\JSONCache;
use App\Cache\RedisCache;
use App\Constants\CacheMethods;
use App\Constants\TextExtras;
use App\Models\BaseTemplate;
class Wrappers {
/**
* Setup of Latte template engine
*/
static public function latte(): \Latte\Engine {
public static function latte(string $template, BaseTemplate $base) {
$latte = new \Latte\Engine;
$cache_path = Misc::env('LATTE_CACHE', __DIR__ . '/../../cache/latte');
$latte->setTempDirectory($cache_path);
@@ -18,13 +22,40 @@ class Wrappers {
$latte->addFunction('path', function (string $endpoint = ''): string {
return Misc::url($endpoint);
});
// Version being used
$latte->addFunction('version', function (): string {
return \Composer\InstalledVersions::getVersion('pablouser1/proxitok');
// Static assets
$latte->addFunction('assets', 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 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');
});
$latte->addFunction('version_scraper', function (): string {
return \Composer\InstalledVersions::getVersion('pablouser1/tikscraper');
});
// https://stackoverflow.com/a/36365553
$latte->addFunction('number', function (float $x) {
if($x > 1000) {
@@ -39,29 +70,75 @@ 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->addFunction('bool_to_str', function (bool $cond): string {
return $cond ? 'yes' : 'no';
});
// Add URLs to video descriptions
$latte->addFunction('render_desc', function (string $desc, array $textExtras = []): string {
$sanitizedDesc = htmlspecialchars($desc);
$out = $sanitizedDesc;
foreach ($textExtras as $extra) {
$url = '';
// We do -1 to also take the # or @
$text = mb_substr($desc, $extra->start - 1, $extra->end - $extra->start, 'UTF-8');
switch ($extra->type) {
// User URL
case TextExtras::USER:
$url = UrlBuilder::user(htmlspecialchars($extra->userUniqueId));
break;
// Hashtag URL
case TextExtras::HASHTAG:
$url = UrlBuilder::tag(htmlspecialchars($extra->hashtagName));
break;
}
// We do \b to avoid non-strict matches ('#hi' would match with '#hii' and we don't want that)
$out = preg_replace("/$text\b/", "<a href=\"$url\">$text</a>", $out);
}
return $out;
});
$latte->render(Misc::getView($template), $base);
}
/**
* Setup of TikTok Api wrapper
*/
static public function api(): \TikScraper\Api {
$options = [
'use_test_endpoints' => Misc::env('API_TEST_ENDPOINTS', false),
'signer' => [
'remote_url' => Misc::env('API_SIGNER_URL', ''),
'browser_url' => Misc::env('API_BROWSER_URL', ''),
'close_when_done' => false
]
];
public static function api(): \TikScraper\Api {
$options = Misc::getScraperOptions();
// Cache config
$cacheEngine = false;
$cacheEngine = null;
if (isset($_ENV['API_CACHE'])) {
switch ($_ENV['API_CACHE']) {
case 'json':
case CacheMethods::JSON:
$cacheEngine = new JSONCache();
break;
case 'redis':
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!');
}
@@ -73,16 +150,14 @@ class Wrappers {
$password = $url['pass'] ?? null;
} else {
$host = $_ENV['REDIS_HOST'];
$port = (int) $_ENV['REDIS_PORT'];
$password = isset($_ENV['REDIS_PASSWORD']) ? $_ENV['REDIS_PASSWORD'] : null;
$port = intval($_ENV['REDIS_PORT']);
$password = $_ENV['REDIS_PASSWORD'] ?? null;
}
$cacheEngine = new RedisCache($host, $port, $password);
break;
}
}
// Legacy mode
$legacy = Misc::env('API_FORCE_LEGACY', false) || isset($_COOKIE['api-legacy']) && $_COOKIE['api-legacy'] === 'on';
return new \TikScraper\Api($options, $legacy, $cacheEngine);
return new \TikScraper\Api($options, $cacheEngine);
}
}
-1
View File
@@ -6,7 +6,6 @@ namespace App\Models;
*/
class BaseTemplate {
public string $title;
public string $version;
function __construct(string $title) {
$this->title = $title;
+12 -5
View File
@@ -1,13 +1,20 @@
<?php
namespace App\Models;
use TikScraper\Models\Meta;
use TikScraper\Models\Response;
class ErrorTemplate extends BaseTemplate {
public Meta $error;
public int $http_code = 502;
public ?int $tiktok_code = -1;
public string $msg = '';
function __construct(object $error) {
public ?Response $response = null;
function __construct(int $http_code, string $msg, ?int $tiktok_code, ?Response $response) {
parent::__construct('Error');
$this->error = $error;
$this->http_code = $http_code;
$this->msg = $msg;
$this->tiktok_code = $tiktok_code;
$this->response = $response;
}
}
+5 -5
View File
@@ -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;
}
}
+7 -4
View File
@@ -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;
}
}
+5 -7
View File
@@ -1,18 +1,16 @@
<?php
namespace App\Models;
/**
* Base for templates with a feed
*/
class RSSTemplate {
public string $title;
class RSSTemplate extends BaseTemplate {
public string $desc;
public string $image;
public string $link;
public array $items;
function __construct(string $title, string $desc, string $link, array $items) {
$this->title = $title;
function __construct(string $title, string $desc, string $image, string $link, array $items) {
parent::__construct($title);
$this->desc = $desc;
$this->image = $image;
$this->link = $link;
$this->items = $items;
}
+31
View File
@@ -0,0 +1,31 @@
<?php
namespace App\Models;
use App\Constants\Themes;
use App\Helpers\Cookies;
use TikScraper\Constants\DownloadMethods;
/**
* Settings model with all possible config items
*/
class SettingsTemplate extends BaseTemplate {
public array $downloaders = [];
public array $themes = [];
public string $currentDownloader;
public string $currentTheme;
public bool $isServiceWorker = false;
function __construct() {
parent::__construct("Settings");
// Downloaders list
$ref = new \ReflectionClass(DownloadMethods::class);
$this->downloaders = $ref->getConstants();
// Themes list
$ref = new \ReflectionClass(Themes::class);
$this->themes = $ref->getConstants();
// Cookies data
$this->currentDownloader = Cookies::downloader();
$this->currentTheme = Cookies::theme();
$this->isServiceWorker = Cookies::check('misc-sw', 'yes');
}
}
+5 -3
View File
@@ -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 {
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

-11
View File
@@ -1,11 +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">
<meta property="og:title" content="ProxiTok" />
<meta property="og:description" content="Alternative frontend for TikTok" />
<meta property="og:type" content="website" />
<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>
-14
View File
@@ -1,14 +0,0 @@
{embed '../form.latte', path: '/settings/api', method: 'POST', submit: true}
{block fields}
<div class="field">
<label class="label">Legacy mode</label>
<div class="select">
<select name="api-legacy">
<option hidden disabled selected value> -- Select an option -- </option>
<option value="on">On</option>
<option value="off">Off</option>
</select>
</div>
</div>
{/block}
{/embed}
-14
View File
@@ -1,14 +0,0 @@
{embed '../form.latte', path: '/settings/general', method: 'POST', submit: true}
{block fields}
<div class="field">
<label class="label">Theme</label>
<div class="select">
<select name="theme">
<option hidden disabled selected value> -- Select an option -- </option>
<option value="default">Default</option>
<option value="card">Card</option>
</select>
</div>
</div>
{/block}
{/embed}
-8
View File
@@ -1,8 +0,0 @@
<div n:ifset="$data->info" 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>
<a class="button is-danger" href="?cursor={$data->feed->minCursor}">Back</a>
{/if}
<a n:attr="disabled => !$data->feed->hasMore" class="button is-success" href="?cursor={$data->feed->maxCursor}">Next</a>
</div>
-13
View File
@@ -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="{path('/download?url=' . urlencode($playAddr) . '&id=' . $id . '&user=' . $uniqueId) . '&watermark=1'}" class="dropdown-item">Watermark</a>
<a target="_blank" href="{path('/download?id=' . $id . '&user=' . $uniqueId)}" class="dropdown-item">No watermark</a>
</div>
</div>
</div>
-5
View File
@@ -1,5 +0,0 @@
{do $endpoint = '/@' . $uniqueId . '/video/' . $id}
<div class="buttons is-centered">
<a class="button is-success is-small" href="{path($endpoint)}">Instance Link</a>
<a class="button is-danger is-small" href="https://www.tiktok.com{$endpoint}">Original Link</a>
</div>
-5
View File
@@ -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>
-36
View File
@@ -1,36 +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="{path('/stream?url=' . urlencode($item->author->avatarThumb))}" />
</p>
</figure>
<div class="media-content">
<div class="content">
<p>
<strong>{$item->author->nickname}</strong> <small><a href="{path('/@' . $item->author->uniqueId)}">@{$item->author->uniqueId}</a></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="{path('/stream?url=' . urlencode($item->video->originCover))}">
<source src="{path('/stream?url=' . $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'}
+9 -7
View File
@@ -1,7 +1,7 @@
{
"name": "pablouser1/proxitok",
"description": "An alternative frontend for TikTok",
"version": "2.3.0.1",
"version": "2.5.0.0",
"license": "AGPL-3.0-or-later",
"type": "project",
"authors": [
@@ -14,17 +14,19 @@
"config": {
"optimize-autoloader": true,
"platform": {
"php": "7.4"
"php": "8.1"
}
},
"require": {
"php": ">=7.4|^8.0",
"ext-redis": "^5.3.2",
"php": "^8.1",
"ext-mbstring": "*",
"latte/latte": "^2.11",
"latte/latte": "^3.0",
"bramus/router": "^1.6",
"josegonzalez/dotenv": "dev-master",
"pablouser1/tikscraper": "^2.0"
"pablouser1/tikscraper": "^2.6",
"josegonzalez/dotenv": "^4.0"
},
"suggest": {
"ext-redis": "For using redis as a caching engine"
},
"autoload": {
"psr-4": {
Generated
+648 -166
View File
File diff suppressed because it is too large Load Diff
+45 -10
View File
@@ -1,29 +1,64 @@
version: '3'
services:
web:
container_name: proxitok-web
image: ghcr.io/pablouser1/proxitok:master
ports:
- 8080:80
- 8080:8080
environment:
- LATTE_CACHE=/cache
- API_CACHE=redis
- REDIS_HOST=proxitok-redis
- REDIS_PORT=6379
- API_SIGNER_URL=http://proxitok-signer:8080/signature
- API_CHROMEDRIVER=http://proxitok-chromedriver:9515
# - API_VERIFYFP=verify_...
# - API_DEVICE_ID=4586...
labels:
- "io.containers.autoupdate=registry"
volumes:
- proxitok-cache:/cache
depends_on:
- redis
- signer
- chromedriver
networks:
- proxitok
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
# Redis, used for caching
redis:
container_name: proxitok-redis
image: redis:7-alpine
command: redis-server --save 60 1 --loglevel warning
image: docker.io/library/redis:7.4-alpine
restart: unless-stopped
signer:
container_name: proxitok-signer
image: ghcr.io/pablouser1/signtok:master
labels:
- "io.containers.autoupdate=registry"
networks:
- proxitok
init: true
user: nobody
read_only: true
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
# Chromedriver instance, used for sending requests to TikTok
chromedriver:
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
volumes:
proxitok-cache:
networks:
proxitok:
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

+120
View File
@@ -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
}
]
+11
View File
@@ -0,0 +1,11 @@
This facilities making the compressed bulma.min.css and cssgg.min.css files, install all dependencies using:
```
yarn install
```
And then use:
```
yarn bulma && yarn cssgg
```
This compiles bulma.scss and cssgg.scss to a css file and helps lowering the size of the css that will be sent to the user.
+3
View File
@@ -10,8 +10,10 @@ $bulmaswatch-import-font: false;
@import "./node_modules/bulma/sass/base/_all.sass";
// Elements
@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";
@@ -26,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";
+10
View File
@@ -1,7 +1,9 @@
@charset "utf-8";
// Common
@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";
@@ -13,3 +15,11 @@
@import "./node_modules/css.gg/icons/scss/comment.scss";
@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/check-o.scss";
@import "./node_modules/css.gg/icons/scss/tag.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 -2
View File
@@ -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",
+16 -16
View File
@@ -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"
@@ -48,9 +48,9 @@ bulmaswatch@^0.8.1:
fsevents "~2.3.2"
css.gg@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/css.gg/-/css.gg-2.0.0.tgz#1ba891092ceac58a2550540171c2d469a86b27b2"
integrity sha512-8qO59kSXLbewo7xaUM4eC8328MTdGmb8atpmw6PRzeDGsZrCkAVjJzKeFDIntagl1/aCee+NG1OQtIvWAjgG/A==
version "2.1.1"
resolved "https://registry.yarnpkg.com/css.gg/-/css.gg-2.1.1.tgz#62b2e242633c1cdf9de9840f2cf343ce03f6548e"
integrity sha512-OJrjd4+CdjrLvrVB+EFctAnk7eeM+zc8aKfVlO5BfNBgSqcC9wMHQTZ7ALcCiZGpE62kVVhwQ3Mvl1u6RkVFvQ==
fill-range@^7.0.1:
version "7.0.1"
@@ -60,9 +60,9 @@ fill-range@^7.0.1:
to-regex-range "^5.0.1"
fsevents@~2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
version "2.3.3"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
glob-parent@~5.1.2:
version "5.1.2"
@@ -72,9 +72,9 @@ glob-parent@~5.1.2:
is-glob "^4.0.1"
immutable@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23"
integrity sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==
version "4.3.4"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.4.tgz#2e07b33837b4bb7662f288c244d1ced1ef65a78f"
integrity sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==
is-binary-path@~2.1.0:
version "2.1.0"
@@ -86,7 +86,7 @@ is-binary-path@~2.1.0:
is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
is-glob@^4.0.1, is-glob@~4.0.1:
version "4.0.3"
@@ -118,9 +118,9 @@ readdirp@~3.6.0:
picomatch "^2.2.1"
sass@^1.46.0:
version "1.52.1"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.52.1.tgz#554693da808543031f9423911d62c60a1acf7889"
integrity sha512-fSzYTbr7z8oQnVJ3Acp9hV80dM1fkMN7mSD/25mpcct9F7FPBMOI8krEYALgU1aZoqGhQNhTPsuSmxjnIvAm4Q==
version "1.68.0"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.68.0.tgz#0034b0cc9a50248b7d1702ac166fd25990023669"
integrity sha512-Lmj9lM/fef0nQswm1J2HJcEsBUba4wgNx2fea6yJHODREoMFnwRpZydBnX/RjyXw2REIwdkbqE4hrTo4qfDBUA==
dependencies:
chokidar ">=3.0.0 <4.0.0"
immutable "^4.0.0"
File diff suppressed because it is too large Load Diff
+5
View File
@@ -0,0 +1,5 @@
variables_order="EGPCS"
[Date]
date.timezone="UTC"
expose_php=Off
+51 -18
View File
@@ -1,32 +1,60 @@
<?php
/** @var \Bramus\Router\Router $router */
use App\Helpers\ErrorHandler;
use App\Helpers\Misc;
use App\Helpers\Wrappers;
use App\Models\BaseTemplate;
$router->set404(function () {
ErrorHandler::showText(404, "That endpoint doesn't exist");
});
$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->mount('/trending', function () use ($router) {
$router->get('/', 'TrendingController@get');
$router->get('/rss', 'TrendingController@rss');
});
$router->get('/redirect/search', 'RedirectController@search');
$router->get('/redirect/download', 'RedirectController@download');
$router->mount('/@([^/]+)', function () use ($router) {
$router->get('/', 'UserController@get');
@@ -34,10 +62,8 @@ $router->mount('/@([^/]+)', function () use ($router) {
$router->get('/rss', 'UserController@rss');
});
/**
* @deprecated Please use /@username/video/id instead
*/
$router->get('/video/(\w+)', 'VideoController@get');
// Workaround that allows /t endpoints
$router->get('/t/([^/]+)', 'VideoController@get');
$router->mount('/tag/([^/]+)', function () use ($router) {
$router->get('/', 'TagController@get');
@@ -46,14 +72,21 @@ $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');
$router->post('/general', 'SettingsController@general');
$router->post('/api', 'SettingsController@api');
$router->post('/misc', 'SettingsController@misc');
});
$router->get('/discover', 'DiscoverController@get');
// -- EMBED -- //
$router->get('/embed/v2/(\d+)', 'EmbedController@v2');
+4 -2
View File
@@ -2,6 +2,7 @@ var opened_video_id = null
const video = document.getElementById('video')
const item_title = document.getElementById('item_title')
const item_date = document.getElementById('item_date')
const audio = document.getElementById('audio')
const audio_title = document.getElementById('audio_title')
const modal = document.getElementById('modal')
@@ -15,7 +16,7 @@ const getVideoDataById = id => {
opened_video_id = id
return el.dataset
}
return false
return null
}
const isModalActive = () => modal.classList.contains('is-active')
@@ -23,9 +24,10 @@ const isModalActive = () => modal.classList.contains('is-active')
const toggleButton = (id, force) => document.getElementById(id).toggleAttribute('disabled', force)
// -- MODAL -- //
const swapData = ({ video_url, desc, video_download_watermark, video_download_nowatermark, video_share_url, music_title, music_url }) => {
const swapData = ({ video_url, desc, createtime, video_download_watermark, video_download_nowatermark, video_share_url, music_title, music_url }) => {
video.src = video_url
item_title.innerText = desc
item_date.innerText = new Date(createtime * 1000).toLocaleString()
download_watermark.href = video_download_watermark
download_nowatermark.href = video_download_nowatermark
share_input.value = video_share_url
-11
View File
@@ -1,11 +0,0 @@
This facilities making the bulma.min.css and fontawesome.min.css files, install all dependencies using:
```
yarn install
```
And then use:
```
yarn bulma && yarn fa
```
This compiles bulma.scss and fontawesome.scss to a css file and helps lowering the size of the css that will be sent to the user.
+68
View File
@@ -0,0 +1,68 @@
/*
CREDITS:
CSS Taken from: https://levelup.gitconnected.com/how-to-make-a-fully-accessible-css-only-carousel-40e8bd62032b
Author: Jennifer Wjertzoch (https://wjertzochjennifer.medium.com)
CodePen: https://codepen.io/jwjertzoch/pen/JjyGeRy
*/
.carousel {
margin: 0 auto;
overflow: hidden;
text-align: center;
}
.slides {
width: 100%;
display: flex;
overflow-x: scroll;
scrollbar-width: none;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
}
.slides::-webkit-scrollbar {
display: none;
}
.slides-item {
max-height: 75vh;
align-items: center;
display: flex;
flex-shrink: 0;
justify-content: center;
margin: 0 1rem;
position: relative;
scroll-snap-align: start;
transform: scale(1);
transform-origin: center center;
transition: transform .5s;
width: 100%;
}
.slides-item img {
max-height: 75vh;
}
.carousel__nav {
padding: 1.25rem .5rem;
}
.slider-nav {
align-items: center;
background-color: #ddd;
border-radius: 50%;
color: #000;
display: inline-flex;
height: 1.5rem;
justify-content: center;
padding: .5rem;
position: relative;
text-decoration: none;
width: 1.5rem;
}
.slider-nav:hover,
.slider-nav:active {
background-color: #000;
color: #fff;
}
+3
View File
@@ -0,0 +1,3 @@
.new-line {
white-space: pre-wrap;
}
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
{"version":3,"sourceRoot":"","sources":["../../scss/node_modules/css.gg/icons/scss/home.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"],"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,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","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/check-o.scss","../../misc/scss/node_modules/css.gg/icons/scss/tag.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,YACI,sBACA,kBACA,cACA,+BACA,WACA,YACA,iBACA,oBAEA,mBACE,WACA,cACA,sBACA,kBACA,SACA,SACA,UACA,YACA,0BACA,yBACA,mBACA,6BACA,wBCvBN,QACI,cACA,iBAeA,eACA,2BACA,8BACA,sBACA,+BACA,kBACA,WACA,YApBA,gBACE,cACA,iBACA,WACA,kBACA,UACA,WACA,uBACA,oBACA,QACA,QAYF,eACE,WACA,cACA,sBACA,kBACA,WACA,YACA,wBACA,uBACA,+BACA,yBACA,MACA,WCtCN,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"}
+4
View File
@@ -0,0 +1,4 @@
<details>
<summary>{$title}</summary>
{block content}{/block}
</details>
+37
View File
@@ -0,0 +1,37 @@
<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="{assets('css', 'cssgg.min.css', true)}">
<link rel="stylesheet" href="{assets('css', 'bulma.min.css', true)}">
<link rel="stylesheet" href="{assets('css', 'misc.css')}">
<link rel="stylesheet" href="{assets('css', 'carousel.css')}">
<title>{$title} - ProxiTok</title>
</head>
@@ -1,5 +1,8 @@
<nav class="navbar" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<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>
@@ -9,14 +12,18 @@
<div id="navbar-menu" class="navbar-menu">
<div class="navbar-start">
<a href="{path('/')}" class="navbar-item">
{include './icon.latte', icon: 'home', text: 'Home'}
<a href="{path('/settings')}" class="navbar-item">
{include './icon.latte', icon: 'options', text: 'Settings'}
</a>
<a href="{path('/settings')}" class="navbar-item">Settings</a>
<a href="{path('/about')}" class="navbar-item">
{include './icon.latte', icon: 'info', text: 'About'}
</a>
</div>
<div class="navbar-end">
<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="{assets('js', 'navbar.js')}"></script>
+17
View File
@@ -0,0 +1,17 @@
{embed '../form.latte', path: '/settings/api', method: 'POST', submit: true}
{block fields}
<div class="field">
<label class="label">Downloader</label>
<div class="control">
<div class="select">
<select name="api-downloader">
{foreach $downloaders as $downloader}
<option value="{$downloader}" n:attr="selected => $currentDownloader === $downloader">{$downloader|firstUpper}</option>
{/foreach}
</select>
</div>
</div>
<p class="help">Watermark downloads will <i>not</i> use third party methods</p>
</div>
{/block}
{/embed}
@@ -0,0 +1,16 @@
{embed '../form.latte', path: '/settings/general', method: 'POST', submit: true}
{block fields}
<div class="field">
<label class="label">Theme</label>
<div class="control">
<div class="select">
<select name="theme">
{foreach $themes as $theme}
<option value="{$theme}" n:attr="selected => $currentTheme === $theme">{$theme|firstUpper}</option>
{/foreach}
</select>
</div>
</div>
</div>
{/block}
{/embed}
@@ -1,22 +1,23 @@
<link rel="stylesheet" href="{path('/styles/themes/card.css')}">
<noscript>JavaScript is required for this section to work!</noscript>
<link rel="stylesheet" href="{assets('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}
{do $share_url = 'https://tiktok.com/@' . $item->author->uniqueId . '/video/' . $item->id}
{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="{path('/stream?url=' . urlencode($item->video->playAddr))}"
data-video_download_watermark="{path('/download?url=' . urlencode($item->video->playAddr) . '&id=' . $item->id . '&user=' . $item->author->uniqueId) . '&watermark='}"
data-video_download_nowatermark="{path('/download?id=' . $item->id . '&user=' . $item->author->uniqueId)}"
data-video_url="{url_stream($item->video->playAddr)}"
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}"
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="{url_stream($item->music->playUrl)}">
<img loading="lazy" src="{url_stream($item->video->originCover)}" />
<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>
@@ -36,6 +37,7 @@
</section>
<footer class="modal-card-foot has-text-centered">
<div class="container">
<p id="item_date"></p>
<div class="field has-addons has-addons-centered">
<div class="control">
<input id="share_input" class="input" readonly />
@@ -65,4 +67,4 @@
</footer>
</div>
</div>
<script src="{path('/scripts/themes/card.js')}"></script>
<script src="{assets('js', 'themes/card.js')}"></script>
@@ -0,0 +1,2 @@
<p class="mb-1">{include '../../icon.latte', icon: 'music', text: $songTitle}</p>
<audio controls preload="none" src="{url_stream($url)}"></audio>
@@ -0,0 +1,27 @@
{if !isset($item->imagePost)}
<video controls n:attr="autoplay => $isAutoplay" poster="{url_stream($item->video->originCover)}" preload="none">
<source src="{url_stream($item->video->playAddr)}" type="video/mp4" />
</video>
{else}
{if isset($isSimple)}
{foreach $item->imagePost->images as $i => $image}
<img src="{url_stream($image->imageURL->urlList[0])}" />
{/foreach}
{else}
<section class="carousel" aria-label="carousel" Tabindex="0">
<div class="slides">
{foreach $item->imagePost->images as $i => $image}
<div class="slides-item" id="{$item->id}-image{$i + 1}" tabindex="0">
<img src="{url_stream($image->imageURL->urlList[0])}" />
</div>
{/foreach}
</div>
<div class="carousel__nav">
{for $i = 0; $i < count($item->imagePost->images); $i++}
<a class="slider-nav" href="#{$item->id}-image{$i + 1}">{$i + 1}</a>
{/for}
</div>
<div class="carousel__skip-message" id="skip-link" tabindex="0"></div>
</section>
{/if}
{/if}
@@ -0,0 +1,7 @@
<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 => !$feed->hasMore" class="button is-success" href="?cursor={$feed->cursor}">Next</a>
</div>
@@ -0,0 +1,8 @@
<div class="field is-grouped is-grouped-centered">
<p class="control">
<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($playAddr, $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,8 @@
<details>
<summary>{include '../../icon.latte', icon: 'tag', text: 'Tags used'}</summary>
<div class="tags">
{foreach $challenges as $challenge}
<a class="tag is-primary is-rounded" href="{path('/tag/' . $challenge->title)}">#{$challenge->title}</a>
{/foreach}
</div>
</details>
+55
View File
@@ -0,0 +1,55 @@
<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>
{if $item->author->verified}
{include '../icon.latte', icon: 'check-o', text: $item->author->nickname}
{else}
{$item->author->nickname}
{/if}
</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)}
{include './common/tags.latte', challenges: $item->challenges}
{/if}
<p class="mb-2 mt-2" n:ifcontent>{render_desc($item->desc, $item->textExtra ?? [])|noescape}</p>
{include './common/audio.latte', songTitle: $item->music->title, url: $item->music->playUrl}
{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">
{include './common/content.latte', item: $item, isAutoplay: false, isBig: false}
</div>
{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', 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}
<div class="has-text-centered">
{embed '../details.latte', title: "Details"}
{block content}
<p>Can duet: {bool_to_str(isset($item->duetEnabled) ? $item->duetEnabled : boolval($item->duetDisplay))}</p>
<p>Can stitch (add this video to other ones): {bool_to_str(isset($item->stitchEnabled) ? $item->stitchEnabled : boolval($item->stitchDisplay))}</p>
<p>Can be shared: {bool_to_str(isset($item->shareEnabled) ? $item->shareEnabled : boolval($item->shareDisplay))}
{/block}
{/embed}
</div>
</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>
+40
View File
@@ -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;">&#9829;</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}

Some files were not shown because too many files have changed in this diff Show More