- 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
This commit is contained in:
Horst Beham
2023-01-14 20:46:07 +01:00
parent a14c89224f
commit 73cc50590d
3 changed files with 149 additions and 97 deletions

View File

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

View File

@@ -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<string> tableNames = new();
private readonly List<int> favListIds = new();
private readonly Dictionary<int, int> favListIndexById = new();
private readonly Dictionary<int, ChannelList> 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<int, int>();
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();
}

View File

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