Greasy Fork

PTH Artist Aliases Filter

Add a box on artist page to filter based on aliases

目前为 2016-12-10 提交的版本。查看 最新版本

// ==UserScript==
// @name        PTH Artist Aliases Filter
// @namespace   PTH Artist Aliases Filter
// @description Add a box on artist page to filter based on aliases
// @include     https://passtheheadphones.me/artist.php?id=*
// @version     1.2.1
// @grant       none
// ==/UserScript==

/* Avoid using jQuery in this userscript, prioritize vanilla javascript as a matter of performance on big pages */

var artist_id = window.location.href.match(/id=(\d+)/)[1];

var box_aliases = 
    '<div class="box box_aliases">' +
        '<div class="head"><strong>Aliases (Click to filter)</strong></div>' + 
        '<ul class="stats nobullet">' +
            '<li>Loading...</li>' +
        '</ul>' +
    '</div>';
document.getElementsByClassName("box_search")[0].insertAdjacentHTML('beforebegin', box_aliases);
var box_aliases_dom = document.getElementsByClassName("box_aliases")[0];

// Display an error message if the API query goes wrong
var set_error_message = function() {
    document.querySelector(".sidebar .box_aliases li").innerHTML = "An error occured";
};

var get_aliases_and_groups = function(json_data) {
    var aliases = {}; // `aliasid` => `name`
    var groups = {}; // `groupid` => `aliasid`

    var response = json_data.response;
    var main_id = response.id;
    var name = response.name;

    var main_aliasid = undefined;

    // Iterate through each artists of each group to find those correct (`id` === `main_id`)
    var torrentgroup = response.torrentgroup;
    for (var i = 0; i < torrentgroup.length; i++) {
        var group = torrentgroup[i];

        var extendedArtists = group.extendedArtists;
        var found = false;
        for (var id in extendedArtists) {
            var artists = extendedArtists[id];
            if (artists) {
                for (var k = 0; k < artists.length; k++) {
                    var artist = artists[k];
                    if (artist.id === main_id) {
                        // This is not perfect:
                        // If a release contains references to multiple aliases of the same artist, it keeps only the first one
                        // For example, see group 72607761 of Snoop Dogg
                        // However, it is better for performance not to have to iterate through an array
                        // So let's say 1 group release => 1 artist alias
                        aliases[artist.aliasid.toString()] = artist.name;
                        groups[group.groupId.toString()] = artist.aliasid.toString();

                        if ((main_aliasid === undefined) && (artist.name === name)) {
                            // Sometimes, the aliasid associated with the artist main id differs, see artist 24926
                            // But we need it to not display "as Alias" besides releases of main artist name
                            main_aliasid = artist.aliasid.toString();
                        }
                        found = true;
                        break;
                    }
                }
            }
            if (found) break;
        }
        // Sometimes, release does not contain any artist because of an issue with the API
        // See: https://what.cd/forums.php?action=viewthread&threadid=192517&postid=5290204
        // In such a case, the release is not linked to any alias, just the default "[Show All]"
        if (!found) groups[group.groupId.toString()] = "-1";
    }
    return {aliases: aliases, groups: groups, main_aliasid: main_aliasid};
};

// Get dom elements corresponding to each alias, it will be stored once and for all (except on reload), usefull for performances
// These elements are those which will be shown or hidden (torrents rows, release groups rows and tables categories)
// During the iteration, a text node is also appended to the release row if the artist alias is different from main artist name
var get_dom_elements_per_alias = function(artist_data) {
    var aliases = artist_data.aliases;
    var groups = artist_data.groups;
    var main_aliasid = artist_data.main_aliasid;

    var dom_elements_per_alias = {"-1": []};
    for (var aliasid in aliases) {
        dom_elements_per_alias[aliasid] = [];
    }

    var torrent_tables = document.getElementsByClassName("torrent_table");

    for (var i = 0; i < torrent_tables.length; i++) {
        var torrent_table = torrent_tables[i];
        var discogs = torrent_table.getElementsByClassName("discog");
        var current_aliasid = undefined;
        var table_aliases = {};
        for (var j = 0; j < discogs.length; j++) {
            var discog = discogs[j];
            // The groupid of each torrent row is the same that the previous encountered main release row
            // This avoid having to extract groupid value at each iteration
            if (discog.classList.contains("group")) {
                var current_groupid = discog.getElementsByClassName("hide_torrents")[0].id.split("_")[1];
                current_aliasid = groups[current_groupid];
                table_aliases[current_aliasid] = 1;
                if ((current_aliasid !== main_aliasid) && (current_aliasid != "-1")) {
                    var strong = discog.getElementsByClassName("group_info")[0].getElementsByTagName("strong")[0];
                    var alias_text = "<text class='artist_alias_name'> <i>as</i> " + aliases[current_aliasid] + "</text>";
                    strong.insertAdjacentHTML("beforeend", alias_text);
                }
            }
            dom_elements_per_alias[current_aliasid].push(discog);
        }

        for (var table_alias in table_aliases) {
            dom_elements_per_alias[table_alias].unshift(torrent_table);
        }
    }

    return dom_elements_per_alias;

};

var hide_elements = function(dom_elements) {
    var nb_elems = dom_elements.length;
    for (var i = 0; i < nb_elems; i++) {
        dom_elements[i].style.display = "none";
    }
};

var show_elements = function(dom_elements) {
    var nb_elems = dom_elements.length;
    for (var i = 0; i < nb_elems; i++) {
        dom_elements[i].style.display = "";
    }
};

var hide_aliases_names = function() {
    var aliases_text = document.getElementsByClassName("artist_alias_name");

    for (var i = 0; i < aliases_text.length; i++) {
        aliases_text[i].style.display = "none";
    }
}

var show_aliases_names = function() {
    var aliases_text = document.getElementsByClassName("artist_alias_name");

    for (var i = 0; i < aliases_text.length; i++) {
        aliases_text[i].style.display = "";
    }
}

var set_aliases_box = function(artist_data) {
    var aliases = artist_data.aliases;
    var groups = artist_data.groups;

    // If there is only one alias, hide the box
    if (Object.keys(aliases).length < 2) {
        box_aliases_dom.style.display = "none";
        return;
    }

    // First, create the associative array of corresponding dom elements
    var dom_elements_per_alias = get_dom_elements_per_alias(artist_data);

    // Then, fill the aliases box
    var list = box_aliases_dom.getElementsByTagName("ul")[0];
    list.getElementsByTagName("li")[0].innerHTML = "<a style='font-size:80%;font-weight:bold' href='#' aliasid='-1'>[Show All]</a>";
    for (var aliasid in aliases) {
        var name = aliases[aliasid];
        list.insertAdjacentHTML('beforeend', "<li><a href='#' aliasid='" + aliasid + "''>" + name + "</a></li>");
    }

    // Finally, bind filtering on aliases links
    var links = list.getElementsByTagName("a");
    var current_alias_filter = "-1";
    for (var i = 0; i < links.length; i++) {
        links[i].addEventListener("click", function(e) {
            e.preventDefault();
            var new_alias_filter = this.getAttribute("aliasid");
            if (new_alias_filter === current_alias_filter) return;

            for (var j = 0; j < links.length; j++) {
                links[j].style.fontWeight = "";
            }
            this.style.fontWeight = "bold";

            if (current_alias_filter === "-1") {
                for (var aliasid in dom_elements_per_alias) {
                    if (aliasid !== new_alias_filter) {
                        hide_elements(dom_elements_per_alias[aliasid]);
                    }
                }
                show_elements(dom_elements_per_alias[new_alias_filter]);
                hide_aliases_names();
            } else if (new_alias_filter === "-1") {
                for (var aliasid in dom_elements_per_alias) {
                    if (aliasid !== current_alias_filter) {
                        show_elements(dom_elements_per_alias[aliasid]);
                    }
                }
                show_aliases_names();
            } else {
                hide_elements(dom_elements_per_alias[current_alias_filter]);
                show_elements(dom_elements_per_alias[new_alias_filter]);
            }

            current_alias_filter = new_alias_filter;
        });
    }
};

// Get cache (associative array {`artist_id` => {groups_ids, aliases, groups}})
var storage_key = "pth_artists_aliases_filter";
var storage = sessionStorage.getItem(storage_key) || "{}";
var cache = JSON.parse(storage);

var artist_cache = cache[artist_id];

// Get an array `groups_ids` of all groupid on the current artist page to ensure that cache is still valid (no new group since last visit)
var dom_groups = document.getElementsByClassName("group");
var groups_ids = [];
for (var i = 0; i < dom_groups.length; i++) {
    var group_id = dom_groups[i].getElementsByClassName("hide_torrents")[0].id.split("_")[1];
    groups_ids.push(group_id);
}
groups_ids.sort();
var stringified_groups_id = groups_ids.toString();

// If cache is not yet set or if it is no longer valid, query the API
if (artist_cache === undefined || (artist_cache.groups_ids !== stringified_groups_id)) {
    var api_req = "/ajax.php?action=artist&id=" + artist_id;
    $.ajax({
        url: api_req,
        success: function(data) {
            if (data.status === "success") {
                var aliases_and_groups = get_aliases_and_groups(data);
                artist_cache = {
                    main_aliasid: aliases_and_groups.main_aliasid,
                    groups_ids: stringified_groups_id,
                    aliases: aliases_and_groups.aliases,
                    groups: aliases_and_groups.groups
                };
                cache[artist_id] = artist_cache;
                sessionStorage.setItem(storage_key, JSON.stringify(cache));
                set_aliases_box(artist_cache);
            } else {
                set_error_message();
            }
        },
        error: set_error_message,
    });
} else {
    set_aliases_box(artist_cache);
}