Highlight Posts with external Links or hide Posts without Links
当前为
// ==UserScript==
// @name Bluesky Link-Highlighter & Filter
// @version 1.2
// @description Highlight Posts with external Links or hide Posts without Links
// @license MIT
// @author Schubsi
// @match https://bsky.app/*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// @namespace https://greasyfork.org/users/1493523
// ==/UserScript==
(function () {
"use strict";
// Default-Werte
let highlightEnabled = GM_getValue("highlightEnabled", true);
let hideWithoutLinks = GM_getValue("hideWithoutLinks", false);
const toggleHighlight = () => {
highlightEnabled = !highlightEnabled;
GM_setValue("highlightEnabled", highlightEnabled);
processPosts();
};
const toggleHide = () => {
hideWithoutLinks = !hideWithoutLinks;
GM_setValue("hideWithoutLinks", hideWithoutLinks);
processPosts();
};
// Menüeinträge in Tampermonkey
GM_registerMenuCommand(
`Highlighting: ${highlightEnabled ? "On" : "Off"}`,
toggleHighlight
);
GM_registerMenuCommand(
`Hide Posts without Links: ${hideWithoutLinks ? "On" : "Off"}`,
toggleHide
);
const styleLinkPost = (post) => {
if (highlightEnabled) {
post.style.outline = "5px solid #4ca2fe";
} else {
post.style.outline = "";
}
};
const styleNonLinkPost = (post) => {
// Statt display:none verwenden wir "visibility: hidden; height: 0" trick,
// um die Post-Elemente weiterhin im Layout zu behalten (für Scroll-Trigger)
if (hideWithoutLinks) {
post.style.visibility = "hidden";
post.style.height = "0px";
post.style.margin = "0";
post.style.padding = "0";
post.style.overflow = "hidden";
} else {
post.style.visibility = "";
post.style.height = "";
post.style.margin = "";
post.style.padding = "";
post.style.overflow = "";
}
};
const autoCheckLink = (post) => {
const linkEl = post.querySelector("a[target='_blank']");
if (linkEl) {
styleLinkPost(post);
return;
}
const content = post.querySelector("div[data-testid='postText']");
if (!content) {
styleNonLinkPost(post);
return;
}
if (
/(?:^|\s)(?!bsky\.app)(?:https?:\/\/)?[a-zA-Z0-9][a-zA-Z0-9\-_.]*[a-zA-Z0-9]*\.[a-zA-Z]{2,}(?:[/?#][^\s]*)*/.test(
content.textContent
)
) {
styleLinkPost(post);
return;
}
// Links als Text in Embeded Posts
const embedPost = post.querySelector("div[aria-label^='Post by ']");
if (!embedPost || !embedPost.children || embedPost.children.length < 2) {
styleNonLinkPost(post);
return;
}
if (
/(?:^|\s)(?!bsky\.app)(?:https?:\/\/)?[a-zA-Z0-9][a-zA-Z0-9\-_.]*[a-zA-Z0-9]*\.[a-zA-Z]{2,}(?:[/?#][^\s]*)*/.test(
embedPost.children[1].textContent
)
) {
styleLinkPost(post);
return;
}
styleNonLinkPost(post);
};
const processPosts = () => {
// Seiten-Filter
const url = window.location.href;
const isHome = url === "https://bsky.app/";
const isSearch = url.startsWith("https://bsky.app/search?q="); // hier kann ich die Posts nicht wie unten selecten
const isProfile = url.match(/https:\/\/bsky.app\/profile\/[^\/]+$/);
if (!(isHome || isSearch || isProfile)) {
return;
}
document
.querySelectorAll("div[data-testid^='feedItem-by-']")
.forEach((post) => {
autoCheckLink(post);
});
};
const observer = new MutationObserver(() => {
processPosts();
});
window.addEventListener("load", () => {
processPosts();
observer.observe(document.body, { childList: true, subtree: true });
});
})();