ProtonDB SteamPlay Integration

Adds game ratings from ProtonDB to the Steam Store

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name ProtonDB SteamPlay Integration
// @description Adds game ratings from ProtonDB to the Steam Store
// @version 0.3.0
// @author Phlebiac
// @match https://store.steampowered.com/app/*
// @connect www.protondb.com
// @run-at document-end
// @noframes
// @license MIT; https://opensource.org/licenses/MIT
// @namespace Phlebiac/ProtonDB
// @icon https://www.protondb.com/sites/protondb/images/apple-touch-icon.png
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// ==/UserScript==

/*  Inspired by / some ideas and code from:
 *    https://openuserjs.org/install/DanMan/Steam_Play_Community_Rating_Notice.user.js
 *    https://raw.githubusercontent.com/guihkx/user-scripts/master/scripts/protondb-integration-for-steam.user.js
 */

;(async () => {
  'use strict'

  const PROTONDB_TIERS = [
    'pending',
    'borked',
    'bronze',
    'silver',
    'gold',
    'platinum'
  ]
  const PROTONDB_CONFIDENCE_LEVELS = ['low', 'moderate', 'good', 'strong']
  const PROTONDB_HOMEPAGE = 'https://www.protondb.com'

  let userPrefs = {
    open_in_new_tab: GM_getValue('open_in_new_tab', false),
    skip_native_games: GM_getValue('skip_native_games', true),
    show_confidence_level: GM_getValue('show_confidence_level', true)
  }

  const appId = getCurrentAppId();

  if (!appId) {
    return;
  }
  if (userPrefs.skip_native_games) {
    if (document.querySelector('span.platform_img.linux') !== null) {
      log('Ignoring native Linux game:', appId);
      return;
    }
  }
  injectCSS();

  GM_xmlhttpRequest({
    method: 'GET',
    url: `${PROTONDB_HOMEPAGE}/api/v1/reports/summaries/${appId}.json`,
    onload: addRatingToStorePage
  })

  function getCurrentAppId() {
    const urlPath = window.location.pathname;
    const appId = urlPath.match(/\/app\/(\d+)/);

    if (appId === null) {
      log('Unable to get AppId from URL path:', urlPath);
      return false;
    }
    return appId[1];
  }

  function addRatingToStorePage(response) {
    let reports = {};
    let tier = 'N/A';

    if (response.status === 200) {
      try {
        reports = JSON.parse(response.responseText);
        tier = reports.tier;
      } catch (err) {
        log('Unable to parse ProtonDB response as JSON:', response);
        log('Javascript error:', err);
        tier = 'error';
      }
      if (!PROTONDB_TIERS.includes(tier)) {
        log('Unknown tier:', tier);
        tier = 'unknown';
      }
    } else if (response.status === 404) {
      log(`App ${appId} doesn't have a page on ProtonDB yet`);
      tier = 'N/A';
    } else {
      log('Got unexpected HTTP code from ProtonDB:', response.status);
      tier = 'error';
    }
    
    let confidence, tooltip = '';
    if ('confidence' in reports && PROTONDB_CONFIDENCE_LEVELS.includes(reports.confidence)) {
      confidence = reports.confidence;
      tooltip = `Confidence: ${confidence}`;
      if ('total' in reports) {
        tooltip += ` with ${reports.total} reports`;
      }
      tooltip += ' | ';
    }
    
    let target = document.querySelector('.game_area_purchase_platform');
    if (target) {
      let node = Object.assign(document.createElement('span'), {
        className: 'protondb_rating_row' 
      });
      node.appendChild(preferencesDialog());
      node.appendChild(createBadge(tier, confidence, tooltip, appId));
      target.insertBefore(node, target.firstChild);
    }
  }

  function createBadge(tier, confidence, tooltip, appId) {
    let confidence_style = confidence && userPrefs.show_confidence_level ?` protondb_confidence_${confidence}` : '';
    return Object.assign(document.createElement('a'), {
      textContent: tier,
      className: `protondb_rating_link protondb_rating_${tier}${confidence_style}`,
      title: tooltip + 'View on www.protondb.com',
      href: `${PROTONDB_HOMEPAGE}/app/${appId}`,
      target: userPrefs.open_in_new_tab ? '_blank' : '_self'
    });
  }

  function preferencesDialog() {
    const container = Object.assign(document.createElement('span'), {
      className: 'protondb_prefs_icon',
      title: 'Preferences for ProtonDB SteamPlay Integration',
      textContent: '⚙'
    })

    container.addEventListener('click', () => {
      const html = `
      <div class="protondb_prefs">
        <div class="newmodal_prompt_description">
          New preferences will only take effect after you refresh the page.
        </div>
        <blockquote>
          <div>
            <input type="checkbox" id="protondb_open_in_new_tab" ${ userPrefs.open_in_new_tab ? 'checked' : '' } />
            <label for="protondb_open_in_new_tab">Open ProtonDB links in new tab</label>
          </div>
          <div>
            <input type="checkbox" id="protondb_skip_native_games" ${ userPrefs.skip_native_games ? 'checked' : '' } />
            <label for="protondb_skip_native_games">Don't check native Linux games</label>
          </div>
          <div>
            <input type="checkbox" id="protondb_show_confidence_level" ${ userPrefs.show_confidence_level ? 'checked' : '' } />
            <label for="protondb_show_confidence_level">Style based on confidence level of ratings</label>
          </div>
        </blockquote>
      </div>`

      unsafeWindow.ShowDialog('ProtonDB SteamPlay Prefs', html);

      // Handle preferences changes
      const inputs = document.querySelectorAll('.protondb_prefs input');

      for (const input of inputs) {
        input.addEventListener('change', event => {
          const target = event.target;
          const prefName = target.id.replace('protondb_', '');

          switch (target.type) {
            case 'text':
              userPrefs[prefName] = target.value;
              GM_setValue(prefName, target.value);
              break;
            case 'checkbox':
              userPrefs[prefName] = target.checked;
              GM_setValue(prefName, target.checked);
              break;
            default:
              break;
          }
        })
      }
    })

    return container;
  }

  function injectCSS() {
    GM_addStyle(`
      .protondb_rating_row {
        text-transform: capitalize;
        vertical-align: top;
      }
      .protondb_rating_link {
        background: #4d4b49 url('https://support.steampowered.com/images/custom/platform_steamplay.png') no-repeat -51px center;
        display: inline-block;
        line-height: 19px;
        font-size: 14px;
        padding: 1px 10px 2px 79px;
        margin-right: 1ex;
        color: #b0aeac;
      }
      .protondb_rating_borked {
        color: #FF1919 !important;
      }
      .protondb_rating_bronze {
        color: #CD7F32 !important;
      }
      .protondb_rating_silver {
        color: #C0C0C0 !important;
      }
      .protondb_rating_gold {
        color: #FFD799 !important;
      }
      .protondb_rating_platinum {
        color: #B4C7DC !important;
      }
      .protondb_confidence_low {
        font-style: italic;
      }
      .protondb_confidence_moderate {
        font-weight: normal;
      }
      .protondb_confidence_good {
        font-weight: bold;
      }
      .protondb_confidence_strong {
        font-variant: small-caps;
        font-weight: bold;
      }
      .protondb_prefs_icon {
        font-size: 16px;
        padding: 0 4px;
        cursor: pointer;
      }
      .protondb_prefs input[type="checkbox"], .protondb_prefs label {
        line-height: 20px;
        vertical-align: middle;
        display: inline-block;
        color: #66c0f4;
        cursor: pointer;
      }
      .protondb_prefs blockquote {
        margin: 15px 0 5px 10px;
      }`)
  }

  function log() {
    console.log('[ProtonDB SteamPlay Integration]', ...arguments)
  }
})()