Letterboxd Bio Modifier

Adds visual bio summary and Wikipedia link to actors and directors pages

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name        Letterboxd Bio Modifier
// @namespace   https://github.com/soyguijarro/userscripts
// @description Adds visual bio summary and Wikipedia link to actors and directors pages
// @copyright   2015, Ramón Guijarro (http://soyguijarro.com)
// @homepageURL https://github.com/soyguijarro/userscripts
// @supportURL  https://github.com/soyguijarro/userscripts/issues
// @icon        https://raw.githubusercontent.com/soyguijarro/userscripts/master/img/letterboxd_icon.png
// @license     GPLv3; http://www.gnu.org/licenses/gpl.html
// @version     1.2
// @include     *://letterboxd.com/director/*
// @include     *://letterboxd.com/actor/*
// @grant       GM_addStyle
// @grant       GM_xmlhttpRequest
// ==/UserScript==

var sidebarElt = document.getElementsByClassName("sidebar")[0],
    bioElt = sidebarElt.getElementsByClassName("tmdb-person-bio")[0],
    tmdbId = bioElt.getAttribute("data-tmdb-id"),
    tmdbBaseUrl = "http://themoviedb.org/person/",
    tmdbUrl = tmdbBaseUrl + tmdbId;

function showBioSummary(res) {
    var dom = new DOMParser().parseFromString(res.responseText, "text/html"),
        tmdbBirthplaceElt = dom.getElementById("place_of_birth"),
        tmdbBirthdayElt = dom.getElementById("birthday"),
        tmdbDeathdayElt = dom.getElementById("deathday"),
        creditsElt = dom.getElementById("leftCol").getElementsByTagName("p")[0],
        creditsMatch = creditsElt.textContent.match(/Known Credits: (\d+)/),
        gotRelevantData = isActualData(tmdbBirthplaceElt) ||
            isActualData(tmdbBirthdayElt),
        bioSummaryElt = document.createElement("section"),
        bioSummaryElts,
        bioInnerElt,
        cssRules = "section.panel-text.bio-summary {\
                        border-bottom: 1px solid #456;\
                    }\
                    section.panel-text.bio-summary p {\
                        padding-left: 25px;\
                        display: block;\
                    }";

    function getFormattedDate(date) {
        var monthNum = date.getMonth(),
            dayNum = date.getDate(),
            yearNum = date.getFullYear(),
            monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

        return monthNames[monthNum] + " " + dayNum + ", " + yearNum;
    }

    function isActualData(elt) {
        var data = elt.textContent,
            exp = /^-$/;

        return !(exp.test(data));
    }

    function showBirthplace() {
        var birthplace = tmdbBirthplaceElt.textContent,
            birthplaceElt = document.createElement("p"),
            birthplaceIconElt = document.createElement("span");

        // Fill element with data and apply styles
        birthplaceElt.classList.add("icon-location");
        birthplaceElt.textContent = birthplace.replace(/ - /g, ", ");
        birthplaceIconElt.style.marginLeft = "2px";

        // Insert element in section
        birthplaceElt.appendChild(birthplaceIconElt);
        bioSummaryElt.appendChild(birthplaceElt);
    }

    function showBornDeathDate() {
        var birthday = new Date(tmdbBirthdayElt.firstElementChild.textContent),
            dateElt = document.createElement("p"),
            dateIconElt = document.createElement("span"),
            msPerYear = 1000 * 60 * 60 * 24 * 365,
            refDate,
            date,
            age;

        // Fill element with data and apply styles
        if (tmdbDeathdayElt) {  // Person is dead
            // Use death date as reference to calculate age
            refDate = new Date(tmdbDeathdayElt.firstElementChild.textContent);
            date = refDate; // Show death date

            dateElt.classList.add("icon-hidden");
            dateIconElt.style.marginLeft = "3px";
        } else {    // Person is alive
            // Use today as reference to calculate age
            refDate = new Date();
            date = birthday;    // Show birthday

            dateElt.classList.add("icon-people");
        }
        age = Math.floor((refDate - birthday.getTime()) / msPerYear);
        dateElt.textContent = getFormattedDate(date) +
            " (age" + ((tmdbDeathdayElt) ? "d " : " ") + age + ")";

        // Insert element in section
        dateElt.appendChild(dateIconElt);
        bioSummaryElt.appendChild(dateElt);
    }

    function showNumCredits() {
        var numCredits = creditsMatch[1],
            creditsElt = document.createElement("p"),
            creditsIconElt = document.createElement("span");

        // Fill element with data and apply styles
        creditsElt.classList.add("icon-list-all");
        creditsElt.textContent = numCredits + " known credits";
        creditsIconElt.style.backgroundPosition = "-740px -110px";

        // Insert element in section
        creditsElt.appendChild(creditsIconElt);
        bioSummaryElt.appendChild(creditsElt);
    }

    // Set up section to be inserted in page
    bioSummaryElt.className = "section panel-text bio-summary";

    // Fill section with available data
    if (gotRelevantData) {
        if (isActualData(tmdbBirthplaceElt)) {
            showBirthplace();
        }
        if (isActualData(tmdbBirthdayElt)) {
            showBornDeathDate();
        }
        if (creditsMatch) {
            showNumCredits();
        }
    } else {
        return; // Abort if no relevant data at all is available
    }

    // Apply common styles to section elements
    bioSummaryElts = bioSummaryElt.children;
    for (var i = 0; i < bioSummaryElts.length; i++) {
        bioSummaryElts[i].classList.add("has-icon")
        bioSummaryElts[i].classList.add("icon-16");
        bioSummaryElts[i].firstElementChild.className = "icon";
    }

    // Insert section in page
    bioInnerElt = bioElt.getElementsByClassName("panel-text condensed")[0] ||
        bioElt.getElementsByClassName("panel-text")[0];

    if (bioInnerElt) {  // Already existing bio section
        bioInnerElt.insertBefore(bioSummaryElt, bioInnerElt.firstElementChild.nextSibling);
    } else {    // No bio section, add missing header
        var bioHeaderElt = document.createElement("h2");
        bioHeaderElt.className = "section-heading";
        bioHeaderElt.textContent = "Bio";

        bioElt.appendChild(bioHeaderElt);
        bioElt.appendChild(bioSummaryElt);
    }
    GM_addStyle(cssRules);
}

function showWikiLink() {
    var linksElt = document.getElementsByClassName("bio-link")[0],
        headerElt = document.getElementsByClassName("page-header")[0],
        personNameElt = headerElt.querySelector("h1.inline-heading.prettify em"),
        wikiLinkElt = document.createElement("li"),
        wikiLinkInnerElt = document.createElement("a"),
        personName = personNameElt.textContent,
        wikiBaseUrl = "https://en.wikipedia.org/wiki/",
        wikiUrl = wikiBaseUrl + personName,
        linksInnerElt;

    // Fill element with data and apply styles
    wikiLinkInnerElt.className = "box-link";
    wikiLinkInnerElt.href = wikiUrl;
    wikiLinkInnerElt.textContent = "Search on Wikipedia";
    wikiLinkElt.appendChild(wikiLinkInnerElt);

    // Insert section in page
    if (linksElt) { // Already existing link section
        linksInnerElt = linksElt.getElementsByTagName("ul")[0];
        linksInnerElt.insertBefore(wikiLinkElt, linksInnerElt.firstElementChild);
    } else {    // No link section, create first
        linksElt = document.createElement("section");
        linksInnerElt = document.createElement("ul");
        linksElt.className = "section bio-link";
        linksInnerElt.className = "box-link-list box-links";

        linksInnerElt.appendChild(wikiLinkElt);
        linksElt.appendChild(linksInnerElt);
        sidebarElt.insertBefore(linksElt,
            sidebarElt.getElementsByClassName("progresspanel")[0]);
    }
}

GM_xmlhttpRequest({
    method: "GET",
    url: tmdbUrl,
    onload: showBioSummary
});

showWikiLink();