Skip to content

Commit

Permalink
Merge pull request #51 from hmlendea/dev
Browse files Browse the repository at this point in the history
Country tags and country-based channel matching
  • Loading branch information
hmlendea authored Oct 17, 2020
2 parents 12774ab + c5d04bb commit e42d5d0
Show file tree
Hide file tree
Showing 17 changed files with 680 additions and 52 deletions.
422 changes: 420 additions & 2 deletions Data/channels.xml

Large diffs are not rendered by default.

111 changes: 103 additions & 8 deletions Data/providers.xml

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions DataAccess/DataObjects/ChannelDefinitionEntity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public sealed class ChannelDefinitionEntity : EntityBase

public string Name { get; set; }

public string Country { get; set; }

public string GroupId { get; set; }

public string LogoUrl { get; set; }
Expand Down
5 changes: 4 additions & 1 deletion DataAccess/DataObjects/PlaylistProviderEntity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,20 @@ public class PlaylistProviderEntity : EntityBase

public int Priority { get; set; }

public bool DontCache { get; set; }
public bool AllowCaching { get; set; }

public string Name { get; set; }

public string UrlFormat { get; set; }

public string Country { get; set; }

public string ChannelNameOverride { get; set; }

public PlaylistProviderEntity()
{
Priority = int.MaxValue;
AllowCaching = true;
}
}
}
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ ChannelDefinitionEntity fields:
- *Id* (string): The TVG ID. If using a TVG provider within your IPTV application, make sure the channel IDs match the TVG IDs of your provider.
- *IsEnabled* (bool): Indicates whether the final playlist will contain this channel or not. Even if enabled, if the group is disabled, the channel will still be omitted.
- *Name* (string): The name of the channel, as displayed in your IPTV application.
- *Country* (string): (Optional) The country where the channel is being broadcasted. The `tvg-country` property will be populated with this value, if it exists. It will also be used uin the channel matching process.
- *GroupId* (string): The ID of the group that this channel will be part of.
- *LogoUrl* (string): The URL to a logo for the channel. Make sure your IPTV application supports the logo format you provide here.
- *Aliases* (string collection): Different variants of the name of the channel, as it can appear in the provider playlists. This is the criteria used to match provider channels to this definition.
Expand All @@ -129,6 +130,7 @@ PlaylistProviderDefinitionEntity fields:
- *Id* (string): The ID of the provider. You can put anything here, used only to distinguish between them.
- *IsEnabled* (bool): Indicates whether this provider will be used or not.
- *Priority* (int): The lower the value, the sooner the provider will be processed. Try to make sure the most reliable providers are processed first, as once a channel is matched with a provider, it will be ignored for all other providers after it.
- *DontCache* (bool): (Optional) Indicates whether this provider's playlist should be cached or not. Useful when the provider updates the playlist multiple times a day. By default it's false.
- *AllowCaching* (bool): (Optional) Indicates whether this provider's playlist should be cached or not. Useful when the provider updates the playlist multiple times a day. By default it's true.
- *UrlFormat* (string): The URL to the m3u playlist file of that provider. Replace the date part of the URL with a timestamp format. For example, *2019-05-19* will be replaced with *{0:yyyy-MM-dd}*. The *0* is the calendar day that is processed (today, or one of the previous ones depending on the *daysToCheck* setting)
- *Country* (string): (Optional) If set, the country will be used in the channel matching process.
- *ChannelNameOverride* (string): (Optional) The channel name override for all the channels in the provider's playlist.
25 changes: 17 additions & 8 deletions Service/ChannelMatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public sealed class ChannelMatcher : IChannelMatcher
{ "([a-zA-Z0-9_ ]{3})[ _\\|\\[\\(\\]\\)\".:-](Ultra|[FU])*_*[HMS][DQ]", "$1" },
{ "4[Kk]\\+*", "" },

{ "^ *[\\|\\[\\(\\]\\)\".:-]* *([A-Z][A-Z]) *[\\|\\[\\(\\]\\)\".:-] *", "$1:" },
{ "^( *[\\|\\[\\(\\]\\)\".:-]* *([A-Z][A-Z]) *[\\|\\[\\(\\]\\)\".:-] *)+", "$2:" },
{ "^ *([A-Z][A-Z]): *(.*) \\(*\\1\\)*$", "$1: $2" },

{ "Moldavia", "Moldova" },
Expand Down Expand Up @@ -65,7 +65,7 @@ public ChannelMatcher(ICacheManager cache)
this.cache = cache;
}

public string NormaliseName(string name)
public string NormaliseName(string name, string country)
{
string normalisedName = cache.GetNormalisedChannelName(name);

Expand All @@ -74,7 +74,16 @@ public string NormaliseName(string name)
return normalisedName;
}

normalisedName = name.RemoveDiacritics();
if (string.IsNullOrWhiteSpace(country))
{
normalisedName = name;
}
else
{
normalisedName = $"{country}: {name}";
}

normalisedName = normalisedName.RemoveDiacritics();
normalisedName = StripChannelName(normalisedName);
normalisedName = normalisedName.ToUpper();

Expand All @@ -83,12 +92,12 @@ public string NormaliseName(string name)
return normalisedName;
}

public bool DoesMatch(ChannelName name1, string name2)
=> DoChannelNamesMatch(name1.Value, name2) ||
name1.Aliases.Any(x => DoChannelNamesMatch(x, name2));
public bool DoesMatch(ChannelName name1, string name2, string country2)
=> DoChannelNamesMatch(name1.Value, name1.Country, name2, country2) ||
name1.Aliases.Any(name1alias => DoChannelNamesMatch(name1alias, name1.Country, name2, country2));

bool DoChannelNamesMatch(string name1, string name2)
=> NormaliseName(name1).Equals(NormaliseName(name2));
bool DoChannelNamesMatch(string name1, string country1, string name2, string country2)
=> NormaliseName(name1, country1).Equals(NormaliseName(name2, country2));

string StripChannelName(string name)
{
Expand Down
4 changes: 2 additions & 2 deletions Service/IChannelMatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ namespace IptvPlaylistAggregator.Service
{
public interface IChannelMatcher
{
string NormaliseName(string name);
string NormaliseName(string name, string country);

bool DoesMatch(ChannelName name1, string name2);
bool DoesMatch(ChannelName name1, string name2, string country2);
}
}
4 changes: 3 additions & 1 deletion Service/Mapping/ChannelDefinitionMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ internal static ChannelDefinition ToServiceModel(this ChannelDefinitionEntity da
ChannelDefinition serviceModel = new ChannelDefinition();
serviceModel.Id = dataObject.Id;
serviceModel.IsEnabled = dataObject.IsEnabled;
serviceModel.Name = new ChannelName(dataObject.Name, dataObject.Aliases);
serviceModel.Name = new ChannelName(dataObject.Name, dataObject.Country, dataObject.Aliases);
serviceModel.Country = dataObject.Country;
serviceModel.GroupId = dataObject.GroupId;
serviceModel.LogoUrl = dataObject.LogoUrl;

Expand All @@ -26,6 +27,7 @@ internal static ChannelDefinitionEntity ToDataObject(this ChannelDefinition serv
dataObject.Id = serviceModel.Id;
dataObject.IsEnabled = serviceModel.IsEnabled;
dataObject.Name = serviceModel.Name.Value;
dataObject.Country = serviceModel.Country;
dataObject.GroupId = serviceModel.GroupId;
dataObject.LogoUrl = serviceModel.LogoUrl;
dataObject.Aliases = serviceModel.Name.Aliases.ToList();
Expand Down
6 changes: 4 additions & 2 deletions Service/Mapping/PlaylistProviderMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ internal static PlaylistProvider ToServiceModel(this PlaylistProviderEntity data
serviceModel.Id = dataObject.Id;
serviceModel.IsEnabled = dataObject.IsEnabled;
serviceModel.Priority = dataObject.Priority;
serviceModel.DontCache = dataObject.DontCache;
serviceModel.AllowCaching = dataObject.AllowCaching;
serviceModel.Name = dataObject.Name;
serviceModel.UrlFormat = dataObject.UrlFormat;
serviceModel.Country = dataObject.Country;
serviceModel.ChannelNameOverride = dataObject.ChannelNameOverride;

return serviceModel;
Expand All @@ -28,9 +29,10 @@ internal static PlaylistProviderEntity ToDataObject(this PlaylistProvider servic
dataObject.Id = serviceModel.Id;
dataObject.IsEnabled = serviceModel.IsEnabled;
dataObject.Priority = serviceModel.Priority;
dataObject.DontCache = serviceModel.DontCache;
dataObject.AllowCaching = serviceModel.AllowCaching;
dataObject.Name = serviceModel.Name;
dataObject.UrlFormat = serviceModel.UrlFormat;
dataObject.Country = serviceModel.Country;
dataObject.ChannelNameOverride = serviceModel.ChannelNameOverride;

return dataObject;
Expand Down
2 changes: 2 additions & 0 deletions Service/Models/Channel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ public sealed class Channel
public string Name { get; set; }

public string Group { get; set; }

public string Country { get; set; }

public string LogoUrl { get; set; }

Expand Down
2 changes: 2 additions & 0 deletions Service/Models/ChannelDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ public sealed class ChannelDefinition

public ChannelName Name { get; set; }

public string Country { get; set; }

public string GroupId { get; set; }

public string LogoUrl { get; set; }
Expand Down
26 changes: 21 additions & 5 deletions Service/Models/ChannelName.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,42 @@
using System.Collections.Generic;
using System.Linq;

namespace IptvPlaylistAggregator.Service.Models
{
public sealed class ChannelName
{
public string Value { get; set; }

public string Country { get; set; }

public IEnumerable<string> Aliases { get; set; }

public ChannelName(string name)
: this(name, new List<string>())
: this(name, country: null)
{

}

public ChannelName(string name, IEnumerable<string> aliases)
public ChannelName(string name, string country)
: this(name, country, new List<string>())
{
Value = name;
Aliases = aliases;
}

public ChannelName(string name, params string[] aliases)
: this(name, country: null, aliases)
{
}

public ChannelName(string name, string country, params string[] aliases)
: this(name, country, aliases.ToList())
{
}

public ChannelName(string name, IEnumerable<string> aliases)
: this(name, country: null, aliases)
{
}

public ChannelName(string name, string country, IEnumerable<string> aliases)
{
Value = name;
Aliases = aliases;
Expand Down
4 changes: 3 additions & 1 deletion Service/Models/PlaylistProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ public class PlaylistProvider

public int Priority { get; set; }

public bool DontCache { get; set; }
public bool AllowCaching { get; set; }

public string Name { get; set; }

public string UrlFormat { get; set; }

public string Country { get; set; }

public string ChannelNameOverride { get; set; }
}
}
5 changes: 3 additions & 2 deletions Service/PlaylistAggregator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ IEnumerable<Channel> GetEnabledChannels(IEnumerable<Channel> filteredProviderCha
new LogInfo(MyLogInfoKey.Channel, channelDef.Name.Value));

List<Channel> matchedChannels = filteredProviderChannels
.Where(x => channelMatcher.DoesMatch(channelDef.Name, x.Name))
.Where(x => channelMatcher.DoesMatch(channelDef.Name, x.Name, x.Country))
.ToList();

if (!matchedChannels.Any())
Expand Down Expand Up @@ -168,6 +168,7 @@ IEnumerable<Channel> GetEnabledChannels(IEnumerable<Channel> filteredProviderCha
Channel channel = new Channel();
channel.Id = channelDef.Id;
channel.Name = channelDef.Name.Value;
channel.Country = channelDef.Country;
channel.Group = groups[channelDef.GroupId].Name;
channel.LogoUrl = channelDef.LogoUrl;
channel.Url = matchedChannel.Url;
Expand Down Expand Up @@ -195,7 +196,7 @@ IEnumerable<Channel> GetUnmatchedChannels(IEnumerable<Channel> filteredProviderC
logger.Info(MyOperation.ChannelMatching, OperationStatus.InProgress, $"Getting unmatched channels");

IEnumerable<Channel> unmatchedChannels = filteredProviderChannels
.Where(x => channelDefinitions.All(y => !channelMatcher.DoesMatch(y.Name, x.Name)))
.Where(x => channelDefinitions.All(y => !channelMatcher.DoesMatch(y.Name, x.Name, x.Country)))
.GroupBy(x => x.Name)
.Select(g => g.First())
.OrderBy(x => x.Name);
Expand Down
12 changes: 10 additions & 2 deletions Service/PlaylistFetcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ public IEnumerable<Playlist> FetchProviderPlaylists(IEnumerable<PlaylistProvider
provider.Priority,
playlist,
(key, oldValue) => playlist);

if (!string.IsNullOrWhiteSpace(provider.Country))
{
foreach (Channel channel in playlist.Channels)
{
channel.Country = provider.Country;
}
}
}
});

Expand Down Expand Up @@ -119,7 +127,7 @@ async Task<Playlist> GetPlaylistForTodayAsync(PlaylistProvider provider)
playlist = playlistFileBuilder.TryParseFile(playlistFile);
}

if (!Playlist.IsNullOrEmpty(playlist) && !provider.DontCache)
if (provider.AllowCaching && !Playlist.IsNullOrEmpty(playlist))
{
cache.StorePlaylistFile(provider.Id, DateTime.UtcNow, playlistFile);
}
Expand Down Expand Up @@ -153,7 +161,7 @@ Playlist GetPlaylistForPastDays(PlaylistProvider provider)

Playlist LoadPlaylistFromCache(PlaylistProvider provider, DateTime date)
{
if (provider.DontCache)
if (provider.AllowCaching)
{
return null;
}
Expand Down
6 changes: 6 additions & 0 deletions Service/PlaylistFileBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public sealed class PlaylistFileBuilder : IPlaylistFileBuilder
const string TvGuideNameTagKey = "tvg-name";
const string TvGuideIdTagKey = "tvg-id";
const string TvGuideLogoTagKey = "tvg-logo";
const string TvGuideCountryTagKey = "tvg-country";
const string TvGuideGroupTagKey = "group-title";
const int DefaultEntryRuntime = -1;

Expand Down Expand Up @@ -138,6 +139,11 @@ string BuildTvGuideHeaderTags(Channel channel)
tvgTags += $" {TvGuideLogoTagKey}=\"{channel.LogoUrl}\"";
}

if (!string.IsNullOrWhiteSpace(channel.Country))
{
tvgTags += $" {TvGuideCountryTagKey}=\"{channel.Country}\"";
}

if (!string.IsNullOrWhiteSpace(channel.Group))
{
tvgTags += $" {TvGuideGroupTagKey}=\"{channel.Group}\"";
Expand Down
Loading

0 comments on commit e42d5d0

Please sign in to comment.