unlock lpsg videos

unlock lpsg video access. may need to manually switch video format since I can't figure that part out. Also load all images ASAP instead of having to scroll to them. Also added a button on top left to hide user info, so you can browse the page more quickly.

// ==UserScript==
// @name         unlock lpsg videos
// @namespace    MBing
// @version      6.0
// @description  unlock lpsg video access. may need to manually switch video format since I can't figure that part out. Also load all images ASAP instead of having to scroll to them. Also added a button on top left to hide user info, so you can browse the page more quickly.
// @author       MBing
// @match        https://www.lpsg.com/threads*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=lpsg.com
// @grant        none
// @license            MIT
// ==/UserScript==

(function() {
    'use strict';

    // 控制是否继续切换后缀
    let shouldContinue = true;
    var volume=0.05;
    var autoSwitchInterval=2500

    //加快照片加载
    //speedupPicLoading();
    //替换不能播放的视频
    replaceUnplayableVideos();
    //增加隐藏用户信息按钮
    createButtonToHideUserInfo();
    //增加向前翻页选择框
    createCheckboxToAutoJumpBackward();
    //增加纯文字页自动翻页选择框
    createCheckboxToAutoJumpTextOnlyPage();
    //增加隐藏纯文字帖子按钮
    createButtonToHideTextOnlyPost();



        //隐藏用户信息的部分
    function createButtonToHideUserInfo(){
        // 用于存储用户的选择状态
        const hideUserInfoKey = 'hideUserInfo';

        // 动态获取当前的隐藏状态
        function getIsUserInfoHidden() {
            return localStorage.getItem(hideUserInfoKey) === 'true';
        }

        // 添加开关按钮
        const toggleButton = document.createElement('button');
        toggleButton.style.position = 'fixed';
        toggleButton.style.top = '5px';
        toggleButton.style.left = '5px';
        toggleButton.style.zIndex = '999999';
        toggleButton.style.padding = '5px 10px';
        toggleButton.style.fontSize = '14px';
        toggleButton.style.backgroundColor = '#a18705';
        toggleButton.style.color = 'white';
        toggleButton.style.border = 'none';
        toggleButton.style.borderRadius = '5px';
        toggleButton.style.cursor = 'pointer';

        // 初始按钮文本
        toggleButton.textContent = getIsUserInfoHidden() ? 'Show User Info' : 'Hide User Info';

        // 添加按钮到页面
        document.body.appendChild(toggleButton);

        // 切换隐藏状态的函数
        function toggleVisibility() {
            const newState = !getIsUserInfoHidden(); // 获取新的状态

            // 更新本地存储
            localStorage.setItem(hideUserInfoKey, newState.toString());

            // 更新按钮文本
            toggleButton.textContent = newState ? 'Show User Info' : 'Hide User Info';

            // 更新元素的显示状态
            document.querySelectorAll('.message-userExtras').forEach(element => {
                element.style.display = newState ? 'none' : '';
            });
        }

        // 初始状态设置
        if (getIsUserInfoHidden()) {
            document.querySelectorAll('.message-userExtras').forEach(element => {
                element.style.display = 'none';
            });
        }

        // 绑定点击事件
        toggleButton.addEventListener('click', toggleVisibility);
    }





        //用于控制向前跳还是向后跳
    function createCheckboxToAutoJumpBackward(){
        // 检查localStorage中是否存在autoJumpBackward变量,若不存在则初始化为false
        if (localStorage.getItem('autoJumpBackward') === null) {
            localStorage.setItem('autoJumpBackward', 'false');
        }

        // 创建一个勾选框
        const checkbox2 = document.createElement('input');
        checkbox2.type = 'checkbox';
        checkbox2.id = 'autoJumpBackward';

        // 根据localStorage的值设置勾选框的初始状态
        if (localStorage.getItem('autoJumpBackward') === 'true') {
            checkbox2.checked = true;
        } else {
            checkbox2.checked = false;
        }

        // 创建一个标签用于描述勾选框
        const label2 = document.createElement('label');
        label2.htmlFor = 'autoJumpBackward';
        label2.textContent = 'Skip Backward';

        // 创建一个容器用于放置勾选框和标签
        const container2 = document.createElement('div');
        container2.id = 'autoJumpcontainer2';
        container2.appendChild(checkbox2);
        container2.appendChild(label2);
        container2.style.position = 'fixed';
        container2.style.top = '5px';
        container2.style.left = '498px';
        container2.style.zIndex = '999999';
        container2.style.padding = '5px 10px';
        container2.style.fontSize = '14px';
        container2.style.backgroundColor = '#a18705';
        container2.style.color = 'white';
        container2.style.border = 'none';
        container2.style.borderRadius = '5px';
        container2.style.cursor = 'pointer';

        // 将容器添加到页面顶部
        document.body.appendChild(container2);

        // 添加事件监听器,更新localStorage的值
        checkbox2.addEventListener('change', function() {
            localStorage.setItem('autoJumpBackward', this.checked ? 'true' : 'false');
        });
    }



        //用于控制是否跳转纯文字页面
    function createCheckboxToAutoJumpTextOnlyPage(){
        // 检查localStorage中是否存在autoJumpTextOnlyPage变量,若不存在则初始化为false
        if (localStorage.getItem('autoJumpTextOnlyPage') === null) {
            localStorage.setItem('autoJumpTextOnlyPage', 'false');
        }

        // 创建一个勾选框
        const checkbox = document.createElement('input');
        checkbox.type = 'checkbox';
        checkbox.id = 'autoJumpCheckbox';

        // 根据localStorage的值设置勾选框的初始状态
        if (localStorage.getItem('autoJumpTextOnlyPage') === 'true') {
            checkbox.checked = true;
        } else {
            checkbox.checked = false;
        }

        // 创建一个标签用于描述勾选框
        const label = document.createElement('label');
        label.htmlFor = 'autoJumpCheckbox';
        label.textContent = 'Autoskip Textonly Pages';

        // 创建一个容器用于放置勾选框和标签
        const container = document.createElement('div');
        container.id = 'autoJumpContainer';
        container.appendChild(checkbox);
        container.appendChild(label);
        container.style.position = 'fixed';
        container.style.top = '5px';
        container.style.left = '292px';
        container.style.zIndex = '999999';
        container.style.padding = '5px 10px';
        container.style.fontSize = '14px';
        container.style.backgroundColor = '#a18705';
        container.style.color = 'white';
        container.style.border = 'none';
        container.style.borderRadius = '5px';
        container.style.cursor = 'pointer';

        // 将容器添加到页面顶部
        document.body.appendChild(container);

        // 添加事件监听器,更新localStorage的值
        checkbox.addEventListener('change', function() {
            localStorage.setItem('autoJumpTextOnlyPage', this.checked ? 'true' : 'false');
        });

    }









        //隐藏没有图片或视频的post
    function createButtonToHideTextOnlyPost(){

        // 用于存储用户的选择状态
        const hideTextOnlyKey = 'hideTextOnlyPost';

        // 动态获取当前的隐藏状态
        function getTextIsHidden() {
            return localStorage.getItem(hideTextOnlyKey) === 'true';
        }

        // 添加开关按钮
        const toggleButton2 = document.createElement('button');
        toggleButton2.style.position = 'fixed';
        toggleButton2.style.top = '5px';
        toggleButton2.style.left = '135px';
        toggleButton2.style.zIndex = '999999';
        toggleButton2.style.padding = '5px 10px';
        toggleButton2.style.fontSize = '14px';
        toggleButton2.style.backgroundColor = '#a18705';
        toggleButton2.style.color = 'white';
        toggleButton2.style.border = 'none';
        toggleButton2.style.borderRadius = '5px';
        toggleButton2.style.cursor = 'pointer';

        // 初始按钮文本
        toggleButton2.textContent = getTextIsHidden() ? 'Show Textonly Post' : 'Hide Textonly Post';

        // 添加按钮到页面
        document.body.appendChild(toggleButton2);


        // 绑定点击事件
        toggleButton2.addEventListener('click', toggleTextOnlyPost);

        // 初始状态设置
        if (getTextIsHidden()) {
            HideTextOnlyPosts();
        }else{
            ShowAllPosts();
        }

        // 切换隐藏状态的函数
        function toggleTextOnlyPost() {
            const newState = !getTextIsHidden(); // 获取新的状态

            // 更新本地存储
            localStorage.setItem(hideTextOnlyKey, newState.toString());

            // 更新按钮文本
            toggleButton2.textContent = newState ? 'Show Textonly Post' : 'Hide Textonly Post';

            // 更新元素的显示状态
            if(newState){
                HideTextOnlyPosts();
            }else{
                ShowAllPosts();
            }
        }

        //隐藏只有文字的帖子
        function HideTextOnlyPosts() {
            //显示额外选项
            const container = document.getElementById('autoJumpContainer');
            container.style.display = '';
            const container2 = document.getElementById('autoJumpcontainer2');
            container2.style.display = '';

            // 获取所有符合条件的article元素
            const articles = document.querySelectorAll('article.message.message--post.js-post.js-inlineModContainer');
            var textPostCount=0;
            var nonTextPostCount=0;

            articles.forEach(article => {
                // 获取每个article中的message-content元素
                const content = article.querySelector('.message-content.js-messageContent');
                if (content) {
                    // 检查message-content中是否存在video元素
                    const hasVideo = content.querySelector('video') !== null;

                    // 检查message-content中是否存在iframe元素
                    const hasIframe = content.querySelector('iframe') !== null;

                    // 检查message-content中是否存在非emoji的img元素
                    var hasValidImage = Array.from(content.querySelectorAll('img')).some(img => {
                        // 检查img元素的class属性是否包含"emoji"字样
                        return !img.className.includes('smilie');
                    });


                    //如果想连图片也跳过,用下面这句
                    //hasValidImage=false;

                    // 如果没有视频且没有非emoji的图片,则隐藏整个article
                    if (!hasVideo && !hasValidImage&& !hasIframe) {
                        textPostCount+=1;
                        article.style.display = 'none';
                    }else{
                        nonTextPostCount+=1;
                    }
                }
            });
            //如果是纯文字页面,自动跳转下一页
            if(nonTextPostCount==0){
                autoClickNextPage();
            }
            console.log("隐藏了"+textPostCount+"篇");
        }

        //显示所有帖子
        function ShowAllPosts() {
            //隐藏额外选项
            const container = document.getElementById('autoJumpContainer');
            container.style.display = 'none';
            const container2 = document.getElementById('autoJumpcontainer2');
            container2.style.display = 'none';
            // 获取所有符合条件的article元素
            const articles = document.querySelectorAll('article.message.message--post.js-post.js-inlineModContainer');
            articles.forEach(article => {
                article.style.display = '';
            });
        }

        // 自动跳转下一页
        function autoClickNextPage() {
            // 获取勾选框
            const checkbox = document.getElementById('autoJumpCheckbox');
            if (!checkbox) {
                console.warn('未找到勾选框,脚本无法运行。');
                return;
            }
            const checkbox2 = document.getElementById('autoJumpBackward');
            if (!checkbox2) {
                console.warn('未找到往前翻勾选框,脚本无法运行。');
                return;
            }

            // 如果勾选框被选中
            if (checkbox.checked) {
                // 查找页面上第一个class="pageNav-jump pageNav-jump--next"的<a>元素
                var nextLink;
                if(checkbox2.checked){
                    nextLink = document.querySelector('a.pageNav-jump.pageNav-jump--prev');
                }else{
                    nextLink = document.querySelector('a.pageNav-jump.pageNav-jump--next');
                }
                if (nextLink) {
                    console.log('自动点击下一页按钮');
                    nextLink.click(); // 模拟点击
                } else {
                    console.warn('未找到下一页按钮');
                }
            }
        }
    }







    function speedupPicLoading(){
        //#改变图片加载速度的部分
        // 获取所有包含 lazy loading 的图片
        const images = document.querySelectorAll('img[loading="lazy"]');

        // 遍历所有懒加载图片,将其 loading 属性更改为 "eager"
        images.forEach(img => {
            img.loading = 'eager'; // 立刻加载图片
        });
    }

        //替换视频的部分
    function replaceUnplayableVideos(){
        var easterEggPoster = document.getElementsByClassName("video-easter-egg-poster");
        var videoDiv=[];
        var imageUrl;
        var newDiv;
        var baseVideoUrl;

        if(easterEggPoster.length==0){
            //console.log("官方时间,无需替换");
            //把官方时间的视频放大然后静音
            enlargeAndMuteVideo();
            return;
        }else if(easterEggPoster.length>5){
            autoSwitchInterval=5000;
        }


        //替换预览照片为视频播放器
        for (let i=easterEggPoster.length-1;i>-1;i--){
            let videoUrl
            imageUrl =easterEggPoster[i].children[0].src;
            videoUrl=imageUrl.replace("attachments/posters","video").replace("/lsvideo/thumbnails","lsvideo/videos").replace(".jpg",".mp4");


            videoDiv[i]=`<video onloadstart="this.volume=${volume}" style="width:750px; max-height: 750px;" controls=\"\" data-xf-init=\"video-init\" data-poster=\"${imageUrl}\" class=\"\" style=\"\" poster=\"${imageUrl}\"><source data-src=\"${videoUrl}\" src=\"${videoUrl}\"><div class=\"bbMediaWrapper-fallback\">Your browser is not able to display this video.</div></video>`;

            //videoDiv[i]=`<video controls=\"\" data-xf-init=\"video-init\" data-poster=\"${imageUrl}\" class=\"\" style=\"\" poster=\"${imageUrl}\"><source data-src=\"${videoUrl}\" src=\"${videoUrl}\"><div class=\"bbMediaWrapper-fallback\">Your browser is not able to display this video.</div></video>`;


            newDiv = document.createElement("div");
            newDiv.setAttribute("class","newVideoDiv");
            newDiv.innerHTML=videoDiv[i];
            easterEggPoster[i].parentElement.parentElement.append(newDiv);
            //console.log("正在插入第几条:"+i+",url:"+videoUrl)
            easterEggPoster[i].parentElement.parentElement.append(createButton("mov",i));
            easterEggPoster[i].parentElement.parentElement.append(createButton("m4v",i));
            easterEggPoster[i].parentElement.parentElement.append(createButton("mp4",i));
        }

        //删除easterEggPoster
        for (let i=easterEggPoster.length-1;i>-1;i--){
            easterEggPoster[i].parentElement.parentElement.removeChild(easterEggPoster[i].parentElement);
        }

        //删除video-easter-egg-blocker
        var easterEggBlocker = document.getElementsByClassName("video-easter-egg-blocker");
        for (let i=easterEggBlocker.length-1;i>-1;i--){
            easterEggBlocker[i].parentElement.removeChild(easterEggBlocker[i]);
        }

        //删除video-easter-egg-overlay
        var easterEggOverlay = document.getElementsByClassName("video-easter-egg-overlay");
        for (let i=easterEggOverlay.length-1;i>-1;i--){
            easterEggOverlay[i].parentElement.removeChild(easterEggOverlay[i]);
        }

        /**
    //调小音量
    var allVideoPlayers = document.getElementsByTagName('video');
    for (let i=allVideoPlayers.length-1;i>-1;i--){
        allVideoPlayers[i].volume = volume;
    }
**/

        //把官方时间的视频放大然后静音
        enlargeAndMuteVideo();

        // 延时后开始检查视频
        setTimeout(checkVideosAndUpdate, autoSwitchInterval);
    }

    //创建按钮
    function createButton(format,entryId){
        var inp;
        inp = document.createElement("input");
        inp.type = "button";
        inp.value = format;
        inp.id = entryId;
        inp.addEventListener('click', function () {
            //点击任何手动切换后缀按钮,即停止自动切换后缀
            shouldContinue = false;
            //console.log('停止切换后缀');
            //切换后缀
            var oldUrl = document.getElementsByClassName("newVideoDiv")[this.id].innerHTML;
            document.getElementsByClassName("newVideoDiv")[this.id].innerHTML=oldUrl.replaceAll("mp4",format).replaceAll("m4v",format).replaceAll("mov",format);
        });
        return inp;
    }


    // 定义一个函数,用于遍历所有 video 元素并检查其 readyState
    function checkVideosAndUpdate() {
        // 如果点击了停止按钮,则不再继续执行
        if (!shouldContinue) return;

        // 获取页面上所有的 video 元素
        const videoElements = document.querySelectorAll('video');

        let allLoaded = true;
        let failCount=0;
        // 遍历所有 video 元素
        videoElements.forEach(videoElement => {
            // 获取当前视频的 readyState
            const state = videoElement.readyState;

            // 如果视频的 readyState 不是 4(HAVE_ENOUGH_DATA),说明视频还没有加载完成
            if (state !== 4) {
                failCount+=1;
                allLoaded = false;

                // 获取视频中的所有 source 标签
                const sources = videoElement.querySelectorAll('source');
                sources.forEach(source => {
                    // 获取当前 source 的 src 和 data-src 属性
                    const currentSrc = source.src || source.getAttribute('data-src');

                    // 根据原视频格式替换为对应的新格式
                    let newSrc = currentSrc;
                    if (currentSrc.endsWith('.mp4')) {
                        newSrc = currentSrc.replace('.mp4', '.mov');
                    } else if (currentSrc.endsWith('.mov')) {
                        newSrc = currentSrc.replace('.mov', '.m4v');
                    } else if (currentSrc.endsWith('.m4v')) {
                        newSrc = currentSrc.replace('.m4v', '.mp4');
                    }

                    // 更新 source 的 src 和 data-src 属性为新的链接
                    //console.log(`替换视频链接: ${currentSrc} 为 ${newSrc}`);
                    source.src = newSrc;
                    source.setAttribute('data-src', newSrc);
                });

                // 重新加载视频
                videoElement.load();
            }
        });

        // 如果还有未加载完成的 video,则延时 2 秒再次执行
        if (!allLoaded) {
            //console.log(failCount+"条视频加载失败,稍后切换后缀重试");
            setTimeout(checkVideosAndUpdate, autoSwitchInterval);
        } else {
            //console.log("所有视频都已加载完成!");
        }
    }

    //把官方时间的视频放大然后静音
    function enlargeAndMuteVideo(){
        // 获取页面上所有的 video 元素
        const videos = document.querySelectorAll('video');
        var count=0;
        videos.forEach(video => {
            const parent = video.parentElement;

            // 检查父元素的 className 是否不是 'newVideoDiv'
            if (parent.className !== 'newVideoDiv') {
                count+=1;
                // 设置 video 的样式
                video.style.width = '750px';
                video.style.maxHeight = '750px';

                // 设置 video 的音量为 0
                video.volume = volume;

                // 将 video 提升到父元素的同级位置,并放在父元素前面
                parent.before(video);
                parent.remove();
            }
        });
        console.log("放大了"+count+"个视频");
    }


})();