From 73cc50590dd1304a6a31984ec4e62887b898c006 Mon Sep 17 00:00:00 2001 From: Horst Beham Date: Sat, 14 Jan 2023 20:46:07 +0100 Subject: [PATCH] - TCL: separate lists for DVB-C/T/S, each starting at 1 - TCL: "Hide" in the UI now translates to "IsSkipped" in the database (just like the TV does it with its menu) - VisionEdge4K: TV doesn't use the disp_order directly but instead only orders channels by it and creates distinct lists per satellite, all starting at 1 --- .../ChanSort.Loader.TCL/DtvDataSerializer.cs | 127 ++++++++++-------- .../VisionEdge4KDbSerializer.cs | 116 ++++++++++------ source/changelog.md | 3 +- 3 files changed, 149 insertions(+), 97 deletions(-) diff --git a/source/ChanSort.Loader.TCL/DtvDataSerializer.cs b/source/ChanSort.Loader.TCL/DtvDataSerializer.cs index c0b95b4..cca6235 100644 --- a/source/ChanSort.Loader.TCL/DtvDataSerializer.cs +++ b/source/ChanSort.Loader.TCL/DtvDataSerializer.cs @@ -12,7 +12,7 @@ namespace ChanSort.Loader.TCL * None of the sample files contained more than a single input source (DVB-C/T/S), so for the time being this loader puts everything into a single list * * When a channel is added to favorites, it will: EditFlag |= 0x01, IsFavor=1, but will keep FavChannelNo=65535 - * When a channel is hidden through the TV's menu, it will result in: EditFlag |= 0x08, IsSkipped=1 + * When a channel is hidden through the TV's menu, it will result in: EditFlag |= 0x08, IsSkipped=1, leaving "VisibleFlag" unchanged (=1) * When a channel is deleted in the menu: EditFlag |= 0x10, IsDelete=1, but it will keep its unique ProgNum * When a channel is moved in the menu: EditFlag |= 0x02, but no change to IsMove(=0) */ @@ -25,13 +25,15 @@ namespace ChanSort.Loader.TCL { Favorite = 0x01, CustomProgNum = 0x02, - Skip = 0x08, + Hidden = 0x08, Delete = 0x10, - AllKnown = Favorite|CustomProgNum|Skip|Delete + AllKnown = Favorite|CustomProgNum|Hidden|Delete } - private readonly ChannelList channels = new (SignalSource.All, "All"); + private readonly ChannelList dvbT = new(SignalSource.Antenna | SignalSource.MaskTvRadioData|SignalSource.Digital, "DVB-T"); + private readonly ChannelList dvbC = new(SignalSource.Cable | SignalSource.MaskTvRadioData | SignalSource.Digital, "DVB-C"); + private readonly ChannelList dvbS = new(SignalSource.Sat | SignalSource.MaskTvRadioData | SignalSource.Digital, "DVB-S"); private string dbDir; private string dtvFile; private string satFile; @@ -51,17 +53,22 @@ namespace ChanSort.Loader.TCL #else this.Features.DeleteMode = DeleteMode.FlagWithoutPrNr; #endif - this.Features.CanSkipChannels = true; + this.Features.CanSkipChannels = false; this.Features.CanLockChannels = true; this.Features.CanHideChannels = true; this.Features.FavoritesMode = FavoritesMode.Flags; this.Features.MaxFavoriteLists = 1; - this.DataRoot.AddChannelList(this.channels); - channels.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.AudioPid)); - channels.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.Provider)); - channels.VisibleColumnFieldNames.Add(nameof(ChannelInfo.ServiceType)); - channels.VisibleColumnFieldNames.Add(nameof(ChannelInfo.Source)); + this.DataRoot.AddChannelList(this.dvbT); + this.DataRoot.AddChannelList(this.dvbC); + this.DataRoot.AddChannelList(this.dvbS); + foreach (var list in this.DataRoot.ChannelLists) + { + list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.AudioPid)); + list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.Provider)); + list.VisibleColumnFieldNames.Add(nameof(ChannelInfo.ServiceType)); + list.VisibleColumnFieldNames.Add(nameof(ChannelInfo.Source)); + } } #endregion @@ -297,17 +304,16 @@ left outer join CurCIOPSerType c on c.u8DtvRoute=p.u8DtvRoute oldProgNr = -1; var name = r.GetString(2)?.TrimEnd(' ', '\0'); - ChannelInfo channel = new ChannelInfo(0, handle, oldProgNr, name); + ChannelInfo channel = new ChannelInfo(SignalSource.Digital, handle, oldProgNr, name); channel.ShortName = r.GetString(3).TrimEnd(' ', '\0'); channel.ServiceId = r.GetInt32(4); var vtype = r.GetInt32(5); channel.ServiceTypeName = vtype == 1 ? "SD-TV" : vtype == 4 ? "HD-TV" : vtype == 6 ? "UHD-TV" : null; channel.PcrPid = r.GetInt32(6); channel.VideoPid = r.GetInt32(7); - channel.Hidden = r.GetBoolean(8); var edit = (EditFlags)r.GetInt32(11); channel.Favorites = (edit & EditFlags.Favorite) != 0 ? Favorites.A : 0; - channel.Skip = (edit & EditFlags.Skip) != 0; + channel.Hidden = (edit & EditFlags.Hidden) != 0; channel.AddDebug($"LCN={r.GetValue(9)}, edit={(int)edit:x4}"); // DVB @@ -322,9 +328,21 @@ left outer join CurCIOPSerType c on c.u8DtvRoute=p.u8DtvRoute channel.SymbolRate = r.GetInt32(ixD + 3); if (channel.FreqInMhz > 10000) channel.FreqInMhz = (int) channel.FreqInMhz; - channel.Source = r.GetString(ixC); } + // get signal source from CurCIOPSerType table + if (r.IsDBNull(ixC)) + continue; + channel.Source = r.GetString(ixC); + if (channel.Source == "dvbc") + channel.SignalSource |= SignalSource.Cable; + else if (channel.Source == "dvbt") + channel.SignalSource |= SignalSource.Antenna; + else if (channel.Source == "dvbs") + channel.SignalSource |= SignalSource.Sat; + else + continue; + // AtrributeTbl (actual typo in the TV's table name!) if (!r.IsDBNull(ixA)) { @@ -332,9 +350,8 @@ left outer join CurCIOPSerType c on c.u8DtvRoute=p.u8DtvRoute channel.ServiceTypeName = LookupData.Instance.GetServiceTypeDescription(channel.ServiceType); channel.SignalSource |= LookupData.Instance.IsRadioTvOrData(channel.ServiceType); channel.Encrypted = r.GetInt32(ixA + 1) != 0; - channel.Hidden = !r.GetBoolean(ixA + 2); channel.IsDeleted |= r.GetBoolean(ixA + 3); - channel.Skip |= r.GetBoolean(ixA + 4); + channel.Hidden |= r.GetBoolean(ixA + 4); channel.Lock = r.GetBoolean(ixA + 5); if (r.GetBoolean(ixA + 6)) channel.Favorites |= Favorites.A; @@ -342,8 +359,11 @@ left outer join CurCIOPSerType c on c.u8DtvRoute=p.u8DtvRoute channel.AddDebug($", FavChannelNo={r.GetInt32(ixA + 10)}"); } - //if (!channel.IsDeleted) - this.DataRoot.AddChannel(this.channels, channel); + if (!channel.IsDeleted) + { + var list = this.DataRoot.GetChannelList(channel.SignalSource); + this.DataRoot.AddChannel(list, channel); + } } } #endregion @@ -360,7 +380,7 @@ left outer join CurCIOPSerType c on c.u8DtvRoute=p.u8DtvRoute using var cmd = conn.CreateCommand(); using var cmd2 = conn.CreateCommand(); - this.WriteChannels(cmd, cmd2, this.channels); + this.WriteChannels(cmd, cmd2); trans.Commit(); cmd.Transaction = null; @@ -374,7 +394,7 @@ left outer join CurCIOPSerType c on c.u8DtvRoute=p.u8DtvRoute #endregion #region WriteChannels() - private void WriteChannels(SqliteCommand cmd, SqliteCommand cmdAttrib, ChannelList channelList) + private void WriteChannels(SqliteCommand cmd, SqliteCommand cmdAttrib) { // what the TV shows as "hide" in the menu is actually "skip" in the database @@ -387,17 +407,14 @@ left outer join CurCIOPSerType c on c.u8DtvRoute=p.u8DtvRoute cmd.Parameters.Add("@nr", SqliteType.Integer); #if !TestBuild cmd.Parameters.Add("@name", SqliteType.Blob, 64); - //cmd.Parameters.Add("@hide", SqliteType.Integer); cmd.Parameters.Add("@editflag", SqliteType.Integer); #endif cmd.Prepare(); #if !TestBuild - cmdAttrib.CommandText = @"update AtrributeTbl set VisibleFlag=@vis, IsDelete=@del, IsSkipped=@skip, IsLock=@lock, IsRename=@ren, IsFavor=@fav where u32Index=@handle;"; // IsMove=IsMove|@mov, + cmdAttrib.CommandText = @"update AtrributeTbl set IsDelete=@del, IsSkipped=@skip, IsLock=@lock, IsRename=@ren, IsFavor=@fav where u32Index=@handle;"; // IsMove=IsMove|@mov, cmdAttrib.Parameters.Add("@handle", SqliteType.Integer); - cmdAttrib.Parameters.Add("@vis", SqliteType.Integer); cmdAttrib.Parameters.Add("@del", SqliteType.Integer); - cmdAttrib.Parameters.Add("@mov", SqliteType.Integer); cmdAttrib.Parameters.Add("@skip", SqliteType.Integer); cmdAttrib.Parameters.Add("@lock", SqliteType.Integer); cmdAttrib.Parameters.Add("@ren", SqliteType.Integer); @@ -405,42 +422,42 @@ left outer join CurCIOPSerType c on c.u8DtvRoute=p.u8DtvRoute cmdAttrib.Prepare(); #endif - foreach (ChannelInfo channel in channelList.Channels) + foreach (var channelList in this.DataRoot.ChannelLists) { - if (channel.IsProxy) // ignore reference list proxy channels - continue; + foreach (ChannelInfo channel in channelList.Channels) + { + if (channel.IsProxy) // ignore reference list proxy channels + continue; - channel.UpdateRawData(); - cmd.Parameters["@handle"].Value = channel.RecordIndex; - cmd.Parameters["@nr"].Value = channel.IsDeleted ? 65535 : channel.NewProgramNr; + channel.UpdateRawData(); + cmd.Parameters["@handle"].Value = channel.RecordIndex; + cmd.Parameters["@nr"].Value = channel.IsDeleted ? 65535 : channel.NewProgramNr; #if !TestBuild - var bytes = Encoding.UTF8.GetBytes(channel.Name); - var blob = new byte[64]; - Tools.MemCopy(bytes, 0, blob, 0, 64); - cmd.Parameters["@name"].Value = blob; - //cmd.Parameters["@hide"].Value = channel.Hidden; - EditFlags flags = 0; - if (channel.Favorites != 0) - flags |= EditFlags.Favorite; - if (channel.Skip) - flags |= EditFlags.Skip; - if (channel.IsDeleted) - flags |= EditFlags.Delete; - else - flags |= EditFlags.CustomProgNum; - cmd.Parameters["@editflag"].Value = (int)flags; + var bytes = Encoding.UTF8.GetBytes(channel.Name); + var blob = new byte[64]; + Tools.MemCopy(bytes, 0, blob, 0, 64); + cmd.Parameters["@name"].Value = blob; + EditFlags flags = 0; + if (channel.Favorites != 0) + flags |= EditFlags.Favorite; + if (channel.Hidden) + flags |= EditFlags.Hidden; + if (channel.IsDeleted) + flags |= EditFlags.Delete; + else + flags |= EditFlags.CustomProgNum; + cmd.Parameters["@editflag"].Value = (int)flags; - cmdAttrib.Parameters["@handle"].Value = channel.RecordIndex; - cmdAttrib.Parameters["@vis"].Value = channel.Hidden ? 0 : 1; - cmdAttrib.Parameters["@del"].Value = channel.IsDeleted ? 1 : 0; - cmdAttrib.Parameters["@skip"].Value = channel.Skip ? 1 : 0; - cmdAttrib.Parameters["@lock"].Value = channel.Lock ? 1 : 0; - cmdAttrib.Parameters["@ren"].Value = channel.IsNameModified ? 1 : 0; - //cmdAttrib.Parameters["@mov"].Value = 1; - cmdAttrib.Parameters["@fav"].Value = channel.Favorites != 0 ? 1 : 0; - cmdAttrib.ExecuteNonQuery(); + cmdAttrib.Parameters["@handle"].Value = channel.RecordIndex; + cmdAttrib.Parameters["@del"].Value = channel.IsDeleted ? 1 : 0; + cmdAttrib.Parameters["@skip"].Value = channel.Hidden ? 1 : 0; + cmdAttrib.Parameters["@lock"].Value = channel.Lock ? 1 : 0; + cmdAttrib.Parameters["@ren"].Value = channel.IsNameModified ? 1 : 0; + cmdAttrib.Parameters["@fav"].Value = channel.Favorites != 0 ? 1 : 0; + cmdAttrib.ExecuteNonQuery(); #endif - cmd.ExecuteNonQuery(); + cmd.ExecuteNonQuery(); + } } } #endregion diff --git a/source/ChanSort.Loader.VisionEdge4K/VisionEdge4KDbSerializer.cs b/source/ChanSort.Loader.VisionEdge4K/VisionEdge4KDbSerializer.cs index df34e6f..825fb86 100644 --- a/source/ChanSort.Loader.VisionEdge4K/VisionEdge4KDbSerializer.cs +++ b/source/ChanSort.Loader.VisionEdge4K/VisionEdge4KDbSerializer.cs @@ -12,16 +12,19 @@ namespace ChanSort.Loader.VisionEdge4K * Currently only "satellite_transponder_table" is supported, but there are databases with additional "cable_transponder_table" and "terrestrial_transponder_table" tables. * All these transponder tables have tp_id values starting at 0, which makes it unclear how to reference them from within program_table. * The guess is that program_table.tp_type=0 means satellite. + * + * The disp_order stored in the database is not used directly by the STB. Instead it only orders the DB results by it and creates internal lists for each satellite, all starting at 1. */ class VisionEdge4KSerializer : SerializerBase { - private readonly ChannelList channels = new (SignalSource.All, "All"); - private readonly ChannelList favs = new (SignalSource.All, "Fav") { IsMixedSourceFavoritesList = true }; - private readonly HashSet tableNames = new(); private readonly List favListIds = new(); private readonly Dictionary favListIndexById = new(); + private readonly Dictionary channels = new(); + private readonly ChannelList favs = new(SignalSource.All, "Fav") { IsMixedSourceFavoritesList = true }; + + #region ctor() public VisionEdge4KSerializer(string inputFile) : base(inputFile) { @@ -35,14 +38,6 @@ namespace ChanSort.Loader.VisionEdge4K #else this.Features.FavoritesMode = FavoritesMode.None; #endif - this.DataRoot.AddChannelList(this.channels); - this.DataRoot.AddChannelList(this.favs); - foreach (var list in this.DataRoot.ChannelLists) - { - list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.AudioPid)); - list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.ShortName)); - list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.Provider)); - } } #endregion @@ -73,6 +68,7 @@ namespace ChanSort.Loader.VisionEdge4K #if WITH_FAVORITES this.ReadFavorites(cmd); #endif + this.AdjustColumns(); } #endregion @@ -87,7 +83,7 @@ namespace ChanSort.Loader.VisionEdge4K #region ReadSatellites() private void ReadSatellites(SqliteCommand cmd) { - cmd.CommandText = "select id, name, angle from satellite_table"; + cmd.CommandText = "select id, name, angle from satellite_table order by disp_order"; using var r = cmd.ExecuteReader(); while (r.Read()) { @@ -108,6 +104,10 @@ namespace ChanSort.Loader.VisionEdge4K sat.OrbitalPosition = $"{pos / 10}.{pos % 10}{eastWest}"; sat.Name = r.GetString(1); this.DataRoot.AddSatellite(sat); + + var list = new ChannelList(SignalSource.Sat | SignalSource.Digital | SignalSource.MaskTvRadioData, sat.Name); + this.channels.Add(sat.Id, list); + this.DataRoot.AddChannelList(list); } } #endregion @@ -144,9 +144,10 @@ namespace ChanSort.Loader.VisionEdge4K cmd.CommandText = @" select p.id, p.disp_order, p.name, p.service_id, p.vid_pid, p.pcr_pid, p.vid_type, p.tv_type, p.ca_type, p.lock, p.skip, p.hide, - st.sat_id, st.on_id, st.ts_id, st.freq, st.sym_rate + st.sat_id, st.on_id, st.ts_id, st.freq, st.pol, st.sym_rate from program_table p -left outer join satellite_transponder_table st on p.tp_type=0 and st.id=p.tp_id"; +left outer join satellite_transponder_table st on p.tp_type=0 and st.id=p.tp_id +order by p.tv_type,p.disp_order"; using var r = cmd.ExecuteReader(); while (r.Read()) @@ -178,9 +179,11 @@ left outer join satellite_transponder_table st on p.tp_type=0 and st.id=p.tp_id" channel.Hidden = r.GetBoolean(ixP + 11); // DVB-S + int satId = 0; if (!r.IsDBNull(ixST + 0)) { - var sat = this.DataRoot.Satellites.TryGet(r.GetInt32(ixST + 0)); + satId = r.GetInt32(ixST + 0); + var sat = this.DataRoot.Satellites.TryGet(satId); channel.Satellite = sat?.Name; channel.SatPosition = sat?.OrbitalPosition; channel.OriginalNetworkId = r.GetInt32(ixST + 1) & 0x7FFF; @@ -188,11 +191,17 @@ left outer join satellite_transponder_table st on p.tp_type=0 and st.id=p.tp_id" channel.FreqInMhz = r.GetInt32(ixST + 3); if (channel.FreqInMhz > 20000) // DVB-S is in MHz already, DVB-C/T in kHz channel.FreqInMhz /= 1000; - channel.SymbolRate = r.GetInt32(ixST + 4); + channel.Polarity = r.GetInt32(ixST + 4) == 0 ? 'H' : 'V'; + channel.SymbolRate = r.GetInt32(ixST + 5); } - this.DataRoot.AddChannel(this.channels, channel); - this.DataRoot.AddChannel(this.favs, channel); + var list = this.channels.TryGet(satId); + if (list != null) + { + channel.OldProgramNr = list.Channels.Count + 1; + this.DataRoot.AddChannel(list, channel); + this.DataRoot.AddChannel(this.favs, channel); + } } } #endregion @@ -201,7 +210,8 @@ left outer join satellite_transponder_table st on p.tp_type=0 and st.id=p.tp_id" private void ReadFavorites(SqliteCommand cmd) { - cmd.CommandText = "select id, fav_name from fav_name_table"; + this.Features.MaxFavoriteLists = 0; + cmd.CommandText = "select id, fav_name from fav_name_table order by id"; using (var r = cmd.ExecuteReader()) { while (r.Read()) @@ -214,7 +224,8 @@ left outer join satellite_transponder_table st on p.tp_type=0 and st.id=p.tp_id" } } - cmd.CommandText = "select fav_group_id, prog_id, disp_order, tv_type from fav_prog_table"; + cmd.CommandText = "select fav_group_id, prog_id, disp_order, tv_type from fav_prog_table order by disp_order"; + var lastProgNr = new Dictionary(); using (var r = cmd.ExecuteReader()) { while (r.Read()) @@ -224,12 +235,28 @@ left outer join satellite_transponder_table st on p.tp_type=0 and st.id=p.tp_id" continue; if (!this.favListIndexById.TryGetValue(r.GetInt32(0), out var idx)) continue; - chan.SetOldPosition(idx + 1, r.GetInt32(2)); + + lastProgNr.TryGetValue(idx, out var nr); + lastProgNr[idx] = ++nr; + chan.SetOldPosition(idx, nr); } } } #endregion + #region AdjustColumns() + private void AdjustColumns() + { + this.DataRoot.AddChannelList(this.favs); + foreach (var list in this.DataRoot.ChannelLists) + { + list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.AudioPid)); + list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.ShortName)); + list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.Provider)); + } + } + #endregion + #region Save() public override void Save() @@ -255,39 +282,44 @@ left outer join satellite_transponder_table st on p.tp_type=0 and st.id=p.tp_id" #region WriteChannels() private void WriteChannels(SqliteCommand cmd, SqliteCommand cmdDelete) { - cmd.CommandText = "update program_table set disp_order=@nr, name=@name, skip=@skip, lock=@lock, hide=@hide where id=@handle"; + cmd.CommandText = "update program_table set disp_order=@nr, name=@name, skip=@skip, lock=@lock, hide=@hide, fav=@fav where id=@handle"; cmd.Parameters.Add("@handle", SqliteType.Integer); cmd.Parameters.Add("@nr", SqliteType.Integer); cmd.Parameters.Add("@name", SqliteType.Text); cmd.Parameters.Add("@skip", SqliteType.Integer); cmd.Parameters.Add("@lock", SqliteType.Integer); cmd.Parameters.Add("@hide", SqliteType.Integer); + cmd.Parameters.Add("@fav", SqliteType.Integer); cmd.Prepare(); cmdDelete.CommandText = "delete from program_table where id=@handle; delete from fav_prog_table where prog_id=@handle;"; cmdDelete.Parameters.Add("@handle", SqliteType.Integer); cmdDelete.Prepare(); - foreach (ChannelInfo channel in this.channels.Channels) + foreach (var list in this.DataRoot.ChannelLists) { - if (channel.IsProxy) // ignore reference list proxy channels - continue; + foreach (ChannelInfo channel in list.Channels) + { + if (channel.IsProxy) // ignore reference list proxy channels + continue; - if (channel.IsDeleted) - { - cmdDelete.Parameters["@handle"].Value = channel.RecordIndex; - cmdDelete.ExecuteNonQuery(); - } - else - { - channel.UpdateRawData(); - cmd.Parameters["@handle"].Value = channel.RecordIndex; - cmd.Parameters["@nr"].Value = channel.NewProgramNr; - cmd.Parameters["@name"].Value = channel.Name; - cmd.Parameters["@skip"].Value = channel.Skip ? 1 : 0; - cmd.Parameters["@lock"].Value = channel.Lock ? 1 : 0; - cmd.Parameters["@hide"].Value = channel.Hidden ? 1 : 0; - cmd.ExecuteNonQuery(); + if (channel.IsDeleted) + { + cmdDelete.Parameters["@handle"].Value = channel.RecordIndex; + cmdDelete.ExecuteNonQuery(); + } + else + { + channel.UpdateRawData(); + cmd.Parameters["@handle"].Value = channel.RecordIndex; + cmd.Parameters["@nr"].Value = channel.NewProgramNr; + cmd.Parameters["@name"].Value = channel.Name; + cmd.Parameters["@skip"].Value = channel.Skip ? 1 : 0; + cmd.Parameters["@lock"].Value = channel.Lock ? 1 : 0; + cmd.Parameters["@hide"].Value = channel.Hidden ? 1 : 0; + cmd.Parameters["@fav"].Value = channel.Favorites == 0 ? 0 : 1; + cmd.ExecuteNonQuery(); + } } } } @@ -306,6 +338,8 @@ left outer join satellite_transponder_table st on p.tp_type=0 and st.id=p.tp_id" cmd.Parameters.Add("@order", SqliteType.Integer); cmd.Parameters.Add("@type", SqliteType.Integer); + int favProgNr = 1; // the TV maintains continuous numbers over all favorite lists, not per-list + int max = this.Features.MaxFavoriteLists; foreach (var chan in favs.Channels) { @@ -318,7 +352,7 @@ left outer join satellite_transponder_table st on p.tp_type=0 and st.id=p.tp_id" continue; cmd.Parameters["@progid"].Value = chan.RecordIndex; cmd.Parameters["@groupid"].Value = this.favListIds[i]; - cmd.Parameters["@order"].Value = num; + cmd.Parameters["@order"].Value = favProgNr++; cmd.Parameters["@type"].Value = (chan.SignalSource & SignalSource.Tv) != 0 ? 0 : 1; cmd.ExecuteNonQuery(); } diff --git a/source/changelog.md b/source/changelog.md index 47b6931..812996b 100644 --- a/source/changelog.md +++ b/source/changelog.md @@ -3,7 +3,8 @@ 2023-01-14 - added support for Vision EDGE 4K set-top-box (DVB-S only) - (DVB-C/T can be added when I receive a file containing such channels) +- TCL: separate lists for DVB-C/T/S, each starting at 1 +- TCL: cleaned up "Hide" vs "Skip" 2023-01-12 - TCL: fixed upload failure due to incorrect checksum when DtvData.db was larger than 307200 bytes