Shows current age or "would be" age in correct birth-and-death-section (improved date detection)
// ==UserScript==
// @name IMDb - Show Current Age
// @namespace https://github.com/BlueAG/TamperMonkey/tree/main/IMDb-Show-Current-Age
// @icon https://www.google.com/s2/favicons?domain=imdb.com
// @version 1.1.3
// @description Shows current age or "would be" age in correct birth-and-death-section (improved date detection)
// @author BlueAG
// @license MIT
// @match https://www.imdb.com/name/nm*
// @grant none
// @compatible chrome
// @compatible firefox
// @compatible opera
// @compatible edge
// @compatible safari
// ==/UserScript==
(function() {
'use strict';
window.addEventListener('load', () => setTimeout(addAgeText, 1500));
function addAgeText() {
if (document.getElementById('imdb-age-text')) return;
console.log("[IMDb Age 1.1.8] Starting...");
const candidates = document.querySelectorAll('[data-testid="birth-and-death-section"]');
console.log(`[IMDb Age 1.1.8] Found ${candidates.length} sections`);
let targetAside = null;
let birthDiv = null;
let dateSpan = null;
let birthText = "";
// Prefer aside with crfwtP class
for (const aside of candidates) {
if (aside.className.includes('crfwtP')) {
targetAside = aside;
console.log("[IMDb Age 1.1.8] Selected aside with crfwtP class");
break;
}
}
// Fallback: first one with birthdate div
if (!targetAside) {
for (const aside of candidates) {
if (aside.querySelector('[data-testid="birth-and-death-birthdate"]')) {
targetAside = aside;
console.log("[IMDb Age 1.1.8] Fallback to first aside with birthdate div");
break;
}
}
}
if (!targetAside) {
console.log("[IMDb Age 1.1.8] No suitable aside found");
return;
}
birthDiv = targetAside.querySelector('[data-testid="birth-and-death-birthdate"]');
if (!birthDiv) {
console.log("[IMDb Age 1.1.8] birth-and-death-birthdate div missing");
return;
}
// Find date span: check all spans inside birthDiv
const allSpans = birthDiv.querySelectorAll('span');
console.log(`[IMDb Age 1.1.8] Found ${allSpans.length} spans inside birth div`);
for (const span of allSpans) {
const t = span.textContent.trim().replace(/\s+/g, ' ');
console.log("[IMDb Age 1.1.8] Checking span text:", t);
if (/^\d{4}$/.test(t) ||
/^[A-Za-z]+\s+\d{1,2},\s+\d{4}$/.test(t) ||
/^[A-Za-z]+\s+\d{1,2}$/.test(t)) { // also allow month + day only (but we'll skip age calc)
dateSpan = span;
birthText = t;
break;
}
}
if (!dateSpan || !birthText) {
console.log("[IMDb Age 1.1.8] No valid date/year text found");
return;
}
console.log("[IMDb Age 1.1.8] Selected birth text:", birthText);
// Skip age if no year
if (!/\d{4}/.test(birthText)) {
console.log("[IMDb Age 1.1.8] No year present - skipping age calculation");
const placeholder = document.createElement('span');
placeholder.id = 'imdb-age-text';
placeholder.style.cssText = `
margin-left: 0px;
font-size: 1.05em;
font-weight: 100;
color: #ffe300;
font-style: italic;
`;
placeholder.textContent = "No birth year found!";
birthDiv.insertAdjacentElement('afterend', placeholder);
return;
}
// Calculate age
const today = new Date();
let age = null;
const isYearOnly = /^\d{4}$/.test(birthText);
if (isYearOnly) {
age = today.getFullYear() - parseInt(birthText);
} else {
const birthDate = new Date(birthText);
if (!isNaN(birthDate.getTime())) {
age = today.getFullYear() - birthDate.getFullYear();
const m = today.getMonth() - birthDate.getMonth();
if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) age--;
}
}
if (age === null || age < 0) {
console.log("[IMDb Age 1.1.8] Invalid age");
return;
}
// Deceased check
const isDeceased =
targetAside.querySelector('[data-testid="birth-and-death-deathdate"]') ||
targetAside.querySelector('[data-testid="birth-and-death-death-age"]') ||
targetAside.textContent.includes('Died');
// Create age element
const ageEl = document.createElement('span');
ageEl.id = 'imdb-age-text';
ageEl.style.cssText = `
margin-left: 0px;
font-size: 1.05em;
font-weight: 500;
color: ${isDeceased ? '#c62828' : '#2e7d32'};
`;
ageEl.textContent = isDeceased
? `Current age would be: ${age} years`
: `Current age: ${age} years${isYearOnly ? ' (approx)' : ''}`;
// Insert after birth div
birthDiv.insertAdjacentElement('afterend', ageEl);
console.log("[IMDb Age 1.1.8] Age inserted:", ageEl.textContent);
}
})();