bilibili native mp4 + converted ass download

在bilibili的视频标题栏添加原生MP4、转换后的ASS的下载链接。

As of 2017-03-03. See the latest version.

// ==UserScript==
// @name        bilibili native mp4 + converted ass download
// @namespace   http://qli5.tk/
// @homepageURL http://qli5.tk/
// @description 在bilibili的视频标题栏添加原生MP4、转换后的ASS的下载链接。
// @include     http://www.bilibili.com/video/av*
// @include     https://www.bilibili.com/video/av*
// @include     http://bangumi.bilibili.com/anime/*/play*
// @include     https://bangumi.bilibili.com/anime/*/play*
// @version     0.1
// @author      qli5
// @copyright   qli5, 2014+, 田生
// @license     Mozilla Public License 2.0; http://www.mozilla.org/MPL/2.0/
// @require     https://greasyfork.org/scripts/2231-bilibili-ass-danmaku-downloader/code/bilibili%20ASS%20Danmaku%20Downloader.user.js
// @run-at      document-end
// ==/UserScript==

//reset dalao's script
window.removeEventListener('DOMContentLoaded', init);
init = function() {};
initFont();
function GM_xmlhttpRequest(q) {
    $.ajax({
        method: q.method,
        url: q.url,
        dataType: 'text',
        success: function(r) {
            q.onload({
                responseText: r
            });
        }
    });
}

(function() {
    'use strict';

    // init
    var mp4A = document.createElement('a');
    var assA = document.createElement('a');
    mp4A.textContent = '原生MP4';
    assA.textContent = 'ASS';

    // I do not know, nor do I care about bilibili's customized events
    function getPlayerWin(callback) {
        if (location.host == 'bangumi.bilibili.com') {
            if (MutationObserver) {
                var observer = new MutationObserver(function() {
                    if (document.querySelector('#bofqi > iframe')) {
                        observer.disconnect();
                        document.querySelector('#bofqi > iframe').addEventListener("load", function () {
                            callback(document.querySelector('#bofqi > iframe').contentWindow);
                        });
                    }
                    else if (document.querySelector('#bofqi > object')) {
                        observer.disconnect();
                        var h=document.querySelector('div.v-title > h1');
                        h.insertBefore(document.createTextNode('[[mp4仅限H5播放器(弹幕列表右上角三个点的按钮切换)]] '), h.firstChild);
                    }
                });
                observer.observe(window.document.getElementById('bofqi'), {childList: true});
            }
            else{
                var t = setInterval(function() {
                    if (document.querySelector('#bofqi > iframe')) {
                        clearInterval(t);
                        document.querySelector('#bofqi > iframe').addEventListener("load", function () {
                            callback(document.querySelector('#bofqi > iframe').contentWindow);
                        });
                    }
                    else if (document.querySelector('#bofqi > object')) {
                        clearInterval(t);
                        var h=document.querySelector('div.v-title > h1');
                        h.insertBefore(document.createTextNode('[[mp4仅限H5播放器(弹幕列表右上角三个点的按钮切换)]] '), h.firstChild);
                    }
                }, 600);
            }
        }
        else {
            if (document.querySelector('#bofqi > object')) {
                var h=document.querySelector('div.v-title > h1');
                h.insertBefore(document.createTextNode('[[mp4仅限H5播放器(弹幕列表右上角三个点的按钮切换)]] '), h.firstChild);
                return;
            }
            callback(window);
        }
    }

    function getPlayer(playerWin, callback) {
        if (MutationObserver) {
            var observer = new MutationObserver(function() {
                if (playerWin.document.querySelector('div.bilibili-player-video-btn.bilibili-player-video-btn-quality > div > ul > li:nth-child(2)')) {
                    observer.disconnect();
                    callback(playerWin);
                }
            });
            observer.observe(playerWin.document.getElementById('bilibiliPlayer'), {childList: true});
        }
        else{
            var t = setInterval(function() {
                if (playerWin.document.querySelector('div.bilibili-player-video-btn.bilibili-player-video-btn-quality > div > ul > li:nth-child(2)')) {
                    clearInterval(t);
                    callback(playerWin);
                }
            }, 600);
        }
    }

    function getInfo(playerWin) {
        var jq = playerWin == window? $ : playerWin.$;
        var _ajax = jq.ajax;
        // jq hijack
        jq.ajax = function(a, c) {
            if (a.url.search('interface.bilibili.com/playurl?') != -1 || a.url.search('bangumi.bilibili.com/player/web_api/playurl?') != -1) {
                var _success = a.success;
                _success({});
                jq.ajax = _ajax;
                var cid = a.url.match(/cid=\d*/)[0].slice(4);
                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' });
                    assA.href=window.URL.createObjectURL(blob);
                });
                a.success = function(res) {
                    mp4A.href = res.durl[0].url;
                    assA.download = mp4A.href.match(/\d(\d|-|hd)*(?=\.mp4)/)[0] + '.ass';
                    var h=document.querySelector('div.v-title > h1');
                    h.insertBefore(document.createTextNode(' '), h.firstChild);
                    h.insertBefore(assA, h.firstChild);
                    h.insertBefore(document.createTextNode(' '), h.firstChild);
                    h.insertBefore(mp4A, h.firstChild);
                };
            }
            _ajax(a, c);
        };
        playerWin.document.querySelector('div.bilibili-player-video-btn.bilibili-player-video-btn-quality > div > ul > li:nth-child(2)').click();
    }

    getPlayerWin(function(playerWin) {
        getPlayer(playerWin, getInfo);
    });
})();