吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2403|回复: 25
收起左侧

[其他原创] 【哔哩哔哩】个人空间视频添加播放进度条

  [复制链接]
梦汐 发表于 2022-11-9 07:49
本帖最后由 梦汐 于 2022-11-11 10:25 编辑

油猴脚本,功能已完善,直接传送门安装就行:传送门
DIVE.png
[JavaScript] 纯文本查看 复制代码
// ==UserScript==
// @name        哔哩哔哩 - beta
// @namespace   Violentmonkey Scripts
// @match       *://*.bilibili.com/*
// @version     1.0
// @noframes    -
// @author      moxi
// @grant       GM_setValue
// @grant       GM_getValue
// @grant       GM_addStyle
// @require     [url=https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.5.1.min.js]https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.5.1.min.js[/url]
// ==/UserScript==
const Match = {
    Init: function () {
        var link = window.location.href
        var rules = this.Rules
        for (keyNmae in rules) {
            var focus = rules[keyNmae] //==[正则,[函数]]
            var result = RegExp(focus[0], "i").exec(link)
            if (result != null) {
                console.log("页面类型", keyNmae, " | ", "使用函数", focus[1]);
                for (let i = 0; i < focus[1].length; i++) {
                    focus[1][i].call(null, { result: result.slice(1,), rules: focus[0] })
                }
            }
        }
    },
    Rules: {//正则
        "Home": [".*://www.bilibili.com(?:$|/$|/\\?.*)", [DeleteSundries]],//主页
        "Video": [".*://www.bilibili.com/video/([ab][v][a-z0-9]*).*", [RecordLastPlayTime, DanmuAirborne]],//视频地址
        "Space": [".*://space.bilibili.com/.*", [AddPlayProgressUI, MarkingForRead]],//空间主页
    },
    config: {
        "HideHaveRead": true,//隐藏已经阅读过的视频
    }
};
(function () { Match.Init() }());
function RecordLastPlayTime() {
    setInterval(function () {
        var Rresult = RegExp(".*://www.bilibili.com/video/([ab][v][a-z0-9]*).*", "i").exec(window.location.href)
        if (Rresult != null) {
            var node = []
            var element = document.querySelector('.bpx-player-ctrl-time-current')
            if (!!element) {
                node.push(element)
            }//播放进度
            var element = document.querySelector('.bpx-player-ctrl-time-duration')
            if (!!element) {
                node.push(element)
            }//视频时长
            if (node.length == 2) {
                var id = Rresult[1]
                //------------------------------------------------------
                var minute = node[0].innerHTML.split(":")
                var progress = (minute[0] * 60) + Math.trunc(minute[1])
                //document.querySelector("bwp-video,video").currentTime
                //------------------------------------------------------
                var minute = node[1].innerHTML.split(":")
                var duration = (minute[0] * 60) + Math.trunc(minute[1])
                //document.querySelector("bwp-video,video").duration
                //------------------------------------------------------
                var json = GM_getValue_local("config", id, {})
                if (!json.progress && !json.duration && !json.interaction) {
                    var type = id[0].toLowerCase == "a" ? "avid" : "bvid";
                    var httpRequest = new XMLHttpRequest();
                    httpRequest.open('GET', `[url=https://api.bilibili.com/x/web-interface/view?]https://api.bilibili.com/x/web-interface/view?[/url]${type}=${id}`, false);
                    httpRequest.send(null);
                    var json = JSON.parse(httpRequest.responseText);
                    var duration = json.data.duration
                    var interaction = json.data.rights['is_stein_gate']
                    if (interaction == 1) {
                        //console.log("该视频为互动视频", id, progress, duration);
                        GM_setValue_local("config", id, {
                            interaction: interaction
                        })
                    } else {
                        //console.log("首次记录", id, progress, duration);
                        GM_setValue_local("config", id, {
                            progress: progress,
                            duration: duration
                        })
                    }
                } else {
                    if (!json.interaction) {//不是互动视频才进行记录
                        var disparity = json.duration - duration
                        if (disparity > -5 && disparity < 5) {//这是哔哩哔哩的BUG//同一个视频差距时间不得超过5秒
                            if (progress > json.progress) {//避免被小数覆盖
                                GM_setValue_local("config", id, {
                                    progress: progress,
                                    duration: duration
                                })
                            }
                        }
                    } else {
                        //console.log(id,"该视频为互动视频,无法记录");
                    }
                }
            }
            //console.log(id, { progress: progress, duration: duration });
        }
    }, 1000)
}
function AddPlayProgressUI() {
    ObserveNewElements(".small-item.fakeDanmu-item", function (node) {
        var id = $(node).attr('data-aid')
        var json = GM_getValue_local("config", id, {})
        //console.log("config", id, json.progress, json.duration);
        if (!$.isEmptyObject(json)) {//判断JSON是否为空
            var progress_ui = document.createElement('div');
            var Percent = GetPercent(json.progress, json.duration)
            $(progress_ui).attr('class', 'progress').attr('style', 'top: 0px;position: absolute;width: 100%;height: 4px;background-color: #909090;').html(`<div id="content" style="width: ${Percent}%;height: 100%;background-color: #f00;"></div>`);
            $(node).find('.cover').append(progress_ui);
            if (Match.config["HideHaveRead"]) {
                if (Percent > 95) {
                    $(node).hide();
                }
            }
        }
    })
}
function DanmuAirborne() {//弹幕空降
    const BarrageAirborne = {
        init: function () {
            this.IntervalID = setInterval((function (execution, This) {
                return function () {
                    execution.call(This)
                }
            }(function () {
                var danmaku = this.hBarrage
                var danmaNode = $(".b-danmaku")
                for (let index = 0; index < danmaNode.length; index++) {
                    if (!null) {//danmaku.includes(this.innerText)
                        var result = RegExp("(?:空降|跳伞|伞兵|空)\\D*(\\d{1,}[::]\\d{1,})", "i").exec(danmaNode[index].innerText)//弹幕是否预设的过滤规则
                        if (result != null && this.status == 0) {//符合则执行
                            console.log(danmaNode[index].innerText);
                            this.status = 1 //许可
                            danmaku.push(danmaNode[index].innerText)
                            var minute = result[1].split(":")//分割
                            if (minute.length == 1) {
                                var minute = result[1].split(":")
                            }
                            var position = (Math.trunc(minute[0]) * 60) + Math.trunc(minute[1])//取秒
                            if (position > document.querySelector("bwp-video,video").currentTime) {
                                var node = $('.bpx-player-video-area').append(`<div class="div dtms" style="position: absolute;z-index: 1;left: 50%;top: 50%;transform: translate(-50%, -50%);"><button class="datumoshi" style="padding: 6px 6px;line-height: 18px;border: none;background: #ffffff00;font-size: 18px;color: #fff;text-shadow: 2px 1px 1px #000;">点击空降到${minute[0]}分${minute[1]}秒</button></div>`).find('.datumoshi')[0];

                                $(node).click(CFunction(function (position, node, This) {
                                    document.querySelector("bwp-video,video").currentTime = position
                                    $('.datumoshi').remove()
                                    This.status = 0
                                }, position, node, this))

                                setTimeout(CFunction(function (position, node, This) {
                                    $(node).remove()
                                    if (This.status != 0) {
                                        This.status = 0
                                    }
                                }, null, node, this), 7500)

                                function CFunction(execution, position, node, This) {
                                    return function () {
                                        execution.call(null, position, node, This)
                                    }
                                }
                            }

                        }
                    }
                }
            }, this)), 1000)
        },
        hBarrage: [],
        IntervalID: undefined,
        status: 0,
    }
    BarrageAirborne.init()
}
function MarkingForRead() {
    ObserveNewElements(".play-all-btn:not(.all,.check,.save)", function (node) {
        setTimeout(
            function () {
                $(node).parent().prepend(`<button class="play-all-btn all" style="width: auto;background-color: #ffffff00;padding: 4px;">反选</button><button class="play-all-btn save" style="width: auto;background-color: #ffffff00;padding: 4px;">保存</button>`)
                $(".play-all-btn.all").click(//全选
                    function () {
                        var checkbox = $('.select')
                        if (checkbox.length == 0) {
                            var item = $('.small-item.fakeDanmu-item')
                            for (let index = 0; index < item.length; index++) {
                                $(item[index]).prepend(`<input type="checkbox" class="select" aid="${$(item[index]).attr("data-aid")}" index="${index}" style="position: absolute;z-index: 10;">`)
                            }
                        } else {
                            checkbox.click()
                        }
                    }
                )
                $(".play-all-btn.save").click(//保存
                    function () {
                        var select = []
                        $('.select').each(function () {
                            if (this.checked) {
                                select.push(this.getAttribute('aid'))
                            }
                        })

                        for (let index = 0; index < select.length; index++) {
                            SetForRead(select[index])
                        }

                    }
                )
            }, 300
        )

    })
}//在UP的投稿列表添加一个全选和保存按钮,选中后按保存会标记为已阅视频
function DeleteSundries() {//删除节点
    var remove = {
        "推荐": ".bili-grid .eva-extension-area",
        "直播": ".bili-grid .live-card-list",
        "动画": ".bili-grid .video-card-list.is-main",
        "番剧": ".bili-grid .bangumi-area",
        "国创": ".bili-grid .guo-chuang-area",
        "综艺": ".bili-grid .variety-area",
        "课堂": ".bili-grid .cheese-card-list",
        "资讯": ".bili-grid .information-area",
        "专栏": ".bili-grid .article-card-list",
        //"跳转": ".banner-link",
        "电影,电视,纪录片": ".bili-grid  .movie-card-list",
    }
    for (key in remove) {
        WaitNodeLoad(null, remove[key], 100, 100, function () {
            if (!this.status) {
                this.parent().remove();
            }
        })
    }
    WaitNodeLoad(null, '.recommended-swipe', 100, 100, function () {
        if (typeof (this.status) == "undefined") {
            console.log("this", this);
            this[0].innerHTML = `<img style="object-fit: cover;position: absolute;top: 50%;left: 50%;display: block;min-width: 100%;min-height: 100%;transform:translate(-50%,-50%);border: 1px solid #000000;background: url([url=https://s1.ax1x.com/2022/11/10/zpbUds.jpg]https://s1.ax1x.com/2022/11/10/zpbUds.jpg[/url]) no-repeat center center;background-size: cover;">`
        }
    })
}

function GM_getValue_local(id, key, defaultValue) {
    var data = GM_getValue(id, {});
    return data[key] || defaultValue;
}
function GM_setValue_local(id, key, value) {
    var data = GM_getValue(id, {});
    data[key] = value;
    return GM_setValue(id, data);
}
function ObserveNewElements(selector, response, filter) {//selector,(node,mutation)=>{},filterRepetition=true)
    'use strict';
    if (!!selector) {
        let config = {
            childList: true,
            subtree: true
        };
        const mutationCallback = (mutationsList) => {
            for (let mutation of mutationsList) {
                let type = mutation.type;
                if (type == "childList") {
                    if (mutation.addedNodes.length != 0) {
                        var New_node = []
                        for (let index = 0; index < mutation.addedNodes.length; index++) {
                            var Nodes = $(mutation.addedNodes[index])
                            for (let Tindex = 0; Tindex < Nodes.length; Tindex++) {
                                if ($(Nodes[Tindex]).is(selector)) {
                                    New_node.push(Nodes[Tindex])
                                }
                            }
                            Nodes.find(selector).each(
                                function () {
                                    New_node.push(this)
                                }
                            )
                        }
                        if (New_node.length > 0) {
                            setTimeout((function (List) {
                                for (let Tindex = 0; Tindex < List.length; Tindex++) {
                                    if (filter) {
                                        if (List[Tindex]['OpenFilter']) {
                                            console.log("重复", List[Tindex]);
                                            continue;
                                        } else {
                                            List[Tindex]['OpenFilter'] = true
                                        }
                                    }
                                    response.call(mutation, List[Tindex], mutation)
                                }
                            }(New_node)), 300)
                        }
                    }
                }
            }
        };
        var observe = new MutationObserver(mutationCallback);
        observe.observe(document, config)
        return observe
    }
}
function GetPercent(num, total) {//取百分比
    num = parseFloat(num);
    total = parseFloat(total);
    if (isNaN(num) || isNaN(total)) {
        return 0;
    }
    return total <= 0 ? "0%" : (Math.round(num / total * 10000) / 100.00);
}
function SetForRead(id) {//将视频标记为已阅
    return new Promise(
        function (response) {
            var type = id.toLowerCase == "a" ? "avid" : "bvid";
            var httpRequest = new XMLHttpRequest();
            httpRequest.open('GET', `[url=https://api.bilibili.com/x/web-interface/view?]https://api.bilibili.com/x/web-interface/view?[/url]${type}=${id}`, false);
            httpRequest.send(null);
            var json = JSON.parse(httpRequest.responseText);
            var duration = json.data.duration
            var interaction = json.data.rights['is_stein_gate']
            if (interaction == 1) {
                console.log("ForRead >>> 互动视频", id, duration, duration);
                GM_setValue_local("config", id, {
                    interaction: interaction
                })
            } else {
                console.log("ForRead >>> 完成记录", id, duration, duration);
                GM_setValue_local("config", id, {
                    progress: duration,//标记为已阅
                    duration: duration
                })
            }
            return response(id)
        }
    )
}
function WaitNodeLoad(parent, selector, interval, times, callback) {//父节点,选择器,间隔,超时次数,回调
    var _selector = selector, _interval = interval, _times = times
    var _node = !parent ? $(_selector) : $(parent).find(_selector)
    if (_node.length == 0) {//匹配失败
        var number = setInterval(
            function () {
                if (_times <= 0) {
                    callback.call({ "status": false })
                    console.log("关闭", number);
                    return clearInterval(number)
                } else {
                    _times--
                    var node = !parent ? $(_selector) : $(parent).find(_selector)
                    if (node.length != 0) {
                        callback.call(node)
                        return clearInterval(number)
                    }
                }
            }, _interval
        )
    } else {
        return callback.call(_node)
    }
}

免费评分

参与人数 9威望 +1 吾爱币 +16 热心值 +9 收起 理由
coffeewithout + 1 + 1 我很赞同!
hkhkhk + 1 用心讨论,共获提升!
KentChen0126 + 1 虽然看不懂,但是点赞是必须的
苏紫方璇 + 1 + 10 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
qinwang + 1 + 1 我很赞同!
15235109295 + 1 + 1 我很赞同!
Break12580 + 1 + 1 谢谢@Thanks!
luozi1653 + 1 + 1 热心回复!
cary_云飞扬 + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

山田凉粉 发表于 2022-11-9 08:51
看着不错,可是是纯小白不会用
补补23456 发表于 2022-11-9 11:47
zoomyou 发表于 2022-11-9 09:09
B站里有些质量高的视频,不仅底端有漂亮的进度条,而且还可以根据视频内容编辑成一段一段的进度,不知道如 ...

分段章节 https://www.bilibili.com/read/cv13543699
必剪客户端可以设置样式
cary_云飞扬 发表于 2022-11-9 07:58
Break12580 发表于 2022-11-9 08:39
谢谢楼主
fa22 发表于 2022-11-9 08:43
不错的说!感谢了!
bandishui 发表于 2022-11-9 08:43
学习一下, 谢谢分享
士兵许三多 发表于 2022-11-9 08:50
进来学习一下,好东西啊
woaini0454 发表于 2022-11-9 08:50
能不能开发b站电视端带弹幕的应用啊 大佬
15235109295 发表于 2022-11-9 08:58
进来学习一下
cassyjj 发表于 2022-11-9 09:09
学习一下
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 03:03

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表