Last active
June 25, 2024 13:24
-
-
Save Kurotaku-sama/0a7f8373992756116940f31716e04a01 to your computer and use it in GitHub Desktop.
A script for some improvements for StreamElements
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name StreamElements improvements | |
// @name:de StreamElements Verbesserungen | |
// @namespace https://kurotaku.de | |
// @version 1.5.4 | |
// @description A script for some improvements for StreamElements | |
// @description:de Ein Skript für einige Verbesserungen für StreamElements | |
// @author Kurotaku | |
// @license MIT | |
// @match https://streamelements.com/*/store | |
// @icon https://cdn.streamelements.com/static/logo/logo_red.png | |
// @updateURL https://gist.github.com/Kurotaku-sama/0a7f8373992756116940f31716e04a01/raw/StreamElements%2520improvements.user.js | |
// @downloadURL https://gist.github.com/Kurotaku-sama/0a7f8373992756116940f31716e04a01/raw/StreamElements%2520improvements.user.js | |
// @require https://gist.github.com/Kurotaku-sama/9ebeb659500f6eee2f780344948e1e8f/raw/kuros_library.user.js | |
// @require https://openuserjs.org/src/libs/sizzle/GM_config.js | |
// @grant GM_getValue | |
// @grant GM_setValue | |
// @grant GM_registerMenuCommand | |
// ==/UserScript== | |
let sold_out_items = []; | |
let subscriber_only_items = []; | |
(function() { | |
init_gm_config(); // Initialize the configuration | |
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.querySelector(".loading-card")) | |
if(i === 120) | |
return; // Abort | |
else | |
await Sleep(1000); // 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("sort_by_price") || GM_config.get("sort_by_price_descending")) | |
sort_by_price(); | |
if(GM_config.get("magnifying_glass_buttons")) | |
magnifying_glass_buttons(); | |
if(GM_config.get("hide_item_buttons")) | |
hide_item_buttons(); | |
} | |
}); | |
})(); | |
function init_gm_config() { | |
GM_registerMenuCommand('Settings', () => { | |
GM_config.open(); | |
}); | |
let frame = document.createElement('div'); | |
document.body.appendChild(frame); | |
GM_config.init( | |
{ | |
'id': 'configuration', | |
'title': 'StreamElements improvements', | |
'fields': | |
{ | |
'script_enabled': | |
{ | |
'label': 'Enable/Disable all improvements', | |
'type': 'checkbox', | |
'default': true | |
}, | |
'items_to_hide': | |
{ | |
'label': 'Hide items by name<br>(each item name must be written in a new line)', | |
'type': 'textarea', | |
'default': '' | |
}, | |
'hide_items_from_list_by_default': | |
{ | |
'label': 'Hide items by default', | |
'type': 'checkbox', | |
'default': true | |
}, | |
'hide_sold_out_items_by_default': | |
{ | |
'label': 'Hide sold out items by default', | |
'type': 'checkbox', | |
'default': false | |
}, | |
'hide_subscriber_items_by_default': | |
{ | |
'label': 'Hide subscriber only items by default', | |
'type': 'checkbox', | |
'default': false | |
}, | |
'gray_out_hidden_items': | |
{ | |
'label': 'Gray out hidden items', | |
'type': 'checkbox', | |
'default': true | |
}, | |
'gray_out_sold_out_items': | |
{ | |
'label': 'Gray out sold out items', | |
'type': 'checkbox', | |
'default': true | |
}, | |
'sort_by_price': | |
{ | |
'label': 'Sort items always by price', | |
'type': 'checkbox', | |
'default': false | |
}, | |
'sort_by_price_descending': | |
{ | |
'label': 'Sort items always by price (descending)', | |
'type': 'checkbox', | |
'default': false | |
}, | |
'magnifying_glass_buttons': | |
{ | |
'label': 'Button in top left corner to search on Steam for this item!', | |
'type': 'checkbox', | |
'default': true | |
}, | |
'hide_item_buttons': | |
{ | |
'label': 'Button in top right corner for qick hide<br>(Warning: you still must save in this popup, to keep the changes saved!)', | |
'type': 'checkbox', | |
'default': true | |
}, | |
}, | |
'events': { | |
'init': () => {GM_config.set("items_to_hide", get_prepared_items_to_hide())}, | |
'save': () => {location.reload()}, | |
}, | |
'frame': frame, | |
'css': '#configuration {background-color: #020923; color:#fff; height:auto !important; width:auto !important; padding:20px !important;max-height: 600px !important;max-width:500px !important; border: 3px solid #fff !important} #configuration .config_header {font-size:17pt; font-weight:bold} #configuration .config_var {margin-top:10px; display: flex;} #configuration_buttons_holder {text-align: center;} #configuration label {color:#fff !important} #configuration #configuration_resetLink {color:#fff;} #configuration input[type="text"] {display:block; color: #fff; width:100%} #configuration input[type="checkbox"] {order:-1; margin: 0 10px 0 0} #configuration textarea {height: 150px; width: 100%; resize: none;background-color: transparent; color:#fff} #configuration #configuration_items_to_hide_var {display : block;}' | |
}); | |
} | |
function insert_new_sidebar_container() { | |
let sidebar = document.querySelector(".side-bar .usr-stats"); | |
let custom_container = "<div id='custom_container' class='usr-stats'></div>"; | |
sidebar.insertAdjacentHTML('afterend', custom_container); | |
} | |
function insert_gm_config_button() { | |
let sidebar = document.querySelector("#custom_container"); | |
let button = "<a id='gm_config_button' class='md-stroked md-button'>StreamElements improvements config</a>"; | |
sidebar.insertAdjacentHTML('beforeend', button); | |
document.querySelector("#gm_config_button").addEventListener("click",() => GM_config.open()); | |
} | |
// Custom controls under the config button | |
function insert_controls() { | |
let sidebar = document.querySelector("#custom_container"); | |
let hide_items_slider = `<div class="slidercontainer"><label class="switch"><input id="toggle-hide-itemlist" type="checkbox" ${GM_config.get("hide_items_from_list_by_default") ? 'checked' : ''}><span class="slider round"></span></label>Show/Hide hidden items</div>`; | |
sidebar.insertAdjacentHTML('beforeend', hide_items_slider); | |
document.getElementById("toggle-hide-itemlist").addEventListener ("click", toggle_hidden_itemlist, false); | |
let sold_out_slider = `<div class="slidercontainer"><label class="switch"><input id="toggle-sold-out" type="checkbox" ${GM_config.get("hide_sold_out_items_by_default") ? 'checked' : ''}><span class="slider round"></span></label>Show/Hide sold out items</div>`; | |
sidebar.insertAdjacentHTML('beforeend', sold_out_slider); | |
document.getElementById("toggle-sold-out").addEventListener ("click", toggle_sold_out_items, false); | |
let subscriber_only_slider = `<div class="slidercontainer"><label class="switch"><input id="toggle-subscriber-only" type="checkbox" ${GM_config.get("hide_subscriber_items_by_default") ? 'checked' : ''}><span class="slider round"></span></label>Show/Hide subscriber items</div>`; | |
sidebar.insertAdjacentHTML('beforeend', subscriber_only_slider); | |
document.getElementById("toggle-subscriber-only").addEventListener ("click", toggle_subscriber_only_items, false); | |
let button_itemlist = "<a id='get-itemlist' class='md-stroked md-button md-dark-theme'>Get itemlist</a>"; | |
sidebar.insertAdjacentHTML('beforeend', button_itemlist); | |
document.getElementById("get-itemlist").addEventListener ("click", get_itemlist, false); | |
let button_export_as_table = "<a id='get-item-table' class='md-stroked md-button md-dark-theme'>Show items as table</a>"; | |
sidebar.insertAdjacentHTML('beforeend', button_export_as_table); | |
document.getElementById("get-item-table").addEventListener ("click", get_item_table, false); | |
let button_open_redemption_history = "<a id='redemption_history' class='md-stroked md-button md-dark-theme'>Show redemption history</a>"; | |
sidebar.insertAdjacentHTML('beforeend', button_open_redemption_history); | |
document.getElementById("redemption_history").addEventListener ("click", show_redemption_history, false); | |
} | |
function sort_by_price() { | |
let descending = GM_config.get("sort_by_price_descending"); | |
let list = document.querySelector(".public-store-items"); // Get container with the items in store | |
let nodesToSort = list.querySelectorAll(".stream-store-list-item"); // Get all items in store | |
Array.prototype.map.call(nodesToSort, function(node) { | |
return { | |
node: node, | |
relevantText: node.querySelector('.item-cost').textContent.replace(/\D/g, '') // Remove all symbols except numbers | |
}; | |
}).sort(function(a, b) { | |
// Check if descending is enabled, if it is than a and b must be switched | |
return descending ? b.relevantText.localeCompare(a.relevantText, undefined, {'numeric': true}) : a.relevantText.localeCompare(b.relevantText, undefined, {'numeric': true}) | |
}).forEach(function(item) { | |
list.appendChild(item.node); | |
}); | |
} | |
function get_itemlist() { // Get list with all items in store | |
let item_list = ""; | |
document.querySelectorAll(".item-title").forEach(function(el){item_list += `${el.getAttribute("title").trim()}\n`}); | |
console.clear(); | |
if(item_list !== "") { | |
console.log(item_list); | |
alert("Item list displayed in the console (F12 on most browsers)\nCopy the list and paste it to the config textarea.\nRemove the items from the list that you still want to see!"); | |
} | |
else | |
alert("There are no items shown currently"); | |
} | |
function get_item_table() { | |
document.getElementById("get-item-table").remove(); // Remove the Button to prevent users from clicking it again | |
let store_items_container = document.querySelector(".public-store-items"); | |
let items = document.querySelectorAll(".stream-store-list-item"); // Get all items in store | |
let table = "<table id='item-table' class='item-table'>"; | |
table += "<tr><th>Name</th><th>Description</th><th>Price</th><th>Stock</th></tr>"; // Cell headlines | |
items.forEach(function(item) { | |
// Get all informations from cards | |
let title = item.querySelector(".item-title").innerText.trim(); | |
let description = item.querySelector(".clamp-description-text").innerText.trim(); | |
let stock = item.querySelector(".item-quantity-left > span") ? item.querySelector(".item-quantity-left > span").innerText.trim().replace("items left", '').replace("item left", '') : "Unlimited"; | |
let cost = item.querySelector(".item-cost").textContent.replace(/\D/g, ''); | |
// Add line to table | |
table += `<tr><td>${title}</td><td>${description}</td><td class='table-item-cost'>${cost}</td><td class='table-item-stock'>${stock}</td></tr>`; | |
}) | |
table += "</table>"; | |
// Remove Filters | |
document.querySelectorAll(".filter-items-input").forEach((filter) => {filter.remove()}); | |
// Download table button | |
let button_download_as_csv = "<a id='download-item-table' class='md-stroked md-button md-dark-theme'>Download table as CSV</a>"; | |
store_items_container.style.display = "unset"; // Change from grid to unset to allow 100 % width | |
store_items_container.innerHTML = button_download_as_csv + table; | |
document.getElementById("download-item-table").addEventListener ("click", function() {download_table_as_csv("item-table")}, false); | |
} | |
function show_redemption_history() { | |
window.open("https://streamelements.com/dashboard/account/redemptions", "_blank").focus(); | |
} | |
function toggle_hidden_itemlist() { | |
let hidden_items = get_hidden_items_array(); | |
let items = document.querySelectorAll(".stream-store-list-item"); // Get all items in store | |
items.forEach(function(item) { | |
let title = get_item_title(item); | |
if(hidden_items.includes(title)) | |
item.classList.toggle("hide-item"); | |
}) | |
} | |
function toggle_sold_out_items() { | |
sold_out_items.forEach(function(item) { | |
item.classList.toggle("sold-out-item"); | |
}); | |
} | |
function toggle_subscriber_only_items() { | |
subscriber_only_items.forEach(function(item) { | |
item.classList.toggle("hide-subscriber-item"); | |
}); | |
} | |
function gray_out_hidden_items() { | |
let hidden_items = get_hidden_items_array(); | |
let items = document.querySelectorAll(".stream-store-list-item"); // Get all items in store | |
items.forEach(function(item) { | |
let title = get_item_title(item); | |
if(hidden_items.includes(title)) | |
item.classList.add("gray-out-item"); | |
}); | |
} | |
function gray_out_sold_out_items() { | |
sold_out_items.forEach(function(item) { | |
item.classList.add("gray-out-item"); | |
}); | |
} | |
function magnifying_glass_buttons() { | |
let items = document.querySelectorAll(".stream-store-list-item"); | |
let magnifying_glass_button = `<div class="magnifying-glass-container"><div class="ico ico-mglass"></div></div>`; | |
items.forEach((item) => { | |
item.insertAdjacentHTML('beforeend', magnifying_glass_button); | |
item.querySelector(".magnifying-glass-container").addEventListener("click", search_on_steam, false); | |
}); | |
} | |
function search_on_steam(event) { | |
let item = event.target; // Get the item | |
while(item.tagName !== "MD-CARD") // Go up till you reach the item | |
item = item.parentNode; | |
let title = get_item_title(item); | |
window.open(`https://store.steampowered.com/search/?term=${title}`, "_blank"); | |
} | |
function hide_item_buttons() { | |
let items = document.querySelectorAll(".stream-store-list-item"); | |
let eye_button = `<div class="eye-slash-container"><div class="eye slash"><div></div><div></div></div></div>`; | |
items.forEach((item) => { | |
let hidden_items = get_hidden_items_array(); | |
let title = get_item_title(item); | |
if(!hidden_items.includes(title)) { | |
item.insertAdjacentHTML('beforeend', eye_button); | |
item.querySelector(".eye-slash-container").addEventListener("click", add_to_hidden, false); | |
} | |
}); | |
} | |
function add_to_hidden(event) { | |
let item = event.target; // Get the item | |
while(item.tagName !== "MD-CARD") // Go up till you reach the item | |
item = item.parentNode; | |
let add_to_hidden_button = item.querySelector(".eye-slash-container"); | |
add_to_hidden_button.remove(); // Remove the button | |
let title = get_item_title(item); | |
GM_config.set("items_to_hide", get_prepared_items_to_hide(title)); // Override old list | |
if(GM_config.get("hide_items_from_list_by_default")) | |
item.classList.add("gray-out-item"); | |
let hide_itemlist_enabled = document.querySelector("#toggle-hide-itemlist").checked; | |
if(hide_itemlist_enabled) | |
item.classList.add("hide-item"); | |
} | |
function get_item_title(item) { | |
return item.querySelector(".item-title").getAttribute("title").trim(); | |
} | |
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(".stream-store-list-item"); | |
items.forEach(function(item) { | |
let quantity_text = item.querySelector(".item-quantity-left > span")?.innerHTML; | |
if(quantity_text === "Sold out") | |
sold_out_items.push(item); | |
}) | |
} | |
function check_subscriber_only_items() { | |
let items = document.querySelectorAll(".stream-store-list-item"); | |
items.forEach(function(item) { | |
if(item.querySelector(".item-subscriber-only")) | |
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; | |
} | |
// Add custom styles | |
let styles = ` | |
/* 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 Slash **/ | |
.eye-slash-container { | |
position: absolute; | |
right: 0; | |
padding: 10px; | |
height: 40px; | |
width: 40px; | |
} | |
.eye-slash-container:hover { | |
cursor: pointer; | |
} | |
.eye{ | |
width:1.25em; | |
height:0.75em; | |
position:absolute; | |
display:inline-block; | |
--background:#aaa; | |
--color:currentColor; | |
} | |
.eye div{ | |
overflow:hidden; | |
height:50%; | |
position:relative; | |
margin-bottom:-1px; | |
} | |
.eye div:before{ | |
content:''; | |
background:currentColor; | |
position:absolute; | |
left:0; | |
right:0; | |
height:300%; | |
border-radius:100%; | |
} | |
.eye div:last-child:before{ | |
bottom:0; | |
} | |
.eye:before{ | |
content:''; | |
position:absolute; | |
top:50%; | |
left:50%; | |
transform:translate(-50%, -50%); | |
width:0.35em; | |
height:0.35em; | |
background:var(--color); | |
border:0.1em solid var(--background); | |
border-radius:100%; | |
z-index:1; | |
} | |
.eye:after{ | |
content:''; | |
position:absolute; | |
top:-0.15em; | |
left:calc(33.333% - 0.15em); | |
transform:rotate(45deg) scaleX(0); | |
transform-origin:left center; | |
width:90%; | |
height:0.1em; | |
background:var(--color); | |
border-top:0.1em solid var(--background); | |
z-index:2; | |
transition:transform 0.25s; | |
} | |
.eye.slash:after{ | |
transform:rotate(45deg) scaleX(1); | |
} | |
/**Magnifying glass**/ | |
.magnifying-glass-container { | |
position: absolute; | |
padding: 10px; | |
height: 40px; | |
width: 40px; | |
} | |
.magnifying-glass-container:hover { | |
cursor: pointer; | |
} | |
.ico-mglass { | |
position: absolute; | |
display:inline-block; | |
background: transparent; | |
border-radius: 30px; | |
height: 12px; | |
width: 12px; | |
border: 2px solid #fff; | |
} | |
.ico-mglass:after { | |
content: ""; | |
height: 2px; | |
width: 8px; | |
background: #fff; | |
position: absolute; | |
top: 9px; | |
left: 6px; | |
-webkit-transform: rotate(45deg); | |
-moz-transform: rotate(45deg); | |
-ms-transform: rotate(45deg); | |
-o-transform: rotate(45deg); | |
} | |
.userpages-wrap {max-width: unset;} | |
.hide-item,.sold-out-item,.hide-subscriber-item {display: none;} | |
.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;}`; | |
// Insert custom Styles | |
let style_sheet = document.createElement("style"); | |
style_sheet.innerText = styles; | |
document.head.appendChild(style_sheet); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment