Fantia downloader

Download your Fantia rewards more easily!

  1. /* jshint esversion: 9 */
  2. // ==UserScript==
  3. // @name Fantia downloader
  4. // @name:en Fantia downloader
  5. // @name:ja Fantia downloader
  6. // @namespace http://tampermonkey.net/
  7. // @version 3.1.9
  8. // @description Download your Fantia rewards more easily!
  9. // @description:en Download your Fantia rewards more easily!
  10. // @description:ja Download your Fantia rewards more easily!
  11. // @author suzumiyahifumi
  12. // @include https://fantia.jp/posts/*
  13. // @include https://fantia.jp/fanclubs/*/backnumbers*
  14. // @icon https://www.google.com/s2/favicons?domain=fantia.jp
  15. // @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.2.0/jszip.min.js
  16. // @grant none
  17. // ==/UserScript==
  18.  
  19. //log: 3.1.5 remove jQuery inject
  20. (function () {
  21. 'use strict';
  22.  
  23. Date.prototype.Format = function (fmt) {
  24. let o = {
  25. "M+": this.getMonth() + 1,
  26. "d+": this.getDate(),
  27. "h+": this.getHours(),
  28. "m+": this.getMinutes(),
  29. "s+": this.getSeconds(),
  30. "q+": Math.floor((this.getMonth() + 3) / 3),
  31. "S": this.getMilliseconds()
  32. };
  33. if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
  34. for (let k in o)
  35. if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
  36. return fmt;
  37. };
  38.  
  39. $('head').append(`<style type="text/css">
  40. .fa-download2::before{
  41. content: "\\f021"
  42. }
  43. .hdr{ pointer-events: none; }
  44. .titleImage{
  45. background-image: url("data:image/png;base64,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");
  46. background-repeat: no-repeat;
  47. background-position: center;
  48. background-size: 200px;
  49. }
  50. #settingCenter{
  51. position: fixed;
  52. z-index: 9999;
  53. width: 50px;
  54. height: 50px;
  55. left: 50px;
  56. top: calc(100vh - 100px);
  57. border-style: solid;
  58. border-color: #c3c3c345;
  59. border-width: thin;
  60. border-radius: 50px;
  61. color: #c3c3c345;
  62. padding: 10px 20px;
  63. cursor: pointer;
  64. transition: border-color 0.8s;
  65. transition: box-shadow 0.5s;
  66. box-shadow: 0 0 10px #000;
  67. font-size: 3em;
  68. backdrop-filter: blur(5px);
  69. background-image: url("data:image/svg+xml;charset=UTF-8,<svg enable-background='new 0 0 24 24' height='512' viewBox='0 0 24 24' width='512' xmlns='http://www.w3.org/2000/svg'><path d='m22.683 9.394-1.88-.239c-.155-.477-.346-.937-.569-1.374l1.161-1.495c.47-.605.415-1.459-.122-1.979l-1.575-1.575c-.525-.542-1.379-.596-1.985-.127l-1.493 1.161c-.437-.223-.897-.414-1.375-.569l-.239-1.877c-.09-.753-.729-1.32-1.486-1.32h-2.24c-.757 0-1.396.567-1.486 1.317l-.239 1.88c-.478.155-.938.345-1.375.569l-1.494-1.161c-.604-.469-1.458-.415-1.979.122l-1.575 1.574c-.542.526-.597 1.38-.127 1.986l1.161 1.494c-.224.437-.414.897-.569 1.374l-1.877.239c-.753.09-1.32.729-1.32 1.486v2.24c0 .757.567 1.396 1.317 1.486l1.88.239c.155.477.346.937.569 1.374l-1.161 1.495c-.47.605-.415 1.459.122 1.979l1.575 1.575c.526.541 1.379.595 1.985.126l1.494-1.161c.437.224.897.415 1.374.569l.239 1.876c.09.755.729 1.322 1.486 1.322h2.24c.757 0 1.396-.567 1.486-1.317l.239-1.88c.477-.155.937-.346 1.374-.569l1.495 1.161c.605.47 1.459.415 1.979-.122l1.575-1.575c.542-.526.597-1.379.127-1.985l-1.161-1.494c.224-.437.415-.897.569-1.374l1.876-.239c.753-.09 1.32-.729 1.32-1.486v-2.24c.001-.757-.566-1.396-1.316-1.486zm-10.683 7.606c-2.757 0-5-2.243-5-5s2.243-5 5-5 5 2.243 5 5-2.243 5-5 5z'/></svg>");
  70. background-size: 30px;
  71. background-repeat: no-repeat;
  72. background-position: center;
  73. }
  74. #settingCenter:hover{
  75. border-color: #c3c3c370;
  76. color: #c3c3c370;
  77. box-shadow: 0px 0px 20px #000;
  78. }
  79. #settingCenter:active{
  80. border-color: #fe7070;
  81. color: #fe7070;
  82. }
  83.  
  84. #settingCenter:after {
  85. content: '';
  86. display: block;
  87. position: absolute;
  88. width: 50px;
  89. height: 50px;
  90. top: 0;
  91. left: 0;
  92. border-radius: 50px;
  93. pointer-events: none;
  94. background-image: radial-gradient(circle, #fe7070 10%, transparent 10.01%);
  95. background-repeat: no-repeat;
  96. background-position: 50%;
  97. transform: scale(10, 10);
  98. opacity: 0;
  99. transition: transform .5s, opacity .5s;
  100. }
  101.  
  102. #settingCenter:active:after {
  103. transform: scale(0, 0);
  104. opacity: .3;
  105. transition: 0s;
  106. }
  107.  
  108. .close {
  109. display: none;
  110. }
  111.  
  112. .unBlur {
  113. background-color: #adadaded !important;
  114. backdrop-filter: blur(0px) !important;
  115. }
  116.  
  117. #settingCenterDiv{
  118. position: fixed;
  119. z-index: 9999;
  120. width: 500px;
  121. height: 90vh;
  122. left: calc(50vw - 250px);
  123. top: 5vh;
  124. background-color: #9090907d;
  125. border-radius: 15px;
  126. backdrop-filter: blur(15px);
  127. box-shadow: 0 0 10px #000;
  128. text-align: center;
  129. margin: 0 auto;
  130. overflow: auto;
  131. min-height: 450px;
  132. }
  133.  
  134. .settingCenterButton:hover {
  135. border-bottom-style: groove;
  136. border-bottom-color: #fff;
  137. }
  138. .settingCenterButton:active {
  139. border-bottom-style: none;
  140. border-bottom-color: #fff0;
  141. }
  142.  
  143. #cookieOn:checked ~ #cookieOnLabel {
  144. background-color: #fff;
  145. }
  146. #cookieOff:checked ~ #cookieOffLabel {
  147. background-color: #fff;
  148. }
  149. #generalSave:checked ~ #generalSaveLabel {
  150. background-color: #fff;
  151. }
  152. #authorSave:checked ~ #authorSaveLabel {
  153. background-color: #fff;
  154. }
  155.  
  156. #paramsTable table {
  157. width: 100%;
  158. height: 100%;
  159. }
  160. #paramsTable th{
  161. text-align: center;
  162. }
  163. #paramsTable table, #paramsTable td {
  164. border: 1px solid #fff0;
  165. }
  166.  
  167. #paramsTable thead, #paramsTable tfoot {
  168. background-color: #fff0;
  169. color: #fff;
  170. }
  171.  
  172. </style>`);
  173.  
  174. $('nav.scroll-tabs>div').append(`<a id="set" class="tab-item tab-item-text set-FD" style="cursor: pointer;" onclick="JAVASCRIPT:getDownLoadButton()">擷取下載</a>`);
  175.  
  176. let init = setInterval(() => {
  177. let pageType = (window.location.href.match(/https:\/\/fantia\.jp\/posts\/*/g) != null) ? `post` : `backnumber`;
  178. let post = (pageType == "backnumber") ? 1 : $(`.the-post`).length;
  179. if (window.setting) {
  180. var postContent = (window.setting.metaData.content == undefined || window.setting.metaData.content.length == 0) ? true : false;
  181. } else {
  182. window.setting = new Setting();
  183. }
  184. if (($(`div[id^='post-content-id-']`).length != 0 || postContent) && post != 0) {
  185.  
  186. // for nonImgbox
  187. $(`div.image-thumbnails`).each((i, div) => {
  188. let b = $(div).closest('div.content-block').find(`div.text-center > div.btn-group-tabs`);
  189. if (b.length == 0) $(div).before(`<div ng-if="$ctrl.isVisibleAndMulti()" class="ng-scope"><div class="text-center"><div class="btn-group btn-group-tabs mb-20" role="group"></div></div></div>`);
  190. });
  191.  
  192. // for single image
  193. $(`a.fantiaImage`).each((i, div) => {
  194. $(div).before(`<div ng-if="$ctrl.isVisibleAndMulti()" class="ng-scope blogBox" blog-img-index="${$(div).attr("data-id")}"><div class="text-center"><div class="btn-group btn-group-tabs mb-20" role="group"></div></div></div>`);
  195. });
  196. // for post
  197. $(`.the-post .post-thumbnail .img-default`).closest(`div.post-thumbnail`).before(`<div ng-if="$ctrl.isVisibleAndMulti()" class="ng-scope"><div class="text-center"><div class="btn-group btn-group-tabs mb-20" role="group"></div></div></div>`);
  198. // make sure the button has been inserted before stopping interval.
  199. if ($(`div[role="group"]`).length) {
  200. window.getDownLoadButton();
  201. clearInterval(init);
  202. }
  203. }
  204. }, 500);
  205.  
  206. class Setting {
  207. constructor() {
  208.  
  209. this.pageType = (window.location.href.match(/https:\/\/fantia\.jp\/posts\/*/g) != null) ? `post` : `backnumber`;
  210. let qs = new URLSearchParams((this.pageType == `post`) ? `` : (window.location.search == ``) ? $(`div.text-center>a.active`).attr("href").split("?")[1] : window.location.search);
  211. this.jsonUrl = `https://fantia.jp/api/v1/${(this.pageType == `post`) ? `posts/${window.location.href.split("/").pop()}` : `fanclub/backnumbers/monthly_contents/plan/${qs.get("plan")}/month/${qs.get("month")}`}`;
  212.  
  213. let authorId = $("h1.fanclub-name>a").attr(`href`).split("/").pop();
  214.  
  215. const keyArr = [`cookieSave`, `lang`, `authorId_${authorId}`, `generalSaveZIP`, `generalSaveFile`, `authorSaveZIP_${authorId}`, `authorSaveFile_${authorId}`, `dateFormat`];
  216. this.cookieOri = document.cookie;
  217. this.cookie = this.cookieParser(keyArr);
  218. this.cookieSave = this.cookie.cookieSave || this.defaultCookie(`cookieSave`);
  219.  
  220. this.setCookie({
  221. cookieSave: this.cookieSave,
  222. lang: (this.cookieSave == `On`) ? this.cookie.lang : this.getOriLang(),
  223. generalSave: this.defaultCookie(`generalSave`),
  224. authorSave: this.defaultCookie(`authorSave`),
  225. authorSaveCheck: this.cookie[`authorId_${authorId}`] || this.defaultCookie(`authorSaveCheck`),
  226. authorId: authorId,
  227. dateFormat: (this.cookieSave == `On`) ? this.cookie.dateFormat : this.defaultCookie(`dateFormat`)
  228. });
  229. if (this.cookieSave == `On`) {
  230. let g = this.cookieParser([`generalSaveZIP`, `generalSaveFile`]);
  231. this.setCookie({
  232. generalSave: {
  233. zipName: g.generalSaveZIP,
  234. fileName: g.generalSaveFile
  235. }
  236. });
  237. if (this.cookie[`authorId_${authorId}`] || this.cookie[`authorId_${authorId}`] == `On`) {
  238. let a = this.cookieParser([`authorSaveZIP_${authorId}`, `authorSaveFile_${authorId}`]);
  239. this[`authorId_${authorId}`] = `On`;
  240. this.setCookie({
  241. authorSaveCheck: `On`,
  242. authorSave: {
  243. zipName: a[`authorSaveZIP_${authorId}`],
  244. fileName: a[`authorSaveFile_${authorId}`]
  245. }
  246. });
  247. }
  248. }
  249. this.saveCookie(false);
  250.  
  251. this.metaJson = {};
  252. this.metaData = {};
  253.  
  254. if (window.csrfToken) {
  255. $.ajaxSetup({
  256. headers: {
  257. "x-csrf-token": window.csrfToken
  258. }
  259. });
  260. }
  261. let self = this;
  262. $.get(this.jsonUrl, (json) => {
  263. self.metaJson = json;
  264. let data = json[self.pageType];
  265. self.metaData = {
  266. user: data.fanclub.creator_name,
  267. uid: data.fanclub.id,
  268. content: data[`${self.pageType}_contents`]
  269. };
  270. });
  271. return this;
  272. }
  273.  
  274. saveCookie(check) {
  275. if (this.cookie.cookieSave == 'On') {
  276. let date = new Date();
  277. date.setDate(date.getDate() + 75);
  278. let cookie = {
  279. cookieSave: this.cookie.cookieSave,
  280. lang: this.cookie.lang,
  281. dateFormat: this.cookie.dateFormat,
  282. Expires: date.toUTCString()
  283. };
  284. cookie.generalSaveZIP = this.cookie.generalSave.zipName;
  285. cookie.generalSaveFile = this.cookie.generalSave.fileName;
  286. if (this[`authorId_${this.authorId}`] == 'On') {
  287. cookie[`authorId_${this.authorId}`] = 'On';
  288. cookie[`authorSaveZIP_${this.authorId}`] = this.cookie.authorSave.zipName;
  289. cookie[`authorSaveFile_${this.authorId}`] = this.cookie.authorSave.fileName;
  290. }
  291. this.updateCookie(cookie);
  292. } else {
  293. let date = new Date();
  294. date.setDate(date.getTime() - 1);
  295. let cookie = {
  296. cookieSave: 'Off',
  297. Expires: date.toUTCString()
  298. };
  299. cookie[`authorId_${this.authorId}`] = 'Off';
  300. this.updateCookie(cookie);
  301. }
  302. return (check != false) ? alert(this.getDefault(`saveMessage`, this.lang)) : true;
  303. }
  304.  
  305. updateCookie(cookie = undefined) {
  306. let Expires = cookie.Expires;
  307. delete cookie.Expires;
  308. for (let [key, value] of Object.entries(cookie)) {
  309. document.cookie = `${key}=${value}; Expires=${Expires}; Path=/`;
  310. }
  311. this.cookieOri = document.cookie;
  312. return this.cookieOri;
  313. }
  314.  
  315. cookieParser(keyArr) {
  316. return (typeof keyArr == `string`) ? document.cookie.split('; ').map(row => row.split('=')).filter(row => keyArr == row[0])[1] || undefined : Object.fromEntries(document.cookie.split('; ').map(row => row.split('=')).filter(row => keyArr.includes(row[0])));
  317. }
  318.  
  319. setCookie(settingObj) {
  320. for (let [key, value] of Object.entries(settingObj)) {
  321. this.cookie[key] = value;
  322. this[key] = value;
  323. }
  324. return this.cookie;
  325. }
  326.  
  327. setLang(Lang) {
  328. let lang = Lang || this.getOriLang().toLowerCase();
  329. if (/^ja\b/.test(lang)) this.lang = `ja`;
  330. if (/^zh\b/.test(lang)) this.lang = `zh`;
  331. return this.lang;
  332. }
  333.  
  334. getOriLang() {
  335. let res = `en`;
  336. let lang = (navigator.language || navigator.browserLanguage).toLowerCase();
  337. if (/^ja\b/.test(lang)) res = `ja`;
  338. if (/^zh\b/.test(lang)) res = `zh`;
  339. return res;
  340. }
  341.  
  342. defaultCookie(key) {
  343. let defaultSetting = {
  344. cookieSave: "Off",
  345. lang: this.getOriLang(),
  346. generalSave: {
  347. zipName: `{postTitle}_{boxTitle}`,
  348. fileName: `{imgIndex:0}`
  349. },
  350. authorSave: {
  351. zipName: `[{user}]{postTitle}_{boxTitle}`,
  352. fileName: `{boxTitle}_{imgIndex:0}`
  353. },
  354. authorSaveCheck: `Off`,
  355. dateFormat: `yyyyMMdd`
  356. };
  357. return (key) ? defaultSetting[key] : defaultSetting;
  358. }
  359.  
  360. getDefault(key, lang = undefined) {
  361. let defaultSetting = {
  362. en: {
  363. downloadImg: `Download Images`,
  364. downloadImgZip: `Download ZIP`,
  365. retrieving: `Retrieving Link`,
  366. zipping: `Zipping`,
  367. processing: `Processing`,
  368. done: `Done`,
  369. // 按紐
  370. settingCenter: `Setting`,
  371. cookieButton: `Cookie`,
  372. languageButton: `言語設定/Language/界面語言`,
  373. generalSave: `Global Save`,
  374. authorSave: `Author Save`,
  375. zipName: `ZIP file name`,
  376. fileName: `image file name`,
  377. dateFormat: `Date Format`,
  378. saveSetting: `Apply Setting`,
  379. closeSetting: `Close`,
  380. tableParams: `Parameter`,
  381. tableMean: `Mean`,
  382. saveMessage: `Setting has save!`,
  383. // 參數
  384. user: `Creator Name`,
  385. uid: `Creator ID`,
  386. postTitle: `Post Title`,
  387. postId: `Post ID`,
  388. boxTitle: `Image Box Title`,
  389. "imgIndex:0": `Index for image, Number is first index number.`,
  390. plan: `Name of Plan`,
  391. fee: `fee of Plan`,
  392. postDate: `Post Date`,
  393. taskDate: `Download Date`,
  394. ext: `Filename Extension`
  395. },
  396. ja: {
  397. downloadImg: `ダウンロード`,
  398. downloadImgZip: `ZIPダウンロード`,
  399. retrieving: `取得中`,
  400. zipping: `zip圧縮`,
  401. processing: `圧縮`,
  402. done: `ダウンロード完了`,
  403. // 按紐
  404. settingCenter: `設定`,
  405. cookieButton: `Cookie`,
  406. languageButton: `Language/言語設定/界面語言`,
  407. generalSave: `保存の設定`,
  408. authorSave: `クリエイターに保存`,
  409. zipName: `ZIPフォルダ`,
  410. fileName: `ファイル`,
  411. dateFormat: `日時の設定`,
  412. saveSetting: `設定を保存する`,
  413. closeSetting: `閉じる`,
  414. tableParams: `パラメータ`,
  415. tableMean: `効果`,
  416. saveMessage: `設定を保存しました!`,
  417. // 參數
  418. user: `クリエイターの名前`,
  419. uid: `クリエイターのID`,
  420. postTitle: `投稿のタイトル`,
  421. postId: `投稿のID`,
  422. boxTitle: `イラストボックスのタイトル`,
  423. "imgIndex:0": `画像のインデックス、番号は最初のインデックス番号です`,
  424. plan: `プラン名`,
  425. fee: `プランの月額料金`,
  426. postDate: `公開日時`,
  427. taskDate: `ダウンロード日時`,
  428. ext: `拡張子`
  429. },
  430. zh: {
  431. downloadImg: `全圖片下載`,
  432. downloadImgZip: `ZIP 下載`,
  433. retrieving: `擷取連結中`,
  434. zipping: `壓縮檔案中`,
  435. processing: `壓縮`,
  436. done: `下載已完成`,
  437. // 按紐
  438. settingCenter: `設定`,
  439. cookieButton: `Cookie`,
  440. languageButton: `Language/界面語言/言語設定`,
  441. generalSave: `全域設定`,
  442. authorSave: `作者特訂`,
  443. zipName: `壓縮檔檔名`,
  444. fileName: `圖片檔檔名`,
  445. dateFormat: `日期時間格式`,
  446. saveSetting: `儲存設定`,
  447. closeSetting: `關閉`,
  448. tableParams: `參數`,
  449. tableMean: `效果`,
  450. saveMessage: `設定已儲存!`,
  451. // 參數
  452. user: `創作者名稱`,
  453. uid: `創作者 ID`,
  454. postTitle: `投稿標題`,
  455. postId: `投稿 ID`,
  456. boxTitle: `圖片區標題`,
  457. "imgIndex:0": `檔案排序號,數字決定起始數字`,
  458. plan: `訂閱方案名`,
  459. fee: `瀏覽月費`,
  460. postDate: `投稿日期`,
  461. taskDate: `下載日期`,
  462. ext: `檔案副檔名`
  463. }
  464. };
  465. return (key) ? defaultSetting[lang || this.lang][key] : defaultSetting[lang || this.lang];
  466. }
  467.  
  468. renderSettingParams() {
  469. $(`#cookie${this.cookieSave}`).attr("checked", true);
  470. $(`#${(this.authorSaveCheck == `On`) ? `authorSave` : `generalSave`}`).attr("checked", true);
  471. $(`#selectSetting option[value='${this.lang}']`).attr("selected", true);
  472. $(`#zipNameInput`).val(this[(this.authorSaveCheck == `On`) ? `authorSave` : `generalSave`].zipName);
  473. $(`#fileNameInput`).val(this[(this.authorSaveCheck == `On`) ? `authorSave` : `generalSave`].fileName);
  474. $(`#dateFormatInput`).val(this.dateFormat);
  475. $(`#paramsTable`).html(this.paramsTemplate(this.lang));
  476. return this;
  477. }
  478.  
  479. changeStyle(mode) {
  480. let blur = CSS.supports(`backdrop-filter`, `blur(15px)`);
  481. switch (mode) {
  482. case `Blur`:
  483.  
  484. return;
  485. case `unBlur`:
  486. return;
  487. default:
  488. return;
  489. }
  490. }
  491.  
  492. changeLang(Lang) {
  493. let lang = Lang || $("#selectSetting option:selected").val();
  494. this.setCookie({
  495. lang: lang
  496. });
  497. $("#titleSetting").text(this.getDefault(`settingCenter`, lang));
  498. $("#cookieSetting").text(this.getDefault(`cookieButton`, lang));
  499. $("#langSetting").text(this.getDefault(`languageButton`, lang));
  500. $("#generalSaveSetting").text(this.getDefault(`generalSave`, lang));
  501. $("#authorSaveSetting").text(this.getDefault(`authorSave`, lang));
  502. $("#zipNameSetting").text(this.getDefault(`zipName`, lang));
  503. $("#fileNameSetting").text(this.getDefault(`fileName`, lang));
  504. $("#dateFormatSetting").text(this.getDefault(`dateFormat`, lang));
  505. $("#saveSetting").text(this.getDefault(`saveSetting`, lang));
  506. $("#closeSetting").text(this.getDefault(`closeSetting`, lang));
  507. $(".downloadSpan").text(this.getDefault('downloadImg', lang));
  508. $(".downloadSpanZip").text(this.getDefault('downloadImgZip', lang));
  509. $("#paramsTable").html(this.paramsTemplate(this.lang));
  510. return;
  511. }
  512.  
  513. changeName(type) {
  514. let name = $(`#${type}NameInput`).val();
  515. let setting = $(`input[name='saveCheck']:checked`).attr("id");
  516. if (name == ``) {
  517. this.changeSaveSetting(setting);
  518. } else {
  519. this[setting][`${type}Name`] = name;
  520. }
  521. return;
  522. }
  523.  
  524. changeSaveSetting(id) {
  525. let setting = this[id];
  526. $(`#zipNameInput`).val(setting.zipName);
  527. $(`#zipNameInput`).attr("placeholder", setting.zipName);
  528. $(`#fileNameInput`).val(setting.fileName);
  529. $(`#fileNameInput`).attr("placeholder", setting.fileName);
  530. return;
  531. }
  532.  
  533. paramsTemplate(lang = this.lang) {
  534. let table = `<table><tbody><tr style="text-align:center;">
  535. <th>${setting.getDefault(`tableParams`, lang)}</th>
  536. <th>${setting.getDefault(`tableMean`, lang)}</th>
  537. </tr>`;
  538. let a = [`user`, `uid`, `postTitle`, `postId`, `boxTitle`, `imgIndex:0`, `plan`, `fee`, `postDate`, `taskDate`, `ext`].forEach((p, i) => {
  539. table += `<tr style="background-color: ${(i % 2 == 0) ? `#71b6ff2b` : `#fff0`};">
  540. <td style="border-right: 1px solid #131313;">{${p}}</td>
  541. <td style="border-left: 1px solid #131313;">${setting.getDefault(p, lang)}</td>
  542. </tr>`;
  543. });
  544.  
  545. table += `</tbody></table>`;
  546.  
  547. return table;
  548. }
  549.  
  550. settingCenterTemplate(lang) {
  551. return `<div id="settingCenterDiv" class="close ${(CSS.supports(`backdrop-filter`, `blur(15px)`)) ? `` : `unBlur`}">
  552. <div class="settingTitleColor" style="width: 100%;height: 25px;position: relative;background-color: #ffffff78;display: flex;align-items: center;">
  553. <p id="titleSetting" style="margin: 0 auto;">${this.getDefault(`settingCenter`, lang)}</p>
  554. </div>
  555. <div class="titleImage" onclick="location.href = 'https://github.com/suzumiyahifumi/Fantia-Downloader-tampermonkey'" style="width: 100%;height: 55px;background-color: #ffffff78;position: relative;margin: 0 auto;cursor: pointer;border-top-style: solid;border-top-color: #757575;border-top-width: 1px;border-bottom-left-radius: 10px;border-bottom-right-radius: 10px;"></div>
  556. <div style="width: 95%;height: 2.5em;background-color: #fff0;margin: 10px auto;position: relative;border-radius: 5px;">
  557. <div class="settingTitleColor" style="width: calc(50% - 1px);height: 100%;background-color: #ffffff69;border-top-left-radius: 5px;border-bottom-left-radius: 5px;float: left;display: flex;align-items: center;margin: 0 1px 0 auto;">
  558. <p id="cookieSetting" style="margin: 0 auto;">${this.getDefault(`cookieButton`, lang)}</p>
  559. </div>
  560. <div class="settingTitleColor" style="width: calc(50% - 1px);height: 100%;background-color: #ffffff69;border-top-right-radius: 5px;border-bottom-right-radius: 5px;float: left;position: relative;margin: 0 auto 0 1px;">
  561. <label style="float: left;width: 50%;height: 100%;display: flex;align-items: center;cursor: pointer;margin: auto;" for="cookieOn" id="cookieOnLabel" class="settingCenterButton"><input style="cursor: pointer;appearance: none;" type="radio" id="cookieOn" onclick="setting.setCookie({cookieSave:'On'})" name="cookieCheck">
  562. <div id="cookieOnLabel" style="width: 100%;height: 100%;display: flex;align-items: center;cursor: pointer;margin: auto;">
  563. <span style="margin: 0 auto;">On</span></div>
  564. </label><label style="float: left;width: 50%;height: 100%;display: flex;align-items: center;cursor: pointer;margin: auto;border-top-right-radius: 5px;border-bottom-right-radius: 5px;" for="cookieOff" id="cookieOffLabel" class="settingCenterButton"><input style="cursor: pointer;appearance: none;" type="radio" name="cookieCheck" id="cookieOff" onclick="setting.setCookie({cookieSave:'Off'})">
  565. <div style="width: 100%;height: 100%;display: flex;align-items: center;cursor: pointer;margin: auto;border-top-right-radius: 5px;border-bottom-right-radius: 5px;" id="cookieOffLabel"><span style="margin: 0 auto;">Off</span></div>
  566. </label></div>
  567. </div>
  568. <div style="width: 95%;height: 2.5em;background-color: #fff0;margin: 10px auto;position: relative;border-radius: 5px;">
  569. <div class="settingTitleColor" style="width: calc(50% - 1px);height: 100%;background-color: #ffffff69;border-top-left-radius: 5px;border-bottom-left-radius: 5px;float: left;display: flex;align-items: center;margin: 0 1px 0 auto;">
  570. <p id="langSetting" style="margin: 0 auto;">${this.getDefault(`languageButton`, lang)}</p>
  571. </div>
  572. <div class="settingCenterButton" style="width: calc(50% - 1px);height: 100%;background-color: #77777769;border-top-right-radius: 5px;border-bottom-right-radius: 5px;border-left-color: #c8c8c800;border-left-width: 1px;border-left-style: solid;float: left;position: relative;margin: 0 auto 0 1px;">
  573. <select id="selectSetting" onchange="setting.changeLang()" style="height: 100%;border-style: hidden;border-top-right-radius: 5px;border-bottom-right-radius: 5px;width: 100%;background-color: #fff;cursor: pointer;text-align: center;text-align-last: center;-webkit-appearance: none;-moz-appearance: none;" name="lang">
  574. <option value="zh">中文</option>
  575. <option value="en">English</option>
  576. <option value="ja">日本語</option>
  577. </select></div>
  578. </div>
  579. <div style="width: 95%;height: calc(100% - 80px - 50px - 7.5em);background-color: #fff0;margin: 10px auto;position: relative;border-radius: 5px;">
  580. <div class="settingTitleColor" style="width: calc(50% - 1px);height: 2.5em;background-color: #ffffff69;border-top-left-radius: 5px;float: left;display: flex;align-items: center;cursor: pointer;margin: 0 1px 1px 0;/*! border-bottom-style: groove; *//*! border-bottom-color: #fff; */">
  581. <label style="float: left;width: 100%;height: 100%;display: flex;align-items: center;cursor: pointer;margin: auto;" for="generalSave" class="settingCenterButton"><input style="cursor: pointer;appearance: none;" type="radio" id="generalSave" name="saveCheck">
  582. <div style="width: 100%;height: 100%;display: flex;align-items: center;cursor: pointer;margin: auto;border-top-left-radius: 5px;" id="generalSaveLabel" onclick="setting.changeSaveSetting('generalSave');setting.setCookie({authorSaveCheck:'Off', authorId_${this.authorId}: 'Off'})"><span id="generalSaveSetting" style="margin: 0 auto;">${this.getDefault(`generalSave`, lang)}</span></div>
  583. </label></div>
  584. <div class="settingTitleColor" style="width: calc(50% - 1px);height: 2.5em;background-color: #ffffff69;border-top-right-radius: 5px;float: left;display: flex;align-items: center;position: relative;cursor: pointer;margin: 0 0 1px 1px;">
  585. <label style="float: left;width: 100%;height: 100%;display: flex;align-items: center;cursor: pointer;margin: auto;" for="authorSave" class="settingCenterButton"><input style="cursor: pointer;appearance: none;" type="radio" name="saveCheck" id="authorSave">
  586. <div style="width: 100%;height: 100%;display: flex;align-items: center;cursor: pointer;margin: auto;border-top-right-radius: 5px;" id="authorSaveLabel" onclick="setting.changeSaveSetting('authorSave');setting.setCookie({authorSaveCheck:'On', authorId_${this.authorId}: 'On'})"><span id="authorSaveSetting" style="margin: 0 auto;">${this.getDefault(`authorSave`, lang)}</span></div>
  587. </label></div>
  588. <div class="settingTitleColor" style="width: calc(25% - 1px);height: 2.5em;float: left;display: flex;align-items: center;position: relative;background-color: #ffffff69;margin: 1px 1px 1px 0;">
  589. <p id="zipNameSetting" style="margin: 0 auto;">${this.getDefault(`zipName`, lang)}</p>
  590. </div>
  591. <div class="settingTitleColor" style="width: calc(60% - 1px);height: 2.5em;background-color: #ffffff69;float: left;display: flex;align-items: center;position: relative;cursor: pointer;margin: 1px 1px 1px 1px;">
  592. <input id="zipNameInput" onchange="setting.changeName('zip')" placeholder="{postTitle}_{boxTitle}" style="margin: 0 auto;background: #ffffff2e;width: 95%;border-style: none;padding: 0.2em;">
  593. </div>
  594. <div class="settingTitleColor" style="width: calc(15% - 2px);height: 2.5em;background-color: #ffffff69;float: left;display: flex;align-items: center;position: relative;margin: 1px auto 1px 1px;">
  595. <p style="margin: 0 auto;">.zip</p>
  596. </div>
  597. <div class="settingTitleColor" style="width: calc(25% - 1px);height: 2.5em;float: left;display: flex;align-items: center;position: relative;background-color: #ffffff69;margin: 1px 1px 1px auto;">
  598. <p id="fileNameSetting" style="margin: 0 auto;">${this.getDefault(`fileName`, lang)}</p>
  599. </div>
  600. <div class="settingTitleColor" style="width: calc(60% - 1px);height: 2.5em;background-color: #ffffff69;float: left;display: flex;align-items: center;position: relative;cursor: pointer;margin: 1px 1px 1px 1px;">
  601. <input id="fileNameInput" onchange="setting.changeName('file')" placeholder="{imgIndex:0}" style="margin: 0 auto;background: #ffffff2e;width: 95%;border-style: none;padding: 0.2em;">
  602. </div>
  603. <div class="settingTitleColor" style="width: calc(15% - 2px);height: 2.5em;background-color: #ffffff69;float: left;display: flex;align-items: center;position: relative;margin: 1px auto 1px 1px;">
  604. <p style="margin: 0 auto;">.{ext}</p>
  605. </div>
  606. <div class="settingTitleColor" style="width: calc(50% - 1px);height: 2.5em;float: left;display: flex;align-items: center;position: relative;background-color: #ffffff69;margin: 1px 1px 1px 0;">
  607. <p id="dateFormatSetting" style="margin: 0 auto;">${this.getDefault(`dateFormat`, lang)}</p>
  608. </div>
  609. <div class="settingTitleColor" style="width: calc(50% - 1px);height: 2.5em;background-color: #ffffff69;float: left;display: flex;align-items: center;position: relative;margin: 1px auto 1px 1px;">
  610. <input id="dateFormatInput" onchange="setting.setCookie({dateFormat: $('#dateFormatInput').val()})" style="margin: 0 auto;background: #ffffff2e;width: 95%;border-style: none;padding: 0.2em;text-align:center;">
  611. </div>
  612. <div id="paramsTable" class="settingTitleColor" style="width: 100%;height: calc(100% - 10em - 6px);position: relative;background-color: #ffffff69;border-bottom-left-radius: 5px;border-bottom-right-radius: 5px;float: left;margin: 1px 0 0 0;overflow: auto;">
  613. </div>
  614. </div>
  615. <div class="settingTitleColor" style="width: 95%;height: 2.5em;background-color: #fff0;margin: 10px auto;position: relative;border-radius: 5px;">
  616. <div class="settingCenterButton" style="width: calc(65% - 5px);height: 100%;background-color: #ffffff69;border-radius: 5px;float: left;cursor: pointer;display: flex;align-items: center;margin: 0 5px 0 0;" onclick="setting.saveCookie();">
  617. <p id="saveSetting" style="margin: 0 auto;">${this.getDefault(`saveSetting`, lang)}</p>
  618. </div>
  619. <div class="settingCenterButton" style="width: calc(35% - 5px);height: 100%;background-color: #f65c5c9e;float: left;position: relative;border-radius: 5px;cursor: pointer;display: flex;align-items: center;margin: 0 0 0 5px;" onclick="$('#settingCenterDiv').addClass('close')">
  620. <p id="closeSetting" style="margin: 0 auto;">${this.getDefault(`closeSetting`, lang)}</p>
  621. </div>
  622. </div>
  623. </div>`;
  624. }
  625. }
  626.  
  627. class downloader {
  628. constructor(event) {
  629. this.pageType = setting.pageType;
  630. this.metaData = setting.metaData;
  631. this.button = ($(event.target).is("button")) ? $(event.target) : $(event.target).closest("button");
  632. this.boxType = this.button.attr("box-type");
  633. this.postContent = $(event.target).closest(".boxIndex");
  634. this.type = (this.button.hasClass(`zip`)) ? `zip` : `file`;
  635. this.boxIndex = this.postContent.attr("boxIndex");
  636.  
  637. if (this.boxType == "box") {
  638. let content = this.metaData.content[this.boxIndex];
  639. let p = (content.plan == null) ? `一般公開` : undefined;
  640. this.metaData.category = content.category;
  641. this.metaData.indextype = (content.category == "blog") ? this.button.closest(".blogBox").attr("blog-img-index") : "photo_gallery";
  642. this.metaData.srcArr = (content.category == "blog") ? [JSON.parse(content.comment).ops.filter(i => {
  643. return (i.insert.fantiaImage && i.insert.fantiaImage.id == this.metaData.indextype) ? true : false
  644. })[0].insert.fantiaImage.original_url] : content.post_content_photos.map(img => img.url.original);
  645. this.metaData.fee = p || content.plan.price;
  646. this.metaData.plan = p || content.plan.name;
  647. this.metaData.postDate = content.parent_post.date;
  648. this.metaData.postId = content.parent_post.url.split("/").pop();
  649. this.metaData.postTitle = content.parent_post.title;
  650. this.metaData.title = content.title;
  651. this.metaData.d = (content.category == "photo_gallery") ? downloader.getDigits(Number(content.post_content_photos.length)) : 1;
  652. } else if (this.boxType == "post") {
  653. let p = `一般公開`;
  654. this.metaData.category = "post";
  655. this.metaData.indextype = "post";
  656. this.metaData.srcArr = [setting.metaJson.post.thumb.original];
  657. this.metaData.fee = p;
  658. this.metaData.plan = p;
  659. this.metaData.postDate = setting.metaJson.post.posted_at;
  660. this.metaData.postId = setting.metaJson.post.uri.show.split("/").pop();
  661. this.metaData.postTitle = setting.metaJson.post.title;
  662. this.metaData.title = setting.metaJson.post.title;
  663. this.metaData.d = 1;
  664. }
  665. this.zipName = `${setting[`${(setting.authorSaveCheck == 'On') ? `author` : `general`}Save`].zipName}.zip`;
  666. this.fileName = `${setting[`${(setting.authorSaveCheck == 'On') ? `author` : `general`}Save`].fileName}.{ext}`;
  667. this.dateFormat = setting.dateFormat;
  668. this.zipfmt = ``;
  669. this.zipImgIndex0 = 0;
  670. this.filefmt = ``;
  671. this.fileImgIndex0 = 0;
  672. this.d = this.metaData.d;
  673.  
  674. this.zip = (this.type == `zip`) ? new JSZip() : undefined;
  675. return this.downloadImg();
  676. }
  677.  
  678. changeButton(mode, input = false) {
  679. let button = this.button;
  680. switch (mode) {
  681. case `start`:
  682. button.addClass(['active', 'hdr']);
  683. if (this.type == `file`) {
  684. button.find('i').removeClass('fa-download');
  685. button.find('i').addClass('fa-spinner');
  686. button.find('i').addClass('fa-pulse');
  687. } else {
  688. button.find('i').removeClass('fa-file-archive-o');
  689. button.find('i').addClass('fa-spinner');
  690. button.find('i').addClass('fa-pulse');
  691. }
  692. break;
  693. case `catchLink`:
  694. button.find('span').text(setting.getDefault(`retrieving`));
  695. break;
  696. case `countTask`:
  697. button.find('span').text(`${this.finCount} / ${this.imgSrc.length}`);
  698. break;
  699. case `pickUp`:
  700. button.find('span').text(setting.getDefault(`zipping`));
  701. break;
  702. case `end`:
  703. if (this.type == `file`) {
  704. button.find('i').removeClass('fa-pulse').removeClass('fa-spinner').addClass('fa-download');
  705. } else {
  706. button.find('i').removeClass('fa-pulse').removeClass('fa-spinner').addClass('fa-file-archive-o');
  707. }
  708. button.removeClass(['active', 'hdr']);
  709. button.find('span').text(setting.getDefault(`done`));
  710. break;
  711. case `log`:
  712. button.find('span').text(input);
  713. break;
  714. default:
  715. return this;
  716. }
  717. return this;
  718. }
  719.  
  720. paramsParser(type, fmt) {
  721. let o = {
  722. user: () => {
  723. return this.metaData.user || $("h1.fanclub-name>a").text();
  724. },
  725. uid: () => {
  726. return this.metaData.uid || this.authorId;
  727. },
  728. postTitle: () => {
  729. return this.metaData.postTitle || $("h1.post-title").text();
  730. },
  731. postId: () => {
  732. return this.metaData.postId || window.location.href.split("/").pop();
  733. },
  734. boxTitle: () => {
  735. return this.metaData.boxTitle || this.button.closest("div.post-content-inner").find('h2').text();
  736. },
  737. plan: () => {
  738. let feeStr = this.metaData.plan || this.button.closest("div.post-content-inner").find(`div.post-content-for strong.ng-binding`).text();
  739. let match = this.metaData.plan || feeStr.match(new RegExp(/(\d+円)以上限定$/g));
  740. if (match != null) return this.metaData.plan || feeStr.replace(match[0], ``);
  741. return this.metaData.plan || `一般公開`;
  742. },
  743. fee: () => {
  744. let feeStr = this.metaData.fee || this.button.closest("div.post-content-inner").find(`div.post-content-for strong.ng-binding`).text();
  745. let match = this.metaData.fee || feeStr.match(new RegExp(/((\d+)円)以上限定$/g));
  746. if (match != null) return this.metaData.fee || RegExp.$1;
  747. return this.metaData.fee || `一般公開`;
  748. },
  749. postDate: () => {
  750. return new Date(this.metaData.postDate || $(`small.post-date>span`).text()).Format(this.dateFormat);
  751. },
  752. taskDate: () => {
  753. return new Date().Format(this.dateFormat);
  754. }
  755. };
  756.  
  757. for (let k in o) {
  758. if (new RegExp('(\\{' + k + '\\})', 'g').test(fmt)) fmt = fmt.replace(RegExp.$1, o[k]());
  759. }
  760.  
  761. let s = (/\{imgIndex(\:(\d+))?\}/g.test(fmt)) ? RegExp.$2 : 0;
  762. if (/\{imgIndex(\:(\d+))?\}/g.test(fmt)) fmt = fmt.replace(RegExp.$1, ``);
  763. this[`${type}fmt`] = fmt;
  764. this[`${type}ImgIndex0`] = s;
  765. return this;
  766. }
  767.  
  768. nextName(type, index, mimeType) {
  769. if (this.metaData.indextype != "photo_gallery") return this[`${type}fmt`].replace(`{imgIndex}`, (this.metaData.indextype).toString().padStart(this.d, 0)).replace(`{ext}`, mimeType.toString().split(`/`)[1]);
  770. return this[`${type}fmt`].replace(`{imgIndex}`, (Number(index) + Number(this[`${type}ImgIndex0`])).toString().padStart(this.d, 0)).replace(`{ext}`, mimeType.toString().split(`/`)[1]);
  771. }
  772.  
  773. downloadImg() {
  774. let dataCont = 0;
  775. this.paramsParser(`zip`, this.zipName);
  776. this.paramsParser(`file`, this.fileName);
  777. this.changeButton(`start`);
  778. this.changeButton(`catchLink`);
  779. this.changeButton(`log`, `${dataCont} / ${this.metaData.srcArr.length}`);
  780. let self = this;
  781. this.metaData.srcArr.forEach((url, i) => {
  782. downloader.loadAsArrayBuffer(url, function (imgData, mimeType, lastModified) {
  783. dataCont += 1;
  784. self.changeButton(`log`, `${dataCont} / ${self.metaData.srcArr.length}`);
  785. self.mimeType = mimeType;
  786. if (self.zip == undefined) {
  787. if (dataCont == self.metaData.srcArr.length) self.changeButton('end');
  788. let content = new Blob([imgData], {
  789. type: mimeType
  790. });
  791. downloader.download(content, self.nextName('file', i, mimeType));
  792. return;
  793. } else {
  794. const sDate = lastModified && lastModified !== '' ? new Date(lastModified) : null
  795. const date = sDate ? new Date(sDate.getTime() - sDate.getTimezoneOffset() * 60000) : new Date()
  796. self.zip.file(self.nextName('file', i, mimeType), imgData, {
  797. date
  798. });
  799. if (dataCont == self.metaData.srcArr.length) {
  800. self.changeButton(`pickUp`);
  801. self.zip.generateAsync({
  802. type: "blob"
  803. },
  804. function updateCallback(metadata) {
  805. self.changeButton(`log`, `${setting.getDefault(`processing`)}:${metadata.percent.toFixed(2)} %`);
  806. }).then(function (content) {
  807. self.changeButton('end');
  808. downloader.download(content, self.nextName('zip', 0, mimeType));
  809. return;
  810. });
  811. }
  812. }
  813. });
  814. });
  815. }
  816.  
  817. static download(content, name) {
  818. let tag = document.createElement('a');
  819. tag.href = (URL || webkitURL).createObjectURL(content);
  820. tag.download = name;
  821. document.body.appendChild(tag);
  822. tag.click();
  823. document.body.removeChild(tag);
  824. return;
  825. }
  826.  
  827. static getDigits(i) {
  828. let L = 0;
  829. while (i >= 1) {
  830. i = i / 10;
  831. L += 1;
  832. }
  833. return `${L}`;
  834. }
  835.  
  836. static loadAsArrayBuffer(url, callback) {
  837. let xhr = new XMLHttpRequest();
  838. xhr.open("GET", url);
  839. xhr.responseType = "arraybuffer";
  840. xhr.onerror = function (error) {
  841. return new Error(`ERROR`);
  842. };
  843. xhr.onload = function () {
  844. if (xhr.status === 200) {
  845. callback(xhr.response, xhr.getResponseHeader("Content-Type"), xhr.getResponseHeader("Last-Modified"));
  846. } else {
  847. return new Error(`ERROR`);
  848. }
  849. };
  850. xhr.send();
  851. }
  852. }
  853.  
  854. window.getDownLoadButton = () => {
  855. $("div.post-content-inner").each((i, div) => {
  856. $(div).addClass("boxIndex").attr("boxIndex", i);
  857. $(div).find("div.btn-group-tabs").append(`<button box-type="box" class="btn btn-default btn-md downloadButton zip" onclick="getImg(event)"><i class="fa fa-file-archive-o fa-2x" style="color: #f9a63b !important;"></i> <span class="btn-text-sub downloadSpanZip" style="color: #f9a63b !important;">${setting.getDefault('downloadImgZip')}</span></button><button box-type="box" class="btn btn-default btn-md downloadButton file" onclick="getImg(event)"><i class="fa fa-download fa-2x" style="color: #fe7070 !important;"></i> <span class="btn-text-sub downloadSpan" style="color: #fe7070 !important;">${setting.getDefault('downloadImg')}</span></button>`);
  858. });
  859. $(`.the-post`).find("div.btn-group-tabs").append(`<button box-type="post" class="btn btn-default btn-md downloadButton zip" onclick="getImg(event)"><i class="fa fa-file-archive-o fa-2x" style="color: #f9a63b !important;"></i> <span class="btn-text-sub downloadSpanZip" style="color: #f9a63b !important;">${setting.getDefault('downloadImgZip')}</span></button><button box-type="post" class="btn btn-default btn-md downloadButton file" onclick="getImg(event)"><i class="fa fa-download fa-2x" style="color: #fe7070 !important;"></i> <span class="btn-text-sub downloadSpan" style="color: #fe7070 !important;">${setting.getDefault('downloadImg')}</span></button>`);
  860. $('.set-FD').remove();
  861. $("div#page").append(`<div id="settingCenter" onclick="openSettingCenter()"></div>`);
  862. $("div#page").append(setting.settingCenterTemplate());
  863. setting.renderSettingParams().paramsTemplate();
  864. return;
  865. };
  866.  
  867. window.openSettingCenter = () => {
  868. if ($(`#settingCenterDiv`).hasClass(`close`)) {
  869. $(`#settingCenterDiv`).removeClass(`close`);
  870. }
  871. return;
  872. };
  873.  
  874. window.getImg = (event) => {
  875. return checkBrowser(event, (event) => {
  876. return new downloader(event);
  877. });
  878. };
  879.  
  880. window.checkBrowser = (event, callBack) => {
  881. try {
  882. let excludes = [];
  883. let ex = excludes.map(b => navigator.userAgent.indexOf(b)).filter(b => (b != -1) ? true : false);
  884. if (ex.length >= 1) {
  885. alert(`請使用 Firefox 下載圖片!\nPlease run this script on Firefox!\n
  886. Also you can check the new script version!`);
  887. return;
  888. } else {
  889. return callBack(event);
  890. }
  891. } catch (err) {
  892. console.log(err);
  893. alert(`出了些問題!你可以嘗試使用 Firefox 下載圖片!\nThere are some ERROR, You can try this script on Firefox!\n
  894. Also you can check the new script version!`);
  895. return;
  896. }
  897. };
  898. })();

QingJ © 2025

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