feat: multi-listing YAML config via --config/CONFIG_FILE#1
Merged
Conversation
There was a problem hiding this comment.
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:getTVListingssimply forwardsconfig.userAgent, butmockConfig.userAgentis set toUnitTestAgent/1.0, so this assertion will fail. Consider changing this test to assert the header equalsmockConfig.userAgent, or move randomness expectations togetConfig()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 (sincegetTVListingsreads the response body on failures), and the expected error assertion should align with theFailed to fetch URL ...error message format used bygetTVListings.
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 (sincegetTVListingscallsresponse.text()on failures) and adjust the expected error string/regex to match theFailed 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.
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
Owner
Author
|
Eh, some future work will have to be done around hardening the new tests, but for now, I think we're ok. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Running multiple zap2xml instances to fetch different TV lineups is awkward - separate containers, separate schedules, separate config management. This adds a
--configflag that accepts a YAML file defining any number of listings, so one container handles everything.Testing
Additional tests added to
config.test.tsNew dependencies
yamlandvalibot