media panel

media panel in the catlife online

// ==UserScript==
// @name         media panel
// @namespace    http://tampermonkey.net/
// @version      2025-01-19
// @description  media panel in the catlife online
// @author       me
// @match        https://worldcats.ru/play/
// @match        https://worldcats.ru/play/?v=b
// @match        https://catlifeonline.com/play/
// @match        https://catlifeonline.com/play/?v=b
// @icon         https://www.google.com/s2/favicons?sz=64&domain=catlifeonline.com
// @grant        none
// ==/UserScript==

(function() {
    // Проверяем, существует ли уже панель, чтобы избежать дублирования
    if (document.getElementById('media-viewer-panel')) {
        console.log('Панель просмотра медиа уже существует.');
        return;
    }

    // --- 1. Создание структуры панели ---
    const panel = document.createElement('div');
    panel.id = 'media-viewer-panel';

    const header = document.createElement('div');
    header.id = 'media-viewer-header';
    header.innerHTML = 'Медиа-просмотрщик <span id="toggle-btn" style="cursor: pointer;">[ - ]</span>';

    const contentArea = document.createElement('div');
    contentArea.id = 'media-viewer-content';
    contentArea.innerHTML = '<p style="text-align: center; color: #aaa;">Перетащите сюда видео, GIF или фото</p>';

    panel.appendChild(header);
    panel.appendChild(contentArea);
    document.body.appendChild(panel);

    // --- 2. Стилизация и позиционирование (инлайн-стили для простоты в консоли) ---
    panel.style.cssText = `
        position: fixed;
        bottom: 10px;
        left: 10px;
        width: 300px; /* Начальная ширина */
        height: 300px; /* Начальная высота для видимости содержимого */
        max-height: 80vh; /* Максимальная высота относительно окна просмотра */
        min-height: 30px; /* Минимальная высота в свернутом виде (только заголовок) */
        background-color: #222;
        border: 1px solid #444;
        border-radius: 8px;
        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
        z-index: 10000;
        display: flex;
        flex-direction: column;
        overflow: hidden; /* Скрыть контент при свертывании */
        color: #eee;
        font-family: Arial, sans-serif;
        font-size: 14px;
        resize: both; /* Позволяет изменять размер панели */
        min-width: 150px;
        max-width: 80vw; /* Максимальная ширина относительно окна просмотра */
        transition: width 0.2s ease, height 0.2s ease; /* Плавное изменение размера */
    `;

    header.style.cssText = `
        background-color: #333;
        padding: 8px 12px;
        display: flex;
        justify-content: space-between;
        align-items: center;
        border-bottom: 1px solid #444;
        user-select: none; /* Запрещает выделение текста в заголовке */
    `;

    contentArea.style.cssText = `
        flex-grow: 1;
        padding: 10px;
        overflow-y: auto; /* Прокрутка для содержимого */
        display: flex;
        flex-direction: column;
        gap: 10px; /* Промежуток между элементами */
        justify-content: flex-start; /* Элементы начинаются сверху */
        align-items: center; /* Центрирование медиа по горизонтали */
        min-width: 100px; /* Минимальная ширина контентной области */
        min-height: 50px; /* Минимальная высота контентной области */
    `;

    // --- 3. Функциональность свертывания/развертывания панели ---
    const toggleBtn = document.getElementById('toggle-btn');
    let isCollapsed = false;toggleBtn.onclick = function() {
        if (isCollapsed) {
            contentArea.style.display = 'flex';
            panel.style.height = '300px'; // Возвращаем к начальной высоте
            panel.style.maxHeight = '80vh'; // Возвращаем максимальную высоту
            toggleBtn.textContent = '[ - ]';
        } else {
            contentArea.style.display = 'none';
            panel.style.height = '30px'; // Сворачиваем до высоты заголовка
            panel.style.maxHeight = '30px'; // Ограничиваем максимальную высоту
            toggleBtn.textContent = '[ + ]';
        }
        isCollapsed = !isCollapsed;
    };

    // --- 4. Функциональность Drag and Drop ---
    contentArea.addEventListener('dragover', (e) => {
        e.preventDefault(); // Разрешаем drop
        contentArea.style.backgroundColor = 'rgba(68, 68, 68, 0.3)'; // Визуальная обратная связь
    });

    contentArea.addEventListener('dragleave', (e) => {
        contentArea.style.backgroundColor = 'transparent'; // Убираем обратную связь
    });

    contentArea.addEventListener('drop', (e) => {
        e.preventDefault();
        contentArea.style.backgroundColor = 'transparent'; // Убираем обратную связь

        const files = e.dataTransfer.files;
        if (files.length > 0) {
            // Удаляем начальное сообщение "Перетащите сюда..."
            if (contentArea.querySelector('p')) {
                contentArea.innerHTML = '';
            }

            for (let i = 0; i < files.length; i++) {
                const file = files[i];
                // Проверяем тип файла: изображение или видео
                if (file.type.startsWith('image/') || file.type.startsWith('video/')) {
                    // Создаем обертку для медиа и кнопки удаления
                    const mediaWrapper = document.createElement('div');
                    mediaWrapper.style.cssText = `
                        position: relative;
                        border: 1px solid #555;
                        border-radius: 4px;
                        overflow: hidden;
                        margin-bottom: 5px; /* Отступ между элементами */
                        box-shadow: 0 2px 5px rgba(0,0,0,0.2);
                        width: 100%; /* Обертка занимает всю доступную ширину */
                        display: flex; /* Для центрирования медиа внутри обертки */
                        justify-content: center;
                        align-items: center;
                        min-height: 50px; /* Минимальная высота для маленьких файлов */
                    `;

                    let mediaElement;
                    let objectURL; // Переменная для хранения URL, чтобы потом его отозвать

                    if (file.type.startsWith('image/')) {
                        mediaElement = document.createElement('img');
                        mediaElement.alt = file.name;
                        objectURL = URL.createObjectURL(file);
                        mediaElement.src = objectURL;
                    } else if (file.type.startsWith('video/')) {
                        mediaElement = document.createElement('video');
                        mediaElement.controls = true; // Добавляем элементы управления видео
                        mediaElement.autoplay = false; // Не автовоспроизводить по умолчанию
                        mediaElement.loop = true; // Зацикливать видео
                        mediaElement.muted = true; // Отключаем звук по умолчанию

                        objectURL = URL.createObjectURL(file);
                        mediaElement.src = objectURL;// *** Обработка ошибок для видео ***
                        mediaElement.onerror = function(e) {
                            console.error(`Ошибка загрузки или воспроизведения медиа: ${file.name}.`, e);
                            const errorDiv = document.createElement('div');
                            errorDiv.style.cssText = `
                                color: red;
                                padding: 10px;
                                text-align: center;
                                background-color: #333;
                                border-top: 1px solid #555;
                                width: 100%;
                            `;
                            errorDiv.textContent = `Ошибка: Не удалось загрузить или воспроизвести "${file.name}"`;

                            mediaWrapper.innerHTML = ''; // Очищаем обертку
                            mediaWrapper.appendChild(errorDiv);
                            mediaWrapper.appendChild(closeButton); // Важно: заново добавить кнопку закрытия

                            // Отозвать URL, если ошибка произошла после его создания
                            if (objectURL) {
                                URL.revokeObjectURL(objectURL);
                                objectURL = null; // Обнуляем, чтобы не пытаться отозвать дважды
                            }
                        };
                    }

                    mediaElement.style.maxWidth = '100%'; // Масштабирование по ширине панели
                    mediaElement.style.height = 'auto'; // Сохранение пропорций
                    mediaElement.style.display = 'block';
                    mediaElement.style.borderRadius = '3px'; // Небольшое скругление углов медиа

                    // Добавляем кнопку удаления
                    const closeButton = document.createElement('span');
                    closeButton.classList.add('close-button'); // Добавляем класс для идентификации
                    closeButton.innerHTML = '&times;'; // Символ "крестик"
                    closeButton.style.cssText = `
                        position: absolute;
                        top: 5px;
                        right: 5px;
                        background-color: rgba(0, 0, 0, 0.6);
                        color: white;
                        border-radius: 50%;
                        width: 20px;
                        height: 20px;
                        display: flex;
                        align-items: center;
                        justify-content: center;
                        cursor: pointer;
                        font-size: 16px;
                        font-weight: bold;
                        line-height: 1; /* Для лучшего выравнивания символа */
                        padding-bottom: 2px;
                        transition: background-color 0.2s ease;
                        z-index: 1; /* Убедимся, что кнопка поверх медиа */
                    `;
                    closeButton.title = 'Удалить файл';
                    // Эффект при наведении
                    closeButton.onmouseover = () => closeButton.style.backgroundColor = 'rgba(255, 0, 0, 0.7)';
                    closeButton.onmouseout = () => closeButton.style.backgroundColor = 'rgba(0, 0, 0, 0.6)';

                    closeButton.onclick = () => {
                        mediaWrapper.remove(); // Удаляем всю обертку с медиа
                        // Очень важно: отзываем URL, чтобы освободить память
                        if (objectURL) {
                            URL.revokeObjectURL(objectURL);
                            console.log(`URL отозван: ${objectURL}`);
                        }
                        // Если больше нет медиа, показываем подсказку снова
                        if (contentArea.children.length === 0) {
                            contentArea.innerHTML = '<p style="text-align: center; color: #aaa;">Перетащите сюда видео, GIF или фото</p>';
                        }
                    };mediaWrapper.appendChild(mediaElement);
                    mediaWrapper.appendChild(closeButton);
                    contentArea.appendChild(mediaWrapper);
                    // Прокручиваем к низу, чтобы показать новый контент
                    contentArea.scrollTop = contentArea.scrollHeight;
                } else {
                    console.warn(`Медиа-просмотрщик: Неподдерживаемый тип файла: ${file.name} (${file.type})`);
                }
            }
        }
    });

    console.log('Медиа-просмотрщик активирован. Панель в левом нижнем углу.');
    console.log('Панель неперемещаема, но ее можно изменять по размеру, потянув за края.');
    console.warn('Внимание: Запуск скриптов из консоли может быть небезопасным. Используйте этот скрипт только на надежных сайтах и понимая, что он делает.');

})();