using System; using System.Collections.Generic; using System.Linq; using MediaBrowser.Controller.LiveTv; namespace Jellyfin.Plugin.Enigma2; /// Keep saved native channels playable after a receiver bouquet migration. public static class ChannelReferenceResolver { public static string Resolve(string reference, IEnumerable channels, Func previousName) { var current = channels.Where(c => !string.IsNullOrWhiteSpace(c.Id)).ToArray(); var exact = current.FirstOrDefault(c => string.Equals(c.Id, reference, StringComparison.OrdinalIgnoreCase)); if (exact != null) return exact.Id; // A changed Enigma service type does not change the DVB service identity. var identity = Identity(reference); var matches = current.Where(c => identity != null && Identity(c.Id) == identity) .Select(c => c.Id).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); if (matches.Length == 1) return matches[0]; if (matches.Length > 1) return reference; // A moved service has a new SID/TSID. Use only a unique exact historical // name; never guess between HD/SD, regional or alternative services. var name = previousName()?.Trim(); if (string.IsNullOrEmpty(name)) return reference; matches = current.Where(c => string.Equals(c.Name?.Trim(), name, StringComparison.OrdinalIgnoreCase)) .Select(c => c.Id).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(); return matches.Length == 1 ? matches[0] : reference; } private static string Identity(string reference) { var fields = reference?.TrimEnd(':').Split(':'); if (fields == null || fields.Length != 10 || fields[0] != "1" || fields[1] != "0") return null; // No URLs, labels or non-DVB references participate in this fallback. if (fields.Any(f => f.Length == 0 || !f.All(Uri.IsHexDigit))) return null; fields[2] = ""; return string.Join(':', fields).ToUpperInvariant(); } }