// ==UserScript== // @name QuickDelete // @description Quickly delete or refresh items in Jellyfin // @namespace https://git.m3.fyi/Marsn3/userscripts // @version 0.4 // @author Marsn3 // @match https://media.m3.fyi/* // @icon https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net // @grant none // @run-at document-end // ==/UserScript== (function () { "use strict"; // Define Constants const username = "mars"; const password = "absw3712mcS"; const userid = "e55a6ca076a14cb5a6ca9cfaa75498c1"; const baseURL = window.origin; var apiKey = "38346c399d57454da3bdbf47ba716765"; // Authorize user fetch(`${baseURL}/Users/${userid}/Authenticate/?pw=${password}`, { method: "POST", headers: { "X-Emby-Authorization": `MediaBrowser Client="QuickDelete", Device="Browser", DeviceId="", Version="1.0.0", Token="${apiKey}"`, }, }) .then((response) => response.json()) .then((data) => (apiKey = data.AccessToken)); // Store AccessToken // Button to refresh the metadata of an item function refreshButton() { let el = document.createElement("button"); el.className = "listItemButton paper-icon-button-light emby-button"; let el2 = document.createElement("span"); // Set icon and color el2.className = "material-icons refresh"; el2.style.color = "#83a598"; el.style.position = "relative"; el.style.overflow = "hidden"; el.appendChild(el2); // Bind refresh function el.onclick = function () { let url = `${window.origin}/Items/${this.parentElement.dataset.id}/Refresh?Recursive=true&ImageRefreshMode=FullRefresh&MetadataRefreshMode=FullRefresh&ReplaceAllImages=true&ReplaceAllMetadata=true`; console.log(`Refreshing ${url}`); // Send refresh request fetch(url, { method: "POST", headers: { "X-Emby-Authorization": `MediaBrowser Client="QuickDelete", Device="Chrome", DeviceId="test", Version="10.8.9", Token="${apiKey}"`, }, }); // Replace empty image with rotating spinner this.parentElement.firstChild.firstChild.classList.remove("audiotrack"); this.parentElement.firstChild.firstChild.classList.add( "sync", "rotating" ); var style = document.createElement("style"); style.innerHTML = ` .rotating { animation: rotate 1s infinite; } @keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }`; // Add style element to document head document.head.appendChild(style); }; //Return complete element return el; } // Button to display bitrate of item function infoButton() { let el = document.createElement("button"); el.className = "listItemButton paper-icon-button-light emby-button"; let el2 = document.createElement("span"); // Set icon and color el2.className = "material-icons info"; el2.style.color = "#fbf1c7"; el.appendChild(el2); // Bind get function el.onclick = function () { var bitrate = 0; let url = `${window.origin}/Users/${userid}/Items/${this.parentElement.dataset.id}`; console.log(`Fetching ${url}`); // Send deletion request fetch(url, { method: "GET", headers: { "X-Emby-Authorization": `MediaBrowser Client="QuickDelete", Device="Chrome", DeviceId="test", Version="10.8.9", Token="${apiKey}"`, }, }) .then((response) => response.json()) .then((data) => alert( `${data.MediaStreams[0].BitRate.toString().substring(0, 3)}kbps` ) ); }; //Return complete element return el; } // Helper function to create delete button function delButton() { let el = document.createElement("button"); el.className = "listItemButton paper-icon-button-light emby-button"; let el2 = document.createElement("span"); // Set icon and color el2.className = "material-icons delete"; el2.style.color = "#fb4934"; el.appendChild(el2); // Bind delete function el.onclick = function () { let url = `${window.origin}/Items/${this.parentElement.dataset.id}`; console.log(`Deleting ${url}`); // Send deletion request fetch(url, { method: "DELETE", headers: { "X-Emby-Authorization": `MediaBrowser Client="QuickDelete", Device="Chrome", DeviceId="test", Version="10.8.9", Token="${apiKey}"`, }, }); // Remove parent to provide feedback and prevent double deletion this.parentElement.remove(); }; //Return complete element return el; } // Insert buttons function insert() { const collection = document.getElementsByClassName("listItem"); for (let i = 0; i < collection.length; i++) { let curr = collection[i]; if (curr.firstChild.firstChild !== null) { if (curr.firstChild.firstChild.classList.contains("audiotrack")) { curr.style.backgroundColor = "rgba(251, 73, 52, 0.7)" curr.firstChild.style.backgroundColor = "#cc2412" } } // Append buttons to list curr.appendChild(refreshButton()); curr.appendChild(infoButton()); curr.appendChild(delButton()); } } // Setup key handler function onKeydown(evt) { // Alt + Q if (evt.altKey && evt.keyCode == 81) { insert(); } } document.addEventListener("keydown", onKeydown, true); })();