Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

A "Never show me this again, please" button.

A topic by dr!ppy created Oct 16, 2020 Views: 1,655 Replies: 19
Viewing posts 1 to 8
(1 edit) (+21)

Itch has many good games. Itch has thousands of terrible games. Itch has many, many games that I never want to play. For instance, if you sort by Windows + Free + Top Rated, many of the top 50 results are gay furry visual novels. That's not my jam. Yes, I could choose "action" or "adventure", but I want to be surprised, and since there are no negative filters, i.e. a way to say what I don't want to see, I have to sift through hundreds of games I have no interest in. 

Even games that I've played before and liked - I'd rather not see them in the results. Sort the Court, for instance. 

So please implement a way that logged-in users can forever hide games. (Negative filters would be nice, too.) Oh, and make it so that you can do this from the search results page.

Thank you.

(+4)

While I would personally love (and make extensive use of) a please don’t show this to me ever again-checklist, using it would be tedious for most users.

Exclusion filters seem the way forward to me. I happen to know that the search once had exclusion filters. Unfortunately, at some point in the last 60 days they stopped working it seems. I’m sure that fixing them is already on some to-do list, but right now, the admins seem to be overwhelmed by Mac users buying Among Us and them complaining that they want their money back because their machine doesn’t run windows games natively (pure speculation on my part).

You have my upvote, but I think that customer wish is already on their radar. If you’ll excuse me, I’m going browsing for homoerrrotic visual novels now. ;)

(+1)

The problem with exclusion filters is that they're filters.  They work only to the extent that the map matches the territory - i.e., to the extent that people are properly tagging their content, such that the tags on an item reliably correspond to things about the content that people commonly want to find or exclude.  And we don't have that here.  Exclusion filters would be a huge improvement, but the tagging system has been so bad for so long that you would need a "hide this item" option anyway.  

(1 edit) (+1)

Plenty of them are tagged just fine for my purposes. See below as an example of something pushed on my front page that I would never want to see. I say both exclusion filters and never again button, please.

(+6)

I think your suggestion of adding ways to exclude certain content is good and I would like to see something of the sort implemented. I'm not sure what would be the ideal solution, but for starters I think that adding the exclusion filter already in place as an option in the UI would be easy, quick and an uncontroversial first step. As it stands few people will ever learn about it. Plus using it is a chore since I have to dig out that thread to copy/paste the sequence to add to the URL. (FYI at the time of writing this comment it seems to be working fine for me.)

Most likely more tools are justified. Maybe blacklisting games with a certain tag from ever appearing to you (the filter, meanwhile, is just temporary and needs to be reapplied). Or just manually picking a game to never be displayed again. Maybe both or neither — it's not out of the question that there are better ways we haven't mentioned. Nonetheless I think the discussion would be worthwhile and productive.

Mind you I am developing a furry visual novel. You used exactly the kind of game I am making as an example of what you'd rather not see and I think you are perfectly valid in your request. Speaking only for my team and I, we know that our content is fundamentally niche and not up everyone's alley. We don't want to annoy people. As far as we are concerned adding options to filter out content would just improve the experience for everyone because your navigation would be just objectively better, it would be easier for everyone to find the games they want, and we the developers would relax knowing we aren't being a nuisance and bothering anyone. It's probably a safe bet that most, if not all users of Itch have a few things they'd like to filter out (particularly those who use it a lot.) I can't speak for other developers, but it wouldn't surprise me if many (particularly those making adult content) agreed with what I just described.

(+2)

I just got very shiny eyes when hearing the (hidden/poorly documented) exclusion filters worked again but then my eyes lost their luster again… They are now kind of working for me: Of the two examples leafo gave, the result number one returns the same as an entirely unfiltered list would. The second example works though. My guess would be that users now have to add tags before they can exclude them.

Nevertheless: Thank you Minoh Workshop! You have improved my itch.io experience - and with a little luck, that of others. :)

(+2)

3 years later. still a thing that people want, but cant have. please, let us hide games we dont want to see. 

(1 edit) (+1)

While not very user friendly, this will work, if you have any custom css addon for your browser. If it is assets, you need to change the scope accordingly. Or just remove "games", but this might affect your library.

And addon to add things to the list with a mouse click would be nice, but this is beyond my abilities. Copy link/accountname/gamename to the url in question and paste above a placeholder, duplicate lines for next time insertion. Rinse, repeat. The underscores are for easy doubleclick selection. Tested with Stylus 1.5.41.

(the  !important deals with page loads in endless scroll)

@-moz-document url-prefix("https://itch.io/games") {
div.game_cell:has(a[href*="paste_full_link_to_game_inside_quotes"]) { display: none !important}
div.game_cell:has(a[href*="paste_full_link_to_game_inside_quotes"]) { display: none !important}
div.game_cell:has(a[href*="paste_full_link_to_game_inside_quotes"]) { display: none !important}
div.game_cell:has(a[href*="//or_ignore_a_publisher.itch"]) { display: none !important}
div.game_cell:has(a[href*="//or_ignore_a_publisher.itch"]) { display: none !important}
div.game_cell:has(a[href*="//or_ignore_a_publisher.itch"]) { display: none !important}
div.game_cell:has(a[href*="itch.io/or_ignore_games_starting_with"]) { display: none !important}
div.game_cell:has(a[href*="itch.io/or_ignore_games_starting_with"]) { display: none !important}
div.game_cell:has(a[href*="itch.io/or_ignore_games_starting_with"]) { display: none !important}
}
(+1)

I grew tired of there not being an option.. so i made a "solution". it is tedious, but it will hide any game you dont wanna see. install tampermonkey, and copy my code from the pastebin to a new script. add or remove games from the list as you please.

https://pastebin.ai/sczkf85tcl

(+1)

If you have to manage the items on the "list" by editing the code of the script, you can also just edit a user style. I adjusted the styles above to deal with page scrolling. You cannot filter by title, but titles are not unique anyways. You do can filter by itch.io/start_of_the_game_name though. You just need to duplicate yourself some entries to copy paste over.

I since made a tool to do something a bit more powerful, but it is an unpacked chrome extension and not yet released. https://itch.io/t/3477347/add-an-option-to-exclude-owned-games-when-searching

You would click on a button or press a key while hovering over a game thumbnail to put it onto an ignore list. Maybe add some feature requests in the other thread, if this interests you.

(+1)

Trying to read through the thread to understand this. Looks cool, powerful.

(+1)

It is, if I may say so. Frightengly so. It might seriously hamper browsing experience, since it is so easy to put thousands of items or devs on ignore in a short time.

Though there are several mechanism to change behaviour. Simplest is to change the style from not show to show, but with a style that tells you, you probably do not want this item or already know it.

I can also stack styles. The screen is some fooling around with it. The page currently has 17 items that are modyfied. They all got blur style on top. The white stuff has opacity near 0. Upper right has a red outline.  Lower right have scale half, for fun.

I do not know how to capture the essence of what happens, when I activate the style to be display none, since, well, the items are just no longer there, so there is nothing to show ;-)


(+1)

This is how it looks, when I changed the opacity style to display none.

(1 edit)

I love that there's a [excellent, well-curated] preloaded list of games to hide hahaha. I pretty much have just given up on Itch being usable the way I want it (I have so many games purchased I need to go through, anyways), but I'll try this out and see if it makes the experience better.

it sure has helped me a lot already :D i could make it better and easier, not having to manually add the links.. but i am lazy. only really takes a few seconds to copy paste. the games list have never been cleaner for me :D

How would you do that not manually? Are tampermonky scripts self modifyable or do you have access to storage?

Try posting this in console and press l on a thumbnail. If you can modify your list, this should work. 

if (document.querySelector('.game_cell'))
document.addEventListener('keydown', event => {
    if (event.key != 'l') { return; }
    setTimeout(() => {
        var cell = null;
        var hovered = document.querySelector(':hover');
        while (true) {
            if (!hovered) { return; }
            if (hovered.classList.contains('game_cell')) {
                cell = hovered;
                break;
            }
            hovered = hovered.querySelector(':hover');
        }
        if (hovered) {
            console.log(hovered.querySelector('.game_title')?.textContent)
            console.log(hovered.querySelector('a')?.href)   
        }
    }, 50);
})
(+1)

tampermonkey has cloud features. it can use google drive, onedrive, dropbox etc. My plan was to just have it add to the list locally with button presses or whatever. then have it autosync with one of those cloud services. that should work in theory, but it is annoying. i am at a point where i am debating whether or not to just make my own browser extension to do what i want. but.. probably not, as my copy paste solution works for me.

(+1)
// ==UserScript==
// @name         ibil tampermonkey version
// @namespace    nonamespace
// @version      1
// @description  itch browse ignore list - barebone tampermonkey version
// @author       https://redonihunter.itch.io/
// @match        *://itch.io/*
// @run-at       document-end
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_listValues
// @grant        GM_deleteValue
// ==/UserScript==
// setup: copy into tampermonkey, edit configs, save
// usage: hover thumbnails, press buttons
// off styles are used when toggled off or in library
// import and export should be compatible to the full ibil extension
// issues: will slow down when toggling 1k+ items. works on ids, so does not catch reuploads with different id. does not work on all pages.
(function () {
if (!document.querySelector('.game_cell')) { return; }
// configuration start
const l1on = '{display:none}';
const l2on = '{display:none}';
const l1off = '{outline:auto blanchedalmond}';
const l2off = '{outline:auto purple}';
const key1 = '1';
const key2 = '2';
const dev1 = '3';
const dev2 = '4';
const togglek = '5';
const export_l1 = '6';
const export_l2 = '7';
const import_l1 = '8';
const import_l2 = '9';
const deleteallkey = '0';
// configuration end
const hks = key1 + key2 + dev1 + dev2 + togglek + export_l1 + import_l1 + export_l2 + import_l2 + deleteallkey;
const ibil1on = document.head.appendChild(document.createElement('style'));
const ibil2on = document.head.appendChild(document.createElement('style'));
const ibil1off = document.head.appendChild(document.createElement('style'));
const ibil2off = document.head.appendChild(document.createElement('style'));
ibil1on.innerText = '.ibil1on' + l1on;
ibil2on.innerText = '.ibil2on' + l2on;
ibil1off.innerText = '.ibil1off' + l1off;
ibil2off.innerText = '.ibil2off' + l2off;
document.addEventListener('keydown', event => {
    if (!hks.includes(event.key)) { return; }
    switch (event.key) {
        case togglek:
            toggle(); break;
        case import_l1:
            importlist('1'); break;
        case import_l2:
            importlist('2'); break;
        case export_l1:
            exportlist('1'); break;
        case export_l2:
            exportlist('2'); break;
        case deleteallkey:
            deleteall(); break;
        default:
            setTimeout(() => {
                var cell, hovered = document.querySelector(':hover');
                while (true) {
                    if (!hovered) { return; }
                    if (hovered.classList.contains('game_cell')) { cell = hovered; break; }
                    hovered = hovered.querySelector(':hover');
                }
                key_on_cell(event.key, cell);
            }, 50);
    }
});
const observer = new MutationObserver((mutationsList, observer) => {
    const temp = [];
    for (var i = 0, ii = mutationsList.length; i < ii; i++) {
        mutationsList[i].addedNodes.forEach((node) => {
            if (node?.classList?.contains('game_cell')) { temp.push(node); }
        });
    }
    if (temp?.length) { update_cell_styles(temp); }
});
observer.observe(document, { childList: true, subtree: true });
update_cell_styles(document.getElementsByClassName('game_cell'));
function do_not_ignore_here() {
    const state = GM_getValue('onoff', 'on');
    if (state == 'off') { return true; }
    if (document.URL == 'https://itch.io/library/recommendations') { return false; }
    return (/^https\:\/\/.+\.itch\.io\/$/.test(document.URL) || document.URL.startsWith('https://itch.io/profile/') ||
        document.URL.startsWith('https://itch.io/my-collections') || document.URL.startsWith('https://itch.io/c/') ||
        document.URL.startsWith('https://itch.io/my-purchases') || document.URL.startsWith('https://itch.io/library') ||
        document.URL.startsWith('https://itch.io/my-feed'))
}
function update_cell_styles(cell_list) {
    const page_dnih = do_not_ignore_here();
    var game_id, author_id, sg, sa;
    for (var i = 0, ii = cell_list.length; i < ii; i++) {
        game_id = cell_list[i]?.getAttribute('data-game_id');
        author_id = cell_list[i]?.querySelector('div.game_author>a')?.getAttribute('data-label');
        cell_list[i].classList.remove('ibil1on', 'ibil2on', 'ibil1off', 'ibil2off');
        sg = GM_getValue(game_id, null);
        if (sg) {
            if (sg?.s == '1') { cell_list[i].classList.add(page_dnih ? 'ibil1off' : 'ibil1on'); }
            if (sg?.s == '2') { cell_list[i].classList.add(page_dnih ? 'ibil2off' : 'ibil2on'); }
        } else {
            sa = GM_getValue(author_id, null);
            if (sa) {
                if (sa?.s == '1') { cell_list[i].classList.add(page_dnih ? 'ibil1off' : 'ibil1on'); }
                if (sa?.s == '2') { cell_list[i].classList.add(page_dnih ? 'ibil2off' : 'ibil2on'); }
            }
        }
    }
}
function key_on_cell(hk, cell) {
    const game_id = cell?.getAttribute('data-game_id');
    const game_link = (cell?.getElementsByClassName('game_link')?.[0] || cell?.getElementsByClassName('title')?.[0])?.href;
    const game_title = give_me_title(cell);
    const game_author = cell?.querySelector('div.game_author>a');
    const author_id = game_author?.getAttribute('data-label');
    const author_link = game_author?.href;
    const author_name = (game_author?.innerText || cell?.querySelector('.user_link')?.innerText ||
        cell?.parentElement?.parentElement?.querySelector('.author_link')?.innerText || author_link || game_link);
    var value, new_s, key_s = (hk == key1 || hk == dev1) ? '1' : '2';
    if (hk == key1 || hk == key2) {
        if (!game_id || !game_link || !game_title || !author_name) { return; }
        value = GM_getValue(game_id, { s: '0' });
        new_s = (value.s == '0') ? (key_s) : (value.s == key_s ? '0' : key_s);
        if (new_s == '0') { GM_deleteValue(game_id) } else { GM_setValue(game_id, { s: new_s, a: author_name, l: game_link, t: game_title }); }
    }
    if (hk == dev1 || hk == dev2) {
        if (!author_id || !author_link || !author_name) { return; }
        value = GM_getValue(author_id, { s: '0' });
        new_s = (value.s == '0') ? (key_s) : (value.s == key_s ? '0' : key_s);
        if (new_s == '0') { GM_deleteValue(author_id) } else { GM_setValue(author_id, { s: new_s, a: author_name, l: author_link }); }
    }
    update_cell_styles([cell]);
}
function toggle() {
    const state = GM_getValue('onoff', 'on');
    GM_setValue('onoff', state == 'on' ? 'off' : 'on')
    update_cell_styles(document.getElementsByClassName('game_cell'));
}
async function importlist(letter) {
    if (!confirm(`Import an exported list and update all items to list ${letter}?`)) { return; }
    var input = document.createElement('input');
    input.type = 'file';
    try {
        input.addEventListener('change', function listener() {
            let fr = new FileReader();
            fr.onload = async () => {
                try {
                    for (const [key, data] of Object.entries(JSON.parse(fr.result))) {
                        if (Object.hasOwn(data, 's')) {
                            if (Object.hasOwn(data, 't')) {
                                GM_setValue(key, { 'l': data.l, 't': data.t, 'a': data.a, 's': letter });
                            } else {
                                GM_setValue(key, { 'l': data.l, 'a': data.a, 's': letter });
                            }
                        }
                    }
                    update_cell_styles(document.getElementsByClassName('game_cell'));
                } catch (e) { console.log(e); alert('Could not parse. Need an exported file, not css or game lists.'); }
            };
            fr.readAsText(this.files[0]);
        })
    } catch (e) { console.log('error while trying to read a file:', e) }
    if (navigator.userActivation.isActive) { input.click() } else { alert('Not allowed or too slow (5s)'); }
}
function exportlist(letter) {
    var blob, value;
    const timestamp = new Date().toLocaleString();
    const filename = `ibil_tampermonkey_export_${letter}_${timestamp}.txt`;
    const temp_data = {};
    for (const key of GM_listValues()) {
        value = GM_getValue(key, null);
        if (value?.s == letter) { temp_data[key] = value; }
    }
    blob = new Blob([JSON.stringify(temp_data)], { type: 'text/plain' });
    try { save_a_blob(blob, filename); } catch (e) { console.log('exporting failed:', e); }
}
function deleteall() {
    if (confirm('Delete all stored items? Remember to export both lists before.')) {
        for (const key of GM_listValues()) { GM_deleteValue(key); }
    }
    update_cell_styles(document.getElementsByClassName('game_cell'));
}
async function save_a_blob(blob, name = 'ibil_export.txt') {
    const a = document.createElement('a');
    a.download = name; a.href = URL.createObjectURL(blob);
    a.addEventListener('click', () => { setTimeout(() => URL.revokeObjectURL(a.href), 300 * 1000); });
    a.click();
}
function give_me_title(cell) {
    if (!cell) { return 'Not a cell'; }
    var node = cell;
    var n, c = 0, t = '';
    const where_to_look = ['title game_link', 'game_title', 'title'];
    const ww = where_to_look.length;
    search_title: while (++c < 7) {
        for (var w = 0; w < ww; w++) {
            n = node.getElementsByClassName(where_to_look[w]);
            if (n.length == 1) { t = n[0]?.innerText; break search_title; }
            if (n.length > 1) { break search_title; }
        }
        if (node.parentElement != document) { node = node.parentElement; } else { break search_title; }
    }
    return t || 'Title not found';
}
})();
(+1)

Bit long for posting in comment, but should work.

I copy pasted and adjusted some logic from my not yet released unpacked extension into a tampermonkey script. It is bare bone and misses bells and whistles, but should do the job. It even has two lists and two styles for each list. Plus import, export. But I do not really have any clue about that tampermonkey and if I am missing something crucial. And I did not test it for very long.

(+1)

I don't know exactly how this works, but I hovered over a game, pressed "1" on my keyboard, and it's gone. Works perfect as far as I'm concerned!! Amazing job.