diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 31d90ae..ab9fcb8 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,6 +27,7 @@ jobs: uses: actions/setup-node@v4 with: node-version-file: package.json + cache: npm - name: Install dependencies run: npm ci @@ -37,5 +38,16 @@ jobs: - name: Lint run: npm run lint - - name: Test + - name: Unit tests run: npm run test:run + + - name: Integration tests + run: | + node dist/index.js --lineupId=USA-DITV751-X --timespan=3 --postalCode=80020 --outputFile=dtv.xml + node dist/index.js --lineupId=USA-OTA80020 --timespan=3 --postalCode=80020 --outputFile=ota.xml + + # Error if they are the same + if cmp -s dtv.xml ota.xml; then + echo "DTV and OTA outputs are the same, which is unexpected." + exit 1 + fi diff --git a/src/config.ts b/src/config.ts index af855b9..1186968 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,38 +1,64 @@ import { UserAgent } from "./useragents.js"; -export const config = { - baseUrl: "https://tvlistings.gracenote.com/api/grid", - lineupId: +function processLineupId(): string { + const lineupId = process.env["LINEUP_ID"] || process.argv.find((arg) => arg.startsWith("--lineupId="))?.split("=")[1] || - "USA-lineupId-DEFAULT", - timespan: - process.env["TIMESPAN"] || - process.argv.find((arg) => arg.startsWith("--timespan="))?.split("=")[1] || - "6", - country: - process.env["COUNTRY"] || - process.argv.find((arg) => arg.startsWith("--country="))?.split("=")[1] || - "USA", - postalCode: - process.env["POSTAL_CODE"] || - process.argv - .find((arg) => arg.startsWith("--postalCode=")) - ?.split("=")[1] || - "30309", - pref: - process.env["PREF"] || - process.argv.find((arg) => arg.startsWith("--pref="))?.split("=")[1] || - "", - timezone: process.env.TZ || "America/New_York", - userAgent: - process.env["USER_AGENT"] || - process.argv.find((arg) => arg.startsWith("--userAgent="))?.split("=")[1] || - UserAgent, - outputFile: - process.env["OUTPUT_FILE"] || - process.argv - .find((arg) => arg.startsWith("--outputFile=")) - ?.split("=")[1] || - "xmltv.xml", -}; + "USA-lineupId-DEFAULT"; + + if (lineupId.includes("OTA")) { + return "USA-lineupId-DEFAULT"; + } + + return lineupId; +} + +function getHeadendId(lineupId: string): string { + const match = lineupId.match(/^(USA|CAN)-(.*?)(?:-[A-Z]+)?$/); + + return match?.[2] || "lineup"; +} + +export function getConfig() { + const lineupId = processLineupId(); + const headendId = getHeadendId(lineupId); + + return { + baseUrl: "https://tvlistings.gracenote.com/api/grid", + lineupId, + headendId, + timespan: + process.env["TIMESPAN"] || + process.argv + .find((arg) => arg.startsWith("--timespan=")) + ?.split("=")[1] || + "6", + country: + process.env["COUNTRY"] || + process.argv.find((arg) => arg.startsWith("--country="))?.split("=")[1] || + "USA", + postalCode: + process.env["POSTAL_CODE"] || + process.argv + .find((arg) => arg.startsWith("--postalCode=")) + ?.split("=")[1] || + "30309", + pref: + process.env["PREF"] || + process.argv.find((arg) => arg.startsWith("--pref="))?.split("=")[1] || + "", + timezone: process.env.TZ || "America/New_York", + userAgent: + process.env["USER_AGENT"] || + process.argv + .find((arg) => arg.startsWith("--userAgent=")) + ?.split("=")[1] || + UserAgent, + outputFile: + process.env["OUTPUT_FILE"] || + process.argv + .find((arg) => arg.startsWith("--outputFile=")) + ?.split("=")[1] || + "xmltv.xml", + }; +} diff --git a/src/index.ts b/src/index.ts index 7ec504a..95daec5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,9 @@ import { writeFileSync } from "node:fs"; import { getTVListings } from "./tvlistings.js"; import { buildXmltv } from "./xmltv.js"; -import { config } from "./config.js"; +import { getConfig } from "./config.js"; + +const config = getConfig(); function isHelp() { if (process.argv.includes("--help")) { diff --git a/src/tvlistings.ts b/src/tvlistings.ts index 2841313..6a353ce 100644 --- a/src/tvlistings.ts +++ b/src/tvlistings.ts @@ -1,4 +1,6 @@ -import { config } from "./config.js"; +import { getConfig } from "./config.js"; + +const config = getConfig(); export interface Program { /** "title": "GMA3" */ @@ -82,7 +84,7 @@ function buildUrl(time: number, timespan: number): string { const params = { lineupId: config.lineupId, timespan: timespan.toString(), - headendId: "lineupId", + headendId: config.headendId, country: config.country, timezone: config.timezone, postalCode: config.postalCode, @@ -91,6 +93,8 @@ function buildUrl(time: number, timespan: number): string { aid: "orbebb", languagecode: "en-us", time: time.toString(), + device: "X", + userId: "-", }; const urlParams = new URLSearchParams(params).toString(); @@ -119,7 +123,7 @@ export async function getTVListings(): Promise { }).then(async (response) => { if (!response.ok) { throw new Error( - `Failed to fetch: ${response.status} ${response.statusText}` + `Failed to fetch: ${response.status} ${response.statusText}`, ); } const chunkData = (await response.json()) as GridApiResponse;