Letterboxd Bio Modifier

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

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 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();