From 3a171c92e13c40cd8c53276199882074c1e05208 Mon Sep 17 00:00:00 2001 From: Igor Katson Date: Mon, 20 Nov 2023 22:22:46 +0000 Subject: [PATCH] Webui getting better --- crates/librqbit/webui/app.ts | 70 +++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/crates/librqbit/webui/app.ts b/crates/librqbit/webui/app.ts index db38354..59b04ab 100644 --- a/crates/librqbit/webui/app.ts +++ b/crates/librqbit/webui/app.ts @@ -101,61 +101,75 @@ async function getTorrentStats(index: number): Promise { } // Display function for listing all torrents with concise information (async/await) -async function displayTorrents(): Promise { +async function displayTorrents() { try { const response = await makeRequest('GET', '/torrents'); - const torrents: Torrent[] = response.torrents; + const torrents = response.torrents; // Create a container for all torrents using Bootstrap classes const torrentsContainer = document.createElement('div'); + torrentsContainer.id = 'torrents-container'; torrentsContainer.classList.add('d-flex', 'flex-column', 'torrents-container'); - for (const torrent of torrents) { - const detailsResponse = await getTorrentDetails(torrent.id); - const statsResponse = await getTorrentStats(torrent.id); + // Map to store existing elements + const existingElementsMap = new Map(); - const totalBytes = detailsResponse.files.reduce((total: number, file: any) => total + file.length, 0); + // Array to hold promises for torrent details and stats + const promises = torrents.map(async (torrent) => { + const detailsPromise = getTorrentDetails(torrent.id); + const statsPromise = getTorrentStats(torrent.id); + const [detailsResponse, statsResponse] = await Promise.all([detailsPromise, statsPromise]); + + const totalBytes = detailsResponse.files.reduce((total, file) => total + file.length, 0); const downloadedBytes = statsResponse.snapshot.have_bytes; // Calculate download percentage const downloadPercentage = (downloadedBytes / totalBytes) * 100; - // Create a container for each torrent using Bootstrap classes - const torrentContainer = document.createElement('div'); - torrentContainer.classList.add('torrent-container', 'd-flex', 'flex-row', 'p-3', 'bg-light', 'rounded', 'mb-3'); + // Check if the torrent container already exists + let torrentContainer = existingElementsMap.get(torrent.id); + + if (!torrentContainer) { + torrentContainer = document.createElement('div'); + torrentContainer.id = `torrent-${torrent.id}`; + torrentContainer.classList.add('torrent-container', 'd-flex', 'flex-row', 'p-3', 'bg-light', 'rounded', 'mb-3'); + existingElementsMap.set(torrent.id, torrentContainer); + } // Display basic information about the torrent const largestFileName = getLargestFileName(detailsResponse); const downloadSpeed = statsResponse.download_speed.human_readable; const eta = getCompletionETA(statsResponse); - // Create and append divs for concise information as columns - const nameColumn = createColumn('Name', largestFileName); - const sizeColumn = createColumn('Size', `${formatBytesToGB(totalBytes)} GB`); - const progressColumn = createColumnWithProgressBar('Progress', downloadPercentage); - const downloadSpeedColumn = createColumn('Download Speed', downloadSpeed); - const etaColumn = createColumn('ETA', eta); - - // Append columns to the torrent container - torrentContainer.appendChild(nameColumn); - torrentContainer.appendChild(sizeColumn); - torrentContainer.appendChild(progressColumn); - torrentContainer.appendChild(downloadSpeedColumn); - torrentContainer.appendChild(etaColumn); + // Update or append columns to the torrent container + torrentContainer.innerHTML = ''; // Clear existing content + torrentContainer.appendChild(createColumn('Name', largestFileName, 'name-column')); + torrentContainer.appendChild(createColumn('Size', `${formatBytesToGB(totalBytes)} GB`, 'size-column')); + torrentContainer.appendChild(createColumnWithProgressBar('Progress', downloadPercentage, 'progress-column')); + torrentContainer.appendChild(createColumn('Download Speed', downloadSpeed, 'download-speed-column')); + torrentContainer.appendChild(createColumn('ETA', eta, 'eta-column')); // Append the torrent container to the torrentsContainer torrentsContainer.appendChild(torrentContainer); - } + }); - // Replace the old content with the new one - const outputDiv = document.getElementById('output'); - outputDiv.innerHTML = ''; - outputDiv.appendChild(torrentsContainer); + // Replace the old content with loading spinners + const outputDiv = document.getElementById('output') || document.createElement('div'); + outputDiv.id = 'output'; + outputDiv.innerHTML = `
Loading...
`; + + // Wait for all promises to resolve + await Promise.all(promises); + + // Replace the loading spinners with the new content + outputDiv.replaceChildren(torrentsContainer); } catch (error) { console.error(error); + // Handle errors as needed } } + // Function to create a column div function createColumn(label: string, value: string): HTMLDivElement { const columnDiv = document.createElement('div'); @@ -224,7 +238,7 @@ function clearErrorAlert(): void { async function init(): Promise { try { await displayTorrents(); - autoRefreshTorrents(5000); // Set the interval (in milliseconds), e.g., 5000 for every 5 seconds + autoRefreshTorrents(500); // Set the interval (in milliseconds), e.g., 5000 for every 5 seconds } catch (error) { console.error(error); }