Skip to content

Instantly share code, notes, and snippets.

@pckv
Last active October 28, 2024 14:11
Show Gist options
  • Save pckv/42acc362705dcbc2abbf51d09c18310d to your computer and use it in GitHub Desktop.
Save pckv/42acc362705dcbc2abbf51d09c18310d to your computer and use it in GitHub Desktop.
#Requires AutoHotkey v2
AutoBurn := false
#b::
{
global AutoBurn
InputBoxObj := InputBox("Paste card IDs as copied from the Hifumin Tools userscript. If you have AutoBurn enabled, position your cursor in the center of the BIG PLUS BUTTON to the left of the Discord message field and press Enter instead of clicking OK. KEEP THE CURSOR OVER THE PLUS BUTTON UNTIL IT WRITES 'done'", "Burn cards")
if InputBoxObj.Result != "OK"
{
return
}
cards := StrSplit(InputBoxObj.Value, ",")
for card in cards
{
if AutoBurn
{
MouseMove 76, 0, 0, "R"
Click
}
Send '/burn ' card '{Enter}'
if AutoBurn
{
MouseMove -76, 0, 0, "R"
}
Sleep 2300
if AutoBurn
{
MouseMove 76, -80, 0, "R"
Click
MouseMove -76, 80, 0, "R"
}
Sleep 1200
}
if AutoBurn
{
MouseMove 76, 0, 0, "R"
Click
}
Send 'done'
}
// ==UserScript==
// @name hifumin burn assistant
// @namespace http://tampermonkey.net/
// @version 2024-10-28
// @description hifumin burn assistant
// @author You
// @match https://hifumin.osucad.com/
// @icon https://www.google.com/s2/favicons?sz=64&domain=osucad.com
// @grant none
// ==/UserScript==
(function () {
"use strict";
let selecting = true;
const cards = [];
let selectedCardIds = [];
let lastSelectedId = null;
const isSelected = (id) => selectedCardIds.includes(id);
const getConditionFromName = (name) => {
if (name.includes("💥")) {
return "badlyDamaged";
}
if (name.includes("⚠️")) {
return "poor";
}
if (name.includes("✔️")) {
return "good";
}
if (name.includes("💎")) {
return "mint";
}
};
const conditionToEmoji = (condition) =>
condition === "mint"
? "🤩"
: condition === "good"
? "🙂"
: condition === "poor"
? "😕"
: "😡"
const getCondition = (card) => {
const name = card.querySelector(".name-box").innerText;
return getConditionFromName(name);
};
const getName = (card) =>
card
.querySelector(".name-box")
.innerText.replace(/💥|⚠️|✔️|💎/g, "")
.trim();
const getId = (card) => card.querySelector(".card-id").innerText;
const getValue = (card) =>
Number(card.querySelector(".value").innerText.replace(/💰/, ""));
const getStar = (card) =>
Number([...card.classList].find((c) => c.startsWith("star")).slice(-1)) - 1;
const getFoil = (card) => card.classList.contains("foil");
const getCardData = (card) => ({
id: getId(card),
name: getName(card),
value: getValue(card),
condition: getCondition(card),
star: getStar(card),
foil: getFoil(card),
});
const getCardDataOfIds = (cardIds) => cards
.filter(card => cardIds.includes(getId(card)))
.map(card => getCardData(card));
const history = [];
const redoHistory = [];
const push = (action, skipHistory = false) => {
if (action.type === "add") {
selectedCardIds.push(...action.cards.map(getId));
action.cards.forEach((card) => updateSelectedStyle(card, true));
} else if (action.type === "remove") {
const removedIds = action.cards.map(getId);
selectedCardIds = selectedCardIds.filter(
(id) => !removedIds.includes(id)
);
action.cards.forEach((card) => updateSelectedStyle(card, false));
}
if (!skipHistory) {
history.push(action);
if (redoHistory.length) redoHistory.length = 0;
}
};
const revert = (action, skipHistory = false) => {
if (action.type === "add") {
push({ ...action, type: "remove" }, skipHistory);
} else if (action.type === "remove") {
push({ ...action, type: "add" }, skipHistory);
}
};
const setAllAs = (selected, filter) => {
const filtered = filter ? cards.filter(filter) : [...cards];
if (!selected) {
push({ type: "remove", cards: filtered.filter(
(card) => isSelected(getId(card))
) });
} else {
const unselectedCards = filtered.filter(
(card) => !isSelected(getId(card))
);
push({ type: "add", cards: unselectedCards });
}
}
const toggleSelectAll = (filter) => {
const filtered = filter ? cards.filter(filter) : [...cards];
const areAllSelected = filtered.every((card) => isSelected(getId(card)));
if (areAllSelected) {
push({ type: "remove", cards: filtered });
} else {
const unselectedCards = filtered.filter(
(card) => !isSelected(getId(card))
);
push({ type: "add", cards: unselectedCards });
}
};
const selectRange = (fromId, toId) => {
const [start, end] = [fromId, toId]
.map((id) => cards.findIndex((card) => getId(card) === id))
.sort((a, b) => a > b);
const cardsToSelect = cards.slice(start, end + 1);
push({ type: "add", cards: cardsToSelect });
};
const deselect = () => {
const selectedCards = cards.filter((card) => isSelected(getId(card)));
push({ type: "remove", cards: selectedCards });
};
const copy = () => {
navigator.clipboard.writeText(selectedCardIds.join(","));
deselect();
};
const toSortable = (name) => name.replaceAll(/[ _-]*/g, "").toLocaleLowerCase()
const sortCard = (nameA, nameB) => toSortable(nameA).localeCompare(toSortable(nameB))
const copyDetailed = () => {
const selectedCards = getCardDataOfIds(selectedCardIds);
const text = selectedCards
.toSorted((a, b) => sortCard(a.name, b.name))
.map(c => `\`${c.id}\` · ${conditionToEmoji(c.condition)} · ${c.name} (${c.value} gold)${c.foil ? " · `foil`" : ""}` )
.join("\n");
navigator.clipboard.writeText(text);
deselect();
}
const copyNames = () => {
const selectedCards = getCardDataOfIds(selectedCardIds);
const names = Array.from(new Set(selectedCards.map(c => c.name))).toSorted(sortCard);
const text = names
.map(c => c.replaceAll("_", "\\_").replaceAll("-", "\\-"))
.join(", ")
navigator.clipboard.writeText(text);
deselect();
}
const undo = () => {
if (!history.length) return;
const action = history.pop();
revert(action, true);
redoHistory.push(action);
};
const redo = () => {
if (!redoHistory.length) return;
const action = redoHistory.pop();
push(action, true);
history.push(action);
};
document.body.addEventListener("keydown", (e) => {
if (!selecting) {
return;
}
if (e.code === "KeyC" && e.shiftKey) {
e.preventDefault();
if (e.ctrlKey) copyNames();
else copyDetailed();
}
else if (e.code === "KeyC" && e.ctrlKey) {
e.preventDefault();
copy();
}
if (e.ctrlKey && !e.shiftKey && e.code === "KeyZ") {
e.preventDefault();
undo();
}
if (
(e.ctrlKey && e.shiftKey && e.code === "KeyZ") ||
(e.ctrlKey && !e.shiftKey && e.code === "KeyY")
) {
e.preventDefault();
redo();
}
if (e.ctrlKey && !e.shiftKey && e.code === "KeyA") {
e.preventDefault();
toggleSelectAll();
}
if (e.ctrlKey && !e.shiftKey && e.code === "KeyD") {
e.preventDefault();
deselect();
}
if (e.altKey && e.code === "Digit1") {
e.preventDefault();
setAllAs(!e.shiftKey, (card) => getStar(card) === 0);
}
if (e.altKey && e.code === "Digit2") {
e.preventDefault();
setAllAs(!e.shiftKey, (card) => getStar(card) === 1);
}
if (e.altKey && e.code === "Digit3") {
e.preventDefault();
setAllAs(!e.shiftKey, (card) => getStar(card) === 2);
}
if (e.altKey && e.code === "KeyF") {
e.preventDefault();
setAllAs(!e.shiftKey, (card) => getFoil(card));
}
if (e.altKey && e.code === "KeyN") {
e.preventDefault();
setAllAs(!e.shiftKey, (card) => !getFoil(card));
}
if (e.altKey && e.code === "KeyM") {
e.preventDefault();
setAllAs(!e.shiftKey, (card) => getCondition(card) === "mint");
}
if (e.altKey && e.code === "KeyG") {
e.preventDefault();
setAllAs(!e.shiftKey, (card) => getCondition(card) === "good");
}
if (e.altKey && e.code === "KeyP") {
e.preventDefault();
setAllAs(!e.shiftKey, (card) => getCondition(card) === "poor");
}
if (e.altKey && e.code === "KeyB") {
e.preventDefault();
setAllAs(!e.shiftKey, (card) => getCondition(card) === "badlyDamaged");
}
});
const results = document.querySelector("#results");
const updateSelectedStyle = (card, selected) => {
card.style.boxShadow = selected ? "0 0 0 7px #007bff" : "";
};
const addSelect = (card) => {
const id = getId(card);
updateSelectedStyle(card, isSelected(id));
const select = () => {
if (isSelected(id)) {
push({ type: "remove", cards: [card] });
lastSelectedId = null;
} else {
push({ type: "add", cards: [card] });
lastSelectedId = id;
console.log(getCardData(card));
}
};
const range = () => {
if (!lastSelectedId) return;
selectRange(lastSelectedId, id);
lastSelectedId = null;
};
const img = card.querySelector("img");
img.oncontextmenu = (e) => {
e.preventDefault();
select();
};
const oldClick = img.onclick;
img.onclick = (e) => {
if (e.ctrlKey) {
e.preventDefault();
select();
} else if (e.shiftKey) {
e.preventDefault();
range();
} else oldClick(e);
};
};
const updateCards = () => {
Object.assign(cards, document.querySelectorAll(".card"));
cards.forEach((card) => {
addSelect(card);
});
};
const update = () => {
updateCards();
};
// Observe changes
let timer;
const observer = new MutationObserver((mutations) => {
if (!selecting) {
return;
}
mutations.forEach((mutation) => {
if (mutation.addedNodes.length > 0) {
clearTimeout(timer);
timer = setTimeout(update, 100);
}
});
});
console.log("hifumin burn assistant loaded");
observer.observe(results, { childList: true });
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment