Greasy Fork

来自缓存

Greasy Fork is available in English.

为风车动漫添加弹幕功能

本脚本为风车动漫网站添加了弹幕功能,你可以发送弹幕并和所有人互动。本插件目前非常不完善,为一个js初学者随便写着玩玩的,弹幕服务器是廉价天翼云服务器1核2G 5M,并且采用flask做后端,性能比较垃圾。如果发弹幕的人多的话我会把弹幕数据上传到github作备份,所以不用担心数据丢失

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         为风车动漫添加弹幕功能
// @namespace    https://github.com/innnky
// @version      0.6
// @description  本脚本为风车动漫网站添加了弹幕功能,你可以发送弹幕并和所有人互动。本插件目前非常不完善,为一个js初学者随便写着玩玩的,弹幕服务器是廉价天翼云服务器1核2G 5M,并且采用flask做后端,性能比较垃圾。如果发弹幕的人多的话我会把弹幕数据上传到github作备份,所以不用担心数据丢失
// @author       innnky
// @match        https://www.dm530p.net/play/*
// @grant        GM_xmlhttpRequest
// @require      https://code.jquery.com/jquery-1.12.4.min.js
// @connect api.innky.xyz
// @license     GPL License
// @supportURL  https://github.com/innnky/fengche-danmu


// ==/UserScript==
(function() {
    'use strict';
    //test
    //fuck
    //sss
    //sssss
    var f_final = function() {


        //·····················································································
        //·····················初始化 将元素添加到网页中·························
        // var box_html = "<div style='display:block;z-index:999;position:absolute; right:10px;top:80%; width:360px; height:40px;line-height:30px; background-color:#f50;color:#fff;text-align:center;font-size:16px;font-family:\"Microsoft YaHei\",\"微软雅黑\",STXihei,\"华文细黑\",Georgia,\"Times New Roman\",Arial,sans-serif;font-weight:bold'>请输入弹幕<input type=\"text\" id=\"danmu_text\" /><input id=\"send_danmu\" type=\"submit\" value=\"发送\" /></div>"

        var xxx = [' <div id=\'function_box\' style=\'display:block;z-index:999;position:absolute; right:10px;top:10PX; width:400px; height:40px;line-height:30px; text-align:center;font-size:16px;font-family:"Microsoft YaHei","微软雅黑",STXihei,"华文细黑",Georgia,"Times New Roman",Arial,sans-serif;font-weight:bold\'>',
            '        <div class="alert alert-primary" role="alert">',
            '            <div class="col-sm-12">',
            '                <div class="form-group row">',
            '                    <div class="col-sm-9">',
            '                    <input type="text" class="form-control" id="danmu_text" placeholder="请输入弹幕">',
            '                    </div>',
            '                    <button id="send_danmu" type="button" class="col-sm-3 btn btn-dark">发送</button>',
            '                    ',
            '                </div>',
            '            </div>',
            '            <div align="left" class="col-sm-12">',
            '                <h6 id="info">提示信息:正在获取弹幕,如果长时间未获取成功,请刷新或反馈bug</h6>',
            '            </div>',
            '        </div>',
            '    </div>'
        ].join("");
        var yyy = ['<div class="position-fixed bottom-0 right-0 p-3" style="z-index: 5; right: 0; bottom: 0;">',
            '      <div id="liveToast" class="toast hide" role="alert" aria-live="assertive" aria-atomic="true" data-delay="2000">',
            '        <div class="toast-header">',
            '          <strong id="h" class="mr-auto">Bootstrap</strong>',
            '          <!-- <small>11 mins ago</small> -->',
            '          <button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">',
            '            <span aria-hidden="true">&times;</span>',
            '          </button>',
            '        </div>',
            '        <div class="toast-body">',
            '          Hello, world! This is a toast message.',
            '        </div>',
            '      </div>',
            '    </div>',
            '    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>',
            '    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF" crossorigin="anonymous"></script>',
            '    '
        ].join("");
        // let zzz = ['<div id=\'setting\' style=\'display:block;z-index:999;position:absolute; left:10px;top:55PX; width:100; height:100px;line-height:30px; text-align:center;font-size:16px;\'><button id="setting_btn" type="button" class="btn btn-info">设置</button></div>',
        //     '<div id=\'setting_box\' style=\'display:block;z-index:999;position:absolute; left:80px;top:10PX; width:300px; height:40px;line-height:30px; text-align:center;font-size:16px;font-family:"Microsoft YaHei","微软雅黑",STXihei,"华文细黑",Georgia,"Times New Roman",Arial,sans-serif;font-weight:bold\'>',
        //     '        <div class="alert alert-primary" role="alert">',
        //     '            <div class="col-sm-12">',
        //     '                <div class="form-group row">',
        //     '                    <label for="formControlRange">弹幕速度</label>',
        //     '                    <input id="speed_ip" type="range" class="form-control-range" id="formControlRange">',
        //     '                    <label for="formControlRange">显示区域</label>',
        //     '                    <input id="display_ip" type="range" class="form-control-range" id="formControlRange">',
        //     '                    <label for="formControlRange">字号</label>',
        //     '                    <input id="fontsize_ip" type="range" class="form-control-range" id="formControlRange">',
        //     '                </div>',
        //     '            </div>',
        //     '        </div>',
        //     '    </div>'
        // ].join("");
        $('head').append('<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous">')
        $("body").append(xxx)
        $("body").append(yyy)
            // $("body").append(zzz)
            // $("#setting_box").hide()
        $("body").append('<script>var st = function(t) {$("#h").text("提示");$(".toast-body").text(t);$(".toast").toast("show");}</script>')
        $("body").append('<div id=\'hide\' style=\'display:block;z-index:999;position:absolute; left:10px;top:10PX; width:100; line-height:30px; text-align:center;font-size:16px;\'><button type="button" class="btn btn-info">Hide</button></div>')
            // $("#setting_btn").click(function() {
            //     if ($("#setting_box").css("display") == 'none') {
            //         $("#setting_box").show()
            //     } else {
            //         $("#setting_box").hide()

        //     }
        // });
        $('#hide').click(function() {
            if ($("#function_box").css("display") == 'none') {
                $("#function_box").show()
            } else {
                $("#function_box").hide()

            }
        });
        var set_info = function(c) {
            $("#info").text("提示信息:" + c);
        }
        var ttoast = function(t) {
                $("#h").text("提示")
                $(".toast-body").text(t)
                    // $('.toast').toast('show');
            }
            // $('body').append(box_html);


        var canvas = document.createElement("canvas");
        var container = document.createElement("div");
        //两个待解决的问题:1.页面缩放,显示区域问题
        //                2.跳转播放时弹幕显示方式。
        // bd = document.getElementById("i_cecream");
        //var bd= document.getElementsByTagName("body")[0];
        //var bdd =document.getElementsByClassName("area")[0];

        let ifg = document.getElementById("fc_playfram").contentWindow.document
        var bdd = ifg.querySelector("[class^=\"ckplayer\"]")
        if (bdd == null) {
            set_info("此播放源暂时未适配弹幕功能")
        }

        bdd.appendChild(container);

        container.appendChild(canvas);
        container.setAttribute("style", "width: inherit;height: 30%;position: absolute;top: 0px;z-index: 99999;")
        canvas.setAttribute("id", "danmu_canvas");
        canvas.setAttribute("style", "width: inherit;height: 100%;")

        //·····················································································
        //·····················获取和设置画布·························
        var font_size = 24;
        var row_size = 26;
        var dispaly_percentage = 0.3;
        var base_speed = 1.5;
        var context = canvas.getContext("2d");
        canvas.width = canvas.clientWidth;
        canvas.height = canvas.clientHeight;
        var dwidth = canvas.width;
        var dheight = canvas.height;
        var maxlen = Math.floor(dheight / row_size) - 1
        var cooling = new Array(maxlen).fill(0);
        var c_time = 200;
        //·····················································································
        //·····················定义函数和对象·························

        function generate_row() {
            let empty_rows = [];
            for (let i = 0; i < cooling.length; i++) {
                if (cooling[i] == 0) {
                    empty_rows.push(i);
                }
            }

            if (empty_rows.length != 0) {
                return empty_rows[Math.floor(empty_rows.length * Math.random())]
            } else {
                return -1
            }
        }
        var get_time = function() {
            let play_time = ifg.querySelector("[class^=\"timetext\"]");
            var tstr = play_time.innerText;
            var min = parseInt(tstr.substr(0, 2));
            var sec = parseInt(tstr.substr(3, 2));
            var t = min * 60 + sec;
            return t;
        }
        var is_pausing = function() {

            let is_playing_tag = ifg.querySelector("[data-title=\"点击播放\"]");
            let temp = is_playing_tag.getAttribute("style")
            return temp.slice(-3, -1) == 'ck'
        }
        var Barrage = function(obj) {
            this.x = dwidth;
            let maxrow = Math.floor(dheight / font_size) - 1;
            this.y = 0;
            this.moveX = -5;
            this.content = obj.content;
            this.time = obj.time;
            this.visable = false;
            this.draw = function() {
                if (this.visable) {
                    // console.log("1111111")
                    context.font = font_size + "px bold 黑体";
                    context.fillStyle = 'rgba(255,255,255,1)';
                    context.fillText(this.content, this.x, this.y);
                    // context.strokeStyle = "black";
                    // context.strokeText(this.content, this.x, this.y)
                }
            };
            this.update = function() {
                var test_v = 0;
                if (last_playtime <= this.time && precise_play_time > this.time) {
                    this.visable = true;

                    let r = generate_row();
                    if (r == -1) {
                        this.visable = false;
                    } else {
                        this.moveX = -base_speed * (1 + r / 13);
                        this.y = (1 + r) * row_size;
                        cooling[r] = this.content.length * row_size;
                    }
                    //
                }
                let tt = precise_play_time - this.time;
                if ((this.x + this.content.length * font_size < test_v) || tt < 0 || tt > (dwidth + this.content.length * font_size - test_v) / (-15 * this.moveX)) {
                    this.visable = false;

                }
                if (this.visable && is_playing) {
                    this.x += this.moveX;
                }

            };
            this.reset = function() {
                this.x = dwidth;
                this.visable = false;
            }
        };

        //·····················································································
        //·····················定义渲染函数·························
        function draw() {
            // canvas.width = canvas.clientWidth;
            // canvas.height = canvas.clientHeight;
            // console.log(precise_play_time+"  "+last_playtime);
            // console.log(x);
            // set_info(JSON.stringify(cooling))
            if (is_playing) {
                for (let i = 0; i < cooling.length; i++) {
                    if (cooling[i] > 0) {
                        cooling[i]--;
                    }
                }
            }
            // set_info(store[0].x)

            store.forEach(element => {

                element.update();

                element.draw();
            });

            last_playtime = precise_play_time;
        }
        var render = function() {

            context.clearRect(0, 0, canvas.width, canvas.height);
            draw();
            requestAnimationFrame(render);
        };


        //·····················································································
        //·····················定义监听函数·························
        var precise_play_time = 0.0;
        var is_playing;
        var time_handler = function(t) {
            precise_play_time = t;
            // console.log();
            is_playing = true;
        }
        var pause_handler = function() {
            is_playing = false;
        }
        var seekHandler = function(state, name) {
            store.forEach(element => {
                element.reset();
            });
            console.log('时间跳转状态:' + state, name);
        }
        var resize_handler = function() {
                // console.log("1111111111111")
                canvas.width = canvas.clientWidth;
                canvas.height = canvas.clientHeight;
                dwidth = canvas.width;
                dheight = canvas.height;
                var maxlen = Math.floor(dheight / row_size) - 1
                cooling = new Array(maxlen).fill(0);

                store.forEach(element => {
                    element.reset();
                });
            }
            // $("#speed_ip").bind("input propertychange", function() {  
            //     base_speed = parseInt($("#speed_ip").val()) / 70 + 0.8;
            //     cooling = new Array(maxlen).fill(0);
            //     store.forEach(element => {
            //         element.reset();
            //     });
            // });
            // // $("#display_ip").bind("input propertychange", function() {  
            // //     base_speed = parseInt($("#speed_ip").val()) / 70 + 0.8;
            // //     cooling = new Array(maxlen).fill(0);
            // //     store.forEach(element => {
            // //         element.reset();
            // //     });
            // // });
            // $("#fontsize_ip").bind("input propertychange", function() {  
            //     font_size = 20 * parseInt($("#fontsize_ip").val()) / 100 + 20;
            //     row_size = font_size + 2;
            //     var maxlen = Math.floor(dheight / row_size) - 1

        //     cooling = new Array(maxlen).fill(0);

        //     store.forEach(element => {
        //         element.reset();
        //     });
        // });

        document.getElementById("fc_playfram").contentWindow.player.addListener("time", time_handler);
        document.getElementById("fc_playfram").contentWindow.player.addListener("pause", pause_handler);
        document.getElementById("fc_playfram").contentWindow.player.addListener("seek", seekHandler);
        document.getElementById("fc_playfram").contentWindow.addEventListener('resize', resize_handler);



        //·····················································································
        //·····················使用假数据初始化弹幕列表·························
        var danmu_data = [{ content: "0s", time: 0 }, { content: "2s", time: 2 }, { content: "5s", time: 5 }, { content: "8s", time: 8 }, { content: "11s", time: 11 }, { content: "14s", time: 14 }];
        var last_playtime = 0;
        var store = [];
        var globale_danmu_data;
        var urlstr = window.location.pathname;
        var ss1 = urlstr.split("-");
        var aid = ss1[0].split('/')[2];
        var ep = ss1[2].split(".")[0];
        var source = ss1[1];
        var start_danmu = function() {
            globale_danmu_data.forEach(element => {
                store.push(new Barrage(element))
            });
            render()
        }
        var a = "";
        var x, y, z;
        GM_xmlhttpRequest({
            method: "get",
            // url: "http://127.0.0.1:5000/getdanmu?aid="+aid+"&ep="+ep+"&source="+source,
            url: "http://api.innky.xyz:5000/getdanmu?aid=" + aid + "&ep=" + ep + "&source=" + source,
            responseType: 'json',
            onload: function(res) {
                if (res.response.status != 0) {
                    set_info("请更新版本后使用或报告bug");
                    null.append(null);
                }
                globale_danmu_data = res.response.data;

                var meta_info = res.response.meta_info;
                var meta_str = ''
                meta_info.forEach(element => {
                        let temp = "列表" + (element.source + 1) + "···" + element.counts + "条 "

                        meta_str += temp;

                    })
                    // ttoast("aaaaaaaa")
                    // setTimeout(function() {
                    //     set_info("qian")
                    //     st("aaaaaaaaa")
                    //     set_info("hou")
                    // }, 4000)
                st("获取弹幕成功!!");
                // setTimeout('st("")', 2000)
                set_info("左上角可以隐藏此框。本集各播放列表对应弹幕数量如下(未显示说明当前无弹幕): " + meta_str);
                start_danmu()
            },
            onerror: function(err) {
                console.log('error')
                st("获取弹幕失败!!");

            }
        });
        let send = document.getElementById("send_danmu");

        send.onclick = function() {

            GM_xmlhttpRequest({
                method: "get",
                // url: "http://127.0.0.1:5000/senddanmu?time="+precise_play_time+"&content="+$("#danmu_text").val()+"&aid="+aid+"&ep="+ep+"&source="+source,
                url: "http://api.innky.xyz:5000/senddanmu?time=" + precise_play_time + "&content=" + $("#danmu_text").val() + "&aid=" + aid + "&ep=" + ep + "&source=" + source,
                responseType: 'json',
                onload: function(res) {
                    let newb = new Barrage({ content: $("#danmu_text").val(), time: precise_play_time });
                    newb.visable = true;
                    store.push(newb);
                    $("#danmu_text").val("")
                    st("发送弹幕成功!")

                },
                onerror: function(err) {
                    console.log('error')
                    $("#danmu_text").val("")
                    st("发送弹幕失败!")

                }
            });

        };
        $("#danmu_text").keydown(function(event) { //给input绑定一个键盘点击事件
            event = event || window.event;
            if (event.keyCode == 13) { //判断点的是否是回车键
                $("#send_danmu").click(); //程序式点击了搜索按钮
            }

        });
    }

    document.getElementById("fc_playfram").onload = f_final;


})();