PageSourceSearch

https://www.toolsfinity.io/assets/js/tools/video-downloader.js

js toolsfinity.io collected 2026-10-02 01:58:11 UTC 4,773 bytes, 114 lines download raw bytes

1document.addEventListener('DOMContentLoaded', () => {
2  const urlInput       = document.getElementById('video-url');
3  const downloadBtn    = document.getElementById('download-btn');
4  const errorBox       = document.getElementById('error-box');
5  const loadingBox     = document.getElementById('loading-box');
6  const resultBox      = document.getElementById('result-box');
7  const resultThumb    = document.getElementById('result-thumb');
8  const resultTitle    = document.getElementById('result-title');
9  const resultAuthor   = document.getElementById('result-author');
10  const resultBadge    = document.getElementById('result-badge');
11  const linksContainer = document.getElementById('links-container');
12
13  const hideAll = () => {
14    errorBox.classList.add('hidden');
15    loadingBox.classList.add('hidden');
16    resultBox.classList.add('hidden');
17  };
18
19  // ── Build a single download button ─────────────────────────────
20  const makeLink = (label, href) => {
21    const a = document.createElement('a');
22    a.href   = href;
23    a.target = '_blank';
24    a.rel    = 'noopener noreferrer';
25    a.className =
26      'flex items-center justify-between p-3 bg-surface border border-border ' +
27      'hover:border-accent rounded-lg text-xs font-semibold hover:bg-border/30 transition-colors';
28    a.innerHTML = `
29      <span>${label}</span>
30      <svg class="w-4 h-4 text-accent shrink-0" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
31        <path stroke-linecap="round" stroke-linejoin="round" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
32      </svg>`;
33    return a;
34  };
35
36  downloadBtn.addEventListener('click', async () => {
37    const videoUrl = urlInput.value.trim();
38    hideAll();
39
40    if (!videoUrl) {
41      errorBox.textContent = 'Please paste a valid video URL.';
42      errorBox.classList.remove('hidden');
43      return;
44    }
45
46    loadingBox.classList.remove('hidden');
47    downloadBtn.disabled = true;
48
49    try {
50      // API expects GET with url as query parameter
51      const proxyUrl = url(`/tools/api-proxy/video-downloader.php?url=${encodeURIComponent(videoUrl)}`);
52      const response = await fetch(proxyUrl);
53      const resData  = await response.json();
54
55      if (!resData.success) {
56        throw new Error(resData.error || 'Failed to retrieve download links. Check the URL and try again.');
57      }
58
59      const info = resData.mediaInfo;
60
61      // ── Fill metadata ─────────────────────────────────────────
62      resultTitle.textContent  = info.title  || 'Video Download';
63      // author field from API, fallback to platform label
64      const authorLabel = info.author || info.authorName || info.creator || '';
65      resultAuthor.textContent = authorLabel ? `By ${authorLabel}` : (info.platform ? info.platform : '');
66      resultBadge.textContent  = info.platform || 'Video';
67
68      // thumbnail or coverImage (both present in real API response)
69      const thumbSrc = info.thumbnail || info.coverImage || '';
70      if (thumbSrc) {
71        resultThumb.src = thumbSrc;
72        resultThumb.classList.remove('hidden');
73      } else {
74        resultThumb.classList.add('hidden');
75      }
76
77      // ── Build download links ──────────────────────────────────
78      linksContainer.innerHTML = '';
79
80      // qualities[] array (multiple resolutions — may be null)
81      if (Array.isArray(info.qualities) && info.qualities.length > 0) {
82        info.qualities.forEach(q => {
83          if (q.url) {
84            linksContainer.appendChild(makeLink(`Download ${q.quality || 'Video'}`, q.url));
85          }
86        });
87      }
88
89      // Direct videoUrl (present when qualities is null, e.g. YouTube)
90      if (info.videoUrl) {
91        const hasQuality = linksContainer.children.length > 0;
92        linksContainer.appendChild(makeLink(hasQuality ? 'Download Video (Best Quality)' : 'Download Video (MP4)', info.videoUrl));
93      }
94
95      // Audio-only link (MP3)
96      if (info.audioUrl || info.musicUrl || info.downloadMp3) {
97        const audioHref = info.audioUrl || info.musicUrl || info.downloadMp3;
98        linksContainer.appendChild(makeLink('Download Audio Only (MP3)', audioHref));
99      }
100
101      if (linksContainer.children.length === 0) {
102        throw new Error('No download links were found for this video.');
103      }
104
105      resultBox.classList.remove('hidden');
106    } catch (err) {
107      errorBox.textContent = err.message;
108      errorBox.classList.remove('hidden');
109    } finally {
110      loadingBox.classList.add('hidden');
111      downloadBtn.disabled = false;
112    }
113  });
114});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.