Compare commits

...

7 Commits

Author SHA1 Message Date
9136ab2565 small style tweak 2024-10-15 11:21:35 +02:00
1438d3037a fix CTRL | SHIFT to just CTRL 2024-09-19 22:56:15 +02:00
fdf688cba2 generalize filterByKeyword function 2024-09-19 16:45:54 +02:00
82584d6a59 don't show brave download button 2024-09-19 15:40:27 +02:00
5e3cab2a63 add custom filter command (Ctrl+F) 2024-09-19 15:16:15 +02:00
2a5f09ce7c tweak style
I thought I wanted to add something for the no domain case
(e.g., a document with file://) but I don't
2024-09-19 14:28:04 +02:00
7a54b7bd99 restore bloomberg -> archive.is redirection 2024-09-13 09:31:53 -04:00
7 changed files with 182 additions and 103 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
rosenrot rosenrot
# don't save the binary file, as it doesn't play nicely with https://difftastic.wilfred.me.uk # don't save the binary file, as it doesn't play nicely with https://difftastic.wilfred.me.uk
webkit/

View File

@ -92,6 +92,7 @@ typedef enum {
show_finder, show_finder,
finder_next, finder_next,
finder_prev, finder_prev,
filter,
halve_window, halve_window,
rebig_window, rebig_window,
@ -134,6 +135,7 @@ static struct {
{ CTRL, KEY(f), show_finder }, { CTRL, KEY(f), show_finder },
{ CTRL, KEY(n), finder_next }, { CTRL, KEY(n), finder_next },
{ CTRL, KEY(N), finder_prev }, { CTRL, KEY(N), finder_prev },
{ CTRL, KEY(F), filter },
{ CTRL, KEY(Up), halve_window }, { CTRL, KEY(Up), halve_window },
{ CTRL, KEY(Down), rebig_window }, { CTRL, KEY(Down), rebig_window },
{ CTRL, KEY(p), prettify }, { CTRL, KEY(p), prettify },

View File

@ -22,7 +22,7 @@ int libre_redirect(const char* uri, char* output)
// "https://google.com", // "https://google.com",
"https://medium.com", "https://medium.com",
"https://translate.google.com", "https://translate.google.com",
// "https://www.bloomberg.com", "https://www.bloomberg.com",
"https://www.royalroad.com", "https://www.royalroad.com",
"https://genius.com", "https://genius.com",
// "https://twitter.com" // "https://twitter.com"
@ -39,7 +39,7 @@ int libre_redirect(const char* uri, char* output)
// "https://search.nunosempere.com", // "https://search.nunosempere.com",
"https://scribe.rip", "https://scribe.rip",
"https://translate.riverside.rocks", "https://translate.riverside.rocks",
// "https://archive.ph/https://www.bloomberg.com", "https://archive.ph/https://www.bloomberg.com",
"https://royalread.nunosempere.com", "https://royalread.nunosempere.com",
"https://dumb.vern.cc", "https://dumb.vern.cc",
"https://example.com" "https://example.com"

View File

@ -1,7 +1,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define STYLE_N 8049 + 1000 #define STYLE_N 9278 + 1000
void read_style_js(char* string) void read_style_js(char* string)
{ {

View File

@ -1,5 +1,5 @@
#pragma once #pragma once
#define STYLE_N 8049 + 1000 #define STYLE_N 9278 + 1000
void read_style_js(char* string); void read_style_js(char* string);

View File

@ -6,8 +6,8 @@
var styles = null; var styles = null;
// console.log(document.domain); // console.log(document.domain);
switch (document.domain) { switch (document.domain) {
case "forum.effectivealtruism.org": case "forum.effectivealtruism.org":
styles = ` styles = `
/* /*
.Layout-main { .Layout-main {
margin-left: 100px; margin-left: 100px;
@ -25,16 +25,16 @@ switch (document.domain) {
} }
*/ */
`; `;
break; break;
case "nationstates.net": case "nationstates.net":
styles = ` styles = `
.adidentifier { .adidentifier {
display: none; display: none;
} }
`; `;
break; break;
case "mail.proton.me": case "mail.proton.me":
styles = ` styles = `
/* /*
.item-container-row.read, .item-container.read { .item-container-row.read, .item-container.read {
background-color: white; background-color: white;
@ -48,24 +48,25 @@ switch (document.domain) {
zoom: 0.625 !important; zoom: 0.625 !important;
*/ */
`; `;
break; break;
case "forum.nunosempere.com": case "forum.nunosempere.com":
styles = ` styles = `
body { body {
zoom: 0.625 !important; zoom: 0.625 !important;
} }
`; `;
break; break;
case "search.brave.com": case "search.brave.com":
styles = ` styles = `
.download-button, .download-button,
a[href^="https://brave.com/download/"] { a[href^="https://brave.com/download/"], .download-cta
{
display: none !important; display: none !important;
} }
`; `;
break; break;
case "search.nunosempere.com": case "search.nunosempere.com":
styles = ` styles = `
/* /*
body { body {
zoom: 1.8; zoom: 1.8;
@ -76,11 +77,11 @@ switch (document.domain) {
display: none; display: none;
} }
`; `;
break; break;
case "reddit.com": case "reddit.com":
// fallthrough // fallthrough
case "old.reddit.com": case "old.reddit.com":
styles = ` styles = `
/* kill sidebar ads */ /* kill sidebar ads */
.ad-container, .ad-container,
a[href^="https://alb.reddit.com"] a[href^="https://alb.reddit.com"]
@ -98,10 +99,10 @@ switch (document.domain) {
display: none !important; display: none !important;
} }
`; `;
break; break;
case "twitter.com": case "twitter.com":
case "x.com": case "x.com":
styles = ` styles = `
/* hide promoted tweets */ /* hide promoted tweets */
:has(meta[property="og:site_name"][content="Twitter"]) :has(meta[property="og:site_name"][content="Twitter"])
[data-testid="cellInnerDiv"]:has(svg + [dir="auto"]) { [data-testid="cellInnerDiv"]:has(svg + [dir="auto"]) {
@ -182,25 +183,27 @@ switch (document.domain) {
background: white !important; background: white !important;
} }
`; `;
break; break;
default: case "":
console.log(`Domain: ${document.domain}`); break;
console.log("No custom style"); default:
console.log(`Domain: ${document.domain}`);
console.log("No custom style");
} }
if (styles != null) { if (styles != null) {
var styleSheet = document.createElement("style"); var styleSheet = document.createElement("style");
styleSheet.innerText = styles; styleSheet.innerText = styles;
document.head.appendChild(styleSheet); document.head.appendChild(styleSheet);
console.log("Style changed"); console.log("Style changed");
} }
// Extra: Replace default alert with new function // Extra: Replace default alert with new function
// whose style can be changed! // whose style can be changed!
window.alert = (message) => { window.alert = (message) => {
let alertDiv = document.getElementById("customAlert"); let alertDiv = document.getElementById("customAlert");
if (!alertDiv) { if (!alertDiv) {
const html = ` const html = `
<div id="customAlert" class="custom-alert"> <div id="customAlert" class="custom-alert">
<div class="custom-alert-content"> <div class="custom-alert-content">
<p id="alertMessage"></p> <p id="alertMessage"></p>
@ -232,68 +235,112 @@ window.alert = (message) => {
} }
</style> </style>
`; `;
document.body.insertAdjacentHTML("beforeend", html); document.body.insertAdjacentHTML("beforeend", html);
alertDiv = document.getElementById("customAlert"); alertDiv = document.getElementById("customAlert");
document.getElementById("alertOkButton").onclick = () => { document.getElementById("alertOkButton").onclick = () => {
alertDiv.classList.remove("visible"); alertDiv.classList.remove("visible");
document.removeEventListener("keydown", dismissAlert); document.removeEventListener("keydown", dismissAlert);
}; };
} }
const dismissAlert = (event) => { const dismissAlert = (event) => {
if ( if (
event.key === "Enter" /*&& event.ctrlKey*/ && event.key === "Enter" /*&& event.ctrlKey*/ &&
alertDiv.classList.contains("visible") alertDiv.classList.contains("visible")
) { ) {
alertDiv.classList.remove("visible"); alertDiv.classList.remove("visible");
document.removeEventListener("keydown", dismissAlert); document.removeEventListener("keydown", dismissAlert);
} }
}; };
document.addEventListener("keydown", dismissAlert); document.addEventListener("keydown", dismissAlert);
document.getElementById("alertMessage").textContent = message; document.getElementById("alertMessage").textContent = message;
alertDiv.classList.add("visible"); alertDiv.classList.add("visible");
}; };
// Extra: hide video players on twitter // Extra: hide video players on twitter
if (document.domain == "twitter.com" || document.domain == "x.com") { if (document.domain == "twitter.com" || document.domain == "x.com") {
// Function to hide the grandparent of video players // Function to hide the grandparent of video players
// takes 0.014ms to run, so performance is not the concern here. // takes 0.014ms to run, so performance is not the concern here.
// timed with console.time, console.timeEnd // timed with console.time, console.timeEnd
function hideVideoPlayerGrandparent() { function hideVideoPlayerGrandparent() {
document document
.querySelectorAll('[data-testid="videoPlayer"]') .querySelectorAll('[data-testid="videoPlayer"]')
.forEach(function (videoPlayer) { .forEach(function (videoPlayer) {
var grandparentElement = var grandparentElement =
videoPlayer.parentElement.parentElement.parentElement.parentElement videoPlayer.parentElement.parentElement.parentElement.parentElement
.parentElement.parentElement; .parentElement.parentElement;
var newTextElement = document.createElement("div"); var newTextElement = document.createElement("div");
newTextElement.textContent = " [ twitter video ] "; newTextElement.textContent = " [ twitter video ] ";
newTextElement.style["margin-top"] = "10px"; newTextElement.style["margin-top"] = "10px";
newTextElement.style["margin-left"] = "10px"; newTextElement.style["margin-left"] = "10px";
newTextElement.style["margin-bottom"] = "10px"; newTextElement.style["margin-bottom"] = "10px";
grandparentElement.replaceWith(newTextElement); grandparentElement.replaceWith(newTextElement);
}); });
} }
// Create a new MutationObserver instance // Create a new MutationObserver instance
var observer = new MutationObserver(function (mutations) { var observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) { mutations.forEach(function (mutation) {
if (mutation.addedNodes.length) { if (mutation.addedNodes.length) {
hideVideoPlayerGrandparent(); // Call the function to hide video players hideVideoPlayerGrandparent(); // Call the function to hide video players
} }
}); });
}); });
// Options for the observer (which mutations to observe) // Options for the observer (which mutations to observe)
var config = { childList: true, subtree: true }; var config = { childList: true, subtree: true };
// Start observing the target node for configured mutations // Start observing the target node for configured mutations
observer.observe(document.body, config); observer.observe(document.body, config);
// Call the function initially to hide any video players on initial load // Call the function initially to hide any video players on initial load
hideVideoPlayerGrandparent(); hideVideoPlayerGrandparent();
} }
// document.body.style.visibility = "visible"; // document.body.style.visibility = "visible";
// Add some code to filter out articles for Sentinel
function filterByKeyword(str) {
// e.g., "keyword" (equivalent to "keyword, p, 1")
// e.g., "keyword, div, 3"
// might not work with level=0, but not sure why
const args = str.split(", ");
let keword = null;
let selector = "p"; /* or "*" for all */
let level = 1;
if (args.length > 0) {
keyword = args[0].trim();
}
if (args.length > 1) {
selector = args[1].trim();
}
if (args.length > 2) {
level = Number(args[2].trim());
}
console.log(keyword, selector, level);
// Get all elements matching the selector
const elements = document.querySelectorAll(selector);
// Convert NodeList to Array to use array methods
const elementsArray = Array.from(elements);
// Filter elements containing the keyword
const matchingElements = elementsArray.filter((element) =>
element.textContent.toLowerCase().includes(keyword.toLowerCase()),
);
// Remove parent of each matching element
matchingElements.forEach((element) => {
let ancestor = element; // Start with the current element
// Loop to climb up the DOM tree according to the level required
for (let i = 0; i < level && ancestor !== null; i++) {
ancestor = ancestor.parentNode; // Move up in the DOM tree
}
if (ancestor) {
ancestor.style.display = "none";
}
});
}

View File

@ -9,7 +9,7 @@
/* Global variables */ /* Global variables */
static GtkNotebook* notebook; static GtkNotebook* notebook;
static GtkWindow* window; static GtkWindow* window;
typedef enum { _SEARCH, _FIND, _HIDDEN } Bar_entry_mode; typedef enum { _SEARCH, _FIND, _FILTER, _HIDDEN } Bar_entry_mode;
static struct { static struct {
GtkHeaderBar* widget; GtkHeaderBar* widget;
GtkEntry* line; GtkEntry* line;
@ -227,6 +227,13 @@ void toggle_bar(GtkNotebook* notebook, Bar_entry_mode mode)
gtk_window_set_focus(window, GTK_WIDGET(bar.line)); gtk_window_set_focus(window, GTK_WIDGET(bar.line));
break; break;
} }
case _FILTER: {
gtk_entry_set_placeholder_text(bar.line, "Filter");
gtk_entry_buffer_set_text(bar.line_text, "", strlen(""));
gtk_widget_set_visible(GTK_WIDGET(bar.widget), 1);
gtk_window_set_focus(window, GTK_WIDGET(bar.line));
break;
}
case _HIDDEN: case _HIDDEN:
gtk_widget_set_visible(GTK_WIDGET(bar.widget), 0); gtk_widget_set_visible(GTK_WIDGET(bar.widget), 0);
} }
@ -236,16 +243,35 @@ void toggle_bar(GtkNotebook* notebook, Bar_entry_mode mode)
void handle_signal_bar_press_enter(GtkEntry* self, GtkNotebook* notebook) /* consider passing notebook as the data here? */ void handle_signal_bar_press_enter(GtkEntry* self, GtkNotebook* notebook) /* consider passing notebook as the data here? */
{ {
WebKitWebView* view = notebook_get_webview(notebook); WebKitWebView* view = notebook_get_webview(notebook);
if (bar.entry_mode == _SEARCH) const char* bar_line_text = gtk_entry_buffer_get_text(bar.line_text);
load_uri(view, gtk_entry_buffer_get_text(bar.line_text)); switch (bar.entry_mode) {
else if (bar.entry_mode == _FIND) case _SEARCH: {
webkit_find_controller_search( load_uri(view, bar_line_text);
webkit_web_view_get_find_controller(view), gtk_widget_set_visible(GTK_WIDGET(bar.widget), 0);
gtk_entry_buffer_get_text(bar.line_text), break;
WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE | WEBKIT_FIND_OPTIONS_WRAP_AROUND, }
G_MAXUINT); case _FIND: {
webkit_find_controller_search(
webkit_web_view_get_find_controller(view),
bar_line_text,
WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE | WEBKIT_FIND_OPTIONS_WRAP_AROUND,
G_MAXUINT);
gtk_widget_set_visible(GTK_WIDGET(bar.widget), 0);
break;
}
case _FILTER: {
const char* js_template = "filterByKeyword(\"%s\")";
char js_command[strlen(js_template) + strlen(bar_line_text) + 2];
snprintf(js_command, sizeof(js_command) + 1, js_template, bar_line_text);
webkit_web_view_evaluate_javascript(view, js_command, -1, NULL, "rosenrot-filter-plugin", NULL, NULL, NULL);
gtk_widget_set_visible(GTK_WIDGET(bar.widget), 0);
break;
}
case _HIDDEN:
// no op
}
gtk_widget_set_visible(GTK_WIDGET(bar.widget), 0);
} }
/* Shortcuts */ /* Shortcuts */
@ -332,6 +358,9 @@ int handle_shortcut(func id)
case show_finder: case show_finder:
toggle_bar(notebook, _FIND); toggle_bar(notebook, _FIND);
break; break;
case filter:
toggle_bar(notebook, _FILTER);
break;
case finder_next: case finder_next:
webkit_find_controller_search_next(webkit_web_view_get_find_controller(view)); webkit_find_controller_search_next(webkit_web_view_get_find_controller(view));