哔哩哔哩(B站|Bilibili)收藏夹Fix(隐藏视频检测)

检测收藏夹中被up主设置为仅自己可见的视频

目前为 2024-11-20 提交的版本。查看 最新版本

// ==UserScript==
// @name              bilibili favlist hidden video detection
// @name:zh-CN        哔哩哔哩(B站|Bilibili)收藏夹Fix(隐藏视频检测)
// @name:zh-TW        嗶哩嗶哩(B站|Bilibili)收藏夾Fix(隱藏影片檢測)
// @namespace         http://tampermonkey.net/
// @version           1
// @description       detect videos in favlist that only visiable to upper
// @description:zh-CN 检测收藏夹中被up主设置为仅自己可见的视频
// @description:zh-TW 檢測收藏夾中被上傳者設定為僅自己可見的影片
// @author            YTB0710
// @match             https://space.bilibili.com/*
// @connect           api.bilibili.com
// @grant             GM_xmlhttpRequest
// @grant             GM_cookie
// @grant             GM_openInTab
// ==/UserScript==

(function () {
    'use strict';

    const textDictionary = {
        'ENTER_AV_OR_BV_HERE': {
            'zh-CN': '在此输入av号或bv号',
            'zh-TW': '在此輸入av號或bv號'
        },
        'DETECT_HIDDEN_VIDEO': {
            'zh-CN': '检测隐藏视频(先刷新页面)',
            'zh-TW': '檢測隱藏影片(先重新載入頁面)'
        },
        'GET_VIDEO_INFO': {
            'zh-CN': '查询视频信息(输入bv号)',
            'zh-TW': '查詢影片資訊(輸入bv號)'
        },
        'REMOVE_VIDEO': {
            'zh-CN': '取消收藏(输入av号)',
            'zh-TW': '取消收藏(輸入av號)'
        },
        'ADD_VIDEO': {
            'zh-CN': '添加收藏(输入av号)',
            'zh-TW': '新增收藏(輸入av號)'
        },
        'AV': {
            'zh-CN': 'av号',
            'zh-TW': 'av號'
        },
        'BV': {
            'zh-CN': 'bv号',
            'zh-TW': 'bv號'
        },
        'ENTER_AV': {
            'zh-CN': '请输入av号',
            'zh-TW': '請輸入av號'
        },
        'ENTER_BV': {
            'zh-CN': '请输入bv号',
            'zh-TW': '請輸入bv號'
        },
        'NO_HIDDEN_VIDEO_ON_THIS_PAGE': {
            'zh-CN': '本页没有隐藏的视频',
            'zh-TW': '本頁沒有隱藏的影片'
        },
        'POSITION_ON_THIS_PAGE': {
            'zh-CN': '在本页的位置(从1开始)',
            'zh-TW': '在本頁的位置(從1開始)'
        },
        'RESPONSE_CONTENT': {
            'zh-CN': 'b站接口响应内容',
            'zh-TW': 'b站介面回應內容'
        },
        'ERROR_COOKIE': {
            'zh-CN': '无法读取cookie, 请更新tampermonkey, 前往控制台查看错误信息',
            'zh-TW': '無法讀取cookie, 請更新tampermonkey, 前往控制台查看錯誤資訊'
        }
    };

    const preferredLanguage = getPreferredLanguage();

    function getPreferredLanguage() {
        const languages = navigator.languages || [navigator.language];
        for (const lang of languages) {
            if (lang === 'zh-CN') {
                return 'zh-CN';
            }
            if (lang === 'zh-TW') {
                return 'zh-TW';
            }
            if (lang === 'zh-HK') {
                return 'zh-TW';
            }
        }
        return 'zh-CN';
    }

    function getText(key) {
        return textDictionary[key][preferredLanguage];
    }

    const checkInterval = setInterval(function () {
        const favSidenav = document.querySelector('.fav-sidenav');
        if (!favSidenav) {
            return;
        }
        clearInterval(checkInterval);

        const watchLaterLink = favSidenav.querySelector('a.watch-later');
        watchLaterLink.style.borderBottom = '1px solid #eee';

        const settingsContainer = document.createElement('div');
        settingsContainer.classList.add('fix-settings-container');
        settingsContainer.style.borderTop = '1px solid #e4e9f0';
        settingsContainer.style.padding = '5px 5px';
        favSidenav.appendChild(settingsContainer);

        const inputTextContainer = document.createElement('div');
        inputTextContainer.classList.add('fix-inputText-container');
        inputTextContainer.style.padding = '5px 0';
        settingsContainer.appendChild(inputTextContainer);

        const inputText = document.createElement('input');
        inputText.type = 'text';
        inputText.classList.add('fix-inputText');
        inputText.placeholder = getText('ENTER_AV_OR_BV_HERE');
        inputTextContainer.appendChild(inputText);

        const buttonsContainer = document.createElement('div');
        buttonsContainer.classList.add('fix-buttons-container');
        buttonsContainer.style.padding = '5px 0';
        settingsContainer.appendChild(buttonsContainer);

        const buttonA = document.createElement('button');
        buttonA.type = 'button';
        buttonA.innerText = getText('DETECT_HIDDEN_VIDEO');
        buttonA.classList.add('fix-action-button');
        buttonA.addEventListener('click', function () {
            const fid = document.querySelector('.fav-item.cur').getAttribute('fid');
            const favAmount = document.querySelector('.fav-item.cur span.num').innerText;
            const lis = document.querySelectorAll('ul.fav-video-list li.small-item');
            if (favAmount == 0) {
                addInfo(getText('NO_HIDDEN_VIDEO_ON_THIS_PAGE'), 12);
                return;
            }
            const element = document.querySelector('.be-pager-next');
            let should;
            if (element && !element.classList.contains('be-pager-disabled')) {
                should = 20;
            } else {
                should = favAmount % 20;
            }
            if (lis.length === should) {
                addInfo(getText('NO_HIDDEN_VIDEO_ON_THIS_PAGE'), 12);
                return;
            }
            GM_xmlhttpRequest({
                method: 'GET',
                url: `https://api.bilibili.com/x/v3/fav/resource/ids?media_id=${fid}`,
                responseType: 'json',
                onload: function (response) {
                    const datas = response.response.data;
                    let position = 0;
                    if (lis.length) {
                        const firstBV = lis[0].getAttribute('data-aid');
                        position = datas.findIndex(data => data.bvid === firstBV);
                    }
                    const head = position % 20;
                    for (let i = 0; i < head; i++) {
                        addInfo(`${getText('BV')}: ${datas[position - head + i].bvid}`, 12);
                        addInfo(`${getText('AV')}: ${datas[position - head + i].id}`, 12);
                        addInfo(`${getText('POSITION_ON_THIS_PAGE')}: ${i + 1}`, 12);
                    }
                    for (let i = 0, j = 0; j < should - head; i++, j++) {
                        if (i >= lis.length || lis[i].getAttribute('data-aid') !== datas[j + position].bvid) {
                            addInfo(`${getText('BV')}: ${datas[j + position].bvid}`, 12);
                            addInfo(`${getText('AV')}: ${datas[j + position].id}`, 12);
                            addInfo(`${getText('POSITION_ON_THIS_PAGE')}: ${j + head + 1}`, 12);
                            i--;
                        }
                    }
                }
            });
        });

        const buttonAContainer = document.createElement('div');
        buttonAContainer.classList.add('fix-button-container');
        buttonAContainer.appendChild(buttonA);
        buttonsContainer.appendChild(buttonAContainer);

        const buttonB = document.createElement('button');
        buttonB.type = 'button';
        buttonB.innerText = getText('GET_VIDEO_INFO');
        buttonB.classList.add('fix-action-button');
        buttonB.addEventListener('click', function () {
            const bv = document.querySelector('div.fix-inputText-container input').value;
            if (!bv) {
                addInfo(getText('ENTER_BV'), 12);
                return;
            }
            GM_openInTab(`https://www.biliplus.com/video/${bv}`, { active: true, insert: false, setParent: true });
            GM_openInTab(`https://xbeibeix.com/video/${bv}`, { insert: false, setParent: true });
            GM_openInTab(`https://www.jijidown.com/video/${bv}`, { insert: false, setParent: true });
        });

        const buttonBContainer = document.createElement('div');
        buttonBContainer.classList.add('fix-button-container');
        buttonBContainer.appendChild(buttonB);
        buttonsContainer.appendChild(buttonBContainer);

        const buttonC = document.createElement('button');
        buttonC.type = 'button';
        buttonC.innerText = getText('REMOVE_VIDEO');
        buttonC.classList.add('fix-action-button');
        buttonC.addEventListener('click', function () {
            GM_cookie.list({ name: 'bili_jct' }, function (cookies, error) {
                if (!error) {
                    const av = document.querySelector('div.fix-inputText-container input').value;
                    if (!av) {
                        addInfo(getText('ENTER_AV'), 12);
                        return;
                    }
                    const id = document.querySelector('.fav-item.cur').getAttribute('fid');
                    const csrf = cookies[0].value;
                    const data = `resources=${av}%3A2&media_id=${id}&platform=web&csrf=${csrf}`;
                    GM_xmlhttpRequest({
                        method: 'POST',
                        url: 'https://api.bilibili.com/x/v3/fav/resource/batch-del',
                        data: data,
                        headers: {
                            'Content-Length': `${data.length}`,
                            'Content-Type': 'application/x-www-form-urlencoded'
                        },
                        onload: function (response) {
                            const json = response.response;
                            addInfo(json, 10);
                            addInfo(`${getText('RESPONSE_CONTENT')}:`, 12);
                        }
                    });
                } else {
                    console.error(error);
                    addInfo(getText('ERROR_COOKIE'), 12);
                }
            });
        });

        const buttonCContainer = document.createElement('div');
        buttonCContainer.classList.add('fix-button-container');
        buttonCContainer.appendChild(buttonC);
        buttonsContainer.appendChild(buttonCContainer);

        const buttonD = document.createElement('button');
        buttonD.type = 'button';
        buttonD.innerText = getText('ADD_VIDEO');
        buttonD.classList.add('fix-action-button');
        buttonD.addEventListener('click', function () {
            GM_cookie.list({ name: 'bili_jct' }, function (cookies, error) {
                if (!error) {
                    const av = document.querySelector('div.fix-inputText-container input').value;
                    if (!av) {
                        addInfo(getText('ENTER_AV'), 12);
                        return;
                    }
                    const id = document.querySelector('.fav-item.cur').getAttribute('fid');
                    const csrf = cookies[0].value;
                    const data = `rid=${av}&type=2&add_media_ids=${id}&csrf=${csrf}`;
                    GM_xmlhttpRequest({
                        method: 'POST',
                        url: 'https://api.bilibili.com/x/v3/fav/resource/deal',
                        data: data,
                        headers: {
                            'Content-Length': `${data.length}`,
                            'Content-Type': 'application/x-www-form-urlencoded'
                        },
                        onload: function (response) {
                            const json = response.response;
                            addInfo(json, 10);
                            addInfo(`${getText('RESPONSE_CONTENT')}:`, 12);
                        }
                    });
                } else {
                    console.error(error);
                    addInfo(getText('ERROR_COOKIE'), 12);
                }
            });
        });

        const buttonDContainer = document.createElement('div');
        buttonDContainer.classList.add('fix-button-container');
        buttonDContainer.appendChild(buttonD);
        buttonsContainer.appendChild(buttonDContainer);

        const textContainer = document.createElement('div');
        textContainer.classList.add('fix-text-container');
        textContainer.style.padding = '5px 0';
        settingsContainer.appendChild(textContainer);

        function addInfo(info, px) {
            const p = document.createElement('p');
            p.innerText = info;
            p.style.fontSize = `${px}px`;
            textContainer.insertAdjacentElement('afterbegin', p);
        }

    }, 300);
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址