您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在禁止保存内容的Telegram私密频道中允许复制文字。
// ==UserScript== // @name Telegram Text Copier // @name:en Telegram Text Copier // @name:tr Telegram Metin Kopyalama // @name:zh-CN Telegram 文字复制器 // @name:zh-TW Telegram 文字複製器 // @name:ru Telegram: Копирование текста // @version 1.0 // @namespace https://github.com/ibryapici/telegram-text-copier // @description Telegram web uygulamasında içeriğin kaydedilmesini kısıtlayan özel kanallardan metin kopyalamayı etkinleştirir. // @description:en Enables text copying on the Telegram webapp from private channels that restrict saving content. // @description:ru Позволяет копировать текст в веб-приложении Telegram из частных каналов, которые ограничивают сохранение контента. // @description:zh-CN 在禁止保存内容的Telegram私密频道中允许复制文字。 // @description:zh-TW 在禁止儲存內容的 Telegram 私密頻道中允許複製文字。 // @author İbrahim Yapıcı & Cursor // @license GNU GPLv3 // @website https://github.com/ibryapici/telegram-text-copier // @match https://web.telegram.org/* // @match https://webk.telegram.org/* // @match https://webz.telegram.org/* // @icon https://img.icons8.com/material-outlined/48/copy.png // ==/UserScript== (function () { const logger = { info: (message) => { console.log(`[Tel Copier] ${message}`); }, error: (message) => { console.error(`[Tel Copier] ${message}`); }, }; const COPY_ICON_K = "\uE94D"; const REFRESH_DELAY = 500; let lastRightClickedMessageText = null; const tel_copy_text = (text, button) => { navigator.clipboard.writeText(text).then( () => { logger.info("Text copied to clipboard"); const originalText = button.textContent; button.textContent = "Copied!"; setTimeout(() => { button.textContent = originalText; }, 1500); }, (err) => logger.error("Failed to copy text: " + err) ); }; // --- Main Logic --- const setupCopyListeners = (messageEl, textEl) => { messageEl.addEventListener("contextmenu", () => { lastRightClickedMessageText = textEl ? textEl.innerText : null; }); }; const addHoverCopyButtonZ = (messageEl, textEl) => { const bubble = messageEl.querySelector(".bubble"); if (!bubble) return; const copyButton = document.createElement("button"); copyButton.className = "Button tiny secondary round tel-copy-button"; copyButton.innerHTML = '<i class="icon icon-copy"></i>'; Object.assign(copyButton.style, { position: "absolute", right: "5px", bottom: "5px", zIndex: 100, opacity: 0, transition: "opacity 0.2s", }); copyButton.onclick = (e) => { e.preventDefault(); e.stopPropagation(); tel_copy_text(textEl.innerText, copyButton); }; bubble.style.position = "relative"; bubble.append(copyButton); bubble.addEventListener("mouseover", () => { copyButton.style.opacity = "1"; }); bubble.addEventListener("mouseout", () => { copyButton.style.opacity = "0"; }); }; const addHoverCopyButtonK = (bubble, textEl) => { const copyButton = document.createElement("button"); copyButton.className = "btn-icon tel-copy-button"; copyButton.innerHTML = `<span class="tgico button-icon">${COPY_ICON_K}</span>`; Object.assign(copyButton.style, { opacity: 0, transition: "opacity 0.2s" }); copyButton.onclick = (e) => { e.stopPropagation(); e.preventDefault(); tel_copy_text(textEl.innerText, copyButton); }; const dateContainer = bubble.querySelector(".message-date, .time"); if (dateContainer) { dateContainer.prepend(copyButton); bubble.addEventListener("mouseover", () => { copyButton.style.opacity = "1"; }); bubble.addEventListener("mouseout", () => { copyButton.style.opacity = "0"; }); } }; const addContextMenuCopyButton = (menuEl, buttonClass, iconHtml, text) => { const copyButton = document.createElement("button"); copyButton.className = buttonClass; copyButton.innerHTML = `${iconHtml}<span class="i18n btn-menu-item-text">${text}</span>`; copyButton.onclick = (e) => { e.stopPropagation(); tel_copy_text( lastRightClickedMessageText, copyButton.querySelector(".i18n") ); menuEl.remove(); }; const itemsContainer = menuEl.querySelector(".btn-menu-items") || menuEl; itemsContainer.appendChild(copyButton); }; // App-Z (/a/) Specific Logic setInterval(() => { // Messages document .querySelectorAll(".message-list .message:not(._tel_processed)") .forEach((message) => { message.classList.add("_tel_processed"); const textEl = message.querySelector( ".text-content, .translatable-message" ); if (textEl && textEl.innerText.trim()) { setupCopyListeners(message, textEl); addHoverCopyButtonZ(message, textEl); } }); // Context Menu const contextMenuA = document.querySelector( ".ContextMenu:not(._tel_processed)" ); if (contextMenuA && lastRightClickedMessageText) { contextMenuA.classList.add("_tel_processed"); addContextMenuCopyButton( contextMenuA, "context-menu-item", '<i class="icon icon-copy"></i>', "Copy Text" ); } }, REFRESH_DELAY); // App-K (/k/) Specific Logic setInterval(() => { // Messages document .querySelectorAll(".bubble:not(._tel_processed)") .forEach((bubble) => { bubble.classList.add("_tel_processed"); const textEl = bubble.querySelector( ".message .text-content, .message .translatable-message" ); if (textEl && textEl.innerText.trim()) { setupCopyListeners(bubble, textEl); addHoverCopyButtonK(bubble, textEl); } }); // Context Menu const contextMenuK = document.querySelector( "#bubble-contextmenu:not(._tel_processed)" ); if (contextMenuK && lastRightClickedMessageText) { contextMenuK.classList.add("_tel_processed"); addContextMenuCopyButton( contextMenuK, "btn-menu-item rp-overflow", `<span class="tgico btn-menu-item-icon">${COPY_ICON_K}</span>`, "Copy Text" ); } }, REFRESH_DELAY); logger.info("Text Copier script loaded."); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址