NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Steam to SteamDB Button
// @namespace https://store.steampowered.com/
// @version 1.1.8
// @description Adds a SteamDB button to Steam app, bundle, or sub pages in the appropriate action container.
// @author g31w0fw0rld
// @license MIT
// @match https://store.steampowered.com/app/*
// @match https://store.steampowered.com/bundle/*
// @match https://store.steampowered.com/sub/*
// @downloadURL https://github.com/g31w0fw0rld/steam-to-steamdb-button/raw/main/steam-to-steamdb-button.user.js
// @updateURL https://github.com/g31w0fw0rld/steam-to-steamdb-button/raw/main/steam-to-steamdb-button.user.js
// @grant none
// ==/UserScript==
(function () {
'use strict';
// =============================================
// CONSTANTES
// =============================================
const STEAMDB_BASE_URL = 'https://steamdb.info/';
const PATH_REGEX = /\/(app|bundle|sub)\/(\d+)/;
const STEAMDB_BUTTON_ID = 'steamdbButtonContainer';
// Icono SVG oficial de SteamDB
const STEAMDB_SVG = '<svg width="16" height="16" viewBox="0 0 128 128" class="octicon octicon-steamdb" aria-hidden="true" style="margin-right: 8px; vertical-align: middle;"><path fill="currentColor" fill-rule="evenodd" d="M63.9 0C30.5 0 3.1 11.9.1 27.1l35.6 6.7c2.9-.9 6.2-1.3 9.6-1.3l16.7-10c-.2-2.5 1.3-5.1 4.7-7.2 4.8-3.1 12.3-4.8 19.9-4.8 5.2-.1 10.5.7 15 2.2 11.2 3.8 13.7 11.1 5.7 16.3-5.1 3.3-13.3 5-21.4 4.8l-22 7.9c-.2 1.6-1.3 3.1-3.4 4.5-5.9 3.8-17.4 4.7-25.6 1.9-3.6-1.2-6-3-7-4.8L2.5 38.4c2.3 3.6 6 6.9 10.8 9.8C5 53 0 59 0 65.5c0 6.4 4.8 12.3 12.9 17.1C4.8 87.3 0 93.2 0 99.6 0 115.3 28.6 128 64 128c35.3 0 64-12.7 64-28.4 0-6.4-4.8-12.3-12.9-17 8.1-4.8 12.9-10.7 12.9-17.1 0-6.5-5-12.6-13.4-17.4 8.3-5.1 13.3-11.4 13.3-18.2 0-16.5-28.7-29.9-64-29.9zm22.8 14.2c-5.2.1-10.2 1.2-13.4 3.3-5.5 3.6-3.8 8.5 3.8 11.1 7.6 2.6 18.1 1.8 23.6-1.8s3.8-8.5-3.8-11c-3.1-1-6.7-1.5-10.2-1.5zm.3 1.7c7.4 0 13.3 2.8 13.3 6.2 0 3.4-5.9 6.2-13.3 6.2s-13.3-2.8-13.3-6.2c0-3.4 5.9-6.2 13.3-6.2zM45.3 34.4c-1.6.1-3.1.2-4.6.4l9.1 1.7a10.8 5 0 1 1-8.1 9.3l-8.9-1.7c1 .9 2.4 1.7 4.3 2.4 6.4 2.2 15.4 1.5 20-1.5s3.2-7.2-3.2-9.3c-2.6-.9-5.7-1.3-8.6-1.3zM109 51v9.3c0 11-20.2 19.9-45 19.9-24.9 0-45-8.9-45-19.9v-9.2c11.5 5.3 27.4 8.6 44.9 8.6 17.6 0 33.6-3.3 45.2-8.7zm0 34.6v8.8c0 11-20.2 19.9-45 19.9-24.9 0-45-8.9-45-19.9v-8.8c11.6 5.1 27.4 8.2 45 8.2s33.5-3.1 45-8.2z"></path></svg>';
// Mapa de contenedores según el tipo de página de Steam
// - app: usa 'queueActionsCtn' (se clona para crear sección separada)
// - bundle/sub: usa 'game_area_purchase_top' (se añade directamente)
const CONTAINER_IDS = {
app: 'queueActionsCtn',
bundle: 'game_area_purchase_top',
sub: 'game_area_purchase_top'
};
// =============================================
// FUNCIONES
// =============================================
/**
* Extrae el tipo de página (app, bundle, sub) y el ID numérico
* desde la URL actual de Steam.
* @returns {{ type: string, id: string } | null} Objeto con tipo e ID, o null si no coincide.
*/
function extractPageType() {
const match = window.location.pathname.match(PATH_REGEX);
if (!match) return null;
return { type: match[1], id: match[2] };
}
/**
* Crea un botón con el estilo nativo de Steam (btn_black btn_medium)
* que abre la página correspondiente de SteamDB en una nueva pestaña.
* @param {string} type - Tipo de página (app, bundle, sub).
* @param {string} id - ID numérico del producto en Steam.
* @returns {HTMLButtonElement} El botón listo para insertar.
*/
function createSteamDBButton(type, id) {
const url = `${STEAMDB_BASE_URL}${type}/${id}/`;
const button = document.createElement('button');
button.className = 'btn_black btn_medium';
button.innerHTML = `<span>${STEAMDB_SVG}SteamDB</span>`;
button.addEventListener('click', () => window.open(url, '_blank'));
return button;
}
/**
* Obtiene el contenedor DOM donde debe insertarse el botón,
* según el tipo de página de Steam.
* @param {string} type - Tipo de página (app, bundle, sub).
* @returns {HTMLElement|null} El contenedor encontrado o null.
*/
function getContainer(type) {
const containerId = CONTAINER_IDS[type];
return containerId ? document.getElementById(containerId) : null;
}
/**
* Inserta el botón de SteamDB en el contenedor apropiado.
* Para páginas de tipo 'app', se clona el contenedor original para crear
* una sección visual separada debajo. Para 'bundle' y 'sub',
* el botón se añade directamente al contenedor existente.
* @param {HTMLButtonElement} button - El botón a insertar.
* @param {HTMLElement} container - El contenedor DOM de destino.
* @param {string} type - Tipo de página (app, bundle, sub).
*/
function insertButton(button, container, type) {
if (type === 'app') {
// Clonar contenedor para crear sección separada debajo
const newContainer = container.cloneNode(true);
newContainer.id = STEAMDB_BUTTON_ID;
newContainer.innerHTML = '';
newContainer.style.paddingTop = 'unset';
container.parentNode.insertBefore(newContainer, container.nextSibling);
newContainer.appendChild(button);
} else {
container.appendChild(button);
}
}
/**
* Punto de entrada: extrae el tipo de página, crea el botón
* y lo inserta en el contenedor correspondiente.
*/
function init() {
const pageInfo = extractPageType();
if (!pageInfo) return;
const { type, id } = pageInfo;
const container = getContainer(type);
if (!container) return;
const button = createSteamDBButton(type, id);
insertButton(button, container, type);
}
// =============================================
// INICIALIZACIÓN
// =============================================
try {
init();
} catch (e) {
console.error('(steam2steamdb): Error al crear el botón SteamDB:', e);
}
})();