This project builds a Node.js IPTV proxy that aggregates multiple live-TV sources (M3U playlists and HDHomeRun tuners), merges EPG (XMLTV) data, and exposes a unified lineup compatible with IPTV clients.
Copilot should help extend and maintain this codebase in JavaScript (ESM).
- Runtime: Node.js ≥ 20
- Admin UI Vue.js 3
- Framework: Express
- Config: YAML files in
/config - Logging: Pino
- Testing: Vitest + supertest
- Style: ESLint + Prettier (flat config)
- ESM imports only
/src /server app.js routes/ services/ sources/ epg/ mapping/ proxies/ utils/ /config sources.yaml mapping.yaml epg.yaml /scripts ingest-epg.js validate-config.js
| Route | Description |
|---|---|
/discover.json |
HDHomeRun discover format |
/lineup.json |
HDHomeRun lineup format |
/stream/:channelId |
Proxy upstream stream |
/images/* |
Proxy channel logos |
- Canonical channel ID (e.g.,
23.1) is the stable exposed identifier. - Match priority:
- Explicit
mapping.yamlentry - Optional match by number + callsign
- Otherwise excluded until mapped.
- Explicit
- Combine multiple XMLTV sources (URLs or local files).
- Deduplicate
<programme>by(channel, start, title). - Keep higher-priority source on conflicts.
- Preserve
<channel id="23.1">unchanged. - Output merged file at
data/merged.xml.
- Prefer pure functions for transforms (EPG merge, mapping).
- Keep I/O (network, filesystem) inside service modules.
- Use JSDoc for structure hints instead of TypeScript.
- Log context with
{sourceId, channelId}on errors. - Use
undicifor fetch,zlibfor gzipped XML. - Keep memory bounded: stream parse XMLTV, don’t buffer it.
When prompted, Copilot should be able to:
- Implement
/src/server/services/mapping/resolver.js- Load
config/mapping.yaml - Map
{sourceId, channelId}→ canonical ID - Provide reverse lookup
- Load
- Implement
/src/server/services/epg/merge.js- Merge multiple XMLTV inputs with conflict priority
- Implement
/src/server/services/proxies/stream-proxy.js- Stream upstream content with timeout and header preservation
- Add Vitest/supertest coverage for routes.
- “Generate
src/server/services/mapping/resolver.jsusing the rules in thisagents.md. Include JSDoc typedefs.” - “Write a Vitest suite for
/lineup.jsonthat mocks the mapping resolver.” - “Implement
scripts/ingest-epg.jsto download, merge, and output XMLTV from config.”
- Use consistent logging (
log.info,log.error). - One default export per file, unless utilities.
- ESM imports (
import x from), notrequire(). - Avoid large async concurrency — rate-limit fetches.
- Use Composition API for Vue.js components
This proxy is designed to run on local/home networks. Upstream IPTV sources and HDHomeRun tuners are typically on the same LAN and will have private/local IP addresses (e.g., 192.168.x.x, 10.x.x.x, 172.16-31.x.x) or local hostnames (e.g., .local, .lan). Do not add code that blocks requests to private or local network addresses — doing so would break the core use case.
- No TypeScript.
- No UI work (mapping UI comes later).
- No DVR/timeshift features.
Never run npm run build or vite build inside the admin/ directory.
The admin build generates content-hashed asset filenames (e.g. index-Abc123.js) and rewrites public/admin/index.html with those hashes. This file is tracked in git and must stay pointing to the stable, non-hashed filenames (index.js, index.css). Running the build will pollute the PR with unrelated asset hash changes.
Whenever you add or update a server API endpoint, also update server/mcp.js.
The MCP interface (POST /mcp) exposes IPTV proxy functionality to AI assistants via the Model Context Protocol. It must stay in sync with the rest of the server:
- Adding a new route or capability? Consider whether it should also be exposed as an MCP tool. If so, register it in
server/mcp.jsusingserver.tool(...). - Changing a data shape (e.g., channel fields, EPG fields, provider config)? Update any affected MCP tools to reflect the new shape.
- Removing or renaming functionality? Remove or rename the corresponding MCP tool so the interface doesn't advertise broken capabilities.
The six current MCP tools and their server-side dependencies are:
| MCP Tool | Server dependency |
|---|---|
list_channels |
libs/channels-cache.js → getChannels() |
get_guide |
server/epg.js → getGuideData() |
list_providers |
libs/config-loader.js → loadConfig('providers') |
get_status |
server/status.js → getSourceStatus() |
reload_channels |
scripts/parseM3U.js → parseAll() |
reload_epg |
server/epg.js → refreshEPG() |
Each MCP tool also has corresponding integration tests in test/integration/mcp.test.js that must be kept up to date.
Copilot: treat this file as the authoritative reference for this repository.