mirror of
https://github.com/Jetsparrow/steam-janitor.git
synced 2026-01-20 21:56:09 +03:00
v0.0.3
Proper ui controls Doesn't mess with layout Demo video
This commit is contained in:
parent
7b7f516b7a
commit
c0f11aa940
19
README.md
19
README.md
@ -1,17 +1,8 @@
|
|||||||
# Steam Janitor
|
# Steam Janitor
|
||||||
_A userscript that makes browsing through thousands of mods viable_
|
_A userscript that makes browsing mods viable_
|
||||||
|
|
||||||
## [Install 0.0.2](https://github.com/Jetsparrow/steam-janitor/raw/main/steam-janitor.user.js)
|
[Demo, install links](https://jetsparrow.github.io/steam-janitor/)
|
||||||
_Requires a userscript extension for your browser, like [Tampermonkey](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo?hl=en)_
|
|
||||||
|
|
||||||
**N.B.: this is a very crude alpha. Developed and tested in Google Chrome**
|
* Adds a "hide" button to all items on the workshop browse page. Hides item forever, until unhidden.
|
||||||
|
* Adds a "filter" checkbox to the top paging controls, allowing to switch between filtered and unfiltered view.
|
||||||
## Filter mods
|
* Adds endless scrolling to workshop browse pages.
|
||||||
|
|
||||||
Adds a little "hide" button to any workshop browse page. Use it, and you will no longer see the hundreds of miscellaneous translations to laguages you don't know, obsolete mods, or gachimuchi memes.
|
|
||||||
|
|
||||||
The userscripts adds a "filter" checkbox to the top paging controls, allowing you to switch between the filtered and unfiltered view.
|
|
||||||
|
|
||||||
## Endless scrolling
|
|
||||||
|
|
||||||
After the filter runs its course, you will be left with barely any mods. Endless scrolling fixes that.
|
|
||||||
16
index.md
16
index.md
@ -1,13 +1,17 @@
|
|||||||
## [Install 0.0.2](https://github.com/Jetsparrow/steam-janitor/raw/main/steam-janitor.user.js)
|
https://user-images.githubusercontent.com/37241560/153673942-b35b53e9-4c88-4695-8631-855243251740.mp4
|
||||||
_Requires a userscript extension for your browser, like [Tampermonkey](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo?hl=en)_
|
|
||||||
|
|
||||||
**N.B.: this is a very crude alpha. Developed and tested in Google Chrome**
|
## [Steam Janitor v0.0.3-alpha - install](https://github.com/Jetsparrow/steam-janitor/raw/main/steam-janitor.user.js)
|
||||||
|
_Requires a userscript extension for your browser, e.g. [Tampermonkey](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo?hl=en)_
|
||||||
|
|
||||||
## Filter mods
|
**N.B.: this is an early alpha. Tested only in Tampermonkey on Google Chrome**
|
||||||
|
|
||||||
Adds a little "hide" button to any workshop browse page. Use it, and you will no longer see the hundreds of miscellaneous translations to laguages you don't know, obsolete mods, or gachimuchi memes.
|
## Filter unwanted items
|
||||||
|
|
||||||
The userscripts adds a "filter" checkbox to the top paging controls, allowing you to switch between the filtered and unfiltered view.
|
A "hide" button is added to every item on a workshop browse page.
|
||||||
|
Clicking it will hide the item forever - until you turn off the filter and unhide it.
|
||||||
|
Translations to laguages you don't know, obsolete mods, gachimuchi memes, and mods that are just not quite your cup of tea - hide once and never see them again.
|
||||||
|
|
||||||
|
The "filter" checkbox at the top paging controls allows you to switch between the filtered and unfiltered view.
|
||||||
|
|
||||||
## Endless scrolling
|
## Endless scrolling
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
// ==UserScript==
|
// ==UserScript==
|
||||||
// @name Steam Janitor
|
// @name Steam Janitor
|
||||||
|
// @namespace jetsparrow-steam-janitor
|
||||||
|
// @author Jetsparrow
|
||||||
// @description Hide unwanted user content in browse view, endless scrolling
|
// @description Hide unwanted user content in browse view, endless scrolling
|
||||||
// @match *://*.steamcommunity.com/workshop/browse/*
|
// @match *://*.steamcommunity.com/workshop/browse/*
|
||||||
// @run-at document-end
|
// @run-at document-end
|
||||||
// @version 0.0.2
|
// @version 0.0.3
|
||||||
// @grant GM_setValue
|
// @grant GM_setValue
|
||||||
// @grant GM_getValue
|
// @grant GM_getValue
|
||||||
// @grant GM_listValues
|
// @downloadURL https://jetsparrow.github.io/steam-janitor/steam-janitor.user.js
|
||||||
// @updateURL https://raw.githubusercontent.com/Jetsparrow/steam-janitor/main/steam-janitor.js
|
|
||||||
// @downloadURL https://raw.githubusercontent.com/Jetsparrow/steam-janitor/main/steam-janitor.js
|
|
||||||
// ==/UserScript==
|
// ==/UserScript==
|
||||||
|
|
||||||
const addGlobalStyle = (doc, css) => {
|
const addGlobalStyle = (doc, css) => {
|
||||||
@ -42,31 +42,60 @@ const onVisible = (element, callback) => {
|
|||||||
|
|
||||||
observer.observe(element);
|
observer.observe(element);
|
||||||
};
|
};
|
||||||
const selectors = {
|
const selector = {
|
||||||
PAGING_INFO: ".workshopBrowsePagingWithBG",
|
PAGING_INFO: ".workshopBrowsePagingWithBG",
|
||||||
ITEM_CONTAINER: ".workshopBrowseItems .workshopItemPreviewHolder",
|
ITEM_CONTAINER: ".workshopBrowseItems .workshopItemPreviewHolder",
|
||||||
ITEMS_CONTAINER: ".workshopBrowseItems",
|
ITEMS_CONTAINER: ".workshopBrowseItems",
|
||||||
ITEMS_HOVERS: ".workshopBrowseItems script",
|
ITEMS_HOVERS: ".workshopBrowseItems script",
|
||||||
NEXT_BUTTON: ".workshopBrowsePagingControls .pagebtn:last-child",
|
NEXT_BUTTON: ".workshopBrowsePagingControls .pagebtn:last-child",
|
||||||
PAGINATOR: ".workshopBrowsePagingControls",
|
PAGINATOR: ".workshopBrowsePagingControls",
|
||||||
FOOTER: ".workshopBrowsePaging"
|
PAGE_INFO: ".workshopBrowsePagingInfo",
|
||||||
|
FOOTER: ".workshopBrowsePaging",
|
||||||
};
|
};
|
||||||
|
|
||||||
const unhiddenClass = "janitorItem";
|
const elemId = {
|
||||||
const hiddenFilteredClass = "janitorItemHidden";
|
scrollTarget: "footer",
|
||||||
const hiddenUnfilteredClass = "janitorItemHiddenUnfiltered";
|
filterToggleCheckbox: "janitorFilterToggleCheckbox",
|
||||||
const hideButtonClass = "janitorHideButton";
|
filterToggleOn: "janitorFilterOnIcon",
|
||||||
const showButtonClass = "janitorShowButton";
|
filterToggleOff: "janitorFilterOffIcon",
|
||||||
|
};
|
||||||
|
|
||||||
|
const cssClass = {
|
||||||
|
unhidden: "janitorItem",
|
||||||
|
hiddenFiltered: "janitorItemHidden",
|
||||||
|
hiddenUnfiltered: "janitorItemHiddenUnfiltered",
|
||||||
|
hideButton: "janitorHideButton",
|
||||||
|
showButton: "janitorShowButton",
|
||||||
|
filterToggle: "janitorFilterToggle",
|
||||||
|
hideButton: "janitorhideButton"
|
||||||
|
};
|
||||||
|
|
||||||
|
const resource = {
|
||||||
|
iconEyeOpen:"https://jetsparrow.github.io/steam-janitor/res/filter_toggle_open.png",
|
||||||
|
iconEyeClosed:"https://jetsparrow.github.io/steam-janitor/res/filter_toggle_closed.png",
|
||||||
|
btnHide:"https://jetsparrow.github.io/steam-janitor/res/janitor_hide.png",
|
||||||
|
btnHideHover:"https://jetsparrow.github.io/steam-janitor/res/janitor_hide_hover.png",
|
||||||
|
btnUnhide:"https://jetsparrow.github.io/steam-janitor/res/janitor_unhide.png",
|
||||||
|
btnUnhideHover:"https://jetsparrow.github.io/steam-janitor/res/janitor_unhide_hover.png",
|
||||||
|
};
|
||||||
|
|
||||||
const janitorCss = `
|
const janitorCss = `
|
||||||
.${hiddenFilteredClass} { display:none !important; }
|
.${cssClass.hiddenFiltered} {display:none !important; }
|
||||||
.${hiddenUnfilteredClass} {opacity: 0.25;}
|
.${cssClass.hiddenUnfiltered} img {opacity: 0.25;}
|
||||||
.${hiddenUnfilteredClass} .${showButtonClass} { display:inline !important; }
|
.${cssClass.hideButton} {width:25px; height:25px;}
|
||||||
.${hiddenUnfilteredClass} .${hideButtonClass} { display:none !important; }
|
.${cssClass.hiddenUnfiltered} .${cssClass.hideButton}:hover {background-image:url("${resource.btnUnhideHover}")}
|
||||||
.${unhiddenClass} .${showButtonClass} { display:none !important; }
|
.${cssClass.hiddenUnfiltered} .${cssClass.hideButton} {background-image:url("${resource.btnUnhide}")}
|
||||||
.${unhiddenClass} .${hideButtonClass} { display:inline !important; }
|
.${cssClass.unhidden} .${cssClass.hideButton}:hover {background-image:url("${resource.btnHideHover}")}
|
||||||
|
.${cssClass.unhidden} .${cssClass.hideButton} {background-image:url("${resource.btnHide}")}
|
||||||
|
.${cssClass.filterToggle} * { vertical-align: middle; }
|
||||||
|
.workshopItem .${cssClass.hideButton} { visibility: hidden; position: absolute; top: 4px; right: 6px; }
|
||||||
|
.workshopItem:hover .${cssClass.hideButton} { visibility: visible; position: absolute; top: 4px; right: 6px;}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const setting = {
|
||||||
|
filterEnabled: "janitorFilterEnabled"
|
||||||
|
};
|
||||||
|
|
||||||
const defaultModData = () => {
|
const defaultModData = () => {
|
||||||
let d = new Object();
|
let d = new Object();
|
||||||
d.hide = false;
|
d.hide = false;
|
||||||
@ -78,41 +107,42 @@ const loadModData = (modId) => {
|
|||||||
}
|
}
|
||||||
const saveModData = (modId, data) => GM_setValue("modid:" + modId, JSON.stringify(data));
|
const saveModData = (modId, data) => GM_setValue("modid:" + modId, JSON.stringify(data));
|
||||||
|
|
||||||
const updateHiddenClass = (doc, modId) => {
|
const updateHiddenClass = (doc, modId, filterOn) => {
|
||||||
var container = doc.getElementById(modId)?.parentElement?.parentElement;
|
var container = doc.getElementById(modId)?.parentElement?.parentElement;
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
const d = loadModData(modId);
|
const d = loadModData(modId);
|
||||||
container.classList.remove(unhiddenClass);
|
container.classList.remove(cssClass.unhidden);
|
||||||
container.classList.remove(hiddenFilteredClass);
|
container.classList.remove(cssClass.hiddenFiltered);
|
||||||
container.classList.remove(hiddenUnfilteredClass);
|
container.classList.remove(cssClass.hiddenUnfiltered);
|
||||||
|
|
||||||
if (!d.hide) container.classList.add(unhiddenClass);
|
if (!d.hide) container.classList.add(cssClass.unhidden);
|
||||||
else if (window.janitorFilterEnabled) container.classList.add(hiddenFilteredClass);
|
else if (filterOn) container.classList.add(cssClass.hiddenFiltered);
|
||||||
else container.classList.add(hiddenUnfilteredClass);
|
else container.classList.add(cssClass.hiddenUnfiltered);
|
||||||
}
|
}
|
||||||
|
|
||||||
const setHidden = (doc, modId, isHidden) => {
|
const toggleHidden = (doc, modId) => {
|
||||||
var d = loadModData(modId);
|
var d = loadModData(modId);
|
||||||
d.hide = isHidden;
|
d.hide = !d.hide;
|
||||||
saveModData(modId, d);
|
saveModData(modId, d);
|
||||||
updateHiddenClass(doc, modId);
|
const filterOn = GM_getValue(setting.filterEnabled);
|
||||||
|
updateHiddenClass(doc, modId, filterOn);
|
||||||
}
|
}
|
||||||
|
|
||||||
const addHideButtons = (doc, container, id) => {
|
const addHideButtons = (doc, container, id) => {
|
||||||
const hide = htmlToElement(doc, `<a class="${hideButtonClass}">hide</a>`)
|
const controls = htmlToElement(doc, `<div class="${cssClass.hideButton}"> </>`);
|
||||||
hide.onclick = () => {setHidden(document, id, true);};
|
controls.onclick = (e) => {
|
||||||
container.prepend(hide);
|
e.cancelBubble = true;
|
||||||
|
toggleHidden(document, id);
|
||||||
const show = htmlToElement(doc, `<a class="${showButtonClass}">show</a>`)
|
};
|
||||||
show.onclick = () => {setHidden(document, id, false);};
|
container.append(controls);
|
||||||
container.prepend(show);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const processContainers = (doc) => {
|
const processContainers = (doc) => {
|
||||||
for (var el of doc.querySelectorAll(selectors.ITEM_CONTAINER)){
|
const filterOn = GM_getValue(setting.filterEnabled);
|
||||||
|
for (var el of doc.querySelectorAll(selector.ITEM_CONTAINER)){
|
||||||
const container = el.parentElement.parentElement;
|
const container = el.parentElement.parentElement;
|
||||||
const id = el.id;
|
const id = el.id;
|
||||||
updateHiddenClass(doc, id);
|
updateHiddenClass(doc, id, filterOn);
|
||||||
|
|
||||||
if (container.janitorButtonsAdded) continue;
|
if (container.janitorButtonsAdded) continue;
|
||||||
container.janitorButtonsAdded = true;
|
container.janitorButtonsAdded = true;
|
||||||
@ -128,14 +158,14 @@ const loadNextPage = (url) => {
|
|||||||
const newDoc = parser.parseFromString(html, "text/html");
|
const newDoc = parser.parseFromString(html, "text/html");
|
||||||
processContainers(newDoc);
|
processContainers(newDoc);
|
||||||
|
|
||||||
const newMods = newDoc.querySelectorAll(selectors.ITEM_CONTAINER);
|
const newMods = newDoc.querySelectorAll(selector.ITEM_CONTAINER);
|
||||||
const modContainer = document.querySelector(selectors.ITEMS_CONTAINER);
|
const modContainer = document.querySelector(selector.ITEMS_CONTAINER);
|
||||||
for (const mod of newMods) {
|
for (const mod of newMods) {
|
||||||
const container = mod.parentElement.parentElement;
|
const container = mod.parentElement.parentElement;
|
||||||
modContainer.appendChild(container);
|
modContainer.appendChild(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
const scripts = newDoc.querySelectorAll(selectors.ITEMS_HOVERS);
|
const scripts = newDoc.querySelectorAll(selector.ITEMS_HOVERS);
|
||||||
for (const newScript of scripts){
|
for (const newScript of scripts){
|
||||||
const matches = newScript.innerHTML.match(/(sharedfile_\d+)/);
|
const matches = newScript.innerHTML.match(/(sharedfile_\d+)/);
|
||||||
if (matches.length < 1) continue;
|
if (matches.length < 1) continue;
|
||||||
@ -144,48 +174,56 @@ const loadNextPage = (url) => {
|
|||||||
eval("try{ "+ newScript.innerHTML + " } catch {} ");
|
eval("try{ "+ newScript.innerHTML + " } catch {} ");
|
||||||
}
|
}
|
||||||
|
|
||||||
const nextUrl = newDoc.querySelector(selectors.NEXT_BUTTON)?.getAttribute("href");
|
const nextUrl = newDoc.querySelector(selector.NEXT_BUTTON)?.getAttribute("href");
|
||||||
const footer = document.getElementById("footer");
|
const footer = document.getElementById(elemId.scrollTarget);
|
||||||
if (nextUrl) onVisible(footer, loadNextPage.bind(null, nextUrl));
|
if (nextUrl) onVisible(footer, loadNextPage.bind(null, nextUrl));
|
||||||
window.history.pushState("", "", url);
|
window.history.pushState("", "", url);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function toggleFilter(checkbox) {
|
function toggleFilter(checkbox) {
|
||||||
window.janitorFilterEnabled = checkbox.checked;
|
GM_setValue(setting.filterEnabled, checkbox.checked);
|
||||||
GM_setValue("janitorFilterEnabled", checkbox.checked);
|
|
||||||
const doc = checkbox.ownerDocument;
|
const doc = checkbox.ownerDocument;
|
||||||
|
doc.getElementById(elemId.filterToggleOff).hidden = checkbox.checked;
|
||||||
|
doc.getElementById(elemId.filterToggleOn).hidden = !checkbox.checked;
|
||||||
processContainers(doc);
|
processContainers(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
const load = () => {
|
const load = () => {
|
||||||
|
|
||||||
console.log(GM_listValues());
|
|
||||||
|
|
||||||
addGlobalStyle(document, janitorCss);
|
addGlobalStyle(document, janitorCss);
|
||||||
|
|
||||||
const filterToggleRoot = document.querySelector(selectors.PAGING_INFO);
|
document.querySelector(selector.PAGE_INFO)?.remove();
|
||||||
|
const filterToggleRoot = document.querySelector(selector.PAGING_INFO);
|
||||||
const toggle = htmlToElement(document, `
|
const toggle = htmlToElement(document, `
|
||||||
<div>
|
<div class="${cssClass.filterToggle}">
|
||||||
<input type="checkbox" id="janitorFilterToggle">
|
|
||||||
<label for="janitorFilterToggle">Filter</label>
|
<input type="checkbox" id="${elemId.filterToggleCheckbox}">
|
||||||
|
|
||||||
|
<label for="${elemId.filterToggleCheckbox}">
|
||||||
|
<img src="${resource.iconEyeOpen}" id="${elemId.filterToggleOff}">
|
||||||
|
<img src="${resource.iconEyeClosed}" id="${elemId.filterToggleOn}">
|
||||||
|
</label>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
const checkbox = toggle.children[0];
|
const checkbox = toggle.children[0];
|
||||||
checkbox.checked = window.janitorFilterEnabled = GM_getValue("janitorFilterEnabled", true);
|
checkbox.checked = GM_getValue(setting.filterEnabled, true);
|
||||||
checkbox.onclick = () => toggleFilter(checkbox);
|
checkbox.onclick = () => toggleFilter(checkbox);
|
||||||
filterToggleRoot.prepend(toggle);
|
filterToggleRoot.prepend(toggle);
|
||||||
|
toggleFilter(checkbox);
|
||||||
processContainers(document);
|
processContainers(document);
|
||||||
|
|
||||||
const nextUrl = document.querySelector(selectors.NEXT_BUTTON)?.getAttribute("href");
|
const nextUrl = document.querySelector(selector.NEXT_BUTTON)?.getAttribute("href");
|
||||||
if (!nextUrl) {
|
if (!nextUrl) {
|
||||||
console.error(`Could not find nextUrl through "${selectors.NEXT_BUTTON}"`);
|
console.error(`Could not find nextUrl through "${selector.NEXT_BUTTON}"`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadNextPage(nextUrl);
|
loadNextPage(nextUrl);
|
||||||
document.querySelector(selectors.PAGINATOR)?.remove();
|
|
||||||
|
document.querySelector(selector.PAGINATOR)?.remove();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
load();
|
load();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user