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.2
  5. // @description Add download button to Fanbox image, and click to download the original image named by format.
  6. // @author HY
  7. // @match *.fanbox.cc/*
  8. // @include *.fanbox.cc/*
  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. //通过fetch获取blob
  35. // fetch(url).then(response => {
  36. // if (response.status == 200)
  37. // return response.blob();
  38. // throw new Error(`status: ${response.status}.`)
  39. // }).then(blob => {
  40. // downloadFile(name, blob, view)
  41. // }).catch(error => {
  42. // console.log("failed. cause:", error)
  43. // })
  44.  
  45. GM_xmlhttpRequest({
  46. method: "GET",
  47. url: url,
  48. binary: true,
  49. responseType: "blob",
  50. onload: function (response) {
  51. downloadFile(name, response.response)
  52. },
  53. onerror: function (e) {
  54. console.log("failed. cause:", e)
  55. },
  56. });
  57. }
  58.  
  59. function downloadFile(fileName, blob) {
  60. //通过a标签的download属性来下载指定文件名的文件
  61. let anchor = getDlBtn();
  62. let src = URL.createObjectURL(blob);
  63. anchor.download = fileName;
  64. anchor.href = src;
  65. anchor.click();
  66. }
  67.  
  68. function getDlBtn() {
  69. if (document.getElementsByClassName("img-link").length == 0) {
  70. btnDownloadImg = document.createElement('A');
  71. btnDownloadImg.className = 'img-link';
  72. document.getElementById("root").appendChild(btnDownloadImg);
  73. }
  74. return document.getElementsByClassName("img-link")[0];
  75. }
  76.  
  77. function setBtn(v, index) {
  78. if (v == null || v.length == 0) return;
  79. let target = v[0];
  80. if (target == null) return;
  81. if (target.getElementsByClassName("dl_btn_div").length > 0) return;
  82. if (target.getElementsByTagName("img").length <= 0 && target.getElementsByTagName("img")[0].src == null) return;
  83.  
  84. let pageUrl = document.location.href;
  85. let picUrl = target.href;
  86.  
  87. let dlbtn = document.createElement('DIV');
  88. target.parentElement.appendChild(dlbtn);
  89. 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>';
  90. dlbtn = target.parentElement.getElementsByClassName("dl_btn_div")[0]
  91.  
  92. //获取文件名
  93. // https://downloads.fanbox.cc/images/post/1459770/6tpWcFZjqFmc1faOs4TraugL.png
  94. let nameArr = picUrl.split("/");
  95. let picName = nameArr[nameArr.length - 1];
  96. let dl_picname = picName.split(".")[0];
  97. let dl_time = new Date().getTime();
  98.  
  99. //获取图片编号
  100. // https://www.fanbox.cc/@shiratamaco/posts/1459770
  101. let dl_userid = pageUrl.split("@")[1].split("/")[0];
  102. let dl_tid = pageUrl.split("/")[pageUrl.split("/").length - 1];
  103. let dl_picno = index;
  104. //替换内容,拼接文件名
  105. let dl_filename = defaultFileName
  106. .replace("<%Userid>", dl_userid)
  107. .replace("<%Postid>", dl_tid)
  108. .replace("<%Time>", dl_time)
  109. .replace("<%PicName>", dl_picname)
  110. .replace("<%PicNo>", dl_picno);
  111. //获取拓展名,推特只存在.jpg和.png格式的图片,故偷个懒不做正则判断
  112. let dl_ext = picUrl.split(".")[picUrl.split(".").length - 1];
  113.  
  114. dlbtn.addEventListener('touchstart', function (e) {
  115. dlbtn.onclick = function (e) {
  116. return false;
  117. }
  118. return false;
  119. });
  120. dlbtn.addEventListener('mousedown', function (e) {
  121. dlbtn.onclick = function (e) {
  122. return false;
  123. }
  124. return false;
  125. });
  126. dlbtn.addEventListener('click', function (e) {
  127. //调用下载方法
  128. cancelBubble(e);
  129. download(picUrl, dl_filename + "." + dl_ext);
  130. return false;
  131. });
  132.  
  133. return false;
  134. }
  135.  
  136. function findFirstA(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 == "a" || tmp.nodeName == "A") {
  142. return tmp
  143. }
  144. }
  145. }
  146. function findFirstLi(node) {
  147. var tmp = node;
  148. for (var i = 0; i < 20; i++) {
  149. tmp = tmp.parentElement
  150. if (tmp == null) return null;
  151. if (tmp.nodeName == "li" || tmp.nodeName == "LI") {
  152. return tmp
  153. }
  154. }
  155. }
  156. function cancelBubble(e) {
  157. var evt = e ? e : window.event;
  158. if (evt.stopPropagation) {
  159. evt.stopPropagation();
  160. } else {
  161. evt.cancelBubble = true;
  162. }
  163. }
  164.  
  165. function waitForKeyElements(
  166. selectorTxt,
  167. actionFunction,
  168. bWaitOnce
  169. ) {
  170. var targetNodes, btargetsFound;
  171.  
  172. targetNodes = $(selectorTxt);
  173.  
  174. if (targetNodes && targetNodes.length > 0) {
  175. btargetsFound = true;
  176. targetNodes.each(function (i, v) {
  177. var jThis = $(this);
  178. var alreadyFound = jThis.data('alreadyFound') || false;
  179.  
  180. if (!alreadyFound) {
  181. var cancelFound = actionFunction(jThis, i);
  182. if (cancelFound) {
  183. btargetsFound = false;
  184. } else {
  185. jThis.data('alreadyFound', true);
  186. }
  187. }
  188. });
  189. } else {
  190. btargetsFound = false;
  191. }
  192.  
  193. var controlObj = waitForKeyElements.controlObj || {};
  194. var controlKey = selectorTxt.replace(/[^\w]/g, "_");
  195. var timeControl = controlObj[controlKey];
  196.  
  197. if (btargetsFound && bWaitOnce && timeControl) {
  198. clearInterval(timeControl);
  199. delete controlObj[controlKey]
  200. } else {
  201. if (!timeControl) {
  202. timeControl = setInterval(function () {
  203. waitForKeyElements(selectorTxt,
  204. actionFunction,
  205. bWaitOnce
  206. );
  207. }, 300);
  208. controlObj[controlKey] = timeControl;
  209. }
  210. }
  211. waitForKeyElements.controlObj = controlObj;
  212. }
  213.  
  214. waitForKeyElements('.DraftEditor-root a[href^="https://downloads.fanbox.cc/images/post"]', setBtn);
  215. })();

QingJ © 2025

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