您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Allow Hamster Kombat to run on Telegram Web and optionally open it in a new tab.
// ==UserScript== // @name Hamster Kombat Desktop // @namespace https://violentmonkey.github.io // @version 1.1.0 // @description Allow Hamster Kombat to run on Telegram Web and optionally open it in a new tab. // @author limbonux // @match https://web.telegram.org/* // @license GPLv3 // @grant none // @icon https://hamsterkombat.io/images/icons/hamster-coin.png // @run-at document-end // ==/UserScript== /** * @typedef {Object} FragmentObject * @property {string} tgWebAppData - The authentication data for the Telegram web app. * @property {("android"|"android_x"|"ios")} tgWebAppPlatform - The current platform of the Telegram web app. * @property {string} tgWebAppThemeParams - The theme parameters for the Telegram web app. * @property {string} tgWebAppVersion - The version of the Telegram web app. */ (() => { "use strict"; /** * Parse the URL fragment into an object. * @param {string} fragment - The URL fragment. * @returns {FragmentObject} The parsed fragment object. */ const parseFragment = (fragment) => Object.fromEntries(new URLSearchParams(fragment).entries()); /** * Serialize the object into a URL fragment string. * @param {FragmentObject} obj - The object to serialize. * @returns {string} The serialized fragment string. */ const serializeFragment = (obj) => new URLSearchParams(obj).toString(); /** * Get the icon content from the icon code. * @param {string} icon - The icon code. * @returns {string} The icon content. */ const getIconContent = (icon) => String.fromCharCode(Number.parseInt(icon, 16)); /** * Handle adding the menu item for version A. * @param {URL} url - The URL to be opened in a new tab. */ const addMenuItemVersionA = (url) => { const menu = document.querySelector(".modal-header .menu-container"); if (!menu || menu.querySelector(".new-menu-item")) return; const menuItem = ` <div class="MenuItem compact new-menu-item" role="menuitem" tabindex="0"> <i class="icon icon-open-in-new-tab"></i> Open in New Tab </div> `; menu.insertAdjacentHTML("beforeend", menuItem); menu.lastElementChild.addEventListener("click", () => window.open(url.href, "_blank")); }; /** * Handle adding the menu item for version K. * @param {URL} url - The URL to be opened in a new tab. */ const addMenuItemVersionK = (url) => { const menuToggleButton = document.querySelector(".popup-header .btn-icon.rp.btn-menu-toggle"); if (!menuToggleButton) return; // Add menu item on menu icon click because the dropdown is dynamically created. menuToggleButton.addEventListener("click", () => { const menu = document.querySelector(".popup-header .btn-menu"); if (!menu || menu.querySelector(".new-menu-item")) return; const menuItem = ` <div class="btn-menu-item rp-overflow new-menu-item"> <span class="tgico btn-menu-item-icon">${getIconContent("e9a3")}</span> <span class="i18n btn-menu-item-text">Open in New Tab</span> </div> `; menu.insertAdjacentHTML("beforeend", menuItem); menu.lastElementChild.addEventListener("click", () => window.open(url.href, "_blank")); }); }; /** * Add a new menu item to open the iframe URL in a new tab. * @param {URL} url - The URL to open in a new tab. */ const addOpenInNewTabMenuItem = (url) => { if (location.pathname.startsWith("/a/")) { addMenuItemVersionA(url); } else if (location.pathname.startsWith("/k/")) { addMenuItemVersionK(url); } }; /** * Manipulate the iframe src to allow running the web app on Telegram Web. * @param {HTMLIFrameElement} iframe - The iframe element. */ const handleIframe = (iframe) => { if (!iframe) return; const url = new URL(iframe.src); const fragmentObject = parseFragment(url.hash.substring(1)); fragmentObject.tgWebAppPlatform = "android"; delete fragmentObject.tgWebAppThemeParams; // Remove unnecessary parameter. url.hash = serializeFragment(fragmentObject); iframe.src = url.href; addOpenInNewTabMenuItem(url); }; /** * Handle mutations and process the iframe for the web app popup. * @param {MutationRecord[]} mutations - List of mutations observed. */ const mutationCallback = (mutations) => { for (const { addedNodes, target } of mutations) { if (addedNodes.length !== 1) continue; if (target.id === "portals" || addedNodes[0].classList.contains("popup-web-app")) { const iframe = target.querySelector("iframe"); handleIframe(iframe); } } }; // Set up MutationObserver to monitor for relevant changes. const observer = new MutationObserver(mutationCallback); const parentElement = document.getElementById("portals") || document.body; // Get the parent element for A or K. if (parentElement) { observer.observe(parentElement, { childList: true }); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址