// ==UserScript== // @name Crunchyroll Arabic Episode Titles and Descriptions Extractor // @namespace https://greasyfork.org/en/scripts/518373-crunchyroll-arabic-episode-titles-and-descriptions-extractor // @version 1.4 // @description Extract titles, episode numbers, and descriptions of all episodes on Crunchyroll and save them as JSON // @author You // @match https://www.crunchyroll.com/ar/series/* // @grant none // @license MIT // @downloadURL none // ==/UserScript== (function() { 'use strict'; // Function to download data as JSON file function downloadJSON(data, filename) { const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(data, null, 2)); const downloadAnchorNode = document.createElement('a'); downloadAnchorNode.setAttribute("href", dataStr); downloadAnchorNode.setAttribute("download", filename); document.body.appendChild(downloadAnchorNode); downloadAnchorNode.click(); downloadAnchorNode.remove(); } // Function to extract titles, episode numbers, and descriptions function extractEpisodeInfo() { const episodes = []; const elements = document.querySelectorAll('div[class*="playable-card-hover__body"]'); elements.forEach(element => { const titleElement = element.querySelector('h4[data-t="episode-title"]'); const descriptionElement = element.querySelector('p[data-t="description"]'); if (titleElement && descriptionElement) { const titleText = titleElement.textContent.trim(); const titleMatch = titleText.match(/ح(\d+)\s*-\s*(.*)/); if (titleMatch) { const episodeNumber = titleMatch[1]; const episodeTitle = titleMatch[2]; const description = descriptionElement.textContent.trim(); episodes.push({ episodeNumber, episodeTitle, description }); } } }); console.log('Episodes:', episodes); downloadJSON(episodes, 'episodes_titles.json'); } // Function to create and add the button to the page function createButton() { const button = document.createElement('button'); button.id = 'episodeInfoButton'; // Add an ID to identify the button later button.innerHTML = 'Get Episodes Info'; button.style.position = 'fixed'; button.style.top = '10px'; button.style.right = '10px'; button.style.zIndex = '1000'; button.style.padding = '10px 20px'; button.style.backgroundColor = '#4CAF50'; button.style.color = 'white'; button.style.border = 'none'; button.style.borderRadius = '5px'; button.style.cursor = 'pointer'; button.addEventListener('click', extractEpisodeInfo); document.body.appendChild(button); } // Observe the DOM for changes and ensure the button is present function ensureButtonPresence() { if (!document.getElementById('episodeInfoButton')) { createButton(); } } // Add the button to the page when it loads window.addEventListener('load', createButton); // Observe DOM changes to re-add the button if it gets removed const observer = new MutationObserver(ensureButtonPresence); observer.observe(document.body, { childList: true, subtree: true }); })();