自定义标签页标题

为任意URL永久设置一个自定义的标签页标题,并强制保持,即使网站动态修改标题。

// ==UserScript==
// @name         自定义标签页标题
// @namespace    http://tampermonkey.net/
// @version      1.3
// @description  为任意URL永久设置一个自定义的标签页标题,并强制保持,即使网站动态修改标题。
// @description:en Permanently set a custom tab title for any URL and force it to stay, even if the site dynamically changes the title.
// @author       yorhaha
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_registerMenuCommand
// @run-at       document-start
// @license MIT
// ==/UserScript==

(async function() {
    'use strict';

    // 关键改动:判断当前脚本是否在顶层窗口运行,如果是在iframe中则直接退出。
    // This is the key fix: check if we are in the top window. If in an iframe, exit.
    if (window.self !== window.top) {
        return;
    }

    const currentUrl = window.location.href;
    let customTitle = await GM_getValue(currentUrl);
    let observer = null;

    // 强制设置并保持标题的函数
    const forceTitle = (title) => {
        // 如果观察者已存在,先断开,避免在自己修改标题时触发死循环
        if (observer) {
            observer.disconnect();
        }

        document.title = title;

        // 创建或重新配置 MutationObserver 来监视标题变化
        const titleElement = document.querySelector('head > title');
        if (titleElement) {
            observer = new MutationObserver((mutations) => {
                // 如果检测到标题被外部脚本修改,则强制改回来
                if (document.title !== title) {
                    console.log(`[Custom Title] 网站尝试将标题修改为 "${document.title}",已恢复为 "${title}"`);
                    document.title = title;
                }
            });
            // 监视 <title> 元素的子节点(即文本内容)的变化
            observer.observe(titleElement, { childList: true });
        }
    };

    // 1. 页面加载时,检查并应用已保存的自定义标题
    if (customTitle) {
        console.log(`[Custom Title] 已加载自定义标题: "${customTitle}"`);
        // 使用 DOMContentLoaded 事件确保 <head> 和 <title> 元素已加载
        window.addEventListener('DOMContentLoaded', (event) => {
            forceTitle(customTitle);
        });
        // 对于某些单页应用,可能需要更早或更晚地执行,@run-at document-start 配合 DOMContentLoaded 是一个比较稳妥的方案
        forceTitle(customTitle); // 立即尝试设置一次
    }

    // 2. 注册(不可用)菜单命令:设置/修改标题
    GM_registerMenuCommand('设置/修改当前页标题', async () => {
        const newTitle = prompt('请输入当前页面的新标题:', document.title);

        // 如果用户输入了内容并且没有取消
        if (newTitle !== null && newTitle.trim() !== '') {
            customTitle = newTitle.trim();
            await GM_setValue(currentUrl, customTitle);
            console.log(`[Custom Title] 已为当前URL设置新标题: "${customTitle}"`);
            forceTitle(customTitle); // 立即应用并开始监视
            alert(`标题已成功设置为: "${customTitle}"`);
        } else if (newTitle !== null) {
            alert('标题不能为空,操作已取消。');
        }
    });

    // 3. 注册(不可用)菜单命令:恢复默认标题
    GM_registerMenuCommand('恢复当前页默认标题', async () => {
        if (await GM_getValue(currentUrl)) {
            if (confirm('确定要删除该页面的自定义标题并恢复默认吗?页面将会刷新。')) {
                await GM_deleteValue(currentUrl);
                if (observer) {
                    observer.disconnect(); // 停止监视
                }
                console.log('[Custom Title] 已删除当前URL的自定义标题,页面将刷新。');
                alert('自定义标题已删除,页面将重新加载以恢复原始标题。');
                window.location.reload();
            }
        } else {
            alert('当前页面没有设置自定义标题。');
        }
    });
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址