Skip to content

Instantly share code, notes, and snippets.

@FoxxMD
Last active March 3, 2024 13:24
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FoxxMD/f3045b4e2c0afe39631c9550bd131133 to your computer and use it in GitHub Desktop.
Save FoxxMD/f3045b4e2c0afe39631c9550bd131133 to your computer and use it in GitHub Desktop.
Qbittorrent get total size, downloaded, uploaded, and overall ratio (WebUI only)
// Tested on qBittorrent 4.6.1
//
// 1. open qbittorent web interface
// 1a. (optionally) filter to just the torrents that should be totalled
// 1b. MAY need to ensure any/all columns to be totalled are enabled -> Size, Downloaded, Uploaded
// 2. open developer tools
// 3. copy and paste the *entirety* of the below code into the developer tools console and hit enter
//
// Will print totals in MiB/GiB/TiB for:
// * Size + Min/Max/Avg
// * Downloaded + % of Size + Min/Max/Avg
// * Uploaded + % of Size + Min/Max/Avg
// and Ratio + Min/Max/Avg
(function() {
const sizeIndex = Array.from(document.querySelector('tr.dynamicTableHeader').childNodes).findIndex(x => x.title === 'Size');
const downloadedIndex = Array.from(document.querySelector('tr.dynamicTableHeader').childNodes).findIndex(x => x.title === 'Downloaded');
const uploadedIndex = Array.from(document.querySelector('tr.dynamicTableHeader').childNodes).findIndex(x => x.title === 'Uploaded');
const ratioIndex = Array.from(document.querySelector('tr.dynamicTableHeader').childNodes).findIndex(x => x.title === 'Ratio');
const tibThreshold = 1048576;
if(sizeIndex === -1 && downloadedIndex === -1 && uploadedIndex === -1) {
console.warn('Must have at least one of the following columns enabled to compute some statistics: Size, Downloaded, Uploaded');
return;
}
const getMibVal = (valueStr, unit) => {
const val = parseFloat(valueStr);
if(val === 0) {
return 0;
}
switch (unit.toLocaleLowerCase()) {
case 'tib':
return val * 1024 * 1024;
case 'gib':
return val * 1024;
case 'mib':
return val;
case 'kib':
return val / 1024;
case 'B':
return val / 1024 / 1024;
}
}
const getTotalBreakdown = (val) => {
return [
`${((val / 1024) / 1024).toLocaleString('en', {maximumFractionDigits: 2})} TiB`,
`${(val / 1024).toLocaleString('en', {maximumFractionDigits: 2})} GiB`,
`${val.toLocaleString('en', {maximumFractionDigits: 2})} MiB`,
].join(' == ');
}
const getHumanSize = (valMib) => {
if(valMib === 0) {
return '0 B';
}
if(valMib < 1) {
return `${(valMib / 1024).toLocaleString('en', {maximumFractionDigits: 2})} KiB`
}
if(valMib >= tibThreshold) {
return `${(valMib / 1024 / 1024).toLocaleString('en', {maximumFractionDigits: 2})} TiB`
}
if(valMib >= 1024) {
return `${(valMib / 1024).toLocaleString('en', {maximumFractionDigits: 2})} GiB`
}
return `${(valMib).toLocaleString('en', {maximumFractionDigits: 2})} MiB`
}
let mibSize = sizeIndex !== -1 ? 0 : null;
let sizeMinMax = [Infinity,0];
let ratio = ratioIndex !== -1 ? 0 : null;
let ratioMinMax = [Infinity,0];
let mibDl = downloadedIndex !== -1 ? 0 : null;
let dlMinMax = [Infinity,0];
let mibUl = uploadedIndex !== -1 ? 0 : null;
let ulMinMax = [Infinity,0];
const elms = document.querySelectorAll('div#torrentsTableDiv tr.torrentsTableContextMenuTarget');
const torNum = elms.length;
elms.forEach((row) => {
if(mibSize !== null) {
const [str, unit] = row.childNodes[sizeIndex].title.split(' ');
const val = getMibVal(str, unit);
mibSize += val;
sizeMinMax = [Math.min(val, sizeMinMax[0]), Math.max(val, sizeMinMax[1])];
}
if(mibDl !== null) {
const [str, unit] = row.childNodes[downloadedIndex].title.split(' ');
const val = getMibVal(str, unit);
mibDl += val;
dlMinMax = [Math.min(val, dlMinMax[0]), Math.max(val, dlMinMax[1])];
}
if(mibDl !== null) {
const [str, unit] = row.childNodes[uploadedIndex].title.split(' ');
const val = getMibVal(str, unit);
mibUl += val;
ulMinMax = [Math.min(val, ulMinMax[0]), Math.max(val, ulMinMax[1])];
}
if(ratio !== null) {
const val = parseFloat(row.childNodes[ratioIndex].title);
ratio += val
ratioMinMax = [Math.min(val, ratioMinMax[0]), Math.max(val, ratioMinMax[1])];
}
});
if(mibSize !== null) {
console.log(`${'Size'.padEnd(11,' ')}: ${getTotalBreakdown(mibSize)} | Min ${getHumanSize(sizeMinMax[0])} | Max ${getHumanSize(sizeMinMax[1])} | Avg ${getHumanSize(mibSize / torNum)}`);
}
if(mibDl !== null) {
const parts = [`${'Downloaded'.padEnd(11,' ')}: ${getTotalBreakdown(mibDl)}`];
if(mibSize !== null) {
parts.push(`${((mibDl / mibSize) * 100).toLocaleString('en', {maximumFractionDigits: 2})}% of Size`);
}
parts.push(`Min ${getHumanSize(dlMinMax[0])} | Max ${getHumanSize(dlMinMax[1])} | Avg ${getHumanSize(mibDl / torNum)}`);
console.log(parts.join(' | '));
}
if(mibUl !== null) {
const parts = [`${'Uploaded'.padEnd(11,' ')}: ${getTotalBreakdown(mibUl)}`];
if(mibSize !== null) {
parts.push(`${((mibUl / mibSize) * 100).toLocaleString('en', {maximumFractionDigits: 2})}% of Size`);
}
parts.push(`Min ${getHumanSize(ulMinMax[0])} | Max ${getHumanSize(ulMinMax[1])} | Avg ${getHumanSize(mibUl / torNum)}`);
console.log(parts.join(' | '));
}
if(mibDl !== null && mibUl !== null) {
const parts = [
`${'Ratio'.padEnd(11,' ')}: ${((mibUl / mibDl)).toLocaleString('en', {maximumFractionDigits: 2})}`,
`Min ${ratioMinMax[0]} | Max ${ratioMinMax[1]} | Avg ${(ratio / torNum).toLocaleString('en', {maximumFractionDigits: 2})}`
];
console.log(parts.join(' | '));
}
})();
@FoxxMD
Copy link
Author

FoxxMD commented Jan 4, 2024

An alternative that displays on the interface (not written by me) here: https://greasyfork.org/en/scripts/483775-calculate-qbittorrent-selected-torrents-size

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment