// ==UserScript==
// @name pixiv helper
// @namespace http://mfish.twbbs.org/
// @include http://www.pixiv.net/member_illust.php?mode=medium&illust_id=*
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js
// @require https://greasyfork.dpdns.org/scripts/2350-filesaver-js/code/filesaverjs.js?version=6255
// @require http://cdnjs.cloudflare.com/ajax/libs/jszip/2.3.0/jszip.min.js
// @require https://greasyfork.dpdns.org/scripts/2963-gif-js/code/gifjs.js?version=8462
// @version 0.3.1.1
// @grant GM_registerMenuCommand
// @grant GM_openInTab
// @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);