/** Types */ import { TiktokAPIResponse } from "./types/downloader/tiktokApi" import { SSSTikResponse } from "./types/downloader/ssstik" import { MusicalDownResponse } from "./types/downloader/musicaldown" import { TiktokUserSearchResponse, UserSearchResult } from "./types/search/userSearch" import { TiktokLiveSearchResponse, LiveSearchResult } from "./types/search/liveSearch" import { TiktokVideoSearchResponse, VideoSearchResult } from "./types/search/videoSearch" import { TiktokStalkUserResponse } from "./types/get/getProfile" import { TiktokVideoCommentsResponse } from "./types/get/getComments" import { TiktokUserPostsResponse } from "./types/get/getUserPosts" import { TiktokUserFavoriteVideosResponse } from "./types/get/getUserLiked" import { TiktokCollectionResponse } from "./types/get/getCollection" /** Services */ import { TiktokAPI } from "./utils/downloader/tiktokApi" import { SSSTik } from "./utils/downloader/ssstik" import { MusicalDown } from "./utils/downloader/musicalDown" import { StalkUser } from "./utils/get/getProfile" import { SearchUser } from "./utils/search/userSearch" import { SearchLive } from "./utils/search/liveSearch" import { getComments } from "./utils/get/getComments" import { getUserPosts } from "./utils/get/getUserPosts" import { getUserLiked } from "./utils/get/getUserLiked" import { SearchVideo } from "./utils/search/videoSearch" import { getCollection } from "./utils/get/getCollection" import { extractCollectionId } from "./utils/downloader/tiktokApi" /** Constants */ import { DOWNLOADER_VERSIONS, SEARCH_TYPES } from "./constants" import { ERROR_MESSAGES } from "./constants" import { validateCookie } from "./utils/validator" /** Types */ type DownloaderVersion = "v1" | "v2" | "v3" type SearchType = "user" | "live" | "video" type TiktokDownloaderResponse = T extends "v1" ? TiktokAPIResponse : T extends "v2" ? SSSTikResponse : T extends "v3" ? MusicalDownResponse : TiktokAPIResponse type SearchResult = { type: T } & (T extends "user" ? UserSearchResult : T extends "live" ? LiveSearchResult : VideoSearchResult) type TiktokSearchResponse = { status: "success" | "error" message?: string result?: SearchResult[] page?: number totalResults?: number } /** Helper Functions */ const handleError = (message: string) => { return { status: "error", message } } /** Main API */ export = { /** * Tiktok Downloader * @param {string} url - The Tiktok URL you want to download * @param {Object} options - The options for downloader * @param {DownloaderVersion} options.version - The version of downloader to use * @param {string} [options.proxy] - Optional proxy URL * @param {boolean} [options.showOriginalResponse] - Whether to show original response * @returns {Promise} */ Downloader: async ( url: string, options?: { version: DownloaderVersion proxy?: string showOriginalResponse?: boolean } ): Promise> => { const version = options?.version?.toLowerCase() as DownloaderVersion switch (version) { case DOWNLOADER_VERSIONS.V1: return (await TiktokAPI( url, options?.proxy, options?.showOriginalResponse )) as TiktokDownloaderResponse case DOWNLOADER_VERSIONS.V2: return (await SSSTik( url, options?.proxy )) as TiktokDownloaderResponse case DOWNLOADER_VERSIONS.V3: return (await MusicalDown( url, options?.proxy )) as TiktokDownloaderResponse default: return (await TiktokAPI( url, options?.proxy, options?.showOriginalResponse )) as TiktokDownloaderResponse } }, /** * Get TikTok Collection * @param {string} collectionIdOrUrl - Collection ID or URL (e.g. 7507916135931218695 or https://www.tiktok.com/@username/collection/name-id) * @param {Object} options - The options for collection * @param {string} [options.proxy] - Optional proxy URL * @param {string} [options.page] - Optional page for pagination * @param {number} [options.count] - Optional number of items to fetch * @returns {Promise} */ Collection: async ( collectionIdOrUrl: string, options?: { proxy?: string page?: number count?: number } ): Promise => { const collectionId = extractCollectionId(collectionIdOrUrl) if (!collectionId) { return { status: "error", message: "Invalid collection ID or URL format" } } return await getCollection(collectionId, options?.proxy, options?.page, options?.count) }, /** * Tiktok Search * @param {string} keyword - The query you want to search * @param {Object} options - The options for search * @param {SearchType} [options.type] - The type of search (user/live/video) * @param {string} [options.cookie] - Cookie for authentication * @param {number} [options.page] - Page number for pagination * @param {string} [options.proxy] - Optional proxy URL * @returns {Promise} */ Search: async ( keyword: string, options?: { type?: T cookie?: string page?: number proxy?: string } ): Promise> => { try { const type = options?.type?.toLowerCase() as SearchType if (!type || !Object.values(SEARCH_TYPES).includes(type)) { throw new Error(ERROR_MESSAGES.INVALID_SEARCH_TYPE) } switch (type) { case SEARCH_TYPES.USER: const userResults = await SearchUser( keyword, options.cookie, options?.page, options?.proxy ) return { ...userResults, result: userResults.result?.map((user) => ({ type: "user" as const, ...user })) as SearchResult<"user">[] } as unknown as TiktokSearchResponse case SEARCH_TYPES.LIVE: const liveResults = await SearchLive( keyword, options.cookie, options?.page, options?.proxy ) return { ...liveResults, result: liveResults.result?.map((live) => ({ type: "live" as const, ...live })) as SearchResult<"live">[] } as unknown as TiktokSearchResponse case SEARCH_TYPES.VIDEO: const videoResults = await SearchVideo( keyword, options.cookie, options?.page, options?.proxy ) return { ...videoResults, result: videoResults.result?.map((video) => ({ type: "video" as const, ...video })) as SearchResult<"video">[] } as unknown as TiktokSearchResponse default: throw new Error(ERROR_MESSAGES.INVALID_SEARCH_TYPE) } } catch (error) { return { status: "error", message: error.message } } }, /** * Tiktok Stalk User * @param {string} username - The username you want to stalk * @param {Object} options - The options for stalk * @param {string|Array} [options.cookie] - Optional cookie for authentication * @param {string} [options.proxy] - Optional proxy URL * @returns {Promise} */ StalkUser: async ( username: string, options?: { cookie?: string | any[] proxy?: string } ): Promise => { return await StalkUser(username, options?.cookie, options?.proxy) }, /** * Tiktok Get Comments * @param {string} url - The Tiktok URL you want to get comments * @param {Object} options - The options for get comments * @param {number} [options.commentLimit] - Limit number of comments to fetch * @param {string} [options.proxy] - Optional proxy URL * @returns {Promise} */ GetVideoComments: async ( url: string, options?: { commentLimit?: number proxy?: string } ): Promise => { return await getComments(url, options?.proxy, options?.commentLimit) }, /** * Tiktok Get User Posts * @param {string} username - The username you want to get posts from * @param {Object} options - The options for getting posts * @param {number} [options.postLimit] - Limit number of posts to fetch * @param {string} [options.proxy] - Optional proxy URL * @returns {Promise} */ GetUserPosts: async ( username: string, options?: { postLimit?: number proxy?: string } ): Promise => { return await getUserPosts(username, options?.proxy, options?.postLimit) }, /** * Tiktok Get User Liked Videos * @param {string} username - The username you want to get liked videos from * @param {Object} options - The options for getting liked videos * @param {string|Array} options.cookie - Cookie for authentication * @param {number} [options.postLimit] - Limit number of posts to fetch * @param {string} [options.proxy] - Optional proxy URL * @returns {Promise} */ GetUserLiked: async ( username: string, options: { cookie: string | any[] postLimit?: number proxy?: string } ): Promise => { if (!validateCookie(options?.cookie)) { return handleError( ERROR_MESSAGES.COOKIE_REQUIRED ) as TiktokUserFavoriteVideosResponse } return await getUserLiked( username, options.cookie, options?.proxy, options?.postLimit ) } }