@nxgiang/tiktok-api 1.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +492 -0
- package/CODE_OF_CONDUCT.md +128 -0
- package/CONTRIBUTING.md +95 -0
- package/LICENSE +201 -0
- package/README.md +1663 -0
- package/bun.lock +367 -0
- package/helper/signature.js +390 -0
- package/helper/webmssdk.js +4586 -0
- package/helper/xbogus.js +563 -0
- package/install.sh +51 -0
- package/lib/cli/index.d.ts +2 -0
- package/lib/cli/index.js +809 -0
- package/lib/constants/api.d.ts +22 -0
- package/lib/constants/api.js +39 -0
- package/lib/constants/headers.d.ts +2 -0
- package/lib/constants/headers.js +5 -0
- package/lib/constants/index.d.ts +23 -0
- package/lib/constants/index.js +26 -0
- package/lib/constants/params.d.ts +19 -0
- package/lib/constants/params.js +531 -0
- package/lib/index.d.ts +93 -0
- package/lib/index.js +137 -0
- package/lib/lib/logger.d.ts +8 -0
- package/lib/lib/logger.js +25 -0
- package/lib/services/cookieManager.d.ts +10 -0
- package/lib/services/cookieManager.js +51 -0
- package/lib/services/downloadManager.d.ts +5 -0
- package/lib/services/downloadManager.js +188 -0
- package/lib/services/tiktokService.d.ts +14 -0
- package/lib/services/tiktokService.js +78 -0
- package/lib/types/common.d.ts +65 -0
- package/lib/types/common.js +2 -0
- package/lib/types/cookieManager.d.ts +13 -0
- package/lib/types/cookieManager.js +2 -0
- package/lib/types/downloader/musicaldownDownloader.d.ts +27 -0
- package/lib/types/downloader/musicaldownDownloader.js +2 -0
- package/lib/types/downloader/ssstikDownloader.d.ts +30 -0
- package/lib/types/downloader/ssstikDownloader.js +2 -0
- package/lib/types/downloader/tiktokApiDownloader.d.ts +38 -0
- package/lib/types/downloader/tiktokApiDownloader.js +2 -0
- package/lib/types/get/getCollection.d.ts +53 -0
- package/lib/types/get/getCollection.js +2 -0
- package/lib/types/get/getComments.d.ts +26 -0
- package/lib/types/get/getComments.js +2 -0
- package/lib/types/get/getMusicDetail.d.ts +49 -0
- package/lib/types/get/getMusicDetail.js +2 -0
- package/lib/types/get/getMusicVideos.d.ts +93 -0
- package/lib/types/get/getMusicVideos.js +2 -0
- package/lib/types/get/getPlaylist.d.ts +65 -0
- package/lib/types/get/getPlaylist.js +2 -0
- package/lib/types/get/getProfile.d.ts +71 -0
- package/lib/types/get/getProfile.js +2 -0
- package/lib/types/get/getTrendings.d.ts +61 -0
- package/lib/types/get/getTrendings.js +2 -0
- package/lib/types/get/getUserLiked.d.ts +90 -0
- package/lib/types/get/getUserLiked.js +2 -0
- package/lib/types/get/getUserPosts.d.ts +68 -0
- package/lib/types/get/getUserPosts.js +2 -0
- package/lib/types/get/getUserReposts.d.ts +104 -0
- package/lib/types/get/getUserReposts.js +2 -0
- package/lib/types/search/index.d.ts +15 -0
- package/lib/types/search/index.js +2 -0
- package/lib/types/search/liveSearch.d.ts +48 -0
- package/lib/types/search/liveSearch.js +2 -0
- package/lib/types/search/userSearch.d.ts +32 -0
- package/lib/types/search/userSearch.js +2 -0
- package/lib/types/search/videoSearch.d.ts +62 -0
- package/lib/types/search/videoSearch.js +2 -0
- package/lib/utils/downloader/musicaldownDownloader.d.ts +2 -0
- package/lib/utils/downloader/musicaldownDownloader.js +193 -0
- package/lib/utils/downloader/ssstikDownloader.d.ts +2 -0
- package/lib/utils/downloader/ssstikDownloader.js +177 -0
- package/lib/utils/downloader/tiktokAPIDownloader.d.ts +3 -0
- package/lib/utils/downloader/tiktokAPIDownloader.js +221 -0
- package/lib/utils/get/getCollection.d.ts +7 -0
- package/lib/utils/get/getCollection.js +113 -0
- package/lib/utils/get/getComments.d.ts +2 -0
- package/lib/utils/get/getComments.js +139 -0
- package/lib/utils/get/getMusicDetail.d.ts +2 -0
- package/lib/utils/get/getMusicDetail.js +68 -0
- package/lib/utils/get/getMusicVideos.d.ts +2 -0
- package/lib/utils/get/getMusicVideos.js +249 -0
- package/lib/utils/get/getPlaylist.d.ts +7 -0
- package/lib/utils/get/getPlaylist.js +115 -0
- package/lib/utils/get/getProfile.d.ts +2 -0
- package/lib/utils/get/getProfile.js +92 -0
- package/lib/utils/get/getTrendings.d.ts +7 -0
- package/lib/utils/get/getTrendings.js +120 -0
- package/lib/utils/get/getUserLiked.d.ts +2 -0
- package/lib/utils/get/getUserLiked.js +204 -0
- package/lib/utils/get/getUserPosts.d.ts +2 -0
- package/lib/utils/get/getUserPosts.js +199 -0
- package/lib/utils/get/getUserRepost.d.ts +2 -0
- package/lib/utils/get/getUserRepost.js +239 -0
- package/lib/utils/search/liveSearch.d.ts +2 -0
- package/lib/utils/search/liveSearch.js +99 -0
- package/lib/utils/search/userSearch.d.ts +2 -0
- package/lib/utils/search/userSearch.js +76 -0
- package/lib/utils/search/videoSearch.d.ts +2 -0
- package/lib/utils/search/videoSearch.js +140 -0
- package/lib/utils/urlExtractors.d.ts +3 -0
- package/lib/utils/urlExtractors.js +37 -0
- package/lib/utils/validator.d.ts +1 -0
- package/lib/utils/validator.js +13 -0
- package/package.json +60 -0
- package/test/collection-test.ts +73 -0
- package/test/comments-test.ts +54 -0
- package/test/downloader-v1-test.ts +49 -0
- package/test/downloader-v2-test.ts +47 -0
- package/test/downloader-v3-test.ts +35 -0
- package/test/music-detail-test.ts +97 -0
- package/test/music-videos-test.ts +86 -0
- package/test/playlist-test.ts +48 -0
- package/test/profile-test.ts +49 -0
- package/test/search-live-test.ts +42 -0
- package/test/search-user-test.ts +46 -0
- package/test/search-video-test.ts +53 -0
- package/test/trending-test.ts +128 -0
- package/test/userliked-test.ts +65 -0
- package/test/userposts-test.ts +56 -0
- package/test/userreposts-test.ts +57 -0
- package/tobyg74-tiktok-api-1.3.7.tgz +0 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getMusicDetail = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const api_1 = require("../../constants/api");
|
|
9
|
+
const params_1 = require("../../constants/params");
|
|
10
|
+
const https_proxy_agent_1 = require("https-proxy-agent");
|
|
11
|
+
const socks_proxy_agent_1 = require("socks-proxy-agent");
|
|
12
|
+
const tiktokService_1 = require("../../services/tiktokService");
|
|
13
|
+
const headers_1 = require("../../constants/headers");
|
|
14
|
+
const urlExtractors_1 = require("../urlExtractors");
|
|
15
|
+
const getMusicDetail = (musicIdOrUrl, cookie, proxy) => new Promise(async (resolve) => {
|
|
16
|
+
try {
|
|
17
|
+
const musicId = (0, urlExtractors_1.extractMusicId)(musicIdOrUrl);
|
|
18
|
+
if (!musicId) {
|
|
19
|
+
return resolve({
|
|
20
|
+
status: "error",
|
|
21
|
+
message: "Invalid music ID or URL format"
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
const Tiktok = new tiktokService_1.TiktokService();
|
|
25
|
+
const params = (0, params_1._getMusicDetailParams)(musicId);
|
|
26
|
+
const xttparams = Tiktok.generateXTTParams(params);
|
|
27
|
+
const url = new URL((0, api_1._tiktokGetMusicDetail)());
|
|
28
|
+
url.search = params;
|
|
29
|
+
const config = {
|
|
30
|
+
headers: {
|
|
31
|
+
"User-Agent": headers_1.webUserAgent,
|
|
32
|
+
Cookie: Array.isArray(cookie) ? cookie.join("; ") : cookie,
|
|
33
|
+
"x-tt-params": xttparams
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
if (proxy) {
|
|
37
|
+
if (proxy.startsWith("http://") || proxy.startsWith("https://")) {
|
|
38
|
+
config.httpsAgent = new https_proxy_agent_1.HttpsProxyAgent(proxy);
|
|
39
|
+
}
|
|
40
|
+
else if (proxy.startsWith("socks://")) {
|
|
41
|
+
config.httpsAgent = new socks_proxy_agent_1.SocksProxyAgent(proxy);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const response = await axios_1.default.get(url.toString(), config);
|
|
45
|
+
if (response.data.statusCode === 0 && response.data.musicInfo) {
|
|
46
|
+
resolve({
|
|
47
|
+
status: "success",
|
|
48
|
+
result: {
|
|
49
|
+
musicInfo: response.data.musicInfo,
|
|
50
|
+
shareMeta: response.data.shareMeta
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
resolve({
|
|
56
|
+
status: "error",
|
|
57
|
+
message: response.data.status_msg || "Music not found or invalid response"
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
resolve({
|
|
63
|
+
status: "error",
|
|
64
|
+
message: err.message || "Failed to fetch music detail"
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
exports.getMusicDetail = getMusicDetail;
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getMusicVideos = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const api_1 = require("../../constants/api");
|
|
9
|
+
const params_1 = require("../../constants/params");
|
|
10
|
+
const https_proxy_agent_1 = require("https-proxy-agent");
|
|
11
|
+
const socks_proxy_agent_1 = require("socks-proxy-agent");
|
|
12
|
+
const tiktokService_1 = require("../../services/tiktokService");
|
|
13
|
+
const async_retry_1 = __importDefault(require("async-retry"));
|
|
14
|
+
const urlExtractors_1 = require("../urlExtractors");
|
|
15
|
+
const getMusicVideos = (musicIdOrUrl, proxy, page, count) => new Promise(async (resolve) => {
|
|
16
|
+
try {
|
|
17
|
+
const musicId = (0, urlExtractors_1.extractMusicId)(musicIdOrUrl);
|
|
18
|
+
if (!musicId) {
|
|
19
|
+
return resolve({
|
|
20
|
+
status: "error",
|
|
21
|
+
message: "Invalid music ID or URL format"
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
const data = await parseMusicVideos(musicId, page || 1, count || 30, proxy);
|
|
25
|
+
if (!data.videos || data.videos.length === 0) {
|
|
26
|
+
return resolve({
|
|
27
|
+
status: "error",
|
|
28
|
+
message: "No videos found for this music ID!"
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
resolve({
|
|
32
|
+
status: "success",
|
|
33
|
+
result: data
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
if (err.status === 400 ||
|
|
38
|
+
(err.response?.data && err.response.data.statusCode === 10201)) {
|
|
39
|
+
return resolve({
|
|
40
|
+
status: "error",
|
|
41
|
+
message: "Music not found!"
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return resolve({
|
|
45
|
+
status: "error",
|
|
46
|
+
message: err.message || "Failed to fetch music videos"
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
exports.getMusicVideos = getMusicVideos;
|
|
51
|
+
const parseMusicVideos = async (musicId, page, count, proxy) => {
|
|
52
|
+
let cursor = 0;
|
|
53
|
+
if (page > 1) {
|
|
54
|
+
cursor = (page - 1) * count;
|
|
55
|
+
}
|
|
56
|
+
const videos = [];
|
|
57
|
+
let musicInfo;
|
|
58
|
+
const Tiktok = new tiktokService_1.TiktokService();
|
|
59
|
+
const params = (0, params_1._getMusicVideosParams)(musicId, cursor, count);
|
|
60
|
+
const xttParams = Tiktok.generateXTTParams(params);
|
|
61
|
+
const result = await requestMusicVideos(proxy, xttParams);
|
|
62
|
+
if (!result) {
|
|
63
|
+
return {
|
|
64
|
+
music: undefined,
|
|
65
|
+
videos: [],
|
|
66
|
+
hasMore: false,
|
|
67
|
+
cursor: 0,
|
|
68
|
+
totalVideos: 0
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (result.musicInfo || result.music) {
|
|
72
|
+
musicInfo = extractMusicInfo(result.musicInfo || result.music);
|
|
73
|
+
}
|
|
74
|
+
else if (result.itemList?.length > 0 && result.itemList[0].music) {
|
|
75
|
+
musicInfo = extractMusicInfoFromVideo(result.itemList[0].music);
|
|
76
|
+
}
|
|
77
|
+
if (result.itemList && result.itemList.length > 0) {
|
|
78
|
+
result.itemList.forEach((item) => {
|
|
79
|
+
const video = extractVideoData(item);
|
|
80
|
+
if (video) {
|
|
81
|
+
videos.push(video);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
const hasMore = result.hasMore || false;
|
|
86
|
+
const nextCursor = result.cursor || cursor + videos.length;
|
|
87
|
+
return {
|
|
88
|
+
music: musicInfo,
|
|
89
|
+
videos,
|
|
90
|
+
hasMore,
|
|
91
|
+
cursor: nextCursor,
|
|
92
|
+
totalVideos: videos.length
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
const extractMusicInfo = (musicData) => {
|
|
96
|
+
return {
|
|
97
|
+
id: musicData.id || musicData.musicId,
|
|
98
|
+
title: musicData.title || "Unknown",
|
|
99
|
+
authorName: musicData.authorName || musicData.author || "Unknown",
|
|
100
|
+
author: musicData.author,
|
|
101
|
+
duration: musicData.duration,
|
|
102
|
+
original: musicData.original,
|
|
103
|
+
playUrl: musicData.playUrl,
|
|
104
|
+
coverThumb: musicData.coverThumb,
|
|
105
|
+
coverLarge: musicData.coverLarge,
|
|
106
|
+
coverMedium: musicData.coverMedium
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
const extractMusicInfoFromVideo = (musicData) => {
|
|
110
|
+
return {
|
|
111
|
+
id: musicData.id,
|
|
112
|
+
title: musicData.title,
|
|
113
|
+
authorName: musicData.authorName,
|
|
114
|
+
duration: musicData.duration,
|
|
115
|
+
original: musicData.original,
|
|
116
|
+
playUrl: musicData.playUrl,
|
|
117
|
+
coverThumb: musicData.coverThumb,
|
|
118
|
+
coverLarge: musicData.coverLarge,
|
|
119
|
+
coverMedium: musicData.coverMedium
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
const extractVideoData = (item) => {
|
|
123
|
+
if (!item || !item.id) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
const author = {
|
|
127
|
+
id: item.author?.id || "",
|
|
128
|
+
uniqueId: item.author?.uniqueId || "",
|
|
129
|
+
nickname: item.author?.nickname || "",
|
|
130
|
+
avatarLarger: item.author?.avatarLarger,
|
|
131
|
+
avatarThumb: item.author?.avatarThumb,
|
|
132
|
+
avatarMedium: item.author?.avatarMedium,
|
|
133
|
+
signature: item.author?.signature,
|
|
134
|
+
verified: item.author?.verified || false,
|
|
135
|
+
openFavorite: item.author?.openFavorite,
|
|
136
|
+
privateAccount: item.author?.privateAccount,
|
|
137
|
+
isADVirtual: item.author?.isADVirtual,
|
|
138
|
+
isEmbedBanned: item.author?.isEmbedBanned
|
|
139
|
+
};
|
|
140
|
+
const stats = {
|
|
141
|
+
collectCount: item.stats?.collectCount,
|
|
142
|
+
commentCount: item.stats?.commentCount || 0,
|
|
143
|
+
diggCount: item.stats?.diggCount || item.stats?.likeCount || 0,
|
|
144
|
+
playCount: item.stats?.playCount || 0,
|
|
145
|
+
shareCount: item.stats?.shareCount || 0
|
|
146
|
+
};
|
|
147
|
+
const music = {
|
|
148
|
+
id: item.music?.id || "",
|
|
149
|
+
title: item.music?.title || "",
|
|
150
|
+
authorName: item.music?.authorName || "",
|
|
151
|
+
duration: item.music?.duration || 0,
|
|
152
|
+
playUrl: item.music?.playUrl,
|
|
153
|
+
coverLarge: item.music?.coverLarge,
|
|
154
|
+
coverMedium: item.music?.coverMedium,
|
|
155
|
+
coverThumb: item.music?.coverThumb,
|
|
156
|
+
original: item.music?.original
|
|
157
|
+
};
|
|
158
|
+
const video = {
|
|
159
|
+
id: item.id,
|
|
160
|
+
desc: item.desc,
|
|
161
|
+
createTime: item.createTime,
|
|
162
|
+
digged: item.digged,
|
|
163
|
+
duetEnabled: item.duetEnabled,
|
|
164
|
+
forFriend: item.forFriend,
|
|
165
|
+
officalItem: item.officalItem,
|
|
166
|
+
originalItem: item.originalItem,
|
|
167
|
+
privateItem: item.privateItem,
|
|
168
|
+
shareEnabled: item.shareEnabled,
|
|
169
|
+
stitchEnabled: item.stitchEnabled,
|
|
170
|
+
stats,
|
|
171
|
+
author,
|
|
172
|
+
music
|
|
173
|
+
};
|
|
174
|
+
if (item.video) {
|
|
175
|
+
const videoDetails = {
|
|
176
|
+
id: item.video.id,
|
|
177
|
+
duration: item.video.duration,
|
|
178
|
+
ratio: item.video.ratio,
|
|
179
|
+
cover: item.video.cover,
|
|
180
|
+
originCover: item.video.originCover,
|
|
181
|
+
dynamicCover: item.video.dynamicCover,
|
|
182
|
+
playAddr: item.video.playAddr,
|
|
183
|
+
downloadAddr: item.video.downloadAddr,
|
|
184
|
+
format: item.video.format,
|
|
185
|
+
bitrate: item.video.bitrate
|
|
186
|
+
};
|
|
187
|
+
video.video = videoDetails;
|
|
188
|
+
}
|
|
189
|
+
if (item.imagePost?.images) {
|
|
190
|
+
video.imagePost = item.imagePost.images.map((img) => img.imageURL?.urlList?.[0] || img.imageURL);
|
|
191
|
+
}
|
|
192
|
+
if (item.effectStickers && Array.isArray(item.effectStickers)) {
|
|
193
|
+
video.effectStickers = item.effectStickers.map((effect) => ({
|
|
194
|
+
id: effect.id || "",
|
|
195
|
+
name: effect.name || "",
|
|
196
|
+
type: effect.type
|
|
197
|
+
}));
|
|
198
|
+
}
|
|
199
|
+
return video;
|
|
200
|
+
};
|
|
201
|
+
const requestMusicVideos = async (proxy, xttParams = "") => {
|
|
202
|
+
return (0, async_retry_1.default)(async (bail, attempt) => {
|
|
203
|
+
try {
|
|
204
|
+
const params = (0, params_1._getMusicVideosParams)("", 0, 30);
|
|
205
|
+
const { data } = await axios_1.default.get(`${(0, api_1._tiktokGetMusic)(params)}`, {
|
|
206
|
+
headers: {
|
|
207
|
+
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.53",
|
|
208
|
+
"x-tt-params": xttParams,
|
|
209
|
+
referer: "https://www.tiktok.com/",
|
|
210
|
+
accept: "application/json, text/plain, */*",
|
|
211
|
+
"accept-language": "en-US,en;q=0.9",
|
|
212
|
+
"cache-control": "no-cache",
|
|
213
|
+
pragma: "no-cache",
|
|
214
|
+
"sec-fetch-dest": "empty",
|
|
215
|
+
"sec-fetch-mode": "cors",
|
|
216
|
+
"sec-fetch-site": "same-origin"
|
|
217
|
+
},
|
|
218
|
+
httpsAgent: (proxy &&
|
|
219
|
+
(proxy.startsWith("http") || proxy.startsWith("https")
|
|
220
|
+
? new https_proxy_agent_1.HttpsProxyAgent(proxy)
|
|
221
|
+
: proxy.startsWith("socks")
|
|
222
|
+
? new socks_proxy_agent_1.SocksProxyAgent(proxy)
|
|
223
|
+
: undefined)) ||
|
|
224
|
+
undefined
|
|
225
|
+
});
|
|
226
|
+
if (data === "" || !data) {
|
|
227
|
+
throw new Error("Empty response");
|
|
228
|
+
}
|
|
229
|
+
return data;
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
if (error.response?.status === 400 ||
|
|
233
|
+
error.response?.status === 404 ||
|
|
234
|
+
error.response?.data?.statusCode === 10201) {
|
|
235
|
+
bail(new Error("Music not found or access forbidden!"));
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
throw error;
|
|
239
|
+
}
|
|
240
|
+
}, {
|
|
241
|
+
retries: 10,
|
|
242
|
+
minTimeout: 1000,
|
|
243
|
+
maxTimeout: 5000,
|
|
244
|
+
factor: 2,
|
|
245
|
+
onRetry: (error, attempt) => {
|
|
246
|
+
console.log(`Retry attempt ${attempt} due to: ${error}`);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { TiktokPlaylistResponse } from "../../types/get/getPlaylist";
|
|
2
|
+
export declare const getPlaylist: (playlistId: string, proxy?: string, page?: number, count?: number) => Promise<TiktokPlaylistResponse>;
|
|
3
|
+
export declare const Playlist: (url: string, options?: {
|
|
4
|
+
page?: number;
|
|
5
|
+
proxy?: string;
|
|
6
|
+
count?: number;
|
|
7
|
+
}) => Promise<TiktokPlaylistResponse>;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Playlist = exports.getPlaylist = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const api_1 = require("../../constants/api");
|
|
9
|
+
const params_1 = require("../../constants/params");
|
|
10
|
+
const https_proxy_agent_1 = require("https-proxy-agent");
|
|
11
|
+
const socks_proxy_agent_1 = require("socks-proxy-agent");
|
|
12
|
+
const constants_1 = require("../../constants");
|
|
13
|
+
const async_retry_1 = __importDefault(require("async-retry"));
|
|
14
|
+
const tiktokAPIDownloader_1 = require("../downloader/tiktokAPIDownloader");
|
|
15
|
+
const urlExtractors_1 = require("../urlExtractors");
|
|
16
|
+
const createProxyAgent = (proxy) => {
|
|
17
|
+
if (!proxy)
|
|
18
|
+
return {};
|
|
19
|
+
if (proxy.startsWith("socks")) {
|
|
20
|
+
return {
|
|
21
|
+
httpsAgent: new socks_proxy_agent_1.SocksProxyAgent(proxy)
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
httpsAgent: new https_proxy_agent_1.HttpsProxyAgent(proxy)
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
const getPlaylist = async (playlistId, proxy, page = 1, count = 5) => {
|
|
29
|
+
try {
|
|
30
|
+
const response = await (0, async_retry_1.default)(async () => {
|
|
31
|
+
const res = await (0, axios_1.default)((0, api_1._tiktokGetPlaylist)((0, params_1._getPlaylistParams)(playlistId, page, count)), {
|
|
32
|
+
method: "GET",
|
|
33
|
+
headers: {
|
|
34
|
+
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:138.0) Gecko/20100101 Firefox/138.0",
|
|
35
|
+
Accept: "*/*",
|
|
36
|
+
"Accept-Language": "en-US,en;q=0.7",
|
|
37
|
+
Referer: "https://www.tiktok.com/",
|
|
38
|
+
Origin: "https://www.tiktok.com",
|
|
39
|
+
"Content-Type": "application/json"
|
|
40
|
+
},
|
|
41
|
+
...createProxyAgent(proxy)
|
|
42
|
+
});
|
|
43
|
+
if (res.data && res.data.statusCode === 0) {
|
|
44
|
+
return res.data;
|
|
45
|
+
}
|
|
46
|
+
throw new Error(constants_1.ERROR_MESSAGES.NETWORK_ERROR);
|
|
47
|
+
}, {
|
|
48
|
+
retries: 20,
|
|
49
|
+
minTimeout: 200,
|
|
50
|
+
maxTimeout: 1000
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
status: "success",
|
|
54
|
+
result: {
|
|
55
|
+
hasMore: response.hasMore,
|
|
56
|
+
itemList: response.itemList || [],
|
|
57
|
+
extra: response.extra
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
return {
|
|
63
|
+
status: "error",
|
|
64
|
+
message: error instanceof Error ? error.message : constants_1.ERROR_MESSAGES.NETWORK_ERROR
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
exports.getPlaylist = getPlaylist;
|
|
69
|
+
const Playlist = async (url, options) => {
|
|
70
|
+
try {
|
|
71
|
+
const processedUrl = url.startsWith("http")
|
|
72
|
+
? await (0, tiktokAPIDownloader_1.handleRedirect)(url, options?.proxy)
|
|
73
|
+
: url;
|
|
74
|
+
const playlistId = (0, urlExtractors_1.extractPlaylistId)(processedUrl);
|
|
75
|
+
if (!playlistId) {
|
|
76
|
+
return {
|
|
77
|
+
status: "error",
|
|
78
|
+
message: "Invalid playlist ID or URL format"
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const response = await (0, axios_1.default)((0, api_1._tiktokGetPlaylist)((0, params_1._getPlaylistParams)(playlistId, options.page, options.count)), {
|
|
82
|
+
method: "GET",
|
|
83
|
+
headers: {
|
|
84
|
+
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:138.0) Gecko/20100101 Firefox/138.0",
|
|
85
|
+
Accept: "*/*",
|
|
86
|
+
"Accept-Language": "en-US,en;q=0.7",
|
|
87
|
+
Referer: "https://www.tiktok.com/",
|
|
88
|
+
Origin: "https://www.tiktok.com"
|
|
89
|
+
},
|
|
90
|
+
...createProxyAgent(options?.proxy)
|
|
91
|
+
});
|
|
92
|
+
if (response.data && response.data.status_code === 0) {
|
|
93
|
+
const data = response.data;
|
|
94
|
+
return {
|
|
95
|
+
status: "success",
|
|
96
|
+
result: {
|
|
97
|
+
itemList: data.itemList || [],
|
|
98
|
+
hasMore: data.hasMore,
|
|
99
|
+
extra: data.extra
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
status: "error",
|
|
105
|
+
message: constants_1.ERROR_MESSAGES.NETWORK_ERROR
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
return {
|
|
110
|
+
status: "error",
|
|
111
|
+
message: error instanceof Error ? error.message : constants_1.ERROR_MESSAGES.NETWORK_ERROR
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
exports.Playlist = Playlist;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.StalkUser = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const cheerio_1 = require("cheerio");
|
|
9
|
+
const api_1 = require("../../constants/api");
|
|
10
|
+
const https_proxy_agent_1 = require("https-proxy-agent");
|
|
11
|
+
const socks_proxy_agent_1 = require("socks-proxy-agent");
|
|
12
|
+
const StalkUser = (username, proxy) => new Promise(async (resolve) => {
|
|
13
|
+
username = username.replace("@", "");
|
|
14
|
+
(0, axios_1.default)(`${api_1._tiktokDesktopUrl}/@${username}`, {
|
|
15
|
+
method: "GET",
|
|
16
|
+
headers: {
|
|
17
|
+
"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"
|
|
18
|
+
},
|
|
19
|
+
httpsAgent: (proxy &&
|
|
20
|
+
(proxy.startsWith("http") || proxy.startsWith("https")
|
|
21
|
+
? new https_proxy_agent_1.HttpsProxyAgent(proxy)
|
|
22
|
+
: proxy.startsWith("socks")
|
|
23
|
+
? new socks_proxy_agent_1.SocksProxyAgent(proxy)
|
|
24
|
+
: undefined)) ||
|
|
25
|
+
undefined
|
|
26
|
+
})
|
|
27
|
+
.then(async ({ data }) => {
|
|
28
|
+
const $ = (0, cheerio_1.load)(data);
|
|
29
|
+
const result = JSON.parse($("script#__UNIVERSAL_DATA_FOR_REHYDRATION__").text());
|
|
30
|
+
if (!result["__DEFAULT_SCOPE__"] &&
|
|
31
|
+
!result["__DEFAULT_SCOPE__"]["webapp.user-detail"]) {
|
|
32
|
+
return resolve({
|
|
33
|
+
status: "error",
|
|
34
|
+
message: "User not found!"
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
const dataUser = result["__DEFAULT_SCOPE__"]["webapp.user-detail"]["userInfo"];
|
|
38
|
+
if (!dataUser) {
|
|
39
|
+
return resolve({
|
|
40
|
+
status: "error",
|
|
41
|
+
message: "User not found!"
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
const { user, stats, statsV2 } = parseDataUser(dataUser);
|
|
45
|
+
let response = {
|
|
46
|
+
status: "success",
|
|
47
|
+
result: {
|
|
48
|
+
user,
|
|
49
|
+
stats,
|
|
50
|
+
statsV2
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
resolve(response);
|
|
54
|
+
})
|
|
55
|
+
.catch((e) => resolve({ status: "error", message: e.message }));
|
|
56
|
+
});
|
|
57
|
+
exports.StalkUser = StalkUser;
|
|
58
|
+
const parseDataUser = (dataUser) => {
|
|
59
|
+
const user = {
|
|
60
|
+
uid: dataUser.user.id,
|
|
61
|
+
username: dataUser.user.uniqueId,
|
|
62
|
+
nickname: dataUser.user.nickname,
|
|
63
|
+
avatarLarger: dataUser.user.avatarLarger,
|
|
64
|
+
avatarThumb: dataUser.user.avatarThumb,
|
|
65
|
+
avatarMedium: dataUser.user.avatarMedium,
|
|
66
|
+
signature: dataUser.user.signature,
|
|
67
|
+
verified: dataUser.user.verified,
|
|
68
|
+
privateAccount: dataUser.user.privateAccount,
|
|
69
|
+
region: dataUser.user.region,
|
|
70
|
+
commerceUser: dataUser.user.commerceUserInfo.commerceUser,
|
|
71
|
+
usernameModifyTime: dataUser.user.uniqueIdModifyTime,
|
|
72
|
+
nicknameModifyTime: dataUser.user.nickNameModifyTime,
|
|
73
|
+
secUid: dataUser.user.secUid
|
|
74
|
+
};
|
|
75
|
+
const stats = {
|
|
76
|
+
followerCount: dataUser.stats.followerCount,
|
|
77
|
+
followingCount: dataUser.stats.followingCount,
|
|
78
|
+
heartCount: dataUser.stats.heartCount,
|
|
79
|
+
videoCount: dataUser.stats.videoCount,
|
|
80
|
+
likeCount: dataUser.stats.diggCount,
|
|
81
|
+
friendCount: dataUser.stats.friendCount
|
|
82
|
+
};
|
|
83
|
+
const statsV2 = {
|
|
84
|
+
followerCount: dataUser.statsV2.followerCount,
|
|
85
|
+
followingCount: dataUser.statsV2.followingCount,
|
|
86
|
+
heartCount: dataUser.statsV2.heartCount,
|
|
87
|
+
videoCount: dataUser.statsV2.videoCount,
|
|
88
|
+
likeCount: dataUser.statsV2.diggCount,
|
|
89
|
+
friendCount: dataUser.statsV2.friendCount
|
|
90
|
+
};
|
|
91
|
+
return { user, stats, statsV2 };
|
|
92
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { TiktokTrendingResponse, TrendingCreator } from "../../types/get/getTrendings";
|
|
2
|
+
export declare const getTrendings: (proxy?: string) => Promise<TiktokTrendingResponse>;
|
|
3
|
+
export declare const getTrendingCreators: (proxy?: string) => Promise<{
|
|
4
|
+
status: "success" | "error";
|
|
5
|
+
message?: string;
|
|
6
|
+
result?: TrendingCreator[];
|
|
7
|
+
}>;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getTrendingCreators = exports.getTrendings = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const api_1 = require("../../constants/api");
|
|
9
|
+
const params_1 = require("../../constants/params");
|
|
10
|
+
const https_proxy_agent_1 = require("https-proxy-agent");
|
|
11
|
+
const socks_proxy_agent_1 = require("socks-proxy-agent");
|
|
12
|
+
const getTrendings = (proxy) => new Promise(async (resolve) => {
|
|
13
|
+
try {
|
|
14
|
+
const params = (0, params_1._getTrendingsParams)();
|
|
15
|
+
const url = (0, api_1._tiktokTrendings)(params);
|
|
16
|
+
const response = await axios_1.default.get(url, {
|
|
17
|
+
headers: {
|
|
18
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0",
|
|
19
|
+
Accept: "application/json, text/plain, */*",
|
|
20
|
+
"Accept-Language": "en-US,en;q=0.9",
|
|
21
|
+
"Accept-Encoding": "gzip, deflate, br",
|
|
22
|
+
Connection: "keep-alive",
|
|
23
|
+
"Sec-Fetch-Dest": "empty",
|
|
24
|
+
"Sec-Fetch-Mode": "cors",
|
|
25
|
+
"Sec-Fetch-Site": "same-origin"
|
|
26
|
+
},
|
|
27
|
+
httpsAgent: (proxy &&
|
|
28
|
+
(proxy.startsWith("http") || proxy.startsWith("https")
|
|
29
|
+
? new https_proxy_agent_1.HttpsProxyAgent(proxy)
|
|
30
|
+
: proxy.startsWith("socks")
|
|
31
|
+
? new socks_proxy_agent_1.SocksProxyAgent(proxy)
|
|
32
|
+
: undefined)) ||
|
|
33
|
+
undefined
|
|
34
|
+
});
|
|
35
|
+
if (response.status !== 200) {
|
|
36
|
+
return resolve({
|
|
37
|
+
status: "error",
|
|
38
|
+
message: "Failed to fetch trending data"
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
const data = response.data;
|
|
42
|
+
if (!data || !data.body || data.statusCode !== 0) {
|
|
43
|
+
return resolve({
|
|
44
|
+
status: "error",
|
|
45
|
+
message: "Invalid response from TikTok API"
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
const trendingData = parseTrendingData(data.body);
|
|
49
|
+
resolve({
|
|
50
|
+
status: "success",
|
|
51
|
+
result: trendingData
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
resolve({
|
|
56
|
+
status: "error",
|
|
57
|
+
message: error.message || "Unknown error occurred"
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
exports.getTrendings = getTrendings;
|
|
62
|
+
const parseTrendingData = (body) => {
|
|
63
|
+
const trendingData = [];
|
|
64
|
+
body.forEach((section) => {
|
|
65
|
+
if (section.exploreList && Array.isArray(section.exploreList)) {
|
|
66
|
+
trendingData.push({
|
|
67
|
+
exploreList: section.exploreList,
|
|
68
|
+
pageState: section.pageState || {}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
return trendingData;
|
|
73
|
+
};
|
|
74
|
+
const getTrendingCreators = async (proxy) => {
|
|
75
|
+
try {
|
|
76
|
+
const trendingResponse = await (0, exports.getTrendings)(proxy);
|
|
77
|
+
if (trendingResponse.status === "error") {
|
|
78
|
+
return {
|
|
79
|
+
status: "error",
|
|
80
|
+
message: trendingResponse.message
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const creators = [];
|
|
84
|
+
trendingResponse.result?.forEach((data) => {
|
|
85
|
+
data.exploreList.forEach((item) => {
|
|
86
|
+
if (item.cardItem && item.cardItem.type === 2) {
|
|
87
|
+
const cardItem = item.cardItem;
|
|
88
|
+
const creator = {
|
|
89
|
+
id: cardItem.id,
|
|
90
|
+
username: cardItem.subTitle.replace("@", ""),
|
|
91
|
+
nickname: cardItem.title,
|
|
92
|
+
avatarThumb: cardItem.cover,
|
|
93
|
+
description: cardItem.description,
|
|
94
|
+
verified: cardItem.extraInfo?.verified || false,
|
|
95
|
+
followerCount: cardItem.extraInfo?.fans || 0,
|
|
96
|
+
likeCount: cardItem.extraInfo?.likes || 0,
|
|
97
|
+
videoCount: cardItem.extraInfo?.video || 0,
|
|
98
|
+
followingCount: cardItem.extraInfo?.following || 0,
|
|
99
|
+
heartCount: cardItem.extraInfo?.heart || 0,
|
|
100
|
+
diggCount: cardItem.extraInfo?.digg || 0,
|
|
101
|
+
secUid: cardItem.extraInfo?.secUid || "",
|
|
102
|
+
link: cardItem.link
|
|
103
|
+
};
|
|
104
|
+
creators.push(creator);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
return {
|
|
109
|
+
status: "success",
|
|
110
|
+
result: creators
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
return {
|
|
115
|
+
status: "error",
|
|
116
|
+
message: error.message || "Unknown error occurred"
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
exports.getTrendingCreators = getTrendingCreators;
|