Get Old Cnblogs Favicon Back

Replace specific favicon with a old one on cnblogs.

Від 30.08.2025. Дивіться остання версія.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(У мене вже є менеджер скриптів, дайте мені встановити його!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Get Old Cnblogs Favicon Back
// @namespace    http://tampermonkey.net/
// @version      1.1.0
// @description  Replace specific favicon with a old one on cnblogs.
// @author       aspen138
// @icon         https://assets.cnblogs.com/favicon_v3_preview.ico?v=1
// @match        *://*.cnblogs.com/*
// @grant        none
// @run-at       document-start
// @license      MIT
// ==/UserScript==



(function () {
  'use strict';

  // Favicon URLs
  const FAVICON_URL_V3 = 'https://assets.cnblogs.com/favicon_v3_preview.ico?v=1';
  const FAVICON_URL_COMMON = 'https://common.cnblogs.com/favicon.svg';
  const FAVICON_URL_V3P2 = 'https://assets.cnblogs.com/favicon_v3_2.ico';
  const FAVICON_URL_DEFAULT = FAVICON_URL_V3; // Default favicon to use

  // Link mappings for different icon types
  const linkMap = {
    "icon": FAVICON_URL_DEFAULT,
    "shortcut icon": FAVICON_URL_DEFAULT,
    "apple-touch-icon": FAVICON_URL_COMMON, // Use SVG for Apple touch icon
  };

  // Meta tag mappings
  const metaMap = {
    "application-name": "博客园",
    "apple-mobile-web-app-title": "博客园"
  };

  function main() {
    waitForElement("body").then(() => {
      console.log("CNBlogs favicon enhancer: Body loaded, initializing...");
    });

    waitForElement("head").then(() => {
      console.log("CNBlogs favicon enhancer: Head loaded, applying changes...");
      monitorHead();
      monitorTitle();
    });
  }

  // Utility function to wait for elements to load
  async function waitForElement(selector) {
    const el = document.querySelector(selector);
    if (el) return el;

    return new Promise((resolve) => {
      const fn = () => {
        const el2 = document.querySelector(selector);
        if (el2) {
          return resolve(el2);
        }
        requestAnimationFrame(fn);
      };
      requestAnimationFrame(fn);
    });
  }

  // Monitor and update favicon and related elements
  function monitorHead() {
    const sync = () => {
      // Update favicon links
      Object.entries(linkMap).forEach(([rel, targetValue]) => {
        let link = document.querySelector(`link[rel="${rel}"]`);

        // If link doesn't exist, create it
        if (!link) {
          link = document.createElement("link");
          link.rel = rel;
          document.head.appendChild(link);
        }

        // Update href if different
        if (link.getAttribute("href") !== targetValue) {
          link.setAttribute("href", targetValue);
          console.log(`CNBlogs favicon enhancer: Updated ${rel} to ${targetValue}`);
        }
      });

      // Update meta tags
      Object.entries(metaMap).forEach(([name, targetValue]) => {
        let meta = document.querySelector(`meta[name="${name}"]`);

        // If meta doesn't exist, create it
        if (!meta) {
          meta = document.createElement("meta");
          meta.name = name;
          document.head.appendChild(meta);
        }

        // Update content if different
        if (meta.getAttribute("content") !== targetValue) {
          meta.setAttribute("content", targetValue);
          console.log(`CNBlogs favicon enhancer: Updated meta ${name} to ${targetValue}`);
        }
      });

      // Handle notification-based favicon switching (if applicable)
      handleNotificationFavicon();
    };

    // Initial sync
    sync();

    // Monitor for changes
    const mutationObserverOptions = {
      subtree: true,
      characterData: true,
      childList: true,
      attributes: true
    };

    // Re-sync when page visibility changes
    window.addEventListener("visibilitychange", sync);

    // Monitor head for changes
    new MutationObserver(sync).observe(document.head, mutationObserverOptions);

    console.log("CNBlogs favicon enhancer: Monitoring started");
  }

  // Handle notification-based favicon switching
  function handleNotificationFavicon() {
    // Check for notification indicators (adjust selector based on CNBlogs structure)
    const hasNotification = document.querySelector('[class*="notification"], [class*="unread"], .msg-count, [data-count]:not([data-count="0"])');

    if (hasNotification) {
      // Use a different favicon when there are notifications
      const notificationFavicon = FAVICON_URL_V3P2;
      const faviconLink = document.querySelector('link[rel="icon"], link[rel="shortcut icon"]');

      if (faviconLink && faviconLink.getAttribute("href") !== notificationFavicon) {
        faviconLink.setAttribute("href", notificationFavicon);
        console.log("CNBlogs favicon enhancer: Switched to notification favicon");
      }
    }
  }

  // Monitor and enhance page title
  async function monitorTitle() {
    const titleEl = await waitForElement("head > title");

    const sync = () => {
      const currentTitle = document.title;

      // Enhance title with CNBlogs branding if needed
      let newTitle = currentTitle;

      // Add notification count to title if present
      const notificationElement = document.querySelector('[class*="notification"], .msg-count');
      if (notificationElement) {
        const count = notificationElement.textContent.trim();
        if (count && count !== '0' && !currentTitle.startsWith(`(${count})`)) {
          newTitle = `(${count}) ${currentTitle}`;
        }
      }

      // Ensure "博客园" branding is present
      if (!newTitle.includes("博客园") && !newTitle.includes("CNBlogs")) {
        if (newTitle.includes(" - ")) {
          newTitle = newTitle.replace(" - ", " - 博客园 - ");
        } else {
          newTitle = `${newTitle} - 博客园`;
        }
      }

      if (newTitle !== document.title) {
        document.title = newTitle;
        console.log(`CNBlogs favicon enhancer: Title updated to "${newTitle}"`);
      }
    };

    // Initial sync
    sync();

    // Monitor for changes
    window.addEventListener("visibilitychange", sync);
    new MutationObserver(sync).observe(titleEl, {
      subtree: true,
      characterData: true,
      childList: true
    });

    // Also monitor for dynamic content changes that might affect notifications
    new MutationObserver(sync).observe(document.body, {
      subtree: true,
      childList: true,
      attributes: true,
      attributeFilter: ['class', 'data-count']
    });

    console.log("CNBlogs favicon enhancer: Title monitoring started");
  }

  // Initialize when DOM is ready
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', main);
  } else {
    main();
  }

  console.log("CNBlogs favicon enhancer: Script loaded and initialized");

})();