@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.
Files changed (122) hide show
  1. package/CHANGELOG.md +492 -0
  2. package/CODE_OF_CONDUCT.md +128 -0
  3. package/CONTRIBUTING.md +95 -0
  4. package/LICENSE +201 -0
  5. package/README.md +1663 -0
  6. package/bun.lock +367 -0
  7. package/helper/signature.js +390 -0
  8. package/helper/webmssdk.js +4586 -0
  9. package/helper/xbogus.js +563 -0
  10. package/install.sh +51 -0
  11. package/lib/cli/index.d.ts +2 -0
  12. package/lib/cli/index.js +809 -0
  13. package/lib/constants/api.d.ts +22 -0
  14. package/lib/constants/api.js +39 -0
  15. package/lib/constants/headers.d.ts +2 -0
  16. package/lib/constants/headers.js +5 -0
  17. package/lib/constants/index.d.ts +23 -0
  18. package/lib/constants/index.js +26 -0
  19. package/lib/constants/params.d.ts +19 -0
  20. package/lib/constants/params.js +531 -0
  21. package/lib/index.d.ts +93 -0
  22. package/lib/index.js +137 -0
  23. package/lib/lib/logger.d.ts +8 -0
  24. package/lib/lib/logger.js +25 -0
  25. package/lib/services/cookieManager.d.ts +10 -0
  26. package/lib/services/cookieManager.js +51 -0
  27. package/lib/services/downloadManager.d.ts +5 -0
  28. package/lib/services/downloadManager.js +188 -0
  29. package/lib/services/tiktokService.d.ts +14 -0
  30. package/lib/services/tiktokService.js +78 -0
  31. package/lib/types/common.d.ts +65 -0
  32. package/lib/types/common.js +2 -0
  33. package/lib/types/cookieManager.d.ts +13 -0
  34. package/lib/types/cookieManager.js +2 -0
  35. package/lib/types/downloader/musicaldownDownloader.d.ts +27 -0
  36. package/lib/types/downloader/musicaldownDownloader.js +2 -0
  37. package/lib/types/downloader/ssstikDownloader.d.ts +30 -0
  38. package/lib/types/downloader/ssstikDownloader.js +2 -0
  39. package/lib/types/downloader/tiktokApiDownloader.d.ts +38 -0
  40. package/lib/types/downloader/tiktokApiDownloader.js +2 -0
  41. package/lib/types/get/getCollection.d.ts +53 -0
  42. package/lib/types/get/getCollection.js +2 -0
  43. package/lib/types/get/getComments.d.ts +26 -0
  44. package/lib/types/get/getComments.js +2 -0
  45. package/lib/types/get/getMusicDetail.d.ts +49 -0
  46. package/lib/types/get/getMusicDetail.js +2 -0
  47. package/lib/types/get/getMusicVideos.d.ts +93 -0
  48. package/lib/types/get/getMusicVideos.js +2 -0
  49. package/lib/types/get/getPlaylist.d.ts +65 -0
  50. package/lib/types/get/getPlaylist.js +2 -0
  51. package/lib/types/get/getProfile.d.ts +71 -0
  52. package/lib/types/get/getProfile.js +2 -0
  53. package/lib/types/get/getTrendings.d.ts +61 -0
  54. package/lib/types/get/getTrendings.js +2 -0
  55. package/lib/types/get/getUserLiked.d.ts +90 -0
  56. package/lib/types/get/getUserLiked.js +2 -0
  57. package/lib/types/get/getUserPosts.d.ts +68 -0
  58. package/lib/types/get/getUserPosts.js +2 -0
  59. package/lib/types/get/getUserReposts.d.ts +104 -0
  60. package/lib/types/get/getUserReposts.js +2 -0
  61. package/lib/types/search/index.d.ts +15 -0
  62. package/lib/types/search/index.js +2 -0
  63. package/lib/types/search/liveSearch.d.ts +48 -0
  64. package/lib/types/search/liveSearch.js +2 -0
  65. package/lib/types/search/userSearch.d.ts +32 -0
  66. package/lib/types/search/userSearch.js +2 -0
  67. package/lib/types/search/videoSearch.d.ts +62 -0
  68. package/lib/types/search/videoSearch.js +2 -0
  69. package/lib/utils/downloader/musicaldownDownloader.d.ts +2 -0
  70. package/lib/utils/downloader/musicaldownDownloader.js +193 -0
  71. package/lib/utils/downloader/ssstikDownloader.d.ts +2 -0
  72. package/lib/utils/downloader/ssstikDownloader.js +177 -0
  73. package/lib/utils/downloader/tiktokAPIDownloader.d.ts +3 -0
  74. package/lib/utils/downloader/tiktokAPIDownloader.js +221 -0
  75. package/lib/utils/get/getCollection.d.ts +7 -0
  76. package/lib/utils/get/getCollection.js +113 -0
  77. package/lib/utils/get/getComments.d.ts +2 -0
  78. package/lib/utils/get/getComments.js +139 -0
  79. package/lib/utils/get/getMusicDetail.d.ts +2 -0
  80. package/lib/utils/get/getMusicDetail.js +68 -0
  81. package/lib/utils/get/getMusicVideos.d.ts +2 -0
  82. package/lib/utils/get/getMusicVideos.js +249 -0
  83. package/lib/utils/get/getPlaylist.d.ts +7 -0
  84. package/lib/utils/get/getPlaylist.js +115 -0
  85. package/lib/utils/get/getProfile.d.ts +2 -0
  86. package/lib/utils/get/getProfile.js +92 -0
  87. package/lib/utils/get/getTrendings.d.ts +7 -0
  88. package/lib/utils/get/getTrendings.js +120 -0
  89. package/lib/utils/get/getUserLiked.d.ts +2 -0
  90. package/lib/utils/get/getUserLiked.js +204 -0
  91. package/lib/utils/get/getUserPosts.d.ts +2 -0
  92. package/lib/utils/get/getUserPosts.js +199 -0
  93. package/lib/utils/get/getUserRepost.d.ts +2 -0
  94. package/lib/utils/get/getUserRepost.js +239 -0
  95. package/lib/utils/search/liveSearch.d.ts +2 -0
  96. package/lib/utils/search/liveSearch.js +99 -0
  97. package/lib/utils/search/userSearch.d.ts +2 -0
  98. package/lib/utils/search/userSearch.js +76 -0
  99. package/lib/utils/search/videoSearch.d.ts +2 -0
  100. package/lib/utils/search/videoSearch.js +140 -0
  101. package/lib/utils/urlExtractors.d.ts +3 -0
  102. package/lib/utils/urlExtractors.js +37 -0
  103. package/lib/utils/validator.d.ts +1 -0
  104. package/lib/utils/validator.js +13 -0
  105. package/package.json +60 -0
  106. package/test/collection-test.ts +73 -0
  107. package/test/comments-test.ts +54 -0
  108. package/test/downloader-v1-test.ts +49 -0
  109. package/test/downloader-v2-test.ts +47 -0
  110. package/test/downloader-v3-test.ts +35 -0
  111. package/test/music-detail-test.ts +97 -0
  112. package/test/music-videos-test.ts +86 -0
  113. package/test/playlist-test.ts +48 -0
  114. package/test/profile-test.ts +49 -0
  115. package/test/search-live-test.ts +42 -0
  116. package/test/search-user-test.ts +46 -0
  117. package/test/search-video-test.ts +53 -0
  118. package/test/trending-test.ts +128 -0
  119. package/test/userliked-test.ts +65 -0
  120. package/test/userposts-test.ts +56 -0
  121. package/test/userreposts-test.ts +57 -0
  122. package/tobyg74-tiktok-api-1.3.7.tgz +0 -0
@@ -0,0 +1,809 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const commander_1 = require("commander");
8
+ const __1 = __importDefault(require(".."));
9
+ const cookieManager_1 = require("../services/cookieManager");
10
+ const logger_1 = require("../lib/logger");
11
+ const chalk_1 = __importDefault(require("chalk"));
12
+ const downloadManager_1 = require("../services/downloadManager");
13
+ const api_1 = require("../constants/api");
14
+ const urlExtractors_1 = require("../utils/urlExtractors");
15
+ const TIKTOK_URL_REGEX = {
16
+ playlist: /https:\/\/(?:www|m)\.tiktok\.com\/@[\w.-]+\/playlist\/[\w-]+-(\d+)/,
17
+ collection: /https:\/\/(?:www|m)\.tiktok\.com\/@[\w.-]+\/collection\/[\w-]+-(\d+)/,
18
+ video: /https:\/\/(?:www|m)\.tiktok\.com\/@[\w.-]+\/video\/(\d+)/,
19
+ photo: /https:\/\/(?:www|m)\.tiktok\.com\/@[\w.-]+\/photo\/(\d+)/,
20
+ shortLink: /https:\/\/(vm|vt|lite)\.tiktok\.com\/[\w\d]+\/?/,
21
+ music: /https:\/\/(?:www|m)\.tiktok\.com\/music\/[\w%-]+-(\d+)/
22
+ };
23
+ const cookieManager = new cookieManager_1.CookieManager();
24
+ commander_1.program
25
+ .name("tiktokdl")
26
+ .description("TikTok downloader and search CLI tool")
27
+ .version("1.0.0");
28
+ commander_1.program
29
+ .command("download")
30
+ .description("Download TikTok Video / Slide / Music / Playlist / Collection")
31
+ .argument("<urls...>", "TikTok URLs (Video / Slide / Music / Playlist / Collection)")
32
+ .option("-o, --output <path>", "Output directory path")
33
+ .option("-v, --version <version>", "Downloader version (v1/v2/v3)", "v1")
34
+ .option("-p, --proxy <proxy>", "Proxy URL (http/https/socks)")
35
+ .option("-c, --count <number>", "Number of items to fetch for playlist/collection (default: 20)", (val) => parseInt(val), 20)
36
+ .action(async (urls, options) => {
37
+ const outputPath = options.output || (0, downloadManager_1.getDefaultDownloadPath)();
38
+ const version = options.version.toLowerCase();
39
+ const count = options.count || 20;
40
+ if (!Array.isArray(urls))
41
+ urls = [urls];
42
+ for (const url of urls) {
43
+ try {
44
+ if (!["v1", "v2", "v3"].includes(version)) {
45
+ throw new Error("Invalid version. Use v1, v2 or v3");
46
+ }
47
+ if (TIKTOK_URL_REGEX.playlist.test(url)) {
48
+ logger_1.Logger.info(`Fetching playlist items from: ${url}`);
49
+ const match = url.match(TIKTOK_URL_REGEX.playlist);
50
+ const results = await __1.default.Playlist(match[1], {
51
+ page: 1,
52
+ proxy: options.proxy,
53
+ count: count
54
+ });
55
+ if (results.status === "success" && results.result) {
56
+ const { itemList } = results.result;
57
+ logger_1.Logger.info(`Found ${itemList.length} items in playlist. Starting download...`);
58
+ for (const [index, item] of itemList.entries()) {
59
+ logger_1.Logger.info(`Downloading [${index + 1}/${itemList.length}]: ${item.id}`);
60
+ const videoUrl = `https://www.tiktok.com/@${item.author?.uniqueId || "unknown"}/video/${item.id}`;
61
+ try {
62
+ const data = await __1.default.Downloader(videoUrl, {
63
+ version: version,
64
+ proxy: options.proxy
65
+ });
66
+ await (0, downloadManager_1.handleMediaDownload)(data, outputPath, version);
67
+ logger_1.Logger.success(`Downloaded: ${videoUrl}`);
68
+ }
69
+ catch (err) {
70
+ logger_1.Logger.error(`Failed to download ${videoUrl}: ${err.message}`);
71
+ }
72
+ }
73
+ logger_1.Logger.info("All downloads finished.");
74
+ }
75
+ else {
76
+ logger_1.Logger.error(`Error: ${results.message}`);
77
+ }
78
+ }
79
+ else if (TIKTOK_URL_REGEX.collection.test(url)) {
80
+ logger_1.Logger.info(`Fetching collection items from: ${url}`);
81
+ const match = url.match(TIKTOK_URL_REGEX.collection);
82
+ const results = await __1.default.Collection(match[1], {
83
+ page: 1,
84
+ proxy: options.proxy,
85
+ count: count
86
+ });
87
+ if (results.status === "success" && results.result) {
88
+ const { itemList } = results.result;
89
+ logger_1.Logger.info(`Found ${itemList.length} items in collection. Starting download...`);
90
+ for (const [index, item] of itemList.entries()) {
91
+ logger_1.Logger.info(`Downloading [${index + 1}/${itemList.length}]: ${item.id}`);
92
+ const videoUrl = `https://www.tiktok.com/@${item.author?.uniqueId || "unknown"}/video/${item.id}`;
93
+ try {
94
+ const data = await __1.default.Downloader(videoUrl, {
95
+ version: version,
96
+ proxy: options.proxy
97
+ });
98
+ await (0, downloadManager_1.handleMediaDownload)(data, outputPath, version);
99
+ logger_1.Logger.success(`Downloaded: ${videoUrl}`);
100
+ }
101
+ catch (err) {
102
+ logger_1.Logger.error(`Failed to download ${videoUrl}: ${err.message}`);
103
+ }
104
+ }
105
+ logger_1.Logger.info("All downloads finished.");
106
+ }
107
+ else {
108
+ logger_1.Logger.error(`Error: ${results.message}`);
109
+ }
110
+ }
111
+ else if (TIKTOK_URL_REGEX.video.test(url) ||
112
+ TIKTOK_URL_REGEX.shortLink.test(url) ||
113
+ TIKTOK_URL_REGEX.photo.test(url)) {
114
+ logger_1.Logger.info("Fetching media information...");
115
+ const data = await __1.default.Downloader(url, {
116
+ version: version,
117
+ proxy: options.proxy
118
+ });
119
+ await (0, downloadManager_1.handleMediaDownload)(data, outputPath, version);
120
+ }
121
+ else {
122
+ logger_1.Logger.error("URL tidak valid atau tidak dikenali: " + url);
123
+ }
124
+ }
125
+ catch (error) {
126
+ logger_1.Logger.error(`Error: ${error.message}`);
127
+ }
128
+ }
129
+ });
130
+ const cookieCommand = commander_1.program.command("cookie").description("Cookie Manager");
131
+ cookieCommand
132
+ .command("set <value>")
133
+ .description("Set a cookie")
134
+ .action((value) => {
135
+ cookieManager.setCookie(value);
136
+ logger_1.Logger.success("Cookie set successfully.");
137
+ });
138
+ cookieCommand
139
+ .command("get")
140
+ .description("Get cookie value")
141
+ .action(() => {
142
+ const cookie = cookieManager.getCookie();
143
+ if (cookie) {
144
+ logger_1.Logger.info(`Cookie: ${cookie}`);
145
+ }
146
+ else {
147
+ logger_1.Logger.warning("No cookie found.");
148
+ }
149
+ });
150
+ cookieCommand
151
+ .command("delete")
152
+ .description("Delete cookie")
153
+ .action(() => {
154
+ cookieManager.deleteCookie();
155
+ logger_1.Logger.success("Cookie deleted successfully.");
156
+ });
157
+ const searchCommand = commander_1.program
158
+ .command("search")
159
+ .description("Search TikTok users or live streams or videos");
160
+ searchCommand
161
+ .command("user")
162
+ .description("Search TikTok users")
163
+ .argument("<keyword>", "Search keyword")
164
+ .option("-p, --page <number>", "Page number", "1")
165
+ .option("--proxy <proxy>", "Proxy URL (http/https/socks)")
166
+ .action(async (keyword, options) => {
167
+ try {
168
+ const page = parseInt(options.page);
169
+ const results = await __1.default.Search(keyword, {
170
+ type: "user",
171
+ cookie: cookieManager.getCookie(),
172
+ page: page,
173
+ proxy: options.proxy
174
+ });
175
+ if (results.status === "success") {
176
+ const data = results.result;
177
+ for (const [index, item] of data.entries()) {
178
+ if (item.type === "user") {
179
+ logger_1.Logger.info(`---- USER ${index + 1} ----`);
180
+ logger_1.Logger.result(`Username: ${item.username}`, chalk_1.default.green);
181
+ logger_1.Logger.result(`Nickname: ${item.nickname}`, chalk_1.default.green);
182
+ logger_1.Logger.result(`Bio: ${item.signature}`, chalk_1.default.green);
183
+ logger_1.Logger.result(`Followers: ${item.followerCount}`, chalk_1.default.yellow);
184
+ logger_1.Logger.result(`Verified: ${item.isVerified ? "Yes" : "No"}`, chalk_1.default.yellow);
185
+ logger_1.Logger.result(`Profile URL: ${item.url}`, chalk_1.default.yellow);
186
+ }
187
+ }
188
+ logger_1.Logger.info(`Total users: ${data.length}`);
189
+ }
190
+ else {
191
+ logger_1.Logger.error(`Error: ${results.message}`);
192
+ }
193
+ }
194
+ catch (error) {
195
+ logger_1.Logger.error(`Error: ${error.message}`);
196
+ }
197
+ });
198
+ searchCommand
199
+ .command("live")
200
+ .description("Search TikTok live streams")
201
+ .argument("<keyword>", "Search keyword")
202
+ .option("-p, --page <number>", "Page number", "1")
203
+ .option("--proxy <proxy>", "Proxy URL (http/https/socks)")
204
+ .action(async (keyword, options) => {
205
+ try {
206
+ const page = parseInt(options.page);
207
+ const results = await __1.default.Search(keyword, {
208
+ type: "live",
209
+ cookie: cookieManager.getCookie(),
210
+ page: page,
211
+ proxy: options.proxy
212
+ });
213
+ if (results.status === "success") {
214
+ const data = results.result;
215
+ for (const [index, item] of data.entries()) {
216
+ if (item.type === "live") {
217
+ logger_1.Logger.info(`---- LIVE ${index + 1} ----`);
218
+ logger_1.Logger.result(`Title: ${item.liveInfo.title}`, chalk_1.default.green);
219
+ logger_1.Logger.result(`Nickname: ${item.liveInfo.owner.nickname}`, chalk_1.default.green);
220
+ logger_1.Logger.result(`Username: ${item.liveInfo.owner.username}`, chalk_1.default.green);
221
+ logger_1.Logger.result(`Verified: ${item.liveInfo.owner.isVerified ? "Yes" : "No"}`, chalk_1.default.green);
222
+ logger_1.Logger.result(`Type Third Party: ${item.liveInfo.liveTypeThirdParty ? "Yes" : "No"}`, chalk_1.default.green);
223
+ logger_1.Logger.result(`Hashtag: ${item.liveInfo.hashtag}`, chalk_1.default.green);
224
+ logger_1.Logger.info(`---- STATISTICS ----`);
225
+ logger_1.Logger.result(`Likes: ${item.liveInfo.stats.likeCount}`, chalk_1.default.yellow);
226
+ logger_1.Logger.result(`Views: ${item.liveInfo.stats.viewerCount}`, chalk_1.default.yellow);
227
+ logger_1.Logger.result(`Users: ${item.liveInfo.stats.totalUser}`, chalk_1.default.yellow);
228
+ }
229
+ }
230
+ logger_1.Logger.info(`Total live streams: ${data.length}`);
231
+ }
232
+ else {
233
+ logger_1.Logger.error(`Error: ${results.message}`);
234
+ }
235
+ }
236
+ catch (error) {
237
+ logger_1.Logger.error(`Error: ${error.message}`);
238
+ }
239
+ });
240
+ searchCommand
241
+ .command("video")
242
+ .description("Search TikTok videos")
243
+ .argument("<keyword>", "Search keyword")
244
+ .option("-p, --page <number>", "Page number", "1")
245
+ .option("--proxy <proxy>", "Proxy URL (http/https/socks)")
246
+ .action(async (keyword, options) => {
247
+ try {
248
+ const page = parseInt(options.page);
249
+ const results = await __1.default.Search(keyword, {
250
+ type: "video",
251
+ cookie: cookieManager.getCookie(),
252
+ page: page,
253
+ proxy: options.proxy
254
+ });
255
+ if (results.status === "success") {
256
+ const data = results.result;
257
+ for (const [index, item] of data.entries()) {
258
+ if (item.type === "video") {
259
+ logger_1.Logger.info(`---- VIDEO ${index + 1} ----`);
260
+ logger_1.Logger.result(`Video ID: ${item.id}`, chalk_1.default.green);
261
+ logger_1.Logger.result(`Description: ${item.desc}`, chalk_1.default.yellow);
262
+ logger_1.Logger.result(`Author: ${item.author.nickname}`, chalk_1.default.yellow);
263
+ logger_1.Logger.result(`Video URL: ${api_1._tiktokDesktopUrl}/@${item.author.uniqueId}/video/${item.id}`, chalk_1.default.yellow);
264
+ logger_1.Logger.info(`---- STATISTICS ----`);
265
+ logger_1.Logger.result(`Likes: ${item.stats.likeCount}`, chalk_1.default.yellow);
266
+ logger_1.Logger.result(`Favorites: ${item.stats.collectCount}`, chalk_1.default.yellow);
267
+ logger_1.Logger.result(`Views: ${item.stats.playCount}`, chalk_1.default.yellow);
268
+ logger_1.Logger.result(`Shares: ${item.stats.shareCount}`, chalk_1.default.yellow);
269
+ logger_1.Logger.result(`Comments: ${item.stats.commentCount}`, chalk_1.default.yellow);
270
+ }
271
+ }
272
+ logger_1.Logger.info(`Total videos: ${data.length}`);
273
+ }
274
+ else {
275
+ logger_1.Logger.error(`Error: ${results.message}`);
276
+ }
277
+ }
278
+ catch (error) {
279
+ logger_1.Logger.error(`Error: ${error.message}`);
280
+ }
281
+ });
282
+ commander_1.program
283
+ .command("getvideocomments")
284
+ .description("Get comments from a TikTok video")
285
+ .argument("<url>", "TikTok video URL")
286
+ .option("-l, --limit <number>", "Limit of comments", "10")
287
+ .option("-p, --proxy <proxy>", "Proxy URL (http/https/socks)")
288
+ .action(async (url, options) => {
289
+ try {
290
+ const limit = parseInt(options.limit);
291
+ const comments = await __1.default.GetVideoComments(url, {
292
+ commentLimit: limit,
293
+ proxy: options.proxy
294
+ });
295
+ if (comments.status === "success") {
296
+ const data = comments.result;
297
+ for (const [index, comment] of data.entries()) {
298
+ logger_1.Logger.info(`---- COMMENT ${index + 1} ----`);
299
+ logger_1.Logger.result(`Username: ${comment.user.username}`, chalk_1.default.green);
300
+ logger_1.Logger.result(`Text: ${comment.text}`, chalk_1.default.green);
301
+ logger_1.Logger.result(`Likes: ${comment.likeCount}`, chalk_1.default.yellow);
302
+ }
303
+ logger_1.Logger.info(`Total comments: ${data.length}`);
304
+ }
305
+ else {
306
+ logger_1.Logger.error(`Error: ${comments.message}`);
307
+ }
308
+ }
309
+ catch (error) {
310
+ logger_1.Logger.error(`Error: ${error.message}`);
311
+ }
312
+ });
313
+ commander_1.program
314
+ .command("getuserposts")
315
+ .description("Get posts from a TikTok user")
316
+ .argument("<username>", "TikTok username")
317
+ .option("-l, --limit <number>", "Limit of posts", "5")
318
+ .option("--proxy <proxy>", "Proxy URL (http/https/socks)")
319
+ .action(async (username, options) => {
320
+ try {
321
+ const postLimit = parseInt(options.limit);
322
+ const results = await __1.default.GetUserPosts(username, {
323
+ postLimit: postLimit,
324
+ proxy: options.proxy
325
+ });
326
+ if (results.status === "success") {
327
+ const data = results.result;
328
+ for (const [index, post] of data.entries()) {
329
+ logger_1.Logger.info(`---- POST ${index + 1} ----`);
330
+ logger_1.Logger.result(`Video ID: ${post.id}`, chalk_1.default.green);
331
+ logger_1.Logger.result(`Description: ${post.desc}`, chalk_1.default.yellow);
332
+ logger_1.Logger.info(`---- STATISTICS ----`);
333
+ logger_1.Logger.result(`Likes: ${post.stats.likeCount}`, chalk_1.default.yellow);
334
+ logger_1.Logger.result(`Favorites: ${post.stats.collectCount}`, chalk_1.default.yellow);
335
+ logger_1.Logger.result(`Views: ${post.stats.playCount}`, chalk_1.default.yellow);
336
+ logger_1.Logger.result(`Shares: ${post.stats.shareCount}`, chalk_1.default.yellow);
337
+ logger_1.Logger.result(`Comments: ${post.stats.commentCount}`, chalk_1.default.yellow);
338
+ }
339
+ logger_1.Logger.info(`Total posts: ${data.length}`);
340
+ }
341
+ else {
342
+ logger_1.Logger.error(`Error: ${results.message}`);
343
+ }
344
+ }
345
+ catch (error) {
346
+ logger_1.Logger.error(`Error: ${error.message}`);
347
+ }
348
+ });
349
+ commander_1.program
350
+ .command("getuserreposts")
351
+ .description("Get reposts from a TikTok user")
352
+ .argument("<username>", "TikTok username")
353
+ .option("-l, --limit <number>", "Limit of reposts", "5")
354
+ .option("--proxy <proxy>", "Proxy URL (http/https/socks)")
355
+ .action(async (username, options) => {
356
+ try {
357
+ const postLimit = parseInt(options.limit);
358
+ const results = await __1.default.GetUserReposts(username, {
359
+ postLimit: postLimit,
360
+ proxy: options.proxy
361
+ });
362
+ if (results.status === "success") {
363
+ const data = results.result;
364
+ for (const [index, repost] of data.entries()) {
365
+ logger_1.Logger.info(`---- REPOST ${index + 1} ----`);
366
+ logger_1.Logger.result(`Video ID: ${repost.id}`, chalk_1.default.green);
367
+ logger_1.Logger.result(`Description: ${repost.desc}`, chalk_1.default.yellow);
368
+ logger_1.Logger.info(`---- STATISTICS ----`);
369
+ logger_1.Logger.result(`Shares: ${repost.stats.shareCount}`, chalk_1.default.yellow);
370
+ if (repost.stats.likeCount) {
371
+ logger_1.Logger.result(`Likes: ${repost.stats.likeCount}`, chalk_1.default.yellow);
372
+ }
373
+ if (repost.stats.collectCount) {
374
+ logger_1.Logger.result(`Favorites: ${repost.stats.collectCount}`, chalk_1.default.yellow);
375
+ }
376
+ if (repost.stats.playCount) {
377
+ logger_1.Logger.result(`Views: ${repost.stats.playCount}`, chalk_1.default.yellow);
378
+ }
379
+ if (repost.stats.commentCount) {
380
+ logger_1.Logger.result(`Comments: ${repost.stats.commentCount}`, chalk_1.default.yellow);
381
+ }
382
+ }
383
+ logger_1.Logger.info(`Total reposts: ${data.length}`);
384
+ }
385
+ else {
386
+ logger_1.Logger.error(`Error: ${results.message}`);
387
+ }
388
+ }
389
+ catch (error) {
390
+ logger_1.Logger.error(`Error: ${error.message}`);
391
+ }
392
+ });
393
+ commander_1.program
394
+ .command("stalk")
395
+ .description("Stalk a TikTok user")
396
+ .argument("<username>", "TikTok username")
397
+ .option("--proxy <proxy>", "Proxy URL (http/https/socks)")
398
+ .action(async (username, options) => {
399
+ try {
400
+ const results = await __1.default.StalkUser(username, {
401
+ proxy: options.proxy
402
+ });
403
+ if (results.status === "success") {
404
+ const data = results.result;
405
+ logger_1.Logger.info("---- TIKTOK STALKER ----");
406
+ logger_1.Logger.result(`Username:${data.user.username}`, chalk_1.default.green);
407
+ logger_1.Logger.result(`Nickname:${data.user.nickname}`, chalk_1.default.green);
408
+ logger_1.Logger.result(`Bio:${data.user.signature}`, chalk_1.default.green);
409
+ logger_1.Logger.result(`Verified:${data.user.verified ? "Yes" : "No"}`, chalk_1.default.green);
410
+ logger_1.Logger.result(`Commerce User:${data.user.commerceUser ? "Yes" : "No"}`, chalk_1.default.green);
411
+ logger_1.Logger.result(`Private Account:${data.user.privateAccount ? "Yes" : "No"}`, chalk_1.default.green);
412
+ logger_1.Logger.result(`Region:${data.user.region}`, chalk_1.default.green);
413
+ logger_1.Logger.info("---- STATISTICS ----");
414
+ logger_1.Logger.result(`Followers:${data.stats.followerCount}`, chalk_1.default.yellow);
415
+ logger_1.Logger.result(`Following:${data.stats.followingCount}`, chalk_1.default.yellow);
416
+ logger_1.Logger.result(`Hearts:${data.stats.heartCount}`, chalk_1.default.yellow);
417
+ logger_1.Logger.result(`Videos:${data.stats.videoCount}`, chalk_1.default.yellow);
418
+ logger_1.Logger.result(`Likes:${data.stats.likeCount}`, chalk_1.default.yellow);
419
+ logger_1.Logger.result(`Friends:${data.stats.friendCount}`, chalk_1.default.yellow);
420
+ }
421
+ else {
422
+ logger_1.Logger.error(`Error: ${results.message}`);
423
+ }
424
+ }
425
+ catch (error) {
426
+ logger_1.Logger.error(`Error: ${error.message}`);
427
+ }
428
+ });
429
+ commander_1.program
430
+ .command("collection")
431
+ .description("Get videos from a TikTok collection (supports collection ID or URL)")
432
+ .argument("<collectionIdOrUrl>", "Collection ID or URL (e.g. 7507916135931218695 or https://www.tiktok.com/@username/collection/name-id)")
433
+ .option("-p, --page <number>", "Page number", "1")
434
+ .option("--proxy <proxy>", "Proxy URL (http/https/socks)")
435
+ .option("-n, --count <number>", "Number of items to fetch", (val) => parseInt(val), 5)
436
+ .action(async (collectionIdOrUrl, options) => {
437
+ try {
438
+ logger_1.Logger.info(`Fetching page ${options.page} with ${options.count} items per page from collection...`);
439
+ const results = await __1.default.Collection(collectionIdOrUrl, {
440
+ page: options.page,
441
+ proxy: options.proxy,
442
+ count: options.count
443
+ });
444
+ if (results.status === "success" && results.result) {
445
+ const { itemList, hasMore } = results.result;
446
+ logger_1.Logger.info(`Found ${itemList.length} videos in collection`);
447
+ logger_1.Logger.info(`Has more videos: ${hasMore}`);
448
+ for (const [index, video] of itemList.entries()) {
449
+ logger_1.Logger.info(`---- VIDEO ${index + 1} ----`);
450
+ logger_1.Logger.result(`Video ID: ${video.id}`, chalk_1.default.green);
451
+ logger_1.Logger.result(`Description: ${video.desc}`, chalk_1.default.yellow);
452
+ logger_1.Logger.result(`Author: ${video.author?.nickname || "Unknown"}`, chalk_1.default.yellow);
453
+ logger_1.Logger.result(`Created: ${new Date(video.createTime * 1000).toLocaleString()}`, chalk_1.default.yellow);
454
+ if (video.statistics) {
455
+ logger_1.Logger.info(`---- STATISTICS ----`);
456
+ logger_1.Logger.result(`Likes: ${video.statistics.likeCount || 0}`, chalk_1.default.yellow);
457
+ logger_1.Logger.result(`Comments: ${video.statistics.commentCount || 0}`, chalk_1.default.yellow);
458
+ logger_1.Logger.result(`Shares: ${video.statistics.shareCount || 0}`, chalk_1.default.yellow);
459
+ logger_1.Logger.result(`Plays: ${video.statistics.playCount || 0}`, chalk_1.default.yellow);
460
+ }
461
+ if (video.video) {
462
+ logger_1.Logger.info(`---- VIDEO URLs ----`);
463
+ const videoUrl = `${api_1._tiktokDesktopUrl}/@${video.author?.uniqueId || "unknown"}/video/${video.id}`;
464
+ logger_1.Logger.result(`Video URL: ${videoUrl}`, chalk_1.default.blue);
465
+ }
466
+ if (video.textExtra?.length > 0) {
467
+ logger_1.Logger.info(`---- HASHTAGS ----`);
468
+ video.textExtra.forEach((tag) => {
469
+ if (tag.hashtagName) {
470
+ logger_1.Logger.result(`#${tag.hashtagName}`, chalk_1.default.cyan);
471
+ }
472
+ });
473
+ }
474
+ }
475
+ if (hasMore) {
476
+ logger_1.Logger.info("\nTo fetch more videos, use:");
477
+ logger_1.Logger.info(`tiktokdl collection ${collectionIdOrUrl} -p ${parseInt(options.page) + 1}`);
478
+ }
479
+ }
480
+ else {
481
+ logger_1.Logger.error(`Error: ${results.message}`);
482
+ }
483
+ }
484
+ catch (error) {
485
+ logger_1.Logger.error(`Error: ${error.message}`);
486
+ }
487
+ });
488
+ commander_1.program
489
+ .command("playlist")
490
+ .description("Get videos from a TikTok playlist")
491
+ .argument("<PlaylistIdOrUrl>", "Collection URL (e.g. https://www.tiktok.com/@username/playlist/name-id)")
492
+ .option("-p, --page <number>", "Page number", "1")
493
+ .option("--proxy <proxy>", "Proxy URL (http/https/socks)")
494
+ .option("-c, --count <number>", "Number of items to fetch (max: 20)", (val) => parseInt(val), 5)
495
+ .option("-r, --raw", "Show raw response", false)
496
+ .action(async (url, options) => {
497
+ try {
498
+ logger_1.Logger.info(`Fetching page ${options.page} with ${options.count} items per page from playlist...`);
499
+ const results = await __1.default.Playlist(url, {
500
+ page: options.page,
501
+ proxy: options.proxy,
502
+ count: options.count
503
+ });
504
+ const contentType = (content) => {
505
+ if (content?.imagePost) {
506
+ return "photo";
507
+ }
508
+ else {
509
+ return "video";
510
+ }
511
+ };
512
+ if (results.status === "success" && results.result) {
513
+ if (options.raw) {
514
+ console.log(JSON.stringify(results.result, null, 2));
515
+ return;
516
+ }
517
+ const { itemList, hasMore } = results.result;
518
+ logger_1.Logger.info(`Found ${itemList.length} items in playlist`);
519
+ logger_1.Logger.info(`Has more items: ${hasMore}`);
520
+ for (const [index, item] of itemList.entries()) {
521
+ logger_1.Logger.info(`---- ITEM ${index + 1} ----`);
522
+ logger_1.Logger.result(`Item ID: ${item.id}`, chalk_1.default.green);
523
+ logger_1.Logger.result(`Description: ${item.desc}`, chalk_1.default.yellow);
524
+ logger_1.Logger.result(`Author: ${item.author?.nickname || "Unknown"}`, chalk_1.default.yellow);
525
+ logger_1.Logger.result(`Created: ${new Date(item.createTime * 1000).toLocaleString()}`, chalk_1.default.yellow);
526
+ if (item.stats) {
527
+ logger_1.Logger.info(`---- STATISTICS ----`);
528
+ logger_1.Logger.result(`Comments: ${item.stats.commentCount || 0}`, chalk_1.default.yellow);
529
+ logger_1.Logger.result(`Shares: ${item.stats.shareCount || 0}`, chalk_1.default.yellow);
530
+ logger_1.Logger.result(`Plays: ${item.stats.playCount || 0}`, chalk_1.default.yellow);
531
+ }
532
+ if (item.video) {
533
+ logger_1.Logger.info(`---- VIDEO URLs ----`);
534
+ const videoUrl = `${api_1._tiktokDesktopUrl}/@${item.author?.uniqueId || "unknown"}/${contentType(item)}/${item.id}`;
535
+ logger_1.Logger.result(`Video URL: ${videoUrl}`, chalk_1.default.blue);
536
+ }
537
+ }
538
+ if (hasMore) {
539
+ logger_1.Logger.info("\nTo fetch more videos, use:");
540
+ logger_1.Logger.info(`tiktokdl playlist ${url} -p ${parseInt(options.page) + 1}`);
541
+ }
542
+ }
543
+ else {
544
+ logger_1.Logger.error(`Error: ${results.message}`);
545
+ }
546
+ }
547
+ catch (error) {
548
+ logger_1.Logger.error(`Error: ${error.message}`);
549
+ }
550
+ });
551
+ commander_1.program
552
+ .command("trending")
553
+ .description("Get TikTok trending content and creators")
554
+ .option("--proxy <proxy>", "Proxy URL (http/https/socks)")
555
+ .option("-c, --creators", "Show only trending creators", false)
556
+ .option("-r, --raw", "Show raw response", false)
557
+ .action(async (options) => {
558
+ try {
559
+ if (options.creators) {
560
+ logger_1.Logger.info("Fetching trending creators...");
561
+ const results = await __1.default.TrendingCreators({
562
+ proxy: options.proxy
563
+ });
564
+ if (results.status === "success" && results.result) {
565
+ if (options.raw) {
566
+ console.log(JSON.stringify(results.result, null, 2));
567
+ return;
568
+ }
569
+ logger_1.Logger.info(`Found ${results.result.length} trending creators`);
570
+ results.result.slice(0, 20).forEach((creator, index) => {
571
+ logger_1.Logger.info(`---- CREATOR ${index + 1} ----`);
572
+ logger_1.Logger.result(`Username: @${creator.username}`, chalk_1.default.green);
573
+ logger_1.Logger.result(`Nickname: ${creator.nickname}`, chalk_1.default.green);
574
+ logger_1.Logger.result(`Verified: ${creator.verified ? "Yes" : "No"}`, chalk_1.default.green);
575
+ logger_1.Logger.result(`Followers: ${creator.followerCount.toLocaleString()}`, chalk_1.default.yellow);
576
+ logger_1.Logger.result(`Total Likes: ${creator.likeCount.toLocaleString()}`, chalk_1.default.yellow);
577
+ logger_1.Logger.result(`Videos: ${creator.videoCount.toLocaleString()}`, chalk_1.default.yellow);
578
+ logger_1.Logger.result(`Following: ${creator.followingCount.toLocaleString()}`, chalk_1.default.yellow);
579
+ logger_1.Logger.result(`Description: ${creator.description.substring(0, 100)}${creator.description.length > 100 ? "..." : ""}`, chalk_1.default.blue);
580
+ logger_1.Logger.result(`Profile: https://www.tiktok.com${creator.link}`, chalk_1.default.blue);
581
+ });
582
+ if (results.result.length > 20) {
583
+ logger_1.Logger.info(`\nShowing first 20 of ${results.result.length} trending creators`);
584
+ }
585
+ const verifiedCount = results.result.filter((c) => c.verified).length;
586
+ const totalFollowers = results.result.reduce((sum, c) => sum + c.followerCount, 0);
587
+ const avgFollowers = Math.round(totalFollowers / results.result.length);
588
+ logger_1.Logger.info(`\n---- STATISTICS ----`);
589
+ logger_1.Logger.result(`Verified creators: ${verifiedCount}/${results.result.length}`, chalk_1.default.cyan);
590
+ logger_1.Logger.result(`Average followers: ${avgFollowers.toLocaleString()}`, chalk_1.default.cyan);
591
+ logger_1.Logger.result(`Total combined followers: ${totalFollowers.toLocaleString()}`, chalk_1.default.cyan);
592
+ }
593
+ else {
594
+ logger_1.Logger.error(`Error: ${results.message}`);
595
+ }
596
+ }
597
+ else {
598
+ logger_1.Logger.info("Fetching trending content...");
599
+ const results = await __1.default.Trending({
600
+ proxy: options.proxy
601
+ });
602
+ if (results.status === "success" && results.result) {
603
+ if (options.raw) {
604
+ console.log(JSON.stringify(results.result, null, 2));
605
+ return;
606
+ }
607
+ logger_1.Logger.info(`Found ${results.result.length} trending sections`);
608
+ results.result.forEach((section, sectionIndex) => {
609
+ logger_1.Logger.info(`\n---- SECTION ${sectionIndex + 1} ----`);
610
+ logger_1.Logger.result(`Items in section: ${section.exploreList.length}`, chalk_1.default.green);
611
+ if (section.pageState) {
612
+ logger_1.Logger.result(`Region: ${section.pageState.region}`, chalk_1.default.yellow);
613
+ logger_1.Logger.result(`OS: ${section.pageState.os}`, chalk_1.default.yellow);
614
+ }
615
+ section.exploreList.slice(0, 5).forEach((item, index) => {
616
+ const cardItem = item.cardItem;
617
+ logger_1.Logger.info(`\n Item ${index + 1}:`);
618
+ logger_1.Logger.result(` Title: ${cardItem.title}`, chalk_1.default.green);
619
+ logger_1.Logger.result(` Subtitle: ${cardItem.subTitle}`, chalk_1.default.green);
620
+ logger_1.Logger.result(` Type: ${cardItem.type}`, chalk_1.default.yellow);
621
+ logger_1.Logger.result(` Description: ${cardItem.description.substring(0, 80)}${cardItem.description.length > 80 ? "..." : ""}`, chalk_1.default.blue);
622
+ if (cardItem.extraInfo) {
623
+ logger_1.Logger.result(` Verified: ${cardItem.extraInfo.verified ? "Yes" : "No"}`, chalk_1.default.cyan);
624
+ logger_1.Logger.result(` Fans: ${cardItem.extraInfo.fans?.toLocaleString() || "N/A"}`, chalk_1.default.cyan);
625
+ logger_1.Logger.result(` Likes: ${cardItem.extraInfo.likes?.toLocaleString() || "N/A"}`, chalk_1.default.cyan);
626
+ logger_1.Logger.result(` Videos: ${cardItem.extraInfo.video || "N/A"}`, chalk_1.default.cyan);
627
+ }
628
+ logger_1.Logger.result(` Profile: https://www.tiktok.com${cardItem.link}`, chalk_1.default.blue);
629
+ });
630
+ if (section.exploreList.length > 5) {
631
+ logger_1.Logger.info(` ... and ${section.exploreList.length - 5} more items`);
632
+ }
633
+ });
634
+ logger_1.Logger.info("\nTip: Use --creators flag to see only trending creators");
635
+ logger_1.Logger.info("Tip: Use --raw flag to see the complete JSON response");
636
+ }
637
+ else {
638
+ logger_1.Logger.error(`Error: ${results.message}`);
639
+ }
640
+ }
641
+ }
642
+ catch (error) {
643
+ logger_1.Logger.error(`Error: ${error.message}`);
644
+ }
645
+ });
646
+ commander_1.program
647
+ .command("getmusicvideos")
648
+ .description("Get videos by music ID or URL")
649
+ .argument("<musicIdOrUrl>", "Music ID or URL (e.g., 6771810675950880769 or https://www.tiktok.com/music/QKThr-6771810675950880769)")
650
+ .option("-p, --page <number>", "Page number", "1")
651
+ .option("-c, --count <number>", "Number of videos per page", "30")
652
+ .option("--proxy <proxy>", "Proxy URL (http/https/socks)")
653
+ .option("-r, --raw", "Show raw response", false)
654
+ .action(async (musicIdOrUrl, options) => {
655
+ try {
656
+ const page = parseInt(options.page);
657
+ const count = parseInt(options.count);
658
+ logger_1.Logger.info(`Fetching videos for music: ${musicIdOrUrl} (page ${page}, ${count} per page)...`);
659
+ const results = await __1.default.GetVideosByMusicId(musicIdOrUrl, {
660
+ page,
661
+ count,
662
+ proxy: options.proxy
663
+ });
664
+ if (results.status === "success" && results.result) {
665
+ if (options.raw) {
666
+ console.log(JSON.stringify(results.result, null, 2));
667
+ return;
668
+ }
669
+ const { music, videos, totalVideos } = results.result;
670
+ if (music) {
671
+ logger_1.Logger.info("\n---- MUSIC INFO ----");
672
+ logger_1.Logger.result(`Music ID: ${music.id}`, chalk_1.default.green);
673
+ logger_1.Logger.result(`Title: ${music.title}`, chalk_1.default.green);
674
+ logger_1.Logger.result(`Author: ${music.authorName}`, chalk_1.default.green);
675
+ logger_1.Logger.result(`Duration: ${music.duration || "N/A"} seconds`, chalk_1.default.yellow);
676
+ logger_1.Logger.result(`Original: ${music.original ? "Yes" : "No"}`, chalk_1.default.yellow);
677
+ }
678
+ if (videos && videos.length > 0) {
679
+ logger_1.Logger.info(`\nFound ${videos.length} videos`);
680
+ if (totalVideos) {
681
+ logger_1.Logger.info(`Total videos using this music: ${totalVideos}`);
682
+ }
683
+ videos.slice(0, 10).forEach((video, index) => {
684
+ logger_1.Logger.info(`\n---- VIDEO ${index + 1} ----`);
685
+ logger_1.Logger.result(`Video ID: ${video.id}`, chalk_1.default.green);
686
+ logger_1.Logger.result(`Description: ${video.desc || "N/A"}`, chalk_1.default.yellow);
687
+ logger_1.Logger.result(`Author: ${video.author?.nickname || "Unknown"}`, chalk_1.default.yellow);
688
+ logger_1.Logger.result(`Username: @${video.author?.uniqueId || "unknown"}`, chalk_1.default.yellow);
689
+ if (video.stats) {
690
+ logger_1.Logger.info("---- STATISTICS ----");
691
+ logger_1.Logger.result(`Likes: ${video.stats.diggCount?.toLocaleString() || 0}`, chalk_1.default.yellow);
692
+ logger_1.Logger.result(`Comments: ${video.stats.commentCount?.toLocaleString() || 0}`, chalk_1.default.yellow);
693
+ logger_1.Logger.result(`Shares: ${video.stats.shareCount?.toLocaleString() || 0}`, chalk_1.default.yellow);
694
+ logger_1.Logger.result(`Plays: ${video.stats.playCount?.toLocaleString() || 0}`, chalk_1.default.yellow);
695
+ }
696
+ const videoUrl = `${api_1._tiktokDesktopUrl}/@${video.author?.uniqueId || "unknown"}/video/${video.id}`;
697
+ logger_1.Logger.result(`Video URL: ${videoUrl}`, chalk_1.default.blue);
698
+ });
699
+ if (videos.length > 10) {
700
+ logger_1.Logger.info(`\n... and ${videos.length - 10} more videos`);
701
+ }
702
+ }
703
+ else {
704
+ logger_1.Logger.warning("No videos found for this music");
705
+ }
706
+ }
707
+ else {
708
+ logger_1.Logger.error(`Error: ${results.message}`);
709
+ }
710
+ }
711
+ catch (error) {
712
+ logger_1.Logger.error(`Error: ${error.message}`);
713
+ }
714
+ });
715
+ commander_1.program
716
+ .command("getmusicdetail")
717
+ .description("Get detailed information about a music/audio track by music ID or URL")
718
+ .argument("<musicIdOrUrl>", "Music ID or URL (e.g., 6771810675950880769 or https://www.tiktok.com/music/QKThr-6771810675950880769)")
719
+ .option("--proxy <proxy>", "Proxy URL (http/https/socks)")
720
+ .option("-r, --raw", "Show raw response", false)
721
+ .action(async (musicIdOrUrl, options) => {
722
+ try {
723
+ const cookie = cookieManager.getCookie();
724
+ if (!cookie) {
725
+ logger_1.Logger.error("Cookie is required for this command. Set cookie using: tiktokdl cookie set <value>");
726
+ return;
727
+ }
728
+ logger_1.Logger.info(`Fetching music detail for: ${musicIdOrUrl}...`);
729
+ const results = await __1.default.GetMusicDetail(musicIdOrUrl, {
730
+ cookie,
731
+ proxy: options.proxy
732
+ });
733
+ if (results.status === "success" && results.result) {
734
+ if (options.raw) {
735
+ console.log(JSON.stringify(results.result, null, 2));
736
+ return;
737
+ }
738
+ const { musicInfo, shareMeta } = results.result;
739
+ logger_1.Logger.info("\n==== MUSIC INFORMATION ====");
740
+ logger_1.Logger.result(`Music ID: ${musicInfo.music.id}`, chalk_1.default.green);
741
+ logger_1.Logger.result(`Title: ${musicInfo.music.title}`, chalk_1.default.green);
742
+ logger_1.Logger.result(`Author: ${musicInfo.music.authorName}`, chalk_1.default.green);
743
+ logger_1.Logger.result(`Duration: ${musicInfo.music.duration} seconds`, chalk_1.default.yellow);
744
+ logger_1.Logger.result(`Original: ${musicInfo.music.original ? "Yes" : "No"}`, chalk_1.default.yellow);
745
+ logger_1.Logger.result(`Copyrighted: ${musicInfo.music.isCopyrighted ? "Yes" : "No"}`, chalk_1.default.yellow);
746
+ logger_1.Logger.result(`Private: ${musicInfo.music.private ? "Yes" : "No"}`, chalk_1.default.yellow);
747
+ logger_1.Logger.info("\n==== AUTHOR INFORMATION ====");
748
+ logger_1.Logger.result(`Author ID: ${musicInfo.author.id}`, chalk_1.default.green);
749
+ logger_1.Logger.result(`Nickname: ${musicInfo.author.nickname}`, chalk_1.default.green);
750
+ logger_1.Logger.result(`Username: @${musicInfo.author.uniqueId}`, chalk_1.default.green);
751
+ logger_1.Logger.result(`Signature: ${musicInfo.author.signature || "N/A"}`, chalk_1.default.yellow);
752
+ logger_1.Logger.result(`Verified: ${musicInfo.author.ftc ? "Yes" : "No"}`, chalk_1.default.yellow);
753
+ logger_1.Logger.result(`Private Account: ${musicInfo.author.privateAccount ? "Yes" : "No"}`, chalk_1.default.yellow);
754
+ logger_1.Logger.info("\n==== STATISTICS ====");
755
+ logger_1.Logger.result(`Videos using this music: ${musicInfo.stats.videoCount.toLocaleString()}`, chalk_1.default.cyan);
756
+ logger_1.Logger.info("\n==== URLs ====");
757
+ logger_1.Logger.result(`Play URL: ${musicInfo.music.playUrl}`, chalk_1.default.blue);
758
+ logger_1.Logger.result(`Cover Thumbnail: ${musicInfo.music.coverThumb}`, chalk_1.default.blue);
759
+ logger_1.Logger.result(`Cover Medium: ${musicInfo.music.coverMedium}`, chalk_1.default.blue);
760
+ logger_1.Logger.result(`Cover Large: ${musicInfo.music.coverLarge}`, chalk_1.default.blue);
761
+ if (shareMeta) {
762
+ logger_1.Logger.info("\n==== SHARE META ====");
763
+ logger_1.Logger.result(`Title: ${shareMeta.title}`, chalk_1.default.magenta);
764
+ logger_1.Logger.result(`Description: ${shareMeta.desc}`, chalk_1.default.magenta);
765
+ }
766
+ logger_1.Logger.info("\n✨ Tip: Use the music ID with 'getmusicvideos' command to see videos using this music");
767
+ }
768
+ else {
769
+ logger_1.Logger.error(`Error: ${results.message}`);
770
+ }
771
+ }
772
+ catch (error) {
773
+ logger_1.Logger.error(`Error: ${error.message}`);
774
+ }
775
+ });
776
+ commander_1.program
777
+ .command("downloadmusic")
778
+ .description("Download music/audio from TikTok by music ID or URL (requires cookie)")
779
+ .argument("<musicIdOrUrl>", "Music ID or TikTok music URL (e.g. 7562597337407785760 or https://www.tiktok.com/music/QKThr-6771810675950880769)")
780
+ .option("-o, --output <path>", "Output directory path")
781
+ .option("--proxy <proxy>", "Proxy URL (http/https/socks)")
782
+ .action(async (musicIdOrUrl, options) => {
783
+ try {
784
+ const cookie = cookieManager.getCookie();
785
+ if (!cookie) {
786
+ logger_1.Logger.error("Cookie is required for downloading music. Set cookie using: tiktokdl cookie set <value>");
787
+ logger_1.Logger.info("\n💡 How to get cookie: Open TikTok in your browser, login, open DevTools (F12), go to Application/Storage > Cookies, and copy the cookie value");
788
+ return;
789
+ }
790
+ const outputPath = options.output || (0, downloadManager_1.getDefaultDownloadPath)();
791
+ const musicId = (0, urlExtractors_1.extractMusicId)(musicIdOrUrl);
792
+ if (!musicId) {
793
+ logger_1.Logger.error("Invalid input. Please provide either a music ID (numbers only) or a valid TikTok music URL");
794
+ logger_1.Logger.info("Example URL: https://www.tiktok.com/music/QKThr-6771810675950880769");
795
+ logger_1.Logger.info("Example ID: 7562597337407785760");
796
+ return;
797
+ }
798
+ logger_1.Logger.info(`Starting music download for music ID: ${musicId}`);
799
+ logger_1.Logger.info(`Output directory: ${outputPath}`);
800
+ await (0, downloadManager_1.downloadMusicFromDetail)(musicIdOrUrl, cookie, outputPath, options.proxy);
801
+ logger_1.Logger.success("\n✅ Music download completed!");
802
+ logger_1.Logger.info("\n💡 Tip: Use 'tiktokdl getmusicdetail' to view detailed information about this music");
803
+ }
804
+ catch (error) {
805
+ logger_1.Logger.error(`Error: ${error.message}`);
806
+ logger_1.Logger.info("\nPossible issues:\n- Invalid or expired cookie\n- Invalid music ID\n- Network/connection problem\n- Music might be region-restricted");
807
+ }
808
+ });
809
+ commander_1.program.parse();