diff --git a/source/ChanSort.Api/Controller/TxtRefListSerializer.cs b/source/ChanSort.Api/Controller/TxtRefListSerializer.cs index a2ea093b..b556ddb4 100644 --- a/source/ChanSort.Api/Controller/TxtRefListSerializer.cs +++ b/source/ChanSort.Api/Controller/TxtRefListSerializer.cs @@ -4,6 +4,9 @@ namespace ChanSort.Api { + /// + /// This class reads .txt files where each line has the format: progNr;name;onid-tsid-sid + /// public class TxtRefListSerializer : SerializerBase { private static readonly char[] Separators = { ';' }; @@ -68,7 +71,7 @@ private void ReadChannels() if (!int.TryParse(parts[0], out progNr)) continue; - var channel = new ChannelInfo(SignalSource.All, lineNr, progNr, parts[1]); + var channel = new ChannelInfo(SignalSource.Any, lineNr, progNr, parts[1]); if (parts.Length >= 3) { var subParts = parts[2].Split('-'); @@ -84,7 +87,6 @@ private void ReadChannels() } } this.DataRoot.AddChannel(this.allChannels, channel); - lineNr++; } } diff --git a/source/ChanSort.Api/Utils/ListDictionary.cs b/source/ChanSort.Api/Utils/ListDictionary.cs new file mode 100644 index 00000000..1220dc71 --- /dev/null +++ b/source/ChanSort.Api/Utils/ListDictionary.cs @@ -0,0 +1,88 @@ +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; + +namespace ChanSort.Api.Utils; + +public class ListDictionary : IDictionary +{ + private readonly ListDictionary dict = new(); + + public IEnumerator> GetEnumerator() => (IEnumerator>)dict.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => dict.GetEnumerator(); + public void Add(KeyValuePair item) => dict.Add(item.Key, item.Value); + public void Clear() => dict.Clear(); + + public bool Contains(KeyValuePair item) + { + var val = dict[item.Key]; + return val != null && Equals(val, item.Value); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + var i = arrayIndex; + foreach (DictionaryEntry entry in dict) + array[i++] = new KeyValuePair((K)entry.Key, (V)entry.Value); + } + + public bool Remove(KeyValuePair item) + { + var val = dict[item.Key]; + if (val != null && Equals(val, item.Value)) + { + dict.Remove(item.Key); + return true; + } + + return false; + } + + public int Count => dict.Count; + public bool IsReadOnly => dict.IsReadOnly; + public bool ContainsKey(K key) => dict.Contains(key); + + public void Add(K key, V value) => dict.Add(key, value); + + public bool Remove(K key) + { + if (!dict.Contains(key)) + return false; + + dict.Remove(key); + return true; + } + + public bool TryGetValue(K key, out V value) + { + var obj = dict[key]; + if (obj == null) + { + value = default; + return false; + } + + value = (V)obj; + return true; + } + + public V this[K key] + { + get => (V)dict[key]; + set => dict[key] = value; + } + + public ICollection Keys => (ICollection)dict.Keys; + + public ICollection Values + { + get + { + var list = new List(); + foreach(DictionaryEntry e in dict) + list.Add((V)e.Value); + return list; + } + } +} \ No newline at end of file diff --git a/source/ChanSort.Loader.Amdb/AmdbSerializer.cs b/source/ChanSort.Loader.Amdb/AmdbSerializer.cs index 7cc0b02a..eb7b7511 100644 --- a/source/ChanSort.Loader.Amdb/AmdbSerializer.cs +++ b/source/ChanSort.Loader.Amdb/AmdbSerializer.cs @@ -1,20 +1,29 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Microsoft.Data.Sqlite; using ChanSort.Api; +using ChanSort.Api.Utils; namespace ChanSort.Loader.Amdb { /* * This class loads amdb*.db files from unknown Android set-top-boxes. + * The srv_table contains two columns which somehow represent an order, but neither is the actual program number as shown in the menu. + * chan_num: seems to be grouped by service type (TV, Radio, Other) across satellites, each group starting at 1 + * chan_order: is probably the order in which the channels where found during the scan. mostly ordered by satellite, but not strictly + * major_chan_num: always 0 (for DVB-S) + * Regardless of these columns, the receiver displays each combination of TV/Radio and satellite as a separate list starting at 1 */ class AmdbSerializer : SerializerBase { private readonly HashSet tableNames = new(); - private readonly ChannelList tv = new (SignalSource.Tv, "TV"); - private readonly ChannelList radio = new(SignalSource.Radio, "Radio"); - private readonly ChannelList data = new(SignalSource.Data, "Data"); + private readonly IDictionary, ChannelList> listBySatellite = new ListDictionary, ChannelList>(); + private static readonly SignalSource[] SignalSources = { SignalSource.Tv, SignalSource.Radio, SignalSource.Data }; + private static readonly string[] SignalSourceNames = { "TV", "Radio", "Other" }; + + private readonly Dictionary onidByNetId = new Dictionary(); #region ctor() public AmdbSerializer(string inputFile) : base(inputFile) @@ -27,10 +36,6 @@ public AmdbSerializer(string inputFile) : base(inputFile) this.Features.CanHaveGaps = false; this.Features.AllowGapsInFavNumbers = false; this.Features.FavoritesMode = FavoritesMode.None; - - this.DataRoot.AddChannelList(tv); - this.DataRoot.AddChannelList(radio); - this.DataRoot.AddChannelList(data); } #endregion @@ -56,6 +61,7 @@ public override void Load() throw LoaderException.TryNext("File doesn't contain the expected tables"); this.ReadSatellites(cmd); + this.ReadNetworks(cmd); this.ReadTransponders(cmd); this.ReadChannels(cmd); this.AdjustColumns(); @@ -91,31 +97,61 @@ private void ReadSatellites(SqliteCommand cmd) pos = 360 - pos; eastWest = "W"; } + sat.OrbitalPosition = $"{pos / 10}.{pos % 10}{eastWest}"; sat.Name = r.GetString(1); this.DataRoot.AddSatellite(sat); + + int i = 0; + foreach (var ss in SignalSources) + { + var list = new ChannelList(SignalSource.Sat | ss, SignalSourceNames[i++] + " " + sat.Name); + this.listBySatellite[Tuple.Create(ss, sat.Id)] = list; + } + } + + foreach (var entry in this.listBySatellite.OrderBy(e => e.Key.Item1)) + { + if ((entry.Key.Item1 & SignalSource.Data) != 0) + continue; + this.DataRoot.AddChannelList(entry.Value); } } #endregion + #region ReadNetworks() + private void ReadNetworks(SqliteCommand cmd) + { + cmd.CommandText = "select db_id, network_id from net_table"; + using var r = cmd.ExecuteReader(); + while (r.Read()) + onidByNetId[r.GetInt32(0)] = r.GetInt32(1); + } + #endregion + #region ReadTransponders() private void ReadTransponders(SqliteCommand cmd) { - cmd.CommandText = "select db_id, db_sat_para_id, freq, polar, symb from ts_table"; + cmd.CommandText = "select db_id, db_sat_para_id, db_net_id, ts_id, freq, polar, symb from ts_table"; using var r = cmd.ExecuteReader(); while (r.Read()) { int id = r.GetInt32(0); int satId = r.GetInt32(1); - int freq = r.GetInt32(2); + var netId = r.GetInt32(2); + var tsid = r.GetInt32(3); + int freq = r.GetInt32(4); if (this.DataRoot.Transponder.TryGet(id) != null) continue; Transponder tp = new Transponder(id); + tp.TransportStreamId = tsid; tp.FrequencyInMhz = (int)(freq/1000); - tp.Polarity = r.GetInt32(3) == 0 ? 'H' : 'V'; + tp.Polarity = r.GetInt32(5) == 0 ? 'H' : 'V'; tp.Satellite = this.DataRoot.Satellites.TryGet(satId); - tp.SymbolRate = r.GetInt32(4) / 1000; + this.onidByNetId.TryGetValue(netId, out var onid); + tp.OriginalNetworkId = onid; + tp.SymbolRate = r.GetInt32(6) / 1000; this.DataRoot.AddTransponder(tp.Satellite, tp); } } @@ -125,15 +161,12 @@ private void ReadTransponders(SqliteCommand cmd) private void ReadChannels(SqliteCommand cmd) { int ixP = 0; - int ixST = ixP + 12; - cmd.CommandText = @" select - p.db_id, p.chan_num, p.name, p.service_id, p.vid_pid, p.pcr_pid, p.service_type, p.vid_fmt, p.free_ca_mode, p.lock, p.skip, p.hidden, - t.db_sat_para_id, 0, t.ts_id, t.freq, t.polar, t.symb + p.db_id, p.chan_num, p.name, p.service_id, p.vid_pid, p.pcr_pid, p.service_type, p.vid_fmt, p.free_ca_mode, p.lock, p.skip, p.hidden, p.db_net_id, p.db_ts_id, p.db_sat_para_id from srv_table p left outer join ts_table t on t.db_id=p.db_ts_id -order by p.chan_num"; +order by t.db_sat_para_id, case p.service_type when 0 then 3 when 1 then 0 when 2 then 1 else p.service_type end, p.chan_num"; using var r = cmd.ExecuteReader(); while (r.Read()) @@ -142,8 +175,10 @@ from srv_table p var oldProgNr = r.GetInt32(ixP + 1); var name = r.GetString(ixP + 2); if (name.StartsWith("xxx")) - name = name.Substring(3); - ChannelInfo channel = new ChannelInfo(0, handle, oldProgNr, name); + name = name.Substring(3).Trim(); + + ChannelInfo channel = new ChannelInfo(0, handle, 0, name); + channel.RecordOrder = oldProgNr; channel.ServiceId = r.GetInt32(ixP + 3) & 0x7FFF; channel.VideoPid = r.GetInt32(ixP + 4); channel.PcrPid = r.IsDBNull(ixP + 5) ? 0 : r.GetInt32(ixP + 5); @@ -170,25 +205,32 @@ from srv_table p channel.Skip = r.GetBoolean(ixP + 10); channel.Hidden = r.GetBoolean(ixP + 11); - // DVB-S - if (!r.IsDBNull(ixST + 0)) + var netDbId = r.GetInt32(ixP + 12); + this.onidByNetId.TryGetValue(netDbId, out var onid); + channel.OriginalNetworkId = onid; + + var tsDbId = r.GetInt32(ixP + 13); + DataRoot.Transponder.TryGetValue(tsDbId, out var transponder); + if (transponder != null) { - var 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; - channel.TransportStreamId = r.GetInt32(ixST + 2) & 0x7FFF; - channel.FreqInMhz = r.GetInt32(ixST + 3); + channel.Transponder = transponder; + channel.TransportStreamId = transponder.TransportStreamId; + channel.Satellite = transponder.Satellite?.Name; + channel.SatPosition = transponder.Satellite?.OrbitalPosition; + channel.FreqInMhz = transponder.FrequencyInMhz; if (channel.FreqInMhz > 20000) // DVB-S is in MHz already, DVB-C/T in kHz channel.FreqInMhz /= 1000; - channel.Polarity = r.GetInt32(ixST + 4) == 0 ? 'H' : 'V'; - channel.SymbolRate = r.GetInt32(ixST + 5)/1000; + channel.Polarity = transponder.Polarity; + channel.SymbolRate = transponder.SymbolRate; } - var list = this.DataRoot.GetChannelList(channel.SignalSource); - if (list != null) + var satId = r.GetInt32(ixP + 14); + var key = Tuple.Create(channel.SignalSource & SignalSource.MaskTvRadioData, satId); + if (this.listBySatellite.TryGetValue(key, out var list)) + { + channel.OldProgramNr = list.Count + 1; this.DataRoot.AddChannel(list, channel); + } } } #endregion @@ -229,9 +271,10 @@ public override void Save() #region WriteChannels() private void WriteChannels(SqliteCommand cmd, SqliteCommand cmdDelete) { - cmd.CommandText = "update srv_table set chan_num=@nr, chan_order=@nr, name=@name, skip=@skip, lock=@lock, hidden=@hide where db_id=@handle"; + cmd.CommandText = "update srv_table set chan_num=@num, chan_order=@order, name=@name, skip=@skip, lock=@lock, hidden=@hide where db_id=@handle"; cmd.Parameters.Add("@handle", SqliteType.Integer); - cmd.Parameters.Add("@nr", SqliteType.Integer); + cmd.Parameters.Add("@num", SqliteType.Integer); + cmd.Parameters.Add("@order", SqliteType.Integer); cmd.Parameters.Add("@name", SqliteType.Text); cmd.Parameters.Add("@skip", SqliteType.Integer); cmd.Parameters.Add("@lock", SqliteType.Integer); @@ -242,31 +285,46 @@ private void WriteChannels(SqliteCommand cmd, SqliteCommand cmdDelete) cmdDelete.Parameters.Add("@handle", SqliteType.Integer); cmdDelete.Prepare(); - foreach (var list in this.DataRoot.ChannelLists) + // combine all lists (including "others") into a single one + IEnumerable union = new List(); + foreach (var list in this.listBySatellite.Values) + union = union.Concat(list.Channels); + + var chanOrder = 1; + var allChannels = union.OrderBy(SignalSourceOrder).ThenBy(ch => ch.NewProgramNr).ToList(); + foreach (ChannelInfo channel in allChannels) { - foreach (ChannelInfo channel in list.Channels.OrderBy(ch => (ch.SignalSource & SignalSource.Tv) != 0 ? 0 : 1).ThenBy(ch => ch.NewProgramNr)) + if (channel.IsProxy) // ignore reference list proxy channels + continue; + + if (channel.IsDeleted) + { + cmdDelete.Parameters["@handle"].Value = channel.RecordIndex; + cmdDelete.ExecuteNonQuery(); + } + else { - 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 = "xxx" + 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(); - } + channel.UpdateRawData(); + cmd.Parameters["@handle"].Value = channel.RecordIndex; + cmd.Parameters["@num"].Value = channel.NewProgramNr; + cmd.Parameters["@order"].Value = chanOrder++; + cmd.Parameters["@name"].Value = "xxx" + 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(); } } + + int SignalSourceOrder(ChannelInfo ch) + { + var ss = ch.SignalSource; + if ((ss & SignalSource.Tv) != 0) + return 0; + if ((ss & SignalSource.Radio) != 0) + return 1; + return 2; + } } #endregion } diff --git a/source/ChanSort.Loader.CmdbBin/ChanSort.Loader.CmdbBin.ini b/source/ChanSort.Loader.CmdbBin/ChanSort.Loader.CmdbBin.ini index 221a9895..1feaa9a2 100644 --- a/source/ChanSort.Loader.CmdbBin/ChanSort.Loader.CmdbBin.ini +++ b/source/ChanSort.Loader.CmdbBin/ChanSort.Loader.CmdbBin.ini @@ -244,6 +244,69 @@ offProvider=200 lenProvider=52 + +# Dijitsu LDM538 with 2668 KB, 8 byte header with 0004 + +[dtv_cmdb_2.bin:2731173] +offChannelBitmap=8 +lenChannelBitmap=752 +offChannelRecord=0x2F8 +lenChannelRecord=424 +numChannelRecord=6000 +offTransponderBitmap=0x0026d478 +lenTransponderBitmap=376 +offTransponderRecord=0x0026d5f0 +lenTransponderRecord=52 +numTransponderRecord=3000 +offSatelliteBitmap=0x00296d04 +lenSatelliteBitmap=32 +offSatelliteRecord=0x00296d24 +lenSatelliteRecord=64 +numSatelliteRecord=254 + +[dvbsChannel:424] +;offEncrypted=13 +;maskEncrypted=0x10 +;offSkip=13 +;maskSkip=0x20 +;offLocked=13 +;maskLocked=0x40 +offChannelType=15 +offServiceType=16 +;offFav=18 +;maskFav=1 +offTransponderIndex=20 +offPmtPid=22 +offPcrPid=26 +offVideoPid=28 +offProgramNr=32 +offServiceId=34 +offAudioPid=54 +offName=146 +lenName=40 +offProvider=196 +lenProvider=200 + +;[dvbsTransponder:52] ; already defined above +;offSatelliteIndex=0 +;offTransportStreamId=6 +;offOriginalNetworkId=8 +;offNetworkId=10 +;offTransponderIndex=14 +;offFreqInMhz=16 +;offSymbolRate=28 + +[dvbsSatellite:64] +offName=2 +lenName=32 +offOrbitalPos=50 + + + + + + + # Philips ChannelMap_100 lists - dtv_cmdb_2.bin with 3443 KB #[dtv_cmdb_2.bin:3525205] diff --git a/source/ChanSort.Loader.DBM/ChanSort.Loader.DBM.ini b/source/ChanSort.Loader.DBM/ChanSort.Loader.DBM.ini index 9f4cc719..93b1b98f 100644 --- a/source/ChanSort.Loader.DBM/ChanSort.Loader.DBM.ini +++ b/source/ChanSort.Loader.DBM/ChanSort.Loader.DBM.ini @@ -1,4 +1,52 @@ -[dbm:163772] + +[dbm:74303] +; overall file layout +isDvbS=false +separateTvRadioData=false +offChecksum=0x0000 +offDataLength=0x0002 +offData=0x0006 + +offTransponderBitmap=0x0006 +lenTransponderBitmap=16 +offTransponderData=0x0016 +numTransponder=100 +lenTransponderData=36 + +offChannelBitmap=0x0E3C +lenChannelBitmap=50 +offChannelData=0x0E6E +numChannel=400 +lenChannelData=176 + +;transponder record +offFreq=0 +offSymRate=8 + +;channel record +offName=0 +lenName=64 +offProgNr=64 +offLcn=66 +offTransponderIndex=70 +offServiceType=76 +offHide=77 +maskHide=0x04 +offSkip=77 +maskSkip=0x08 +offLock=77 +maskLock=0x10 +offFavorites=79 +offTsid=96 +offOnid=98 +offSid=100 +offPcrPid=104 +offVideoPid=106 + + +;--------------------------------------- + +[dbm:163772] ; overall file layout isDvbS=false offChecksum=0x0000 diff --git a/source/ChanSort.Loader.DBM/DbmSerializer.cs b/source/ChanSort.Loader.DBM/DbmSerializer.cs index 8eb5a133..44c7e4c6 100644 --- a/source/ChanSort.Loader.DBM/DbmSerializer.cs +++ b/source/ChanSort.Loader.DBM/DbmSerializer.cs @@ -18,6 +18,7 @@ public class DbmSerializer : SerializerBase private IniFile.Section sec; private DataMapping mapping; private bool isDvbS; + private bool separateTvRadioData; private readonly ChannelList allChannels = new(SignalSource.All, "All"); private readonly StringBuilder logMessages = new(); @@ -36,18 +37,6 @@ public DbmSerializer(string inputFile) : base(inputFile) this.Features.AllowGapsInFavNumbers = false; this.Features.CanEditFavListNames = false; - this.DataRoot.AddChannelList(this.allChannels); - - foreach (var list in this.DataRoot.ChannelLists) - { - list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.AudioPid)); - list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.ChannelOrTransponder)); - list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.Provider)); - list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.Encrypted)); - list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.ServiceType)); - list.VisibleColumnFieldNames.Add(nameof(ChannelInfo.ServiceTypeName)); - } - string iniFile = Assembly.GetExecutingAssembly().Location.Replace(".dll", ".ini"); this.ini = new IniFile(iniFile); } @@ -63,6 +52,18 @@ public override void Load() if (sec == null) throw LoaderException.Fail($"No configuration for .DBM files with size {info.Length} in .ini file"); + this.separateTvRadioData = sec.GetBool("separateTvRadioData"); + if (separateTvRadioData) + { + this.DataRoot.AddChannelList(new ChannelList(SignalSource.Tv, "TV")); + this.DataRoot.AddChannelList(new ChannelList(SignalSource.Radio, "Radio")); + this.DataRoot.AddChannelList(new ChannelList(SignalSource.Data, "Data")); + } + else + this.DataRoot.AddChannelList(this.allChannels); + AdjustColumns(); + + this.isDvbS = sec.GetBool("isDvbS"); if (isDvbS) { @@ -89,6 +90,21 @@ public override void Load() } #endregion + #region AdjustColumns() + private void AdjustColumns() + { + foreach (var list in this.DataRoot.ChannelLists) + { + list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.AudioPid)); + list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.ChannelOrTransponder)); + list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.Provider)); + list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.Encrypted)); + list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.ServiceType)); + list.VisibleColumnFieldNames.Add(nameof(ChannelInfo.ServiceTypeName)); + } + } + #endregion + #region ValidateChecksum() private void ValidateChecksum() { @@ -213,7 +229,9 @@ private void LoadChannels() c.SatPosition = sat.OrbitalPosition; } - this.DataRoot.AddChannel(this.allChannels, c); + var list = this.DataRoot.GetChannelList(c.SignalSource); + if (list != null) + this.DataRoot.AddChannel(list, c); } mapping.BaseOffset += recordSize; diff --git a/source/ChanSort.Loader.Panasonic/SvlSerializer.cs b/source/ChanSort.Loader.Panasonic/SvlSerializer.cs index c187d6d2..16ab16b3 100644 --- a/source/ChanSort.Loader.Panasonic/SvlSerializer.cs +++ b/source/ChanSort.Loader.Panasonic/SvlSerializer.cs @@ -5,7 +5,6 @@ using System.Text; using Microsoft.Data.Sqlite; using ChanSort.Api; -using System.Runtime.Remoting.Channels; namespace ChanSort.Loader.Panasonic { @@ -103,7 +102,7 @@ private string GetUncypheredWorkFile() if (cypherMode == CypherMode.None) return this.FileName; - this.TempPath = Path.GetTempFileName(); + this.TempPath = Path.Combine(Path.GetDirectoryName(this.FileName) ?? "", Path.GetFileNameWithoutExtension(this.FileName) + "_decrypted.db"); //Path.GetTempFileName(); this.DeleteTempPath(); if (cypherMode == CypherMode.Encryption) @@ -120,9 +119,9 @@ private CypherMode GetCypherMode(string file) using var stream = File.OpenRead(file); using var rdr = new BinaryReader(stream); uint value = (uint)rdr.ReadInt32(); - if (value == 0x694C5153) return CypherMode.None; // "SQLi" - if (value == 0x42445350) return CypherMode.HeaderAndChecksum; // "PSDB" - if (value == 0xA07DCB50) return CypherMode.Encryption; + if (value == 0x694C5153) return CypherMode.None; // "SQLi", already decrypted svl.db or svl.bin + if (value == 0x42445350) return CypherMode.HeaderAndChecksum; // "PSDB" - svl.bin + if (value == 0xA07DCB50) return CypherMode.Encryption; // svl.db return CypherMode.Unknown; } #endregion diff --git a/source/ChanSort.sln b/source/ChanSort.sln index ce1e8c09..83d89a9c 100644 --- a/source/ChanSort.sln +++ b/source/ChanSort.sln @@ -112,6 +112,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HDD Hex Edit Neo", "HDD Hex Information\FileStructures_for_HHD_Hex_Editor_Neo\chansort.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\chansort.h Information\FileStructures_for_HHD_Hex_Editor_Neo\cvt_database-dat.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\cvt_database-dat.h Information\FileStructures_for_HHD_Hex_Editor_Neo\dbm.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\dbm.h + Information\FileStructures_for_HHD_Hex_Editor_Neo\dtv-cmdb.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\dtv-cmdb.h Information\FileStructures_for_HHD_Hex_Editor_Neo\dtv_cmdb_1-bin.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\dtv_cmdb_1-bin.h Information\FileStructures_for_HHD_Hex_Editor_Neo\dtv_cmdb_2-bin.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\dtv_cmdb_2-bin.h Information\FileStructures_for_HHD_Hex_Editor_Neo\get_doc_size.js = Information\FileStructures_for_HHD_Hex_Editor_Neo\get_doc_size.js diff --git a/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/dbm-163772-dvbc.h b/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/dbm-163772-dvbc.h deleted file mode 100644 index e69de29b..00000000 diff --git a/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/dbm-781736-dvbs.h b/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/dbm-781736-dvbs.h deleted file mode 100644 index e69de29b..00000000 diff --git a/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/dbm-793736-dvbs.h b/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/dbm-793736-dvbs.h deleted file mode 100644 index e69de29b..00000000 diff --git a/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/dbm-948368-dvbs.h b/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/dbm-948368-dvbs.h deleted file mode 100644 index e69de29b..00000000 diff --git a/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/dbm.h b/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/dbm.h index ac0a681d..bad9e15e 100644 --- a/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/dbm.h +++ b/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/dbm.h @@ -97,6 +97,20 @@ public struct DBM switch (GetDocumentSize()) { + case 74303: + // Renkforce 1510 C HD, Telestar digiHD TC 7 + satBitmapLength = 0; + satRecordCount = 0; + satRecordLength = 84; + transponderBitmapLength = 16; + transponderRecordCount = 100; + transponderRecordLength = 36; + unknownDataLength = 22; + channelBitmapLength = 50; + channelRecordCount = 400; + channelRecordLength = 176; + bytesBetweenTransponderIndexAndServiceType = 2; + break; case 163772: // TechniSat DVB-C TS_Programmliste_06_01.DBM satBitmapLength = 0; diff --git a/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/dtv-cmdb.h b/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/dtv-cmdb.h new file mode 100644 index 00000000..b006527b --- /dev/null +++ b/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/dtv-cmdb.h @@ -0,0 +1,151 @@ +#include "chansort.h" +#pragma script("get_doc_size.js") + +/* +structure definition for various variants of MStar (aka MorningStar) DVB-C and DVB-S receiver channel list formats. +Also used by various models from brands like AEG, Akiwa, Auvisio, Boca, Botech, Comag, Dyon, LogiSat, Kjaerulff, Micro, Megasat, Schwaiger, SeaSat, Strong, TechniSat, TeleSystem, Trekstor, Xoro, Zehnder, ... +Typical file names include: vodafone.DBM, HB_DATABASE_6_29.DBM, MAS_HRS8520_23_08_2011.DBM, ... +*/ + +struct s_Satellite +{ + var off0 = current_offset; + word u; + byte Name[34]; + word LowFreq; + word HighFreq; + var off1 = current_offset; + byte u1[50 - (off1 - off0)]; + word OrbitalPos; + + var off1 = current_offset; + byte unk[satRecordLength - (off1 - off0)]; +}; + +struct s_Transponder +{ + var off0 = current_offset; + byte SatIndex; + byte unk1[5]; + word Tsid; + word Onid; + word Nid; + byte u[2]; + word transponderIndex; + word FreqInMhz; + byte unk2[10]; + word SymRate; + var off1 = current_offset; + byte unk[transponderRecordLength - (off1 - off0)]; +}; + +enum e_Favorites : byte +{ + A=0x01, + B=0x04, + C=0x08, + D=0x10 +}; + +enum e_Flags : byte +{ + Encrypted=0x10, + Skip=0x20, + Lock=0x40 +}; + +enum e_ServiceType : byte +{ + TV=1, + Radio=2 +}; + +struct s_Channel +{ + var off0 = current_offset; + word Index; + byte u0[13]; + //e_Flags Flags; + //byte u1; + + byte ChannelType; + byte ServiceType; + + byte u1[3]; + word TransponderIndex; + word PmtPid; + word u2; + word PcrPid; + word VideoPid; + word u3; + word ProgNr; + word ServiceId; + byte u4[14]; + char AudioLang1[4]; + word AudioPid1; + char AudioLang2[4]; + word AudioPid2; + byte u90[84]; + char Name[50]; + char Provider[224]; + + var off1 = current_offset; + byte unk[channelRecordLength - (off1-off0)]; +}; + + +public struct dtv_cmdb_2 +{ + var headerLength = 0; + var channelBitmapLength = 0; + var channelRecordCount = 0; + var channelRecordLength = 0; + var channelBlockUnknownLength = 0; + var transponderBitmapLength = 0; + var transponderRecordCount = 0; + var transponderRecordLength = 0; + var transponderBlockUnknownLength = 0; + var satBitmapLength = 0; + var satRecordCount = 0; + var satRecordLength = 0; + + switch (GetDocumentSize()) + { + case 2731173: + // Dijitsu LDM538 + headerLength = 8; + channelBitmapLength = 750; + channelRecordCount = 6000; + channelRecordLength = 424; + channelBlockUnknownLength = 2; + transponderBitmapLength = 376; + transponderRecordCount = 3200; + transponderBlockUnknownLength = 3348; + transponderRecordLength = 52; + satBitmapLength = 32; + satRecordCount = 254; + satRecordLength = 64; + break; + + default: + $assert(false, "Structure for this file size is not supported"); + break; + } + + byte Header[headerLength]; + + byte ChannelBitmap[channelBitmapLength]; + byte unk[2]; + s_Channel ChannelData[channelRecordCount]; + //byte ChannelBlockUnknown[channelBlockUnknownLength]; + + byte TransponderBitmap[transponderBitmapLength]; + s_Transponder TransponderData[transponderRecordCount]; + byte TransponderBlockUnknown[transponderBlockUnknownLength]; + + byte SatelliteBitmap[satBitmapLength]; + s_Satellite SatelliteData[satRecordCount]; + + byte Extra[*]; +}; + diff --git a/source/changelog.md b/source/changelog.md index a7704c66..71689a05 100644 --- a/source/changelog.md +++ b/source/changelog.md @@ -1,6 +1,15 @@ ChanSort Change Log =================== +2023-10-22 +- fixed loading .txt reference lists +- added support for HB\_DATABASE\_\*.DBM channel lists with file size 74303 + (e.g. Renkforce 1510 C HD, Telestar digiHD TC 7) +- added support for dtv_cmdb_2.bin files with file size 2731173 + (e.g. Dijitsu Android TV with LD-M538 board) +- improved experimental support for amdb\*.db Android STB channel lists + (now grouped by TV and radio for each satellite) + 2023-09-17 - added support for Philips Repair channel list format 2.0 - added experimental support for amdb\*.db Android STB channel lists diff --git a/source/fileformats.md b/source/fileformats.md index a4beda4b..40c5c394 100644 --- a/source/fileformats.md +++ b/source/fileformats.md @@ -51,12 +51,21 @@ Special thanks to Hisense for supporting ChanSort with technical information and Panasonic --- -Most Viera models since 2011 with channel list formats +**Android-TVs** come with different internal hardware, firmware and file formats, so support depends on the model. +- mnt/vendor/tvdata/database/tv.db file (LSW500 and LXW700 series) +- channellist.txt (MX700, MZ800) +- channels.sdx ("fire-OS" MXW834) +- NOT supported: CLONE00001/settingsDB\_enc.db (JXW600) +- NOT supported: hotel\_setup/Channel\_list/channel\_list.bin (JXW800) +On some models you can export/import the list by selecting "Input: Cable" (or any other TV source), then +open the menu, Channels, Export/Import. +Other models require to use the secret hotel menu: Menu / Picture / Picture Mode / User Defined / Contrast / 6x ok. + +**Viera** models since 2011 with channel list formats - svl.bin -- svl.db -- Android-TVs of LXS600 and LXW700 series with mnt/vendor/tvdata/database/tv.db file -- NOT supported: models on Vestel plattform, e.g. JXW600 with CLONE00001/settingsDB\_enc.db -- NOT supported: models on MediaTek(?) plattform, e.g. JXW800 with hotel\_setup/Channel\_list/channel\_list.bin +- svl.db (JZT1500, ...) +To export/import files on Viera models, format the USB stick with FAT32 and create an empty file or directory +named hotel.pwd. After plugging in the stick on the TV enter 4850 for TV->USB or 4851 for USB->TV TCL / Thomson --- diff --git a/source/fileformats_de.md b/source/fileformats_de.md index b61cbc3c..eafcad1a 100644 --- a/source/fileformats_de.md +++ b/source/fileformats_de.md @@ -51,12 +51,23 @@ Besonderen Dank verdient Hisense f Panasonic --- -Die meisten Viera-Modelle seit 2011 mit Senderlisten im Format -- svl.bin -- svl.db -- Android-TVs der LXS600 und LXW700 Serie mit mnt/vendor/tvdata/database/tv.db Datei -- NICHT unterstützt: Modelle auf Vestel Plattform, z.B. JXW600 mit CLONE00001/settingsDB\_enc.db -- NICHT unterstützt: Modelle auf MediaTek(?) Plattform, z.B. JXW800 mit hotel\_setup/Channel\_list/channel\_list.bin +**Android-TVs** gibt es mit unterschiedlicher interner hardware, firmware und Senderlistenformaten. Unterstützt werden +- mnt/vendor/tvdata/database/tv.db file (LSW500 and LXW700 series) +- channellist.txt (MX700, MZ800) +- channels.sdx ("fire-OS" MXW834) +- NICHT unterstützt: CLONE00001/settingsDB\_enc.db (JXW600) +- NICHT unterstützt: hotel\_setup/Channel\_list/channel\_list.bin (JXW800) +Bei einigen Modellen kann man die Senderliste importieren/exportieren, indem man "Input: Kabel" (oder eine andere TV-Quelle) +und dann im Menü den Punkt "Kanal". +Bei anderen Modellen ist eventuell nur der Umweg über das geheime Hotel-Menü möglich: +Menü / Bild / Bildmodus / Benutzerdefiniert / Kontrast / 6x Ok. + +**Viera** Modelle mit Senderlisten im Format +- svl.bin +- svl.db (JZT1500, ...) +Zum Exportieren/Importieren wird ein USB stickmit FAT32 benötigt, auf dem man eine leere Datei oder ein Verzeichnis +mit dem Namen "hotel.pwd" erstellt. Nach dem Anstecken an den TV kann man den codes 4850 für TV->USB oder 4851 für +USB->TV eingeben. TCL / Thomson ---