Greasy Fork

Greasy Fork is available in English.

bilibili plus bilibilijj

在bilibili界面上直接添加jj的三种下载链接。flv是分段超清,mp4是整段高清,ass下载已引用大神代码修复。请登录jj以跳过广告页。播放弹幕可使用potplayer等。视频弹幕同名即可自动加载。

当前为 2017-02-27 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name        bilibili plus bilibilijj
// @namespace   http://qli5.tk/
// @description 在bilibili界面上直接添加jj的三种下载链接。flv是分段超清,mp4是整段高清,ass下载已引用大神代码修复。请登录jj以跳过广告页。播放弹幕可使用potplayer等。视频弹幕同名即可自动加载。
// @include     http://www.bilibili.com/video/av*
// @include     https://www.bilibili.com/video/av*
// @include     http://bangumi.bilibili.com/anime/*
// @include     https://bangumi.bilibili.com/anime/*
// @version     0.4
// @grant       GM_xmlhttpRequest
// @grant       GM_getValue
// @grant       GM_setValue
// @author      qli5
// @copyright   qli5, 2014+, 田生
// @license     Mozilla Public License 2.0; http://www.mozilla.org/MPL/2.0/
// @require     http://greasyfork.icu/scripts/2231-bilibili-ass-danmaku-downloader/code/bilibili%20ASS%20Danmaku%20Downloader.user.js
// @connect-src www.jijidown.com
// @connect-src comment.bilibili.com
// @connect-src www.flvcd.com
// ==/UserScript==

// 感谢所有大佬,鄙人只做了微小的工作。
(function () {
    // jj的站长说被攻击了,所以加了很严格的机器人检查。可以尝试加快检查,但是如果您真的是机器人也没办法。
    var testingBypassSafedog = GM_getValue && GM_getValue('testingBypassSafedog') || undefined;
    // 本测试功能适合一次会下载很多视频的场景,可以尽量方便地把mp4的文件名改成ass的。这是我能在同源限制下想出的最好办法。请诸大佬指教。
    var testingMP4Rename = GM_getValue && GM_getValue('testingMP4Rename') || undefined;
    // 本测试功能适合看完就删的场景,可以将ass的文件名改成mp4的。文件名一般是数字乱码,也有可能失败,但不需要多点击。
    var testingASSRename = GM_getValue && GM_getValue('testingASSRename') || undefined;
    // 本测试功能将在jj无数据时尝试另一个老牌通用解析网站flvcd.com。暂时没做番剧解析。
    var testingFLVCD = GM_getValue && GM_getValue('testingFLVCD') || undefined;
    // 强迫症就请自己动手把undefined改成true/false吧

    // settings
    if (GM_setValue && (typeof (testingBypassSafedog) != 'boolean' || typeof (testingMP4Rename) != 'boolean' || typeof (testingASSRename) != 'boolean' || typeof (testingFLVCD) != 'boolean')) {
        testingBypassSafedog = confirm('欢迎使用bilibili plus bilibilijj。jj的站长说被攻击了,所以加了很严格的机器人检查。可以尝试加快检查,但是如果您真的是机器人也没办法。要这样做吗?');
        testingMP4Rename = confirm('本测试功能适合一次会下载很多视频的场景,可以尽量方便地把mp4的文件名改成ass的。这是我能在同源限制下想出的最好办法。请诸大佬指教。要这样做吗?');
        testingASSRename = confirm('本测试功能适合看完就删的场景,可以将ass的文件名改成mp4的。文件名一般是数字乱码,也有可能失败,但不需要多点击。要这样做吗?');
        testingFLVCD = confirm('本测试功能将在jj无数据时尝试另一个老牌通用解析网站flvcd.com。暂时没做番剧解析。要这样做吗?');
        alert('到油猴界面重置脚本可以清除这些设置,强迫症可以继续改源码。多谢使用。');
        GM_setValue('testingBypassSafedog', testingBypassSafedog);
        GM_setValue('testingMP4Rename', testingMP4Rename);
        GM_setValue('testingASSRename', testingASSRename);
        GM_setValue('testingFLVCD', testingFLVCD);
    }

    // reset dalao's script
    window.removeEventListener('DOMContentLoaded', init);
    GM_addStyle = init = function () { };
    initFont();

    var paraOriginal;
    GM_xmlhttpRequest(paraOriginal = {
        method: 'GET',
        url: 'http://www.jijidown' + location.href.match(/\.com.*/)[0],
        onload: function (response) {
            var doc = new DOMParser().parseFromString(response.responseText, 'text/html');
            var links = document.createElement('div');

            // anchor to jj
            var aa;
            aa = document.createElement('a');
            aa.href = 'http://www.jijidown' + location.href.match(/\.com.*/)[0];
            aa.textContent = 'bilibilijj';
            links.appendChild(aa);

            // testingMP4Rename
            var input, button;
            if (testingMP4Rename) {
                input = document.createElement('input');
                input.type = 'text';
                input.value = '请选择ass...';
                input.onclick = function () { this.select(); };
                links.appendChild(input);
                button = document.createElement('button');
                button.onclick = function () {
                    try {
                        input.select();
                        document.execCommand('copy');
                    }
                    catch (e) {
                        console.warn('Oops, copy failed' + e);
                    }
                };
                button.textContent = 'copy';
                links.appendChild(button);
            }

            if (doc.getElementsByClassName('yjs-browser-verification').length > 0) {
                // jj boom
                links.appendChild(document.createTextNode('jj觉得你是机器人,请手动访问一次。'));

                // testingBypassSafedog
                if (testingBypassSafedog) {
                    links.appendChild(document.createTextNode('但是你选择了跳过jj的机器人验证,讨厌~~稍后刷新'));
                    var jschl_vc = response.responseText.match(/<input type="hidden" name="jschl_vc" value=".*(?="\/>)/)[0].slice(44);
                    var pass = response.responseText.match(/<input type="hidden" name="pass" value=".*(?="\/>)/)[0].slice(40);
                    var jschl_answer = eval(
                        response.responseText
                        .match(/setTimeout\(function\(\){[\s\S]*?}[\s\S]*?(?=})/)[0].slice(23)
                        .replace("a = document.getElementById('jschl-answer');", 'a = {}')
                        .replace("f = document.getElementById('challenge-form');", '// f')
                        .replace("f.submit();", 'a;')
                    );

                    // safedog will reject false starts. you may tweak the delay if you have a higher RTT, especially if you are not in China
                    setTimeout(function () {
                        links.remove();
                        GM_xmlhttpRequest({
                            method: 'GET',
                            url: 'http://www.jijidown.com/cdn-cgi/l/chk_jschl?' + 'jschl_vc=' + encodeURIComponent(jschl_vc) + '&pass=' + encodeURIComponent(pass) + '&jschl_answer=' + encodeURIComponent(jschl_answer.value),
                            headers: {
                                'Referer': 'http://www.jijidown.com/'
                            },
                            onload: function () {
                                GM_xmlhttpRequest(paraOriginal);
                            }
                        });
                    }, 4000);

                    testingBypassSafedog = false; // to avoid infinite loop
                }
            }
            else {
                // testingFLVCD index_*.html
                var indexCount;
                if (testingFLVCD) indexCount = 1;

                // parse jj
                var listCols = doc.getElementById('Right_Main');
                if (listCols.children.length === 0) links.appendChild(document.createTextNode('本视频貌似太冷门了,需要到jj刷新一下。'));
                for (var i = 0; i < listCols.children.length; i++) {
                    var list = listCols.children[i];
                    for (var j = 0; j < list.children.length; j++) {
                        var flvDiv, mp4Div, assDiv;
                        var name, cid;
                        if (list.children[j].querySelector('span.PBoxName')) {
                            flvDiv = list.children[j].querySelector('span.Data_Main > span.Data_Flv > span.Data_Data');
                            mp4Div = list.children[j].querySelector('span.Data_Main > span.Data_Mp4 > span.Data_Data');
                            assDiv = list.children[j].querySelector('span.Data_Main > span.Data_Ass > span.Data_Data');
                            if (list.children[j].querySelector('span.PBoxName').textContent == '下载地址(右侧方块切换类型)')
                                name = assDiv.children[0].title.slice(0, -7);
                            else
                                name = list.children[j].querySelector('span.PBoxName').textContent;
                            cid = list.children[j].getAttribute('data-cid');

                            // name
                            links.appendChild(document.createElement('br'));
                            links.appendChild(document.createTextNode(name));
                            links.appendChild(document.createTextNode(' '));

                            // flv
                            var a;
                            a = document.createElement('a');
                            a.href = 'http://www.jijidown.com' + flvDiv.querySelector('a').getAttribute('href');
                            a.textContent = 'flv';
                            links.appendChild(a);
                            links.appendChild(document.createTextNode(' '));

                            // mp4
                            a = document.createElement('a');
                            if (testingASSRename)
                                a.onclick = function () { this.nextSibling.nextSibling.download = this.href.match(/\/\d*(?=(-1-hd)?\.mp4)/)[0].slice(1) + '-1-hd.ass'; };
                            if (mp4Div.querySelector('a'))
                                a.href = 'http://www.jijidown.com' + mp4Div.querySelector('a').getAttribute('href');
                            else if (testingFLVCD && location.host == 'www.bilibili.com') {
                                // testingFLVCD
                                (function (a) {
                                    GM_xmlhttpRequest({
                                        method: 'GET',
                                        // flvcd is not that smart on bilibili. manual convert required...
                                        url: 'http://www.flvcd.com/parse.php?format=high&kw=' + location.href.match(/http:\/\/www.bilibili.com\/video\/av\d*/) + '/index_' + indexCount + '.html',
                                        onload: function (response) {
                                            var doc = new DOMParser().parseFromString(response.responseText, 'text/html');
                                            a.href = doc.getElementsByClassName('link')[0].getAttribute('href');
                                            if (doc.getElementsByClassName('link').length > 1) console.warn('flvcd fail. bilibili changed its api?');
                                        }
                                    });
                                })(a);
                            }
                            else {
                                a.onclick = function () { alert('no mp4 data\nplease check jj'); };
                            }
                            a.textContent = 'mp4';
                            links.appendChild(a);
                            links.appendChild(document.createTextNode(' '));

                            // ass
                            a = document.createElement('a');
                            a.onclick = (function (name, cid, self) {
                                return function () {
                                    if (self.href.slice(0, 4) != 'blob') {
                                        fetchDanmaku(cid, function (danmaku) {
                                            var ass = generateASS(setPosition(danmaku), {
                                                'title': name,
                                                'ori': location.href,
                                            });
                                            // I would assume most users are using Windows
                                            var blob = new Blob(['\ufeff' + ass], { type: 'application/octet-stream' });
                                            self.setAttribute('href', window.URL.createObjectURL(blob));
                                            self.click();
                                        });
                                        return false;
                                    }
                                    if (testingMP4Rename) {
                                        input.value = name + '.mp4';
                                        input.select();
                                    }
                                };
                            })(name, cid, a);
                            a.download = name + '.ass';
                            a.href = 'http://www.bilibilijj.com' + assDiv.querySelector('a').getAttribute('href');
                            a.textContent = 'ass';
                            links.appendChild(a);

                            if (testingFLVCD) indexCount++;
                        }
                    }
                }
            }

            // set styles
            links.style.backgroundColor = 'white';
            links.style.padding = '10px';
            links.style.border = 'black';
            links.style.borderWidth = 'thin';
            links.style.borderStyle = 'dashed';

            // append to page
            if (location.hostname == 'www.bilibili.com') {
                links.style.zIndex = '500000';
                links.style.position = 'absolute';
                links.style.top = '0px';
                document.querySelector('.v_small').appendChild(links);
            }
            else if (location.hostname == 'bangumi.bilibili.com') {
                document.querySelector('.v1-bangumi-list-part-wrapper').appendChild(links);
            }
        }
    });
})();