Skip to content

Instantly share code, notes, and snippets.

@trungdq88
Last active April 6, 2023 14:07
Show Gist options
  • Save trungdq88/6c9de42a87a24446a630cec59ece845e to your computer and use it in GitHub Desktop.
Save trungdq88/6c9de42a87a24446a630cec59ece845e to your computer and use it in GitHub Desktop.
A scriptable's script to get Paddle revenue from multiple accounts using puppeteer.
/*
RUN THE SCRIPT BY YOURSELF:
- Run `node paddle-revenue.js` on your server and let it run 24/7.
- Access the API at http://your_server_ip:8175/ (JSON)
HOSTED VERSION:
If you don't want to run the script by your own, you can use the
hosted version. The price is $5 per month per Paddle account.
Here is how:
1. Go to Paddle dashboard → Business Account → Team Members.
2. Invite "paddle-bot-{your_vendor_id}@tdinh.me" to your Paddle
team. Replace the {your_vendor_id} with your paddle vendor ID,
for example, if your vendor ID is 811502, use the email
[email protected] for the invitation. Make sure to set
the permission as "Finance" so that the account only have access
to reports and revenue.
3. Ping me via Twitter @tdinh_me to make payment, then I will
set up the bot for you.
4. After the bot has been set up, you can access the JSON data
by sending a request to https://tdinh.me/paddle-bot/{your_vendor_id}
License for this code: MIT
*/
const puppeteer = require('puppeteer');
const fs = require('fs');
async function getRevenue({ username, password }) {
const browser = await puppeteer.launch({
headless: true,
});
console.log(new Date(), username, 'Browser launched');
const page = await browser.newPage();
try {
await page.goto('https://vendors.paddle.com/');
console.log(new Date(), username, 'Page loaded');
// wait for page to finish loading
await page.waitForSelector('[type=email]', { visible: true });
// Enter username
await page.type('[type=email]', username);
// Enter password
await page.type('[type=password]', password);
// Click login
await page.click('[type=submit]');
console.log(new Date(), username, 'Logged in');
// Wait for the element with class big-num to show up and have content
await page.waitForSelector('.financial-stats', { visible: true });
// get the element with the big-num class
const element = await page.$('.financial-stats');
console.log(new Date(), username, 'Got element');
// get element's text
let value = (await page.evaluate((el) => el.textContent, element))
.trim()
.replace('BalanceUS', '');
console.log(new Date(), username, 'Got text', value);
await browser.close();
return value;
} catch (e) {
console.error(new Date(), 'failed', e);
// take screenshot
await page.screenshot({ path: 'error.png' });
}
}
async function start() {
const devutils = await getRevenue({
username: 'account1',
password: 'password1',
});
const xnapper = await getRevenue({
username: 'account2',
password: 'password2',
});
const blackmagic = await getRevenue({
username: 'acccount3',
password: 'password3',
});
const data = { devutils, xnapper, blackmagic, updated: new Date() };
console.log(new Date(), 'result', data);
// write to file
fs.writeFileSync('data.json', JSON.stringify(data));
}
// http server to serve the data.json file
const PORT = 8175;
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'application/json' });
try {
res.end(fs.readFileSync('data.json'));
} catch (e) {
console.error(e);
res.end(JSON.stringify({ error: 'uh oh' }));
}
});
server.listen(PORT);
// run the script every 5 minutes
setInterval(start, 1000 * 60 * 5);
start();
// Use this script in the Scriptable app (https://scriptable.app/)
// data
let url = "http://your_host_ip:8175/"
let r = new Request(url)
let json = await r.loadJSON()
let minutesAgo = Math.round((Date.now() - new Date(json.updated).getTime()) / 1000 / 60)
// UI
const w = new ListWidget()
const now = new Date()
getwidget("DevUtils", 13, "#888888")
getwidget(json.devutils, 18, "#63ca56")
w.addSpacer(6)
getwidget("Black Magic", 13, "#888888")
getwidget(json.blackmagic, 18, "")
w.addSpacer(6)
getwidget("Xnapper", 13, "#888888")
getwidget(json.xnapper, 18, "#964eea")
w.addSpacer(6)
getwidget("Updated: " + minutesAgo + "m ago", 10, "#888888")
Script.setWidget(w)
Script.complete()
w.presentMedium()
function getwidget(value, size, color) {
const titlew = w.addText(value)
if (color) { titlew.textColor = new Color(color) }
titlew.font = Font.boldSystemFont(size || 13)
}
@trungdq88
Copy link
Author

@vasco3 you shouldn't use this with your main account. Invite a new team member without 2FA and with the Financial role.

@vasco3
Copy link

vasco3 commented Sep 8, 2022

@trungdq88 ok I see! great idea 💯

my only concern would be that https://scriptable.app would insert a backdoor by giving them so much access to my phone

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