mirror of
https://github.com/PredatH0r/ChanSort.git
synced 2026-05-07 18:15:34 +02:00
- added support for Philips Repair channel list format 2.0
- added experimental support for amdb\*.db Android STB channel lists
This commit is contained in:
16
source/ChanSort.Loader.Amdb/AmdbPlugin.cs
Normal file
16
source/ChanSort.Loader.Amdb/AmdbPlugin.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using ChanSort.Api;
|
||||
|
||||
namespace ChanSort.Loader.Amdb
|
||||
{
|
||||
public class AmdbPlugin : ISerializerPlugin
|
||||
{
|
||||
public string DllName { get; set; }
|
||||
public string PluginName => "AMDB (*.db)";
|
||||
public string FileFilter => "amdb*.db";
|
||||
|
||||
public SerializerBase CreateSerializer(string inputFile)
|
||||
{
|
||||
return new AmdbSerializer(inputFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
273
source/ChanSort.Loader.Amdb/AmdbSerializer.cs
Normal file
273
source/ChanSort.Loader.Amdb/AmdbSerializer.cs
Normal file
@@ -0,0 +1,273 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using ChanSort.Api;
|
||||
|
||||
namespace ChanSort.Loader.Amdb
|
||||
{
|
||||
/*
|
||||
* This class loads amdb*.db files from unknown Android set-top-boxes.
|
||||
*/
|
||||
class AmdbSerializer : SerializerBase
|
||||
{
|
||||
private readonly HashSet<string> 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");
|
||||
|
||||
#region ctor()
|
||||
public AmdbSerializer(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;
|
||||
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
|
||||
|
||||
#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[] { "sat_para_table", "ts_table", "srv_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);
|
||||
this.AdjustColumns();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region RepairCorruptedDatabaseImage()
|
||||
private void RepairCorruptedDatabaseImage(SqliteCommand cmd)
|
||||
{
|
||||
cmd.CommandText = "REINDEX";
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ReadSatellites()
|
||||
private void ReadSatellites(SqliteCommand cmd)
|
||||
{
|
||||
cmd.CommandText = "select db_id, sat_name, sat_longitude from sat_para_table order by db_id";
|
||||
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 db_id, db_sat_para_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);
|
||||
|
||||
if (this.DataRoot.Transponder.TryGet(id) != null)
|
||||
continue;
|
||||
Transponder tp = new Transponder(id);
|
||||
tp.FrequencyInMhz = (int)(freq/1000);
|
||||
tp.Polarity = r.GetInt32(3) == 0 ? 'H' : 'V';
|
||||
tp.Satellite = this.DataRoot.Satellites.TryGet(satId);
|
||||
tp.SymbolRate = r.GetInt32(4) / 1000;
|
||||
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.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
|
||||
from srv_table p
|
||||
left outer join ts_table t on t.db_id=p.db_ts_id
|
||||
order by p.chan_num";
|
||||
|
||||
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);
|
||||
if (name.StartsWith("xxx"))
|
||||
name = name.Substring(3);
|
||||
ChannelInfo channel = new ChannelInfo(0, handle, oldProgNr, name);
|
||||
channel.ServiceId = r.GetInt32(ixP + 3) & 0x7FFF;
|
||||
channel.VideoPid = r.GetInt32(ixP + 4);
|
||||
channel.PcrPid = r.IsDBNull(ixP + 5) ? 0 : r.GetInt32(ixP + 5);
|
||||
var serviceType = r.GetInt32(ixP + 6);
|
||||
var vidFmt = r.GetInt32(ixP + 7);
|
||||
channel.ServiceType = serviceType;
|
||||
if (serviceType == 1)
|
||||
{
|
||||
channel.ServiceTypeName = vidFmt == 2 ? "HD TV" : "TV";
|
||||
channel.SignalSource |= SignalSource.Tv;
|
||||
}
|
||||
else if (serviceType == 2)
|
||||
{
|
||||
channel.ServiceTypeName = "Radio";
|
||||
channel.SignalSource |= SignalSource.Radio;
|
||||
}
|
||||
else
|
||||
{
|
||||
channel.ServiceTypeName = "Data";
|
||||
channel.SignalSource |= 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 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);
|
||||
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;
|
||||
}
|
||||
|
||||
var list = this.DataRoot.GetChannelList(channel.SignalSource);
|
||||
if (list != null)
|
||||
this.DataRoot.AddChannel(list, channel);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region AdjustColumns()
|
||||
private void AdjustColumns()
|
||||
{
|
||||
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));
|
||||
list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.NetworkName));
|
||||
list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.NetworkOperator));
|
||||
}
|
||||
}
|
||||
#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);
|
||||
trans.Commit();
|
||||
|
||||
cmd.Transaction = null;
|
||||
this.RepairCorruptedDatabaseImage(cmd);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#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.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 srv_table where db_id=@handle";
|
||||
cmdDelete.Parameters.Add("@handle", SqliteType.Integer);
|
||||
cmdDelete.Prepare();
|
||||
|
||||
foreach (var list in this.DataRoot.ChannelLists)
|
||||
{
|
||||
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
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
23
source/ChanSort.Loader.Amdb/ChanSort.Loader.Amdb.csproj
Normal file
23
source/ChanSort.Loader.Amdb/ChanSort.Loader.Amdb.csproj
Normal file
@@ -0,0 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<OutputPath>..\Debug\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<OutputPath>..\Release\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="7.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ChanSort.Api\ChanSort.Api.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -11,7 +11,7 @@ namespace ChanSort.Loader.Philips
|
||||
{
|
||||
/*
|
||||
|
||||
This loader handles the file format versions 1.x (*Table and *.dat files), version 25.x-45.x (*Db.bin files + tv.db and list.db)
|
||||
This loader handles the file format versions 1.x, 2.0 (*Table and *.dat files), version 25.x-45.x (*Db.bin files + tv.db and list.db)
|
||||
Version 30.x and 45.x were tested, version 25 is untested due to the lack of any sample files. Based on what I read online, the files are pretty much the
|
||||
same as with Format 45.
|
||||
|
||||
@@ -458,13 +458,17 @@ namespace ChanSort.Loader.Philips
|
||||
throw LoaderException.Fail("Unsupported file content: " + path);
|
||||
}
|
||||
|
||||
var channelCount = recordCount;
|
||||
if (version == 2)
|
||||
channelCount = BitConverter.ToInt16(data, 2); // number of used channels
|
||||
|
||||
this.dataFilePaths.Add(path);
|
||||
|
||||
var dvbStringDecoder = new DvbStringDecoder(this.DefaultEncoding);
|
||||
|
||||
var mapping = new DataMapping(this.ini.GetSection(mappingName));
|
||||
mapping.SetDataPtr(data, 12 + (chanLstBin.VersionMajor <= 11 ? recordCount * 4 : 0));
|
||||
for (int i = 0; i < recordCount; i++, mapping.BaseOffset += recordSize)
|
||||
for (int i = 0; i < channelCount; i++, mapping.BaseOffset += recordSize)
|
||||
{
|
||||
var ch = LoadDvbsChannel(list, mapping, i, dvbStringDecoder);
|
||||
this.DataRoot.AddChannel(list, ch);
|
||||
@@ -542,8 +546,11 @@ namespace ChanSort.Loader.Philips
|
||||
ch.Satellite = t.Satellite?.Name;
|
||||
if (t.OriginalNetworkId != 0)
|
||||
ch.OriginalNetworkId = t.OriginalNetworkId;
|
||||
if (t.TransportStreamId != 0)
|
||||
ch.TransportStreamId = t.TransportStreamId;
|
||||
if (chanLstBin.VersionMajor != 2)
|
||||
{
|
||||
if (t.TransportStreamId != 0) // does not work in version 2.0
|
||||
ch.TransportStreamId = t.TransportStreamId;
|
||||
}
|
||||
}
|
||||
|
||||
return ch;
|
||||
|
||||
@@ -262,6 +262,17 @@ lenName=32
|
||||
offProvider=60
|
||||
lenProvider=32
|
||||
|
||||
[tuneinfo.dat]
|
||||
offSymRate=0
|
||||
offFreq=2
|
||||
maskFreq=0x3FFF
|
||||
offPolarity=2
|
||||
maskPolarity=0x4000
|
||||
offSatIndex=6
|
||||
maskSatIndex=0xFFF0
|
||||
offOnid=16
|
||||
offTsid=18
|
||||
|
||||
[CableDigSrvTable_entry]
|
||||
offChecksum=0
|
||||
offSymbolRate=24
|
||||
|
||||
@@ -133,7 +133,7 @@ namespace ChanSort.Loader.Philips
|
||||
|
||||
if (majorVersion == 0 || majorVersion >= 100 && majorVersion <= 115)
|
||||
return new XmlSerializer(inputFile);
|
||||
if (majorVersion == 1 || majorVersion == 30 || majorVersion == 45) // || majorVersion == 11 // format version 11 is similar to 1.x, but not (yet) supported
|
||||
if (majorVersion == 1 || majorVersion == 2 || majorVersion == 30 || majorVersion == 45) // || majorVersion == 11 // format version 11 is similar to 1.x, but not (yet) supported
|
||||
return new BinarySerializer(inputFile);
|
||||
if (majorVersion == -1)
|
||||
return new DbSerializer(inputFile);
|
||||
|
||||
@@ -156,6 +156,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChanSort.Loader.Medion", "C
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChanSort.Loader.TechniSat", "ChanSort.Loader.TechniSat\ChanSort.Loader.TechniSat.csproj", "{A5C22199-1C51-4265-89CA-A7183F1BDB8B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChanSort.Loader.Amdb", "ChanSort.Loader.Amdb\ChanSort.Loader.Amdb.csproj", "{30E9D084-6F3C-41A9-9B46-846178C91BDB}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
All_Debug|Any CPU = All_Debug|Any CPU
|
||||
@@ -1433,6 +1435,36 @@ Global
|
||||
{A5C22199-1C51-4265-89CA-A7183F1BDB8B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{A5C22199-1C51-4265-89CA-A7183F1BDB8B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{A5C22199-1C51-4265-89CA-A7183F1BDB8B}.Release|x86.Build.0 = Release|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.All_Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.All_Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.All_Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.All_Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.All_Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.All_Debug|x86.Build.0 = Debug|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.All_Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.All_Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.All_Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.All_Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.All_Release|x86.ActiveCfg = Release|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.All_Release|x86.Build.0 = Release|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.NoDevExpress_Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.NoDevExpress_Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.NoDevExpress_Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.NoDevExpress_Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.NoDevExpress_Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.NoDevExpress_Debug|x86.Build.0 = Debug|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{30E9D084-6F3C-41A9-9B46-846178C91BDB}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -125,6 +125,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ChanSort.Api\ChanSort.Api.csproj" />
|
||||
<ProjectReference Include="..\ChanSort.Loader.Amdb\ChanSort.Loader.Amdb.csproj" />
|
||||
<ProjectReference Include="..\ChanSort.Loader.Android\ChanSort.Loader.Android.csproj" />
|
||||
<ProjectReference Include="..\ChanSort.Loader.CmdbBin\ChanSort.Loader.CmdbBin.csproj" />
|
||||
<ProjectReference Include="..\ChanSort.Loader.DBM\ChanSort.Loader.DBM.csproj" />
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
ChanSort Change Log
|
||||
===================
|
||||
|
||||
2023-09-17
|
||||
- added support for Philips Repair channel list format 2.0
|
||||
- added experimental support for amdb\*.db Android STB channel lists
|
||||
|
||||
2023-08-17
|
||||
- fixed error when opening the reference list dialog
|
||||
|
||||
|
||||
Reference in New Issue
Block a user