Last active
April 20, 2024 20:01
-
-
Save DontTalkToMeThx/00b47382b7ddc54e01c58a23ef4b7d15 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name e621 Set and Pool Favoriter | |
// @version 0.2 | |
// @description Lets you favorite pools and sets. | |
// @author DefinitelyNotAFurry4 | |
// @match https://e621.net/post_sets* | |
// @match https://e621.net/pools* | |
// @icon https://www.google.com/s2/favicons?sz=64&domain=e621.net | |
// @grant GM_addElement | |
// @grant GM_setValue | |
// @grant GM_getValue | |
// @run-at document-end | |
// ==/UserScript== | |
const POOLS_URL = "https://e621.net/pools.json?limit=100&search[id]=" | |
const SETS_URL = "https://e621.net/post_sets.json?limit=100&search[id]=" | |
// Ruby's time_ago_in_words in javascript | |
// https://gist.github.com/deadkarma/1989808 | |
const DateHelper = { | |
// Takes a timestamp and converts it to a relative time | |
// DateHelper.timeAgoInWords(1331079503000) | |
timeAgoInWords: function (from) { | |
return this.distanceOfTimeInWords(new Date, from); | |
}, | |
distanceOfTimeInWords: function (to, from) { | |
var distanceInSeconds = ((to - from) / 1000); | |
var distanceInMinutes = Math.floor(distanceInSeconds / 60); | |
var tense = distanceInSeconds < 0 ? " from now" : " ago"; | |
distanceInMinutes = Math.abs(distanceInMinutes); | |
if (distanceInMinutes == 0) { return 'less than a minute' + tense; } | |
if (distanceInMinutes == 1) { return 'a minute' + tense; } | |
if (distanceInMinutes < 45) { return distanceInMinutes + ' minutes' + tense; } | |
if (distanceInMinutes < 90) { return 'an hour' + tense; } | |
if (distanceInMinutes < 1440) { return Math.floor(distanceInMinutes / 60) + ' hours' + tense; } | |
if (distanceInMinutes < 2880) { return 'a day' + tense; } | |
if (distanceInMinutes < 43200) { return Math.floor(distanceInMinutes / 1440) + ' days' + tense; } | |
if (distanceInMinutes < 86400) { return 'a month' + tense; } | |
if (distanceInMinutes < 525960) { return Math.floor(distanceInMinutes / 43200) + ' months' + tense; } | |
if (distanceInMinutes < 1051199) { return 'a year' + tense; } | |
return 'over ' + Math.floor(distanceInMinutes / 525960) + ' years'; | |
} | |
}; | |
/** | |
* Fetches data for favorited content. | |
* @param {Array} favoriteIds The favorite id array. | |
* @param {boolean} isPools Whether or not the data being fetched is pools or sets. | |
* @param {boolean} raw Whether or not to return raw data | |
* @returns An array of objects, where the object reprensts a pool or set | |
*/ | |
async function fetchData(favoriteIds, isPools, raw = false) { | |
// The max you can get by id seems to be 100, so we need to request in batches of 100. | |
let data = [] | |
for (let i = 0; i < favoriteIds.length / 100; i++) { | |
let idSlice = favoriteIds.slice(i * 100, i * 100 + 100) | |
let res = await fetch((isPools ? POOLS_URL : SETS_URL) + idSlice.join(",")) | |
if (res.ok) data.push(...(await res.json())) | |
else { | |
console.error(await res.text()) | |
alert("Unable to load favorites") | |
return null | |
} | |
} | |
// Preserve favorite order | |
let realData = [] | |
for (let id of favoriteIds) { | |
let d = data.find(f => f.id == id) | |
if (!raw) { | |
let easyData = [] | |
if (isPools) { | |
easyData.push("", { html: `<a href="/pools/${d.id}">${d.name.replaceAll("_", " ")}</a>` }, d.post_count) | |
} else { | |
easyData.push({ html: `<a href="/post_sets/${d.id}">${d.name}</a>` }, { html: `<a href="/posts?tags=set:${d.shortname}">${d.shortname}</a>` }, { html: `<a href="https://e621.new/users/${d.creator_id}">https://e621.new/users/${d.creator_id}</a>` }, d.post_count, { isDate: true, value: d.created_at }, { isDate: true, value: d.updated_at }, d.is_public ? "Public" : "Private") | |
} | |
realData.push(easyData) | |
} else { | |
realData.push(d) | |
} | |
} | |
return realData | |
} | |
async function getFavorites(isPools) { | |
return isPools ? await GM_getValue("favoritePools", []) : await GM_getValue("favoriteSets", []) | |
} | |
async function getHideShowButton(table, showing) { | |
let button = document.createElement("button") | |
button.innerText = showing ? "Hide" : "Show" | |
if (showing) button.classList.add("button", "btn-danger") | |
else button.classList.add("button", "btn-success") | |
button.addEventListener("click", () => { | |
if (showing) { | |
showing = false | |
button.classList.remove("btn-danger") | |
button.classList.add("btn-success") | |
} else { | |
showing = true | |
button.classList.remove("btn-success") | |
button.classList.add("btn-danger") | |
} | |
GM_setValue("showingFavorites", showing) | |
button.innerText = showing ? "Hide" : "Show" | |
table.style.display = showing ? null : "none" | |
}) | |
return button | |
} | |
async function showFavorites(isPools, afterElement) { | |
let title = document.createElement("h2") | |
title.innerText = "Favorites" | |
afterElement.after(title) | |
let loading = document.createElement("h3") | |
loading.innerText = "Loading" | |
loading.style.marginBottom = "3em" | |
title.after(loading) | |
let favoriteIds = await getFavorites(isPools) | |
if (favoriteIds.length > 0) { | |
let favortieData = await fetchData(favoriteIds, isPools) | |
let table = document.createElement("table") | |
table.style.marginBottom = "3em" | |
table.classList.add("striped") | |
if (isPools) { | |
let tHead = document.createElement("thead") | |
let tr = document.createElement("tr") | |
tHead.appendChild(tr) | |
let padding = document.createElement("th") | |
padding.setAttribute("width", "5%") | |
tr.appendChild(padding) | |
let name = document.createElement("th") | |
name.innerText = "Name" | |
name.setAttribute("width", "60%") | |
tr.appendChild(name) | |
let count = document.createElement("th") | |
count.innerText = "Count" | |
count.setAttribute("width", "10%") | |
tr.appendChild(count) | |
table.appendChild(tHead) | |
} else { | |
let tHead = document.createElement("thead") | |
let tr = document.createElement("tr") | |
tHead.appendChild(tr) | |
let name = document.createElement("th") | |
name.innerText = "Name" | |
name.setAttribute("width", "30%") | |
tr.appendChild(name) | |
let shortName = document.createElement("th") | |
shortName.innerText = "Short Name" | |
shortName.setAttribute("width", "20%") | |
tr.appendChild(shortName) | |
let creator = document.createElement("th") | |
creator.innerText = "Creator" | |
creator.setAttribute("width", "15%") | |
tr.appendChild(creator) | |
let posts = document.createElement("th") | |
posts.innerText = "Posts" | |
posts.setAttribute("width", "5%") | |
tr.appendChild(posts) | |
let created = document.createElement("th") | |
created.innerText = "Created" | |
created.setAttribute("width", "10%") | |
tr.appendChild(created) | |
let updated = document.createElement("th") | |
updated.innerText = "Updated" | |
updated.setAttribute("width", "10%") | |
tr.appendChild(updated) | |
let status = document.createElement("th") | |
status.innerText = "Status" | |
status.setAttribute("width", "10%") | |
tr.appendChild(status) | |
table.appendChild(tHead) | |
} | |
let tBody = document.createElement("tbody") | |
table.appendChild(tBody) | |
for (let data of favortieData) { | |
let tr = document.createElement("tr") | |
for (let d of data) { | |
let td = document.createElement("td") | |
if (d.html) td.innerHTML = d.html | |
else if (d.isDate) { | |
let date = new Date(d.value) | |
let timeAgo = DateHelper.timeAgoInWords(date) | |
let time = document.createElement("time") | |
time.dateTime = date.toISOString() | |
time.title = date.toString() | |
time.innerText = timeAgo | |
td.appendChild(time) | |
} else { | |
td.innerText = d | |
} | |
tr.appendChild(td) | |
} | |
tBody.appendChild(tr) | |
} | |
let showing = await GM_getValue("showingFavorites", true) | |
if (!showing) table.style.display = "none" | |
loading.remove() | |
title.after(table) | |
title.after(await getHideShowButton(table, showing)) | |
} else { | |
loading.remove() | |
let emptyNode = document.createElement("h3") | |
emptyNode.style.marginBottom = "3em" | |
emptyNode.innerText = "Empty" | |
title.after(emptyNode) | |
} | |
} | |
async function showPoolGalleryFavorites(afterElement) { | |
// let title = document.createElement("h2") | |
// title.innerText = "Favorites" | |
// afterElement.after(title) | |
// let loading = document.createElement("h3") | |
// loading.innerText = "Loading" | |
// loading.style.marginBottom = "3em" | |
// title.after(loading) | |
// let favoriteIds = await getFavorites(true) | |
} | |
async function addFavorite(id, isPools) { | |
let favoriteIds = await getFavorites(isPools) | |
favoriteIds.push(id) | |
GM_setValue(isPools ? "favoritePools" : "favoriteSets", favoriteIds) | |
} | |
async function removeFavorite(id, isPools) { | |
let favoriteIds = await getFavorites(isPools) | |
let index = favoriteIds.indexOf(id) | |
if (index != -1) { | |
favoriteIds.splice(index, 1) | |
GM_setValue(isPools ? "favoritePools" : "favoriteSets", favoriteIds) | |
} | |
} | |
async function addButtons(id, isPools) { | |
let favoriteIds = await getFavorites(isPools) | |
let isFavorited = favoriteIds.includes(id) | |
let after = isPools ? document.getElementById("description") : document.getElementsByClassName("set-description-bottom")[0] | |
let favoriteButton = document.createElement("button") | |
favoriteButton.innerText = isFavorited ? "Unfavorite" : "Favorite" | |
if (isFavorited) favoriteButton.classList.add("button", "btn-danger") | |
else favoriteButton.classList.add("button", "btn-success") | |
favoriteButton.addEventListener("click", () => { | |
if (isFavorited) { | |
isFavorited = false | |
removeFavorite(id, isPools) | |
favoriteButton.classList.remove("btn-danger") | |
favoriteButton.classList.add("btn-success") | |
} else { | |
isFavorited = true | |
addFavorite(id, isPools) | |
favoriteButton.classList.remove("btn-success") | |
favoriteButton.classList.add("btn-danger") | |
} | |
favoriteButton.innerText = isFavorited ? "Unfavorite" : "Favorite" | |
}) | |
after.after(favoriteButton) | |
} | |
(async function () { | |
'use strict'; | |
let isPools = window.location.pathname.startsWith("/pools") | |
if (window.location.pathname == "/post_sets" || window.location.pathname == "/pools") { | |
let searchForm = document.getElementById("searchform") | |
showFavorites(isPools, searchForm) | |
} else if (window.location.pathname == "/pools/gallery") { | |
// Unfortunately this isn't really possible without massive load times. | |
// let searchForm = document.getElementById("searchform") | |
// showPoolGalleryFavorites(searchForm.nextElementSibling) | |
} else { | |
let id = parseInt(window.location.pathname.split("/").at(-1)) | |
if (isNaN(id)) return | |
addButtons(id, isPools) | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment