// ==UserScript==
// @name StreamElements improvements
// @name:de StreamElements Verbesserungen
// @namespace https://kurotaku.de
// @version 1.7.5
// @description A script for some improvements for StreamElements
// @description:de Ein Skript für einige Verbesserungen für StreamElements
// @author Kurotaku
// @license CC BY-NC-SA 4.0
// @match https://streamelements.com/*/store*
// @icon https://cdn.streamelements.com/static/logo/logo_red.png
// @updateURL https://raw.githubusercontent.com/Kurotaku-sama/Userscripts/main/userscripts/StreamElements_improvements/script.user.js
// @downloadURL https://raw.githubusercontent.com/Kurotaku-sama/Userscripts/main/userscripts/StreamElements_improvements/script.user.js
// @require https://raw.githubusercontent.com/Kurotaku-sama/Userscripts/main/libraries/kuros_library.js
// @require https://cdn.jsdelivr.net/npm/sweetalert2
// @require https://openuserjs.org/src/libs/sizzle/GM_config.js
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_addStyle
// @grant GM_registerMenuCommand
// @run-at document-body
// ==/UserScript==
let sold_out_items = [];
let subscriber_only_items = [];
(async function() {
await init_gm_config();
wait_for_element('.side-bar .usr-stats').then(async () => {
insert_new_sidebar_container(); // Insert a new sidebar for the custom buttons
insert_gm_config_button(); // Add the button to the filter container to open the configuration menu
if(GM_config.get("script_enabled")) { // Check if the script is disabled in config
insert_controls();
for(let i = 0; i < 120; i++) // While the page items are still loading (2 minute limit than abort the functions)
if(document.querySelectorAll("user-public-store > :nth-child(3) > div").length === 0)
if(i === 120)
return; // Abort
else
await sleep_s(1); // Wait and try again
if(GM_config.get("hide_items_from_list_by_default"))
toggle_hidden_itemlist();
if(GM_config.get("gray_out_hidden_items")) // If items should be grayed out that are in hidden list
gray_out_hidden_items();
check_sold_out_items();
if(GM_config.get("hide_sold_out_items_by_default")) // Hide items when out of stock
toggle_sold_out_items();
check_subscriber_only_items();
if(GM_config.get("hide_subscriber_items_by_default")) // Hide items when out of stock
toggle_subscriber_only_items();
if(GM_config.get("gray_out_sold_out_items")) // If items should be grayed out that are out of stock
gray_out_sold_out_items();
// if(GM_config.get("default_sorting") !== "Default") // Change the default sorting if its not "Default"
// change_default_sorting();
// if(GM_config.get("default_sorting") === "Default" && (GM_config.get("sort_by_price_ascending") || GM_config.get("sort_by_price_descending"))) // Sort by price if Default is selected
if(GM_config.get("sort_by_price_ascending") || GM_config.get("sort_by_price_descending")) // Sort by price if Default is selected
sort_by_price();
if(GM_config.get("magnifying_glass_buttons"))
magnifying_glass_buttons();
if(GM_config.get("hide_item_buttons"))
hide_item_buttons();
}
});
})();
async function init_gm_config() {
const config_id = "configuration_streamelements_improvements";
await migrate_config_id(config_id);
GM_registerMenuCommand("Settings", () => GM_config.open());
GM_config.init({
id: config_id,
title: 'StreamElements improvements',
fields: {
script_enabled: {
type: 'checkbox',
default: true,
label: 'Enable/Disable all improvements',
},
items_to_hide: {
section: ['Hide Items'],
label: 'Hide items by name
(each item name must be written in a new line)',
type: 'textarea',
},
hide_items_from_list_by_default: {
type: 'checkbox',
default: true,
label: 'Hide items by default',
},
hide_sold_out_items_by_default: {
type: 'checkbox',
default: false,
label: 'Hide sold out items by default',
},
hide_subscriber_items_by_default: {
type: 'checkbox',
default: false,
label: 'Hide subscriber only items by default',
},
gray_out_hidden_items: {
section: ['Gray out'],
type: 'checkbox',
default: true,
label: 'Gray out hidden items',
},
gray_out_sold_out_items: {
type: 'checkbox',
default: true,
label: 'Gray out sold out items',
},
// default_sorting: {
// section: ['Sorting'],
// type: 'select',
// default: 'Default',
// label: 'StreamElements default Sorting',
// options: ['Default', 'Newest first', 'Subscribers only', 'Cost']
// },
sort_by_price_ascending: {
section: ['Sorting'],
type: 'checkbox',
default: true,
label: 'Sort items by price (ascending)',
},
sort_by_price_descending: {
type: 'checkbox',
default: false,
label: 'Sort items by price (descending)',
},
hint_sorting_info: {
type: 'hidden',
label: `
Info: Sorting logic (click me)
| Name | Description | Price | Stock |
|---|---|---|---|
| ${title} | ${description} | ${cost} | ${stock} |
inside content block
let desc_span = content_block.querySelector("p > span");
let desc = desc_span?.textContent || "";
// Try to match a Steam URL
let steam_url_regex = /https?:\/\/store\.steampowered\.com\/(app|bundle)\/\d+\/[\w\d%_\-]+\/?/i;
let match = desc.match(steam_url_regex);
if (match) {
// Open matched Steam link
window.open(match[0], "_blank");
} else {
// Fallback: search by title from tags in the details area
let paragraphs = item.querySelectorAll(":scope > :nth-child(2) > div > p");
for (let p of paragraphs) {
if (p.innerText.includes("shopping_basket")) {
return p.innerText
.replace("shopping_basket", "")
.replace("items left", "")
.replace("left", "")
.trim();
}
}
// If no stock paragraph found, treat as unlimited
return "Unlimited";
}
function get_item_cost(item) {
// Find all tags in the details area
let paragraphs = item.querySelectorAll(":scope > :nth-child(2) > div > p");
for (let p of paragraphs) {
if (p.innerText.includes("monetization_on")) {
let number = p.innerText
.replace("monetization_on", "")
.replace(/\D/g, "") // Remove all non-digits
.trim();
return parseInt(number, 10) || 0; // Return as integer
}
}
// Fallback if no cost info is found
return 0;
}
function get_prepared_items_to_hide(new_title = null) {
let items_to_hide = GM_config.get("items_to_hide");
if(new_title) // Add new item title if exist
items_to_hide += `\n${new_title.trim()}`;
items_to_hide = items_to_hide.replace(/^\s*$(?:\r\n?|\n)/gm, ""); // Remove blank lines
items_to_hide = trim_spaces(items_to_hide); // Remove Spaces
items_to_hide = sort_alphabetically(items_to_hide); // Sort alphabetical
return items_to_hide;
}
function check_sold_out_items() {
let items = document.querySelectorAll("user-public-store > :nth-child(3) > div");
items.forEach(function(item) {
let quantity_text = get_item_quantity(item);
if (quantity_text.toLowerCase().includes("sold out"))
sold_out_items.push(item);
})
}
function check_subscriber_only_items() {
let items = document.querySelectorAll("user-public-store > :nth-child(3) > div");
items.forEach(function(item) {
let icons = item.querySelectorAll("span.material-icons");
for (let icon of icons)
if (icon.textContent.trim() === "star")
subscriber_only_items.push(item);
});
}
function get_hidden_items_array() {
let hidden_items = GM_config.get("items_to_hide").split("\n");
hidden_items = hidden_items.map(function (el) {return el.trim();}); // Trim away the spaces
hidden_items = hidden_items.filter((el) => el !== ""); // Remove all empty lines (shouldn't happen anymore, but safe is safe)
return hidden_items;
}
GM_addStyle(`
/* Switch */
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 34px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
}
input:checked + .slider {
background-color: #2196F3;
}
input:focus + .slider {
box-shadow: 0 0 1px #2196F3;
}
input:checked + .slider:before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}
/* Rounded sliders */
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}
/* Eye fixed positioning after update */
user-public-store > :nth-child(3) > div {
position: relative;
}
.eye-container,
.magnifying-glass-container {
position: absolute;
height: 30px;
width: 30px;
background-color: rgba(20, 20, 20, 0.3);
border-radius: 50%;
color: white;
cursor: pointer;
padding: 3px;
margin: unset;
}
/* Eye */
.eye-container {
right: 5px;
top: 5px;
}
/* Magnifying Glass */
.magnifying-glass-container {
left: 5px;
top: 5px;
}
.userpages-wrap {max-width: unset !important;}
.hide-item,.sold-out-item,.hide-subscriber-item {display: none !important;}
.gray-out-item {filter: saturate(0%);}
.sort-buttons-container {display: grid; grid-template-columns: 50% 50%;}
.slidercontainer {letter-spacing: 1.2px;padding-left: 16px;padding-right: 16px;font-size: 12px;line-height: 36px;user-select: none;text-transform: uppercase;font-weight: 600; margin-top: 15px;}
.slidercontainer > .switch {margin-right: 10px;}
.item-table td, .item-table th {border: 2px solid #fff;padding: 10px;}
.table-item-cost,.table-item-stock {text-align:center;}
`);
let title_el = content_block.querySelector("h6");
let title = title_el?.textContent.trim() || "";
window.open(`https://store.steampowered.com/search/?term=${encodeURIComponent(title)}`, "_blank");
}
}
function hide_item_buttons() {
let items = document.querySelectorAll("user-public-store > :nth-child(3) > div");
let eye_button = `