From 71ff9344a10594949b36190a8bade6ff578c1bed Mon Sep 17 00:00:00 2001 From: hubble_dubble Date: Mon, 26 Jan 2026 00:59:03 +0000 Subject: [PATCH] Changes to the compse yml and the way and amout of artikeltexte are delivered and taht not duplicates are displayed --- docker-compose.yml | 38 ++++++++++++++++++++++++++--- server-app/main.go | 28 +++++++++++++++++++-- volumes/web/static/js/index-lite.js | 8 +++++- volumes/web/static/js/index.js | 28 ++++++++++++++++----- 4 files changed, 89 insertions(+), 13 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index dcbc8a6..d7fa183 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,6 +3,8 @@ services: build: ./db image: bunker-database:latest restart: unless-stopped + networks: + - backend environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} @@ -15,10 +17,32 @@ services: - ./volumes/db-init/data:/docker-entrypoint-initdb.d/data:ro - ./volumes/data:/data - server-app: + server-app-blue: build: ./server-app image: bunker-server-app:latest + container_name: server-app-blue restart: unless-stopped + networks: + - proxy + - backend + environment: + APP_PORT: ${APP_PORT} + DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@database:5432/${POSTGRES_DB}?sslmode=disable + expose: + - "8080" + volumes: + - ./volumes/web:/app/web + depends_on: + - database + + server-app-green: + build: ./server-app + image: bunker-server-app:latest + container_name: server-app-green + restart: unless-stopped + networks: + - proxy + - backend environment: APP_PORT: ${APP_PORT} DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@database:5432/${POSTGRES_DB}?sslmode=disable @@ -33,6 +57,8 @@ services: build: ./ai-worker image: bunker-ai-worker:latest restart: unless-stopped + networks: + - backend environment: DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@database:5432/${POSTGRES_DB}?sslmode=disable SD_MODEL_PATH: /app/models/sd15 @@ -47,12 +73,16 @@ services: build: ./background-worker image: bunker-background-worker:latest restart: unless-stopped + networks: + - backend environment: DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@database:5432/${POSTGRES_DB}?sslmode=disable RMV_API_KEY: ${RMV_API_KEY} depends_on: - database -volumes: - caddy_data: - caddy_config: \ No newline at end of file +networks: + proxy: + external: true + backend: + driver: bridge \ No newline at end of file diff --git a/server-app/main.go b/server-app/main.go index 391dbfd..ef5a456 100644 --- a/server-app/main.go +++ b/server-app/main.go @@ -206,7 +206,7 @@ func main() { if err := withConn(r, func(conn *pgx.Conn) error { rows, err := conn.Query(r.Context(), ` - SELECT title, link, summary, image, published_at + SELECT article_id, title, link, summary, image, published_at FROM articles WHERE image IS NOT NULL ORDER BY COALESCE(published_at, created_at) DESC @@ -238,16 +238,40 @@ func main() { w.Write([]byte("\n")) flusher.Flush() + seen := make(map[string]struct{}) + rowCount := 0 + for rows.Next() { + rowCount++ + var articleID *string var title, link, summary string var image *string var published *time.Time - if err := rows.Scan(&title, &link, &summary, &image, &published); err != nil { + if err := rows.Scan(&articleID, &title, &link, &summary, &image, &published); err != nil { return err } + id := "" + if articleID != nil { + id = strings.TrimSpace(*articleID) + } + if id == "" { + if link != "" { + id = link + } else if title != "" { + id = title + } else { + id = fmt.Sprintf("row:%d", rowCount) + } + } + if _, exists := seen[id]; exists { + continue + } + seen[id] = struct{}{} + item := map[string]interface{}{ + "id": id, "title": title, "link": link, "text": summary, diff --git a/volumes/web/static/js/index-lite.js b/volumes/web/static/js/index-lite.js index afe4044..5b0cbf3 100644 --- a/volumes/web/static/js/index-lite.js +++ b/volumes/web/static/js/index-lite.js @@ -38,10 +38,16 @@ async function loadNews() { const lines = text.split("\n").map((line) => line.trim()).filter(Boolean); const items = []; + const seen = new Set(); for (const line of lines) { try { const parsed = JSON.parse(line); + const fallbackTitle = stripTags(parsed.title); + const id = parsed.id || parsed.link || fallbackTitle || `idx:${items.length}`; + if (seen.has(id)) continue; + seen.add(id); items.push({ + id, title: stripTags(parsed.title), text: stripTags(parsed.text), link: parsed.link, @@ -49,7 +55,7 @@ async function loadNews() { } catch (err) { console.warn("NDJSON parse error", err); } - if (items.length >= 60) break; + if (items.length >= 20) break; } newsContainer.innerHTML = ""; diff --git a/volumes/web/static/js/index.js b/volumes/web/static/js/index.js index 847453b..5cdc296 100644 --- a/volumes/web/static/js/index.js +++ b/volumes/web/static/js/index.js @@ -32,9 +32,14 @@ async function ladeNews() { const loadingEl = null; + container.innerHTML = ""; + const newsIndex = new Map(); + const maxItems = 20; + let renderedCount = 0; const getKey = (nachricht) => { + if (nachricht?.id) return `id:${nachricht.id}`; if (nachricht?.link) return `link:${nachricht.link}`; if (nachricht?.title) return `title:${stripTags(nachricht.title)}`; if (nachricht?.publishedAt) return `ts:${nachricht.publishedAt}`; @@ -109,13 +114,15 @@ async function ladeNews() { const existing = newsIndex.get(key); if (existing) { updateFields(existing, nachricht); - return; + return false; } const state = buildItem(nachricht); updateFields(state, nachricht); newsIndex.set(key, state); container.appendChild(state.item); + renderedCount += 1; + return true; }; try { @@ -136,6 +143,7 @@ async function ladeNews() { const decoder = new TextDecoder("utf-8"); let buffer = ""; + let stop = false; while (true) { const { value, done } = await reader.read(); if (done) break; @@ -148,19 +156,27 @@ async function ladeNews() { const s = line.trim(); if (!s) continue; try { - renderItem(JSON.parse(s)); - foundAny = true; + const added = renderItem(JSON.parse(s)); + if (added) foundAny = true; + if (renderedCount >= maxItems) { + stop = true; + break; + } } catch (e) { console.warn("NDJSON parse error:", s.slice(0, 200)); } } + if (stop) break; + } + if (stop) { + await reader.cancel(); } const last = buffer.trim(); - if (last) { + if (last && renderedCount < maxItems) { try { - renderItem(JSON.parse(last)); - foundAny = true; + const added = renderItem(JSON.parse(last)); + if (added) foundAny = true; } catch {} }