Custom Title

【使用前先看介绍/有问题可反馈】自定义标题 (Custom Title): 支持自定义标题

Du musst eine Erweiterung wie Tampermonkey, Greasemonkey oder Violentmonkey installieren, um dieses Skript zu installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey oder Violentmonkey installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey oder Violentmonkey installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey oder Userscripts installieren.

Um dieses Skript zu installieren, müssen Sie eine Erweiterung wie Tampermonkey installieren.

Sie müssten eine Skript Manager Erweiterung installieren damit sie dieses Skript installieren können

(Ich habe schon ein Skript Manager, Lass mich es installieren!)

Um dieses Design zu installieren, müssen Sie eine Erweiterung wie Stylus installieren.

Um dieses Design zu installieren, müssen Sie eine Erweiterung wie Stylus installieren.

Um dieses Design zu installieren, müssen Sie eine Erweiterung wie Stylus installieren.

Um diesen Stil zu installieren, müssen Sie eine Erweiterung für den Benutzerstil Verwaltung installieren.

Um diesen Stil zu installieren, müssen Sie eine Erweiterung für den Benutzerstil Verwaltung installieren.

Um diesen Stil zu installieren, müssen Sie eine Erweiterung für den Benutzerstil Verwaltung installieren.

(Ich habe bereits einen Benutzerstil Verwaltung, ich möchte ihn installieren!)

// ==UserScript==
// @name         Custom Title
// @namespace    http://tampermonkey.net/
// @version      1.0.0
// @description  【使用前先看介绍/有问题可反馈】自定义标题 (Custom Title): 支持自定义标题
// @author       cc
// @include      *
// @license      MIT
// @grant        GM_setValue
// @grant        GM_getValue
// ==/UserScript==

(function() {
    'use strict';

    // storage
    let storage;
    const _VERSION_ = '1.0.0';
    const focusKey = 'KeyT';            // T
    const clearKey = 'Digit1';          // 1
    const expiredTime = 30 * 86400 * 1000;      // 30 day
    const interval = 86400 * 1000;      // 1 day

    function notify(msg) {
        console.log(`%c${msg}`, 'background-color: yellow; color: black;');
    }

    function getDefaultStorage() {
        return {
            lastUpdateTime: new Date().getTime(),
            titleInfoDict: {},
        }
    }

    function loadStorage() {
        storage = GM_getValue('storage');
        if (!storage) {
            storage = getDefaultStorage();
            GM_setValue('storage', storage);
            notify('[Custom Title]: storage initialized');
            console.log(storage);
        } else {
            notify('[Custom Title]: storage down here');
            console.log(storage);
            clearExpiredTitle();
        }
    }

    function applyTitle() {
        let titleInfo = storage.titleInfoDict[location.href];
        if (titleInfo && document.title !== titleInfo.newTitle) {
            document.title = titleInfo.newTitle;
            notify('[Custom Title]: applied title');
        } else if (titleInfo) {
            notify('[Custom Title]: no need to replace title');
        } else {
            notify('[Custom Title]: no title can be appied');
        }
    }

    // functions
    function updateTitle() {
        let titleInfo = storage.titleInfoDict[location.href];
        let newTitle = prompt('请输入需要为此网页自定义的标题,可通过 \'Ctrl+Shift+T\' 或直接输入空以取消:', titleInfo ? titleInfo.newTitle : document.title);
        if (newTitle) {
            storage.titleInfoDict[location.href] = {
                oldTitle: titleInfo ? titleInfo.oldTitle : document.title,
                newTitle: newTitle,
                lastUpdateTime: new Date().getTime(),
            };
            document.title = newTitle;
            GM_setValue('storage', storage);
            notify('[Custom Title]: updated title');
        } else if (newTitle !== null && newTitle.constructor === String) {
            removeTitle();
        }
    }

    function removeTitle() {
        let titleInfo = storage.titleInfoDict[location.href];
        if (titleInfo) {
            let res = confirm('是否为此网页移除自定义标题?');
            if (res) {
                document.title = titleInfo.oldTitle;
                delete storage.titleInfoDict[location.href];
                GM_setValue('storage', storage);
                notify('[Custom Title]: removed title');
            }
        } else {
            alert('你还未为此网页设置自定义标题');
        }
    }

    function removeAllTitles() {
        let res = confirm('是否清除所有自定义标题?');
        if (res) {
            let titleInfo = storage.titleInfoDict[location.href];
            if (titleInfo) {
                document.title = titleInfo.oldTitle;
            }
            storage = getDefaultStorage();
            GM_setValue('storage', storage);
            alert('已清除所有自定义标题');
            notify('[Custom Title]: removed all titles');
        }
    }

    function clearExpiredTitle() {
        let currentTime = new Date().getTime();
        if (storage.lastUpdateTime + interval < currentTime) {
            let titleInfoDict = storage.titleInfoDict;
            for (let key of Object.keys(titleInfoDict)) {
                if (titleInfoDict[key].lastUpdateTime + expiredTime < currentTime) {
                    delete titleInfoDict[key];
                }
            }
            storage.titleInfoDict = titleInfoDict;
            storage.lastUpdateTime = currentTime;
            GM_setValue('storage', storage);
            notify('[Custom Title]: cleared expired titles');
        }
    }

    function bindObserver() {
        // key observer
        document.onkeydown = function(e) {
            console.log(e);

            if (e.ctrlKey && e.shiftKey && e.code == focusKey) {
                e.preventDefault();
                removeTitle();
                notify('[Custom Title]: trigger remove title');
            } else if (e.ctrlKey && e.code == focusKey) {
                e.preventDefault();
                updateTitle();
                notify('[Custom Title]: trigger update title');
            } else if (e.ctrlKey && e.code == clearKey) {
                e.preventDefault();
                removeAllTitles();
                notify('[Custom Title]: trigger remove all titles');
            }
        }
        // title observer
        let title = document.querySelector('title');
        let observer = new MutationObserver(function(mutations) {
            console.log(mutations);
            applyTitle();
            notify('[Custom Title]: trigger title change event');
        });
        let config = { subtree: true, characterData: true, childList: true };
        observer.observe(title, config);

        // hash observer
        window.onhashchange = function() {
            applyTitle();
            notify('[Custom Title]: trigger hash change event');
        };

        // call apply again
        applyTitle();
    }

    // main function
    document.onreadystatechange = function() {
        if (document.readyState === 'complete') {
            notify(`[Custom Title]: version ${_VERSION_}`);
            loadStorage();
            applyTitle();
            bindObserver();
        }
    }
})();