UNPKG

@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
"use strict"; 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;