pixelmatorTutorialDownloader

download pixcelmator pro tutorial resouces and youtube videos to local disk

当前为 2023-04-05 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name pixelmatorTutorialDownloader
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.16
  5. // @description download pixcelmator pro tutorial resouces and youtube videos to local disk
  6. // @author mooring@codernote.club
  7. // @match https://www.pixelmator.com/tutorials/*
  8. // @match https://www.pixelmator.com/support/guide/pixelmator-pro/*
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=pixelmator.com
  10. // @run-at document-end
  11. // @grant GM_registerMenuCommand
  12. // @license MIT
  13. // ==/UserScript==
  14.  
  15. let proxy = '';
  16.  
  17. function getCategoryInfo(cmd, collect, init){
  18. let category = document.querySelector('.tutorialsBrowser__categoriesList >.tutorialsBrowser__categoriesItem.is-active').innerText;
  19. let moreless = document.querySelector('.tutorialsBrowser__mainCategoryMore>.tutorialsBrowser__mainCategoryMoreBtn');
  20. let commands = [];
  21. let download = [];
  22. let html = [];
  23. let foldmap = {};
  24. if(!moreless.parentElement.classList.contains('is-inactive')){
  25. moreless.click();
  26. }
  27. if(init){
  28. commands.push(`cls`);
  29. commands.push(`@set proxy=`);
  30. commands.push(`@set proxy=${proxy}`);
  31. commands.push(`@set pxystr=`)
  32. commands.push(`@if "%25proxy%25" == "" @echo.>"%25~dp0assets\\proxy.conf"`);
  33. commands.push(`@if not "%25proxy%25" == "" @echo %25proxy%25>"%25~dp0assets\\proxy.conf"`);
  34. commands.push(`@if not "%25proxy%25" == "" @set pxystr=--proxy "%25proxy%25"`);
  35. commands.push(`@set getpage=%25~dp0..\\bin\\getpage.exe`);
  36. commands.push(`@echo @set down=..\\bin\\yt-dlp --write-thumbnail --embed-metadata --cache-dir cache --write-link -f "bv+ba" --progress %25pxystr%25 --no-playlist --restrict-filenames --write-subs --audio-quality 10 --merge-output-format "mp4" --sub-langs "en-US.*,zh-Hans.*" --convert-thumbnails png --ffmpeg-location ..\\bin ${init?'>':'>>'} %25~dp0${collect||category}_ytb.cmd`);
  37. html.push(`<!doctype html>`);
  38. html.push(`<html lang="en-US">`)
  39. html.push(`<head>`)
  40. html.push(`<meta charset="utf-8"/>`)
  41. html.push(`<title>Pixelmator Pro Tutorial</title>`)
  42. html.push(`<meta name="author" content="mooring@codernote.club"/>`)
  43. html.push(`<meta name="description" content="Pixelmator Pro Tutorial"/>`)
  44. html.push(`<meta name="viewport" content="width=device-width, initial-scale=1"/>`)
  45. html.push(`<style>`);
  46. html.push(`h2.category {width: 80%;display: block;border-bottom: 1px dodgerblue dotted;margin: 0.5em auto;padding-bottom: 0.5em;}`);
  47. html.push(`.items {width: 80%;margin: 0 auto;display: flex;flex-wrap: wrap;justify-content:flex-start}`);
  48. html.push(`.item {width:23.7em;padding:10px}`);
  49. html.push(`.img {width: 100%;height: 13em;cursor:pointer;position:relative;}`);
  50. html.push(`.img:before{display:block;width:3em;height:3em;content:"▶️";border-radius:2em;position:absolute;left:8.6em;top:3.8em;font-size:20px;color:white;text-align:center;line-height:3em;padding:0;margin:0;}`);
  51. html.push(`.title {font-weight:600;cursor:pointer;text-align: center;font-size: 1.2em;padding-bottom: 1em;}`);
  52. html.push(`img.image-x2 {width: 100%;height: 100%;border-radius: 1em;}`);
  53. html.push(`</style>`);
  54. html.push(`<script>`);
  55. html.push(`function viewVideo(evt,url){ var img=new Image(); img.onerror=function(){window.open(url.replace("video.mp4","index.html"))};img.onload=function(){window.open(url)};img.src=url.replace(".mp4",".png");}`);
  56. html.push(`</script></head><body>`);
  57. commands.push(`@echo @echo resource downloader ${init?'>':'>>'} %25~dp0${collect||category}_res.cmd`);
  58. commands.push(`@echo @title %25cd%25 >> %25~dp0${collect||category}_res.cmd`);
  59. commands.push(`@echo @title %25cd%25 >> %25~dp0${collect||category}_ytb.cmd`);
  60. }
  61. commands.push(`@cd %25~dp0`);
  62. commands.push(`@if not exist %25~dp0${category} mkdir %25~dp0${category}`);
  63. commands.push(`@cd %25~dp0${category}`);
  64. let items = document.querySelectorAll('.tutorialsBrowser__mainCategoryList >.tutorialsBrowser__mainItem');
  65. items.forEach((item,index)=>{
  66. let img = item.querySelector('.tutorialsThumbnail__image');
  67. let lnk = item.querySelector('.tutorialsThumbnail__link').href;
  68. let tit = item.querySelector('.tutorialsThumbnail__title').innerText;
  69. let src = 'https:'+img.getAttribute('src').replace(/^https?:/i,'');
  70. let x2 = 'https:'+img.getAttribute('srcset').replace(/^https?:/i,'');
  71. let pth = lnk.split('/').slice(-2,-1)[0];
  72. src = src.split('/');
  73. x2 = x2.split('/');
  74. if(!foldmap[pth]){
  75. foldmap[pth] = 1;
  76. commands.push(`@if not exist "${pth}\\img" mkdir "${pth}\\img"`);
  77. }
  78. if(index == 0){
  79. html.push(`<h2 class="category">${category}</h2><div class="items">`);
  80. }
  81. html.push(`<div class="item">`);
  82. html.push(`<div class="img" onclick="viewVideo(this,'./${category}/${pth}/video.mp4')">`);
  83. html.push(`<img src="./${category}/${pth}/img/${x2.slice(-1)[0].split(' ')[0]}" class="image-x2" />`);
  84. html.push(`</div>`);
  85. html.push(`<div class="title" onclick="window.open('${lnk}','_blank')">${tit}</div>`);
  86. html.push(`</div>`);
  87. let img1 = `${pth}\\img\\${src.slice(-1)[0]}`,
  88. url1 = `${encodeURI(src.join('/')).replace(/%/g,'%%')}`;
  89. commands.push(`@rem downloading ${encodeURI(src.join('/'))}`);
  90. commands.push(`@if not exist "${img1}" @curl -o "${img1}" "${url1}" 2>NUL`);
  91. let img2 = `${pth}\\img\\${x2.slice(-1)[0].split(' ')[0]}`,
  92. url2 = `${encodeURI(x2.join('/').split(' ')[0]).replace(/%/g,'%%')}`;
  93. commands.push(`@rem downloading ${encodeURI(x2.join('/').split(' ')[0])}`);
  94. commands.push(`@if not exist "${img2}" @curl -o "${img2}" "${url2}" 2>NUL`);
  95. commands.push(`@%25getpage%25 "${lnk}" "${category}\\${pth}" "${collect||category}"`);
  96. });
  97. if(items.length>0){
  98. html.push(`</div>`);
  99. }
  100. commands.push('@cd %25~dp0');
  101. if(collect){
  102. return {category, commands, html}
  103. }else{
  104. let content = cmd == 'cmd' ? commands.join("\n") : html.join("\n");
  105. down(cmd, category, content)
  106. }
  107. }
  108.  
  109. function getGuideCmd(){
  110. let guides = document.querySelectorAll('.guides-menu a');
  111. let cmds = [];
  112. let lproxy = localStorage.getItem('pixelmatorTutorialDownloader_proxy');
  113. proxy = prompt("Input proxy string like http://127.0.0.1:8899, if no proxy keep it empty", lproxy || '');
  114. localStorage.setItem('pixelmatorTutorialDownloader_proxy', proxy||'');
  115. cmds.push(`cls`);
  116. cmds.push(`@set proxy=`);
  117. cmds.push(`@set proxy=${proxy}`);
  118. cmds.push(`@set pxystr=`)
  119. cmds.push(`@if "%25proxy%25" == "" @echo.>"%25~dp0assets\\proxy.conf"`);
  120. cmds.push(`@if not "%25proxy%25" == "" @echo %25proxy%25>"%25~dp0assets\\proxy.conf"`);
  121. cmds.push(`@if not "%25proxy%25" == "" @set pxystr=--proxy "%25proxy%25"`);
  122. cmds.push(`@set getpage=%25~dp0..\\bin\\getpage.exe`);
  123. cmds.push(`@if not exist %25~dp0guide mkdir %25~dp0guide`);
  124. for(let i=0,il=guides.length; i<il; i++){
  125. let guide = guides[i];
  126. let match = guide.getAttribute('href').match(/\/pixelmator-pro\/(\d+)/)
  127. if(!guide.parentElement.classList.contains('openable') && match){
  128. cmds.push(`@if not exist "%25~dp0guide\\${match[1]}" mkdir "%25~dp0guide\\${match[1]}\\img"`);
  129. cmds.push(`@cd %25~dp0guide`);
  130. cmds.push([
  131. '@%25getpage%25',
  132. `"${guide.href}"`,
  133. `"guide\\${match[1]}"`,
  134. `"${guide.innerText.replace(/\"/g,'')}"`
  135. ].join(' '));
  136. }
  137. }
  138. down('cmd', 'Guides', cmds.join("\n"))
  139. }
  140. function down(cmd, category, content){
  141. let ele = document.createElement('a');
  142. ele.style.display = 'none';
  143. ele.setAttribute('href', 'data:text/plain;charset=utf-8,' + content);
  144. ele.setAttribute('download', category + '.' + cmd);
  145. document.body.appendChild(ele);
  146. ele.click();
  147. document.body.removeChild(ele);
  148. }
  149. function collect(cmd){
  150. let html = [];
  151. let commands = [];
  152. let cmdfile = 'Resources';
  153. let categories = document.querySelectorAll('.tutorialsBrowser__categoriesItem> .tutorialsBrowser__categoriesLink');
  154. let lproxy = localStorage.getItem('pixelmatorTutorialDownloader_proxy');
  155. if(cmd=='cmd'){
  156. proxy = prompt("Input proxy string like http://127.0.0.1:8899, if no proxy keep it empty", lproxy || '');
  157. localStorage.setItem('pixelmatorTutorialDownloader_proxy', proxy||'');
  158. }
  159. for(let i=0,il=categories.length;i<il;i++){
  160. categories[i].click();
  161. let source = getCategoryInfo(1, cmdfile, i==0);
  162. if(source.html.length>0){
  163. html = html.concat(source.html);
  164. }
  165. commands = commands.concat(source.commands);
  166. }
  167. html.push('</body></html>')
  168. down(cmd, cmdfile,(cmd=='cmd'?commands:html).join("\n"));
  169. }
  170.  
  171. (function() {
  172. 'use strict';
  173. GM_registerMenuCommand("get All Command", function(evt, keybord){
  174. collect('cmd');
  175. });
  176. GM_registerMenuCommand("get All HTML", function(evt, keybord){
  177. collect('html');
  178. });
  179. GM_registerMenuCommand("get Category Command", function(evt, keybord){
  180. let lproxy = localStorage.getItem('pixelmatorTutorialDownloader_proxy');
  181. proxy = prompt("Input proxy string like http://127.0.0.1:8899, if no proxy keep it empty", lproxy || '');
  182. localStorage.setItem('archiveAssistant_proxy', proxy||'');
  183. getCategoryInfo('cmd', false, true);
  184. });
  185. GM_registerMenuCommand("get Category HTML", function(evt, keybord){
  186. getCategoryInfo('html', false, true);
  187. });
  188. GM_registerMenuCommand("get User Guides", function(evt, keybord){
  189. getGuideCmd();
  190. });
  191. })();