use page instead of cursor
This commit is contained in:
parent
baa8fa2cc8
commit
004e74d338
@ -402,8 +402,8 @@ program
|
|||||||
"<collectionIdOrUrl>",
|
"<collectionIdOrUrl>",
|
||||||
"Collection ID or URL (e.g. 7507916135931218695 or https://www.tiktok.com/@username/collection/name-id)"
|
"Collection ID or URL (e.g. 7507916135931218695 or https://www.tiktok.com/@username/collection/name-id)"
|
||||||
)
|
)
|
||||||
.option("-c, --cursor <cursor>", "Cursor for pagination", "0")
|
.option("-p, --page <number>", "Page number", "1")
|
||||||
.option("-p, --proxy <proxy>", "Proxy URL (http/https/socks)")
|
.option("--proxy <proxy>", "Proxy URL (http/https/socks)")
|
||||||
.option(
|
.option(
|
||||||
"-n, --count <number>",
|
"-n, --count <number>",
|
||||||
"Number of items to fetch",
|
"Number of items to fetch",
|
||||||
@ -412,19 +412,18 @@ program
|
|||||||
)
|
)
|
||||||
.action(async (collectionIdOrUrl, options) => {
|
.action(async (collectionIdOrUrl, options) => {
|
||||||
try {
|
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, {
|
const results = await Tiktok.Collection(collectionIdOrUrl, {
|
||||||
cursor: options.cursor,
|
page: options.page,
|
||||||
proxy: options.proxy,
|
proxy: options.proxy,
|
||||||
count: options.count
|
count: options.count
|
||||||
})
|
})
|
||||||
|
|
||||||
if (results.status === "success" && results.result) {
|
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(`Found ${itemList.length} videos in collection`)
|
||||||
Logger.info(`Has more videos: ${hasMore}`)
|
Logger.info(`Has more videos: ${hasMore}`)
|
||||||
Logger.info(`Next cursor: ${cursor}\n`)
|
|
||||||
|
|
||||||
for (const [index, video] of itemList.entries()) {
|
for (const [index, video] of itemList.entries()) {
|
||||||
Logger.info(`---- VIDEO ${index + 1} ----`)
|
Logger.info(`---- VIDEO ${index + 1} ----`)
|
||||||
@ -461,9 +460,8 @@ program
|
|||||||
|
|
||||||
if (video.video) {
|
if (video.video) {
|
||||||
Logger.info(`---- VIDEO URLs ----`)
|
Logger.info(`---- VIDEO URLs ----`)
|
||||||
const videoUrl = `${_tiktokurl}/@${
|
const videoUrl = `${_tiktokurl}/@${video.author?.uniqueId || "unknown"
|
||||||
video.author?.uniqueId || "unknown"
|
}/video/${video.id}`
|
||||||
}/video/${video.id}`
|
|
||||||
Logger.result(`Video URL: ${videoUrl}`, chalk.blue)
|
Logger.result(`Video URL: ${videoUrl}`, chalk.blue)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,7 +477,7 @@ program
|
|||||||
|
|
||||||
if (hasMore) {
|
if (hasMore) {
|
||||||
Logger.info("\nTo fetch more videos, use:")
|
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 {
|
} else {
|
||||||
Logger.error(`Error: ${results.message}`)
|
Logger.error(`Error: ${results.message}`)
|
||||||
|
|||||||
@ -353,7 +353,12 @@ const generateOdinId = () => {
|
|||||||
return `${prefix}${random}`
|
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({
|
return qs.stringify({
|
||||||
WebIdLastTime: Date.now(),
|
WebIdLastTime: Date.now(),
|
||||||
aid: 1988,
|
aid: 1988,
|
||||||
@ -368,7 +373,7 @@ export const _getCollectionParams = (collectionId: string, cursor: string = "0",
|
|||||||
collectionId,
|
collectionId,
|
||||||
cookie_enabled: true,
|
cookie_enabled: true,
|
||||||
count,
|
count,
|
||||||
cursor,
|
cursor: cursor.toString(),
|
||||||
data_collection_enabled: true,
|
data_collection_enabled: true,
|
||||||
device_id: "7002566096994190854",
|
device_id: "7002566096994190854",
|
||||||
device_platform: "web_pc",
|
device_platform: "web_pc",
|
||||||
|
|||||||
@ -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 {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 {Object} options - The options for collection
|
||||||
* @param {string} [options.proxy] - Optional proxy URL
|
* @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
|
* @param {number} [options.count] - Optional number of items to fetch
|
||||||
* @returns {Promise<TiktokCollectionResponse>}
|
* @returns {Promise<TiktokCollectionResponse>}
|
||||||
*/
|
*/
|
||||||
@ -138,7 +138,7 @@ export = {
|
|||||||
collectionIdOrUrl: string,
|
collectionIdOrUrl: string,
|
||||||
options?: {
|
options?: {
|
||||||
proxy?: string
|
proxy?: string
|
||||||
cursor?: string
|
page?: number
|
||||||
count?: number
|
count?: number
|
||||||
}
|
}
|
||||||
): Promise<TiktokCollectionResponse> => {
|
): Promise<TiktokCollectionResponse> => {
|
||||||
@ -149,7 +149,7 @@ export = {
|
|||||||
message: "Invalid collection ID or URL format"
|
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)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -49,6 +49,5 @@ export type TiktokCollectionResponse = {
|
|||||||
}>
|
}>
|
||||||
}>
|
}>
|
||||||
hasMore: boolean
|
hasMore: boolean
|
||||||
cursor: string
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,7 +43,6 @@ export interface TiktokCollectionResponse {
|
|||||||
status: "success" | "error"
|
status: "success" | "error"
|
||||||
message?: string
|
message?: string
|
||||||
result?: {
|
result?: {
|
||||||
cursor: string
|
|
||||||
hasMore: boolean
|
hasMore: boolean
|
||||||
itemList: CollectionItem[]
|
itemList: CollectionItem[]
|
||||||
extra?: {
|
extra?: {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import Axios from "axios"
|
import Axios from "axios"
|
||||||
import asyncRetry from "async-retry"
|
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 { _tiktokApiParams, _getCollectionParams } from "../../constants/params"
|
||||||
import {
|
import {
|
||||||
AuthorTiktokAPI,
|
AuthorTiktokAPI,
|
||||||
@ -282,8 +282,9 @@ export const TiktokAPI = async (
|
|||||||
export const Collection = async (
|
export const Collection = async (
|
||||||
collectionIdOrUrl: string,
|
collectionIdOrUrl: string,
|
||||||
options?: {
|
options?: {
|
||||||
cursor?: string
|
page?: number,
|
||||||
proxy?: string
|
proxy?: string,
|
||||||
|
count?: number
|
||||||
}
|
}
|
||||||
): Promise<TiktokCollectionResponse> => {
|
): Promise<TiktokCollectionResponse> => {
|
||||||
try {
|
try {
|
||||||
@ -296,55 +297,31 @@ export const Collection = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const response = await Axios(
|
const response = await Axios(
|
||||||
_tiktokvFeed(_getCollectionParams(collectionId, options?.cursor)),
|
_tiktokGetCollection(
|
||||||
|
_getCollectionParams(collectionId, options.page, options.count)
|
||||||
|
),
|
||||||
{
|
{
|
||||||
method: "OPTIONS",
|
method: "GET",
|
||||||
headers: { "User-Agent": USER_AGENT },
|
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)
|
...createProxyAgent(options?.proxy)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (response.data && response.data.status_code === 0) {
|
if (response.data && response.data.status_code === 0) {
|
||||||
const data = response.data
|
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 {
|
return {
|
||||||
status: "success",
|
status: "success",
|
||||||
result: {
|
result: {
|
||||||
itemList,
|
itemList: data.itemList || [],
|
||||||
hasMore: data.has_more,
|
hasMore: data.hasMore
|
||||||
cursor: data.cursor
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,14 +30,14 @@ const createProxyAgent = (proxy?: string): ProxyConfig => {
|
|||||||
* Get TikTok Collection
|
* Get TikTok Collection
|
||||||
* @param {string} collectionId - Collection ID
|
* @param {string} collectionId - Collection ID
|
||||||
* @param {string} proxy - Your Proxy (optional)
|
* @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)
|
* @param {number} count - Number of items to fetch (optional)
|
||||||
* @returns {Promise<TiktokCollectionResponse>}
|
* @returns {Promise<TiktokCollectionResponse>}
|
||||||
*/
|
*/
|
||||||
export const getCollection = async (
|
export const getCollection = async (
|
||||||
collectionId: string,
|
collectionId: string,
|
||||||
proxy?: string,
|
proxy?: string,
|
||||||
cursor: string = "0",
|
page: number = 1,
|
||||||
count: number = 5
|
count: number = 5
|
||||||
): Promise<TiktokCollectionResponse> => {
|
): Promise<TiktokCollectionResponse> => {
|
||||||
try {
|
try {
|
||||||
@ -45,7 +45,7 @@ export const getCollection = async (
|
|||||||
async () => {
|
async () => {
|
||||||
const res = await Axios(
|
const res = await Axios(
|
||||||
_tiktokGetCollection(
|
_tiktokGetCollection(
|
||||||
_getCollectionParams(collectionId, cursor, count)
|
_getCollectionParams(collectionId, page, count)
|
||||||
),
|
),
|
||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
@ -77,9 +77,8 @@ export const getCollection = async (
|
|||||||
return {
|
return {
|
||||||
status: "success",
|
status: "success",
|
||||||
result: {
|
result: {
|
||||||
cursor: response.cursor,
|
|
||||||
hasMore: response.hasMore,
|
hasMore: response.hasMore,
|
||||||
itemList: response.itemList,
|
itemList: response.itemList || [],
|
||||||
extra: response.extra
|
extra: response.extra
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
69
test/collection-test.ts
Normal file
69
test/collection-test.ts
Normal file
@ -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()
|
||||||
@ -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()
|
|
||||||
Loading…
x
Reference in New Issue
Block a user