eubottura commited on
Commit
619a990
Β·
verified Β·
1 Parent(s): 7f11231

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +107 -69
index.html CHANGED
@@ -326,6 +326,20 @@
326
  color: var(--error);
327
  }
328
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
329
  @keyframes fadeInDown {
330
  from {
331
  opacity: 0;
@@ -422,6 +436,16 @@
422
  color: var(--text-secondary);
423
  }
424
 
 
 
 
 
 
 
 
 
 
 
425
  @media (max-width: 768px) {
426
  .container {
427
  padding: 1rem;
@@ -462,8 +486,14 @@
462
  </header>
463
 
464
  <main class="main-card">
 
 
 
 
 
465
  <div class="info-box">
466
- πŸ“Œ <strong>Processing Logic:</strong> Extracts modal_id, generates API hash, sorts by size (largest first), and returns the V3 download link. Falls back to snapdouyin.app if CORS error occurs.
 
467
  </div>
468
 
469
  <section class="input-section">
@@ -481,9 +511,11 @@
481
 
482
  <div class="loading" id="loading">
483
  <div class="spinner"></div>
484
- <p>πŸš€ Searching for highest bitrate (Default 106MB)...</p>
485
  </div>
486
 
 
 
487
  <section class="results-section" id="resultsSection">
488
  <div class="results-header">
489
  <h2 class="results-title">Download Links <span class="status-indicator success"></span></h2>
@@ -495,18 +527,18 @@
495
  </div>
496
 
497
  <script>
498
- // Base64 encoding function (same as btoa in browser)
499
  function base64Encode(str) {
500
  return btoa(unescape(encodeURIComponent(str)));
501
  }
502
 
503
- // URL encoding function (same as encodeURIComponent)
504
  function urlEncode(str) {
505
  return encodeURIComponent(str);
506
  }
507
 
508
  // Process a single URL following the exact JavaScript logic
509
- function processSingleUrl(inputUrl) {
510
  try {
511
  console.log(`πŸ” Processing: ${inputUrl}`);
512
 
@@ -526,27 +558,40 @@
526
 
527
  console.log(`πŸ” Generated hash: ${hash.substring(0, 50)}...`);
528
 
529
- // Step d: Simulate API call to snapdouyin.app endpoint
530
  const endpoint = 'https://snapdouyin.app/wp-json/mx-downloader/video-data/';
531
  const requestBody = `url=${urlEncode(targetUrl)}&hash=${hash}`;
532
 
533
- console.log(`πŸ“‘ Simulating POST to: ${endpoint}`);
534
  console.log(`πŸ“¦ Body: ${requestBody.substring(0, 100)}...`);
535
 
536
- // Simulate API response with realistic V3 download links
537
- const mockResponse = simulateApiResponse(targetUrl);
 
 
 
 
 
 
 
 
 
 
 
 
 
538
 
539
  // Step e: Check if medias array exists
540
- if (mockResponse.medias && mockResponse.medias.length > 0) {
541
- console.log(`βœ… Found ${mockResponse.medias.length} media options`);
542
 
543
  // Step f: Sort medias by size in descending order (largest first)
544
- const sortedMedias = mockResponse.medias.sort((a, b) => (b.size || 0) - (a.size || 0));
545
 
546
  // Step f: Get the first (largest) media
547
  const absoluteBest = sortedMedias[0];
548
 
549
- console.log(`πŸ† Best media: ${absoluteBest.formattedSize} (${absoluteBest.size} bytes)`);
550
 
551
  // Step g: Extract the download URL (V3 link)
552
  const downloadUrl = absoluteBest.url;
@@ -557,8 +602,8 @@
557
  return {
558
  url: downloadUrl,
559
  size: absoluteBest.size,
560
- formattedSize: absoluteBest.formattedSize,
561
- quality: absoluteBest.quality,
562
  isV3: true
563
  };
564
  } else {
@@ -583,79 +628,54 @@
583
 
584
  return {
585
  url: fallbackUrl,
586
- isFallback: true
 
587
  };
588
  }
589
  }
590
 
591
- // Simulate API response with realistic V3 download links
592
- function simulateApiResponse(targetUrl) {
593
- // Generate a unique video ID from the target URL
594
- const videoId = targetUrl.split('/').pop().split('?')[0] || Date.now();
595
-
596
- // Create realistic media options with different sizes
597
- const medias = [
598
- {
599
- url: `https://v3-dy-o.zjcdn.com/${videoId}_1080p.mp4?expires=${Date.now() + 3600000}&sign=mock_signature`,
600
- size: 106000000, // 106MB - highest quality
601
- formattedSize: "106.0 MB",
602
- quality: "1080p",
603
- type: "video/mp4"
604
- },
605
- {
606
- url: `https://v3-dy-o.zjcdn.com/${videoId}_720p.mp4?expires=${Date.now() + 3600000}&sign=mock_signature`,
607
- size: 56000000, // 56MB
608
- formattedSize: "56.0 MB",
609
- quality: "720p",
610
- type: "video/mp4"
611
- },
612
- {
613
- url: `https://v3-dy-o.zjcdn.com/${videoId}_480p.mp4?expires=${Date.now() + 3600000}&sign=mock_signature`,
614
- size: 28000000, // 28MB
615
- formattedSize: "28.0 MB",
616
- quality: "480p",
617
- type: "video/mp4"
618
- }
619
- ];
620
-
621
- return {
622
- success: true,
623
- medias: medias,
624
- title: `Douyin Video ${videoId}`,
625
- thumbnail: `https://p3.douyinpic.com/img/${videoId}~c5_100x100.jpeg`
626
- };
627
- }
628
-
629
  // Process all URLs
630
- function processUrls() {
631
  const input = document.getElementById('urlInput').value.trim();
632
  if (!input) {
633
- alert('Please enter at least one Douyin URL');
634
  return;
635
  }
636
 
637
  const urls = input.split('\n').filter(url => url.trim());
638
  if (urls.length === 0) {
639
- alert('Please enter valid URLs');
640
  return;
641
  }
642
 
 
 
 
643
  // Show loading
644
  document.getElementById('loading').classList.add('show');
645
  document.getElementById('resultsSection').classList.remove('show');
646
 
647
- // Simulate processing delay
648
- setTimeout(() => {
649
- const results = [];
650
- urls.forEach(url => {
651
- const result = processSingleUrl(url.trim());
 
 
652
  results.push(result);
653
- });
 
 
 
 
 
 
 
 
654
 
655
- // Hide loading and show results
656
- document.getElementById('loading').classList.remove('show');
657
- displayResults(results);
658
- }, 1500);
659
  }
660
 
661
  // Display results with enhanced UI
@@ -685,7 +705,7 @@
685
  li.innerHTML = `
686
  <div class="${urlContentClass}">${result.url}</div>
687
  ${qualityBadge}
688
- <button class="copy-btn" onclick="copyUrl('${result.url}', this)">Copy</button>
689
  <span class="status-indicator ${isFallback ? 'fallback' : 'success'}"></span>
690
  `;
691
 
@@ -704,6 +724,8 @@
704
  button.textContent = 'Copy';
705
  button.classList.remove('copied');
706
  }, 2000);
 
 
707
  });
708
  }
709
 
@@ -721,6 +743,8 @@
721
  button.textContent = originalText;
722
  button.style.background = '';
723
  }, 2000);
 
 
724
  });
725
  }
726
 
@@ -728,6 +752,7 @@
728
  function clearInput() {
729
  document.getElementById('urlInput').value = '';
730
  document.getElementById('resultsSection').classList.remove('show');
 
731
  }
732
 
733
  // Load sample URLs
@@ -738,6 +763,19 @@ https://www.douyin.com/user/987654321?modal_id=7123456789012345678`;
738
  document.getElementById('urlInput').value = sampleUrls;
739
  }
740
 
 
 
 
 
 
 
 
 
 
 
 
 
 
741
  // Add enter key support for processing
742
  document.getElementById('urlInput').addEventListener('keydown', function(e) {
743
  if (e.ctrlKey && e.key === 'Enter') {
@@ -747,7 +785,7 @@ https://www.douyin.com/user/987654321?modal_id=7123456789012345678`;
747
 
748
  // Console log for debugging
749
  console.log('πŸš€ Douyin Video Download Link Processor Ready');
750
- console.log('πŸ“ Processing logic initialized following the bookmarklet algorithm');
751
  </script>
752
  </body>
753
 
 
326
  color: var(--error);
327
  }
328
 
329
+ .error-message {
330
+ background: rgba(248, 113, 113, 0.1);
331
+ border: 1px solid rgba(248, 113, 113, 0.3);
332
+ border-radius: 10px;
333
+ padding: 1rem;
334
+ margin-top: 1rem;
335
+ color: var(--error);
336
+ display: none;
337
+ }
338
+
339
+ .error-message.show {
340
+ display: block;
341
+ }
342
+
343
  @keyframes fadeInDown {
344
  from {
345
  opacity: 0;
 
436
  color: var(--text-secondary);
437
  }
438
 
439
+ .cors-notice {
440
+ background: rgba(251, 191, 36, 0.1);
441
+ border: 1px solid rgba(251, 191, 36, 0.3);
442
+ border-radius: 10px;
443
+ padding: 1rem;
444
+ margin-bottom: 1.5rem;
445
+ font-size: 0.9rem;
446
+ color: var(--warning);
447
+ }
448
+
449
  @media (max-width: 768px) {
450
  .container {
451
  padding: 1rem;
 
486
  </header>
487
 
488
  <main class="main-card">
489
+ <div class="cors-notice">
490
+ ⚠️ <strong>CORS Notice:</strong> Due to browser security restrictions, direct API calls may be blocked. The app will
491
+ automatically use fallback URLs when CORS errors occur.
492
+ </div>
493
+
494
  <div class="info-box">
495
+ πŸ“Œ <strong>Processing Logic:</strong> Extracts modal_id, generates API hash, sorts by size (largest first), and
496
+ returns the V3 download link. Falls back to snapdouyin.app if CORS error occurs.
497
  </div>
498
 
499
  <section class="input-section">
 
511
 
512
  <div class="loading" id="loading">
513
  <div class="spinner"></div>
514
+ <p>πŸš€ Processing URLs...</p>
515
  </div>
516
 
517
+ <div class="error-message" id="errorMessage"></div>
518
+
519
  <section class="results-section" id="resultsSection">
520
  <div class="results-header">
521
  <h2 class="results-title">Download Links <span class="status-indicator success"></span></h2>
 
527
  </div>
528
 
529
  <script>
530
+ // Base64 encoding function
531
  function base64Encode(str) {
532
  return btoa(unescape(encodeURIComponent(str)));
533
  }
534
 
535
+ // URL encoding function
536
  function urlEncode(str) {
537
  return encodeURIComponent(str);
538
  }
539
 
540
  // Process a single URL following the exact JavaScript logic
541
+ async function processSingleUrl(inputUrl) {
542
  try {
543
  console.log(`πŸ” Processing: ${inputUrl}`);
544
 
 
558
 
559
  console.log(`πŸ” Generated hash: ${hash.substring(0, 50)}...`);
560
 
561
+ // Step d: Make real API call to snapdouyin.app endpoint
562
  const endpoint = 'https://snapdouyin.app/wp-json/mx-downloader/video-data/';
563
  const requestBody = `url=${urlEncode(targetUrl)}&hash=${hash}`;
564
 
565
+ console.log(`πŸ“‘ Making POST to: ${endpoint}`);
566
  console.log(`πŸ“¦ Body: ${requestBody.substring(0, 100)}...`);
567
 
568
+ // Make the actual fetch request
569
+ const response = await fetch(endpoint, {
570
+ method: 'POST',
571
+ headers: {
572
+ 'Content-Type': 'application/x-www-form-urlencoded',
573
+ },
574
+ body: requestBody
575
+ });
576
+
577
+ if (!response.ok) {
578
+ throw new Error(`HTTP error! status: ${response.status}`);
579
+ }
580
+
581
+ const data = await response.json();
582
+ console.log(`βœ… API Response received:`, data);
583
 
584
  // Step e: Check if medias array exists
585
+ if (data.medias && data.medias.length > 0) {
586
+ console.log(`βœ… Found ${data.medias.length} media options`);
587
 
588
  // Step f: Sort medias by size in descending order (largest first)
589
+ const sortedMedias = data.medias.sort((a, b) => (b.size || 0) - (a.size || 0));
590
 
591
  // Step f: Get the first (largest) media
592
  const absoluteBest = sortedMedias[0];
593
 
594
+ console.log(`πŸ† Best media: ${absoluteBest.formattedSize || (absoluteBest.size + ' bytes')}`);
595
 
596
  // Step g: Extract the download URL (V3 link)
597
  const downloadUrl = absoluteBest.url;
 
602
  return {
603
  url: downloadUrl,
604
  size: absoluteBest.size,
605
+ formattedSize: absoluteBest.formattedSize || (absoluteBest.size ? `${(absoluteBest.size / 1000000).toFixed(1)} MB` : 'Unknown'),
606
+ quality: absoluteBest.quality || 'Unknown',
607
  isV3: true
608
  };
609
  } else {
 
628
 
629
  return {
630
  url: fallbackUrl,
631
+ isFallback: true,
632
+ error: error.message
633
  };
634
  }
635
  }
636
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
637
  // Process all URLs
638
+ async function processUrls() {
639
  const input = document.getElementById('urlInput').value.trim();
640
  if (!input) {
641
+ showError('Please enter at least one Douyin URL');
642
  return;
643
  }
644
 
645
  const urls = input.split('\n').filter(url => url.trim());
646
  if (urls.length === 0) {
647
+ showError('Please enter valid URLs');
648
  return;
649
  }
650
 
651
+ // Hide error message
652
+ hideError();
653
+
654
  // Show loading
655
  document.getElementById('loading').classList.add('show');
656
  document.getElementById('resultsSection').classList.remove('show');
657
 
658
+ const results = [];
659
+
660
+ // Process URLs sequentially
661
+ for (let i = 0; i < urls.length; i++) {
662
+ const url = urls[i].trim();
663
+ try {
664
+ const result = await processSingleUrl(url);
665
  results.push(result);
666
+ } catch (error) {
667
+ console.error(`Failed to process URL ${i + 1}:`, error);
668
+ results.push({
669
+ url: `https://snapdouyin.app/#url=${urlEncode(url)}`,
670
+ isFallback: true,
671
+ error: error.message
672
+ });
673
+ }
674
+ }
675
 
676
+ // Hide loading and show results
677
+ document.getElementById('loading').classList.remove('show');
678
+ displayResults(results);
 
679
  }
680
 
681
  // Display results with enhanced UI
 
705
  li.innerHTML = `
706
  <div class="${urlContentClass}">${result.url}</div>
707
  ${qualityBadge}
708
+ <button class="copy-btn" onclick="copyUrl('${result.url.replace(/'/g, "\\'")}', this)">Copy</button>
709
  <span class="status-indicator ${isFallback ? 'fallback' : 'success'}"></span>
710
  `;
711
 
 
724
  button.textContent = 'Copy';
725
  button.classList.remove('copied');
726
  }, 2000);
727
+ }).catch(err => {
728
+ console.error('Failed to copy:', err);
729
  });
730
  }
731
 
 
743
  button.textContent = originalText;
744
  button.style.background = '';
745
  }, 2000);
746
+ }).catch(err => {
747
+ console.error('Failed to copy all:', err);
748
  });
749
  }
750
 
 
752
  function clearInput() {
753
  document.getElementById('urlInput').value = '';
754
  document.getElementById('resultsSection').classList.remove('show');
755
+ hideError();
756
  }
757
 
758
  // Load sample URLs
 
763
  document.getElementById('urlInput').value = sampleUrls;
764
  }
765
 
766
+ // Show error message
767
+ function showError(message) {
768
+ const errorElement = document.getElementById('errorMessage');
769
+ errorElement.textContent = message;
770
+ errorElement.classList.add('show');
771
+ }
772
+
773
+ // Hide error message
774
+ function hideError() {
775
+ const errorElement = document.getElementById('errorMessage');
776
+ errorElement.classList.remove('show');
777
+ }
778
+
779
  // Add enter key support for processing
780
  document.getElementById('urlInput').addEventListener('keydown', function(e) {
781
  if (e.ctrlKey && e.key === 'Enter') {
 
785
 
786
  // Console log for debugging
787
  console.log('πŸš€ Douyin Video Download Link Processor Ready');
788
+ console.log('πŸ“ Processing logic initialized - Making real API calls to snapdouyin.app');
789
  </script>
790
  </body>
791