shadowx-tiksr 1.0.0
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/README.md +232 -0
- package/index.js +245 -0
- package/package.json +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# shadowx-tiksr
|
|
2
|
+
|
|
3
|
+
🎵 TikTok video search & download module by Mueid Mursalin Rifat
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
📦 Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install shadowx-tiksr
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Requires Node.js 18+ (recommended) or 16+.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
🚀 Quick Start
|
|
18
|
+
|
|
19
|
+
```javascript
|
|
20
|
+
const TikSR = require('shadowx-tiksr');
|
|
21
|
+
const tiktok = new TikSR();
|
|
22
|
+
|
|
23
|
+
// Search videos
|
|
24
|
+
async function searchTikTok() {
|
|
25
|
+
try {
|
|
26
|
+
const result = await tiktok.search('Goku');
|
|
27
|
+
|
|
28
|
+
console.log('✅ Found!');
|
|
29
|
+
console.log('📹 Title:', result.video.title);
|
|
30
|
+
console.log('👤 Creator:', result.video.author.nickname);
|
|
31
|
+
console.log('❤️ Likes:', result.video.stats.likes);
|
|
32
|
+
console.log('📥 Download:', result.downloads.video);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error('❌ Error:', error.message);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
searchTikTok();
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
📥 Download Video Directly
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
// Get first video download link
|
|
47
|
+
const video = await tiktok.download('funny cats');
|
|
48
|
+
console.log('Download URL:', video.download.video_url);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
📋 API Reference
|
|
54
|
+
|
|
55
|
+
new TikSR(options)
|
|
56
|
+
|
|
57
|
+
Option Type Default Description
|
|
58
|
+
baseURL string 'https://shadowx-api.onrender.com/api' API endpoint
|
|
59
|
+
timeout number 30000 Request timeout (ms)
|
|
60
|
+
|
|
61
|
+
Methods
|
|
62
|
+
|
|
63
|
+
Method Description Returns
|
|
64
|
+
search(query) Search videos by keyword Promise<Object>
|
|
65
|
+
download(query) Get first video download Promise<Object>
|
|
66
|
+
extractVideoId(url) Extract ID from TikTok URL string\|null
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
📤 Response Format
|
|
71
|
+
|
|
72
|
+
```javascript
|
|
73
|
+
{
|
|
74
|
+
success: true,
|
|
75
|
+
query: "Goku",
|
|
76
|
+
|
|
77
|
+
package: {
|
|
78
|
+
name: "shadowx-tiksr",
|
|
79
|
+
version: "1.0.0",
|
|
80
|
+
author: "Mueid Mursalin Rifat"
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
video: {
|
|
84
|
+
title: "Son Goku Super Saiyan 5 THIS FORM IS INSANE 🔥",
|
|
85
|
+
region: "PK",
|
|
86
|
+
duration: 30,
|
|
87
|
+
play_url: "https://.../video.mp4",
|
|
88
|
+
music_url: "https://.../audio.mp3",
|
|
89
|
+
|
|
90
|
+
stats: {
|
|
91
|
+
play_count: "56.6K",
|
|
92
|
+
likes: "2.9K",
|
|
93
|
+
comments: "25",
|
|
94
|
+
shares: "154",
|
|
95
|
+
downloads: "25"
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
author: {
|
|
99
|
+
nickname: "Skull Anime",
|
|
100
|
+
username: "skulanime",
|
|
101
|
+
profile_url: "https://www.tiktok.com/@skulanime"
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
downloads: {
|
|
106
|
+
video: "https://.../video.mp4",
|
|
107
|
+
audio: "https://.../audio.mp3",
|
|
108
|
+
video_no_watermark: "https://.../video.mp4"
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
metadata: {
|
|
112
|
+
region: "PK",
|
|
113
|
+
operator: "Mueid Mursalin Rifat",
|
|
114
|
+
powered_by: "CatX TikTok API",
|
|
115
|
+
timestamp: "2024-01-01T12:00:00.000Z"
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
📝 Examples
|
|
123
|
+
|
|
124
|
+
Search with Different Queries
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
const tiktok = new TikSR();
|
|
128
|
+
|
|
129
|
+
const queries = ['dance', 'cooking', 'funny cats'];
|
|
130
|
+
|
|
131
|
+
for (const query of queries) {
|
|
132
|
+
const result = await tiktok.search(query);
|
|
133
|
+
console.log(`${query}: ${result.video.title}`);
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Get Video Statistics
|
|
138
|
+
|
|
139
|
+
```javascript
|
|
140
|
+
const result = await tiktok.search('anime');
|
|
141
|
+
|
|
142
|
+
console.log('📊 Statistics:');
|
|
143
|
+
console.log(`👁️ Views: ${result.video.stats.play_count}`);
|
|
144
|
+
console.log(`❤️ Likes: ${result.video.stats.likes}`);
|
|
145
|
+
console.log(`💬 Comments: ${result.video.stats.comments}`);
|
|
146
|
+
console.log(`↗️ Shares: ${result.video.stats.shares}`);
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Extract Video ID from URL
|
|
150
|
+
|
|
151
|
+
```javascript
|
|
152
|
+
const url = 'https://www.tiktok.com/@user/video/123456789';
|
|
153
|
+
const videoId = tiktok.extractVideoId(url);
|
|
154
|
+
console.log(videoId); // '123456789'
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Error Handling
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
try {
|
|
161
|
+
const result = await tiktok.search('');
|
|
162
|
+
} catch (error) {
|
|
163
|
+
console.log('Error Code:', error.code);
|
|
164
|
+
console.log('Message:', error.message);
|
|
165
|
+
console.log('Status:', error.statusCode);
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Common error codes:
|
|
170
|
+
|
|
171
|
+
· INVALID_QUERY - Empty or invalid search
|
|
172
|
+
· NOT_FOUND - No videos found
|
|
173
|
+
· RATE_LIMITED - Too many requests
|
|
174
|
+
· TIMEOUT - Request timed out
|
|
175
|
+
· NETWORK_ERROR - Connection issues
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
⚙️ Configuration
|
|
180
|
+
|
|
181
|
+
Environment Variables
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
TIKTOK_API_URL=https://shadowx-api.onrender.com/api
|
|
185
|
+
TIKTOK_TIMEOUT=30000
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Custom Configuration
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
const tiktok = new TikSR({
|
|
192
|
+
baseURL: 'https://your-custom-api.com/api',
|
|
193
|
+
timeout: 60000 // 60 seconds
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
🔧 Requirements
|
|
200
|
+
|
|
201
|
+
· Node.js: 16.x or higher (18+ recommended)
|
|
202
|
+
· npm: 7.x or higher
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
📄 License
|
|
210
|
+
|
|
211
|
+
MIT © Mueid Mursalin Rifat
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
🙏 Credits
|
|
216
|
+
|
|
217
|
+
· Author: Mueid Mursalin Rifat
|
|
218
|
+
· API: ShadowX TikTokSr API
|
|
219
|
+
· Powered by: ShadowX
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
🔗 Links
|
|
224
|
+
|
|
225
|
+
· npm Package
|
|
226
|
+
· GitHub Repository
|
|
227
|
+
· Issue Tracker
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
---
|
package/index.js
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
|
|
3
|
+
class ShadowXTikSR {
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
this.baseURL = options.baseURL || 'https://shadowx-api.onrender.com/api';
|
|
6
|
+
this.timeout = options.timeout || 30000;
|
|
7
|
+
this.userAgent = options.userAgent || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36';
|
|
8
|
+
|
|
9
|
+
this.client = axios.create({
|
|
10
|
+
baseURL: this.baseURL,
|
|
11
|
+
timeout: this.timeout,
|
|
12
|
+
headers: {
|
|
13
|
+
'User-Agent': this.userAgent,
|
|
14
|
+
'Accept': 'application/json'
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get module metadata
|
|
21
|
+
*/
|
|
22
|
+
static getMeta() {
|
|
23
|
+
return {
|
|
24
|
+
name: "shadowx-tiksr",
|
|
25
|
+
version: "1.0.0",
|
|
26
|
+
description: "TikTok search and download module",
|
|
27
|
+
author: "Mueid Mursalin Rifat",
|
|
28
|
+
license: "MIT",
|
|
29
|
+
supported: ["Video search", "Video download", "Metadata extraction"]
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Search TikTok videos by query
|
|
35
|
+
* @param {string} query - Search term (e.g., "Goku", "funny cats", "dance")
|
|
36
|
+
* @returns {Promise<Object>} Search results with video details
|
|
37
|
+
*/
|
|
38
|
+
async search(query) {
|
|
39
|
+
if (!query || typeof query !== 'string') {
|
|
40
|
+
throw new Error('Search query is required');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
console.log(`🔍 Searching TikTok for: "${query}"`);
|
|
45
|
+
|
|
46
|
+
const response = await this.client.get('/tiksr', {
|
|
47
|
+
params: { query: encodeURIComponent(query) }
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const data = response.data;
|
|
51
|
+
|
|
52
|
+
if (!data || !data.status) {
|
|
53
|
+
throw new Error(data?.message || 'Search failed');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return this._formatResponse(data, query);
|
|
57
|
+
|
|
58
|
+
} catch (error) {
|
|
59
|
+
throw this._handleError(error, { query });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Download TikTok video by search (returns first result)
|
|
65
|
+
* @param {string} query - Search term
|
|
66
|
+
* @returns {Promise<Object>} Video download info
|
|
67
|
+
*/
|
|
68
|
+
async download(query) {
|
|
69
|
+
const result = await this.search(query);
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
success: true,
|
|
73
|
+
message: 'Video ready for download',
|
|
74
|
+
download: {
|
|
75
|
+
video_url: result.video.play_url,
|
|
76
|
+
audio_url: result.video.music_url,
|
|
77
|
+
filename: `${result.video.title?.substring(0, 50) || 'tiktok_video'}.mp4`,
|
|
78
|
+
size: 'Unknown', // API doesn't provide size
|
|
79
|
+
quality: 'HD'
|
|
80
|
+
},
|
|
81
|
+
...result
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Format API response
|
|
87
|
+
*/
|
|
88
|
+
_formatResponse(data, query) {
|
|
89
|
+
// Format numbers with K/M/B suffixes
|
|
90
|
+
const formatNumber = (num) => {
|
|
91
|
+
if (!num && num !== 0) return 'N/A';
|
|
92
|
+
if (num >= 1000000) return (num / 1000000).toFixed(1) + 'M';
|
|
93
|
+
if (num >= 1000) return (num / 1000).toFixed(1) + 'K';
|
|
94
|
+
return num.toString();
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
success: true,
|
|
99
|
+
query: query,
|
|
100
|
+
|
|
101
|
+
// Package info
|
|
102
|
+
package: {
|
|
103
|
+
name: 'shadowx-tiksr',
|
|
104
|
+
version: '1.0.0',
|
|
105
|
+
author: 'Mueid Mursalin Rifat'
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
// Video details
|
|
109
|
+
video: {
|
|
110
|
+
title: data.title || 'No title',
|
|
111
|
+
region: data.region || 'Unknown',
|
|
112
|
+
duration: data.duration || 0,
|
|
113
|
+
play_url: data.play_url || null,
|
|
114
|
+
music_url: data.music_url || null,
|
|
115
|
+
|
|
116
|
+
// Statistics
|
|
117
|
+
stats: {
|
|
118
|
+
play_count: formatNumber(data.stats?.play_count),
|
|
119
|
+
likes: formatNumber(data.stats?.likes),
|
|
120
|
+
comments: formatNumber(data.stats?.comments),
|
|
121
|
+
shares: formatNumber(data.stats?.shares),
|
|
122
|
+
downloads: formatNumber(data.stats?.downloads),
|
|
123
|
+
raw: data.stats // Original numbers
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
// Author info
|
|
127
|
+
author: {
|
|
128
|
+
nickname: data.author?.nickname || 'Unknown',
|
|
129
|
+
username: data.author?.username || 'unknown',
|
|
130
|
+
profile_url: data.author?.username ?
|
|
131
|
+
`https://www.tiktok.com/@${data.author.username}` : null
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
// Direct download links
|
|
136
|
+
downloads: {
|
|
137
|
+
video: data.play_url,
|
|
138
|
+
audio: data.music_url,
|
|
139
|
+
video_no_watermark: data.play_url, // API provides clean video
|
|
140
|
+
thumbnail: data.thumbnail || null
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
// Additional info
|
|
144
|
+
metadata: {
|
|
145
|
+
region: data.region,
|
|
146
|
+
operator: data.operator || 'Mueid Mursalin Rifat',
|
|
147
|
+
powered_by: data.powered_by || 'CatX TikTok API',
|
|
148
|
+
timestamp: new Date().toISOString()
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
// Raw data for reference
|
|
152
|
+
raw: data
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Handle errors
|
|
158
|
+
*/
|
|
159
|
+
_handleError(error, context = {}) {
|
|
160
|
+
let errorMessage = 'Failed to process TikTok request';
|
|
161
|
+
let statusCode = 500;
|
|
162
|
+
let errorCode = 'UNKNOWN_ERROR';
|
|
163
|
+
|
|
164
|
+
if (error.response) {
|
|
165
|
+
statusCode = error.response.status;
|
|
166
|
+
|
|
167
|
+
switch (statusCode) {
|
|
168
|
+
case 400:
|
|
169
|
+
errorMessage = 'Invalid search query';
|
|
170
|
+
errorCode = 'INVALID_QUERY';
|
|
171
|
+
break;
|
|
172
|
+
case 404:
|
|
173
|
+
errorMessage = 'No videos found for this query';
|
|
174
|
+
errorCode = 'NOT_FOUND';
|
|
175
|
+
break;
|
|
176
|
+
case 429:
|
|
177
|
+
errorMessage = 'Rate limit exceeded. Try again later';
|
|
178
|
+
errorCode = 'RATE_LIMITED';
|
|
179
|
+
break;
|
|
180
|
+
case 500:
|
|
181
|
+
case 502:
|
|
182
|
+
case 503:
|
|
183
|
+
errorMessage = 'TikTok API service unavailable';
|
|
184
|
+
errorCode = 'SERVICE_UNAVAILABLE';
|
|
185
|
+
break;
|
|
186
|
+
default:
|
|
187
|
+
errorMessage = `API Error: ${error.response.data?.message || error.message}`;
|
|
188
|
+
}
|
|
189
|
+
} else if (error.code === 'ECONNABORTED') {
|
|
190
|
+
errorMessage = 'Request timeout';
|
|
191
|
+
errorCode = 'TIMEOUT';
|
|
192
|
+
} else if (error.code === 'ENOTFOUND') {
|
|
193
|
+
errorMessage = 'Network error - cannot connect to API';
|
|
194
|
+
errorCode = 'NETWORK_ERROR';
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const formattedError = new Error(errorMessage);
|
|
198
|
+
formattedError.code = errorCode;
|
|
199
|
+
formattedError.statusCode = statusCode;
|
|
200
|
+
formattedError.context = context;
|
|
201
|
+
formattedError.timestamp = new Date().toISOString();
|
|
202
|
+
|
|
203
|
+
return formattedError;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Get trending videos (if supported by API)
|
|
208
|
+
*/
|
|
209
|
+
async trending() {
|
|
210
|
+
try {
|
|
211
|
+
const response = await this.client.get('/tiktok/trending');
|
|
212
|
+
return response.data;
|
|
213
|
+
} catch (error) {
|
|
214
|
+
throw this._handleError(error);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Extract video ID from TikTok URL
|
|
220
|
+
* @param {string} url - TikTok video URL
|
|
221
|
+
* @returns {string|null} Video ID
|
|
222
|
+
*/
|
|
223
|
+
extractVideoId(url) {
|
|
224
|
+
if (!url) return null;
|
|
225
|
+
|
|
226
|
+
const patterns = [
|
|
227
|
+
/tiktok\.com\/@[\w.-]+\/video\/(\d+)/i,
|
|
228
|
+
/tiktok\.com\/video\/(\d+)/i,
|
|
229
|
+
/vm\.tiktok\.com\/([\w]+)/i
|
|
230
|
+
];
|
|
231
|
+
|
|
232
|
+
for (const pattern of patterns) {
|
|
233
|
+
const match = url.match(pattern);
|
|
234
|
+
if (match) return match[1];
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Export
|
|
242
|
+
module.exports = ShadowXTikSR;
|
|
243
|
+
module.exports.create = (options) => new ShadowXTikSR(options);
|
|
244
|
+
module.exports.default = new ShadowXTikSR();
|
|
245
|
+
module.exports.meta = ShadowXTikSR.getMeta();
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "shadowx-tiksr",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "TikTok video search and download module - Search videos by query, get video details, download links, and metadata",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node examples/basic-usage.js"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"tiktok",
|
|
11
|
+
"downloader",
|
|
12
|
+
"tiktok-downloader",
|
|
13
|
+
"tiktok-search",
|
|
14
|
+
"video-downloader",
|
|
15
|
+
"social-media",
|
|
16
|
+
"tiktok-api",
|
|
17
|
+
"shadowx",
|
|
18
|
+
"tiksr",
|
|
19
|
+
"tiktok-video",
|
|
20
|
+
"tiktok-no-watermark"
|
|
21
|
+
],
|
|
22
|
+
"author": "Mueid Mursalin Rifat",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"axios": "^1.6.2"
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/mueidmursalin/shadowx-tiksr.git"
|
|
30
|
+
},
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/mueidmursalin/shadowx-tiksr/issues"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://github.com/mueidmursalin/shadowx-tiksr#readme",
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=16.0.0"
|
|
37
|
+
}
|
|
38
|
+
}
|