Skip to content

Instantly share code, notes, and snippets.

@abraxas86
Last active April 20, 2025 18:20
Show Gist options
  • Save abraxas86/ad72ba46b6cdd86dc63058bba0c629c2 to your computer and use it in GitHub Desktop.
Save abraxas86/ad72ba46b6cdd86dc63058bba0c629c2 to your computer and use it in GitHub Desktop.
Export collecitons on itch.io as csv files
// ==UserScript==
// @name Itch Collection CSV Exporter
// @namespace https://github.com/abraxas86/tampermonkey-scripts/blob/main/itch.io/
// @version 4.5
// @description Scroll down to the bottom of your collection, click the button, get CSV of your collection!
// @author Abraxas86
// @match https://itch.io/c/*
// @match https://itch.io/my-purchases
// @match https://itch.io/b/*
// @match https://itch.io/bundle/*
// @match https://itch.io/s/*
// @require https://gist.github.com/raw/2625891/waitForKeyElements.js
// @require https://raw.githubusercontent.com/eligrey/FileSaver.js/master/src/FileSaver.js
// @grant none
// @icon https://itch.io//static/images/itchio-square-144.png
// ==/UserScript==
/* globals jQuery, $, waitForKeyElements, saveAs */
(function() {
'use strict';
const games = [];
let mode = "null";
let gameID = "";
let imagePath = "";
let Title = "";
let Synopsis = "";
let Author = "";
let Genre = "";
let URL = "";
let Blurb = "";
let output = "gameid,genre,title,author,synopsis,imagepath,url,blurb\n";
let filename = $('.grid_header > h2:nth-child(1)').text();
if(!filename) {
filename = $('.stat_header_widget .text_container h2 .object_title').text();
}
waitForKeyElements(".game_link", makeRed);
if (document.querySelector('[class*=bundle_download_page]')) {
mode = "bundle";
} else if (document.querySelector('[class*=game_list]')) {
mode = "list";
} else if (document.querySelector('[id^=game_grid]') || document.querySelector('[class*=bundle]')) {
mode = "grid";
} else {
mode = "Error";
}
//alert(mode);
$('.footer').prepend('<span class="csvButton">Export to CSV</span>&nbsp;&nbsp;&nbsp;<input type="text" id="fileName" class="csvText" value=""> <span class="extension">.csv</span><p></p>');
$('#fileName').attr("value", filename);
$('.csvButton').css({'color':'white','background-color':'grey','border-radius':'10px','padding':'15px','cursor':'pointer'});
$('.extension').css({'font-size':'14pt'});
$('.csvText').css({'padding':'5px','border':'none','border-radius':'10px','font-size':'13pt','background-color':'#555555','color':'#BCBCBC','text-align':'right'});
function makeRed() {
$('.game_link').css("color", "red");
}
$('.csvButton').click(function() {
// These elements will mess up our data for the CSV.
$('.price_value').remove();
$('.gif_label').remove();
console.log("======= Game Package Data =======");
// GRID MODE
if (mode == 'grid') {
$('.game_cell').each(function() {
const cell = $(this);
// Itch Game ID
gameID = cell.attr('data-game_id');
console.log("gameID: " + gameID);
// Path to thumbnail
imagePath = cell.find('.lazy_loaded').attr('src');
console.log("imagePath: " + imagePath);
// Game Title Note Note: .title is for bundle compatibility
Title = cell.find('.game_title, .title').text().replace(/"/g, '""');
console.log("Title: " + Title);
// Game URL Note: .title is for bundle compatibility
URL = cell.find('.game_title a, .title').attr('href');
console.log("URL: " + URL);
// Game Synopsis Note: .short_text is for bundle compatibility
Synopsis = cell.find('.game_text, .short_text').text().replace(/"/g, '""');
console.log("Synopsis: " + Synopsis);
// Game Author
Author = cell.find('.game_author, .user_link').text().replace(/"/g, '""');
console.log("Author: " + Author);
// Game Genre
Genre = cell.find('.game_genre').text().replace(/"/g, '""');
console.log("Genre: " + Genre);
// Game Blurb (user-created comment about library item)
Blurb = cell.find('.blurb_drop').text().trim().replace(/"/g, '""');
console.log("Blurb: " + Blurb);
// Build Array to push to CSV File, sanitizing data to prevent commas in scraped data from screwing things up
games.push(`"${gameID}","${Genre}","${Title}","${Author}","${Synopsis}","${imagePath}","${URL}","${Blurb}"`);
});
} else if (mode == 'list') {
$('.game_row').each(function() {
const row = $(this);
// Game Title
Title = row.find('.conversion_link_widget .game_title').text().replace(/"/g, '""');
console.log("Title: " + Title);
// Itch Game ID
gameID = row.find('.game_cell').attr('data-game_id');
console.log("gameID: " + gameID);
// Path to thumbnail
imagePath = row.find('.game_thumb').attr('src');
console.log("imagePath: " + imagePath);
// Game URL
URL = row.find('.game_title').attr('href');
console.log("URL: " + URL);
// Game Synopsis (not avaiable in list mode)
Synopsis = "";
console.log("Synopsis: " + Synopsis);
// Game Author
Author = row.find('.author_link').text().replace(/"/g, '""');
console.log("Author: " + Author);
// Game Genre
Genre = row.find('.game_genre').text().replace(/"/g, '""');
console.log("Genre: " + Genre);
// Game Blurb
Blurb = row.find('.blurb_drop').text().trim().replace(/"/g, '""');
console.log("Blurb: " + Blurb);
// Build Array to push to CSV File, sanitizing data to prevent commas in scraped data from screwing things up
games.push(`"${gameID}","${Genre}","${Title}","${Author}","${Synopsis}","${imagePath}","${URL}","${Blurb}"`);
});
} else if (mode == 'bundle') {
$('.game_row').each(function() {
const row = $(this);
// Path to thumbnail
imagePath = row.find('.game_thumb').attr('data-background_image');
console.log("imagePath: " + imagePath);
// Game URL
URL = row.find('.game_title a').attr('href');
console.log("URL: " + URL);
// Game Title
Title = row.find('.game_title a').text().replace(/"/g, '""');
console.log("Title: " + Title);
// Game Synopsis
Synopsis = row.find('.game_short_text').text().trim().replace(/"/g, '""');
console.log("Synopsis: " + Synopsis);
// Game Author
Author = row.find('.game_author a').text().replace(/"/g, '""');
console.log("Author: " + Author);
// GameID (not available in bundle lists)
gameID = "";
console.log("gameID: " + gameID);
// Game Blurb (not available in bundle lists)
Blurb = "";
console.log("Blurb: " + Blurb);
// Build Array to push to CSV File
games.push(`"${gameID}","${Genre}","${Title}","${Author}","${Synopsis}","${imagePath}","${URL}","${Blurb}"`);
});
} else if (mode == 'bundlegrid') {
$('.game_cell').each(function() {
const cell = $(this);
// Itch Game ID
gameID = cell.attr('data-game_id');
console.log("gameID: " + gameID);
// Path to thumbnail
imagePath = cell.find('.lazy_loaded').attr('src');
console.log("imagePath: " + imagePath);
// Game Title
Title = cell.find('.game_title').text().replace(/"/g, '""');
console.log("Title: " + Title);
// Game URL
URL = cell.find('.game_title a').attr('href');
console.log("URL: " + URL);
// Game Synopsis
Synopsis = cell.find('.game_text').text().replace(/"/g, '""');
console.log("Synopsis: " + Synopsis);
// Game Author
Author = cell.find('.game_author').text().replace(/"/g, '""');
console.log("Author: " + Author);
// Game Genre
Genre = cell.find('.game_genre').text().replace(/"/g, '""');
console.log("Genre: " + Genre);
// Game Blurb (user-created comment about library item)
Blurb = cell.find('.blurb_drop').text().trim().replace(/"/g, '""');
console.log("Blurb: " + Blurb);
// Build Array to push to CSV File, sanitizing data to prevent commas in scraped data from screwing things up
games.push(`"${gameID}","${Genre}","${Title}","${Author}","${Synopsis}","${imagePath}","${URL}","${Blurb}"`);
});
} else {
alert("Error: Unable to correctly identify code.");
}
// Format array for CSV output, sanitizing for titles with commas,
// and adding a newline at the end of each title
for (let i = 0; i < games.length; i++) {
output += games[i] + "\n";
}
filename = document.getElementById("fileName").value;
if (filename === "") {
filename = "collection";
}
filename = filename + ".csv";
const blob = new Blob([output], {
type: "text/plain;charset=utf-8"
});
saveAs(blob, filename);
});
})();
@abraxas86
Copy link
Author

4.0

Glaubits noticed that my script wasn't working for bundles. Great catch! I thought this was going to be pretty easy, but it turns out the Bundle lists are kind of a hybrid between lists and grids...

I changed up the way I was targeting lists vs grids since I had consider a third option.

It seems to all be working now I think (I hope).

Hopefully this makes your setup working, Glaubits!

@abraxas86
Copy link
Author

4.1

Minor bug-fixes. In my attempts to fix the logic, I scuffed up the list-view logic. I also have no idea what I was thinking when I prefixed a bunch of variables with "$" but it was probably due to my brain being on PowerShell at the time 🙃

Anyway, this should be good to go now. My bad for the whoopsies in 4.0. Thanks again for the suggestion and the challenge Glaubits!

@abraxas86
Copy link
Author

I just realized Doover25 asked me about bundles 100 days ago today... I must have misunderstood what they meant at the time, but it's working.

@abraxas86
Copy link
Author

4.5

Forgot to remove a line of debug code. The functionality it self was also broken and I didn't catch it. It's good now I hope. It passed the tests I threw at it, at least.

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