Skip to content

Instantly share code, notes, and snippets.

@thecodewarrior
Last active April 4, 2021 19:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thecodewarrior/bf48e0f72ba74e801929859a26fd35e4 to your computer and use it in GitHub Desktop.
Save thecodewarrior/bf48e0f72ba74e801929859a26fd35e4 to your computer and use it in GitHub Desktop.
CurseForge download scraper

A scraper to copy the current time and the download counts for various mods in a format suitable for pasting into Google Sheets. To use it, go to the project list page in the author portal and click "Copy Download Counts" in the TamperMonkey menu. The script will then ask for a series of mod page slugs (the ID in the URL) and optionally the special slug author, which loads the author dashboard to get your total download count.

Note! If an error occurs and the script doesn't successfully copy, reload the project list page before trying again. The previous instance of the script will still be waiting for results and so things might occur out of order the next time you try to run it.

The installer URL is https://gist.github.com/thecodewarrior/bf48e0f72ba74e801929859a26fd35e4/raw/CurseForgeDownloadScraper.js

// ==UserScript==
// @name CurseForge mod download scraper
// @namespace http://tampermonkey.net/
// @version 0.2
// @description Scrapes the download count from CurseForge mod pages
// @author You
// @match https://www.curseforge.com/minecraft/mc-mods/*
// @match https://authors.curseforge.com/dashboard
// @match https://authors.curseforge.com/dashboard/projects
// @icon https://www.google.com/s2/favicons?domain=curseforge.com
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_listValues
// @grant GM_deleteValue
// @grant GM_openInTab
// @grant GM_addValueChangeListener
// @grant GM_removeValueChangeListener
// @grant GM_setClipboard
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @downloadURL https://gist.github.com/thecodewarrior/bf48e0f72ba74e801929859a26fd35e4/raw/CurseForgeDownloadScraper.js
// ==/UserScript==
(function() {
'use strict';
function modUrl(slug) {
return slug === 'author' ? 'https://authors.curseforge.com/dashboard' : 'https://www.curseforge.com/minecraft/mc-mods/' + slug
}
function modKey(slug) {
return slug === 'author' ? 'author' : 'mod:' + slug
}
function scrapeModPage() {
let path = window.location.pathname.split('/')
let slug = path[path.length-1]
let candidates = document.querySelectorAll('.w-full.flex.justify-between')
for(let element of candidates) {
let spans = element.querySelectorAll('span')
if(spans.length != 2)
continue
if(spans[0].textContent !== 'Total Downloads')
continue
let downloads = parseInt(spans[1].textContent.replace(/,/g, ''))
console.log(downloads)
GM_setValue(modKey(slug), JSON.stringify({
slug,
downloads
}))
break
}
}
function scrapeDashboard() {
let element = document.querySelector('.e-dashboard-stats .e-tile-count')
let downloads = element.textContent
console.log(downloads)
GM_setValue('author', JSON.stringify({
slug: 'author',
downloads
}))
}
function loadModStats(slug, index) {
return new Promise((resolve, reject) => {
setTimeout(() => {
let tab = GM_openInTab(modUrl(slug))
let listener = GM_addValueChangeListener(modKey(slug), (name, oldValue, newValue, remote) => {
tab.close()
resolve(JSON.parse(newValue))
GM_removeValueChangeListener(listener)
GM_deleteValue(modKey(slug))
})
}, index * 500)
})
}
function launchScrapeManager() {
let input = window.prompt(
'Enter the comma-separated mod slugs (or `author` for the author dashboard)',
GM_getValue('previous-slugs') ?? 'author'
)
GM_setValue('previous-slugs', input)
let slugs = input.split(',').map(it => it.trim())
for(let slug of slugs) {
GM_deleteValue(modKey(slug))
}
Promise.all(slugs.map((slug, index) => loadModStats(slug, index))).then(values => {
let now = new Date().toLocaleString('en-US', { hour12: false }).replace(',', '')
var text = now + "\t" + values.map(it => it.downloads).join('\t')
GM_setClipboard(text)
window.alert('Downloads copied successfully')
})
}
if(window.location.href === 'https://authors.curseforge.com/dashboard/projects') {
GM_registerMenuCommand("Copy download counts", launchScrapeManager);
} else if(window.location.href === 'https://authors.curseforge.com/dashboard') {
scrapeDashboard()
} else {
scrapeModPage()
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment