BilibiliTimer

B站H5播放器全屏时实时显示当前系统时间和播放进度

目前为 2017-06-26 提交的版本。查看 最新版本

// ==UserScript==
// @name         BilibiliTimer
// @version      1.4.24
// @description  B站H5播放器全屏时实时显示当前系统时间和播放进度
// @author       AnnAngela
// @match        *://www.bilibili.com/video/av*
// @match        *://www.bilibili.com/watchlater*
// @match        *://www.bilibili.com/html/*layer.htm*
// @match        *://live.bilibili.com/*
// @compatible   chrome
// @run-at       document-start
// @grant        unsafeWindow
// @grant        GM_addStyle
// @namespace    https://greasyfork.org/users/129402
// ==/UserScript==

(function() {
    'use strict';
    /* 防止重复加载 */
    if (unsafeWindow.BilibiliTimer) return;
    unsafeWindow.BilibiliTimer = {};
    /*
     * 出于实现上的考虑,以下代码被保存为纯文本,并通过unsafeWindow.eval运行,以操作真实环境下的DOM节点
     */
    var code = [
        "(function() {",
        "    'use strict';",
        "    if (!String.prototype.includes) String.prototype.includes = function includes(s) {",
        "        return this.indexOf(s) !== -1;",
        "    };",
        "    var BilibiliTimer = window.BilibiliTimer || (window.BilibiliTimer = {});",
        "    var LF = String.fromCharCode(10);",
        "    BilibiliTimer.date = function bilibiliPlayerDate() {",
        "        var _date = new Date();",
        "        ['getDate', 'getFullYear', 'getHours', 'getMilliseconds', 'getMinutes', 'getMonth', 'getSeconds', 'getTime', 'getUTCDate', 'getUTCFullYear', 'getUTCHours', 'getUTCMilliseconds', 'getUTCMinutes', 'getUTCMonth', 'getUTCSeconds', 'getYear'].forEach(function(key) {",
        "            _date[key] = function() {",
        "                var result = Date.prototype[key].apply(_date, arguments);",
        "                if (key.includes('Month')) result++;",
        "                if (typeof result === 'number' && (result + '').length === 1) return '0' + result;",
        "                else return result + '';",
        "            };",
        "        });",
        "        return _date;",
        "    };",
        "    BilibiliTimer.isLive = function bilibiliIsLive(a, b) {",
        "        return location.host === 'live.bilibili.com' ? a : b;",
        "    };",
        "    BilibiliTimer.selector = BilibiliTimer.isLive({",
        "        container: '.bilibili-live-player-video-area',",
        "        controller: '.bilibili-live-player-video-controller',",
        "        fullscreenSendbar: null",
        "    }, {",
        "        container: '.bilibili-player-video-wrap',",
        "        controller: '.bilibili-player-video-control',",
        "        fullscreenSendbar: '.bilibili-player-video-sendbar.active'",
        "    });",
        "    BilibiliTimer.classList = BilibiliTimer.isLive({",
        "        timer: 'bilibili-live-player-video-info-container',",
        "        closeButton: 'bilibili-live-player-video-info-close',",
        "        panel: 'bilibili-live-player-video-info-panel',",
        "        restartButton: 'live-icon-reload'",
        "    }, {",
        "        timer: 'bilibili-player-video-info-container',",
        "        closeButton: 'bilibili-player-video-info-close',",
        "        panel: 'bilibili-player-video-info-panel',",
        "        restartButton: 'bilibili-player-iconfont icon-24repeaton'",
        "    });",
        "    BilibiliTimer.closeButtonText = BilibiliTimer.isLive('x', '[x]');",
        "    BilibiliTimer.globallock = false;",
        "    BilibiliTimer.widthSet = false;",
        "    BilibiliTimer.onResizing = 0;",
        "    BilibiliTimer.getControllerTop = function BilibiliTimerGetControllerTop() {",
        "        var controller = $(BilibiliTimer.selector.controller);",
        "        if (controller.closest('.mode-miniscreen')[0]) return $(window).height();",
        "        var _top = $(BilibiliTimer.selector.controller).offset().top;",
        "        var fullscreenSendbar = $(BilibiliTimer.selector.fullscreenSendbar);",
        "        if (fullscreenSendbar[0]) _top -= fullscreenSendbar.outerHeight(true);",
        "        return _top;",
        "    };",
        "    $(window).on('resize.BilibiliTimer', function() {",
        "        BilibiliTimer.onResizing = 1;",
        "    });",
        "    $(document).on({",
        "        'mousemove.BilibiliTimer': function(e) {",
        "            if (BilibiliTimer && BilibiliTimer.timer && BilibiliTimer.timer.data('onMousedown')) {",
        "                var maxTop = BilibiliTimer.getControllerTop() - BilibiliTimer.timer.outerHeight() - 10;",
        "                var maxLeft = $(window).width() - BilibiliTimer.timer.outerWidth() - 10;",
        "                BilibiliTimer.timer.css({",
        "                    left: Math.max(Math.min(BilibiliTimer.timer.data('baseOffset').left + e.clientX, maxLeft), 10),",
        "                    top: Math.max(Math.min(BilibiliTimer.timer.data('baseOffset').top + e.clientY, maxTop), 10)",
        "                });",
        "                window.getSelection().removeAllRanges();",
        "            }",
        "        },",
        "        'mouseup.BilibiliTimer': function(e) {",
        "            if (BilibiliTimer && BilibiliTimer.timer && BilibiliTimer.timer.data('onMousedown')) {",
        "                BilibiliTimer.timer.data('onMousedown', false);",
        "                localStorage.setItem('BilibiliTimerOffset', JSON.stringify({",
        "                    top: BilibiliTimer.timer.css('top'),",
        "                    left: BilibiliTimer.timer.css('left')",
        "                }));",
        "            }",
        "        }",
        "    });",
        "    BilibiliTimer.template = {};",
        "    var timer = BilibiliTimer.template.timer = $('<div/>');",
        "    timer.attr('id', 'BilibiliTimer').addClass(BilibiliTimer.classList.timer);",
        "    var closeButton = BilibiliTimer.template.closeButton = $('<a/>');",
        "    closeButton.text(BilibiliTimer.closeButtonText).attr({",
        "        href: 'javascript:void(0);',",
        "        id: 'BilibiliTimerCloseButton'",
        "    });",
        "    closeButton.addClass(BilibiliTimer.classList.closeButton);",
        "    var restartButton = BilibiliTimer.template.restartButton = $('<a/>');",
        "    restartButton.attr({",
        "        href: 'javascript:void(0);',",
        "        id: 'BilibiliTimerRestartButton',",
        "        title: '如果发现浮窗出现问题,' + LF + '例如无法正常拖动,无法正常显示时间等,' + LF + '请点击该按钮重建浮窗尝试修复!'",
        "    });",
        "    restartButton.addClass(BilibiliTimer.classList.closeButton).addClass(BilibiliTimer.classList.restartButton);",
        "    var panel = BilibiliTimer.template.panel = $('<div/>');",
        "    panel.addClass(BilibiliTimer.classList.panel);",
        "    panel.append(\"<div class='info-line'><span class='info-title'>系统时间:</span><span class='info-data' id='BilibiliTimerNowTime'> - </span></div>\");",
        "    panel.append(BilibiliTimer.isLive('', \"<div class='info-line'><span class='info-title'>播放进度:</span><span class='info-data' id='BilibiliTimerVideoTime'> - </span></div>\"));",
        "    BilibiliTimer.init = function BilibiliTimerInit() {",
        "        BilibiliTimer.onResizing = 0;",
        "        BilibiliTimer.widthSet = false;",
        "        BilibiliTimer.timer = BilibiliTimer.template.timer.clone();",
        "        BilibiliTimer.closeButton = BilibiliTimer.template.closeButton.clone();",
        "        BilibiliTimer.restartButton = BilibiliTimer.template.restartButton.clone();",
        "        BilibiliTimer.panel = BilibiliTimer.template.panel.clone();",
        "        BilibiliTimer.timer.append(BilibiliTimer.closeButton).append(BilibiliTimer.restartButton).append(BilibiliTimer.panel);",
        "        BilibiliTimer.timer.on('mousedown', function(e) {",
        "            var baseX = Math.max(e.clientX, 0);",
        "            var baseY = Math.max(e.clientY, 0);",
        "            var baseOffsetX = Math.max(BilibiliTimer.timer.offset().left, 0);",
        "            var baseOffsetY = Math.max(BilibiliTimer.timer.offset().top, 0);",
        "            BilibiliTimer.timer.data({",
        "                baseOffset: {",
        "                    left: baseOffsetX - baseX,",
        "                    top: baseOffsetY - baseY",
        "                },",
        "                onMousedown: true",
        "            });",
        "        });",
        "        BilibiliTimer.closeButton.on('click', function() {",
        "            BilibiliTimer.globallock = true;",
        "            BilibiliTimer.timer.fadeOut(370);",
        "        });",
        "        BilibiliTimer.restartButton.on('click', BilibiliTimer.restart.bind(BilibiliTimer));",
        "        if (!localStorage.getItem('BilibiliTimerOffset')) {",
        "            BilibiliTimer.timer.css({",
        "                right: '10px',",
        "                top: '10px'",
        "            }).css({",
        "                left: BilibiliTimer.timer.offset().left + 'px',",
        "                right: 'auto'",
        "            });",
        "        } else BilibiliTimer.timer.css(JSON.parse(localStorage.getItem('BilibiliTimerOffset')));",
        "        $(BilibiliTimer.selector.container).append(BilibiliTimer.timer);",
        "        $(window).resize();",
        "    };",
        "    BilibiliTimer.globalWatcher = function BilibiliTimerGlobalWatcher() {",
        "        var timer = BilibiliTimer.timer;",
        "        if (!timer || !timer[0]) {",
        "            BilibiliTimer.init();",
        "            return;",
        "        }",
        "        if (!timer.closest('body')[0]) {",
        "            BilibiliTimer.restart();",
        "            return;",
        "        }",
        "        if (!!$(':-webkit-full-screen')[0]) {",
        "            if (!BilibiliTimer.globallock) {",
        "                timer.fadeIn();",
        "                if (BilibiliTimer.onResizing === 2) {",
        "                    BilibiliTimer.onResizing = 0;",
        "                    var maxTop = BilibiliTimer.getControllerTop() - timer.outerHeight() - 10;",
        "                    var maxLeft = $(window).width() - timer.outerWidth() - 10;",
        "                    timer.css({",
        "                        left: Math.max(Math.min(parseInt(timer.css('left')), maxLeft), 10),",
        "                        top: Math.max(Math.min(parseInt(timer.css('top')), maxTop), 10)",
        "                    });",
        "                    localStorage.setItem('BilibiliTimerOffset', JSON.stringify({",
        "                        top: timer.css('top'),",
        "                        left: timer.css('left')",
        "                    }));",
        "                } else if (BilibiliTimer.onResizing === 1) {",
        "                    BilibiliTimer.onResizing = 2;",
        "                }",
        "            }",
        "        } else {",
        "            BilibiliTimer.onResizing = 0;",
        "            BilibiliTimer.globallock = false;",
        "            timer.fadeOut();",
        "        }",
        "        if (timer.is(':visible')) {",
        "            var date = BilibiliTimer.date();",
        "            timer.find('#BilibiliTimerNowTime').text(date.getFullYear() + '-' + date.getMonth() + '-' + date.getDate() + ' ' + date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds());",
        "            if (!BilibiliTimer.widthSet) {",
        "                var maxWidth = 0;",
        "                timer.find('.info-line').each(function() {",
        "                    var width = 0;",
        "                    $(this).children().each(function() {",
        "                        if ($(this).is('.info-title')) $(this).width($(this).text().length * parseInt($(this).css('font-size')));",
        "                        width += $(this).outerWidth(true);",
        "                    });",
        "                    if (maxWidth < width) maxWidth = width;",
        "                });",
        "                timer.width(maxWidth);",
        "                BilibiliTimer.widthSet = true;",
        "            }",
        "            var video = $('video');",
        "            if (!video.data('onListened')) {",
        "                video.data('onListened', true);",
        "                video.on('timeupdate.BilibiliTimer', BilibiliTimer.videoListener.bind(BilibiliTimer));",
        "                BilibiliTimer.videoListener({",
        "                    target: video[0]",
        "                });",
        "            }",
        "            if (!timer.data('timeFilled')) {",
        "                timer.data('timeFilled', true);",
        "                BilibiliTimer.videoListener({",
        "                    target: video[0]",
        "                });",
        "            }",
        "        }",
        "    };",
        "    BilibiliTimer.timeParse = function BilibiliTimerTimeParse(time) {",
        "        time = parseInt(time)",
        "        var sec = time % 60,",
        "            min = (time - sec) / 60;",
        "        if (sec < 10) sec = '0' + sec;",
        "        return min + ':' + sec;",
        "    };",
        "    BilibiliTimer.videoListener = function BilibiliTimerVideoListener(e) {",
        "        var curTime = e.target.currentTime || 0;",
        "        var durTime = e.target.duration || 0;",
        "        if (!curTime || !durTime) return;",
        "        BilibiliTimer && BilibiliTimer.timer.find('#BilibiliTimerVideoTime').text(BilibiliTimer.timeParse(curTime) + '/' + BilibiliTimer.timeParse(durTime));",
        "    }",
        "    BilibiliTimer.start = function BilibiliTimerStart() {",
        "        if (!BilibiliTimer.interval) BilibiliTimer.interval = {",
        "            globalWatcher: setInterval(BilibiliTimer.globalWatcher, 100)",
        "        };",
        "    };",
        "    BilibiliTimer.restart = function BilibiliTimerRestart() {",
        "        for (var i in BilibiliTimer.interval) {",
        "            if (BilibiliTimer.interval[i]) clearInterval(BilibiliTimer.interval[i]);",
        "        }",
        "        $(document).add('video').off('.BilibiliTimer');",
        "        $('video').data('onListened', false);",
        "        $('#BilibiliTimer').fadeOut(370, function() {",
        "            $(this).remove();",
        "            window.BilibiliTimer = undefined;",
        "        });",
        "    };",
        "    BilibiliTimer.start();",
        "})();"
    ].join('\n');
    var css = [
        "#BilibiliTimer {",
        "    cursor: move;",
        "    display: block;",
        "}",
        "#BilibiliTimerCloseButton.bilibili-live-player-video-info-close {",
        "    color: rgb(0, 0, 0);",
        "    padding: 0px;",
        "    height: 15px;",
        "    background: rgb(221, 221, 221);",
        "    width: 1em;",
        "    text-align: center;",
        "    top: 8px;",
        "}",
        "#BilibiliTimerRestartButton {",
        "    top: auto;",
        "    bottom: 10px;",
        "}"
    ].join('\n');

    unsafeWindow.addEventListener('load', function() {
        GM_addStyle(css);
        unsafeWindow.BilibiliTimerCode = code;
        unsafeWindow.eval([
            "setInterval(function() {",
            "    if (!window.BilibiliTimer || !window.BilibiliTimer.init) eval(window.BilibiliTimerCode);",
            "}, 250);",
        ].join('\n'));
    });
})();