🏠 Home 

9GAG Likes Page Filter Tool

A tool which allows to filter the 9GAG upvotes / likes personal page only on the tags you are interested into (e.g. funny, gaming, pcmr, etc...).


Install this script?
// ==UserScript==
// @name         9GAG Likes Page Filter Tool
// @namespace    [email protected]
// @version      0.2
// @description  A tool which allows to filter the 9GAG upvotes / likes personal page only on the tags you are interested into (e.g. funny, gaming, pcmr, etc...).
// @author       Pierpaolo Tommasi
// @match        *://9gag.com/u/*/likes
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        none
// @license MIT
// ==/UserScript==
// This is a set containg the tags currently filtered on
let activeFilters;
// A map where the key is the tag and the value is an array of article ID (strings)
let tagToArticles;
// A map where the key is the article ID and the value is the array of tags (strings)
let articleToTags;
// The count hide option (how many articles should a tag have in order to be displayed)
let hidesCount;
// Which sorting should be applied on the discovered tags
let sorting;
// Query the current view and return a map where the key are the tags and
// the values are the articles with the given tag.
function getNewArticles() {
const _articleToTags = { };
const listView = document.getElementById("list-view-2");
const articles = [ ... listView.querySelectorAll("article") ];
articles.forEach(a => {
const articleId = a.getAttribute("id");
if (!articleToTags.has(articleId)) {
_articleToTags[articleId] = [ ... a.querySelectorAll(".ui-post-tags a") ].map(a => a.innerText);
}
});
return _articleToTags;
}
// Remove the existing menu, to repaint a new one
function cleanMenu() {
const menu = document.getElementById("tags_extra_menu");
menu && menu.remove();
}
function createFilteredTagButton(tag, count) {
const tagElement = document.createElement("div");
tagElement.innerHTML = `${tag} (${count})`;
tagElement.setAttribute("style", "display: inline-block; margin: 2px 4px; padding: 4px 2px 4px 4px; background-color: powderblue; border-radius: 2px;");
const addElement = document.createElement("span");
addElement.innerHTML = `Clear`;
addElement.setAttribute("style", "cursor: pointer; margin: 2px 0px 2px 8px; padding: 2px; background-color: mediumslateblue; border-radius: 2px;");
tagElement.appendChild(addElement);
addElement.onclick = () => {
if(activeFilters.has(tag)) {
activeFilters.delete(tag);
repaintMenu("clear link -> onclick");
updateFilters();
}
};
return tagElement;
}
function createTagButton(tag, count) {
const tagElement = document.createElement("div");
tagElement.innerHTML = `${tag} (${count})`;
tagElement.setAttribute("style", "display: inline-block; margin: 2px 4px; padding: 4px 2px 4px 4px; background-color: powderblue; border-radius: 2px;");
const addElement = document.createElement("span");
addElement.innerHTML = `Add`;
addElement.setAttribute("style", "cursor: pointer; margin: 2px 0px 2px 8px; padding: 2px; background-color: mediumslateblue; border-radius: 2px;");
tagElement.appendChild(addElement);
addElement.onclick = () => {
if(!activeFilters.has(tag)) {
activeFilters.add(tag);
repaintMenu("add link -> onclick");
updateFilters();
}
};
return tagElement;
}
function createFiltersMenu() {
const filtersMenu = document.createElement("div");
const filtersLabel = document.createElement("div");
filtersLabel.innerHTML = "Only posts with one of these tags will be displayed:";
filtersMenu.appendChild(filtersLabel);
if (activeFilters.size > 0) {
activeFilters.forEach(tag => {
filtersMenu.appendChild(createFilteredTagButton(tag, tagToArticles.get(tag).length));
});
} else {
const noFilters = document.createElement("div");
noFilters.innerHTML = "No selection yet.";
filtersMenu.appendChild(noFilters);
}
return filtersMenu;
}
function createTagOptionsMenu() {
const tagOptionsMenu = document.createElement("div");
//------ Sub menu with the tags count
const countLabelSubMenu = document.createElement("div");
const countLabelBefore = document.createElement("span");
countLabelBefore.innerHTML = "Only tags with at least ";
const countLabelInput = document.createElement("input");
countLabelInput.setAttribute("type", "number");
countLabelInput.setAttribute("min", "1");
countLabelInput.setAttribute("max", "99");
countLabelInput.setAttribute("value", hidesCount);
countLabelInput.onchange = () => {
const newHidesCount = parseInt(countLabelInput.value);
if (!isNaN(newHidesCount)) {
hidesCount = newHidesCount;
repaintMenu("input hides count -> onchange");
}
};
const countLabelAfter = document.createElement("span");
countLabelAfter.innerHTML = " posts will be displayed.";
countLabelSubMenu.appendChild(countLabelBefore);
countLabelSubMenu.appendChild(countLabelInput);
countLabelSubMenu.appendChild(countLabelAfter);
tagOptionsMenu.appendChild(countLabelSubMenu);
//------ Sub menu with the sorting
const sortTagSubMenu = document.createElement("div");
sortTagSubMenu.setAttribute("style", "margin-top: 3px;");
const sortLabel = document.createElement("span");
sortLabel.innerHTML = "Sort tags by ";
const sortInput = document.createElement("select");
sortInput.setAttribute("style", "height: inherit; padding: inherit; font-weight: normal; margin: 0; display: inline-block;");
const unsortedOpt = document.createElement("option");
unsortedOpt.innerHTML = "Unsorted";
unsortedOpt.setAttribute("value", "unsorted");
if (sorting === "unsorted") {
unsortedOpt.setAttribute("selected", "true");
}
sortInput.appendChild(unsortedOpt);
const articlesCountOpt = document.createElement("option");
articlesCountOpt.innerHTML = "Articles count";
articlesCountOpt.setAttribute("value", "count");
if (sorting === "count") {
articlesCountOpt.setAttribute("selected", "true");
}
sortInput.appendChild(articlesCountOpt);
const alphabeticOpt = document.createElement("option");
alphabeticOpt.innerHTML = "Alphabetic order";
alphabeticOpt.setAttribute("value", "alphabetic");
if (sorting === "alphabetic") {
alphabeticOpt.setAttribute("selected", "true");
}
sortInput.appendChild(alphabeticOpt);
sortInput.onchange = () => {
sorting = sortInput.value;
repaintMenu("select sorting -> onchange");
};
sortTagSubMenu.appendChild(sortLabel);
sortTagSubMenu.appendChild(sortInput);
tagOptionsMenu.appendChild(sortTagSubMenu);
//------ Sub menu for custom tags
const manualAddSubMenu = document.createElement("div");
manualAddSubMenu.setAttribute("style", "margin-top: 3px;");
const addLabel = document.createElement("span");
addLabel.innerHTML = "Manually add a tag: ";
const addTextInput = document.createElement("input");
addTextInput.setAttribute("type", "text");
addTextInput.setAttribute("style", "height: inherit; padding: inherit; display: inline; margin: inherit; width: 60px;");
const addButton = document.createElement("button");
addButton.innerHTML = "Add";
addButton.onclick = () => {
if (addTextInput.value) {
activeFilters.add(addTextInput.value);
if(!tagToArticles.has(addTextInput.value)) {
tagToArticles.set(addTextInput.value, []);
}
repaintMenu("add tag -> onclick");
updateFilters();
}
}
manualAddSubMenu.appendChild(addLabel);
manualAddSubMenu.appendChild(addTextInput);
manualAddSubMenu.appendChild(addButton);
tagOptionsMenu.appendChild(manualAddSubMenu);
//------
return tagOptionsMenu;
}
function createTagsMenu() {
const tagsMenu = document.createElement("div");
const tagLabel = document.createElement("div");
tagLabel.innerHTML = "Tags discovered so far:";
tagsMenu.appendChild(tagLabel);
const getSortedTags = () => {
const tags = [ ... tagToArticles.keys() ];
switch(sorting) {
case "unsorted":
return tags;
case "alphabetic":
return tags.sort((t1, t2) => t1.toLocaleLowerCase().localeCompare(t2.toLocaleLowerCase()));
case "count":
return tags.sort((t1, t2) => tagToArticles.get(t2).length - tagToArticles.get(t1).length);
default:
return tags;
}
}
getSortedTags().forEach(tag => {
const count = tagToArticles.get(tag).length;
if (count >= hidesCount) {
tagsMenu.appendChild(createTagButton(tag, count));
}
});
return tagsMenu;
}
function repaintMenu(caller) {
cleanMenu();
// console.log("Repainting menu after call from ", caller);
const menu = document.createElement("div");
menu.setAttribute("id", "tags_extra_menu");
menu.setAttribute("style", "position: fixed; right: calc(var(--main-margin) - 60px); top: 42px; bottom: 0px; overflow-y: scroll; width: 360px; margin: 10px; padding: 6px; background-color: white; z-index: 100;");
document.querySelector("#page").before(menu);
menu.appendChild(createFiltersMenu());
menu.appendChild(document.createElement("hr"));
menu.appendChild(createTagOptionsMenu());
menu.appendChild(document.createElement("hr"));
menu.appendChild(createTagsMenu());
}
function shouldHide(articleId) {
if (activeFilters.size == 0) {
return false;
}
const tags = articleToTags.get(articleId);
let hide = true;
tags.forEach(t => {
if(activeFilters.has(t)) {
hide = false;
}
});
return hide;
}
function updateFilters(delta) {
const updateArticle = (articleId) => {
const el = document.getElementById(articleId);
if (shouldHide(articleId)) {
el.setAttribute("style", "display: none");
} else {
el.removeAttribute("style");
}
}
if (delta == undefined) {
for (const articleId of articleToTags.keys()) {
updateArticle(articleId);
}
} else {
for (const articleId in delta) {
updateArticle(articleId);
}
}
}
(function() {
'use strict';
console.log("9gag like filter activated!");
const addDelta = (newArticleToTags) => {
for (const articleId in newArticleToTags) {
if (!articleToTags.has(articleId)) {
const tags = newArticleToTags[articleId];
articleToTags.set(articleId, tags);
tags.forEach(tag => {
if(tagToArticles.has(tag)) {
tagToArticles.get(tag).push(articleId);
} else {
tagToArticles.set(tag, [articleId]);
}
});
}
}
repaintMenu("addDelta");
updateFilters(newArticleToTags);
}
// 9gag.com/u/<anything>/likes/
const likePage = /9gag\.com\/u\/\w*\/likes/;
let isFilterActive = false;
setInterval(() => {
if (likePage.test(window.location.href)) {
if (!isFilterActive) {
console.log("Activating tag filter menu in /likes page");
isFilterActive = true;
activeFilters = new Set();
tagToArticles = new Map();
articleToTags = new Map();
hidesCount = 1;
sorting = "unsorted";
}
} else {
if (isFilterActive) {
console.log("De-activating tag filter menu in /likes page");
isFilterActive = false;
cleanMenu();
}
}
if (isFilterActive) {
const newArticleToTags = getNewArticles();
if (Object.keys(newArticleToTags).length > 0) {
addDelta(newArticleToTags);
}
}
}, 500);
})();