Get Old Cnblogs Favicon Back

Replace specific favicon with a old one on cnblogs.

// ==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");

})();