Old Reddit with New Reddit Profile Pictures - Universal Version

Injects new Reddit profile pictures into Old Reddit and Reddit-Stream.com next to the username. Caches in localstorage.

目前為 2024-11-06 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Old Reddit with New Reddit Profile Pictures - Universal Version
// @namespace    https://github.com/Nick2bad4u/UserStyles
// @version      3.5
// @description  Injects new Reddit profile pictures into Old Reddit and Reddit-Stream.com next to the username. Caches in localstorage.
// @author       Nick2bad4u
// @match        https://*.reddit.com/*
// @match        https://www.*.reddit.com/*
// @match        https://reddit-stream.com/*
// @connect      reddit.com
// @license      Unlicense
// @icon         https://www.google.com/s2/favicons?sz=64&domain=reddit.com
// @run-at       document-start
// ==/UserScript==

(function () {
  "use strict";
  console.log("Script loaded");

  let profilePictureCache = JSON.parse(
    localStorage.getItem("profilePictureCache") || "{}",
  );
  let cacheTimestamps = JSON.parse(
    localStorage.getItem("cacheTimestamps") || "{}",
  );
  const CACHE_DURATION = 7 * 24 * 60 * 60 * 1000; // 7 days in milliseconds
  const MAX_CACHE_SIZE = 25000; // Maximum number of cache entries

  function saveCache() {
    localStorage.setItem(
      "profilePictureCache",
      JSON.stringify(profilePictureCache),
    );
    localStorage.setItem("cacheTimestamps", JSON.stringify(cacheTimestamps));
  }

  function flushOldCache() {
    console.log("Flushing old cache");
    const now = Date.now();
    for (const username in cacheTimestamps) {
      if (now - cacheTimestamps[username] > CACHE_DURATION) {
        console.log(`Deleting cache for ${username}`);
        delete profilePictureCache[username];
        delete cacheTimestamps[username];
      }
    }
    saveCache();
    console.log("Old cache entries flushed");
  }

  function limitCacheSize() {
    const cacheEntries = Object.keys(profilePictureCache);
    if (cacheEntries.length > MAX_CACHE_SIZE) {
      console.log("Cache size exceeded, removing oldest entries");
      const sortedEntries = cacheEntries.sort(
        (a, b) => cacheTimestamps[a] - cacheTimestamps[b],
      );
      const entriesToRemove = sortedEntries.slice(
        0,
        cacheEntries.length - MAX_CACHE_SIZE,
      );
      entriesToRemove.forEach((username) => {
        delete profilePictureCache[username];
        delete cacheTimestamps[username];
      });
      saveCache();
      console.log("Cache size limited");
    }
  }

  async function fetchProfilePictures(usernames) {
    console.log("Fetching profile pictures");
    const uncachedUsernames = usernames.filter(
      (username) =>
        !profilePictureCache[username] &&
        username !== "[deleted]" &&
        username !== "[removed]",
    );
    if (uncachedUsernames.length === 0) {
      console.log("All usernames are cached");
      return usernames.map((username) => profilePictureCache[username]);
    }

    console.log(
      `Fetching profile pictures for: ${uncachedUsernames.join(", ")}`,
    );

    const fetchPromises = uncachedUsernames.map(async (username) => {
      try {
        const response = await fetch(
          `https://www.reddit.com/user/${username}/about.json`,
        );
        if (!response.ok) {
          console.error(
            `Error fetching profile picture for ${username}: ${response.statusText}`,
          );
          return null;
        }
        const data = await response.json();
        if (data.data && data.data.icon_img) {
          const profilePictureUrl = data.data.icon_img.split("?")[0];
          profilePictureCache[username] = profilePictureUrl;
          cacheTimestamps[username] = Date.now();
          saveCache();
          console.log(`Fetched profile picture: ${username}`);
          return profilePictureUrl;
        } else {
          console.warn(`No profile picture found for: ${username}`);
          return null;
        }
      } catch (error) {
        console.error(`Error fetching profile picture for ${username}:`, error);
        return null;
      }
    });

    const results = await Promise.all(fetchPromises);
    limitCacheSize();
    return usernames.map((username) => profilePictureCache[username]);
  }

  async function injectProfilePictures(comments) {
    console.log(`Comments found: ${comments.length}`);
    const usernames = Array.from(comments)
      .map((comment) => comment.textContent.trim())
      .filter(
        (username) => username !== "[deleted]" && username !== "[removed]",
      );
    const profilePictureUrls = await fetchProfilePictures(usernames);

    comments.forEach((comment, index) => {
      const username = usernames[index];
      const profilePictureUrl = profilePictureUrls[index];
      if (
        profilePictureUrl &&
        !comment.previousElementSibling?.classList.contains("profile-picture")
      ) {
        console.log(`Injecting profile picture: ${username}`);
        const img = document.createElement("img");
        img.src = profilePictureUrl;
        img.classList.add("profile-picture");
        img.onerror = () => {
          img.style.display = "none";
        };
        img.addEventListener("click", () => {
          window.open(profilePictureUrl, "_blank");
        });
        comment.insertAdjacentElement("beforebegin", img);

        const enlargedImg = document.createElement("img");
        enlargedImg.src = profilePictureUrl;
        enlargedImg.classList.add("enlarged-profile-picture");
        document.body.appendChild(enlargedImg);
        img.addEventListener("mouseover", () => {
          enlargedImg.style.display = "block";
          const rect = img.getBoundingClientRect();
          enlargedImg.style.top = `${rect.top + window.scrollY + 20}px`;
          enlargedImg.style.left = `${rect.left + window.scrollX + 20}px`;
        });
        img.addEventListener("mouseout", () => {
          enlargedImg.style.display = "none";
        });
      }
    });
    console.log("Profile pictures injected");
  }

  function setupObserver() {
    console.log("Setting up observer");
    const observer = new MutationObserver((mutations) => {
      const comments = document.querySelectorAll(".author, .c-username");
      if (comments.length > 0) {
        console.log("New comments detected");
        observer.disconnect();
        injectProfilePictures(comments);
      }
    });
    observer.observe(document.body, {
      childList: true,
      subtree: true,
    });
    console.log("Observer initialized");
  }

  function runScript() {
    flushOldCache();
    console.log("Cache loaded:", profilePictureCache);
    setupObserver();
  }

  window.addEventListener("load", () => {
    console.log("Page loaded");
    runScript();
    setInterval(runScript, 10000); // Run every 10 seconds
  });

  const style = document.createElement("style");
  style.textContent = `
        .profile-picture {
            width: 20px;
            height: 20px;
            border-radius: 50%;
            margin-right: 5px;
            transition: transform 0.2s ease-in-out;
            position: relative;
            z-index: 1;
            cursor: pointer;
        }
        .enlarged-profile-picture {
            width: 250px;
            height: 250px;
            border-radius: 50%;
            position: absolute;
            display: none;
            z-index: 1000;
            pointer-events: none;
            outline: 3px solid #000;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 1);
            background-color: rgba(0, 0, 0, 1);
        }
    `;
  document.head.appendChild(style);
})();

QingJ © 2025

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