diff --git a/src/index.ts b/src/index.ts index 78cf263..24becf0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,236 +1,288 @@ -/** Downloader */ -import { MusicalDown } from "./utils/downloader/musicalDown" -import { SSSTik } from "./utils/downloader/ssstik" +/** 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" + +/** Services */ import { TiktokAPI } from "./utils/downloader/tiktokApi" - -/** Get */ +import { SSSTik } from "./utils/downloader/ssstik" +import { MusicalDown } from "./utils/downloader/musicalDown" import { StalkUser } from "./utils/get/getProfile" - -/** Search */ import { SearchUser } from "./utils/search/userSearch" import { SearchLive } from "./utils/search/liveSearch" - -/** Types */ -import { MusicalDownResponse } from "./types/downloader/musicaldown" -import { SSSTikResponse } from "./types/downloader/ssstik" -import { TiktokAPIResponse } from "./types/downloader/tiktokApi" -import { TiktokUserSearchResponse } from "./types/search/userSearch" -import { TiktokStalkUserResponse } from "./types/get/getProfile" -import { TiktokLiveSearchResponse } from "./types/search/liveSearch" -import { TiktokVideoCommentsResponse } from "./types/get/getComments" import { getComments } from "./utils/get/getComments" -import { TiktokUserPostsResponse } from "./types/get/getUserPosts" import { getUserPosts } from "./utils/get/getUserPosts" import { getUserLiked } from "./utils/get/getUserLiked" -import { TiktokUserFavoriteVideosResponse } from "./types/get/getUserLiked" -import { TiktokVideoSearchResponse } from "./types/search/videoSearch" import { SearchVideo } from "./utils/search/videoSearch" -type TiktokDownloaderResponse = T extends "v1" +/** 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 TiktokSearchResponse = - T extends "user" - ? TiktokUserSearchResponse - : T extends "live" - ? TiktokLiveSearchResponse - : TiktokVideoSearchResponse +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 {string} options.version - The version of downloader - * @param {string} options.proxy - Your Proxy (optional) - * @param {boolean} options.showOriginalResponse - Show Original Response (optional) & Only for v1 + * @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 ( + Downloader: async ( url: string, - options?: { version: T; proxy?: string; showOriginalResponse?: boolean } + options?: { + version: DownloaderVersion + proxy?: string + showOriginalResponse?: boolean + } ): Promise> => { - switch (options?.version.toLowerCase()) { - case "v1": { - const response = await TiktokAPI( + const version = options?.version?.toLowerCase() as DownloaderVersion + + switch (version) { + case DOWNLOADER_VERSIONS.V1: + return (await TiktokAPI( url, options?.proxy, options?.showOriginalResponse - ) - return response as TiktokDownloaderResponse - } - case "v2": { - const response = await SSSTik(url, options?.proxy) - return response as TiktokDownloaderResponse - } - case "v3": { - const response = await MusicalDown(url, options?.proxy) - return response as TiktokDownloaderResponse - } - default: { - const response = await TiktokAPI( + )) 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 - ) - return response as TiktokDownloaderResponse - } + )) as TiktokDownloaderResponse } }, + /** * Tiktok Search - * @param {string} query - The query you want to search - * @param {object} options - The options for search - * @param {string} options.type - The type of search - * @param {string | any[]} options.cookie - Your Tiktok Cookie (optional) - * @param {number} options.page - The page of search (optional) - * @param {string} options.proxy - Your Proxy (optional) + * @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 ( - query: string, - options: { - type: T - cookie: string | any[] + Search: async ( + keyword: string, + options?: { + type?: T + cookie?: string page?: number proxy?: string } ): Promise> => { - if (!options?.cookie) { + 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: "Cookie is required!" - } as TiktokSearchResponse - } - switch (options?.type.toLowerCase()) { - case "user": { - const response = await SearchUser( - query, - options?.cookie, - options?.page, - options?.proxy - ) - return response as TiktokSearchResponse - } - case "live": { - const response = await SearchLive( - query, - options?.cookie, - options?.page, - options?.proxy - ) - return response as TiktokSearchResponse - } - case "video": { - const response = await SearchVideo( - query, - options?.cookie, - options?.page, - options?.proxy - ) - return response as TiktokSearchResponse - } - default: { - const response = await SearchUser( - query, - options?.cookie, - options?.page, - options?.proxy - ) - return response as TiktokSearchResponse + message: error.message } } }, + /** * Tiktok Stalk User * @param {string} username - The username you want to stalk - * @param {object} options - The options for stalk - * @param {string | any[]} options.cookie - Your Tiktok Cookie (optional) - * @param {string} options.proxy - Your Proxy (optional) + * @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[] - postLimit?: number proxy?: string } ): Promise => { - const response = await StalkUser(username, options?.cookie, options?.proxy) - return response + 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 {string} options.proxy - Your Proxy (optional) - * @param {number} options.page - The page you want to get (optional) + * @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 } + options?: { + commentLimit?: number + proxy?: string + } ): Promise => { - const response = await getComments( - url, - options?.proxy, - options?.commentLimit - ) - return response + 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 return (optional) - * @param {string} options.proxy - Your Proxy (optional) + * @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 } + options?: { + postLimit?: number + proxy?: string + } ): Promise => { - const response = await getUserPosts( - username, - options?.proxy, - options?.postLimit - ) - return response + 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 | any[]} options.cookie - Your Tiktok Cookie (optional) - * @param {number} options.postLimit - Limit number of posts to return (optional) - * @param {string} options.proxy - Your Proxy (optional) + * @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 (!options?.cookie) { - return { - status: "error", - message: "Cookie is required!" - } as TiktokUserFavoriteVideosResponse + options: { + cookie: string | any[] + postLimit?: number + proxy?: string } - const response = await getUserLiked( + ): Promise => { + if (!validateCookie(options?.cookie)) { + return handleError( + ERROR_MESSAGES.COOKIE_REQUIRED + ) as TiktokUserFavoriteVideosResponse + } + + return await getUserLiked( username, - options?.cookie, + options.cookie, options?.proxy, options?.postLimit ) - return response } }