From a14c89224fc0502a64203d73b37e6c3d07473d24 Mon Sep 17 00:00:00 2001 From: Horst Beham Date: Sat, 14 Jan 2023 15:22:16 +0100 Subject: [PATCH] - added support for Vision Edge 4K set-top-box database.db format --- readme.md | 1 + readme_de.md | 1 + readme_pl.md | 1 + readme_tr-TR.md | 1 + source/ChanSort.Api/Model/ChannelList.cs | 7 + .../ChanSort.Loader.VisionEdge4K.csproj | 23 ++ .../VisionEdge4KDbSerializer.cs | 329 ++++++++++++++++++ .../VisionEdge4KPlugin.cs | 16 + source/ChanSort.sln | 34 +- source/ChanSort/ChanSort.csproj | 1 + source/changelog.md | 7 + source/fileformats.md | 4 + source/fileformats_de.md | 4 + 13 files changed, 428 insertions(+), 1 deletion(-) create mode 100644 source/ChanSort.Loader.VisionEdge4K/ChanSort.Loader.VisionEdge4K.csproj create mode 100644 source/ChanSort.Loader.VisionEdge4K/VisionEdge4KDbSerializer.cs create mode 100644 source/ChanSort.Loader.VisionEdge4K/VisionEdge4KPlugin.cs diff --git a/readme.md b/readme.md index 927a095..d78fdfb 100644 --- a/readme.md +++ b/readme.md @@ -62,6 +62,7 @@ it may work anyway: - [Grundig](source/fileformats.md#grundig) - [SatcoDX: ITT, Medion, Nabo, ok., PEAQ, Schaub-Lorenz, Silva-Schneider, Telefunken, ...](source/fileformats.md#satcodx) - [DBM: Xoro, Strong, TechniSat, ...](source/fileformats.md#dbm) +- [Vision Edge 4K](source/fileformats.md#visionedge) - [VDR](source/fileformats.md#vdr) - [SAT>IP m3u](source/fileformats.md#m3u) - [Enigma2](source/fileformats.md#enigma2) diff --git a/readme_de.md b/readme_de.md index a7b5324..5f85fda 100644 --- a/readme_de.md +++ b/readme_de.md @@ -62,6 +62,7 @@ hier nicht angeführt ist, könnte es trotzdem funktiontionieren: - [Grundig](source/fileformats_de.md#grundig) - [SatcoDX: ITT, Medion, Nabo, ok., PEAQ, Schaub-Lorenz, Silva-Schneider, Telefunken, ...](source/fileformats_de.md#satcodx) - [DBM: Xoro, Strong, TechniSat, ...](source/fileformats_de.md#dbm) +- [Vision Edge 4K](source/fileformats.md#visionedge) - [VDR](source/fileformats_de.md#vdr) - [SAT>IP m3u](source/fileformats_de.md#m3u) - [Enigma2](source/fileformats_de.md#enigma2) diff --git a/readme_pl.md b/readme_pl.md index f245516..dac3757 100644 --- a/readme_pl.md +++ b/readme_pl.md @@ -62,6 +62,7 @@ to może i tak zadziaÅ‚ać: - [Grundig](source/fileformats.md#grundig) - [SatcoDX: ITT, Medion, Nabo, ok., PEAQ, Schaub-Lorenz, Silva-Schneider, Telefunken, ...](source/fileformats.md#satcodx) - [DBM: Xoro, Strong, TechniSat, ...](source/fileformats.md#dbm) +- [Vision Edge 4K](source/fileformats.md#visionedge) - [VDR](source/fileformats.md#vdr) - [SAT>IP m3u](source/fileformats.md#m3u) - [Enigma2](source/fileformats.md#enigma2) diff --git a/readme_tr-TR.md b/readme_tr-TR.md index c67b787..e70c697 100644 --- a/readme_tr-TR.md +++ b/readme_tr-TR.md @@ -58,6 +58,7 @@ Bu liste nelerin desteklendiÄŸine dair bir örnek teÅŸkil eder, ancak yine de bu - [Grundig](source/fileformats.md#grundig) - [SatcoDX: ITT, Medion, Nabo, ok., PEAQ, Schaub-Lorenz, Silva-Schneider, Telefunken, ...](source/fileformats.md#satcodx) - [DBM: Xoro, Strong, TechniSat, ...](source/fileformats.md#dbm) +- [Vision Edge 4K](source/fileformats.md#visionedge) - [VDR](source/fileformats.md#vdr) - [SAT>IP m3u](source/fileformats.md#m3u) - [Enigma2](source/fileformats.md#enigma2) diff --git a/source/ChanSort.Api/Model/ChannelList.cs b/source/ChanSort.Api/Model/ChannelList.cs index 1157bb4..9b64e75 100644 --- a/source/ChanSort.Api/Model/ChannelList.cs +++ b/source/ChanSort.Api/Model/ChannelList.cs @@ -9,6 +9,7 @@ namespace ChanSort.Api private readonly Dictionary> channelByUid = new (); private readonly Dictionary channelByProgNr = new (); private readonly Dictionary> channelByName = new (); + private readonly Dictionary channelById = new(); private int insertProgramNr = 1; private int duplicateUidCount; private int duplicateProgNrCount; @@ -115,6 +116,8 @@ namespace ChanSort.Api if (ci.ProgramNrPreset != 0) ++this.PresetProgramNrCount; + this.channelById[ci.RecordIndex] = ci; + this.Channels.Add(ci); return warning2; @@ -136,6 +139,10 @@ namespace ChanSort.Api } #endregion + #region GetChannelById() + public ChannelInfo GetChannelById(long id) => this.channelById.TryGet(id); + #endregion + #region GetChannelByName() public IEnumerable GetChannelByName(string name) { diff --git a/source/ChanSort.Loader.VisionEdge4K/ChanSort.Loader.VisionEdge4K.csproj b/source/ChanSort.Loader.VisionEdge4K/ChanSort.Loader.VisionEdge4K.csproj new file mode 100644 index 0000000..8995035 --- /dev/null +++ b/source/ChanSort.Loader.VisionEdge4K/ChanSort.Loader.VisionEdge4K.csproj @@ -0,0 +1,23 @@ + + + + net48 + disable + latest + + + + ..\Debug\ + + + ..\Release\ + + + + + + + + + + diff --git a/source/ChanSort.Loader.VisionEdge4K/VisionEdge4KDbSerializer.cs b/source/ChanSort.Loader.VisionEdge4K/VisionEdge4KDbSerializer.cs new file mode 100644 index 0000000..df34e6f --- /dev/null +++ b/source/ChanSort.Loader.VisionEdge4K/VisionEdge4KDbSerializer.cs @@ -0,0 +1,329 @@ +#define WITH_FAVORITES + +using System.Collections.Generic; +using System.Linq; +using Microsoft.Data.Sqlite; +using ChanSort.Api; + +namespace ChanSort.Loader.VisionEdge4K +{ + /* + * This class loads the database.db file from Vision EDGE 4K set-top-boxes. + * 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. + */ + 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(); + + #region ctor() + public VisionEdge4KSerializer(string inputFile) : base(inputFile) + { + this.Features.ChannelNameEdit = ChannelNameEditMode.All; + this.Features.DeleteMode = DeleteMode.Physically; + this.Features.CanSkipChannels = true; + this.Features.CanLockChannels = true; + this.Features.CanHideChannels = true; +#if WITH_FAVORITES + this.Features.FavoritesMode = FavoritesMode.MixedSource; +#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 + + #region Load() + public override void Load() + { + string connString = $"Data Source={this.FileName};Pooling=False"; + using var conn = new SqliteConnection(connString); + conn.Open(); + + using var cmd = conn.CreateCommand(); + + this.RepairCorruptedDatabaseImage(cmd); + + cmd.CommandText = "SELECT name FROM sqlite_master WHERE type = 'table'"; + using (var r = cmd.ExecuteReader()) + { + while (r.Read()) + this.tableNames.Add(r.GetString(0).ToLowerInvariant()); + } + + if (new[] { "satellite_table", "satellite_transponder_table", "program_table", "fav_prog_table"}.Any(tbl => !tableNames.Contains(tbl))) + throw LoaderException.TryNext("File doesn't contain the expected tables"); + + this.ReadSatellites(cmd); + this.ReadTransponders(cmd); + this.ReadChannels(cmd); +#if WITH_FAVORITES + this.ReadFavorites(cmd); +#endif + } + #endregion + + #region RepairCorruptedDatabaseImage() + private void RepairCorruptedDatabaseImage(SqliteCommand cmd) + { + cmd.CommandText = "REINDEX"; + cmd.ExecuteNonQuery(); + } + #endregion + + #region ReadSatellites() + private void ReadSatellites(SqliteCommand cmd) + { + cmd.CommandText = "select id, name, angle from satellite_table"; + using var r = cmd.ExecuteReader(); + while (r.Read()) + { + Satellite sat = new Satellite(r.GetInt32(0)); + string eastWest = "E"; + int pos = r.GetInt32(2); + // i haven't seen a file containing satellites on the west side. could be either negative or > 180° + if (pos < 0) + { + pos = -pos; + eastWest = "W"; + } + else if (pos > 180) + { + pos = 360 - pos; + eastWest = "W"; + } + sat.OrbitalPosition = $"{pos / 10}.{pos % 10}{eastWest}"; + sat.Name = r.GetString(1); + this.DataRoot.AddSatellite(sat); + } + } + #endregion + + #region ReadTransponders() + private void ReadTransponders(SqliteCommand cmd) + { + cmd.CommandText = "select id, sat_id, freq, pol, sym_rate from satellite_transponder_table"; + using var r = cmd.ExecuteReader(); + while (r.Read()) + { + int id = r.GetInt32(0); + int satId = r.GetInt32(1); + int freq = r.GetInt32(2); + + if (this.DataRoot.Transponder.TryGet(id) != null) + continue; + Transponder tp = new Transponder(id); + tp.FrequencyInMhz = freq; + tp.Polarity = r.GetInt32(3) == 0 ? 'H' : 'V'; + tp.Satellite = this.DataRoot.Satellites.TryGet(satId); + tp.SymbolRate = r.GetInt32(4); + this.DataRoot.AddTransponder(tp.Satellite, tp); + } + } + #endregion + + #region ReadChannels() + private void ReadChannels(SqliteCommand cmd) + { + int ixP = 0; + int ixST = ixP + 12; + + 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 +from program_table p +left outer join satellite_transponder_table st on p.tp_type=0 and st.id=p.tp_id"; + + using var r = cmd.ExecuteReader(); + while (r.Read()) + { + var handle = r.GetInt32(ixP + 0); + var oldProgNr = r.GetInt32(ixP + 1); + var name = r.GetString(ixP + 2); + ChannelInfo channel = new ChannelInfo(0, handle, oldProgNr, name); + channel.ServiceId = r.GetInt32(ixP + 3) & 0x7FFF; + channel.VideoPid = r.GetInt32(ixP + 4); + channel.PcrPid = r.GetInt32(ixP + 5); + var vidType = r.GetInt32(ixP + 6); + var tvType = r.GetInt32(ixP + 7); + if (tvType == 0) + { + channel.ServiceType = vidType; + channel.ServiceTypeName = "TV"; + channel.SignalSource |= SignalSource.Tv; + } + else + { + channel.ServiceType = 0; + channel.ServiceTypeName = "Radio/Data"; + channel.SignalSource |= SignalSource.Radio | SignalSource.Data; + } + channel.Encrypted = r.GetInt32(ixP + 8) != 0; + channel.Lock = r.GetBoolean(ixP + 9); + channel.Skip = r.GetBoolean(ixP + 10); + channel.Hidden = r.GetBoolean(ixP + 11); + + // DVB-S + if (!r.IsDBNull(ixST + 0)) + { + var sat = this.DataRoot.Satellites.TryGet(r.GetInt32(ixST + 0)); + channel.Satellite = sat?.Name; + channel.SatPosition = sat?.OrbitalPosition; + channel.OriginalNetworkId = r.GetInt32(ixST + 1) & 0x7FFF; + channel.TransportStreamId = r.GetInt32(ixST + 2) & 0x7FFF; + 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); + } + + this.DataRoot.AddChannel(this.channels, channel); + this.DataRoot.AddChannel(this.favs, channel); + } + } + #endregion + + #region ReadFavorites + + private void ReadFavorites(SqliteCommand cmd) + { + cmd.CommandText = "select id, fav_name from fav_name_table"; + using (var r = cmd.ExecuteReader()) + { + while (r.Read()) + { + var id = r.GetInt32(0); + favListIds.Add(id); + favListIndexById[id] = this.Features.MaxFavoriteLists; + this.favs.SetFavListCaption(this.Features.MaxFavoriteLists, r.GetString(1)); + ++this.Features.MaxFavoriteLists; + } + } + + cmd.CommandText = "select fav_group_id, prog_id, disp_order, tv_type from fav_prog_table"; + using (var r = cmd.ExecuteReader()) + { + while (r.Read()) + { + var chan = this.favs.GetChannelById(r.GetInt32(1)); + if (chan == null) + continue; + if (!this.favListIndexById.TryGetValue(r.GetInt32(0), out var idx)) + continue; + chan.SetOldPosition(idx + 1, r.GetInt32(2)); + } + } + } + #endregion + + + #region Save() + public override void Save() + { + string channelConnString = $"Data Source={this.FileName};Pooling=False"; + using var conn = new SqliteConnection(channelConnString); + conn.Open(); + using var trans = conn.BeginTransaction(); + using var cmd = conn.CreateCommand(); + using var cmd2 = conn.CreateCommand(); + + this.WriteChannels(cmd, cmd2); +#if WITH_FAVORITES + this.WriteFavorites(cmd); +#endif + trans.Commit(); + + cmd.Transaction = null; + this.RepairCorruptedDatabaseImage(cmd); + } + #endregion + + #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.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.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) + { + 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(); + } + } + } + #endregion + + #region WriteFavorites() + private void WriteFavorites(SqliteCommand cmd) + { + cmd.Parameters.Clear(); + cmd.CommandText = "delete from fav_prog_table"; + cmd.ExecuteNonQuery(); + + cmd.CommandText = "insert into fav_prog_table(prog_id, fav_group_id, disp_order, tv_type) values (@progid, @groupid, @order, @type)"; + cmd.Parameters.Add("@progid", SqliteType.Integer); + cmd.Parameters.Add("@groupid", SqliteType.Integer); + cmd.Parameters.Add("@order", SqliteType.Integer); + cmd.Parameters.Add("@type", SqliteType.Integer); + + int max = this.Features.MaxFavoriteLists; + foreach (var chan in favs.Channels) + { + if (chan.IsProxy) + continue; + for (int i = 0; i < max; i++) + { + var num = chan.GetPosition(i + 1); + if (num <= 0) + continue; + cmd.Parameters["@progid"].Value = chan.RecordIndex; + cmd.Parameters["@groupid"].Value = this.favListIds[i]; + cmd.Parameters["@order"].Value = num; + cmd.Parameters["@type"].Value = (chan.SignalSource & SignalSource.Tv) != 0 ? 0 : 1; + cmd.ExecuteNonQuery(); + } + } + } + #endregion + } +} diff --git a/source/ChanSort.Loader.VisionEdge4K/VisionEdge4KPlugin.cs b/source/ChanSort.Loader.VisionEdge4K/VisionEdge4KPlugin.cs new file mode 100644 index 0000000..af9ddf8 --- /dev/null +++ b/source/ChanSort.Loader.VisionEdge4K/VisionEdge4KPlugin.cs @@ -0,0 +1,16 @@ +using ChanSort.Api; + +namespace ChanSort.Loader.VisionEdge4K +{ + public class VisionEdge4KPlugin : ISerializerPlugin + { + public string DllName { get; set; } + public string PluginName => "Vision EDGE 4K (*.db)"; + public string FileFilter => "*.db"; + + public SerializerBase CreateSerializer(string inputFile) + { + return new VisionEdge4KSerializer(inputFile); + } + } +} \ No newline at end of file diff --git a/source/ChanSort.sln b/source/ChanSort.sln index 8a0bd0c..ff16b8e 100644 --- a/source/ChanSort.sln +++ b/source/ChanSort.sln @@ -103,7 +103,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChanSort.Loader.Unsupported EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChanSort.Loader.TCL", "ChanSort.Loader.TCL\ChanSort.Loader.TCL.csproj", "{460D9527-F7EF-4277-9382-FB609A44D66A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChanSort.Loader.DBM", "ChanSort.Loader.DBM\ChanSort.Loader.DBM.csproj", "{C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChanSort.Loader.DBM", "ChanSort.Loader.DBM\ChanSort.Loader.DBM.csproj", "{C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChanSort.Loader.VisionEdge4K", "ChanSort.Loader.VisionEdge4K\ChanSort.Loader.VisionEdge4K.csproj", "{71ABCE5E-A833-4729-BC30-35FF0AE01DCA}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -1292,6 +1294,36 @@ Global {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.Release|Mixed Platforms.Build.0 = Release|Any CPU {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.Release|x86.ActiveCfg = Release|Any CPU {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.Release|x86.Build.0 = Release|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.All_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.All_Debug|Any CPU.Build.0 = Debug|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.All_Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.All_Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.All_Debug|x86.ActiveCfg = Debug|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.All_Debug|x86.Build.0 = Debug|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.All_Release|Any CPU.ActiveCfg = Release|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.All_Release|Any CPU.Build.0 = Release|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.All_Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.All_Release|Mixed Platforms.Build.0 = Release|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.All_Release|x86.ActiveCfg = Release|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.All_Release|x86.Build.0 = Release|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.Debug|x86.ActiveCfg = Debug|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.Debug|x86.Build.0 = Debug|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.NoDevExpress_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.NoDevExpress_Debug|Any CPU.Build.0 = Debug|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.NoDevExpress_Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.NoDevExpress_Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.NoDevExpress_Debug|x86.ActiveCfg = Debug|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.NoDevExpress_Debug|x86.Build.0 = Debug|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.Release|Any CPU.Build.0 = Release|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.Release|x86.ActiveCfg = Release|Any CPU + {71ABCE5E-A833-4729-BC30-35FF0AE01DCA}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/source/ChanSort/ChanSort.csproj b/source/ChanSort/ChanSort.csproj index 36b044a..33d9983 100644 --- a/source/ChanSort/ChanSort.csproj +++ b/source/ChanSort/ChanSort.csproj @@ -147,6 +147,7 @@ + diff --git a/source/changelog.md b/source/changelog.md index 30c5237..47b6931 100644 --- a/source/changelog.md +++ b/source/changelog.md @@ -1,6 +1,13 @@ ChanSort Change Log =================== +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) + +2023-01-12 +- TCL: fixed upload failure due to incorrect checksum when DtvData.db was larger than 307200 bytes + 2023-01-10 - TCL: fixed deleting channels diff --git a/source/fileformats.md b/source/fileformats.md index 4993815..7ae60e6 100644 --- a/source/fileformats.md +++ b/source/fileformats.md @@ -110,6 +110,10 @@ Various brands use the same hardware for DVB-S, which exports .sdx files --- Various brands use the same hardware for DVB-S and DVB-C receivers, which export variations of .DBM-files +VISION EDGE 4K +--- +database.db file exported by this DVB-S/C/T set-top-box + VDR (Linux Video Disk Recorder) --- Supports the channels.conf file format. diff --git a/source/fileformats_de.md b/source/fileformats_de.md index 2ae22b6..8bc55f8 100644 --- a/source/fileformats_de.md +++ b/source/fileformats_de.md @@ -110,6 +110,10 @@ Mehrere Marken nutzen die gleiche Hardware f --- Mehrere Marken nutzen die gleiche Hardware für DVB-S und DVB-C Receiver, die .HBM Dateien in unterschiedlichen Varianten exportieren. +VISION EDGE 4K +--- +database.db Datei, die von dieser DVB-S/C/T Set-Top-Box exportiert wird + VDR (Linux Video Disk Recorder) --- Unterstützung des channels.conf Dateiformats.