Greasy Fork is available in English.

Filmografie von IMDb nach Wikipedia

Wandelt die Filmografie von IMDb mithilfe von Wikidata in Wikipedia-Quelltext um

// ==UserScript==
// @name         Filmografie von IMDb nach Wikipedia
// @version      4.2.2
// @description  Wandelt die Filmografie von IMDb mithilfe von Wikidata in Wikipedia-Quelltext um
// @author       CennoxX
// @namespace    https://greasyfork.org/users/21515
// @homepage     https://github.com/CennoxX/userscripts
// @supportURL   https://github.com/CennoxX/userscripts/issues/new?title=[Filmografie%20von%20IMDb%20nach%20Wikipedia]%20
// @connect      query-main.wikidata.org
// @connect      www.imdb.com
// @match        https://www.imdb.com/*/name/*
// @match        https://www.imdb.com/name/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=wikipedia.org
// @grant        GM.xmlHttpRequest
// @grant        GM.setClipboard
// @grant        GM.registerMenuCommand
// @grant        unsafeWindow
// @license      MIT
// @noframes
// ==/UserScript==
/* jshint esversion: 11 */

(function(){
    "use strict";
    var sha256 = {
        loadActor: "4faf04583fbf1fbc7a025e5dffc7abc3486e9a04571898a27a5a1ef59c2965f3",
        loadActress: "0cf092f3616dbc56105327bf09ec9f486d5fc243a1d66eb3bf791fda117c5079",
        loadEpisodeActor: "4cda84f556104467ecebd3c8911671f85c4d8a8f7877d7a95bfa814e2d3da4fc",
        loadEpisodeActress: "5d6728cf6dfa5f1df8b3ead8076d2b61035c7c3dfb0e5b8e2e286a01c9aa5199"
    };
    unsafeWindow.ladeFilmografie = function(showShort = true, episodeLabel = "Folge", showAlert = false){
        setTimeout(async() =>{
            var isMale = document.querySelector(".filmo-section-actor,.filmo-section-actress").classList.contains("filmo-section-actor");
            var imdbId = location.href.match(/nm\d+/)[0];
            var filmography = [];
            var done = 0;
            var request = 1;
            var checkIfCompleted = setInterval(async () => {
                if (done / request != 1){
                    console.clear();
                    console.log("requests:", done, "/", request);
                } else {
                    await getDataFromWikidata();
                    var formattedFilmography = "== Filmografie ==";
                    filmography.forEach(entry => {
                        formattedFilmography += entry.toString();
                    });
                    GM.setClipboard(formattedFilmography);
                    var successMessage = "Filmografie wurde erfolgreich kopiert.";
                    if (showAlert){
                        alert(successMessage);
                    } else {
                        console.clear();
                        console.log(formattedFilmography);
                        console.log(successMessage);
                    }
                    clearInterval(checkIfCompleted);
                }
            }, 1000);
            var resp = await fetch(`https://caching.graphql.imdb.com/?operationName=NameMainFilmographyPaginatedCredits&variables={"id":"${imdbId}","includeUserRating":false,"locale":"de-DE"}&extensions={"persistedQuery":{"sha256Hash":"${(isMale ? sha256.loadActor : sha256.loadActress)}","version":1}}`, {
                method: "GET",
                headers: {
                    "Content-Type": "application/json",
                    "x-imdb-user-country": "DE"
                }
            });
            var workObj = await resp.json();
            var work = workObj.data.name[(isMale ? "actor_credits" : "actress_credits")].edges.map(i => i.node);
            done++;
            for(var w of work){
                var credit = new Credit();
                credit.yearFrom = w.episodeCredits.yearRange?.year ?? w.title.releaseYear?.year;
                if (!credit.yearFrom){
                    continue;
                }
                credit.yearTo = w.episodeCredits.yearRange ? w.episodeCredits.yearRange.endYear ?? 0 : 0;
                credit.dt = w.title.titleText.text;
                credit.ot = w.title.originalTitleText.text;
                var creditType = w.title.titleType.text;
                if (creditType == "Video Game" || creditType == "Podcast Series"){
                    continue;
                }
                if (creditType == "Video" && w.title.titleGenres.genres.some(i => i.genre.text == "Short")){
                    creditType = "Kurzfilm";
                }
                credit.type = creditType
                    .replace(/Documentary short/, "Dokumentar-Kurzfilm")
                    .replace(/(TV Movie d|D)ocumentary/, "Dokumentarfilm")
                    .replace(/TV Series short/, "Webserie")
                    .replace(/TV Series( documentary)?/, "Fernsehserie")
                    .replace(/TV Mini Series( documentary)?/, "Miniserie")
                    .replace(/TV Movie/, "Fernsehfilm")
                    .replace(/(Video s|TV S|TV Mini Series s|S)hort/, "Kurzfilm")
                    .replace(/(Movie|Music Video|Video)/, "");
                if (!showShort && credit.type.includes("Kurzfilm")){
                    continue;
                }
                credit.imdbid = w.title.id;
                credit.voice = w.attributes?.[0].text == "voice";
                credit.role = w.characters?.[0].name;
                filmography.push(credit);
                if (credit.type.includes("serie")){
                    getDataFromIMDb(credit.imdbid, "");
                }
            }

            filmography = filmography.reverse().sort((a,b) => {
                return a.yearFrom - b.yearFrom;
            });

            function getDataFromIMDb(titleId, page){
                request++;
                GM.xmlHttpRequest({
                    method: "GET",
                    url: `https://caching.graphql.imdb.com/?operationName=EpisodeBottomSheetCast&variables={"after":"${page}","episodeCreditsFilter":{},"locale":"de-DE","nameId":"${imdbId}","titleId":"${titleId}"}&extensions={"persistedQuery":{"sha256Hash":"${(isMale ? sha256.loadEpisodeActor : sha256.loadEpisodeActress)}","version":1}}`,
                    headers: {
                        "Content-Type": "application/json",
                        "x-imdb-user-country": "DE"
                    },
                    onload: function(response){
                        done++;
                        var respText = response.responseText;
                        if (respText.length > 0){
                            var jsonObj = JSON.parse(respText);
                            var credit = filmography.find(c => {
                                return c.imdbid == titleId;
                            });
                            var ep = jsonObj.data.name.credits.edges[0]?.node;
                            if (credit && ep){
                                credit.numberOfEpisodes += ep.episodeCredits.edges.filter(i => i.node.attributes?.[0]?.text != "credit only").length;
                                if (ep.episodeCredits.pageInfo.hasNextPage){
                                    getDataFromIMDb(titleId, ep.episodeCredits.pageInfo.endCursor);
                                }
                                if (credit.numberOfEpisodes == 1){
                                    var epCredit = ep.episodeCredits.edges[0].node.title;
                                    credit.episodeid = epCredit.id;
                                    if (epCredit.series.displayableEpisodeNumber.episodeNumber.text != "unknown"){
                                        var season = epCredit.series.displayableEpisodeNumber.displayableSeason.text;
                                        var episode = epCredit.series.displayableEpisodeNumber.episodeNumber.text;
                                        credit.episodeName = ((season == "1" && episode.length > 3 ? "" : season + "x") + episode).replace(/x(\d)$/,"x0$1");
                                    }
                                } else {
                                    credit.episodeName = "";
                                }
                            }
                        }
                    },
                    onerror: function(response){
                        done++;
                        console.error("Error in fetching contents: " + response.responseText);
                    }
                });
            }

            async function getDataFromWikidata(){
                request++;
                var imdbIds = filmography.flatMap(i => [i.episodeid, i.imdbid]).filter(i => i).join('" "');
                var sparqlQuery = `SELECT ?imdb ?dt (SAMPLE(?ot) AS ?ot) ?dewiki WHERE {
                VALUES ?imdb { "${imdbIds}" }
                ?item wdt:P345 ?imdb.
                OPTIONAL {
                    ?item rdfs:label ?dt.
                    FILTER((LANG(?dt)) = "de")
                }
                OPTIONAL {
                    ?item wdt:P1476 ?ot.
                }
                OPTIONAL {
                    ?dewiki schema:about ?item;
                            schema:isPartOf <https://de.wikipedia.org/>.
                }
            }
            GROUP BY ?imdb ?dt ?dewiki`;
                var resp = await fetch("https://query-main.wikidata.org/sparql?format=json", {
                    "headers": {
                        "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
                    },
                    "body": "query=" + encodeURIComponent(sparqlQuery),
                    "method": "POST",
                    "mode": "cors"
                });
                var jsonObj = await resp.json();
                jsonObj.results.bindings.forEach(i => {
                    var credit = filmography.find(c => c.imdbid == i.imdb.value);
                    i.dewiki = i.dewiki ? decodeURIComponent(i.dewiki.value).slice(30).replace(/_/g," ") : "";
                    if (credit){
                        credit.link = i.dewiki;
                        credit.dt = i.dt?.value || credit.dt;
                        credit.ot = i.ot?.value || credit.ot;
                    }
                    var episodeCredit = filmography.find(c => c.episodeid == i.imdb.value);
                    if (episodeCredit){
                        if (i.dewiki){
                            var article = i.dewiki;
                            if (article.slice(-1) == ")"){
                                article += `|${article.split(" (")[0]}`;
                            }
                            episodeCredit.episodeName += ` ''[[${article}]]''`;
                        } else if (i.dt){
                            episodeCredit.episodeName += ` ''${i.dt?.value}''`;
                        }
                    }
                });
                done++;
            }

            function Credit(){
                this.numberOfEpisodes = 0;
                this.episodeid = "";
                this.formatTitle = function(title = ""){
                    return title.replace(/[-–:., \d’'!…]/g, "").toLowerCase();
                };
                this.compareTitles = function(titleA,titleB){
                    return this.formatTitle(titleA) == this.formatTitle(titleB);
                };
                this.getYearPart = function(){
                    var currentYear = new Date().getFullYear();
                    if (this.type.includes("serie") && this.numberOfEpisodes > 1 && (this.yearFrom == currentYear || (this.yearTo && this.yearTo == currentYear))){
                        return `seit ${this.yearFrom}`;
                    }
                    if (!this.yearTo || this.yearTo == this.yearFrom){
                        return this.yearFrom;
                    }
                    if (this.numberOfEpisodes == 2 && parseInt(this.yearFrom) + 1 != this.yearTo){
                        return `${this.yearFrom}, ${this.yearTo}`;
                    }
                    return `${this.yearFrom}–${this.yearTo}`;
                };
                this.getTitlePart = function(){
                    this.dt = this.dt.replace(" - ", " – ").replace("...", "…").replace(/'/g, "’");
                    if (!this.link){
                        return this.dt;
                    }
                    if (this.link.slice(-1) == ")"){
                        this.dt = this.link.split(" (")[0];
                        return `[[${this.link}|${this.dt}]]`;
                    }
                    this.dt = this.link;
                    return `[[${this.link}]]`;
                };
                this.getDescriptionPart = function(){
                    this.ot = this.ot.replace(" - ", " – ").replace("...", "…").replace(/'/g, "’");
                    if (!this.compareTitles(this.ot, this.dt) && !this.type && !this.voice){
                        return ` ''(${this.ot})''`;
                    }
                    var descriptionPart = "";
                    if (!this.compareTitles(this.ot, this.dt)){
                        descriptionPart += ` (''${this.ot}''`;
                    }
                    if (this.type){
                        descriptionPart += (descriptionPart ? ", " : " (") + this.type;
                    }
                    if (!`${this.getYearPart()}`.startsWith("seit")){
                        if (this.numberOfEpisodes > 1){
                            descriptionPart += `, ${this.numberOfEpisodes} ${episodeLabel}n`;
                        } else if (this.numberOfEpisodes && this.episodeName){
                            descriptionPart += `, ${episodeLabel} ${this.episodeName}`;
                        } else if (this.numberOfEpisodes){
                            descriptionPart += `, eine ${episodeLabel}`;
                        }
                    }
                    if (this.voice){
                        if (this.role){
                            descriptionPart += (descriptionPart ? ", " : " (") + "Stimme von ''" + this.role.split(" (")[0] + "''";
                        }else{
                            descriptionPart += (descriptionPart ? ", " : " (") + "Sprechrolle";
                        }
                    }
                    descriptionPart += descriptionPart ? ")" : "";
                    return descriptionPart;
                };
                this.toString = function(){
                    return `\n* ${this.getYearPart()}: ${this.getTitlePart()}${this.getDescriptionPart()}`;
                };
            }
        }, 0);
        return "Filmografie lädt …";
    };

    GM.registerMenuCommand("Filmografie laden",() => {
        unsafeWindow.ladeFilmografie(undefined, undefined, true);
    },"f");

    console.log('Um die Filmografie mit Standardeinstellungen zu laden, genügt ein Klick im Menü des Userscripts auf "Filmografie laden".\n' +
                'Die Filmografie kann in der Console mit erweiterten Einstellungen in der Form "ladeFilmografie(showShort, episodeLabel);" aufgerufen werden.\n' +
                'Dabei steht "episodeLabel" für die verwendete Bezeichnung "Folge" oder "Episode" und "showShort" dafür, ob Kurzfilme aufgeführt werden sollen oder nicht (true oder false).');
})();