Valider fase 11: fiks size-inkonsistens og UTF-8-trunkering i RSS
Fase 11 (produksjon) validert — LiveKit, pruning og podcast-RSS: - rss.rs + synops-rss: Les filstørrelse fra både 'size_bytes' (intentions) og 'size' (publishing) med COALESCE — forhindrer manglende enclosure- størrelse i podcast-feeds avhengig av opplastingsmetode. - pruning.rs + synops-prune: Samme COALESCE-fix for konsistent size-tracking. - rss.rs + synops-rss: Fiks truncate_description til å bruke char-indeksering istedenfor byte-indeksering — forhindrer panic på norsk tekst (å, ø, æ). LiveKit kjører i Docker (healthy), token-generering via join_communication, pruning-loop aktiv, RSS-endepunkt returnerer korrekt 404 for ukjent slug. Alle 61 maskinrommet-tester bestått.
This commit is contained in:
parent
2ccbebe222
commit
a836be6992
5 changed files with 20 additions and 16 deletions
|
|
@ -222,7 +222,7 @@ async fn prune_by_ttl(
|
||||||
WHEN n.metadata->>'mime' LIKE 'video/%' THEN 'video'
|
WHEN n.metadata->>'mime' LIKE 'video/%' THEN 'video'
|
||||||
ELSE 'other'
|
ELSE 'other'
|
||||||
END AS mime_category,
|
END AS mime_category,
|
||||||
COALESCE((n.metadata->>'size_bytes')::bigint, 0) AS size_bytes,
|
COALESCE((n.metadata->>'size_bytes')::bigint, (n.metadata->>'size')::bigint, 0) AS size_bytes,
|
||||||
n.created_at,
|
n.created_at,
|
||||||
n.last_accessed_at,
|
n.last_accessed_at,
|
||||||
EXISTS(
|
EXISTS(
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,7 @@ async fn fetch_feed_items(
|
||||||
e.metadata,
|
e.metadata,
|
||||||
m.metadata->>'cas_hash' AS cas_hash,
|
m.metadata->>'cas_hash' AS cas_hash,
|
||||||
m.metadata->>'mime' AS mime,
|
m.metadata->>'mime' AS mime,
|
||||||
(m.metadata->>'size')::bigint AS size
|
COALESCE((m.metadata->>'size_bytes')::bigint, (m.metadata->>'size')::bigint) AS size
|
||||||
FROM edges e
|
FROM edges e
|
||||||
JOIN nodes n ON n.id = e.source_id
|
JOIN nodes n ON n.id = e.source_id
|
||||||
LEFT JOIN edges me ON me.source_id = n.id AND me.edge_type = 'has_media'
|
LEFT JOIN edges me ON me.source_id = n.id AND me.edge_type = 'has_media'
|
||||||
|
|
@ -476,13 +476,16 @@ fn short_id(id: Uuid) -> String {
|
||||||
id.to_string()[..8].to_string()
|
id.to_string()[..8].to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trunkér beskrivelse til maks antall tegn, på ordgrense.
|
/// Trunkér beskrivelse til maks antall tegn (chars, ikke bytes), på ordgrense.
|
||||||
fn truncate_description(s: &str, max_len: usize) -> String {
|
fn truncate_description(s: &str, max_chars: usize) -> String {
|
||||||
if s.len() <= max_len {
|
let char_count = s.chars().count();
|
||||||
|
if char_count <= max_chars {
|
||||||
return s.to_string();
|
return s.to_string();
|
||||||
}
|
}
|
||||||
match s[..max_len].rfind(' ') {
|
// Finn byte-posisjon for max_chars tegn
|
||||||
|
let byte_end = s.char_indices().nth(max_chars).map(|(i, _)| i).unwrap_or(s.len());
|
||||||
|
match s[..byte_end].rfind(' ') {
|
||||||
Some(pos) => format!("{}…", &s[..pos]),
|
Some(pos) => format!("{}…", &s[..pos]),
|
||||||
None => format!("{}…", &s[..max_len]),
|
None => format!("{}…", &s[..byte_end]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
3
tasks.md
3
tasks.md
|
|
@ -299,8 +299,7 @@ med spesifikasjon for det som trenger en dedikert sesjon.
|
||||||
- [x] 23.2 Valider fase 3–4 (frontend + tilgang): SvelteKit-oppsett, OIDC-flow, sanntid, mottaksflate, TipTap-editor, node_access-matrise, team-transitivitet, visibility-filtrering.
|
- [x] 23.2 Valider fase 3–4 (frontend + tilgang): SvelteKit-oppsett, OIDC-flow, sanntid, mottaksflate, TipTap-editor, node_access-matrise, team-transitivitet, visibility-filtrering.
|
||||||
- [x] 23.3 Valider fase 5–8 (kommunikasjon + CAS + lyd + aliaser): chat-loop, kontekst-arv, CAS-hashing/deduplisering, Whisper-pipeline, segmenttabell, SRT-eksport, alias-identitet.
|
- [x] 23.3 Valider fase 5–8 (kommunikasjon + CAS + lyd + aliaser): chat-loop, kontekst-arv, CAS-hashing/deduplisering, Whisper-pipeline, segmenttabell, SRT-eksport, alias-identitet.
|
||||||
- [x] 23.4 Valider fase 9–10 (visninger + AI): kanban drag-and-drop, kalender, dagbok, kunnskapsgraf, LiteLLM-ruting, AI-foreslåtte edges, oppsummering, TTS.
|
- [x] 23.4 Valider fase 9–10 (visninger + AI): kanban drag-and-drop, kalender, dagbok, kunnskapsgraf, LiteLLM-ruting, AI-foreslåtte edges, oppsummering, TTS.
|
||||||
- [~] 23.5 Valider fase 11 (produksjon): LiveKit-oppsett, sanntidslyd, pruning-logikk, podcast-RSS.
|
- [x] 23.5 Valider fase 11 (produksjon): LiveKit-oppsett, sanntidslyd, pruning-logikk, podcast-RSS.
|
||||||
> Påbegynt: 2026-03-18T15:10
|
|
||||||
- [ ] 23.6 Valider fase 13–14 (traits + publisering): trait-validering, pakkevelger, Tera-templates, HTML-rendering, forside, slot-håndtering, redaksjonell flyt, planlagt publisering, A/B-testing.
|
- [ ] 23.6 Valider fase 13–14 (traits + publisering): trait-validering, pakkevelger, Tera-templates, HTML-rendering, forside, slot-håndtering, redaksjonell flyt, planlagt publisering, A/B-testing.
|
||||||
- [ ] 23.7 Valider fase 15–16 (admin + lydmixer): systemvarsler, graceful shutdown, jobbkø-oversikt, ressursstyring, serverhelse, Web Audio mixer, delt kontroll, sound pads, EQ, stemmeeffekter.
|
- [ ] 23.7 Valider fase 15–16 (admin + lydmixer): systemvarsler, graceful shutdown, jobbkø-oversikt, ressursstyring, serverhelse, Web Audio mixer, delt kontroll, sound pads, EQ, stemmeeffekter.
|
||||||
- [ ] 23.8 Valider fase 17–18 (lydstudio-utbedring + AI-verktøy): responsivt layout, FFmpeg-validering, fade/silence, AI-presets, direction-logikk, drag-and-drop integrasjon.
|
- [ ] 23.8 Valider fase 17–18 (lydstudio-utbedring + AI-verktøy): responsivt layout, FFmpeg-validering, fade/silence, AI-presets, direction-logikk, drag-and-drop integrasjon.
|
||||||
|
|
|
||||||
|
|
@ -259,7 +259,7 @@ async fn phase_ttl(
|
||||||
WHEN n.metadata->>'mime' LIKE 'video/%' THEN 'video'
|
WHEN n.metadata->>'mime' LIKE 'video/%' THEN 'video'
|
||||||
ELSE 'other'
|
ELSE 'other'
|
||||||
END AS mime_category,
|
END AS mime_category,
|
||||||
COALESCE((n.metadata->>'size_bytes')::bigint, 0) AS size_bytes,
|
COALESCE((n.metadata->>'size_bytes')::bigint, (n.metadata->>'size')::bigint, 0) AS size_bytes,
|
||||||
n.created_at,
|
n.created_at,
|
||||||
n.last_accessed_at,
|
n.last_accessed_at,
|
||||||
EXISTS(
|
EXISTS(
|
||||||
|
|
|
||||||
|
|
@ -268,7 +268,7 @@ async fn fetch_feed_items(
|
||||||
e.metadata,
|
e.metadata,
|
||||||
m.metadata->>'cas_hash' AS cas_hash,
|
m.metadata->>'cas_hash' AS cas_hash,
|
||||||
m.metadata->>'mime' AS mime,
|
m.metadata->>'mime' AS mime,
|
||||||
(m.metadata->>'size')::bigint AS size
|
COALESCE((m.metadata->>'size_bytes')::bigint, (m.metadata->>'size')::bigint) AS size
|
||||||
FROM edges e
|
FROM edges e
|
||||||
JOIN nodes n ON n.id = e.source_id
|
JOIN nodes n ON n.id = e.source_id
|
||||||
LEFT JOIN edges me ON me.source_id = n.id AND me.edge_type = 'has_media'
|
LEFT JOIN edges me ON me.source_id = n.id AND me.edge_type = 'has_media'
|
||||||
|
|
@ -562,13 +562,15 @@ fn short_id(id: Uuid) -> String {
|
||||||
id.to_string()[..8].to_string()
|
id.to_string()[..8].to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trunkér beskrivelse til maks antall tegn, på ordgrense.
|
/// Trunkér beskrivelse til maks antall tegn (chars, ikke bytes), på ordgrense.
|
||||||
fn truncate_description(s: &str, max_len: usize) -> String {
|
fn truncate_description(s: &str, max_chars: usize) -> String {
|
||||||
if s.len() <= max_len {
|
let char_count = s.chars().count();
|
||||||
|
if char_count <= max_chars {
|
||||||
return s.to_string();
|
return s.to_string();
|
||||||
}
|
}
|
||||||
match s[..max_len].rfind(' ') {
|
let byte_end = s.char_indices().nth(max_chars).map(|(i, _)| i).unwrap_or(s.len());
|
||||||
|
match s[..byte_end].rfind(' ') {
|
||||||
Some(pos) => format!("{}…", &s[..pos]),
|
Some(pos) => format!("{}…", &s[..pos]),
|
||||||
None => format!("{}…", &s[..max_len]),
|
None => format!("{}…", &s[..byte_end]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue