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