Poipiku下载器

从Poipiku下载图片或文字

目前为 2022-01-25 提交的版本。查看 最新版本

// ==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.2
// @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 lang = (
    window.navigator.language ||
    window.navigator.browserLanguage ||
    "en-us"
  ).toLowerCase();

  const i18nMap = {
    "en-us": {
      ui_logined: "Logined",
      ui_password: "Password",
      ui_qualitytrue: "You can download high quality images.",
      ui_qualityfalse: "You cannot download high quality images.",
      ui_mode: "Rename image with page id",
      btn_downloadimages: "Save images (.zip)",
      btn_downloadimageseperately: "Save images Seperately",
      btn_downloadtext: "Save text (.txt)",
      error_default: "Something went wrong",
      error_fetch: "Fetch content error. Entered wrong password?",
      error_noimage: "No Images",
      txt_title: "Title: ",
      txt_author: "Author: ",
      txt_twitter: "Twitter: ",
      txt_link: "Link: ",
    },
    "zh-cn": {
      ui_logined: "登录(不可用)状态",
      ui_password: "密码",
      ui_qualitytrue: "可以下载高质量图片。",
      ui_qualityfalse: "不能下载高质量图片。",
      ui_mode: "图片命名包含当页ID",
      btn_downloadimages: "图片打包为(.zip)",
      btn_downloadimageseperately: "独立保存图片",
      btn_downloadtext: "保存文字为(.txt)",
      error_default: "出错了",
      error_fetch: "请求失败。是否输入密码有误?",
      error_noimage: "没有图片",
      txt_title: "标题:",
      txt_author: "作者:",
      txt_twitter: "推特:",
      txt_link: "地址:",
    },
  };
  const i18n = (key) =>
    (i18nMap[lang] && i18nMap[lang][key]) || i18nMap["en-us"][key];

  const website = "poipiku";
  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");
  const fontFamily = "Arial, 'Microsoft Yahei', Helvetica, sans-serif";

  if (!workId) {
    return;
  }

  const $panel = $(`<div>
    <div>${i18n("ui_logined")}: <b style="color:red">${logined}</b>.</div>
    <div class="line-qualitytip" >${
      logined ? i18n("ui_qualitytrue") : i18n("ui_qualityfalse")
    }</div>
    <div class="line-password">${i18n(
      "ui_password"
    )} <input type='text' class="password"></div>
    <div class="line-mode" >${i18n(
      "ui_mode"
    )} <input type='checkbox' class="saveFileMode"></div>
    <div class="line-images">
      <button class="btn-downloadImagesSeperately" style="font-size:20px">${i18n(
        "btn_downloadimageseperately"
      )} <b class='status'></b></button></button><br>
      <button class="btn-downloadImages" style="font-size:20px">${i18n(
        "btn_downloadimages"
      )} <b class='status'></b></button>
    </div>
    <div class="line-text"><button class="btn-downloadText" style="font-size:20px">${i18n(
      "btn_downloadtext"
    )}</button></div>
  </div>`)
    .css({
      position: "fixed",
      left: 0,
      top: 50,
      zIndex: 999999,
      background: "#fff",
      color: "#333",
      fontSize: 18,
      fontFamily: fontFamily,
      padding: 10,
    })
    .appendTo($("body"));

  const $password = $panel.find(".password");
  const $saveFileMode = $panel.find(".saveFileMode");
  $panel.find("button").css({
    fontFamily: fontFamily,
  });

  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", downloadImagesAsZip);
  $panel
    .find(".btn-downloadImagesSeperately")
    .on("click", downloadImagesSeperately);
  $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(i18n("error_default")));
        },
      });
    });
  }

  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(i18n("error_default")));
        },
      });
    });
  }

  // 过滤文件名非法字符
  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, saveAsZip, $status) {
    let zip = new JSZip();
    let finishehCount = 0;
    let folder = zip.folder(getSaveFilename());

    $status = $status || $("<div></div>");
    $status.text(`0/${list.length}`);

    let promises = list.map((src, index) => {
      return getBlob(src).then((blob) => {
        finishehCount++;
        $status.text(`${finishehCount}/${list.length}`);

        if (saveAsZip) {
          folder.file(getSaveImageFilename(src, index), blob, { binary: true });
        } else {
          let suffix = src.split(".").splice(-1);
          saveAs(
            new Blob([blob]),
            `${getSaveFilename()}_${index + 1}.${suffix}`
          );

          console.log("save image", index);
        }
      });
    });

    Promise.all(promises).then(() => {
      if (saveAsZip) {
        zip
          .generateAsync({ type: "blob", base64: true })
          .then((content) => saveAs(content, getSaveFilename()));
      }
    });
  }

  // 保存文字的默认方法
  function saveText(option) {
    let str = "";

    if (option.title) {
      str += `${i18n("txt_title")}${option.title}\n`;
    }
    if (option.author) {
      str += `${i18n("txt_author")}${option.author}\n`;
    }
    if (option.twitter) {
      str += `${i18n("txt_twitter")}${option.twitter}\n`;
    }
    str += `${i18n("txt_link")}${window.location.href}\n`;
    str += `\n\n`;
    str += option.content;

    saveAs(
      new Blob([str], { type: "text/plain;charset=UTF-8" }),
      getSaveFilename() + ".txt"
    );
  }

  // 下载图片
  function downloadImages(saveAsZip, $status) {
    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(i18n("error_fetch"));
          }
          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, saveAsZip, $status);
        } else {
          throw new Error(i18n("error_noimage"));
        }
      })
      .catch((e) => {
        alert(e.message || i18n("error_default"));
      });
  }

  // 打包图片
  function downloadImagesAsZip() {
    downloadImages(true, $(this).find(".status"));
  }

  // 独立下载图片
  function downloadImagesSeperately() {
    downloadImages(false, $(this).find(".status"));
  }

  // 下载文字
  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 || i18n("error_default"));
      });
  }
});

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址