feat: update rating, new, stereo, and cc
Based on https://github.com/jef/zap2xml/issues/47#issuecomment-3100061128 and https://github.com/jef/zap2xml/issues/47#issuecomment-3097884632
This commit is contained in:
@@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
|
||||
import type { GridApiResponse } from "./tvlistings.js";
|
||||
import {
|
||||
buildChannelsXml,
|
||||
buildProgrammesXml,
|
||||
buildProgramsXml,
|
||||
buildXmltv,
|
||||
escapeXml,
|
||||
formatDate,
|
||||
@@ -57,7 +57,9 @@ describe("buildXmltv", () => {
|
||||
it("should generate valid XML structure", () => {
|
||||
const result = buildXmltv(mockData);
|
||||
expect(result).toContain('<?xml version="1.0" encoding="UTF-8"?>');
|
||||
expect(result).toContain('<tv generator-info-name="zap2it-grid">');
|
||||
expect(result).toContain(
|
||||
'<tv generator-info-name="jef/zap2xml" generator-info-url="https://github.com/jef/zap2xml">',
|
||||
);
|
||||
expect(result).toContain("</tv>");
|
||||
});
|
||||
|
||||
@@ -85,14 +87,16 @@ describe("buildXmltv", () => {
|
||||
|
||||
it("should include rating information", () => {
|
||||
const result = buildXmltv(mockData);
|
||||
expect(result).toContain("<rating><value>TV-PG</value></rating>");
|
||||
expect(result).toContain(
|
||||
'<rating system="MPAA"><value>TV-PG</value></rating>',
|
||||
);
|
||||
});
|
||||
|
||||
it("should include categories from flags and tags", () => {
|
||||
const result = buildXmltv(mockData);
|
||||
expect(result).toContain("<category>New</category>");
|
||||
expect(result).toContain("<category>Stereo</category>");
|
||||
expect(result).toContain("<category>CC</category>");
|
||||
expect(result).toContain("<new />");
|
||||
expect(result).toContain('<audio type="stereo" />');
|
||||
expect(result).toContain('<audio type="cc" />');
|
||||
});
|
||||
|
||||
it("should include episode information", () => {
|
||||
@@ -108,7 +112,9 @@ describe("buildXmltv", () => {
|
||||
const emptyData: GridApiResponse = { channels: [] };
|
||||
const result = buildXmltv(emptyData);
|
||||
expect(result).toContain('<?xml version="1.0" encoding="UTF-8"?>');
|
||||
expect(result).toContain('<tv generator-info-name="zap2it-grid">');
|
||||
expect(result).toContain(
|
||||
'<tv generator-info-name="jef/zap2xml" generator-info-url="https://github.com/jef/zap2xml">',
|
||||
);
|
||||
expect(result).toContain("</tv>");
|
||||
expect(result).not.toContain("<channel");
|
||||
expect(result).not.toContain("<programme");
|
||||
@@ -252,9 +258,9 @@ describe("buildChannelsXml", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildProgrammesXml", () => {
|
||||
describe("buildProgramsXml", () => {
|
||||
it("should build programme XML correctly", () => {
|
||||
const result = buildProgrammesXml(mockData);
|
||||
const result = buildProgramsXml(mockData);
|
||||
expect(result).toContain(
|
||||
'<programme start="20250718190000 +0000" stop="20250718200000 +0000" channel="19629">',
|
||||
);
|
||||
@@ -263,16 +269,20 @@ describe("buildProgrammesXml", () => {
|
||||
expect(result).toContain(
|
||||
"<desc>BIA performs; comic Zarna Garg; lifestyle contributor Lori Bergamotto; ABC News chief medical correspondent Dr. Tara Narula.</desc>",
|
||||
);
|
||||
expect(result).toContain("<rating><value>TV-PG</value></rating>");
|
||||
expect(result).toContain("<category>New</category>");
|
||||
expect(result).toContain("<category>Stereo</category>");
|
||||
expect(result).toContain("<category>CC</category>");
|
||||
expect(result).toContain(
|
||||
'<rating system="MPAA"><value>TV-PG</value></rating>',
|
||||
);
|
||||
expect(result).toContain("<new />");
|
||||
expect(result).toContain('<audio type="stereo" />');
|
||||
expect(result).toContain('<audio type="cc" />');
|
||||
expect(result).toContain('<episode-num system="season">5</episode-num>');
|
||||
expect(result).toContain('<episode-num system="episode">217</episode-num>');
|
||||
expect(result).toContain(
|
||||
'<episode-num system="series">SH05918266</episode-num>',
|
||||
);
|
||||
expect(result).toContain('<icon src="p30687311_b_v13_aa" />');
|
||||
expect(result).toContain(
|
||||
'<icon src="https://zap2it.tmsimg.com/assets/p30687311_b_v13_aa.jpg" />',
|
||||
);
|
||||
});
|
||||
|
||||
it("should handle programmes without optional fields", () => {
|
||||
@@ -318,7 +328,7 @@ describe("buildProgrammesXml", () => {
|
||||
},
|
||||
],
|
||||
};
|
||||
const result = buildProgrammesXml(minimalProgramme);
|
||||
const result = buildProgramsXml(minimalProgramme);
|
||||
expect(result).toContain(
|
||||
'<programme start="20250718190000 +0000" stop="20250718193000 +0000" channel="123">',
|
||||
);
|
||||
|
||||
29
src/xmltv.ts
29
src/xmltv.ts
@@ -55,7 +55,7 @@ export function buildChannelsXml(data: GridApiResponse): string {
|
||||
return xml;
|
||||
}
|
||||
|
||||
export function buildProgrammesXml(data: GridApiResponse): string {
|
||||
export function buildProgramsXml(data: GridApiResponse): string {
|
||||
let xml = "";
|
||||
|
||||
for (const channel of data.channels) {
|
||||
@@ -79,20 +79,23 @@ export function buildProgrammesXml(data: GridApiResponse): string {
|
||||
}
|
||||
|
||||
if (event.rating) {
|
||||
xml += ` <rating><value>${escapeXml(
|
||||
xml += ` <rating system="MPAA"><value>${escapeXml(
|
||||
event.rating,
|
||||
)}</value></rating>\n`;
|
||||
}
|
||||
|
||||
if (event.flag && event.flag.length > 0) {
|
||||
for (const flag of event.flag) {
|
||||
xml += ` <category>${escapeXml(flag)}</category>\n`;
|
||||
if (event.flag.includes("New")) {
|
||||
xml += ` <new />\n`;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.tags && event.tags.length > 0) {
|
||||
for (const tag of event.tags) {
|
||||
xml += ` <category>${escapeXml(tag)}</category>\n`;
|
||||
if (event.tags.includes("Stereo")) {
|
||||
xml += ` <audio type="stereo" />\n`;
|
||||
}
|
||||
if (event.tags.includes("CC")) {
|
||||
xml += ` <audio type="cc" />\n`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +117,13 @@ export function buildProgrammesXml(data: GridApiResponse): string {
|
||||
)}</episode-num>\n`;
|
||||
}
|
||||
|
||||
// S01E01 and S11E22
|
||||
if (event.program.season && event.program.episode) {
|
||||
xml += ` <episode-num system="onscreen">${escapeXml(
|
||||
`S${event.program.season.padStart(2, "0")}E${event.program.episode.padStart(2, "0")}`,
|
||||
)}</episode-num>\n`;
|
||||
}
|
||||
|
||||
if (event.thumbnail) {
|
||||
const src = event.thumbnail.startsWith("http")
|
||||
? event.thumbnail
|
||||
@@ -131,10 +141,11 @@ export function buildProgrammesXml(data: GridApiResponse): string {
|
||||
export function buildXmltv(data: GridApiResponse): string {
|
||||
console.log("Building XMLTV file");
|
||||
|
||||
let xml =
|
||||
'<?xml version="1.0" encoding="UTF-8"?>\n<tv generator-info-name="zap2it-grid">\n';
|
||||
let xml = '<?xml version="1.0" encoding="UTF-8"?>\n';
|
||||
xml +=
|
||||
'<tv generator-info-name="jef/zap2xml" generator-info-url="https://github.com/jef/zap2xml">\n';
|
||||
xml += buildChannelsXml(data);
|
||||
xml += buildProgrammesXml(data);
|
||||
xml += buildProgramsXml(data);
|
||||
xml += "</tv>\n";
|
||||
|
||||
return xml;
|
||||
|
||||
Reference in New Issue
Block a user