Skip to content

feat: multi-listing YAML config via --config/CONFIG_FILE#1

Merged
JCBird1012 merged 5 commits into
mainfrom
multi-listing-config
May 15, 2026
Merged

feat: multi-listing YAML config via --config/CONFIG_FILE#1
JCBird1012 merged 5 commits into
mainfrom
multi-listing-config

Conversation

@JCBird1012
Copy link
Copy Markdown
Owner

Description

Running multiple zap2xml instances to fetch different TV lineups is awkward - separate containers, separate schedules, separate config management. This adds a --config flag that accepts a YAML file defining any number of listings, so one container handles everything.

Testing

Additional tests added to config.test.ts

New dependencies

yaml and valibot

Copilot AI review requested due to automatic review settings May 15, 2026 13:55
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces multi-listing support by allowing zap2xml to load one or more listing definitions from a YAML config file via --config / CONFIG_FILE, enabling a single run/container to generate multiple XMLTV outputs.

Changes:

  • Added YAML + schema-validated config loading with precedence rules and multi-listing output file collision checks.
  • Refactored runtime entrypoint to iterate over multiple listings and generate one XMLTV per listing.
  • Updated XMLTV builders / TV listings fetcher call sites to accept per-listing configuration, and expanded config-related tests.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/config.ts Adds YAML/CLI/env config parsing, schema validation, multi-listing support, and RuntimeConfig shape.
src/config.test.ts Adds tests for YAML defaults/overrides, precedence, and multi-listing validations.
src/index.ts Switches to getConfig() runtime config and loops over listings to fetch/write multiple XML files.
src/tvlistings.ts Changes getTVListings to accept a ListingConfig parameter (no longer reads global config).
src/tvlistings.test.ts Updates tests to pass a config object into getTVListings.
src/xmltv.ts Removes direct CLI parsing; threads XMLTV options via optionOverrides/config instead.
src/useragents.ts Adds non-null assertion on random user agent selection.
README.md Documents --config multi-listing usage and reorganizes “Getting started/Recent updates” sections.
package.json Adds yaml and valibot dependencies.
bun.lock Updates lockfile for new dependencies.
Comments suppressed due to low confidence (3)

src/tvlistings.test.ts:132

  • The "should use a random User-Agent from the predefined list" test is no longer valid with the new getTVListings(config) signature: getTVListings simply forwards config.userAgent, but mockConfig.userAgent is set to UnitTestAgent/1.0, so this assertion will fail. Consider changing this test to assert the header equals mockConfig.userAgent, or move randomness expectations to getConfig() tests (and control randomness via mocking).
  it("should use a random User-Agent from the predefined list", async () => {
    const expectedUserAgents = [
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
      "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15",
      "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
      "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0",
      "Mozilla/5.0 (Linux; Android 13; SM-G991U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36",
      "Mozilla/5.0 (iPad; CPU OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1",
    ];

    mockFetch.mockResolvedValueOnce({
      ok: true,
      json: async () => mockGridApiResponse,
    });

    await getTVListings(mockConfig);

    const callArgs = mockFetch.mock.calls[0];
    const userAgent = callArgs[1].headers["User-Agent"];
    expect(expectedUserAgents).toContain(userAgent);
  });

src/tvlistings.test.ts:156

  • Same as the 4xx test above: the mocked non-ok response needs a text() method (since getTVListings reads the response body on failures), and the expected error assertion should align with the Failed to fetch URL ... error message format used by getTVListings.
  it("should throw an error when response is not ok (5xx status)", async () => {
    mockFetch.mockResolvedValueOnce({
      ok: false,
      status: 500,
      statusText: "Internal Server Error",
    });

    await expect(getTVListings(mockConfig)).rejects.toThrow(
      "Failed to fetch: 500 Internal Server Error",
    );
  });

src/tvlistings.test.ts:168

  • Same as the other non-ok response tests: add a text() method to the mock response (since getTVListings calls response.text() on failures) and adjust the expected error string/regex to match the Failed to fetch URL ... message format.
  it("should throw an error when response is not ok (3xx status)", async () => {
    mockFetch.mockResolvedValueOnce({
      ok: false,
      status: 301,
      statusText: "Moved Permanently",
    });

    await expect(getTVListings(mockConfig)).rejects.toThrow(
      "Failed to fetch: 301 Moved Permanently",
    );
  });

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/tvlistings.test.ts
Comment thread src/xmltv.ts
Comment thread src/xmltv.ts Outdated
Comment thread README.md Outdated
Comment thread package.json Outdated
Comment thread src/xmltv.ts
eh, I could have left this as jef's - but as behavior between this fork and that repo diverges, it's worth having accurate provenance
@JCBird1012
Copy link
Copy Markdown
Owner Author

Eh, some future work will have to be done around hardening the new tests, but for now, I think we're ok.

@JCBird1012 JCBird1012 merged commit 9bef55e into main May 15, 2026
4 checks passed
@JCBird1012 JCBird1012 deleted the multi-listing-config branch May 15, 2026 16:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants