feat: add tiktok get comments
This commit is contained in:
parent
46acd692e3
commit
3bcbecbb6e
@ -8,6 +8,8 @@ export const _tiktokSearchLiveFull = (params: any): string =>
|
||||
`${_tiktokurl}/api/search/live/full/?${params}`
|
||||
export const _tiktokGetPosts = (params: any): string =>
|
||||
`${_tiktokurl}/api/post/item_list/?${params}`
|
||||
export const _tiktokGetComments = (params: any): string =>
|
||||
`${_tiktokurl}/api/comment/list/?${params}`
|
||||
|
||||
/** Tiktokv */
|
||||
export const _tiktokvApi: string = `https://api16-normal-useast5.tiktokv.us`
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import qs from "qs"
|
||||
|
||||
export const _userPostsParams = () => {
|
||||
/** Get Params */
|
||||
export const _getUserPostsParams = () => {
|
||||
return (
|
||||
qs.stringify({
|
||||
aid: 1988,
|
||||
@ -37,14 +38,70 @@ export const _userPostsParams = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export const _xttParams = (secUid: string, cursor: number, count: number) => {
|
||||
return qs.stringify({
|
||||
aid: "1988",
|
||||
cookie_enabled: true,
|
||||
screen_width: 0,
|
||||
screen_height: 0,
|
||||
browser_language: "",
|
||||
browser_platform: "",
|
||||
browser_name: "",
|
||||
browser_version: "",
|
||||
browser_online: "",
|
||||
timezone_name: "Europe/London",
|
||||
secUid,
|
||||
cursor,
|
||||
count,
|
||||
is_encryption: 1
|
||||
})
|
||||
}
|
||||
|
||||
export const _getCommentsParams = (id: string, count: number) => {
|
||||
let cursor = 0
|
||||
|
||||
// 50 comments per page
|
||||
if (count > 50) {
|
||||
for (let i = 1; i < count; i++) {
|
||||
cursor += 50
|
||||
}
|
||||
}
|
||||
|
||||
return qs.stringify({
|
||||
aid: "1988",
|
||||
app_language: "ja-JP",
|
||||
app_name: "tiktok_web",
|
||||
aweme_id: id,
|
||||
browser_language: "en-US",
|
||||
browser_name: "Mozilla",
|
||||
browser_online: true,
|
||||
browser_platform: "Linux x86_64",
|
||||
browser_version: "5.0 (X11)",
|
||||
channel: "tiktok_web",
|
||||
cookie_enabled: true,
|
||||
count: 50,
|
||||
cursor: cursor,
|
||||
device_id: "7445428925624813064",
|
||||
os: "linux",
|
||||
region: "ID",
|
||||
screen_height: 768,
|
||||
screen_width: 1366
|
||||
})
|
||||
}
|
||||
|
||||
/** Search */
|
||||
export const _userSearchParams = (
|
||||
keyword: string,
|
||||
page: number = 1,
|
||||
page: number,
|
||||
xbogus?: any
|
||||
) => {
|
||||
let cursor = 0
|
||||
for (let i = 1; i < page; i++) {
|
||||
cursor += 10
|
||||
|
||||
// 10 users per page
|
||||
if (page > 1) {
|
||||
for (let i = 1; i < page; i++) {
|
||||
cursor += 10
|
||||
}
|
||||
}
|
||||
|
||||
const params = {
|
||||
@ -98,10 +155,14 @@ export const _userSearchParams = (
|
||||
return qs.stringify(params)
|
||||
}
|
||||
|
||||
export const _liveSearchParams = (keyword: string, page: number = 1) => {
|
||||
export const _liveSearchParams = (keyword: string, page: number) => {
|
||||
let cursor = 0
|
||||
for (let i = 1; i < page; i++) {
|
||||
cursor += 12
|
||||
|
||||
// 12 cursor for 20 lives per page
|
||||
if (page > 1) {
|
||||
for (let i = 1; i < page; i++) {
|
||||
cursor += 12
|
||||
}
|
||||
}
|
||||
|
||||
let offset = `${cursor}`
|
||||
@ -142,6 +203,7 @@ export const _liveSearchParams = (keyword: string, page: number = 1) => {
|
||||
})
|
||||
}
|
||||
|
||||
/** Downloader Params */
|
||||
export const _tiktokApiParams = (args: any) => {
|
||||
return new URLSearchParams({
|
||||
...args,
|
||||
@ -178,25 +240,6 @@ export const _tiktokApiParams = (args: any) => {
|
||||
}).toString()
|
||||
}
|
||||
|
||||
export const _xttParams = (secUid: string, cursor: number, count: number) => {
|
||||
return qs.stringify({
|
||||
aid: "1988",
|
||||
cookie_enabled: true,
|
||||
screen_width: 0,
|
||||
screen_height: 0,
|
||||
browser_language: "",
|
||||
browser_platform: "",
|
||||
browser_name: "",
|
||||
browser_version: "",
|
||||
browser_online: "",
|
||||
timezone_name: "Europe/London",
|
||||
secUid,
|
||||
cursor,
|
||||
count,
|
||||
is_encryption: 1
|
||||
})
|
||||
}
|
||||
|
||||
const randomChar = (char: string, range: number) => {
|
||||
let chars = ""
|
||||
|
||||
|
||||
70
src/index.ts
70
src/index.ts
@ -3,18 +3,22 @@ import { MusicalDown } from "./utils/downloader/musicalDown"
|
||||
import { SSSTik } from "./utils/downloader/ssstik"
|
||||
import { TiktokAPI } from "./utils/downloader/tiktokApi"
|
||||
|
||||
/** Get */
|
||||
import { StalkUser } from "./utils/get/getProfile"
|
||||
|
||||
/** Search */
|
||||
import { StalkUser } from "./utils/search/stalker"
|
||||
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 { StalkResult } from "./types/search/stalker"
|
||||
import { SearchLive } from "./utils/search/liveSearch"
|
||||
import { StalkResult } from "./types/get/getProfile"
|
||||
import { TiktokLiveSearchResponse } from "./types/search/liveSearch"
|
||||
import { CommentsResult } from "./types/get/getComments"
|
||||
import { getComments } from "./utils/get/getComments"
|
||||
|
||||
type TiktokDownloaderResponse<T extends "v1" | "v2" | "v3"> = T extends "v1"
|
||||
? TiktokAPIResponse
|
||||
@ -35,28 +39,38 @@ export = {
|
||||
* @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
|
||||
* @returns {Promise<TiktokDownloaderResponse>}
|
||||
*/
|
||||
|
||||
Downloader: async <T extends "v1" | "v2" | "v3">(
|
||||
url: string,
|
||||
options?: { version: T }
|
||||
options?: { version: T; proxy?: string; showOriginalResponse?: boolean }
|
||||
): Promise<TiktokDownloaderResponse<T>> => {
|
||||
switch (options?.version.toLowerCase()) {
|
||||
case "v1": {
|
||||
const response = await TiktokAPI(url)
|
||||
const response = await TiktokAPI(
|
||||
url,
|
||||
options?.proxy,
|
||||
options?.showOriginalResponse
|
||||
)
|
||||
return response as TiktokDownloaderResponse<T>
|
||||
}
|
||||
case "v2": {
|
||||
const response = await SSSTik(url)
|
||||
const response = await SSSTik(url, options?.proxy)
|
||||
return response as TiktokDownloaderResponse<T>
|
||||
}
|
||||
case "v3": {
|
||||
const response = await MusicalDown(url)
|
||||
const response = await MusicalDown(url, options?.proxy)
|
||||
return response as TiktokDownloaderResponse<T>
|
||||
}
|
||||
default: {
|
||||
const response = await TiktokAPI(url)
|
||||
const response = await TiktokAPI(
|
||||
url,
|
||||
options?.proxy,
|
||||
options?.showOriginalResponse
|
||||
)
|
||||
return response as TiktokDownloaderResponse<T>
|
||||
}
|
||||
}
|
||||
@ -66,13 +80,19 @@ export = {
|
||||
* @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} options.cookie - Your Tiktok Cookie (optional)
|
||||
* @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)
|
||||
* @returns {Promise<TiktokSearchResponse>}
|
||||
*/
|
||||
Search: async <T extends "user" | "live">(
|
||||
query: string,
|
||||
options: { type: T; cookie?: string; page?: number; proxy?: string }
|
||||
options: {
|
||||
type: T
|
||||
cookie?: string | any[]
|
||||
page?: number
|
||||
proxy?: string
|
||||
}
|
||||
): Promise<TiktokSearchResponse<T>> => {
|
||||
switch (options?.type.toLowerCase()) {
|
||||
case "user": {
|
||||
@ -108,12 +128,18 @@ export = {
|
||||
* Tiktok Stalk User
|
||||
* @param {string} username - The username you want to stalk
|
||||
* @param {object} options - The options for stalk
|
||||
* @param {string} options.cookie - Your Tiktok Cookie (optional)
|
||||
* @param {string | any[]} options.cookie - Your Tiktok Cookie (optional)
|
||||
* @param {number} options.postLimit - The limit of post you want to get (optional)
|
||||
* @param {string} options.proxy - Your Proxy (optional)
|
||||
* @returns {Promise<StalkResult>}
|
||||
*/
|
||||
StalkUser: async (
|
||||
username: string,
|
||||
options?: { cookie?: string; postLimit?: number; proxy?: string }
|
||||
options?: {
|
||||
cookie?: string | any[]
|
||||
postLimit?: number
|
||||
proxy?: string
|
||||
}
|
||||
): Promise<StalkResult> => {
|
||||
const response = await StalkUser(
|
||||
username,
|
||||
@ -122,5 +148,25 @@ export = {
|
||||
options?.proxy
|
||||
)
|
||||
return response
|
||||
},
|
||||
|
||||
/**
|
||||
* 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)
|
||||
* @returns {Promise<CommentsResult>}
|
||||
*/
|
||||
GetComments: async (
|
||||
url: string,
|
||||
options?: { commentLimit?: number; proxy?: string }
|
||||
): Promise<CommentsResult> => {
|
||||
const response = await getComments(
|
||||
url,
|
||||
options?.proxy,
|
||||
options?.commentLimit
|
||||
)
|
||||
return response
|
||||
}
|
||||
}
|
||||
|
||||
28
src/types/get/getComments.ts
Normal file
28
src/types/get/getComments.ts
Normal file
@ -0,0 +1,28 @@
|
||||
export type CommentsResult = {
|
||||
status: "success" | "error"
|
||||
message?: string
|
||||
result?: Comments[]
|
||||
totalComments?: number
|
||||
}
|
||||
|
||||
export type Comments = {
|
||||
cid: string
|
||||
text: string
|
||||
commentLanguage: string
|
||||
createTime: number
|
||||
likeCount: number
|
||||
isAuthorLiked: boolean
|
||||
isCommentTranslatable: boolean
|
||||
replyCommentTotal: number
|
||||
replyComment: Comments[] | null
|
||||
user: User
|
||||
url: string
|
||||
}
|
||||
|
||||
export type User = {
|
||||
uid: string
|
||||
avatarThumb: string[]
|
||||
nickname: string
|
||||
username: string
|
||||
isVerified: boolean
|
||||
}
|
||||
176
src/utils/get/getComments.ts
Normal file
176
src/utils/get/getComments.ts
Normal file
@ -0,0 +1,176 @@
|
||||
import Axios from "axios"
|
||||
import { _tiktokGetComments } from "../../constants/api"
|
||||
import { _getCommentsParams } from "../../constants/params"
|
||||
import { HttpsProxyAgent } from "https-proxy-agent"
|
||||
import { SocksProxyAgent } from "socks-proxy-agent"
|
||||
import { Comments, CommentsResult, User } from "../../types/get/getComments"
|
||||
|
||||
const TiktokURLregex =
|
||||
/https:\/\/(?:m|www|vm|vt|lite)?\.?tiktok\.com\/((?:.*\b(?:(?:usr|v|embed|user|video|photo)\/|\?shareId=|\&item_id=)(\d+))|\w+)/
|
||||
|
||||
/**
|
||||
* Tiktok Get Comments
|
||||
* @param {string} url - Tiktok URL
|
||||
* @param {string} proxy - Your Proxy (optional)
|
||||
* @param {number} commentLimit - Comment Limit (optional)
|
||||
* @returns {Promise<CommentsResult>}
|
||||
*/
|
||||
|
||||
export const getComments = async (
|
||||
url: string,
|
||||
proxy?: string,
|
||||
commentLimit?: number
|
||||
): Promise<CommentsResult> =>
|
||||
new Promise(async (resolve) => {
|
||||
if (!TiktokURLregex.test(url)) {
|
||||
return resolve({
|
||||
status: "error",
|
||||
message: "Invalid Tiktok URL. Make sure your url is correct!"
|
||||
})
|
||||
}
|
||||
url = url.replace("https://vm", "https://vt")
|
||||
Axios(url, {
|
||||
method: "HEAD",
|
||||
httpsAgent:
|
||||
(proxy &&
|
||||
(proxy.startsWith("http") || proxy.startsWith("https")
|
||||
? new HttpsProxyAgent(proxy)
|
||||
: proxy.startsWith("socks")
|
||||
? new SocksProxyAgent(proxy)
|
||||
: undefined)) ||
|
||||
undefined
|
||||
})
|
||||
.then(async ({ request }) => {
|
||||
const { responseUrl } = request.res
|
||||
let ID = responseUrl.match(/\d{17,21}/g)
|
||||
if (ID === null)
|
||||
return resolve({
|
||||
status: "error",
|
||||
message:
|
||||
"Failed to fetch tiktok url. Make sure your tiktok url is correct!"
|
||||
})
|
||||
ID = ID[0]
|
||||
|
||||
const resultComments = await parseComments(ID, commentLimit, proxy)
|
||||
return resolve({
|
||||
status: "success",
|
||||
result: resultComments.comments,
|
||||
totalComments: resultComments.total
|
||||
})
|
||||
})
|
||||
.catch((e) => resolve({ status: "error", message: e.message }))
|
||||
})
|
||||
|
||||
const requestComments = async (
|
||||
id: string,
|
||||
commentLimit: number,
|
||||
proxy?: string
|
||||
) => {
|
||||
const { data } = await Axios(
|
||||
_tiktokGetComments(_getCommentsParams(id, commentLimit)),
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"User-Agent":
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36"
|
||||
},
|
||||
httpsAgent:
|
||||
(proxy &&
|
||||
(proxy.startsWith("http") || proxy.startsWith("https")
|
||||
? new HttpsProxyAgent(proxy)
|
||||
: proxy.startsWith("socks")
|
||||
? new SocksProxyAgent(proxy)
|
||||
: undefined)) ||
|
||||
undefined
|
||||
}
|
||||
)
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
const parseComments = async (
|
||||
id: string,
|
||||
commentLimit?: number,
|
||||
proxy?: string
|
||||
) => {
|
||||
const comments: Comments[] = []
|
||||
let cursor: number = 0
|
||||
let counter: number = 0
|
||||
let count: number = 50
|
||||
let total: number = 0
|
||||
let hasMore: boolean = true
|
||||
|
||||
while (hasMore) {
|
||||
for (let i = 0; i < count; i++) {}
|
||||
|
||||
const result = await requestComments(id, cursor, proxy)
|
||||
|
||||
// Check if the result has more comments
|
||||
if (result.has_more === 0) hasMore = false
|
||||
|
||||
result.comments?.forEach((v: any) => {
|
||||
const comment = {
|
||||
cid: v.cid,
|
||||
text: v.text,
|
||||
commentLanguage: v.comment_language,
|
||||
createTime: v.create_time,
|
||||
likeCount: v.digg_count,
|
||||
isAuthorLiked: v.is_author_digged,
|
||||
isCommentTranslatable: v.is_comment_translatable,
|
||||
replyCommentTotal: v.reply_comment_total,
|
||||
user: {
|
||||
uid: v.user.uid,
|
||||
avatarThumb: v.user.avatar_thumb.url_list,
|
||||
nickname: v.user.nickname,
|
||||
username: v.user.unique_id,
|
||||
isVerified: v.user.custom_verify !== ""
|
||||
} as User,
|
||||
url: v.share_info?.url || "",
|
||||
replyComment: []
|
||||
}
|
||||
|
||||
if (v.reply_comment !== null) {
|
||||
v.reply_comment.forEach((v: any) => {
|
||||
comment.replyComment.push({
|
||||
cid: v.cid,
|
||||
text: v.text,
|
||||
commentLanguage: v.comment_language,
|
||||
createTime: v.create_time,
|
||||
likeCount: v.digg_count,
|
||||
isAuthorLiked: v.is_author_digged,
|
||||
isCommentTranslatable: v.is_comment_translatable,
|
||||
replyCommentTotal: v.reply_comment_total,
|
||||
user: {
|
||||
uid: v.user.uid,
|
||||
avatarThumb: v.user.avatar_thumb.url_list,
|
||||
nickname: v.user.nickname,
|
||||
username: v.user.unique_id,
|
||||
isVerified: v.user.custom_verify !== ""
|
||||
} as User,
|
||||
url: v.share_info?.url || "",
|
||||
replyComment: []
|
||||
})
|
||||
|
||||
total++
|
||||
})
|
||||
}
|
||||
total++
|
||||
comments.push(comment)
|
||||
})
|
||||
|
||||
// Check if the comments length is equal to the comment limit
|
||||
if (commentLimit) {
|
||||
let loopCount = Math.floor(commentLimit / 50)
|
||||
if (counter >= loopCount) hasMore = false
|
||||
}
|
||||
|
||||
hasMore = result.has_more === 1
|
||||
cursor = result.has_more === 1 ? result.cursor : 0
|
||||
counter++
|
||||
}
|
||||
|
||||
return {
|
||||
total: total,
|
||||
comments: commentLimit ? comments.slice(0, commentLimit) : comments
|
||||
}
|
||||
}
|
||||
@ -1,263 +0,0 @@
|
||||
import Axios from "axios"
|
||||
import qs from "qs"
|
||||
import { load } from "cheerio"
|
||||
import { _tiktokGetPosts, _tiktokurl } from "../../constants/api"
|
||||
import {
|
||||
AuthorPost,
|
||||
Posts,
|
||||
StalkResult,
|
||||
Stats,
|
||||
Users
|
||||
} from "../../types/search/stalker"
|
||||
import { _userPostsParams, _xttParams } from "../../constants/params"
|
||||
import { createCipheriv } from "crypto"
|
||||
import { HttpsProxyAgent } from "https-proxy-agent"
|
||||
import { SocksProxyAgent } from "socks-proxy-agent"
|
||||
|
||||
/**
|
||||
* Tiktok Stalk User
|
||||
* @param {string} username - The username you want to stalk
|
||||
* @param {object|string} cookie - Your Tiktok Cookie (optional)
|
||||
* @param {number} postLimit - The limit of post you want to get (optional)
|
||||
* @param {string} proxy - Your Proxy (optional)
|
||||
* @returns {Promise<StalkResult>}
|
||||
*/
|
||||
|
||||
export const StalkUser = (
|
||||
username: string,
|
||||
cookie?: any,
|
||||
postLimit?: number,
|
||||
proxy?: string
|
||||
): Promise<StalkResult> =>
|
||||
new Promise(async (resolve) => {
|
||||
username = username.replace("@", "")
|
||||
Axios.get(`${_tiktokurl}/@${username}`, {
|
||||
headers: {
|
||||
"User-Agent":
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36",
|
||||
cookie:
|
||||
typeof cookie === "object"
|
||||
? cookie.map((v) => `${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(async ({ data }) => {
|
||||
const $ = load(data)
|
||||
const result = JSON.parse(
|
||||
$("script#__UNIVERSAL_DATA_FOR_REHYDRATION__").text()
|
||||
)
|
||||
if (
|
||||
!result["__DEFAULT_SCOPE__"] &&
|
||||
!result["__DEFAULT_SCOPE__"]["webapp.user-detail"]
|
||||
) {
|
||||
return resolve({
|
||||
status: "error",
|
||||
message: "User not found!"
|
||||
})
|
||||
}
|
||||
const dataUser =
|
||||
result["__DEFAULT_SCOPE__"]["webapp.user-detail"]["userInfo"]
|
||||
|
||||
const posts: Posts[] = await parsePosts(dataUser, postLimit, proxy)
|
||||
const { users, stats } = parseDataUser(dataUser, posts)
|
||||
|
||||
resolve({
|
||||
status: "success",
|
||||
result: {
|
||||
users,
|
||||
stats,
|
||||
posts
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch((e) => resolve({ status: "error", message: e.message }))
|
||||
})
|
||||
|
||||
/**
|
||||
* Thanks to:
|
||||
* https://github.com/atharahmed/tiktok-private-api/blob/020ede2eaa6021bcd363282d8cef1aacaff2f88c/src/repositories/user.repository.ts#L148
|
||||
*/
|
||||
|
||||
const request = async (
|
||||
secUid: string,
|
||||
cursor = 0,
|
||||
count = 30,
|
||||
proxy?: string
|
||||
) => {
|
||||
const { data } = await Axios.get(`${_tiktokGetPosts(_userPostsParams())}`, {
|
||||
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(_xttParams(secUid, cursor, count))
|
||||
},
|
||||
httpsAgent:
|
||||
(proxy &&
|
||||
(proxy.startsWith("http") || proxy.startsWith("https")
|
||||
? new HttpsProxyAgent(proxy)
|
||||
: proxy.startsWith("socks")
|
||||
? new SocksProxyAgent(proxy)
|
||||
: undefined)) ||
|
||||
undefined
|
||||
})
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
const parseDataUser = (dataUser: any, posts: Posts[]) => {
|
||||
// User Info Result
|
||||
const users: Users = {
|
||||
id: dataUser.user.id,
|
||||
username: dataUser.user.uniqueId,
|
||||
nickname: dataUser.user.nickname,
|
||||
avatarLarger: dataUser.user.avatarLarger,
|
||||
avatarThumb: dataUser.user.avatarThumb,
|
||||
avatarMedium: dataUser.user.avatarMedium,
|
||||
signature: dataUser.user.signature,
|
||||
verified: dataUser.user.verified,
|
||||
privateAccount: dataUser.user.privateAccount,
|
||||
region: dataUser.user.region,
|
||||
commerceUser: dataUser.user.commerceUserInfo.commerceUser,
|
||||
usernameModifyTime: dataUser.user.uniqueIdModifyTime,
|
||||
nicknameModifyTime: dataUser.user.nickNameModifyTime
|
||||
}
|
||||
|
||||
// Statistics Result
|
||||
const stats: Stats = {
|
||||
followerCount: dataUser.stats.followerCount,
|
||||
followingCount: dataUser.stats.followingCount,
|
||||
heartCount: dataUser.stats.heartCount,
|
||||
videoCount: dataUser.stats.videoCount,
|
||||
likeCount: dataUser.stats.diggCount,
|
||||
friendCount: dataUser.stats.friendCount,
|
||||
postCount: posts.length
|
||||
}
|
||||
|
||||
return { users, stats }
|
||||
}
|
||||
|
||||
const parsePosts = async (
|
||||
dataUser: any,
|
||||
postLimit?: number,
|
||||
proxy?: string
|
||||
): Promise<Posts[]> => {
|
||||
// Posts Result
|
||||
let hasMore = true
|
||||
let cursor: number | null = null
|
||||
const posts: Posts[] = []
|
||||
while (hasMore) {
|
||||
let result2: any | null = null
|
||||
let counter = 0
|
||||
|
||||
// Prevent missing response posts
|
||||
for (let i = 0; i < 30; i++) {
|
||||
result2 = await request(dataUser.user.secUid, cursor, 30, proxy)
|
||||
if (result2 !== "") break
|
||||
}
|
||||
|
||||
// Validate
|
||||
if (result2 === "") hasMore = false // No More Post
|
||||
|
||||
result2?.itemList?.forEach((v: any) => {
|
||||
const author: AuthorPost = {
|
||||
id: v.author.id,
|
||||
username: v.author.uniqueId,
|
||||
nickname: v.author.nickname,
|
||||
avatarLarger: v.author.avatarLarger,
|
||||
avatarThumb: v.author.avatarThumb,
|
||||
avatarMedium: v.author.avatarMedium,
|
||||
signature: v.author.signature,
|
||||
verified: v.author.verified,
|
||||
openFavorite: v.author.openFavorite,
|
||||
privateAccount: v.author.privateAccount,
|
||||
isADVirtual: v.author.isADVirtual,
|
||||
isEmbedBanned: v.author.isEmbedBanned
|
||||
}
|
||||
|
||||
if (v.imagePost) {
|
||||
const images: string[] = v.imagePost.images.map(
|
||||
(img: any) => img.imageURL.urlList[0]
|
||||
)
|
||||
|
||||
posts.push({
|
||||
id: v.id,
|
||||
desc: v.desc,
|
||||
createTime: v.createTime,
|
||||
digged: v.digged,
|
||||
duetEnabled: v.duetEnabled,
|
||||
forFriend: v.forFriend,
|
||||
officalItem: v.officalItem,
|
||||
originalItem: v.originalItem,
|
||||
privateItem: v.privateItem,
|
||||
shareEnabled: v.shareEnabled,
|
||||
stitchEnabled: v.stitchEnabled,
|
||||
stats: v.stats,
|
||||
music: v.music,
|
||||
author,
|
||||
images
|
||||
})
|
||||
} else {
|
||||
const video = {
|
||||
id: v.video.id,
|
||||
duration: v.video.duration,
|
||||
format: v.video.format,
|
||||
bitrate: v.video.bitrate,
|
||||
ratio: v.video.ratio,
|
||||
playAddr: v.video.playAddr,
|
||||
cover: v.video.cover,
|
||||
originCover: v.video.originCover,
|
||||
dynamicCover: v.video.dynamicCover,
|
||||
downloadAddr: v.video.downloadAddr
|
||||
}
|
||||
|
||||
posts.push({
|
||||
id: v.id,
|
||||
desc: v.desc,
|
||||
createTime: v.createTime,
|
||||
digged: v.digged,
|
||||
duetEnabled: v.duetEnabled,
|
||||
forFriend: v.forFriend,
|
||||
officalItem: v.officalItem,
|
||||
originalItem: v.originalItem,
|
||||
privateItem: v.privateItem,
|
||||
shareEnabled: v.shareEnabled,
|
||||
stitchEnabled: v.stitchEnabled,
|
||||
stats: v.stats,
|
||||
music: v.music,
|
||||
author,
|
||||
video
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Restrict too many data requests
|
||||
if (postLimit !== 0) {
|
||||
let loopCount = Math.floor(postLimit / 30)
|
||||
if (counter >= loopCount) break
|
||||
}
|
||||
|
||||
hasMore = result2.hasMore
|
||||
cursor = hasMore ? result2.cursor : null
|
||||
counter++
|
||||
}
|
||||
|
||||
return postLimit ? posts.slice(0, postLimit) : posts
|
||||
}
|
||||
|
||||
const xttparams = (params: any) => {
|
||||
const cipher = createCipheriv(
|
||||
"aes-128-cbc",
|
||||
"webapp1.0+202106",
|
||||
"webapp1.0+202106"
|
||||
)
|
||||
return Buffer.concat([cipher.update(params), cipher.final()]).toString(
|
||||
"base64"
|
||||
)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user