您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Add a box on artist page to filter based on aliases
当前为
- // ==UserScript==
- // @name RED 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=*
- // @include https://redacted.ch/artist.php?id=*
- // @version 1.3.0
- // @grant none
- // ==/UserScript==
- /* Avoid using jQuery in this userscript, prioritize vanilla javascript as a matter of performance on big pages */
- "use strict";
- function Storage(alias_id) {
- this.key = "red.artists_aliases_filter." + alias_id;
- this.save = function(data) {
- if (typeof data !== 'string') {
- data = JSON.stringify(data);
- }
- sessionStorage.setItem(this.key, data);
- };
- this.load = function() {
- let storage = sessionStorage.getItem(this.key) || "{}";
- return JSON.parse(storage);
- };
- };
- function Builder() {
- this.make_box_aliases = function() {
- let box_aliases =
- "<div class='box box_aliases'>" +
- "<div class='head'><strong>Aliases</strong></div>" +
- "<ul class='stats nobullet'></ul>" +
- "</div>";
- return box_aliases;
- };
- this.make_alias_release = function(alias_id, alias_name) {
- let alias_release =
- "<text class='alias_id'>" +
- " <i>as</i> " +
- "<a href='#content' alias_id='" + alias_id + "'>" +
- alias_name +
- "</a>" +
- "</text>";
- return alias_release;
- }
- this.make_alias_li = function(alias_id, alias_name) {
- let alias_li =
- "<li>" +
- "<a href='#' alias_id='" + alias_id.toString() + "'>" + alias_name + "</a>" +
- "</li>";
- return alias_li;
- };
- this.make_alias_title = function(artist_name) {
- let main = "<a id='main_title' href='#' alias_id='-1'>" + artist_name + "</a>";
- let alias = "<span id='alias_title'></span>";
- let title =
- "<h2 id='title_filtering'>" +
- main + " " + alias +
- "</h2>";
- return title;
- };
- };
- function Manager() {
- this.builder = new Builder();
- this.current_alias_id = "-1";
- this.try_catch = function(func) {
- let self = this;
- func = func.bind(this);
- function wrapped() {
- try {
- func();
- } catch(err) {
- let err_msg = err.message + " (line " + err.lineNumber + ")";
- console.log("Error in RED AAF: '" + err_msg + "'.");
- self.set_error_message(err_msg);
- }
- }
- return wrapped;
- };
- this.get_aliases_list = function() {
- let aliases_list = document.getElementById("aliases_list");
- return aliases_list;
- };
- this.set_error_message = function(msg) {
- let error_msg =
- "<li>" +
- "<strong>An error occured.</strong></br>" +
- msg +
- "</li>";
- let aliases_list = this.get_aliases_list();
- aliases_list.innerHTML = error_msg;
- };
- this.proceed = function() {
- let start = this.try_catch(this.start);
- start();
- };
- this.start = function() {
- this.set_box_aliases();
- this.set_loading_message();
- let artist_id = this.get_artist_id();
- let storage = new Storage(artist_id);
- let storage_data = storage.load();
- this.set_style_node();
- this.reset_style();
- let hash = this.compute_hash();
- let self = this;
- // If cache is not yet set or if it is no longer valid, query the API
- if (storage_data["hash"] !== hash) {
- this.query_api(artist_id, function(json_data) {
- let data = self.parse_json_data(json_data);
- data["hash"] = hash;
- storage.save(data);
- self.set_aliases(data);
- });
- } else {
- this.set_aliases(storage_data);
- }
- };
- this.set_box_aliases = function() {
- let box_search = document.getElementsByClassName("box_search")[0];
- let box_aliases = this.builder.make_box_aliases();
- box_search.insertAdjacentHTML('beforebegin', box_aliases);
- box_aliases = box_search.parentNode.getElementsByClassName("box_aliases")[0];
- box_aliases.getElementsByClassName("stats")[0].id = "aliases_list";
- };
- this.set_loading_message = function() {
- let aliases_list = this.get_aliases_list();
- aliases_list.innerHTML = "<li>Loading...</li>";
- };
- this.get_artist_id = function() {
- let artist_id = window.location.href.match(/id=(\d+)/)[1];
- return artist_id;
- };
- this.set_style_node = function() {
- let head = document.getElementsByTagName('head')[0];
- let style = document.createElement('style');
- style.type = 'text/css';
- style.id = "artist_alias_filter_css";
- head.appendChild(style);
- };
- this.set_style = function(css) {
- let style = document.getElementById("artist_alias_filter_css");
- style.innerHTML = css;
- };
- this.reset_style = function() {
- let style = "#title_filtering { display: none; }";
- this.set_style(style);
- };
- this.filter_style = function(alias_id) {
- let style =
- "#default_title { display: none; } " +
- ".alias_id:not(.alias_id_" + alias_id.toString() + ") { display: none; }";
- this.set_style(style);
- };
- // Set 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)
- this.compute_hash = function() {
- let elements = document.querySelectorAll("[id^='showimg_']");
- let groups_ids = [];
- for (let i = 0, len = elements.length; i < len; i++) {
- let group_id = elements[i].id.split("_")[1];
- groups_ids.push(group_id);
- }
- groups_ids.sort();
- let version = GM_info.script.version;
- groups_ids.unshift("version:" + version);
- let hash = groups_ids.toString();
- return hash;
- };
- // Parse JSON response after having queried the API and extract
- // main_alias_id, main_name, aliases and groups
- this.parse_json_data = function(json_data) {
- json_data = json_data.response;
- let main_name = json_data.name;
- let main_alias_id = undefined;
- let aliases = {};
- let groups = {};
- let main_id = json_data["id"]
- // Iterate through each artists of each group to find those correct (`id` === `main_id`)
- let torrentgroup = json_data.torrentgroup;
- for (let i = 0, len = torrentgroup.length; i < len; i++) {
- let group = torrentgroup[i];
- let extendedArtists = group["extendedArtists"];
- let found = false;
- let alias_id = -1;
- let group_id = group["groupId"].toString();
- for (let id in extendedArtists) {
- let artists = extendedArtists[id];
- if (artists) {
- for (let j = 0, len_ = artists.length; j < len_; j++) {
- let artist = artists[j];
- 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
- alias_id = artist["aliasid"].toString();
- aliases[alias_id] = artist["name"];
- if ((main_alias_id === undefined) && (artist["name"] === main_name)) {
- // Sometimes, the alias_id 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_alias_id = alias_id;
- }
- 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 (aliasid == -1), the release is not linked to any alias, just the default "[Show All]"
- groups[group_id] = alias_id;
- }
- let data = {
- "main_name": main_name,
- "main_alias_id": main_alias_id,
- "aliases": aliases,
- "groups": groups
- };
- return data;
- };
- this.query_api = function(artist_id, callback) {
- let self = this;
- let url = "/ajax.php?action=artist&id=" + artist_id;
- let xhr = new XMLHttpRequest();
- xhr.timeout = 20000;
- xhr.ontimeout = this.try_catch(
- function() {
- self.set_error_message("The API query timed out.");
- }
- );
- xhr.onerror = this.try_catch(
- function() {
- self.set_error_message("The API query failed.\n" + xhr.statusText);
- }
- );
- xhr.onload = this.try_catch(
- function() {
- if (xhr.status === 200) {
- let data = JSON.parse(xhr.responseText);
- callback(data);
- } else {
- self.set_error_message("The API query returned an error.\n" + xhr.statusText);
- }
- }
- );
- xhr.open("GET", url, true);
- xhr.send(null);
- };
- this.set_alias_title = function(alias_name) {
- document.getElementById("alias_title").innerHTML = "[" + alias_name + "]";
- };
- this.append_alias_filter = function(alias_id, alias_name) {
- let li = this.builder.make_alias_li(alias_id, alias_name);
- let aliases_list = this.get_aliases_list();
- aliases_list.insertAdjacentHTML('beforeend', li);
- };
- this.set_aliases = function(data) {
- if (Object.keys(data["aliases"]).length < 2) {
- this.cancel_process();
- return;
- }
- this.init_alias_title(data["main_name"]);
- this.fill_aliases_list(data["aliases"]);
- this.classify_releases(data["aliases"], data["groups"], data["main_alias_id"]);
- this.bind_filter(data["aliases"]);
- };
- this.cancel_process = function() {
- let box_aliases = document.getElementsByClassName("box_aliases")[0];
- box_aliases.style.display = "none";
- };
- this.init_alias_title = function(main_name) {
- let content = document.getElementById("content");
- let header = content.getElementsByClassName("header")[0];
- let h2 = header.getElementsByTagName("h2")[0];
- h2.id = "default_title";
- let title = this.builder.make_alias_title(main_name);
- h2.insertAdjacentHTML("afterend", title);
- };
- this.fill_aliases_list = function(aliases) {
- let aliases_list = this.get_aliases_list();
- aliases_list.innerHTML = "";
- this.append_alias_filter(-1, "[Show All]");
- let first = aliases_list.getElementsByTagName("a")[0];
- first.style.fontSize = "80%";
- first.style.fontWeight = "bold";
- for (let alias_id in aliases) {
- let name = aliases[alias_id];
- this.append_alias_filter(alias_id, name);
- }
- };
- this.classify_releases = function(aliases, groups, main_alias_id) {
- let torrent_tables = document.getElementsByClassName("torrent_table");
- let categories = document.getElementById("discog_table").getElementsByClassName("box")[0];
- for (let i = 0, len = torrent_tables.length; i < len; i++) {
- let table = torrent_tables[i];
- let id = table.getAttribute("id");
- let aliases_in_this_category = {};
- let discogs = table.getElementsByClassName("discog");
- let alias_id = undefined;
- for (let j = 0, len_ = discogs.length; j < len_; j++) {
- let 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")) {
- let group_id = discog.querySelector("[id^='showimg_']").id.split("_")[1];
- alias_id = groups[group_id];
- aliases_in_this_category[alias_id] = 1;
- if ((alias_id !== main_alias_id) && (alias_id != -1)) {
- let group_info = discog.getElementsByClassName("group_info")[0];
- let strong = group_info.getElementsByTagName("strong")[0];
- let name = aliases[alias_id];
- let alias_text = this.builder.make_alias_release(alias_id, name);
- strong.insertAdjacentHTML("beforeend", alias_text);
- }
- }
- discog.className += " alias_id alias_id_" + alias_id;
- }
- let category_aliases = " alias_id";
- for (let alias in aliases_in_this_category) {
- category_aliases += " alias_id_" + alias;
- }
- table.className += category_aliases;
- categories.querySelector("[href='#" + id + "']").className += category_aliases;
- }
- };
- this.bind_filter = function(aliases) {
- let self = this;
- let filters = document.querySelectorAll("[alias_id]");
- function callback(event) {
- let call = self.try_catch(
- function() {
- let clicked = event.target;
- if (clicked.getAttribute("href") === "#") {
- event.preventDefault();
- }
- let alias_id = clicked.getAttribute("alias_id");
- self.filter_releases(alias_id, aliases);
- }
- );
- call();
- }
- for (let i = 0, len = filters.length; i < len; i++) {
- let filter = filters[i];
- filter.addEventListener("click", callback);
- }
- };
- this.filter_releases = function(alias_id, aliases) {
- let current_alias_id = this.current_alias_id;
- if (alias_id === current_alias_id) return;
- let aliases_list = this.get_aliases_list();
- let current_link = aliases_list.querySelector("[alias_id='" + current_alias_id + "']");
- let new_link = aliases_list.querySelector("[alias_id='" + alias_id + "']");
- current_link.style.fontWeight = "";
- new_link.style.fontWeight = "bold";
- if (alias_id === "-1") {
- this.reset_style();
- } else {
- this.set_alias_title(aliases[alias_id]);
- this.filter_style(alias_id);
- }
- this.current_alias_id = alias_id;
- };
- };
- let manager = new Manager();
- manager.proceed();