Clipboard image upload patch in Bahamut forum

Automatically upload image to Bahamut when you paste images in forum editor.

目前为 2024-02-07 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Clipboard image upload patch in Bahamut forum
  3. // @name:zh-TW 巴哈姆特論壇區剪貼簿圖片上傳補丁
  4. // @namespace https://jtdjdu6868.com/
  5. // @version 1.1
  6. // @description Automatically upload image to Bahamut when you paste images in forum editor.
  7. // @description:zh-TW 在編輯討論區文章時貼上支援的圖片格式,自動上傳至巴哈圖庫
  8. // @author jtdjdu6868
  9. // @match https://forum.gamer.com.tw/post1.php*
  10. // @match https://forum.gamer.com.tw/C.php*
  11. // @icon https://www.google.com/s2/favicons?sz=64&domain=gamer.com.tw
  12. // @grant none
  13. // @run-at document-idle
  14. // @license BY
  15. // ==/UserScript==
  16.  
  17. (function() {
  18. 'use strict';
  19. function pasteHandler(e)
  20. {
  21. const items = (e.clipboardData || e.originalEvent.clipboardData).items;
  22. for(let i = 0; i < items.length; ++i)
  23. {
  24. if("image/gif,image/jpeg,image/png,image/webp".split(",").includes(items[i].type))
  25. {
  26. e.preventDefault();
  27. console.log("paste image");
  28. toastr.info("上傳中...");
  29.  
  30. const blob = items[i].getAsFile();
  31. const bsn = +new URL(window.location.href).searchParams.get("bsn");
  32.  
  33. // get upload token (piccToken)
  34. fetch(`https://api.gamer.com.tw/forum/v1/image_token.php?bsn=${bsn}`, {
  35. credentials: "include",
  36. }).then((res) => res.json()).then((res) => {
  37. if(res.code !== void 0 && res.message || res.error)
  38. {
  39. throw res.message || res.error.message;
  40. }
  41. const piccToken = res.token || res.data.token;
  42. return piccToken;
  43. }).then((piccToken) => {
  44. // pack payload
  45. const payload = new FormData();
  46. payload.append("token", piccToken);
  47. payload.append("dzfile", blob);
  48.  
  49. return payload;
  50. }).then((payload) => {
  51.  
  52. // upload payoad with piccToken
  53. // use xhr because server returns a readablestream, xhr is more simpler
  54. return new Promise((resolve, reject) => {
  55. const xhr = new XMLHttpRequest();
  56. xhr.open("POST", "https://picc.gamer.com.tw/ajax/truth_image_upload.php", true);
  57. xhr.withCredentials = true;
  58. xhr.onload = (e) => {
  59. // return image token
  60. resolve(e.target.responseText);
  61. };
  62.  
  63. const headers = {
  64. "Accept": "application/json",
  65. "Cache-Control": "no-cache",
  66. "X-Requested-With": "XMLHttpRequest"
  67. };
  68. Object.keys(headers).forEach((key) => xhr.setRequestHeader(key, headers[key]));
  69.  
  70. xhr.send(payload);
  71. });
  72. }).then((res) => JSON.parse(res)).then((res) => {
  73. if(res.token === void 0)
  74. {
  75. throw res;
  76. }
  77.  
  78. // get image url by token
  79. return fetch(`https://api.gamer.com.tw/forum/v1/image_upload.php?token=${res.token}&bsn=${bsn}`, {
  80. credentials: "include",
  81. });
  82. }).then((res) => res.json()).then((res) => {
  83. // receive url
  84. if(res.code !== void 0 && res.message || res.error)
  85. {
  86. throw res.message || res.error.message;
  87. }
  88. let urlList = res.data ? res.data.list : res;
  89.  
  90. // extract first url
  91. return urlList[0];
  92. }).then((url) => {
  93. toastr.clear();
  94. toastr.success("上傳成功");
  95. // insert to RTF or source
  96. if(bahaRte.isPlainText)
  97. {
  98. // source
  99. document.execCommand("insertText", false, `[img=${url}]`);
  100. }
  101. else
  102. {
  103. // RTF
  104. bahaRte.doc.execCommand("insertImage", false, url);
  105. }
  106. Forum.Editor.detectThumbnail();
  107. }).catch((err) => {
  108. toastr.clear();
  109. toastr.error(err);
  110. });
  111. }
  112. else if(items[i].type.indexOf('image') === 0)
  113. {
  114. // unsupported image type
  115. toastr.warning("目前巴哈圖庫只支援png, jpg, gif, webp");
  116. e.preventDefault();
  117. }
  118. }
  119. };
  120. // bind event after bahaRte loaded
  121. jQuery(window).on('load', () => {
  122. bahaRte.doc.body.addEventListener("paste", pasteHandler);
  123. document.getElementById("source")?.addEventListener?.("paste", pasteHandler);
  124. });
  125. })();