2024-04-22 15:58:37 +02:00

175 lines
5.6 KiB
TypeScript

import Axios from "axios"
import { _tiktokapi, _tiktokurl } from "../../constants/api"
import { _tiktokApiParams } from "../../constants/params"
import { Author, TiktokAPIResponse, Statistics, Music, responseParser, Video } from "../../types/downloader/tiktokApi"
const TiktokURLregex = /https:\/\/(?:m|www|vm|vt|lite)?\.?tiktok\.com\/((?:.*\b(?:(?:usr|v|embed|user|video)\/|\?shareId=|\&item_id=)(\d+))|\w+)/
/**
* Tiktok API Downloader
* @param {string} url - Tiktok URL
* @returns {Promise<TiktokAPIResponse>}
*/
export const TiktokAPI = (url: string) =>
new Promise<TiktokAPIResponse>((resolve, reject) => {
if (!TiktokURLregex.test(url)) {
return resolve({
status: "error",
message: "Invalid Tiktok URL. Make sure your url is correct!"
})
}
url = url.replace("https://vm", "https://vt")
Axios.head(url)
.then(async ({ request }) => {
const { responseUrl } = request.res
let ID = responseUrl.match(/\d{17,21}/g)
if (ID === null)
return resolve({
status: "error",
message: "Failed to fetch tiktok url. Make sure your tiktok url is correct!"
})
ID = ID[0]
let data2 = await fetchTiktokData(ID)
if (!data2?.content) {
return resolve({
status: "error",
message: "Failed to fetch tiktok data. Make sure your tiktok url is correct!"
})
}
const { content, author, statistics, music } = data2
// Download Result
if (content.image_post_info) {
// Images or Slide Result
resolve({
status: "success",
result: {
type: "image",
id: content.aweme_id,
createTime: content.create_time,
description: content.desc,
hashtag: content.text_extra.filter((x) => x.hashtag_name !== undefined).map((v) => v.hashtag_name),
isADS: content.is_ads,
author,
statistics,
images: content.image_post_info.images.map((v) => v.display_image.url_list[0]),
music
}
})
} else {
// Video Result
const video: Video = {
ratio: content.video.ratio,
duration: content.video.duration,
playAddr: content.video.play_addr.url_list,
downloadAddr: content.video.download_addr.url_list,
cover: content.video.cover.url_list,
dynamicCover: content.video.dynamic_cover.url_list,
originCover: content.video.origin_cover.url_list
}
resolve({
status: "success",
result: {
type: "video",
id: content.aweme_id,
createTime: content.create_time,
description: content.desc,
hashtag: content.text_extra.filter((x) => x.hashtag_name !== undefined).map((v) => v.hashtag_name),
isADS: content.is_ads,
author,
statistics,
video,
music
}
})
}
})
.catch((e) => resolve({ status: "error", message: e.message }))
})
const fetchTiktokData = async (ID: string): Promise<responseParser> | null => {
const res = await fetch(
_tiktokapi(
new URLSearchParams(
_tiktokApiParams({
aweme_id: ID
})
).toString()
),
{
method: "GET",
headers: {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36"
}
}
)
if (res.headers.get("content-length") !== "0") {
const data = await res.json()
if (data) {
return parseTiktokData(ID, data)
}
}
return null
}
const parseTiktokData = (ID: string, data: any): responseParser => {
let content = data?.aweme_list
if (!content) return { content: null }
content = content.find((v: any) => v.aweme_id === ID)
// Statistics Result
const statistics: Statistics = {
commentCount: content.statistics.comment_count,
diggCount: content.statistics.digg_count,
downloadCount: content.statistics.download_count,
playCount: content.statistics.play_count,
shareCount: content.statistics.share_count,
forwardCount: content.statistics.forward_count,
loseCount: content.statistics.lose_count,
loseCommentCount: content.statistics.lose_comment_count,
whatsappShareCount: content.statistics.whatsapp_share_count,
collectCount: content.statistics.collect_count,
repostCount: content.statistics.repost_count
}
// Author Result
const author: Author = {
uid: content.author.uid,
username: content.author.unique_id,
nickname: content.author.nickname,
signature: content.author.signature,
region: content.author.region,
avatarThumb: content.author.avatar_thumb.url_list,
avatarMedium: content.author.avatar_medium.url_list,
url: `${_tiktokurl}/@${content.author.unique_id}`
}
// Music Result
const music: Music = {
id: content.music.id,
title: content.music.title,
author: content.music.author,
album: content.music.album,
playUrl: content.music.play_url.url_list,
coverLarge: content.music.cover_large.url_list,
coverMedium: content.music.cover_medium.url_list,
coverThumb: content.music.cover_thumb.url_list,
duration: content.music.duration,
isCommerceMusic: content.music.is_commerce_music,
isOriginalSound: content.music.is_original_sound,
isAuthorArtist: content.music.is_author_artist
}
return { content, statistics, author, music }
}