Age-calculator - stashdb.org (fixed)

Adds performer age at scene date after DOM settles

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        Age-calculator - stashdb.org (fixed)
// @namespace   Violentmonkey Scripts
// @match       https://stashdb.org/performers/*
// @grant       none
// @version     1.2
// @author      Yahigod
// @license     MIT
// @description Adds performer age at scene date after DOM settles
// ==/UserScript==

(function () {
  'use strict';

  let observerTimer;
  const timeoutDuration = 900; // ms of no DOM changes before running
  let isScriptRunning = false;

  // --- Mutation observer with debounce ---
  const mutationObserver = new MutationObserver(() => {
    clearTimeout(observerTimer);
    observerTimer = setTimeout(runScriptIfNoMutations, timeoutDuration);
  });

  const body = document.querySelector('body');
  if (body) {
    mutationObserver.observe(body, { childList: true, subtree: true });
  }

  // Initial delayed attempt
  observerTimer = setTimeout(runScriptIfNoMutations, timeoutDuration);

  function runScriptIfNoMutations() {
    if (isScriptRunning) return;

    // Stop observer while we modify DOM
    mutationObserver.disconnect();
    isScriptRunning = true;

    try {
      // ---------------- YOUR ORIGINAL CODE (with minimal fixes) ----------------
      (function() {
        'use strict';

        // Function to calculate age
        function calculateAge(birthdate, sceneDate) {
          const birthDate = new Date(birthdate);
          const sceneDateObject = new Date(sceneDate);

          const ageInMilliseconds = sceneDateObject - birthDate;
          const ageInYears = ageInMilliseconds / (365 * 24 * 60 * 60 * 1000);

          const birthYear = birthDate.getFullYear();
          const sceneYear = sceneDateObject.getFullYear();

          const birthMonth = birthDate.getMonth();
          const sceneMonth = sceneDateObject.getMonth();

          const birthDay = birthDate.getDate();
          const sceneDay = sceneDateObject.getDate();

          let years = sceneYear - birthYear;
          let months = sceneMonth - birthMonth;
          let days = sceneDay - birthDay;

          if (days < 0) {
            months -= 1;
            days += 30; // Assuming an average of 30 days per month
          }

          if (months < 0) {
            years -= 1;
            months += 12;
          }

          let ageText = '';

          if (years > 0) {
            ageText += `${years}y `;
          }

          if (months > 0) {
            ageText += `${months}m `;
          }

          if (days > 0) {
            ageText += `${days}d `;
          }

          ageText += 'old';

          return ageText.trim();
        }

        // Extract and print birthdates
        const rows = document.querySelectorAll('tr');
        let birthdate;

        for (const row of rows) {
          const cells = row.querySelectorAll('td');

          if (cells.length == 2) {
            const birthdateCell = cells[0].textContent.trim();
            if (birthdateCell === "Birthdate") {
              // ✅ FIX #1: extract ONLY the ISO date even if the cell is polluted
              const match = cells[1].textContent.match(/\d{4}-\d{2}-\d{2}/);
              birthdate = match ? match[0] : undefined;
            }
          }
        }

        if (!birthdate) return; // can't do anything without a valid birthdate

        // Add age next to each date in SceneCard elements
        const sceneCards = document.querySelectorAll('.SceneCard.card');

        for (const sceneCard of sceneCards) {
          const dateStrong = sceneCard.querySelector('.card-footer strong');

          if (!dateStrong) continue;

          // ✅ FIX #2: prevent duplicates (looks for our tag)
          const footer = dateStrong.parentElement;
          if (footer && footer.querySelector('.age-calculator-age')) {
            continue;
          }

          const dateText = dateStrong.textContent.trim();
          const age = calculateAge(birthdate, dateText);

          // ✅ FIX #3: don't insert junk results like just "old"
          if (!/\d/.test(age)) continue;

          // ✅ FIX #4: put age UNDER the date with a real line break
          dateStrong.insertAdjacentHTML(
            'afterend',
            `<br><span class="age-calculator-age">${age}</span>`
          );
        }
      })();
      // ------------------------------------------------------------------------
    } catch (e) {
      console.error('[Age-calculator]', e);
    } finally {
      // Reconnect observer
      if (body) {
        mutationObserver.observe(body, { childList: true, subtree: true });
      }
      isScriptRunning = false;
    }
  }
})();