Skip to content

Commit

Permalink
feat: snaptik slideshow
Browse files Browse the repository at this point in the history
  • Loading branch information
krypton-byte committed Nov 27, 2023
1 parent 98d1e9a commit d97c5c1
Show file tree
Hide file tree
Showing 7 changed files with 1,510 additions and 136 deletions.
1,273 changes: 1,273 additions & 0 deletions poetry.lock

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[tool.poetry]
name = "tiktok-downloader"
version = "0.1.0"
description = "tiktok downloader"
authors = ["krypton-byte <[email protected]>"]
license = "GPL-3.0"
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.11"
bs4 = "^0.0.1"
flask = "^3.0.0"
cloudscraper = "^1.2.71"
requests = "^2.31.0"
tqdm = "^4.66.1"
rich = "^13.7.0"
httpx = "^0.25.2"
aiohttp = "^3.9.1"
moviepy = "^1.0.3"
js2py = "^0.74"


[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
4 changes: 3 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ requests
tqdm
rich
httpx
aiohttp
aiohttp
moviepy
pyjsparser
Empty file added test.json
Empty file.
3 changes: 3 additions & 0 deletions tiktok_downloader/Except.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
class InvalidUrl(Exception):
pass

class NoImageToSlideshow(Exception):
pass
148 changes: 75 additions & 73 deletions tiktok_downloader/snaptik.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import re
from bs4 import BeautifulSoup
from httpx import AsyncClient
from sys import stderr
from ast import literal_eval
from .utils import Download, DownloadAsync
import pyjsparser
from .utils import Download, DownloadAsync, Type, extension_to_type
from .Except import InvalidUrl
from requests import Session
from re import findall
Expand All @@ -11,141 +14,140 @@


class Snaptik(Session):
'''
"""
:param tiktok_url:
```python
>>> tik=snaptik('url')
>>> tik.get_media()
[<[type:video]>, <[type:video]>]
```
'''
"""

def __init__(self, tiktok_url: str) -> None:
super().__init__()
self.headers: dict[str, str] = {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/86.0.4240.111 Safari/537.36'
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/86.0.4240.111 Safari/537.36"
}
self.tiktok_url = tiktok_url

def render(self, token, interval: int = 1):
result = self.get('https://snaptik.app/render.php', params={'token': token}).json()
while True:
resp = self.get("https://snaptik.app/task.php", params={'token': result['task_id']}).json()
if resp['progress'] == 100:
return Download(resp['download_url'], self, Type.VIDEO)

def get_media(self) -> list[Download]:
'''
"""
```python
>>> <snaptik object>.get_media()
[<[type:video]>, <[type:video]>]
```
'''
"""
result = []
resp = cloudscraper.create_scraper().get(
'https://snaptik.app/abc2.php',
"https://snaptik.app/abc2.php",
params={
'url': self.tiktok_url,
'lang': 'en',
"url": self.tiktok_url,
"lang": "en",
**dict(
findall(
'name="(token)" value="(.*?)"',
self.get('https://snaptik.app/en').text))}
self.get("https://snaptik.app/en").text,
)
),
},
)
if 'error_api_web;' in resp.text or 'Error:' in resp.text:
if "error_api_web;" in resp.text or "Error:" in resp.text:
raise InvalidUrl()
stderr.flush()
dec = decoder(*literal_eval(
findall(
r'\(\".*?,.*?,.*?,.*?,.*?.*?\)',
resp.text
)[0]
))

stderr.flush()

current_url = urlparse(resp.url).scheme + "://" + urlparse(resp.url).netloc
links_list = [
i for i in findall(r'<a href=\\"(https?://[\w\./\-&?=]+)', dec)
] + [
current_url + i.strip('\\') for i in findall(r'(/file.php?.*?)\"', dec)
dec = decoder(
*literal_eval(findall(r"\(\".*?,.*?,.*?,.*?,.*?.*?\)", resp.text)[0])
)
dec = pyjsparser.parse(re.sub(r"(async|await)", "", dec))["body"][0][
"consequent"
]["body"][0]["consequent"]["body"][1]["expression"]["right"]["value"]
bs = BeautifulSoup(dec)
for vl in bs.find_all("div", attrs={"class","video-links"}):
for a in vl.find_all("a"):
result.append(Download(a["href"] if a['href'].startswith('http') else 'https://snaptik.app' + a['href'], self, Type.VIDEO))
for button in vl.find_all("button"):
try:
result.append(Download(button['data-backup'], self, Type.VIDEO))
except KeyError:
result.append(Download('', self, Type.VIDEO, render=lambda invertal: self.render(button['data-token'])))
result.extend(
[
Download(obj["href"], self, Type.IMAGE)
for obj in bs.find_all(
"a", attrs={"data-event": "download_albumPhoto_photo"}
)
]

# If our video is slideshow - download link will have "?type=dl", so let's move it to the 1 place
index_to_move = None
for index, link in enumerate(links_list):
if "?type=dl" in link:
index_to_move = index
break

# Move the link to the first position (0 index) if found
if index_to_move is not None:
links_list.insert(0, links_list.pop(index_to_move))

return [
Download(
i,
self
) for i in links_list
]
)
return result

def __iter__(self):
yield from self.get_media()


class SnaptikAsync(AsyncClient):
'''
"""
:param tiktok_url:
```python
>>> tik=snaptik('url')
>>> tik.get_media()
[<[type:video]>, <[type:video]>]
```
'''
"""

def __init__(self, tiktok_url: str) -> None:
super().__init__()
self.headers: dict[str, str] = {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/86.0.4240.111 Safari/537.36'
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/86.0.4240.111 Safari/537.36"
}
self.tiktok_url = tiktok_url

async def get_media(self) -> list[DownloadAsync]:
'''
"""
```python
>>> <snaptik object>.get_media()
[<[type:video]>, <[type:video]>]
```
'''
"""
resp = await self.get(
'https://snaptik.app/abc2.php',
"https://snaptik.app/abc2.php",
params={
'url': self.tiktok_url,
'lang': 'en',
"url": self.tiktok_url,
"lang": "en",
**dict(
findall(
'name="(token)" value="(.*?)"',
(await self.get('https://snaptik.app/en')).text))},
(await self.get("https://snaptik.app/en")).text,
)
),
},
)
if 'error_api_web;' in resp.text or 'Error:' in resp.text:
if "error_api_web;" in resp.text or "Error:" in resp.text:
raise InvalidUrl()
stderr.flush()
dec = decoder(*literal_eval(
findall(
r'\(\".*?,.*?,.*?,.*?,.*?.*?\)',
resp.text
)[0]
))
dec = decoder(
*literal_eval(findall(r"\(\".*?,.*?,.*?,.*?,.*?.*?\)", resp.text)[0])
)

stderr.flush()
return [
DownloadAsync(
i,
self
DownloadAsync(i, self)
for i in set(
[
"https://snaptik.app" + x.strip("\\")
for x in findall(r"(/file.php?.*?)\"", dec)
]
+ [i.strip("\\") for i in findall(r"\"(https?://snapxcdn.*?)\"", dec)]
)
for i in set(['https://snaptik.app' + x.strip('\\') for x in findall(
r'(/file.php?.*?)\"',
dec
)] + [i.strip('\\') for i in findall(
r'\"(https?://snapxcdn.*?)\"',
dec
)])
]

async def __aiter__(self):
Expand Down
Loading

1 comment on commit d97c5c1

@vercel
Copy link

@vercel vercel bot commented on d97c5c1 Nov 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.