diff --git a/src/cli/index.ts b/src/cli/index.ts index c4e88ea..4da69ef 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -402,8 +402,8 @@ program "", "Collection ID or URL (e.g. 7507916135931218695 or https://www.tiktok.com/@username/collection/name-id)" ) - .option("-c, --cursor ", "Cursor for pagination", "0") - .option("-p, --proxy ", "Proxy URL (http/https/socks)") + .option("-p, --page ", "Page number", "1") + .option("--proxy ", "Proxy URL (http/https/socks)") .option( "-n, --count ", "Number of items to fetch", @@ -412,19 +412,18 @@ program ) .action(async (collectionIdOrUrl, options) => { try { - Logger.info(`Fetching collection... (count: ${options.count})`) + Logger.info(`Fetching page ${options.page} with ${options.count} items per page from collection...`) const results = await Tiktok.Collection(collectionIdOrUrl, { - cursor: options.cursor, + page: options.page, proxy: options.proxy, count: options.count }) if (results.status === "success" && results.result) { - const { itemList, hasMore, cursor } = results.result + const { itemList, hasMore } = results.result Logger.info(`Found ${itemList.length} videos in collection`) Logger.info(`Has more videos: ${hasMore}`) - Logger.info(`Next cursor: ${cursor}\n`) for (const [index, video] of itemList.entries()) { Logger.info(`---- VIDEO ${index + 1} ----`) @@ -461,9 +460,8 @@ program if (video.video) { Logger.info(`---- VIDEO URLs ----`) - const videoUrl = `${_tiktokurl}/@${ - video.author?.uniqueId || "unknown" - }/video/${video.id}` + const videoUrl = `${_tiktokurl}/@${video.author?.uniqueId || "unknown" + }/video/${video.id}` Logger.result(`Video URL: ${videoUrl}`, chalk.blue) } @@ -479,7 +477,7 @@ program if (hasMore) { Logger.info("\nTo fetch more videos, use:") - Logger.info(`tiktokdl collection ${collectionIdOrUrl} -c ${cursor}`) + Logger.info(`tiktokdl collection ${collectionIdOrUrl} -p ${parseInt(options.page) + 1}`) } } else { Logger.error(`Error: ${results.message}`) diff --git a/src/constants/params.ts b/src/constants/params.ts index 53b622b..8203b0d 100644 --- a/src/constants/params.ts +++ b/src/constants/params.ts @@ -353,7 +353,12 @@ const generateOdinId = () => { return `${prefix}${random}` } -export const _getCollectionParams = (collectionId: string, cursor: string = "0", count: number = 5) => { +export const _getCollectionParams = (collectionId: string, page: number = 1, count: number = 5) => { + let cursor = 0 + if (page > 0) { + cursor = (page - 1) * count + } + return qs.stringify({ WebIdLastTime: Date.now(), aid: 1988, @@ -368,7 +373,7 @@ export const _getCollectionParams = (collectionId: string, cursor: string = "0", collectionId, cookie_enabled: true, count, - cursor, + cursor: cursor.toString(), data_collection_enabled: true, device_id: "7002566096994190854", device_platform: "web_pc", diff --git a/src/index.ts b/src/index.ts index 052acb4..8fe6d28 100644 --- a/src/index.ts +++ b/src/index.ts @@ -130,7 +130,7 @@ export = { * @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.cursor] - Optional cursor for pagination + * @param {string} [options.page] - Optional page for pagination * @param {number} [options.count] - Optional number of items to fetch * @returns {Promise} */ @@ -138,7 +138,7 @@ export = { collectionIdOrUrl: string, options?: { proxy?: string - cursor?: string + page?: number count?: number } ): Promise => { @@ -149,7 +149,7 @@ export = { message: "Invalid collection ID or URL format" } } - return await getCollection(collectionId, options?.proxy, options?.cursor, options?.count) + return await getCollection(collectionId, options?.proxy, options?.page, options?.count) }, /** diff --git a/src/types/downloader/tiktokApi.ts b/src/types/downloader/tiktokApi.ts index f096f04..cb56fec 100644 --- a/src/types/downloader/tiktokApi.ts +++ b/src/types/downloader/tiktokApi.ts @@ -49,6 +49,5 @@ export type TiktokCollectionResponse = { }> }> hasMore: boolean - cursor: string } } diff --git a/src/types/get/getCollection.ts b/src/types/get/getCollection.ts index 65ad7d6..fe944b5 100644 --- a/src/types/get/getCollection.ts +++ b/src/types/get/getCollection.ts @@ -43,7 +43,6 @@ export interface TiktokCollectionResponse { status: "success" | "error" message?: string result?: { - cursor: string hasMore: boolean itemList: CollectionItem[] extra?: { diff --git a/src/utils/downloader/tiktokApi.ts b/src/utils/downloader/tiktokApi.ts index 01d8cf2..53507df 100644 --- a/src/utils/downloader/tiktokApi.ts +++ b/src/utils/downloader/tiktokApi.ts @@ -1,6 +1,6 @@ import Axios from "axios" import asyncRetry from "async-retry" -import { _tiktokvFeed, _tiktokurl } from "../../constants/api" +import { _tiktokvFeed, _tiktokurl, _tiktokGetCollection } from "../../constants/api" import { _tiktokApiParams, _getCollectionParams } from "../../constants/params" import { AuthorTiktokAPI, @@ -282,8 +282,9 @@ export const TiktokAPI = async ( export const Collection = async ( collectionIdOrUrl: string, options?: { - cursor?: string - proxy?: string + page?: number, + proxy?: string, + count?: number } ): Promise => { try { @@ -296,55 +297,31 @@ export const Collection = async ( } const response = await Axios( - _tiktokvFeed(_getCollectionParams(collectionId, options?.cursor)), + _tiktokGetCollection( + _getCollectionParams(collectionId, options.page, options.count) + ), { - method: "OPTIONS", - headers: { "User-Agent": USER_AGENT }, + method: "GET", + headers: { + "User-Agent": + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36", + Accept: "*/*", + "Accept-Language": "en-US,en;q=0.7", + Referer: "https://www.tiktok.com/", + Origin: "https://www.tiktok.com" + }, ...createProxyAgent(options?.proxy) } ) if (response.data && response.data.status_code === 0) { const data = response.data - const itemList = data.aweme_list.map((item: any) => ({ - id: item.aweme_id, - desc: item.desc, - createTime: item.create_time, - author: { - uid: item.author.uid, - username: item.author.unique_id, - uniqueId: item.author.unique_id, - nickname: item.author.nickname, - signature: item.author.signature, - region: item.author.region, - avatarThumb: item.author?.avatar_thumb?.url_list || [], - avatarMedium: item.author?.avatar_medium?.url_list || [], - url: `${_tiktokurl}/@${item.author.unique_id}` - }, - statistics: { - likeCount: item.statistics.digg_count, - commentCount: item.statistics.comment_count, - shareCount: item.statistics.share_count, - playCount: item.statistics.play_count - }, - video: { - ratio: item.video.ratio, - duration: item.video.duration, - playAddr: item.video?.play_addr?.url_list || [], - downloadAddr: item.video?.download_addr?.url_list || [], - cover: item.video?.cover?.url_list || [], - dynamicCover: item.video?.dynamic_cover?.url_list || [], - originCover: item.video?.origin_cover?.url_list || [] - }, - textExtra: item.text_extra || [] - })) return { status: "success", result: { - itemList, - hasMore: data.has_more, - cursor: data.cursor + itemList: data.itemList || [], + hasMore: data.hasMore } } } diff --git a/src/utils/get/getCollection.ts b/src/utils/get/getCollection.ts index d9df375..6fe7858 100644 --- a/src/utils/get/getCollection.ts +++ b/src/utils/get/getCollection.ts @@ -30,14 +30,14 @@ const createProxyAgent = (proxy?: string): ProxyConfig => { * Get TikTok Collection * @param {string} collectionId - Collection ID * @param {string} proxy - Your Proxy (optional) - * @param {string} cursor - Cursor for pagination (optional) + * @param {string} page - Page for pagination (optional) * @param {number} count - Number of items to fetch (optional) * @returns {Promise} */ export const getCollection = async ( collectionId: string, proxy?: string, - cursor: string = "0", + page: number = 1, count: number = 5 ): Promise => { try { @@ -45,7 +45,7 @@ export const getCollection = async ( async () => { const res = await Axios( _tiktokGetCollection( - _getCollectionParams(collectionId, cursor, count) + _getCollectionParams(collectionId, page, count) ), { method: "GET", @@ -77,9 +77,8 @@ export const getCollection = async ( return { status: "success", result: { - cursor: response.cursor, hasMore: response.hasMore, - itemList: response.itemList, + itemList: response.itemList || [], extra: response.extra } } diff --git a/test/collection-test.ts b/test/collection-test.ts new file mode 100644 index 0000000..056efc1 --- /dev/null +++ b/test/collection-test.ts @@ -0,0 +1,69 @@ +import { Collection } from "../src/utils/downloader/tiktokApi" + +async function testCollection() { + try { + // You can use either a collection ID or URL + const collectionIdOrUrl = "https://www.tiktok.com/@getrex.co.nz/collection/big%20back-7507916135931218695" + + console.log("Testing Collection method...") + const result = await Collection(collectionIdOrUrl, { + page: 2, + count: 5, // Optional: Number of items to fetch + proxy: undefined // Optional: Add your proxy if needed + }) + + if (result.status === "success" && result.result) { + console.log("\nCollection fetched successfully!") + console.log("========================") + console.log("Collection Overview:") + console.log("========================") + console.log(`Collection ID: ${collectionIdOrUrl}`) + console.log(`Total items fetched: ${result.result.itemList.length}`) + console.log(`Has more items: ${result.result.hasMore}`) + + // Log all items + result.result.itemList.forEach((item, index) => { + console.log(`\nItem ${index + 1}:`) + console.log("-------------------") + console.log(`ID: ${item.id}`) + console.log(`Description: ${item.desc}`) + console.log(`Author: ${item.author.nickname}`) + console.log(`Created: ${new Date(item.createTime * 1000).toLocaleString()}`) + + // Log video URL + if (item.video?.playAddr?.[0]) { + console.log(`Video URL: ${item.video.playAddr[0]}`) + } else { + console.log("No video URL available") + } + + // Log item statistics + if (item.statistics) { + console.log("\nStatistics:") + console.log(`- Likes: ${item.statistics.likeCount || 0}`) + console.log(`- Comments: ${item.statistics.commentCount || 0}`) + console.log(`- Shares: ${item.statistics.shareCount || 0}`) + console.log(`- Plays: ${item.statistics.playCount || 0}`) + } + + // Log hashtags if available + if (item.textExtra?.length > 0) { + console.log("\nHashtags:") + item.textExtra.forEach(tag => { + if (tag.hashtagName) { + console.log(`- #${tag.hashtagName}`) + } + }) + } + console.log("========================") + }) + } else { + console.error("Error:", result.message) + } + } catch (error) { + console.error("Test failed:", error) + } +} + +// Run the test +testCollection() \ No newline at end of file diff --git a/test/collection.ts b/test/collection.ts deleted file mode 100644 index 63b7e14..0000000 --- a/test/collection.ts +++ /dev/null @@ -1,85 +0,0 @@ -import Tiktok from "../src" - -async function testCollection() { - try { - // Test collection ID from your example - const collectionId = "7507916135931218695" - - console.log("Fetching collection...") - const collection = await Tiktok.Collection(collectionId, { - cursor: "0" // Optional: For pagination - }) - - console.log(collection) - - if (collection.status === "success" && collection.result) { - const { itemList, hasMore, cursor } = collection.result - - console.log(`\nFound ${itemList.length} videos in collection`) - console.log(`Has more videos: ${hasMore}`) - console.log(`Next cursor: ${cursor}\n`) - - // Print details of first video - if (itemList.length > 0) { - const firstVideo = itemList[0] - console.log("First video details:") - console.log("-------------------") - console.log(`Description: ${firstVideo.desc}`) - console.log(`Author: ${firstVideo.author?.nickname || 'Unknown'}`) - console.log( - `Created: ${new Date(firstVideo.createTime * 1000).toLocaleString()}` - ) - - // Print statistics if available - if (firstVideo.statistics) { - console.log("\nStatistics:") - console.log(`- Likes: ${firstVideo.statistics.likeCount || 0}`) - console.log(`- Comments: ${firstVideo.statistics.commentCount || 0}`) - console.log(`- Shares: ${firstVideo.statistics.shareCount || 0}`) - console.log(`- Plays: ${firstVideo.statistics.playCount || 0}`) - } - - // Print video URLs if available - if (firstVideo.video) { - console.log("\nVideo URLs:") - if (firstVideo.video.playAddr?.[0]) { - console.log(`- Play URL: ${firstVideo.video.playAddr[0]}`) - } - if (firstVideo.video.downloadAddr?.[0]) { - console.log(`- Download URL: ${firstVideo.video.downloadAddr[0]}`) - } - } - - // Print hashtags if available - if (firstVideo.textExtra?.length > 0) { - console.log("\nHashtags:") - firstVideo.textExtra.forEach((tag) => { - if (tag.hashtagName) { - console.log(`- #${tag.hashtagName}`) - } - }) - } - } - - // If there are more videos, you can fetch the next page - if (hasMore) { - console.log("\nFetching next page...") - const nextPage = await Tiktok.Collection(collectionId, { - proxy: "http://your-proxy-url", // Optional: Add your proxy if needed - cursor: cursor - }) - - if (nextPage.status === "success" && nextPage.result) { - console.log(`Found ${nextPage.result.itemList.length} more videos`) - } - } - } else { - console.error("Error:", collection.message) - } - } catch (error) { - console.error("Test failed:", error) - } -} - -// Run the test -testCollection()