Destiny 2 "Find Fireteam" improvements

Fixes some poor design choices on the Destiny 2 "Find Fireteam" page and filters out spam

  1. // ==UserScript==
  2. // @name Destiny 2 "Find Fireteam" improvements
  3. // @namespace D2FFI
  4. // @version 1.204
  5. // @description Fixes some poor design choices on the Destiny 2 "Find Fireteam" page and filters out spam
  6. // @author Richard "mindphlux" Kämmerer
  7. // @match https://www.bungie.net/en/ClanV2/FireteamSearch*
  8. // @match https://www.bungie.net/en/ClanV2/PublicFireteam*
  9. // @icon https://www.google.com/s2/favicons?sz=64&domain=bungie.net
  10. // @grant none
  11. // @license MIT
  12. // ==/UserScript==
  13.  
  14. (function() {
  15. 'use strict';
  16.  
  17. var clanAdverts = /КЛАН|клан|reclut[a|o|iamo]|recherche|recrute|recruit[e|ing|ment]|buscamo[s]|suche/;
  18. var spamStrings = /[carry|help]-d2|[fast\-|my]carry|d2[xur|\-sherpa]|game-job|sky[gold|coach]|trialsnow/;
  19. var defaultTitle = /(.*)\/\/(.*)/;
  20.  
  21. var platformSelect = document.querySelector('select[name=platform]');
  22. var activitySelect = document.querySelector('select[name=activityType]');
  23. var languageSelect = document.querySelector('select[name=lang]');
  24. var disabled = document.querySelector('h2[class=section-header]');
  25.  
  26. // we need to check which page the user is on so we can disable/enable features and prevent errors
  27.  
  28. var currentPage = "";
  29.  
  30. if(/FireteamSearch/.test(window.location.href)) {
  31. currentPage = "search";
  32. }
  33. else if(/PublicFireteam/.test(window.location.href)) {
  34. currentPage = "fireteam";
  35. }
  36.  
  37. // if the API has been disabled (again) we'll display the @BungieHelp twitter feed so the user
  38. // can check what's going on instead of just seeing a mostly blank page
  39. // this only works on the Fireteam search page so we'll just return on any other page
  40.  
  41. if(currentPage == "search") {
  42. if(disabled != null && disabled.innerHTML == "This feature is currently disabled.") {
  43. var disabledParent = disabled.closest('div');
  44.  
  45. var twitterScript = document.createElement('script');
  46. twitterScript.type = 'text/javascript';
  47. twitterScript.src = 'https://platform.twitter.com/widgets.js';
  48. document.head.appendChild(twitterScript);
  49.  
  50. var twitterEmbed = document.createElement('a');
  51. twitterEmbed.classList.add('twitter-timeline');
  52. twitterEmbed.dataset.theme = 'dark';
  53. twitterEmbed.href = 'https://twitter.com/BungieHelp?ref_src=twsrc%5Etfw';
  54. disabledParent.appendChild(twitterEmbed);
  55.  
  56. return;
  57. }
  58. }
  59. else if(currentPage == "") return;
  60.  
  61. var activities = {
  62. 0: "Anything",
  63. 2: "Crucible",
  64. 3: "Trials of Osiris",
  65. 4: "Nightfall",
  66. 5: "Up For Anything",
  67. 6: "Gambit",
  68. 7: "Blind Well",
  69. 12: "Nightmare Hunt",
  70. 14: "Altar of Sorrow",
  71. 20: "Raid: Last Wish",
  72. 21: "Raid: Garden of Salvation",
  73. 22: "Raid: Deep Stone Crypt",
  74. 23: "Exo Challenge",
  75. 25: "Empire Hunt",
  76. 27: "Exotic Quest",
  77. 28: "Raid: Vault of Glass",
  78. 33: "Dungeon: Shattered Throne",
  79. 34: "Dungeon: Prophecy",
  80. 35: "Dungeon: Pit of Heresy",
  81. 36: "Dares of Eternity",
  82. 37: "Dungeon: Grasp of Avarice",
  83. 38: "Raid: Vow of the Disciple",
  84. 39: "Campaign",
  85. 40: "The Wellspring",
  86. 41: "S16: Battlegrounds",
  87. 43: "Dungeon: Duality",
  88. 44: "S17: Nightmare Containment",
  89. 45: "S17: Sever",
  90. 47: "S18: Ketchcrash",
  91. 48: "S18: Expedition",
  92. 49: "S18: Pirate Hideout",
  93. 50: "Raid: King's Fall",
  94. 51: "Battlegrounds",
  95. 52: "Dungeon: Spire of the Watcher",
  96. 53: "S19: Operations",
  97. 54: "Looking For Help",
  98. 55: "Keep It Chill",
  99. };
  100.  
  101. // remove Bungie advert and replace it with a warning about being not logged in if that's the case
  102. // since dynamically set body classes aren't available at script runtime we're checking cookies
  103.  
  104. var cookies = document.cookie.split(";");
  105.  
  106. var isLoggedIn = false;
  107.  
  108. cookies.forEach((item) => {
  109. if(item.trim().startsWith("bunglesight")) isLoggedIn = true;
  110. });
  111.  
  112. // only needed for Fireteam search page
  113. if(currentPage == "search") {
  114. if(isLoggedIn) {
  115. document.querySelector('.promo').remove();
  116. }
  117. else {
  118. document.querySelector('.promo').innerHTML = '<strong><span style="color:red">You must be logged in to use Fireteam Search!</span></strong>';
  119. }
  120. }
  121.  
  122. // to prevent the browser from entering an endless loop of page reloads we're using a hash to see if we already reloaded
  123.  
  124. function ReloadPage(page) {
  125. if(window.location.hash == page || window.location.hash == null) return;
  126. location.href = "https://www.bungie.net/en/ClanV2/FireteamSearch?platform=" +
  127. platformSelect[platformSelect.selectedIndex].value +
  128. "&activityType=" +
  129. activitySelect[activitySelect.selectedIndex].value +
  130. "&lang=" + languageSelect[languageSelect.selectedIndex].value +
  131. "#" +
  132. page;
  133. }
  134.  
  135. // reroute dropdowns to our own function so the userscript still works after using the select boxes
  136. // only needed on Fireteam search page
  137.  
  138. if(currentPage == "search") {
  139.  
  140. platformSelect.onchange = (e) => {
  141. e.preventDefault();
  142. e.stopPropagation();
  143. ReloadPage("platform");
  144. }
  145.  
  146. activitySelect.onchange = (e) => {
  147. e.preventDefault();
  148. e.stopPropagation();
  149. ReloadPage("activity");
  150. }
  151.  
  152. languageSelect.onchange = (e) => {
  153. e.preventDefault();
  154. e.stopPropagation();
  155. ReloadPage("language");
  156. }
  157. }
  158.  
  159. // add textual description of the activity
  160. // so people who can't remember dozens of icons can actually understand what's going on
  161.  
  162. if(currentPage == "search") {
  163.  
  164. // Fireteam search page
  165. var lis = document.getElementById('clansList').querySelectorAll('li');
  166. lis.forEach((item, index) => {
  167. var activityId = item.querySelector('.activity-icon').getAttribute('data-activity');
  168. var title = item.querySelector('.title');
  169.  
  170. // removes the post if it's spam or a clan ad
  171. if(spamStrings.test(title.innerHTML.toLowerCase()) || clanAdverts.test(title.innerHTML.toLowerCase())) {
  172. item.remove();
  173. return;
  174. }
  175.  
  176. // remove the original post title if it was left blank (which is then replaced by Bungie with the same info we already added)
  177. var newTitle = (activities[activityId] != null ? activities[activityId] : "N/A");
  178. if(!defaultTitle.test(title.innerHTML)) {
  179. newTitle += " | " + title.innerHTML;
  180. }
  181.  
  182. title.innerHTML = newTitle;
  183. });
  184. }
  185. else if(currentPage == "fireteam")
  186. {
  187.  
  188. // Fireteam page
  189. var activityId = document.querySelector('span[class=activity-icon]').getAttribute('data-activity');
  190. var title = document.querySelector('h2[class=section-header]');
  191.  
  192. // remove the original title if it was left blank (which is then replaced by Bungie with the same info we already added)
  193. var newTitle = (activities[activityId] != null ? activities[activityId] : "N/A");
  194. if(!defaultTitle.test(title.innerHTML)) {
  195. newTitle += " | " + title.innerHTML;
  196. }
  197.  
  198. // for the sake of consistency let's also change the window title accordingly
  199. title.innerHTML = newTitle;
  200. document.title = newTitle + " | Bungie.net";
  201. }
  202.  
  203. })();