|
立刻注册账号,享受更清爽的界面!
您需要 登录 才可以下载或查看,没有账号?注册
×
但是这个脚本不支持hostloc,然后由于是油猴脚本都是js.所以用GPT帮忙改了下. 现在能支持hostloc了. 其它类似hostloc 的discuz bbs 理论也能用.你们自己添加// @match 匹配url 页面试试. 我只测试了hostloc.

下一次更新 希望看能不能搞上imgur免费图床.个人还是觉得imgur非常稳定的.
- // ==UserScript==
- // @name 奶昔论坛 编辑器增强
- // @namespace https://forum.naixi.net/
- // @version 0.1.00
- // @description 为 奶昔论坛 编辑器增加图片上传功能
- // @author Zhiyang
- // @match *://forum.naixi.net/*
- // @icon https://forum.naixi.net/static/image/common/logo.svg
- // @grant GM_xmlhttpRequest
- // @license MPL-2.0 License
- // @supportURL https://forum.naixi.net/thread-2295-1-1.html
- // @homepageURL https://forum.naixi.net/thread-2295-1-1.html
- // ==/UserScript==
- /**
- *
- *
- * 当前版本更新日志
- * 0.0.11 - 2024.12.18 !!!更新前注意备份您的配置!!!
- * - 新增 支持 HOSTLOC
- * 0.0.11 - 2024.10.05 !!!更新前注意备份您的配置!!!
- * - 新增 支持 0-RTT/telegraph 项目
- */
- (function () {
- 'use strict';
- // 图床配置, 默认提供的是这位大佬的 https://www.nodeseek.com/post-38305-1 , 这个图床上传限制 5p / IP / 小时
- // 当 type 为 LskyPro 时以下所有配置项均有用, 为 Chevereto 时 url 和 token 有用, 为 Telegraph / EasyImages 时只有 url 有用
- // Telegraph 官网 https://telegra.ph/ 在大陆被阻断, 可以使用 https://github.com/cf-pages/Telegraph-Image 提供的服务或者自己部署
- // Telegraph2 by @Xiefengshang 使用的是 https://github.com/0-RTT/telegraph 项目(个人考虑到其缓存做的更好所以使用)
- // EasyImages 官网 https://png.cm/ 限制单 ip 每天上传 3 张, 项目地址 https://github.com/icret/EasyImages2.0, 这个图床真烂, 两套接口不统一下, 文档也不写几句话
- const imgHost = {
- type: "Telegraph2", // 图床类型, 支持 LskyPro / Telegraph / Telegraph2 / Chevereto / EasyImages
- url: "https://pic.j8.work", // 图床地址, 带上协议头
- token: null, // 图床 token, 可选, 不填则为游客上传, LskyPro 在 /user/tokens 生成, Chevereto 必填, 在 /settings/api 生成, EasyImages 填写则使用后端接口上传, 不填写则使用前端接口上传
- storageId: null, // 图床存储策略ID, 可选项, 不填则为默认策略, 普通用户可在上传页抓包得到, 管理员可以在后台看到
- };
- const mdImgName = 0; // 0(非 Telegraph): 使用图床返回的原始名称, 其他值则名称固定为该值
- const submitByKey = true; // 是否按下 Ctrl+Enter 后触发发帖动作
- // 页面加载完毕后载入功能
- window.addEventListener('load', initEditorEnhancer, false);
- function initEditorEnhancer() {
- // 监听粘贴事件
- document.addEventListener('paste', (event) => handlePasteEvt(event));
- // 给编辑器绑定拖拽事件
- var dropZone = document.getElementById('code-mirror-editor') || document.getElementById('postbox');
- // 阻止默认行为
- dropZone.addEventListener('dragover', function (e) {
- e.preventDefault();
- e.stopPropagation();
- e.dataTransfer.dropEffect = 'copy'; // 显示为复制图标
- });
- // 处理文件拖放
- dropZone.addEventListener('drop', function (e) {
- e.preventDefault();
- e.stopPropagation();
- log('正在处理拖放内容...');
- let imageFiles = [];
- for (let file of e.dataTransfer.files) {
- if (/^image\//i.test(file.type)) { // 确保只处理图片文件
- imageFiles.push(file);
- log(`拖放的文件名: ${file.name}`);
- }
- }
- log(`拖放的图片数量: ${imageFiles.length}`);
- if (imageFiles.length === 0) {
- log('你拖放的内容好像没有图片哦', 'red');
- return;
- }
- // 调整uploadImage函数以接受File对象数组而不是DataTransferItemList
- uploadImage(imageFiles.map(file => {
- return {
- kind: 'file',
- type: file.type,
- getAsFile: () => file
- };
- }));
- });
- // 修改图片按钮的行为
- // 图片按钮
- let checkExist = setInterval(function () {
- const oldElement = document.querySelector('.toolbar-item.i-icon.i-icon-pic[title="图片"]');
- if (oldElement) {
- clearInterval(checkExist);
- const newElement = oldElement.cloneNode(true);
- oldElement.parentNode.replaceChild(newElement, oldElement);
- newElement.addEventListener('click', handleImgBtnClick);
- }
- }, 200);
- // 监听 Ctrl+Enter 快捷键
- if (submitByKey)
- document.addEventListener('keydown', function (event) {
- if (event.ctrlKey && event.key === 'Enter') {
- // 获取按钮元素
- const button = document.querySelector('.submit.btn');
- // 触发点击事件
- button.click();
- }
- });
- }
- // 粘贴事件处理
- function handlePasteEvt(event) {
- log('正在处理粘贴内容...');
- const items = (event.clipboardData || event.originalEvent.clipboardData).items;
- if (items.length === 0) {
- log('你粘贴的内容好像没有图片哦', 'red');
- return;
- }
- uploadImage(items)
- }
- // 图片按钮点击事件处理
- function handleImgBtnClick() {
- // 创建一个隐藏的文件输入元素
- const input = document.createElement('input');
- input.type = 'file';
- input.multiple = true; // 允许多选文件
- input.accept = 'image/*'; // 仅接受图片文件
- // 当文件被选择后的处理
- input.onchange = e => {
- const files = e.target.files; // 获取用户选择的文件列表
- if (files.length) {
- const items = [...files].map(file => ({
- kind: 'file',
- type: file.type,
- getAsFile: () => file
- }));
- uploadImage(items);
- }
- };
- // 触发文件输入框的点击事件,打开文件选择窗口
- input.click();
- }
- // 处理并上传图片
- async function uploadImage(items) {
- let imageFiles = [];
- for (let item of items) {
- if (item.kind === 'file' && item.type.indexOf('image/') !== -1) {
- let blob = item.getAsFile();
- imageFiles.push(blob);
- }
- }
- if (imageFiles.length > 0) {
- event.preventDefault();
- for (let i = 0; i < imageFiles.length; i++) {
- if (imageFiles.length > 1)
- log(`上传第 ${i + 1} / ${imageFiles.length} 张图片...`);
- else
- log(`上传图片...`);
- let file = imageFiles[i];
- let formData = new FormData();
- formData.append('file', file);
- if (imgHost.type === 'LskyPro') {
- if (imgHost.storageId) formData.append('strategy_id', imgHost.storageId);
- await uploadToLsky(formData);
- } else if (imgHost.type === 'Telegraph') {
- await uploadToTelegraph(formData);
- } else if (imgHost.type === 'Telegraph2') {
- await uploadToTelegraph2(formData);
- } else if (imgHost.type === 'Chevereto') {
- await uploadToChevereto(file);
- } else if (imgHost.type === 'EasyImages') {
- await uploadToEasyImages(file);
- } else {
- log(`暂不支持的图床类型: ${imgHost.type}, 取消上传`, 'red');
- return;
- }
- }
- } else {
- log('你粘贴的内容好像没有图片哦', 'red');
- }
- }
- async function uploadToLsky(formData) {
- return new Promise((resolve, reject) => {
- let headers = {
- 'Accept': 'application/json'
- };
- if (imgHost.token)
- headers['Authorization'] = `Bearer ${imgHost.token}`;
- GM_xmlhttpRequest({
- method: 'POST',
- url: `${imgHost.url}/api/v1/upload`,
- headers: headers,
- data: formData,
- onload: (rsp) => {
- let rspJson = JSON.parse(rsp.responseText);
- if (rsp.status !== 200) {
- log(`图片上传失败: ${rsp.status} ${rsp.statusText}`, 'red');
- reject(rspJson.message);
- }
- if (rspJson.status === true) {
- // 图片上传成功
- if (rspJson?.data?.links?.markdown)
- insertToEditor(mdImgName === 0 ? rspJson.data.links.markdown : ``);
- else {
- log('图片上传成功, 但接口返回有误, 原始返回已粘贴到编辑器', 'red');
- insertToEditor(`图片上传成功, 但接口返回有误: ${JSON.stringify(rspJson)})`);
- }
- } else
- log(`图片上传失败: ${rspJson.message}`, 'red');
- resolve();
- },
- onerror: (error) => {
- log(`图片上传失败: ${error.status} ${error.statusText}`, 'red');
- reject(error);
- }
- });
- });
- }
- async function uploadToTelegraph(formData) {
- return new Promise((resolve, reject) => {
- GM_xmlhttpRequest({
- method: 'POST',
- url: `${imgHost.url}/upload`,
- data: formData,
- onload: (rsp) => {
- let rspJson = JSON.parse(rsp.responseText);
- rspJson = rspJson[0];
- if (rsp.status !== 200) {
- log(`图片上传失败: ${rsp.status} ${rsp.statusText}`, 'red');
- reject(rspJson.message);
- }
- if (rspJson) {
- // 图片上传成功
- if (rspJson?.src)
- insertToEditor(``);
- else {
- log('图片上传成功, 但接口返回有误, 原始返回已粘贴到编辑器', 'red');
- insertToEditor(`图片上传成功, 但接口返回有误: ${JSON.stringify(rspJson)})`);
- }
- } else
- log(`图片上传失败: ${JSON.stringify(rspJson)}`, 'red');
- resolve();
- },
- onerror: (error) => {
- log(`图片上传失败: ${error.status} ${error.statusText}`, 'red');
- reject(error);
- }
- });
- });
- }
- async function uploadToTelegraph2(formData) {
- return new Promise((resolve, reject) => {
- GM_xmlhttpRequest({
- method: 'POST',
- url: `${imgHost.url}/upload`,
- data: formData,
- onload: (rsp) => {
- let rspJson = JSON.parse(rsp.responseText);
- if (rsp.status !== 200 || !rspJson || !rspJson.data) {
- log(`图片上传失败: ${rsp.status} ${rsp.statusText}`, 'red');
- reject(rspJson?.message || '图片上传失败,缺少 data 字段');
- }
- const result = rspJson.data;
- // 图片上传成功
- if (result) {
- insertToCursor(`${result}`, `${mdImgName}`);
- log('图片上传成功', 'green');
- resolve(result);
- } else {
- log('图片上传成功, 但接口返回有误, 原始返回已粘贴到编辑器', 'red');
- insertToCursor(null, null, `图片上传成功, 但接口返回有误: ${JSON.stringify(rspJson)}`)
- resolve();
- }
- },
- onerror: (error) => {
- log(`图片上传失败: ${error.status} ${error.statusText}`, 'red');
- reject(error);
- }
- });
- });
- }
- async function uploadToChevereto(file) {
- return new Promise((resolve, reject) => {
- let headers = {
- 'Accept': 'application/json'
- };
- if (!imgHost.token) {
- log('Chevereto 图床需配置 token', 'red');
- reject('Chevereto 图床需要 token, 请填写 token 后重试');
- return;
- }
- headers['X-API-Key'] = imgHost.token;
- let formData = new FormData();
- formData.append('source', file);
- GM_xmlhttpRequest({
- method: 'POST',
- url: `${imgHost.url}/api/1/upload`,
- headers: headers,
- data: formData,
- onload: (rsp) => {
- let rspJson = JSON.parse(rsp.responseText);
- if (rsp.status !== 200) {
- log(`图片上传失败: ${rsp.status} ${rsp.statusText}`, 'red');
- reject(rspJson?.success?.message || rspJson?.error?.message);
- }
- if (rspJson.status_code === 200) {
- // 图片上传成功
- let imgUrl = rspJson.image.url || rspJson.image.url_viewer || rspJson.image.url_short;
- if (imgUrl)
- insertToEditor(mdImgName === 0 ? `` : ``);
- else {
- log('图片上传成功, 但接口返回有误, 原始返回已粘贴到编辑器', 'red');
- insertToEditor(`图片上传成功, 但接口返回有误: ${JSON.stringify(rspJson)})`);
- }
- } else
- log(`图片上传失败: ${rspJson?.success?.message || rspJson?.error?.message}`, 'red');
- resolve();
- },
- onerror: (error) => {
- log(`图片上传失败: ${error.status} ${error.statusText}`, 'red');
- reject(error);
- }
- });
- });
- }
- async function uploadToEasyImages(file) {
- return new Promise((resolve, reject) => {
- let url = imgHost.url;
- let formData = new FormData();
- if (imgHost.token) {
- // 带token, 使用后端接口上传
- url += '/api/index.php'
- formData.append('token', imgHost.token);
- formData.append('image', file);
- } else {
- // 不带token, 使用前端接口上传
- url += '/app/upload.php'
- formData.append('file', file);
- // 十位时间戳作为sign
- formData.append('sign', Math.floor(Date.now() / 1000));
- }
- GM_xmlhttpRequest({
- method: 'POST',
- url: url,
- data: formData,
- onload: (rsp) => {
- let rspJson = JSON.parse(rsp.responseText);
- if (rsp.status !== 200) {
- log(`图片上传失败: ${rsp.status} ${rsp.statusText}`, 'red');
- reject(rspJson.result);
- }
- if (rspJson.code === 200) {
- // 图片上传成功
- if (rspJson?.url)
- insertToEditor(``);
- else {
- log('图片上传成功, 但接口返回有误, 原始返回已粘贴到编辑器', 'red');
- insertToEditor(`图片上传成功, 但接口返回有误: ${JSON.stringify(rspJson)})`);
- }
- } else
- log(`图片上传失败: ${JSON.stringify(rspJson)}`, 'red');
- resolve();
- },
- onerror: (error) => {
- log(`图片上传失败: ${error.status} ${error.statusText}`, 'red');
- reject(error);
- }
- });
- });
- }
- function insertToCursor(sourceUrl, sourceName, errorString) {
- const codeMirrorElement = document.querySelector('.CodeMirror');
- const discuzEditorTextarea = document.querySelector('#e_textarea');
- if (codeMirrorElement) { // nodeseek 使用markdown语法
- const fullLink = ``
- const codeMirrorInstance = codeMirrorElement.CodeMirror;
- if (codeMirrorInstance) {
- const cursor = codeMirrorInstance.getCursor();
- codeMirrorInstance.replaceRange(`\n${fullLink} \n`, cursor);
- }
- } else if (discuzEditorTextarea) { //discuz 使用 BBS code语法
- const fullLink = `[img]${sourceUrl}[/img]`
- const cursorPosition = discuzEditorTextarea.selectionStart; // 获取光标位置
- const textBefore = discuzEditorTextarea.value.substring(0, cursorPosition); // 光标前的文本
- const textAfter = discuzEditorTextarea.value.substring(cursorPosition); // 光标后的文本
- const markdownLink = fullLink; // 你要插入的内容
- discuzEditorTextarea.value = `${textBefore}${markdownLink}${textAfter}`; // 拼接插入的文本
- // 更新光标位置到插入文本的末尾
- discuzEditorTextarea.selectionStart = discuzEditorTextarea.selectionEnd = cursorPosition + markdownLink.length;
- // 让光标保持在文本框中
- discuzEditorTextarea.focus();
- } else {
- log('出现错误: 未找到编辑栏', 'red');
- }
- }
- function insertToEditor(fullLink, sourceName, sourceUrl) {
- const codeMirrorElement = document.querySelector('.CodeMirror');
- if (codeMirrorElement) { // nodeseek 使用markdown语法
- // nodeseek 还是用老逻辑 完整链接
- const codeMirrorInstance = codeMirrorElement.CodeMirror;
- if (codeMirrorInstance) {
- const cursor = codeMirrorInstance.getCursor();
- codeMirrorInstance.replaceRange(`\n${fullLink} \n`, cursor);
- }
- }
- if (fullLink.startsWith('!['))
- log('图片已插入到编辑器~', 'green');
- }
- // 在编辑器打印日志
- function log(message, color = '') {
- if (!document.getElementById('editor-enhance-logs')) {
- initEditorLogDiv();
- }
- const logDiv = document.getElementById('editor-enhance-logs');
- logDiv.innerHTML = `<div${color ? ` style="color: ${color};` : ''}"> ${message} </div>`;
- console.log(`[NodeSeek-Editor-Enhance] ${message}`);
- }
- // 初始化显示日志的容器
- function initEditorLogDiv() {
- const logDiv = document.createElement('div');
- logDiv.id = 'editor-enhance-logs';
- logDiv.innerHTML = '';
- document.body.appendChild(logDiv);
- const editorToolbarDiv = document.querySelector('.mde-toolbar') || document.querySelector('#e_controls');
- editorToolbarDiv.appendChild(logDiv);
- }
- })();
复制代码 |
|