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
---