您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
拦截并修改上传文件名
// ==UserScript== // @name 文件上传改名脚本 - Perplexity专用 // @namespace http://tampermonkey.net/ // @version 2.1 // @description 拦截并修改上传文件名 // @author You // @match https://www.perplexity.ai/* // @run-at document-start // @grant unsafeWindow // @grant GM_setValue // @grant GM_getValue // @license GPL-3.0 // ==/UserScript== (function() { 'use strict'; // 可维护的文件后缀名库配置 const FILE_EXTENSIONS = { programming: [ 'java', 'py', 'js', 'ts', 'cpp', 'c', 'h', 'hpp', 'cs', 'php', 'rb', 'go', 'rs', 'swift', 'kt', 'scala', 'sh', 'bat', 'ps1', 'pl', 'r', 'sql', 'html', 'css', 'jsx', 'tsx', 'vue', 'svelte' ], config: [ 'json', 'xml', 'yaml', 'yml', 'toml', 'ini', 'conf', 'properties', 'env', 'dockerfile' ], scripts: [ 'lua', 'vim', 'awk', 'sed' ] }; let controlButton = null; let configPanel = null; let observer = null; // 获取所有需要处理的后缀名 function getAllExtensions() { const allExtensions = []; Object.values(FILE_EXTENSIONS).forEach(category => { allExtensions.push(...category); }); return allExtensions; } // 检查文件是否需要改名 function shouldRenameFile(filename) { const extension = filename.split('.').pop().toLowerCase(); return getAllExtensions().includes(extension); } // 生成新文件名 function generateNewFilename(originalName) { const parts = originalName.split('.'); const extension = parts.pop(); const baseName = parts.join('.'); return `${baseName}_${extension}.txt`; } // 检查按钮是否存在 function isButtonExists() { return document.getElementById('file-rename-toggle') !== null; } // 检查面板是否存在 function isPanelExists() { return document.getElementById('file-rename-config') !== null; } // 创建配置面板 function createConfigPanel() { // 如果已存在则不重复创建 if (isPanelExists()) return; const panel = document.createElement('div'); panel.id = 'file-rename-config'; panel.style.cssText = ` position: fixed !important; top: 70px !important; right: 20px !important; width: 300px !important; background: #fff !important; border: 2px solid #007bff !important; border-radius: 8px !important; padding: 15px !important; box-shadow: 0 4px 12px rgba(0,0,0,0.15) !important; z-index: 999999 !important; font-family: Arial, sans-serif !important; font-size: 14px !important; display: none !important; `; panel.innerHTML = ` <div style="margin-bottom: 10px; font-weight: bold; color: #007bff;"> 文件改名脚本配置 <button id="close-config" style="float: right; background: none; border: none; font-size: 16px; cursor: pointer;">×</button> </div> <div style="margin-bottom: 10px;"> <label>当前支持的文件类型:</label> <div id="extension-list" style="max-height: 150px; overflow-y: auto; border: 1px solid #ddd; padding: 5px; margin-top: 5px;"> ${getAllExtensions().map(ext => `<span style="display: inline-block; background: #e9ecef; padding: 2px 6px; margin: 2px; border-radius: 3px;">.${ext}</span>`).join('')} </div> </div> <div style="margin-bottom: 10px;"> <label for="new-extension">添加新后缀名:</label> <input type="text" id="new-extension" placeholder="例如: jsx" style="width: 100%; padding: 5px; margin-top: 5px;"> <button id="add-extension" style="width: 100%; padding: 5px; margin-top: 5px; background: #007bff; color: white; border: none; border-radius: 3px; cursor: pointer;">添加</button> </div> <div style="text-align: center; font-size: 12px; color: #666;"> 脚本状态: <span id="script-status" style="color: #28a745;">运行中</span> </div> `; document.body.appendChild(panel); configPanel = panel; // 绑定事件 const closeBtn = panel.querySelector('#close-config'); if (closeBtn) { closeBtn.onclick = () => { panel.style.display = 'none'; }; } const addBtn = panel.querySelector('#add-extension'); if (addBtn) { addBtn.onclick = () => { const input = panel.querySelector('#new-extension'); const newExt = input.value.trim().toLowerCase(); if (newExt && !getAllExtensions().includes(newExt)) { FILE_EXTENSIONS.programming.push(newExt); input.value = ''; updateExtensionList(); console.log(`已添加新后缀名: .${newExt}`); } }; } function updateExtensionList() { const listDiv = panel.querySelector('#extension-list'); if (listDiv) { listDiv.innerHTML = getAllExtensions().map(ext => `<span style="display: inline-block; background: #e9ecef; padding: 2px 6px; margin: 2px; border-radius: 3px;">.${ext}</span>` ).join(''); } } } // 创建控制按钮 function createControlButton() { // 如果已存在则不重复创建 if (isButtonExists()) return; const button = document.createElement('div'); button.id = 'file-rename-toggle'; button.innerHTML = '📁'; button.title = '文件改名脚本配置'; button.style.cssText = ` position: fixed !important; top: 20px !important; right: 20px !important; width: 40px !important; height: 40px !important; background: #007bff !important; color: white !important; border: none !important; border-radius: 50% !important; cursor: pointer !important; z-index: 999999 !important; font-size: 16px !important; box-shadow: 0 2px 8px rgba(0,0,0,0.2) !important; display: flex !important; align-items: center !important; justify-content: center !important; user-select: none !important; `; button.onclick = () => { if (!isPanelExists()) { createConfigPanel(); } const panel = document.getElementById('file-rename-config'); if (panel) { panel.style.display = panel.style.display === 'none' ? 'block' : 'none'; } }; document.body.appendChild(button); controlButton = button; } // 使用MutationObserver监听DOM变化 function setupDOMObserver() { if (observer) { observer.disconnect(); } observer = new MutationObserver((mutations) => { let needsRecreation = false; mutations.forEach((mutation) => { // 检查是否有节点被移除 if (mutation.type === 'childList') { mutation.removedNodes.forEach((node) => { if (node.nodeType === Node.ELEMENT_NODE) { // 检查我们的按钮或面板是否被移除 if (node.id === 'file-rename-toggle' || node.id === 'file-rename-config' || node.contains && ( node.contains(controlButton) || node.contains(configPanel) )) { needsRecreation = true; } } }); } }); if (needsRecreation || !isButtonExists()) { console.log('检测到按钮丢失,重新创建...'); setTimeout(() => { createControlButton(); createConfigPanel(); }, 100); } }); // 监听整个document的变化 observer.observe(document.body, { childList: true, subtree: true }); } // 定期检查按钮状态 function setupPeriodicCheck() { setInterval(() => { if (!isButtonExists()) { console.log('定期检查发现按钮丢失,重新创建...'); createControlButton(); createConfigPanel(); } }, 2000); // 每2秒检查一次 } // 主要的文件拦截逻辑 function interceptFileUploads() { // 使用事件委托来处理动态添加的文件输入框 document.addEventListener('change', function(event) { if (event.target.type === 'file') { const fileInput = event.target; const files = Array.from(fileInput.files); let hasChanges = false; const newFiles = files.map(file => { if (shouldRenameFile(file.name)) { const newName = generateNewFilename(file.name); console.log(`文件改名: ${file.name} → ${newName}`); hasChanges = true; return new File([file], newName, { type: 'text/plain', lastModified: file.lastModified }); } return file; }); if (hasChanges) { const dt = new DataTransfer(); newFiles.forEach(file => dt.items.add(file)); fileInput.files = dt.files; showNotification('文件已自动改名为.txt格式'); } } }, true); // 拦截FormData const OriginalFormData = unsafeWindow.FormData; unsafeWindow.FormData = function(...args) { const formData = new OriginalFormData(...args); const originalAppend = formData.append; formData.append = function(name, value, filename) { if (value instanceof File && filename && shouldRenameFile(filename)) { const newFilename = generateNewFilename(filename); console.log(`FormData文件改名: ${filename} → ${newFilename}`); return originalAppend.call(this, name, value, newFilename); } return originalAppend.apply(this, arguments); }; return formData; }; } // 显示通知 function showNotification(message) { const notification = document.createElement('div'); notification.style.cssText = ` position: fixed !important; top: 70px !important; right: 20px !important; background: #28a745 !important; color: white !important; padding: 10px 15px !important; border-radius: 5px !important; z-index: 1000000 !important; font-size: 14px !important; box-shadow: 0 2px 8px rgba(0,0,0,0.2) !important; `; notification.textContent = message; document.body.appendChild(notification); setTimeout(() => { if (notification.parentNode) { notification.remove(); } }, 3000); } // 初始化脚本 function init() { console.log('文件上传改名脚本启动中...'); // 创建UI界面 createControlButton(); createConfigPanel(); // 设置DOM监听器 setupDOMObserver(); // 设置定期检查 setupPeriodicCheck(); // 启动文件拦截 interceptFileUploads(); console.log('文件上传改名脚本已启动 - Perplexity专用版'); console.log('支持的文件类型:', getAllExtensions()); } // 等待页面加载 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } // 页面完全加载后再次确保按钮存在 window.addEventListener('load', () => { setTimeout(() => { if (!isButtonExists()) { createControlButton(); createConfigPanel(); } }, 1000); }); })();