Skip to content

Instantly share code, notes, and snippets.

@jmpinit
Last active May 20, 2023 16:01
Show Gist options
  • Save jmpinit/f3b819ecfc73e0aa65dec4f2ef5b35c3 to your computer and use it in GitHub Desktop.
Save jmpinit/f3b819ecfc73e0aa65dec4f2ef5b35c3 to your computer and use it in GitHub Desktop.
A Greasemonkey/Tampermonkey/Violentmonkey user script to automatically remove articles of specific types from the GitHub feed. Also registers disinterest for each of them so they may show up less often.
// ==UserScript==
// @name Remove published releases from GitHub feed
// @namespace Violentmonkey Scripts
// @match https://github.com/
// @grant none
// @version 1.0
// @author Owen Trueblood
// @description Remove published releases from GitHub feed
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// @require https://gist.github.com/raw/2625891/waitForKeyElements.js
// ==/UserScript==
const blockedArticleTypes = [
'NEW_DISCUSSION',
'RELEASE',
];
function submitDisinterestForm(formElement) {
// Find the input associated with the desired text
const labelElements = formElement.querySelectorAll('label');
let targetInputElement = null;
for (const labelElement of labelElements) {
const spanElement = labelElement.querySelector('span');
if (spanElement && spanElement.textContent.trim().startsWith('I want to see fewer')) {
targetInputElement = labelElement.querySelector('input[type="checkbox"]');
break;
}
}
if (!targetInputElement) {
console.error('Could not find the checkbox for the disinterest form', formElement);
throw new Error('Could not find the checkbox for the disinterest form');
}
targetInputElement.checked = true;
// Submit the form
const formData = new FormData(formElement);
const url = formElement.getAttribute('action');
const options = {
method: 'POST',
body: formData,
headers: {
'accept': 'application/json',
'x-requested-with': 'XMLHttpRequest',
},
};
return fetch(url, options)
.then(response => {
if (response.ok) {
console.log('Registered disinterest');
} else {
console.error('Form submission failed.');
}
});
}
function findRootArticles() {
const allArticles = document.getElementsByTagName('article');
const rootArticles = [];
for (let i = 0; i < allArticles.length; i++) {
const article = allArticles[i];
let isDescendant = false;
// Check if the current article is a descendant of any other article
let parentElement = article.parentElement;
while (parentElement !== null) {
if (parentElement.tagName === 'ARTICLE') {
isDescendant = true;
break;
}
parentElement = parentElement.parentElement;
}
// If the article is not a descendant of any other article, add it to the rootArticles array
if (!isDescendant) {
rootArticles.push(article);
}
}
return rootArticles;
}
function getDisinterestForm(article) {
const forms = Array.from(article.getElementsByTagName('form')).filter((form) => form.getAttribute('action') === '/conduit/register_disinterest');
if (forms.length > 0) {
return forms[0];
} else {
console.error('Could not find the disinterest form for the article', article);
throw new Error('Could not find the disinterest form for the article');
}
}
function findRootArticles() {
const allArticles = document.getElementsByTagName('article');
const rootArticles = [];
for (let i = 0; i < allArticles.length; i++) {
const article = allArticles[i];
let isDescendant = false;
// Check if the current article is a descendant of any other article
let parentElement = article.parentElement;
while (parentElement !== null) {
if (parentElement.tagName === 'ARTICLE') {
isDescendant = true;
break;
}
parentElement = parentElement.parentElement;
}
// If the article is not a descendant of any other article, add it to the rootArticles array
if (!isDescendant) {
rootArticles.push(article);
}
}
return rootArticles;
}
function getArticleType(article) {
const data = JSON.parse(article.getAttribute('data-hydro-view'));
return data?.payload?.feed_card?.card_type;
}
function getBlockedArticles() {
return findRootArticles().filter((article) => {
const articleType = getArticleType(article);
return blockedArticleTypes.indexOf(articleType) !== -1;
});
}
waitForKeyElements('#conduit-feed-frame', () => getBlockedArticles().forEach(async (article) => {
const articleType = getArticleType(article);
const form = getDisinterestForm(article);
await submitDisinterestForm(form);
article.remove();
console.log(`Deleted an article of type ${articleType}`);
}));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment