Greasy Fork

Alienware Arena Filters

Filter out tier-restricted content on Alienware Arena

目前为 2025-01-28 提交的版本。查看 最新版本

// ==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 &amp; 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,
    });
  }
})();