Extract images for tieba.baidu.com

Adds a button that get all attached images as original size to every post.

当前为 2016-06-22 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Extract images for tieba.baidu.com
  3. // @name:zh 贴吧壁纸收割机
  4. // @namespace https://github.com/cmheia/extract-images-for-tieba
  5. // @description Adds a button that get all attached images as original size to every post.
  6. // @include http://tieba.baidu.com/p/*
  7. // @author cmheia
  8. // @version 0.2.3
  9. // @icon http://tb1.bdstatic.com/tb/favicon.ico
  10. // @grant GM_setClipboard
  11. // @grant GM_xmlhttpRequest
  12. // @license MPL
  13. // ==/UserScript==
  14. (function () {
  15. var $id = function (o) {
  16. return document.getElementById(o);
  17. };
  18.  
  19. // 去重
  20. var doUnique = function (arr) {
  21. var result = [], hash = {};
  22. for (var i = 0, elem; (elem = arr[i]) !== undefined; i++) {
  23. if (!hash[elem]) {
  24. result.push(elem);
  25. hash[elem] = true;
  26. }
  27. }
  28. return result;
  29. };
  30.  
  31. // 插入样式表
  32. var apendStyle = function (cssText) {
  33. var head = document.head || document.getElementsByTagName('head')[0];
  34. var style = document.createElement('style');
  35. style.type = 'text/css';
  36. var textNode = document.createTextNode(cssText);
  37. style.appendChild(textNode);
  38. head.appendChild(style);
  39. };
  40.  
  41. // 创建样式表
  42. var addStyle = function () {
  43. apendStyle(".margin8 {margin:8px;} .preview_item {padding:3px;float:left;position:relative;} .preview_box {max-width:300px;max-height:300px;vertical-align:bottom;} .preview_container {z-index:11000;} .preview_selector {position:absolute;left:0;} .preview_excluded {background:#FFCCFF;}");
  44. };
  45.  
  46. // 取得分页数量
  47. var getPages = function () {
  48. return parseInt(document.getElementsByClassName('l_posts_num')[0].childNodes[3].getElementsByTagName("span")[1].innerText);
  49. };
  50.  
  51. // 取得单个分页原图链接
  52. var extractSinglePage = function (content) {
  53. var imageSrcArray = [];
  54. var regexImageTag = new RegExp(/<img[^<>]*class=\"BDE_Image\"[^<>]*src\=\"((http|https):\/\/)imgsrc\.baidu\.com[\w\d\/\.\-\%\=]*(jpg|jpeg|gif|png|webp)\"([^<>]*)>/, "gi");
  55. var regexImageSrc = new RegExp(/((http|https):\/\/)+(\w+\.)+(\w+)[\w\/\.\-\%\=]*(jpg|jpeg|gif|png|webp)/, "gi");
  56. var regexImageId = new RegExp(/([\w\d]+)\.(jpg|jpeg|gif|png|webp)$/, "gi");
  57. var images = content.match(regexImageTag);
  58. if (null !== images) {
  59. for (var i = 0; i < images.length; i++) {
  60. var currentImageSrc = images[i].match(regexImageSrc);
  61. if (null !== currentImageSrc && 1 === currentImageSrc.length) {
  62. imageSrcArray.push("http://imgsrc.baidu.com/forum/pic/item/" + currentImageSrc[0].match(regexImageId)[0]);
  63. }
  64. }
  65. }
  66.  
  67. var result = doUnique(imageSrcArray);
  68. if (null === result || 0 === result.length) {
  69. return null;
  70. }
  71. return result;
  72. };
  73.  
  74. // 取得所有分页原图链接
  75. var extractAllPages = function (pages, auto) {
  76. var imageSrc = {};
  77. var parsedPages = 0;
  78.  
  79. var parseRespond = function (xhr) {
  80. var currentPage = xhr.finalUrl.replace(/http\:\/\/tieba.baidu.com\/p\/(\d+)\?pn=(\d+)$/, "$2") - 1;
  81. var regexImageTag = new RegExp(/<img[^<>]*class=\"BDE_Image\"[^<>]*src\=\"((http|https):\/\/)imgsrc\.baidu\.com[\w\d\/\.\-\%\=]*(jpg|jpeg|gif|png|webp)\"([^<>]*)>/, "gi");
  82. var regexImageSrc = new RegExp(/((http|https):\/\/)+(\w+\.)+(\w+)[\w\/\.\-\%\=]*(jpg|jpeg|gif|png|webp)/, "gi");
  83. var regexImageId = new RegExp(/([\w\d]+)\.(jpg|jpeg|gif|png|webp)$/, "gi");
  84. var images = xhr.response.match(regexImageTag);
  85.  
  86. imageSrc[currentPage] = [];
  87. if (null !== images) {
  88. for (var i = 0; i < images.length; i++) {
  89. var currentImageSrc = images[i].match(regexImageSrc);
  90. if (null !== currentImageSrc && 1 === currentImageSrc.length) {
  91. imageSrc[currentPage].push("http://imgsrc.baidu.com/forum/pic/item/" + currentImageSrc[0].match(regexImageId)[0]);
  92. }
  93. }
  94. }
  95. parsedPages++;
  96.  
  97. if (pages === parsedPages) {
  98. var imageSrcArray = [];
  99. for (var i = 0; i < pages; i++) {
  100. for (var j = 0; j < imageSrc[i].length; j++) {
  101. imageSrcArray.push(imageSrc[i][j]);
  102. }
  103. }
  104.  
  105. var result = doUnique(imageSrcArray);
  106. if (null === result || 0 === result.length) {
  107. $id("extracted").innerHTML = "然而并没有图片 (╯#-_-)╯~~~~~~~~~~~~~~~~~╧═╧";
  108. } else {
  109. exportAlbum(result, auto);
  110. }
  111. }
  112. };
  113. var xhrErrorHandler = function (xhr) {
  114. parsedPages++;
  115. };
  116.  
  117. for (var i = 1; i <= pages; i++) {
  118. var url = window.location.origin + window.location.pathname + "?pn=" + i;
  119. GM_xmlhttpRequest({
  120. method: 'GET',
  121. url: url,
  122. onload: parseRespond,
  123. onerror: xhrErrorHandler
  124. });
  125. }
  126. };
  127.  
  128. // 仅收割当前分页
  129. var extracterImage = function (auto) {
  130. var message = $id("extracted");
  131. var result = extractSinglePage(document.getElementsByClassName("p_postlist")[0].innerHTML);
  132. if (null !== result && 0 < result.length) {
  133. exportAlbum(result, auto);
  134. } else {
  135. message.innerHTML = "然而并不能收割 (╯#-_-)╯~~~~~~~~~~~~~~~~~╧═╧";
  136. }
  137. };
  138.  
  139. // 收割全部分页
  140. var extracterImages = function (auto) {
  141. var pages = getPages();
  142. var message = $id("extracted");
  143. if (0 === pages) {
  144. message.innerHTML = "度娘又改版了 (╯#-_-)╯~~~~~~~~~~~~~~~~~╧═╧";
  145. } else if (1 === pages) {
  146. var result = extractSinglePage(document.getElementsByClassName("p_postlist")[0].innerHTML);
  147. if (null !== result && 0 < result.length) {
  148. exportAlbum(result, auto);
  149. } else {
  150. message.innerHTML = "然而并不能收割 (╯#-_-)╯~~~~~~~~~~~~~~~~~╧═╧";
  151. }
  152. } else {
  153. extractAllPages(pages, auto);
  154. message.innerHTML = "正在搞这 " + pages + " 页图,不要急嘛 (๑•̀_•́๑)";
  155. }
  156. };
  157.  
  158. // 新建图集
  159. var exportAlbum = function (images, auto) {
  160. if (null === images || 0 === images.length) {
  161. return;
  162. }
  163. var imageCount = images.length;
  164.  
  165. if (auto) {
  166. GM_setClipboard(images.join("\r\n"));
  167. $id("extracted").innerHTML = "搞到这" + imageCount + "张图啦 (⺻▽⺻ )";
  168. return;
  169. }
  170.  
  171. // 删除图集
  172. var removeAlbum = function () {
  173. if (null !== $id("preview_window")) {
  174. document.body.removeChild($id("preview_window"));
  175. }
  176. $id("extracted").innerHTML = "";
  177. };
  178.  
  179. // 恢复被隐藏的元素
  180. var showOtherElements = function (imags) {
  181. for (var i = 0; i < document.body.childNodes.length; i++) {
  182. if ("DIV" === document.body.childNodes[i].tagName && "y" === document.body.childNodes[i].getAttribute("data-hide")) {
  183. document.body.childNodes[i].style.display = "";
  184. }
  185. }
  186. document.getElementsByClassName("tbui_aside_float_bar")[0].style.display = "";
  187. };
  188.  
  189. // 隐藏无关元素
  190. var hideOtherElements = function () {
  191. for (var i = 0; i < document.body.childNodes.length; i++) {
  192. if ("DIV" === document.body.childNodes[i].tagName && "com_userbar_message" !== document.body.childNodes[i].id) {
  193. document.body.childNodes[i].style.display = "none";
  194. document.body.childNodes[i].setAttribute("data-hide", "y");
  195. }
  196. }
  197. document.getElementsByClassName("tbui_aside_float_bar")[0].style.display = "none";
  198. };
  199.  
  200. // 导出选中图片链接
  201. var exportSelected = function () {
  202. var items = $id("preview_list");
  203. var counts = items.childNodes.length;
  204. var result = [];
  205. for (var i = 0; i < counts; i++) {
  206. if (items.childNodes[i].childNodes[1].checked) {
  207. result.push(items.childNodes[i].childNodes[0].src);
  208. }
  209. }
  210. if (0 < result.length) {
  211. GM_setClipboard(result.join("\r\n"));
  212. $id("export_msg").innerHTML = "搞到这" + result.length + "张图啦 (⺻▽⺻ )";
  213. } else {
  214. $id("export_msg").innerHTML = "至少选择一张图吧 ◔ ‸◔?";
  215. }
  216. };
  217.  
  218. // 关闭图片墙
  219. var closePreviewWindow = function () {
  220. showOtherElements();
  221. $id("preview_window").style.display = "none";
  222. };
  223.  
  224. // 选中全部图片
  225. var previewSelectAll = function () {
  226. var items = $id("preview_list");
  227. var counts = items.childNodes.length;
  228. var result = [];
  229. for (var i = 0; i < counts; i++) {
  230. items.childNodes[i].childNodes[1].checked = true;
  231. items.childNodes[i].className = "preview_item";
  232. }
  233. $id("previewer_selected").innerHTML = counts;
  234. };
  235.  
  236. // 反选
  237. var previewSelectInvert = function () {
  238. var items = $id("preview_list");
  239. var counts = items.childNodes.length;
  240. var result = [];
  241. for (var i = 0; i < counts; i++) {
  242. items.childNodes[i].childNodes[1].checked = !items.childNodes[i].childNodes[1].checked;
  243. items.childNodes[i].className = (items.childNodes[i].childNodes[1].checked)? "preview_item": "preview_item preview_excluded";
  244. }
  245. $id("previewer_selected").innerHTML = counts - parseInt($id("previewer_selected").innerHTML);
  246. };
  247.  
  248. // 点击图片切换选中状态
  249. var previewSelector = function (o) {
  250. o.nextSibling.checked = !o.nextSibling.checked;
  251. var selected = $id("previewer_selected");
  252. selected.innerHTML = parseInt(selected.innerHTML) + ((o.nextSibling.checked === true)? 1: -1);
  253. if (o.nextSibling.checked) {
  254. o.parentNode.className = "preview_item";
  255. } else {
  256. o.parentNode.className = "preview_item preview_excluded";
  257. }
  258. };
  259.  
  260. // 创建控制栏
  261. var controller = document.createElement('div');
  262. controller.id = "previewer_ctrl";
  263. controller.style = "position:relative";
  264.  
  265. var info = document.createElement('span');
  266. info.id = "previewer_info";
  267. info.className = "margin8";
  268. info.innerHTML = "共<span class='red'>" + imageCount + "</span>图,已选<span id='previewer_selected' class='red'>" + imageCount + "</span>图";
  269. controller.appendChild(info);
  270.  
  271. var buttonClose = document.createElement('a');
  272. buttonClose.href = "javascript:;";
  273. buttonClose.className = "margin8";
  274. buttonClose.innerHTML = "关闭图片墙";
  275. buttonClose.addEventListener("click", closePreviewWindow);
  276. controller.appendChild(buttonClose);
  277.  
  278. var buttonSelectAll = document.createElement('a');
  279. buttonSelectAll.href = "javascript:;";
  280. buttonSelectAll.className = "margin8";
  281. buttonSelectAll.innerHTML = "全选";
  282. buttonSelectAll.addEventListener("click", previewSelectAll);
  283. controller.appendChild(buttonSelectAll);
  284.  
  285. var buttonInvert = document.createElement('a');
  286. buttonInvert.href = "javascript:;";
  287. buttonInvert.className = "margin8";
  288. buttonInvert.innerHTML = "反选";
  289. buttonInvert.addEventListener("click", previewSelectInvert);
  290. controller.appendChild(buttonInvert);
  291.  
  292. var buttonExportSelected = document.createElement('a');
  293. buttonExportSelected.href = "javascript:;";
  294. buttonExportSelected.className = "margin8";
  295. buttonExportSelected.innerHTML = "导出选定图片";
  296. buttonExportSelected.addEventListener("click", exportSelected);
  297. controller.appendChild(buttonExportSelected);
  298.  
  299. var message = document.createElement('span');
  300. message.id = "export_msg";
  301. message.className = "margin8";
  302. controller.appendChild(message);
  303.  
  304. // 创建图片列表
  305. var itemList = document.createElement('ul');
  306. itemList.id = "preview_list";
  307.  
  308. var previewer = document.createElement('div');
  309. previewer.id = "preview_matrix";
  310. previewer.appendChild(itemList);
  311.  
  312. for (var i = 0; i < imageCount; i++) {
  313. var item = document.createElement('li');
  314. item.innerHTML = "<img id='" + "preview_img_" + i + "' class='preview_box' src='" + images[i] + "'><input type='checkbox' id='" + "preview_cb_" + i + "' class='preview_selector' checked='checked'>";
  315. item.className = "preview_item";
  316. item.childNodes[0].addEventListener("click", function () {
  317. previewSelector(this);
  318. });
  319. itemList.appendChild(item);
  320. }
  321.  
  322. // 删除旧的图片墙
  323. removeAlbum();
  324. var container = document.createElement('div');
  325. container.id = "preview_window";
  326. container.className = "preview_container";
  327. container.appendChild(controller);
  328. container.appendChild(previewer);
  329. hideOtherElements();
  330. document.body.appendChild(container);
  331.  
  332. var button = document.createElement('a');
  333. button.href = "javascript:;";
  334. button.innerHTML = "打开图片墙";
  335. button.addEventListener("click", function () {
  336. hideOtherElements();
  337. $id("preview_window").style.display = "";
  338. });
  339. $id("extracted").appendChild(button);
  340. };
  341.  
  342. // 添加按钮
  343. var addButton = function () {
  344. var button = document.createElement('li');
  345. button.innerHTML="<a href='javascript:;' class='margin8'>收割</a><span id='extracted'></span>";
  346. button.class = "l_reply_num";
  347. button.childNodes[0].addEventListener("click", function () {
  348. extracterImages(false);
  349. });
  350. document.addEventListener("keydown", function (event) {
  351. // F9 = 120
  352. // F10 = 121
  353. if (120 === event.keyCode) {
  354. extracterImage(true);
  355. } else if (121 === event.keyCode) {
  356. extracterImages(true);
  357. }
  358. }, true);
  359. document.getElementsByClassName('l_posts_num')[0].appendChild(button);
  360. };
  361.  
  362. // 运行
  363. addStyle();
  364. addButton();
  365. }) ();