I wouldn’t mind seeing a button that let’s me get a CSV of the upgrade finder results. Something like itemId,itemName,upgradePercent,isOwned. I’m using the results from askMrRobot in a google sheet that calculates what soft reserves in different raids are most worth selecting (based on droprate, # of other ppl soft ressing the item, and how big of an upgrade the item is worth ←- this part uses AMR).
Note that if column values are separated by \t instead of by commas (and rows separated by \n), then copy-pasting the results into google sheets automagically separates the results out into multiple columns & rows.
It doesn’t need to download a file, just copying the CSV to my clipboard or showing a text box to copy the CSV would suffice.
I came up with the following script that I paste into console after doing an upgrade finder, which does what I want by just looking at the results of the HTML and making a button on the page that will copy the CSV to my clipboard for me, but I figure something similar native in the web app could be useful:
(() => {
const container = document.querySelector('#panelUpgList');
if (!container) {
alert('❌ No #panelUpgList found');
return;
}
const rows = Array.from(container.querySelectorAll(':scope > .o-upg-item'));
const data = rows.map(row => {
const name = row.querySelector('.name')?.textContent.trim() || '';
const raw = row.querySelector('.score')?.textContent.replace(/\s|%/g, '') || '';
const score = parseFloat(raw);
return { name, score: Number.isFinite(score) ? score : 0, owned: raw === "Owned" };
}).filter(r => r.name);
const csv = ['Item Name\tScore\tOwned']
.concat(data.map(r => `${r.name}\t${r.score}%\t${r.owned}`))
.join('\n');
const btn = document.createElement('button');
btn.textContent = `Copy ${data.length} rows as TSV`;
btn.style.cssText = `
position: fixed; top: 10px; right: 10px; z-index: 99999;
padding: 8px 12px; font-size: 14px; border: 1px solid #888;
background: #222; color: #fff; border-radius: 4px; cursor: pointer;
`;
document.body.appendChild(btn);
btn.onclick = async () => {
await navigator.clipboard.writeText(csv);
btn.textContent = "✅ Copied as TSV!";
setTimeout(() => btn.remove(), 1500);
};
console.log(`✅ TSV ready: ${data.length} rows`);
console.log(csv);
})();
(() => {
const container = document.querySelector('#panelUpgList');
if (!container) {
alert('❌ No #panelUpgList found');
return;
}
const rows = Array.from(container.querySelectorAll(':scope > .o-upg-item'));
const data = rows.map(row => {
const name = row.querySelector('.name')?.textContent.trim() || '';
const raw = row.querySelector('.score')?.textContent.replace(/\s|%/g, '') || '';
const score = parseFloat(raw);
return { name, score: Number.isFinite(score) ? score : 0, owned: raw === "Owned" };
}).filter(r => r.name);
const csv = ['Item Name\tScore\tOwned']
.concat(data.map(r => `${r.name}\t${r.score}%\t${r.owned}`))
.join('\n');
const btn = document.createElement('button');
btn.textContent = `Copy ${data.length} rows as TSV`;
btn.style.cssText = `
position: fixed; top: 10px; right: 10px; z-index: 99999;
padding: 8px 12px; font-size: 14px; border: 1px solid #888;
background: #222; color: #fff; border-radius: 4px; cursor: pointer;
`;
document.body.appendChild(btn);
btn.onclick = async () => {
await navigator.clipboard.writeText(csv);
btn.textContent = "✅ Copied as TSV!";
setTimeout(() => btn.remove(), 1500);
};
console.log(`✅ TSV ready: ${data.length} rows`);
console.log(csv);
})();