Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- (function() {
- // --- Configuration ---
- const scriptIdentifier = 'downloader-script'; // Unique identifier for elements created by this script
- const imageSelector = '.media-slider .selected-image img.image.contain-no-grow'; // Selector for images
- const nextButtonSelector = '.modal-next-button'; // Selector for the website's next button
- const prevButtonSelector = '.modal-prev-button'; // Selector for the website's previous button
- const closeWebsiteButtonSelector = '.modal-close-button'; // Selector for the website's close button
- const detectionDelay = 1000; // Increased milliseconds to wait after a click before checking for images
- const updateDelay = 700; // Milliseconds to wait after simulating navigation before rescanning
- const thumbnailWidth = '200px'; // Desired width for image thumbnails
- // --- Cleanup Previous Instances ---
- console.log(`Checking for and removing previous instances of '${scriptIdentifier}' script elements...`);
- const previousElements = document.querySelectorAll(`[data-${scriptIdentifier}="true"]`);
- previousElements.forEach(el => {
- console.log(`Removing previous element:`, el);
- if (el.parentNode) {
- el.parentNode.removeChild(el);
- }
- });
- // Note: Removing previous global event listeners added anonymously is difficult.
- // This cleanup focuses on removing the DOM elements created by previous runs.
- // The logic below is designed to only operate with the *new* elements it creates.
- // --- Global variables ---
- let overlay = null; // Holds the main overlay element when active
- let imageGridContainer = null; // Holds the div for image thumbnails inside the overlay
- let statusIndicator = null; // Holds the persistent top-center status/button element
- let statusTextElement = null; // Holds the "Downloader active" text element
- let activateButtonElement = null; // Holds the "Downloader" button element
- // --- Function to simulate click on a website button ---
- function simulateWebsiteButtonClick(selector) {
- const targetButton = document.querySelector(selector);
- if (targetButton) {
- console.log(`Simulating click on website button: ${selector}`);
- targetButton.click(); // Trigger the website's event handler
- return true; // Indicate button was found and clicked
- } else {
- console.warn(`Website button not found: ${selector}.`);
- return false; // Indicate button was not found
- }
- }
- // --- Function to display temporary messages in the overlay ---
- function showOverlayMessage(messageText, color = 'yellow', duration = 3000) {
- if (!overlay) {
- console.error("Overlay not initialized, cannot show message.");
- return;
- }
- // Remove any previous messages first within this overlay instance
- overlay.querySelectorAll('.overlay-message').forEach(msg => msg.remove());
- const messageElement = document.createElement('p');
- messageElement.innerText = messageText;
- messageElement.style.color = color;
- messageElement.style.marginTop = '10px';
- messageElement.style.padding = '10px';
- messageElement.style.backgroundColor = 'rgba(0,0,0,0.5)';
- messageElement.style.borderRadius = '5px';
- messageElement.style.textAlign = 'center';
- messageElement.classList.add('overlay-message'); // Add a class for easy selection/removal
- messageElement.style.zIndex = '10002'; // Ensure message is above image grid
- // Find a reference point below the close button and above the image grid
- // This makes the message appear consistently near the top
- const referenceElement = imageGridContainer || overlay.querySelector('button');
- if(referenceElement) {
- // Insert message before the reference element
- overlay.insertBefore(messageElement, referenceElement);
- } else {
- // Fallback: append to the overlay
- overlay.appendChild(messageElement);
- }
- // Remove the message after a duration
- setTimeout(() => {
- if(messageElement && messageElement.parentNode) {
- messageElement.parentNode.removeChild(messageElement);
- }
- }, duration);
- }
- // --- Function to select images and update the overlay content ---
- function updateOverlayContent() {
- // Ensure the image grid container exists for the *current* overlay instance
- if (!imageGridContainer || !overlay || !document.body.contains(overlay)) {
- console.warn("Overlay or image grid container not active/initialized. Cannot update content.");
- return;
- }
- // Clear previously loaded images and messages within the grid container
- imageGridContainer.innerHTML = '';
- // Also clear messages that might be outside the grid container but within overlay
- overlay.querySelectorAll('.overlay-message').forEach(msg => msg.remove());
- const images = document.querySelectorAll(imageSelector);
- if (images.length === 0) {
- showOverlayMessage('No images found on this gallery slide with the provided selector.', 'yellow', 5000);
- console.log('No images found with the provided selector on this slide.');
- return;
- }
- // Add new images and download buttons
- images.forEach((img, index) => {
- const thumbContainer = document.createElement('div');
- thumbContainer.style.margin = '10px';
- thumbContainer.style.border = '1px solid #ccc';
- thumbContainer.style.padding = '5px';
- thumbContainer.style.backgroundColor = '#fff';
- thumbContainer.style.display = 'flex';
- thumbContainer.style.flexDirection = 'column';
- thumbContainer.style.alignItems = 'center';
- thumbContainer.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)';
- thumbContainer.style.width = `calc(${thumbnailWidth} + 10px)`; // Container slightly wider than thumb + padding
- thumbContainer.style.flexShrink = '0'; // Prevent shrinking
- const thumb = document.createElement('img');
- thumb.src = img.src;
- thumb.style.width = thumbnailWidth; // Use the configured width
- thumb.style.height = 'auto'; // Maintain aspect ratio
- thumb.style.display = 'block';
- thumb.style.marginBottom = '10px';
- const downloadButton = document.createElement('a');
- downloadButton.href = img.src;
- // Attempt to create a filename from the URL
- const urlParts = img.src.split('/');
- let filename = urlParts.pop();
- if (!filename || filename.indexOf('.') === -1 || filename.startsWith('?')) { // Added check for query param only filename
- filename = `image_${index + 1}.png`;
- } else {
- filename = filename.split('?')[0]; // Remove query parameters
- }
- downloadButton.download = filename;
- downloadButton.innerText = 'Download';
- downloadButton.style.display = 'block';
- downloadButton.style.width = '100%'; // Make button fill the container width
- downloadButton.style.padding = '5px 0'; // Adjust padding
- downloadButton.style.backgroundColor = '#007bff';
- downloadButton.style.color = '#fff';
- downloadButton.style.textDecoration = 'none';
- downloadButton.style.borderRadius = '5px';
- downloadButton.style.textAlign = 'center';
- downloadButton.style.cursor = 'pointer';
- downloadButton.style.transition = 'background-color 0.3s ease';
- downloadButton.onmouseover = function() { this.style.backgroundColor = '#0056b3'; };
- downloadButton.onmouseout = function() { this.style.backgroundColor = '#007bff'; };
- thumbContainer.appendChild(thumb);
- thumbContainer.appendChild(downloadButton);
- imageGridContainer.appendChild(thumbContainer);
- });
- }
- // --- Function to create and activate the downloader overlay ---
- function activateDownloaderOverlay() {
- // Check if overlay is already active by checking the global variable
- if (overlay !== null) {
- console.log("Downloader overlay is already active.");
- return; // Don't create a new one if one exists
- }
- console.log("Activating downloader overlay...");
- // Create the main overlay element
- overlay = document.createElement('div');
- overlay.setAttribute(`data-${scriptIdentifier}`, 'true'); // Mark element for cleanup
- overlay.style.position = 'fixed';
- overlay.style.top = '0';
- overlay.style.left = '0';
- overlay.style.width = '100%';
- overlay.style.height = '100%';
- overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.8)'; // Semi-transparent black
- overlay.style.zIndex = '10000'; // Ensure it's on top
- overlay.style.overflowY = 'auto'; // Enable scrolling
- overlay.style.display = 'flex';
- overlay.style.flexDirection = 'column'; // Stack content vertically
- overlay.style.alignItems = 'center'; // Center items horizontally
- overlay.style.padding = '20px';
- overlay.style.boxSizing = 'border-box';
- overlay.style.color = '#fff'; // Default text color for messages
- // Add a Close button to the overlay
- const closeButton = document.createElement('button');
- closeButton.innerText = 'Close Gallery View';
- closeButton.style.position = 'absolute';
- closeButton.style.top = '10px';
- closeButton.style.right = '10px';
- closeButton.style.padding = '10px';
- closeButton.style.cursor = 'pointer';
- closeButton.style.zIndex = '10001'; // Ensure button is above other content
- closeButton.onclick = function() {
- // --- Action when overlay close button is clicked ---
- console.log("Closing downloader overlay...");
- // 1. Simulate click on the website's close button
- simulateWebsiteButtonClick(closeWebsiteButtonSelector);
- // 2. Remove this overlay from the DOM
- if (overlay && overlay.parentNode) {
- overlay.parentNode.removeChild(overlay);
- }
- // 3. Clean up global references
- overlay = null;
- imageGridContainer = null;
- console.log("Overlay closed and references cleared.");
- // 4. Show the "Downloader active" status again
- showStatusText();
- };
- overlay.appendChild(closeButton);
- // Create container for the image grid
- imageGridContainer = document.createElement('div');
- imageGridContainer.style.display = 'flex';
- imageGridContainer.style.flexWrap = 'wrap';
- imageGridContainer.style.justifyContent = 'center';
- imageGridContainer.style.width = '100%';
- imageGridContainer.style.marginTop = '60px'; // Adjust spacing below close button
- imageGridContainer.style.marginBottom = '20px';
- overlay.appendChild(imageGridContainer);
- // Create container for navigation buttons
- const navButtonContainer = document.createElement('div');
- navButtonContainer.style.display = 'flex';
- navButtonContainer.style.gap = '20px';
- navButtonContainer.style.marginBottom = '20px';
- const prevButton = document.createElement('button');
- prevButton.innerText = 'Previous';
- prevButton.style.padding = '10px 20px';
- prevButton.style.cursor = 'pointer';
- prevButton.onclick = function() {
- const clicked = simulateWebsiteButtonClick(prevButtonSelector);
- if(clicked) {
- // Only update overlay if the website button was found and clicked
- setTimeout(updateOverlayContent, updateDelay);
- } else {
- // Optionally show a message in the overlay if nav button wasn't found
- showOverlayMessage(`Could not find website's Previous button: ${prevButtonSelector}`);
- }
- };
- navButtonContainer.appendChild(prevButton);
- const nextButton = document.createElement('button');
- nextButton.innerText = 'Next';
- nextButton.style.padding = '10px 20px';
- nextButton.style.cursor = 'pointer';
- nextButton.onclick = function() {
- const clicked = simulateWebsiteButtonClick(nextButtonSelector);
- if(clicked) {
- // Only update overlay if the website button was found and clicked
- setTimeout(updateOverlayContent, updateDelay);
- } else {
- // Optionally show a message in the overlay if nav button wasn't found
- showOverlayMessage(`Could not find website's Next button: ${nextButtonSelector}`);
- }
- };
- navButtonContainer.appendChild(nextButton);
- overlay.appendChild(navButtonContainer);
- // Add the overlay to the document body
- document.body.appendChild(overlay);
- // Populate the overlay with images from the current view immediately
- updateOverlayContent();
- }
- // --- Functions to manage the status indicator ---
- function setupStatusIndicator() {
- // Check if status indicator is already set up by checking the global variable
- if (statusIndicator !== null) {
- return; // Already set up
- }
- console.log("Setting up status indicator.");
- statusIndicator = document.createElement('div');
- statusIndicator.setAttribute(`data-${scriptIdentifier}`, 'true'); // Mark element for cleanup
- statusIndicator.style.position = 'fixed';
- statusIndicator.style.top = '10px';
- statusIndicator.style.left = '50%';
- statusIndicator.style.transform = 'translateX(-50%)'; // Center horizontally
- statusIndicator.style.zIndex = '9999'; // Below the main overlay
- statusIndicator.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
- statusIndicator.style.color = '#fff';
- statusIndicator.style.padding = '8px 15px';
- statusIndicator.style.borderRadius = '5px';
- statusIndicator.style.fontSize = '14px';
- statusIndicator.style.display = 'flex'; // Use flex for internal elements
- statusIndicator.style.alignItems = 'center';
- statusIndicator.style.pointerEvents = 'none'; // Make the container non-interactive by default
- statusTextElement = document.createElement('span');
- statusTextElement.innerText = 'Downloader active';
- statusTextElement.style.pointerEvents = 'none'; // Text is not clickable
- statusIndicator.appendChild(statusTextElement);
- activateButtonElement = document.createElement('button');
- activateButtonElement.innerText = 'Downloader';
- activateButtonElement.style.display = 'none'; // Hidden initially
- activateButtonElement.style.marginLeft = '10px'; // Space between text and button
- activateButtonElement.style.padding = '5px 10px';
- activateButtonElement.style.cursor = 'pointer';
- activateButtonElement.style.pointerEvents = 'auto'; // Button is clickable
- activateButtonElement.onclick = function(event) {
- console.log("Activate button clicked.");
- event.stopPropagation(); // Prevent the click from bubbling up
- hideStatusIndicatorElements(); // Hide status indicator elements
- activateDownloaderOverlay(); // Activate the overlay
- };
- statusIndicator.appendChild(activateButtonElement);
- document.body.appendChild(statusIndicator);
- // Initially show the "active" text
- showStatusText();
- }
- function showStatusText() {
- // Check if the current status indicator elements exist before trying to update
- if (statusTextElement && activateButtonElement && statusIndicator && document.body.contains(statusIndicator)) {
- statusTextElement.style.display = 'inline';
- activateButtonElement.style.display = 'none';
- statusIndicator.style.cursor = 'default'; // Not clickable when just text
- statusIndicator.style.pointerEvents = 'none'; // Make the entire indicator non-interactive
- statusIndicator.onclick = null; // Ensure no click listener is attached to the container
- console.log("Showing status text.");
- } else {
- console.warn("Status indicator elements not found, cannot show status text.");
- }
- }
- function showActivateButton() {
- // Only show button if overlay is not active and status indicator elements exist
- if (statusTextElement && activateButtonElement && statusIndicator && document.body.contains(statusIndicator) && overlay === null) {
- statusTextElement.style.display = 'none';
- activateButtonElement.style.display = 'inline-block';
- statusIndicator.style.cursor = 'pointer'; // Make the indicator clickable
- statusIndicator.style.pointerEvents = 'auto'; // Make the entire indicator interactive
- // Attach click listener to the indicator container to activate the overlay
- statusIndicator.onclick = function(event) {
- console.log("Status indicator (button state) clicked.");
- event.stopPropagation(); // Prevent the click from bubbling
- hideStatusIndicatorElements(); // Hide the indicator elements
- activateDownloaderOverlay(); // Activate the overlay
- statusIndicator.onclick = null; // Remove this specific click listener after use
- };
- // Note: The activateButtonElement also has its own click listener,
- // which provides a smaller clickable target within the indicator.
- // Both lead to the same activation logic.
- console.log("Showing activate button.");
- } else {
- console.warn("Status indicator elements not found or overlay is active, cannot show activate button.");
- // If elements are missing but overlay is not active, maybe set up indicator again?
- // Removed auto-setup logic here to keep it simpler and rely on user re-running script if needed.
- if (overlay !== null) {
- console.log("Overlay is active, not showing activate button.");
- }
- }
- }
- function hideStatusIndicatorElements() {
- // Check if the current status indicator elements exist before trying to update
- if (statusTextElement && activateButtonElement && statusIndicator && document.body.contains(statusIndicator)) {
- statusTextElement.style.display = 'none';
- activateButtonElement.style.display = 'none';
- statusIndicator.style.cursor = 'default';
- statusIndicator.style.pointerEvents = 'none'; // Make non-interactive
- statusIndicator.onclick = null; // Ensure click listener is removed
- console.log("Hiding status indicator elements.");
- } else {
- console.warn("Status indicator elements not found, cannot hide elements.");
- }
- }
- // --- Global Event Listener to detect gallery opening ---
- // This listener is added *once* when the script runs and persists.
- // Its logic checks for the presence of our *current* statusIndicator before acting.
- document.addEventListener('click', function(event) {
- // If our overlay is already active, do not try to detect a new gallery
- if (overlay !== null) {
- return;
- }
- // Only proceed if our status indicator element exists (means our script is running)
- if (statusIndicator === null || !document.body.contains(statusIndicator)) {
- console.log("Click detected, but status indicator not found. Script may not be fully initialized or its elements were removed manually.");
- return; // Don't run detection logic if indicator is gone
- }
- console.log(`Click detected. Waiting ${detectionDelay}ms to check for gallery images.`);
- // Wait a short time to allow DOM to update after click (e.g., gallery modal opening)
- setTimeout(() => {
- // Re-check if the statusIndicator is still valid after the timeout
- if (statusIndicator === null || !document.body.contains(statusIndicator)) {
- console.log("Timeout finished, but status indicator not found. Skipping gallery detection.");
- return;
- }
- // Check if images matching the selector are now present
- const images = document.querySelectorAll(imageSelector);
- if (images.length > 0) {
- console.log(`Gallery detected (${images.length} images found). Checking if Downloader button should be shown.`);
- // If images are found and our overlay is not active, show the "Downloader" button
- if (overlay === null) {
- showActivateButton();
- } else {
- console.log("Gallery detected, but overlay is already active.");
- }
- } else {
- console.log("No gallery images found after delay.");
- // If no images are found, ensure the status text is shown (gallery closed or not opened)
- if (overlay === null) { // Only show status text if overlay is not active
- showStatusText();
- } else {
- console.log("No images found, but overlay is active.");
- }
- }
- }, detectionDelay);
- });
- // --- Script Execution Start ---
- // 1. Set up the persistent status indicator
- // This also handles checking if it's already set up by this *instance* of the script.
- setupStatusIndicator();
- // The global click listener and the activate button will handle showing the overlay
- // when a gallery is detected and the user clicks the button/indicator.
- console.log(`'${scriptIdentifier}' script initialized and listening for clicks.`);
- })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement