wanzxcvi 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/index.js +9 -0
- package/package.json +19 -0
- package/readme.MD +5 -0
- package/src/spamNgl.js +218 -0
- package/src/ttdl.js +131 -0
- package/src/wanz.js +5 -0
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "wanzxcvi",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Package by Wanz",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo 'Error: no test specified' && exit 1"
|
|
8
|
+
},
|
|
9
|
+
"keywords": ["wanz", "npm", "package"],
|
|
10
|
+
"author": "WanzOfficial",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"axios": "^1.6.0"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"index.js",
|
|
17
|
+
"src/"
|
|
18
|
+
]
|
|
19
|
+
}
|
package/readme.MD
ADDED
package/src/spamNgl.js
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* NGL Spammer - Pure Async Function
|
|
5
|
+
* @param {string} username - NGL username atau link
|
|
6
|
+
* @param {string} message - Pesan yang mau di-spam
|
|
7
|
+
* @param {number} count - Jumlah spam (default: 10)
|
|
8
|
+
* @param {Object} options - Opsi tambahan
|
|
9
|
+
* @returns {Promise<Object>} Hasil spam
|
|
10
|
+
*/
|
|
11
|
+
async function spamNgl(username, message, count = 10, options = {}) {
|
|
12
|
+
const cleanUsername = extractUsername(username);
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
minDelay = 1000,
|
|
16
|
+
maxDelay = 3000,
|
|
17
|
+
timeout = 30000,
|
|
18
|
+
maxRetries = 3
|
|
19
|
+
} = options;
|
|
20
|
+
|
|
21
|
+
if (!cleanUsername) throw new Error('Username tidak valid');
|
|
22
|
+
if (!message || message.length < 1) throw new Error('Pesan tidak boleh kosong');
|
|
23
|
+
if (count < 1) throw new Error('Jumlah spam minimal 1');
|
|
24
|
+
|
|
25
|
+
const results = {
|
|
26
|
+
total: count,
|
|
27
|
+
success: 0,
|
|
28
|
+
failed: 0,
|
|
29
|
+
rateLimit: 0,
|
|
30
|
+
errors: [],
|
|
31
|
+
startTime: Date.now()
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
for (let i = 1; i <= count; i++) {
|
|
35
|
+
try {
|
|
36
|
+
const result = await sendMessage(cleanUsername, message, {
|
|
37
|
+
timeout,
|
|
38
|
+
maxRetries,
|
|
39
|
+
deviceId: generateDeviceId()
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (result.success) {
|
|
43
|
+
results.success++;
|
|
44
|
+
} else if (result.rateLimit) {
|
|
45
|
+
results.rateLimit++;
|
|
46
|
+
await sleep(randomInt(5000, 8000));
|
|
47
|
+
} else {
|
|
48
|
+
results.failed++;
|
|
49
|
+
results.errors.push({
|
|
50
|
+
attempt: i,
|
|
51
|
+
error: result.error
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (i < count) {
|
|
56
|
+
await sleep(randomInt(minDelay, maxDelay));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
} catch (error) {
|
|
60
|
+
results.failed++;
|
|
61
|
+
results.errors.push({
|
|
62
|
+
attempt: i,
|
|
63
|
+
error: error.message
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
results.duration = (Date.now() - results.startTime) / 1000;
|
|
69
|
+
results.successRate = (results.success / count) * 100;
|
|
70
|
+
|
|
71
|
+
return results;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
function extractUsername(input) {
|
|
76
|
+
input = input.trim();
|
|
77
|
+
if (!input) return null;
|
|
78
|
+
|
|
79
|
+
const patterns = [
|
|
80
|
+
/ngl\.link\/(?:@)?([a-zA-Z0-9_]+)/,
|
|
81
|
+
/^(?:@)?([a-zA-Z0-9_]+)$/
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
for (const pattern of patterns) {
|
|
85
|
+
const match = input.match(pattern);
|
|
86
|
+
if (match) return match[1];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return input;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function generateDeviceId() {
|
|
93
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
94
|
+
const r = Math.random() * 16 | 0;
|
|
95
|
+
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
96
|
+
return v.toString(16);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function randomInt(min, max) {
|
|
101
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function sleep(ms) {
|
|
105
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
async function sendMessage(username, message, options = {}) {
|
|
110
|
+
const {
|
|
111
|
+
timeout = 30000,
|
|
112
|
+
maxRetries = 3,
|
|
113
|
+
deviceId = generateDeviceId()
|
|
114
|
+
} = options;
|
|
115
|
+
|
|
116
|
+
const payload = {
|
|
117
|
+
username: username,
|
|
118
|
+
question: message,
|
|
119
|
+
deviceId: deviceId,
|
|
120
|
+
gameSlug: "",
|
|
121
|
+
referrer: ""
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const headers = {
|
|
125
|
+
'User-Agent': getRandomUserAgent(),
|
|
126
|
+
'Accept': 'application/json, text/plain, */*',
|
|
127
|
+
'Content-Type': 'application/json',
|
|
128
|
+
'Origin': 'https://ngl.link',
|
|
129
|
+
'Referer': `https://ngl.link/${username}`
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
let lastError = null;
|
|
133
|
+
|
|
134
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
135
|
+
try {
|
|
136
|
+
const response = await axios.post(
|
|
137
|
+
'https://ngl.link/api/submit',
|
|
138
|
+
payload,
|
|
139
|
+
{ headers, timeout }
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
if (response.status === 200) {
|
|
143
|
+
const data = response.data;
|
|
144
|
+
|
|
145
|
+
if (data.success === true ||
|
|
146
|
+
data.status === 'success' ||
|
|
147
|
+
data.message === 'success') {
|
|
148
|
+
return { success: true };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const responseStr = JSON.stringify(data).toLowerCase();
|
|
152
|
+
if (responseStr.includes('rate') && responseStr.includes('limit')) {
|
|
153
|
+
return { success: false, rateLimit: true, error: 'Rate limit' };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (data.error) {
|
|
157
|
+
return { success: false, rateLimit: false, error: data.error };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return { success: true };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (response.status === 429) {
|
|
164
|
+
return { success: false, rateLimit: true, error: 'Rate limit (429)' };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (response.status === 403) {
|
|
168
|
+
return { success: false, rateLimit: false, error: 'Blocked (403)' };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
success: false,
|
|
173
|
+
rateLimit: false,
|
|
174
|
+
error: `HTTP ${response.status}`
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
} catch (error) {
|
|
178
|
+
lastError = error;
|
|
179
|
+
|
|
180
|
+
if (error.response) {
|
|
181
|
+
const status = error.response.status;
|
|
182
|
+
if (status === 429) {
|
|
183
|
+
return { success: false, rateLimit: true, error: 'Rate limit' };
|
|
184
|
+
}
|
|
185
|
+
if (status === 403) {
|
|
186
|
+
return { success: false, rateLimit: false, error: 'Blocked' };
|
|
187
|
+
}
|
|
188
|
+
await sleep(1000 * (attempt + 1));
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (error.code === 'ECONNABORTED' || error.code === 'ETIMEDOUT') {
|
|
193
|
+
await sleep(2000 * (attempt + 1));
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
await sleep(1000 * (attempt + 1));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
success: false,
|
|
203
|
+
rateLimit: false,
|
|
204
|
+
error: lastError ? lastError.message : 'Max retries exceeded'
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function getRandomUserAgent() {
|
|
209
|
+
const agents = [
|
|
210
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
211
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
212
|
+
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
213
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/121.0',
|
|
214
|
+
];
|
|
215
|
+
return agents[Math.floor(Math.random() * agents.length)];
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
module.exports = spamNgl;
|
package/src/ttdl.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* TikTok Video Downloader - No Watermark
|
|
5
|
+
* @param {string} url - URL video TikTok (contoh: https://www.tiktok.com/@user/video/123)
|
|
6
|
+
* @param {Object} options - Opsi tambahan
|
|
7
|
+
* @param {string} options.quality - 'hd' atau 'sd' (default: 'hd')
|
|
8
|
+
* @param {number} options.timeout - Timeout request (ms) (default: 30000)
|
|
9
|
+
* @returns {Promise<Object>} Hasil download
|
|
10
|
+
*/
|
|
11
|
+
async function ttdl(url, options = {}) {
|
|
12
|
+
const {
|
|
13
|
+
quality = 'hd',
|
|
14
|
+
timeout = 30000
|
|
15
|
+
} = options;
|
|
16
|
+
|
|
17
|
+
// Validasi URL
|
|
18
|
+
if (!url || typeof url !== 'string') {
|
|
19
|
+
throw new Error('URL TikTok tidak valid');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const videoId = extractVideoId(url);
|
|
23
|
+
if (!videoId) {
|
|
24
|
+
throw new Error('Gagal mengekstrak ID video dari URL');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
// Pake API eksternal (TikWM)
|
|
29
|
+
const response = await axios.get('https://www.tikwm.com/api/', {
|
|
30
|
+
params: {
|
|
31
|
+
url: url,
|
|
32
|
+
count: 12,
|
|
33
|
+
cursor: 0,
|
|
34
|
+
web: 1,
|
|
35
|
+
hd: quality === 'hd' ? 1 : 0
|
|
36
|
+
},
|
|
37
|
+
timeout: timeout,
|
|
38
|
+
headers: {
|
|
39
|
+
'User-Agent': getRandomUserAgent(),
|
|
40
|
+
'Accept': 'application/json'
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const data = response.data;
|
|
45
|
+
|
|
46
|
+
// Cek apakah response sukses
|
|
47
|
+
if (!data || data.code !== 0) {
|
|
48
|
+
throw new Error(data?.msg || 'Gagal mengambil data video');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const videoData = data.data;
|
|
52
|
+
|
|
53
|
+
// Ambil URL video tanpa watermark
|
|
54
|
+
const videoUrl = quality === 'hd' && videoData.hdplay
|
|
55
|
+
? videoData.hdplay
|
|
56
|
+
: videoData.play;
|
|
57
|
+
|
|
58
|
+
if (!videoUrl) {
|
|
59
|
+
throw new Error('URL video tidak ditemukan');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Return hasil
|
|
63
|
+
return {
|
|
64
|
+
success: true,
|
|
65
|
+
videoId: videoData.id,
|
|
66
|
+
title: videoData.title || 'No title',
|
|
67
|
+
description: videoData.desc || '',
|
|
68
|
+
duration: videoData.duration || 0,
|
|
69
|
+
author: {
|
|
70
|
+
username: videoData.author?.unique_id || '',
|
|
71
|
+
nickname: videoData.author?.nickname || '',
|
|
72
|
+
avatar: videoData.author?.avatar || ''
|
|
73
|
+
},
|
|
74
|
+
stats: {
|
|
75
|
+
views: videoData.play_count || 0,
|
|
76
|
+
likes: videoData.digg_count || 0,
|
|
77
|
+
shares: videoData.share_count || 0,
|
|
78
|
+
comments: videoData.comment_count || 0
|
|
79
|
+
},
|
|
80
|
+
video: {
|
|
81
|
+
url: videoUrl,
|
|
82
|
+
quality: quality,
|
|
83
|
+
width: videoData.width || 0,
|
|
84
|
+
height: videoData.height || 0,
|
|
85
|
+
format: 'mp4'
|
|
86
|
+
},
|
|
87
|
+
cover: videoData.cover || '',
|
|
88
|
+
music: videoData.music_info?.play || '',
|
|
89
|
+
extractedAt: new Date().toISOString()
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
} catch (error) {
|
|
93
|
+
if (error.response) {
|
|
94
|
+
throw new Error(`API error: ${error.response.status}`);
|
|
95
|
+
}
|
|
96
|
+
throw new Error(error.message || 'Gagal mendownload video');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
function extractVideoId(url) {
|
|
102
|
+
const patterns = [
|
|
103
|
+
/tiktok\.com\/@[\w.]+\/video\/(\d+)/,
|
|
104
|
+
/tiktok\.com\/v\/(\d+)/,
|
|
105
|
+
/vt\.tiktok\.com\/\w+/,
|
|
106
|
+
/vm\.tiktok\.com\/\w+/
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
for (const pattern of patterns) {
|
|
110
|
+
const match = url.match(pattern);
|
|
111
|
+
if (match) {
|
|
112
|
+
if (url.includes('vt.tiktok.com') || url.includes('vm.tiktok.com')) {
|
|
113
|
+
return url;
|
|
114
|
+
}
|
|
115
|
+
return match[1] || url;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function getRandomUserAgent() {
|
|
123
|
+
const agents = [
|
|
124
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
125
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
126
|
+
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
|
|
127
|
+
];
|
|
128
|
+
return agents[Math.floor(Math.random() * agents.length)];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
module.exports = ttdl;
|