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

Done.

3.2

Changes:

  • Fixed data to clean up lines that may have a double-quote
  • Got rid of silly debug code

@abraxas86
Copy link
Author

3.3
Untipo over on Itch pointed out that my script wasn't working on the purchases page. Good catch! Thanks.

I've added a new @match line so it will activate on the purchases page.

@abraxas86
Copy link
Author

3.5
Refactored code to make it a bit less stupid in how it hunts for the data. Also exports "Blurb" text now. I think Itch intended for this to be used to write your own thoughts on each item, but you can also use it to add your own metadata to the csv.

IntuitiveThinker on Itch had asked if there was a way to differentiate different types of content (games, books, physical games, soundtracks, etc). I couldn't find any way to do this, so I was thinking that adding it to the Blurb is probably the best way to manage it. If Itch ever expands to allow this type of info to be added, I will update the script to reflect the change.

Thanks for the suggestion!

@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