FanboxPic Downloader

Add download button to Fanbox image, and click to download the original image named by format.

目前為 2020-10-18 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name FanboxPic Downloader
  3. // @namespace TypeNANA
  4. // @version 0.1
  5. // @description Add download button to Fanbox image, and click to download the original image named by format.
  6. // @author HY
  7. // @match https://*.fanbox.cc/*/posts/*
  8. // @include https://*.fanbox.cc/*/posts/*
  9. // @require http://code.jquery.com/jquery-3.3.1.min.js
  10. // @grant GM_xmlhttpRequest
  11. // ==/UserScript==
  12.  
  13. (function () {
  14. /** Edit defaultFileName to change the file name format
  15. *
  16. * <%Userid> Fanbox user ID. eg: shiratamaco
  17. * <%Postid> Fanbox post ID. eg: 1459770
  18. * <%Time> Current timestamp. eg: 1550557810891
  19. * <%PicName> Original pic name. eg: 6tpWcFZjqFmc1faOs4TraugL
  20. * <%PicNo> Ordinal number of pic. eg: 0
  21. *
  22. * default: "fanbox <%Userid> <%Postid>_p<%PicNo>"
  23. * result: "fanbox shiratamaco 1459770_p0.jpg"
  24. *
  25. * example1: "<%Userid> <%Postid> <%PicName>”
  26. * result: "shiratamaco 1459770 6tpWcFZjqFmc1faOs4TraugL.jpg"
  27. *
  28. * example2: "<%Postid>_p<%PicNo>”
  29. * result: "1459770_p0.jpg"
  30. */
  31. let defaultFileName = "fanbox <%Userid> <%Postid>_p<%PicNo>";
  32.  
  33. function download(url, name) {
  34. //获取blob,这边因为跨域所以采用了GM_xmlhttpRequest
  35. GM_xmlhttpRequest({
  36. method: "GET",
  37. url: url,
  38. binary: true,
  39. responseType: "blob",
  40. onload: function (response) {
  41. downloadFile(name, response.response)
  42. },
  43. onerror: function (e) {
  44. console.log("failed. cause:", e)
  45. },
  46. });
  47. }
  48.  
  49. function downloadFile(fileName, blob) {
  50. //通过a标签的download属性来下载指定文件名的文件
  51. let anchor = getDlBtn();
  52. let src = URL.createObjectURL(blob);
  53. anchor.download = fileName;
  54. anchor.href = src;
  55. anchor.click();
  56. }
  57.  
  58. function getDlBtn() {
  59. if (document.getElementsByClassName("img-link").length == 0) {
  60. btnDownloadImg = document.createElement('A');
  61. btnDownloadImg.className = 'img-link';
  62. document.getElementById("root").appendChild(btnDownloadImg);
  63. }
  64. return document.getElementsByClassName("img-link")[0];
  65. }
  66.  
  67. function setBtn(v, index) {
  68. if (v == null || v.length == 0) return;
  69. let target = v[0];
  70. if (target == null) return;
  71. if (target.getElementsByClassName("dl_btn_div").length > 0) return;
  72. if (target.getElementsByTagName("img").length <= 0 && target.getElementsByTagName("img")[0].src == null) return;
  73.  
  74. let pageUrl = document.location.href;
  75. let picUrl = target.href;
  76.  
  77. let dlbtn = document.createElement('DIV');
  78. target.parentElement.appendChild(dlbtn);
  79. dlbtn.outerHTML = '<div class="dl_btn_div" style="cursor: pointer;display: table;font-size: 15px;color: white;position: absolute;right: 5px;bottom: 5px;background: #0000007f;height: 30px;width: 30px;border-radius: 15px;text-align: center;"><svg class="icon" style="width: 15px;height: 15px;vertical-align: top;display: inline-block;margin-top: 7px;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3658"><path d="M925.248 356.928l-258.176-258.176a64 64 0 0 0-45.248-18.752H144a64 64 0 0 0-64 64v736a64 64 0 0 0 64 64h736a64 64 0 0 0 64-64V402.176a64 64 0 0 0-18.752-45.248zM288 144h192V256H288V144z m448 736H288V736h448v144z m144 0H800V704a32 32 0 0 0-32-32H256a32 32 0 0 0-32 32v176H144v-736H224V288a32 32 0 0 0 32 32h256a32 32 0 0 0 32-32V144h77.824l258.176 258.176V880z" p-id="3659"></path></svg></div>';
  80. dlbtn = target.parentElement.getElementsByClassName("dl_btn_div")[0]
  81.  
  82. //获取文件名
  83. // https://downloads.fanbox.cc/images/post/1459770/6tpWcFZjqFmc1faOs4TraugL.png
  84. let nameArr = picUrl.split("/");
  85. let picName = nameArr[nameArr.length - 1];
  86. let dl_picname = picName.split(".")[0];
  87. let dl_time = new Date().getTime();
  88.  
  89. //获取图片编号
  90. // https://www.fanbox.cc/@shiratamaco/posts/1459770
  91. let dl_userid = pageUrl.split("@")[1].split("/")[0];
  92. let dl_tid = pageUrl.split("/")[pageUrl.split("/").length - 1];
  93. let dl_picno = index;
  94. //替换内容,拼接文件名
  95. let dl_filename = defaultFileName
  96. .replace("<%Userid>", dl_userid)
  97. .replace("<%Postid>", dl_tid)
  98. .replace("<%Time>", dl_time)
  99. .replace("<%PicName>", dl_picname)
  100. .replace("<%PicNo>", dl_picno);
  101. //获取拓展名,推特只存在.jpg和.png格式的图片,故偷个懒不做正则判断
  102. let dl_ext = picUrl.split(".")[picUrl.split(".").length - 1];
  103.  
  104. dlbtn.addEventListener('touchstart', function (e) {
  105. dlbtn.onclick = function (e) {
  106. return false;
  107. }
  108. return false;
  109. });
  110. dlbtn.addEventListener('mousedown', function (e) {
  111. dlbtn.onclick = function (e) {
  112. return false;
  113. }
  114. return false;
  115. });
  116. dlbtn.addEventListener('click', function (e) {
  117. //调用下载方法
  118. cancelBubble(e);
  119. download(picUrl, dl_filename + "." + dl_ext);
  120. return false;
  121. });
  122.  
  123. return false;
  124. }
  125.  
  126. function findFirstA(node) {
  127. var tmp = node;
  128. for (var i = 0; i < 20; i++) {
  129. tmp = tmp.parentElement
  130. if (tmp == null) return null;
  131. if (tmp.nodeName == "a" || tmp.nodeName == "A") {
  132. return tmp
  133. }
  134. }
  135. }
  136. function findFirstLi(node) {
  137. var tmp = node;
  138. for (var i = 0; i < 20; i++) {
  139. tmp = tmp.parentElement
  140. if (tmp == null) return null;
  141. if (tmp.nodeName == "li" || tmp.nodeName == "LI") {
  142. return tmp
  143. }
  144. }
  145. }
  146. function cancelBubble(e) {
  147. var evt = e ? e : window.event;
  148. if (evt.stopPropagation) {
  149. evt.stopPropagation();
  150. } else {
  151. evt.cancelBubble = true;
  152. }
  153. }
  154.  
  155. function waitForKeyElements(
  156. selectorTxt,
  157. actionFunction,
  158. bWaitOnce
  159. ) {
  160. var targetNodes, btargetsFound;
  161.  
  162. targetNodes = $(selectorTxt);
  163.  
  164. if (targetNodes && targetNodes.length > 0) {
  165. btargetsFound = true;
  166. targetNodes.each(function (i, v) {
  167. var jThis = $(this);
  168. var alreadyFound = jThis.data('alreadyFound') || false;
  169.  
  170. if (!alreadyFound) {
  171. var cancelFound = actionFunction(jThis, i);
  172. if (cancelFound) {
  173. btargetsFound = false;
  174. } else {
  175. jThis.data('alreadyFound', true);
  176. }
  177. }
  178. });
  179. } else {
  180. btargetsFound = false;
  181. }
  182.  
  183. var controlObj = waitForKeyElements.controlObj || {};
  184. var controlKey = selectorTxt.replace(/[^\w]/g, "_");
  185. var timeControl = controlObj[controlKey];
  186.  
  187. if (btargetsFound && bWaitOnce && timeControl) {
  188. clearInterval(timeControl);
  189. delete controlObj[controlKey]
  190. } else {
  191. if (!timeControl) {
  192. timeControl = setInterval(function () {
  193. waitForKeyElements(selectorTxt,
  194. actionFunction,
  195. bWaitOnce
  196. );
  197. }, 300);
  198. controlObj[controlKey] = timeControl;
  199. }
  200. }
  201. waitForKeyElements.controlObj = controlObj;
  202. }
  203.  
  204. waitForKeyElements('.DraftEditor-root a[href^="https://downloads.fanbox.cc/images/post"]', setBtn);
  205. })();

QingJ © 2025

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