Greasy Fork is available in English.

评论才是本体!

Acfun 复制小剧场

// ==UserScript==
// @name         评论才是本体!
// @namespace    org.jixun.acfun.comment.screenshot
// @version      1.0.2
// @description  Acfun 复制小剧场
// @author       Jixun
// @include      http://www.acfun.tv/a/ac*
// @include      http://www.acfun.tv/v/ac*
// @require      https://greasyfork.org/scripts/2599/code/gm2-port-v104.js
// @grant        GM_xmlhttpRequest
// @grant        unsafeWindow
// @run-at       document-start
// ==/UserScript==

/* globals unsafeWindow, unsafeExec, GM_xmlhttpRequest, html2canvas */
/* jshint browser:true, devel: true, newcap: false */

/* jshint -W097 */
'use strict';

var w = unsafeWindow;
w.GM_PROXY = true;
var PROXY_STR = 'jixun://ACFUN_IMG_PROXY_' + (+new Date());
var FLAG_DEBUG = false;

console.info('评论才是本体! VM 入口 -->');
addEventListener('DOMContentLoaded', function () {
    // Inject html2canvas (with some custom fix)
    var sPaint = document.createElement('script');
    sPaint.src = 'https://greasyfork.org/scripts/13980/code/html2canvas.js?version=87728';
    document.head.appendChild(sPaint);

    // Inject loader :D
    unsafeExec(loader, PROXY_STR, FLAG_DEBUG);

    document.addEventListener(PROXY_STR, function (e) {
        if (e.detail.src.indexOf('http://cdn.aixifan.com/dotnet/') === 0) {
            if (FLAG_DEBUG) console.info('CROS: 抓取圖片 %s', e.detail.src);

            // Code taken from: 
            // http://stackoverflow.com/a/8781262
            // By: Brock Adams
            GM_xmlhttpRequest({
                method: 'GET',
                url: e.detail.src,
                overrideMimeType: 'text/plain; charset=x-user-defined',
                onload: function (r) {
                    var parts = e.detail.callback.split('.');
                    var fn = unsafeWindow;
                    var scope;
                    for (var i = 0; i < parts.length; i++) {
                        scope = fn;
                        fn = fn[parts[i]];
                    }
                    
                    // 自带的 btoa 会报错
                    fn.call(scope, {
                        type: 'image/png',
                        content: customBase64Encode (r.responseText)
                    });
                }
            });
        }
    }, false);
}, false);

// Code taken from: 
// http://stackoverflow.com/a/8781262
// By: Brock Adams
function customBase64Encode (inputStr) {
    var
        bbLen               = 3,
        enCharLen           = 4,
        inpLen              = inputStr.length,
        inx                 = 0,
        jnx,
        keyStr              = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
        output              = "",
        paddingBytes        = 0;
    var
        bytebuffer          = new Array (bbLen),
        encodedCharIndexes  = new Array (enCharLen);

    while (inx < inpLen) {
        for (jnx = 0;  jnx < bbLen;  ++jnx) {
            if (inx < inpLen)
                bytebuffer[jnx] = inputStr.charCodeAt (inx++) & 0xff;
            else
                bytebuffer[jnx] = 0;
        }

        encodedCharIndexes[0] = bytebuffer[0] >> 2;
        encodedCharIndexes[1] = ( (bytebuffer[0] & 0x3) << 4)   |  (bytebuffer[1] >> 4);
        encodedCharIndexes[2] = ( (bytebuffer[1] & 0x0f) << 2)  |  (bytebuffer[2] >> 6);
        encodedCharIndexes[3] = bytebuffer[2] & 0x3f;

        paddingBytes          = inx - (inpLen - 1);
        switch (paddingBytes) {
            case 1:
                encodedCharIndexes[3] = 64;
                break;
            case 2:
                encodedCharIndexes[3] = 64;
                encodedCharIndexes[2] = 64;
                break;
            default:
                break;
        }

        for (jnx = 0;  jnx < enCharLen;  ++jnx)
            output += keyStr.charAt ( encodedCharIndexes[jnx] );
    }
    return output;
}

function loader(PROXY_STR, FLAG_DEBUG) {
    var w = window;

    var bac = w.document.body.appendChild;
    w.document.body.appendChild = function (node) {
        if (node.tagName == 'SCRIPT') {
            var src = node.getAttribute('src');
            if (src.indexOf(PROXY_STR) === 0) {
                var m = src.match(/url=(.+?)&callback=([\w.]+)/);
                document.dispatchEvent(new CustomEvent(PROXY_STR, {
                    detail: {
                        src: decodeURIComponent(m[1]),
                        callback: m[2]
                    }
                }));

                node.setAttribute("type", "text/do-nothing");
            }
        }
        return bac.apply(this, arguments);
    };

    console.info('评论才是本体! 截图工具已载入 @jixun');

    var $ = w.$;
    $(function () {
        $('#area-comment')
            .on('mouseover', over)
            .on('mouseout',  out);

        var $space, $prevCanvas = {};
        var $screenshot = $('<span title="图片准备中..">[ 小剧场? ]</span>').css({
            position: 'absolute',
            right: '1em',
            top: '1em',
            zIndex: '999',
            color: '#aaa',
        });

        var $holder = $('<span>').css({
            overflow: 'hidden',
            opacity: 0.3,
            position: 'absolute'
        }).appendTo($screenshot);

        if (!FLAG_DEBUG) {
            $holder.css({
                top: 0,
                left: 0,
                height: '100%',
                width: '100%'
            });
        }

        var $doneShot = false;

        $screenshot.mouseenter(function (e) {
            e.preventDefault();
            e.stopPropagation();

            if ($doneShot) return ;

            // 生成当前图层 :D
            $screenshot.hide();
            html2canvas($space[0], {
                onrendered: function (canvas) {
                    canvas.title = '图片就绪 :D';
                    $doneShot = true;
                    if ($prevCanvas.length) $prevCanvas.remove();
                    $prevCanvas = $(canvas);

                    /*
                    // 打上我们的小广告 :D
                    var ctx = canvas.getContext('2d');
                    ctx.textAlign = 'right';
                    ctx.fillStyle = '#777';
                    ctx.fillText('@评论才是本体', canvas.width - 10, 20);
                    ctx.fillText('AcFun 小剧场截图工具 by Jixun', canvas.width - 10, 34);
                    */

                    $holder.append(canvas);
                    // document.body.appendChild(canvas);
                    $screenshot.show();
                },

                logging: FLAG_DEBUG,
                proxy: PROXY_STR
            });
        });

        function over (e) {
            var $new_space = find_space(e);
            if ($new_space) {
                if (!$space || !$new_space[0].isEqualNode($space[0])) {
                    $space = $new_space;

                    $space.find('.content-comment').each(function () {
                        this.innerHTML = this.innerHTML.replace(/\n/g, '<br>');
                    });

                    $space.find('img').css('display', 'inline');

                    $doneShot = false;
                    if ($prevCanvas.length) $prevCanvas.remove();
                    $screenshot.appendTo($space);
                }
            }
        }

        function out (e) {
            // TODO: ??
        }

        function find_space(e) {
            var $el = $(e.target);
            if ($el.parent().attr('id') == 'area-comment-inner')
                return $el;

            var $pn = $el.parents('.item-comment-quote:last');
            if ($pn.length)
                return $pn;

        }
    });
}