Sort ChickenSmoothie group pets by width, height, or area, with draggable control panel + saved settings
目前為
// ==UserScript==
// @name CS - Sort Pets by Image Size
// @namespace http://tampermonkey.net/
// @version 2.0
// @description Sort ChickenSmoothie group pets by width, height, or area, with draggable control panel + saved settings
// @author lissajo
// @match https://www.chickensmoothie.com/accounts/viewgroup.php*
// @grant none
// @license MIT
// ==/UserScript==
(function () {
"use strict";
const ENABLE_KEY = "cs_sort_pets_enabled";
const MODE_KEY = "cs_sort_pets_mode";
const POS_X_KEY = "cs_sort_box_x";
const POS_Y_KEY = "cs_sort_box_y";
let sortingEnabled = localStorage.getItem(ENABLE_KEY) === "true";
const MODES = ["area", "width", "height"];
let mode = localStorage.getItem(MODE_KEY) || "area";
/* --------------------------------------------------------
CREATE DRAGGABLE CONTROL PANEL
-------------------------------------------------------- */
function createControlBox() {
const box = document.createElement("div");
box.id = "cs-sort-box";
box.style.position = "fixed";
box.style.zIndex = "999999";
box.style.background = "#222";
box.style.padding = "10px";
box.style.borderRadius = "10px";
box.style.color = "white";
box.style.fontSize = "13px";
box.style.boxShadow = "0 0 8px rgba(0,0,0,0.4)";
box.style.cursor = "move";
box.style.userSelect = "none";
// Restore position
box.style.left = (localStorage.getItem(POS_X_KEY) || 20) + "px";
box.style.top = (localStorage.getItem(POS_Y_KEY) || 20) + "px";
box.innerHTML = `
<div style="font-weight:bold; margin-bottom:5px;">Pet Sorter</div>
<button id="cs-toggle" style="width:100%; margin-bottom:6px; padding:4px; border:none; border-radius:5px; cursor:pointer;">
Sorting: ${sortingEnabled ? "ON" : "OFF"}
</button>
<button id="cs-mode" style="width:100%; padding:4px; border:none; border-radius:5px; cursor:pointer;">
Mode: ${mode.toUpperCase()}
</button>
`;
document.body.appendChild(box);
makeDraggable(box);
initButtons();
}
/* --------------------------------------------------------
BUTTON LOGIC
-------------------------------------------------------- */
function initButtons() {
const toggleBtn = document.getElementById("cs-toggle");
const modeBtn = document.getElementById("cs-mode");
toggleBtn.style.background = sortingEnabled ? "#4caf50" : "#b71c1c";
toggleBtn.onclick = () => {
sortingEnabled = !sortingEnabled;
localStorage.setItem(ENABLE_KEY, sortingEnabled);
toggleBtn.textContent = "Sorting: " + (sortingEnabled ? "ON" : "OFF");
toggleBtn.style.background = sortingEnabled ? "#4caf50" : "#b71c1c";
if (sortingEnabled) sortPets();
};
modeBtn.onclick = () => {
let i = MODES.indexOf(mode);
mode = MODES[(i + 1) % MODES.length];
localStorage.setItem(MODE_KEY, mode);
modeBtn.textContent = "Mode: " + mode.toUpperCase();
if (sortingEnabled) sortPets();
};
}
/* --------------------------------------------------------
MAKE BOX DRAGGABLE + SAVE POSITION
-------------------------------------------------------- */
function makeDraggable(el) {
let offsetX = 0, offsetY = 0, dragging = false;
el.addEventListener("mousedown", (e) => {
dragging = true;
offsetX = e.clientX - el.offsetLeft;
offsetY = e.clientY - el.offsetTop;
el.style.opacity = "0.8";
});
document.addEventListener("mouseup", () => {
if (dragging) {
dragging = false;
el.style.opacity = "1";
// Save the final position
localStorage.setItem(POS_X_KEY, el.offsetLeft);
localStorage.setItem(POS_Y_KEY, el.offsetTop);
}
});
document.addEventListener("mousemove", (e) => {
if (dragging) {
el.style.left = (e.clientX - offsetX) + "px";
el.style.top = (e.clientY - offsetY) + "px";
}
});
}
/* --------------------------------------------------------
SORT PETS
-------------------------------------------------------- */
async function sortPets() {
if (!sortingEnabled) return;
// Small delay for page to render pets
await new Promise(res => setTimeout(res, 700));
const pets = Array.from(document.querySelectorAll("dl.pet"));
if (!pets.length) return;
const container = pets[0].parentElement;
const petData = [];
for (let dl of pets) {
const img = dl.querySelector("img");
if (!img) continue;
if (!img.complete) {
await new Promise(res => {
img.onload = img.onerror = res;
});
}
const width = img.naturalWidth || img.width;
const height = img.naturalHeight || img.height;
const area = width * height;
petData.push({
dl,
width,
height,
area
});
}
// Sort by selected mode
petData.sort((a, b) => {
return a[mode] - b[mode];
});
// Reinsert sorted pets
for (let pet of petData) {
container.appendChild(pet.dl);
}
}
/* --------------------------------------------------------
INIT
-------------------------------------------------------- */
function init() {
createControlBox();
if (sortingEnabled) sortPets();
}
window.addEventListener("load", init);
})();