// Define API URL and base path const apiUrl = window.origin == 'null' ? 'http://localhost:3030' : ''; // Helper function for making API requests (async/await) async function makeRequest(method, path, data) { const url = apiUrl + path; const options = { method, headers: { 'Accept': 'application/json', }, body: data, }; try { const response = await fetch(url, options); if (!response.ok) { const errorBody = await response.text(); try { const json = JSON.parse(errorBody); displayApiError({ status: response.status, statusText: response.statusText, body: json.human_readable !== undefined ? json.human_readable : errorBody, }); } catch (e) { displayApiError({ status: response.status, statusText: response.statusText, body: errorBody, }); } return Promise.reject(errorBody); } const result = await response.json(); return result; } catch (error) { console.error(error); displayApiError({ status: error.status, statusText: error.statusText, body: error.toString(), }); return Promise.reject(`Error: ${error.message}`); } } // Helper function to display the API response function displayResult(result) { const outputDiv = document.getElementById('output'); if (outputDiv) { outputDiv.innerHTML = `
${result}`;
}
}
// Function to get detailed information about a torrent (async/await)
async function getTorrentDetails(index) {
return makeRequest('GET', `/torrents/${index}`);
}
// Function to get detailed statistics about a torrent (async/await)
async function getTorrentStats(index) {
return makeRequest('GET', `/torrents/${index}/stats`);
}
// Display function for listing all torrents with concise information (async/await)
async function displayTorrents() {
try {
const response = await makeRequest('GET', '/torrents');
const torrents = response.torrents;
// Create a container for all torrents using Bootstrap classes
const torrentsContainer = document.createElement('div');
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);
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');
// 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);
// Append the torrent container to the torrentsContainer
torrentsContainer.appendChild(torrentContainer);
}
// Replace the old content with the new one
const outputDiv = document.getElementById('output');
outputDiv.replaceChildren(torrentsContainer);
}
catch (error) {
console.error(error);
}
}
// Function to create a column div
function createColumn(label, value) {
const columnDiv = document.createElement('div');
columnDiv.classList.add('me-3', 'p-2');
columnDiv.innerHTML = `${label}
${value}
`; return columnDiv; } // Function to create a column div with a progress bar function createColumnWithProgressBar(label, percentage) { const columnDiv = document.createElement('div'); columnDiv.classList.add('column', 'me-3', 'p-2'); columnDiv.innerHTML = `${label}
${percentage.toFixed(2)}%
`; return columnDiv; } // Function to format bytes to GB function formatBytesToGB(bytes) { const GB = bytes / (1024 * 1024 * 1024); return GB.toFixed(2); } // Function to get the name of the largest file in a torrent function getLargestFileName(torrentDetails) { const largestFile = torrentDetails.files.reduce((prev, current) => (prev.length > current.length) ? prev : current); return largestFile.name; } // Function to get the completion ETA of a torrent function getCompletionETA(stats) { if (stats.time_remaining) { return stats.time_remaining.human_readable; } else { return 'N/A'; } } // Helper function to display API errors in an alert function displayApiError(error) { const errorAlert = document.getElementById('error-alert'); if (errorAlert) { errorAlert.innerHTML = `