From c4db969f0fefa06b997b7c064e358b91e22a5bd1 Mon Sep 17 00:00:00 2001 From: Daffa Maulana Satria Date: Sat, 26 Apr 2025 16:42:50 +0700 Subject: [PATCH] feat : added dowload all button Info : 1. FE only 2. Changed anchor from _blank to direct href 3. still using only second link (the first one is error idk) --- frontend/css/styles_global.css | 5 - frontend/css/styles_mobile.css | 40 +++++- frontend/javascript/script.js | 215 ++++++++++++++++++++++++++++++--- index.html | 7 +- 4 files changed, 236 insertions(+), 31 deletions(-) diff --git a/frontend/css/styles_global.css b/frontend/css/styles_global.css index 7cdd034..3ee6f98 100644 --- a/frontend/css/styles_global.css +++ b/frontend/css/styles_global.css @@ -84,9 +84,4 @@ body { .container-input button:active { background-color: #6470ce; -} - -.download-button:hover, -.stream-button:hover { - filter: brightness(95%); } \ No newline at end of file diff --git a/frontend/css/styles_mobile.css b/frontend/css/styles_mobile.css index c903b72..ebd39fa 100644 --- a/frontend/css/styles_mobile.css +++ b/frontend/css/styles_mobile.css @@ -190,7 +190,6 @@ } /* Result */ - .container-result { width: 100%; height: 100vh; @@ -219,24 +218,26 @@ border: none; border-radius: 8px; height: 100px; - width: 100%; - max-width: 449px; - min-width: 209px; + max-width: 500px; transition: all 0.3s ease; + flex: auto; display: flex; flex-direction: column; overflow: hidden; - flex-shrink: 0; + align-items: center; + justify-items: center; } .container-item-default { height: 100px; width: 100%; - flex-shrink: 0; + flex: auto; display: flex; flex-direction: row; position: relative; overflow: hidden; + align-items: center; + justify-content: center; } .container-image { @@ -338,6 +339,33 @@ border: solid 1px #a2adff; } +.download-all-button { + width: 100%; + font-size: 12px; + padding-bottom: 6px; + padding-top: 6px; + color: #7a88f7; + background-color: white; + border: solid 1px #a2adff; + border-radius: 4px; +} + +.download-button:hover, +.stream-button:hover { + filter: brightness(95%); +} + +.download-all-container.inactive { + display: none; +} + +.download-all-warning { + font-size: 0.8em; + color: #bd2a2f; + margin-top: 8px; + display: block; +} + .stream-button { width: 100%; font-size: 10px; diff --git a/frontend/javascript/script.js b/frontend/javascript/script.js index 42051f2..6793662 100644 --- a/frontend/javascript/script.js +++ b/frontend/javascript/script.js @@ -1,4 +1,5 @@ -// Global +// Global variables +const box_result = document.getElementById('result'); const api = 'http://127.0.0.1:5000'; // Change This // const api = 'https://teradl-api.dapuntaratya.com'; // Change This @@ -24,6 +25,13 @@ submitButton.addEventListener('click', (event) => { readInput(url); }); +// HTML template for the Download All container +const downloadAllContainerHTML = ` +
+ + Note: This downloads all files individually. Please allow multiple downloads in your browser if prompted. +
`; + // Loading Spinner 1 function loading(element_id, active) { const loadingBox = document.getElementById(element_id); @@ -109,7 +117,7 @@ async function readInput(raw_url) { stream_box.innerHTML = ''; stream_box.className = 'stream-video-section inactive' - document.getElementById('result').innerHTML = ''; + clearResult(); // Clear previous results, including the old button container loading('submit_button', true); await fetchURL(url); loading('submit_button', false); @@ -137,30 +145,56 @@ async function fetchURL(url) { 'body' : JSON.stringify({'url':url, 'mode':mode}) }; - const req = await fetch(get_file_url, data); - const response = await req.json(); + try { + const req = await fetch(get_file_url, data); + const response = await req.json(); - if (response.status == 'success') { - params = {uk:response.uk, shareid:response.shareid, timestamp:response.timestamp, sign:response.sign, js_token:response.js_token, cookie:response.cookie}; - await sortFile(response.list); - } + if (response.status == 'success') { + // Clear previous results and add the button container structure first + clearResult(); + box_result.innerHTML = downloadAllContainerHTML; + addDownloadAllEventListener(); // Re-attach listener after adding the button + + // Now process and display the files + params = response; + await sortFile(response.list); + + // Show the button container *if* files were actually added by sortFile + const fileItems = box_result.querySelectorAll('.container-item'); + const downloadAllContainer = document.getElementById('download-all-container'); + if (fileItems.length > 0 && downloadAllContainer) { + downloadAllContainer.classList.remove('inactive'); + } else if (downloadAllContainer) { + downloadAllContainer.classList.add('inactive'); + } + } - else { - loading('submit_button', false); - inputForm.value = ''; + else { + errorFetch(); + } + } catch (error) { errorFetch(); } } // Error Fetch function errorFetch() { - const box_result = document.getElementById('result'); + clearResult(); box_result.innerHTML = ` -
- Fetch Failed +
+ Fetch Failed
`; } +// Clear Result +function clearResult() { + box_result.innerHTML = ''; + + const streamSection = document.getElementById('stream-video'); + streamSection.innerHTML = ''; + streamSection.classList.add('inactive'); +} + // Sort File Recursively async function sortFile(list_file) { list_file.forEach((item) => { @@ -171,10 +205,12 @@ async function sortFile(list_file) { // Show Item async function printItem(item) { - const box_result = document.getElementById('result'); const new_element = document.createElement('div'); new_element.id = `file-${item.fs_id}`; new_element.className = 'container-item'; + if (item.link) { + new_element.dataset.dlink = item.link; + } new_element.innerHTML = `
@@ -247,7 +283,7 @@ async function initDownload(fs_id, dlink=null) { new_element.setAttribute('value',value); box_button.appendChild(new_element); - new_element.addEventListener('click', () => startDownload(new_element.value)); + new_element.addEventListener('click', () => startDownload(new_element.value)); // Keep this for individual buttons }); } @@ -257,11 +293,18 @@ async function initDownload(fs_id, dlink=null) { } // Start Download -function startDownload(url) { +function startDownload(url, filename = '') { // Optional filename parameter const anchor = document.createElement('a'); anchor.href = url; - anchor.target = '_blank'; // JANGAN gunakan anchor.download di sini! + + // this case is for multiple download, so that the browser will not open many new tab (biar ga open new tab banyak) + // anchor.target = '_blank'; + + // can be used to set custom filename + anchor.download = filename || ''; // Use provided filename or empty string -> banh ini kyknya ga masalah? soalnya butuh buat download semua + + // Append, click, remove is still necessary to trigger the download document.body.appendChild(anchor); anchor.click(); document.body.removeChild(anchor); @@ -287,7 +330,6 @@ async function initStream(fs_id, dlink=null) { // Get URL Stream async function getURLStream(fs_id, dlink=null) { - let param; try { @@ -318,6 +360,141 @@ async function getURLStream(fs_id, dlink=null) { catch {return('');} } +// Get and Start Download All) +async function getAndStartDownload(fs_id, dlink = null, linkPreference = 'url_2', filename = '') { // Added filename parameter + console.log(`Attempting to get link for fs_id: ${fs_id}`); + let param; + if (dlink && mode === 2) { // Mode 2 uses provided dlink + param = {'url': dlink, 'mode': mode}; + } else if (mode === 1 || mode === 3) { // Mode 1 and 3 need params + if (!params || Object.keys(params).length === 0) { + console.error("Global params not set for mode 1 or 3."); + return; + } + param = {...params, 'fs_id': fs_id, 'mode': mode}; + } else { + console.error(`Invalid mode (${mode}) or missing dlink for mode 2.`); + return; + } + + const get_link_url = `${api}/generate_link`; + const headers = {'Content-Type': 'application/json'}; + const data = { + 'method': 'POST', + 'mode': 'cors', + 'headers': headers, + 'body': JSON.stringify(param) + }; + + try { + const req = await fetch(get_link_url, data); + const response = await req.json(); + + if (response.status == 'success' && response.download_link) { + const links = response.download_link; + let urlToDownload = null; + + if (linkPreference === 'url_2' && links.url_2) { + urlToDownload = links.url_2; + } else if (links.url_1) { + urlToDownload = links.url_1; // Fallback to url_1 + } else if (links.url_2) { + urlToDownload = links.url_2; // Use url_2 if url_1 wasn't available but url_2 is + } else if (links.url_3) { + urlToDownload = links.url_3; // Fallback further if needed + } + + + if (urlToDownload) { + console.log(`Starting download for fs_id: ${fs_id} using URL: ${urlToDownload}`); + startDownload(urlToDownload, filename); + await sleep(0.5); // Delay 500ms + } else { + console.error(`No suitable download link found for fs_id: ${fs_id}`); + } + } else { + console.error(`Failed to get download link for fs_id: ${fs_id}. Status: ${response.status}, Message: ${response.message || 'No message'}`); + } + } catch (error) { + console.error(`Error fetching download link for fs_id: ${fs_id}:`, error); + } +} + + +// Initialization for Download All +async function initDownloadAll(linkPreference = 'url_2') { + const downloadAllButton = document.getElementById('download-all-button'); + if (downloadAllButton) { + downloadAllButton.disabled = true; + downloadAllButton.innerText = 'Downloading...'; + } + + const fileItems = box_result.querySelectorAll('.container-item'); + console.log(`Found ${fileItems.length} file items to download.`); + + if (fileItems.length === 0) { + console.log("No files found to download."); + if (downloadAllButton) { + downloadAllButton.disabled = false; + downloadAllButton.innerText = 'Download All'; + } + return; + } + + // Check if params are needed and available for modes 1 or 3 + if ((mode === 1 || mode === 3) && (!params || Object.keys(params).length === 0)) { + console.error("Cannot start 'Download All': Required parameters (uk, shareid, etc.) are missing."); + alert("Error: Could not retrieve necessary information to start downloads. Please try fetching the file list again."); + if (downloadAllButton) { + downloadAllButton.disabled = false; + downloadAllButton.innerText = 'Download All'; + } + return; + } + + + for (const item of fileItems) { + const fs_id = item.id.replace('file-', ''); + let dlink = null; + + if (mode === 2) { + dlink = item.dataset.dlink; + if (!dlink) { + console.warn(`Could not find dlink for fs_id: ${fs_id} in mode 2. Skipping this file.`); + continue; + } + } + + const titleSpan = item.querySelector('.title'); + const filename = titleSpan ? titleSpan.innerText : ''; + + await getAndStartDownload(fs_id, dlink, linkPreference, filename); + } + + console.log("Finished attempting to download all files."); + if (downloadAllButton) { + downloadAllButton.disabled = false; + downloadAllButton.innerText = 'Download All'; + } +} + +// Function to add the event listener +function addDownloadAllEventListener() { + const downloadAllButton = document.getElementById('download-all-button'); + if (downloadAllButton) { + // Remove existing listener first to prevent duplicates if called multiple times + downloadAllButton.replaceWith(downloadAllButton.cloneNode(true)); + // Get the new clone and add the listener + const newButton = document.getElementById('download-all-button'); + if (newButton) { + newButton.addEventListener('click', () => { + initDownloadAll('url_2'); // Default url_2 yg pertama masih error banh + }); + } + } +} + + // Change status color function changeStatus(mode) { const status_box = document.getElementById('status-mode'); diff --git a/index.html b/index.html index af47f39..19621be 100644 --- a/index.html +++ b/index.html @@ -70,7 +70,12 @@
-
+
+ +
+ +
+