bilipager

人类能用的B站分P列表

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да инсталирате разширение, като например Tampermonkey .

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         bilipager
// @namespace    http://s.xmcp.ml/
// @version      0.3.3
// @description  人类能用的B站分P列表
// @author       xmcp
// @match        *://www.bilibili.com/video/*
// @supportURL   https://github.com/xmcp/bilipager
// @contributionURL https://s.xmcp.ml/pakkujs/donate.png
// @grant        none
// ==/UserScript==

const ZINDEX_NORMAL=114514;
const ZINDEX_FULLSCREEN=2147483647;
const WIDTH=350;
const ANIMATION_TIME_MS=200;
const CSSTEXT=`
.bilipager-list::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}
.bilipager-list::-webkit-scrollbar-track {
    background-color: rgba(255,255,255,.3);
}
.bilipager-list::-webkit-scrollbar-thumb {
    background-color: rgba(128,128,128,.6);
}
.bilipager-list::-webkit-scrollbar-thumb:active {
    background-color: rgba(128,128,128,1);
}

.bilipager-list:empty, .bilipager-popover:empty {
    display: none;
}

.bilipager-list {
    width: ${WIDTH}px;
    position: fixed;
    height: 100%;
    background-color: rgba(225,225,225,.9);
    top: 0;
    left: -${WIDTH-1}px;
    opacity: 0;
    z-index: ${ZINDEX_FULLSCREEN};
    box-sizing: border-box;
    padding: 2em 0;
    overflow-y: auto;
    word-break: break-all;
    transition: left ${ANIMATION_TIME_MS}ms ease-out, opacity ${ANIMATION_TIME_MS}ms ease-out;
}
.bilipager-list:hover, .bilipager-list.hover {
    left: 0;
    opacity: 1;
}

.bilipager-list p {
    overflow: hidden;
    padding: .5em .3em .5em .5em;
    cursor: pointer;
    white-space: nowrap;
    transition: padding .2s ease;
}

.bilipager-list p code {
    font-family: Consolas, Courier, monospace;
}

.bilipager-list p span {
    font-size: 1.2em;
}

.bilipager-list p:hover {
    background-color: rgba(255,255,255,.8);
    white-space: normal;
    padding: .5em 0 .5em .8em;
    box-shadow: 0 1px 25px rgba(0,0,0,.3);
}

.bilipager-list p.bilipager-curp {
    background-color: black;
    color: white;
}

.bilipager-list p.animation {
    color: black;
    -webkit-animation: page-switch 1s ease;
            animation: page-switch 1s ease;
}

@-webkit-keyframes page-switch {
    0%   {box-shadow: 0 1px 25px rgba(0,0,0,.3);   background-color: rgba(255,255,255,.8);}
    20%  {box-shadow: 0 1px 25px rgba(0,0,255,.5); background-color: rgba(205,205,255,1); }
    50%  {box-shadow: 0 1px 25px rgba(0,0,255,.5); background-color: rgba(205,205,255,1); }
    100% {box-shadow: 0 1px 25px rgba(0,0,0,.3);   background-color: rgba(255,255,255,.8);}
}
@keyframes page-switch {
    0%   {box-shadow: 0 1px 25px rgba(0,0,0,.3);   background-color: rgba(255,255,255,.8);}
    20%  {box-shadow: 0 1px 25px rgba(0,0,255,.5); background-color: rgba(205,205,255,1); }
    50%  {box-shadow: 0 1px 25px rgba(0,0,255,.5); background-color: rgba(205,205,255,1); }
    100% {box-shadow: 0 1px 25px rgba(0,0,0,.3);   background-color: rgba(255,255,255,.8);}
}

.bilipager-popover {
    min-width: 150px;
    position: absolute;
    height: 1.7em;
    line-height: 1.7em;
    font-size: 1.2em;
    padding: 0 .5em;
    background-color: black;
    color: white;
    top: 42px;
    left: 10px;
    z-index: ${ZINDEX_NORMAL};
    border-radius: 3px;
    word-break: break-all;
    white-space: nowrap;
}

.bilipager-popover:before {
    content: "";
    position: absolute;
    width: 0;
    height: 0;
    top: 50%;
    left: -4px;
    margin-top: -5px;
    border-width: 5px 5px 5px 0;
    border-color: transparent;
    border-right-color: black;
    border-style: solid;
}
`;

(function() {
    'use strict';

    let list_root=document.createElement('div');
    list_root.className='bilipager-list';
    list_root.addEventListener('mousewheel',function(e) {
        e.stopPropagation();
    });

    let popover=document.createElement('div');
    popover.className='bilipager-popover';
    popover.addEventListener('mouseover',function(e) {
        list_root.classList.add('hover');
        setTimeout(function() {
            list_root.classList.remove('hover');
        },ANIMATION_TIME_MS+10);
    });

    let playlist_cache={};

    function format_duration(d) {
        function pad(t) {
            return (''+t).padStart(2,'0');
        }
        return d<3600 ?
            (Math.floor(d/60)+':'+pad(d%60)) :
            (Math.floor(d/3600)+':'+pad(Math.floor((d%3600)/60))+':'+pad(d%60));
    }

    function reload_ui(aid) {
        if(!playlist_cache[aid]) {
            playlist_cache[aid]=fetch('https://api.bilibili.com/x/player/pagelist?aid='+aid).then(res=>res.json());
        }
        playlist_cache[aid].then(function(plist) {
            list_root.textContent='';
            popover.textContent='';

            console.log('!!',plist);
            if(plist.data.length<=1) return;

            plist.data.forEach(function(p) {
                let li=document.createElement('p');

                let li_1=document.createElement('code');
                li_1.textContent=`[${p.page}] ${format_duration(p.duration)} `;
                li.appendChild(li_1);
                let li_2=document.createElement('span');
                li_2.textContent=`${p.part}`;
                li.appendChild(li_2);

                li.addEventListener('click',function() {
                    li.classList.add('animation');

                    const ind_10=Math.floor((p.page-1)/10)*10+1;
                    const ind_30=Math.floor((p.page-1)/30)*30+1;

                    function paginate_failed() {
                        //alert('pagination failed');
                        location.href='//www.bilibili.com/video/av'+aid+'/?p='+p.page;
                    }

                    for(const pager_30 of document.querySelectorAll('#multi_page .more-box li')) {
                        if(pager_30.textContent.startsWith(ind_30+'-')) {
                            pager_30.click();
                            setTimeout(function() {
                                for(const pager_10 of document.querySelectorAll('#multi_page .paging li')) {
                                    if(pager_10.textContent.startsWith(ind_10+'-')) {
                                        pager_10.click();
                                        setTimeout(function() {
                                            const paginate_link=document.querySelector(`a.router-link-active[href="/video/av${aid}/?p=${p.page}"]`);
                                            if(paginate_link) {
                                                console.log('switch: pagniate link');
                                                paginate_link.click();
                                                return;
                                            }
                                            paginate_failed();
                                        },1);
                                        return;
                                    }
                                }
                                paginate_failed();
                            },1);
                            return;
                        }
                    }
                    paginate_failed();
                });
                list_root.appendChild(li);

                if(p.cid===parseInt(window.cid)) {
                    li.className='bilipager-curp';
                    if(li.scrollIntoViewIfNeeded) {
                        li.scrollIntoViewIfNeeded();
                    } else {
                        li.scrollIntoView(false);
                    }
                    popover.textContent=`[${p.page}/${plist.data.length}] ${p.part}`;
                }
            });
        });
    }

    function setup_listener() {
        function onfschange(e) {
            const elem=document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.body;
            if(list_root.parentNode!==elem) {
                if(list_root.parentNode) {
                    list_root.parentNode.removeChild(list_root);
                }
                elem.appendChild(list_root);
            }
        }
        document.addEventListener('fullscreenchange',onfschange);
        document.addEventListener('webkitfullscreenchange',onfschange);
        document.addEventListener('mozfullscreenchange',onfschange);

        addEventListener('message',function(e) {
            if(e.data.type==='pakku_event_danmaku_loaded') {
                reload_ui(window.aid);
            }
        });
    }

    if(window.aid) {
        let cssobj=document.createElement('style');
        cssobj.textContent=CSSTEXT;
        document.head.appendChild(cssobj);
        document.body.appendChild(list_root);
        document.body.appendChild(popover);
        setup_listener();
        reload_ui(window.aid);
    }
})();