use new channel identifiers in M3U and XMLTV to disambiguate in Plex (#1920)

This commit is contained in:
Jason Dove
2024-10-16 09:37:33 -05:00
committed by GitHub
parent 5d0f40978d
commit c063720169
12 changed files with 104 additions and 17 deletions
+3
View File
@@ -4,6 +4,9 @@ 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]
### Changed
- **BREAKING CHANGE**: Change channel identifiers used in XMLTV to work around bad behavior in Plex
### Fixed
- Fix startup error with MySql backend caused by database cleaner
- Fix emptying trash with ElasticSearch backend
@@ -7,6 +7,7 @@ using ErsatzTV.Core.Domain.Filler;
using ErsatzTV.Core.Emby;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Iptv;
using ErsatzTV.Core.Jellyfin;
using ErsatzTV.Core.Streaming;
using ErsatzTV.Infrastructure.Data;
@@ -514,6 +515,8 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData>
{
ProgrammeStart = start,
ProgrammeStop = stop,
ChannelId = ChannelIdentifier.FromNumber(request.ChannelNumber),
ChannelIdLegacy = ChannelIdentifier.LegacyFromNumber(request.ChannelNumber),
request.ChannelNumber,
HasCustomTitle = hasCustomTitle,
displayItem.CustomTitle,
@@ -569,6 +572,8 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData>
{
ProgrammeStart = start,
ProgrammeStop = stop,
ChannelId = ChannelIdentifier.FromNumber(request.ChannelNumber),
ChannelIdLegacy = ChannelIdentifier.LegacyFromNumber(request.ChannelNumber),
request.ChannelNumber,
HasCustomTitle = hasCustomTitle,
displayItem.CustomTitle,
@@ -629,6 +634,8 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData>
{
ProgrammeStart = start,
ProgrammeStop = stop,
ChannelId = ChannelIdentifier.FromNumber(request.ChannelNumber),
ChannelIdLegacy = ChannelIdentifier.LegacyFromNumber(request.ChannelNumber),
request.ChannelNumber,
HasCustomTitle = hasCustomTitle,
displayItem.CustomTitle,
@@ -686,6 +693,8 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData>
{
ProgrammeStart = start,
ProgrammeStop = stop,
ChannelId = ChannelIdentifier.FromNumber(request.ChannelNumber),
ChannelIdLegacy = ChannelIdentifier.LegacyFromNumber(request.ChannelNumber),
request.ChannelNumber,
HasCustomTitle = hasCustomTitle,
displayItem.CustomTitle,
@@ -738,6 +747,8 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData>
{
ProgrammeStart = start,
ProgrammeStop = stop,
ChannelId = ChannelIdentifier.FromNumber(request.ChannelNumber),
ChannelIdLegacy = ChannelIdentifier.LegacyFromNumber(request.ChannelNumber),
request.ChannelNumber,
HasCustomTitle = hasCustomTitle,
displayItem.CustomTitle,
@@ -4,6 +4,7 @@ using System.Xml;
using Dapper;
using ErsatzTV.Core;
using ErsatzTV.Core.Interfaces.Metadata;
using ErsatzTV.Core.Iptv;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
@@ -78,6 +79,8 @@ public class RefreshChannelListHandler : IRequestHandler<RefreshChannelList>
{
var data = new
{
ChannelId = ChannelIdentifier.FromNumber(channel.Number),
ChannelIdLegacy = ChannelIdentifier.LegacyFromNumber(channel.Number),
ChannelNumber = channel.Number,
ChannelName = channel.Name,
ChannelCategories = GetCategories(channel.Categories),
@@ -0,0 +1,33 @@
using ErsatzTV.Core.Iptv;
using FluentAssertions;
using NUnit.Framework;
namespace ErsatzTV.Core.Tests.Iptv;
[TestFixture]
public class ChannelIdentifierTests
{
[TestCase("1.23", "1.23.etv")]
[TestCase("12.3", "12.3.etv")]
[TestCase("123", "123.etv")]
[TestCase("1.24", "1.24.etv")]
[TestCase("12.4", "12.4.etv")]
[TestCase("124", "124.etv")]
public void TestLegacy(string channelNumber, string expected)
{
string actual = ChannelIdentifier.LegacyFromNumber(channelNumber);
actual.Should().Be(expected);
}
[TestCase("1.23", "C1.23.150.ersatztv.org")]
[TestCase("12.3", "C12.3.198.ersatztv.org")]
[TestCase("123", "C123.246.ersatztv.org")]
[TestCase("1.24", "C1.24.151.ersatztv.org")]
[TestCase("12.4", "C12.4.199.ersatztv.org")]
[TestCase("124", "C124.247.ersatztv.org")]
public void TestNew(string channelNumber, string expected)
{
string actual = ChannelIdentifier.FromNumber(channelNumber);
actual.Should().Be(expected);
}
}
+25
View File
@@ -0,0 +1,25 @@
using System.Globalization;
namespace ErsatzTV.Core.Iptv;
public static class ChannelIdentifier
{
public static string LegacyFromNumber(string channelNumber)
{
return $"{channelNumber}.etv";
}
public static string FromNumber(string channelNumber)
{
// get rid of any decimal (only two are allowed)
int number = (int)(decimal.Parse(channelNumber, CultureInfo.InvariantCulture) * 100);
int id = 0;
while (number != 0)
{
id += number % 10 + 48;
number /= 10;
}
return $"C{channelNumber}.{id}.ersatztv.org";
}
}
+1 -1
View File
@@ -86,7 +86,7 @@ public class ChannelPlaylist
sb.AppendLine(
CultureInfo.InvariantCulture,
$"#EXTINF:0 tvg-id=\"{channel.Number}.etv\" channel-id=\"{shortUniqueId}\" channel-number=\"{channel.Number}\" CUID=\"{shortUniqueId}\" tvg-chno=\"{channel.Number}\" tvg-name=\"{channel.Name}\" tvg-logo=\"{logo}\" group-title=\"{channel.Group}\" tvc-stream-vcodec=\"{vcodec}\" tvc-stream-acodec=\"{acodec}\", {channel.Name}");
$"#EXTINF:0 tvg-id=\"{ChannelIdentifier.FromNumber(channel.Number)}\" channel-id=\"{shortUniqueId}\" channel-number=\"{channel.Number}\" CUID=\"{shortUniqueId}\" tvg-chno=\"{channel.Number}\" tvg-name=\"{channel.Name}\" tvg-logo=\"{logo}\" group-title=\"{channel.Group}\" tvc-stream-vcodec=\"{vcodec}\" tvc-stream-acodec=\"{acodec}\", {channel.Name}");
sb.AppendLine(
CultureInfo.InvariantCulture,
$"{_scheme}://{_host}{_baseUrl}/iptv/channel/{channel.Number}.{format}");
+3 -1
View File
@@ -1,6 +1,8 @@
{{ ##
Available values:
- channel_id
- channel_id_legacy
- channel_number
- channel_name
- channel_categories
@@ -16,7 +18,7 @@ The resulting XML will be minified by ErsatzTV - so feel free to keep things nic
## }}
<channel id="{{ channel_number }}.etv">
<channel id="{{ channel_id }}">
<display-name>{{ channel_number }} {{ channel_name }}</display-name>
<display-name>{{ channel_number }}</display-name>
<display-name>{{ channel_name }}</display-name>
+3 -1
View File
@@ -3,6 +3,8 @@
Available values:
- programme_start
- programme_stop
- channel_id
- channel_id_legacy
- channel_number
- has_custom_title
- custom_title
@@ -27,7 +29,7 @@ The resulting XML will be minified by ErsatzTV - so feel free to keep things nic
## }}
<programme start="{{ programme_start }}" stop="{{ programme_stop }}" channel="{{ channel_number }}.etv">
<programme start="{{ programme_start }}" stop="{{ programme_stop }}" channel="{{ channel_id }}">
{{ if has_custom_title }}
<title lang="en">{{ custom_title }}</title>
{{ else }}
+3 -1
View File
@@ -3,6 +3,8 @@
Available values:
- programme_start
- programme_stop
- channel_id
- channel_id_legacy
- channel_number
- has_custom_title
- custom_title
@@ -22,7 +24,7 @@ The resulting XML will be minified by ErsatzTV - so feel free to keep things nic
## }}
<programme start="{{ programme_start }}" stop="{{ programme_stop }}" channel="{{ channel_number }}.etv">
<programme start="{{ programme_start }}" stop="{{ programme_stop }}" channel="{{ channel_id }}">
{{ if has_custom_title }}
<title lang="en">{{ custom_title }}</title>
{{ else }}
@@ -3,6 +3,8 @@
Available values:
- programme_start
- programme_stop
- channel_id
- channel_id_legacy
- channel_number
- has_custom_title
- custom_title
@@ -30,7 +32,7 @@ The resulting XML will be minified by ErsatzTV - so feel free to keep things nic
## }}
<programme start="{{ programme_start }}" stop="{{ programme_stop }}" channel="{{ channel_number }}.etv">
<programme start="{{ programme_start }}" stop="{{ programme_stop }}" channel="{{ channel_id }}">
{{ if has_custom_title }}
<title lang="en">{{ custom_title }}</title>
{{ else }}
@@ -3,6 +3,8 @@
Available values:
- programme_start
- programme_stop
- channel_id
- channel_id_legacy
- channel_number
- has_custom_title
- custom_title
@@ -19,7 +21,7 @@ The resulting XML will be minified by ErsatzTV - so feel free to keep things nic
## }}
<programme start="{{ programme_start }}" stop="{{ programme_stop }}" channel="{{ channel_number }}.etv">
<programme start="{{ programme_start }}" stop="{{ programme_stop }}" channel="{{ channel_id }}">
{{ if has_custom_title }}
<title lang="en">{{ custom_title }}</title>
{{ else }}
+3 -1
View File
@@ -3,6 +3,8 @@
Available values:
- programme_start
- programme_stop
- channel_id
- channel_id_legacy
- channel_number
- has_custom_title
- custom_title
@@ -28,7 +30,7 @@ The resulting XML will be minified by ErsatzTV - so feel free to keep things nic
## }}
<programme start="{{ programme_start }}" stop="{{ programme_stop }}" channel="{{ channel_number }}.etv">
<programme start="{{ programme_start }}" stop="{{ programme_stop }}" channel="{{ channel_id }}">
{{ if has_custom_title }}
<title lang="en">{{ custom_title }}</title>
{{ else }}