mirror of
https://github.com/PredatH0r/ChanSort.git
synced 2026-05-07 05:17:26 +02:00
- Philips: fixes for ChannelMap_100, 105 and 110 formats
- Philips: support for FLASH/*.bin DVB-T/C and preset DVB-S lists (mgr_chan_s_pkg.db) - Toshiba: lists with chmgt_type001\\chmgt.bin can now be opened without zipping them - Toshiba: selecting the hotelopt_type001.bin will now also load the list (if the type is supported) - Alden: added support for "Alden" Android SmartTV channel list format (dvr_rtk_tv.db)
This commit is contained in:
@@ -9,6 +9,9 @@ namespace ChanSort.Api
|
||||
{
|
||||
public abstract class SerializerBase : IDisposable
|
||||
{
|
||||
public const string ERR_UnknownFormat = "unknown channel list format";
|
||||
public const string ERR_UnsupportedFormat = "Detected a known but unsupported channel list format: {0}";
|
||||
|
||||
#region class SupportedFeatures
|
||||
|
||||
public enum DeleteMode
|
||||
|
||||
229
source/ChanSort.Loader.Android/AldenSerializer.cs
Normal file
229
source/ChanSort.Loader.Android/AldenSerializer.cs
Normal file
@@ -0,0 +1,229 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using ChanSort.Api;
|
||||
|
||||
namespace ChanSort.Loader.Android
|
||||
{
|
||||
/*
|
||||
|
||||
Android TVs typically store a SQLite based data file containing an "android_metadata" table. The rest differs from brand to brand.
|
||||
|
||||
Philips ChannelMap_30 and _45 use the android database format for the tv.db file. That's handled in the Philips loaders, not here.
|
||||
|
||||
Alden uses a variant very similar to Philips, but instead of a single "channels" table containing channels from all sources,
|
||||
it has distinct (atv|dtv)_(cable|antena|satellite)_channels tables. And TV and Radio channels are also put in different lists, starting at 1 each
|
||||
|
||||
*/
|
||||
public class AldenSerializer : SerializerBase
|
||||
{
|
||||
private readonly ChannelList analChannels = new ChannelList(SignalSource.Analog, "Analog");
|
||||
private readonly ChannelList dvbtTvChannels = new ChannelList(SignalSource.DvbT|SignalSource.Tv, "DVB-T TV");
|
||||
private readonly ChannelList dvbtRadioChannels = new ChannelList(SignalSource.DvbT|SignalSource.Radio, "DVB-T Radio");
|
||||
private readonly ChannelList dvbtDataChannels = new ChannelList(SignalSource.DvbT | SignalSource.Data, "DVB-T Data");
|
||||
private readonly ChannelList dvbcTvChannels = new ChannelList(SignalSource.DvbC|SignalSource.Tv, "DVB-C TV");
|
||||
private readonly ChannelList dvbcRadioChannels = new ChannelList(SignalSource.DvbC|SignalSource.Radio, "DVB-C Radio");
|
||||
private readonly ChannelList dvbcDataChannels = new ChannelList(SignalSource.DvbC | SignalSource.Data, "DVB-C Data");
|
||||
private readonly ChannelList dvbsTvChannels = new ChannelList(SignalSource.DvbS|SignalSource.Tv, "DVB-S TV");
|
||||
private readonly ChannelList dvbsRadioChannels = new ChannelList(SignalSource.DvbS|SignalSource.Radio, "DVB-S Radio");
|
||||
private readonly ChannelList dvbsDataChannels = new ChannelList(SignalSource.DvbS | SignalSource.Data, "DVB-S Data");
|
||||
|
||||
private readonly StringBuilder logMessages = new StringBuilder();
|
||||
|
||||
private readonly Tuple<string, ChannelList, ChannelList, ChannelList>[] subLists;
|
||||
|
||||
|
||||
#region ctor()
|
||||
public AldenSerializer(string inputFile) : base(inputFile)
|
||||
{
|
||||
this.Features.ChannelNameEdit = ChannelNameEditMode.None;
|
||||
this.Features.CanSkipChannels = true;
|
||||
this.Features.CanLockChannels = true;
|
||||
this.Features.CanHideChannels = true;
|
||||
this.Features.DeleteMode = DeleteMode.Physically;
|
||||
this.Features.CanSaveAs = true;
|
||||
this.Features.CanHaveGaps = true; // at least the DVB-S Data list had gaps
|
||||
this.Features.FavoritesMode = FavoritesMode.OrderedPerSource;
|
||||
this.Features.MaxFavoriteLists = 1;
|
||||
this.Features.AllowGapsInFavNumbers = false;
|
||||
this.Features.CanEditFavListNames = false;
|
||||
|
||||
this.subLists = new[]
|
||||
{
|
||||
Tuple.Create("atv_cable_channels", analChannels, (ChannelList)null, (ChannelList)null),
|
||||
Tuple.Create("dtv_antena_channels", dvbtTvChannels, dvbtRadioChannels, dvbtDataChannels),
|
||||
Tuple.Create("dtv_cable_channels", dvbcTvChannels, dvbcRadioChannels, dvbcDataChannels),
|
||||
Tuple.Create("dtv_satellite_channels", dvbsTvChannels, dvbsRadioChannels, dvbsDataChannels)
|
||||
};
|
||||
|
||||
foreach (var subList in subLists)
|
||||
{
|
||||
this.DataRoot.AddChannelList(subList.Item2);
|
||||
if (subList.Item3 != null)
|
||||
this.DataRoot.AddChannelList(subList.Item3);
|
||||
if (subList.Item4 != null)
|
||||
this.DataRoot.AddChannelList(subList.Item4);
|
||||
}
|
||||
|
||||
foreach (var list in this.DataRoot.ChannelLists)
|
||||
{
|
||||
list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.ShortName));
|
||||
list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.ServiceType));
|
||||
list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.ServiceTypeName));
|
||||
list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.Satellite));
|
||||
list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.Provider));
|
||||
list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.PcrPid));
|
||||
list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.VideoPid));
|
||||
list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.AudioPid));
|
||||
list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.ChannelOrTransponder));
|
||||
list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.Provider));
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
// loading
|
||||
|
||||
#region Load()
|
||||
public override void Load()
|
||||
{
|
||||
using var conn = new SqliteConnection($"Data Source={this.FileName}");
|
||||
conn.Open();
|
||||
using var cmd = conn.CreateCommand();
|
||||
|
||||
foreach (var table in new[] { "dtv_satellite_channels" })
|
||||
{
|
||||
cmd.CommandText = $"select count(1) from sqlite_master where type='table' and name='{table}'";
|
||||
if ((long)cmd.ExecuteScalar() == 0)
|
||||
throw new FileLoadException(ERR_UnknownFormat);
|
||||
}
|
||||
|
||||
var columns = "_id, type, service_type, original_network_id, transport_stream_id, service_id, display_number, display_name, browsable, searchable, locked, "
|
||||
+ "internal_provider_flag1, internal_provider_flag4, favorite, scrambled, channel_index";
|
||||
var fields = columns.Split(',');
|
||||
var c = new Dictionary<string, int>();
|
||||
for (int i = 0; i < fields.Length; i++)
|
||||
c[fields[i].Trim()] = i;
|
||||
|
||||
|
||||
foreach (var subList in this.subLists)
|
||||
{
|
||||
cmd.CommandText = $"select count(1) from sqlite_master where type='table' and name='{subList.Item1}'";
|
||||
if ((long)cmd.ExecuteScalar() == 0)
|
||||
continue;
|
||||
|
||||
cmd.CommandText = $"select {columns} from {subList.Item1}";
|
||||
using var r = cmd.ExecuteReader();
|
||||
|
||||
while (r.Read())
|
||||
{
|
||||
var ch = new ChannelInfo(SignalSource.DvbS, r.GetInt32(c["_id"]), r.GetInt32(c["display_number"]), r.GetString(c["display_name"]));
|
||||
ch.OriginalNetworkId = r.GetInt16(c["original_network_id"]);
|
||||
ch.TransportStreamId = r.GetInt16(c["transport_stream_id"]);
|
||||
ch.ServiceId = r.GetInt16(c["service_id"]);
|
||||
ch.Hidden = r.GetInt16(c["browsable"]) == 0;
|
||||
ch.Skip = r.GetInt16(c["searchable"]) == 0;
|
||||
ch.Lock = r.GetInt16(c["locked"]) != 0;
|
||||
ch.FreqInMhz = (decimal)r.GetInt64(c["internal_provider_flag1"]) / 100000;
|
||||
ch.SymbolRate = r.GetInt32(c["internal_provider_flag4"]) / 1000;
|
||||
var f = r.GetInt32(c["favorite"]); // unknown if this is a flag or an ordered number for a single fav list. assuming the latter for now
|
||||
ch.SetOldPosition(1, f == 0 ? -1 : f);
|
||||
ch.Encrypted = r.GetBoolean(c["scrambled"]);
|
||||
ch.RecordOrder = r.GetInt32(c["channel_index"]);
|
||||
|
||||
var source = r.GetString(c["service_type"]);
|
||||
ChannelList list;
|
||||
if (source == "SERVICE_TYPE_AUDIO_VIDEO")
|
||||
{
|
||||
list = subList.Item2;
|
||||
ch.SignalSource |= SignalSource.Tv;
|
||||
}
|
||||
else if (source == "SERVICE_TYPE_AUDIO")
|
||||
{
|
||||
list = subList.Item3;
|
||||
ch.SignalSource |= SignalSource.Radio;
|
||||
}
|
||||
else
|
||||
{
|
||||
list = subList.Item4;
|
||||
ch.SignalSource |= SignalSource.Data;
|
||||
}
|
||||
this.DataRoot.AddChannel(list, ch);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Save()
|
||||
/// <summary>
|
||||
/// The "tv.db" file was reported to exist as early as in ChannelMap_25 format and has been seen in formats 30 and 45 too
|
||||
/// </summary>
|
||||
public override void Save(string outputFile)
|
||||
{
|
||||
this.FileName = outputFile;
|
||||
|
||||
using var conn = new SqliteConnection($"Data Source={outputFile}");
|
||||
conn.Open();
|
||||
using var trans = conn.BeginTransaction();
|
||||
using var cmd = conn.CreateCommand();
|
||||
cmd.Parameters.Clear();
|
||||
cmd.Parameters.Add("@id", SqliteType.Integer);
|
||||
cmd.Parameters.Add("@prNum", SqliteType.Text);
|
||||
cmd.Parameters.Add("@name", SqliteType.Text);
|
||||
cmd.Parameters.Add("@browsable", SqliteType.Integer);
|
||||
cmd.Parameters.Add("@searchable", SqliteType.Integer);
|
||||
cmd.Parameters.Add("@locked", SqliteType.Integer);
|
||||
|
||||
using var del = conn.CreateCommand();
|
||||
del.Parameters.Add("@id", SqliteType.Integer);
|
||||
|
||||
foreach (var list in this.DataRoot.ChannelLists)
|
||||
{
|
||||
var table = this.subLists.First(sl => sl.Item2 == list || sl.Item3 == list || sl.Item4 == list).Item1;
|
||||
cmd.CommandText = $"update {table} set display_number=@prNum, display_name=@name, browsable=@browsable, searchable=@searchable, locked=@locked where _id=@id";
|
||||
cmd.Prepare();
|
||||
|
||||
del.CommandText = $"delete from {table} where _id=@id";
|
||||
del.Prepare();
|
||||
|
||||
foreach (var ch in list.Channels)
|
||||
{
|
||||
if (ch.IsProxy)
|
||||
continue;
|
||||
|
||||
if (ch.IsDeleted)
|
||||
{
|
||||
del.Parameters["@id"].Value = ch.RecordOrder;
|
||||
del.ExecuteNonQuery();
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd.Parameters["@id"].Value = ch.RecordIndex;
|
||||
cmd.Parameters["@prNum"].Value = ch.NewProgramNr.ToString();
|
||||
cmd.Parameters["@name"].Value = ch.Name;
|
||||
cmd.Parameters["@browsable"].Value = ch.Hidden ? 0 : 1; // TODO check which one is which (Skip/Hide)
|
||||
cmd.Parameters["@searchable"].Value = ch.Skip ? 0 : 1;
|
||||
cmd.Parameters["@locked"].Value = ch.Lock ? 1 : 0;
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
trans.Commit();
|
||||
conn.Close();
|
||||
}
|
||||
#endregion
|
||||
|
||||
// framework support methods
|
||||
|
||||
#region GetFileInformation
|
||||
public override string GetFileInformation()
|
||||
{
|
||||
return base.GetFileInformation() + this.logMessages.Replace("\n", "\r\n");
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
23
source/ChanSort.Loader.Android/AndroidPlugin.cs
Normal file
23
source/ChanSort.Loader.Android/AndroidPlugin.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System.IO;
|
||||
using ChanSort.Api;
|
||||
|
||||
namespace ChanSort.Loader.Android
|
||||
{
|
||||
public class AndroidPlugin : ISerializerPlugin
|
||||
{
|
||||
public string DllName { get; set; }
|
||||
public string PluginName => "Android (*.db)";
|
||||
public string FileFilter => "*.db";
|
||||
|
||||
public SerializerBase CreateSerializer(string inputFile)
|
||||
{
|
||||
var file = Path.GetFileName(inputFile).ToLowerInvariant();
|
||||
|
||||
// dvr_rtk_tv.db known from "Alden"
|
||||
if (file.StartsWith("dvr_rtk_tv") && file.EndsWith(".db"))
|
||||
return new AldenSerializer(inputFile);
|
||||
|
||||
throw new FileLoadException(SerializerBase.ERR_UnknownFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{5088DB0D-6BDE-4678-8C50-A14E6A294A45}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>ChanSort.Loader.Android</RootNamespace>
|
||||
<AssemblyName>ChanSort.Loader.Android</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Data.Sqlite, Version=5.0.8.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Data.Sqlite.Core.5.0.8\lib\netstandard2.0\Microsoft.Data.Sqlite.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLRaw.batteries_v2, Version=2.0.4.976, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SQLitePCLRaw.bundle_e_sqlite3.2.0.4\lib\net461\SQLitePCLRaw.batteries_v2.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLRaw.core, Version=2.0.4.976, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SQLitePCLRaw.core.2.0.4\lib\netstandard2.0\SQLitePCLRaw.core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLRaw.nativelibrary, Version=2.0.4.976, Culture=neutral, PublicKeyToken=502ed628492ab262, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SQLitePCLRaw.bundle_e_sqlite3.2.0.4\lib\net461\SQLitePCLRaw.nativelibrary.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLRaw.provider.dynamic_cdecl, Version=2.0.4.976, Culture=neutral, PublicKeyToken=b68184102cba0b3b, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.4\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AndroidPlugin.cs" />
|
||||
<Compile Include="AldenSerializer.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ChanSort.Api\ChanSort.Api.csproj">
|
||||
<Project>{dccffa08-472b-4d17-bb90-8f513fc01392}</Project>
|
||||
<Name>ChanSort.Api</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.4\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets" Condition="Exists('..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.4\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.4\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\SQLitePCLRaw.lib.e_sqlite3.2.0.4\build\net461\SQLitePCLRaw.lib.e_sqlite3.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
36
source/ChanSort.Loader.Android/Properties/AssemblyInfo.cs
Normal file
36
source/ChanSort.Loader.Android/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("ChanSort.Loader.Android")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("ChanSort.Loader.Android")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2021")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("5088db0d-6bde-4678-8c50-a14e6a294a45")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
13
source/ChanSort.Loader.Android/packages.config
Normal file
13
source/ChanSort.Loader.Android/packages.config
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Data.Sqlite" version="5.0.8" targetFramework="net48" />
|
||||
<package id="Microsoft.Data.Sqlite.Core" version="5.0.8" targetFramework="net48" />
|
||||
<package id="SQLitePCLRaw.bundle_e_sqlite3" version="2.0.4" targetFramework="net48" />
|
||||
<package id="SQLitePCLRaw.core" version="2.0.4" targetFramework="net48" />
|
||||
<package id="SQLitePCLRaw.lib.e_sqlite3" version="2.0.4" targetFramework="net48" />
|
||||
<package id="SQLitePCLRaw.provider.dynamic_cdecl" version="2.0.4" targetFramework="net48" />
|
||||
<package id="System.Buffers" version="4.4.0" targetFramework="net48" />
|
||||
<package id="System.Memory" version="4.5.3" targetFramework="net48" />
|
||||
<package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net48" />
|
||||
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net48" />
|
||||
</packages>
|
||||
@@ -10,7 +10,6 @@ namespace ChanSort.Loader.Panasonic
|
||||
{
|
||||
class Serializer : SerializerBase
|
||||
{
|
||||
private const string ERR_FileFormatOrEncryption = "File uses an unknown format or encryption";
|
||||
private readonly ChannelList avbtChannels = new ChannelList(SignalSource.AnalogT, "Analog Antenna");
|
||||
private readonly ChannelList avbcChannels = new ChannelList(SignalSource.AnalogC, "Analog Cable");
|
||||
private readonly ChannelList dvbtChannels = new ChannelList(SignalSource.DvbT, "DVB-T");
|
||||
@@ -97,7 +96,7 @@ namespace ChanSort.Loader.Panasonic
|
||||
{
|
||||
this.cypherMode = this.GetCypherMode(this.FileName);
|
||||
if (cypherMode == CypherMode.Unknown)
|
||||
throw new FileLoadException(ERR_FileFormatOrEncryption);
|
||||
throw new FileLoadException(ERR_UnknownFormat);
|
||||
if (cypherMode == CypherMode.None)
|
||||
return this.FileName;
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ reorderRecordsByChannelNumber=false
|
||||
############################################################################
|
||||
# Repair\channel_db_ver.db, atv_chan_phy_c.db, FLASH_DTVINFO_S_FTA, mgr_chan_s_fta.db, ... - experimental
|
||||
# unfortunately read-only because all attempts so far produced inconsistencies between the channels in the menu and what the tuner actually put on screen
|
||||
# There is a program number at offset 0 and another one around 450. My guess is that the 1st is the "new" number and the 2nd the "old" number - or it is the other way around.
|
||||
# When both numbers are updated and also the value of RecordIndex is set to PrNr-1, the TV doesn't show any changes.
|
||||
|
||||
[mgr_chan_s_fta.db]
|
||||
lenHeader=64
|
||||
@@ -15,23 +17,96 @@ lenEntry=476
|
||||
lenFooter=12
|
||||
offFooterChecksum=8
|
||||
reorderRecordsByChannelNumber=false
|
||||
allowEdit=false
|
||||
allowEdit=true
|
||||
|
||||
[mgr_chan_s_fta.db_entry]
|
||||
# there is a program number at offset 0 and 452. My guess is that 0 is the "new" number and 452 the "old" number, which should be left untouched. Or it is the other way around.
|
||||
# when both numbers are updated and also the value at 456 set to PrNr-1, the TV didn't show any changes.
|
||||
offProgNr=0
|
||||
offName=20
|
||||
offFav=16
|
||||
offName=20
|
||||
lenName=200
|
||||
offFreq=444,468
|
||||
offSymbolRate=450
|
||||
offOldProgNr=452
|
||||
offRecordIndex=456
|
||||
offTsid=460
|
||||
offSid=464
|
||||
offOnid=466
|
||||
|
||||
|
||||
|
||||
[mgr_chan_s_pkg.db]
|
||||
lenHeader=64
|
||||
lenEntry=480
|
||||
lenFooter=12
|
||||
offFooterChecksum=8
|
||||
reorderRecordsByChannelNumber=false
|
||||
allowEdit=true
|
||||
|
||||
[mgr_chan_s_pkg.db_entry]
|
||||
offProgNr=0
|
||||
offFav=16
|
||||
offName=20
|
||||
lenName=200
|
||||
offFreq=444,468
|
||||
offSymbolRate=450
|
||||
offOldProgNr=452
|
||||
offRecordIndex=456
|
||||
offTsid=460
|
||||
offSid=464
|
||||
offOnid=466
|
||||
|
||||
|
||||
|
||||
[mgr_chan_dvbt.db]
|
||||
lenHeader=64
|
||||
lenEntry=472
|
||||
lenFooter=12
|
||||
offFooterChecksum=8
|
||||
reorderRecordsByChannelNumber=false
|
||||
allowEdit=true
|
||||
|
||||
[mgr_chan_dvbt.db_entry]
|
||||
offProgNr=0
|
||||
offFav=16
|
||||
offName=20
|
||||
lenName=200
|
||||
offProvider=224
|
||||
lenProvider=200
|
||||
offFreq=440
|
||||
offOldProgNr=448
|
||||
offRecordIndex=456
|
||||
offTsid=460
|
||||
offSymbolRate=462
|
||||
offSid=464
|
||||
offOnid=466
|
||||
|
||||
|
||||
|
||||
[mgr_chan_dvbc.db]
|
||||
lenHeader=64
|
||||
lenEntry=472
|
||||
lenFooter=12
|
||||
offFooterChecksum=8
|
||||
reorderRecordsByChannelNumber=false
|
||||
allowEdit=true
|
||||
|
||||
[mgr_chan_dvbc.db_entry]
|
||||
offProgNr=0
|
||||
offFav=16
|
||||
offName=20
|
||||
lenName=200
|
||||
offProvider=224
|
||||
lenProvider=200
|
||||
offFreq=440
|
||||
offOldProgNr=448
|
||||
offRecordIndex=456
|
||||
offTsid=460
|
||||
offSymbolRate=462
|
||||
offSid=464
|
||||
offOnid=466
|
||||
|
||||
|
||||
|
||||
############################################################################
|
||||
# Repair\ChannelList\chanLst.bin version 1.x with AntennaDigSrvTable, CableDigSrvTable and service.dat (for DVB-S) - should be stable
|
||||
|
||||
|
||||
@@ -11,17 +11,18 @@ namespace ChanSort.Loader.Philips
|
||||
/*
|
||||
* This serializer is used for the channel list format with a Repair\ folder containing files like channel_db_ver.db, mgr_chan_s_fta.db, ...
|
||||
* The .db files are proprietary binary files, not SQLite databases.
|
||||
* So far only the mgr_chan_s_fta.db file holing DVB-S channels is reverse engineered, the offsets are defined in PChanSort.Loader.Philips.ini
|
||||
*
|
||||
* Unfortunately modifying the .db files does not seem to be enough. The TV also depends on channel data in the FLASH_* files, which I don't know how how to edit.
|
||||
* Therefore lists of this format can be read as read-only reference lists, but modifications are disabled.
|
||||
* Due to lack of sample lists, the analog and DVB-C files have not been reverse engineered yet.
|
||||
* The data offsets are defined in ChanSort.Loader.Philips.ini
|
||||
*/
|
||||
class DbSerializer : SerializerBase
|
||||
{
|
||||
private readonly IniFile ini;
|
||||
private readonly List<string> dataFilePaths = new List<string>();
|
||||
|
||||
private readonly ChannelList dvbsChannels = new ChannelList(SignalSource.DvbS, "DVB-S");
|
||||
private readonly ChannelList dvbtChannels = new ChannelList(SignalSource.DvbT, "DVB-T");
|
||||
private readonly ChannelList dvbcChannels = new ChannelList(SignalSource.DvbT, "DVB-C");
|
||||
private readonly ChannelList dvbsFtaChannels = new ChannelList(SignalSource.DvbS | SignalSource.Provider0, "DVB-S FTA");
|
||||
private readonly ChannelList dvbsPkgChannels = new ChannelList(SignalSource.DvbS | SignalSource.Provider1, "DVB-S Preset");
|
||||
private readonly Dictionary<ChannelList, string> fileByList = new();
|
||||
|
||||
|
||||
public DbSerializer(string inputFile) : base(inputFile)
|
||||
@@ -29,27 +30,30 @@ namespace ChanSort.Loader.Philips
|
||||
this.Features.MaxFavoriteLists = 1;
|
||||
this.Features.FavoritesMode = FavoritesMode.OrderedPerSource;
|
||||
this.Features.DeleteMode = DeleteMode.NotSupported;
|
||||
this.Features.CanHaveGaps = false;
|
||||
this.Features.CanHaveGaps = true; // the mgr_chan_s_pkg can have gaps
|
||||
|
||||
string iniFile = Assembly.GetExecutingAssembly().Location.Replace(".dll", ".ini");
|
||||
this.ini = new IniFile(iniFile);
|
||||
|
||||
this.DataRoot.AddChannelList(dvbsChannels);
|
||||
dvbsChannels.VisibleColumnFieldNames = new List<string>
|
||||
this.DataRoot.AddChannelList(dvbtChannels);
|
||||
this.DataRoot.AddChannelList(dvbcChannels);
|
||||
this.DataRoot.AddChannelList(dvbsFtaChannels);
|
||||
this.DataRoot.AddChannelList(dvbsPkgChannels);
|
||||
foreach (var list in this.DataRoot.ChannelLists)
|
||||
{
|
||||
"Position", //nameof(Channel.NewProgramNr),
|
||||
"OldPosition", // nameof(Channel.OldProgramNr),
|
||||
nameof(Channel.Name),
|
||||
nameof(Channel.Favorites),
|
||||
nameof(Channel.FreqInMhz),
|
||||
nameof(Channel.SymbolRate),
|
||||
nameof(Channel.TransportStreamId),
|
||||
nameof(Channel.OriginalNetworkId),
|
||||
nameof(Channel.ServiceId)
|
||||
};
|
||||
|
||||
var sec = ini.GetSection("mgr_chan_s_fta.db");
|
||||
dvbsChannels.ReadOnly = sec.GetBool("allowEdit", false);
|
||||
list.VisibleColumnFieldNames = new List<string>
|
||||
{
|
||||
"Position", //nameof(Channel.NewProgramNr),
|
||||
"OldPosition", // nameof(Channel.OldProgramNr),
|
||||
nameof(Channel.Name),
|
||||
nameof(Channel.Favorites),
|
||||
nameof(Channel.FreqInMhz),
|
||||
nameof(Channel.SymbolRate),
|
||||
nameof(Channel.TransportStreamId),
|
||||
nameof(Channel.OriginalNetworkId),
|
||||
nameof(Channel.ServiceId)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#region Load()
|
||||
@@ -57,23 +61,42 @@ namespace ChanSort.Loader.Philips
|
||||
{
|
||||
bool validList = false;
|
||||
|
||||
foreach (var file in Directory.GetFiles(Path.GetDirectoryName(this.FileName)))
|
||||
foreach (var file in Directory.GetFiles(Path.GetDirectoryName(this.FileName) ?? ""))
|
||||
{
|
||||
var lc = Path.GetFileName(file).ToLowerInvariant();
|
||||
switch (lc)
|
||||
{
|
||||
case "atv_channel_t.db":
|
||||
// TODO: no sample file yet that contains analog terrestrial channels
|
||||
break;
|
||||
case "atv_channel_c.db":
|
||||
// TODO: no sample file yet that contains analog cable channels
|
||||
break;
|
||||
case "channel_db_ver.db":
|
||||
LoadVersion(file);
|
||||
break;
|
||||
case "mgr_chan_dvbt.db":
|
||||
LoadDvb(file, lc, dvbtChannels);
|
||||
validList = true;
|
||||
break;
|
||||
case "mgr_chan_dvbc.db":
|
||||
// no sample file with DVB-C data yet, so this here is a guess based on DVB-T
|
||||
LoadDvb(file, lc, dvbcChannels);
|
||||
validList = true;
|
||||
break;
|
||||
case "mgr_chan_s_fta.db":
|
||||
LoadDvbs(file);
|
||||
LoadDvb(file, lc, dvbsFtaChannels);
|
||||
validList = true;
|
||||
break;
|
||||
case "mgr_chan_s_pkg.db":
|
||||
LoadDvb(file, lc, dvbsPkgChannels);
|
||||
validList = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!validList)
|
||||
throw new FileLoadException(this.FileName + " is not a supported Philips Repair/mgr_chan_s_fta.db channel list");
|
||||
throw new FileLoadException(this.FileName + " is not a supported Philips Repair/channel_db_ver.db channel list");
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -96,7 +119,7 @@ namespace ChanSort.Loader.Philips
|
||||
this.FileFormatVersion += $":{data[6]:D2}";
|
||||
|
||||
// Philips doesn't export any information about the TV model in this format. For automated stats I manually place modelinfo.txt files in the folders
|
||||
for (var dir = Path.GetDirectoryName(file); dir != ""; dir = Path.GetDirectoryName(dir))
|
||||
for (var dir = Path.GetDirectoryName(file); dir != null; dir = Path.GetDirectoryName(dir))
|
||||
{
|
||||
var path = Path.Combine(dir, "modelinfo.txt");
|
||||
if (File.Exists(path))
|
||||
@@ -109,11 +132,12 @@ namespace ChanSort.Loader.Philips
|
||||
#endregion
|
||||
|
||||
#region LoadDvbs()
|
||||
private void LoadDvbs(string file)
|
||||
private void LoadDvb(string path, string sectionName, ChannelList list)
|
||||
{
|
||||
var data = File.ReadAllBytes(file);
|
||||
var signalSource = list.SignalSource;
|
||||
var data = File.ReadAllBytes(path);
|
||||
|
||||
var sec = ini.GetSection("mgr_chan_s_fta.db");
|
||||
var sec = ini.GetSection(sectionName);
|
||||
var lenHeader = sec.GetInt("lenHeader");
|
||||
var lenFooter = sec.GetInt("lenFooter");
|
||||
var lenEntry = sec.GetInt("lenEntry");
|
||||
@@ -121,9 +145,11 @@ namespace ChanSort.Loader.Philips
|
||||
|
||||
var records = (data.Length - lenHeader - lenFooter) / lenEntry;
|
||||
if (records <= 0)
|
||||
throw new FileLoadException("Currently only DVB-S lists are supported and mgr_chan_s_fta.db contains no channels.");
|
||||
return;
|
||||
|
||||
var mapping = new DataMapping(this.ini.GetSection("mgr_chan_s_fta.db_entry"));
|
||||
list.ReadOnly = !sec.GetBool("allowEdit", false);
|
||||
|
||||
var mapping = new DataMapping(this.ini.GetSection(sectionName + "_entry"));
|
||||
sec = ini.GetSection("mgr_chan_s_fta.db_entry");
|
||||
var lenName = sec.GetInt("lenName");
|
||||
for (int i = 0; i < records; i++)
|
||||
@@ -136,26 +162,30 @@ namespace ChanSort.Loader.Philips
|
||||
var name = data[off + 0] == 0 ? (data[off + 1] == 0 ? "" : Encoding.BigEndianUnicode.GetString(data, off, lenName)) : DefaultEncoding.GetString(data, off, lenName);
|
||||
name = name.TrimEnd('\0');
|
||||
|
||||
var ch = new Channel(SignalSource.DvbS, i, oldProgNr, name);
|
||||
var ch = new Channel(signalSource, i, oldProgNr, name);
|
||||
ch.RecordOrder = i;
|
||||
var favPos = mapping.GetWord("offFav");
|
||||
if (favPos > 0)
|
||||
ch.SetOldPosition(1, favPos);
|
||||
ch.SymbolRate = mapping.GetWord("offSymbolRate");
|
||||
ch.FreqInMhz = mapping.GetWord("offFreq");
|
||||
ch.FreqInMhz = mapping.GetDword("offFreq");
|
||||
if (ch.FreqInMhz > 13000) // DVB-S stores value in MHz, DVB-T in Hz
|
||||
ch.FreqInMhz /= 1000;
|
||||
if (ch.FreqInMhz > 13000)
|
||||
ch.FreqInMhz /= 1000;
|
||||
ch.TransportStreamId = mapping.GetWord("offTsid");
|
||||
ch.OriginalNetworkId = mapping.GetWord("offOnid");
|
||||
ch.ServiceId = mapping.GetWord("offSid");
|
||||
this.DataRoot.AddChannel(dvbsChannels, ch);
|
||||
this.DataRoot.AddChannel(list, ch);
|
||||
}
|
||||
|
||||
var offChecksum = data.Length - lenFooter + offFooterChecksum;
|
||||
var expectedChecksum = BitConverter.ToUInt16(data, offChecksum);
|
||||
var actualChecksum = CalcChecksum(data, 0, offChecksum);
|
||||
if (actualChecksum != expectedChecksum)
|
||||
throw new FileLoadException($"File {file} contains invalid checksum. Expected {expectedChecksum:x4} but calculated {actualChecksum:x4}");
|
||||
throw new FileLoadException($"File {path} contains invalid checksum. Expected {expectedChecksum:x4} but calculated {actualChecksum:x4}");
|
||||
|
||||
this.dataFilePaths.Add(file);
|
||||
this.fileByList[list] = path;
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -177,46 +207,43 @@ namespace ChanSort.Loader.Philips
|
||||
}
|
||||
#endregion
|
||||
|
||||
public override IEnumerable<string> GetDataFilePaths() => this.dataFilePaths.ToList();
|
||||
public override IEnumerable<string> GetDataFilePaths() => this.fileByList.Values.ToList();
|
||||
|
||||
#region Save()
|
||||
|
||||
public override void Save(string tvOutputFile)
|
||||
{
|
||||
foreach (var file in this.dataFilePaths)
|
||||
foreach (var listAndFile in this.fileByList)
|
||||
{
|
||||
var lc = Path.GetFileName(file).ToLowerInvariant();
|
||||
switch (lc)
|
||||
{
|
||||
case "mgr_chan_s_fta.db":
|
||||
SaveDvbs(file);
|
||||
break;
|
||||
}
|
||||
var list = listAndFile.Key;
|
||||
var file = listAndFile.Value;
|
||||
var secName = Path.GetFileName(file).ToLowerInvariant();
|
||||
SaveDvb(file, secName, list);
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveDvbs(string file)
|
||||
private void SaveDvb(string file, string secName, ChannelList list)
|
||||
{
|
||||
var data = File.ReadAllBytes(file);
|
||||
|
||||
var sec = ini.GetSection("mgr_chan_s_fta.db");
|
||||
var sec = ini.GetSection(secName);
|
||||
var lenHeader = sec.GetInt("lenHeader");
|
||||
var lenFooter = sec.GetInt("lenFooter");
|
||||
var lenEntry = sec.GetInt("lenEntry");
|
||||
var offFooterChecksum = sec.GetInt("offFooterChecksum");
|
||||
|
||||
var mapping = new DataMapping(ini.GetSection("mgr_chan_s_fta.db_entry"));
|
||||
var mapping = new DataMapping(ini.GetSection(secName + "_entry"));
|
||||
|
||||
if (sec.GetBool("reorderRecordsByChannelNumber"))
|
||||
{
|
||||
// physically reorder channels
|
||||
var newData = new byte[data.Length];
|
||||
Array.Copy(data, newData, lenHeader);
|
||||
var off = lenHeader + lenEntry * dvbsChannels.Channels.Count;
|
||||
var off = lenHeader + lenEntry * list.Channels.Count;
|
||||
Array.Copy(data, off, newData, off, lenFooter);
|
||||
|
||||
int i = 0;
|
||||
foreach (var ch in dvbsChannels.Channels.OrderBy(c => c.NewProgramNr))
|
||||
foreach (var ch in list.Channels.OrderBy(c => c.NewProgramNr))
|
||||
{
|
||||
off = lenHeader + i * lenEntry;
|
||||
Array.Copy(data, lenHeader + ch.RecordOrder * lenEntry, newData, off, lenEntry);
|
||||
@@ -233,7 +260,7 @@ namespace ChanSort.Loader.Philips
|
||||
else
|
||||
{
|
||||
// update channel data
|
||||
foreach (var ch in dvbsChannels.Channels)
|
||||
foreach (var ch in list.Channels)
|
||||
{
|
||||
mapping.SetDataPtr(data, lenHeader + ch.RecordOrder * lenEntry);
|
||||
mapping.SetWord("offProgNr", ch.NewProgramNr);
|
||||
|
||||
@@ -136,7 +136,7 @@ namespace ChanSort.Loader.Philips
|
||||
if (majorVersion == -1)
|
||||
return new DbSerializer(inputFile);
|
||||
|
||||
throw new FileLoadException($"Philips ChannelMap format version {majorVersion} is not supported.");
|
||||
throw new FileLoadException(majorVersion == int.MinValue ? SerializerBase.ERR_UnknownFormat : $"Philips ChannelMap format version {majorVersion} is not supported (yet).");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
using ChanSort.Api;
|
||||
@@ -378,9 +377,15 @@ namespace ChanSort.Loader.Philips
|
||||
// use special configs for version 100 variants
|
||||
var dir = Path.GetDirectoryName(this.FileName) ?? "";
|
||||
if (File.Exists(Path.Combine(dir, "atv_cmdb.bin")))
|
||||
{
|
||||
this.iniMapSection = ini.GetSection("Map100_cmdb.bin");
|
||||
this.FileFormatVersion += "/cmdb";
|
||||
}
|
||||
else if (File.Exists(Path.Combine(dir, "channelFile.bin")))
|
||||
{
|
||||
this.iniMapSection = ini.GetSection("Map100_channelFile.bin");
|
||||
this.FileFormatVersion += "/channelFile";
|
||||
}
|
||||
|
||||
if (this.iniMapSection?.GetBool("setReorderedFavNumber") ?? false)
|
||||
this.Features.FavoritesMode = FavoritesMode.OrderedPerSource;
|
||||
@@ -762,7 +767,7 @@ namespace ChanSort.Loader.Philips
|
||||
#region ReorderNodes()
|
||||
private void ReorderNodes(FileData file)
|
||||
{
|
||||
var progNrAttrib = file.formatVersion == 1 ? "presetnumber" : "ChannelNumer";
|
||||
var progNrAttrib = file.formatVersion == 1 ? "presetnumber" : "ChannelNumber";
|
||||
|
||||
var nodes = file.doc.DocumentElement.GetElementsByTagName("Channel");
|
||||
var list = new List<XmlElement>();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using ChanSort.Api;
|
||||
using Microsoft.Data.Sqlite;
|
||||
|
||||
@@ -17,6 +18,8 @@ namespace ChanSort.Loader.Toshiba
|
||||
private readonly ChannelList satRadioChannels = new(SignalSource.DvbS | SignalSource.Radio, "Sat-Radio");
|
||||
private readonly ChannelList satTvChannels = new(SignalSource.DvbS | SignalSource.Tv, "Sat-TV");
|
||||
|
||||
private string workingDir;
|
||||
|
||||
#region ctor()
|
||||
|
||||
public ChmgtDbSerializer(string inputFile) : base(inputFile)
|
||||
@@ -41,9 +44,16 @@ namespace ChanSort.Loader.Toshiba
|
||||
|
||||
public override void Load()
|
||||
{
|
||||
UnzipFileToTempFolder();
|
||||
// this.FileName can be either hotelopt_type001.bin (as an anchor for the directory structure), or a .zip file containing that directory structure
|
||||
if (Path.GetExtension(this.FileName).ToLowerInvariant() == ".zip")
|
||||
{
|
||||
UnzipFileToTempFolder();
|
||||
workingDir = this.TempPath;
|
||||
}
|
||||
else
|
||||
workingDir = Path.GetDirectoryName(this.FileName);
|
||||
|
||||
var sysDataConnString = "Data Source=" + TempPath + FILE_dvbSysData_db;
|
||||
var sysDataConnString = "Data Source=" + this.workingDir + FILE_dvbSysData_db;
|
||||
using (var conn = new SqliteConnection(sysDataConnString))
|
||||
{
|
||||
conn.Open();
|
||||
@@ -53,7 +63,7 @@ namespace ChanSort.Loader.Toshiba
|
||||
ReadTransponders(cmd);
|
||||
}
|
||||
|
||||
var mainDataConnString = "Data Source=" + TempPath + FILE_dvbMainData_db;
|
||||
var mainDataConnString = "Data Source=" + this.workingDir + FILE_dvbMainData_db;
|
||||
using (var conn = new SqliteConnection(mainDataConnString))
|
||||
{
|
||||
conn.Open();
|
||||
@@ -61,7 +71,7 @@ namespace ChanSort.Loader.Toshiba
|
||||
ReadCryptInfo(cmd);
|
||||
}
|
||||
|
||||
var channelConnString = "Data Source=" + TempPath + FILE_chmgt_db;
|
||||
var channelConnString = "Data Source=" + this.workingDir + FILE_chmgt_db;
|
||||
using (var conn = new SqliteConnection(channelConnString))
|
||||
{
|
||||
conn.Open();
|
||||
@@ -250,7 +260,7 @@ namespace ChanSort.Loader.Toshiba
|
||||
|
||||
public override void Save(string tvOutputFile)
|
||||
{
|
||||
var channelConnString = "Data Source=" + TempPath + FILE_chmgt_db;
|
||||
var channelConnString = "Data Source=" + this.workingDir + FILE_chmgt_db;
|
||||
using (var conn = new SqliteConnection(channelConnString))
|
||||
{
|
||||
conn.Open();
|
||||
@@ -268,7 +278,8 @@ namespace ChanSort.Loader.Toshiba
|
||||
RepairCorruptedDatabaseImage(cmd);
|
||||
}
|
||||
|
||||
ZipToOutputFile(tvOutputFile);
|
||||
if (Path.GetExtension(this.FileName).ToLowerInvariant() == ".zip")
|
||||
ZipToOutputFile(tvOutputFile);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -6,15 +6,63 @@ namespace ChanSort.Loader.Toshiba
|
||||
public class ToshibaPlugin : ISerializerPlugin
|
||||
{
|
||||
public string DllName { get; set; }
|
||||
public string PluginName => "Toshiba (*.zip, settingsDB.db)";
|
||||
public string FileFilter => "*.zip;*.db";
|
||||
public string PluginName => "Toshiba";
|
||||
public string FileFilter => "*.db;*.bin;*.zip";
|
||||
|
||||
public SerializerBase CreateSerializer(string inputFile)
|
||||
{
|
||||
if (Path.GetExtension(inputFile).ToLowerInvariant() == ".db")
|
||||
var dir = Path.GetDirectoryName(inputFile);
|
||||
var name = Path.GetFileName(inputFile).ToLowerInvariant();
|
||||
var ext = Path.GetExtension(name);
|
||||
const string FILE_hotelopt = "hotelopt_type001.bin";
|
||||
|
||||
// CLONE00001\settingsDB.db
|
||||
if (name == "settingsdb.db")
|
||||
return new SettingsDbSerializer(inputFile);
|
||||
else
|
||||
|
||||
// selecting a chmgt.db, dvbMainData.db or dvbSysData.db directly -> use hotelopt_type001.bin instead
|
||||
if (ext == ".db")
|
||||
{
|
||||
var hotelopt = Path.Combine(Path.GetDirectoryName(dir), FILE_hotelopt);
|
||||
if (File.Exists(hotelopt))
|
||||
return new ChmgtDbSerializer(hotelopt);
|
||||
}
|
||||
|
||||
// hotelopt_type001.bin can belong to different formats
|
||||
if (name == FILE_hotelopt)
|
||||
{
|
||||
if (File.Exists(Path.Combine(dir, "chmgt_type001", "chmgt.db")))
|
||||
return new ChmgtDbSerializer(inputFile);
|
||||
|
||||
// atv_cmdb.bin is handledby the CmdbBin loader
|
||||
if (File.Exists(Path.Combine(dir, "atv_cmdb.bin")))
|
||||
return null;
|
||||
|
||||
// "Acropolis" format with chmgt_type001\*.txt is not supported
|
||||
throw new FileLoadException(string.Format(SerializerBase.ERR_UnsupportedFormat, "Euro*.txt"));
|
||||
}
|
||||
|
||||
// chmgt.db folder structure in a .zip file (for backward-compatibility with older ChanSort versions)
|
||||
if (ext == ".zip")
|
||||
return new ChmgtDbSerializer(inputFile);
|
||||
|
||||
// *.sdx is handled by the SatcoDX loader
|
||||
if (ext == ".sdx")
|
||||
return null;
|
||||
|
||||
// atv_cmdb.bin is handled by the CmdbBin loader
|
||||
if ((name.StartsWith("atv_") || name.StartsWith("dtv_")) && ext == ".bin")
|
||||
return null;
|
||||
|
||||
// Hotel\tcl_clone_user.bin
|
||||
if (name.StartsWith("tcl_clone_") && name.EndsWith(".bin"))
|
||||
throw new FileLoadException(string.Format(SerializerBase.ERR_UnsupportedFormat, "tcl_clone_user.bin"));
|
||||
|
||||
// HOTEL_*.bin
|
||||
if (name.StartsWith("hotel_") && name.EndsWith(".bin"))
|
||||
throw new FileLoadException(string.Format(SerializerBase.ERR_UnsupportedFormat, "HOTEL_*.bin"));
|
||||
|
||||
throw new FileLoadException(SerializerBase.ERR_UnknownFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,6 +90,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChanSort.Loader.LG.UI", "Ch
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChanSort.Loader.CmdbBin", "ChanSort.Loader.CmdbBin\ChanSort.Loader.CmdbBin.csproj", "{B594DDA4-7BD5-450E-B648-668E0F659813}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChanSort.Loader.Android", "ChanSort.Loader.Android\ChanSort.Loader.Android.csproj", "{5088DB0D-6BDE-4678-8C50-A14E6A294A45}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
All_Debug|Any CPU = All_Debug|Any CPU
|
||||
@@ -1097,6 +1099,36 @@ Global
|
||||
{B594DDA4-7BD5-450E-B648-668E0F659813}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{B594DDA4-7BD5-450E-B648-668E0F659813}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{B594DDA4-7BD5-450E-B648-668E0F659813}.Release|x86.Build.0 = Release|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.All_Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.All_Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.All_Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.All_Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.All_Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.All_Debug|x86.Build.0 = Debug|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.All_Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.All_Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.All_Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.All_Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.All_Release|x86.ActiveCfg = Release|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.All_Release|x86.Build.0 = Release|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.NoDevExpress_Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.NoDevExpress_Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.NoDevExpress_Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.NoDevExpress_Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.NoDevExpress_Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.NoDevExpress_Debug|x86.Build.0 = Debug|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{5088DB0D-6BDE-4678-8C50-A14E6A294A45}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -522,6 +522,14 @@
|
||||
<Project>{DCCFFA08-472B-4D17-BB90-8F513FC01392}</Project>
|
||||
<Name>ChanSort.Api</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ChanSort.Loader.Android\ChanSort.Loader.Android.csproj">
|
||||
<Project>{5088db0d-6bde-4678-8c50-a14e6a294a45}</Project>
|
||||
<Name>ChanSort.Loader.Android</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ChanSort.Loader.CmdbBin\ChanSort.Loader.CmdbBin.csproj">
|
||||
<Project>{b594dda4-7bd5-450e-b648-668e0f659813}</Project>
|
||||
<Name>ChanSort.Loader.CmdbBin</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ChanSort.Loader.Enigma2\ChanSort.Loader.Enigma2.csproj">
|
||||
<Project>{4ad7f77e-617c-4741-82ae-e7a41c85ee4d}</Project>
|
||||
<Name>ChanSort.Loader.Enigma2</Name>
|
||||
|
||||
@@ -567,7 +567,7 @@ namespace ChanSort.Ui
|
||||
{
|
||||
serializer?.Dispose();
|
||||
var errMsg = ex is FileLoadException ? ex.Message : ex.ToString(); // FileLoadExceptions are normal when a Loader does not support a file. No stack trace needed
|
||||
errorMsgs.AppendLine($"{plugin.DllName} ({plugin.PluginName}): {errMsg}\n\n");
|
||||
errorMsgs.AppendLine($"{plugin.PluginName}: {errMsg}\n\n");
|
||||
if (ex is ArgumentException)
|
||||
{
|
||||
var msg = ex.ToString();
|
||||
@@ -614,7 +614,7 @@ namespace ChanSort.Ui
|
||||
this.currentPlugin = plugin;
|
||||
this.currentTvSerializer = serializer;
|
||||
this.DataRoot = serializer.DataRoot;
|
||||
this.AddFileToMruList(tvDataFile);
|
||||
this.AddFileToMruList(serializer.FileName);
|
||||
this.UpdateMruMenu();
|
||||
|
||||
return true;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
@@ -55,11 +55,11 @@
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.3.0" newVersion="4.1.3.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
|
||||
@@ -13,43 +13,30 @@ struct SHeader
|
||||
uint32 channelBlockSize;
|
||||
};
|
||||
|
||||
struct SChannel
|
||||
struct SChannel_fta
|
||||
{
|
||||
uint32 curProgNr;
|
||||
uint32 u1;
|
||||
uint8 u2[8];
|
||||
uint32 favNr;
|
||||
union
|
||||
{
|
||||
char chName1[200];
|
||||
#pragma byte_order (BigEndian)
|
||||
big_endian wchar_t chName2[100];
|
||||
#pragma byte_order ()
|
||||
struct
|
||||
{
|
||||
uint8 zero;
|
||||
wchar_t chName3[99];
|
||||
uint8 zero2;
|
||||
} chName4;
|
||||
} chName;
|
||||
char chName1[200];
|
||||
uint16 u3;
|
||||
uint8 u3b[208];
|
||||
uint8 u3c[2];
|
||||
uint16 u3d;
|
||||
uint8 u4[10];
|
||||
uint16 freqInMhz1;
|
||||
uint16 u5;
|
||||
uint32 freqInMhz1;
|
||||
//uint16 u5;
|
||||
uint16 u6;
|
||||
uint16 symRate;
|
||||
uint32 curProgNr2;
|
||||
uint32 prevProgNr;
|
||||
uint32 oldProgNr;
|
||||
uint32 channelIndex;
|
||||
uint16 tsid;
|
||||
uint16 u7;
|
||||
uint16 sid;
|
||||
uint16 onid;
|
||||
uint16 freqInMhz2;
|
||||
uint16 u9;
|
||||
uint32 u10;
|
||||
uint8 padding[6];
|
||||
};
|
||||
|
||||
struct SFooter
|
||||
@@ -70,8 +57,105 @@ public struct Philips_mgr_chan_s_fta
|
||||
|
||||
SHeader header;
|
||||
|
||||
var recordCount = header.channelBlockSize / sizeof(SChannel);
|
||||
SChannel channels[recordCount];
|
||||
var recordCount = header.channelBlockSize / sizeof(SChannel_fta);
|
||||
SChannel_fta channels[recordCount];
|
||||
|
||||
SFooter footer;
|
||||
};
|
||||
|
||||
//#########################################################
|
||||
|
||||
struct SChannel_pkg
|
||||
{
|
||||
uint32 curProgNr;
|
||||
uint32 u1;
|
||||
uint8 u2[8];
|
||||
uint32 favNr;
|
||||
char chName1[200];
|
||||
uint16 u3;
|
||||
uint8 u3b[208];
|
||||
uint8 u3c[2];
|
||||
uint16 u3d;
|
||||
uint8 u4[10];
|
||||
uint32 freqInMhz1;
|
||||
//uint16 u5;
|
||||
uint16 u6;
|
||||
uint16 symRate;
|
||||
uint32 oldProgNr;
|
||||
uint32 channelIndex;
|
||||
uint16 tsid;
|
||||
uint16 u7;
|
||||
uint16 sid;
|
||||
uint16 onid;
|
||||
uint16 freqInMhz2;
|
||||
uint8 padding[10];
|
||||
};
|
||||
|
||||
public struct Philips_mgr_chan_s_pkg
|
||||
{
|
||||
var docSize = GetDocumentSize();
|
||||
|
||||
char filename[32];
|
||||
|
||||
SHeader header;
|
||||
|
||||
var recordCount = header.channelBlockSize / sizeof(SChannel_pkg);
|
||||
SChannel_pkg channels[recordCount];
|
||||
|
||||
SFooter footer;
|
||||
};
|
||||
|
||||
//#########################################################
|
||||
|
||||
struct CChannel
|
||||
{
|
||||
uint32 curProgNr;
|
||||
uint32 u1;
|
||||
uint8 u2[8];
|
||||
uint32 favNr;
|
||||
union
|
||||
{
|
||||
char chName1[200];
|
||||
#pragma byte_order (BigEndian)
|
||||
big_endian wchar_t chName2[100];
|
||||
#pragma byte_order ()
|
||||
struct
|
||||
{
|
||||
uint8 zero;
|
||||
wchar_t chName3[99];
|
||||
uint8 zero2;
|
||||
} chName4;
|
||||
} chName;
|
||||
uint16 u3;
|
||||
uint16 u3b;
|
||||
char provider[200];
|
||||
uint8 u4[16];
|
||||
uint32 freqInHz;
|
||||
uint16 u6;
|
||||
uint16 not_symRate;
|
||||
uint32 oldProgNr;
|
||||
uint8 u7[4];
|
||||
uint32 channelIndex;
|
||||
uint16 tsid;
|
||||
uint16 symRate_maybe;
|
||||
uint16 sid;
|
||||
uint16 onid;
|
||||
//uint16 freqInMhz2;
|
||||
//uint16 u9;
|
||||
uint32 u10;
|
||||
};
|
||||
|
||||
|
||||
public struct Philips_mgr_chan_dvbt
|
||||
{
|
||||
var docSize = GetDocumentSize();
|
||||
|
||||
char filename[32];
|
||||
|
||||
SHeader header;
|
||||
|
||||
var recordCount = header.channelBlockSize / sizeof(CChannel);
|
||||
CChannel channels[recordCount];
|
||||
|
||||
SFooter footer;
|
||||
};
|
||||
@@ -1,5 +1,13 @@
|
||||
ChanSort Change Log
|
||||
===================
|
||||
|
||||
2021-09-06
|
||||
- Philips: fixes for ChannelMap_100, 105 and 110 formats
|
||||
- Philips: support for FLASH/*.bin DVB-T/C and preset DVB-S lists (mgr_chan_s_pkg.db)
|
||||
- Toshiba: lists with chmgt_type001\\chmgt.bin can now be opened without zipping them
|
||||
- Toshiba: selecting the hotelopt_type001.bin will now also load the list (if the type is supported)
|
||||
- Alden: added support for "Alden" Android SmartTV channel list format (dvr_rtk_tv.db)
|
||||
|
||||
2021-09-05_2010
|
||||
- Philips: fixed wrong .ini settings for formats 100, 105 and 110
|
||||
|
||||
@@ -11,7 +19,7 @@ ChanSort Change Log
|
||||
- one that exports \*cmdb\*.bin files is now fully tested and working.
|
||||
- ones that export only .xml files inside the channellib and s2channellib folders should work too, but not confirmed.
|
||||
- Philips: ChannelFormat_105 and 110 specific settings in .ini, currently best-effort without user confirmation.
|
||||
- Philips: added support for Repair\\Mgr_chan_s_fta.db lists. Can be read as a reference list, but editing is
|
||||
- Philips: added support for Repair\\mgr_chan_s_fta.db lists. Can be read as a reference list, but editing is
|
||||
currently disabled in the .ini file (enabling it is experimental)
|
||||
- added experimental support for 8 variants of "dtv_cmdb_2.bin" DVB-S channel lists (DVB-C/T not supported yet).
|
||||
Brands known to use this format include Sharp, Toshiba, Dyon, OK.
|
||||
|
||||
Reference in New Issue
Block a user