Skip to content

Commit 3de1db4

Browse files
committed
Fixed "dd_progid" tag
1 parent 0089561 commit 3de1db4

File tree

2 files changed

+21
-25
lines changed

2 files changed

+21
-25
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ I also *somewhat* maintain a version of the original in the [historical-perl bra
1212

1313
# (2025-08-09)
1414

15+
* Restored `<episode-num system="dd_progid">` tag that Plex uses that was missing.
1516
* Fixed Sorting so output is listed by Channel ID (common station/gracenote id) then by date/time.
1617

1718
# (2025-08-07)

src/xmltv.ts

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ cli
3737
cli.parse(process.argv);
3838
const options = cli.opts() as { [key: string]: any };
3939

40+
// Helper to mimic Perl dd_progid emission: (..########)(####) -> XX########.####
41+
function toDdProgid(rawId: string | undefined | null): string | null {
42+
if (!rawId) return null;
43+
const m = rawId.match(/^(.{2}\d{8})(\d{4})$/);
44+
return m ? `${m[1]}.${m[2]}` : null;
45+
}
46+
4047
export function buildChannelsXml(data: GridApiResponse): string {
4148
let xml = "";
4249

@@ -156,29 +163,26 @@ export function buildProgramsXml(data: GridApiResponse): string {
156163
xml += ` <icon src="${escapeXml(src)}" />\n`;
157164
}
158165

159-
// Optional series link
160-
if (event.program.seriesId && event.program.tmsId) {
161-
const encodedUrl = `https://tvlistings.gracenote.com//overview.html?programSeriesId=${event.program.seriesId}&amp;tmsId=${event.program.tmsId}`;
166+
if (event.program.seriesId && (event.program as any).tmsId) {
167+
const encodedUrl = `https://tvlistings.gracenote.com//overview.html?programSeriesId=${event.program.seriesId}&amp;tmsId=${(event.program as any).tmsId}`;
162168
xml += ` <url>${encodedUrl}</url>\n`;
163169
}
164170

165171
const skipXmltvNs = genreSet.has("movie") || genreSet.has("sports");
166172
const episodeNumTags: string[] = [];
167173

174+
// ---- dd_progid (Perl behavior) — compute once, independent of season/episode presence
175+
const ddProgid = toDdProgid(event.program.id);
176+
if (ddProgid) {
177+
episodeNumTags.push(` <episode-num system="dd_progid">${escapeXml(ddProgid)}</episode-num>\n`);
178+
}
179+
// ----------------------------------------------------------------------
180+
168181
if (event.program.season && event.program.episode && !skipXmltvNs) {
169-
const onscreen = `S${event.program.season.padStart(2, "0")}E${event.program.episode.padStart(
170-
2,
171-
"0"
172-
)}`;
182+
const onscreen = `S${event.program.season.padStart(2, "0")}E${event.program.episode.padStart(2, "0")}`;
173183
episodeNumTags.push(` <episode-num system="onscreen">${escapeXml(onscreen)}</episode-num>\n`);
174184
episodeNumTags.push(` <episode-num system="common">${escapeXml(onscreen)}</episode-num>\n`);
175185

176-
if (/\.\d{8}\d{4}/.test(event.program.id)) {
177-
episodeNumTags.push(
178-
` <episode-num system="dd_progid">${escapeXml(event.program.id)}</episode-num>\n`
179-
);
180-
}
181-
182186
const seasonNum = parseInt(event.program.season, 10);
183187
const episodeNum = parseInt(event.program.episode, 10);
184188
if (!isNaN(seasonNum) && !isNaN(episodeNum) && seasonNum >= 1 && episodeNum >= 1) {
@@ -208,13 +212,7 @@ export function buildProgramsXml(data: GridApiResponse): string {
208212
}
209213
}
210214
} else if (!event.program.episode && event.program.id) {
211-
const match = event.program.id.match(/^(.\d{8})(\d{4})/);
212-
if (match) {
213-
episodeNumTags.push(
214-
` <episode-num system="dd_progid">${match[1]}.${match[2]}</episode-num>\n`
215-
);
216-
}
217-
215+
// No season/episode — xmltv_ns based on MMDD (only if not movie/sports)
218216
const nyFormatter = new Intl.DateTimeFormat("en-US", {
219217
timeZone: "America/New_York",
220218
year: "numeric",
@@ -241,9 +239,7 @@ export function buildProgramsXml(data: GridApiResponse): string {
241239
xml += episodeNumTags.join("");
242240

243241
if (event.program.originalAirDate || event.program.episodeAirDate) {
244-
const airDate = new Date(
245-
event.program.episodeAirDate || event.program.originalAirDate || ""
246-
);
242+
const airDate = new Date(event.program.episodeAirDate || event.program.originalAirDate || "");
247243
if (!isNaN(airDate.getTime())) {
248244
xml += ` <episode-num system="original-air-date">${airDate
249245
.toISOString()
@@ -290,8 +286,7 @@ export function buildXmltv(data: GridApiResponse): string {
290286
console.log("Building XMLTV file");
291287

292288
let xml = '<?xml version="1.0" encoding="UTF-8"?>\n';
293-
xml +=
294-
'<tv generator-info-name="jef/zap2xml" generator-info-url="https://github.com/jef/zap2xml">\n';
289+
xml += '<tv generator-info-name="jef/zap2xml" generator-info-url="https://github.com/jef/zap2xml">\n';
295290
xml += buildChannelsXml(data);
296291
xml += buildProgramsXml(data);
297292
xml += "</tv>\n";

0 commit comments

Comments
 (0)