Pixiv Downloader

一键下载Pixiv各页面原图。支持多图下载,动图下载,按作品标签下载,画师作品批量下载。动图支持格式转换:Gif | Apng | Webp | Webm。下载的图片将保存到以画师名命名的单独文件夹(需要调整tampermonkey“下载”设置为“浏览器API”)。保留已下载图片的记录。

Від 29.05.2023. Дивіться остання версія.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(У мене вже є менеджер скриптів, дайте мені встановити його!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Pixiv Downloader
// @namespace    https://greasyfork.org/zh-CN/scripts/432150
// @version      0.8.8
// @description:en  Download the original images of Pixiv pages with one click. Supports:multiple illustrations, ugoira(animation), and batch downloads of artists' work. Ugoira support format conversion: Gif | Apng | Webp | Webm. The downloaded images will be saved in a separate folder named after the artist (you need to adjust the tampermonkey "Download" setting to "Browser API"). A record of downloaded images is kept.
// @description  一键下载Pixiv各页面原图。支持多图下载,动图下载,按作品标签下载,画师作品批量下载。动图支持格式转换:Gif | Apng | Webp | Webm。下载的图片将保存到以画师名命名的单独文件夹(需要调整tampermonkey“下载”设置为“浏览器API”)。保留已下载图片的记录。
// @description:zh-TW  一鍵下載Pixiv各頁面原圖。支持多圖下載,動圖下載,按作品標籤下載,畫師作品批次下載。動圖支持格式轉換:Gif | Apng | Webp | Webm。下載的圖片將保存到以畫師名命名的單獨文件夾(需要調整tampermonkey“下載”設置為“瀏覽器API”)。保留已下載圖片的紀錄。
// @author       ruaruarua
// @match        https://www.pixiv.net/*
// @icon         https://www.pixiv.net/favicon.ico
// @noframes
// @grant        GM_xmlhttpRequest
// @grant        GM_download
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_info
// @grant        GM_registerMenuCommand
// @connect      i.pximg.net
// @require      https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/gif.js/0.2.0/gif.js
// @require      https://greasyfork.org/scripts/455256-toanimatedwebp/code/toAnimatedWebp.js?version=1120088
// ==/UserScript==
(function (workerChunk, JSZip, GIF) {
  'use strict';

  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }

  var workerChunk__default = /*#__PURE__*/_interopDefaultLegacy(workerChunk);
  var JSZip__default = /*#__PURE__*/_interopDefaultLegacy(JSZip);
  var GIF__default = /*#__PURE__*/_interopDefaultLegacy(GIF);

  var e=[],t=[];function n(n,r){if(n&&"undefined"!=typeof document){var a,s=!0===r.prepend?"prepend":"append",d=!0===r.singleTag,i="string"==typeof r.container?document.querySelector(r.container):document.getElementsByTagName("head")[0];if(d){var u=e.indexOf(i);-1===u&&(u=e.push(i)-1,t[u]={}),a=t[u]&&t[u][s]?t[u][s]:t[u][s]=c();}else a=c();65279===n.charCodeAt(0)&&(n=n.substring(1)),a.styleSheet?a.styleSheet.cssText+=n:a.appendChild(document.createTextNode(n));}function c(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),r.attributes)for(var t=Object.keys(r.attributes),n=0;n<t.length;n++)e.setAttribute(t[n],r.attributes[t[n]]);var a="prepend"===s?"afterbegin":"beforeend";return i.insertAdjacentElement(a,e),e}}

  var css$3 = "@property --pdl-progress {\n  syntax: '<percentage>';\n  inherits: true;\n  initial-value: 0%;\n}\n@keyframes pdl_loading {\n  100% {\n    transform: translate(-50%, -50%) rotate(360deg);\n  }\n}\n.pdl-btn {\n  position: relative;\n  border-top-right-radius: 8px;\n  background: no-repeat center/85%;\n  background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E %3Cpath fill='%233C3C3C' d='M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm-32-316v116h-67c-10.7 0-16 12.9-8.5 20.5l99 99c4.7 4.7 12.3 4.7 17 0l99-99c7.6-7.6 2.2-20.5-8.5-20.5h-67V140c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12z'%3E%3C/path%3E %3C/svg%3E\");\n  color: #01b468;\n  display: inline-block;\n  font-size: 13px;\n  font-weight: bold;\n  height: 32px;\n  line-height: 32px;\n  margin: 0;\n  overflow: hidden;\n  padding: 0;\n  border: none;\n  text-decoration: none !important;\n  text-align: center;\n  text-overflow: ellipsis;\n  user-select: none;\n  white-space: nowrap;\n  width: 32px;\n  z-index: 1;\n  cursor: pointer;\n}\n.pdl-btn-main {\n  margin: 0 0 0 10px;\n}\n.pdl-btn-sub {\n  bottom: 0;\n  background-color: rgba(255, 255, 255, 0.5);\n  left: 0;\n  position: absolute;\n}\n.pdl-btn-sub.artworks {\n  position: sticky;\n  top: 40px;\n  border-radius: 4px;\n}\n.pdl-btn-sub.presentation {\n  position: fixed;\n  top: 50px;\n  right: 16px;\n  border-radius: 8px;\n  left: auto;\n}\n.pdl-btn-sub-bookmark.pdl-btn-sub-bookmark {\n  left: auto;\n  right: 0;\n  bottom: 34px;\n  border-radius: 8px;\n  border-top-right-radius: 0px;\n  border-bottom-right-radius: 0px;\n}\n.pdl-error {\n  background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E %3Cpath fill='%23EA0000' d='M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm101.8-262.2L295.6 256l62.2 62.2c4.7 4.7 4.7 12.3 0 17l-22.6 22.6c-4.7 4.7-12.3 4.7-17 0L256 295.6l-62.2 62.2c-4.7 4.7-12.3 4.7-17 0l-22.6-22.6c-4.7-4.7-4.7-12.3 0-17l62.2-62.2-62.2-62.2c-4.7-4.7-4.7-12.3 0-17l22.6-22.6c4.7-4.7 12.3-4.7 17 0l62.2 62.2 62.2-62.2c4.7-4.7 12.3-4.7 17 0l22.6 22.6c4.7 4.7 4.7 12.3 0 17z'%3E%3C/path%3E %3C/svg%3E\") !important;\n}\n.pdl-complete {\n  background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E %3Cpath fill='%2301B468' d='M256 8C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm0 48c110.532 0 200 89.451 200 200 0 110.532-89.451 200-200 200-110.532 0-200-89.451-200-200 0-110.532 89.451-200 200-200m140.204 130.267l-22.536-22.718c-4.667-4.705-12.265-4.736-16.97-.068L215.346 303.697l-59.792-60.277c-4.667-4.705-12.265-4.736-16.97-.069l-22.719 22.536c-4.705 4.667-4.736 12.265-.068 16.971l90.781 91.516c4.667 4.705 12.265 4.736 16.97.068l172.589-171.204c4.704-4.668 4.734-12.266.067-16.971z'%3E%3C/path%3E %3C/svg%3E\") !important;\n}\n.pdl-progress {\n  background-image: none !important;\n  cursor: default !important;\n}\n.pdl-progress:after {\n  content: '';\n  display: inline-block;\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  width: 27px;\n  height: 27px;\n  transform: translate(-50%, -50%);\n  -webkit-mask: radial-gradient(transparent, transparent 54%, #000 57%, #000);\n  mask: radial-gradient(transparent, transparent 54%, #000 57%, #000);\n  border-radius: 50%;\n}\n.pdl-progress:not(:empty):after {\n  background: conic-gradient(\n    #01b468 0,\n    #01b468 var(--pdl-progress),\n    transparent var(--pdl-progress),\n    transparent\n  );\n  transition: --pdl-progress 0.2s ease;\n}\n.pdl-progress:empty:after {\n  background: conic-gradient(#01b468 0, #01b468 25%, #01b46833 25%, #01b46833);\n  animation: 1.5s infinite linear pdl_loading;\n}\n\n.pdl-btn.pdl-tag {\n  height: auto;\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 4px;\n  left: -1px;\n  background-color: rgba(0, 0, 0, 0.12);\n  transition: background-image 0.5s;\n}\n\n.pdl-btn.pdl-tag.pdl-tag-hide,\n.pdl-btn.pdl-modal-tag.pdl-tag-hide {\n  background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E  %3C/svg%3E\");\n  pointer-events: none;\n}\n\n.pdl-btn.pdl-modal-tag {\n  position: absolute;\n  right: 65px;\n  top: 6px;\n  background-origin: content-box;\n  border-radius: 4px;\n  padding: 5px;\n  width: 42px;\n  height: 50px;\n  background-color: rgba(0, 0, 0, 0.04);\n  transition: 0.25s background-color;\n}\n\n.pdl-btn.pdl-modal-tag:not(.pdl-tag-hide):hover {\n  background-color: rgba(0, 0, 0, 0.12);\n}\n\n.pdl-wrap-artworks {\n  position: absolute;\n  right: 8px;\n  top: 0px;\n  bottom: 0px;\n  margin-top: 40px;\n}\n";
  n(css$3,{});

  var css$2 = ".pdl-modal * {\n  font-family: 'win-bug-omega, system-ui, -apple-system, \"Segoe UI\", Roboto, Ubuntu, Cantarell, \"Noto Sans\", \"Hiragino Kaku Gothic ProN\", Meiryo, sans-serif';\n  line-height: 1.15;\n}\n\n.pdl-modal {\n  position: fixed;\n  top: 0;\n  left: 0;\n  width: 100%;\n  height: 100%;\n  display: flex;\n  z-index: 99;\n  background-color: rgba(0, 0, 0, 0.32);\n  user-select: none;\n}\n\n.pdl-dialog {\n  position: relative;\n  background-color: #fff;\n  border-radius: 24px;\n  margin: auto;\n  padding: 20px 40px 30px 40px;\n  width: 600px;\n  font-size: 16px;\n}\n\n.pdl-dialog-header > h3 {\n  font-weight: bold;\n  font-size: 1.17em;\n  margin: 1em 0;\n}\n\n.pdl-dialog-close {\n  position: absolute;\n  top: 10px;\n  right: 10px;\n  margin: 0;\n  padding: 0;\n  width: 25px;\n  height: 25px;\n  border: none;\n  cursor: pointer;\n  border-radius: 50%;\n  background-color: transparent;\n  transform: rotate(45deg);\n  transition: 0.25s background-color;\n  background: linear-gradient(rgb(125, 125, 125) 0%, rgb(125, 125, 125) 100%)\n      center/18px 2px no-repeat,\n    linear-gradient(rgb(125, 125, 125) 0%, rgb(125, 125, 125) 100%) center/2px\n      18px no-repeat;\n}\n\n.pdl-dialog-close:hover {\n  background-color: rgba(0, 0, 0, 0.05);\n}\n\n.pdl-dialog-content hr {\n  height: 0 !important;\n  margin: 0;\n  border: none;\n  border-top: 1px solid rgba(0, 0, 0, 0.1);\n}\n\n.pdl-dialog-content hr.sub {\n  margin-inline-start: 1.5em;\n}\n\n/* button */\n.pdl-dialog-button {\n  font-size: 16px;\n  background-color: #fff;\n  border: 1px solid rgb(125, 125, 125);\n  border-radius: 5px;\n  padding: 0.5em 1.5em;\n  cursor: pointer;\n  transition: 0.2s opacity;\n  line-height: 1.15;\n}\n.pdl-dialog-button:hover {\n  opacity: 0.7;\n}\n\n.pdl-dialog-button.primary {\n  color: #fff;\n  background-color: #0096fa;\n  border-color: #0096fa;\n}\n\n.pdl-dialog-button.icon {\n  padding: 0.5em 0.8em;\n}\n\n.pdl-dialog-button[disabled] {\n  cursor: not-allowed !important;\n  color: #c0c4cc;\n  background-color: #fff;\n  border-color: #e4e7ed;\n  opacity: 1 !important;\n}\n\n.pdl-dialog-button[disabled]:hover {\n  opacity: 1 !important;\n}\n\n.pdl-dialog-button.primary[disabled] {\n  color: #fff;\n  background-color: #a0cfff;\n  border-color: #a0cfff;\n}\n\n/* tabs */\n.pdl-tabs-nav {\n  display: flex;\n  align-items: center;\n  border-bottom: 1px solid #dcdfe6;\n  position: relative;\n}\n\n.pdl-tabs-nav .pdl-tab-item {\n  padding: 0px 16px;\n  line-height: 2.5;\n  cursor: pointer;\n  transition: 0.2s color;\n}\n\n.pdl-tabs-nav .pdl-tab-item:nth-child(2) {\n  padding-left: 0px;\n}\n\n.pdl-tabs-nav .pdl-tab-item:last-child {\n  padding-right: 0px;\n}\n\n.pdl-tab-item:hover,\n.pdl-tab-item.active {\n  color: #0096fa;\n}\n\n.pdl-tab-item.active {\n  font-weight: 700;\n}\n\n.pdl-tabs-content {\n  padding: 16px;\n  min-height: 200px;\n}\n\n.pdl-tabs-nav .pdl-tabs__active-bar {\n  position: absolute;\n  bottom: 0;\n  left: 0;\n  height: 2px;\n  background-color: #0096fa;\n  z-index: 1;\n  transition: width 0.2s, transform 0.2s;\n}\n\n/* filename */\n\n#pdl-setting-filename a {\n  color: #0096fa;\n  text-decoration: underline;\n}\n#pdl-setting-filename .tags-option label,\n#pdl-setting-filename .tags-option input {\n  cursor: pointer;\n}\n\n#pdl-setting-filename .tags-content {\n  flex: 1;\n  display: flex;\n  gap: 20px;\n}\n\n#pdl-setting-filename .pdl-input-wrap,\n#pdl-setting-filename .tags-option {\n  display: flex;\n  align-items: center;\n  margin: 12px 0;\n  gap: 12px;\n}\n\n#pdl-setting-filename .pdl-input-wrap label,\n#pdl-setting-filename .tags-option .tags-title {\n  cursor: default;\n  font-weight: 700;\n  width: 6em;\n}\n\n#pdl-setting-filename .pdl-input-wrap input[type='text'] {\n  height: auto;\n  padding: 0.5em;\n  font-size: 16px;\n  line-height: 1.5;\n  flex: 1;\n  border: 1px solid #333;\n}\n\n#pdl-setting-filename .pdl-input-wrap input[type='text']:focus {\n  background-color: #fff !important;\n}\n\n#pdl-setting-filename .pdl-input-wrap button {\n  line-height: 1.5;\n}\n\n/* ugoria */\n#pdl-setting-ugoria p.option-header {\n  font-weight: 700;\n}\n\n#pdl-setting-ugoria #pdl-ugoria-format-wrap {\n  display: flex;\n  justify-content: space-between;\n  flex-wrap: nowrap;\n  margin: 1.5em 1em;\n}\n\n#pdl-ugoria-format-wrap .pdl-ugoria-format-item,\n#pdl-ugoria-format-wrap .pdl-ugoria-format-item label,\n#pdl-ugoria-format-wrap .pdl-ugoria-format-item input {\n  cursor: pointer;\n}\n\n#pdl-ugoria-format-wrap .pdl-ugoria-format-item label {\n  padding-left: 4px;\n}\n\n/* history */\n#pdl-setting-history div {\n  text-align: center;\n  margin: 1em 0;\n}\n\n#pdl-setting-history .btn-history {\n  width: 80%;\n}\n\n/* others setting */\n#pdl-setting-others .pdl-options {\n  display: flex;\n  align-items: center;\n  gap: 20px;\n  cursor: pointer;\n  transition: 0.2s background-color;\n  padding: 1em 0.5em;\n  border-radius: 4px;\n}\n\n#pdl-setting-others .pdl-options:hover {\n  background-color: rgba(0, 0, 0, 0.05);\n}\n\n#pdl-setting-others .pdl-options.sub-option {\n  padding: 0.5em;\n  padding-inline-start: 2em;\n}\n\n/* donate */\n#pdl-setting-donate {\n  text-align: center;\n}\n\n#pdl-setting-donate p {\n  margin: 0.5em 0;\n}\n\n/* upgrade msg */\n.pdl-changelog h4 {\n  margin: 1em 0;\n  font-weight: bold !important;\n}\n\n.pdl-changelog ul {\n  padding-inline-start: 40px !important;\n}\n\n.pdl-changelog li {\n  line-height: 2;\n  list-style-type: disc !important;\n}\n\n.pdl-changelog p {\n  margin: 0.5em 0;\n}\n";
  n(css$2,{});

  var css$1 = ".pdl-dlbar-status_bar {\n  flex-grow: 1;\n  height: 46px;\n  line-height: 46px;\n  padding-right: 8px;\n  text-align: right;\n  font-weight: bold;\n  font-size: 16px;\n  color: rgb(133, 133, 133);\n  cursor: default;\n  white-space: nowrap;\n}\n\n.pdl-btn-all.pdl-btn-all,\n.pdl-stop.pdl-stop {\n  background-color: transparent;\n  border: none;\n  padding: 0 10px;\n}\n\n.pdl-btn-all.pdl-btn-all:hover,\n.pdl-stop.pdl-stop:hover {\n  color: rgb(31, 31, 31);\n}\n\n.pdl-btn-all::before,\n.pdl-stop::before {\n  content: '';\n  height: 24px;\n  width: 24px;\n  transition: background-image 0.2s ease 0s;\n  background: no-repeat center/85%;\n}\n\n.pdl-btn-all::before {\n  background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E %3Cpath fill='%23858585' d='M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm-32-316v116h-67c-10.7 0-16 12.9-8.5 20.5l99 99c4.7 4.7 12.3 4.7 17 0l99-99c7.6-7.6 2.2-20.5-8.5-20.5h-67V140c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12z'%3E%3C/path%3E %3C/svg%3E\");\n}\n\n.pdl-stop::before {\n  background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E %3Cpath fill='%23858585' d='M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm101.8-262.2L295.6 256l62.2 62.2c4.7 4.7 4.7 12.3 0 17l-22.6 22.6c-4.7 4.7-12.3 4.7-17 0L256 295.6l-62.2 62.2c-4.7 4.7-12.3 4.7-17 0l-22.6-22.6c-4.7-4.7-4.7-12.3 0-17l62.2-62.2-62.2-62.2c-4.7-4.7-4.7-12.3 0-17l22.6-22.6c4.7-4.7 12.3-4.7 17 0l62.2 62.2 62.2-62.2c4.7-4.7 12.3-4.7 17 0l22.6 22.6c4.7 4.7 4.7 12.3 0 17z'%3E%3C/path%3E %3C/svg%3E\");\n}\n\n.pdl-btn-all:hover::before {\n  background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E %3Cpath fill='%231F1F1F' d='M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm-32-316v116h-67c-10.7 0-16 12.9-8.5 20.5l99 99c4.7 4.7 12.3 4.7 17 0l99-99c7.6-7.6 2.2-20.5-8.5-20.5h-67V140c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12z'%3E%3C/path%3E %3C/svg%3E\");\n}\n\n.pdl-stop:hover::before {\n  background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E %3Cpath fill='%231F1F1F' d='M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm101.8-262.2L295.6 256l62.2 62.2c4.7 4.7 4.7 12.3 0 17l-22.6 22.6c-4.7 4.7-12.3 4.7-17 0L256 295.6l-62.2 62.2c-4.7 4.7-12.3 4.7-17 0l-22.6-22.6c-4.7-4.7-4.7-12.3 0-17l62.2-62.2-62.2-62.2c-4.7-4.7-4.7-12.3 0-17l22.6-22.6c4.7-4.7 12.3-4.7 17 0l62.2 62.2 62.2-62.2c4.7-4.7 12.3-4.7 17 0l22.6 22.6c4.7 4.7 4.7 12.3 0 17z'%3E%3C/path%3E %3C/svg%3E\");\n}\n\n.pdl-hide {\n  display: none !important;\n}\n\n.pdl-filter-wrap {\n  display: flex;\n  justify-content: flex-end;\n  gap: 12px;\n  margin: 4px 0;\n  font-weight: bold;\n  font-size: 14px;\n  line-height: 14px;\n  color: rgb(133, 133, 133);\n  transition: color 0.2s ease 0s;\n}\n\n.pdl-filter-wrap.unavailable {\n  pointer-events: none !important;\n  opacity: 0.5 !important;\n}\n\n.pdl-filter-wrap .pdl-filter:hover {\n  color: rgb(31, 31, 31);\n}\n\n.pdl-filter-wrap label {\n  padding-left: 8px;\n  cursor: pointer;\n}\n\n.pdl-checkbox.pdl-checkbox {\n  vertical-align: top;\n  appearance: none;\n  position: relative;\n  box-sizing: border-box;\n  width: 28px;\n  border: 2px solid transparent;\n  cursor: pointer;\n  border-radius: 14px;\n  height: 14px;\n  background-color: rgba(133, 133, 133);\n  transition: background-color 0.2s ease 0s, box-shadow 0.2s ease 0s;\n}\n\n.pdl-checkbox:hover {\n  background-color: rgba(31, 31, 31);\n}\n\n.pdl-checkbox::after {\n  content: '';\n  position: absolute;\n  display: block;\n  top: 0px;\n  left: 0px;\n  width: 10px;\n  height: 10px;\n  transform: translateX(0px);\n  background-color: rgb(255, 255, 255);\n  border-radius: 10px;\n  transition: transform 0.2s ease 0s;\n}\n\n.pdl-checkbox:checked {\n  background-color: rgb(0, 150, 250);\n}\n\n.pdl-checkbox:checked::after {\n  transform: translateX(14px);\n}\n\n.pdl-dlbar {\n  display: flex;\n  flex-grow: 1;\n}\n\n.pdl-dlbar-follow_latest {\n  padding: 0 8px;\n}\n";
  n(css$1,{});

  var css = "[data-theme='dark'] .pdl-btn-all::before {\n  background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E %3Cpath fill='%23858585' d='M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm-32-316v116h-67c-10.7 0-16 12.9-8.5 20.5l99 99c4.7 4.7 12.3 4.7 17 0l99-99c7.6-7.6 2.2-20.5-8.5-20.5h-67V140c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12z'%3E%3C/path%3E %3C/svg%3E\");\n}\n\n[data-theme='dark'] .pdl-btn-main,\n[data-theme='dark'] .pdl-btn-all:hover::before {\n  background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E %3Cpath fill='%23D6D6D6' d='M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm-32-316v116h-67c-10.7 0-16 12.9-8.5 20.5l99 99c4.7 4.7 12.3 4.7 17 0l99-99c7.6-7.6 2.2-20.5-8.5-20.5h-67V140c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12z'%3E%3C/path%3E %3C/svg%3E\");\n}\n\n[data-theme='dark'] .pdl-stop::before {\n  background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E %3Cpath fill='%23858585' d='M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm101.8-262.2L295.6 256l62.2 62.2c4.7 4.7 4.7 12.3 0 17l-22.6 22.6c-4.7 4.7-12.3 4.7-17 0L256 295.6l-62.2 62.2c-4.7 4.7-12.3 4.7-17 0l-22.6-22.6c-4.7-4.7-4.7-12.3 0-17l62.2-62.2-62.2-62.2c-4.7-4.7-4.7-12.3 0-17l22.6-22.6c4.7-4.7 12.3-4.7 17 0l62.2 62.2 62.2-62.2c4.7-4.7 12.3-4.7 17 0l22.6 22.6c4.7 4.7 4.7 12.3 0 17z'%3E%3C/path%3E %3C/svg%3E\");\n}\n\n[data-theme='dark'] .pdl-stop:hover::before {\n  background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E %3Cpath fill='%23D6D6D6' d='M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm101.8-262.2L295.6 256l62.2 62.2c4.7 4.7 4.7 12.3 0 17l-22.6 22.6c-4.7 4.7-12.3 4.7-17 0L256 295.6l-62.2 62.2c-4.7 4.7-12.3 4.7-17 0l-22.6-22.6c-4.7-4.7-4.7-12.3 0-17l62.2-62.2-62.2-62.2c-4.7-4.7-4.7-12.3 0-17l22.6-22.6c4.7-4.7 12.3-4.7 17 0l62.2 62.2 62.2-62.2c4.7-4.7 12.3-4.7 17 0l22.6 22.6c4.7 4.7 4.7 12.3 0 17z'%3E%3C/path%3E %3C/svg%3E\");\n}\n\n[data-theme='dark'] .pdl-checkbox:not(:checked):hover {\n  background-color: rgba(155, 155, 155);\n}\n\n[data-theme='dark'] .pdl-btn.pdl-tag {\n  background-color: rgba(255, 255, 255, 0.4);\n}\n\n[data-theme='dark'] .pdl-btn.pdl-modal-tag {\n  background-color: rgba(255, 255, 255, 0.4);\n}\n\n[data-theme='dark'] .pdl-btn.pdl-modal-tag:hover {\n  background-color: rgba(255, 255, 255, 0.6);\n}\n\n[data-theme='dark'] .pdl-wrap .pdl-filter:hover,\n[data-theme='dark'] .pdl-stop.pdl-stop:hover,\n[data-theme='dark'] .pdl-btn-all.pdl-btn-all:hover {\n  color: rgb(214, 214, 214);\n}\n\n/* modal */\n[data-theme='dark'] .pdl-dialog {\n  background-color: rgb(31, 31, 31);\n}\n\n[data-theme='dark'] .pdl-dialog-footer button {\n  background-color: rgb(245, 245, 245);\n}\n\n[data-theme='dark'] .pdl-dialog-content hr {\n  border-top: 1px solid rgba(255, 255, 255, 0.3);\n}\n\n/* others setting */\n[data-theme='dark'] #pdl-setting-others .pdl-options:hover {\n  background-color: rgba(255, 255, 255, 0.1);\n}\n";
  n(css,{});

  var IllustType;
  (function (IllustType) {
      IllustType[IllustType["illusts"] = 0] = "illusts";
      IllustType[IllustType["manga"] = 1] = "manga";
      IllustType[IllustType["ugoira"] = 2] = "ugoira";
  })(IllustType || (IllustType = {}));
  var BookmarkRestrict;
  (function (BookmarkRestrict) {
      BookmarkRestrict[BookmarkRestrict["public"] = 0] = "public";
      BookmarkRestrict[BookmarkRestrict["private"] = 1] = "private";
  })(BookmarkRestrict || (BookmarkRestrict = {}));

  const defaultSettings = Object.freeze({
      version: '0.8.8',
      ugoriaFormat: 'zip',
      folderPattern: 'pixiv/{artist}',
      filenamePattern: '{artist}_{title}_{id}_p{page}',
      tagLang: 'ja',
      showMsg: true,
      log: false,
      filter: {
          exclude_downloaded: false,
          [IllustType.illusts]: true,
          [IllustType.manga]: true,
          [IllustType.ugoira]: true
      },
      bundleIllusts: false,
      bundleManga: false,
      addBookmark: false,
      addBookmarkWithTags: false,
      privateR18: false
  });
  const regexp = {
      preloadData: /"meta-preload-data" content='(.*?)'>/,
      globalData: /"meta-global-data" content='(.*?)'>/,
      artworksPage: /artworks\/(\d+)$/,
      userPage: /users\/(\d+)/,
      bookmarkPage: /users\/\d+\/bookmarks\/artworks/,
      userPageTags: /users\/\d+\/(artworks|illustrations|manga|bookmarks(?!artworks))/,
      ppSearchPage: /\/tags\/.*\/(artworks|illustrations|manga)/,
      suscribePage: /bookmark_new_illust/,
      activityHref: /illust_id=(\d+)/,
      originSrcPageNum: /(?<=_p)\d+/,
      followLatest: /\/bookmark_new_illust(?:_r18)?\.php/
  };
  const depsUrls = {
      gifWorker: 'https://cdnjs.cloudflare.com/ajax/libs/gif.js/0.2.0/gif.worker.js',
      pako: 'https://cdnjs.cloudflare.com/ajax/libs/pako/2.0.4/pako.min.js',
      upng: 'https://cdnjs.cloudflare.com/ajax/libs/upng-js/2.1.0/UPNG.min.js'
  };
  const creditCode = `<img style="display: block; margin: 1em auto; width: 200px"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAACWCAYAAAA8AXHiAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAACxMAAAsTAQCanBgAADzWSURBVHhe7Z0HnBRF9sdrMyxZoiCegKCCOZ3xzKcCgp56CoqKohj+6pmznBGMGM+cQDALBgwneuZ4nieGU5KKIoqAIrCEDf1/3zddQ29vd09P2oD++BQzW93TXV316uWqLvhZUCowv8P8+OOP5uOPPzY9evQwvXr1MoWFhe6RYDiOY2bPnm2+/vprs+WWW5p27dq5R37bWCEwNTU1K6WDfvNYvny5M2LECKd58+bOjjvu6Hz77bfukXB88803zuabb+60aNHCueqqq5xVq1a5R+JB+t79tmZBnms5U7IqQWdrHhYvXmymTZvm/hWNlStXmpkzZxohMOVCcK9UKCkpMT/88INZtmyZqa6uNgUFBe6RaHzxxRdm6dKl7l9rJKqieX0Txi+//GKGDh1qhKOYs846y1RVRc+fsrIy0759eyWOyspK2Ll7JBxrr722ef31182ECRPMyJEjTXFxsXskHOeee67p27ev+b//+79Y92iqWGMJCy4yb9481YNeeOGFlBwINbNbt26qV8G94g567969lYDXWmsttyYatIM2iWqLGuLWrnlYYwmrdevWyoHATz/9ZL777jv9HgYIqmPHjqaoqEg5FmIUAsg1xo4dax588EFz/fXXm/Lycrd2zUOTIiy4CDqNKMluTThatmxpNt54YxVPiMXvv/8+JaF07dpVCYvrw1nywVHatm1rDjvsMLU64+hk6G60Jc4zNyY0GcJCPI0ePdoMGjTIiAWmXCUKDNr+++9vNthgA7PeeuupmEs1kB06dFDCgqDgcg0tqrj/zTffbAYPHmzGjRuXUk9sVJDGL5OZ3OghHMfZZpttYDmO6DXOl19+6R4JhwyEI7PdmTNnjn5PhX/9619Oq1at9B4nn3yyuiDiQvrR/ZY7VFRUOMJFtT177723s2TJEvdI44b0xZImw7FQjvv166cc5auvvjJTp05VMREFzu3UqZPp3r27fk8FxJQ9LxXH4t633Xab2XrrrVVfSsVBM0GzZs3MlVdeaf70pz+Z4cOHm+bNm7tHmgCaCscC77//vtOmTRudwZtuuqkjg+8eiQYz/7PPPnNk8N2aYMyePdvp3LmzXn+PPfZwfv31V/dIXcyfP9/Zbrvt9Ny+ffsqV4xC3DYEAU4lhOz+1fjRpDiWtNdstdVWZt9999W/P/30UzNlyhT9ngrXXHON2XHHHdWHFAUh2mRYZtGiRZEcCwcnliOAy6XyYV133XXahlGjRrk18dGiRYuU4aVGh8bAscTaiz0jZ8yYoSEUabrqWmLxuUfCIaJEzxcCcObNm+fW1gXtsHrcH/7wh0iO+MUXXzg9evTQc//4xz86QojukbrgulZXEmPCrQ0HoaFrr73WkYngiBUcW3+jD9PRC/OFRsGx3nvvPXPUUUeZ++67L5aesv7665tjjjlGvwuRmXvuuUe/R0EGXj/Ri15++WX9HgS87zvttJN+h3NFcSFcHzhhgYjPSP1HjAJ1kwARsfoZhaefflq565gxY8xTTz0Vyy1BKOqGG25QVwb6Z4OjoTnWgQce6EjHafD3zTffdGuj8c477ziiaMfiFkBEpiNEo+eLEhzKHeEMIt6cCy+8UC3EKC767rvvOq1bt9ZrCqG7tcE47rjj9DzKs88+69YGg/tvttlmei5t5j5xMHPmTGejjTbSvtxnn30y0uVyhUbBsbB40FGYccOGDdMwTCrgm8IaYyb/73//M//+97/dI8HgfOl09XSjR4VxAOrx2F922WVm1113jeQUePJFIdfv1sMfBvxjOGy32GILs+2227q1wXj44YfNl19+qd+HDBlixEjR76lAG0jd6dmzp+qhcazgvKKhORbWkrDv5Iw++OCDI60xi0cffVR1LazEl156ya0NBj6s//znP8ot0tFZoiDErHqTEIxytygsXLjQefHFF9UqTKVL3nXXXcq9hRidV155Ja22LliwQP176HQNCThWAYQlM7NBg1b//e9/zX777adcoFWrVkaIxuy99956LIxr4IV+5plnVNfBw17fPh70tY8++kitVThFrjgEz/PEE08ohxswYECsjInGBumTpQ3OsZiRzOKLLrrIKSkpUa5Fot3PP//snpFbYOkxo9PhBL8jPcCxGlzHgiPhozn99NONKPJah2ed2GBcEGT+8MMPk7E0eTb99IPcKeJuf//732OnxdQnPvnkkzUnAbChOZYX0qnO3/72N+eBBx5QX04criImv3PEEUeolYjfB+4X9jtSj+WRndLSUmfatGlubV288MILzvHHH+98+umnbk1dfPzxx3rOk08+6dZkDtorBoM+A5xbJpV7JByiPqi1+fLLL6fU2+obcKx6JSzcAjgWGRQGdvr06UlXgZ8Y+NtfFwQcntapKRaRI1aie6QurrvuOj2Pcs0117i1tcEg9evXT88R68qtrYujjz5az0HRZkJkA4wL3CZcb+DAgSmDzfRfly5d9Pw999yzjrGDGuHtZxR6FPv6Qr0RFlzl/vvvVw/4euutp51CWX/99bVu/Pjxah1mAjgbXE6UXC1XXHFF6KIGvPbWn7XTTju5tbUBMW+88cZ6Dt73MO7x8MMPKzFw7ziZE6mAxSgi2nn77bcjORA6IgQv6oOW8847L9lGnnvixIka5yQqYPuZCcfz3n333VlPgjioF8KCqE488UQ1yxmsoIKjcezYsaEEkQrMTBuchtuEKf4MWJ8+ffQ8wjuk4gRh11131XNoc1AICOLDAYkzkxAKf+cCccT/PffcoxOI9jEx4UwAg+Tss89OOm2DCu6ZSy+9NJaozQb1QljEvNBpmF277LKLM2HCBEcUbc1UuOOOO3TWYw3SWRCXv2MhTEQmeVVRIH/KdiDXCcMJJ5yQPI+2BAHvPMchrKBlYLkiJIAYw7cWR0/6/PPP1b9F2+C89957r3vEce68804VyxzDqkZPxdf2wQcf6HnUWW6NHpdPz3zeCeutt97SGSSWn3POOedoqokfyP4zzzxTCYuO8TobETFXX321cpn99tsvMjUFztKtWzftOJTgr7/+2j1SGyjbEDrnocwHEQmDwbH77rsvp0TkB4P717/+VScXYaooMLG22morbTflggsuSIpgOHb79u21HukQxGXh4qNGjdJnp6+feeYZ90jukXfC2n///fVhIYoovxQEs+WWW+q5WHh2MGHvgwYN0npEFwp31ExD3+BcyujRo93a2hCT3llnnXX0HJT+oDgj3AOdLxe6UxQgcjg5bbnkkkvc2mCghNv46IABA2q121q7iPCojAw44/bbb6/nDh48OG8iMa+EhQhBcYT9ouhaYqFDCFs8+OCDSUWSY6eddprOJBL46ACLJ554wmnXrp12BmIgKigL6+/YsaOeS/JdkBjj2tYC6969u5rtuQTPgni76aabnIsvvtj57rvv3CO1AQFsuOGG2g7SoVHao4D+dfvtt2vA25uWzb1IxaHvUC3sZCCdCIMJkYiVafsfAkb1IGAdxtWzhdwrf4SFlcMMo7z66qturePceuutTrNmzVTZJhZmgV4EEdLZX331lVubEBdXXnmlDgAF300YUKSJO8IFYPnoUH7dhQEaMmRIMqMCrmE7PR0Q+8O1EfRbYpLoZ3BZxGmQ/mSfl2fCH5Yqj8rex3+tuXPn6gTmfvjfLCAqng+F3VuP8k99r169Yq0byAQQVt487zbGJ/eBePU7YMMNmV0aE/RuoiEzzf1WG5x7xhlnmIMOOkhz0v/85z+7R+qCHHEbNxQCMo899phmTXjBsvjttttOc684hrc77N5heOihh7Q95JHZLFIvyEiQCaLrFMmqEEJ3jyRApECIT6ML9ANtpu1BIDfrueeeS7bRfy3bz/SxEJ1+B6xMsv3sXUyb7rNmDGlQxhwLvQmrLQhE9FG6mbU4Jr26EfqC15GJrB82bJhyGnSAIH2MGY0Ca2duGGjPzjvvrJyA602ePNk9shrc34pXIdRY2RReYFDAdfEVhek0tCNsYxE4NeKP+2OtBel5cNbLL79cuRoqQFiuGn2HaIcD+732WJFED+gzCmOAcs+YbLHFFrVUDgvOoz+ycajKNTIXhVgiuA8OPfTQ0Ie2IgxHY5QO8c9//jO5iIFdW3i4bADRwu65HjqbX8xgFDCgHIfArC8oLvBfCTdUq9fqNOlg6NChem+K12XgBVaiTWfu1KlTpG6JbsV5iET6Mgy011rOGDpBbcdyx92CQzVu4qUfWREWpisNhCvgUkCx9DeUAcSJx3kQznvvveceWQ3ypNZdd12dcXRgutwjDFhO3Jfr4o32gyxRe/y2225za+MD4s9kAjAhbRYHHC/MMkNXpG2c95e//CVSB+Ma1qpGd33ttdfcI6vB5EHJ55pw2zDnMD5G67o49dRT3dr0kBVhwWZRtLFGaASNxfloRZztdIKkmPc8EIo8pjFugzFjxqgSDavnGGIzlWWUDlCurbd/9913rxN/gwMgEuzABSGKG2XCqRBvpGJzT4jr8ccfd4/UhSUULNco6832M8+DQk5fMtFF/1PuT0HNKC8v1+sxib3KvB+I9iOPPFJVklS+tTBkRVhg1qxZGiuzDkcKK2fGjRuXtF6Q6zg9Ca7C3ex53oJPhZkSZD1lAjobcxuuRUfjR/MTFoNswzvMUL+uRGQAfQQrystVaCOW3imnnJK2CBVFPKlbsbI5ijvDdYh7wtHjgHZBCGJUJCe7vxBj5JxU/YwbKM7qpzBkRVgMHgUWjb6BGLMPwEJOq4Db8xhYTHs8zdtuu62zww476KyaNGmSPgjn5Ar2WiwwIPCK+yLo+taxSPHOYgiJFGk4GlyZkJIFDlbEOoOHcg2BesHAMeH89+OaPDuEznW9ky8I/N5/7ShwPoW+xKuONGAc6OfDDz9cU7m9/qx8Qu6RHcfygswBvOTIcYKhYbpDYwLOQ8tF4by20xkAVrpQj0IM97J46qmnkusa0UHQIy2YONQj+ukPLyBIxBDHcd6y6npNBYSVMz8W6/3YEQWfCxmaIh61njVud955p5HB0r8bAiKOjYgUXYfoxSabbKJ7OwAhnqRPCh8XPighOv2tTBKtB8uWLUtmqLL6hnOA6Fzm1ltv1e8iVutkggrRJffoEp3OiKWs3+sTCxcuNP/4xz/Uh5Z35Ipj2dnuBWwZ5RPFHo97QwGzGW6BCEM8WmAZ2cAuFhoGCeBZTj/9dBV3KL1wKft8N998sz4Pv7nhhhuSSjz6ls08QPx4fXH49KzrAA7pbUN9ggwI2o5Rw8a8+UJOOZboDu631aBOxIYWy8HSBVxERJaZOHFich1fupBO1PWKcBUv58Tzzzo82sl36XSt52/pfOVG1Nl6AAezx+E6lmNNmzZNPd88p+hSetxCLDYjirpywvPOO083XWsIcH/WVvKsoue5tflB3pd/CRfQDTZYrAmBEUZ59dVXVQSxbIpBigJiVPQfHdzJkyfrAtd0wY54hEZE/9Ml9JYYAEvPWGQh5nWtZVxz5swxzz//vIpElqLRdgCBIu7FpDeih2nIBPCMr7zyihIQCza8i1h5ZlQCjrGki9BUQ4BJxZI1Fu1uttlmbm3uIUwr3vKvVOZpOsCRinkv+k2sICieZEx0RBnOxUwR5ndCxIUdoz7o2cPqo67FsVz2Y0PBa6yEQZ41tShkI1Z2BmbZuVeJzRTsBcoMRrn1K7hB2GuvvXRp10svvaTB3UwRxvrhmGHHqPdyN4uw+qhrcSzoN00BGCMywZVzY6RhAAj9uEdDkIpj4c+R0yI3ImM2xgWBz4ceekgDsXGoPwjc77dUGhKkPBET9ubS9+/fP9LHJm1O7cciRIMjU/SNJJvHYUhiHp7hTKLgiIRMO4zf8fvfUmlIEKYTTpskKpyuXr9eECCsSOVdzqmjXFN34oknmrvuukutIPKNjjjiCM0pItcKq8j/m7hAuUXZR/ENe0kS96f8lhAmQul/Xs8iUkDfduE1GDIBfi728kL1wcfHfTFszj//fLUoMaLYyYY8ryjI+GS2dwMhHGKCXMMWUmPI7iQ9OFOwrg6Wy7VZphQketc0jhXnecLAWgF8ZkQCiAJwrTgIO48FL/ju8O15Y4Xki5EqBOLcQ87JzI8Fd3rzzTd11znMboCviN312LFu7ty5WpcuRNQq18JDfvnll5vDDz9clf01DdL37rfa39MFv8WFQDQgHcMKicJvRcetdf+uXbvqGODn8nJJ/rbjHFsaCXVl7HmHeslKIDYIl8FLjXfbG7TFAw21x6F0YnRwPa+iiEwn9cbmI3GdoFm9JpcwcIwsCBZuBGWDekG/UcjiQCE/5JBDNCrCekw7Nnzi3onzSr0oyHVyG4QmDZjovm0oYQNyobAsUy04tWDZFYl5drtECnlchE+4LsXf8WtyCfOLxYEdB0BYiUxTxsOuGqeQiMl9cgm5b+4Iyw66Fyz7ovFYFXGT+LgGnQmns2sKKaxRpJ7j/s7PZeEeQfUNUWhLNoQFcOmMGzdOtx4gXVtEmfYnn7vttlvGyXxRkDHK745+ONZ4Lx8ymh2ACWWgCxBWwAIhrIBcD7N6iBPy9gfOP+WUU3SfdGl3VnpJKnDt2HpEPYD20D/ptgldVcSkZlywU7QQqF6DscDJecIJJ2hMk9hhriFtzv+OfswYrzONhDoi/cweXnvLnlbkKsGJwkAWqkW6HCtzDiS/q1klpTLgWP2WqL4Jw4033phMzabwna2Xpk6dqmIxn5D21rUKpdLMnz/f/St74P9gLZ8Ff2PJENYhAMwbGwjbXHLJJWrdAGmbflqk8ptEISvuY4elnuB/7mxAaAkuxSf7u+KPuuWWW4zoWLFf2ulHUPuQPGR81IEQUpJjsfSH/HCsO5TnkSNHqnwmryqXIJzDEiiyM2Xg7fApJwtaB+hFuhwru8K96u9+Ydw1DFjK+JuCOBpGEH3JHveZ7j0WBO7JIhCW+rM2EQuexReso7SAY9UiLHLD7W52tuAwI7aXa9BAQgM4Re0eBhQWMEShfgmrcRQ/ICYWZrCmkxhuPhRwwBiRwOhVRQjtwXi8NMKCWetABXUIi4dgcQPuAbuAlJJqH/VsgP6FW+L888/XZUreFdJwNlH+nTfeeMOt+Z2wRKSpNUcqEdY240O2az7A/hIiNtUjb4HfUsSr3pdjLGfzv8WjDmF5gVh87rnnMl4NmwvYvUVpvMVvnbDsNpYU0VdVZWGFcz7AUjLuwzI5LyAumE2YbxLCKho1atQFoues1q5dkDFJMHLdddd1a+ofdvHBWWedpQHu+gDKfqYlX/BeG2WcV+rheqFfLr74Yg1A5+P+bCxCYJut0vlusfbaa2tKt82qDcCqenszxbfffmtEXus7cPClACFu/QzrFHxeIir1Aayvi9/Y32UK+2vvXblmJv4iP6Q/3W+5g9fPhwVG/JQ+pF/CEgu94NlEnVCfIT6suOB33A+rPp1+kd8trRfCEr1JXQoEp8l1J/cc5xyvhyOXPc1Ga4kDrht0rpiiUmTAalYf41wyVVmmhSPXO2Ac81/L2w7Meghq+PDhOptzTVxewvKC+8fpO17/izuHxR/k66dDXJlA2rU0uMU5Bg9vBwofGbPniiuu0L2pbMcsWLDAvP322xlnRgTBSwheFDAgvmO0A9FL+8hx+uyzz8z06dM1a4M2UViUAbfgO2/P4DhiyZ5HpCGX8BJvEGzf0Sbe++hdgeSFPY9P+z3fqBeOxQxGDLIRGoslCdEgEh9//HGzzjrraIeMGDHCvPjii7qChNxqVuPwySoZL1J1dqagwy2h3HTTTZpSUlpSagqLCk1hgZRCGRQpYjvo89AGUaz1O8mNJD+i93Tr1i1nHMs+pxXR/G0Jg1VB9BeFkA0hHPqQCetdrgZ4lhdeeEH7mpVIYRwwV5B21o8o9IJOZ3azitgunWLGsWTK/95BiIz3+9FhiE5A59oOzyUYMJZ2jRs3TnfsIwpguaxTzf3kvgWO1BXrM9iBBhDWcccdZ0aOHKmRhVwRloWXEPCe83Ywoha//PKLW5vALrvsom9Es/3aUICw6kUUekEnYeF5Hx69i2X5EBAWjg0BEYRmdQ5rAusDtA2FGEsIwiGURCkpKzGlzcrke4mGQyAerXfbybNQ5yW2fIFkStZlWqKiDeisRx99tK6kykdQORPUO8cKA7McKxCxyMphcq9ZAAo3YJb+0X2vcz45FiutH3roYfPIow+br0WHKi0tc48m2oeIsZmacDPqsFoRfyeddJI54IADIsWMbTf3Sgfea7IqnMxdOD5xP3LQt9lmGyWodA2hfAGOpYQlnKH8wgsvVKUUC4IFEoAAI0vH6RAsJWYlM4TBZmbzcPl8EKwt7m05A+BvO0C5BgM4ZcpzZuzY682cb78xRYWY2QlCIGi+1VZbqdKOmKTO1tNfo0aNUr0xCrbd6faZn1jRr0gVziY4nwq01bYTyYFhw8TjO/dFV7Ppyh988IG59NJL1beF5BFaSaTNkPpLiEAupPtJ4e0lIMrWPgQZOcb+6WzPw65xbMPDjm9kevo9w4AwDd5gPPd4aYVg1WOeCnHPsR7pXBeuzersQYMGO336bKDP2r37OhrL5JlZvY2neyP5m33S+/btp3t6EoTlGUHQdbMpjEOcfkkF0pdYqkcCZdj1OM7e9GzvJJxZ60hAYMdDxp4QDuk3ZKCSDm1jiKSmC7E5a6+9ti6mkesnQjqswmBzLgKadscVHoj9x4XlM80CC7sTB2U+EOPjJrYRNIo1iF6Qo024iMal03GcGzQAuShcm8Ar+6uutVZ7JZ6BA/dTwiI9muwLCIy3aXXp3MVp224tp43UswEbgeGga+aiZAN2BCT2y9oB0cU0yYB9vILAjkAiHXQLBLs9JWEb/vaPPVt9WsIiCG430oOWIKxIHQufDoozPh18NBSheGX/cj3N6kTh9rNqdobBWYj+YYHoxA/Ep9xT91qHhY4ePVp1BsC1zznnHDX7cTNgFaIsH3roocp6Afel5AOwfgrPjIXYv/8AEcPF5pJLLhXrdBszc+YsscgeN7379DEbbriBaVHeQp2OGB/sP+91qoaBtlsRExfe/sVtgO6J8o5IZIwIt+Bm6N69u3vWatAuDCAvcOWQXeoHm6CQWUoYD1eQ3TsMp/H999+fHA+2OmCPLxtB8UOeMX4GKRyMvB5YKWyfV3kwwyl+2MR99ulk91/y1WGvdvbxG1ItpMOU8i14vQnt8hdmnAW/9c/oXBauz7ORUcGMRKwjIsjLYoXLpElP6r5anEtfIO6pz2e7vPCnNdkiBo57Rm3Qv0Igym0JYLM6x/umEC+4F/vCs0rHP66IRmjAC/85FlKfu8UUftAI5DoJYIhLf6NYbEmaLMdsA8moYBWJcLVanebdtI1z/R2f68I9yBVj52UL2g/BkdYDwTHJSKJjEzXOz2e7vDj22GNr9Q3qBmLIvzWlBWPAtpSoHkwExsO2N1+Qa+d3MUVcSFuS4kE6Utk7bgdEJ+IFJ6m1gDiXkm8gfnDYYgnh6uCeDzwwzgwdOkSPsfWkjfJ7258PeEUhHnYWC+M769Kli4on1IZ07p/v9sr169/zni3oFEoYctlpDCjuBfZGwJWAzgjBE/bBKUm2QD4HyMJLWE0BayRh5RLch0HFyBArSTmY6Clmzz33VG5VX+34nbBiQHQVLcx+0VWSn3i0bYHd45wV/UstUbZXJNQD6pOwLMfCInrkkUe0TbRj6NCh5sADD8x4tUu68BIWFiEE3rlzZxWHhJ9wVOJExvNundh84tSuD47qR84JC4Ih/QXPNCID/YTBgDggFnQmvmMm48H1EhMuDM6H0IjG84m+RcHdQGAY1Cdh4WYhc4ClU7SfZyNhEZcJbcLVEie3ifZmM8BewmKRL9EQdE8KBARBEQ0hrMMr9ajjk3DPmWeemdRP6XtcOUQQvBkQjBt9znPlghCThCXfy1NdMFXnQCxnn322+kzgNBAEv5HrJ9NL7Cf1lLi45pprtINAur/NBDznO++8o23Ff0a7AUSF4swxJsbAgQPNzjvvrMTFuUH9Y9uazYB5CYsdeCZMmOD+FQ2IDX2QFHPAPmZPPfWUxjUJ3QEmMz5H6zvEF0Z6DRyR52Iz4HQD2/LMCcKSL+XsEmw38YJImJ1QOE5Lsj+HDBlSi8r9INGMLYzgVn7QqcwuZg7FsmquR6P5zmwh9oiVA3u3qbcoydzfxgvzTVi0FQIitYedlO1sDwJcmb05xdxXCy1f7fISFuNBFqiVAvxtvzNu9L/l+JtvvrmKcUQm4HnQF8lzmzJlitaRgsNLPYPAfSFGlukzTkiWcePGaUYw3JoYKf2FtIF24JI4a6UuQViffPJJOWkX/IAf2xlqgUlNQzbccEO3pi4gyAsuuECzQvHYQiA8ELMAIkHeU4c+YIkKwuFvGkRhhkGA3o70I5+EZbkKxIKLgfYG3cuexycDChfbbbfd9Lks+J09L134fxvVHwBuafVWOBAF4iIqQL9aoJuRZLnrrrsmuRjjduqpp5qPP/44SZzQgAWrqImktGzZUrkfHBqvP4s4GG/G7I477lAOSJYH2RfC6RKed2J7BJrlOoGFhZE416Ig11HnGzEzmcn6nbibNFIdikKssZ1yUedxjGvlo3DtefPm6Tq5uPcBeLL5XdDxTIoQiRb7t0Xc/guDfSY/GCvGl4iKcDR9EwfbphPfxfFq7yuEp0vx8OITcbDXsjsBeoPQyrHkIcqR21A04oiCOQ17t7JWfp/xDEwXzD5mDso+XBRRg9wHtIOSD/B8KOtwUmKZce4DN0HJ5zeIAelP90jmsPe1/W05FvUo7l9++aXp16+fSgPUBrh8fQKOhQSiPbSRlJq7775b9TN0QOFi9e9uSAX0luuvv15zuWUGKatGzrOZLuBh4gx4phg/frym+CJG4tyHQaed6GSIz3xMPq8oRE/C68+EZ7IdfPDBmm/vFcMNDem3+k9NToVZs2bpBvVYXhgU6A1ePSFfgCCw9CBsBi0dwDHgriIa3Jr8gb6gTzAw6CN2NIZjeAGhc05Dot4IC2sFpTIVYO2kZcBW4QBXXXWVZidmg7gcDhYPkaRDyFwbyxGCRAzmg2N5wUZ0p512mvqiSG+BuyKWAAo71nufPn00BMUCj4cffjjQUs838ioK4QDobTgY+cRkJXUV/SAMDBQzEB0LPc8fYOV4XEJJB9yDJWoUcte99wi6n7dNDByWJA5JrN1cty/IKsTFgJqABU4fcQ7EjW7IXvkW9DmWGvlT9jo2Lw5LLx+Q58/Pjn7PPvus7p9ExiLWJlmJ3E8erNY7/jKBtDdpLeWycF32SSUtJl3wW3aBsa/sDbp+NiUuuDdWGTlXZLzS56J76V6wtl2kILEnP3u5X3LJJWoBC6dzr5C95QnkGrlPm2EpN1zJC2YKMwSF+MYbb1Sfj3fG+yFtc7/V5gyAY97juQJtnPTkk+app59WHw/3QCxyf45R+C69ZqTrTZVTY5xqKfwtBb2G/VZ5owN/5xLcG9Am2sD1bV0YSD1ipRN+Jl5/h3iHs7I+EwerF1izOLeJydpzgb2f/YwLOX9p6G4zFuledNKkSeqF5zc4VskEOOqoozSNmbRXYl12kMLAMQpeYgiRB0f3yivkfhXLl5v5IiYYDPQm66y17bFt5rOQIsdsQWzjPIyKTsSFv8+998UdIlxfnZhMAO4dBCYymRh4x23UgmfCIY3IpBB6A+iWOE4J96CmWFUFAwDXBvflemlgVSxRiJMTJ+B0z4sBwoCz7d5779WEfTJCyRDFQZoJeOsUjjc2ZbWQ9tYRFbkqlSKiEQs8byYlX23zYtttt9UFLjLQzuDBg9Wh6T8nCqghQlS6eyNikRU4pC4LMWjhhQQWvKZYJrTuBX/SSSfpixzijKX0Q+3UZDpGFG71wHr1IGS0zETVl0hzzTW4ryiUqqMwQBZ0XIcOHXQZmkW+Bs8W//X52xZvfapjuSxeDBw4UPUmSwiinCtxsHUkfWjbkw7EEHBIw2ZFjxd42e19KBD0+PHj3aMJiAFRZ6WW3L82YYkl5owYMUIVu0cffdStdXQzU3KrcdnbZUG5BB3CggmUfdY1WpDUzxIxOJ9FPgeRyRRU39DFC/Lu77vvPkdUjFqve2N8WOI1evTorF9ZYgE3ZEnXpptuqoyFezzyyCPuUUdz/uGgbKlO+M6iDmFhEYk+ow0dMmSI1jGQFRUVujUgaw75O9dgA1XW6nFf1jdGIZ+E1ViLH0wA4nZMeAZddKAkgYl+qGsfWSic7VjZsSf+i/WImPRakMSQuScLe2FKFvK72ltFEhbAmkBpJeJt37aO8oci7vcpZQIi6Dj5ePk2KTH4UlAMpT2qoLP9ITHK37Ea/j5HYWesyGY97LDDNGcMZRwl3Gbd4mAmxspYZgruy9hjkGBAYdVjAFiQ80/KNpYmhovn2OqtIhlYYNOEbQ5PrsHiR2J/WBy8b5pYFw/A/WV21mp4EDjPtvW3gjDLzwsIi9QX8qvI2uWllVtssUXWjCAMjAHXxoUBkXvHTY7VfxAaz/agQYN0ZrHiONVGGn40NsKyHZwO0v1NHMKygCkwQeEy3CPoPpm0OR3I9es/CE2yIHt9UtIlqsaKdAk900HFz4QD9thjj03uAuQH3IMwDsQYdR8kBqEz4ovptj8OckpYiNE4jUTM4lBcExDGFfIBUonI4iT3Ca7Pe4jQWdMF7RXLUrND2b4qL0AUCjFkDRyivDHhjDPOCLRkcgUsFWsteb83tKsgn/e3IJuTHXBk2LTgzyImi1M6XfTv31+vgaPVe49cQMYlu70bcGby4vF99tkn+bAUNpbIBOxNxbt0uGaYhzcXxNSYCDJO8YINSXBcQhC2v/E74nNKB7zejxeN3nPPPW6No+nVV111lboW6JdMkTVhsSEGr8OwD4iX/IQTTtCQQSYgbMB18M3gOwmClygaY8kHofpBfjoSgk3gbN/jU6Jv4oJz8Ul5f8M7ebgWu9KkWuMQBblm/LfYy/nut9XAB0V+PCBjgb2bSCumPgpcK+h6LEvCl8UqEpTQ3xEMEvv2339/8+ijj2pWAjor+2Clo+txLn3s/Q3LxQBrHGzgOlOkdDfIDNQ0WJyjQQSDQ5WEM6w9sgLiAKLCGmHPd3wuhxxySHITL/6mo8KuFUaUDQ3bJjtQfOaqnVHuBtwLJFTaTdKyBYtXWMZFFoQfrGEkAZPjUVkc8typE/2IgKMw8to3bzwoWxByIHJOO3jNbDqAfTe24hVdYfX+Y0El6LzGAFQTm7zJsrAoHUzanFoUwm6hYkxdZke2kPvqJ9yPBaGAUEE6gBs0tgJXsSWs3n8sqASdFwekFlaLupX4lH6m0gfq7HE+00lHhFPxShrys1B5kGRRSCkKyVVnn1A2wSAXPFXIJQy8fYIYFkRkCYpl2YQEWDyRLeQ5VCQgRjNtY2MGkQry6nnO/v37qxPUC1EQEp+Vy82qioVm1YpfTOWyn0xNNe9rdkxRSUtT2rKDKW3W1hRLKShupr8REtbfpQIOVfxn7FNKuAjdLgzCPOKFdHB8MlhxZ48XNAiud/PNN2vAkpUjOOVyqZzDBdlfgA1Zhw8froFZL3Ghz/GKEN6I4V/ahY6I0xGPNnqkBdz5/fffV+OELEwL6lnXhw7iXxTCwlUIgBid1RFpG/02Y8YM3eOA32QSGGZBMesHuRbxVl4e4MWqigXmp88nm4q575jlC6YbZ+UvcnN4E0LJ5V8Fxaa4RWdTttb6plXPvUz73nuZ4tL0FlTw/KnGDsKKZRVmSlSA1OKTTz5ZB4lBZDdiZl0csHSJVGcIOwoQ77XXXqs7AU+ePLmOyIZw2M8KTzOeaiuOAS9k4hhhEq8Xm5Ut1BMk9656oT1wbgoEZkG2BlYt9exhZe9BvxEfJUUbTsNayUxgNx0hH71lqwQx2FWMi2a9Yr58/Ejz/WuXmyVfv2mcFUuED5WYgsIyEavFUkq0SGNM5dIfzOJZU82cF880s6acZpb+9IWSHYINDpbgfKv7xwvuH5chxCKsdIlKlE/lEOxiwtZGpHMwS1kDx5q4OOv2kOeskeMabLoRBR6W+/DqD5Y5+R+eTSsQxeTQs8DAPg8ZAeTn0z6OzZw5U+sBxIAVBKeBsCyhsOLZ1vMbO0m4PvVMHF6U5CVuFpYSl2PBBZtneAk7LhA977z9jnle9BsbY61e9qOZPfUCM2PS0WbVohmmtEUHU9SstSkoEm4pBAWHqqpxzMqqai1VMi4FUl/SvI0pLW9rfv1qqvl84gFm3gd3moJVdu2hFap1kQ4dxCKsdEGHQxCwbMDCyquvvlo3T4taU+gFsUQWXtCJ5P2kwvHHH69KJcToFTWIJ3bjA+SUsce5BVs1MdgA0WYXbKCYwr0gGnLFEIe2U2mXFbMQkiUsBt6KUjiWl/vRF4haQKoQ7wrKBP027mc2ZzFKQaFZsWSucJxTzC+fPiL6luiVQlAgQbSJUlW5zJS27Wm6/+l8s96frzRt199XdC72KBMCk39l5e1N85JCM+/ta8yc10ebmiomA8+ZHiMJQl4Ii8FEMech2V8AgmKVTtzAM78jsYwVKWyfxMreVMCSYutGv9geM2aMcibAu429m94jmuE0AOK3viAIC0OAdthENwsIzV4fw8MSFsRvX3LAJmb0gQUGBaIWoO8hZjPhWoBfVS5faGZPOdlUfPu+KS5ra5zCZkoo/EMZr5GzqqtXiKgsNt33uMx02vSvpkOfAWa93S4wrXvsaqqEO+lbZrleYbkpKW1tFnw03nzz2hVSw++zR04IC7bP4NnOQuQhkthzi1egkcnIgHMOBIf7goJYsYPu7Wg7cHAQ69nPBIgg+0o6xCQ7oXgBZ4WAADvXWRGNTod4pE2IVa8FBvFCxIBzLGHRZvQrQB2rv71A/4IDcy0v4acLp3ql+fbN64Wo3jMl5WvJjWsPIb3I1WsqV5hW62xjWnfpZ37874Pm8ydHCrdaaTpscqj8pLm00aO3FhSJGG1nFvz7djP/v+NMgXC0bJE1YeGOgIAYNPQqBoOQACyfHWJIb0bn4u2qpLDaRZEsR+c7BIhC7PeLeDvfPxCcm8oIgNjZXAQrDQsNa9QfOfC+CgTl2oLfYsEBfuvV2XCVWMLCt+NtA8q5nQgYEd7JgkVKqgrqwUUXXZQWcSlnSXw1i4Wgfv7iGVPaMvFOxdVHErBXdZwaIbz2xhECWv7jf8yCjx80i6Y/b5p37Guate8hs2eFnGt/K5ar6F7NW3U0c9/9h1m+aLZb6796fGRFWKyoxb+F9YbCyiy1HY34YAAYJNwLI0aMUB0IpRjLCG6FuMCa4hjbB0Ew3sEIA0SK7sW+pGHnoyxjidIe8r/RrfxmvrXQEGPepEMmgrVE+Y03bublOP4kOTis3d3Z7mNlwXVwQ8C54uiMXnifcP7HE02BU2lqCspEZAUTJ+o377wuKipTAnOkD0plclQvX2AKy1qK+GxjatQVsRrco1rEorNqsfl55vNKkNkgY8JC/yEQyrZDDB6ciY6zs9mCWYrLAWWW3WPwN+EW4PfsJINegkhhw1V0jzgzGQJFN2J/TfScIEDoWG4An49dGOIFjj7ENi4HL/F4OZaa9x5OB0ey23AT1/RzTd4LDahHiQ8C4p+Vx8Rg48D2yK/zPjSLv3rVFJag8wnxJKp9gERExxLCKm3dVURnlalZ9av0a6EQS5VwJplcxeWmGiuxcqXUJQiMa2kpKjE/f/mcqVqxOFmXCVIusQ8D3Am2DmfCEhs7dqzOei9hocMMHz5cOxJfFk5SBhnvO6KBQSATEuLgXAaCzAY4TBT4PVYcyjhWpp8Y8WsdeeSRKqpoH2LZq6tZLoOlRgAcz7/3GhAZ+7tjMSLiyRywz8X14KxMKByxPIOXE/KdfqENXAdR7+eUqAhwaYgfP5nfix4EWvzjh3eYiu8+EI7TWgacfxC1o9ZctViANdWr5PsKU7VymSnvurVZZ4dTVdea/5/7jVNVYYqEU7Xtubtp3W1r0w7naMsupmL+Z/qbQghOrojFWbl0vilbq6cp75Sw4DMgrtWrdNyK2GBWw2Gw9EiZCcp8QKdCbMH+2SA1bMN9PPJwP1aZoK8ROojiXBCGHTg/hwRwSPxlnAeBwTWjrucHv0PMwUlps1fH4hhiEg6Mtef3meELQ3fEMoRgibH6l7OhGvAaOODdajwMENVKEWPTHx1qqhfPMUWldgWVcB2x8ApL25jmbbooR0KZb9ahr+m8zfGmebse5vuPJph5b44xJcVFprKmwHTa+gTTfoOBpqxNV1Mo5y+Y8az5+oVzTVmpcMHCRLRg1bIFpnXvP5veg+7Qe6cr1qSPMl9MQYeiEOPNDiIqRNVbb72lyu+wYcOSm4NhhUFkzGq7ERscCJHEzGaRBTHFKEAk3D+IqOAyiFgIAPcBg+gnKtqAbgeXDPLqcz4ikEnjJxyO8UxwQP8xgJ5ldSivn8wLDAWblkKohvOiQOsrF8811UvnSh+tTieCQzXr+kfT+6CJZoMhk80GQ5/Rsu6eo01hcXOxBseZH96+NsExC4pNUYFjfnjrWjN9Yn/zxcRBpmLRLNNxwwNEod9IRPdq46mwuMRULf5Kro+CnxkyJqxUYPAgHNg8+TuWCFD08ekgChhYwGBBXLgk4IRxdv7zA0Ki8JZ3dB9wzDHHqH/KC85BbBOuQcx5wzW5AFYjnIpnwU8GF/brYezGh74JmIBej38YVi37yTiiExV4JhNKeefNDjEt2vcyi2b80/z40QMi9u4zc1670syYNMLMff0qUyzEVFhULM9dJdytwrTrtYtp1WUTs+z7j8yyH7DiRbFvs45cbLUyX4jHvmKRqVq+yK1JH3kjLAsG0gvEAoSErhLE6TIF14TTodgjJhFhiGAbDLZAn8O/hShD1FklPVdgAkE4iGl0MZR02uMFInTkyJHqbIUrxnIcJ/vR8hA+xfIrFq4pX38UPeqbqRebb4WoFk0bb1b+MlvaUmCcQmmHcOUVi380HfodaNr3PcAs/1msYRR4wjhCWMWlLTzXF0hfJqKGtccuHeSNsAhvIBYYSILA1k81ePBgdZpCANZTjTjiHD6Z8Tatht/ce++9mjLL3lreMEkQEKOY+QAL1abaeoFCjw8M0Ea7zXeuwETCALHPQJwziAPDMXnZAr40uHVK1BljKshSTXDDwpLmpqRZay2kyJS139CUdugnivxSU1DWzvQYcJMQ1UHmuzeuFm40XwiyNGEh6jXIwNDLJJG4XSMkLHQQRA3EgTLtFTlYj15LjEAwSi4iA8XX6mN0PLsDIk5wTyBaooDVad0PKO92cL1ARFudho3L0t0h2QJxCyHbCWPBM2HV8vJOgGESJtqxjL2pOlEguFwoCrglpNVI9CH3JUyjnyLWSsrbmV4DbzI9B99lNjjwPrEIW5lZz55sKpctNMUlhICE27WQe4uyj9jzOi/4Pek0q42E9JFXUcgGH3AETHPCHXAlP9Av0LfgIhAC/ixLcKNGjUpuNc3udOhqYcBQsJ50fFaIwSAgduBkED7iyOu/Sge4Ogg833LLLW7NatB+tsmmvbzIyRufzATwjZIWHeS/lkm/U11In2m3FahOtfjr183MZ/9m2v5hB1Mx/1Mz+7nTTM2qJeoDSwi5QlNW3onGCrHNl4/VpFBTXWWKytsLcdXNe4+LvO/dQBAZFwLchsHErwWnwLsNR8LHhIhjluPwxM8FFyAcw443gAF64403dIaHAX8UCYVYaoRTCBuFAQ6C3mM5Y7pAdGAUQPToUxghdjJ4wX1Q4i3xBp0TBxAWsb3Zz55olsx8WdSjRBYGvqv1Btxo2vXc00yfdIxZ8t17ci/inRAOBLPQtOy2uan8VSxK0acKSsqlvsY4K381JW16mt5/ud9Urlxs/vfQX00ZUrEQK9cRQ2Gh6bTdiab7jmfpvdPlPtI/+d+7AecifilCKogg/DZwCrIhIR6ICmIiAwLdBLBjCi8BArgMMMmjiAoQZEanY79TXBdRwFLNlKgABGIzIbDqwkQd98F44PwoorIGDiEm/GdBIFGv7fp7m6qaKiUOMhjcI/o/3MhZschUr1go5WdTI9+LigrNsu/e1+Q+p3q5qVm+wFRjXRaVm7V3OMUUCxec/+G9ouRWqJIPOdaI9VjcqrPpsMEgZYCZTYV64Fh0GoVgMHlRcBXEHtYTSiued+KNWEjUsQc53mosN3532WWXmXPOOSelyMJNAQdBZwlaupRrMAkITdFm9KhU0YJUuP3221Wf5FnZfdn7vJaEqqsqzKcPDFACKSJnXYipx363mTY9djPfvD7aLP/hE9HDiA/S5wmvvCUM5WFCPM3ar286bnygad6ut1k04znz1T/PEQJM+AQ5t7JypWn1hx1Nr33HihGQGVnI/RvmXTpYf8xgxIQfODfPO+887Rx8PXjusx20dMG9QRSX4ZVqcFzENMYHEyNToBbwrBgD6GRwb68rhtZQ4E3ff3iP+f6ta01JaQvjVC0z7Tc/yqy9zfEarllNROFwCPmsWGyWzP1AXRNO5ZIEkeoz18jYrDK99rvFtFtvF/mL/K700WCEFQb0Md63jHhEV8IStEHd+gSZFliicA4SDv1gELAKMUYwTkgTyhZwaJzHcHC4oT++aLFSRNmMycea6oWfmQKx3ETNNq26bqOcKEEcQl7JCSGfLpVRhbW3aslcs2LBdP0slIOFbhiHE6ukrnW/Q0yPva7MmFuBRkVYiBP0MBvxv/zyy9WyAlGcIy4QlXfeeafqPYSY/I5TC9wRiGjcFhAWXno/GMA4bUoMdCLDA2OBuGVYvj/n0kbahVgKAyJt0eyXzcwnjjKlzRPLuKoqlwsnWmUcaRLpMom7EqTWHySBO6KosEh+wz0SmbaJs0TRX77QOCWtzSZHTjGlrbomfpshIKy8K+9xgPebmB5xNR6WiD8pLfrgMQYwDnAL4P4499xzNTkxDOSIQVxYpnwGIW6bOA8LlbRsAs24Qyyx+cG5NocNfTTMIEBrWkuswJ4Db9I3ZJCwV1ZSZsqatzTNm7U0zZq3ksJba/mUv8vlU0oZn/J3aVlz4Ybe9O0asRiXmpK2PUyfg+5XovJ7yjJBoyAsMkhJIRbuqdwCIstGZ/EDSws/lw2thA0uwMqziPKbxQX6E4AD0oagoLcXED3qAItDrA/PCxybkFfHjf5ieg64yRQ0byNGnVh6Ul0jYrFGh7RIzqAUu5+I1UThu8vLDKnKlUu+N2UdN5Jr3Whad95UjwQL4fTQ4IRFh+NasLnvOEtxhuYSrKbBlIegcDNEbaDh9e7HCrWkABEGK3bRo8LcCRbkaBHuIgOEpWpMtrpA3NWYdmIN9trvH6a02w5m+a/zVSRCesKOEp8BJcGpakSB/9WsWlFhWvUbYnrvf5dp0amvHOZYbtDghEX+N555wNvqsQijdAzA4OCURGxZjhAFjAFihABlOyroi1UGMWA0RDlZ44IoAIsoAOnYqTgWDlf0QJ4LhzGTwovE0CeIpLqg0LTovJnpd8gjwnFuMM1If6mGaJaqeMOB6lRWmBopfKeucuVS5Wwt19vZbHjQA6b3vteY4uZrCaHmjqgUKO8ykxsM7FwiFpBuM8n7XeKAjfOF6zjdu3d33n//fbc2HMINdbecPfbYw+HVHmGQvtBP0fV0dzv7d7bgdXX77ruvM2bMmFob8AdB9E1n+PDhKu+Ki4udCRMmuEeiUSP/VlUsdJb+MM354ZOJzjf/GuXMnHKCM+PpEVpmP3+KM+eNK52F059zlv30P6dqZWab48WB9Ft2O/rlAnQkb70QURV7IHfYYYeEoiFl6tSpbm00uI9wLt0iqL7Bc0HcYvW5NdFgr1EmG8/32GOPubXR4Klq5H96sKamyqmuWuFUV1Y41auWJYp8r6mS+0tb9Bz33HwAwmpUfqw4YGUQGRAA0YnvK9NAcrawS+rJkCCclEuQWoT4RjSHuUa8gAot+B4m2PzHciwAFUJb+XnDar6wYMGC5L6bLVu2dN599133SDTGjx+v4qgqiw1b/UCknXzyyc66667rDBs2LON9V4MQl3M3VsCxGoW7IS7Ym8ku6SItJs4+ECQKEvQmP9+mLOcCGAS4BrA22YuBGGeusNrHlAAuEH/eV2NHkyEsnIbE0HCm4uMiiTCVrwsLDG87zkb2SQ1zOmYCnJn2/vjHaFeuITNfExYJGRFDtX64poAmQ1gQCcQlnFY5VZwYIu4Iy+FI7gtbfpYJ0HtI4IO7MOCEY3INuBS+L4iW5WRNiWs1GcLCscmsxStPVgFJg36R4QdZB5ZLkQ4Nl8kVMBggLHxuEFYqx2cm4B7kopFJSygqzr5ijQVNhrAgou22207zs3AipiIqHIzsuAeng7vAsVJZj+hNbBHOmsNUhAJBYQnyybn8Ni6wJmkX3DcVcLCSp8V2lameuTGhSSnv6YDBs555uBvp0KkGhjAKcTrep8jOOamAaIWwEIO4HdCJUsFuNYnul0q0NSVC8mONJSxEoOUicZZ5McjsTkPs0pZUIFMVwoJ4SbuOQ1iIczJPCdfk0phobFhjCQsuxSoaRCB5VamWWaEnseAV8USSIfG6VEDvg6vwG/9eWWFgFRLrKVlX2JR0prQhndFkHKTpQjiCviFfntGtCcfixYud3XffXZ2vOD2nTZvmHgnH66+/7gjX0t/wginCRnGAozdueKcpQvq7aTlI0wUcgRSZOLoKy95JC4ZTbb/99roRbiqwKJVd/BCJrDSKE3oBKP1xz22qaHKxwnwDJRyxGbTQIwzkcEXleP3WIExraYEorVVFYZn7v+N3ZABoCo7FZlS58xz+jt9hTMX/A/eR72+RaQ9jAAAAAElFTkSuQmCC"
/>`;

  const lang = document.documentElement.getAttribute('lang')?.toLowerCase() ||
      'en';
  const i18nLib = {
      en: {
          bookmarks: 'Bookmarks',
          bookmarks_public: 'Public',
          bookmarks_private: 'Private',
          stop: 'Stop',
          dlbar_category_works: 'Works',
          dlbar_filter_illusts: 'Illustrations',
          dlbar_filter_manga: 'Manga',
          dlbar_filter_ugoria: 'Ugoria',
          dlbar_filter_exclude_downloaded: 'Exclude downloaded',
          'dlbar.follow_latest.category_all.single': 'All (page)',
          'dlbar.follow_latest.category_all.all': 'All (batch)',
          'dlbar.follow_latest.category_r18.single': 'R-18 (page)',
          'dlbar.follow_latest.category_r18.all': 'R-18 (batch)',
          feedback: 'Feedback',
          gm_menu_setting: 'Settings',
          tabs_nav_filename: 'Filename',
          tags_lang: 'Tags language: ',
          tags_tips: '{artist}, {artistID}, {title}, {id}, {page}, {tags}',
          tags_tips2: 'Note: Tags language may not be the language you selected, <a href="https://crowdin.com/project/pixiv-tags" target="_blank">some tags without translations</a> may still be in other languages.',
          folder: 'Folder:',
          folder_tips: "I don't need subfolder",
          folder_tips2: "If you don't need a subfolder, just leave the folder name blank",
          folder_vm_tips: "VM doesn't support",
          folder_api_tips: 'Need Browser Api',
          filename: 'FileName:',
          filename_tips: 'Your Name?',
          tabs_nav_history: 'History',
          'modal_history_content.import_btn': 'Import',
          'modal_history_content.export_btn': 'Export',
          'modal_history_content.clear_btn': 'Clear',
          clear_history_tips: 'Do you really want to clear history?',
          tabs_nav_ugoria: 'Ugoria',
          modal_ugoria_format_title: 'Ugoria Format:',
          tabs_nav_others: 'Others',
          'modal_others_content.bundle_illusts': 'Pack multi-page illustrations into a .zip archive',
          'modal_others_content.bundle_manga': 'Pack manga into a .zip archive',
          'modal_others_content.add_bookmark': 'Bookmark work when downloading a single work',
          'modal_others_content.add_bookmark_tags': 'Add works tags',
          'modal_others_content.add_bookmark_private_r18': 'Bookmark R-18 works to private category',
          tabs_nav_donate: 'Feedback / Donate'
      },
      'zh-cn': {
          bookmarks: '收藏',
          bookmarks_public: '公开',
          bookmarks_private: '不公开',
          stop: '停止',
          dlbar_category_works: '作品',
          dlbar_filter_illusts: '插画',
          dlbar_filter_manga: '漫画',
          dlbar_filter_ugoria: '动图',
          dlbar_filter_exclude_downloaded: '排除已下载图片',
          'dlbar.follow_latest.category_all.single': '全部(单页)',
          'dlbar.follow_latest.category_all.all': '全部(批量)',
          'dlbar.follow_latest.category_r18.single': 'R-18(单页)',
          'dlbar.follow_latest.category_r18.all': 'R-18(批量)',
          feedback: '有问题or想建议?这里反馈',
          gm_menu_setting: '设置',
          tabs_nav_filename: '文件名',
          tags_lang: '标签语言:',
          tags_tips: '{artist}:作者, {artistID}:作者ID, {title}:作品标题, {id}:作品pixiv ID, {page}:页码, {tags}:作品标签。',
          tags_tips2: '请注意:标签翻译不一定是你选择的语言,部分<a href="https://crowdin.com/project/pixiv-tags" target="_blank">无对应语言翻译的标签</a>仍可能是其他语言。',
          folder: '文件夹名:',
          folder_tips: '我不想保存到子文件夹',
          folder_tips2: '如果不想保存到画师目录,文件夹名留空即可。',
          folder_vm_tips: 'Violentmonkey不支持',
          folder_api_tips: '需要Browser Api',
          filename: '文件名:',
          filename_tips: '你的名字?',
          tabs_nav_history: '历史记录',
          'modal_history_content.import_btn': '导入记录',
          'modal_history_content.export_btn': '导出记录',
          'modal_history_content.clear_btn': '清除记录',
          clear_history_tips: '真的要清除历史记录吗?',
          tabs_nav_ugoria: '动图',
          modal_ugoria_format_title: '动图格式:',
          tabs_nav_others: '其它',
          'modal_others_content.bundle_illusts': '将多页插图打包为.zip压缩包',
          'modal_others_content.bundle_manga': '将多页漫画作品打包为.zip压缩包',
          'modal_others_content.add_bookmark': '下载单个作品时收藏作品',
          'modal_others_content.add_bookmark_tags': '收藏时添加作品标签',
          'modal_others_content.add_bookmark_private_r18': '将R-18作品收藏到不公开类别',
          tabs_nav_donate: '反馈 / 赞赏'
      },
      zh: {},
      ja: {},
      ko: {},
      'zh-tw': {}
  };
  i18nLib.en = Object.create(i18nLib['zh-cn'], Object.getOwnPropertyDescriptors(i18nLib.en));
  i18nLib.ja = Object.create(i18nLib.en);
  i18nLib.ko = Object.create(i18nLib.en);
  i18nLib['zh-tw'] = Object.create(i18nLib['zh-cn']);
  i18nLib.zh = i18nLib['zh-cn'];
  const i18n = (key) => i18nLib[lang]?.[key] || `i18n[${lang}][${key}] not found`;
  const modalHtml = {
      upgradeMsgTitle: `<h3>Pixiv Downloader ${defaultSettings.version}</h3>`,
      upgradeMsgContent: `      <div class="pdl-changelog">
  <p>可乐涨价,我的暑假结束了...</p>
  <h4>新增</h4>
  <ul>
    <li>现在可以批量下载“已关注用户的新作”。</li>
    <li>——可以选择下载单页或全部(最多34页)</li>
    <li>——点击“全部”或“R-18”按钮切换需要下载的作品类别</li>
  </ul>
  <h4>其它</h4>
  <ul>
  <li>稍微提高了webp转换速度</li>
  <li>一些其它调整</li>
</ul>
</div>`,
      modalCreditFooter: `<style>.pdl-dialog-footer {
    position: relative;
    font-size: 12px;
  }</style><details style="margin-top: 1.5em;">
  <summary style="display: inline-block; list-style: none; cursor: pointer; color: #0096fa; text-decoration: underline">脚本还行?请我喝杯可乐吧!</summary>
  ${creditCode}
  <p style="text-align: center">愿你每天都能找到对的色图,就像我每天都能喝到香草味可乐</p>
</details>`,
      modalFeedback: `<a target="_blank" style="position: absolute; right: 0px; top: 0px; color: #0096fa; text-decoration: underline" href="https://greasyfork.org/zh-CN/scripts/432150-pixiv-downloader/feedback">${i18n('feedback')}</a>`,
      modalSettingsContent: `      <div>
  <div class="pdl-tabs-nav">
  <div class="pdl-tabs__active-bar"></div>
  </div>
  <div class="pdl-tabs-content">
  </div>
</div>`,
      modalSettingFilename: `            <div id="pdl-setting-filename">
<div>
  <div class="pdl-input-wrap">
    <label for="pdlfolder">${i18n('folder')}</label>
    <input type="text" id="pdlfolder" maxlength="100" />
    <button id="pdl-filename-folder-reset" class="pdl-dialog-button icon" disabled>↺</button>
    <button id="pdl-filename-folder-confirm" class="pdl-dialog-button icon primary" disabled>✓</button>
  </div>
  <div class="pdl-input-wrap">
    <label for="pdlfilename">${i18n('filename')}</label>
    <input
      type="text"
      id="pdlfilename"
      placeholder="${i18n('filename_tips')}"
      required
      maxlength="100"
    />
    <button id="pdl-filename-filename-reset" class="pdl-dialog-button icon" disabled>↺</button>
    <button id="pdl-filename-filename-confirm" class="pdl-dialog-button icon primary" disabled>✓</button>
  </div>
</div>
<div class="tags-option">
<span class="tags-title">${i18n('tags_lang')}</span>
<div class="tags-content">
  <div class="tags-item">
    <input type="radio" name="lang" id="lang_ja" value="ja" />
    <label for="lang_ja">日本語(default)</label>
  </div>
  <div class="tags-item">
    <input type="radio" name="lang" id="lang_zh" value="zh" />
    <label for="lang_zh">简中</label>
  </div>
  <div class="tags-item">
    <input type="radio" name="lang" id="lang_zh_tw" value="zh_tw" />
    <label for="lang_zh_tw">繁中</label>
  </div>
  <div class="tags-item">
    <input type="radio" name="lang" id="lang_en" value="en" />
    <label for="lang_en">English</label>
  </div>
</div>
</div>
<p style="font-size: 14px; margin: 0.5em 0">
  ${i18n('tags_tips')}
</p>
<p style="font-size: 14px; margin: 0.5em 0">
  ${i18n('folder_tips2')}
</p>
<p style="font-size: 14px; margin: 0.5em 0">
  ${i18n('tags_tips2')}
</p>
</div>`,
      modalSettingUgoria: `            <div id="pdl-setting-ugoria">
<p class="option-header">${i18n('modal_ugoria_format_title')}</p>
<div id="pdl-ugoria-format-wrap">
  <div class="pdl-ugoria-format-item">
    <input
      type="radio"
      id="pdl-ugoria-zip"
      value="zip"
      name="format"
    /><label for="pdl-ugoria-zip">Zip</label>
  </div>
  <div class="pdl-ugoria-format-item">
    <input
      type="radio"
      id="pdl-ugoria-gif"
      value="gif"
      name="format"
    /><label for="pdl-ugoria-gif">Gif</label>
  </div>
  <div class="pdl-ugoria-format-item">
    <input
      type="radio"
      id="pdl-ugoria-apng"
      value="png"
      name="format"
    /><label for="pdl-ugoria-apng">Png</label>
  </div>
  <div class="pdl-ugoria-format-item">
    <input
      type="radio"
      id="pdl-ugoria-webm"
      value="webm"
      name="format"
    /><label for="pdl-ugoria-webm">Webm</label>
  </div>
  <div class="pdl-ugoria-format-item">
    <input
      type="radio"
      id="pdl-ugoria-webp"
      value="webp"
      name="format"
    /><label for="pdl-ugoria-webp">Webp</label>
  </div>
</div>
</div>`,
      modalSettingHistory: `            <div id="pdl-setting-history">
<div>
  <button id="pdl-export" class="btn-history pdl-dialog-button primary">
    ${i18n('modal_history_content.export_btn')}
  </button>
</div>
<div>
  <input
    type="file"
    id="pdl-import"
    accept=".txt"
    style="display: none"
  /><button id="pdl-import-btn" class="btn-history pdl-dialog-button primary">
    ${i18n('modal_history_content.import_btn')}
  </button>
</div>
<div>
  <button id="pdl-clear-history" class="btn-history pdl-dialog-button primary">
    ${i18n('modal_history_content.clear_btn')}
  </button>
</div>
</div>`,
      modalSettingOthers: `            <div id="pdl-setting-others">
<div>
  <label class="pdl-options"
    ><input
      id="pdl-options-bundle-illusts"
      type="checkbox"
      class="pdl-checkbox"
    /><span
      >${i18n('modal_others_content.bundle_illusts')}</span
    ></label
  >
</div>
<hr />
<div>
  <label class="pdl-options"
    ><input
      id="pdl-options-bundle-manga"
      type="checkbox"
      class="pdl-checkbox"
    /><span
      >${i18n('modal_others_content.bundle_manga')}</span
    ></label
  >
</div>
<hr />
<div>
  <label class="pdl-options"
    ><input
      id="pdl-options-add-bookmark"
      type="checkbox"
      class="pdl-checkbox"
    /><span
      >${i18n('modal_others_content.add_bookmark')}</span
    ></label
  >
</div>
<hr />
<div>
  <label class="pdl-options sub-option"
    ><input
      id="pdl-options-add-bookmark-tags"
      type="checkbox"
      class="pdl-checkbox"
    /><span
      >${i18n('modal_others_content.add_bookmark_tags')}</span
    ></label
  >
</div>
<hr class="sub"/>
<div>
  <label class="pdl-options sub-option"
    ><input
      id="pdl-options-add-bookmark-private-r18"
      type="checkbox"
      class="pdl-checkbox"
    /><span
      >${i18n('modal_others_content.add_bookmark_private_r18')}</span
    ></label
  >
</div>
</div>`,
      modalSettingDonate: `            <div id="pdl-setting-donate">
${creditCode}
<p>如果脚本有帮助到你,欢迎扫码请我喝杯可乐 ^_^</p>
<p><a target="_blank" style="color: #0096fa; text-decoration: underline" href="https://greasyfork.org/zh-CN/scripts/432150-pixiv-downloader/feedback">${i18n('feedback')}</a></p>
</div>`
  };

  function add$1(pixivId) {
      this._records.add(pixivId);
      localStorage.setItem(`pdlTemp-${pixivId}`, '');
  }
  function has(pixivId) {
      return this._records.has(pixivId);
  }
  function getHistory() {
      const storage = localStorage.pixivDownloader || '[]';
      return new Set(JSON.parse(storage));
  }
  function updateHistory() {
      Object.keys(localStorage).forEach((key) => {
          const matchResult = /pdlTemp-(\d+)/.exec(key);
          if (matchResult) {
              this._records.add(matchResult[1]);
              localStorage.removeItem(matchResult[0]);
          }
      });
      this.saveHistory();
  }
  function clearHistory() {
      const isConfirm = confirm(i18n('clear_history_tips'));
      if (!isConfirm)
          return;
      this.updateHistory();
      this._records = new Set();
      localStorage.pixivDownloader = '[]';
      location.reload();
  }
  function saveHistory(historyArr) {
      if (historyArr) {
          localStorage.pixivDownloader = JSON.stringify(historyArr);
      }
      else {
          localStorage.pixivDownloader = JSON.stringify([...this._records]);
      }
  }
  function getAll() {
      return [...this._records];
  }
  const pixivHistory = {
      _records: getHistory(),
      add: add$1,
      has,
      getAll,
      updateHistory,
      saveHistory,
      clearHistory
  };

  function debugLog(...msgs) {
  }

  function sleep(delay) {
      return new Promise((resolve) => {
          setTimeout(resolve, delay);
      });
  }
  function wakeableSleep(delay) {
      let wake = () => void {};
      const sleep = new Promise((r) => {
          setTimeout(r, delay);
          wake = r;
      });
      return {
          wake,
          sleep
      };
  }
  function getSelfId() {
      return document.querySelector('#qualtrics_user-id')
          ?.textContent;
  }
  const env = {
      isViolentmonkey: GM_info.scriptHandler === 'Violentmonkey',
      isBlobDlAvaliable: !(navigator.userAgent.includes('Firefox') &&
          GM_info.scriptHandler === 'Tampermonkey' &&
          parseFloat(GM_info.version ?? '') > 4.17),
      isSupportSubpath: GM_info.downloadMode && GM_info.downloadMode === 'browser'
  };

  function getSettings() {
      let settings;
      if (!localStorage.pdlSetting) {
          settings = { ...defaultSettings };
          saveSettings(settings);
      }
      else {
          settings = JSON.parse(localStorage.pdlSetting);
          if (settings.version !== defaultSettings.version) {
              settings.version = defaultSettings.version;
              settings.showMsg = true;
              settings = { ...defaultSettings, ...settings };
              saveSettings(settings);
          }
      }
      return settings;
  }
  function saveSettings(settingObj) {
      settingObj = settingObj || settings;
      localStorage.pdlSetting = JSON.stringify(settingObj);
  }
  function upgradeSettings(key, value) {
      if (key in settings && settings[key] !== value) {
          settings[key] = value;
          saveSettings();
      }
  }
  const settings = getSettings();

  const handleWorker = `
let webpApi = {};
Module.onRuntimeInitialized = () => {
  webpApi = {
    init: Module.cwrap('init', '', ['number', 'number', 'number']),
    createBuffer: Module.cwrap('createBuffer', 'number', ['number']),
    addFrame: Module.cwrap('addFrame', 'number', ['number', 'number', 'number']),
    generate: Module.cwrap('generate', 'number', []),
    freeResult: Module.cwrap('freeResult', '', []),
    getResultPointer: Module.cwrap('getResultPointer', 'number', []),
    getResultSize: Module.cwrap('getResultSize', 'number', []),
  };

  postMessage('ok');
};

onmessage = (evt) => {
  const { data, delays, lossless = 1, quality = 75, method = 4} = evt.data;

  webpApi.init(lossless, quality, method);
  data.forEach((u8a, idx) => {
    const pointer = webpApi.createBuffer(u8a.length);
    Module.HEAPU8.set(u8a, pointer);
    webpApi.addFrame(pointer, u8a.length, delays[idx]);
    postMessage(idx);
  });

  webpApi.generate();
  const resultPointer = webpApi.getResultPointer();
  const resultSize = webpApi.getResultSize();
  const result = new Uint8Array(Module.HEAP8.buffer, resultPointer, resultSize);
  postMessage(result);
  webpApi.freeResult();
};`;

  async function _requestJson(url, init) {
      const res = await fetch(url, init);
      if (!res.ok)
          throw new Error('[Error]fail to fetch:' + url + ', code:' + res.status);
      const data = await res.json();
      if (data.error)
          throw new Error('[Error]JSON return error: ' + data.message);
      return data.body;
  }
  async function getJson(url) {
      let json;
      let retry = 0;
      const MAX_RETRY = 3;
      do {
          try {
              debugLog('[Info]fetch url:', url);
              json = await _requestJson(url);
          }
          catch (error) {
              retry++;
              if (retry === MAX_RETRY)
                  throw error;
              sleep(3000);
          }
      } while (!json);
      return json;
  }
  async function getArtworkHtml(illustId) {
      let params = '';
      if (settings.tagLang !== 'ja')
          params = '?lang=' + settings.tagLang;
      const res = await fetch('https://www.pixiv.net/artworks/' + illustId + params);
      if (!res.ok)
          throw new Error(String(res.status));
      return await res.text();
  }
  async function _getDeps(url) {
      return fetch(url).then((res) => {
          if (res.ok)
              return res.text();
          throw new Error(`[Pixiv Downloader]Fetch dependency ${url} failed: ${res.status} ${res.statusText}`);
      });
  }
  async function getGifWS() {
      let gifWS;
      if (!(gifWS = await GM_getValue('gifWS'))) {
          gifWS = await _getDeps(depsUrls.gifWorker);
          GM_setValue('gifWS', gifWS);
      }
      return gifWS;
  }
  async function getApngWS() {
      let apngWS;
      if (!(apngWS = await GM_getValue('apngWS'))) {
          const [pako, upng] = await Promise.all([
              _getDeps(depsUrls.pako),
              _getDeps(depsUrls.upng)
          ]);
          const upngScript = upng
              .replace('window.UPNG', 'UPNG')
              .replace('window.pako', 'pako');
          const workerEvt = `onmessage = (evt) => {
      const {data, width, height, delay } = evt.data;
      const png = UPNG.encode(data, width, height, 0, delay, {loop: 0});
      if (!png) console.log('Convert Apng failed.');
      postMessage(png);
    };`;
          apngWS = workerEvt + pako + upngScript;
          GM_setValue('apngWS', apngWS);
      }
      return apngWS;
  }
  function getWebpWS() {
      return workerChunk__default["default"] + handleWorker;
  }
  function addBookmark$1(illustId, token, tags, restrict) {
      return _requestJson('/ajax/illusts/bookmarks/add', {
          method: 'POST',
          headers: {
              accept: 'application/json',
              'content-type': 'application/json; charset=utf-8',
              'x-csrf-token': token
          },
          body: JSON.stringify({
              illust_id: illustId,
              restrict,
              comment: '',
              tags
          })
      });
  }
  function getFollowLatestWorks(page, mode) {
      return _requestJson(`/ajax/follow_latest/illust?p=${page}&mode=${mode}&lang=jp`);
  }
  const api = {
      getJson,
      getArtworkHtml,
      getGifWS,
      getApngWS,
      getWebpWS,
      getFollowLatestWorks,
      addBookmark: addBookmark$1
  };

  function initialDeps() {
      return Promise.all([api.getGifWS(), api.getApngWS(), api.getWebpWS()]).then(([gif, apng, webp]) => {
          this._deps.gif = URL.createObjectURL(new Blob([gif], { type: 'text/javascript' }));
          this._deps.apng = URL.createObjectURL(new Blob([apng], { type: 'text/javascript' }));
          this._deps.webp = URL.createObjectURL(new Blob([webp], { type: 'text/javascript' }));
          return this;
      });
  }
  function _createImgElements(zip) {
      const eles = [];
      zip.forEach((_, file) => {
          eles.push(new Promise((resolve) => {
              const image = new Image();
              image.onload = () => {
                  resolve(image);
              };
              file
                  .async('blob')
                  .then((blob) => void (image.src = URL.createObjectURL(blob)));
          }));
      });
      return Promise.all(eles);
  }
  function createInstance() {
      const zip = new JSZip__default["default"]();
      const freeApngWorkers = [];
      const freeWebpWorkers = [];
      const MAX_CONVERT = 2;
      let queue = [];
      let active = [];
      let isStop = false;
      const convertTo = {
          webp: (frames, convertMeta) => {
              return new Promise((resolve, reject) => {
                  let worker;
                  let reuse = false;
                  if (freeWebpWorkers.length) {
                      worker = freeWebpWorkers.shift();
                      reuse = true;
                  }
                  else {
                      worker = new Worker(createConverter._deps.webp);
                  }
                  convertMeta.abort = () => {
                      reject('[Info]Convert stop manually, reject when convert webp. ' +
                          convertMeta.id);
                      convertMeta.isAborted = true;
                      worker.terminate();
                  };
                  const workerLoad = new Promise((resolve) => {
                      if (reuse)
                          return resolve();
                      worker.onmessage = (evt) => {
                          if (evt.data === 'ok') {
                              resolve();
                          }
                      };
                  });
                  const delays = convertMeta.source.framesInfo.map((frameInfo) => {
                      return Number(frameInfo.delay);
                  });
                  const data = [];
                  let completed = 0;
                  frames.forEach((frame, idx) => {
                      const canvas = document.createElement('canvas');
                      const width = (canvas.width = frame.naturalWidth);
                      const height = (canvas.height = frame.naturalHeight);
                      const context = canvas.getContext('2d');
                      if (!context)
                          return;
                      context.drawImage(frame, 0, 0, width, height);
                      data.push(new Promise((resolve, reject) => {
                          canvas.toBlob((blob) => {
                              if (!blob)
                                  return reject('[Pixiv Downloader]toBlob failed: ' + idx);
                              blob.arrayBuffer().then((buffer) => {
                                  const u8a = new Uint8Array(buffer);
                                  resolve(u8a);
                                  convertMeta.onProgress?.((++completed / frames.length) * 0.5, 'webp');
                              });
                          }, 'image/webp', 1);
                      }));
                  });
                  workerLoad
                      .then(() => Promise.all(data))
                      .then((u8arrs) => {
                      if (convertMeta.isAborted)
                          return;
                      worker.onmessage = (evt) => {
                          if (typeof evt.data !== 'object') {
                              debugLog('[Info]Webp convert phrase 2:', convertMeta.id, evt.data);
                              convertMeta.onProgress?.(0.5 + (evt.data / frames.length) * 0.5, 'webp');
                          }
                          else {
                              freeWebpWorkers.push(worker);
                              resolve(new Blob([evt.data], { type: 'image/webp' }));
                          }
                      };
                      worker.postMessage({ data: u8arrs, delays });
                  })
                      .catch(console.error);
              });
          },
          gif: (frames, convertMeta) => {
              return new Promise((resolve, reject) => {
                  const gif = new GIF__default["default"]({
                      workers: 2,
                      quality: 10,
                      workerScript: createConverter._deps.gif
                  });
                  convertMeta.abort = () => {
                      gif.abort();
                      convertMeta.isAborted = true;
                  };
                  debugLog('[Info]Start convert:', convertMeta.id);
                  frames.forEach((frame, i) => {
                      gif.addFrame(frame, {
                          delay: convertMeta.source.framesInfo[i].delay
                      });
                  });
                  gif.on('progress', (progress) => {
                      debugLog('[Info]Convert progress:', convertMeta.id);
                      if (typeof convertMeta.onProgress === 'function')
                          convertMeta.onProgress(progress, 'gif');
                  });
                  gif.on('finished', (gifBlob) => {
                      resolve(gifBlob);
                  });
                  gif.on('abort', () => {
                      reject('[Info]Convert stop: abort. ' + convertMeta.id);
                  });
                  gif.render();
              });
          },
          png: (frames, convertMeta) => {
              return new Promise((resolve, reject) => {
                  const canvas = document.createElement('canvas');
                  const width = (canvas.width = frames[0].naturalWidth);
                  const height = (canvas.height = frames[0].naturalHeight);
                  const context = canvas.getContext('2d', { willReadFrequently: true });
                  if (!context)
                      return reject('[Error]Can not get canvas context');
                  const data = [];
                  const delay = convertMeta.source.framesInfo.map((frameInfo) => {
                      return Number(frameInfo.delay);
                  });
                  frames.forEach((frame) => {
                      if (convertMeta.isAborted)
                          throw ('[Info]Convert stop manually, reject when drawImage. ' +
                              convertMeta.id);
                      context.clearRect(0, 0, width, height);
                      context.drawImage(frame, 0, 0, width, height);
                      data.push(context.getImageData(0, 0, width, height).data);
                  });
                  debugLog('[Info]Start convert:', convertMeta.id);
                  let worker;
                  if (freeApngWorkers.length) {
                      worker = freeApngWorkers.shift();
                  }
                  else {
                      worker = new Worker(createConverter._deps.apng);
                  }
                  convertMeta.abort = () => {
                      reject('[Info]Convert stop manually, reject when convert apng. ' +
                          convertMeta.id);
                      convertMeta.isAborted = true;
                      worker.terminate();
                  };
                  worker.onmessage = function (e) {
                      freeApngWorkers.push(worker);
                      if (!e.data) {
                          return reject('[Error]apng data is null. ' + convertMeta.id);
                      }
                      const pngBlob = new Blob([e.data], { type: 'image/png' });
                      resolve(pngBlob);
                  };
                  const cfg = { data, width, height, delay };
                  worker.postMessage(cfg);
              });
          },
          webm: (frames, convertMeta) => {
              return new Promise((resolve, reject) => {
                  const canvas = document.createElement('canvas');
                  const width = (canvas.width = frames[0].naturalWidth);
                  const height = (canvas.height = frames[0].naturalHeight);
                  const context = canvas.getContext('2d');
                  if (!context)
                      return reject('[Error]Can not get canvas context');
                  const stream = canvas.captureStream();
                  const recorder = new MediaRecorder(stream, {
                      mimeType: 'video/webm',
                      videoBitsPerSecond: 80000000
                  });
                  const delay = convertMeta.source.framesInfo.map((frame) => {
                      return Number(frame.delay);
                  });
                  const data = [];
                  let frame = 0;
                  const displayFrame = () => {
                      context.clearRect(0, 0, width, height);
                      context.drawImage(frames[frame], 0, 0);
                      if (convertMeta.isAborted) {
                          return recorder.stop();
                      }
                      setTimeout(() => {
                          if (typeof convertMeta.onProgress === 'function')
                              convertMeta.onProgress((frame + 1) / frames.length, 'webm');
                          if (frame === frames.length - 1) {
                              return recorder.stop();
                          }
                          else {
                              frame++;
                          }
                          displayFrame();
                      }, delay[frame]);
                  };
                  recorder.ondataavailable = (event) => {
                      if (event.data && event.data.size) {
                          data.push(event.data);
                      }
                  };
                  recorder.onstop = () => {
                      if (convertMeta.isAborted) {
                          return reject('[info]Convert stop manually, reject when convert webm.' +
                              convertMeta.id);
                      }
                      resolve(new Blob(data, { type: 'video/webm' }));
                  };
                  displayFrame();
                  recorder.start();
              });
          }
      };
      const convert = (convertMeta) => {
          const { id, source, resolve, reject } = convertMeta;
          let frames;
          active.push(convertMeta);
          if (typeof convertMeta.onProgress === 'function')
              convertMeta.onProgress(0, 'zip');
          const newFolder = zip.folder(id);
          if (!newFolder)
              throw '[Error]Can not get new root folder';
          newFolder
              .loadAsync(source.data)
              .then(_createImgElements)
              .then((imgEles) => {
              zip.remove(id);
              frames = imgEles;
              if (convertMeta.isAborted)
                  throw '[Info]Convert stop manually, reject when unzip. ' + id;
              return convertTo[source.format](frames, convertMeta);
          })
              .then(resolve)
              .catch(reject)
              .finally(() => {
              frames.forEach((frame) => URL.revokeObjectURL(frame.src));
              active.splice(active.indexOf(convertMeta), 1);
              if (queue.length)
                  convert(queue.shift());
          });
      };
      return {
          add: (convertSource, handler) => {
              debugLog('[Info]Converter add', convertSource.id);
              return new Promise((resolve, reject) => {
                  queue.push({
                      id: convertSource.id,
                      isAborted: false,
                      source: convertSource,
                      onProgress: handler?.onProgress,
                      resolve,
                      reject,
                      abort() {
                          this.isAborted = true;
                      }
                  });
                  while (active.length < MAX_CONVERT && queue.length && !isStop) {
                      convert(queue.shift());
                  }
              });
          },
          del: (taskIds) => {
              if (!taskIds.length)
                  return;
              isStop = true;
              active = active.filter((convertMeta) => {
                  if (taskIds.includes(convertMeta.id)) {
                      convertMeta.abort();
                  }
                  else {
                      return true;
                  }
              });
              queue = queue.filter((convertMeta) => !taskIds.includes(convertMeta.id));
              isStop = false;
              while (active.length < MAX_CONVERT && queue.length) {
                  convert(queue.shift());
              }
          }
      };
  }
  const createConverter = {
      _deps: {
          gif: '',
          apng: '',
          webp: ''
      },
      initialDeps,
      createInstance
  };

  const zip = new JSZip__default["default"]();
  function add(id, name, data) {
      zip.folder(id)?.file(name, data);
  }
  function bundle(id) {
      const folder = zip.folder(id);
      if (!folder)
          throw new Error('[Error]no folder:' + id);
      return folder.generateAsync({ type: 'blob' });
  }
  function remove(ids) {
      if (typeof ids === 'string') {
          zip.remove(ids);
      }
      else {
          const dirs = zip.filter((_, file) => file.dir).map((dir) => dir.name);
          const dirsToDel = ids.filter((id) => dirs.some((dir) => dir.includes(id)));
          dirsToDel.forEach((dir) => zip.remove(dir));
      }
  }
  function fileCount(id) {
      let count = 0;
      zip.folder(id)?.forEach(() => count++);
      return count;
  }
  const compressor = {
      add,
      bundle,
      remove,
      fileCount
  };

  const _saveWithoutSubpath = (blob, downloadMeta) => {
      const dlEle = document.createElement('a');
      dlEle.href = URL.createObjectURL(blob);
      dlEle.download = downloadMeta.source.path;
      dlEle.click();
      URL.revokeObjectURL(dlEle.href);
      downloadMeta.resolve(downloadMeta.taskId);
  };
  const _saveWithSubpath = (blob, downloadMeta) => {
      const imgUrl = URL.createObjectURL(blob);
      const request = {
          url: imgUrl,
          name: downloadMeta.source.path,
          onerror: (error) => {
              console.log('[pixiv downloader]Error when saving', downloadMeta.source.path);
              URL.revokeObjectURL(imgUrl);
              downloadMeta.reject(error);
          },
          onload: () => {
              if (typeof downloadMeta.onLoad === 'function')
                  downloadMeta.onLoad();
              URL.revokeObjectURL(imgUrl);
              downloadMeta.resolve(downloadMeta.taskId);
          }
      };
      downloadMeta.abort = GM_download(request).abort;
  };
  function createDownloader(converter) {
      const MAX_DOWNLOAD = 5;
      const MAX_RETRY = 3;
      const INTERVAL = 500;
      const TIMEOUT = 20000;
      let isStop = false;
      let queue = [];
      let active = [];
      let save;
      if (env.isBlobDlAvaliable && env.isSupportSubpath) {
          save = _saveWithSubpath;
      }
      else {
          debugLog('[Info]scriptHandler:', GM_info.scriptHandler, GM_info.version);
          save = _saveWithoutSubpath;
      }
      const download = (downloadMeta) => {
          const { taskId, source } = downloadMeta;
          debugLog('[Info]Start download:', source.path);
          active.push(downloadMeta);
          let abortObj;
          const errorHandler = errorHandlerFactory(downloadMeta);
          if ((!env.isBlobDlAvaliable || env.isViolentmonkey) &&
              !('kind' in source)) {
              abortObj = GM_download({
                  url: source.src,
                  name: source.path,
                  headers: {
                      referer: 'https://www.pixiv.net'
                  },
                  ontimeout: errorHandler,
                  onerror: errorHandler,
                  onload: async () => {
                      debugLog('[Info]Download complete', source.path);
                      if (typeof downloadMeta.onLoad === 'function')
                          downloadMeta.onLoad();
                      downloadMeta.resolve(taskId);
                      await sleep(INTERVAL);
                      active.splice(active.indexOf(downloadMeta), 1);
                      if (queue.length && !isStop)
                          download(queue.shift());
                  }
              });
          }
          else {
              abortObj = GM_xmlhttpRequest({
                  url: source.src,
                  timeout: TIMEOUT,
                  method: 'GET',
                  headers: {
                      referer: 'https://www.pixiv.net'
                  },
                  responseType: 'blob',
                  ontimeout: errorHandler,
                  onerror: errorHandler,
                  onprogress: (e) => {
                      if (e.lengthComputable &&
                          typeof downloadMeta.onProgress === 'function') {
                          downloadMeta.onProgress(e.loaded / e.total);
                      }
                  },
                  onload: async (e) => {
                      if (downloadMeta.state === 0 )
                          return debugLog();
                      if (!('kind' in source)) {
                          save(e.response, downloadMeta);
                      }
                      else if (source.kind === 'convert') {
                          const convertSource = {
                              id: taskId,
                              data: e.response,
                              format: settings.ugoriaFormat,
                              framesInfo: source.ugoiraMeta?.frames
                          };
                          converter
                              .add(convertSource, { onProgress: downloadMeta.onProgress })
                              .then((blob) => {
                              save(blob, downloadMeta);
                          }, downloadMeta.reject);
                      }
                      else if (source.kind === 'bundle') {
                          compressor.add(taskId, source.filename, e.response);
                          if (compressor.fileCount(taskId) === source.pageCount) {
                              compressor.bundle(taskId).then((blob) => {
                                  save(blob, downloadMeta);
                                  compressor.remove(taskId);
                              });
                          }
                          else {
                              downloadMeta.resolve(taskId);
                              if (typeof downloadMeta.onLoad === 'function')
                                  downloadMeta.onLoad();
                          }
                      }
                      await sleep(INTERVAL);
                      active.splice(active.indexOf(downloadMeta), 1);
                      if (queue.length && !isStop)
                          download(queue.shift());
                  }
              });
          }
          downloadMeta.abort = () => {
              downloadMeta.state = 0 ;
              abortObj.abort();
              downloadMeta.reject('[Warning]xhr abort manually. ' + taskId);
          };
      };
      function errorHandlerFactory(downloadMeta) {
          return function () {
              const { source } = downloadMeta;
              debugLog('[Error]xmlhttpRequest timeout:', source.src);
              downloadMeta.retry++;
              if (downloadMeta.retry > MAX_RETRY) {
                  downloadMeta.reject('[Error]xmlhttpRequest failed: ' + source.src);
                  console.log('[pixiv downloader]Network error:', source.path, source.src);
                  active.splice(active.indexOf(downloadMeta), 1);
                  if (queue.length && !isStop)
                      download(queue.shift());
              }
              else {
                  debugLog('[Warning]retry xhr:', downloadMeta.retry, source.src);
                  download(downloadMeta);
              }
          };
      }
      function add(metas, handler = {}) {
          if (metas.length < 1)
              return Promise.resolve('');
          const promises = [];
          metas.forEach((source) => {
              let downloadMeta;
              promises.push(new Promise((resolve, reject) => {
                  downloadMeta = {
                      taskId: source.taskId,
                      source,
                      state: 1 ,
                      retry: 0,
                      onProgress: handler.onProgress,
                      onLoad: handler.onLoad,
                      resolve,
                      reject
                  };
                  queue.push(downloadMeta);
              }));
          });
          while (active.length < MAX_DOWNLOAD && queue.length && !isStop) {
              download(queue.shift());
          }
          return Promise.all(promises).then(([taskId]) => taskId);
      }
      function del(taskIds) {
          if (!taskIds.length)
              return;
          isStop = true;
          active = active.filter((downloadMeta) => {
              if (taskIds.includes(downloadMeta.taskId)) {
                  downloadMeta.abort?.();
              }
              else {
                  return true;
              }
          });
          queue = queue.filter((downloadMeta) => !taskIds.includes(downloadMeta.taskId));
          isStop = false;
          while (active.length < MAX_DOWNLOAD && queue.length) {
              download(queue.shift());
          }
      }
      return {
          add,
          del
      };
  }

  const needBundle = (type) => {
      return ((type === IllustType.manga && settings.bundleManga) ||
          (type === IllustType.illusts && settings.bundleIllusts));
  };
  const replaceInvalidChar = (string) => {
      if (!string)
          return '';
      const temp = document.createElement('div');
      temp.innerHTML = string;
      if (!temp.textContent)
          return '';
      return temp.textContent
          .trim()
          .replace(/^\.|\.$/g, '')
          .replace(/[\u200b-\u200f\uFEFF\u202a-\u202e\\/:*?|]/g, '')
          .replace(/"/g, "'")
          .replace(/</g, '﹤')
          .replace(/>/g, '﹥');
  };
  const getFilePath = ({ user, userId, title, tagStr, illustId, page, ext }, option = { needBundle: false, needConvert: false }) => {
      let pathPattern;
      if (settings.folderPattern &&
          env.isSupportSubpath &&
          (!option.needConvert || env.isBlobDlAvaliable) &&
          !option.needBundle) {
          pathPattern = settings.folderPattern + '/' + settings.filenamePattern;
      }
      else {
          pathPattern = settings.filenamePattern;
      }
      if (option.needBundle && !settings.filenamePattern.includes('{page}')) {
          pathPattern += '_{page}';
      }
      return (pathPattern
          .replaceAll('{artist}', user)
          .replaceAll('{artistID}', userId)
          .replaceAll('{title}', title)
          .replaceAll('{tags}', tagStr)
          .replaceAll('{page}', String(page))
          .replaceAll('{id}', illustId) + ext);
  };
  const makeTagsStr = (prev, cur, index, tagsArr) => {
      const tag = settings.tagLang === 'ja' ? cur.tag : cur.translation?.['en'] || cur.tag;
      if (index < tagsArr.length - 1) {
          return prev + tag + '_';
      }
      else {
          return prev + tag;
      }
  };
  function filterWorks(works, option) {
      const obj = {
          unavaliable: [],
          avaliable: [],
          invalid: []
      };
      works.forEach((work) => {
          if (!work.isBookmarkable) {
              obj.unavaliable.push(work.id);
          }
          else if (option.exclude_downloaded && pixivHistory.has(work.id)) {
              obj.invalid.push(work.id);
          }
          else if (!option[work.illustType]) {
              obj.invalid.push(work.id);
          }
          else {
              obj.avaliable.push(work.id);
          }
      });
      return obj;
  }
  async function getFollowLatestGenerator(filterOption, mode, page) {
      const MAX_PAGE = 34;
      const MAX_ILLUSTS_PER_PAGE = 60;
      let lastId;
      let total;
      let data;
      let cache;
      function findLastId(ids) {
          return Math.min(...ids.map((id) => Number(id)));
      }
      if (page === undefined) {
          data = await api.getFollowLatestWorks(1, mode);
          const ids = data.page.ids;
          total = ids.length;
          lastId = findLastId(ids);
          if (total === MAX_ILLUSTS_PER_PAGE) {
              const secondPageData = await api.getFollowLatestWorks(2, mode);
              const secondIds = secondPageData.page.ids;
              const secondLastId = findLastId(secondIds);
              if (secondLastId < lastId) {
                  lastId = secondLastId;
                  cache = secondPageData;
                  total += secondIds.length;
              }
          }
      }
      else {
          data = await api.getFollowLatestWorks(page, mode);
          total = data.page.ids.length;
      }
      async function* generateIds() {
          yield filterWorks(data.thumbnails.illust, filterOption);
          if (page === undefined) {
              if (total === MAX_ILLUSTS_PER_PAGE)
                  return;
              if (total < MAX_ILLUSTS_PER_PAGE * 2) {
                  yield filterWorks(cache.thumbnails.illust, filterOption);
                  return;
              }
              let currentPage = 3;
              while (currentPage <= MAX_PAGE) {
                  const data = await api.getFollowLatestWorks(currentPage, mode);
                  const ids = data.page.ids;
                  const pageLastId = findLastId(ids);
                  if (pageLastId >= lastId) {
                      yield filterWorks(cache.thumbnails.illust, filterOption);
                      break;
                  }
                  lastId = pageLastId;
                  total += ids.length;
                  yield { ...filterWorks(cache.thumbnails.illust, filterOption), total };
                  cache = data;
                  currentPage++;
                  await sleep(3000);
              }
          }
      }
      return {
          total,
          generator: generateIds()
      };
  }
  async function getChunksGenerator(userId, category, tag, rest, filterOption) {
      const OFFSET = 48;
      let requestUrl;
      if (category === 'bookmarks') {
          requestUrl = `https://www.pixiv.net/ajax/user/${userId}/illusts/bookmarks?tag=${tag}&offset=0&limit=${OFFSET}&rest=${rest}&lang=ja`;
      }
      else {
          requestUrl = `https://www.pixiv.net/ajax/user/${userId}/${category}/tag?tag=${tag}&offset=0&limit=${OFFSET}&lang=ja`;
      }
      let head = 0;
      const firstPageData = await api.getJson(requestUrl);
      const total = firstPageData.total;
      async function* generateIds() {
          yield filterWorks(firstPageData.works, filterOption);
          head += OFFSET;
          while (head < total) {
              const data = await api.getJson(requestUrl.replace('offset=0', 'offset=' + head));
              head += OFFSET;
              await sleep(3000);
              yield filterWorks(data.works, filterOption);
          }
      }
      return {
          total,
          generator: generateIds()
      };
  }
  async function getAllWorksGenerator(userId, filterOption) {
      const requestUrl = 'https://www.pixiv.net/ajax/user/' + userId + '/profile/all';
      const profile = await api.getJson(requestUrl);
      let illustIds = [];
      let mangaIds = [];
      if ((filterOption[IllustType.illusts] || filterOption[IllustType.ugoira]) &&
          typeof profile.illusts === 'object') {
          illustIds.push(...Object.keys(profile.illusts).reverse());
      }
      if (filterOption[IllustType.manga] && typeof profile.manga === 'object') {
          mangaIds.push(...Object.keys(profile.manga).reverse());
      }
      if (filterOption.exclude_downloaded) {
          illustIds = illustIds.filter((id) => !pixivHistory.has(id));
          mangaIds = mangaIds.filter((id) => !pixivHistory.has(id));
      }
      async function* generateIds() {
          const OFFSET = 48;
          const baseUrl = 'https://www.pixiv.net/ajax/user/' + userId + '/profile/illusts';
          let workCategory = 'illust';
          while (illustIds.length > 0) {
              let searchStr = '?';
              const chunk = illustIds.splice(0, OFFSET);
              searchStr +=
                  chunk.map((id) => 'ids[]=' + id).join('&') +
                      `&work_category=${workCategory}&is_first_page=0&lang=ja`;
              const data = await api.getJson(baseUrl + searchStr);
              await sleep(3000);
              yield filterWorks(Object.values(data.works), filterOption);
          }
          workCategory = 'manga';
          while (mangaIds.length > 0) {
              let searchStr = '?';
              const chunk = mangaIds.splice(0, OFFSET);
              searchStr +=
                  chunk.map((id) => 'ids[]=' + id).join('&') +
                      `&work_category=${workCategory}&is_first_page=0&lang=ja`;
              const data = await api.getJson(baseUrl + searchStr);
              await sleep(3000);
              yield filterWorks(Object.values(data.works), filterOption);
          }
      }
      return {
          total: illustIds.length + mangaIds.length,
          generator: generateIds()
      };
  }
  async function getArtworkData(illustId) {
      const htmlText = await api.getArtworkHtml(illustId);
      const preloadDataText = htmlText.match(regexp.preloadData);
      if (!preloadDataText)
          throw new Error('[Error]Fail to parse preload data.');
      const preloadData = JSON.parse(preloadDataText[1]);
      const illustData = preloadData.illust[illustId];
      const globalDataText = htmlText.match(regexp.globalData);
      if (!globalDataText)
          throw new Error('[Error]Fail to parse global data.');
      const globalData = JSON.parse(globalDataText[1]);
      let ugoiraMeta;
      if (illustData.illustType === IllustType.ugoira) {
          ugoiraMeta = await api.getJson('/ajax/illust/' + illustId + '/ugoira_meta');
      }
      return {
          illustData,
          globalData,
          ugoiraMeta
      };
  }
  function getDownloadSource(artworkData, seletedPage) {
      const { illustData, ugoiraMeta } = artworkData;
      const { illustType, userName, userId, illustTitle, illustId, tags, pageCount } = illustData;
      const pathInfo = {
          user: replaceInvalidChar(userName) || 'userId-' + userId,
          title: replaceInvalidChar(illustTitle) || 'illustId-' + illustId,
          tagStr: replaceInvalidChar(tags.tags.reduce(makeTagsStr, '')),
          illustId,
          userId,
          ext: '',
          page: 0
      };
      const metas = [];
      const taskId = illustId + '_' + Math.random().toString(36).slice(2);
      if (illustType === IllustType.illusts || illustType === IllustType.manga) {
          const firstImgSrc = illustData.urls.original;
          const srcPrefix = firstImgSrc.slice(0, firstImgSrc.indexOf('_') + 2);
          const extendName = firstImgSrc.slice(-4);
          pathInfo.ext = extendName;
          if (pageCount > 1 && seletedPage === undefined) {
              if (needBundle(illustType)) {
                  const path = getFilePath({ ...pathInfo, ext: '.zip', page: pageCount });
                  for (let i = 0; i < pageCount; i++) {
                      pathInfo.page = i;
                      metas.push({
                          kind: 'bundle',
                          taskId,
                          path,
                          src: srcPrefix + i + extendName,
                          filename: getFilePath(pathInfo, { needBundle: true }),
                          pageCount
                      });
                  }
              }
              else {
                  for (let i = 0; i < pageCount; i++) {
                      pathInfo.page = i;
                      metas.push({
                          taskId,
                          path: getFilePath(pathInfo),
                          src: srcPrefix + i + extendName
                      });
                  }
              }
          }
          else {
              let src = firstImgSrc;
              if (seletedPage !== undefined) {
                  src = srcPrefix + seletedPage + extendName;
                  pathInfo.page = seletedPage;
              }
              metas.push({
                  taskId,
                  path: getFilePath(pathInfo),
                  src
              });
          }
      }
      else if (illustType === IllustType.ugoira && ugoiraMeta) {
          pathInfo.ext = '.' + settings.ugoriaFormat;
          if (settings.ugoriaFormat !== 'zip') {
              metas.push({
                  kind: 'convert',
                  ugoiraMeta,
                  taskId,
                  src: ugoiraMeta.originalSrc,
                  path: getFilePath(pathInfo, { needConvert: true })
              });
          }
          else {
              metas.push({
                  taskId,
                  src: ugoiraMeta.originalSrc,
                  path: getFilePath(pathInfo)
              });
          }
      }
      return metas;
  }
  const parser = {
      getChunksGenerator,
      getAllWorksGenerator,
      getFollowLatestGenerator,
      getArtworkData,
      getDownloadSource
  };

  let converter;
  let downloader;
  async function initial() {
      converter = await createConverter
          .initialDeps()
          .then((createConverter) => createConverter.createInstance());
      downloader = createDownloader(converter);
  }

  function addBookmark(pdlBtn, illustId, token, tags) {
      if (!settings.addBookmark)
          return;
      api
          .addBookmark(illustId, token, settings.addBookmarkWithTags ? tags : [], settings.privateR18 && tags.includes('R-18')
          ? BookmarkRestrict.private
          : BookmarkRestrict.public)
          .then(() => {
          const bookmarkBtnRef = findBookmarkBtn(pdlBtn);
          if (!bookmarkBtnRef)
              return;
          switch (bookmarkBtnRef.kind) {
              case "main" : {
                  const pathBorder = bookmarkBtnRef.button.querySelector('svg g path');
                  pathBorder && (pathBorder.style.color = 'rgb(255, 64, 96)');
                  break;
              }
              case "sub" : {
                  const pathBorder = bookmarkBtnRef.button.querySelector('path');
                  pathBorder && (pathBorder.style.color = 'rgb(255, 64, 96)');
                  break;
              }
              case "rank" : {
                  bookmarkBtnRef.button.style.backgroundColor = 'rgb(255, 64, 96)';
                  break;
              }
          }
      })
          .catch((reason) => {
          console.error(reason.message);
      });
  }
  function findBookmarkBtn(pdlBtn) {
      const bookmarkBtnRef = {};
      if (pdlBtn.classList.contains('pdl-btn-sub')) {
          const btn = pdlBtn.parentElement?.nextElementSibling?.querySelector('button[type="button"]');
          if (btn) {
              bookmarkBtnRef.kind = "sub" ;
              bookmarkBtnRef.button = btn;
          }
          else {
              const btn = pdlBtn.parentElement?.querySelector('div._one-click-bookmark');
              if (btn) {
                  bookmarkBtnRef.kind = "rank" ;
                  bookmarkBtnRef.button = btn;
              }
          }
      }
      else if (pdlBtn.classList.contains('pdl-btn-main')) {
          const btn = pdlBtn.parentElement?.parentElement?.querySelector('button.gtm-main-bookmark');
          if (btn) {
              bookmarkBtnRef.kind = "main" ;
              bookmarkBtnRef.button = btn;
          }
      }
      else {
          return debugLog();
      }
      return bookmarkBtnRef;
  }

  function handleDownload(pdlBtn, illustId) {
      let pageCount, pageComplete = 0, shouldDownloadPage;
      const pageAttr = pdlBtn.getAttribute('should-download');
      if (pageAttr) {
          shouldDownloadPage = Number(pageAttr);
      }
      const onProgress = (progress = 0, type = null) => {
          if (pageCount > 1)
              return;
          progress = Math.floor(progress * 100);
          switch (type) {
              case null:
                  pdlBtn.style.setProperty('--pdl-progress', progress + '%');
              case 'gif':
              case 'webm':
              case 'webp':
                  pdlBtn.textContent = String(progress);
                  break;
              case 'zip':
                  pdlBtn.textContent = '';
                  break;
          }
      };
      const onLoad = function () {
          if (pageCount < 2)
              return;
          const progress = Math.floor((++pageComplete / pageCount) * 100);
          pdlBtn.textContent = String(progress);
          pdlBtn.style.setProperty('--pdl-progress', progress + '%');
      };
      pdlBtn.classList.add('pdl-progress');
      parser
          .getArtworkData(illustId)
          .then((artworkData) => {
          const { illustData, globalData } = artworkData;
          const { illustId, tags, bookmarkData } = illustData;
          if (!bookmarkData) {
              const { token } = globalData;
              const tagsArr = tags.tags.map((item) => item.tag);
              addBookmark(pdlBtn, illustId, token, tagsArr);
          }
          return parser.getDownloadSource(artworkData, shouldDownloadPage);
      })
          .then((sources) => {
          pageCount = sources.length;
          return downloader.add(sources, { onLoad, onProgress });
      })
          .then(() => {
          pixivHistory.add(illustId);
          pdlBtn.classList.remove('pdl-error');
          pdlBtn.classList.add('pdl-complete');
      })
          .catch((err) => {
          if (err)
              console.log(err);
          pdlBtn.classList.remove('pdl-complete');
          pdlBtn.classList.add('pdl-error');
      })
          .finally(() => {
          pdlBtn.innerHTML = '';
          pdlBtn.style.removeProperty('--pdl-progress');
          pdlBtn.classList.remove('pdl-progress');
      });
  }

  function createPdlBtn(attributes, textContent = '', { addEvent } = { addEvent: true }) {
      const ele = document.createElement('button');
      ele.textContent = textContent;
      if (!attributes)
          return ele;
      const { attrs, classList } = attributes;
      if (classList && classList.length > 0) {
          for (const cla of classList) {
              ele.classList.add(cla);
          }
      }
      if (attrs) {
          for (const key in attrs) {
              ele.setAttribute(key, attrs[key]);
          }
      }
      if (addEvent) {
          ele.addEventListener('click', (evt) => {
              evt.preventDefault();
              evt.stopPropagation();
              const ele = evt.currentTarget;
              if (!ele.classList.contains('pdl-progress')) {
                  handleDownload(ele, ele.getAttribute('pdl-id'));
              }
          });
      }
      return ele;
  }
  function getIllustId(node) {
      const isLinkToArtworksPage = regexp.artworksPage.exec(node.href);
      if (isLinkToArtworksPage) {
          if (node.getAttribute('data-gtm-value') ||
              node.classList.contains('gtm-illust-recommend-node-node') ||
              node.classList.contains('gtm-discover-user-recommend-node') ||
              node.classList.contains('work')) {
              return isLinkToArtworksPage[1];
          }
      }
      else {
          const isActivityThumb = regexp.activityHref.exec(node.href);
          if (isActivityThumb && node.classList.contains('work')) {
              return isActivityThumb[1];
          }
      }
      return '';
  }
  function createThunbnailsBtn(nodes) {
      const isBookmarkPage = regexp.bookmarkPage.test(location.pathname);
      nodes.forEach((e) => {
          if (e.childElementCount !== 0 &&
              !e.querySelector('.pdl-btn-sub')) {
              const illustId = getIllustId(e);
              if (illustId) {
                  const attrs = {
                      attrs: { 'pdl-id': illustId },
                      classList: ['pdl-btn', 'pdl-btn-sub']
                  };
                  if (pixivHistory.has(illustId))
                      attrs.classList.push('pdl-complete');
                  if (isBookmarkPage)
                      attrs.classList.push('pdl-btn-sub-bookmark');
                  e.appendChild(createPdlBtn(attrs));
              }
          }
      });
  }
  function compatPixivPreviewer(nodes) {
      const isPpSearchPage = regexp.ppSearchPage.test(location.pathname);
      if (!isPpSearchPage)
          return;
      nodes.forEach((node) => {
          const pdlEle = node.querySelector('.pdl-btn');
          if (!pdlEle)
              return false;
          pdlEle.remove();
      });
  }

  function createMainBtn(id) {
      if (document.querySelector('.pdl-btn-main'))
          return;
      const handleBar = document.querySelector('main section section');
      if (handleBar) {
          const pdlBtnWrap = handleBar.lastElementChild.cloneNode();
          const attrs = {
              attrs: { 'pdl-id': id },
              classList: ['pdl-btn', 'pdl-btn-main']
          };
          if (pixivHistory.has(id))
              attrs.classList.push('pdl-complete');
          pdlBtnWrap.appendChild(createPdlBtn(attrs));
          handleBar.appendChild(pdlBtnWrap);
      }
  }
  function createMultyWorksBtn(id) {
      const works = document.querySelectorAll("[role='presentation'] > a");
      if (works.length < 2)
          return;
      const containers = Array.from(works).map((node) => node.parentElement.parentElement);
      if (containers[0].querySelector('.pdl-btn'))
          return;
      containers.forEach((node, idx) => {
          const wrapper = document.createElement('div');
          wrapper.classList.add('pdl-wrap-artworks');
          const attrs = {
              attrs: { 'pdl-id': id, 'should-download': String(idx) },
              classList: ['pdl-btn', 'pdl-btn-sub', 'artworks']
          };
          wrapper.appendChild(createPdlBtn(attrs));
          node.appendChild(wrapper);
      });
  }
  const createPresentationBtn = (() => {
      let observer, btn;
      function cb(mutationList) {
          const newImg = mutationList[1]['addedNodes'][0];
          const [pageNum] = regexp.originSrcPageNum.exec(newImg.src) ?? [];
          if (!pageNum)
              throw new Error('[Error]Invalid Image Element.');
          btn?.setAttribute('should-download', String(pageNum));
      }
      return (id) => {
          const containers = document.querySelector("body > [role='presentation'] > div");
          if (!containers) {
              if (observer) {
                  observer.disconnect();
                  observer = null;
                  btn = null;
              }
              return;
          }
          if (containers.querySelector('.pdl-btn'))
              return;
          const img = containers.querySelector('img');
          if (!img)
              return;
          const isOriginImg = regexp.originSrcPageNum.exec(img.src);
          if (!isOriginImg)
              return;
          const [pageNum] = isOriginImg;
          const attrs = {
              attrs: { 'pdl-id': id, 'should-download': pageNum },
              classList: ['pdl-btn', 'pdl-btn-sub', 'presentation']
          };
          btn = createPdlBtn(attrs);
          containers.appendChild(btn);
          if (!img.parentElement)
              return;
          observer = new MutationObserver(cb);
          observer.observe(img.parentElement, { childList: true, subtree: true });
      };
  })();
  function createPreviewModalBtn() {
      const illustModalBtn = document.querySelectorAll('.gtm-manga-viewer-preview-modal-open');
      const mangaModalBtn = document.querySelectorAll('.gtm-manga-viewer-open-preview');
      const mangaViewerModalBtn = document.querySelectorAll('.gtm-manga-viewer-close-icon')?.[1];
      if (!illustModalBtn.length && !mangaModalBtn.length)
          return;
      const btns = [...illustModalBtn, ...mangaModalBtn];
      if (mangaViewerModalBtn)
          btns.push(mangaViewerModalBtn);
      btns.forEach((node) => {
          node.addEventListener('click', handleModalClick);
      });
  }
  function handleModalClick() {
      const timer = setInterval(() => {
          const ulList = document.querySelectorAll('ul');
          const previewList = ulList[ulList.length - 1];
          if (getComputedStyle(previewList).display !== 'grid')
              return;
          clearInterval(timer);
          const [, id] = regexp.artworksPage.exec(location.pathname) ?? [];
          previewList.childNodes.forEach((node, idx) => {
              node.style.position = 'relative';
              const attrs = {
                  attrs: { 'pdl-id': id, 'should-download': String(idx) },
                  classList: ['pdl-btn', 'pdl-btn-sub']
              };
              node.appendChild(createPdlBtn(attrs));
          });
      }, 300);
  }

  function changeDlbarDisplay() {
      document.querySelectorAll('.pdl-dlbar .pdl-btn-all').forEach((ele) => {
          ele.classList.toggle('pdl-hide');
      });
      document.querySelector('.pdl-dlbar .pdl-stop')?.classList.toggle('pdl-hide');
      document.querySelectorAll('.pdl-tag').forEach((ele) => {
          ele.classList.toggle('pdl-tag-hide');
      });
      document.querySelector('.pdl-filter-wrap')?.classList.toggle('unavailable');
  }
  let isDownloading = false;
  const dlBarRef = {
      filter: {
          exclude_downloaded: undefined,
          [IllustType.illusts]: undefined,
          [IllustType.manga]: undefined,
          [IllustType.ugoira]: undefined
      },
      statusBar: undefined,
      abortBtn: undefined
  };
  function getFilterOption() {
      return {
          exclude_downloaded: dlBarRef.filter.exclude_downloaded?.checked ??
              defaultSettings.filter.exclude_downloaded,
          [IllustType.illusts]: dlBarRef.filter[IllustType.illusts]?.checked ??
              defaultSettings.filter[IllustType.illusts],
          [IllustType.manga]: dlBarRef.filter[IllustType.manga]?.checked ??
              defaultSettings.filter[IllustType.manga],
          [IllustType.ugoira]: dlBarRef.filter[IllustType.ugoira]?.checked ??
              defaultSettings.filter[IllustType.ugoira]
      };
  }
  function updateStatus(str) {
      dlBarRef.statusBar && (dlBarRef.statusBar.textContent = str);
  }
  function onProgressCB(progressData) {
      if (typeof progressData === 'string') {
          updateStatus(progressData);
      }
      else {
          debugLog('update progress by', progressData.illustId);
          updateStatus(`Downloading: ${progressData.completed} / ${progressData.avaliable}`);
      }
  }
  async function useDownload(chunksGenerators) {
      if (!dlBarRef.abortBtn)
          return;
      isDownloading = true;
      changeDlbarDisplay();
      let total = 0;
      let failedResult;
      const idsGenerators = [];
      try {
          if (chunksGenerators instanceof Array) {
              await Promise.all(chunksGenerators).then((chunksGenerator) => {
                  chunksGenerator.forEach((val) => {
                      total += val.total;
                      idsGenerators.push(val.generator);
                  });
              });
          }
          else {
              await chunksGenerators.then((val) => {
                  total = val.total;
                  idsGenerators.push(val.generator);
              });
          }
      }
      catch (error) {
          console.error(error);
          updateStatus('Network error, see console.');
          changeDlbarDisplay();
          isDownloading = false;
          return;
      }
      try {
          if (total === 0) {
              throw 'No works.';
          }
          debugLog('[Info]Total:', total);
          const { failed, unavaliable } = await downloadByIds(total, idsGenerators, dlBarRef.abortBtn, onProgressCB);
          if (failed.length || unavaliable.length) {
              updateStatus(`Failed: ${failed.length + unavaliable.length}. See console.`);
              console.log('[Pixiv Downloader]Failed: ', failed.join(', '));
              console.log('[Pixiv Downloader]Unavaliable: ', unavaliable.join(', '));
              if (failed.length)
                  failedResult = failed;
          }
          else {
              updateStatus('Complete');
          }
      }
      catch (error) {
          updateStatus(error);
      }
      changeDlbarDisplay();
      isDownloading = false;
      return failedResult;
  }
  async function downloadByIds(total, idsGenerators, abortBtn, onProgress) {
      let resolve;
      let reject;
      const done = new Promise((r, j) => {
          resolve = r;
          reject = j;
      });
      let wakeFn;
      let completed = 0;
      const failed = [], unavaliable = [], invalid = [];
      let isCanceled = false;
      const tasks = [];
      let tooManyRequests = false;
      abortBtn.onclick = () => {
          isCanceled = true;
          abortBtn.onclick = null;
          reject(`Stopped. ${completed} / ${total - failed.length - unavaliable.length - invalid.length}`);
          wakeFn && wakeFn();
          if (tasks.length) {
              downloader.del(tasks);
              converter.del(tasks);
              compressor.remove(tasks);
              tasks.length = 0;
          }
      };
      const afterEach = (illustId) => {
          const avaliable = total - failed.length - unavaliable.length - invalid.length;
          onProgress({
              illustId,
              avaliable,
              completed
          });
          if (completed === avaliable) {
              resolve({ failed, unavaliable });
          }
      };
      onProgress('Downloading...');
      try {
          for (const idsGenerator of idsGenerators) {
              if (isCanceled)
                  return done;
              for await (const ids of idsGenerator) {
                  debugLog('[Info]ids:', ids);
                  if (isCanceled)
                      return done;
                  if (ids.unavaliable.length) {
                      unavaliable.push(...ids.unavaliable);
                  }
                  if (ids.invalid.length) {
                      invalid.push(...ids.invalid);
                  }
                  if (typeof ids.total === 'number' && !Number.isNaN(ids.total)) {
                      total = ids.total;
                  }
                  if (ids.avaliable.length) {
                      for (const id of ids.avaliable) {
                          if (isCanceled)
                              return done;
                          if (tooManyRequests) {
                              onProgress('Too many requests, wait 30s');
                              const { wake, sleep } = wakeableSleep(30000);
                              wakeFn = wake;
                              await sleep;
                              tooManyRequests = false;
                              if (isCanceled)
                                  return done;
                              onProgress('Downloading...');
                          }
                          parser
                              .getArtworkData(id)
                              .then(parser.getDownloadSource)
                              .then((sources) => {
                              if (isCanceled) {
                                  throw '[Warning]Download stop manually: ' + id;
                              }
                              tasks.push(sources[0].taskId);
                              return downloader.add(sources);
                          })
                              .then((taskId) => {
                              pixivHistory.add(id);
                              if (!isCanceled) {
                                  tasks.splice(tasks.indexOf(taskId), 1);
                                  completed++;
                                  afterEach(id);
                              }
                          }, (reason) => {
                              if (!isCanceled) {
                                  if (reason.message && reason.message === '429')
                                      tooManyRequests = true;
                                  if (reason.message &&
                                      reason.message === '[Error]Fail to parse preload data.') {
                                      unavaliable.push(id);
                                  }
                                  else {
                                      failed.push(id);
                                  }
                                  afterEach(id);
                              }
                          });
                          await sleep(1000);
                      }
                  }
                  else {
                      afterEach();
                  }
              }
          }
      }
      catch (error) {
          console.error(error);
          reject('Network Error, see console');
          abortBtn.click();
      }
      return done;
  }
  function downloadWorks(evt) {
      evt.preventDefault();
      evt.stopPropagation();
      if (isDownloading)
          return;
      const btn = evt.target;
      const userId = btn.getAttribute('pdl-userid');
      const filterOption = getFilterOption();
      const ids = parser.getAllWorksGenerator(userId, filterOption);
      useDownload(ids).then((failed) => {
          if (failed instanceof Array && failed.length) {
              const gen = async function* () {
                  yield {
                      avaliable: failed,
                      unavaliable: [],
                      invalid: []
                  };
              };
              useDownload(Promise.resolve({ total: failed.length, generator: gen() }));
          }
      });
  }
  async function downloadBookmarksOrTags(evt) {
      evt.preventDefault();
      evt.stopPropagation();
      if (isDownloading)
          return;
      const btn = evt.target;
      const userId = btn.getAttribute('pdl-userid');
      const category = btn.getAttribute('category');
      const tag = btn.getAttribute('tag') || '';
      const rest = (btn.getAttribute('rest') || 'show');
      const filterOption = getFilterOption();
      let idsGenerators;
      if (rest === 'all') {
          const idsShowPromise = parser.getChunksGenerator(userId, 'bookmarks', '', 'show', filterOption);
          const idsHidePromise = parser.getChunksGenerator(userId, 'bookmarks', '', 'hide', filterOption);
          idsGenerators = [idsShowPromise, idsHidePromise];
      }
      else {
          idsGenerators = parser.getChunksGenerator(userId, category, tag, rest, filterOption);
      }
      useDownload(idsGenerators).then((failed) => {
          if (failed instanceof Array && failed.length) {
              const gen = async function* () {
                  yield {
                      avaliable: failed,
                      unavaliable: [],
                      invalid: []
                  };
              };
              useDownload(Promise.resolve({ total: failed.length, generator: gen() }));
          }
      });
  }
  function downloadFollowLatest(evt) {
      evt.preventDefault();
      evt.stopPropagation();
      if (isDownloading)
          return;
      const btn = evt.target;
      let idsGenerators;
      const mode = location.pathname.includes('r18') ? 'r18' : 'all';
      const filterOption = getFilterOption();
      if (btn.classList.contains('pdl-dl-all')) {
          idsGenerators = parser.getFollowLatestGenerator(filterOption, mode);
      }
      else {
          const params = new URLSearchParams(location.search);
          const page = Number(params.get('p')) || 1;
          idsGenerators = parser.getFollowLatestGenerator(filterOption, mode, page);
      }
      useDownload(idsGenerators).then((failed) => {
          if (failed instanceof Array && failed.length) {
              const gen = async function* () {
                  yield {
                      avaliable: failed,
                      unavaliable: [],
                      invalid: []
                  };
              };
              useDownload(Promise.resolve({ total: failed.length, generator: gen() }));
          }
      });
  }

  function createFilterEl(id, filterType, text) {
      const checkbox = document.createElement('input');
      const label = document.createElement('label');
      checkbox.id = id;
      checkbox.type = 'checkbox';
      checkbox.classList.add('pdl-checkbox');
      checkbox.setAttribute('category', String(filterType));
      checkbox.checked = settings.filter[filterType];
      label.setAttribute('for', id);
      label.setAttribute('category', String(filterType));
      label.textContent = text;
      checkbox.addEventListener('change', (evt) => {
          const checkbox = evt.currentTarget;
          const category = checkbox.getAttribute('category');
          upgradeSettings('filter', {
              ...settings.filter,
              [category]: checkbox.checked
          });
      });
      dlBarRef.filter[filterType] = checkbox;
      const wrap = document.createElement('div');
      wrap.classList.add('pdl-filter');
      wrap.appendChild(checkbox);
      wrap.appendChild(label);
      return wrap;
  }
  function createFilter() {
      const wrapper = document.createElement('div');
      wrapper.classList.add('pdl-filter-wrap');
      wrapper.appendChild(createFilterEl('pdl-filter-exclude_downloaded', 'exclude_downloaded', i18n('dlbar_filter_exclude_downloaded')));
      wrapper.appendChild(createFilterEl('pdl-filter-illusts', IllustType.illusts, i18n('dlbar_filter_illusts')));
      wrapper.appendChild(createFilterEl('pdl-filter-manga', IllustType.manga, i18n('dlbar_filter_manga')));
      wrapper.appendChild(createFilterEl('pdl-filter-ugoria', IllustType.ugoira, i18n('dlbar_filter_ugoria')));
      return wrapper;
  }
  function createDownloadBar(userId) {
      const nav = document.querySelector('nav[class~="sc-192ftwf-0"]');
      if (!nav)
          return;
      const dlBtn = nav.querySelector('.pdl-btn-all');
      if (dlBtn) {
          if (dlBtn.getAttribute('pdl-userid') === userId)
              return;
          removeDownloadBar();
      }
      const dlBar = document.createElement('div');
      dlBar.classList.add('pdl-dlbar');
      const statusBar = document.createElement('div');
      statusBar.classList.add('pdl-dlbar-status_bar');
      dlBarRef.statusBar = dlBar.appendChild(statusBar);
      const baseClasses = nav.querySelector('a:not([aria-current])').classList;
      dlBarRef.abortBtn = dlBar.appendChild(createPdlBtn({
          attrs: { 'pdl-userId': userId },
          classList: [...baseClasses, 'pdl-stop', 'pdl-hide']
      }, i18n('stop'), { addEvent: false }));
      if (userId !== getSelfId()) {
          const hasWorks = ["a[href$='illustrations']", "a[href$='manga']"].some((selector) => !!nav.querySelector(selector));
          if (hasWorks) {
              const el = createPdlBtn({
                  attrs: { 'pdl-userid': userId },
                  classList: [...baseClasses, 'pdl-btn-all']
              }, i18n('dlbar_category_works'), { addEvent: false });
              el.addEventListener('click', downloadWorks);
              dlBar.appendChild(el);
          }
          if (nav.querySelector("a[href*='bookmarks']")) {
              const el = createPdlBtn({
                  attrs: { 'pdl-userid': userId, category: 'bookmarks' },
                  classList: [...baseClasses, 'pdl-btn-all']
              }, i18n('bookmarks'), { addEvent: false });
              el.addEventListener('click', downloadBookmarksOrTags);
              dlBar.appendChild(el);
          }
      }
      else {
          if (nav.querySelector("a[href*='bookmarks']")) {
              dlBar.appendChild(createPdlBtn({
                  attrs: { 'pdl-userid': userId, category: 'bookmarks', rest: 'all' },
                  classList: [...baseClasses, 'pdl-btn-all']
              }, i18n('bookmarks'), { addEvent: false }));
              dlBar.appendChild(createPdlBtn({
                  attrs: {
                      'pdl-userid': userId,
                      category: 'bookmarks',
                      rest: 'show'
                  },
                  classList: [...baseClasses, 'pdl-btn-all']
              }, i18n('bookmarks_public'), { addEvent: false }));
              dlBar.appendChild(createPdlBtn({
                  attrs: {
                      'pdl-userid': userId,
                      category: 'bookmarks',
                      rest: 'hide'
                  },
                  classList: [...baseClasses, 'pdl-btn-all']
              }, i18n('bookmarks_private'), { addEvent: false }));
              dlBar
                  .querySelectorAll('.pdl-btn-all')
                  .forEach((node) => {
                  node.addEventListener('click', downloadBookmarksOrTags);
              });
          }
      }
      const filter = createFilter();
      nav.parentElement.insertBefore(filter, nav);
      nav.appendChild(dlBar);
  }
  function removeDownloadBar() {
      const dlBarWrap = document.querySelector('.pdl-dlbar');
      if (dlBarWrap) {
          dlBarWrap.remove();
          document.querySelector('.pdl-filter-wrap')?.remove();
      }
  }
  function createTagsBtn(userId, category) {
      const tagsEles = document.querySelectorAll('section> div:nth-child(2) > div > div');
      if (!tagsEles.length)
          return;
      let cate;
      if (category === 'illustrations' || category === 'artworks') {
          cate = 'illusts';
      }
      else {
          cate = category;
      }
      let rest = 'show';
      if (userId === getSelfId() &&
          category === 'bookmarks' &&
          location.search.includes('rest=hide'))
          rest = 'hide';
      tagsEles.forEach((ele) => {
          const tagBtn = ele.querySelector('.pdl-btn');
          if (tagBtn) {
              const btnRest = tagBtn.getAttribute('rest');
              if (rest !== btnRest)
                  tagBtn.setAttribute('rest', rest);
              return;
          }
          let tag;
          const tagLink = ele.querySelector('a');
          if (!tagLink)
              return;
          if (tagLink.getAttribute('status') !== 'active') {
              if (rest === 'hide') {
                  tag = tagLink.href.slice(tagLink.href.lastIndexOf('/') + 1, tagLink.href.lastIndexOf('?'));
              }
              else {
                  tag = tagLink.href.slice(tagLink.href.lastIndexOf('/') + 1);
              }
          }
          else {
              const tagTextEles = ele.querySelectorAll('div[title]');
              if (!tagTextEles.length)
                  return console.log('[Info]No Tags Element found.');
              tag = tagTextEles[tagTextEles.length - 1].getAttribute('title').slice(1);
          }
          const attrs = {
              attrs: { 'pdl-userId': userId, category: cate, tag, rest },
              classList: ['pdl-btn', 'pdl-tag']
          };
          if (isDownloading)
              attrs.classList.push('pdl-tag-hide');
          const dlBtn = createPdlBtn(attrs, '', { addEvent: false });
          if (!(tagLink.href.includes('bookmarks') &&
              tagLink.getAttribute('status') !== 'active')) {
              dlBtn.style.backgroundColor = tagLink.getAttribute('color') + '80';
          }
          dlBtn.addEventListener('click', downloadBookmarksOrTags);
          ele.appendChild(dlBtn);
      });
      let modalTagsEles;
      let modal;
      if (category === 'bookmarks') {
          modal = document.querySelector('div[role="presentation"]');
          if (!modal)
              return;
          modalTagsEles = modal.querySelectorAll('a');
      }
      else {
          const charcoalTokens = document.querySelectorAll('.charcoal-token');
          modal = charcoalTokens[charcoalTokens.length - 1];
          if (!modal)
              return;
          modalTagsEles = modal.querySelectorAll('a');
      }
      if (!regexp.userPageTags.exec(modalTagsEles[0]?.href))
          return;
      modalTagsEles.forEach((ele) => {
          if (ele.querySelector('.pdl-btn'))
              return;
          let tag;
          if (rest === 'hide') {
              tag = ele.href.slice(ele.href.lastIndexOf('/') + 1, ele.href.lastIndexOf('?'));
          }
          else {
              tag = ele.href.slice(ele.href.lastIndexOf('/') + 1);
          }
          const attrs = {
              attrs: { 'pdl-userId': userId, category: cate, tag, rest },
              classList: ['pdl-btn', 'pdl-modal-tag']
          };
          if (isDownloading)
              attrs.classList.push('pdl-tag-hide');
          const dlBtn = createPdlBtn(attrs, '', { addEvent: false });
          dlBtn.addEventListener('click', (evt) => {
              modal.querySelector('svg').parentElement.click();
              downloadBookmarksOrTags(evt);
          });
          ele.appendChild(dlBtn);
      });
  }

  function createFollowLatestDownloadBar() {
      const prevDlBtn = document.querySelector('.pdl-btn-all');
      if (prevDlBtn) {
          const prevDlAllBtn = document.querySelector('.pdl-dl-all');
          if (location.pathname.includes('r18')) {
              prevDlBtn.textContent !==
                  i18n('dlbar.follow_latest.category_r18.single') &&
                  (prevDlBtn.textContent = i18n('dlbar.follow_latest.category_r18.single'));
              prevDlAllBtn.textContent !==
                  i18n('dlbar.follow_latest.category_r18.all') &&
                  (prevDlAllBtn.textContent = i18n('dlbar.follow_latest.category_r18.all'));
          }
          else {
              prevDlBtn.textContent !==
                  i18n('dlbar.follow_latest.category_all.single') &&
                  (prevDlBtn.textContent = i18n('dlbar.follow_latest.category_all.single'));
              prevDlAllBtn.textContent !==
                  i18n('dlbar.follow_latest.category_all.all') &&
                  (prevDlAllBtn.textContent = i18n('dlbar.follow_latest.category_all.all'));
          }
          return;
      }
      const nav = document.querySelector('nav');
      if (!nav || nav.parentElement.childElementCount === 1)
          return;
      const navBar = nav.parentElement;
      const modeSwitch = nav.nextElementSibling;
      const filter = createFilter();
      navBar.parentElement.insertBefore(filter, navBar);
      const dlBar = document.createElement('div');
      dlBar.classList.add('pdl-dlbar');
      dlBar.classList.add('pdl-dlbar-follow_latest');
      const statusBar = document.createElement('div');
      statusBar.classList.add('pdl-dlbar-status_bar');
      dlBarRef.statusBar = dlBar.appendChild(statusBar);
      const baseClasses = nav.querySelector('a:not([aria-current])').classList;
      dlBarRef.abortBtn = dlBar.appendChild(createPdlBtn({
          attrs: { 'pdl-userid': '' },
          classList: [...baseClasses, 'pdl-stop', 'pdl-hide']
      }, i18n('stop'), { addEvent: false }));
      const dlBtn = createPdlBtn({
          attrs: { 'pdl-userid': '' },
          classList: [...baseClasses, 'pdl-btn-all']
      },
      i18n('dlbar_category_works'), { addEvent: false });
      dlBtn.addEventListener('click', downloadFollowLatest);
      dlBar.appendChild(dlBtn);
      const dlAllBtn = createPdlBtn({
          attrs: { 'pdl-userid': '' },
          classList: [...baseClasses, 'pdl-btn-all', 'pdl-dl-all']
      },
      i18n('dlbar_category_works'), { addEvent: false });
      dlAllBtn.addEventListener('click', downloadFollowLatest);
      dlBar.appendChild(dlAllBtn);
      navBar.insertBefore(dlBar, modeSwitch);
  }

  let firstRun = true;
  function observerCallback(records) {
      const addedNodes = [];
      records.forEach((record) => {
          if (!record.addedNodes.length)
              return;
          record.addedNodes.forEach((node) => {
              if (node.nodeType === Node.ELEMENT_NODE &&
                  node.tagName !== 'BUTTON' &&
                  node.tagName !== 'IMG') {
                  addedNodes.push(node);
              }
          });
      });
      if (!addedNodes.length) {
          return;
      }
      if (firstRun) {
          createThunbnailsBtn(document.querySelectorAll('a'));
          firstRun = false;
      }
      else {
          compatPixivPreviewer(addedNodes);
          const thunmnails = addedNodes.reduce((prev, current) => {
              return prev.concat(Array.from(current.querySelectorAll('a')));
          }, []);
          createThunbnailsBtn(thunmnails);
      }
      const isArtworksPage = regexp.artworksPage.exec(location.pathname);
      const isUserPage = regexp.userPage.exec(location.pathname);
      const isTagsPage = regexp.userPageTags.exec(location.pathname);
      if (isArtworksPage) {
          const id = isArtworksPage[1];
          createMainBtn(id);
          createMultyWorksBtn(id);
          createPresentationBtn(id);
          createPreviewModalBtn();
      }
      else if (isUserPage) {
          createDownloadBar(isUserPage[1]);
          if (isTagsPage) {
              createTagsBtn(isUserPage[1], isTagsPage[1]);
          }
      }
      else if (regexp.followLatest.test(location.pathname)) {
          createFollowLatestDownloadBar();
      }
      else {
          removeDownloadBar();
      }
  }

  function createModal({ header = '', content, footer = '' }, option) {
      const modal = document.createElement('div');
      const dialog = document.createElement('div');
      modal.classList.add('pdl-modal');
      dialog.classList.add('pdl-dialog');
      if (option.closeOnClickModal) {
          dialog.onclick = (e) => {
              e.stopPropagation();
          };
          modal.onclick = () => {
              modal.remove();
          };
      }
      dialog.innerHTML = `  <header class="pdl-dialog-header">${header}</header>
  <div class="pdl-dialog-content">${content}</div>
  <footer class="pdl-dialog-footer">${footer}</footer>`;
      const closeBtn = document.createElement('button');
      closeBtn.classList.add('pdl-dialog-close');
      closeBtn.onclick = () => {
          modal.remove();
      };
      dialog.insertBefore(closeBtn, dialog.firstChild);
      modal.appendChild(dialog);
      return modal;
  }

  function showUpgradeMsg() {
      document.body.appendChild(createModal({
          header: modalHtml.upgradeMsgTitle,
          content: modalHtml.upgradeMsgContent,
          footer: modalHtml.modalCreditFooter + modalHtml.modalFeedback
      }, { closeOnClickModal: false }));
  }

  function createTabsPart({ tabName, paneHtml }) {
      const tab = document.createElement('div');
      tab.classList.add('pdl-tab-item');
      tab.textContent = tabName;
      const pane = document.createElement('div');
      pane.classList.add('pdl-tab-pane');
      pane.innerHTML = paneHtml;
      return {
          tab,
          pane
      };
  }
  function createTabFilename({ tabName, paneHtml }) {
      const { tab, pane } = createTabsPart({ tabName, paneHtml });
      const folder = pane.querySelector('#pdlfolder');
      const folderReset = pane.querySelector('#pdl-filename-folder-reset');
      const folderUpdate = pane.querySelector('#pdl-filename-folder-confirm');
      const filename = pane.querySelector('#pdlfilename');
      const filenameReset = pane.querySelector('#pdl-filename-filename-reset');
      const filenameUpdate = pane.querySelector('#pdl-filename-filename-confirm');
      if (!folder || !filename)
          throw new Error('[Error]Can not create modal.');
      filename.value = settings.filenamePattern;
      if (!env.isSupportSubpath) {
          folder.setAttribute('disabled', '');
          folder.value = '';
      }
      else {
          folder.value = settings.folderPattern;
      }
      folder.placeholder = env.isViolentmonkey
          ? i18n('folder_vm_tips')
          : !env.isSupportSubpath
              ? i18n('folder_api_tips')
              : i18n('folder_tips');
      folder.addEventListener('input', () => {
          folderReset?.removeAttribute('disabled');
          folderUpdate?.removeAttribute('disabled');
      });
      folderReset?.addEventListener('click', () => {
          folder.value = settings.folderPattern;
          folderReset?.setAttribute('disabled', '');
          folderUpdate?.setAttribute('disabled', '');
      });
      folderUpdate?.addEventListener('click', () => {
          const folderPattern = folder.value
              .split('/')
              .map((path) => path
              .trim()
              .replace(/^\.+|\.+$|[\u200b-\u200f\uFEFF\u202a-\u202e\\:*?"|<>]/g, ''))
              .filter((path) => !!path)
              .join('/') ?? '';
          upgradeSettings('folderPattern', folderPattern);
          folder.value = folderPattern;
          folderReset?.setAttribute('disabled', '');
          folderUpdate?.setAttribute('disabled', '');
      });
      filename.addEventListener('input', () => {
          filenameReset?.removeAttribute('disabled');
          filenameUpdate?.removeAttribute('disabled');
      });
      filenameReset?.addEventListener('click', () => {
          filename.value = settings.filenamePattern;
          filenameReset?.setAttribute('disabled', '');
          filenameUpdate?.setAttribute('disabled', '');
      });
      filenameUpdate?.addEventListener('click', () => {
          const filenamePattern = filename.value
              .trim()
              .replace(/^\.+|[\u200b-\u200f\uFEFF\u202a-\u202e\\/:*?"|<>]/g, '') ??
              '';
          if (filenamePattern === '')
              return filenameReset?.click();
          upgradeSettings('filenamePattern', filenamePattern);
          filename.value = filenamePattern;
          filenameReset?.setAttribute('disabled', '');
          filenameUpdate?.setAttribute('disabled', '');
      });
      pane
          .querySelectorAll('.tags-content .tags-item input')
          .forEach((input) => {
          if (settings.tagLang === input.value)
              input.checked = true;
          input.addEventListener('change', (ev) => {
              upgradeSettings('tagLang', ev.currentTarget.value);
          });
      });
      return {
          tab,
          pane
      };
  }
  function createTabUgoria({ tabName, paneHtml }) {
      const { tab, pane } = createTabsPart({ tabName, paneHtml });
      pane
          .querySelectorAll('.pdl-ugoria-format-item input[type="radio"]')
          .forEach((el) => {
          if (settings.ugoriaFormat === el.value)
              el.checked = true;
          el.addEventListener('change', (ev) => {
              upgradeSettings('ugoriaFormat', ev.currentTarget.value);
          });
      });
      return {
          tab,
          pane
      };
  }
  function createTabHistory({ tabName, paneHtml }) {
      const { tab, pane } = createTabsPart({ tabName, paneHtml });
      const file = pane.querySelector('#pdl-import');
      file?.addEventListener('change', (evt) => {
          const file = evt.currentTarget.files?.[0];
          if (!file)
              return;
          if (file.type === 'text/plain') {
              const reader = new FileReader();
              reader.readAsText(file);
              reader.onload = (readEvt) => {
                  const text = readEvt.target?.result;
                  try {
                      if (typeof text !== 'string')
                          throw new Error('Invalid file');
                      const history = JSON.parse(text);
                      if (!(history instanceof Array))
                          throw new Error('Invalid file');
                      if (history.length &&
                          !history.every((id) => typeof id === 'string')) {
                          throw new Error('Invalid id type');
                      }
                      pixivHistory.saveHistory(history);
                      location.reload();
                  }
                  catch (error) {
                      alert(error.message);
                  }
              };
          }
          else {
              alert('Invalid file');
          }
      });
      const importBtn = pane.querySelector('#pdl-import-btn');
      importBtn?.addEventListener('click', () => file?.click());
      const exportBtn = pane.querySelector('#pdl-export');
      exportBtn?.addEventListener('click', () => {
          const dlEle = document.createElement('a');
          const history = JSON.stringify(pixivHistory.getAll());
          dlEle.href = URL.createObjectURL(new Blob([history], { type: 'text/plain' }));
          dlEle.download = 'Pixiv Downloader ' + new Date().toLocaleString() + '.txt';
          dlEle.click();
          URL.revokeObjectURL(dlEle.href);
      });
      const clearBtn = pane.querySelector('#pdl-clear-history');
      clearBtn?.addEventListener('click', () => pixivHistory.clearHistory());
      return {
          tab,
          pane
      };
  }
  function createTabOthers({ tabName, paneHtml }) {
      const { tab, pane } = createTabsPart({ tabName, paneHtml });
      [
          { selector: '#pdl-options-bundle-illusts', settingKey: 'bundleIllusts' },
          { selector: '#pdl-options-bundle-manga', settingKey: 'bundleManga' },
          { selector: '#pdl-options-add-bookmark', settingKey: 'addBookmark' },
          {
              selector: '#pdl-options-add-bookmark-tags',
              settingKey: 'addBookmarkWithTags'
          },
          {
              selector: '#pdl-options-add-bookmark-private-r18',
              settingKey: 'privateR18'
          }
      ].forEach(({ selector, settingKey }) => {
          const optionEl = pane.querySelector(selector);
          optionEl && (optionEl.checked = settings[settingKey]);
          optionEl?.addEventListener('change', (ev) => {
              upgradeSettings(settingKey, ev.currentTarget.checked);
          });
      });
      return {
          tab,
          pane
      };
  }
  function showSettings() {
      if (document.querySelector('.pdl-modal'))
          return;
      const modal = createModal({
          content: modalHtml.modalSettingsContent
      }, { closeOnClickModal: false });
      const tabsNav = modal.querySelector('.pdl-tabs-nav');
      const tabContent = modal.querySelector('.pdl-tabs-content');
      [
          createTabFilename({
              tabName: i18n('tabs_nav_filename'),
              paneHtml: modalHtml.modalSettingFilename
          }),
          createTabUgoria({
              tabName: i18n('tabs_nav_ugoria'),
              paneHtml: modalHtml.modalSettingUgoria
          }),
          createTabHistory({
              tabName: i18n('tabs_nav_history'),
              paneHtml: modalHtml.modalSettingHistory
          }),
          createTabOthers({
              tabName: i18n('tabs_nav_others'),
              paneHtml: modalHtml.modalSettingOthers
          }),
          createTabsPart({
              tabName: i18n('tabs_nav_donate'),
              paneHtml: modalHtml.modalSettingDonate
          })
      ].forEach(({ tab, pane }) => {
          tabsNav.appendChild(tab);
          tabContent.appendChild(pane);
      });
      const panes = Array.from(tabContent.querySelectorAll('.pdl-tab-pane'));
      panes.forEach((el) => {
          el.style.setProperty('display', 'none');
      });
      const activeBar = tabsNav.querySelector('.pdl-tabs__active-bar');
      const tabs = Array.from(modal.querySelectorAll('.pdl-tabs-nav .pdl-tab-item'));
      tabs.forEach((el) => {
          el.addEventListener('click', (ev) => {
              const tab = ev.currentTarget;
              if (!tab)
                  return;
              tabs.forEach((tab) => tab.classList.remove('active'));
              tab.classList.add('active');
              activeBar.style.width = getComputedStyle(tab).width;
              activeBar.style.transform = `translateX(${tab.offsetLeft + parseFloat(getComputedStyle(tab).paddingLeft)}px)`;
              panes.forEach((pane) => pane.style.setProperty('display', 'none'));
              panes[tabs.indexOf(tab)].style.removeProperty('display');
          });
      });
      tabs[0].classList.add('active');
      panes[0].style.removeProperty('display');
      document.body.appendChild(modal);
      activeBar.style.width = getComputedStyle(tabs[0]).width;
      activeBar.style.transform = `translateX(${tabs[0].offsetLeft + parseFloat(getComputedStyle(tabs[0]).paddingLeft)}px)`;
  }

  pixivHistory.updateHistory();
  GM_registerMenuCommand(i18n('gm_menu_setting'), showSettings, 's');
  initial()
      .then(() => {
      if (settings.showMsg) {
          showUpgradeMsg();
          upgradeSettings('showMsg', false);
      }
      new MutationObserver(observerCallback).observe(document.body, {
          childList: true,
          subtree: true
      });
      document.addEventListener('keydown', (e) => {
          if (e.ctrlKey && e.key === 'q') {
              const pdlMainBtn = document.querySelector('.pdl-btn-main');
              if (pdlMainBtn) {
                  e.preventDefault();
                  if (!e.repeat) {
                      pdlMainBtn.dispatchEvent(new MouseEvent('click'));
                  }
              }
          }
      });
  })
      .catch(console.error);

})(workerChunk, JSZip, GIF);