Skip to content

Instantly share code, notes, and snippets.

@bitWolfy
Last active August 19, 2021 18:40
Show Gist options
  • Save bitWolfy/4c6c6eba6c91bd1a7480709104be28c1 to your computer and use it in GitHub Desktop.
Save bitWolfy/4c6c6eba6c91bd1a7480709104be28c1 to your computer and use it in GitHub Desktop.
const fetch = require('node-fetch');
const fs = require("fs");
// Script settings
const settings = {
// Username and API key used to authorize the request
username: "bitWolfy",
apikey: "apikey",
// User to search for.
// The favorites must either be public, or the name must match the username in the auth section.
lookup: "bitWolfy",
// Directory to which the output will be saved
outputDir: "/output/",
// Defines what to output and how
// If `outputMerge` is set to true, all available data is printed into one file
// Otherwise, the results are split into separate files that can be individually enabled
outputMerge: false,
outputPrint: {
artists: true,
characters: true,
},
// Timing between requests.
// 500 is the minimum; if you get errors 429 or 503, set this to 1000
throttle: 500,
};
/**
* Returns the URLs of the newest images that matches the specified tags
* @param tags string[] Tags to look for
* @param limit number Number of posts to return
* @returns Array of post URLs
*/
async function fetchPosts(search, username, apikey, throttle) {
const data = {
total: 0,
artists: {},
characters: {},
};
if (!username || !apikey) return Promise.resolve(data);
if (!throttle || throttle < 500) throttle = 500;
let posts = [];
let total = 0;
let page = 1;
do {
console.log("Processing page " + page);
const response = await fetch(
// Request the data from the posts.json endpoint of the e621 API
`https://e621.net/posts.json?tags=fav:${search}+status:any&limit=320&page=${page}`, {
// Set the header to your own value. Include your name and the script version in it
headers: {
"User-Agent": "bitwolfy/favorites_search",
"Authorization": `Basic ${Buffer.from(username + ":" + apikey).toString('base64')}`
}
}
);
posts = (await response.json())["posts"];
for (const post of posts) {
for (const artist of post.tags.artist) {
if (data.artists[artist]) data.artists[artist]++;
else data.artists[artist] = 1;
}
for (const character of post.tags.character) {
if (data.characters[character]) data.characters[character]++;
else data.characters[character] = 1;
}
}
total += posts.length;
// Throttle the requests
await new Promise((resolve) => { setTimeout(() => { resolve(); }, throttle) });
page++;
} while (posts.length != 0 && page <= 750)
data.total = total;
// Sort results
let sortable = [];
for (const [artist, posts] of Object.entries(data.artists))
sortable.push([artist, posts]);
sortable.sort((a, b) => b[1] - a[1]);
data.artists = {};
for (let dataPoint of sortable)
data.artists[dataPoint[0]] = dataPoint[1];
for (const nonArtist of ["avoid_posting", "conditional_dnp", "unknown_artist", "anonymous_artist", "sound_warning"])
delete data.artists[nonArtist];
sortable = [];
for (const [character, posts] of Object.entries(data.characters))
sortable.push([character, posts]);
sortable.sort((a, b) => b[1] - a[1]);
data.characters = {};
for (let dataPoint of sortable)
data.characters[dataPoint[0]] = dataPoint[1];
return data;
}
// Execute the script and format the output
fetchPosts(settings.lookup, settings.username, settings.apikey, settings.throttle).then((data) => {
if (!settings.outputDir.endsWith("/")) settings.outputDir += "/";
if (!fs.existsSync(settings.outputDir))
fs.mkdirSync(settings.outputDir);
if (settings.outputMerge)
fs.writeFileSync(settings.outputDir + "favorites.txt", JSON.stringify(data, null, 4));
else {
if (settings.outputPrint.artists)
fs.writeFileSync(settings.outputDir + "favorites_artists.txt", JSON.stringify(data.artists, null, 4));
if (settings.outputPrint.characters)
fs.writeFileSync(settings.outputDir + "favorites_characters.txt", JSON.stringify(data.characters, null, 4));
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment