Compare commits

...

159 Commits

Author SHA1 Message Date
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
Pablo Ferreiro c041e84967 Fixed video on Safari 2022-05-30 13:48:06 +02:00
Pablo Ferreiro 6c7c0272d4 Added support for non-ascii characters 2022-05-24 16:35:48 +02:00
Pablo Ferreiro f1728257f2 Fix optional parameters positioning and ttwid 2022-05-24 16:03:43 +02:00
Pablo Ferreiro 0c100d650b hotfix 2022-05-24 14:17:41 +02:00
Pablo Ferreiro 55e1e9057b Updated wrapper 2022-05-24 14:10:41 +02:00
Pablo Ferreiro 14a8829087 Using prebuilt image 2022-05-22 13:14:30 +02:00
Pablo Ferreiro 367fe8d9de Merge pull request #36 from aosus/master
Auto build the docker image and push it to ghcr.io
2022-05-22 12:54:43 +02:00
Pablo Ferreiro abf23450db Changed chromedriver with SignTok 2022-05-22 12:52:56 +02:00
Pablo Ferreiro 177f290e56 Avoid warning 2022-05-22 12:31:49 +02:00
Pablo Ferreiro cd524c8da8 fixed dotenv 2022-05-22 12:12:37 +02:00
Pablo Ferreiro 33d5994159 PHP7 and new dotnet parser 2022-05-22 11:48:06 +02:00
FarisZR 62a6f6b9dd Create docker-publish.yml 2022-05-21 22:28:09 +03:00
Pablo Ferreiro 9a662ffe1b Fixed RSS pubDate 2022-05-18 11:44:58 +02:00
Pablo Ferreiro 4232ca8d64 Hide warnings 2022-04-24 08:09:45 +02:00
Pablo Ferreiro 47a3dc7e76 Added new TikTok Sigi state script 2022-04-23 19:56:57 +02:00
Pablo Ferreiro 288add48d5 Redirect: Remove @ or # if sent accidentally 2022-04-21 19:59:55 +02:00
Pablo Ferreiro e545bd6ddd Removed deprecated option from Signer 2022-04-17 23:55:45 +02:00
Pablo Ferreiro c04122d11f Trending fix 2022-04-17 23:16:00 +02:00
Pablo Ferreiro d9165d693f hotfix 2022-04-17 23:02:37 +02:00
Pablo Ferreiro 717997685a Hashtag fix 2022-04-17 22:57:41 +02:00
Pablo Ferreiro 2c68b34d06 hotfix 2022-04-12 15:30:49 +02:00
Pablo Ferreiro 816c5cf55f Strict robots again 2022-04-10 13:06:42 +02:00
Pablo Ferreiro 568c9c9ea9 revert robots 2022-04-10 13:03:00 +02:00
Pablo Ferreiro 47a232de3d Strict robots.txt 2022-04-10 12:16:55 +02:00
Pablo Ferreiro 3730c95f29 hotfix 2022-04-10 12:12:55 +02:00
Pablo Ferreiro d0d36c26f3 WIP embed.js support and robots.txt 2022-04-10 12:10:48 +02:00
Pablo Ferreiro 5368c08039 Fixed undefined variable 2022-04-04 10:34:14 +02:00
Pablo Ferreiro bed4ef9d3a Merge pull request #24 from Zottelchen/patch-1
fix typo
2022-03-31 19:26:54 +02:00
Zottelchen fdcb33fb18 fix typo 2022-03-31 15:03:01 +00:00
Pablo Ferreiro bc4468c5ab Reverting APP_PATH to APP_URL 2022-03-29 19:37:57 +02:00
Pablo Ferreiro 1a86abeb2d Small patch 2022-03-29 19:35:29 +02:00
Pablo Ferreiro 44ee065ec6 Icons, themes, removed instance proxy and more 2022-03-29 19:30:31 +02:00
Pablo Ferreiro 9a35c61023 Update Wrapper, fixes MIME issues 2022-03-28 18:07:50 +02:00
Pablo Ferreiro 9f43caa3c4 Added public instances section on README 2022-03-18 16:01:10 +01:00
Pablo Ferreiro 44429cb7e4 bump wrapper 2022-03-18 15:02:26 +01:00
Pablo Ferreiro ade2b3c01a hotfix 2022-03-16 00:33:59 +01:00
Pablo Ferreiro e4e6f05362 upstream from PussTheCat-org/docker-proxitok-quay 2022-03-16 00:26:45 +01:00
Pablo Ferreiro eb69e8a22e Added Credits for Dockerfile 2022-03-15 23:57:48 +01:00
Pablo Ferreiro 5fffc7ae08 hotfix 2022-03-15 23:05:04 +01:00
Pablo Ferreiro f0765e266c Working Docker 2022-03-15 22:52:54 +01:00
Pablo Ferreiro c26e027c01 Redirect to Wiki for Self-Hosting 2022-03-15 17:23:03 +01:00
Pablo Ferreiro 6eee156541 /video follows TikTok schema 2022-03-14 11:50:47 +01:00
Pablo Ferreiro c682432920 Accept chromedriver url for sign and .env cleanup 2022-03-13 23:18:10 +01:00
Pablo Ferreiro d061c210a2 Heroku fix 2022-03-13 18:42:41 +01:00
Pablo Ferreiro 3b5c3cd96c hotfix 2022-03-13 18:32:44 +01:00
Pablo Ferreiro 1b29950d89 Heroku using nginx, reverted public and some fixes 2022-03-13 18:22:36 +01:00
Pablo Ferreiro 8ece2c2b25 Fixed JSON Cache and Cache returning VERIFY_CODE 2022-03-12 19:28:37 +01:00
Pablo Ferreiro 7ba324c935 hotfix 2022-03-12 00:34:42 +01:00
Pablo Ferreiro 9c95620384 Fixed /video 2022-03-11 23:39:56 +01:00
Pablo Ferreiro 7b5ec2211e Hopefully last fix 2022-03-11 23:37:12 +01:00
Pablo Ferreiro 2bdd433a17 Fixed RSS 2022-03-11 23:24:56 +01:00
Pablo Ferreiro b8f8eb710f More fixes 2022-03-11 23:24:13 +01:00
Pablo Ferreiro c62df9d631 That... Could have gone better 2022-03-11 23:18:26 +01:00
Pablo Ferreiro 605e204453 Fixed composer.json 2022-03-11 23:03:51 +01:00
Pablo Ferreiro 7011867fd8 Merge pull request #18 from pablouser1/new-api
New Wrapper using TikTok's new Api
2022-03-11 23:00:00 +01:00
Pablo Ferreiro a4a4b0497c Merged with new-api 2022-03-11 22:59:16 +01:00
Pablo Ferreiro f1de8e979b Fixed trending, added explanation on VERIFY_CODE 2022-03-11 22:46:12 +01:00
Pablo Ferreiro 1e1376506c Bump wrapper 2022-03-11 21:02:34 +01:00
Pablo Ferreiro 198c88a1d7 Bump wrapper 2022-03-11 20:55:30 +01:00
Pablo Ferreiro 73dd93420f Force legacy mode, instance level and user level 2022-03-11 20:50:11 +01:00
Pablo Ferreiro db3799c344 public folder, update wrapper 2022-03-11 18:56:19 +01:00
Pablo Ferreiro 1eb6626153 Added Redirector 2022-03-11 16:11:56 +01:00
Pablo Ferreiro c413017b00 Merge pull request #14 from IronMaltese/patch-1
Libredirect
2022-03-06 12:51:25 +01:00
IronMaltese 669c0d29d4 Update README.md 2022-03-05 16:50:47 -05:00
Pablo Ferreiro 58170665ed Dropdown and updated wrapper 2022-02-24 21:13:38 +01:00
Pablo Ferreiro d60e4400a2 Instance-level proxy and test endpoint fix 2022-02-20 16:25:15 +01:00
Pablo Ferreiro c47d6cd6d4 Reverted to last usable version 2022-02-16 15:20:35 +01:00
Pablo Ferreiro 279a4f50c6 Updated composer.lock 2022-02-16 12:54:28 +01:00
Pablo Ferreiro 9711bb903c Updated Wrapper 2022-02-15 13:55:36 +01:00
Pablo Ferreiro a11a17f9d2 Fixed rss 2022-02-13 23:40:56 +01:00
Pablo Ferreiro c690adab63 Upstream 2022-02-13 22:43:46 +01:00
Pablo Ferreiro 1d37d8c417 Fixed trending 2022-02-13 22:30:47 +01:00
Pablo Ferreiro 90cf0bfb56 Fix Redis 2022-02-13 22:27:21 +01:00
115 changed files with 2036 additions and 983 deletions
+9
View File
@@ -0,0 +1,9 @@
node_modules
/.env
/.git
/.vscode
/vendor
/cache/latte/*
!/cache/latte/.gitkeep
/cache/api/*
!/cache/api/.gitkeep
+16 -4
View File
@@ -1,12 +1,24 @@
# APP_URL="http://localhost:8000" # Full url path, PLEASE REPLACE TO YOUR OWN ONE
# SIGNER_URL="https://tiktok-sign.herokuapp.com/signature" # External signing service
# 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_CACHE=redis # Cache engine for TikTok Api, (more info on README)
# Redis cache, used on Helpers\CacheEngines\RedisCache
# API CONFIG
# API_SIGNER="remote"
# API_SIGNER_URL="http://localhost:8080"
# API_TEST_ENDPOINTS=true # Uncomment for usage of testing TikTok endpoints, may help sometimes
# API_CACHE=redis
# Redis cache, used on Helpers\CacheEngines\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
# API_CACHE_JSON=/tmp/proxitok_api # Path for JSON API Cache, leave commented for ./cache/api
# Proxy Config
# PROXY_HOST=http://EXAMPLE_IP # Host to be used as proxy, make sure to type a valid protocol. Available: http:// | https:// | socks4:// | socks5://
# PROXY_PORT=8080
# PROXY_USERNAME=username
# PROXY_PASSWORD=password
# 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.
**Enviroment (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.
+102
View File
@@ -0,0 +1,102 @@
name: Docker
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
on:
push:
branches: [ master ]
# Publish semver tags as releases.
tags: [ 'v*.*.*' ]
pull_request:
branches: [ master ]
env:
# Use docker.io for Docker Hub if empty
REGISTRY: ghcr.io
# github.repository as <account>/<repo>
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
# This is used to complete the identity challenge
# with sigstore/fulcio when running outside of PRs.
id-token: write
steps:
- 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@main
with:
cosign-release: 'v2.0.0-rc.0'
# Workaround: https://github.com/docker/build-push-action/issues/461
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v2
# Login against a Docker registry except on PR
# https://github.com/docker/login-action
- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Extract metadata (tags, labels) for Docker
# https://github.com/docker/metadata-action
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v3
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# 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,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
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
# Sign the resulting Docker image digest except on PRs.
# This will only write to the public Rekor transparency log when the Docker
# repository is public to avoid leaking data. If you would like to publish
# transparency data even for private images, pass --force to cosign below.
# https://github.com/sigstore/cosign
- 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 }}
+2 -3
View File
@@ -1,12 +1,11 @@
RewriteEngine on
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.php [L]
RewriteRule ^ index.php [QSA,L]
# Disable index view
Options -Indexes
# Hide a specific file
<Files .env>
Order allow,deny
Deny from all
+25
View File
@@ -0,0 +1,25 @@
FROM php:8.1-apache
WORKDIR /var/www/html
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 . .
# 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
EXPOSE 80
CMD apachectl -D FOREGROUND
+1 -1
View File
@@ -1 +1 @@
web: vendor/bin/heroku-php-apache2
web: vendor/bin/heroku-php-nginx -C misc/setup/heroku/nginx.conf
+31 -49
View File
@@ -4,65 +4,47 @@ Use Tiktok with an alternative frontend, inspired by Nitter.
## Features
* Privacy: All requests made to TikTok are server-side, so you will never connect to their servers
* See user's feed
* See trending
* See trending and discovery tab
* See tags
* See video by id
* Discovery
* Create a following list, which you can later use to see all the feeds from those users
* Themes
* RSS Feed for user, trending and tag (just add /rss to the url)
## Installation
Clone the repository and fetch the requiered external packages with:
```bash
composer install
## 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
## Public instances
[This](https://github.com/pablouser1/ProxiTok/wiki/Public-instances) wiki article contains a list with all the known public instances.
## 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.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.pabloferreiro.es$3
Example result: https://proxitok.pabloferreiro.es/@tiktok
Pattern type: Regular Expression
Apply to: Main window (address bar)
```
WARNING: You'll need a personal Github token for composer.
Then you can run it using for example the PHP Development Server with:
```bash
php -S localhost:8080
```
## Configuration
### .env
Move the .env.example file to .env and modify it.
### Cache engines
Available cache engines:
* redis: Writes response to Redis
* json: Writes response to JSON file
### Apache
You don't have to do anything more
### Nginx
Add the following to your config (you can modify the proxitok part if you have or not a subdir):
```
location /proxitok {
return 302 $scheme://$host/proxitok/;
}
location /proxitok/ {
try_files $uri $uri/ /proxitok/index.php?$query_string;
}
location /proxitok/.env {
deny all;
return 404;
}
```
## TODO
* Add a NoJS version / Make the whole program without required JS
* Better error handling
## TODO / Known issues
* Replace placeholder favicon
* Make video on /video fit screen and don't overflow
* i18n
* 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
* [TikScraper](https://github.com/pablouser1/TikScraperPHP)
[TheFrenchGhosty](https://thefrenchghosty.me) ([Github](https://github.com/TheFrenchGhosty)): Initial Dockerfile and fixes to a usable state.
### External libraries
* [TikScraperPHP](https://github.com/pablouser1/TikScraperPHP)
* [Latte](https://github.com/nette/latte)
* [bramus/router](https://github.com/bramus/router)
* [PHP dotenv](https://github.com/vlucas/phpdotenv)
* [Bulma](https://github.com/jgthms/bulma) and [Bulmaswatch](https://github.com/jenil/bulmaswatch)
* [FeedWriter](https://github.com/mibe/FeedWriter)
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\CacheInterface;
class ApcuCache implements CacheInterface {
function __construct() {
if (!(extension_loaded('apcu') && apcu_enabled())) {
throw new \Exception('APCu not enabled');
}
}
public function get(string $cache_key): ?object {
$data = apcu_fetch($cache_key);
return $data !== false ? json_decode($data) : null;
}
public function exists(string $cache_key): bool {
return apcu_exists($cache_key);
}
public function set(string $cache_key, string $data, $timeout = 3600): void {
apcu_store($cache_key, $data, $timeout);
}
}
+6 -5
View File
@@ -1,15 +1,16 @@
<?php
namespace App\Cache;
use App\Helpers\Misc;
use TikScraper\Interfaces\CacheInterface;
class JSONCache {
private string $cache_path = '';
class JSONCache implements CacheInterface {
private string $cache_path = __DIR__ . '/../../cache/api';
function __construct() {
$this->cache_path = Misc::env('API_CACHE_JSON', __DIR__ . '/../../cache/api');
if (isset($_ENV['API_CACHE_JSON']) && !empty($_ENV['API_CACHE_JSON'])) {
$this->cache_path = $_ENV['API_CACHE_JSON'];
}
}
public function get(string $cache_key): ?object {
$filename = $this->cache_path . '/' . $cache_key . '.json';
if (is_file($filename)) {
+6 -7
View File
@@ -1,7 +1,9 @@
<?php
namespace App\Cache;
class RedisCache {
use TikScraper\Interfaces\CacheInterface;
class RedisCache implements CacheInterface {
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, array $data, $timeout = 3600) {
$this->client->set($cache_key, json_encode($data), $timeout);
public function set(string $cache_key, string $data, $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 Themes {
const DEFAULT = "default";
const CARD = "card";
}
+6 -7
View File
@@ -2,18 +2,17 @@
namespace App\Controllers;
use App\Helpers\ErrorHandler;
use App\Helpers\Misc;
use App\Helpers\Wrappers;
use App\Models\DiscoverTemplate;
class DiscoverController {
static public function get() {
$api = Misc::api();
$feed = $api->getDiscover();
if ($feed->meta->success) {
$latte = Misc::latte();
$latte->render(Misc::getView('discover'), new DiscoverTemplate($feed));
$api = Wrappers::api();
$data = $api->discover();
if ($data->meta->success) {
Wrappers::latte('discover', new DiscoverTemplate($data));
} else {
ErrorHandler::show($feed->meta);
ErrorHandler::showMeta($data->meta);
}
}
}
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace App\Controllers;
use App\Helpers\ErrorHandler;
use App\Helpers\Wrappers;
use App\Models\VideoTemplate;
class EmbedController {
static public function v2(int $id) {
$api = Wrappers::api();
$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::showMeta($video->error());
}
}
}
+10 -7
View File
@@ -3,19 +3,22 @@ namespace App\Controllers;
use App\Helpers\ErrorHandler;
use App\Helpers\Misc;
use App\Models\FeedTemplate;
use App\Helpers\Wrappers;
use App\Models\FullTemplate;
class MusicController {
static public function get(string $music_id) {
$cursor = Misc::getCursor();
$api = Misc::api();
$feed = $api->getMusicFeed($music_id, $cursor);
if ($feed->meta->success) {
$latte = Misc::latte();
$latte->render(Misc::getView('music'), new FeedTemplate('Music', $feed));
$api = Wrappers::api();
$music = $api->music($music_id);
$music->feed($cursor);
if ($music->ok()) {
$info = $music->getInfo();
$feed = $music->getFeed();
Wrappers::latte('music', new FullTemplate('Music', $info, $feed));
} else {
ErrorHandler::show($feed->meta);
ErrorHandler::showMeta($music->error());
}
}
}
+36 -33
View File
@@ -1,25 +1,54 @@
<?php
namespace App\Controllers;
use App\Helpers\Cookies;
use App\Helpers\Misc;
use TikScraper\Constants\UserAgents as TikScraperUserAgents;
class ProxyController {
const VALID_TIKTOK_DOMAINS = [
"tiktokcdn.com", "tiktokcdn-us.com", "tiktok.com"
];
static private function isValidDomain(string $url) {
static public function stream() {
self::checkUrl();
$url = $_GET['url'];
$config['user_agent'] = Misc::env("USER_AGENT", TikScraperUserAgents::DEFAULT);
$streamer = new \TikScraper\Stream($config);
$streamer->url($url);
}
static public function download() {
self::checkUrl();
$method = Cookies::downloader();
$downloader = new \TikScraper\Download($method);
// 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() {
if (isset($_GET['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);
}
} else {
self::checkUrl();
$url = $_GET['url'];
$streamer = new \TikScraper\Stream();
$streamer->url($url);
}
}
}
+84 -10
View File
@@ -1,24 +1,98 @@
<?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() {
$endpoint = '';
if (isset($_GET['user'])) {
$endpoint = '/@' . $_GET['user'];
} else if (isset($_GET['tag'])) {
$endpoint = '/tag/' . $_GET['tag'];
} else if (isset($_GET['music'])) {
$endpoint = '/music/' . $_GET['music'];
} else if (isset($_GET['video'])) {
$endpoint = '/video/' . $_GET['video'];
static public 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 = '/@' . urlencode($term);
break;
case 'tag':
// Remove # if sent
if ($term[0] === '#') {
$term = substr($term, 1);
}
$endpoint = '/tag/' . urlencode($term);
break;
case 'music':
$endpoint = '/music/' . urlencode($term);
break;
case 'video':
// The @username part is not used, but
// it is the schema that TikTok follows
$endpoint = '/@placeholder/video/' . urlencode($term);
break;
}
}
$url = Misc::url($endpoint);
header("Location: {$url}");
}
static public function download() {
if (!(isset($_GET['videoId'], $_GET['authorUsername'], $_GET['playAddr']))) {
ErrorHandler::showText(400, 'Request incomplete');
return;
}
$watermark = isset($_GET['watermark']) && $_GET['watermark'] === 'yes' ? true : false;
$url = '';
if ($watermark) {
$url = UrlBuilder::download($_GET['playAddr'], $_GET['authorUsername'], $_GET['videoId'], true);
} else {
$url = UrlBuilder::download(UrlBuilder::video_external($_GET['authorUsername'], $_GET['videoId']), $_GET['authorUsername'], $_GET['videoId'], false);
}
header("Location: {$url}");
}
/**
* to_endpoint maps a TikTok URL into a ProxiTok-compatible endpoint URL.
*/
static private function to_endpoint(string $url): string {
if (preg_match('%^(?:https?://)?(?:www\.)?(?:vm\.|vt\.)?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 '';
}
}
+24 -7
View File
@@ -3,20 +3,37 @@ namespace App\Controllers;
use App\Helpers\Misc;
use App\Helpers\Cookies;
use App\Helpers\Wrappers;
use App\Models\SettingsTemplate;
class SettingsController {
static public function index() {
$latte = Misc::latte();
$latte->render(Misc::getView('settings'), new SettingsTemplate());
Wrappers::latte('settings', new SettingsTemplate());
}
static public function proxy() {
if (in_array(Cookies::PROXY, $_POST)) {
foreach (Cookies::PROXY as $proxy_element) {
Cookies::set($proxy_element, $_POST[$proxy_element]);
}
static public function general() {
if (isset($_POST['theme'])) {
$theme = $_POST['theme'];
Cookies::set('theme', $theme);
}
self::redirect();
}
static public function api() {
// TODO, ADD COUNT
if (isset($_POST['api-test_endpoints'])) {
$test_endpoints = $_POST['api-test_endpoints'];
Cookies::set('api-test_endpoints', $test_endpoints);
}
if (isset($_POST['api-downloader'])) {
$downloader = $_POST['api-downloader'];
Cookies::set("api-downloader", $downloader);
}
self::redirect();
}
static private function redirect() {
$url = Misc::url('/settings');
header("Location: {$url}");
}
+19 -15
View File
@@ -3,30 +3,34 @@ namespace App\Controllers;
use App\Helpers\ErrorHandler;
use App\Helpers\Misc;
use App\Helpers\RSS;
use App\Models\FeedTemplate;
use App\Helpers\UrlBuilder;
use App\Helpers\Wrappers;
use App\Models\FullTemplate;
use App\Models\RSSTemplate;
class TagController {
static public function get(string $name) {
$cursor = Misc::getCursor();
$api = Misc::api();
$feed = $api->getHashtagFeed($name, $cursor);
if ($feed->meta->success) {
$latte = Misc::latte();
$latte->render(Misc::getView('tag'), new FeedTemplate('Tag', $feed));
$api = Wrappers::api();
$hashtag = $api->hashtag($name);
$hashtag->feed($cursor);
if ($hashtag->ok()) {
$info = $hashtag->getInfo();
$feed = $hashtag->getFeed();
Wrappers::latte('tag', new FullTemplate($info->detail->title, $info, $feed));
} else {
ErrorHandler::show($feed->meta);
ErrorHandler::showMeta($hashtag->error());
}
}
static public function rss(string $name) {
$api = Misc::api();
$feed = $api->getHashtagFeed($name);
if ($feed->meta->success) {
$feed = RSS::build("/tag/{$name}", "{$name} Tag", $feed->info->detail->desc, $feed->items);
// Setup headers
RSS::setHeaders('tag.rss');
echo $feed;
$api = Wrappers::api();
$hashtag = $api->hashtag($name);
$hashtag->feed();
if ($hashtag->ok()) {
$data = $hashtag->getFull();
Misc::rss($name);
Wrappers::latte('rss', new RSSTemplate($name, $data->info->detail->desc, UrlBuilder::tag($name), $data->feed->items));
}
}
}
+20 -16
View File
@@ -4,30 +4,34 @@ namespace App\Controllers;
use App\Helpers\Misc;
use App\Models\FeedTemplate;
use App\Helpers\ErrorHandler;
use App\Helpers\RSS;
use App\Helpers\Wrappers;
use App\Models\RSSTemplate;
class TrendingController {
static public function get() {
$cursor = Misc::getCursor();
$page = $_GET['page'] ?? 0;
$api = Misc::api();
$feed = $api->getTrending($cursor, $page);
if ($feed->meta->success) {
$latte = Misc::latte();
$latte->render(Misc::getView('trending'), new FeedTemplate('Trending', $feed));
$api = Wrappers::api();
$cursor = Misc::getTtwid();
$trending = $api->trending();
$trending->feed($cursor);
$feed = $trending->getFeed();
if ($feed && $feed->meta->success) {
Wrappers::latte('trending', new FeedTemplate('Trending', $feed));
} else {
ErrorHandler::show($feed->meta);
ErrorHandler::showMeta($trending->error());
}
}
static public function rss() {
$api = Misc::api();
$feed = $api->getTrending();
if ($feed->meta->success) {
$feed = RSS::build('/trending', 'Trending', 'Tiktok trending', $feed->items);
// Setup headers
RSS::setHeaders('trending.rss');
echo $feed;
$api = Wrappers::api();
$trending = $api->trending();
$trending->feed();
$feed = $trending->getFeed();
if ($feed && $feed->meta->success) {
Misc::rss('Trending');
Wrappers::latte('rss', new RSSTemplate('Trending', 'Trending on TikTok', Misc::url('/trending'), $feed->items));
}
}
}
+33 -19
View File
@@ -3,34 +3,48 @@ namespace App\Controllers;
use App\Helpers\ErrorHandler;
use App\Helpers\Misc;
use App\Helpers\RSS;
use App\Models\FeedTemplate;
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) {
$cursor = Misc::getCursor();
$api = Misc::api();
$feed = $api->getUserFeed($username, $cursor);
if ($feed->meta->success) {
if ($feed->info->detail->privateAccount) {
http_response_code(400);
echo 'Private account detected! Not supported';
}
$latte = Misc::latte();
$latte->render(Misc::getView('user'), new FeedTemplate($feed->info->detail->nickname, $feed));
$api = Wrappers::api();
$user = $api->user($username);
$user->feed($cursor);
if ($user->ok()) {
$info = $user->getInfo();
$feed = $user->getFeed();
Wrappers::latte('user', new FullTemplate($info->detail->nickname, $info, $feed));
} else {
ErrorHandler::show($feed->meta);
ErrorHandler::showMeta($user->error());
}
}
static public function video(string $username, string $video_id) {
$api = Wrappers::api();
$video = $api->video($video_id);
$video->feed();
if ($video->ok()) {
$item = $video->getFeed()->items[0];
$info = $video->getInfo();
Wrappers::latte('video', new VideoTemplate($item, $info));
} else {
ErrorHandler::showMeta($video->error());
}
}
static public function rss(string $username) {
$api = Misc::api();
$feed = $api->getUserFeed($username);
if ($feed->meta->success) {
$feed = RSS::build('/@'.$username, $feed->info->detail->nickname, $feed->info->detail->signature, $feed->items);
// Setup headers
RSS::setHeaders('user.rss');
echo $feed;
$api = Wrappers::api();
$user = $api->user($username);
$user->feed();
if ($user->ok()) {
$data = $user->getFull();
Misc::rss($username);
Wrappers::latte('rss', new RSSTemplate($username, $data->info->detail->signature, UrlBuilder::user($username), $data->feed->items));
}
}
}
+1 -12
View File
@@ -1,19 +1,8 @@
<?php
namespace App\Controllers;
use App\Helpers\ErrorHandler;
use App\Helpers\Misc;
use App\Models\FeedTemplate;
class VideoController {
static public function get(string $video_id) {
$api = Misc::api();
$item = $api->getVideoByID($video_id);
if ($item->meta->success) {
$latte = Misc::latte();
$latte->render(Misc::getView('video'), new FeedTemplate($item->info->detail->nickname, $item));
} else {
ErrorHandler::show($item->meta);
}
UserController::video('placeholder', $video_id);
}
}
+23 -4
View File
@@ -1,20 +1,39 @@
<?php
namespace App\Helpers;
class Cookies {
const PROXY = ['proxy-host', 'proxy-port', 'proxy-username', 'proxy-password'];
use App\Constants\Themes;
static public function get(string $name): string {
class Cookies {
static public function get(string $name, string $default_value = ''): string {
if (isset($_COOKIE[$name]) && !empty($_COOKIE[$name])) {
return $_COOKIE[$name];
}
return '';
return $default_value;
}
static public function theme(): string {
$theme = self::get('theme');
$ref = new \ReflectionClass(Themes::class);
$themes = $ref->getConstants();
if ($theme && in_array($theme, $themes)) {
return $theme;
}
return 'default';
}
static public function downloader(): string {
$downloader = self::get('api-downloader', 'default');
return $downloader;
}
static public function exists(string $name): bool {
return isset($_COOKIE[$name]);
}
static public function check(string $name, string $value): bool {
return self::exists($name) && $_COOKIE[$name] === $value;
}
static public function set(string $name, string $value) {
setcookie($name, $value, time()+60*60*24*30, '/', '', isset($_SERVER['HTTPS']), true);
}
+8 -3
View File
@@ -2,11 +2,16 @@
namespace App\Helpers;
use App\Models\ErrorTemplate;
use TikScraper\Models\Meta;
class ErrorHandler {
static public function show(object $meta) {
static public function showMeta(Meta $meta) {
http_response_code($meta->http_code);
$latte = Misc::latte();
$latte->render(Misc::getView('error'), new ErrorTemplate($meta));
Wrappers::latte('error', new ErrorTemplate($meta->http_code, $meta->tiktok_msg, $meta->tiktok_code));
}
static public function showText(int $code, string $msg) {
http_response_code($code);
Wrappers::latte('error', new ErrorTemplate($code, $msg));
}
}
+11 -80
View File
@@ -1,103 +1,34 @@
<?php
namespace App\Helpers;
use App\Cache\JSONCache;
use App\Cache\RedisCache;
class Misc {
static public function getCursor(): int {
return isset($_GET['cursor']) && is_numeric($_GET['cursor']) ? (int) $_GET['cursor'] : 0;
}
static public function url(string $endpoint = '') {
static public function getTtwid(): string {
return isset($_GET['cursor']) ? $_GET['cursor'] : '';
}
static public function url(string $endpoint = ''): string {
return self::env('APP_URL', '') . $endpoint;
}
static public function env(string $key, string $default_value): string {
return isset($_ENV[$key]) && !empty($_ENV[$key]) ? $_ENV[$key] : $default_value;
static public 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";
return __DIR__ . "/../../templates/views/{$template}.latte";
}
/**
* Setup of TikTok Api wrapper
* Common method for rss feeds
*/
static public function api(): \TikScraper\Api {
$options = [
'remote_signer' => self::env('SIGNER_URL', 'http://localhost:8080/signature')
];
$cacheEngine = false;
// Proxy config
foreach(Cookies::PROXY as $proxy_element) {
if (isset($_COOKIE[$proxy_element])) {
$options['proxy'][$proxy_element] = $_COOKIE[$proxy_element];
}
}
// Cache config
if (isset($_ENV['API_CACHE'])) {
switch ($_ENV['API_CACHE']) {
case 'json':
$cacheEngine = new JSONCache();
break;
case 'redis':
if (!(isset($_ENV['REDIS_URL']) || isset($_ENV['REDIS_HOST'], $_ENV['REDIS_PORT']))) {
throw new \Exception('You need to set REDIS_URL or REDIS_HOST and REDIS_PORT to use Redis Cache!');
}
if (isset($_ENV['REDIS_URL'])) {
$url = parse_url($_ENV['REDIS_URL']);
$host = $url['host'];
$port = $url['port'];
$password = $url['pass'] ?? null;
} else {
$host = $_ENV['REDIS_HOST'];
$port = (int) $_ENV['REDIS_PORT'];
$password = $_ENV['REDIS_PASSWORD'] ?? null;
}
$cacheEngine = new RedisCache($host, $port, $password);
break;
}
}
$api = new \TikScraper\Api($options, $cacheEngine);
return $api;
}
/**
* Setup of Latte template engine
*/
static public function latte(): \Latte\Engine {
$latte = new \Latte\Engine;
$cache_path = self::env('LATTE_CACHE', __DIR__ . '/../../cache/latte');
$latte->setTempDirectory($cache_path);
// -- CUSTOM FUNCTIONS -- //
// Get URL with optional endpoint
$latte->addFunction('path', function (string $endpoint = ''): string {
return self::url($endpoint);
});
// Version being used
$latte->addFunction('version', function (): string {
return \Composer\InstalledVersions::getVersion('pablouser1/proxitok');
});
// https://stackoverflow.com/a/36365553
$latte->addFunction('number', function (float $x) {
if($x > 1000) {
$x_number_format = number_format($x);
$x_array = explode(',', $x_number_format);
$x_parts = array('K', 'M', 'B', 'T');
$x_count_parts = count($x_array) - 1;
$x_display = $x;
$x_display = $x_array[0] . ((int) $x_array[1][0] !== 0 ? '.' . $x_array[1][0] : '');
$x_display .= $x_parts[$x_count_parts - 1];
return $x_display;
}
return $x;
});
return $latte;
static public function rss(string $title) {
header('Content-Disposition: attachment; filename="' . $title . '.rss' . '"');
}
}
-34
View File
@@ -1,34 +0,0 @@
<?php
namespace App\Helpers;
use \FeedWriter\RSS2;
use \Sovit\TikTok\Download;
class RSS {
static public function build(string $endpoint, string $title, string $description, array $items): string {
$url = Misc::env('APP_URL', '');
$download = new Download();
$rss = new RSS2();
$rss->setTitle($title);
$rss->setDescription($description);
$rss->setLink($url . $endpoint);
$rss->setSelfLink($url . $endpoint . '/rss');
foreach ($items as $item) {
$item_rss = $rss->createNewItem();
$video = $item->video->playAddr;
$item_rss->setTitle($item->desc);
$item_rss->setDescription($item->desc);
$item_rss->setLink($url . '/video/' . $item->id);
$item_rss->setDate((int) $item->createTime);
$item_rss->setId($item->id, false);
$item_rss->addEnclosure($url . '/stream?url=' . urlencode($video), $download->file_size($video), 'video/mp4');
$rss->addItem($item_rss);
}
return $rss->generateFeed();
}
static public function setHeaders (string $filename) {
header('Content-Type: application/rss+xml');
header('Content-Disposition: attachment; filename="' . $filename . '"');
}
}
+30
View File
@@ -0,0 +1,30 @@
<?php
namespace App\Helpers;
class UrlBuilder {
static public function stream(string $url): string {
return Misc::url('/stream?url=' . urlencode($url));
}
static public function download(string $url, string $username, string $id, bool $watermark): string {
$down_url = Misc::url('/download?url=' . urlencode($url) . '&id=' . $id . '&user=' . $username);
if ($watermark) $down_url .= '&watermark=1';
return $down_url;
}
static public function user(string $username): string {
return Misc::url('/@' . $username);
}
static public function tag(string $tag): string {
return Misc::url('/tag/' . $tag);
}
static public function video_internal(string $username, string $id): string {
return Misc::url('/@' . $username . "/video/" . $id);
}
static public function video_external(string $username, string $id): string {
return "https://www.tiktok.com/@" . $username . "/video/" . $id;
}
}
+175
View File
@@ -0,0 +1,175 @@
<?php
namespace App\Helpers;
use App\Cache\ApcuCache;
use App\Cache\JSONCache;
use App\Cache\RedisCache;
use App\Constants\CacheMethods;
use App\Models\BaseTemplate;
use TikScraper\Constants\UserAgents as TikScraperUserAgents;
class Wrappers {
/**
* Setup of Latte template engine
*/
static public function latte(string $template, BaseTemplate $base) {
$latte = new \Latte\Engine;
$cache_path = Misc::env('LATTE_CACHE', __DIR__ . '/../../cache/latte');
$latte->setTempDirectory($cache_path);
// -- CUSTOM FUNCTIONS -- //
// Get URL with optional endpoint
$latte->addFunction('path', function (string $endpoint = ''): string {
return Misc::url($endpoint);
});
// Static assets
$latte->addFunction('static', function (string $type, string $file, bool $isVendor = false): string {
$endpoint = '';
switch ($type) {
case 'js':
$endpoint .= '/scripts';
break;
case 'css':
$endpoint .= '/styles';
break;
default:
throw new \Exception('Invalid static asset type');
}
if ($isVendor) $endpoint .= '/vendor';
$endpoint .= '/' . $file;
return Misc::url($endpoint);
});
$latte->addFunction('theme', function(): string {
return Cookies::theme();
});
// Version being used
$latte->addFunction('version_frontend', function (): string {
return \Composer\InstalledVersions::getVersion('pablouser1/proxitok');
});
$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) {
$x_number_format = number_format($x);
$x_array = explode(',', $x_number_format);
$x_parts = array('K', 'M', 'B', 'T');
$x_count_parts = count($x_array) - 1;
$x_display = $x;
$x_display = $x_array[0] . ((int) $x_array[1][0] !== 0 ? '.' . $x_array[1][0] : '');
$x_display .= $x_parts[$x_count_parts - 1];
return $x_display;
}
return $x;
});
// UrlBuilder
$latte->addFunction('url_stream', function (string $url): string {
return UrlBuilder::stream($url);
});
$latte->addFunction('url_user', function (string $username): string {
return UrlBuilder::user($username);
});
$latte->addFunction('url_tag', function (string $tag): string {
return UrlBuilder::tag($tag);
});
$latte->addFunction('url_video_internal', function (string $username, string $id): string {
return UrlBuilder::video_internal($username, $id);
});
$latte->addFunction('url_video_external', function (string $username, string $id): string {
return UrlBuilder::video_external($username, $id);
});
$latte->addFunction('url_download', function (string $url, string $username, string $id, bool $watermark): string {
return UrlBuilder::download($url, $username, $id, $watermark);
});
$latte->render(Misc::getView($template), $base);
}
/**
* Setup of TikTok Api wrapper
*/
static public function api(): \TikScraper\Api {
$method = Misc::env('API_SIGNER', '');
$url = Misc::env('API_SIGNER_URL', '');
if (!$method) {
// Legacy support
$browser_url = Misc::env('API_BROWSER_URL', '');
if ($url) {
$method = 'remote';
} elseif ($browser_url) {
$url = $browser_url;
$method = 'browser';
}
}
$options = [
'use_test_endpoints' => Misc::env('API_TEST_ENDPOINTS', false) || isset($_COOKIE['api-test_endpoints']) && $_COOKIE['api-test_endpoints'] === 'yes',
'signer' => [
'method' => $method,
'url' => $url,
'close_when_done' => false
]
];
// -- PROXY CONFIG -- //
$proxy_host = Misc::env('PROXY_HOST', '');
$proxy_port = Misc::env('PROXY_PORT', '');
if ($proxy_host && $proxy_port) {
$options['proxy'] = [
'host' => $proxy_host,
'port' => $proxy_port,
'username' => Misc::env('PROXY_USERNAME', null),
'password' => Misc::env('PROXY_PASSWORD', null)
];
}
// Cache config
$cacheEngine = null;
if (isset($_ENV['API_CACHE'])) {
switch ($_ENV['API_CACHE']) {
case CacheMethods::JSON:
$cacheEngine = new JSONCache();
break;
case CacheMethods::APCU:
$cacheEngine = new ApcuCache();
break;
case CacheMethods::REDIS:
if (!(isset($_ENV['REDIS_URL']) || isset($_ENV['REDIS_HOST'], $_ENV['REDIS_PORT']))) {
throw new \Exception('You need to set REDIS_URL or REDIS_HOST and REDIS_PORT to use Redis Cache!');
}
if (isset($_ENV['REDIS_URL'])) {
$url = parse_url($_ENV['REDIS_URL']);
$host = $url['host'];
$port = $url['port'];
$password = $url['pass'] ?? null;
} else {
$host = $_ENV['REDIS_HOST'];
$port = (int) $_ENV['REDIS_PORT'];
$password = isset($_ENV['REDIS_PASSWORD']) ? $_ENV['REDIS_PASSWORD'] : null;
}
$cacheEngine = new RedisCache($host, $port, $password);
break;
}
}
$customUa = Misc::env("USER_AGENT", '');
if ($customUa) {
$options['user_agent'] = $customUa;
}
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;
+4 -7
View File
@@ -3,14 +3,11 @@ namespace App\Models;
use TikScraper\Models\Discover;
/**
* Base for templates with a feed
*/
class DiscoverTemplate extends BaseTemplate {
public Discover $feed;
public Discover $data;
function __construct(Discover $feed) {
parent::__construct('Discover');
$this->feed = $feed;
function __construct(Discover $data) {
parent::__construct("Discover");
$this->data = $data;
}
}
+8 -3
View File
@@ -2,10 +2,15 @@
namespace App\Models;
class ErrorTemplate extends BaseTemplate {
public object $error;
public int $http_code = 502;
public ?int $tiktok_code = -1;
public string $msg = '';
function __construct(object $error) {
function __construct(int $http_code, string $msg, ?int $tiktok_code = null) {
parent::__construct('Error');
$this->error = $error;
$this->http_code = $http_code;
$this->msg = $msg;
$this->tiktok_code = $tiktok_code;
}
}
+19
View File
@@ -0,0 +1,19 @@
<?php
namespace App\Models;
use TikScraper\Models\Feed;
use TikScraper\Models\Info;
/**
* Base for templates with both info and feed
*/
class FullTemplate extends BaseTemplate {
public Info $info;
public Feed $feed;
function __construct(string $title, Info $info, Feed $feed) {
parent::__construct($title);
$this->info = $info;
$this->feed = $feed;
}
}
-34
View File
@@ -1,34 +0,0 @@
<?php
namespace App\Models;
/**
* Exclusive for /
*/
class HomeTemplate extends BaseTemplate {
public array $forms = [
[
'title' => 'Search by user',
'input' => 'user',
'placeholder' => 'Type username'
],
[
'title' => 'Search by video ID',
'input' => 'video',
'placeholder' => 'Type video ID'
],
[
'title' => 'Search by tag',
'input' => 'tag',
'placeholder' => 'Type tag'
],
[
'title' => 'Search by music ID',
'input' => 'music',
'placeholder' => 'Type music'
]
];
function __construct() {
parent::__construct('Home');
}
}
+15
View File
@@ -0,0 +1,15 @@
<?php
namespace App\Models;
class RSSTemplate extends BaseTemplate {
public string $desc;
public string $link;
public array $items;
function __construct(string $title, string $desc, string $link, array $items) {
parent::__construct($title);
$this->desc = $desc;
$this->link = $link;
$this->items = $items;
}
}
+22 -5
View File
@@ -1,16 +1,33 @@
<?php
namespace App\Models;
use App\Constants\Themes;
use App\Helpers\Cookies;
use TikScraper\Constants\DownloadMethods;
/**
* Exclusive for /settings
*/
* Settings model with all possible config items
*/
class SettingsTemplate extends BaseTemplate {
public array $proxy_elements = [];
public array $downloaders = [];
public array $themes = [];
public bool $isTestEndpoints = false;
public string $currentDownloader;
public string $currentTheme;
public bool $isServiceWorker = false;
function __construct() {
parent::__construct('Settings');
$this->proxy_elements = Cookies::PROXY;
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->isTestEndpoints = Cookies::check('api-test_endpoints', 'yes');
$this->currentDownloader = Cookies::downloader();
$this->currentTheme = Cookies::theme();
$this->isServiceWorker = Cookies::check('misc-sw', 'yes');
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
namespace App\Models;
use TikScraper\Models\Info;
/**
* Base for templates with a feed
*/
class VideoTemplate extends BaseTemplate {
public object $item;
public Info $info;
public string $layout = 'hero';
function __construct(object $item, Info $info, bool $isEmbed = false) {
parent::__construct('Video');
$this->item = $item;
$this->info = $info;
if ($isEmbed) {
$this->layout = 'embed';
} else {
$this->layout = 'hero';
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

-9
View File
@@ -1,9 +0,0 @@
<div class="tags">
{if !empty($following)}
{foreach $following as $user}
<span class="tag">{$user}</span>
{/foreach}
{else}
<p>None</p>
{/if}
</div>
-8
View File
@@ -1,8 +0,0 @@
<footer class="footer">
<div class="content has-text-centered">
<p>
Made with <span style="color: #e25555;">&#9829;</span> in <a href="https://github.com/pablouser1/ProxiTok">Github</a>
</p>
<p>Version: {version()}</p>
</div>
</footer>
-10
View File
@@ -1,10 +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/bulma.min.css')}">
<title>{$title} - ProxiTok</title>
</head>
-18
View File
@@ -1,18 +0,0 @@
<nav class="navbar" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<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>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbar-menu" class="navbar-menu">
<div class="navbar-start">
<a href="{path('/')}" class="navbar-item">Home</a>
<a href="{path('/settings')}" class="navbar-item">Settings</a>
<a href="{path('/about')}" class="navbar-item">About</a>
</div>
</div>
</nav>
<script src="{path('/scripts/navbar.js')}"></script>
-15
View File
@@ -1,15 +0,0 @@
<form action="{path('/settings/proxy')}" method="POST">
{foreach $proxy_elements as $proxy_element}
<div class="field">
<label class="label">{$proxy_element}</label>
<div class="control">
<input name="{$proxy_element}" class="input" value="{isset($_COOKIE[$proxy_element]) ? $_COOKIE[$proxy_element] : ''}" required />
</div>
</div>
{/foreach}
<div class="field">
<div class="control">
<button class="button is-success" type="submit">Submit</button>
</div>
</div>
</form>
+12 -6
View File
@@ -1,24 +1,30 @@
{
"name": "pablouser1/proxitok",
"description": "An alternative frontend for TikTok",
"version": "1.5.0",
"version": "2.4.8.0",
"license": "AGPL-3.0-or-later",
"type": "project",
"homepage": "https://github.com/pablouser1/ProxiTok",
"authors": [
{
"name": "Pablo Ferreiro",
"homepage": "https://github.com/pablouser1"
}
],
"homepage": "https://github.com/pablouser1/ProxiTok",
"config": {
"optimize-autoloader": true,
"platform": {
"php": "7.4"
}
},
"require": {
"php": ">=7.4|^8.0",
"ext-redis": "^5.3.2",
"ext-mbstring": "*",
"pablouser1/tikscraper": "^1.0",
"latte/latte": "^2.10",
"vlucas/phpdotenv": "^5.4",
"latte/latte": "^2.11",
"bramus/router": "^1.6",
"mibe/feedwriter": "^1.1"
"josegonzalez/dotenv": "dev-master",
"pablouser1/tikscraper": "^2.3"
},
"autoload": {
"psr-4": {
Generated
+256 -318
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "f5e451a254a58bf7d512421237641801",
"content-hash": "edc1f7ddb80ad13369e0536c32518ece",
"packages": [
{
"name": "bramus/router",
@@ -58,30 +58,76 @@
"time": "2021-11-18T19:24:07+00:00"
},
{
"name": "graham-campbell/result-type",
"version": "v1.0.4",
"name": "deemon47/user-agent-generator",
"version": "v1.0.1",
"source": {
"type": "git",
"url": "https://github.com/GrahamCampbell/Result-Type.git",
"reference": "0690bde05318336c7221785f2a932467f98b64ca"
"url": "https://github.com/Deemon47/user-agent-generator.git",
"reference": "5af13fd2e905c5441eb4d61aad3a71bd1e801709"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/0690bde05318336c7221785f2a932467f98b64ca",
"reference": "0690bde05318336c7221785f2a932467f98b64ca",
"url": "https://api.github.com/repos/Deemon47/user-agent-generator/zipball/5af13fd2e905c5441eb4d61aad3a71bd1e801709",
"reference": "5af13fd2e905c5441eb4d61aad3a71bd1e801709",
"shasum": ""
},
"require": {
"php": "^7.0 || ^8.0",
"phpoption/phpoption": "^1.8"
},
"require-dev": {
"phpunit/phpunit": "^6.5.14 || ^7.5.20 || ^8.5.19 || ^9.5.8"
},
"type": "library",
"autoload": {
"psr-4": {
"GrahamCampbell\\ResultType\\": "src/"
"Deemon47\\": "./"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-3.0-only"
],
"authors": [
{
"name": "phpfail",
"email": "phpfail@gihub.com"
},
{
"name": "Dee",
"email": "deemon47@gmail.com"
}
],
"description": "Generate random User-Agent http header with parameters",
"support": {
"source": "https://github.com/Deemon47/user-agent-generator/tree/v1.0.1"
},
"time": "2020-04-11T12:05:34+00:00"
},
{
"name": "josegonzalez/dotenv",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/josegonzalez/php-dotenv.git",
"reference": "f6d2fb63610f98b7ae859031566228dbade1a79c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/josegonzalez/php-dotenv/zipball/f6d2fb63610f98b7ae859031566228dbade1a79c",
"reference": "f6d2fb63610f98b7ae859031566228dbade1a79c",
"shasum": ""
},
"require": {
"m1/env": "2.*",
"php": ">=5.5.0"
},
"require-dev": {
"php-mock/php-mock-phpunit": "^1.1",
"satooshi/php-coveralls": "1.*",
"squizlabs/php_codesniffer": "2.*"
},
"default-branch": true,
"type": "library",
"autoload": {
"psr-0": {
"josegonzalez\\Dotenv": [
"src",
"tests"
]
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -90,62 +136,52 @@
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
"name": "Jose Diaz-Gonzalez",
"email": "dotenv@josegonzalez.com",
"homepage": "http://josediazgonzalez.com",
"role": "Maintainer"
}
],
"description": "An Implementation Of The Result Type",
"description": "dotenv file parsing for PHP",
"homepage": "https://github.com/josegonzalez/php-dotenv",
"keywords": [
"Graham Campbell",
"GrahamCampbell",
"Result Type",
"Result-Type",
"result"
"configuration",
"dotenv",
"php"
],
"support": {
"issues": "https://github.com/GrahamCampbell/Result-Type/issues",
"source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.0.4"
"issues": "https://github.com/josegonzalez/php-dotenv/issues",
"source": "https://github.com/josegonzalez/php-dotenv/tree/master"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type",
"type": "tidelift"
}
],
"time": "2021-11-21T21:41:47+00:00"
"time": "2019-07-07T21:21:39+00:00"
},
{
"name": "latte/latte",
"version": "v2.10.8",
"version": "v2.11.6",
"source": {
"type": "git",
"url": "https://github.com/nette/latte.git",
"reference": "596b28bf098ebb852732d60b00538139a009c4db"
"reference": "af4dbb23a6044b1cf4904830a9b00246318c93d4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/latte/zipball/596b28bf098ebb852732d60b00538139a009c4db",
"reference": "596b28bf098ebb852732d60b00538139a009c4db",
"url": "https://api.github.com/repos/nette/latte/zipball/af4dbb23a6044b1cf4904830a9b00246318c93d4",
"reference": "af4dbb23a6044b1cf4904830a9b00246318c93d4",
"shasum": ""
},
"require": {
"ext-json": "*",
"ext-tokenizer": "*",
"php": ">=7.1 <8.2"
"php": ">=7.1 <8.3"
},
"conflict": {
"nette/application": "<2.4.1"
},
"require-dev": {
"nette/php-generator": "^3.3.4",
"nette/tester": "~2.0",
"nette/tester": "^2.0",
"nette/utils": "^3.0",
"phpstan/phpstan": "^0.12",
"phpstan/phpstan": "^1",
"tracy/tracy": "^2.3"
},
"suggest": {
@@ -161,7 +197,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.10-dev"
"dev-master": "2.11-dev"
}
},
"autoload": {
@@ -199,127 +235,97 @@
],
"support": {
"issues": "https://github.com/nette/latte/issues",
"source": "https://github.com/nette/latte/tree/v2.10.8"
"source": "https://github.com/nette/latte/tree/v2.11.6"
},
"time": "2022-01-04T14:13:28+00:00"
"time": "2022-11-04T14:53:52+00:00"
},
{
"name": "mibe/feedwriter",
"version": "v1.1.1",
"name": "m1/env",
"version": "2.2.0",
"source": {
"type": "git",
"url": "https://github.com/mibe/FeedWriter.git",
"reference": "f4cc748ad8700e36663f08cfeebe7fd39b00eea2"
"url": "https://github.com/m1/Env.git",
"reference": "5c296e3e13450a207e12b343f3af1d7ab569f6f3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mibe/FeedWriter/zipball/f4cc748ad8700e36663f08cfeebe7fd39b00eea2",
"reference": "f4cc748ad8700e36663f08cfeebe7fd39b00eea2",
"url": "https://api.github.com/repos/m1/Env/zipball/5c296e3e13450a207e12b343f3af1d7ab569f6f3",
"reference": "5c296e3e13450a207e12b343f3af1d7ab569f6f3",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
"require-dev": {
"phpunit/phpunit": "4.*",
"scrutinizer/ocular": "~1.1",
"squizlabs/php_codesniffer": "^2.3"
},
"suggest": {
"josegonzalez/dotenv": "For loading of .env",
"m1/vars": "For loading of configs"
},
"type": "library",
"autoload": {
"psr-4": {
"FeedWriter\\": ""
"M1\\Env\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-3.0"
"MIT"
],
"authors": [
{
"name": "Michael Bemmerl",
"email": "mail@mx-server.de"
},
{
"name": "Phil Freo"
},
{
"name": "Paul Ferrett"
},
{
"name": "Brennen Bearnes"
},
{
"name": "Michael Robinson",
"email": "mike@pagesofinterest.net"
},
{
"name": "Baptiste Fontaine"
},
{
"name": "Kristián Valentín"
},
{
"name": "Brandtley McMinn"
},
{
"name": "Julian Bogdani"
},
{
"name": "Anis Uddin Ahmad",
"email": "anis.programmer@gmail.com"
},
{
"name": "Cedric Gampert"
},
{
"name": "Yamek"
},
{
"name": "thielj"
},
{
"name": "Pavel Khakhlou"
},
{
"name": "Daniel"
},
{
"name": "Tino Goratsch"
"name": "Miles Croxford",
"email": "hello@milescroxford.com",
"homepage": "http://milescroxford.com",
"role": "Developer"
}
],
"description": "Generate feeds in either RSS 1.0, RSS 2.0 or ATOM formats",
"homepage": "https://github.com/mibe/FeedWriter",
"description": "Env is a lightweight library bringing .env file parser compatibility to PHP. In short - it enables you to read .env files with PHP.",
"homepage": "https://github.com/m1/Env",
"keywords": [
"RSS 1.0",
"atom",
"feed",
"rss",
"rss 2.0",
"rss2"
".env",
"config",
"dotenv",
"env",
"loader",
"m1",
"parser",
"support"
],
"support": {
"issues": "https://github.com/mibe/FeedWriter/issues",
"source": "https://github.com/mibe/FeedWriter/tree/master"
"issues": "https://github.com/m1/Env/issues",
"source": "https://github.com/m1/Env/tree/2.2.0"
},
"time": "2016-11-19T20:47:44+00:00"
"time": "2020-02-19T09:02:13+00:00"
},
{
"name": "pablouser1/tikscraper",
"version": "v1.2.1",
"version": "v2.3.6.2",
"source": {
"type": "git",
"url": "https://github.com/pablouser1/TikScraperPHP.git",
"reference": "2022b2c2d661383d09c4727091df7fae345844a5"
"reference": "10394fb5fb5213d05fe0eb29f7582423fc15d08a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pablouser1/TikScraperPHP/zipball/2022b2c2d661383d09c4727091df7fae345844a5",
"reference": "2022b2c2d661383d09c4727091df7fae345844a5",
"url": "https://api.github.com/repos/pablouser1/TikScraperPHP/zipball/10394fb5fb5213d05fe0eb29f7582423fc15d08a",
"reference": "10394fb5fb5213d05fe0eb29f7582423fc15d08a",
"shasum": ""
},
"require": {
"php": ">=7.3|^8.0"
"deemon47/user-agent-generator": "^1.0",
"ext-curl": "*",
"ext-json": "*",
"ext-xml": "*",
"php": ">=7.4|^8.0",
"php-webdriver/webdriver": "^1.12",
"sapistudio/seleniumstealth": "^1.0"
},
"require-dev": {
"pestphp/pest": "^1.22"
},
"type": "library",
"autoload": {
@@ -333,181 +339,125 @@
],
"authors": [
{
"name": "Pablo Ferreiro"
"name": "Pablo Ferreiro",
"homepage": "https://pabloferreiro.es"
}
],
"description": "Get data from TikTok API",
"support": {
"issues": "https://github.com/pablouser1/TikScraperPHP/issues",
"source": "https://github.com/pablouser1/TikScraperPHP/tree/v1.2.1"
"source": "https://github.com/pablouser1/TikScraperPHP/tree/v2.3.6.2"
},
"time": "2022-02-13T20:28:38+00:00"
"time": "2023-04-01T13:46:50+00:00"
},
{
"name": "phpoption/phpoption",
"version": "1.8.1",
"name": "php-webdriver/webdriver",
"version": "1.14.0",
"source": {
"type": "git",
"url": "https://github.com/schmittjoh/php-option.git",
"reference": "eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15"
"url": "https://github.com/php-webdriver/php-webdriver.git",
"reference": "3ea4f924afb43056bf9c630509e657d951608563"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/schmittjoh/php-option/zipball/eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15",
"reference": "eab7a0df01fe2344d172bff4cd6dbd3f8b84ad15",
"url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/3ea4f924afb43056bf9c630509e657d951608563",
"reference": "3ea4f924afb43056bf9c630509e657d951608563",
"shasum": ""
},
"require": {
"php": "^7.0 || ^8.0"
"ext-curl": "*",
"ext-json": "*",
"ext-zip": "*",
"php": "^7.3 || ^8.0",
"symfony/polyfill-mbstring": "^1.12",
"symfony/process": "^5.0 || ^6.0"
},
"replace": {
"facebook/webdriver": "*"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.4.1",
"phpunit/phpunit": "^6.5.14 || ^7.5.20 || ^8.5.19 || ^9.5.8"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.8-dev"
}
},
"autoload": {
"psr-4": {
"PhpOption\\": "src/PhpOption/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"Apache-2.0"
],
"authors": [
{
"name": "Johannes M. Schmitt",
"email": "schmittjoh@gmail.com",
"homepage": "https://github.com/schmittjoh"
},
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
}
],
"description": "Option Type for PHP",
"keywords": [
"language",
"option",
"php",
"type"
],
"support": {
"issues": "https://github.com/schmittjoh/php-option/issues",
"source": "https://github.com/schmittjoh/php-option/tree/1.8.1"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption",
"type": "tidelift"
}
],
"time": "2021-12-04T23:24:31+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.24.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "30885182c981ab175d4d034db0f6f469898070ab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab",
"reference": "30885182c981ab175d4d034db0f6f469898070ab",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"provide": {
"ext-ctype": "*"
"ergebnis/composer-normalize": "^2.20.0",
"ondram/ci-detector": "^4.0",
"php-coveralls/php-coveralls": "^2.4",
"php-mock/php-mock-phpunit": "^2.0",
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpunit/phpunit": "^9.3",
"squizlabs/php_codesniffer": "^3.5",
"symfony/var-dumper": "^5.0 || ^6.0"
},
"suggest": {
"ext-ctype": "For best performance"
"ext-SimpleXML": "For Firefox profile creation"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
},
"files": [
"bootstrap.php"
]
"lib/Exception/TimeoutException.php"
],
"psr-4": {
"Facebook\\WebDriver\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for ctype functions",
"homepage": "https://symfony.com",
"description": "A PHP client for Selenium WebDriver. Previously facebook/webdriver.",
"homepage": "https://github.com/php-webdriver/php-webdriver",
"keywords": [
"compatibility",
"ctype",
"polyfill",
"portable"
"Chromedriver",
"geckodriver",
"php",
"selenium",
"webdriver"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.24.0"
"issues": "https://github.com/php-webdriver/php-webdriver/issues",
"source": "https://github.com/php-webdriver/php-webdriver/tree/1.14.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2021-10-20T20:35:02+00:00"
"time": "2023-02-09T12:12:19+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.24.0",
"name": "sapistudio/seleniumstealth",
"version": "1.0.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825"
"url": "https://github.com/Sapistudio/SeleniumStealth.git",
"reference": "4b392077e3d609fed564b78ae2e8becb98f01957"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825",
"reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825",
"url": "https://api.github.com/repos/Sapistudio/SeleniumStealth/zipball/4b392077e3d609fed564b78ae2e8becb98f01957",
"reference": "4b392077e3d609fed564b78ae2e8becb98f01957",
"shasum": ""
},
"type": "library",
"autoload": {
"psr-4": {
"SapiStudio\\SeleniumStealth\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"support": {
"issues": "https://github.com/Sapistudio/SeleniumStealth/issues",
"source": "https://github.com/Sapistudio/SeleniumStealth/tree/1.0.3"
},
"time": "2022-01-10T20:04:41+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"shasum": ""
},
"require": {
@@ -522,7 +472,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.23-dev"
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -561,7 +511,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.24.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
},
"funding": [
{
@@ -577,20 +527,20 @@
"type": "tidelift"
}
],
"time": "2021-11-30T18:21:41+00:00"
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.24.0",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "57b712b08eddb97c762a8caa32c84e037892d2e9"
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/57b712b08eddb97c762a8caa32c84e037892d2e9",
"reference": "57b712b08eddb97c762a8caa32c84e037892d2e9",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"shasum": ""
},
"require": {
@@ -599,7 +549,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.23-dev"
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -644,7 +594,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.24.0"
"source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
},
"funding": [
{
@@ -660,99 +610,87 @@
"type": "tidelift"
}
],
"time": "2021-09-13T13:58:33+00:00"
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "vlucas/phpdotenv",
"version": "v5.4.1",
"name": "symfony/process",
"version": "v5.4.22",
"source": {
"type": "git",
"url": "https://github.com/vlucas/phpdotenv.git",
"reference": "264dce589e7ce37a7ba99cb901eed8249fbec92f"
"url": "https://github.com/symfony/process.git",
"reference": "4b850da0cc3a2a9181c1ed407adbca4733dc839b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/264dce589e7ce37a7ba99cb901eed8249fbec92f",
"reference": "264dce589e7ce37a7ba99cb901eed8249fbec92f",
"url": "https://api.github.com/repos/symfony/process/zipball/4b850da0cc3a2a9181c1ed407adbca4733dc839b",
"reference": "4b850da0cc3a2a9181c1ed407adbca4733dc839b",
"shasum": ""
},
"require": {
"ext-pcre": "*",
"graham-campbell/result-type": "^1.0.2",
"php": "^7.1.3 || ^8.0",
"phpoption/phpoption": "^1.8",
"symfony/polyfill-ctype": "^1.23",
"symfony/polyfill-mbstring": "^1.23.1",
"symfony/polyfill-php80": "^1.23.1"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.4.1",
"ext-filter": "*",
"phpunit/phpunit": "^7.5.20 || ^8.5.21 || ^9.5.10"
},
"suggest": {
"ext-filter": "Required to use the boolean validator."
"php": ">=7.2.5",
"symfony/polyfill-php80": "^1.16"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.4-dev"
}
},
"autoload": {
"psr-4": {
"Dotenv\\": "src/"
}
"Symfony\\Component\\Process\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
"MIT"
],
"authors": [
{
"name": "Graham Campbell",
"email": "hello@gjcampbell.co.uk",
"homepage": "https://github.com/GrahamCampbell"
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Vance Lucas",
"email": "vance@vancelucas.com",
"homepage": "https://github.com/vlucas"
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.",
"keywords": [
"dotenv",
"env",
"environment"
],
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
"issues": "https://github.com/vlucas/phpdotenv/issues",
"source": "https://github.com/vlucas/phpdotenv/tree/v5.4.1"
"source": "https://github.com/symfony/process/tree/v5.4.22"
},
"funding": [
{
"url": "https://github.com/GrahamCampbell",
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv",
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2021-12-12T23:22:04+00:00"
"time": "2023-03-06T21:29:33+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"stability-flags": {
"josegonzalez/dotenv": 20
},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=7.4|^8.0",
"ext-redis": "^5.3.2",
"ext-mbstring": "*"
},
"platform-dev": [],
"plugin-api-version": "2.2.0"
"platform-overrides": {
"php": "7.4"
},
"plugin-api-version": "2.3.0"
}
+64
View File
@@ -0,0 +1,64 @@
version: '3'
services:
web:
container_name: proxitok-web
image: ghcr.io/pablouser1/proxitok:master
ports:
- 8080:80
environment:
- LATTE_CACHE=/cache
- API_CACHE=redis
- REDIS_HOST=proxitok-redis
- REDIS_PORT=6379
- API_SIGNER=remote
- API_SIGNER_URL=http://proxitok-signer:8080/signature
volumes:
- proxitok-cache:/cache
depends_on:
- redis
- signer
networks:
- proxitok
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
redis:
container_name: proxitok-redis
image: redis:7-alpine
command: redis-server --save 60 1 --loglevel warning
restart: unless-stopped
networks:
- proxitok
user: nobody
read_only: true
security_opt:
- no-new-privileges:true
tmpfs:
- /data:size=10M,mode=0770,uid=65534,gid=65534,noexec,nosuid,nodev
cap_drop:
- ALL
signer:
container_name: proxitok-signer
image: ghcr.io/pablouser1/signtok:master
networks:
- proxitok
user: nobody
read_only: true
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
volumes:
proxitok-cache:
networks:
proxitok:
+15
View File
@@ -0,0 +1,15 @@
// Workaround to allow TikTok embed
const blockquotes = document.getElementsByClassName('tiktok-embed')
for (let i = 0; i < blockquotes.length; i++) {
const blockquote = blockquotes[i]
if (blockquote.children.length > 0 && blockquote.children[0].tagName !== 'iframe') {
const iframe = document.createElement('iframe')
iframe.style = 'width: 100%; height: 710px; display: block; visibility: unset; max-height: 710px;'
iframe.src = 'https://www.tiktok.com/embed/v2/' + blockquote.dataset.videoId // This url will get redirected
// Remove placeholder section
blockquote.children[0].remove()
// Add iframe
blockquote.appendChild(iframe)
}
}
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

+6 -3
View File
@@ -1,9 +1,12 @@
<?php
require __DIR__ . "/vendor/autoload.php";
// LOAD DOTENV
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->safeLoad();
$dotenv = new josegonzalez\Dotenv\Loader(__DIR__ . '/.env');
$dotenv->raiseExceptions(false);
$result = $dotenv->parse();
if ($result !== false) {
$dotenv->toEnv();
}
// ROUTER
$router = new Bramus\Router\Router();
+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.
+8 -2
View File
@@ -10,9 +10,12 @@ $bulmaswatch-import-font: false;
@import "./node_modules/bulma/sass/base/_all.sass";
// Elements
@import "./node_modules/bulma/sass/elements/button.sass";
@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";
@import "./node_modules/bulma/sass/elements/tag.sass";
@import "./node_modules/bulma/sass/elements/title.sass";
@@ -21,13 +24,16 @@ $bulmaswatch-import-font: false;
@import "./node_modules/bulma/sass/form/shared.sass";
@import "./node_modules/bulma/sass/form/input-textarea.sass";
@import "./node_modules/bulma/sass/form/checkbox-radio.sass";
@import "./node_modules/bulma/sass/form/select.sass";
@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";
@import "./node_modules/bulma/sass/components/modal.sass";
@import "./node_modules/bulma/sass/components/navbar.sass";
@import "./node_modules/bulma/sass/components/media.sass";
// Grids
@import "./node_modules/bulma/sass/grid/columns.sass";
+23
View File
@@ -0,0 +1,23 @@
@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";
// Feed
@import "./node_modules/css.gg/icons/scss/feed.scss";
@import "./node_modules/css.gg/icons/scss/eye.scss";
@import "./node_modules/css.gg/icons/scss/heart.scss";
@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/lock.scss";
@import "./node_modules/css.gg/icons/scss/lock-unlock.scss";
// Video
@import "./node_modules/css.gg/icons/scss/music.scss";
+14
View File
@@ -0,0 +1,14 @@
{
"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"
},
"dependencies": {
"bulma": "^0.9.3",
"bulmaswatch": "^0.8.1",
"css.gg": "^2.0.0",
"sass": "^1.46.0"
}
}
+18 -13
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"
@@ -23,9 +23,9 @@ braces@~3.0.2:
fill-range "^7.0.1"
bulma@^0.9.3:
version "0.9.3"
resolved "https://registry.yarnpkg.com/bulma/-/bulma-0.9.3.tgz#ddccb7436ebe3e21bf47afe01d3c43a296b70243"
integrity sha512-0d7GNW1PY4ud8TWxdNcP6Cc8Bu7MxcntD/RRLGWuiw/s0a9P+XlH/6QoOIrmbj6o8WWJzJYhytiu9nFjTszk1g==
version "0.9.4"
resolved "https://registry.yarnpkg.com/bulma/-/bulma-0.9.4.tgz#0ca8aeb1847a34264768dba26a064c8be72674a1"
integrity sha512-86FlT5+1GrsgKbPLRRY7cGDg8fsJiP/jzTqXXVqiUZZ2aZT8uemEOHlU1CDU+TxklPEZ11HZNNWclRBBecP4CQ==
bulmaswatch@^0.8.1:
version "0.8.1"
@@ -47,6 +47,11 @@ bulmaswatch@^0.8.1:
optionalDependencies:
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==
fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
@@ -67,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.1.0"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.1.0.tgz#f795787f0db780183307b9eb2091fcac1f6fafef"
integrity sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==
is-binary-path@~2.1.0:
version "2.1.0"
@@ -81,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"
@@ -113,9 +118,9 @@ readdirp@~3.6.0:
picomatch "^2.2.1"
sass@^1.46.0:
version "1.49.7"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.49.7.tgz#22a86a50552b9b11f71404dfad1b9ff44c6b0c49"
integrity sha512-13dml55EMIR2rS4d/RDHHP0sXMY3+30e1TKsyXaSz3iLWVoDWEoboY8WzJd5JMnxrRHffKO3wq2mpJ0jxRJiEQ==
version "1.56.1"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.56.1.tgz#94d3910cd468fd075fa87f5bb17437a0b617d8a7"
integrity sha512-VpEyKpyBPCxE7qGDtOcdJ6fFbcpOM+Emu7uZLxVrkX8KVU/Dp5UF7WLvzqRuUhB6mqqQt1xffLoG+AndxTZrCQ==
dependencies:
chokidar ">=3.0.0 <4.0.0"
immutable "^4.0.0"
+15
View File
@@ -0,0 +1,15 @@
location / {
# try to serve file directly, fallback to rewrite
try_files $uri @rewriteapp;
}
location @rewriteapp {
# rewrite all to index.php
rewrite ^(.*)$ /index.php/$1 last;
}
location ~ ^/index\.php(/|$) {
try_files @heroku-fcgi @heroku-fcgi;
# ensure that /index.php isn't accessible directly, but only through a rewrite
internal;
}
+2
View File
@@ -0,0 +1,2 @@
User-agent: *
Disallow: /
+58 -9
View File
@@ -1,20 +1,60 @@
<?php
/** @var \Bramus\Router\Router $router */
use App\Helpers\ErrorHandler;
use App\Helpers\Misc;
use App\Helpers\Wrappers;
use App\Models\BaseTemplate;
use App\Models\HomeTemplate;
$router->set404(function () {
ErrorHandler::showText(404, "That endpoint doesn't exist");
});
$router->get('/', function () {
$latte = Misc::latte();
$latte->render(Misc::getView('home'), new HomeTemplate);
Wrappers::latte('home', new BaseTemplate('Home'));
});
$router->get('/about', function () {
$latte = Misc::latte();
$latte->render(Misc::getView('about'), new BaseTemplate('About'));
Wrappers::latte('about', new BaseTemplate('About'));
});
$router->get('/verify', function () {
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('/redirect', 'RedirectController@redirect');
$router->get('/download', 'ProxyController@download');
$router->get('/redirect/search', 'RedirectController@search');
$router->get('/redirect/download', 'RedirectController@download');
$router->mount('/trending', function () use ($router) {
$router->get('/', 'TrendingController@get');
@@ -23,13 +63,17 @@ $router->mount('/trending', function () use ($router) {
$router->mount('/@([^/]+)', function () use ($router) {
$router->get('/', 'UserController@get');
$router->get('/video/(\w+)', 'UserController@video');
$router->get('/rss', 'UserController@rss');
});
// Deprecated, please use /@USERNAME/video/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');
$router->mount('/tag/([^/]+)', function () use ($router) {
$router->get('/', 'TagController@get');
$router->get('/rss', 'TagController@rss');
});
@@ -38,7 +82,12 @@ $router->get('/music/([^/]+)', 'MusicController@get');
// -- Settings -- //
$router->mount('/settings', function () use ($router) {
$router->get('/', 'SettingsController@index');
$router->post('/proxy', 'SettingsController@proxy');
$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
-1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-11
View File
@@ -1,11 +0,0 @@
This facilities making the bulma.min.css file, install all dependencies using:
```
yarn install
```
And then use:
```
yarn bulma
```
This compiles bulma.scss to a css file and helps lowering the size of the css that will be sent to the user.
-12
View File
@@ -1,12 +0,0 @@
{
"name": "proxitok-scss",
"private": true,
"scripts": {
"bulma": "sass --style=compressed bulma.scss ../bulma.min.css"
},
"dependencies": {
"bulma": "^0.9.3",
"bulmaswatch": "^0.8.1",
"sass": "^1.46.0"
}
}
+1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
{"version":3,"sourceRoot":"","sources":["../../misc/scss/node_modules/css.gg/icons/scss/home.scss","../../misc/scss/node_modules/css.gg/icons/scss/options.scss","../../misc/scss/node_modules/css.gg/icons/scss/info.scss","../../misc/scss/node_modules/css.gg/icons/scss/code-slash.scss","../../misc/scss/node_modules/css.gg/icons/scss/search.scss","../../misc/scss/node_modules/css.gg/icons/scss/feed.scss","../../misc/scss/node_modules/css.gg/icons/scss/eye.scss","../../misc/scss/node_modules/css.gg/icons/scss/heart.scss","../../misc/scss/node_modules/css.gg/icons/scss/comment.scss","../../misc/scss/node_modules/css.gg/icons/scss/share.scss","../../misc/scss/node_modules/css.gg/icons/scss/software-download.scss","../../misc/scss/node_modules/css.gg/icons/scss/lock.scss","../../misc/scss/node_modules/css.gg/icons/scss/lock-unlock.scss","../../misc/scss/node_modules/css.gg/icons/scss/music.scss"],"names":[],"mappings":"AAAA,SACE,yLACA,sBACA,kBACA,cACA,+BACA,WACA,YACA,iBACA,aACA,gBACA,4BACA,2BACA,6BACA,4BACA,mBAEA,gBACE,WACA,cACA,sBACA,kBAGF,iBACE,WACA,cACA,sBACA,kBACA,qBACA,sBACA,2BACA,wBACA,SACA,kBACA,WACA,YACA,OAGF,gBACE,UACA,YACA,iBACA,oBACA,4BACA,6BACA,gBACA,SACA,SCjDJ,YACI,sBACA,kBACA,cACA,+BACA,WACA,WACA,qCAEA,mBACE,WACA,cACA,sBACA,kBACA,UACA,WACA,iBACA,mBAGF,oBACE,WACA,cACA,sBACA,kBACA,UACA,WACA,iBACA,mBACA,SACA,UAGF,mBACE,YACA,WCnCN,SACI,sBACA,kBACA,cACA,+BACA,WACA,YACA,iBACA,mBAEA,iCACE,WACA,cACA,sBACA,kBACA,kBACA,UACA,wBACA,SAGF,gBACE,WACA,WAGF,iBACE,WACA,QC5BN,eACI,cACA,kBACA,sBACA,6CACA,UACA,YACA,wBAEA,sBACE,WACA,cACA,sBACA,kBACA,UACA,WACA,yBAGF,uBACE,WACA,cACA,sBACA,kBACA,UACA,WACA,yBACA,sBACA,qBACA,UACA,QAGF,sBACE,uBACA,wBACA,WACA,QCrCN,WACI,sBACA,kBACA,cACA,+BACA,WACA,YACA,iBACA,mBACA,iBACA,gBAEA,kBACE,WACA,cACA,sBACA,kBACA,kBACA,UACA,WACA,wBACA,yBACA,SACA,UCvBN,SACI,cACA,sBACA,wBACA,sBASA,iBACA,gBACA,kBACA,+BACA,UACA,WACA,kBAbA,iCACE,cACA,sBACA,wBACA,sBAWF,iCACE,WACA,kBACA,kBACA,WACA,WACA,QACA,SACA,WAGF,gBACE,UACA,QACA,WCnCN,QACI,kBACA,cACA,+BACA,WACA,YACA,iCACA,gCACA,gBACA,sBAEA,+BACE,WACA,cACA,oBACA,kBACA,sBAGF,eACE,QACA,8CACA,WACA,YAGF,gBACE,UACA,WACA,iBACA,WACA,SC/BN,UACI,iBACA,6BACA,8BACA,WACA,WACA,gBAeA,sBACA,kBACA,gHACA,cAhBA,iBACE,iBACA,6BACA,8BACA,WACA,WACA,gBACA,WACA,cACA,sBACA,kBAQF,kBACE,WACA,cACA,sBACA,kBAGF,iBACE,WACA,wBACA,QAGF,kBACE,WACA,YACA,sBACA,wBACA,UACA,QC7CN,YACI,sBACA,kBACA,cACA,+BACA,WACA,YACA,iBACA,gBACA,0CAEA,mBACE,WACA,cACA,sBACA,kBACA,UAGF,oBACE,WACA,cACA,sBACA,kBACA,UACA,iBACA,+BACA,+BACA,UACA,YACA,WAGF,mBACE,WACA,wBACA,qBACA,SACA,QCtCN,UACI,sBACA,kBACA,cACA,+BACA,UACA,WACA,wBACA,oBACA,kCAEA,iBACE,WACA,cACA,sBACA,kBACA,kBACA,WACA,WACA,wBACA,SAGF,kBACE,WACA,cACA,sBACA,kBACA,kBACA,WACA,WACA,wBACA,SACA,MACA,yBAGF,iBACE,SACA,wBCvCN,sBACI,sBACA,kBACA,cACA,+BACA,WACA,WACA,iBACA,aACA,8BACA,+BACA,eAEA,6BACE,WACA,cACA,sBACA,kBACA,UACA,WACA,sBACA,wBACA,yBACA,SACA,WAGF,8BACE,WACA,cACA,sBACA,kBACA,kBACA,UACA,YACA,wBACA,SACA,WCrCN,SACI,sBACA,kBACA,cACA,+BACA,WACA,YACA,iBACA,4BACA,2BACA,4BACA,iBAEA,gBACE,WACA,cACA,sBACA,kBACA,WACA,YACA,kBACA,+BACA,qBACA,UACA,QCxBN,gBACI,sBACA,kBACA,cACA,+BACA,WACA,WACA,iBACA,8BACA,6BACA,4BACA,iBACA,iBAEA,+CACE,WACA,cACA,sBACA,kBAGF,uBACE,+BACA,qBACA,WACA,YACA,kBACA,UACA,SAGF,wBACE,UACA,WACA,wBACA,UACA,QCpCN,UACI,cACA,sBACA,iBAQA,2BACA,4BACA,gBACA,gBACA,kBACA,6CACA,WACA,YAbA,mCACE,cACA,sBACA,iBAYF,mCACE,WACA,kBACA,UACA,WACA,QACA,UACA,uBACA,mBAGF,iBACE","file":"cssgg.min.css"}
+1
View File
@@ -0,0 +1 @@
{include './themes/' . theme() . '.latte'}
+10
View File
@@ -0,0 +1,10 @@
<form action="{path($path)}" method="{$method}">
{block fields}{/block}
{ifset $submit}
<div class="field">
<div class="control">
<button class="button is-success" type="submit">Submit</button>
</div>
</div>
{/ifset}
</form>
+35
View File
@@ -0,0 +1,35 @@
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="apple-touch-icon" sizes="180x180" href="{path('/apple-touch-icon.png')}">
<link rel="icon" type="image/png" sizes="32x32" href="{path('/favicon-32x32.png')}">
<link rel="icon" type="image/png" sizes="16x16" href="{path('/favicon-16x16.png')}">
<link rel="manifest" href="{path('/manifest')}">
{if isset($og, $og_content, $og_url)}
<!-- Using TikTok's meta config -->
<meta property="og:title" content="{$og->title}" />
<meta property="og:description" content="{$og->description}" />
<meta property="og:url" content="{$og_url}" />
<meta property="og:image" content="{url_stream($og_content)}" />
<meta property="twitter:title" content="{$og->title}" />
<meta property="twitter:description" content="{$og->description}" />
<meta property="twitter:image" content="{url_stream($og_content)}" />
{else}
<!-- Using predifined ProxiTok config -->
<meta property="og:title" content="{$title}" />
<meta property="og:description" content="Alternative frontend for TikTok" />
<meta property="twitter:title" content="{$title}" />
<meta property="twitter:description" content="Alternative frontend for TikTok" />
{/if}
<meta property="og:site_name" content="ProxiTok" />
<meta property="og:type" content="website" />
<meta property="twitter:card" content="summary" />
<meta property="twitter:site" content="ProxiTok" />
{if isset($has_rss)}
<link rel="alternate" type="application/rss+xml" title="{$title}" href="{$_SERVER['REQUEST_URI'] . '/rss'}" />
{/if}
<link rel="stylesheet" href="{static('css', 'cssgg.min.css', true)}">
<link rel="stylesheet" href="{static('css', 'bulma.min.css', true)}">
<title>{$title} - ProxiTok</title>
</head>
+14
View File
@@ -0,0 +1,14 @@
{define icon_common, $icon}
<span class="icon">
<i class="gg-{$icon}"></i>
</span>
{/define}
{if isset($text)}
<span class="icon-text">
{include icon_common, icon: $icon}
<span>{$text}</span>
</span>
{else}
{include icon_common, icon: $icon}
{/if}
+29
View File
@@ -0,0 +1,29 @@
<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>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbar-menu" class="navbar-menu">
<div class="navbar-start">
<a href="{path('/settings')}" class="navbar-item">
{include './icon.latte', icon: 'options', text: '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="{static('js', 'navbar.js')}"></script>
+3
View File
@@ -0,0 +1,3 @@
<a href="{$_SERVER['REQUEST_URI'] . '/rss'}">
{include './icon.latte', icon: 'feed', text: 'RSS Feed'}
</a>
+31
View File
@@ -0,0 +1,31 @@
{embed '../form.latte', path: '/settings/api', method: 'POST', submit: true}
{block fields}
<div class="field">
<label class="label">Use test endpoints</label>
<div class="control">
<label class="radio">
<input type="radio" name="api-test_endpoints" value="yes" n:attr="checked => $isTestEndpoints" />
<span>Yes</span>
</label>
<label class="radio">
<input type="radio" name="api-test_endpoints" value="no" n:attr="checked => !$isTestEndpoints" />
<span>No</span>
</label>
</div>
<p class="help">This <i>may</i> help bypass rate limits</p>
</div>
<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,29 +1,27 @@
<link rel="stylesheet" href="{path('/styles/feed.css')}">
<noscript>JavaScript is required for this section to work!</noscript>
<link rel="stylesheet" href="{static('css', 'themes/card.css')}">
<section class="section">
<noscript>JavaScript is required for this section to work!</noscript>
<div class="columns is-multiline is-vcentered">
{foreach $feed->items as $item}
{do $share_url = 'https://tiktok.com/@' . $item->author->uniqueId . '/video/' . $item->id}
{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('/stream?url=' . urlencode($item->video->playAddr) . '&download=1&id=' . $item->id . '&user=' . $item->author->uniqueId) . '&watermark='}"
data-video_download_nowatermark="{path('/stream?download=1&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}
</div>
<div class="buttons">
{if isset($_GET['cursor']) && $_GET['cursor'] != 0 }
<a class="button is-danger" href="?">First</a>
<button class="button is-danger" onclick="history.back()">Back</button>
{if empty($feed->items)}
<p class="title">No items sent by TikTok!</p>
{/if}
<a n:attr="disabled => !$feed->hasMore" class="button is-success" href="?cursor={$feed->maxCursor}">Next</a>
</div>
</div>
{include './common/controls.latte'}
</section>
<!-- MODAL -->
@@ -39,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 />
@@ -47,9 +46,16 @@
<button class="button is-primary" onclick="copyShare()">Copy</button>
</div>
</div>
<div class="buttons is-centered">
<a target="_blank" id="download_watermark" class="button is-info">Download with watermark</a>
<a target="_blank" id="download_nowatermark" class="button is-info">Download without watermark</a>
<div id="download_dropdown" class="dropdown is-hoverable">
<div class="dropdown-trigger">
<button id="download_button" class="button" aria-haspopup="true" aria-controls="dropdown-menu">Download</button>
</div>
<div class="dropdown-menu" role="menu">
<div class="dropdown-content">
<a id="download_watermark" target="_blank" class="dropdown-item">With watermark</a>
<a id="download_nowatermark" target="_blank" class="dropdown-item">Without watermark</a>
</div>
</div>
</div>
<p id="audio_title"></p>
<audio id="audio" controls preload="none"></audio>
@@ -61,4 +67,4 @@
</footer>
</div>
</div>
<script src="{path('/scripts/feed.js')}"></script>
<script src="{static('js', 'themes/card.js')}"></script>
@@ -0,0 +1,19 @@
{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}
<div n:class="columns, is-centered, is-vcentered, is-multiline, $isBig ? is-mobile">
{foreach $item->imagePost->images as $image}
{if $isBig}
<div class="column is-half">
{else}
<div class="column is-one-third-tablet is-one-third-desktop is-one-quarter-widescreen is-one-fifth-fullhd">
{/if}
<figure class="image">
<img width="{$image->imageWidth}" height="{$image->imageHeight}" src="{$image->imageURL->urlList[0]}" />
</figure>
</div>
{/foreach}
</div>
{/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->maxCursor}">Next</a>
</div>
@@ -0,0 +1,8 @@
<div class="field is-grouped is-grouped-centered">
<p class="control">
<a target="_blank" href="{url_download($playAddr, $uniqueId, $id, true)}" class="button is-info">Watermark</a>
</p>
<p class="control">
<a target="_blank" href="{url_download(url_video_external($uniqueId, $id), $uniqueId, $id, false)}" class="button is-success">No watermark</a>
</p>
</div>
@@ -0,0 +1,12 @@
<div class="field is-grouped is-grouped-centered">
<p class="control">
<a class="button is-success" href="{url_video_internal($uniqueId, $id)}">
{include '../../icon.latte', icon: 'lock', text: 'Instance'}
</a>
</p>
<p class="control">
<a class="button is-warning" href="{url_video_external($uniqueId, $id)}">
{include '../../icon.latte', icon: 'lock-unlock', text: 'Original'}
</a>
</p>
</div>
@@ -0,0 +1,6 @@
<p>
{include '../../icon.latte', icon: 'eye', text: number($playCount)}
{include '../../icon.latte', icon: 'heart', text: number($diggCount)}
{include '../../icon.latte', icon: 'comment', text: number($commentCount)}
{include '../../icon.latte', icon: 'share', text: number($shareCount)}
</p>
@@ -0,0 +1,5 @@
<div class="tags">
{foreach $challenges as $challenge}
<a class="tag is-rounded" href="{path('/tag/' . $challenge->title)}">#{$challenge->title}</a>
{/foreach}
</div>
+38
View File
@@ -0,0 +1,38 @@
<div class="container">
{foreach $feed->items as $item}
<article class="media">
<figure class="media-left">
<p class="image is-64x64">
<img class="is-rounded" src="{url_stream($item->author->avatarThumb)}" />
</p>
</figure>
<div class="media-content">
<p>
<strong>{$item->author->nickname}</strong>
<small>
<a href="{url_user($item->author->uniqueId)}">@{$item->author->uniqueId}</a>
</small>
<small title="{date('M d, Y H:i:s e', $item->createTime)}">{date('M d, Y', $item->createTime)}</small>
</p>
{if !empty($item->challenges)}
<p>{include './common/tags.latte', challenges: $item->challenges}</p>
{/if}
<p n:ifcontent>{$item->desc}</p>
<p>Song: {$item->music->title}</p>
<audio controls preload="none" src="{$item->music->playUrl}"></audio>
{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>
<p class="has-text-centered"><b>Download video</b></p>
{include './common/download.latte', playAddr: $item->video->playAddr, id: $item->id, uniqueId: $item->author->uniqueId}
<p class="has-text-centered"><b>Share link</b></p>
{include './common/share.latte', uniqueId: $item->author->uniqueId, id: $item->id}
</div>
</article>
{/foreach}
{if empty($feed->items)}
<p class="title">No items sent by TikTok!</p>
{/if}
</div>
{include './common/controls.latte'}
@@ -15,7 +15,6 @@
<section class="section">
{block content}{/block}
</section>
{include '../components/footer.latte'}
{block extra}{/block}
</body>
</html>
+10
View File
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
{include '../components/head.latte'}
<body>
{block content}{/block}
{block extra}{/block}
</body>
</html>
@@ -9,12 +9,9 @@
{include '../components/navbar.latte'}
</div>
<div class="hero-body">
<div class="container has-text-centered">
<div class="container">
{block content}{/block}
</div>
</div>
<div class="hero-foot">
{include '../components/footer.latte'}
</div>
</section>
{block extra}{/block}
+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}
@@ -5,7 +5,7 @@
{/block}
{block content}
{foreach $feed->items as $type => $items}
{foreach $data->items as $type => $items}
<p class="title">{$type|firstUpper}</p>
<div class="columns is-multiline is-vcentered">
{foreach $items as $item}
@@ -17,7 +17,7 @@
{if !empty($item->cardItem->cover)}
<div class="media-left">
<figure class="image is-96x96">
<img width="96" height="96" src="{path('/stream?url=' . urlencode($item->cardItem->cover))}" />
<img loading="lazy" width="96" height="96" src="{path('/stream?url=' . urlencode($item->cardItem->cover))}" />
</figure>
</div>
{/if}
+18
View File
@@ -0,0 +1,18 @@
{layout '../layouts/hero.latte'}
{block content}
<p class="title">There was an error processing your request!</p>
<div class="content">
<p>HTTP Code: {$http_code}</p>
{if isset($tiktok_code)}
<p>
<span>API error code {$tiktok_code} ({$msg})</span>
{if $tiktok_code === 10000 || $tiktok_code === -1}
<a href="{path('/verify')}">What does this mean?</a>
{/if}
</p>
{else}
<p>{$msg}</p>
{/if}
</div>
{/block}
+41
View File
@@ -0,0 +1,41 @@
{layout '../layouts/hero.latte'}
{block content}
<p class="title has-text-centered">Welcome to ProxiTok!</p>
<p class="subtitle has-text-centered">An alternative open source frontend for TikTok</p>
{embed '../components/form.latte', path: '/redirect/search', method: 'GET'}
{block fields}
<div class="field has-addons has-addons-centered">
<div class="control">
<input class="input" name="term" placeholder="Search" required>
</div>
<div class="control">
<div class="select">
<select name="type">
<option value="url">TikTok URL</option>
<option value="user">Username</option>
<option value="tag">Tag</option>
<option value="music">Music ID</option>
<option value="video">Video ID</option>
</select>
</div>
</div>
<div class="control">
<button type="submit" class="button is-success">
{include '../components/icon.latte', icon: 'search', text: 'Search'}
</a>
</div>
</div>
{/block}
{/embed}
<div class="columns is-centered is-mobile">
<div class="column is-narrow">
<p>Discover</p>
<a class="button is-success" href="{path('/discover')}">Go</a>
</div>
<div class="column is-narrow">
<p>Trending</p>
<a class="button is-success" href="{path('/trending')}">Go</a>
</div>
</div>
{/block}
+11
View File
@@ -0,0 +1,11 @@
{layout '../layouts/default.latte'}
{block header}
<p class="title">{$info->detail->title}</p>
<p class="subtitle">{$info->detail->desc}</p>
<p>Videos: {number($info->stats->videoCount)}</p>
{/block}
{block content}
{include '../components/feed.latte'}
{/block}

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