NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @namespace https://openuserjs.org/users/Xegor // @name Bungie.net Enhanced LFG // @description Adds some functionality to Bungie.net, such as improved LFG. // @author Xegor // @copyright 2019, Xegor (https://openuserjs.org/users/Xegor) // @license 0BSD // @version 0.0.7 // @match https://www.bungie.net/* // @grant none // @updateURL https://openuserjs.org/meta/Xegor/Bungie.net_Enhanced_LFG.meta.js // @downloadURL https://openuserjs.org/src/scripts/Xegor/Bungie.net_Enhanced_LFG.user.js // ==/UserScript== // ==OpenUserJS== // @author Xegor // ==/OpenUserJS== (function () { 'use strict'; // Improvements to LFG page function setupFireteamSearch() { if (window.location.pathname.indexOf("ClanV2/FireteamSearch") == -1) { return; } const css = document.createElement("style"); css.type = "text/css"; css.innerText = ` .RefreshIcon { } .RefreshIcon.RefreshIconBusy { color: tomato; -webkit-animation: 0.5s linear 0s 1 RefreshIconSpin; -moz-animation: 0.5s linear 0s 1 RefreshIconSpin; animation: 0.5s linear 0s 1 RefreshIconSpin; } @keyframes RefreshIconSpin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } } `; document.body.appendChild(css); const refs = { refreshButton: null }; function addDiv(html) { const div = document.createElement("div"); div.style.marginTop = "auto"; div.style.marginBottom = "auto"; div.innerHTML = html; document.getElementsByClassName("options-container")[0].appendChild(div); return div; } function refreshList() { refs.refreshButton.classList.add("RefreshIconBusy"); let event = document.createEvent('Event'); event.initEvent('change', true, true); document.getElementsByName("activityType")[1].dispatchEvent(event); console.log("refresh"); } let autorefreshHandle = null; let autorefreshEnabled = false; let autorefreshInterval = 0; let windowActive = true; function updateAutorefresh(forceImmediate) { if (autorefreshHandle !== null) { clearTimeout(autorefreshHandle); autorefreshHandle = null; } if (autorefreshEnabled && windowActive) { if (forceImmediate) { refreshList(); } else { autorefreshHandle = setTimeout(refreshList, (autorefreshInterval * 1000) | 0); } } } window.onfocus = (function () { windowActive = true; updateAutorefresh(true); }); window.onblur = (function () { windowActive = false; updateAutorefresh(); }); const prestigeRegexp = /prestige|(\bpres(t)?\b)/i; const activityRegexps = [ { activity: "Raid", regexp: /\bsos\b|spire/i, icon: "//www.bungie.net/common/destiny2_content/icons/70422198861e09744fbc020bf1925be5.jpg" }, { activity: "Raid", regexp: /\beow\b|eater/i, icon: "//www.bungie.net/common/destiny2_content/icons/69adea04559ff05a3422358109747187.jpg" }, { activity: "Raid", regexp: /levi|\blev\b/i, icon: "//www.bungie.net/common/destiny2_content/icons/3edffbccc60b995c5e5deed0b7f07c1c.jpg" }, { activity: "Raid", regexp: /wish|(\blw\b)|riven|shuro|kalli|morgeth|vault|queenswalk/i, icon: "//www.bungie.net/common/destiny2_content/icons/ecc3e805988dd9947f37c46428e4a12b.jpg" }, { activity: "Raid", regexp: /scourge|(\bsotp\b)/i, icon: "//www.bungie.net/common/destiny2_content/icons/1879398bc8a50d47cdd14cc746c073e1.jpg" }, { activity: "Raid", regexp: /crown|(\bcos\b)/i, icon: "//www.bungie.net/common/destiny2_content/icons/6039feb4c132650cab776f8cb872441d.jpg" }, ]; // // Filter by text // let div = addDiv(` <div class="form-element companion-text-input"> <input type="text" id="text_filter" name="text_filter" placeholder="Filter by text..." onsubmit="return false;"/> </div> `); const textFilter = document.getElementById("text_filter"); function updateFilters() { const fireteams = document.getElementsByClassName("item-fireteam"); let regexps = []; let filterText = textFilter.value ? textFilter.value.trim() : ""; if (filterText[0] === '/' && filterText[filterText.length - 2] === '/') { let re = filterText.substring(1, filterText.length - 2); if (re.length) { try { regexps.push(new RegExp(re, "i")); } catch (err) { } } } else { let words = filterText.split(/\s+/); for (let i = 0; i < words.length; ++i) { let word = words[i].trim().replace(/\*/g, "\\S*"); //word = "\\b" + word + "\\b"; try { regexps.push(new RegExp(word, "i")); } catch (err) { } } } for (let i = 0; i < fireteams.length; ++i) { const title = fireteams[i].getElementsByClassName("title")[0]; let teamName = title.lastChild.textContent; let ok = true; for (let j = 0; j < regexps.length; ++j) { ok = ok && regexps[j].test(teamName); } fireteams[i].style.display = ok ? "" : "none"; let actIcon = fireteams[i].getElementsByClassName("activity-icon")[0]; let type = actIcon.getAttribute("data-activity"); let icon = ""; for (let j = 0; j < activityRegexps.length; ++j) { let act = activityRegexps[j]; if ((!act.activity || type == act.activity) && (!act.regexp || act.regexp.test(teamName))) { icon = act.icon; break; } } if (icon) { actIcon.style.backgroundImage = 'url("' + icon + '")'; actIcon.style.backgroundSize = 'cover'; let borderColor = "white"; if (prestigeRegexp.test(teamName)) { borderColor = "gold"; } actIcon.style.outline = "2px solid " + borderColor; } /*if (icon && title.firstChild == title.lastChild) { let div = document.createElement("div"); //div.innerText = "[" + type + "]"; div.style.marginRight = "8px"; div.style.display = "inline-block"; div.style.height = "32px"; div.style.width = "32px"; div.style.verticalAlign = "middle"; div.style.backgroundImage = 'url("' + icon + '")'; div.style.backgroundSize = 'contain'; title.insertBefore(div, title.firstChild); }*/ } refs.refreshButton.classList.remove("RefreshIconBusy"); } textFilter.value = localStorage.getItem("TextFilter", ""); textFilter.oninput = function () { localStorage.setItem("TextFilter", textFilter.value); updateFilters(); }; const observer = new MutationObserver(function (mutationsList, observer) { updateFilters(); updateAutorefresh(); }); observer.observe(document.getElementsByClassName("clanResults")[0], { childList: true, subtree: true }); // // Spacer // addDiv("").style.flexGrow = 1; // // Refresh // const autorefreshDiv = addDiv(` <div class="form-element" style="display: inline-block;"> <input type="checkbox" id="autorefresh_enabled" name="a1" /> </div> <div class="form-element companion-text-input" style="display: inline-block;"> <input type="text" id="autorefresh_interval" name="a2" placeholder="0" style="width: 2em;" onsubmit="return false;"/> <span style="color: white";>s</span> </div> `); const autorefreshChk = document.getElementById("autorefresh_enabled"); const autorefreshInput = document.getElementById("autorefresh_interval"); //autorefreshChk.checked = localStorage.getItem("AutorefreshEnabled", "") == "1"; autorefreshEnabled = autorefreshChk.checked; autorefreshChk.onchange = function () { autorefreshEnabled = autorefreshChk.checked; //localStorage.setItem("AutorefreshEnabled", autorefreshEnabled ? "1" : "0"); updateAutorefresh(); }; autorefreshInput.value = localStorage.getItem("AutorefreshInterval", ""); autorefreshInterval = Math.max(0, parseFloat(autorefreshInput.value || "") || 0); autorefreshInput.oninput = function () { autorefreshInterval = Math.max(0, parseFloat(autorefreshInput.value || "") || 0); localStorage.setItem("AutorefreshInterval", autorefreshInterval); updateAutorefresh(); }; const refreshDiv = addDiv(` <div class="nav_top"> <div class="RefreshIcon notification-badges" style="padding-top: 0;"><i class="material-icons">refresh</i></div> </div> `); refs.refreshButton = refreshDiv.getElementsByClassName("notification-badges")[0]; refs.refreshButton.onclick = function () { refreshList(); }; updateFilters(); updateAutorefresh(); } // Add blizzard IDs on profile pages, for easy copying function setupProfilePage() { const sv = window.ServerVars; if (sv && sv.PageData && sv.PageData.OnPageUser) { const id = sv.PageData.OnPageUser.MembershipData.bungieNetUser.blizzardDisplayName; const divs = document.getElementsByClassName("unique-name"); if (divs.length == 1) { divs[0].innerHTML += "<div>" + id + "</div>"; } } } // Improvements to fireteam actions in LFG: // - Add button to fetch user ids on fireteam view function setupFireteamActions() { function selectNodeText(textNode) { if (document.body.createTextRange) { // ms const range = document.body.createTextRange(); range.moveToElementText(textNode); range.select(); } else if (window.getSelection) { // moz, opera, webkit const selection = window.getSelection(); const range = document.createRange(); range.selectNodeContents(textNode); selection.removeAllRanges(); selection.addRange(range); } } function fetchName(div) { fetch(div.href) .then(function (response) { return response.text(); }) .then(function (data) { const re = /"blizzardDisplayName":\s*"([^"]+)"/; const match = re.exec(data); if (match) { const span = document.createElement("span"); span.style.marginLeft = "1em"; span.innerHTML = match[1]; span.onclick = function () { selectNodeText(span); }; div.parentNode.appendChild(span); const a = document.createElement("a"); a.style.marginLeft = "1em"; a.href = "https://destinytracker.com/d2/profile/pc/" + match[1].replace(/#/, "-"); a.target = "_blank"; a.style.display = "inline-block"; a.style.verticalAlign = "middle"; a.style.width = "32px"; a.style.height = "20px"; a.style.backgroundImage = "url('https://destinytracker.com/Images/DestinyTracker/FavIcon/favicon-32.png')"; a.style.backgroundPosition = "center"; div.parentNode.appendChild(a); } }); } const divs = document.getElementsByClassName("fireteam-actions"); if (divs.length) { const a = document.createElement("a"); a.className = "btn_fireteam button small gold"; a.innerHTML = "Get Blizzard Ids"; a.onclick = function () { const names = document.getElementsByClassName("display-name"); for (let i = 0; i < names.length; ++i) { fetchName(names[i]); } a.parentNode.removeChild(a); return false; }; divs[0].appendChild(a); } } setupFireteamSearch(); setupProfilePage(); setupFireteamActions(); })();