Download pictures from telegraph

Download pictures from telegra.ph

  1. // ==UserScript==
  2. // @name Download pictures from telegraph
  3. // @name:zh-CN 下载Telegraph页面图片
  4. // @version 0.6.0
  5. // @description Download pictures from telegra.ph
  6. // @description:zh-CN 下载“telegra.ph”页面上的图片
  7. // @author OWENDSWANG
  8. // @match https://telegra.ph/*
  9. // @exclude https://telegra.ph/
  10. // @icon https://avatars.githubusercontent.com/u/9076865?s=40&v=4
  11. // @license MIT
  12. // @homepage https://greasyfork.org/zh-CN/scripts/422130-download-pictures-from-telegraph
  13. // @supportURL https://github.com/owendswang/Download-Pictures-from-Telegraph
  14. // @run-at document-end
  15. // @grant GM_download
  16. // @grant GM_xmlhttpRequest
  17. // @grant GM_setClipboard
  18. // @grant GM_notification
  19. // @namespace https://www.owendswang.com/
  20. // ==/UserScript==
  21.  
  22. (function() {
  23. 'use strict';
  24.  
  25. var tlEditor = document.getElementById('_tl_editor');
  26. var pageTitle = document.getElementsByTagName('h1')[0];
  27.  
  28. function saveAs(blob, name) {
  29. const link = document.createElement("a");
  30. link.style.display = "none";
  31. link.href = URL.createObjectURL(blob);
  32. link.download = name;
  33. link.target = '_blank';
  34. document.body.appendChild(link);
  35. link.click();
  36. const timeout = setTimeout(() => {
  37. URL.revokeObjectURL(link.href);
  38. link.parentNode.removeChild(link);
  39. }, 1000);
  40. }
  41.  
  42. async function downloadSingle(url, fileName) {
  43. try {
  44. const res = await fetch(url, { browsingTopics: false });
  45. if (!res.ok) {
  46. throw new Error(`Response status: ${res.status}`);
  47. }
  48. const blob = await res.blob();
  49. saveAs(blob, fileName);
  50. } catch(e) {
  51. console.log(e);
  52. }
  53. }
  54.  
  55. // 'download' button
  56. function download(imgSrcList) {
  57. // console.log(imgSrcList);
  58. var i = 1;
  59. var padLength = imgSrcList.length.toString().length;
  60. var title = pageTitle.textContent.replace('[Click to copy this title]', '').replace('[Copied]', '').replace(/ - Page \d+$/, '');
  61. imgSrcList.forEach(function(src) {
  62. // var fileName = src.split('/')[src.split('/').length - 1];
  63. // fileName = fileName.split('?')[0];
  64. var ext = src.split('.').length > 1 ? src.split('.')[src.split('.').length - 1] : 'jpg';
  65. var fileName = title + ' (' + i.toString().padStart(padLength, '0') + ').' + ext;
  66. fileName = fileName.replace(/[<>|\|*|"|\/|\|:|?]/g, '_');
  67. // 1. GM_download wouldn't work with urls without file extension
  68. // GM_download({
  69. // url: src,
  70. // name: fileName,
  71. // onerror(error) {
  72. // console.log(error);
  73. // }
  74. // });
  75. // 2. fetch wouldn't work with cross-site request
  76. // downloadSingle(src, fileName);
  77. // 3. GM_xmlhttpRequest works fine
  78. GM_xmlhttpRequest({
  79. method: 'GET',
  80. url: src,
  81. responseType: 'blob',
  82. // headers: {},
  83. onload({ status, response }) {
  84. saveAs(response, fileName);
  85. },
  86. onerror(error) {
  87. console.log(error);
  88. GM_notification({
  89. text: error.error,
  90. title: 'Download Error',
  91. });
  92. }
  93. });
  94. i += 1;
  95. })
  96. }
  97.  
  98. // header 'download' button
  99. var headerButton = document.createElement('button');
  100. var figureList = document.getElementsByTagName('figure');
  101. headerButton.innerHTML = '<b>Download</b> (' + figureList.length.toString() + ' images in total)';
  102. headerButton.style.marginLeft = '10px';
  103. headerButton.style.paddingLeft = '15px';
  104. headerButton.style.paddingRight = '15px';
  105. headerButton.style.backgroundColor = 'rgba(0,0,0,0)';
  106. headerButton.style.border = '2px solid rgba(0,0,0,0.5)';
  107. headerButton.style.borderRadius = '5px';
  108. headerButton.type = 'button';
  109. headerButton.addEventListener('mouseover', function(event) {
  110. this.style.backgroundColor = 'rgba(0,0,0,0.1)';
  111. });
  112. headerButton.addEventListener('mouseout', function(event) {
  113. this.style.backgroundColor = 'rgba(0,0,0,0)';
  114. });
  115. headerButton.onclick = function() {
  116. var imgSrcList = [];
  117. for (var i = 0; i < figureList.length; i++) {
  118. var img = figureList[i].getElementsByTagName('img')[0];
  119. var src = img.getAttribute('src');
  120. imgSrcList.push(src);
  121. }
  122. download(imgSrcList);
  123. };
  124. var addressList = document.getElementsByTagName('address');
  125. addressList[0].appendChild(headerButton);
  126.  
  127. // bottom 'download' button
  128. var divButtonBottom = document.createElement('div');
  129. divButtonBottom.style.display = 'flex';
  130. divButtonBottom.style.justifyContent = 'center';
  131. var buttonBottom = document.createElement('button');
  132. buttonBottom.innerHTML = '<b>Download</b> (' + figureList.length.toString() + ' images in total)';
  133. buttonBottom.style.margin = '10px';
  134. buttonBottom.style.paddingTop = '10px';
  135. buttonBottom.style.paddingBottom = '10px';
  136. buttonBottom.style.paddingLeft = '20px';
  137. buttonBottom.style.paddingRight = '20px';
  138. buttonBottom.style.backgroundColor = 'rgba(0,0,0,0)';
  139. buttonBottom.style.border = '2px solid rgba(0,0,0,0.5)';
  140. buttonBottom.style.borderRadius = '5px';
  141. buttonBottom.type = 'button';
  142. buttonBottom.addEventListener('mouseover', function(event) {
  143. this.style.backgroundColor = 'rgba(0,0,0,0.1)';
  144. });
  145. buttonBottom.addEventListener('mouseout', function(event) {
  146. this.style.backgroundColor = 'rgba(0,0,0,0)';
  147. });
  148. buttonBottom.onclick = function() {
  149. var imgSrcList = [];
  150. for (var i = 0; i < figureList.length; i++) {
  151. var img = figureList[i].getElementsByTagName('img')[0];
  152. var src = img.getAttribute('src');
  153. imgSrcList.push(src);
  154. }
  155. download(imgSrcList);
  156. };
  157. divButtonBottom.appendChild(buttonBottom);
  158. tlEditor.appendChild(divButtonBottom);
  159.  
  160. // 'to top' button
  161. var toTopBtn = document.createElement('button');
  162. toTopBtn.id = 'to_top_btn';
  163. toTopBtn.textContent = '▲';
  164. toTopBtn.style.fontSize = '2rem';
  165. toTopBtn.style.position = 'fixed';
  166. toTopBtn.style.bottom = '2rem';
  167. toTopBtn.style.textAlign = 'center';
  168. toTopBtn.style.width = '4rem';
  169. toTopBtn.style.height = '4rem';
  170. toTopBtn.style.lineHeight = '3rem';
  171. toTopBtn.style.opacity = '0';
  172. toTopBtn.style.padding = '0';
  173. toTopBtn.style.borderWidth = '2px';
  174. toTopBtn.style.borderStyle = 'solid';
  175. toTopBtn.style.borderColor = 'gray';
  176. toTopBtn.style.borderRadius = '5px';
  177. toTopBtn.style.transition = 'opacity 1s';
  178. toTopBtn.style.backgroundColor = 'rgba(0, 0, 0, 0.1)';
  179. toTopBtn.addEventListener('mouseover', function(event) {
  180. this.style.backgroundColor = 'rgba(0,0,0,0.2)';
  181. });
  182. toTopBtn.addEventListener('mouseout', function(event) {
  183. this.style.backgroundColor = 'rgba(0,0,0,0.1)';
  184. });
  185. toTopBtn.addEventListener('mousedown', function(event) {
  186. this.style.backgroundColor = 'rgba(0,0,0,0.3)';
  187. });
  188. toTopBtn.addEventListener('mouseup', function(event) {
  189. this.style.backgroundColor = 'rgba(0,0,0,0.2)';
  190. });
  191.  
  192. function setToTopBtnXPos() {
  193. var left = (document.body.clientWidth + tlEditor.offsetWidth) / 2;
  194. var remPx = parseInt(getComputedStyle(document.documentElement).fontSize);
  195. if (left + toTopBtn.offsetWidth + 2 * remPx < document.body.clientWidth) {
  196. toTopBtn.style.removeProperty('right');
  197. toTopBtn.style.left = left.toString() + 'px';
  198. } else {
  199. toTopBtn.style.removeProperty('left');
  200. toTopBtn.style.right = '2rem';
  201. }
  202. }
  203. window.onresize = setToTopBtnXPos;
  204. setToTopBtnXPos();
  205.  
  206. window.onscroll = function() {
  207. if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
  208. toTopBtn.style.opacity = '1';
  209. } else {
  210. toTopBtn.style.opacity = '0';
  211. }
  212. };
  213.  
  214. function topFunction() {
  215. window.scrollTo({ top: 0, behavior: 'smooth' });
  216. }
  217. toTopBtn.onclick = topFunction;
  218.  
  219. var style4toTopBtn = document.createElement('style');
  220. style4toTopBtn.textContent = '\
  221. @media only screen and (max-width: 732px) {\
  222. button#to_top_btn {\
  223. display: none;\
  224. }\
  225. ';
  226. document.head.appendChild(style4toTopBtn);
  227. tlEditor.appendChild(toTopBtn);
  228.  
  229. // 'copy title' button
  230. var copyTip = document.createElement('small');
  231. copyTip.textContent = '[Click to copy this title]';
  232. copyTip.style.backgroundColor = 'lightgray';
  233. copyTip.style.position = 'absolute';
  234. copyTip.style.right = '0px';
  235. copyTip.style.bottom = '0px';
  236. copyTip.style.fontSize = '1rem';
  237. copyTip.style.fontWeight = 'normal';
  238. copyTip.style.color = 'gray';
  239. copyTip.style.lineHeight = '1rem';
  240. copyTip.style.padding = '0.1rem';
  241. pageTitle.title = 'Click to copy this title'
  242. pageTitle.style.position = 'relative';
  243. pageTitle.addEventListener('mouseover', function(event) {
  244. this.style.backgroundColor = 'lightgray';
  245. copyTip.style.display = 'block';
  246. if (pageTitle.getElementsByTagName('small').length > 0) {
  247. copyTip.textContent = '[Click to copy this title]';
  248. } else {
  249. pageTitle.appendChild(copyTip);
  250. }
  251. });
  252. pageTitle.addEventListener('mouseout', function(event) {
  253. this.style.backgroundColor = null;
  254. copyTip.style.display = 'none';
  255. });
  256. pageTitle.addEventListener('mousedown', function(event) {
  257. this.style.backgroundColor = 'darkgray';
  258. copyTip.style.backgroundColor = 'darkgray';
  259. });
  260. pageTitle.addEventListener('mouseup', function(event) {
  261. this.style.backgroundColor = 'lightgray';
  262. copyTip.style.backgroundColor = 'lightgray';
  263. });
  264. pageTitle.onclick = function() {
  265. GM_setClipboard(pageTitle.textContent.replace('[Click to copy this title]', '').replace('[Copied]', '').replace(/ - Page \d+$/, ''), 'text');
  266. copyTip.textContent = '[Copied]';
  267. };
  268. })();