Created
July 22, 2022 22:13
-
-
Save ssimono/48e90b28775deee3e7f2e34a3f1337e1 to your computer and use it in GitHub Desktop.
Export the expenses of a Splittypie event into CSV. Runs on the browser only.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Usage: Copy this entire snippet and paste it into the developer console. | |
* A link will appear on the top just above the event title (on Desktop view). | |
* Just click it to get a CSV containing the expenses. | |
* | |
* Please double-check the result as this is made via frontend scrapping and | |
* can therefore miss edge cases or break upon future changes in the document | |
* structure. | |
*/ | |
function collect() { | |
const selectors = Object.entries({ | |
month: '.month', | |
day: '.day', | |
creditor: '.transaction-list-item-description strong', | |
subject: '.transaction-list-item-description em', | |
participants: '.transaction-list-item-description small', | |
amount: '.transaction-list-item-amount strong', | |
}); | |
const expenses = []; | |
let year = undefined; | |
for (let div of document.querySelectorAll('.transaction-list-item')) { | |
const previousSibling = div.previousElementSibling; | |
if (previousSibling.classList.contains('transaction-list-date')) { | |
const yearStr = previousSibling.querySelector('strong').innerText; | |
year = parseInt(yearStr.replace(/^\D*/g, ''), 10); | |
} | |
const expense = Object.fromEntries(selectors.map(([field, selector]) => | |
[field, div.querySelector(selector)?.innerText?.trim()] | |
)); | |
const timestamp = Date.parse(`${expense.month} ${expense.day} ${year}`); | |
const date = Number.isNaN(timestamp) | |
? null | |
: new Date(timestamp).toISOString().substring(0, 10); | |
if (!expense.participants && /settled up/i.test(div.innerText)) { | |
expense.subject = 'Settled up'; | |
expense.participants = div.querySelector('strong:last-child').innerText.trim(); | |
} | |
expenses.push({ | |
creditor: expense.creditor, | |
subject: expense.subject, | |
participants: expense.participants?.split(/\s*,\s*/).join('/'), | |
date, | |
amount: parseFloat(expense.amount), | |
}); | |
} | |
return expenses; | |
} | |
const link = document.createElement('a'); | |
document.querySelector('main .container').prepend(link); | |
link.innerText = 'Scrapping…'; | |
const csvFields = ['creditor', 'subject', 'participants', 'date', 'amount']; | |
const csvData = [csvFields]; | |
for(let expense of collect()) { | |
csvData.push(csvFields.map(f => expense[f])); | |
} | |
const url = window.URL.createObjectURL(new Blob([csvData.join('\n')], { type: 'text/csv' })); | |
link.setAttribute('href', url); | |
link.innerText = 'Download expenses as CSV'; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See tsubik/splittypie#16