Skip to content

Commit e077f27

Browse files
committed
feat: update rating, new, stereo, and cc
Based on #47 (comment) and #47 (comment)
1 parent 3ab0370 commit e077f27

File tree

2 files changed

+45
-24
lines changed

2 files changed

+45
-24
lines changed

src/xmltv.test.ts

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
22
import type { GridApiResponse } from "./tvlistings.js";
33
import {
44
buildChannelsXml,
5-
buildProgrammesXml,
5+
buildProgramsXml,
66
buildXmltv,
77
escapeXml,
88
formatDate,
@@ -57,7 +57,9 @@ describe("buildXmltv", () => {
5757
it("should generate valid XML structure", () => {
5858
const result = buildXmltv(mockData);
5959
expect(result).toContain('<?xml version="1.0" encoding="UTF-8"?>');
60-
expect(result).toContain('<tv generator-info-name="zap2it-grid">');
60+
expect(result).toContain(
61+
'<tv generator-info-name="jef/zap2xml" generator-info-url="https://github.com/jef/zap2xml">',
62+
);
6163
expect(result).toContain("</tv>");
6264
});
6365

@@ -85,14 +87,16 @@ describe("buildXmltv", () => {
8587

8688
it("should include rating information", () => {
8789
const result = buildXmltv(mockData);
88-
expect(result).toContain("<rating><value>TV-PG</value></rating>");
90+
expect(result).toContain(
91+
'<rating system="MPAA"><value>TV-PG</value></rating>',
92+
);
8993
});
9094

9195
it("should include categories from flags and tags", () => {
9296
const result = buildXmltv(mockData);
93-
expect(result).toContain("<category>New</category>");
94-
expect(result).toContain("<category>Stereo</category>");
95-
expect(result).toContain("<category>CC</category>");
97+
expect(result).toContain("<new />");
98+
expect(result).toContain('<audio type="stereo" />');
99+
expect(result).toContain('<audio type="cc" />');
96100
});
97101

98102
it("should include episode information", () => {
@@ -108,7 +112,9 @@ describe("buildXmltv", () => {
108112
const emptyData: GridApiResponse = { channels: [] };
109113
const result = buildXmltv(emptyData);
110114
expect(result).toContain('<?xml version="1.0" encoding="UTF-8"?>');
111-
expect(result).toContain('<tv generator-info-name="zap2it-grid">');
115+
expect(result).toContain(
116+
'<tv generator-info-name="jef/zap2xml" generator-info-url="https://github.com/jef/zap2xml">',
117+
);
112118
expect(result).toContain("</tv>");
113119
expect(result).not.toContain("<channel");
114120
expect(result).not.toContain("<programme");
@@ -252,9 +258,9 @@ describe("buildChannelsXml", () => {
252258
});
253259
});
254260

255-
describe("buildProgrammesXml", () => {
261+
describe("buildProgramsXml", () => {
256262
it("should build programme XML correctly", () => {
257-
const result = buildProgrammesXml(mockData);
263+
const result = buildProgramsXml(mockData);
258264
expect(result).toContain(
259265
'<programme start="20250718190000 +0000" stop="20250718200000 +0000" channel="19629">',
260266
);
@@ -263,16 +269,20 @@ describe("buildProgrammesXml", () => {
263269
expect(result).toContain(
264270
"<desc>BIA performs; comic Zarna Garg; lifestyle contributor Lori Bergamotto; ABC News chief medical correspondent Dr. Tara Narula.</desc>",
265271
);
266-
expect(result).toContain("<rating><value>TV-PG</value></rating>");
267-
expect(result).toContain("<category>New</category>");
268-
expect(result).toContain("<category>Stereo</category>");
269-
expect(result).toContain("<category>CC</category>");
272+
expect(result).toContain(
273+
'<rating system="MPAA"><value>TV-PG</value></rating>',
274+
);
275+
expect(result).toContain("<new />");
276+
expect(result).toContain('<audio type="stereo" />');
277+
expect(result).toContain('<audio type="cc" />');
270278
expect(result).toContain('<episode-num system="season">5</episode-num>');
271279
expect(result).toContain('<episode-num system="episode">217</episode-num>');
272280
expect(result).toContain(
273281
'<episode-num system="series">SH05918266</episode-num>',
274282
);
275-
expect(result).toContain('<icon src="p30687311_b_v13_aa" />');
283+
expect(result).toContain(
284+
'<icon src="https://zap2it.tmsimg.com/assets/p30687311_b_v13_aa.jpg" />',
285+
);
276286
});
277287

278288
it("should handle programmes without optional fields", () => {
@@ -318,7 +328,7 @@ describe("buildProgrammesXml", () => {
318328
},
319329
],
320330
};
321-
const result = buildProgrammesXml(minimalProgramme);
331+
const result = buildProgramsXml(minimalProgramme);
322332
expect(result).toContain(
323333
'<programme start="20250718190000 +0000" stop="20250718193000 +0000" channel="123">',
324334
);

src/xmltv.ts

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export function buildChannelsXml(data: GridApiResponse): string {
5555
return xml;
5656
}
5757

58-
export function buildProgrammesXml(data: GridApiResponse): string {
58+
export function buildProgramsXml(data: GridApiResponse): string {
5959
let xml = "";
6060

6161
for (const channel of data.channels) {
@@ -79,20 +79,23 @@ export function buildProgrammesXml(data: GridApiResponse): string {
7979
}
8080

8181
if (event.rating) {
82-
xml += ` <rating><value>${escapeXml(
82+
xml += ` <rating system="MPAA"><value>${escapeXml(
8383
event.rating,
8484
)}</value></rating>\n`;
8585
}
8686

8787
if (event.flag && event.flag.length > 0) {
88-
for (const flag of event.flag) {
89-
xml += ` <category>${escapeXml(flag)}</category>\n`;
88+
if (event.flag.includes("New")) {
89+
xml += ` <new />\n`;
9090
}
9191
}
9292

9393
if (event.tags && event.tags.length > 0) {
94-
for (const tag of event.tags) {
95-
xml += ` <category>${escapeXml(tag)}</category>\n`;
94+
if (event.tags.includes("Stereo")) {
95+
xml += ` <audio type="stereo" />\n`;
96+
}
97+
if (event.tags.includes("CC")) {
98+
xml += ` <audio type="cc" />\n`;
9699
}
97100
}
98101

@@ -114,6 +117,13 @@ export function buildProgrammesXml(data: GridApiResponse): string {
114117
)}</episode-num>\n`;
115118
}
116119

120+
// S01E01 and S11E22
121+
if (event.program.season && event.program.episode) {
122+
xml += ` <episode-num system="onscreen">${escapeXml(
123+
`S${event.program.season.padStart(2, "0")}E${event.program.episode.padStart(2, "0")}`,
124+
)}</episode-num>\n`;
125+
}
126+
117127
if (event.thumbnail) {
118128
const src = event.thumbnail.startsWith("http")
119129
? event.thumbnail
@@ -131,10 +141,11 @@ export function buildProgrammesXml(data: GridApiResponse): string {
131141
export function buildXmltv(data: GridApiResponse): string {
132142
console.log("Building XMLTV file");
133143

134-
let xml =
135-
'<?xml version="1.0" encoding="UTF-8"?>\n<tv generator-info-name="zap2it-grid">\n';
144+
let xml = '<?xml version="1.0" encoding="UTF-8"?>\n';
145+
xml +=
146+
'<tv generator-info-name="jef/zap2xml" generator-info-url="https://github.com/jef/zap2xml">\n';
136147
xml += buildChannelsXml(data);
137-
xml += buildProgrammesXml(data);
148+
xml += buildProgramsXml(data);
138149
xml += "</tv>\n";
139150

140151
return xml;

0 commit comments

Comments
 (0)