Browse Source

generate valid xmltv (#351)

pull/353/head
Jason Dove 5 years ago committed by GitHub
parent
commit
77308a9ac5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      CHANGELOG.md
  2. 123
      ErsatzTV.Core/Iptv/ChannelGuide.cs

5
CHANGELOG.md

@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]
### Fixed
- Generate XMLTV that validates successfully
- Properly order elements
- Omit channels with no programmes
- Properly identify channels using the format number.etv like `15.etv`
## [0.0.55-alpha] - 2021-09-03
### Fixed

123
ErsatzTV.Core/Iptv/ChannelGuide.cs

@ -36,32 +36,39 @@ namespace ErsatzTV.Core.Iptv @@ -36,32 +36,39 @@ namespace ErsatzTV.Core.Iptv
xml.WriteStartElement("tv");
xml.WriteAttributeString("generator-info-name", "ersatztv");
var sortedChannelItems = new Dictionary<Channel, List<PlayoutItem>>();
foreach (Channel channel in _channels.OrderBy(c => decimal.Parse(c.Number)))
{
xml.WriteStartElement("channel");
xml.WriteAttributeString("id", channel.Number);
xml.WriteStartElement("display-name");
xml.WriteAttributeString("lang", "en");
xml.WriteString(channel.Name);
xml.WriteEndElement(); // display-name
xml.WriteStartElement("icon");
string logo = Optional(channel.Artwork).Flatten()
.Filter(a => a.ArtworkKind == ArtworkKind.Logo)
.HeadOrNone()
.Match(
artwork => $"{_scheme}://{_host}/iptv/logos/{artwork.Path}",
() => $"{_scheme}://{_host}/iptv/images/ersatztv-500.png");
xml.WriteAttributeString("src", logo);
xml.WriteEndElement(); // icon
xml.WriteEndElement(); // channel
var sortedItems = channel.Playouts.Collect(p => p.Items).OrderBy(x => x.Start).ToList();
sortedChannelItems.Add(channel, sortedItems);
if (sortedItems.Any())
{
xml.WriteStartElement("channel");
xml.WriteAttributeString("id", $"{channel.Number}.etv");
xml.WriteStartElement("display-name");
xml.WriteAttributeString("lang", "en");
xml.WriteString(channel.Name);
xml.WriteEndElement(); // display-name
xml.WriteStartElement("icon");
string logo = Optional(channel.Artwork).Flatten()
.Filter(a => a.ArtworkKind == ArtworkKind.Logo)
.HeadOrNone()
.Match(
artwork => $"{_scheme}://{_host}/iptv/logos/{artwork.Path}",
() => $"{_scheme}://{_host}/iptv/images/ersatztv-500.png");
xml.WriteAttributeString("src", logo);
xml.WriteEndElement(); // icon
xml.WriteEndElement(); // channel
}
}
foreach (Channel channel in _channels.OrderBy(c => c.Number))
foreach ((Channel channel, List<PlayoutItem> sorted) in sortedChannelItems.OrderBy(kvp => kvp.Key.Number))
{
var sorted = channel.Playouts.Collect(p => p.Items).OrderBy(x => x.Start).ToList();
var i = 0;
while (i < sorted.Count)
{
@ -90,7 +97,9 @@ namespace ErsatzTV.Core.Iptv @@ -90,7 +97,9 @@ namespace ErsatzTV.Core.Iptv
PlayoutItem finishItem = sorted[finishIndex];
i = finishIndex;
// ReSharper disable once StringLiteralTypo
string start = startItem.StartOffset.ToString("yyyyMMddHHmmss zzz").Replace(":", string.Empty);
// ReSharper disable once StringLiteralTypo
string stop = finishItem.FinishOffset.ToString("yyyyMMddHHmmss zzz").Replace(":", string.Empty);
string title = GetTitle(startItem);
@ -101,27 +110,51 @@ namespace ErsatzTV.Core.Iptv @@ -101,27 +110,51 @@ namespace ErsatzTV.Core.Iptv
xml.WriteStartElement("programme");
xml.WriteAttributeString("start", start);
xml.WriteAttributeString("stop", stop);
xml.WriteAttributeString("channel", channel.Number);
xml.WriteAttributeString("channel", $"{channel.Number}.etv");
xml.WriteStartElement("title");
xml.WriteAttributeString("lang", "en");
xml.WriteString(title);
xml.WriteEndElement(); // title
if (!hasCustomTitle && startItem.MediaItem is Movie movie)
if (!string.IsNullOrWhiteSpace(subtitle))
{
xml.WriteStartElement("category");
xml.WriteStartElement("sub-title");
xml.WriteAttributeString("lang", "en");
xml.WriteString("Movie");
xml.WriteEndElement(); // category
Option<MovieMetadata> maybeMetadata = movie.MovieMetadata.HeadOrNone();
if (maybeMetadata.IsSome)
xml.WriteString(subtitle);
xml.WriteEndElement(); // subtitle
}
if (!isSameCustomShow)
{
if (!string.IsNullOrWhiteSpace(description))
{
MovieMetadata metadata = maybeMetadata.ValueUnsafe();
xml.WriteStartElement("desc");
xml.WriteAttributeString("lang", "en");
xml.WriteString(description);
xml.WriteEndElement(); // desc
}
}
if (!hasCustomTitle && startItem.MediaItem is Movie movie)
{
foreach (MovieMetadata metadata in movie.MovieMetadata.HeadOrNone())
{
if (metadata.Year.HasValue)
{
xml.WriteStartElement("date");
xml.WriteString(metadata.Year.Value.ToString());
xml.WriteEndElement(); // date
}
}
xml.WriteStartElement("category");
xml.WriteAttributeString("lang", "en");
xml.WriteString("Movie");
xml.WriteEndElement(); // category
foreach (MovieMetadata metadata in movie.MovieMetadata.HeadOrNone())
{
string poster = Optional(metadata.Artwork).Flatten()
.Filter(a => a.ArtworkKind == ArtworkKind.Poster)
.HeadOrNone()
@ -136,22 +169,6 @@ namespace ErsatzTV.Core.Iptv @@ -136,22 +169,6 @@ namespace ErsatzTV.Core.Iptv
}
}
xml.WriteStartElement("title");
xml.WriteAttributeString("lang", "en");
xml.WriteString(title);
xml.WriteEndElement(); // title
if (!string.IsNullOrWhiteSpace(subtitle))
{
xml.WriteStartElement("sub-title");
xml.WriteAttributeString("lang", "en");
xml.WriteString(subtitle);
xml.WriteEndElement(); // subtitle
}
xml.WriteStartElement("previously-shown");
xml.WriteEndElement(); // previously-shown
if (startItem.MediaItem is Episode episode && (!hasCustomTitle || isSameCustomShow))
{
Option<ShowMetadata> maybeMetadata =
@ -200,17 +217,9 @@ namespace ErsatzTV.Core.Iptv @@ -200,17 +217,9 @@ namespace ErsatzTV.Core.Iptv
}
}
}
if (!isSameCustomShow)
{
if (!string.IsNullOrWhiteSpace(description))
{
xml.WriteStartElement("desc");
xml.WriteAttributeString("lang", "en");
xml.WriteString(description);
xml.WriteEndElement(); // desc
}
}
xml.WriteStartElement("previously-shown");
xml.WriteEndElement(); // previously-shown
foreach (ContentRating rating in contentRating)
{

Loading…
Cancel
Save