Refactor IptvEndpoints to improve XML generation and encoding handling
ci / build-backend (push) Successful in 1m20s
ci / build-frontend (push) Successful in 39s
ci / tests (push) Successful in 1m21s
ci / sonar (push) Successful in 3m46s

Updated the RenderGuide method to return a byte array instead of a string, enhancing performance and ensuring proper UTF-8 encoding without a BOM. Adjusted the XML writing process to use a MemoryStream for direct byte output, improving compatibility with XMLTV parsers. This change streamlines the generation of the EPG XML file and ensures accurate encoding in the response.
This commit is contained in:
Leonid Pershin
2026-08-02 13:18:55 +03:00
parent cbeee92d26
commit 89b68a26e7
@@ -82,8 +82,8 @@ public static class IptvEndpoints
);
return Results.File(
Encoding.UTF8.GetBytes(RenderGuide(channels, Origin(request))),
"application/xml",
RenderGuide(channels, Origin(request)),
"application/xml; charset=utf-8",
fileDownloadName: "telewave-epg.xml"
);
}
@@ -137,35 +137,45 @@ public static class IptvEndpoints
private static string Attribute(string value) =>
value.Replace("\"", string.Empty).ReplaceLineEndings(" ").Trim();
private static string RenderGuide(IReadOnlyList<IptvChannelDto> channels, string origin)
private static byte[] RenderGuide(IReadOnlyList<IptvChannelDto> channels, string origin)
{
var output = new StringBuilder();
using var output = new MemoryStream();
// Пишем сразу в поток в UTF-8, а не в StringBuilder: XmlWriter поверх строки объявил бы
// encoding="utf-16" (строки .NET — UTF-16), тогда как байты мы всё равно отдаём в UTF-8.
// Часть плееров (Go encoding/xml) отвергает такое расхождение декларации и реальных байт.
// BOM не пишем: XMLTV его не ждёт, и он мешает строгим парсерам.
// Через XmlWriter, а не склейкой строк: в названия и описания приходит текст из библиотеки,
// и экранировать его руками — верный способ однажды отдать битый XML.
using var writer = XmlWriter.Create(
output,
new XmlWriterSettings { Indent = true, Encoding = Encoding.UTF8 }
);
writer.WriteStartDocument();
writer.WriteStartElement("tv");
writer.WriteAttributeString("generator-info-name", "TeleWave");
// Сначала все каналы, потом все передачи: XMLTV требует именно такого порядка секций.
foreach (var channel in channels)
WriteChannel(writer, channel, origin);
foreach (var channel in channels)
using (
var writer = XmlWriter.Create(
output,
new XmlWriterSettings
{
Indent = true,
Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false),
}
)
)
{
foreach (var programme in channel.Programmes)
WriteProgramme(writer, channel.Slug, programme, origin);
writer.WriteStartDocument();
writer.WriteStartElement("tv");
writer.WriteAttributeString("generator-info-name", "TeleWave");
// Сначала все каналы, потом все передачи: XMLTV требует именно такого порядка секций.
foreach (var channel in channels)
WriteChannel(writer, channel, origin);
foreach (var channel in channels)
{
foreach (var programme in channel.Programmes)
WriteProgramme(writer, channel.Slug, programme, origin);
}
writer.WriteEndElement();
writer.WriteEndDocument();
}
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Flush();
return output.ToString();
return output.ToArray();
}
private static void WriteChannel(XmlWriter writer, IptvChannelDto channel, string origin)