feat: support upto 15 days of listings
- change default timespan to 6 - parallize tv listing chunks special thanks to @majortom9 https://github.com/jef/zap2xml/issues/41#issuecomment-3092418305
This commit is contained in:
42
README.md
42
README.md
@@ -44,27 +44,27 @@ See [Environment variables](#environment-variables) for configuration options.
|
||||
|
||||
### Environment variables
|
||||
|
||||
| Variable | Description | Type | Default |
|
||||
| ------------- | --------------------------------------------------------------------------------------------------------------- | ------- | -------------------------------- |
|
||||
| `LINEUP_ID` | Lineup ID; Read more in the [Wiki](https://github.com/jef/zap2xml/wiki/Retrieving-Lineup-ID) | String | `USA-lineupId-DEFAULT` (Attenna) |
|
||||
| `TIMESPAN` | Either 3 or 6 hours of shows | Integer | 3 |
|
||||
| `PREF` | User Preferences, comma separated list. `m` for showing music, `p` for showing pay-per-view, `h` for showing HD | String | (empty) |
|
||||
| `COUNTRY` | Country code (default: `US`) | String | US |
|
||||
| `POSTAL_CODE` | Postal code of where shows are available. | Integer | 30309 |
|
||||
| `USER_AGENT` | Custom user agent string for HTTP requests. | String | Uses random if not specified |
|
||||
| `TZ` | Timezone | String | System default |
|
||||
| `SLEEP_TIME` | Sleep time before next run in seconds (default: 10800, Only used with Docker.) | Integer | 10800 |
|
||||
| `OUTPUT_FILE` | Output file name (default: xmltv.xml) | String | xmltv.xml |
|
||||
| Variable | Description | Type | Default |
|
||||
| ------------- | --------------------------------------------------------------------------------------------------------------- | ------ | -------------------------------- |
|
||||
| `LINEUP_ID` | Lineup ID; Read more in the [Wiki](https://github.com/jef/zap2xml/wiki/Retrieving-Lineup-ID) | String | `USA-lineupId-DEFAULT` (Attenna) |
|
||||
| `TIMESPAN` | Either 3 or 6 hours of shows | String | 3 |
|
||||
| `PREF` | User Preferences, comma separated list. `m` for showing music, `p` for showing pay-per-view, `h` for showing HD | String | (empty) |
|
||||
| `COUNTRY` | Country code (default: `US`) | String | US |
|
||||
| `POSTAL_CODE` | Postal code of where shows are available. | String | 30309 |
|
||||
| `USER_AGENT` | Custom user agent string for HTTP requests. | String | Uses random if not specified |
|
||||
| `TZ` | Timezone | String | System default |
|
||||
| `SLEEP_TIME` | Sleep time before next run in seconds (default: 10800, Only used with Docker.) | String | 10800 |
|
||||
| `OUTPUT_FILE` | Output file name (default: xmltv.xml) | String | xmltv.xml |
|
||||
|
||||
### Command line arguments
|
||||
|
||||
| Argument | Description | Type | Default |
|
||||
| -------------- | --------------------------------------------------------------------------------------------------------------- | ------- | -------------------------------- |
|
||||
| `--lineupId` | Lineup ID; Read more in the [Wiki](https://github.com/jef/zap2xml/wiki/Retrieving-Lineup-ID) | String | `USA-lineupId-DEFAULT` (Attenna) |
|
||||
| `--timespan` | Either 3 or 6 hours of shows | Integer | 3 |
|
||||
| `--pref` | User Preferences, comma separated list. `m` for showing music, `p` for showing pay-per-view, `h` for showing HD | String | (empty) |
|
||||
| `--country` | Country code (default: `US`) | String | US |
|
||||
| `--postalCode` | Postal code of where shows are available. | Integer | 30309 |
|
||||
| `--userAgent` | Custom user agent string for HTTP requests. | String | Uses random if not specified |
|
||||
| `--timezone` | Timezone | String | System default |
|
||||
| `--outputFile` | Output file name (default: xmltv.xml) | String | xmltv.xml |
|
||||
| Argument | Description | Type | Default |
|
||||
| -------------- | --------------------------------------------------------------------------------------------------------------- | ------ | -------------------------------- |
|
||||
| `--lineupId` | Lineup ID; Read more in the [Wiki](https://github.com/jef/zap2xml/wiki/Retrieving-Lineup-ID) | String | `USA-lineupId-DEFAULT` (Attenna) |
|
||||
| `--timespan` | Either 3 or 6 hours of shows | String | 3 |
|
||||
| `--pref` | User Preferences, comma separated list. `m` for showing music, `p` for showing pay-per-view, `h` for showing HD | String | (empty) |
|
||||
| `--country` | Country code (default: `US`) | String | US |
|
||||
| `--postalCode` | Postal code of where shows are available. | String | 30309 |
|
||||
| `--userAgent` | Custom user agent string for HTTP requests. | String | Uses random if not specified |
|
||||
| `--timezone` | Timezone | String | System default |
|
||||
| `--outputFile` | Output file name (default: xmltv.xml) | String | xmltv.xml |
|
||||
|
||||
@@ -9,7 +9,7 @@ export const config = {
|
||||
timespan:
|
||||
process.env["TIMESPAN"] ||
|
||||
process.argv.find((arg) => arg.startsWith("--timespan="))?.split("=")[1] ||
|
||||
"3",
|
||||
"6",
|
||||
country:
|
||||
process.env["COUNTRY"] ||
|
||||
process.argv.find((arg) => arg.startsWith("--country="))?.split("=")[1] ||
|
||||
|
||||
@@ -11,7 +11,7 @@ Usage: node dist/index.js [options]
|
||||
Options:
|
||||
--help Show this help message
|
||||
--lineupId=ID Lineup ID (default: USA-lineupId-DEFAULT)
|
||||
--timespan=NUM Timespan in hours (default: 3)
|
||||
--timespan=NUM Timespan in hours (up to 360 = 15 days, default: 6)
|
||||
--pref=LIST User preferences, comma separated. Can be m, p, and h (default: empty)'
|
||||
--country=CON Country code (default: USA)
|
||||
--postalCode=ZIP Postal code (default: 30309)
|
||||
|
||||
@@ -78,10 +78,10 @@ export interface GridApiResponse {
|
||||
channels: Channel[];
|
||||
}
|
||||
|
||||
function buildUrl() {
|
||||
function buildUrl(time: number, timespan: number): string {
|
||||
const params = {
|
||||
lineupId: config.lineupId,
|
||||
timespan: config.timespan,
|
||||
timespan: timespan.toString(),
|
||||
headendId: "lineupId",
|
||||
country: config.country,
|
||||
timezone: config.timezone,
|
||||
@@ -90,7 +90,7 @@ function buildUrl() {
|
||||
pref: config.pref + "16,128" || "16,128",
|
||||
aid: "orbebb",
|
||||
languagecode: "en-us",
|
||||
time: Math.floor(Date.now() / 1000).toString(),
|
||||
time: time.toString(),
|
||||
};
|
||||
|
||||
const urlParams = new URLSearchParams(params).toString();
|
||||
@@ -101,19 +101,47 @@ function buildUrl() {
|
||||
export async function getTVListings(): Promise<GridApiResponse> {
|
||||
console.log("Fetching TV listings");
|
||||
|
||||
const url = buildUrl();
|
||||
const totalHours = parseInt(config.timespan, 10);
|
||||
const chunkHours = 6; // Gracenote allows up to 6 hours per request
|
||||
const now = Math.floor(Date.now() / 1000); // Current time in UNIX timestamp
|
||||
const channelsMap: Map<string, Channel> = new Map();
|
||||
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
"User-Agent": config.userAgent || "",
|
||||
},
|
||||
});
|
||||
const fetchPromises: Promise<void>[] = [];
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Failed to fetch: ${response.status} ${response.statusText}`,
|
||||
);
|
||||
for (let offset = 0; offset < totalHours; offset += chunkHours) {
|
||||
const time = now + offset * 3600;
|
||||
const url = buildUrl(time, chunkHours);
|
||||
|
||||
const fetchPromise = fetch(url, {
|
||||
headers: {
|
||||
"User-Agent": config.userAgent || "",
|
||||
},
|
||||
}).then(async (response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Failed to fetch: ${response.status} ${response.statusText}`
|
||||
);
|
||||
}
|
||||
const chunkData = (await response.json()) as GridApiResponse;
|
||||
|
||||
for (const newChannel of chunkData.channels) {
|
||||
if (!channelsMap.has(newChannel.channelId)) {
|
||||
// Clone channel with its events
|
||||
channelsMap.set(newChannel.channelId, {
|
||||
...newChannel,
|
||||
events: [...newChannel.events],
|
||||
});
|
||||
} else {
|
||||
const existingChannel = channelsMap.get(newChannel.channelId)!;
|
||||
existingChannel.events.push(...newChannel.events);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
fetchPromises.push(fetchPromise);
|
||||
}
|
||||
|
||||
return (await response.json()) as GridApiResponse;
|
||||
await Promise.all(fetchPromises);
|
||||
|
||||
return { channels: Array.from(channelsMap.values()) };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user