- // ==UserScript==
- // @name Alienware Arena Filters
- // @namespace http://updownleftdie.com/
- // @version 1.1
- // @description Filter out tier-restricted content on Alienware Arena
- // @author UpDownLeftDie
- // @match https://*.alienwarearena.com/*
- // @grant GM_setValue
- // @grant GM_getValue
- // @license AGPL
- // ==/UserScript==
-
- (function () {
- 'use strict';
-
- // Settings management
- const defaultSettings = {
- hideClosedGiveaways: true,
- hideTierRestricted: true,
- autoSyncTier: true,
- hideOutOfStock: true,
- hideClaimed: true,
- };
-
- function getSettings() {
- const savedSettings = GM_getValue('filterSettings');
- // Start with default settings as base
- const settings = { ...defaultSettings };
-
- if (savedSettings) {
- try {
- const parsed = JSON.parse(savedSettings);
- // Merge saved settings with defaults
- Object.assign(settings, parsed);
- // Ensure userTier is a number or undefined
- settings.userTier =
- parsed.userTier != null ? Number(parsed.userTier) : undefined;
-
- // If Number() returned NaN, set to undefined
- if (Number.isNaN(settings.userTier)) {
- settings.userTier = undefined;
- }
- } catch (e) {
- console.error('Error parsing saved settings:', e);
- // On error, return defaults
- return defaultSettings;
- }
- }
-
- return settings;
- }
- function saveSettings(settings) {
- const prevSettings = getSettings();
- const newSettings = {
- ...prevSettings,
- ...settings,
- };
- GM_setValue('filterSettings', JSON.stringify(newSettings));
- }
-
- // Function to extract tier number from text
- function extractTier(text) {
- const match = text.match(/Tier\s*(\d+)/i);
- return match ? parseInt(match[1]) : null;
- }
-
- // Function to check and store user's tier on control center page
- function checkAndStoreTier() {
- const tierImg = document.querySelector(
- 'img[src*="/images/content/tier-tags/"]',
- );
- if (tierImg) {
- const tierMatch = tierImg.src.match(/tier-tags\/(\d+)\.png/);
- if (tierMatch) {
- const userTier = parseInt(tierMatch[1]);
- saveSettings({ userTier });
- console.log('Stored user tier:', userTier);
- }
- }
- }
-
- // Function to filter community giveaways
- function filterGiveaways() {
- const settings = getSettings();
- const userTier = settings.userTier ?? 99;
- const giveaways = document.querySelectorAll(
- 'div.mb-3.community-giveaways__listing__row',
- );
-
- giveaways.forEach((giveaway) => {
- const text = giveaway.textContent;
- if (settings.hideClosedGiveaways && text.includes('Closed')) {
- giveaway.style.display = 'none';
- return;
- }
-
- if (settings.hideTierRestricted) {
- const tierNumber = extractTier(text);
- if (tierNumber && tierNumber > userTier) {
- giveaway.style.display = 'none';
- }
- }
- });
- }
-
- // Function to filter marketplace items
- function filterMarketplace() {
- const settings = getSettings();
- const userTier = settings.userTier ?? 99;
- const items = document.querySelectorAll(
- '.pointer.marketplace-game-small, .pointer.marketplace-game-large, .product-tile, .featured-tile',
- );
-
- items.forEach((item) => {
- const text = item.textContent;
- if (
- settings.hideOutOfStock &&
- text.toLowerCase().includes('out of stock')
- ) {
- item.style.display = 'none';
- return;
- }
-
- if (settings.hideClaimed && text.toLowerCase().includes('claimed')) {
- item.style.display = 'none';
- return;
- }
-
- if (settings.hideTierRestricted) {
- const tierNumber = extractTier(text);
- if (tierNumber && tierNumber > userTier) {
- item.style.display = 'none';
- }
- }
- });
-
- if (
- [...document.querySelectorAll('.row.mt-3 .featured-tile')].every(
- (tile) => tile.style.display === 'none',
- )
- ) {
- const flashDealsSection = document.querySelector(
- 'div[style*="border-style: solid"][class*="row mt-3"]',
- );
- if (flashDealsSection) {
- flashDealsSection.style.display = 'none';
- }
- }
- }
-
- // Function to create settings menu
- function createSettingsMenu() {
- const settings = getSettings();
- const menuHTML = `
- <div
- id="alienware-filter-settings"
- role="dialog"
- aria-labelledby="settings-title"
- aria-modal="true">
- <div role="document">
- <!-- Title -->
- <div id="settings-title" role="heading" aria-level="1">Filter Settings</div>
-
- <!-- Settings Form -->
- <form>
- <!-- Global Settings Section -->
- <div class="settings-section" style="margin-bottom: 20px">
- <div role="heading" aria-level="2" class="section-heading">
- Global Settings
- </div>
- <div
- class="settings-group"
- role="group"
- aria-label="Global Filter Options">
- <div class="setting">
- <label class="settingsLabel">
- <input type="checkbox" id="hideTierRestricted" ${
- settings.hideTierRestricted ? 'checked' : ''
- }
- aria-describedby="hideTierDesc"> Hide Higher Tier Content
- </label>
- <span id="hideTierDesc" class="sr-only"
- >If checked, content requiring a higher tier than your current
- tier will be hidden</span
- >
- </div>
- <div class="setting">
- <label class="settingsLabel">
- <input type="checkbox" id="autoSyncTier" ${
- !settings.hideTierRestricted ? 'disabled' : ''
- } ${settings.autoSyncTier ? 'checked' : ''}
- aria-describedby="autoSyncTierDesc"> Auto Sync Tier
- </label>
- <span id="hideTierDesc" class="sr-only"
- >If checked, tier restrictions will be automatically synced from
- your profile</span
- >
- </div>
- <div class="setting">
- <label class="settingsLabel">
- User tier:
- <input id="manualSetTier" type="text" inputmode="numeric" pattern="[0-9]*" size="1" maxlength="2" ${
- settings.autoSyncTier ? 'disabled' : ''
- } value="${settings.userTier ? settings.userTier : ''}"
- aria-describedby="manualSetTierDesc">
- </label>
- <span id="manualSetTierDesc" class="sr-only">
- The user tier that is used to filter content on the site</span>
- </div>
- </div>
- </div>
-
- <!-- Game Vault and Marketplace Section -->
- <div class="settings-section" style="margin-bottom: 20px">
- <div role="heading" aria-level="2" class="section-heading">
- Marketplace & Game Vault
- </div>
- <div
- class="settings-group"
- role="group"
- aria-label="Marketplace Options">
- <div class="setting">
- <label class="settingsLabel">
- <input type="checkbox" id="hideOutOfStock" ${
- settings.hideOutOfStock ? 'checked' : ''
- }
- aria-describedby="hideStockDesc"> Hide Out of Stock Items
- </label>
- <span id="hideStockDesc" class="sr-only"
- >If checked, items that are out of stock will be hidden</span
- >
- </div>
- <div class="setting">
- <label class="settingsLabel">
- <input type="checkbox" id="hideClaimed" ${
- settings.hideClaimed ? 'checked' : ''
- } aria-describedby="hideClaimedDesc"> Hide Claimed
- Items
- </label>
- <span id="hideClaimedDesc" class="sr-only"
- >If checked, items that you have claimed will be hidden</span
- >
- </div>
- </div>
- </div>
-
- <!-- Community Giveaways Section -->
- <div class="settings-section" style="margin-bottom: 20px">
- <div role="heading" aria-level="2" class="section-heading">
- Community Giveaways
- </div>
- <div
- class="settings-group"
- role="group"
- aria-label="Community Giveaway Options">
- <div class="setting">
- <label class="settingsLabel">
- <input type="checkbox" id="hideClosedGiveaways" ${
- settings.hideClosedGiveaways ? 'checked' : ''
- }
- aria-describedby="hideClosedDesc"> Hide Closed Giveaways
- </label>
- <span id="hideClosedDesc" class="sr-only"
- >If checked, giveaways that are already closed will be
- hidden</span
- >
- </div>
- </div>
- </div>
-
- <!-- Action Buttons -->
- <div style="text-align: right">
- <button id="saveFilterSettings" type="submit">Save</button>
- <button id="closeFilterSettings" type="button">Close</button>
- </div>
- </form>
- </div>
- </div>
-
- <style>
- #alienware-filter-settings {
- display: none;
- position: fixed;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- background: #1a1a1a;
- padding: 20px;
- border-radius: 8px;
- z-index: 10000;
- min-width: 300px;
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
- }
- #settings-title {
- color: #fff;
- font-size: 1.5em;
- font-weight: bold;
- margin-bottom: 15px;
- }
- #manualSetTier {
- color: white;
- padding: 2px;
- text-align: center;
- }
- #manualSetTier:disabled {
- color: grey;
- }
- .section-heading {
- color: #00bc8c;
- font-size: 1.1em;
- margin-bottom: 10px;
- font-weight: bold;
- }
- .setting {
- margin-bottom: 10px;
- margin-left: 15px;
- }
- .settingsLabel {
- color: #fff;
- display: block;
- margin-bottom: 5px;
- }
- #saveFilterSettings {
- background: #00bc8c;
- color: #fff;
- border: none;
- padding: 5px 15px;
- border-radius: 4px;
- cursor: pointer;
- }
- #closeFilterSettings {
- background: #e74c3c;
- color: #fff;
- border: none;
- padding: 5px 15px;
- border-radius: 4px;
- margin-left: 10px;
- cursor: pointer;
- }
- .sr-only {
- position: absolute;
- width: 1px;
- height: 1px;
- padding: 0;
- margin: -1px;
- overflow: hidden;
- clip: rect(0, 0, 0, 0);
- border: 0;
- }
- </style>
- `;
-
- // Add menu to page
- document.body.insertAdjacentHTML('beforeend', menuHTML);
-
- // Add event listeners
- document
- .getElementById('saveFilterSettings')
- .addEventListener('click', () => {
- const hideClosedGiveaways = document.getElementById(
- 'hideClosedGiveaways',
- ).checked;
- const hideTierRestricted =
- document.getElementById('hideTierRestricted').checked;
- const autoSyncTier = document.getElementById('autoSyncTier').checked;
- const hideOutOfStock =
- document.getElementById('hideOutOfStock').checked;
- const hideClaimed = document.getElementById('hideClaimed').checked;
-
- const newSettings = {
- hideClosedGiveaways,
- hideTierRestricted,
- autoSyncTier,
- hideOutOfStock,
- hideClaimed,
- ...(!autoSyncTier && {
- userTier: document.getElementById('manualSetTier').value,
- }),
- };
- saveSettings(newSettings);
- document.getElementById('alienware-filter-settings').style.display =
- 'none';
- location.reload(); // Reload to apply new settings
- });
-
- // Add keyboard event listeners for accessibility
- const modal = document.getElementById('alienware-filter-settings');
-
- document
- .getElementById('closeFilterSettings')
- .addEventListener('click', () => {
- modal.style.display = 'none';
- });
-
- // Handle ESC key to close modal
- document.addEventListener('keydown', (e) => {
- if (e.key === 'Escape' && modal.style.display === 'block') {
- modal.style.display = 'none';
- }
- });
-
- // Trap focus within modal when it's open
- modal.addEventListener('keydown', (e) => {
- if (e.key === 'Tab') {
- const focusableElements = modal.querySelectorAll(
- 'button, input[type="checkbox"]',
- );
- const firstFocusable = focusableElements[0];
- const lastFocusable = focusableElements[focusableElements.length - 1];
-
- if (e.shiftKey) {
- if (document.activeElement === firstFocusable) {
- lastFocusable.focus();
- e.preventDefault();
- }
- } else {
- if (document.activeElement === lastFocusable) {
- firstFocusable.focus();
- e.preventDefault();
- }
- }
- }
- });
- }
-
- // Function to add settings button to menu
- function addSettingsButton() {
- const menuList = document.querySelector(
- '.nav-item-mus .dropdown-menu.dropdown-menu-end',
- );
- if (menuList) {
- const settingsItem = document.createElement('a');
- settingsItem.className = 'dropdown-item';
- settingsItem.href = '#';
- settingsItem.textContent = 'Filter Settings';
- settingsItem.addEventListener('click', (e) => {
- e.preventDefault();
- document.getElementById('alienware-filter-settings').style.display =
- 'block';
- });
- menuList.insertBefore(settingsItem, menuList.lastElementChild);
- }
- }
-
- // Initialize everything based on current page
- const currentPath = window.location.pathname;
-
- // Add settings menu to all pages
- createSettingsMenu();
- addSettingsButton();
-
- const settings = getSettings();
- if (settings.autoSyncTier && currentPath === '/control-center') {
- checkAndStoreTier();
- } else if (currentPath === '/community-giveaways') {
- // Add mutation observer for dynamic content loading
- const observer = new MutationObserver((mutations, obs) => {
- filterGiveaways();
- });
-
- observer.observe(document.body, {
- childList: true,
- subtree: true,
- });
- } else if (currentPath.startsWith('/marketplace')) {
- // Add mutation observer for dynamic content loading
- const observer = new MutationObserver((mutations, obs) => {
- filterMarketplace();
- });
-
- observer.observe(document.body, {
- childList: true,
- subtree: true,
- });
- }
- })();