RED Artist Aliases Filter

Add a box on artist page to filter based on aliases

  1. // ==UserScript==
  2. // @name RED Artist Aliases Filter
  3. // @namespace PTH Artist Aliases Filter
  4. // @description Add a box on artist page to filter based on aliases
  5. // @include https://passtheheadphones.me/artist.php?id=*
  6. // @include https://redacted.ch/artist.php?id=*
  7. // @include https://redacted.sh/artist.php?id=*
  8. // @version 1.3.7
  9. // @grant GM_registerMenuCommand
  10. // ==/UserScript==
  11.  
  12. /* Avoid using jQuery in this userscript, prioritize vanilla javascript as a matter of performance on big pages */
  13.  
  14. "use strict";
  15.  
  16. function Storage(alias_id) {
  17. this.key = "red.artists_aliases_filter." + alias_id;
  18.  
  19. this.save = function(data) {
  20. if (typeof data !== 'string') {
  21. data = JSON.stringify(data);
  22. }
  23. sessionStorage.setItem(this.key, data);
  24. };
  25.  
  26. this.load = function() {
  27. let storage = sessionStorage.getItem(this.key) || "{}";
  28. return JSON.parse(storage);
  29. };
  30. };
  31.  
  32. function ConfigManager() {
  33. this.key = "red.artists_aliases_filter.CONFIG";
  34.  
  35. this.default = {
  36. "display_nb_groups": 0
  37. };
  38.  
  39. this.save = function(config) {
  40. if (typeof config !== 'string') {
  41. config = JSON.stringify(config);
  42. }
  43. localStorage.setItem(this.key, config);
  44. };
  45.  
  46. this.load = function() {
  47. let config = {};
  48. for (let key in this.default) {
  49. config[key] = this.default[key];
  50. }
  51. let parsed = JSON.parse(localStorage.getItem(this.key) || "{}");
  52. for (let key in parsed) {
  53. if (this.default.hasOwnProperty(key)) {
  54. config[key] = parsed[key];
  55. }
  56. }
  57. return config;
  58. };
  59. };
  60.  
  61. function Builder() {
  62. this.make_box_aliases = function() {
  63. let box_aliases =
  64. "<div class='box box_aliases'>" +
  65. "<div class='head'><strong>Aliases</strong></div>" +
  66. "<ul class='stats nobullet'></ul>" +
  67. "</div>";
  68. return box_aliases;
  69. };
  70.  
  71. this.make_alias_release = function(alias_id, alias_name) {
  72. let alias_release =
  73. "<text class='filtering_off'>" +
  74. " <i>as</i> " +
  75. "<a href='#content' class='alias_filter' alias_id='" + alias_id + "'>" +
  76. alias_name +
  77. "</a>" +
  78. "</text>";
  79. return alias_release;
  80. };
  81.  
  82. this.mousehover_nb_groups = "Number of releases with this alias";
  83.  
  84. this.make_alias_li = function(alias_id, alias_name, nb_groups) {
  85. let nb_groups_str = "";
  86. if (nb_groups !== undefined) {
  87. nb_groups_str = "(" + nb_groups.toString() + ")";
  88. }
  89. let span_nb_groups =
  90. "<span title='" + this.mousehover_nb_groups + "' class='alias_list_nb_groups'>" +
  91. nb_groups_str +
  92. "</span>";
  93. let alias_li =
  94. "<li>" +
  95. "<a href='#' class='alias_filter' alias_id='" + alias_id.toString() + "'>" + alias_name + "</a>" +
  96. " " + span_nb_groups +
  97. "</li>";
  98. return alias_li;
  99. };
  100.  
  101. this.make_tag_ul = function(alias_id, innerHTML) {
  102. let tag_ul =
  103. "<ul class='stats nobullet filtering_on alias_id alias_id_" + alias_id + "'>" +
  104. innerHTML +
  105. "</ul>";
  106. return tag_ul;
  107. };
  108.  
  109. this.make_tag_li = function(alias_name, tag_name, tag_count) {
  110. let href = "torrents.php?taglist=" + tag_name +
  111. "&amp;artistname=" + encodeURIComponent(alias_name) +
  112. "&amp;action=advanced&amp;searchsubmit=1";
  113.  
  114. // Count do not need formatting (see Bach) on the contrary of stats
  115. let tag_li =
  116. "<li>" +
  117. "<a href='" + href + "'>" + tag_name + "</a> (" + tag_count.toString() + ")" +
  118. "</li>";
  119. return tag_li;
  120. };
  121.  
  122. this.make_stats_ul = function(alias_id, innerHTML) {
  123. let stats_ul =
  124. "<ul class='stats nobullet filtering_on alias_id alias_id_" + alias_id + "'>" +
  125. innerHTML +
  126. "</ul>";
  127. return stats_ul;
  128. }
  129.  
  130. this.make_stats_li = function(type, number) {
  131. let stats_li =
  132. "<li>" +
  133. "Number of " + type + ": " + number.toLocaleString("en") +
  134. "</li>";
  135. return stats_li;
  136. }
  137.  
  138. this.make_alias_title = function(artist_name) {
  139. let main = "<a href='#' class='alias_filter' alias_id='-1'>" + artist_name + "</a>";
  140. let alias = "<span id='alias_title'></span>";
  141. let span_nb_groups =
  142. "<span id='alias_title_nb_groups' title='" + this.mousehover_nb_groups + "'>" +
  143. "</span>";
  144. let title =
  145. "<h2 class='filtering_on'>" +
  146. main + " " + alias + " " + span_nb_groups +
  147. "</h2>";
  148. return title;
  149. };
  150.  
  151. this.make_css_style = function(id) {
  152. let style =
  153. "<style type='text/css' " + (id === undefined ? "" : "id='" + id + "'") + ">" +
  154. "</style>";
  155. return style;
  156. }
  157. };
  158.  
  159. function Manager() {
  160. this.builder = new Builder();
  161. this.config_manager = new ConfigManager();
  162.  
  163. this.config = undefined;
  164.  
  165. this.current_alias_id = "-1";
  166.  
  167. this.try_catch = function(func) {
  168. let self = this;
  169. func = func.bind(this);
  170.  
  171. function wrapped() {
  172. try {
  173. func();
  174. } catch(err) {
  175. let err_msg = err.message + " (line " + err.lineNumber + ")";
  176. console.log("Error in RED AAF: '" + err_msg + "'.");
  177. self.set_error_message(err_msg);
  178. }
  179. }
  180.  
  181. return wrapped;
  182. };
  183.  
  184. this.get_aliases_list = function() {
  185. let aliases_list = document.getElementById("aliases_list");
  186. return aliases_list;
  187. };
  188.  
  189. this.set_error_message = function(msg) {
  190. let error_msg =
  191. "<li>" +
  192. "<strong>An error occured.</strong></br>" +
  193. msg +
  194. "</li>";
  195. let aliases_list = this.get_aliases_list();
  196. aliases_list.innerHTML = error_msg;
  197. };
  198.  
  199. this.proceed = function() {
  200. let start = this.try_catch(this.start);
  201. start();
  202. };
  203.  
  204. this.start = function() {
  205. let artist_id = this.get_artist_id();
  206.  
  207. this.set_box_aliases();
  208. this.set_loading_message();
  209.  
  210. this.set_style_node();
  211. this.reset_style();
  212.  
  213. let config = this.config_manager.load();
  214. this.config = config;
  215. this.apply_config(config);
  216. this.register_config();
  217.  
  218. let hash = this.compute_hash();
  219.  
  220. let storage = new Storage(artist_id);
  221. let storage_data = storage.load();
  222.  
  223. let self = this;
  224.  
  225. // If cache is not yet set or if it is no longer valid, query the API
  226. if (storage_data["hash"] !== hash) {
  227. this.query_api(artist_id, function(json_data) {
  228. let data = self.parse_json_data(json_data);
  229. data["hash"] = hash;
  230. storage.save(data);
  231. self.set_aliases(data);
  232. });
  233. } else {
  234. this.set_aliases(storage_data);
  235. }
  236. };
  237.  
  238. this.set_box_aliases = function() {
  239. let box_search = document.getElementsByClassName("box_search")[0];
  240. let box_aliases = this.builder.make_box_aliases();
  241. box_search.insertAdjacentHTML('beforebegin', box_aliases);
  242. box_aliases = box_search.parentNode.getElementsByClassName("box_aliases")[0];
  243. box_aliases.getElementsByClassName("stats")[0].id = "aliases_list";
  244. };
  245.  
  246. this.set_loading_message = function() {
  247. let aliases_list = this.get_aliases_list();
  248. aliases_list.innerHTML = "<li>Loading...</li>";
  249. };
  250.  
  251. this.get_artist_id = function() {
  252. let artist_id = window.location.href.match(/id=(\d+)/)[1];
  253. return artist_id;
  254. };
  255.  
  256. this.set_style_node = function() {
  257. let head = document.getElementsByTagName('head')[0];
  258. let style_filter = this.builder.make_css_style("artist_alias_filter_css");
  259. let style_nb_groups = this.builder.make_css_style("artist_alias_filter_nb_groups_css");
  260. head.insertAdjacentHTML('beforeend', style_filter);
  261. head.insertAdjacentHTML('beforeend', style_nb_groups);
  262. };
  263.  
  264. this.set_style_filter = function(css) {
  265. let style = document.getElementById("artist_alias_filter_css");
  266. style.innerHTML = css;
  267. };
  268.  
  269. this.set_style_nb_groups = function(css) {
  270. let style = document.getElementById("artist_alias_filter_nb_groups_css");
  271. style.innerHTML = css;
  272. };
  273.  
  274. this.reset_style = function() {
  275. let style =
  276. ".filtering_on { display: none; }";
  277. this.set_style_filter(style);
  278. };
  279.  
  280. this.filter_style = function(alias_id) {
  281. let style =
  282. ".filtering_off { display: none; } " +
  283. ".alias_id:not(.alias_id_" + alias_id.toString() + ") { display: none; }";
  284. this.set_style_filter(style);
  285. };
  286.  
  287. this.register_config = function() {
  288. let self = this;
  289.  
  290. let caption = "RED Artist Alias Filter - Configuration";
  291.  
  292. function callback() {
  293. let new_config = self.configure(self.config);
  294. self.config = new_config;
  295. self.config_manager.save(new_config);
  296. self.apply_config(new_config);
  297. };
  298.  
  299. // Undefined using GreaseMonkey
  300. if (typeof GM_registerMenuCommand != "undefined") {
  301. GM_registerMenuCommand(caption, callback);
  302. }
  303. };
  304.  
  305. this.configure = function(current_config) {
  306. let new_config = {};
  307. for (var key in current_config) {
  308. new_config[key] = current_config[key];
  309. }
  310.  
  311. let display_nb_groups = current_config["display_nb_groups"];
  312. let text =
  313. "Display of the number of releases per alias:\n" +
  314. "0. Don't display\n" +
  315. "1. Display it in the Aliases box\n" +
  316. "2. Display it in the title while on a filtered page\n" +
  317. "3. Both";
  318.  
  319. let value = prompt(text, display_nb_groups);
  320.  
  321. if (value === null) {
  322. return current_config;
  323. }
  324.  
  325. let val = parseInt(value);
  326.  
  327. if ([0, 1, 2, 3].indexOf(val) === -1) {
  328. alert("Invalid value!");
  329. return current_config;
  330. }
  331.  
  332. new_config["display_nb_groups"] = val;
  333. return new_config
  334. };
  335.  
  336. this.apply_config = function(config) {
  337. let display_nb_groups = config["display_nb_groups"];
  338. let style = "";
  339.  
  340. if (display_nb_groups === 0 || display_nb_groups === 1) {
  341. style += "#alias_title_nb_groups { display: none; } ";
  342. }
  343.  
  344. if (display_nb_groups === 0 || display_nb_groups === 2) {
  345. style += ".alias_list_nb_groups { display: none; } ";
  346. }
  347.  
  348. this.set_style_nb_groups(style);
  349. };
  350.  
  351. // Set an array `groups_ids` of all groupid on the current artist page
  352. // to ensure that cache is still valid (no new group since last visit)
  353. this.compute_hash = function() {
  354. let elements = document.querySelectorAll("[id^='showimg_']");
  355. let groups_ids = [];
  356. for (let i = 0, len = elements.length; i < len; i++) {
  357. let group_id = elements[i].id.split("_")[1];
  358. groups_ids.push(group_id);
  359. }
  360. groups_ids.sort();
  361.  
  362. let version = GM_info.script.version;
  363. groups_ids.unshift("version:" + version);
  364.  
  365. let hash = groups_ids.toString();
  366. return hash;
  367. };
  368.  
  369. // Parse JSON response after having queried the API and extract
  370. // main_alias_id, main_name, aliases, groups, and tags
  371. this.parse_json_data = function(json_data) {
  372. json_data = json_data.response;
  373. let main_name = json_data.name;
  374. let main_alias_id = undefined;
  375. let aliases = {}; // alias_id => alias_name
  376. let groups = {}; // group_id => alias_id
  377. let aliases_tags = {}; // alias_id => tag_name => count
  378. let tags = {}; // alias_id => [tag_name, count]
  379.  
  380. let main_id = json_data["id"]
  381.  
  382. // Iterate through each artists of each group to find those correct (`id` === `main_id`)
  383. let torrentgroup = json_data.torrentgroup;
  384. for (let i = 0, len = torrentgroup.length; i < len; i++) {
  385. let group = torrentgroup[i];
  386.  
  387. // Same release can appear twice in different categories
  388. if (groups.hasOwnProperty(group) && groups[group] !== "-1") {
  389. continue;
  390. }
  391.  
  392. let extendedArtists = group["extendedArtists"];
  393. let release_type = group["releaseType"];
  394. let found = false;
  395.  
  396. let alias_id = "-1";
  397. let group_id = group["groupId"].toString();
  398.  
  399. // Search alias_id through the list of artists lists
  400. for (let id in extendedArtists) {
  401. let artists = extendedArtists[id];
  402. if (artists) {
  403. for (let j = 0, len_ = artists.length; j < len_; j++) {
  404. let artist = artists[j];
  405. if (artist["id"] === main_id) {
  406. // This is not perfect:
  407. // If a release contains references to multiple aliases of the same artist, it keeps only the first one
  408. // For example, see group 72607761 of Snoop Dogg
  409. // However, it is better for performance not to have to iterate through an array
  410. // So let's say 1 group release => 1 artist alias
  411. alias_id = artist["aliasid"].toString();
  412. aliases[alias_id] = artist["name"];
  413.  
  414. if ((main_alias_id === undefined) && (artist["name"] === main_name)) {
  415. // Sometimes, the alias_id associated with the artist main id differs, see artist 24926
  416. // But we need it to not display "as Alias" besides releases of main artist name
  417. main_alias_id = alias_id;
  418. }
  419. found = true;
  420. break;
  421. }
  422. }
  423. }
  424. if (found) break;
  425. }
  426.  
  427. // Sometimes, release does not contain any artist because of an issue with the API
  428. // See: https://what.cd/forums.php?action=viewthread&threadid=192517&postid=5290204
  429. // In such a case (aliasid == -1), the release is not linked to any alias, just the default "[Show All]"
  430. groups[group_id] = alias_id;
  431.  
  432. // Create the dictionary to update tags box
  433. // Skip compilations and soundtracks
  434. // See Gazelle code source: https://github.com/WhatCD/Gazelle/blob/2aa4553f7a508e0051cae2249229bfe0f3f99c89/sections/artist/artist.php#L258
  435. if (release_type !== 7 && release_type !== 3 && alias_id !== "-1") {
  436. if (!aliases_tags.hasOwnProperty(alias_id)) {
  437. aliases_tags[alias_id] = {};
  438. }
  439. let artist_tags = aliases_tags[alias_id];
  440. let group_tags = group["tags"];
  441. for (let j = 0, len_ = group_tags.length; j < len_; j++) {
  442. let tag = group_tags[j];
  443. if (!artist_tags.hasOwnProperty(tag)) {
  444. artist_tags[tag] = 1;
  445. } else {
  446. artist_tags[tag] += 1
  447. }
  448. }
  449. }
  450. }
  451.  
  452. // Sort tags list by count and keep only top 50 (see Gazelle code source)
  453. for (let artist_id in aliases_tags) {
  454. let tags_dict = aliases_tags[artist_id];
  455. let tags_pairs = Object.keys(tags_dict).map(function(tag) {
  456. return [tag, tags_dict[tag]];
  457. });
  458. tags_pairs.sort(function(pair_1, pair_2) {
  459. return pair_2[1] - pair_1[1];
  460. });
  461. tags_pairs = tags_pairs.slice(0, 50);
  462. tags[artist_id] = tags_pairs;
  463. }
  464.  
  465. let data = {
  466. "tags": tags,
  467. "main_name": main_name,
  468. "main_alias_id": main_alias_id,
  469. "aliases": aliases,
  470. "groups": groups
  471. };
  472.  
  473. return data;
  474. };
  475.  
  476. this.query_api = function(artist_id, callback) {
  477. let self = this;
  478. let url = "/ajax.php?action=artist&id=" + artist_id;
  479.  
  480. let xhr = new XMLHttpRequest();
  481. xhr.timeout = 20000;
  482.  
  483. xhr.ontimeout = this.try_catch(
  484. function() {
  485. self.set_error_message("The API query timed out.");
  486. }
  487. );
  488.  
  489. xhr.onerror = this.try_catch(
  490. function() {
  491. self.set_error_message("The API query failed.\n" + xhr.statusText);
  492. }
  493. );
  494.  
  495. xhr.onload = this.try_catch(
  496. function() {
  497. if (xhr.status === 200) {
  498. let data = JSON.parse(xhr.responseText);
  499. callback(data);
  500. } else {
  501. self.set_error_message("The API query returned an error.\n" + xhr.statusText);
  502. }
  503. }
  504. );
  505.  
  506. xhr.open("GET", url, true);
  507. xhr.send(null);
  508. };
  509.  
  510. this.set_alias_title = function(alias_name, nb_groups) {
  511. document.getElementById("alias_title").innerHTML = "[" + alias_name + "]";
  512. document.getElementById("alias_title_nb_groups").innerHTML = "(" + nb_groups.toString() + ")";
  513. };
  514.  
  515. this.append_alias_filter = function(alias_id, alias_name, nb_groups) {
  516. let li = this.builder.make_alias_li(alias_id, alias_name, nb_groups);
  517. let aliases_list = this.get_aliases_list();
  518. aliases_list.insertAdjacentHTML('beforeend', li);
  519. };
  520.  
  521. this.set_aliases = function(data) {
  522. if (Object.keys(data["aliases"]).length < 2) {
  523. this.cancel_process();
  524. return;
  525. }
  526. this.init_alias_title(data["main_name"]);
  527. let stats = this.classify_releases(data["aliases"], data["groups"], data["main_alias_id"]);
  528. this.populate_tags(data["aliases"], data["tags"]);
  529. this.compute_stats(stats);
  530. this.fill_aliases_list(data["aliases"], stats);
  531. this.bind_filter(data["aliases"], stats);
  532. };
  533.  
  534. this.cancel_process = function() {
  535. let box_aliases = document.getElementsByClassName("box_aliases")[0];
  536. box_aliases.style.display = "none";
  537. };
  538.  
  539. this.init_alias_title = function(main_name) {
  540. let content = document.getElementById("content");
  541. let header = content.getElementsByClassName("header")[0];
  542. let h2 = header.getElementsByTagName("h2")[0];
  543. h2.className += " filtering_off";
  544.  
  545. let title = this.builder.make_alias_title(main_name);
  546.  
  547. h2.insertAdjacentHTML("afterend", title);
  548. };
  549.  
  550. this.fill_aliases_list = function(aliases, stats) {
  551. let aliases_list = this.get_aliases_list();
  552. aliases_list.innerHTML = "";
  553. this.append_alias_filter("-1", "[Show All]");
  554. let first = aliases_list.getElementsByTagName("a")[0];
  555. first.style.fontSize = "80%";
  556. first.style.fontWeight = "bold";
  557. for (let alias_id in aliases) {
  558. let name = aliases[alias_id];
  559. this.append_alias_filter(alias_id, name, stats[alias_id]["groups"]);
  560. }
  561. };
  562.  
  563. this.classify_releases = function(aliases, groups, main_alias_id) {
  564. let stats = {}; // Compute stats while classifying trough torrents
  565. let torrent_tables = document.getElementsByClassName("torrent_table");
  566. let categories = document.getElementById("discog_table").getElementsByClassName("box")[0];
  567.  
  568. for (let alias_id in aliases) {
  569. stats[alias_id] = {
  570. "groups_ids": {},
  571. "groups": 0,
  572. "torrents": 0,
  573. "seeders": 0,
  574. "leechers": 0,
  575. "snatches": 0
  576. }
  577. }
  578.  
  579. for (let i = 0, len = torrent_tables.length; i < len; i++) {
  580. let table = torrent_tables[i];
  581. let category_id = table.getAttribute("id");
  582. let aliases_in_this_category = {};
  583.  
  584. let discogs = table.getElementsByClassName("discog");
  585. let count_stats = false;
  586. let alias_id = undefined;
  587. let group_id = undefined;
  588.  
  589. for (let j = 0, len_ = discogs.length; j < len_; j++) {
  590. let discog = discogs[j];
  591. // The groupid of each torrent row is the same that the previous encountered main release row
  592. // This avoid having to extract groupid value at each iteration
  593.  
  594. if (discog.classList.contains("group")) {
  595. // Retrieve group_id and alias_id for this release
  596. group_id = discog.querySelector("[id^='showimg_']").id.split("_")[1];
  597. alias_id = groups[group_id];
  598. aliases_in_this_category[alias_id] = 1;
  599.  
  600. // Append "as Alias" to release artist name if needed
  601. if (alias_id !== main_alias_id && alias_id !== "-1") {
  602. let group_info = discog.getElementsByClassName("group_info")[0];
  603. let strong = group_info.getElementsByTagName("strong")[0];
  604. let name = aliases[alias_id];
  605.  
  606. let alias_text = this.builder.make_alias_release(alias_id, name);
  607.  
  608. strong.insertAdjacentHTML("beforeend", alias_text);
  609. }
  610.  
  611. // Avoid same torrents in two different categories to be counted twice for stats
  612. if (alias_id === "-1" || stats[alias_id]["groups_ids"].hasOwnProperty(group_id)) {
  613. count_stats = false;
  614. } else {
  615. stats[alias_id]["groups_ids"][group_id] = 1;
  616. stats[alias_id]["groups"] += 1;
  617. count_stats = true;
  618. }
  619. } else if (count_stats && discog.classList.contains("torrent_row") && alias_id !== "-1") {
  620. // Update stats with the current torrent
  621. let alias_stats = stats[alias_id];
  622. let cols = discog.getElementsByClassName("number_column");
  623.  
  624. let seeders = parseInt(cols[2].innerText);
  625. let leechers = parseInt(cols[3].innerText);
  626. let snatches = parseInt(cols[1].innerText);
  627.  
  628. alias_stats["torrents"] += 1;
  629. alias_stats["seeders"] += seeders;
  630. alias_stats["leechers"] += leechers;
  631. alias_stats["snatches"] += snatches;
  632. }
  633.  
  634. discog.className += " alias_id alias_id_" + alias_id;
  635. }
  636.  
  637. let category_aliases = " alias_id";
  638. for (let alias_id in aliases_in_this_category) {
  639. category_aliases += " alias_id_" + alias_id;
  640. }
  641. table.className += category_aliases;
  642. categories.querySelector("[href='#" + category_id + "']").className += category_aliases;
  643. }
  644.  
  645. return stats;
  646. };
  647.  
  648. this.bind_filter = function(aliases, stats) {
  649. let self = this;
  650. let filters = document.getElementsByClassName("alias_filter");
  651.  
  652. function callback(event) {
  653. let call = self.try_catch(
  654. function() {
  655. let clicked = event.target;
  656. if (clicked.getAttribute("href") === "#") {
  657. event.preventDefault();
  658. }
  659. let alias_id = clicked.getAttribute("alias_id");
  660. self.filter_releases(alias_id, aliases, stats);
  661. }
  662. );
  663. call();
  664. }
  665.  
  666. for (let i = 0, len = filters.length; i < len; i++) {
  667. let filter = filters[i];
  668. filter.addEventListener("click", callback);
  669. }
  670. };
  671.  
  672. this.populate_tags = function(aliases, tags) {
  673. let box_tags = document.getElementsByClassName("box_tags")[0];
  674. if (!box_tags) {
  675. return;
  676. }
  677.  
  678. let tag_list = box_tags.getElementsByClassName("stats")[0];
  679. tag_list.className += " filtering_off";
  680.  
  681. for (let alias_id in tags) {
  682. let alias_tags = tags[alias_id];
  683. let alias_name = aliases[alias_id];
  684. let li_list = "";
  685.  
  686. for (let i = 0, len = alias_tags.length; i < len; i++) {
  687. let tag_and_count = alias_tags[i];
  688. let tag = tag_and_count[0];
  689. let count = tag_and_count[1];
  690. let li = this.builder.make_tag_li(alias_name, tag, count);
  691. li_list += li;
  692. }
  693.  
  694. if (li_list === "") {
  695. li_list = "<li>No torrent tags</li>";
  696. }
  697.  
  698. let ul = this.builder.make_tag_ul(alias_id, li_list);
  699. tag_list.insertAdjacentHTML("beforebegin", ul);
  700. }
  701. };
  702.  
  703. this.compute_stats = function(stats) {
  704. let box_stats = document.getElementsByClassName("box_statistics_artist")[0];
  705. if (!box_stats) {
  706. return;
  707. }
  708.  
  709. let stats_list = box_stats.getElementsByClassName("stats")[0];
  710. stats_list.className += " filtering_off";
  711.  
  712. let builder = this.builder;
  713. let labels = ["groups", "torrents", "seeders", "leechers", "snatches"];
  714.  
  715. for (let alias_id in stats) {
  716. let alias_stats = stats[alias_id];
  717. let li_list = "";
  718.  
  719. for (let i = 0, len = labels.length; i < len; i++) {
  720. let label = labels[i];
  721. li_list += builder.make_stats_li(label, alias_stats[label]);
  722. }
  723.  
  724. let ul = builder.make_stats_ul(alias_id, li_list);
  725. stats_list.insertAdjacentHTML("beforebegin", ul);
  726. }
  727. };
  728.  
  729. this.filter_releases = function(alias_id, aliases, stats) {
  730. let current_alias_id = this.current_alias_id;
  731. if (alias_id === current_alias_id) return;
  732.  
  733. let aliases_list = this.get_aliases_list();
  734. let current_link = aliases_list.querySelector("[alias_id='" + current_alias_id + "']");
  735. let new_link = aliases_list.querySelector("[alias_id='" + alias_id + "']");
  736.  
  737. current_link.style.fontWeight = "";
  738. new_link.style.fontWeight = "bold";
  739.  
  740. if (alias_id === "-1") {
  741. this.reset_style();
  742. } else {
  743. this.set_alias_title(aliases[alias_id], stats[alias_id]["groups"]);
  744. this.filter_style(alias_id);
  745. }
  746.  
  747. this.current_alias_id = alias_id;
  748. };
  749. };
  750.  
  751. let manager = new Manager();
  752. manager.proceed();