Boosty Image URL Cleaner

Удаление параметров mw и mh из ссылок на изображения на Boosty, если не указано "&croped", позволяет загружать изображения-превью в оригинальном разрешении

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Boosty Image URL Cleaner
// @version      1.11
// @description  Удаление параметров mw и mh из ссылок на изображения на Boosty, если не указано "&croped",  позволяет загружать изображения-превью в оригинальном разрешении
// @match        *://*.boosty.to/*
// @grant        none
// @namespace http://tampermonkey.net/
// ==/UserScript==

(function() {
    'use strict';
    // --- (Этот скрипт оптимизирован для эффективности) ---
    // --- (Использует MutationObserver для обработки только НОВЫХ img) ---
    // --- (Использует Map для кэширования уже обработанных URL) ---

    // --- КАТЕГОРИЯ: КЭШИРОВАНИЕ И СОСТОЯНИЕ ---
    // Этот раздел содержит переменные, используемые для оптимизации и отслеживания состояния.
    // - urlCleanCache: Map-объект для кэширования.
    //   - Ключ: Оригинальный URL изображения.
    //   - Значение: Уже очищенный URL.
    //   - Это предотвращает повторную обработку одного и того же URL (например,
    //     одинаковых аватарок в комментариях) и значительно ускоряет скрипт.
    const urlCleanCache = new Map();

    // --- КАТЕГОРИЯ: ОСНОВНАЯ ЛОГИКА ---
    // Функции, выполняющие основную работу скрипта.

    /**
     * Принимает URL, очищает его от параметров 'mw' и 'mh',
     * если в нем нет параметра "&croped".
     * Использует кэширование для быстрого ответа.
     *
     * @param {string} url - Оригинальный URL изображения.
     * @returns {string} - Очищенный URL.
     */
    function cleanURL(url) {
        // 1. Сначала проверяем, нет ли уже готового URL в кэше
        if (urlCleanCache.has(url)) {
            return urlCleanCache.get(url);
        }

        // 2. Если в кэше нет, проводим анализ и очистку
        let urlParts = url.split('?');
        
        // Если URL вообще не содержит параметров (нет '?'),
        // он уже "чистый". Кэшируем его как есть.
        if (urlParts.length < 2) {
            urlCleanCache.set(url, url); // Кэшируем "чистый" URL (он же = оригиналу)
            return url;
        }

        let baseUrl = urlParts[0];
        // Собираем обратно строку запроса, на случай если в ней был '?'
        let queryString = urlParts.slice(1).join('?'); 
        let searchParams = new URLSearchParams(queryString);

        // 3. Главное условие:
        // Если в строке запроса есть "&croped" (или "croped" как первый параметр),
        // мы НЕ трогаем 'mw' и 'mh', т.к. они нужны для кадрирования.
        // Мы проверяем именно `queryString`, а не `searchParams.has`
        // для точного соответствия оригинальной логике (поиск подстроки).
        if (!queryString.includes('&croped') && !queryString.startsWith('croped=')) {
            // Удаляем параметры, отвечающие за ограничение размера
            searchParams.delete('mw');
            searchParams.delete('mh');
        }

        // 4. Собираем URL обратно
        const newQueryString = searchParams.toString();
        const finalUrl = newQueryString ? `${baseUrl}?${newQueryString}` : baseUrl;

        // 5. Сохраняем результат в кэш
        urlCleanCache.set(url, finalUrl);
        return finalUrl;
    }

    // --- КАТЕГОРИЯ: ОБРАБОТКА DOM ---
    // Функции, которые взаимодействуют с элементами на странице.

    /**
     * Обрабатывает один DOM-узел <img>.
     * Проверяет, является ли он целевым изображением Boosty,
     * и применяет к нему `cleanURL` для `src` и `srcset`.
     *
     * @param {Node} node - DOM-узел для проверки.
     */
    function processImage(node) {
        // Убеждаемся, что это:
        // 1. Элемент (nodeType === 1)
        // 2. Тег <img> с `src`, содержащим "boosty.to/image"
        // 3. Элемент, который мы еще не обрабатывали (нет `data-cleaned="true"`)
        // Селектор :not([data-cleaned="true"]) - ключевой для производительности.
        if (node.nodeType === 1 &&
            node.matches('img[src*="boosty.to/image"]:not([data-cleaned="true"])')) {

            // Помечаем сразу, чтобы избежать повторной обработки
            // этим же скриптом или другим колбэком MutationObserver.
            node.dataset.cleaned = 'true';

            // Чистим основной `src`
            // (cleanURL быстро возьмет из кэша, если URL уже встречался)
            if (node.src) {
                node.src = cleanURL(node.src);
            }

            // Чистим `srcset`, который используется для адаптивных изображений
            if (node.srcset) {
                // `srcset` - это строка вида "url1 100w, url2 200w, ..."
                node.srcset = node.srcset.split(',') // -> ["url1 100w", " url2 200w"]
                    .map(srcEntry => {
                        const parts = srcEntry.trim().split(' '); // -> ["url1", "100w"] или ["url2"]
                        const url = parts[0];
                        const size = parts[1] || ''; // '100w' или пустая строка
                        
                        // Чистим только URL, а дескриптор размера (size) оставляем
                        return `${cleanURL(url)} ${size}`;
                    })
                    .join(', '); // Собираем обратно в строку
            }
        }
    }

    // --- КАТЕГОРИЯ: НАБЛЮДЕНИЕ ЗА DOM И ИНИЦИАЛИЗАЦИЯ ---
    // Код, который запускает скрипт и отслеживает будущие изменения.

    // 1. Создание Наблюдателя (MutationObserver)
    // Это современный и очень эффективный способ реагировать
    // на добавление новых элементов на страницу (например, при
    // бесконечной прокрутке или открытии комментариев).
    const observer = new MutationObserver((mutations) => {
        // Перебираем все зафиксированные мутации
        for (const mutation of mutations) {
            // Нас интересуют только *добавленные* узлы
            for (const node of mutation.addedNodes) {
                // А. Если добавлен сам <img>
                // (nodeType === 1 нужен, чтобы отсеять текст, комменты и т.д.)
                if (node.nodeType === 1) {
                    processImage(node);
                }

                // Б. Если добавлен контейнер (например, <div> с постом),
                // ищем <img> *внутри* него.
                // `node.querySelectorAll` существует только у элементов.
                if (node.querySelectorAll) {
                    node.querySelectorAll('img[src*="boosty.to/image"]:not([data-cleaned="true"])')
                        .forEach(processImage);
                }
            }
        }
    });

    // 2. Запуск наблюдателя
    // Мы "прикрепляем" его к document.body и говорим:
    // - childList: true -> следи за добавлением/удалением дочерних элементов
    // - subtree: true   -> следи за всеми потомками, а не только прямыми
    observer.observe(document.body, { childList: true, subtree: true });

    // 3. Первоначальная обработка
    // Наблюдатель `observer` сработает только на *новые* элементы.
    // Эта строка находит и обрабатывает все картинки, которые
    // уже были на странице в момент запуска скрипта.
    document.querySelectorAll('img[src*="boosty.to/image"]:not([data-cleaned="true"])')
        .forEach(processImage);
})();