TOOLS为非官方社区,欢迎一起建设,答疑群:717421103

版本260427.1

全站通知:

油猴工具/图片粘贴上传BWIKI

阅读

    

2026-04-27更新

    

最新编辑:WIKI不易猫猫叹气

阅读:

  

更新日期:2026-04-27

  

最新编辑:WIKI不易猫猫叹气

来自ToolsWIKI_BWIKI_哔哩哔哩
跳到导航 跳到搜索
页面贡献者 :
WIKI不易猫猫叹气
油猴工具/图片粘贴上传BWIKI
小工具稳定
自动上传你在bwiki原生编辑器里粘贴的图片,并直接插入[[File:文件名]]代码。
  1. 支持:PNG、JPEG、GIF和WebP
  2. 有单文件最大限制(可配置)
  3. 获取API令牌并生成时间戳文件名
作者
WIKI不易猫猫叹气
系列油猴工具
版本1.0.0

// ==UserScript==
// @name         MediaWiki图片粘贴上传工具
// @namespace    http://tampermonkey.net/
// @version      1.0.2
// @description  自动上传粘贴到MediaWiki编辑器的图片
// @author       You
// @match        *://wiki.biligame.com/*
// @match        *://*.biligame.com/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // 轮询检查mw变量是否存在
    const timer = setInterval(() => {
        if (window.mw && typeof window.mw === 'object') {
            clearInterval(timer);
            console.log('✅ MediaWiki已加载,开始初始化图片上传脚本');
            initImageUploader();
        }
    }, 300);

    // 配置
    const CONFIG = {
        SUPPORTED_TYPES: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'],
        MAX_SIZE: 10 * 1024 * 1024, // 10MB
        NAMING_PREFIX: 'Paste_'
    };

    // 工具函数
    const Utils = {
        // 获取编辑器元素
        getEditorElement() {
            // 优先查找CodeMirror编辑器
            const codeMirrorEditable = document.querySelector('.CodeMirror-code[contenteditable="true"]');
            if (codeMirrorEditable) return codeMirrorEditable;

            // 查找标准textarea
            const textarea = document.querySelector('#wpTextbox1');
            if (textarea) return textarea;

            // 查找其他可能的编辑器
            const codeMirror = document.querySelector('.CodeMirror-code');
            if (codeMirror) return codeMirror;

            return null;
        },

        // 获取API URL
        getApiUrl() {
            const server = mw.config.get('wgServer');
            const scriptPath = mw.config.get('wgScriptPath');
            return server + scriptPath + '/api.php';
        },

        // 生成文件名
        generateFileName(originalName) {
            const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
            const extension = originalName.split('.').pop() || 'png';
            return `${CONFIG.NAMING_PREFIX}${timestamp}.${extension}`;
        },

        // 检查文件类型
        isValidImageType(type) {
            return CONFIG.SUPPORTED_TYPES.includes(type);
        },

        // 检查文件大小
        isValidSize(size) {
            return size <= CONFIG.MAX_SIZE;
        }
    };

    // 图片上传器
    const ImageUploader = {
        // 获取CSRF令牌
        async getCsrfToken() {
            const response = await fetch(Utils.getApiUrl(), {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                },
                body: new URLSearchParams({
                    action: 'query',
                    meta: 'tokens',
                    type: 'csrf',
                    format: 'json'
                })
            });

            const data = await response.json();
            return data.query.tokens.csrftoken;
        },

        // 上传图片
        async uploadImage(file) {
            const token = await this.getCsrfToken();
            const fileName = Utils.generateFileName(file.name);

            const formData = new FormData();
            formData.append('action', 'upload');
            formData.append('filename', fileName);
            formData.append('file', file);
            formData.append('token', token);
            formData.append('format', 'json');
            formData.append('ignorewarnings', '1');

            const response = await fetch(Utils.getApiUrl(), {
                method: 'POST',
                body: formData
            });

            const data = await response.json();

            if (data.upload && data.upload.result === 'Success') {
                return {
                    success: true,
                    filename: data.upload.filename,
                    url: data.upload.imageinfo.url
                };
            } else {
                const errorMsg = data.error ? data.error.info : '未知错误';
                throw new Error('上传失败: ' + errorMsg);
            }
        }
    };

    // 粘贴处理器
    const PasteHandler = {
        // 处理粘贴事件
        async handlePaste(event) {
            const clipboardData = event.clipboardData;
            if (!clipboardData) return;

            const items = Array.from(clipboardData.items);

            for (const item of items) {
                if (item.kind === 'file' && item.type.startsWith('image/')) {
                    const file = item.getAsFile();
                    if (!file) continue;

                    // 验证文件
                    if (!Utils.isValidImageType(file.type) || !Utils.isValidSize(file.size)) {
                        continue;
                    }

                    // 阻止默认粘贴行为
                    event.preventDefault();
                    event.stopPropagation();
                    event.stopImmediatePropagation();

                    try {
                        const result = await ImageUploader.uploadImage(file);
                        if (result.success) {
                            this.insertImageCode(result.filename);
                        }
                    } catch (error) {
                        console.error('图片上传失败:', error);
                        alert('图片上传失败: ' + error.message);
                    }
                }
            }
        },

        // 插入图片代码
        insertImageCode(filename) {
            const editor = Utils.getEditorElement();
            if (!editor) return;

            const imageCode = `[[File:${filename}]]`;

            if (editor.tagName === 'TEXTAREA') {
                // 标准textarea
                const start = editor.selectionStart;
                const end = editor.selectionEnd;
                const text = editor.value;
                editor.value = text.substring(0, start) + imageCode + text.substring(end);
                editor.selectionStart = editor.selectionEnd = start + imageCode.length;
            } else {
                // CodeMirror或其他编辑器
                const selection = window.getSelection();
                if (selection.rangeCount > 0) {
                    const range = selection.getRangeAt(0);
                    range.deleteContents();
                    range.insertNode(document.createTextNode(imageCode));
                    range.collapse(false);
                    selection.removeAllRanges();
                    selection.addRange(range);
                }
            }

            // 触发input事件
            editor.dispatchEvent(new Event('input', { bubbles: true }));
        },

        // 初始化
        init() {
            const editor = Utils.getEditorElement();
            if (!editor) return;

            // 绑定粘贴事件(使用capture模式)
            const boundHandler = this.handlePaste.bind(this);
            editor.removeEventListener('paste', boundHandler);
            editor.addEventListener('paste', boundHandler, true);

            // 同时在document上监听作为备用
            document.removeEventListener('paste', boundHandler);
            document.addEventListener('paste', boundHandler, true);
        }
    };

    // 初始化图片上传器
    function initImageUploader() {
        console.log('开始初始化图片上传器...');
        PasteHandler.init();
        console.log('✅ 图片上传器初始化完成');
    }

})();