eubottura commited on
Commit
c2d5210
·
verified ·
1 Parent(s): 34b822f

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +851 -19
index.html CHANGED
@@ -1,19 +1,851 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="pt-BR">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Douyin V3 Link Extractor - CDN Direta</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap');
11
+
12
+ * {
13
+ font-family: 'Inter', sans-serif;
14
+ }
15
+
16
+ .animated-bg {
17
+ background: linear-gradient(-45deg, #667eea, #764ba2, #f093fb, #f5576c);
18
+ background-size: 400% 400%;
19
+ animation: gradient 15s ease infinite;
20
+ }
21
+
22
+ @keyframes gradient {
23
+ 0% {
24
+ background-position: 0% 50%;
25
+ }
26
+
27
+ 50% {
28
+ background-position: 100% 50%;
29
+ }
30
+
31
+ 100% {
32
+ background-position: 0% 50%;
33
+ }
34
+ }
35
+
36
+ .glass-card {
37
+ background: rgba(255, 255, 255, 0.95);
38
+ backdrop-filter: blur(20px);
39
+ border: 1px solid rgba(255, 255, 255, 0.3);
40
+ box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.15);
41
+ }
42
+
43
+ .url-line {
44
+ animation: slideIn 0.3s ease-out;
45
+ }
46
+
47
+ @keyframes slideIn {
48
+ from {
49
+ opacity: 0;
50
+ transform: translateX(-20px);
51
+ }
52
+
53
+ to {
54
+ opacity: 1;
55
+ transform: translateX(0);
56
+ }
57
+ }
58
+
59
+ .process-animation {
60
+ animation: processPulse 1.5s ease-in-out infinite;
61
+ }
62
+
63
+ @keyframes processPulse {
64
+
65
+ 0%,
66
+ 100% {
67
+ opacity: 1;
68
+ transform: scale(1);
69
+ }
70
+
71
+ 50% {
72
+ opacity: 0.6;
73
+ transform: scale(1.05);
74
+ }
75
+ }
76
+
77
+ .result-item {
78
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
79
+ }
80
+
81
+ .result-item:hover {
82
+ transform: translateY(-2px);
83
+ box-shadow: 0 15px 35px -5px rgba(102, 126, 234, 0.3);
84
+ }
85
+
86
+ .btn-primary {
87
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
88
+ transition: all 0.3s ease;
89
+ }
90
+
91
+ .btn-primary:hover {
92
+ transform: translateY(-2px);
93
+ box-shadow: 0 10px 20px rgba(102, 126, 234, 0.4);
94
+ }
95
+
96
+ .success-badge {
97
+ background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
98
+ color: white;
99
+ padding: 4px 12px;
100
+ border-radius: 20px;
101
+ font-size: 0.75rem;
102
+ font-weight: 600;
103
+ }
104
+
105
+ .error-badge {
106
+ background: linear-gradient(135deg, #eb3349 0%, #f45c43 100%);
107
+ color: white;
108
+ padding: 4px 12px;
109
+ border-radius: 20px;
110
+ font-size: 0.75rem;
111
+ font-weight: 600;
112
+ }
113
+
114
+ .custom-scrollbar::-webkit-scrollbar {
115
+ width: 10px;
116
+ }
117
+
118
+ .custom-scrollbar::-webkit-scrollbar-track {
119
+ background: #f1f1f1;
120
+ border-radius: 10px;
121
+ }
122
+
123
+ .custom-scrollbar::-webkit-scrollbar-thumb {
124
+ background: linear-gradient(135deg, #667eea, #764ba2);
125
+ border-radius: 10px;
126
+ }
127
+
128
+ .floating {
129
+ animation: float 3s ease-in-out infinite;
130
+ }
131
+
132
+ @keyframes float {
133
+
134
+ 0%,
135
+ 100% {
136
+ transform: translateY(0px);
137
+ }
138
+
139
+ 50% {
140
+ transform: translateY(-10px);
141
+ }
142
+ }
143
+
144
+ .script-view {
145
+ background: #1e1e1e;
146
+ color: #d4d4d4;
147
+ font-family: 'Courier New', monospace;
148
+ font-size: 0.85rem;
149
+ line-height: 1.5;
150
+ }
151
+
152
+ .keyword {
153
+ color: #569cd6;
154
+ }
155
+
156
+ .string {
157
+ color: #ce9178;
158
+ }
159
+
160
+ .function {
161
+ color: #dcdcaa;
162
+ }
163
+
164
+ .comment {
165
+ color: #6a9955;
166
+ }
167
+
168
+ .number {
169
+ color: #b5cea8;
170
+ }
171
+
172
+ .v3-badge {
173
+ background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
174
+ color: white;
175
+ padding: 2px 8px;
176
+ border-radius: 12px;
177
+ font-size: 0.7rem;
178
+ font-weight: 700;
179
+ text-transform: uppercase;
180
+ letter-spacing: 0.5px;
181
+ }
182
+
183
+ .direct-link {
184
+ background: linear-gradient(135deg, #667eea15 0%, #764ba215 100%);
185
+ border: 2px solid transparent;
186
+ background-clip: padding-box;
187
+ position: relative;
188
+ }
189
+
190
+ .direct-link::before {
191
+ content: '';
192
+ position: absolute;
193
+ top: 0;
194
+ left: 0;
195
+ right: 0;
196
+ bottom: 0;
197
+ z-index: -1;
198
+ margin: -2px;
199
+ border-radius: inherit;
200
+ background: linear-gradient(135deg, #667eea, #764ba2);
201
+ }
202
+
203
+ .result-number {
204
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
205
+ color: white;
206
+ width: 32px;
207
+ height: 32px;
208
+ display: flex;
209
+ align-items: center;
210
+ justify-content: center;
211
+ border-radius: 50%;
212
+ font-weight: bold;
213
+ font-size: 14px;
214
+ flex-shrink: 0;
215
+ }
216
+
217
+ .console-log {
218
+ font-family: 'Courier New', monospace;
219
+ background: #2d2d2d;
220
+ color: #00ff00;
221
+ padding: 8px 12px;
222
+ border-radius: 6px;
223
+ font-size: 0.85rem;
224
+ margin: 4px 0;
225
+ border-left: 3px solid #00ff00;
226
+ }
227
+
228
+ .console-error {
229
+ color: #ff6b6b;
230
+ border-left-color: #ff6b6b;
231
+ }
232
+
233
+ .console-success {
234
+ color: #00ff00;
235
+ border-left-color: #00ff00;
236
+ }
237
+
238
+ .console-info {
239
+ color: #17a2b8;
240
+ border-left-color: #17a2b8;
241
+ }
242
+
243
+ .download-btn {
244
+ background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
245
+ transition: all 0.3s ease;
246
+ }
247
+
248
+ .download-btn:hover {
249
+ transform: scale(1.05);
250
+ box-shadow: 0 5px 15px rgba(17, 153, 142, 0.4);
251
+ }
252
+
253
+ .video-info {
254
+ background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
255
+ border-radius: 12px;
256
+ padding: 16px;
257
+ }
258
+
259
+ .v3-url {
260
+ background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
261
+ color: #00ff00;
262
+ border-left: 4px solid #f5576c;
263
+ padding: 12px;
264
+ border-radius: 8px;
265
+ font-family: 'Courier New', monospace;
266
+ font-size: 0.85rem;
267
+ word-break: break-all;
268
+ max-height: 100px;
269
+ overflow-y: auto;
270
+ }
271
+
272
+ .cdn-badge {
273
+ display: inline-flex;
274
+ align-items: center;
275
+ padding: 4px 10px;
276
+ background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
277
+ color: white;
278
+ border-radius: 20px;
279
+ font-size: 0.75rem;
280
+ font-weight: 600;
281
+ }
282
+
283
+ .copy-btn {
284
+ transition: all 0.3s ease;
285
+ }
286
+
287
+ .copy-btn:hover {
288
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
289
+ color: white;
290
+ }
291
+
292
+ .copy-btn.copied {
293
+ background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
294
+ color: white;
295
+ }
296
+
297
+ .v3-header {
298
+ background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
299
+ color: white;
300
+ padding: 4px 12px;
301
+ border-radius: 8px;
302
+ font-size: 0.75rem;
303
+ font-weight: 700;
304
+ text-transform: uppercase;
305
+ letter-spacing: 1px;
306
+ display: inline-block;
307
+ margin-bottom: 8px;
308
+ }
309
+
310
+ .processing-step {
311
+ background: rgba(102, 126, 234, 0.1);
312
+ border-left: 3px solid #667eea;
313
+ padding: 8px 12px;
314
+ margin: 4px 0;
315
+ border-radius: 4px;
316
+ font-size: 0.85rem;
317
+ }
318
+
319
+ .step-success {
320
+ background: rgba(17, 153, 142, 0.1);
321
+ border-left-color: #11998e;
322
+ }
323
+
324
+ .step-error {
325
+ background: rgba(235, 51, 73, 0.1);
326
+ border-left-color: #eb3349;
327
+ }
328
+
329
+ .redirect-animation {
330
+ animation: redirectPulse 1s ease-in-out infinite;
331
+ }
332
+
333
+ @keyframes redirectPulse {
334
+
335
+ 0%,
336
+ 100% {
337
+ opacity: 1;
338
+ }
339
+
340
+ 50% {
341
+ opacity: 0.5;
342
+ }
343
+ }
344
+
345
+ .bookmarklet-btn {
346
+ background: linear-gradient(135deg, #ff6b6b 0%, #feca57 100%);
347
+ transition: all 0.3s ease;
348
+ }
349
+
350
+ .bookmarklet-btn:hover {
351
+ transform: translateY(-2px);
352
+ box-shadow: 0 10px 20px rgba(255, 107, 107, 0.4);
353
+ }
354
+
355
+ .notification {
356
+ position: fixed;
357
+ top: 20px;
358
+ right: 20px;
359
+ padding: 16px 24px;
360
+ border-radius: 12px;
361
+ color: white;
362
+ font-weight: 600;
363
+ z-index: 1000;
364
+ animation: slideInNotification 0.3s ease-out;
365
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
366
+ }
367
+
368
+ .notification.success {
369
+ background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
370
+ }
371
+
372
+ .notification.error {
373
+ background: linear-gradient(135deg, #eb3349 0%, #f45c43 100%);
374
+ }
375
+
376
+ @keyframes slideInNotification {
377
+ from {
378
+ transform: translateX(400px);
379
+ opacity: 0;
380
+ }
381
+
382
+ to {
383
+ transform: translateX(0);
384
+ opacity: 1;
385
+ }
386
+ }
387
+ </style>
388
+ </head>
389
+
390
+ <body class="animated-bg min-h-screen">
391
+ <div class="container mx-auto px-4 py-8 max-w-6xl">
392
+ <!-- Header -->
393
+ <header class="text-center mb-10">
394
+ <div class="inline-flex items-center justify-center mb-4 floating">
395
+ <i class="fas fa-bolt text-white text-5xl mr-4"></i>
396
+ <h1 class="text-5xl font-bold text-white">Douyin CDN Extractor</h1>
397
+ <span class="v3-badge ml-3">V3</span>
398
+ </div>
399
+ <p class="text-white/90 text-xl mb-2">Extração Direta da CDN - Link V3 Final</p>
400
+ <p class="text-white/70 text-sm">Redirecionamento automático para a URL original da CDN</p>
401
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank"
402
+ class="inline-block mt-4 text-white/80 hover:text-white transition-all text-sm">
403
+ Built with anycoder <i class="fas fa-external-link-alt ml-1"></i>
404
+ </a>
405
+ </header>
406
+
407
+ <!-- Main Card -->
408
+ <main class="glass-card rounded-3xl p-8">
409
+ <!-- URL Input Section -->
410
+ <section class="mb-8">
411
+ <div class="flex items-center mb-4">
412
+ <div
413
+ class="w-10 h-10 bg-gradient-to-r from-purple-500 to-pink-500 rounded-lg flex items-center justify-center mr-3">
414
+ <i class="fas fa-link text-white"></i>
415
+ </div>
416
+ <h2 class="text-2xl font-bold text-gray-800">Insira as URLs do Douyin</h2>
417
+ </div>
418
+
419
+ <div class="space-y-4">
420
+ <div class="relative">
421
+ <textarea id="urlInput"
422
+ placeholder="Digite as URLs do Douyin (uma por linha)&#10;Exemplo: https://www.douyin.com/video/7123456789012345678&#10;Exemplo: https://v.douyin.com/ieABCDEF/"
423
+ class="w-full p-5 border-2 border-gray-200 rounded-xl focus:border-purple-500 focus:outline-none resize-none custom-scrollbar transition-all duration-300 text-gray-700"
424
+ rows="6"></textarea>
425
+ <div class="absolute top-3 right-3">
426
+ <span id="urlCount" class="text-sm text-gray-500 bg-gray-100 px-3 py-1 rounded-full font-medium">0 URLs</span>
427
+ </div>
428
+ </div>
429
+
430
+ <div class="flex gap-3 flex-wrap">
431
+ <button onclick="executeExtraction()"
432
+ class="btn-primary text-white px-8 py-3 rounded-xl font-semibold flex items-center justify-center flex-1 min-w-[200px]">
433
+ <i class="fas fa-bolt mr-2"></i>
434
+ Extrair CDN V3
435
+ </button>
436
+ <button onclick="clearAll()"
437
+ class="px-6 py-3 bg-gray-200 text-gray-700 rounded-xl font-semibold hover:bg-gray-300 transition-all duration-300 flex items-center">
438
+ <i class="fas fa-trash mr-2"></i>
439
+ Limpar
440
+ </button>
441
+ <button onclick="loadSampleUrls()"
442
+ class="px-6 py-3 bg-gradient-to-r from-green-400 to-blue-500 text-white rounded-xl font-semibold hover:from-green-500 hover:to-blue-600 transition-all duration-300 flex items-center">
443
+ <i class="fas fa-magic mr-2"></i>
444
+ Exemplo
445
+ </button>
446
+ <button onclick="createBookmarklet()"
447
+ class="bookmarklet-btn text-white px-6 py-3 rounded-xl font-semibold flex items-center">
448
+ <i class="fas fa-bookmark mr-2"></i>
449
+ Bookmarklet
450
+ </button>
451
+ </div>
452
+ </div>
453
+ </section>
454
+
455
+ <!-- Processing Status -->
456
+ <section id="processingSection" class="hidden mb-8">
457
+ <div class="flex items-center mb-4">
458
+ <div
459
+ class="w-10 h-10 bg-gradient-to-r from-blue-500 to-cyan-500 rounded-lg flex items-center justify-center mr-3">
460
+ <i class="fas fa-cogs text-white process-animation"></i>
461
+ </div>
462
+ <h2 class="text-2xl font-bold text-gray-800">Processando Links V3</h2>
463
+ </div>
464
+ <div id="processingList" class="space-y-3 max-h-96 overflow-y-auto custom-scrollbar"></div>
465
+ </section>
466
+
467
+ <!-- Results Section -->
468
+ <section id="resultsSection" class="hidden">
469
+ <div class="flex items-center justify-between mb-4">
470
+ <div class="flex items-center">
471
+ <div
472
+ class="w-10 h-10 bg-gradient-to-r from-green-500 to-emerald-500 rounded-lg flex items-center justify-center mr-3">
473
+ <i class="fas fa-check-double text-white"></i>
474
+ </div>
475
+ <h2 class="text-2xl font-bold text-gray-800">Links CDN V3 Extraídos</h2>
476
+ </div>
477
+ <div class="flex gap-2">
478
+ <button onclick="downloadAllAsText()"
479
+ class="px-4 py-2 bg-blue-100 text-blue-700 rounded-lg font-semibold hover:bg-blue-200 transition-all duration-300 flex items-center">
480
+ <i class="fas fa-file-download mr-2"></i>
481
+ Salvar Links
482
+ </button>
483
+ <button onclick="copyAllResults()"
484
+ class="px-4 py-2 bg-green-100 text-green-700 rounded-lg font-semibold hover:bg-green-200 transition-all duration-300 flex items-center">
485
+ <i class="fas fa-copy mr-2"></i>
486
+ Copiar Tudo
487
+ </button>
488
+ </div>
489
+ </div>
490
+
491
+ <div class="bg-gradient-to-br from-gray-50 to-gray-100 rounded-xl p-6">
492
+ <ol id="resultsList" class="space-y-4 custom-scrollbar max-h-[600px] overflow-y-auto"></ol>
493
+ </div>
494
+ </section>
495
+
496
+ <!-- JavaScript Function Display -->
497
+ <section class="mt-8">
498
+ <div class="direct-link rounded-xl p-6">
499
+ <div class="flex items-center mb-3">
500
+ <i class="fas fa-code text-purple-600 text-xl mr-3"></i>
501
+ <h3 class="text-lg font-bold text-gray-800">Script de Extração V3 - CDN Direta</h3>
502
+ </div>
503
+ <div class="script-view p-4 rounded-lg overflow-x-auto text-xs">
504
+ <pre><span class="comment">// Script exato para extração V3 com redirecionamento</span>
505
+ <span class="keyword">javascript:</span>(<span class="keyword">function</span>(){
506
+ <span class="keyword">const</span> u=window.location.href.<span class="function">split</span>(<span class="string">'?'</span>)[<span class="number">0</span>];
507
+ <span class="keyword">const</span> vid=<span class="keyword">new</span> <span class="function">URLSearchParams</span>(window.location.search).<span class="function">get</span>(<span class="string">'modal_id'</span>);
508
+ <span class="keyword">const</span> targetUrl=vid?<span class="string">`https://www.douyin.com/video/</span><span class="function">${vid}</span><span class="string">`</span>:u;
509
+ <span class="keyword">const</span> hash=<span class="function">btoa</span>(targetUrl)+(targetUrl.length+<span class="number">1000</span>)+<span class="function">btoa</span>(<span class="string">'aio-dl'</span>);
510
+
511
+ <span class="function">console</span>.<span class="function">log</span>(<span class="string">"🚀 Extraindo link real da CDN..."</span>);
512
+
513
+ <span class="function">fetch</span>(<span class="string">'https://snapdouyin.app/wp-json/mx-downloader/video-data/'</span>, {
514
+ method: <span class="string">'POST'</span>,
515
+ headers: {<span class="string">'Content-Type'</span>:<span class="string">'application/x-www-form-urlencoded'</span>},
516
+ body: <span class="string">`url=</span><span class="function">${encodeURIComponent(targetUrl)}</span><span class="string">&hash=</span><span class="function">${hash}</span><span class="string">`</span>
517
+ })
518
+ .<span class="function">then</span>(r => r.<span class="function">json</span>())
519
+ .<span class="function">then</span>(data => {
520
+ <span class="keyword">if</span>(data.medias && data.medias.length > <span class="number">0</span>) {
521
+ <span class="comment">/* Pega a melhor qualidade (Original) */</span>
522
+ <span class="keyword">let</span> best = data.medias.<span class="function">find</span>(m => m.quality === <span class="string">'original'</span>) || data.medias[<span class="number">0</span>];
523
+ <span class="keyword">let</span> phpLink = best.url;
524
+
525
+ <span class="comment">/* Segue o rastro do link V3 */</span>
526
+ <span class="function">console</span>.<span class="function">log</span>(<span class="string">"🔗 Seguindo rastro do link V3..."</span>);
527
+ window.location.href = phpLink;
528
+ }
529
+ })
530
+ .<span class="function">catch</span>(e => {
531
+ <span class="comment">/* Fallback caso o fetch seja bloqueado */</span>
532
+ <span class="function">alert</span>(<span class="string">"Clique OK para gerar o link final na página do Snap."</span>);
533
+ window.<span class="function">open</span>(<span class="string">`https://snapdouyin.app/#url=</span><span class="function">${encodeURIComponent(targetUrl)}</span><span class="string">`</span>,<span class="string">'_blank'</span>);
534
+ });
535
+ })();</pre>
536
+ </div>
537
+ <div class="mt-3 p-3 bg-pink-50 rounded-lg">
538
+ <p class="text-sm text-pink-700">
539
+ <i class="fas fa-bolt mr-2"></i>
540
+ Redirecionamento automático para URL final da CDN V3
541
+ </p>
542
+ </div>
543
+ </div>
544
+ </section>
545
+ </main>
546
+
547
+ <!-- Footer -->
548
+ <footer class="text-center mt-10 text-white/80">
549
+ <p class="text-sm">
550
+ <i class="fas fa-server mr-2"></i>
551
+ Links V3 Diretos da CDN | Redirecionamento Automático | Qualidade Original
552
+ </p>
553
+ </footer>
554
+ </div>
555
+
556
+ <script>
557
+ let extractedLinks = [];
558
+
559
+ // Update URL count
560
+ document.getElementById('urlInput').addEventListener('input', function() {
561
+ const urls = this.value.split('\n').filter(url => url.trim());
562
+ document.getElementById('urlCount').textContent = `${urls.length} URLs`;
563
+ });
564
+
565
+ // Load sample URLs
566
+ function loadSampleUrls() {
567
+ const sampleUrls = [
568
+ 'https://v.douyin.com/ie2dGKkT/',
569
+ 'https://www.douyin.com/video/7300000000000000000',
570
+ 'https://v.douyin.com/ie1ABCDEF/'
571
+ ];
572
+ document.getElementById('urlInput').value = sampleUrls.join('\n');
573
+ document.getElementById('urlCount').textContent = `${sampleUrls.length} URLs`;
574
+ showNotification('URLs de exemplo carregadas', 'success');
575
+ }
576
+
577
+ // Clear all
578
+ function clearAll() {
579
+ document.getElementById('urlInput').value = '';
580
+ document.getElementById('urlCount').textContent = '0 URLs';
581
+ document.getElementById('processingSection').classList.add('hidden');
582
+ document.getElementById('resultsSection').classList.add('hidden');
583
+ extractedLinks = [];
584
+ showNotification('Todos os campos foram limpos', 'success');
585
+ }
586
+
587
+ // Create bookmarklet
588
+ function createBookmarklet() {
589
+ const bookmarkletCode = `javascript:(function(){
590
+ const u=window.location.href.split('?')[0];
591
+ const vid=new URLSearchParams(window.location.search).get('modal_id');
592
+ const targetUrl=vid? \`https://www.douyin.com/video/\${vid}\`:u;
593
+ const hash=btoa(targetUrl)+(targetUrl.length+1000)+btoa('aio-dl');
594
+
595
+ console.log("🚀 Extraindo link real da CDN...");
596
+
597
+ fetch('https://snapdouyin.app/wp-json/mx-downloader/video-data/', {
598
+ method: 'POST',
599
+ headers: {'Content-Type':'application/x-www-form-urlencoded'},
600
+ body: \`url=\${encodeURIComponent(targetUrl)}&hash=\${hash}\`
601
+ })
602
+ .then(r => r.json())
603
+ .then(data => {
604
+ if(data.medias && data.medias.length > 0) {
605
+ let best = data.medias.find(m => m.quality === 'original') || data.medias[0];
606
+ let phpLink = best.url;
607
+
608
+ console.log("🔗 Seguindo rastro do link V3...");
609
+ window.location.href = phpLink;
610
+ }
611
+ })
612
+ .catch(e => {
613
+ alert("Clique OK para gerar o link final na página do Snap.");
614
+ window.open(\`https://snapdouyin.app/#url=\${encodeURIComponent(targetUrl)}\`,'_blank');
615
+ });
616
+ })();`;
617
+
618
+ navigator.clipboard.writeText(bookmarkletCode).then(() => {
619
+ showNotification('Bookmarklet copiado! Arraste para sua barra de favoritos', 'success');
620
+ }).catch(() => {
621
+ showNotification('Não foi possível copiar o bookmarklet', 'error');
622
+ });
623
+ }
624
+
625
+ // Execute extraction
626
+ async function executeExtraction() {
627
+ const input = document.getElementById('urlInput').value;
628
+ const urls = input.split('\n').filter(url => url.trim());
629
+
630
+ if (urls.length === 0) {
631
+ showNotification('Por favor, insira pelo menos uma URL do Douyin', 'error');
632
+ return;
633
+ }
634
+
635
+ // Show processing section
636
+ document.getElementById('processingSection').classList.remove('hidden');
637
+ document.getElementById('processingList').innerHTML = '';
638
+ document.getElementById('resultsSection').classList.add('hidden');
639
+
640
+ extractedLinks = [];
641
+
642
+ // Process each URL
643
+ for (let i = 0; i < urls.length; i++) {
644
+ const url = urls[i].trim();
645
+ await extractV3Link(url, i + 1);
646
+ }
647
+
648
+ // Show results
649
+ showResults();
650
+ }
651
+
652
+ // Extract V3 link following the exact pattern
653
+ async function extractV3Link(url, index) {
654
+ // Create processing container
655
+ const processingContainer = document.createElement('div');
656
+ processingContainer.className = 'url-line bg-white p-4 rounded-lg border border-gray-200 shadow-sm mb-3';
657
+
658
+ document.getElementById('processingList').appendChild(processingContainer);
659
+
660
+ try {
661
+ // Step 1: Preparação
662
+ addProcessingStep(processingContainer, '🚀 Extraindo link real da CDN...', 'info');
663
+ await sleep(500);
664
+
665
+ // Step 2: Process URL (exactly like the script)
666
+ addProcessingStep(processingContainer, '📝 Processando URL e gerando hash...', 'info');
667
+
668
+ const u = url.split('?')[0];
669
+ const urlParams = new URLSearchParams(url.split('?')[1] || '');
670
+ const vid = urlParams.get('modal_id');
671
+ const targetUrl = vid ? `https://www.douyin.com/video/${vid}` : u;
672
+ const hash = btoa(targetUrl) + (targetUrl.length + 1000) + btoa('aio-dl');
673
+
674
+ await sleep(500);
675
+ addProcessingStep(processingContainer, '🔗 Conectando ao servidor...', 'info');
676
+
677
+ // Step 3: Fetch video data
678
+ const response = await fetch('https://snapdouyin.app/wp-json/mx-downloader/video-data/', {
679
+ method: 'POST',
680
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
681
+ body: `url=${encodeURIComponent(targetUrl)}&hash=${hash}`
682
+ });
683
+
684
+ const data = await response.json();
685
+
686
+ if (!data.medias || data.medias.length === 0) {
687
+ throw new Error('Nenhuma mídia encontrada');
688
+ }
689
+
690
+ await sleep(500);
691
+ addProcessingStep(processingContainer, '🎯 Buscando melhor qualidade (Original)...', 'info');
692
+
693
+ // Step 4: Find best quality (exactly like the script)
694
+ let best = data.medias.find(m => m.quality === 'original') || data.medias[0];
695
+ let phpLink = best.url;
696
+
697
+ await sleep(500);
698
+ addProcessingStep(processingContainer, '🔍 Seguindo rastro do link V3...', 'info');
699
+
700
+ // Step 5: Get final V3 URL (follow redirect)
701
+ const headResponse = await fetch(phpLink, {
702
+ method: 'HEAD',
703
+ redirect: 'follow'
704
+ });
705
+
706
+ let finalV3 = headResponse.url;
707
+
708
+ await sleep(500);
709
+
710
+ // Success!
711
+ addProcessingStep(processingContainer, '✅ Link V3 final obtido!', 'success');
712
+
713
+ extractedLinks.push({
714
+ originalUrl: url,
715
+ v3Url: finalV3,
716
+ index: index,
717
+ title: data.title || 'Vídeo Douyin',
718
+ quality: best.quality || 'original'
719
+ });
720
+
721
+ // Update container to success state
722
+ setTimeout(() => {
723
+ processingContainer.className = 'url-line bg-gradient-to-r from-green-50 to-emerald-50 p-4 rounded-lg border-2 border-green-300 shadow-md mb-3';
724
+ processingContainer.innerHTML = `
725
+ <div class="flex items-center justify-between mb-2">
726
+ <div class="flex items-center">
727
+ <div class="w-8 h-8 bg-green-500 rounded-full flex items-center justify-center mr-3">
728
+ <i class="fas fa-check text-white text-sm"></i>
729
+ </div>
730
+ <div>
731
+ <span class="text-sm font-bold text-gray-800">Link V3 ${index} - Extraído!</span>
732
+ <div class="text-xs text-gray-600">Redirecionamento CDN | Qualidade: ${extractedLinks[index-1].quality}</div>
733
+ </div>
734
+ </div>
735
+ <div class="cdn-badge">
736
+ <i class="fas fa-server mr-1"></i>CDN V3
737
+ </div>
738
+ </div>
739
+ <div class="space-y-1">
740
+ <div class="processing-step step-success">🚀 Link real da CDN extraído</div>
741
+ <div class="processing-step step-success">📝 URL processada e hash gerado</div>
742
+ <div class="processing-step step-success">🔗 Conectado ao servidor</div>
743
+ <div class="processing-step step-success">🎯 Qualidade original encontrada</div>
744
+ <div class="processing-step step-success">🔍 Rastro do link V3 seguido</div>
745
+ <div class="console-log console-success">✅ Link V3 final obtido!</div>
746
+ </div>
747
+ `;
748
+ }, 500);
749
+
750
+ } catch (error) {
751
+ addProcessingStep(processingContainer, `❌ Erro: ${error.message}`, 'error');
752
+
753
+ // Update container to error state
754
+ processingContainer.className = 'url-line bg-gradient-to-r from-red-50 to-pink-50 p-4 rounded-lg border-2 border-red-300 shadow-md mb-3';
755
+ processingContainer.innerHTML = `
756
+ <div class="flex items-center justify-between mb-2">
757
+ <div class="flex items-center">
758
+ <div class="w-8 h-8 bg-red-500 rounded-full flex items-center justify-center mr-3">
759
+ <i class="fas fa-times text-white text-sm"></i>
760
+ </div>
761
+ <div>
762
+ <span class="text-sm font-bold text-gray-800">URL ${index} - Falha</span>
763
+ <div class="text-xs text-gray-600">Não foi possível extrair o link V3</div>
764
+ </div>
765
+ </div>
766
+ <div class="error-badge text-xs">Erro</div>
767
+ </div>
768
+ <div class="console-log console-error">❌ Erro: ${error.message}</div>
769
+ `;
770
+ }
771
+ }
772
+
773
+ // Add processing step
774
+ function addProcessingStep(container, message, type) {
775
+ const step = document.createElement('div');
776
+ const stepClass = type === 'success' ? 'step-success' :
777
+ type === 'error' ? 'step-error' : '';
778
+ step.className = `processing-step ${stepClass}`;
779
+ step.textContent = message;
780
+ container.appendChild(step);
781
+ container.scrollTop = container.scrollHeight;
782
+ }
783
+
784
+ // Sleep helper
785
+ function sleep(ms) {
786
+ return new Promise(resolve => setTimeout(resolve, ms));
787
+ }
788
+
789
+ // Show results
790
+ function showResults() {
791
+ if (extractedLinks.length === 0) {
792
+ showNotification('Nenhum link V3 foi extraído', 'error');
793
+ return;
794
+ }
795
+
796
+ document.getElementById('resultsSection').classList.remove('hidden');
797
+ const resultsList = document.getElementById('resultsList');
798
+ resultsList.innerHTML = '';
799
+
800
+ extractedLinks.forEach((item, index) => {
801
+ const li = document.createElement('li');
802
+ li.className = 'result-item bg-white p-5 rounded-xl border-2 border-gray-200 hover:border-purple-300';
803
+ li.innerHTML = `
804
+ <div class="flex items-start">
805
+ <span class="result-number mr-4">${item.index}</span>
806
+ <div class="flex-1">
807
+ <div class="video-info mb-3">
808
+ <div class="flex items-center justify-between mb-2">
809
+ <h4 class="font-semibold text-gray-800">${item.title}</h4>
810
+ <div class="flex gap-2">
811
+ <span class="cdn-badge">
812
+ <i class="fas fa-server mr-1"></i>CDN V3
813
+ </span>
814
+ </div>
815
+ </div>
816
+ <div class="text-xs text-gray-500">
817
+ <i class="fas fa-link mr-1"></i>
818
+ Fonte: ${item.originalUrl}
819
+ <span class="ml-3">
820
+ <i class="fas fa-video mr-1"></i>
821
+ Qualidade: ${item.quality}
822
+ </span>
823
+ </div>
824
+ </div>
825
+
826
+ <div class="space-y-3">
827
+ <div>
828
+ <span class="v3-header">
829
+ <i class="fas fa-bolt mr-1"></i>LINK CDN V3 DIRETO
830
+ </span>
831
+ <div class="v3-url">
832
+ ${item.v3Url}
833
+ </div>
834
+ </div>
835
+ </div>
836
+ </div>
837
+ <div class="flex flex-col gap-2 ml-4">
838
+ <button onclick="downloadVideo('${item.v3Url}', '${item.title}')"
839
+ class="download-btn px-3 py-2 text-white rounded-lg text-xs font-semibold flex items-center"
840
+ title="Baixar vídeo">
841
+ <i class="fas fa-download mr-1"></i>
842
+ Download
843
+ </button>
844
+ <button onclick="copySingleUrl('${item.v3Url}', this)"
845
+ class="copy-btn px-3 py-2 bg-gray-100 text-gray-700 rounded-lg text-xs font-semibold flex items-center"
846
+ title="Copiar URL">
847
+ <i class="fas fa-copy mr-1"></i>
848
+ Copiar
849
+ </button>
850
+ <button onclick="openInNewTab('${item.v3Url}')"
851
+ class="px-3 py-2 bg-purple-100 text-purple-700 rounded-lg text-xs font-semibold flex items-center hover:bg-purple-200 transition-colors