NodeSeek Plugin

NodeSeek插件: 图床粘贴

  1. // ==UserScript==
  2. // @name NodeSeek Plugin
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0
  5. // @description NodeSeek插件: 图床粘贴
  6. // @license GPL License
  7. // @author beibiele
  8. // @match https://www.nodeseek.com/*
  9. // @grant GM_xmlhttpRequest
  10. // @grant GM_setClipboard
  11. // @grant GM_registerMenuCommand
  12. // @grant GM_getValue
  13. // @grant GM_setValue
  14. // ==/UserScript==
  15.  
  16. (function() {
  17. 'use strict';
  18.  
  19. // 常量定义
  20. const CONFIG = {
  21. STORAGE_KEY: 'nodeseek_plus_config',
  22. API_LIST: [
  23. {
  24. id: '111666',
  25. name: '111666图床'
  26. },
  27. {
  28. id: 'uhsea',
  29. name: '屋舍图床'
  30. }
  31. ]
  32. };
  33.  
  34. // 默认配置
  35. const defaultConfig = {
  36. apiId: CONFIG.API_LIST[0].id
  37. };
  38.  
  39. // 当前选择的图床 ID(用于缓存)
  40. let currentApiId = null;
  41.  
  42. // 获取当前配置
  43. function getConfig() {
  44. const config = GM_getValue(CONFIG.STORAGE_KEY, defaultConfig);
  45. // 更新缓存
  46. currentApiId = config.apiId;
  47. return config;
  48. }
  49.  
  50. // 保存配置
  51. function saveConfig(config) {
  52. GM_setValue(CONFIG.STORAGE_KEY, config);
  53. // 更新缓存
  54. currentApiId = config.apiId;
  55. }
  56.  
  57. // 显示配置界面
  58. function showConfigDialog() {
  59. const config = getConfig();
  60. const currentApi = CONFIG.API_LIST.find(api => api.id === config.apiId) || CONFIG.API_LIST[0];
  61.  
  62. // 创建对话框
  63. const dialog = document.createElement('div');
  64. dialog.style.cssText = `
  65. position: fixed;
  66. top: 50%;
  67. left: 50%;
  68. transform: translate(-50%, -50%);
  69. background: white;
  70. padding: 20px;
  71. border-radius: 8px;
  72. box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  73. z-index: 10000;
  74. font-family: Arial, sans-serif;
  75. `;
  76.  
  77. // 创建标题
  78. const title = document.createElement('h3');
  79. title.textContent = '选择图床';
  80. title.style.margin = '0 0 15px 0';
  81. dialog.appendChild(title);
  82.  
  83. // 创建下拉选择框
  84. const select = document.createElement('select');
  85. select.style.cssText = `
  86. width: 100%;
  87. padding: 8px;
  88. margin-bottom: 15px;
  89. border: 1px solid #ddd;
  90. border-radius: 4px;
  91. font-size: 14px;
  92. `;
  93.  
  94. // 添加选项
  95. CONFIG.API_LIST.forEach(api => {
  96. const option = document.createElement('option');
  97. option.value = api.id;
  98. option.textContent = api.name;
  99. if (api.id === currentApi.id) {
  100. option.selected = true;
  101. }
  102. select.appendChild(option);
  103. });
  104.  
  105. dialog.appendChild(select);
  106.  
  107. // 创建按钮容器
  108. const buttonContainer = document.createElement('div');
  109. buttonContainer.style.cssText = `
  110. display: flex;
  111. justify-content: flex-end;
  112. gap: 10px;
  113. `;
  114.  
  115. // 创建取消按钮
  116. const cancelButton = document.createElement('button');
  117. cancelButton.textContent = '取消';
  118. cancelButton.style.cssText = `
  119. padding: 8px 15px;
  120. border: 1px solid #ddd;
  121. border-radius: 4px;
  122. background: #f5f5f5;
  123. cursor: pointer;
  124. `;
  125. cancelButton.onclick = () => {
  126. document.body.removeChild(dialog);
  127. document.body.removeChild(overlay);
  128. };
  129.  
  130. // 创建确定按钮
  131. const confirmButton = document.createElement('button');
  132. confirmButton.textContent = '确定';
  133. confirmButton.style.cssText = `
  134. padding: 8px 15px;
  135. border: none;
  136. border-radius: 4px;
  137. background: #4CAF50;
  138. color: white;
  139. cursor: pointer;
  140. `;
  141. confirmButton.onclick = () => {
  142. const newApiId = select.value;
  143. saveConfig({
  144. ...config,
  145. apiId: newApiId
  146. });
  147. const newApi = CONFIG.API_LIST.find(api => api.id === newApiId);
  148. alert(`已切换到:${newApi.name},需要重新复制图片哦~`);
  149. document.body.removeChild(dialog);
  150. document.body.removeChild(overlay);
  151.  
  152. // 重新注册(不可用)菜单命令以更新显示
  153. try {
  154. GM_unregisterMenuCommand("当前图床: " + currentApi.name);
  155. initMonkeyMenu();
  156. } catch (e) {
  157. console.error("无法更新菜单");
  158. }
  159. };
  160.  
  161. buttonContainer.appendChild(cancelButton);
  162. buttonContainer.appendChild(confirmButton);
  163. dialog.appendChild(buttonContainer);
  164.  
  165. // 创建遮罩层
  166. const overlay = document.createElement('div');
  167. overlay.style.cssText = `
  168. position: fixed;
  169. top: 0;
  170. left: 0;
  171. width: 100%;
  172. height: 100%;
  173. background: rgba(0, 0, 0, 0.5);
  174. z-index: 9999;
  175. `;
  176.  
  177. // 添加到页面
  178. document.body.appendChild(overlay);
  179. document.body.appendChild(dialog);
  180. }
  181.  
  182. // 初始化脚本菜单
  183. function initMonkeyMenu() {
  184. try {
  185. const config = getConfig();
  186. const currentApi = CONFIG.API_LIST.find(api => api.id === config.apiId) || CONFIG.API_LIST[0];
  187. GM_registerMenuCommand(`当前图床: ${currentApi.name}`, showConfigDialog);
  188. } catch (e) {
  189. console.error("无法使用Tampermonkey");
  190. }
  191. }
  192.  
  193. // 初始化菜单和配置
  194. initMonkeyMenu();
  195. getConfig(); // 初始化当前图床 ID
  196.  
  197. document.addEventListener('keyup', doc_keyUp, false);
  198. async function doc_keyUp(event) {
  199. if (event.ctrlKey && event.code == "KeyV") {
  200. handlePaste();
  201. }
  202. }
  203.  
  204. async function handlePaste() {
  205. let imageFiles = [];
  206. const clipboardItems = await navigator.clipboard.read();
  207. for (const clipboardItem of clipboardItems) {
  208. for (const type of clipboardItem.types) {
  209. if (type.indexOf('image/') !== -1) {
  210. let blob = await clipboardItem.getType(type);
  211. imageFiles.push(blob);
  212. }
  213. }
  214. }
  215.  
  216. if (imageFiles.length > 0) {
  217. for (let file of imageFiles) {
  218. await uploadToImageHost(file);
  219. }
  220. }
  221. }
  222.  
  223. // 111666图床上传函数
  224. function upload_111666(file) {
  225. const apiUrl = 'https://i.111666.best';
  226. const uploadEndpoint = '/image';
  227.  
  228. return new Promise((resolve, reject) => {
  229. const formData = new FormData();
  230. formData.append('file', file);
  231.  
  232. GM_xmlhttpRequest({
  233. method: 'POST',
  234. url: apiUrl + uploadEndpoint,
  235. data: formData,
  236. headers: {
  237. 'Auth-Token': crypto.randomUUID()
  238. },
  239. onload: (response) => {
  240. let jsonResponse = JSON.parse(response.responseText);
  241. if (response.status === 200 && jsonResponse && jsonResponse.ok) {
  242. insertToEditor(apiUrl + jsonResponse.src);
  243. } else {
  244. mscAlert('图片上传成功,但未获取到Markdown链接');
  245. }
  246. resolve();
  247. },
  248. onerror: (error) => {
  249. mscAlert('图片上传遇到错误,请检查网络或稍后重试。');
  250. reject(error);
  251. }
  252. });
  253. });
  254. }
  255.  
  256. // 屋舍图床上传函数
  257. function upload_uhsea(file) {
  258. const apiUrl = 'https://uhsea.com/Frontend/upload';
  259.  
  260. return new Promise((resolve, reject) => {
  261. const formData = new FormData();
  262. formData.append('file', file);
  263.  
  264. GM_xmlhttpRequest({
  265. method: 'POST',
  266. url: apiUrl,
  267. data: formData,
  268. onload: (response) => {
  269. let jsonResponse = JSON.parse(response.responseText);
  270. if (response.status === 200 && jsonResponse && jsonResponse.data) {
  271. insertToEditor(jsonResponse.data);
  272. } else {
  273. mscAlert('图片上传成功,但未获取到Markdown链接');
  274. }
  275. resolve();
  276. },
  277. onerror: (error) => {
  278. mscAlert('图片上传遇到错误,请检查网络或稍后重试。');
  279. reject(error);
  280. }
  281. });
  282. });
  283. }
  284.  
  285. // 根据当前选择的图床调用对应的上传函数
  286. function uploadToImageHost(file) {
  287. // 使用缓存的图床 ID
  288. const apiId = currentApiId || defaultConfig.apiId;
  289. const apiConfig = CONFIG.API_LIST.find(api => api.id === apiId);
  290.  
  291. // 如果没有找到配置,使用默认图床
  292. if (!apiConfig) {
  293. console.warn('未找到对应的图床配置,使用默认图床');
  294. return upload_111666(file);
  295. }
  296.  
  297. switch (apiConfig.id) {
  298. case '111666':
  299. return upload_111666(file);
  300. case 'uhsea':
  301. return upload_uhsea(file);
  302. default:
  303. console.warn('不支持的图床,使用默认图床');
  304. return upload_111666(file);
  305. }
  306. }
  307.  
  308. function insertToEditor(Link) {
  309. const codeMirrorElement = document.querySelector('.CodeMirror');
  310. if (codeMirrorElement) {
  311. const codeMirrorInstance = codeMirrorElement.CodeMirror;
  312. if (codeMirrorInstance) {
  313. const cursor = codeMirrorInstance.getCursor();
  314. let markdownLink = '![](' + Link + ')';
  315. GM_setClipboard(markdownLink);
  316. codeMirrorInstance.replaceRange(markdownLink + '\n', cursor);
  317. }
  318. }
  319. }
  320. })();

QingJ © 2025

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