Greasy Fork is available in English.
Blendet Themen und Beiträge von bestimmten Nutzern auf debianforum.de aus
// ==UserScript==
// @name dfde-user-filter
// @namespace http://tampermonkey.net/
// @version 1.17
// @description Blendet Themen und Beiträge von bestimmten Nutzern auf debianforum.de aus
// @author megabert
// @match https://debianforum.de/forum/*
// @license MIT
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// ==/UserScript==
const DEFAULTS = {
geblockte_nutzer: '',
filter_nach_ersteller: true,
filter_beitraege: true,
geblockte_titel: '',
filter_nach_titel: true,
geblockte_beitraege: '',
filter_nach_beitragsid: true,
};
let cfg = {
geblockte_nutzer: GM_getValue('geblockte_nutzer', DEFAULTS.geblockte_nutzer),
filter_nach_ersteller: GM_getValue('filter_nach_ersteller', DEFAULTS.filter_nach_ersteller),
filter_beitraege: GM_getValue('filter_beitraege', DEFAULTS.filter_beitraege),
geblockte_titel: GM_getValue('geblockte_titel', DEFAULTS.geblockte_titel),
filter_nach_titel: GM_getValue('filter_nach_titel', DEFAULTS.filter_nach_titel),
geblockte_beitraege: GM_getValue('geblockte_beitraege', DEFAULTS.geblockte_beitraege),
filter_nach_beitragsid: GM_getValue('filter_nach_beitragsid', DEFAULTS.filter_nach_beitragsid),
};
GM_registerMenuCommand('Einstellungen', zeigeEinstellungen);
einmal_filter();
setInterval(filtere_inhalt, 2000);
function getGeblockteNutzerListe() {
return cfg.geblockte_nutzer
.split('|')
.map(s => s.split('::')[0].trim().toLowerCase())
.filter(s => s.length > 0);
}
function filtere_inhalt() {
filtere_themen_nach_nutzer();
filtere_themen_nach_titel();
filtere_beitraege_nach_nutzer();
filtere_beitraege_nach_id();
aktualisiereZeilenfarben();
}
function aktualisiereZeilenfarben() {
let i = 0;
document.querySelectorAll('ul.topiclist.topics li.row').forEach(row => {
if (row.style.display === 'none') return;
row.classList.toggle('bg1', i % 2 === 0);
row.classList.toggle('bg2', i % 2 !== 0);
i++;
});
}
function einmal_filter() {
fuegeAusblendenButtonsHinzu();
fuegeAusblendenButtonsBeitraegeHinzu();
filtere_inhalt();
}
function mylog(message) { console.log('dfde-user-filter: ' + message); }
function verstecke(container, label) {
if (!container || container.style.display === 'none') return;
container.style.display = 'none';
mylog(label);
}
function filtere_themen_nach_nutzer() {
const nutzer = getGeblockteNutzerListe();
if (nutzer.length === 0 || !cfg.filter_nach_ersteller) return;
document.querySelectorAll('ul.topiclist.topics li.row').forEach(row => {
if (row.style.display === 'none') return;
const el = row.querySelector('div.responsive-hide .username');
if (el && nutzer.includes(el.textContent.trim().toLowerCase())) {
verstecke(row, 'Thema ausgeblendet (Ersteller: ' + el.textContent.trim() + ')');
}
});
}
function filtere_beitraege_nach_nutzer() {
const nutzer = getGeblockteNutzerListe();
if (nutzer.length === 0 || !cfg.filter_beitraege) return;
const startParam = parseInt(new URLSearchParams(window.location.search).get('start') || '0', 10);
const posts = document.querySelectorAll('div.post');
posts.forEach(post => {
if (startParam === 0 && post.querySelector('h3.first')) return;
if (post.style.display === 'none') return;
const el = post.querySelector('dl.postprofile dt .username, dl.postprofile dt .username-coloured');
mylog("beitrag gefunden von benutzer: " + (el && el.textContent.trim().toLowerCase()));
if (el && nutzer.includes(el.textContent.trim().toLowerCase())) {
verstecke(post, 'Beitrag ausgeblendet (Autor: ' + el.textContent.trim() + ')');
const next = post.nextElementSibling;
if (next && next.tagName === 'HR' && next.classList.contains('divider')) {
next.style.display = 'none';
}
}
});
}
function getTitelRegexListe() {
return cfg.geblockte_titel
.split('|')
.map(s => s.trim())
.filter(s => s.length > 0)
.map(s => { try { return new RegExp(s, 'i'); } catch (e) { mylog('Ungültiger Titel-Regex: ' + e.message); return null; } })
.filter(r => r !== null);
}
function filtere_themen_nach_titel() {
if (!cfg.filter_nach_titel) return;
const muster = getTitelRegexListe();
if (muster.length === 0) return;
document.querySelectorAll('ul.topiclist.topics li.row').forEach(row => {
if (row.style.display === 'none') return;
const titelEl = row.querySelector('a.topictitle');
if (!titelEl) return;
const titel = titelEl.textContent.trim();
if (muster.some(re => re.test(titel))) {
verstecke(row, 'Thema ausgeblendet (Titel: ' + titel + ')');
}
});
}
function fuegeAusblendenButtonsHinzu() {
if (!document.querySelector('ul.topiclist.topics')) return;
if (!document.getElementById('cf-hide-btn-style')) {
const style = document.createElement('style');
style.id = 'cf-hide-btn-style';
style.textContent = `
.cf-hide-btn {
background: none; border: none; cursor: pointer;
color: #aaa; padding: 0 0 0 7px; font-size: 11px;
vertical-align: middle; line-height: 1;
}
.cf-hide-btn:hover { color: #c00; }
`;
document.head.appendChild(style);
}
document.querySelectorAll('ul.topiclist.topics li.row').forEach(row => {
if (row.querySelector('.cf-hide-btn')) return;
const titelEl = row.querySelector('a.topictitle');
const userEl = row.querySelector('div.responsive-hide .username');
if (!titelEl || !userEl) return;
const btn = document.createElement('button');
btn.className = 'cf-hide-btn';
btn.title = 'Thread ausblenden';
btn.innerHTML = '<i class="icon fa-eye-slash fa-fw" aria-hidden="true"></i>';
btn.addEventListener('click', e => {
e.preventDefault();
e.stopPropagation();
const titel = titelEl.textContent.trim();
const escaped = titel.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const liste = nutzerZuListe(cfg.geblockte_titel);
if (!liste.includes(escaped)) {
liste.push(escaped);
cfg.geblockte_titel = listeZuNutzer(liste);
GM_setValue('geblockte_titel', cfg.geblockte_titel);
}
if (!cfg.filter_nach_titel) {
cfg.filter_nach_titel = true;
GM_setValue('filter_nach_titel', true);
}
verstecke(row, 'Thema ausgeblendet (Titel-Button: ' + titel + ')');
});
titelEl.after(btn);
});
}
function nutzerZuListe(nutzer) {
return nutzer.split('|').map(s => s.trim()).filter(s => s.length > 0);
}
function listeZuNutzer(liste) {
return liste.filter(s => s.trim().length > 0).join('|');
}
// ---- Beitrags-ID-Filter ----
function kuerzeZeitstempel(zeit) {
const m = zeit.match(/(\d{2})\.(\d{2})\.\d{4}\s+(\d{2}):(\d{2})/);
if (!m) return zeit;
return m[3] + ':' + m[4] + ' ' + m[1] + '.' + m[2];
}
function getGeblockteBeitraegeListe() {
return cfg.geblockte_beitraege
.split('|')
.map(s => s.trim())
.filter(s => s.length > 0)
.map(s => { const p = s.split('::'); return { id: p[0] || '', username: p[1] || '', zeit: p[2] || '', titel: p[3] || '' }; });
}
function filtere_beitraege_nach_id() {
if (!cfg.filter_nach_beitragsid) return;
const liste = getGeblockteBeitraegeListe();
if (liste.length === 0) return;
const ids = new Set(liste.map(e => e.id));
document.querySelectorAll('div.post').forEach(post => {
if (post.style.display === 'none') return;
const postId = post.id.replace(/^p/, '');
if (ids.has(postId)) {
verstecke(post, 'Beitrag ausgeblendet (ID: ' + postId + ')');
const next = post.nextElementSibling;
if (next && next.tagName === 'HR' && next.classList.contains('divider')) {
next.style.display = 'none';
}
}
});
}
function fuegeAusblendenButtonsBeitraegeHinzu() {
if (!document.querySelector('div.post')) return;
if (!document.getElementById('cf-hide-btn-style')) {
const style = document.createElement('style');
style.id = 'cf-hide-btn-style';
style.textContent = `
.cf-hide-btn {
background: none; border: none; cursor: pointer;
color: #aaa; padding: 0 0 0 7px; font-size: 11px;
vertical-align: middle; line-height: 1;
}
.cf-hide-btn:hover { color: #c00; }
`;
document.head.appendChild(style);
}
const startParam = parseInt(new URLSearchParams(window.location.search).get('start') || '0', 10);
document.querySelectorAll('div.post').forEach(post => {
if (post.querySelector('.cf-post-hide-btn')) return;
if (startParam === 0 && post.querySelector('h3.first')) return;
const h3 = post.querySelector('h3');
if (!h3) return;
const userEl = post.querySelector('dl.postprofile dt .username, dl.postprofile dt .username-coloured');
if (!userEl) return;
const authorEl = post.querySelector('p.author');
const zeitMatch = authorEl ? authorEl.textContent.match(/(\d{2}\.\d{2}\.\d{4}\s+\d{2}:\d{2}:\d{2})/) : null;
const zeitKurz = kuerzeZeitstempel(zeitMatch ? zeitMatch[1] : '');
const postId = post.id.replace(/^p/, '');
const username = userEl.textContent.trim();
const titelEl = h3.querySelector('a');
const titel = titelEl ? titelEl.textContent.trim() : '';
const btn = document.createElement('button');
btn.className = 'cf-hide-btn cf-post-hide-btn';
btn.title = 'Beitrag ausblenden';
btn.innerHTML = '<i class="icon fa-eye-slash fa-fw" aria-hidden="true"></i>';
btn.addEventListener('click', e => {
e.preventDefault();
e.stopPropagation();
const eintrag = postId + '::' + username + '::' + zeitKurz + '::' + titel;
const liste = nutzerZuListe(cfg.geblockte_beitraege);
if (!liste.some(s => s.split('::')[0] === postId)) {
liste.push(eintrag);
cfg.geblockte_beitraege = listeZuNutzer(liste);
GM_setValue('geblockte_beitraege', cfg.geblockte_beitraege);
}
if (!cfg.filter_nach_beitragsid) {
cfg.filter_nach_beitragsid = true;
GM_setValue('filter_nach_beitragsid', true);
}
verstecke(post, 'Beitrag ausgeblendet (ID-Button: ' + postId + ')');
const next = post.nextElementSibling;
if (next && next.tagName === 'HR' && next.classList.contains('divider')) {
next.style.display = 'none';
}
});
h3.appendChild(btn);
});
}
// ---- Import/Export ----
function djb2Hash(str) {
let hash = 5381;
for (let i = 0; i < str.length; i++) {
hash = ((hash << 5) + hash) + str.charCodeAt(i);
hash |= 0;
}
return (hash >>> 0).toString(16).padStart(8, '0');
}
function cfgExportieren() {
const json = JSON.stringify(cfg);
return btoa('v1:' + djb2Hash(json) + ':' + json);
}
function cfgImportieren(str) {
let decoded;
try { decoded = atob(str); } catch (e) { return { ok: false, fehler: 'Ungültiger Base64-String.' }; }
const sep1 = decoded.indexOf(':');
const sep2 = decoded.indexOf(':', sep1 + 1);
if (sep1 < 0 || sep2 < 0) return { ok: false, fehler: 'Ungültiges Format.' };
const version = decoded.slice(0, sep1);
const hash = decoded.slice(sep1 + 1, sep2);
const json = decoded.slice(sep2 + 1);
if (version !== 'v1') return { ok: false, fehler: 'Unbekannte Version: ' + version };
if (djb2Hash(json) !== hash) return { ok: false, fehler: 'Prüfziffer ungültig — String beschädigt?' };
let neu;
try { neu = JSON.parse(json); } catch (e) { return { ok: false, fehler: 'JSON-Fehler: ' + e.message }; }
for (const key of Object.keys(DEFAULTS)) {
if (!(key in neu)) neu[key] = DEFAULTS[key];
}
return { ok: true, cfg: neu };
}
// ---- Dialog ----
const DIALOG_CSS = `
* { box-sizing: border-box; font-family: system-ui, sans-serif; margin: 0; padding: 0; }
#cf-overlay {
position: absolute; inset: 0;
background: rgba(0,0,0,0.55);
display: flex; align-items: center; justify-content: center;
}
#cf-box {
background: #fff; border-radius: 12px; padding: 28px 32px;
max-width: 480px; width: 90%;
box-shadow: 0 8px 32px rgba(0,0,0,0.25);
max-height: 90vh; overflow-y: auto;
}
h2 { font-size: 18px; color: #222; font-weight: 700; margin-bottom: 20px; }
.cf-row { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; cursor: pointer; }
.cf-row input[type="checkbox"] {
width: 18px; height: 18px; flex-shrink: 0; cursor: pointer;
accent-color: #2563eb; margin: 0;
}
.cf-row span { font-size: 14px; color: #333; line-height: 1.4; }
hr { border: none; border-top: 1px solid #eee; margin: 16px 0; }
.cf-label { display: block; font-size: 13px; color: #444; margin-bottom: 8px; font-weight: 600; }
#cf-nutzer-liste { display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
.cf-nutzer-zeile { display: flex; align-items: center; gap: 6px; }
.cf-nutzer-zeile input[type="text"] {
flex: 1; padding: 7px 10px;
border: 1px solid #ccc; border-radius: 6px;
font-size: 13px; color: #222; background: #fff; min-width: 0;
}
.cf-nutzer-zeile input[type="text"]:focus { border-color: #2563eb; outline: none; }
.cf-nutzer-zeile input.cf-nutzer-kommentar { flex: 0.8; color: #888; font-style: italic; }
.cf-btn-remove {
width: 28px; height: 28px; border: 1px solid #ccc; border-radius: 50%;
background: #f5f5f5; color: #666; font-size: 16px; cursor: pointer;
display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.cf-btn-remove:hover { background: #fee2e2; border-color: #f87171; color: #c00; }
#cf-btn-add {
display: flex; align-items: center; gap: 6px; padding: 6px 12px;
border: 1px dashed #2563eb; border-radius: 6px;
background: #eff6ff; color: #2563eb; font-size: 13px; cursor: pointer;
width: 100%; justify-content: center; margin-bottom: 4px;
}
#cf-btn-add:hover { background: #dbeafe; }
#cf-hint { font-size: 12px; color: #888; margin-top: 4px; font-style: italic; }
#cf-buttons { display: flex; gap: 10px; margin-top: 24px; justify-content: flex-end; flex-wrap: wrap; }
#cf-buttons button {
padding: 8px 16px; border-radius: 6px; font-size: 14px; cursor: pointer;
border: 1px solid #ccc; background: #f5f5f5; color: #333; font-weight: 500;
}
#cf-save { background: #2563eb; color: #fff; border-color: #2563eb; font-weight: 700; padding: 8px 20px; }
#cf-titel-liste { display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
.cf-titel-zeile { display: flex; align-items: center; gap: 6px; }
.cf-titel-zeile input[type="text"] {
flex: 1; padding: 7px 10px;
border: 1px solid #ccc; border-radius: 6px;
font-size: 13px; font-family: monospace; color: #222; background: #fff; min-width: 0;
}
.cf-titel-zeile input[type="text"]:focus { border-color: #2563eb; outline: none; }
#cf-btn-titel-add {
display: flex; align-items: center; gap: 6px; padding: 6px 12px;
border: 1px dashed #2563eb; border-radius: 6px;
background: #eff6ff; color: #2563eb; font-size: 13px; cursor: pointer;
width: 100%; justify-content: center; margin-bottom: 4px;
}
#cf-btn-titel-add:hover { background: #dbeafe; }
#cf-beitrag-liste { display: flex; flex-direction: column; gap: 4px; margin-bottom: 8px; }
.cf-beitrag-zeile { display: flex; align-items: center; gap: 6px; padding: 4px 0; }
.cf-beitrag-info { flex: 1; font-size: 12px; color: #555; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cf-beitrag-info a { color: #2563eb; text-decoration: none; }
.cf-beitrag-info a:hover { text-decoration: underline; }
#cf-ie-box {
display: none;
background: #fff; border-radius: 12px; padding: 28px 32px;
max-width: 480px; width: 90%;
box-shadow: 0 8px 32px rgba(0,0,0,0.25);
max-height: 90vh; overflow-y: auto;
}
.cf-ie-textarea {
width: 100%; height: 80px;
border: 1px solid #ccc; border-radius: 6px;
padding: 7px 10px; font-size: 12px; font-family: monospace;
color: #444; background: #f9f9f9; resize: vertical;
margin-bottom: 16px; display: block;
}
.cf-ie-input {
width: 100%; height: 80px;
border: 1px solid #ccc; border-radius: 6px;
padding: 7px 10px; font-size: 12px; font-family: monospace;
color: #222; background: #fff; resize: vertical;
margin-bottom: 8px; display: block;
}
.cf-ie-input:focus { border-color: #2563eb; outline: none; }
#cf-ie-error { font-size: 12px; color: #c00; margin-bottom: 12px; min-height: 16px; }
#cf-ie-buttons { display: flex; gap: 10px; margin-top: 24px; justify-content: flex-end; flex-wrap: wrap; }
#cf-ie-buttons button {
padding: 8px 16px; border-radius: 6px; font-size: 14px; cursor: pointer;
border: 1px solid #ccc; background: #f5f5f5; color: #333; font-weight: 500;
}
#cf-ie-import-btn { background: #2563eb; color: #fff; border-color: #2563eb; font-weight: 700; padding: 8px 20px; }
`;
let _host = null;
let _shadow = null;
function vorbereiteDialog() {
_host = document.createElement('div');
_host.style.cssText = 'position:fixed;inset:0;z-index:999999;';
_shadow = _host.attachShadow({ mode: 'open' });
const styleEl = document.createElement('style');
styleEl.textContent = DIALOG_CSS;
_shadow.appendChild(styleEl);
const overlay = document.createElement('div');
overlay.id = 'cf-overlay';
const box = document.createElement('div');
box.id = 'cf-box';
box.innerHTML = `
<h2>⚙ Nutzer-Filter Einstellungen</h2>
<label class="cf-row">
<input type="checkbox" id="cf-filter-ersteller">
<span>Themen nach Ersteller filtern</span>
</label>
<label class="cf-row">
<input type="checkbox" id="cf-filter-beitraege">
<span>Beiträge in der Threadansicht ausblenden</span>
</label>
<hr>
<span class="cf-label">Geblockte Nutzernamen</span>
<div id="cf-nutzer-liste"></div>
<button id="cf-btn-add">+ Nutzer hinzufügen</button>
<div id="cf-hint">Groß-/Kleinschreibung wird ignoriert.</div>
<hr>
<label class="cf-row">
<input type="checkbox" id="cf-filter-titel">
<span>Threads nach Titel ausblenden (RegEx)</span>
</label>
<div id="cf-titel-liste"></div>
<button id="cf-btn-titel-add">+ Regex hinzufügen</button>
<div id="cf-hint">Reguläre Ausdrücke, Groß-/Kleinschreibung wird ignoriert.</div>
<hr>
<label class="cf-row">
<input type="checkbox" id="cf-filter-beitragsid">
<span>Einzelne Beiträge ausblenden (Nur per Ausblendsymbol)</span>
</label>
<span class="cf-label">Ausgeblendete Beiträge</span>
<div id="cf-beitrag-liste"></div>
<div id="cf-buttons">
<button id="cf-ie-btn">Import/Export</button>
<button id="cf-reset">Zurücksetzen</button>
<button id="cf-cancel">Abbrechen</button>
<button id="cf-save">Speichern</button>
</div>
`;
overlay.appendChild(box);
const ieBox = document.createElement('div');
ieBox.id = 'cf-ie-box';
ieBox.innerHTML = `
<h2>⇅ Import / Export</h2>
<span class="cf-label">Aktuelle Konfiguration (Export)</span>
<textarea class="cf-ie-textarea" id="cf-ie-export" readonly></textarea>
<span class="cf-label">Konfiguration importieren</span>
<textarea class="cf-ie-input" id="cf-ie-import" placeholder="Import-String hier einfügen …"></textarea>
<div id="cf-ie-error"></div>
<div id="cf-ie-buttons">
<button id="cf-ie-cancel">Abbrechen</button>
<button id="cf-ie-import-btn">Importieren</button>
</div>
`;
overlay.appendChild(ieBox);
_shadow.appendChild(overlay);
_shadow.querySelector('#cf-btn-add').addEventListener('click', () => addNutzerZeile(''));
_shadow.querySelector('#cf-btn-titel-add').addEventListener('click', () => addTitelZeile(''));
_shadow.querySelector('#cf-save').addEventListener('click', () => {
cfg.filter_nach_ersteller = _shadow.querySelector('#cf-filter-ersteller').checked;
cfg.filter_beitraege = _shadow.querySelector('#cf-filter-beitraege').checked;
cfg.geblockte_nutzer = listeZuNutzer(getNutzerWerte());
cfg.filter_nach_titel = _shadow.querySelector('#cf-filter-titel').checked;
cfg.geblockte_titel = listeZuNutzer(getTitelWerte());
cfg.filter_nach_beitragsid = _shadow.querySelector('#cf-filter-beitragsid').checked;
cfg.geblockte_beitraege = listeZuNutzer(
Array.from(_shadow.querySelectorAll('.cf-beitrag-zeile')).map(z => z.dataset.eintrag)
);
GM_setValue('filter_nach_ersteller', cfg.filter_nach_ersteller);
GM_setValue('filter_beitraege', cfg.filter_beitraege);
GM_setValue('geblockte_nutzer', cfg.geblockte_nutzer);
GM_setValue('filter_nach_titel', cfg.filter_nach_titel);
GM_setValue('geblockte_titel', cfg.geblockte_titel);
GM_setValue('filter_nach_beitragsid', cfg.filter_nach_beitragsid);
GM_setValue('geblockte_beitraege', cfg.geblockte_beitraege);
schliessen();
filtere_inhalt();
mylog('Einstellungen gespeichert');
});
_shadow.querySelector('#cf-reset').addEventListener('click', () => {
_shadow.querySelector('#cf-filter-ersteller').checked = DEFAULTS.filter_nach_ersteller;
_shadow.querySelector('#cf-filter-beitraege').checked = DEFAULTS.filter_beitraege;
_shadow.querySelector('#cf-nutzer-liste').innerHTML = '';
addNutzerZeile('');
_shadow.querySelector('#cf-filter-titel').checked = DEFAULTS.filter_nach_titel;
_shadow.querySelector('#cf-titel-liste').innerHTML = '';
addTitelZeile('');
_shadow.querySelector('#cf-filter-beitragsid').checked = DEFAULTS.filter_nach_beitragsid;
_shadow.querySelector('#cf-beitrag-liste').innerHTML = '';
});
_shadow.querySelector('#cf-cancel').addEventListener('click', schliessen);
overlay.addEventListener('click', e => { if (e.target === overlay) schliessen(); });
_shadow.querySelector('#cf-ie-btn').addEventListener('click', () => {
_shadow.querySelector('#cf-ie-export').value = cfgExportieren();
_shadow.querySelector('#cf-ie-import').value = '';
_shadow.querySelector('#cf-ie-error').textContent = '';
_shadow.querySelector('#cf-ie-error').style.color = '';
_shadow.querySelector('#cf-box').style.display = 'none';
_shadow.querySelector('#cf-ie-box').style.display = 'block';
});
_shadow.querySelector('#cf-ie-cancel').addEventListener('click', () => {
_shadow.querySelector('#cf-ie-box').style.display = 'none';
befuelleHauptDialog();
_shadow.querySelector('#cf-box').style.display = '';
});
_shadow.querySelector('#cf-ie-import-btn').addEventListener('click', () => {
const errEl = _shadow.querySelector('#cf-ie-error');
const str = _shadow.querySelector('#cf-ie-import').value.trim();
if (!str) {
errEl.style.color = '';
errEl.textContent = 'Bitte einen Import-String eingeben.';
return;
}
const result = cfgImportieren(str);
if (!result.ok) {
errEl.style.color = '';
errEl.textContent = result.fehler;
return;
}
const neu = result.cfg;
cfg.geblockte_nutzer = neu.geblockte_nutzer;
cfg.filter_nach_ersteller = neu.filter_nach_ersteller;
cfg.filter_beitraege = neu.filter_beitraege;
cfg.geblockte_titel = neu.geblockte_titel;
cfg.filter_nach_titel = neu.filter_nach_titel;
cfg.geblockte_beitraege = neu.geblockte_beitraege;
cfg.filter_nach_beitragsid = neu.filter_nach_beitragsid;
GM_setValue('geblockte_nutzer', cfg.geblockte_nutzer);
GM_setValue('filter_nach_ersteller', cfg.filter_nach_ersteller);
GM_setValue('filter_beitraege', cfg.filter_beitraege);
GM_setValue('geblockte_titel', cfg.geblockte_titel);
GM_setValue('filter_nach_titel', cfg.filter_nach_titel);
GM_setValue('geblockte_beitraege', cfg.geblockte_beitraege);
GM_setValue('filter_nach_beitragsid', cfg.filter_nach_beitragsid);
errEl.style.color = '#16a34a';
errEl.textContent = 'Konfiguration erfolgreich importiert.';
filtere_inhalt();
mylog('Konfiguration importiert');
});
mylog('Dialog vorbereitet');
}
function befuelleHauptDialog() {
_shadow.querySelector('#cf-filter-ersteller').checked = cfg.filter_nach_ersteller;
_shadow.querySelector('#cf-filter-beitraege').checked = cfg.filter_beitraege;
_shadow.querySelector('#cf-nutzer-liste').innerHTML = '';
const liste = nutzerZuListe(cfg.geblockte_nutzer);
(liste.length > 0 ? liste : ['']).forEach(n => addNutzerZeile(n));
_shadow.querySelector('#cf-filter-titel').checked = cfg.filter_nach_titel;
_shadow.querySelector('#cf-titel-liste').innerHTML = '';
const titelListe = nutzerZuListe(cfg.geblockte_titel);
(titelListe.length > 0 ? titelListe : ['']).forEach(t => addTitelZeile(t));
_shadow.querySelector('#cf-filter-beitragsid').checked = cfg.filter_nach_beitragsid;
_shadow.querySelector('#cf-beitrag-liste').innerHTML = '';
getGeblockteBeitraegeListe().forEach(e => addBeitragZeile(e.id + '::' + e.username + '::' + e.zeit + '::' + e.titel));
}
function zeigeEinstellungen() {
if (!_host) vorbereiteDialog();
befuelleHauptDialog();
document.body.appendChild(_host);
}
function schliessen() {
_host?.remove();
}
function addNutzerZeile(eintrag) {
const liste = _shadow.querySelector('#cf-nutzer-liste');
const zeile = document.createElement('div');
zeile.className = 'cf-nutzer-zeile';
const parts = eintrag.split('::');
const inputName = document.createElement('input');
inputName.type = 'text';
inputName.value = parts[0] || '';
inputName.placeholder = 'z.B. DEBIANUNDANDREAS';
const inputKommentar = document.createElement('input');
inputKommentar.type = 'text';
inputKommentar.className = 'cf-nutzer-kommentar';
inputKommentar.value = parts[1] || '';
inputKommentar.placeholder = 'Kommentar (optional)';
const btnRemove = document.createElement('button');
btnRemove.className = 'cf-btn-remove';
btnRemove.title = 'Entfernen';
btnRemove.textContent = '×';
btnRemove.addEventListener('click', () => {
if (_shadow.querySelectorAll('.cf-nutzer-zeile').length > 1) {
zeile.remove();
} else {
inputName.value = '';
inputKommentar.value = '';
}
});
zeile.appendChild(inputName);
zeile.appendChild(inputKommentar);
zeile.appendChild(btnRemove);
liste.appendChild(zeile);
inputName.focus();
}
function getNutzerWerte() {
return Array.from(_shadow.querySelectorAll('.cf-nutzer-zeile')).map(zeile => {
const inputs = zeile.querySelectorAll('input[type="text"]');
const name = inputs[0].value.trim();
const kommentar = inputs[1].value.trim();
return kommentar ? name + '::' + kommentar : name;
});
}
function addTitelZeile(wert) {
const liste = _shadow.querySelector('#cf-titel-liste');
const zeile = document.createElement('div');
zeile.className = 'cf-titel-zeile';
const input = document.createElement('input');
input.type = 'text';
input.value = wert;
input.placeholder = 'z.B. Debian Quatscher';
const btnRemove = document.createElement('button');
btnRemove.className = 'cf-btn-remove';
btnRemove.title = 'Entfernen';
btnRemove.textContent = '×';
btnRemove.addEventListener('click', () => {
if (_shadow.querySelectorAll('.cf-titel-zeile').length > 1) {
zeile.remove();
} else {
input.value = '';
}
});
zeile.appendChild(input);
zeile.appendChild(btnRemove);
liste.appendChild(zeile);
}
function getTitelWerte() {
return Array.from(_shadow.querySelectorAll('.cf-titel-zeile input[type="text"]'))
.map(el => el.value.trim());
}
function addBeitragZeile(eintrag) {
const liste = _shadow.querySelector('#cf-beitrag-liste');
const zeile = document.createElement('div');
zeile.className = 'cf-beitrag-zeile';
zeile.dataset.eintrag = eintrag;
const parts = eintrag.split('::');
const postId = parts[0] || '';
const username = parts[1] || '';
const zeit = parts[2] || '';
const titel = parts[3] || '';
const titelKurz = titel.length > 20 ? titel.slice(0, 20) + '…' : (titel || ('#' + postId));
const info = document.createElement('span');
info.className = 'cf-beitrag-info';
const link = document.createElement('a');
link.href = 'https://debianforum.de/forum/viewtopic.php?p=' + postId + '#p' + postId;
link.target = '_blank';
link.textContent = titelKurz;
info.appendChild(link);
info.appendChild(document.createTextNode(' · ' + username + ' · ' + zeit));
const btnRemove = document.createElement('button');
btnRemove.className = 'cf-btn-remove';
btnRemove.title = 'Entfernen';
btnRemove.textContent = '×';
btnRemove.addEventListener('click', () => zeile.remove());
zeile.appendChild(info);
zeile.appendChild(btnRemove);
liste.appendChild(zeile);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', vorbereiteDialog);
} else {
vorbereiteDialog();
}