AvBase Ultimate Enhancer

Enhances avbase.net with video previews, zoom sliders, Sukebei RSS results in a styled table, larger images, titles below images, original size image popups, and adds Jable, Missav, and videoId copy buttons with 404 transparency at the correct position.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @name         AvBase Ultimate Enhancer
// @namespace    http://tampermonkey.net/
// @version      2.3.2
// @description  Enhances avbase.net with video previews, zoom sliders, Sukebei RSS results in a styled table, larger images, titles below images, original size image popups, and adds Jable, Missav, and videoId copy buttons with 404 transparency at the correct position.
// @match        https://www.avbase.net/*
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // 合併後的樣式
    GM_addStyle(`
        .adaptive-container {
            height: auto !important;
            min-height: 100%;
            width: 100%;
            display: flex;
            flex-direction: column;
            grid-column: 1 / -1;
            align-items: center;
            overflow: visible;
        }
        .vertical-container {
            display: flex;
            flex-direction: column;
            align-items: center;
            width: 100%;
            overflow-x: auto;
            overflow-y: visible;
            height: auto;
        }
        .image-container {
            display: flex;
            flex-direction: column;
            align-items: center;
            width: 100%;
            gap: 1px;
            height: auto;
        }
        .scene-container {
            width: 100%;
            max-width: 800px;
            height: auto;
            min-height: 450px;
        }
        .table-wrapper {
            width: 100%;
            padding: 10px;
            height: auto;
        }
        .toggle-button {
            padding: 5px 295px;
            background-color: #1e293b;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            margin: 5px 0;
        }
        .toggle-button img {
            width: 20px;
            height: 20px;
            filter: brightness(100%) invert(1);
            transition: transform 0.2s ease;
        }
        .toggle-button:active img {
            transform: scale(1.2);
        }
        .controls-bar {
            width: 100%;
            max-width: 800px;
            background-color: #000000;
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 5px 10px;
            margin: 0;
            box-sizing: border-box;
        }
        .controls-bar button {
            background-color: #000000;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            padding: 5px;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: transform 0.2s ease;
            margin-right: 8px;
        }
        .controls-bar button:last-child {
            margin-right: 0;
        }
        .controls-bar button img {
            width: 20px;
            height: 20px;
            filter: brightness(100%) invert(1);
        }
        .controls-bar button:active {
            transform: scale(1.2);
        }
        .zoom-slider-container {
            display: flex;
            align-items: center;
            position: relative;
            margin: 0;
        }
        .zoom-button {
            background-color: #000000;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            padding: 5px;
            display: flex;
            align-items: center;
            justify-content: center;
            margin-right: 8px;
        }
        .zoom-button img {
            width: 20px;
            height: 20px;
            filter: brightness(100%) invert(1);
        }
        .zoom-slider {
            -webkit-appearance: none;
            appearance: none;
            width: 0;
            height: 6px;
            background: #1e293b;
            outline: none;
            opacity: 0;
            transition: opacity 0.3s ease, width 0.3s ease;
            border-radius: 4px;
            margin: 0 5px;
            vertical-align: middle;
        }
        .zoom-slider.show {
            opacity: 1;
            width: 70px;
        }
        .zoom-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 12px;
            height: 12px;
            background: #fff;
            cursor: pointer;
            border-radius: 50%;
        }
        .zoom-slider::-moz-range-thumb {
            width: 12px;
            height: 12px;
            background: #fff;
            cursor: pointer;
            border-radius: 50%;
        }
        .zoom-value {
            color: white;
            font-size: 12px;
            margin-right: 5px;
            width: 40px;
            text-align: right;
            opacity: 0;
            transition: opacity 0.3s ease;
            vertical-align: middle;
        }
        .zoom-value.show {
            opacity: 1;
        }
        .volume-slider-container {
            display: flex;
            align-items: center;
            position: relative;
        }
        .volume-slider {
            -webkit-appearance: none;
            appearance: none;
            width: 0;
            height: 6px;
            background: #1e293b;
            outline: none;
            opacity: 0;
            transition: opacity 0.3s ease, width 0.3s ease;
            border-radius: 4px;
            margin: 0 5px;
        }
        .volume-slider.show {
            opacity: 1;
            width: 70px;
        }
        .volume-slider:hover {
            opacity: 1;
        }
        .volume-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 12px;
            height: 12px;
            background: #fff;
            cursor: pointer;
            border-radius: 50%;
        }
        .volume-slider::-moz-range-thumb {
            width: 16px;
            height: 16px;
            background: #fff;
            cursor: pointer;
            border-radius: 50%;
        }
        .fullscreen-button {
            background-color: #000000;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            padding: 5px;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .fullscreen-button img {
            width: 20px;
            height: 20px;
            filter: brightness(100%) invert(1);
        }
        .table-wrapper svg {
            fill: white;
            width: 20px;
            height: 20px;
        }
        @media (min-width: 1024px) {
            .cl-container {
                width: 100%;
            }
        }
        .sm\\:grid-cols-2 {
            grid-template-columns: repeat(6, minmax(0, 1fr));
        }
        .sm\\:grid-cols-3 {
            grid-template-columns: repeat(6, minmax(0, 1fr));
        }
        .large-image {
            width: 100%;
            max-width: 100%;
            height: auto;
            object-fit: contain;
            display: block;
            border-radius: 4px;
            cursor: zoom-in;
        }
        .title-below-image {
            font-size: 0.75rem;
            display: -webkit-box;
            -webkit-line-clamp: 3;
            -webkit-box-orient: vertical;
            overflow: hidden;
            text-overflow: ellipsis;
            padding: 8px;
            text-align: center;
            color: #333;
            text-decoration: none;
            font-weight: bold;
            width: 100%;
            box-sizing: border-box;
        }
        .image-title-container {
            display: block;
            width: 100%;
            text-align: center;
        }
        .overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.8);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 1000;
            opacity: 0;
            transition: opacity 0.3s ease;
        }
        .overlay.show {
            opacity: 1;
        }
        .overlay-image {
            max-width: 90%;
            max-height: 90%;
            width: auto;
            height: auto;
            object-fit: contain;
            cursor: zoom-out;
            border-radius: 4px;
        }
        a-scene .a-canvas + div {
            display: none !important;
        }
        .jable-btn, .missav-btn, .copy-btn {
            display: flex;
            align-items: center;
            justify-content: center;
            height: 2rem;
            line-height: 2rem;
            text-align: center;
            background-color: #4b5563;
            color: white;
            border-radius: 0.25rem;
            font-size: 0.75rem;
            font-weight: normal;
            padding: 0 0.5rem;
            cursor: pointer;
        }
        .jable-btn, .missav-btn {
            width: 2rem;
        }
        .copy-btn {
            max-width: 10rem;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
        .transparent {
            background-color: transparent !important;
        }
        .jable-btn a, .missav-btn a {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 100%;
            height: 100%;
            color: inherit;
            text-decoration: none;
        }
    `);

    // 動態載入 A-Frame 庫
    function loadAFrame() {
        const aframeScript = document.createElement('script');
        aframeScript.src = 'https://aframe.io/releases/1.7.0/aframe.min.js';
        document.head.appendChild(aframeScript);
    }

    // 處理 DMM 鏈接
    function processDmmLink(link) {
        try {
            if (link.includes('al.dmm.co.jp')) {
                const urlParams = new URLSearchParams(new URL(link).search);
                const acred = urlParams.get('acred');
                if (acred) return decodeURIComponent(acred);
                const lurl = urlParams.get('lurl');
                if (lurl) return decodeURIComponent(lurl);
            }
            return link;
        } catch (error) {
            console.error('處理 DMM 鏈接時出錯:', error);
            return link;
        }
    }

    // 檢查圖片是否存在
    function checkImageExists(url) {
        return new Promise((resolve) => {
            const img = new Image();
            img.onload = () => resolve(true);
            img.onerror = () => resolve(false);
            img.src = url;
            setTimeout(() => resolve(false), 5000);
        });
    }

    // 檢查視頻可用性
    async function checkVideoAvailability(url) {
        try {
            const response = await fetch(url, { method: 'HEAD' });
            return response.ok;
        } catch (error) {
            console.error(`檢查 ${url} 失敗:`, error);
            return false;
        }
    }

    // 從圖片 URL 提取影片 ID 並構造更大圖片 URL
    function getLargerImageUrl(smallImageUrl) {
        let match = smallImageUrl.match(/\/([^\/]+)(ps|jm)\.jpg$/i);
        if (!match) return null;
        let videoId = match[1];
        const suffix = match[2].toLowerCase();

        if (suffix === 'ps' && smallImageUrl.includes('awsimgsrc.dmm.co.jp')) {
            if (/^[a-zA-Z]+[0-9]{3}$/.test(videoId)) {
                videoId = videoId.replace(/([a-zA-Z]+)([0-9]{3})/, '$100$2');
            }
            return `https://awsimgsrc.dmm.co.jp/pics_dig/digital/video/${videoId}/${videoId}pl.jpg`;
        }
        if (suffix === 'jm' && smallImageUrl.includes('pics.dmm.co.jp')) {
            return smallImageUrl.replace(/jm\.jpg$/i, 'jp.jpg');
        }
        return smallImageUrl.replace(/ps\.jpg$/i, 'pl.jpg');
    }

    // 獲取 Sukebei RSS 結果
    function fetchSukebeiResults(videoId) {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: 'GET',
                url: `https://sukebei.nyaa.si/?page=rss&q=${encodeURIComponent(videoId)}`,
                headers: {
                    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36",
                    "Referer": "https://sukebei.nyaa.si/"
                },
                onload: function(response) {
                    if (response.status === 200) {
                        let parser = new DOMParser();
                        let xmlDoc = parser.parseFromString(response.responseText, "text/xml");
                        let items = xmlDoc.getElementsByTagName("item");
                        let results = [];
                        for (let i = 0; i < items.length; i++) {
                            let item = items[i];
                            let title = item.getElementsByTagName("title")[0]?.textContent.trim() || "";
                            let link = item.getElementsByTagName("link")[0]?.textContent.trim() || "";
                            let size = item.getElementsByTagName("nyaa:size")[0]?.textContent.trim() || "";
                            let pubDate = item.getElementsByTagName("pubDate")[0]?.textContent.trim() || "";
                            let infoHash = item.getElementsByTagName("nyaa:infoHash")[0]?.textContent.trim() || "";
                            let magnet = infoHash ? "magnet:?xt=urn:btih:" + infoHash : "";
                            results.push({ name: title, link: link, size: size, date: pubDate, magnet: magnet });
                        }
                        resolve(results);
                    } else {
                        reject(`HTTP error: ${response.status}`);
                    }
                },
                onerror: function(err) {
                    reject(err);
                }
            });
        });
    }

    // 檢查 Jable 是否返回 404
    function checkJableAvailability(videoId) {
        return new Promise(resolve => {
            GM_xmlhttpRequest({
                method: 'GET',
                url: `https://jable.tv/videos/${encodeURIComponent(videoId)}/`,
                onload: response => {
                    const is404 = response.status === 404 ||
                                  response.responseText.includes('<title>404') ||
                                  response.responseText.includes('<h1>Not Found</h1>');
                    resolve(!is404);
                },
                onerror: () => resolve(false)
            });
        });
    }

    // 檢查 Missav 是否返回 404
    function checkMissavAvailability(videoId) {
        return new Promise(resolve => {
            GM_xmlhttpRequest({
                method: 'GET',
                url: `https://missav.ai/${encodeURIComponent(videoId)}`,
                onload: response => {
                    const is404 = response.responseText.includes('404') ||
                                  response.responseText.includes('找不到頁面');
                    resolve(!is404);
                },
                onerror: () => resolve(false)
            });
        });
    }

    // 圖片增強功能
    function enhanceImages() {
        const resultContainers = document.querySelectorAll('.bg-base.border.border-light.rounded-lg.overflow-hidden');
        if (!resultContainers.length) return;

        resultContainers.forEach((container) => {
            const imageLink = container.querySelector('div.flex.items-center.justify-center.bg-base2 a[rel="noopener noreferrer sponsored"] img');
            const titleLink = container.querySelector('a.text-md.font-bold.btn-ghost.rounded-lg.m-1[class*="line-clamp"]');

            if (imageLink && titleLink) {
                const smallImageUrl = imageLink.src;
                let largeImageUrl = smallImageUrl;

                if (smallImageUrl.match(/ps\.jpg$/i) && smallImageUrl.includes('awsimgsrc.dmm.co.jp')) {
                    let videoId = smallImageUrl.match(/\/([^\/]+)ps\.jpg$/i)[1];
                    if (/^[a-zA-Z]+[0-9]{3}$/.test(videoId)) {
                        videoId = videoId.replace(/([a-zA-Z]+)([0-9]{3})/, '$100$2');
                    }
                    largeImageUrl = `https://awsimgsrc.dmm.co.jp/pics_dig/digital/video/${videoId}/${videoId}pl.jpg`;
                } else if (smallImageUrl.match(/jm\.jpg$/i) && smallImageUrl.includes('pics.dmm.co.jp')) {
                    largeImageUrl = smallImageUrl.replace(/jm\.jpg$/i, 'jp.jpg');
                } else if (smallImageUrl.match(/ps\.jpg$/i)) {
                    largeImageUrl = smallImageUrl.replace(/ps\.jpg$/i, 'pl.jpg');
                }

                imageLink.src = largeImageUrl;
                imageLink.classList.add('large-image');

                const imageAnchor = imageLink.parentElement;
                const imageContainerDiv = imageAnchor.closest('.flex.items-center.justify-center.bg-base2.grow-0.shrink-0.w-28.h-40.basis-28');
                if (imageContainerDiv) {
                    imageContainerDiv.innerHTML = '';
                    imageContainerDiv.appendChild(imageLink);
                    imageContainerDiv.style.width = '100%';
                    imageContainerDiv.style.height = 'auto';
                    imageContainerDiv.style.display = 'block';
                    imageContainerDiv.style.padding = '0';
                }

                imageLink.addEventListener('click', async () => {
                    const overlay = document.createElement('div');
                    overlay.className = 'overlay';
                    const overlayImage = document.createElement('img');
                    overlayImage.className = 'overlay-image';

                    let finalImageUrl = largeImageUrl;
                    const largerImageUrl = getLargerImageUrl(smallImageUrl);
                    if (largerImageUrl) {
                        const largerImageExists = await checkImageExists(largerImageUrl);
                        if (largerImageExists) finalImageUrl = largerImageUrl;
                    }

                    if (smallImageUrl.match(/ps\.jpg$/i)) {
                        let videoId = smallImageUrl.match(/\/([^\/]+)ps\.jpg$/i)[1];
                        if (/^[a-zA-Z]+[0-9]{3}$/.test(videoId)) {
                            videoId = videoId.replace(/([a-zA-Z]+)([0-9]{3})/, '$100$2');
                        }
                        const awsPlImageUrl = `https://awsimgsrc.dmm.co.jp/pics_dig/digital/video/${videoId}/${videoId}pl.jpg`;
                        const awsImageExists = await checkImageExists(awsPlImageUrl);
                        if (awsImageExists) finalImageUrl = awsPlImageUrl;
                    }

                    overlayImage.src = finalImageUrl;
                    overlay.appendChild(overlayImage);
                    document.body.appendChild(overlay);
                    setTimeout(() => overlay.classList.add('show'), 10);

                    overlay.addEventListener('click', () => {
                        overlay.classList.remove('show');
                        setTimeout(() => overlay.remove(), 300);
                    });
                });

                const imageTitleContainer = document.createElement('div');
                imageTitleContainer.className = 'image-title-container';
                imageTitleContainer.appendChild(imageContainerDiv);

                titleLink.classList.remove('text-md');
                titleLink.classList.add('title-below-image');
                const titleContainer = titleLink.parentElement;
                titleContainer.style.display = 'block';
                titleContainer.style.margin = '0';
                imageTitleContainer.appendChild(titleContainer);

                const flexContainer = container.querySelector('.flex.min-w-0.border-y.border-light');
                if (flexContainer) {
                    flexContainer.innerHTML = '';
                    flexContainer.appendChild(imageTitleContainer);
                    flexContainer.style.display = 'block';
                }

                container.style.display = 'block';
            }
        });
    }

    // 視頻和詳情頁增強功能
    async function enhanceDetails() {
        if (!window.location.href.startsWith('https://www.avbase.net/works/')) return;

        loadAFrame();

        const container = document.querySelector('.flex.overflow-x-auto.overflow-y-hidden');
        if (!container) return;

        const titleLink = document.querySelector('h1.text-lg')?.parentElement;
        if (titleLink && titleLink.href && titleLink.href.includes('al.dmm.co.jp')) {
            titleLink.href = processDmmLink(titleLink.href);
        }

        const verticalContainer = document.createElement('div');
        verticalContainer.className = 'vertical-container';
        container.parentNode.replaceChild(verticalContainer, container);

        const parentContainer = verticalContainer.closest('.h-44.w-full.flex');
        if (parentContainer) {
            parentContainer.className = 'adaptive-container bg-base-300';
        }

        const codeElement = document.querySelector('span[dir="rtl"].pl-1.whitespace-nowrap.overflow-hidden.text-ellipsis');
        const code = codeElement ? codeElement.textContent.trim() : null;
        if (!code) return;

        // 添加 Jable、Missav 和複製按鈕
        const buttonContainer = document.querySelector('div.flex.gap-2.items-center');
        if (buttonContainer) {
            const targetSpan = buttonContainer.querySelector('span.text-xs.flex');
            if (targetSpan) {
                const videoIdElement = document.querySelector('div.flex.gap-2.items-center span.text-xs div span:not(.text-gray-400)') ||
                                      document.querySelector('span[dir="rtl"].pl-1.whitespace-nowrap.overflow-hidden.text-ellipsis');
                const videoId = videoIdElement ? videoIdElement.textContent.trim() : null;

                if (videoId && !buttonContainer.querySelector('.jable-btn') && !buttonContainer.querySelector('.missav-btn') && !buttonContainer.querySelector('.copy-btn')) {
                    const encodedVideoId = encodeURIComponent(videoId);

                    // Jable 按鈕
                    const jableButton = document.createElement('div');
                    jableButton.className = 'jable-btn';
                    const jableLink = document.createElement('a');
                    jableLink.href = `https://jable.tv/videos/${encodedVideoId}/`;
                    jableLink.target = '_blank';
                    jableLink.rel = 'noopener noreferrer';
                    jableLink.textContent = 'J';
                    jableButton.appendChild(jableLink);

                    // Missav 按鈕
                    const missavButton = document.createElement('div');
                    missavButton.className = 'missav-btn';
                    const missavLink = document.createElement('a');
                    missavLink.href = `https://missav.ai/${encodedVideoId}`;
                    missavLink.target = '_blank';
                    missavLink.rel = 'noopener noreferrer';
                    missavLink.textContent = 'M';
                    missavButton.appendChild(missavLink);

                    // 複製按鈕
                    const copyButton = document.createElement('div');
                    copyButton.className = 'copy-btn';
                    copyButton.textContent = encodedVideoId;
                    copyButton.title = '點擊複製 videoId';

                    // 動態設置按鈕寬度
                    const charWidth = 0.5;
                    const padding = 1;
                    const textWidth = encodedVideoId.length * charWidth;
                    const copiedWidth = 3 * charWidth;
                    const buttonWidth = Math.max(textWidth, copiedWidth) + padding;
                    copyButton.style.width = `${buttonWidth}rem`;

                    copyButton.addEventListener('click', () => {
                        navigator.clipboard.writeText(encodedVideoId).then(() => {
                            copyButton.textContent = '已復製';
                            setTimeout(() => copyButton.textContent = encodedVideoId, 1500);
                        }).catch(err => console.error('複製失敗:', err));
                    });

                    // 插入按鈕
                    buttonContainer.insertBefore(copyButton, targetSpan);
                    buttonContainer.insertBefore(missavButton, copyButton);
                    buttonContainer.insertBefore(jableButton, missavButton);

                    // 檢查 404 並設置背景
                    Promise.all([checkJableAvailability(videoId), checkMissavAvailability(videoId)])
                        .then(([jableAvailable, missavAvailable]) => {
                            if (!jableAvailable) jableButton.classList.add('transparent');
                            if (!missavAvailable) missavButton.classList.add('transparent');
                        });
                }
            }
        }

        let videoUrls = [];
        const isVR = code.toLowerCase().includes('vr') || code.toLowerCase().includes('aqu') || code.toLowerCase().includes('exmo') || code.startsWith('1fsvss');
        const prefix = code.includes('_') ? 'h_1' : code.substr(0, 3);

        if ((code.startsWith('1f') && !code.startsWith('1fsvss')) || code.startsWith('1m')) {
            videoUrls.push(`https://videos.vpdmm.cc/litevideo/freepv/${code.charAt(0)}/${code.substr(0,3)}/${code.substr(0,6)}${code.substr(8,3)}/${code.substr(0,6)}${code.substr(8,3)}4k.mp4`);
        }
        if (isVR) {
            videoUrls.push(`https://cc3001.dmm.com/vrsample/${code.charAt(0)}/${prefix}/${code}/${code}vrlite.mp4`);
        } else {
            videoUrls.push(`https://cc3001.dmm.com/litevideo/freepv/${code.charAt(0)}/${prefix}/${code}/${code}hhb.mp4`);
        }
        videoUrls.push(`https://cc3001.dmm.com/litevideo/freepv/${code.charAt(0)}/${prefix}/${code}/${code}_dmb_w.mp4`);
        if (code.includes('_')) {
            videoUrls.push(`https://cc3001.dmm.com/vrsample/${code.charAt(0)}/${prefix}/${code}/${code}vrlite.mp4`);
        }

        const availabilityChecks = videoUrls.map(url => checkVideoAvailability(url));
        const results = await Promise.all(availabilityChecks);
        const availableVideoUrl = videoUrls[results.findIndex(result => result)];

        if (availableVideoUrl) {
            const sceneContainer = document.createElement('div');
            sceneContainer.className = 'scene-container';
            verticalContainer.appendChild(sceneContainer);

            let isVRMode = isVR;
            let cameraZoom = 160;
            let lastVolume = 1;

            function initializePlayer() {
                sceneContainer.innerHTML = '';
                if (isVRMode) {
                    const scene = document.createElement('a-scene');
                    scene.setAttribute('embedded', '');
                    scene.setAttribute('vr-mode-ui', 'enabled: false');
                    sceneContainer.appendChild(scene);

                    const videoSphere = document.createElement('a-videosphere');
                    videoSphere.setAttribute('src', availableVideoUrl);
                    videoSphere.setAttribute('rotation', '0 -180 0');
                    videoSphere.setAttribute('phi-start', '0');
                    videoSphere.setAttribute('phi-length', '180');
                    videoSphere.setAttribute('autoplay', '');
                    videoSphere.setAttribute('muted', '');
                    scene.appendChild(videoSphere);

                    const camera = document.createElement('a-camera');
                    camera.setAttribute('position', `0 0 ${cameraZoom}`);
                    camera.setAttribute('rotation', '0 90 0');
                    scene.appendChild(camera);
                } else {
                    const videoElement = document.createElement('video');
                    videoElement.src = availableVideoUrl;
                    videoElement.controls = true;
                    videoElement.style.width = '100%';
                    videoElement.style.maxWidth = '800px';
                    videoElement.style.height = 'auto';
                    videoElement.style.aspectRatio = '16/9';
                    sceneContainer.appendChild(videoElement);
                    videoElement.addEventListener('loadeddata', () => videoElement.play());
                }
            }
            initializePlayer();

            const controlsBar = document.createElement('div');
            controlsBar.className = 'controls-bar';
            verticalContainer.appendChild(controlsBar);

            const leftControls = document.createElement('div');
            leftControls.style.display = 'flex';
            leftControls.style.alignItems = 'center';
            controlsBar.appendChild(leftControls);

            const rightControls = document.createElement('div');
            rightControls.style.display = 'flex';
            rightControls.style.alignItems = 'center';
            controlsBar.appendChild(rightControls);

            function createButton(svgUrl, onClick, comment) {
                const button = document.createElement('button');
                const img = document.createElement('img');
                img.src = svgUrl;
                img.style.width = '20px';
                img.style.height = '20px';
                button.appendChild(img);
                button.addEventListener('click', onClick);
                return button;
            }

            const playPauseButton = createButton(
                'https://raw.githubusercontent.com/leogfa/svg/b99823546f418d86bc5c3ecdd53b7c02e38cad9c/play.svg',
                () => {
                    const video = isVRMode ?
                        sceneContainer.querySelector('a-videosphere').components.material.material.map.image :
                        sceneContainer.querySelector('video');
                    if (video.paused) {
                        video.play();
                        playPauseButton.firstChild.src = 'https://raw.githubusercontent.com/leogfa/svg/b99823546f418d86bc5c3ecdd53b7c02e38cad9c/pause.svg';
                    } else {
                        video.pause();
                        playPauseButton.firstChild.src = 'https://raw.githubusercontent.com/leogfa/svg/b99823546f418d86bc5c3ecdd53b7c02e38cad9c/play.svg';
                    }
                },
                '播放/暫停按鈕'
            );
            leftControls.appendChild(playPauseButton);

            const rewindButton = createButton(
                'https://raw.githubusercontent.com/leogfa/svg/b99823546f418d86bc5c3ecdd53b7c02e38cad9c/seek-backward-10.svg',
                () => {
                    const video = isVRMode ?
                        sceneContainer.querySelector('a-videosphere').components.material.material.map.image :
                        sceneContainer.querySelector('video');
                    video.currentTime = Math.max(0, video.currentTime - 5);
                },
                '倒退5秒按鈕'
            );
            leftControls.appendChild(rewindButton);

            const forwardButton = createButton(
                'https://raw.githubusercontent.com/leogfa/svg/b99823546f418d86bc5c3ecdd53b7c02e38cad9c/seek-forward-10.svg',
                () => {
                    const video = isVRMode ?
                        sceneContainer.querySelector('a-videosphere').components.material.material.map.image :
                        sceneContainer.querySelector('video');
                    video.currentTime = Math.min(video.duration, video.currentTime + 5);
                },
                '快進5秒按鈕'
            );
            leftControls.appendChild(forwardButton);

            const volumeContainer = document.createElement('div');
            volumeContainer.className = 'volume-slider-container';
            const volumeButton = createButton(
                'https://raw.githubusercontent.com/leogfa/svg/b99823546f418d86bc5c3ecdd53b7c02e38cad9c/volume-high.svg',
                () => {
                    const video = isVRMode ?
                        sceneContainer.querySelector('a-videosphere').components.material.material.map.image :
                        sceneContainer.querySelector('video');
                    if (video.muted) {
                        video.muted = false;
                        video.volume = lastVolume;
                        volumeButton.firstChild.src = 'https://raw.githubusercontent.com/leogfa/svg/b99823546f418d86bc5c3ecdd53b7c02e38cad9c/volume-high.svg';
                    } else {
                        lastVolume = video.volume;
                        video.muted = true;
                        volumeButton.firstChild.src = 'https://raw.githubusercontent.com/leogfa/svg/b99823546f418d86bc5c3ecdd53b7c02e38cad9c/mute.svg';
                    }
                },
                '音量開關按鈕'
            );
            const volumeSlider = document.createElement('input');
            volumeSlider.type = 'range';
            volumeSlider.className = 'volume-slider';
            volumeSlider.min = '0';
            volumeSlider.max = '1';
            volumeSlider.step = '0.01';
            volumeSlider.value = '1';
            volumeSlider.addEventListener('input', () => {
                const video = isVRMode ?
                    sceneContainer.querySelector('a-videosphere').components.material.material.map.image :
                    sceneContainer.querySelector('video');
                video.muted = false;
                video.volume = parseFloat(volumeSlider.value);
                lastVolume = video.volume;
                volumeButton.firstChild.src = video.volume === 0 ?
                    'https://raw.githubusercontent.com/leogfa/svg/b99823546f418d86bc5c3ecdd53b7c02e38cad9c/mute.svg' :
                    'https://raw.githubusercontent.com/leogfa/svg/b99823546f418d86bc5c3ecdd53b7c02e38cad9c/volume-high.svg';
            });
            volumeContainer.appendChild(volumeButton);
            volumeContainer.appendChild(volumeSlider);
            volumeContainer.addEventListener('mouseenter', () => {
                volumeSlider.classList.add('show');
            });
            volumeContainer.addEventListener('mouseleave', () => {
                volumeSlider.classList.remove('show');
            });
            leftControls.appendChild(volumeContainer);

            const zoomContainer = document.createElement('div');
            zoomContainer.className = 'zoom-slider-container';
            const zoomButton = document.createElement('button');
            zoomButton.className = 'zoom-button';
            const zoomImg = document.createElement('img');
            zoomImg.src = 'https://raw.githubusercontent.com/leogfa/svg/b99823546f418d86bc5c3ecdd53b7c02e38cad9c/search.svg';
            zoomImg.style.width = '20px';
            zoomImg.style.height = '20px';
            zoomButton.appendChild(zoomImg);
            const zoomSlider = document.createElement('input');
            zoomSlider.type = 'range';
            zoomSlider.className = 'zoom-slider';
            zoomSlider.min = '-480';
            zoomSlider.max = '480';
            zoomSlider.step = '10';
            zoomSlider.value = '160';
            const zoomValue = document.createElement('span');
            zoomValue.className = 'zoom-value';
            zoomValue.textContent = '160';
            zoomButton.addEventListener('click', () => {
                zoomSlider.classList.toggle('show');
                zoomValue.classList.toggle('show');
            });
            zoomSlider.addEventListener('input', () => {
                if (!isVRMode) return;
                const camera = sceneContainer.querySelector('a-camera');
                if (!camera) return;
                cameraZoom = parseFloat(zoomSlider.value);
                camera.setAttribute('position', `0 0 ${cameraZoom}`);
                zoomValue.textContent = cameraZoom;
            });
            zoomContainer.appendChild(zoomValue);
            zoomContainer.appendChild(zoomSlider);
            zoomContainer.appendChild(zoomButton);
            rightControls.appendChild(zoomContainer);

            const togglePlayerButton = createButton(
                isVRMode ? 'https://raw.githubusercontent.com/leogfa/svg/b99823546f418d86bc5c3ecdd53b7c02e38cad9c/2d-label-icon.svg' : 'https://raw.githubusercontent.com/leogfa/svg/b99823546f418d86bc5c3ecdd53b7c02e38cad9c/vr-label-icon.svg',
                () => {
                    const video = isVRMode ?
                        sceneContainer.querySelector('a-videosphere')?.components.material.material.map.image :
                        sceneContainer.querySelector('video');
                    if (video) {
                        video.pause();
                        video.currentTime = 0;
                    }
                    isVRMode = !isVRMode;
                    initializePlayer();
                    togglePlayerButton.firstChild.src = isVRMode ?
                        'https://raw.githubusercontent.com/leogfa/svg/b99823546f418d86bc5c3ecdd53b7c02e38cad9c/2d-label-icon.svg' :
                        'https://raw.githubusercontent.com/leogfa/svg/b99823546f418d86bc5c3ecdd53b7c02e38cad9c/vr-label-icon.svg';
                },
                '2D/VR切換按鈕'
            );
            rightControls.appendChild(togglePlayerButton);

            const fullscreenButton = createButton(
                'https://raw.githubusercontent.com/leogfa/svg/65fdb85e8047e4b5b6e221e5516962c534d8efb6/fullscreen.svg',
                () => {
                    if (!document.fullscreenElement) {
                        sceneContainer.requestFullscreen().catch(err => {
                            console.error('無法進入全螢幕:', err);
                        });
                    } else {
                        document.exitFullscreen();
                    }
                },
                '全螢幕切換按鈕'
            );
            fullscreenButton.className = 'fullscreen-button';
            rightControls.appendChild(fullscreenButton);
        }

        const imageContainer = document.createElement('div');
        imageContainer.className = 'image-container';
        imageContainer.style.display = 'none';
        verticalContainer.appendChild(imageContainer);

        container.querySelectorAll('a').forEach(link => {
            let newSrc = link.href;
            if (newSrc.includes('al.dmm.co.jp')) {
                newSrc = processDmmLink(newSrc);
            }
            const img = link.querySelector('img');
            if (img) {
                img.src = newSrc;
                img.style.width = 'auto';
                img.style.height = 'auto';
                img.style.maxWidth = '100%';
                img.style.objectFit = 'contain';
            }
            link.href = newSrc;
            link.style.display = 'block';
            link.style.width = 'auto';
            link.style.height = 'auto';
            imageContainer.appendChild(link);
        });

        const toggleButton = document.createElement('button');
        const toggleImg = document.createElement('img');
        toggleImg.src = 'https://raw.githubusercontent.com/leogfa/svg/b99823546f418d86bc5c3ecdd53b7c02e38cad9c/eye.svg';
        toggleImg.style.width = '20px';
        toggleImg.style.height = '20px';
        toggleButton.appendChild(toggleImg);
        toggleButton.className = 'toggle-button';
        toggleButton.addEventListener('click', () => {
            imageContainer.style.display = imageContainer.style.display === 'none' ? 'flex' : 'none';
            toggleImg.src = imageContainer.style.display === 'none' ?
                'https://raw.githubusercontent.com/leogfa/svg/b99823546f418d86bc5c3ecdd53b7c02e38cad9c/eye.svg' :
                'https://raw.githubusercontent.com/leogfa/svg/b99823546f418d86bc5c3ecdd53b7c02e38cad9c/no-eye.svg';
            verticalContainer.style.height = 'auto';
            parentContainer.style.height = 'auto';
        });
        verticalContainer.insertBefore(toggleButton, imageContainer);

        const videoIdElement = document.querySelector('div.flex.gap-2.items-center span.text-xs div span:not(.text-gray-400)');
        const videoId = videoIdElement ? videoIdElement.textContent.trim() : null;
        if (videoId) {
            fetchSukebeiResults(videoId).then(results => {
                let tableWrapper = document.createElement('div');
                tableWrapper.className = 'table-wrapper';

                let table = document.createElement('table');
                table.style.width = '100%';
                table.style.borderCollapse = 'collapse';
                table.style.fontSize = '12px';
                table.style.margin = '0';

                if (results.length) {
                    results.forEach(result => {
                        let tr = document.createElement('tr');

                        let tdName = document.createElement('td');
                        tdName.style.padding = '8px';
                        tdName.style.border = '1px solid #ddd';
                        tdName.style.width = '60%';
                        tdName.textContent = result.name;
                        tr.appendChild(tdName);

                        let tdLink = document.createElement('td');
                        tdLink.style.padding = '8px';
                        tdLink.style.border = '1px solid #ddd';
                        tdLink.style.textAlign = 'center';
                        tdLink.style.width = '15%';
                        let iconWrapper = document.createElement('div');
                        iconWrapper.style.display = 'inline-flex';
                        iconWrapper.style.gap = '8px';
                        iconWrapper.style.alignItems = 'center';
                        let aTorrent = document.createElement('a');
                        aTorrent.href = result.link;
                        aTorrent.target = '_blank';
                        aTorrent.innerHTML = `<img src="https://raw.githubusercontent.com/leogfa/svg/fde17c8702542028c186c6fb170a8bc26a6c1be5/download.svg" style="width: 24px; height: 24px; filter: brightness(100%) invert(1);">`;
                        iconWrapper.appendChild(aTorrent);
                        let btnMagnet = document.createElement('button');
                        btnMagnet.style.background = 'none';
                        btnMagnet.style.border = 'none';
                        btnMagnet.style.cursor = 'pointer';
                        btnMagnet.innerHTML = `<img src="https://raw.githubusercontent.com/leogfa/svg/3edada4e4c0a5c1a83938a427459a488d22ec6a4/magnet.svg" style="width: 24px; height: 24px; filter: brightness(100%) invert(1);">`;
                        btnMagnet.addEventListener('click', () => {
                            if (navigator.clipboard) {
                                navigator.clipboard.writeText(result.magnet).then(() => {
                                    btnMagnet.textContent = '已複製';
                                    setTimeout(() => {
                                        btnMagnet.innerHTML = `<img src="https://raw.githubusercontent.com/leogfa/svg/3edada4e4c0a5c1a83938a427459a488d22ec6a4/magnet.svg" style="width: 24px; height: 24px; filter: brightness(100%) invert(1);">`;
                                    }, 1500);
                                });
                            }
                        });
                        iconWrapper.appendChild(btnMagnet);
                        tdLink.appendChild(iconWrapper);
                        tr.appendChild(tdLink);

                        let tdSize = document.createElement('td');
                        tdSize.style.padding = '8px';
                        tdSize.style.border = '1px solid #ddd';
                        tdSize.style.textAlign = 'center';
                        tdSize.style.width = '10%';
                        tdSize.textContent = result.size;
                        tr.appendChild(tdSize);

                        let tdDate = document.createElement('td');
                        tdDate.style.padding = '8px';
                        tdDate.style.border = '1px solid #ddd';
                        tdDate.style.textAlign = 'center';
                        tdDate.style.width = '15%';
                        let d = new Date(result.date);
                        function pad(n) { return n < 10 ? "0" + n : n; }
                        let formattedDate = `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}`;
                        tdDate.textContent = formattedDate;
                        tr.appendChild(tdDate);

                        table.appendChild(tr);
                    });
                } else {
                    let noResultRow = document.createElement('tr');
                    let noResultTd = document.createElement('td');
                    noResultTd.colSpan = "4";
                    noResultTd.style.padding = '8px';
                    noResultTd.style.textAlign = 'center';
                    noResultTd.textContent = '找不到Seed';
                    noResultRow.appendChild(noResultTd);
                    table.appendChild(noResultRow);
                }
                tableWrapper.appendChild(table);
                imageContainer.insertAdjacentElement('afterend', tableWrapper);
            }).catch(err => {
                console.error('Sukebei RSS 搜尋失敗: ', err);
            });
        }
    }

    // 主初始化函數
    function initialize() {
        if (!window.location.href.startsWith('https://www.avbase.net/works/')) {
            enhanceImages();
        }
        enhanceDetails();

        let lastUrl = location.href;
        const urlObserver = new MutationObserver(() => {
            const url = location.href;
            if (url !== lastUrl) {
                lastUrl = url;
                enhanceImages();
                enhanceDetails();
            }
        });
        urlObserver.observe(document, { subtree: true, childList: true });

        const contentObserver = new MutationObserver(() => {
            if (!window.location.href.startsWith('https://www.avbase.net/works/')) {
                enhanceImages();
            } else {
                enhanceDetails();
            }
        });
        contentObserver.observe(document.body, { childList: true, subtree: true });
    }

    initialize();
})();