diff --git a/src/utils/get/getUserLiked.ts b/src/utils/get/getUserLiked.ts index c9892e9..3bcd3e6 100644 --- a/src/utils/get/getUserLiked.ts +++ b/src/utils/get/getUserLiked.ts @@ -15,6 +15,7 @@ import { StatisticsAuthorLiked, ImagesLiked } from "../../types/get/getUserLiked" +import retry from "async-retry" export const getUserLiked = ( username: string, @@ -215,22 +216,38 @@ const requestUserLiked = async ( url.searchParams.append("X-Bogus", xbogus) const xttparams = Tiktok.generateXTTParams(url.searchParams.toString()) - const { data } = await Axios.get(`${url.toString()}`, { - headers: { - "user-agent": - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.35", - cookie, - "x-tt-params": xttparams + return await retry( + async (bail, attempt) => { + try { + const { data } = await Axios.get(url.toString(), { + headers: { + "user-agent": + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.35", + cookie, + "x-tt-params": xttparams + }, + httpsAgent: + (proxy && + (proxy.startsWith("http") || proxy.startsWith("https") + ? new HttpsProxyAgent(proxy) + : proxy.startsWith("socks") + ? new SocksProxyAgent(proxy) + : undefined)) || + undefined + }) + return data + } catch (error) { + if (attempt === 3) { + bail(error) + } + throw error + } }, - httpsAgent: - (proxy && - (proxy.startsWith("http") || proxy.startsWith("https") - ? new HttpsProxyAgent(proxy) - : proxy.startsWith("socks") - ? new SocksProxyAgent(proxy) - : undefined)) || - undefined - }) - - return data + { + retries: 3, + minTimeout: 1000, + maxTimeout: 5000, + factor: 2 + } + ) } diff --git a/src/utils/get/getUserPosts.ts b/src/utils/get/getUserPosts.ts index 480fc79..9644efd 100644 --- a/src/utils/get/getUserPosts.ts +++ b/src/utils/get/getUserPosts.ts @@ -10,6 +10,7 @@ import { HttpsProxyAgent } from "https-proxy-agent" import { SocksProxyAgent } from "socks-proxy-agent" import { TiktokService } from "../../services/tiktokService" import { StalkUser } from "../get/getProfile" +import retry from "async-retry" export const getUserPosts = ( username: string, @@ -58,14 +59,17 @@ const parseUserPosts = async ( let cursor = 0 const posts: Posts[] = [] let counter = 0 + + const Tiktok = new TiktokService() + const xttparams = Tiktok.generateXTTParams( + _xttParams(secUid, cursor, postLimit) + ) + while (hasMore) { let result: any | null = null // Prevent missing response posts - for (let i = 0; i < 30; i++) { - result = await requestUserPosts(secUid, cursor, postLimit, proxy) - if (result !== "") break - } + result = await requestUserPosts(proxy, xttparams) // Validate if (result === "") { @@ -161,33 +165,51 @@ const parseUserPosts = async ( } const requestUserPosts = async ( - secUid: string, - cursor: number = 0, - count: number = 30, - proxy?: string + proxy?: string, + xttparams: string = "" ): Promise => { - const Tiktok = new TiktokService() - - const { data } = await Axios.get( - `${_tiktokGetPosts(_getUserPostsParams())}`, - { - headers: { - "user-agent": - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.35", - "X-tt-params": Tiktok.generateXTTParams( - _xttParams(secUid, cursor, count) + return retry( + async (bail, attempt) => { + try { + const { data } = await Axios.get( + `${_tiktokGetPosts(_getUserPostsParams())}`, + { + headers: { + "user-agent": + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.35", + "x-tt-params": xttparams + }, + httpsAgent: + (proxy && + (proxy.startsWith("http") || proxy.startsWith("https") + ? new HttpsProxyAgent(proxy) + : proxy.startsWith("socks") + ? new SocksProxyAgent(proxy) + : undefined)) || + undefined + } ) - }, - httpsAgent: - (proxy && - (proxy.startsWith("http") || proxy.startsWith("https") - ? new HttpsProxyAgent(proxy) - : proxy.startsWith("socks") - ? new SocksProxyAgent(proxy) - : undefined)) || - undefined + console.log(data) + return data + } catch (error) { + if ( + error.response?.status === 400 || + error.response?.data?.statusCode === 10201 + ) { + bail(new Error("Video not found!")) + return + } + throw error + } + }, + { + retries: 3, + minTimeout: 1000, + maxTimeout: 5000, + factor: 2, + onRetry: (error, attempt) => { + console.log(`Retry attempt ${attempt} due to: ${error}`) + } } ) - - return data } diff --git a/src/utils/search/videoSearch.ts b/src/utils/search/videoSearch.ts index 4996ff2..ff77418 100644 --- a/src/utils/search/videoSearch.ts +++ b/src/utils/search/videoSearch.ts @@ -4,6 +4,7 @@ import { _liveSearchParams, _videoSearchParams } from "../../constants/params" import { SocksProxyAgent } from "socks-proxy-agent" import { HttpsProxyAgent } from "https-proxy-agent" import { TiktokService } from "../../services/tiktokService" +import retry from "async-retry" import { TiktokVideoSearchResponse, AuthorVideoSearch, @@ -36,119 +37,140 @@ export const SearchVideo = async ( }) } - const Tiktok = new TiktokService() - const url = new URL( - _tiktokSearchVideoFull(_videoSearchParams(keyword, page)) - ) - const signature = Tiktok.generateSignature(url) - url.searchParams.append("_signature", signature) - const xbogus = Tiktok.generateXBogus(url, signature) - url.searchParams.append("X-Bogus", xbogus) + try { + const data = await requestVideoSearch(keyword, page, cookie, proxy) - Axios(_tiktokSearchVideoFull(_videoSearchParams(keyword, page)), { - method: "GET", - headers: { - "User-Agent": - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0", - cookie: - typeof cookie === "object" - ? cookie.map((v: any) => `${v.name}=${v.value}`).join("; ") - : cookie - }, - httpsAgent: - (proxy && - (proxy.startsWith("http") || proxy.startsWith("https") - ? new HttpsProxyAgent(proxy) - : proxy.startsWith("socks") - ? new SocksProxyAgent(proxy) - : undefined)) || - undefined - }) - .then(({ data }) => { - // Cookie Invalid - if (data.status_code === 2483) - return resolve({ status: "error", message: "Invalid cookie!" }) - // Another Error - if (data.status_code !== 0) - return resolve({ - status: "error", - message: - data.status_msg || - "An error occurred! Please report this issue to the developer." - }) - if (!data.item_list) - return resolve({ status: "error", message: "Video not found!" }) - - const result: VideoSearchResult[] = [] - data.item_list.forEach((v: any) => { - const video: VideoSearch = { - id: v.video.id, - ratio: v.video.ratio, - cover: v.video.cover, - originCover: v.video.originCover, - dynamicCover: v.video.dynamicCover, - playAddr: v.video.playAddr, - downloadAddr: v.video.downloadAddr, - format: v.video.format - } - - const stats: StatisticsVideoSearch = { - diggCount: v.stats.diggCount, - shareCount: v.stats.shareCount, - commentCount: v.stats.commentCount, - playCount: v.stats.playCount, - collectCount: v.stats.collectCount - } - - const author: AuthorVideoSearch = { - id: v.author.id, - uniqueId: v.author.uniqueId, - nickname: v.author.nickname, - avatarThumb: v.author.avatarThumb, - avatarMedium: v.author.avatarMedium, - avatarLarger: v.author.avatarLarger, - signature: v.author.signature, - verified: v.author.verified, - secUid: v.author.secUid, - openFavorite: v.author.openFavorite, - privateAccount: v.author.privateAccount, - isADVirtual: v.author.isADVirtual, - tiktokSeller: v.author.ttSeller, - isEmbedBanned: v.author.isEmbedBanned - } - - const music: MusicVideoSearch = { - id: v.music.id, - title: v.music.title, - playUrl: v.music.playUrl, - coverThumb: v.music.coverThumb, - coverMedium: v.music.coverMedium, - coverLarge: v.music.coverLarge, - authorName: v.music.authorName, - original: v.music.original, - album: v.music.album, - duration: v.music.duration, - isCopyrighted: v.music.isCopyrighted - } - result.push({ - id: v.id, - desc: v.desc, - createTime: v.createTime, - author, - stats, - video, - music - }) + // Cookie Invalid + if (data.status_code === 2483) + return resolve({ status: "error", message: "Invalid cookie!" }) + // Another Error + if (data.status_code !== 0) + return resolve({ + status: "error", + message: + data.status_msg || + "An error occurred! Please report this issue to the developer." }) + if (!data.item_list) + return resolve({ status: "error", message: "Video not found!" }) - resolve({ - status: "success", - result, - page, - totalResults: result.length + const result: VideoSearchResult[] = [] + data.item_list.forEach((v: any) => { + const video: VideoSearch = { + id: v.video.id, + ratio: v.video.ratio, + cover: v.video.cover, + originCover: v.video.originCover, + dynamicCover: v.video.dynamicCover, + playAddr: v.video.playAddr, + downloadAddr: v.video.downloadAddr, + format: v.video.format + } + + const stats: StatisticsVideoSearch = { + likeCount: v.stats.diggCount, + shareCount: v.stats.shareCount, + commentCount: v.stats.commentCount, + playCount: v.stats.playCount, + collectCount: v.stats.collectCount + } + + const author: AuthorVideoSearch = { + id: v.author.id, + uniqueId: v.author.uniqueId, + nickname: v.author.nickname, + avatarThumb: v.author.avatarThumb, + avatarMedium: v.author.avatarMedium, + avatarLarger: v.author.avatarLarger, + signature: v.author.signature, + verified: v.author.verified, + secUid: v.author.secUid, + openFavorite: v.author.openFavorite, + privateAccount: v.author.privateAccount, + isADVirtual: v.author.isADVirtual, + tiktokSeller: v.author.ttSeller, + isEmbedBanned: v.author.isEmbedBanned + } + + const music: MusicVideoSearch = { + id: v.music.id, + title: v.music.title, + playUrl: v.music.playUrl, + coverThumb: v.music.coverThumb, + coverMedium: v.music.coverMedium, + coverLarge: v.music.coverLarge, + authorName: v.music.authorName, + original: v.music.original, + album: v.music.album, + duration: v.music.duration, + isCopyrighted: v.music.isCopyrighted + } + result.push({ + id: v.id, + desc: v.desc, + createTime: v.createTime, + author, + stats, + video, + music }) }) - .catch((e) => { - resolve({ status: "error", message: e.message }) + + resolve({ + status: "success", + result, + page, + totalResults: result.length }) + } catch (e) { + resolve({ status: "error", message: e.message }) + } }) + +const requestVideoSearch = async ( + keyword: string, + page: number, + cookie: string | any[], + proxy?: string +): Promise => { + return retry( + async (bail, attempt) => { + try { + const { data } = await Axios( + _tiktokSearchVideoFull(_videoSearchParams(keyword, page)), + { + method: "GET", + headers: { + "User-Agent": + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0", + cookie: + typeof cookie === "object" + ? cookie.map((v: any) => `${v.name}=${v.value}`).join("; ") + : cookie + }, + httpsAgent: + (proxy && + (proxy.startsWith("http") || proxy.startsWith("https") + ? new HttpsProxyAgent(proxy) + : proxy.startsWith("socks") + ? new SocksProxyAgent(proxy) + : undefined)) || + undefined + } + ) + return data + } catch (error) { + throw error + } + }, + { + retries: 3, + minTimeout: 1000, + maxTimeout: 5000, + factor: 2, + onRetry: (error, attempt) => { + console.log(`Retry attempt ${attempt} due to: ${error}`) + } + } + ) +}