From bbfa93a586716fb89cf5ee69a6fec8964198ce96 Mon Sep 17 00:00:00 2001 From: Meik Date: Thu, 12 Feb 2026 17:40:52 +0100 Subject: [PATCH] chore: checkpoint current working state --- backend/server.js | 101 +++++++++++++++++++++++++++++++++++------ extension/content.js | 18 ++++++++ extension/popup.html | 1 + extension/popup.js | 21 +++++++-- web/app.js | 106 +++++++++++++++++++++++++++++++++---------- web/index.html | 3 +- 6 files changed, 206 insertions(+), 44 deletions(-) diff --git a/backend/server.js b/backend/server.js index 3d3edb8..c63b5fb 100644 --- a/backend/server.js +++ b/backend/server.js @@ -687,6 +687,77 @@ function sanitizeProfileNumber(value) { return parsed; } +function applyProfileVariantTemplates(text, profileNumber) { + if (typeof text !== 'string' || !text) { + return text || ''; + } + + const normalizedProfileNumber = sanitizeProfileNumber(profileNumber); + let result = text.replace(/\{Profil(?:e)?-(\d+)(?:-(\d+))?\?\s*"([\s\S]*?)"(?:\s*:\s*"([\s\S]*?)")?\}/gi, (match, startStr, endStr, ifText, elseText) => { + if (!normalizedProfileNumber) { + return ''; + } + + const start = parseInt(startStr, 10); + const end = endStr ? parseInt(endStr, 10) : start; + if (Number.isNaN(start) || Number.isNaN(end)) { + return ''; + } + + const lower = Math.min(start, end); + const upper = Math.max(start, end); + if (normalizedProfileNumber < lower || normalizedProfileNumber > upper) { + return elseText || ''; + } + return ifText || ''; + }); + + result = result.replace(/\{Profil(?:e)?-(\d+)(?:-(\d+))?:([\s\S]*?)\}/gi, (match, startStr, endStr, content) => { + if (!normalizedProfileNumber) { + return ''; + } + + const start = parseInt(startStr, 10); + const end = endStr ? parseInt(endStr, 10) : start; + if (Number.isNaN(start) || Number.isNaN(end)) { + return ''; + } + + const lower = Math.min(start, end); + const upper = Math.max(start, end); + if (normalizedProfileNumber < lower || normalizedProfileNumber > upper) { + return ''; + } + return content; + }); + + return result; +} + +function applyRandomNumberTemplates(text) { + if (typeof text !== 'string' || !text) { + return text || ''; + } + + return text.replace(/\{ZUFALL-(-?\d+)-(-?\d+)\}/gi, (match, startStr, endStr) => { + const start = parseInt(startStr, 10); + const end = parseInt(endStr, 10); + if (Number.isNaN(start) || Number.isNaN(end)) { + return match; + } + + const lower = Math.min(start, end); + const upper = Math.max(start, end); + const span = upper - lower + 1; + if (span <= 0) { + return String(lower); + } + + const value = Math.floor(Math.random() * span) + lower; + return String(value); + }); +} + function normalizeDeadline(value) { if (!value && value !== 0) { return null; @@ -5059,13 +5130,8 @@ app.delete('/api/search-posts', (req, res) => { app.get('/api/profile-state', (req, res) => { try { const scopeId = req.profileScope; - let profileNumber = getScopedProfileNumber(scopeId); - if (!profileNumber) { - profileNumber = 1; - setScopedProfileNumber(scopeId, profileNumber); - } - - res.json({ profile_number: profileNumber }); + const profileNumber = getScopedProfileNumber(scopeId); + res.json({ profile_number: profileNumber || null }); } catch (error) { res.status(500).json({ error: error.message }); } @@ -5469,10 +5535,9 @@ app.post('/api/posts/:postId/check', (req, res) => { didChange = true; } - let profileValue = sanitizeProfileNumber(profile_number); + let profileValue = sanitizeProfileNumber(profile_number) || getScopedProfileNumber(req.profileScope); if (!profileValue) { - const storedProfile = getScopedProfileNumber(req.profileScope); - profileValue = storedProfile || requiredProfiles[0]; + return res.status(400).json({ error: 'Profil muss zuerst ausgewählt werden.' }); } const completedRows = db.prepare('SELECT profile_number FROM checks WHERE post_id = ?').all(postId); @@ -5620,10 +5685,9 @@ app.post('/api/check-by-url', (req, res) => { didChange = true; } - let profileValue = sanitizeProfileNumber(profile_number); + let profileValue = sanitizeProfileNumber(profile_number) || getScopedProfileNumber(req.profileScope); if (!profileValue) { - const storedProfile = getScopedProfileNumber(req.profileScope); - profileValue = storedProfile || requiredProfiles[0]; + return res.status(400).json({ error: 'Profil muss zuerst ausgewählt werden.' }); } const completedRows = db.prepare('SELECT profile_number FROM checks WHERE post_id = ?').all(post.id); @@ -6673,10 +6737,11 @@ app.post('/api/ai/generate-comment', async (req, res) => { } let promptPrefix = settings.prompt_prefix || ''; + const normalizedProfileNumber = sanitizeProfileNumber(profileNumber); // Get friend names for the profile if available - if (profileNumber) { - const friends = db.prepare('SELECT friend_names FROM profile_friends WHERE profile_number = ?').get(profileNumber); + if (normalizedProfileNumber) { + const friends = db.prepare('SELECT friend_names FROM profile_friends WHERE profile_number = ?').get(normalizedProfileNumber); if (friends && friends.friend_names) { promptPrefix = promptPrefix.replace('{FREUNDE}', friends.friend_names); } else { @@ -6686,6 +6751,12 @@ app.post('/api/ai/generate-comment', async (req, res) => { promptPrefix = promptPrefix.replace('{FREUNDE}', ''); } + const today = new Date(); + const todayDisplay = today.toLocaleDateString('de-DE'); + promptPrefix = promptPrefix.replaceAll('{DATUM}', todayDisplay); + promptPrefix = applyRandomNumberTemplates(promptPrefix); + promptPrefix = applyProfileVariantTemplates(promptPrefix, normalizedProfileNumber); + // Try each active credential until one succeeds let lastError = null; const attemptDetails = []; diff --git a/extension/content.js b/extension/content.js index 858ad15..60c33c4 100644 --- a/extension/content.js +++ b/extension/content.js @@ -17,6 +17,7 @@ const SEARCH_RESULTS_PATH_PREFIX = '/search'; const FEED_HOME_PATHS = ['/', '/home.php']; const sessionSearchRecordedUrls = new Set(); const sessionSearchInfoCache = new Map(); +let profileSelectionNoticeShown = false; function isOnSearchResultsPage() { try { @@ -49,6 +50,19 @@ function maybeRedirectPageReelsToMain() { if (typeof pathname !== 'string') { return false; } + if (pathname.toLowerCase() === '/profile.php') { + const params = new URLSearchParams(location.search || ''); + const profileId = params.get('id'); + const sk = params.get('sk'); + if (profileId && sk && sk.toLowerCase().startsWith('reel')) { + const targetUrl = `${location.origin}/profile.php?id=${encodeURIComponent(profileId)}`; + if (location.href !== targetUrl) { + location.replace(targetUrl); + return true; + } + return false; + } + } const match = pathname.match(/^\/([^/]+)\/reels\/?$/i); if (!match) { return false; @@ -513,6 +527,10 @@ async function getProfileNumber() { console.warn('[FB Tracker] Failed to resolve profile number from backend:', error); } + if (!profileSelectionNoticeShown) { + profileSelectionNoticeShown = true; + showToast('Bitte zuerst ein Profil im Tracker auswählen.', 'error'); + } return null; } diff --git a/extension/popup.html b/extension/popup.html index 147efca..687ea6c 100644 --- a/extension/popup.html +++ b/extension/popup.html @@ -112,6 +112,7 @@
+ @@ -1089,7 +1090,7 @@

- Dieser Text wird vor dem eigentlichen Post-Text an die KI gesendet. Verwende {FREUNDE} als Platzhalter für Freundesnamen. + Dieser Text wird vor dem eigentlichen Post-Text an die KI gesendet. Platzhalter: {FREUNDE} (Freundesnamen), {DATUM} (heutiges Datum), {Profil-1?"Text1":"Text2"} bzw. {Profil-1?"Text1"} für profilabhängige Varianten (auch mit Profile) und {ZUFALL-1-5} für eine Zufallszahl im Bereich.