// ==UserScript==
// @name Poipiku Downloader
// @name:zh-CN Poipiku下载器
// @description Download images or text from Poipiku
// @description:zh-cn 从Poipiku下载图片或文字
// @author calary
// @namespace http://tampermonkey.net/
// @version 0.3.1
// @license GPL-3.0
// @include http*://poipiku.com*
// @match https://poipiku.com/
// @connect img.poipiku.com
// @connect img-org.poipiku.com
// @icon https://poipiku.com/favicon.ico
// @require https://cdn.bootcdn.net/ajax/libs/jquery/2.2.4/jquery.min.js
// @require https://cdn.bootcss.com/jszip/3.1.4/jszip.min.js
// @require https://cdn.bootcss.com/FileSaver.js/1.3.2/FileSaver.min.js
// @grant GM.xmlHttpRequest
// @grant GM_xmlhttpRequest
// @run-at document-end
// ==/UserScript==
jQuery(function ($) {
const website = "poipiku";
const defaultErrorMsg = "Something went wrong";
const url = window.location.href;
const execResult = /\/(\d+)\/(\d+)/.exec(url);
const authorId = execResult && execResult[1];
const workId = execResult && execResult[2];
const logined = $(".LoginButton").length === 0;
const isText = $(".IllustItem").hasClass("Text");
const hasPassword = $(".IllustItem").hasClass("Password");
if (!workId) {
return;
}
const $panel = $(`<div>
<div>Logined: <b style="color:red">${logined}</b>.</div>
<div class="line-qualitytip" >You <b style="color:red">${
logined ? "can" : "cannot"
}</b> download high quality images.</div>
<div class="line-password">Password<input type='text' class="password"></div>
<div class="line-mode" >Rename image with page id<input type='checkbox' class="saveFileMode"></div>
<div class="line-images"><button class="btn-downloadImages" style="font-size:20px">Download Images<b class='status'></b></button></div>
<div class="line-text"><button class="btn-downloadText" style="font-size:20px">Download Text</button></div>
</div>`)
.css({
position: "fixed",
left: 0,
top: 50,
zIndex: 999999,
background: "#fff",
color: "#333",
fontSize: 18,
fontFamily: "sans-serif",
padding: 10,
})
.appendTo($("body"));
const $password = $panel.find(".password");
const $saveFileMode = $panel.find(".saveFileMode");
if (!hasPassword) {
$panel.find(".line-password").hide();
}
if (isText) {
$panel.find(".line-images").hide();
$panel.find(".line-qualitytip").hide();
$panel.find(".line-mode").hide();
} else {
$panel.find(".line-text").hide();
}
$panel.find(".btn-downloadImages").on("click", downloadImages);
$panel.find(".btn-downloadText").on("click", downloadText);
function request(config) {
return new Promise((resolve, reject) => {
$.ajax({
...config,
success: (response) => {
resolve(response);
},
error: () => {
reject(new Error("Something went wrong"));
},
});
});
}
function getBlob(url) {
// return fetch(url).then((response) => response.blob());
return new Promise((resolve, reject) => {
GM.xmlHttpRequest({
method: "GET",
url: url,
responseType: "blob",
headers: { referer: window.location.href },
onload: (payload) => {
resolve(payload.response);
},
onerror: () => {
reject(new Error(defaultErrorMsg));
},
});
});
}
// 过滤文件名非法字符
function filterFilename(filename) {
return filename.replace(/\?|\*|\:|\"|\<|\>|\\|\/|\|/g, "");
}
// 生成保存文件名
function getSaveFilename() {
const twitter = $(".UserInfoProgile a").html();
const username = $(".UserInfoUserName a").html();
const username2 = twitter ? twitter.substring(1) : username;
const desc = $(".IllustItemDesc").text().substring(0, 20);
return filterFilename(
`[${username2}][${website}][${authorId}_${workId}]${desc}`
);
}
// 生成保存图片文件名
// 默认:序号.后缀名
// 选中:网站_作品id_序号.后缀名
function getSaveImageFilename(src, index) {
let suffix = src.split(".").splice(-1);
const mode = $saveFileMode.is(":checked");
if (mode) {
return `${website}_${workId}_${index + 1}.${suffix}`;
}
return `${index + 1}.${suffix}`;
}
// 批量下载图片的默认方法
function saveImages(list, $status) {
let zip = new JSZip();
let finishehCount = 0;
let folder = zip.folder(getSaveFilename());
let currentBlob;
let isMultiple = list.lenght > 1;
$status = $status || $("<div></div>");
$status.text(`0/${list.length}`);
let promises = list.map((src, index) => {
return getBlob(src).then((blob) => {
currentBlob = blob;
finishehCount++;
$status.text(`${finishehCount}/${list.length}`);
if (isMultiple) {
folder.file(getSaveImageFilename(src, index), blob, { binary: true });
}
});
});
Promise.all(promises).then(() => {
if (isMultiple) {
zip
.generateAsync({ type: "blob", base64: true })
.then((content) => saveAs(content, getSaveFilename()));
} else {
let suffix = list[0].split(".").splice(-1);
saveAs(new Blob([currentBlob]), getSaveFilename() + "." + suffix);
}
});
}
// 保存文字的默认方法
function saveText(option) {
let str = "";
if (option.title) {
str += `标题:${option.title}\n`;
}
if (option.author) {
str += `作者:${option.author}\n`;
}
if (option.twitter) {
str += `推特:${option.twitter}\n`;
}
str += `地址:${window.location.href}\n`;
str += `\n\n`;
str += option.content;
saveAs(
new Blob([str], { type: "text/plain;charset=UTF-8" }),
getSaveFilename() + ".txt"
);
}
// 下载图片
function downloadImages() {
const $this = $(this);
const promise = logined
? request({
url: "/f/ShowIllustDetailF.jsp",
type: "POST",
data: {
ID: authorId,
TD: workId,
AD: "-1",
PAS: $password.val(),
},
dataType: "json",
}).then((payload) => {
if (!payload.html) {
throw new Error("Fetch content error. Entered wrong password?");
}
return payload.html;
})
: request({
url: "/f/ShowAppendFileF.jsp",
type: "POST",
data: {
UID: authorId,
IID: workId,
PAS: $password.val(),
MD: 0,
TWF: -1,
},
dataType: "json",
}).then((payload) => {
if (payload.result_num < 0) {
throw new Error(payload.html);
}
return $(".IllustItemThumb").eq(0).prop("outerHTML") + payload.html;
});
promise
.then((html) => {
let $page = $(html);
let list = [];
$page
.find(logined ? ".DetailIllustItemImage" : ".IllustItemThumbImg")
.each(function () {
const src = $(this).attr("src");
if (src && !/warning\.png/.test(src)) {
list.push(window.location.protocol + src);
}
});
if (list.length) {
saveImages(list, $this.find(".status"));
} else {
throw new Error("No Images");
}
})
.catch((e) => {
alert(e.message || defaultErrorMsg);
});
}
// 下载文字
function downloadText() {
request({
url: "/f/ShowAppendFileF.jsp",
type: "POST",
data: {
UID: authorId,
IID: workId,
PAS: $password.val(),
MD: 0,
TWF: -1,
},
dataType: "json",
})
.then((payload) => {
if (payload.result_num < 0) {
throw new Error(payload.html);
}
let $page = $(payload.html);
saveText({
title: $(".IllustItemDesc").text(),
author: $(".UserInfoUserName a").html(),
twitter: $(".UserInfoProgile a").prop("href"),
content: $page.find(".NovelSection").text(),
});
})
.catch((e) => {
alert(e.message || defaultErrorMsg);
});
}
});