您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a button to upload any source files to Grok by renaming them to .txt so they are accepted.
当前为
// ==UserScript== // @name Grok Source File Uploader // @namespace https://gf.qytechs.cn/users/your-username // @version 1.2 // @description Adds a button to upload any source files to Grok by renaming them to .txt so they are accepted. // @author Moore // @match *://x.com/i/grok* // @match *://*.x.com/i/grok* // @grant none // @run-at document-idle // @license MIT // ==/UserScript== (function () { 'use strict'; function log(msg) { console.log(`[GrokUploader] ${msg}`); } function addCustomStyles() { const style = document.createElement("style"); style.textContent = ` /* Try to match full hover behavior of native Grok media button */ .custom-upload-btn:hover { background-color: rgba(182, 185, 188, 0.1) !important; border-radius: 9999px !important; } .custom-upload-btn:focus-visible { outline: 2px solid rgba(29, 155, 240, 0.5) !important; } .custom-upload-btn { transition: background-color 0.2s ease-in-out; } `; document.head.appendChild(style); //log("🎨 Custom hover styles injected."); } function injectUploadButton() { const mediaBtn = document.querySelector('button[aria-label="Media"]'); if (!mediaBtn) { //log("❌ Media button not found."); return false; } if (document.getElementById('custom-grok-upload-wrapper')) { //log("✅ Upload button already injected."); return true; } //log("✅ Found Media button. Proceeding to clone."); const wrapperDiv = document.createElement("div"); wrapperDiv.className = mediaBtn.parentElement.className; wrapperDiv.id = "custom-grok-upload-wrapper"; const customBtn = mediaBtn.cloneNode(true); customBtn.id = "custom-grok-upload"; customBtn.classList.add("custom-upload-btn"); customBtn.setAttribute("aria-label", "Upload source files"); // Inherit all original classes while keeping ours customBtn.classList.add(...mediaBtn.classList); customBtn.style.cssText = mediaBtn.style.cssText; const originalSvg = mediaBtn.querySelector("svg"); const svgClass = originalSvg?.getAttribute("class") || ""; const svgStyle = originalSvg?.getAttribute("style") || getComputedStyle(originalSvg)?.color || ""; customBtn.querySelector("svg").outerHTML = ` <svg viewBox="0 0 24 24" aria-hidden="true" class="${svgClass}" style="color: ${svgStyle};"> <g> <path d="M5 20h14v-2H5v2zm7-18L5.33 9h3.17v4h4.99v-4h3.17L12 2z"></path> </g> </svg> `; const fileInput = document.createElement("input"); fileInput.type = "file"; fileInput.accept = "*/*"; fileInput.multiple = true; fileInput.style.display = "none"; customBtn.addEventListener("click", () => { //log("📂 File input clicked."); fileInput.click(); }); fileInput.addEventListener("change", async (e) => { //log(`📁 Selected ${e.target.files.length} file(s).`); const files = Array.from(e.target.files); if (files.length === 0) return; const nativeInput = document.querySelector('input[type="file"]'); if (!nativeInput) { //log("❌ Native Grok file input not found."); alert("Grok file input not found. Try clicking the 📎 icon manually once first."); return; } const dt = new DataTransfer(); for (const file of files) { const content = await file.text(); const renamedFile = new File( [new Blob([content], { type: "text/plain" })], file.name.replace(/\.[^/.]+$/, "") + ".txt", { type: "text/plain" } ); dt.items.add(renamedFile); //log(`📦 Converted ${file.name} → ${renamedFile.name}`); } nativeInput.files = dt.files; nativeInput.dispatchEvent(new Event("change", { bubbles: true })); //log("✅ Injected files into native Grok file input."); fileInput.value = ""; }); wrapperDiv.appendChild(customBtn); document.body.appendChild(fileInput); mediaBtn.parentElement.parentElement.insertBefore(wrapperDiv, mediaBtn.parentElement); //log("🚀 Upload button injected next to original."); return true; } function waitForMediaButton(timeout = 10000, interval = 500) { const start = Date.now(); const intervalId = setInterval(() => { const success = injectUploadButton(); if (success) { //log("🎯 Injection succeeded."); clearInterval(intervalId); } else if (Date.now() - start > timeout) { //log("⏱️ Timeout reached. Giving up injection."); clearInterval(intervalId); } }, interval); } addCustomStyles(); waitForMediaButton(); const observer = new MutationObserver(() => { //log("👀 DOM mutated. Retrying injection."); injectUploadButton(); }); observer.observe(document.body, { childList: true, subtree: true }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址