- // ==UserScript==
- // @name Mediux Titlecards Fix
- // @license MIT
- // @version 2.1
- // @description Adds fixes and functions to MediUx
- // @author azuravian
- // @require https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
- // @match https://mediux.pro/*
- // @grant GM_xmlhttpRequest
- // @grant GM_setValue
- // @grant GM_getValue
- // @run-at document-end
- // @namespace https://greasyfork.org/users/1025348
- // ==/UserScript==
-
- waitForKeyElements(
- "code.whitespace-pre-wrap",
- start);
-
- function sleep(ms) {
- return new Promise(resolve => setTimeout(resolve, ms));
- }
-
- function isString(value) {
- return typeof value === 'string';
- }
-
- function isNonEmptyObject(obj) {
- return (
- typeof obj === 'object' && // Check if it's an object
- obj !== null && // Check that it's not null
- !Array.isArray(obj) && // Ensure it's not an array
- Object.keys(obj).length > 0 // Check if it has keys
- );
- }
-
- function addTooltips() {
- const buttons = [fcbutton, fpbutton, bsetbutton]; // Assuming these are your button variables
-
- buttons.forEach((button, index) => {
- switch (index) {
- case 0:
- button.title = "Copy links to collection images"; // Tooltip for fcbutton
- break;
- case 1:
- button.title = "Another action"; // Tooltip for fpbutton
- break;
- case 2:
- button.title = "Perform a batch action"; // Tooltip for bsetbutton
- break;
- }
- });
- }
-
- function showNotification(message) {
- // Create the notification div
- const notification = document.createElement('div');
- const myleftDiv = document.querySelector('#myleftdiv');
- const parentDiv = $(myleftDiv).parent();
-
- // Set the styles directly
- notification.style.width = '50%';
- notification.style.height = '50%';
- notification.style.backgroundColor = 'rgba(200, 200, 200, 0.85)'; // Semi-transparent
- notification.style.color = 'black';
- notification.style.padding = '20px';
- notification.style.borderRadius = '5px';
- notification.style.justifyContent = 'center';
- notification.style.alignItems = 'center';
- notification.style.zIndex = '1000'; // Ensure it’s on top
- notification.style.display = 'none'; // Initially hidden
- // Set the message
- notification.innerText = message;
-
- $(myleftDiv).after(notification);
-
- // Show the notification
- notification.style.display = 'flex';
-
- // Hide after 2-3 seconds
- setTimeout(() => {
- notification.style.display = 'none';
- parentDiv.removeChild(notification); // Remove it from the DOM
- }, 3000); // Adjust the time as needed
- }
-
- function get_posters() {
- const regexpost = /posterCheck/g
- var scriptlist = document.querySelectorAll('script')
- for (let i = scriptlist.length - 1; i >= 0; i--) {
- const element = scriptlist[i];
- if (regexpost.test(element.textContent)) {
- var str1 = element.textContent.replace('self.__next_f.push(', '');
- var str1 = str1.substring(0, str1.length - 1);
- var jsonString = JSON.parse(str1)[1].split('{"set":')[1];
- var fullJson = `{"set":${jsonString}`;
- var parsedObject = JSON.parse(fullJson.substring(0, fullJson.length - 2));
- return parsedObject.set.files;
- }
- }
- }
-
- function get_sets() {
- const regexpost = /posterCheck/g
- var scriptlist = document.querySelectorAll('script')
- for (let i = scriptlist.length - 1; i >= 0; i--) {
- const element = scriptlist[i];
- if (regexpost.test(element.textContent)) {
- var str1 = element.textContent.replace('self.__next_f.push(', '');
- var str1 = str1.substring(0, str1.length - 1);
- var jsonString = JSON.parse(str1)[1].split('{"set":')[1];
- var fullJson = `{"set":${jsonString}`;
- var parsedObject = JSON.parse(fullJson.substring(0, fullJson.length - 2));
- GM_setValue('creator', parsedObject.set.user_created.username);
- return parsedObject.set.boxset.sets;
- }
- }
- }
-
- function get_set(setnum) {
- return new Promise((resolve, reject) => {
- GM_xmlhttpRequest({
- method: 'GET',
- url: `https://mediux.pro/sets/` + setnum,
- timeout: 30000,
- onload: (response) => {
- resolve(response.responseText); // Resolve the promise with the response
- },
- onerror: () => {
- console.log('[Mediux Fixes] An error occurred loading set ${setnum}');
- reject(new Error('Request failed'));
- },
- ontimeout: () => {
- console.log('[Mediux Fixes] It took too long to load set ${setnum}');
- reject(new Error('Request timed out'));
- }
- });
- });
- }
-
-
-
- async function load_boxset(codeblock) {
- const button = document.querySelector('#bsetbutton');
- let originalText = codeblock.textContent; // Store the original content
- originalText += `\n`;
- const sets = get_sets();
- const creator = GM_getValue('creator');
- const startTime = Date.now();
- let elapsedTime = 0;
- let latestMovieTitle = ""; // Variable to store the latest movie title
-
- // Replace codeblock text with a timer
- codeblock.innerText = "Processing... 0 seconds";
-
- const timerInterval = setInterval(() => {
- elapsedTime = Math.floor((Date.now() - startTime) / 1000);
- codeblock.innerText = `Processing... ${elapsedTime} seconds\nProcessed Movies: ${latestMovieTitle}`;
- }, 1000);
-
- for (const set of sets) {
- try {
- const response = await get_set(set.id);
- const response2 = response.replaceAll('\\', '');
- const regexfiles = /"files":(\[{"id":.*?}]),"boxset":/s;
- const match = response2.match(regexfiles);
-
-
- if (match && match[1]) {
- let filesArray;
- try {
- filesArray = JSON.parse(match[1]);
- } catch (error) {
- console.error('Error parsing filesArray:', error);
- return;
- }
- const filteredFiles = filesArray.filter(file => !file.title.trim().endsWith('Collection'))
- filteredFiles.sort((a, b) => a.title.localeCompare(b.title))
- for (const f of filteredFiles) {
- if (f.movie_id !== null) {
- const posterId = f.fileType = 'poster' && f.id.length > 0 ? f.id : 'N/A';
- const movieId = isNonEmptyObject(f.movie_id) ? f.movie_id.id : 'N/A';
- const movieTitle = isString(f.title) && f.title.length > 0 ? f.title.trimEnd() : 'N/A';
- originalText += ` ${movieId}: # ${movieTitle} Poster by ${creator} on MediUX. https://mediux.pro/sets/${set.id}\n url_poster: https://api.mediux.pro/assets/${posterId}\n `;
- latestMovieTitle = latestMovieTitle + movieTitle + ', '; // Update the latest movie title
- console.log(`Title: ${f.title}\nPoster: ${posterId}\n`);
- }
- else if (f.movie_id_backdrop !== null) {
- const backdropId = f.fileType = 'backdrop' && f.id.length > 0 ? f.id : 'N/A';
- const movieId = isNonEmptyObject(f.movie_id_backdrop) ? f.movie_id_backdrop.id : 'N/A';
- originalText += `url_background: https://api.mediux.pro/assets/${backdropId}\n\n`
- console.log(`Backdrop: ${backdropId}\nMovie id: ${movieId}\n`);
- }
- }
- } else {
- console.log('No match found');
- }
- } catch (error) {
- console.error('Error fetching set:', error);
- }
- }
-
- // Stop the timer
- clearInterval(timerInterval);
- codeblock.innerText = "Processing complete!"; // Temporary message
-
- // Create a clickable link for copying the results
- const copyLink = document.createElement('a');
- copyLink.href = "#";
- copyLink.innerText = "Click here to copy the results";
- copyLink.style.color = 'blue'; // Styling for visibility
- copyLink.style.cursor = 'pointer';
-
- // Add click event listener to copy the results
- copyLink.addEventListener('click', async (e) => {
- e.preventDefault(); // Prevent default link behavior
- try {
- await navigator.clipboard.writeText(originalText);
- codeblock.innerText = originalText;
- color_change(button);
- showNotification("Results copied to clipboard!"); // Feedback to the user
- } catch (err) {
- console.error('Failed to copy: ', err);
- }
- });
-
- // Append the link to the codeblock
- codeblock.appendChild(copyLink);
- const totalTime = Math.floor((Date.now() - startTime) / 1000);
- console.log(`Total time taken: ${totalTime} seconds`);
- }
-
- function color_change(button) {
- button.classList.remove('bg-gray-500');
- button.classList.add('bg-green-500');
-
- // After 3 seconds, change it back to bg-gray-500
- setTimeout(() => {
- button.classList.remove('bg-green-500');
- button.classList.add('bg-gray-500');
- }, 3000); // 3000 milliseconds = 3 seconds
- }
-
- function fix_posters(codeblock) {
- const button = document.querySelector('#fpbutton');
- var yaml = codeblock.textContent;
- var posters = get_posters();
- var seasons = posters.filter((poster) => poster.title.includes("Season"));
- for (i in seasons) {
- var current = seasons.filter((season) => season.title.includes(`Season ${i}`));
- yaml = yaml + ` ${i}:\n url_poster: https://api.mediux.pro/assets/${current[0].id}\n`;
- }
- codeblock.innerText = yaml;
- navigator.clipboard.writeText(yaml);
- showNotification("Results copied to clipboard!");
- color_change(button);
- }
-
- function fix_cards(codeblock) {
- const button = document.querySelector('#fcbutton');
- const str = codeblock.innerText;
- const regextest = /(seasons:\n)( episodes:)/g;
- const regex = /( episodes:)/g;
- let counter = 1;
- if (regextest.test(str)) {
- const modifiedStr = str.replace(regex, (match) => {
- const newLine = ` ${counter++}:\n`; // Create the new line with the counter
- return `${newLine}${match}`; // Return the new line followed by the match
- });
- codeblock.innerText = modifiedStr;
- navigator.clipboard.writeText(modifiedStr);
- showNotification("Results copied to clipboard!");
- color_change(button);
- }
- }
-
- function start() {
- const codeblock = document.querySelector('code.whitespace-pre-wrap');
- const myDiv = document.querySelector('.flex.flex-col.space-y-1\\.5.text-center.sm\\:text-left');
- $(myDiv).children('h2, p').wrapAll('<div class="flex flex-row" style="align-items: center"><div id="myleftdiv" style="width: 25%; align: left"></div></div>');
- const myleftdiv = document.querySelector('#myleftdiv');
-
- var fcbutton = $('<button id="fcbutton" title = "Fix missing season numbers in TitleCard YAML" class="duration-500 top-1 left-1 text-xs py-1 px-2 bg-gray-500 text-white rounded flex items-center justify-center"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-gallery-vertical-end w-5 h-5"><path d="M7 2h10"></path><path d="M5 6h14"></path><rect width="18" height="12" x="3" y="10" rx="2"></rect></svg></button>');
- // Set the onclick event to call the runner function
- fcbutton.on('click', () => fix_cards(codeblock));
-
- var fpbutton = $('<button id="fpbutton" title = "Fix missing season posters YAML" class="duration-500 top-1 left-1 text-xs py-1 px-2 bg-gray-500 text-white rounded flex items-center justify-center" style="margin-left:10px""><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-gallery-horizontal-end w-5 h-5"><path d="M2 7v10"></path><path d="M6 5v14"></path><rect width="12" height="18" x="10" y="3" rx="2"></rect></svg></button>');
- // Set the onclick event to call the runner function
- fpbutton.on('click', () => fix_posters(codeblock));
-
- var bsetbutton = $('<button id="bsetbutton" title = "Generate YAML for associated boxset" class="duration-500 top-1 left-1 text-xs py-1 px-2 bg-gray-500 text-white rounded flex items-center justify-center" style="margin-left:10px"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-gallery-horizontal-end w-5 h-5""><rect width="18" height="18" x="3" y="3" rx="2"></rect><path d="M7 7v10"></path><path d="M11 7v10"></path><path d="m15 7 2 10"></path></svg></button>');
- // Set the onclick event to call the runner function
- bsetbutton.on('click', () => load_boxset(codeblock));
-
- var wrappedButtons = $('<div id="extbuttons" class="flex flex-row" style="margin-top: 10px"></div>').append(fcbutton).append(fpbutton).append(bsetbutton);
- $(myleftdiv).append(wrappedButtons);
- $(myleftdiv).parent().append('<div style="width: 25%;"></div>');
- }
-
-
- /*--- waitForKeyElements(): A utility function, for Greasemonkey scripts,
- that detects and handles AJAXed content.
- Usage example:
- waitForKeyElements (
- "div.comments"
- , commentCallbackFunction
- );
- //--- Page-specific function to do what we want when the node is found.
- function commentCallbackFunction (jNode) {
- jNode.text ("This comment changed by waitForKeyElements().");
- }
- IMPORTANT: This function requires your script to have loaded jQuery.
- */
- function waitForKeyElements (
- selectorTxt, /* Required: The jQuery selector string that
- specifies the desired element(s).
- */
- actionFunction, /* Required: The code to run when elements are
- found. It is passed a jNode to the matched
- element.
- */
- bWaitOnce, /* Optional: If false, will continue to scan for
- new elements even after the first match is
- found.
- */
- iframeSelector /* Optional: If set, identifies the iframe to
- search.
- */
- ) {
- var targetNodes, btargetsFound;
-
- if (typeof iframeSelector == "undefined")
- targetNodes = jQuery(selectorTxt);
- else
- targetNodes = jQuery(iframeSelector).contents ()
- .find (selectorTxt);
-
- if (targetNodes && targetNodes.length > 0) {
- btargetsFound = true;
- /*--- Found target node(s). Go through each and act if they
- are new.
- */
- targetNodes.each ( function () {
- var jThis = jQuery(this);
- var alreadyFound = jThis.data ('alreadyFound') || false;
-
- if (!alreadyFound) {
- //--- Call the payload function.
- var cancelFound = actionFunction (jThis);
- if (cancelFound)
- btargetsFound = false;
- else
- jThis.data ('alreadyFound', true);
- }
- } );
- }
- else {
- btargetsFound = false;
- }
-
- //--- Get the timer-control variable for this selector.
- var controlObj = waitForKeyElements.controlObj || {};
- var controlKey = selectorTxt.replace (/[^\w]/g, "_");
- var timeControl = controlObj [controlKey];
-
- //--- Now set or clear the timer as appropriate.
- if (btargetsFound && bWaitOnce && timeControl) {
- //--- The only condition where we need to clear the timer.
- clearInterval (timeControl);
- delete controlObj [controlKey]
- }
- else {
- //--- Set a timer, if needed.
- if ( ! timeControl) {
- timeControl = setInterval ( function () {
- waitForKeyElements ( selectorTxt,
- actionFunction,
- bWaitOnce,
- iframeSelector
- );
- },
- 300
- );
- controlObj [controlKey] = timeControl;
- }
- }
- waitForKeyElements.controlObj = controlObj;
- }