Greasy Fork is available in English.

pixiv download helper

A small script to download the new png animated image in pixiv

Script này đã bị xóa.

// ==UserScript==
// @name        pixiv download helper
// @namespace   http://mfish.twbbs.org/
// @include     http://www.pixiv.net/member_illust.php?mode=medium&illust_id=*
// @require     http://cdn.staticfile.org/jquery/1.11.1/jquery.min.js
// @require     https://greasyfork.org/scripts/2350-filesaver-js/code/filesaverjs.js?version=6255
// @require     http://cdn.staticfile.org/jszip/2.3.0/jszip.min.js
// @require     https://greasyfork.org/scripts/2963-gif-js/code/gifjs.js?version=8462
// @version     0.3.2
// @grant       GM_registerMenuCommand
// @description A small script to download the new png animated image in pixiv
// ==/UserScript==

var global = unsafeWindow;
this.$ = this.jQuery = $.noConflict();

//https://gist.github.com/lsauer/5196979
//lsauer.com , lo sauer 2013
//JavaScript List of selected MIME types
//A comprehensive MIME List is available here: https://gist.github.com/lsauer/2838503

var mimeTypes =
    {
        'a' : 'application/octet-stream',
        'ai' : 'application/postscript',
        'aif' : 'audio/x-aiff',
        'aifc' : 'audio/x-aiff',
        'aiff' : 'audio/x-aiff',
        'au' : 'audio/basic',
        'avi' : 'video/x-msvideo',
        'bat' : 'text/plain',
        'bin' : 'application/octet-stream',
        'bmp' : 'image/x-ms-bmp',
        'c' : 'text/plain',
        'cdf' : 'application/x-cdf',
        'csh' : 'application/x-csh',
        'css' : 'text/css',
        'dll' : 'application/octet-stream',
        'doc' : 'application/msword',
        'dot' : 'application/msword',
        'dvi' : 'application/x-dvi',
        'eml' : 'message/rfc822',
        'eps' : 'application/postscript',
        'etx' : 'text/x-setext',
        'exe' : 'application/octet-stream',
        'gif' : 'image/gif',
        'gtar' : 'application/x-gtar',
        'h' : 'text/plain',
        'hdf' : 'application/x-hdf',
        'htm' : 'text/html',
        'html' : 'text/html',
        'jpe' : 'image/jpeg',
        'jpeg' : 'image/jpeg',
        'jpg' : 'image/jpeg',
        'js' : 'application/x-javascript',
        'ksh' : 'text/plain',
        'latex' : 'application/x-latex',
        'm1v' : 'video/mpeg',
        'man' : 'application/x-troff-man',
        'me' : 'application/x-troff-me',
        'mht' : 'message/rfc822',
        'mhtml' : 'message/rfc822',
        'mif' : 'application/x-mif',
        'mov' : 'video/quicktime',
        'movie' : 'video/x-sgi-movie',
        'mp2' : 'audio/mpeg',
        'mp3' : 'audio/mpeg',
        'mp4' : 'video/mp4',
        'mpa' : 'video/mpeg',
        'mpe' : 'video/mpeg',
        'mpeg' : 'video/mpeg',
        'mpg' : 'video/mpeg',
        'ms' : 'application/x-troff-ms',
        'nc' : 'application/x-netcdf',
        'nws' : 'message/rfc822',
        'o' : 'application/octet-stream',
        'obj' : 'application/octet-stream',
        'oda' : 'application/oda',
        'pbm' : 'image/x-portable-bitmap',
        'pdf' : 'application/pdf',
        'pfx' : 'application/x-pkcs12',
        'pgm' : 'image/x-portable-graymap',
        'png' : 'image/png',
        'pnm' : 'image/x-portable-anymap',
        'pot' : 'application/vnd.ms-powerpoint',
        'ppa' : 'application/vnd.ms-powerpoint',
        'ppm' : 'image/x-portable-pixmap',
        'pps' : 'application/vnd.ms-powerpoint',
        'ppt' : 'application/vnd.ms-powerpoint',
        'pptx' : 'application/vnd.ms-powerpoint',
        'ps' : 'application/postscript',
        'pwz' : 'application/vnd.ms-powerpoint',
        'py' : 'text/x-python',
        'pyc' : 'application/x-python-code',
        'pyo' : 'application/x-python-code',
        'qt' : 'video/quicktime',
        'ra' : 'audio/x-pn-realaudio',
        'ram' : 'application/x-pn-realaudio',
        'ras' : 'image/x-cmu-raster',
        'rdf' : 'application/xml',
        'rgb' : 'image/x-rgb',
        'roff' : 'application/x-troff',
        'rtx' : 'text/richtext',
        'sgm' : 'text/x-sgml',
        'sgml' : 'text/x-sgml',
        'sh' : 'application/x-sh',
        'shar' : 'application/x-shar',
        'snd' : 'audio/basic',
        'so' : 'application/octet-stream',
        'src' : 'application/x-wais-source',
        'swf' : 'application/x-shockwave-flash',
        't' : 'application/x-troff',
        'tar' : 'application/x-tar',
        'tcl' : 'application/x-tcl',
        'tex' : 'application/x-tex',
        'texi' : 'application/x-texinfo',
        'texinfo': 'application/x-texinfo',
        'tif' : 'image/tiff',
        'tiff' : 'image/tiff',
        'tr' : 'application/x-troff',
        'tsv' : 'text/tab-separated-values',
        'txt' : 'text/plain',
        'ustar' : 'application/x-ustar',
        'vcf' : 'text/x-vcard',
        'wav' : 'audio/x-wav',
        'wiz' : 'application/msword',
        'wsdl' : 'application/xml',
        'xbm' : 'image/x-xbitmap',
        'xlb' : 'application/vnd.ms-excel',
        'xls' : 'application/vnd.ms-excel',
        'xlsx' : 'application/vnd.ms-excel',
        'xml' : 'text/xml',
        'xpdl' : 'application/xml',
        'xpm' : 'image/x-xpixmap',
        'xsl' : 'application/xml',
        'xwd' : 'image/x-xwindowdump',
        'zip' : 'application/zip'
    }

function last(arr) {
    var l = arr.length;
    return arr[l - 1];
}

var Deferer = (function(){
    function Deferer () {
        this.called = 0;
        this.count = 0;
    }
    Deferer.prototype.done = function done() {
        /*override this to your callback*/
        console.log('seems forgot to bind a callback')
    }
    Deferer.prototype.tick = function tick() {
        //console.log('ticked');
        this.called++;
        if (this.count === this.called) {
            this.done();
        }
    }
    return Deferer;
}())

function getMIME(name) {
    return mimeTypes[getFileExtension(name)] || '';
}

function getFileExtension(name) {
    return last(name.split('.'));
}

var extractFiles = (function () {
    var fileCache = [];
    var unzippedCache = [];
    
    function extractFiles(blob, callback) {
        
        var index = fileCache.indexOf(blob)
        if (index >= 0) {
            setTimeout(function(){
                callback(unzippedCache[index]);
            }, 0)
            return;
        }
        
        var fileReader = new FileReader();
        fileReader.onload = function() {
            var arrayBuffer = this.result;
            
            var zip = new JSZip(arrayBuffer, {checkCRC32:true});
            var file = zip.file(/\d+.(?:jpg|png|gif)/i);
            
            var unzippedFiles = [];
            
            //console.log(file);
            file.forEach(function(file){
                var fileName, arrayBuffer, mime, blob;
                if(file.dir) {return;}
                fileName = file.name;
                arrayBuffer = file.asArrayBuffer();
                mime = getMIME(fileName);
                //console.log(arrayBuffer);
                //console.log(mime);
                blob = new Blob([arrayBuffer], {type : mime});
                unzippedFiles.push({
                    blob : blob,
                    fileName : fileName,
                    mime : mime
                })
                
                fileCache.push(blob);
                unzippedCache.push(unzippedFiles);
                
            })
            callback(unzippedFiles.slice(0));
        };
        fileReader.readAsArrayBuffer(blob);
    }
    return extractFiles;
    
}());

var download = function(){
    var cachedFile = {};
    function download(src, callback) {
        if (cachedFile[src]) {
            setTimeout(function(){
                callback(cachedFile[src]);
            }, 0)
            return;
        }
        
        //console.log(src);
        var oReq = new XMLHttpRequest();
        oReq.open("GET", src, true);
        oReq.responseType = "blob";
        
        oReq.onload = function (oEvent) {
            var blob, objectURL;
            blob = oReq.response; // Note: not oReq.responseText
            if (blob) {
                cachedFile[src] = blob;
                callback(blob);
                //objectURL = URL.createObjectURL(blob);
                //GM_openInTab(objectURL);
            } else {
                console.log('fail to download', src);
            }
        };
        oReq.send(null);
    }
    return download;
}();

function getUrl (blob, name) {
    return URL.createObjectURL(blob);
}

var getGIF = (function(){
    function getGIF (files, delays, size, callback, onprogress) {
        var imageCount = 0;
        var defer = new Deferer();
        //console.log(defer);
        var gif = new GIF({
            workers : 2,
            quality : 10,
            workerScript : GIF_worker_URL,
            width : size[0],
            height : size[1]
        });
        files.forEach(function(file){
            var delay, filename, imgElement;
            imgElement = document.createElement("img");
            imgElement.src = getUrl(file.blob);
            
            defer.count++;
            $(imgElement).on('load', defer.tick.bind(defer));
            
            delays.some(function(element){
                if (element.file === file.fileName ) {
                    delay = element.delay;
                    return true;
                } else {
                    return false;
                }
            });
            //console.log(imgElement, delay, file.fileName);
            gif.addFrame(imgElement, {delay: delay});
        })
        gif.on('finished', function(blob) {
            callback(blob);
        });
        if (onprogress) {
            gif.on('progress', function(p) {
                onprogress(p);
            });
        }
        defer.done = function(){
            gif.render();
        }
    }
    return getGIF;
}());

$('body').append(modal);
(function($){
    var defaultOption = {
        stat : 'on'
    };
    function off(el) {
        el = $(el);
        el.find('.modal').slideUp(500,function(){
            el.fadeOut(200);
        });
    }
    function on(el) {
        el = $(el);
        el.find('.modal').hide();
        el.fadeIn(200,function(){
            el.find('.modal').slideDown(500);
        });
    }
    $.fn.modal = function modal(option) {
        option = option || {};
        $.extend(option, defaultOption);
        var _modal = $(this);
        if (!_modal.is('.inited')) {
            _modal.on('click', function(e){
                if ($(e.target).is('.mmis1000-modal .exit')) {
                    off(_modal);
                }
                if ($(e.target).is('.mmis1000-modal')) {
                    off(_modal);
                }
            });
            _modal.addClass('inited');
        }
        switch (option.stat) {
            case "on":
                on(_modal);
                break;
            case "off":
                off(_modal);
                break;
            default:
                on(_modal);
        }
    };
}(jQuery));

var modal_css = ".mmis1000-modal{background:rgba(128,128,128,0.5);bottom:0;display:none;left:0;overflow:hidden;position:fixed;right:0;top:0;z-index:99999}"+
    ".mmis1000-modal .modal{background:#fff;border-radius:10px;bottom:25px;left:25px;position:absolute;right:25px;top:25px}"+
    ".mmis1000-modal .modal .head{border-bottom-color:#ddd;border-bottom-style:solid;border-bottom-width:2px;height:30px;left:0;padding-left:5px;position:absolute;right:0;top:0}"+
    ".mmis1000-modal .modal .head .text{color:#666;font-size:20px;line-height:30px}"+
    ".mmis1000-modal .modal .head .exit{background:red;border-radius:4px;color:#fff;cursor:pointer;font-size:20px;height:20px;line-height:20px;position:absolute;right:5px;text-align:center;top:5px;width:20px}"+
    ".mmis1000-modal .modal .content-wrapper{bottom:10px;left:0;overflow:auto;position:absolute;right:0;top:32px}"+
    ".mmis1000-modal .modal .content-wrapper .content{font-size:18px;left:10px;position:absolute;right:10px;text-align:center;top:10px}"+
    ".mmis1000-modal .modal .content-wrapper .content img{max-width:100%}";
$('head').append($('<style></style>').html(modal_css));
var modal = $([
    "<div id='test' class='mmis1000-modal'>",
    "<div class='modal'>",
    "<div class='head'>",
    "<span class='text'>大圖檢視</span>",
    "<div class='exit'>",
    "X",
    "</div>",
    "</div>",
    "<div class='content-wrapper'>",
    "<div class='content'>",
    "</div>",
    "</div>",
    "</div>",
    "</div>"
].join(''));
$('body').append(modal);
var modalContent = modal.find('.content');
//$(modal).modal();//debug
/*=== main program starts from here ===*/

function checkUp() {
    if (!global.pixiv.context.ugokuIllustData) {
        alert('這看起來只是一般的gif或靜圖歐,請直接右鍵下載!');
        throw new Error('can not found zipped image source');
    }
}
function checkUpLogin() {
    if (!global.pixiv.context.ugokuIllustFullscreenData) {
        alert('沒登入的話,是無法瀏覽大圖的歐!');
        throw new Error('can not found zipped fullscreen image source');
    }
}
function downloadSmall() {
    checkUp();
    var context = global.pixiv.context;
    var illustrate = context.ugokuIllustData;
    var src = illustrate.src;
    var title = context.illustTitle;
    download(src, function(blob) {
        /*objectURL = getUrl(blob);
        GM_openInTab(objectURL);*/
        saveAs(blob, title + '.zip');
    });
}

function downloadFullScreen() {
    checkUp();
    checkUpLogin();
    var context = global.pixiv.context;
    var illustrate = context.ugokuIllustFullscreenData;
    var src = illustrate.src;
    var title = context.illustTitle;
    download(src, function(blob) {
        /*objectURL = getUrl(blob);
        GM_openInTab(objectURL);*/
        saveAs(blob, title + '(fullscreen).zip');
    });
}

function showPictures() {
    checkUp();
    checkUpLogin();
    var context = global.pixiv.context;
    var illustrate = context.ugokuIllustFullscreenData;
    var src = illustrate.src;
    download(src, function(blob) {
        modal.modal();
        modalContent.html('');
        extractFiles(blob, function(files){
            files.forEach(function(file){
                var url = getUrl(file.blob);
                modalContent.append($('<p></p>').text(file.fileName));
                modalContent.append($('<img/>').attr('src', url));
            })
        });
    });
}
var showSmallGif = (function(){
    var cachedFileUrl = null;
    function showSmallGif() {
        checkUp()
        if (cachedFileUrl) {
            modalContent.html('');
            modal.modal();
            var url = cachedFileUrl;
            modalContent.append($('<img/>').attr('src', url));
            return;
        }
        var context = global.pixiv.context;
        var illustrate = context.ugokuIllustData;
        var src = illustrate.src;
        var delays = global.pixiv.context.ugokuIllustData.frames.slice(0);
        var size = global.pixiv.context.ugokuIllustData.size.slice(0);
        download(src, function(blob) {
            modalContent.html('');
            modal.modal();
            modalContent.append($('<p></p>').text('生成中,請稍候'));
            extractFiles(blob, function(files){
                getGIF(files, delays, size, function(blob){
                    modalContent.html('');
                    var url = cachedFileUrl =getUrl(blob);
                    modalContent.append($('<img/>').attr('src', url));
                }, function(p) {
                    modalContent.html('');
                    modalContent.append($('<p></p>').text('生成中,請稍候'));
                    modalContent.append($('<p></p>').text( Math.floor(p * 100) + ' %'));
                });
            });
        });
    }
    return showSmallGif;
}());
var showGif = (function(){
    var cachedFileUrl = null;
    function showGif() {
        checkUp();
        checkUpLogin();
        if (cachedFileUrl) {
            modalContent.html('');
            modal.modal();
            var url = cachedFileUrl;
            modalContent.append($('<img/>').attr('src', url));
            return;
        }
        var context = global.pixiv.context;
        var illustrate = context.ugokuIllustFullscreenData;
        var src = illustrate.src;
        var delays = global.pixiv.context.ugokuIllustData.frames.slice(0);
        var size = global.pixiv.context.illustSize.slice(0);
        download(src, function(blob) {
            modalContent.html('');
            modal.modal();
            modalContent.append($('<p></p>').text('生成中,請稍候'));
            extractFiles(blob, function(files){
                getGIF(files, delays, size, function(blob){
                    modalContent.html('');
                    var url = cachedFileUrl =getUrl(blob);
                    modalContent.append($('<img/>').attr('src', url));
                }, function(p) {
                    modalContent.html('');
                    modalContent.append($('<p></p>').text('生成中,請稍候'));
                    modalContent.append($('<p></p>').text( Math.floor(p * 100) + ' %'));
                });
            });
        });
    }
    return showGif;
}())


GM_registerMenuCommand( '下載檔案!(小圖)', downloadSmall);
GM_registerMenuCommand( '下載檔案!(大圖)', downloadFullScreen);
GM_registerMenuCommand( '檢視個別檔案!(大圖)', showPictures);
GM_registerMenuCommand( '存為gif!(小圖)', showSmallGif);
GM_registerMenuCommand( '存為gif!(大圖)', showGif);