前往
大廳
主題

迷你懸浮視窗腳本

Jason | 2024-12-17 23:57:47 | 巴幣 0 | 人氣 100

// ==UserScript==
// @name         Youtube 迷你懸浮視窗
// @namespace    http://tampermonkey.net/
// @version      2024-03-29
// @description  try to take over the world!
// @author       You
// @match        https://www.youtube.com/*
// @grant        GM_addStyle
// ==/UserScript==

//●目前問題
//※在迷你懸浮視窗移動的過程中,如果按下右鍵(此時鼠標正在迷你懸浮視窗上)
//會有即使你鬆開左鍵迷你懸浮視窗還是會黏在你鼠標上的bug
//如果將迷你懸浮視窗拖曳到視窗外放開左鍵也會有這個bug

//阻止影片加速的功能,並不是完全阻止影片加速,中間還是會有類似一幀的播放

//懸浮視窗大小是設定鎖死的 320px * 180px,所以遇到其他大小的影片比例(EX:直式短影音)會看不到完整影片
//若要改善可能整個4個拖曳區塊大小、播放/暫停鍵位置、懸浮視窗關閉按鈕的位置都要重寫

//(已解決)如果是在影片介面(網址含有youtube.com/watch?v=)重整
//當下由於抓不到影片元素腳本就被執行的關係,整個懸浮視窗除了CSS的部分其他都無法套用
//點擊進去其他影片就可以恢復

//有時候影片播放狀態跟暫停/播放鍵的狀態還是會不同(EX:影片正在播放可以暫停/播放鍵顯示的是三角形)

//是否顯示進度條
const DisplayProgressBar = true;

(function() {
    GM_addStyle(`
        .mini-close {
            float: right;
            position: relative;
            bottom: 382px;
            right: 7px;
            fill: #fff;
            width: 26px;
            height: 26px;
            opacity: 0;
            z-index: 200;
            /*cursor: pointer;*/
            transition: 0.2s;
        }
        .mini-state-play , .mini-state-pause {
            /*border: 1px #fff solid;*/
            position: relative;
            left: 100px;
            width: 119px;
            height: 104px;
            opacity: 0;
            transition: 0.2s;
        }
        #movie_player:not(.alike) .mini-state-play button svg path,
        #movie_player:not(.alike) .mini-state-pause button svg path {
            display: none;
        }
        #movie_player:not(.alike) .mini-state-play , #movie_player:not(.alike) .mini-state-pause {
            z-index: -1;
        }
        .mini-state-play {
            bottom: 145px;
        }
        .mini-state-pause {
            bottom: 251px;
            /*padding-left: 1px;*/
        }
        .drag {
            border: 0px #000 solid;
            /*cursor: move;*/
            position: relative;
            z-index: 100;
        }
        .drag-top {
            width: 100%;
            height: 40px;
        }
        .drag-left {
            width: 100px;
            height: 100px;
            float: left;
        }
        .drag-right {
            width: 100px;
            height: 100px;
            float: right;
        }
        .drag-bottom {
            width: 100%;
            height: 40px;
            margin-top: 100px
        }
        #movie_player.ytp-fullscreen {
            width: 100% ;
            height: 100% ;
            position: static;
        }
        #movie_player.alike:not(.ytp-fullscreen) {
            position: fixed;
            z-index: 1337;
            width: 320px ;
            height: 180px ;
            border-radius: 8px;
            box-shadow: 0px 0px 8px #000 !important;
            /*如果要回復以前預設的懸浮視窗位置,把下面的margin left top註解掉就好*/
            margin: 0 !important;
            left: 850px;
            top: 400px;
        }
        #movie_player.alike:not(.ytp-fullscreen) .ytp-bezel-text-hide ,
        #movie_player.alike:not(.ytp-fullscreen) .ytp-spinner ,
        #movie_player.alike:not(.ytp-fullscreen) .ytp-overlay .ytp-speedmaster-has-icon,
        #movie_player.alike:not(.ytp-fullscreen) .ytp-gradient-bottom ,
        #movie_player.alike:not(.ytp-fullscreen) .html5-endscreen ,
        #movie_player.alike:not(.ytp-fullscreen) .ytp-ce-element{
            display: none !important;
        }
        #columns #movie_player.alike > .ytp-chrome-bottom {
            display: none;
        }
        .mini-progress-bar .ytp-chapter-hover-container {
            width: 320px !important;
        }
        .mini-progress-bar {
            opacity: 0;
            /*transition: 0.1s;*/
            top: 176px;
            pointer-events: none;
        }
        ytd-watch-flexy:not(.alikeSmall) #columns #movie_player.alike:not(.ytp-fullscreen) video,
        ytd-watch-flexy:not(.alikeSmall) #columns #movie_player.alike:not(.ytp-fullscreen) .html5-video-container {
            display: block;
            width: 100% !important;
            height: 100% !important;
            top: 0 !important;
            left: 0 !important;
        }
        /*CC字幕*/
        #movie_player.alike:not(.ytp-fullscreen) #ytp-caption-window-container .caption-window .captions-text .caption-visual-line .ytp-caption-segment {
            font-size: 14.5px !important;
        }
        #movie_player.alike:not(.ytp-fullscreen) .caption-window.ytp-caption-window-bottom {
            margin-bottom: 4px !important;
            pointer-events: none;
        }
    `);
    let playerDocked = false;
    function activate() {
        if (!playerDocked) {
          $("#movie_player").addClass("alike");
          window.dispatchEvent(new Event('resize'));
          playerDocked = true;
        }
    }
    function deactivate() {
        if (playerDocked) {
          $("#movie_player").removeClass("alike");
          window.dispatchEvent(new Event('resize'));
          playerDocked = false;
        }
    }
    function scrolling() {
        let limiter = $("#player-container #ytd-player");
        let top_of_element = $(limiter).offset().top;
        let bottom_of_element = $(limiter).offset().top + $(limiter).outerHeight();
        let bottom_of_screen = $(window).scrollTop() + $(window).innerHeight();
        let top_of_screen = $(window).scrollTop();
        if ((bottom_of_screen > top_of_element) && (top_of_screen < bottom_of_element)) {
          //如果影片可視(迷你視窗關閉)
          deactivate();
          $('#movie_player').css('right','');
          $('#movie_player').css('left','');
          $('#movie_player').css('top','');
          $('#movie_player').css('bottom','');
        } else {
          //如果影片不可視(迷你視窗開啟)
          activate();
        }
    }
    //阻止長按加速功能
    function preventLongPressAcceleration() {
        let timeStart, timeEnd , time;
        $('.mini-state-pause , .mini-state-play , .drag , .mini-close').each((index) => {
            $('.mini-state-pause , .mini-state-play , .drag , .mini-close')[index].onmousedown = (e) => {
                if($('#movie_player.alike')[0]) {
                    timeStart = new Date().getTime();
                    time = setInterval(() => {
                        timeEnd = new Date().getTime();
                        if(timeEnd - timeStart > 560) {
                            clearInterval(time);
                            $('.html5-video-container video')[0].playbackRate = $('.ytp-bezel[aria-label = "暫停"]')[0]||$('.ytp-bezel[aria-label="停止即時播放"]')[0] ? 0 : 1;
                        }
                    }, 10);
                }
            }
        });
        $('.mini-state-pause , .mini-state-play , .drag , .mini-close').each((index) => {
            $('.mini-state-pause , .mini-state-play , .drag , .mini-close')[index].onmouseup = (e) => {
                if($('#movie_player.alike')[0]) {
                   clearInterval(time);
                   $('.html5-video-container video')[0].playbackRate = 1;
                }
            }
        });
    }
    //確保找到影片元素再執行
    function findMoviePlayer() {
        return new Promise((resolve, reject) => {
            const checkPlayer = () => {
                if ($('#movie_player')[0] === undefined) {
                    //console.log('抓不到');
                    setTimeout(checkPlayer, 100);
                }
                else {
                    resolve($('#movie_player')[0]);
                }
            }
            checkPlayer();
        });
    }
    //主要拖曳事件函數  參考來自:https://zh.javascript.info/mouse-drag-and-drop
    function drag(miniVideo, flag) {
        //let miniVideo = $('#movie_player')[0];
        //console.log(miniVideo);
        miniVideo.onmousedown = (e) => {
            //如果現在是一般頁面(迷你懸浮視窗沒有出現),則不給拖曳
            if(!$('#movie_player.alike:not(.ytp-fullscreen)')[0]) return
            let mouseCoordinatesX = e.pageX - $('#movie_player').offset().left;
            let mouseCoordinatesY = e.pageY - $('#movie_player').offset().top;
            //console.log(e.pageX - $('#movie_player').offset().left,e.pageY - $('#movie_player').offset().top);
            //如果在播放按鈕上,則不給拖曳
            if(100 < mouseCoordinatesX && mouseCoordinatesX < 200 && 39 < mouseCoordinatesY && mouseCoordinatesY < 139) {
                //console.log('現在在播放按鈕上');
                //終止冒泡,取消滑鼠在播放按鈕上的拖曳效果所造成的暫停/播放
                e.stopPropagation();
                return
            }

            let shiftX = e.clientX - miniVideo.getBoundingClientRect().left;
            let shiftY = e.clientY - miniVideo.getBoundingClientRect().top;
            function move(clientX , clientY) {
                miniVideo.style.left = clientX - shiftX + 'px';
                miniVideo.style.top = clientY - shiftY + 'px';
            }
            move(e.clientX, e.clientY);

            function onMouseMove(e) {
                move(e.clientX, e.clientY);
            }

            document.addEventListener('mousemove', onMouseMove);

            miniVideo.onmouseup = () => {
                document.removeEventListener('mousemove', onMouseMove);
                miniVideo.onmouseup = null;
            }
        }
        miniVideo.ondragstart = () => {
            return false;
        }
    };
    function addNode() {
         $('.html5-video-container').append($(`<div class='drag drag-top'></div>`));
         $('.html5-video-container').append($(`<div class='drag drag-left'></div>`));
         $('.html5-video-container').append($(`<div class='drag drag-right'></div>`));
         $('.html5-video-container').append($(`<div class='drag drag-bottom'></div>`));
         $('.html5-video-container').append($(`<div class='mini-state-play'></div>`));
         $('.html5-video-container').append($(`<div class='mini-state-pause'></div>`));
         $('.html5-video-container').append($(`<div class='mini-close'></div>`));
         //影片暫停時的播放標誌(三角形)
         $('.mini-state-pause').append($(`<button class="ytp-play-button ytp-button" aria-keyshortcuts="k" data-title-no-tooltip="播放" aria-label="播放鍵盤快速鍵k"><svg height="100%" version="1.1" viewBox="0 0 36 36" width="100%"><use class="ytp-svg-shadow" xlink:href="#ytp-id-43"></use><path class="ytp-svg-fill" d="M 12,26 18.5,22 18.5,14 12,10 z M 18.5,22 25,18 25,18 18.5,14 z" id="ytp-id-43"></path></svg></button>`));
         //影片播放時的播放標誌(雙長方形)
         $('.mini-state-play').append($(`<button class="ytp-play-button ytp-button" aria-keyshortcuts="k" data-title-no-tooltip="暫停" aria-label="暫停鍵盤快速鍵k"><svg height="100%" version="1.1" viewBox="0 0 36 36" width="100%"><use class="ytp-svg-shadow" xlink:href="#ytp-id-73"></use><path class="ytp-svg-fill" d="M 12,26 16,26 16,10 12,10 z M 21,26 25,26 25,10 21,10 z" id="ytp-id-73"></path></svg></button>`));
         //增加右上角關閉迷你懸浮視窗的按鈕
         $('.mini-close').append($(`<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" data-pointer="none" viewBox="0 0 16 16"><path d="m8 6.939 3.182-3.182a.75.75 0 1 1 1.061 1.061L9.061 8l3.182 3.182a.75.75 0 1 1-1.061 1.061L8 9.061l-3.182 3.182a.75.75 0 1 1-1.061-1.061L6.939 8 3.757 4.818a.75.75 0 1 1 1.061-1.061L8 6.939z"></path></svg>`));
    }
    function miniProgressBar() {
        if($('#movie_player.alike:not(.ytp-fullscreen)')[0]) {
            if(!$('.mini-progress-bar')[0]) {
                $('#movie_player').append($('.ytp-progress-bar-container'));
                $('.ytp-progress-bar-container').addClass('mini-progress-bar');
                $('.mini-progress-bar').css('opacity', '0');
                $('.ytp-progress-bar-container').css('display', 'block');
                //console.log('已增加');
            }
        }
        else if($('#movie_player:not(.alike)')[0]||$('#movie_player.ytp-fullscreen')[0]) {
            if($('.mini-progress-bar')[0]) {
                $('.ytp-chrome-bottom').append($('.ytp-progress-bar-container'));
                $('.mini-progress-bar').css('opacity', '1');
                $('.ytp-progress-bar-container').removeClass('mini-progress-bar');
                //console.log('已還原');
            }
        }
    }
    async function handleUIActions(nowUrl) {
        //暫停時點擊其他影片進去後會自動播放,所以將標籤內容改正回來,改為.ytp-bezel[aria-label = "播放"]
        await findMoviePlayer();
        if(nowUrl!==window.location.href) {
            $('.ytp-bezel[aria-label = "暫停"] , .ytp-bezel[aria-label="停止即時播放"]').attr('aria-label', '播放');
            miniProgressBar();
         }
        /*$('.drag , .mini-close').mouseover((e) => {
            if($('#movie_player.alike:not(.ytp-fullscreen)')[0]) {
                //終止冒泡
                $('.drag').css('cursor', 'move');
                $('.mini-close').css('cursor', 'pointer');
                }
        });*/
        //在迷你懸浮視窗上的「可移動區域」、「關閉按鈕」上,封鎖點擊滑鼠左鍵造成暫停的效果
        $('.drag , .mini-close').click((e) => {
            if($('#movie_player.alike:not(.ytp-fullscreen)')[0]) {
                //終止冒泡
                e.stopPropagation();
            }
        });
        //滑鼠移動到迷你懸浮視窗上的「可移動區域」、「關閉按鈕」時,改變滑鼠樣式
        $('.drag , .mini-close').mouseover((e) => {
            if($('#movie_player.alike:not(.ytp-fullscreen)')[0]) {
                $('.drag').css('cursor', 'move');
                $('.mini-close').css('cursor', 'pointer');
            }
        });

        //滑鼠移上去時顯示暫停/播放標誌
        $('.mini-state-pause , .mini-state-play , .drag , .mini-close').mouseover((e) => {
            if($('#movie_player.alike')[0]) {
                //當滑鼠移上去時,如果目前是暫停狀態,表示點擊後會播放,所以顯示播放圖示,隱藏暫停圖示
                if($('.ytp-bezel[aria-label = "暫停"]')[0]||$('.ytp-bezel[aria-label="停止即時播放"]')[0]) {
                   $('.mini-state-pause').css('opacity', '0.9');
                   $('.mini-state-play').css('opacity', '0');
                }
                //當滑鼠移上去時,如果目前是播放狀態,表示點擊後會暫停,所以顯示暫停圖示,隱藏播放圖示
                else {
                    $('.mini-state-pause').css('opacity', '0');
                    $('.mini-state-play').css('opacity', '0.9');
                }
                $('.mini-close , .mini-progress-bar').css('opacity', '0.9');
                $('.mini-progress-bar').css('opacity', '1');
                $('.mini-state-pause .ytp-button , .mini-state-play .ytp-button').css('cursor', 'pointer');
            }
            else {
                $('.mini-state-pause .ytp-button , .mini-state-play .ytp-button').css('cursor', 'default');
                $('.drag').css('cursor', 'default');
                $('.mini-close').css('cursor', 'default');
            }
        });
        $('.mini-state-pause , .drag , .mini-close').mouseout((e) => {
            $('.mini-state-pause , .mini-state-play , .mini-close , .mini-progress-bar').css('opacity', '0');
        });
        //點擊播放、暫停時,更換標誌
        $('.mini-state-pause').click((e) => {
            if($('#movie_player.alike')[0]) {
                //當點擊時,如果目前是暫停狀態,表示點擊後會播放,所以顯示播放圖示,隱藏暫停圖示
                if($('.ytp-bezel[aria-label = "暫停"]')[0]||$('.ytp-bezel[aria-label="停止即時播放"]')[0]) {
                    $('.mini-state-pause').css('opacity', '0');
                    $('.mini-state-play').css('opacity', '0.9');
                    //這邊在檢查到$('.ytp-bezel[aria-label = "暫停"]')[0]後將其印出
                    //但結果是ytp-bezel[aria-label = "播放"],表示在按下按鈕的那刻還是暫停狀態,之後就變到播放狀態了
                    //console.log($('.ytp-bezel[aria-label = "暫停"]')[0],'播放');
                }
                //當點擊時,如果目前是播放狀態,表示點擊後會暫停,所以顯示暫停圖示,隱藏播放圖示
                else {
                    $('.mini-state-pause').css('opacity', '0.9');
                    $('.mini-state-play').css('opacity', '0');
                    //console.log($('.ytp-bezel[aria-label = "暫停"]')[0],'暫停');
                }
            }
            //e.stopPropagation();
        });

        //右上角關閉迷你懸浮視窗的按鈕功能實現
        $('.mini-close').click(() => {
            /*if(!$('#movie_player:not(.alike)')[0]) {
                $('#movie_player').hide();
            }*/
            $("#movie_player").removeClass("alike");
        });
    }
    async function Run() {
        let miniVideo = await findMoviePlayer();
        drag(miniVideo);
        addNode();
        preventLongPressAcceleration();
    }
    $(() => {
        window.addEventListener("yt-navigate-finish", () => {
            if (window.location.href.indexOf('youtube.com/watch?v=') > -1) {
                $("#movie_player").removeClass("alike");
                //scrolling();
                $(window).scroll(() => {
                    scrolling();
                });
                if(!$('.drag')[0]) {
                    //儲存目前網址,用來檢查有沒有切換頁面
                    var nowUrl = window.location.href;
                    Run();
                }
                handleUIActions(nowUrl);
                if(DisplayProgressBar) {
                    $(window).scroll(() => {
                        miniProgressBar();
                    });
                    $(window).keydown((e) => {
                        if(e.keyCode == 70) {
                            miniProgressBar();
                        }
                    });
                }
            }
            else {
                if($("#movie_player.alike")[0]) $("#movie_player").removeClass("alike");
                console.log('非影片介面');
                console.log($("#movie_player")[0]);
            }
        });
    });

})();

創作回應

更多創作