@tobyg74/tiktok-api-dl
Version:
Scraper for downloading media in the form of videos, images and audio from Tiktok. Also for stalking Tiktok Users
194 lines (193 loc) • 7.19 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TiktokAPI = void 0;
const axios_1 = __importDefault(require("axios"));
const async_retry_1 = __importDefault(require("async-retry"));
const api_1 = require("../../constants/api");
const params_1 = require("../../constants/params");
const https_proxy_agent_1 = require("https-proxy-agent");
const socks_proxy_agent_1 = require("socks-proxy-agent");
const constants_1 = require("../../constants");
const TIKTOK_URL_REGEX = /https:\/\/(?:m|www|vm|vt|lite)?\.?tiktok\.com\/((?:.*\b(?:(?:usr|v|embed|user|video|photo)\/|\?shareId=|\&item_id=)(\d+))|\w+)/;
const USER_AGENT = "com.zhiliaoapp.musically/300904 (2018111632; U; Android 10; en_US; Pixel 4; Build/QQ3A.200805.001; Cronet/58.0.2991.0)";
const createProxyAgent = (proxy) => {
if (!proxy)
return {};
const isHttpProxy = proxy.startsWith("http") || proxy.startsWith("https");
const isSocksProxy = proxy.startsWith("socks");
if (!isHttpProxy && !isSocksProxy)
return {};
return {
httpsAgent: isHttpProxy
? new https_proxy_agent_1.HttpsProxyAgent(proxy)
: new socks_proxy_agent_1.SocksProxyAgent(proxy)
};
};
const validateTikTokUrl = (url) => {
return TIKTOK_URL_REGEX.test(url);
};
const extractVideoId = (responseUrl) => {
const matches = responseUrl.match(/\d{17,21}/g);
return matches ? matches[0] : null;
};
const parseStatistics = (content) => ({
commentCount: content.statistics.comment_count,
likeCount: content.statistics.digg_count,
shareCount: content.statistics.share_count,
playCount: content.statistics.play_count,
downloadCount: content.statistics.download_count
});
const parseAuthor = (content) => ({
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: `${api_1._tiktokurl}/@${content.author.unique_id}`
});
const parseMusic = (content) => ({
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
});
const parseVideo = (content) => ({
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 || []
});
const parseTiktokData = (ID, data) => {
const content = data?.aweme_list?.find((v) => v.aweme_id === ID);
if (!content)
return { content: null };
return {
content,
statistics: parseStatistics(content),
author: parseAuthor(content),
music: parseMusic(content)
};
};
const fetchTiktokData = async (ID, proxy) => {
try {
const response = await (0, async_retry_1.default)(async () => {
const res = await (0, axios_1.default)((0, api_1._tiktokvFeed)((0, params_1._tiktokApiParams)({ aweme_id: ID })), {
method: "OPTIONS",
headers: { "User-Agent": USER_AGENT },
...createProxyAgent(proxy)
});
if (res.data && res.data.status_code === 0) {
return res.data;
}
throw new Error(constants_1.ERROR_MESSAGES.NETWORK_ERROR);
}, {
retries: 20,
minTimeout: 200,
maxTimeout: 1000
});
return parseTiktokData(ID, response);
}
catch (error) {
console.error("Error fetching TikTok data:", error);
return null;
}
};
const createImageResponse = (content, author, statistics, music) => ({
status: "success",
result: {
type: "image",
id: content.aweme_id,
createTime: content.create_time,
desc: content.desc,
isTurnOffComment: content.item_comment_settings === 3,
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
}
});
const createVideoResponse = (content, author, statistics, music) => ({
status: "success",
result: {
type: "video",
id: content.aweme_id,
createTime: content.create_time,
desc: content.desc,
isTurnOffComment: content.item_comment_settings === 3,
hashtag: content.text_extra
.filter((x) => x.hashtag_name !== undefined)
.map((v) => v.hashtag_name),
isADS: content.is_ads,
author,
statistics,
video: parseVideo(content),
music
}
});
const TiktokAPI = async (url, proxy, showOriginalResponse) => {
try {
if (!validateTikTokUrl(url)) {
return {
status: "error",
message: constants_1.ERROR_MESSAGES.INVALID_URL
};
}
url = url.replace("https://vm", "https://vt");
const { request } = await (0, axios_1.default)(url, {
method: "HEAD",
...createProxyAgent(proxy)
});
const videoId = extractVideoId(request.res.responseUrl);
if (!videoId) {
return {
status: "error",
message: constants_1.ERROR_MESSAGES.INVALID_URL
};
}
const data = await fetchTiktokData(videoId, proxy);
if (!data?.content) {
return {
status: "error",
message: constants_1.ERROR_MESSAGES.NETWORK_ERROR
};
}
const { content, author, statistics, music } = data;
const response = content.image_post_info
? createImageResponse(content, author, statistics, music)
: createVideoResponse(content, author, statistics, music);
if (showOriginalResponse) {
return {
status: "success",
resultNotParsed: data
};
}
return response;
}
catch (error) {
return {
status: "error",
message: error instanceof Error ? error.message : constants_1.ERROR_MESSAGES.NETWORK_ERROR
};
}
};
exports.TiktokAPI = TiktokAPI;