Initial commit: banking statement download scripts
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
// =============================================================================
|
||||
// MyCard Statement Download Helper (mycard.com.au)
|
||||
// =============================================================================
|
||||
// PASTE + ENTER, then click statement rows normally.
|
||||
// The blob tab still opens (just close it), BUT you also get a properly
|
||||
// named PDF saved automatically.
|
||||
//
|
||||
// TO STOP: just refresh the page (F5)
|
||||
// =============================================================================
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
if (window._mcStatementHelper) {
|
||||
if (window._mcOrigWindowOpen) window.open = window._mcOrigWindowOpen;
|
||||
console.log('🔄 Restarting MyCard helper...');
|
||||
}
|
||||
window._mcStatementHelper = true;
|
||||
|
||||
let downloadCount = 0;
|
||||
let lastClickedDate = null;
|
||||
const downloadedSet = new Set();
|
||||
|
||||
const monthNames = ['', 'January', 'February', 'March', 'April', 'May', 'June',
|
||||
'July', 'August', 'September', 'October', 'November', 'December'];
|
||||
|
||||
function extractDate(text) {
|
||||
const m = text.match(/(\d{1,2})\s+(January|February|March|April|May|June|July|August|September|October|November|December)\s+(\d{4})/);
|
||||
if (!m) return null;
|
||||
const monthNum = new Date(`${m[2]} 1, 2000`).getMonth() + 1;
|
||||
return { year: m[3], monthNum: String(monthNum).padStart(2, '0'), monthName: m[2] };
|
||||
}
|
||||
|
||||
// Click events compose through shadow DOM — use composedPath() to read inner elements
|
||||
document.addEventListener('click', function (e) {
|
||||
const path = e.composedPath();
|
||||
for (const el of path) {
|
||||
if (!(el instanceof HTMLElement)) continue;
|
||||
// Search this element and its children for <p> with a date
|
||||
const paragraphs = el.querySelectorAll ? el.querySelectorAll('p') : [];
|
||||
for (const p of paragraphs) {
|
||||
const date = extractDate(p.textContent.trim());
|
||||
if (date) {
|
||||
lastClickedDate = date;
|
||||
console.log(`⏳ MyCard-Statement-${date.year}-${date.monthNum}-${date.monthName}.pdf...`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
|
||||
// Also try mousedown with composedPath
|
||||
document.addEventListener('mousedown', function (e) {
|
||||
const path = e.composedPath();
|
||||
for (const el of path) {
|
||||
if (!(el instanceof HTMLElement)) continue;
|
||||
const paragraphs = el.querySelectorAll ? el.querySelectorAll('p') : [];
|
||||
for (const p of paragraphs) {
|
||||
const date = extractDate(p.textContent.trim());
|
||||
if (date) {
|
||||
lastClickedDate = date;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
|
||||
// Search all shadow roots for dates (fallback)
|
||||
function findDateInShadowDom() {
|
||||
function searchNode(node) {
|
||||
if (node.shadowRoot) {
|
||||
const ps = node.shadowRoot.querySelectorAll('p');
|
||||
for (const p of ps) {
|
||||
const date = extractDate(p.textContent.trim());
|
||||
if (date) return date;
|
||||
}
|
||||
for (const child of node.shadowRoot.querySelectorAll('*')) {
|
||||
const result = searchNode(child);
|
||||
if (result) return result;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
for (const el of document.querySelectorAll('*')) {
|
||||
const result = searchNode(el);
|
||||
if (result) return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function savePdf(blob, filename) {
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url; a.download = filename;
|
||||
document.body.appendChild(a); a.click(); document.body.removeChild(a);
|
||||
setTimeout(() => URL.revokeObjectURL(url), 2000);
|
||||
}
|
||||
|
||||
// Intercept window.open — fetch blob URL and save as named PDF
|
||||
const origWindowOpen = window._mcOrigWindowOpen || window.open;
|
||||
window._mcOrigWindowOpen = origWindowOpen;
|
||||
window.open = function (url, ...rest) {
|
||||
const win = origWindowOpen.call(this, url, ...rest);
|
||||
|
||||
if (typeof url === 'string' && url.startsWith('blob:')) {
|
||||
if (downloadedSet.has(url)) return win;
|
||||
downloadedSet.add(url);
|
||||
setTimeout(() => downloadedSet.delete(url), 5000);
|
||||
|
||||
// Try click-tracked date, then shadow DOM scan
|
||||
const date = lastClickedDate || findDateInShadowDom();
|
||||
|
||||
fetch(url)
|
||||
.then(r => r.blob())
|
||||
.then(blob => {
|
||||
return blob.slice(0, 5).text().then(h => {
|
||||
if (h !== '%PDF-') return;
|
||||
let fn;
|
||||
if (date) {
|
||||
fn = `MyCard-Statement-${date.year}-${date.monthNum}-${date.monthName}.pdf`;
|
||||
} else {
|
||||
fn = `MyCard-Statement-${Date.now()}.pdf`;
|
||||
}
|
||||
savePdf(blob, fn);
|
||||
downloadCount++;
|
||||
console.log(`✅ #${downloadCount} ${fn} (${(blob.size / 1024).toFixed(0)} KB)`);
|
||||
console.log(` Close the blob tab, then click next statement.`);
|
||||
});
|
||||
})
|
||||
.catch(err => console.error('❌ Failed:', err));
|
||||
}
|
||||
|
||||
return win;
|
||||
};
|
||||
|
||||
console.log('');
|
||||
console.log('✅ MyCard download helper active!');
|
||||
console.log('👆 Click statement rows normally.');
|
||||
console.log(' Each click: PDF saves as file + blob tab opens (close it).');
|
||||
console.log(' To stop: refresh (F5)');
|
||||
console.log('');
|
||||
})();
|
||||
Reference in New Issue
Block a user