feat: EPG improvements for better catch-up playback - #1164
Conversation
Greptile SummaryThis PR improves EPG catch-up reliability with three changes:
Confidence Score: 3/5The selective-delete and retention logic are sound, but the unique index creation in the EpgDatabase constructor will throw for any existing multi-source database where two EPG providers carry overlapping channels, breaking all EPG on upgrade. Two distinct defects in the database layer affect real-world upgrade paths. First, creating the unique index inside the constructor rather than a migration means any user with duplicate (channel_id, start, title) rows — common with multi-source setups — gets a constructor throw and a dead EPG worker until they clear their database manually. Second, omitting source_url from the unique key means the last-parsed source overwrites earlier source_url values, silently breaking per-source programme filtering for channels covered by more than one feed. apps/electron-backend/src/app/workers/epg-database.ts — specifically the CREATE UNIQUE INDEX call in the constructor (line 34-37) and the INSERT OR REPLACE unique key choice (line 39-42). Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant R as Renderer
participant E as EpgEvents (Main)
participant W as EpgWorkerService
participant DB as EpgDatabase (Worker)
R->>E: EPG_FORCE_FETCH(url)
E->>W: deleteFetchedUrl(url)
E->>W: sendProgressToRenderer(url, 'queued')
W-->>R: progress: queued
E->>W: fetchEpgFromUrl(url)
W->>DB: new EpgDatabase() [constructor runs CREATE UNIQUE INDEX]
Note over DB: Throws if existing rows have duplicate channel_id+start+title
DB->>DB: deleteTodayAndFutureStmt in insertChannels txn
Note over DB: Deletes start >= today OR start < now-7d
loop Per channel batch
DB->>DB: insertChannels
end
loop Per program batch
DB->>DB: INSERT OR REPLACE - source_url not in unique key
end
W-->>R: EPG_COMPLETE / EPG_ERROR
E-->>R: success true or false
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant R as Renderer
participant E as EpgEvents (Main)
participant W as EpgWorkerService
participant DB as EpgDatabase (Worker)
R->>E: EPG_FORCE_FETCH(url)
E->>W: deleteFetchedUrl(url)
E->>W: sendProgressToRenderer(url, 'queued')
W-->>R: progress: queued
E->>W: fetchEpgFromUrl(url)
W->>DB: new EpgDatabase() [constructor runs CREATE UNIQUE INDEX]
Note over DB: Throws if existing rows have duplicate channel_id+start+title
DB->>DB: deleteTodayAndFutureStmt in insertChannels txn
Note over DB: Deletes start >= today OR start < now-7d
loop Per channel batch
DB->>DB: insertChannels
end
loop Per program batch
DB->>DB: INSERT OR REPLACE - source_url not in unique key
end
W-->>R: EPG_COMPLETE / EPG_ERROR
E-->>R: success true or false
Prompt To Fix All With AIFix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
apps/electron-backend/src/app/workers/epg-database.ts:34-37
**Unique index creation in constructor crashes on multi-source upgrade**
`CREATE UNIQUE INDEX … ON epg_programs(channel_id, start, title)` will throw `SQLITE_CONSTRAINT_UNIQUE` and abort the `EpgDatabase` constructor if any two rows already share the same `(channel_id, start, title)` triplet. This is a realistic scenario for users who have configured more than one EPG source that both carry the same channel (e.g., `BBC.uk` at 22:00 "News at Ten" from Source A and Source B). Old code inserted both rows with different `source_url` values and no unique constraint, so duplicates on this triplet are present in the majority of multi-source databases. A failed constructor means the EPG worker cannot start at all until the user manually clears the database. The index should be created via a schema migration that de-dupes rows first, not inside the hot-path constructor.
Reviews (2): Last reviewed commit: "feat: add archive EPG feature" | Re-trigger Greptile |
2be9325 to
88ec6e2
Compare
|
@greptileai Please review the changes. |
88ec6e2 to
3293ee3
Compare
|
@greptileai Is this good now? |
|
Largely yes — all four previous review issues are resolved:
One minor residual concern worth being aware of: the unique key is Also, Otherwise the logic is solid and the PR achieves its stated goals cleanly. |
3293ee3 to
0691008
Compare
Improves EPG data reliability with three changes. First, EPG_FORCE_FETCH bypasses the 12-hour freshness check so manual refresh always re-fetches the XMLTV feed (needed when using different epg sources with different update times).
Second, changes the EPG import to preserve past programmes across refreshes — instead of wiping all old data before inserting new data, the parser now only replaces programmes starting today or later, keeping yesterday's archive intact. This is needed because many EPG sources only provide data looking forward, not backwards, and this enables supporting catch-up even in those instances.
Third, adds a rolling 7-day retention cap for this archive, so storage doesn't grow unbounded. Together these ensure catch-up programmes remain visible for their full archive window across daily EPG updates and most IPTV providers.