mirror of
https://github.com/PredatH0r/ChanSort.git
synced 2026-02-28 01:00:43 +01:00
- Philips: added support for ChannelMap_115 format
- Philips: ChannelMap formats 100-115 did not always fill "Source" and "Polarity" columns correctly - Philips: improved experimental support for Philips FLASH\_\*/\*.db file formats (read-only by default, can be enabled in Philips.ini for testing) - added Polish readme and updated translation (by JakubDriver)
This commit is contained in:
@@ -17,94 +17,49 @@
|
||||
; ---------------------------------------------
|
||||
; mappings that are the same for all format variants
|
||||
|
||||
[flash_db]
|
||||
reorderRecordsByChannelNumber=true
|
||||
allowEdit=false
|
||||
|
||||
[mgr_chan_s_fta.db]
|
||||
lenHeader=64
|
||||
lenFooter=12
|
||||
offFooterChecksum=8
|
||||
reorderRecordsByChannelNumber=false
|
||||
allowEdit=false
|
||||
; field mappings needed to calculate variable channel record length: blockSize / (tvChannels + radioChannels)
|
||||
numTvChannels=0x2C
|
||||
numRadioChannels=0x30
|
||||
channelBlockSize=0x3C
|
||||
|
||||
[mgr_chan_s_fta.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_s_pkg.db]
|
||||
lenHeader=64
|
||||
lenFooter=12
|
||||
offFooterChecksum=8
|
||||
reorderRecordsByChannelNumber=false
|
||||
allowEdit=false
|
||||
; field mappings needed to calculate variable channel record length: blockSize / (tvChannels+radioChannels)
|
||||
numTvChannels=0x2C
|
||||
numRadioChannels=0x30
|
||||
channelBlockSize=0x3C
|
||||
|
||||
[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=false
|
||||
; field mappings needed to calculate variable channel record length: blockSize / (tvChannels + radioChannels)
|
||||
numTvChannels=0x2C
|
||||
numRadioChannels=0x30
|
||||
channelBlockSize=0x3C
|
||||
|
||||
[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=false
|
||||
; field mappings needed to calculate variable channel record length: blockSize / (tvChannels + radioChannels)
|
||||
numTvChannels=0x2C
|
||||
numRadioChannels=0x30
|
||||
channelBlockSize=0x3C
|
||||
|
||||
[mgr_chan_dvbc.db_entry]
|
||||
[mgr.db_entry:472]
|
||||
offProgNr=0
|
||||
offFav=16
|
||||
offName=20
|
||||
@@ -119,6 +74,33 @@ offSymbolRate=462
|
||||
offSid=464
|
||||
offOnid=466
|
||||
|
||||
[mgr.db_entry:476]
|
||||
offProgNr=0
|
||||
offFav=16
|
||||
offName=20
|
||||
lenName=200
|
||||
offFreq=444,468
|
||||
offSymbolRate=450
|
||||
offOldProgNr=452
|
||||
offRecordIndex=456
|
||||
offTsid=460
|
||||
offSid=464
|
||||
offOnid=466
|
||||
|
||||
[mgr.db_entry:480]
|
||||
offProgNr=0
|
||||
offFav=16
|
||||
offName=20
|
||||
lenName=200
|
||||
offFreq=444,468
|
||||
offSymbolRate=450
|
||||
offOldProgNr=452
|
||||
offRecordIndex=456
|
||||
offTsid=460
|
||||
offSid=464
|
||||
offOnid=466
|
||||
|
||||
|
||||
; ---------------------------------------------
|
||||
; variant with 476 bytes per entry in mgr_chan_s_fta.db
|
||||
|
||||
|
||||
@@ -38,12 +38,13 @@ namespace ChanSort.Loader.Philips
|
||||
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> dbFileByList = new();
|
||||
private readonly Dictionary<ChannelList, Tuple<string, int>> dbFileByList = new();
|
||||
private readonly Dictionary<ChannelList, Tuple<string, int>> flashFileByList = new();
|
||||
private int dvbtChannelRecordLength;
|
||||
private int dvbcChannelRecordLength;
|
||||
private int ftaChannelRecordLength;
|
||||
private int pkgChannelRecordLength;
|
||||
private readonly bool reorderPhysically;
|
||||
|
||||
|
||||
#region ctor()
|
||||
@@ -57,6 +58,10 @@ namespace ChanSort.Loader.Philips
|
||||
string iniFile = Assembly.GetExecutingAssembly().Location.Replace(".dll", ".ini");
|
||||
this.ini = new IniFile(iniFile);
|
||||
|
||||
var sec = ini.GetSection("flash_db");
|
||||
this.reorderPhysically = sec.GetBool("reorderRecordsByChannelNumber", true);
|
||||
var allowEdit = sec.GetBool("allowEdit", false);
|
||||
|
||||
this.DataRoot.AddChannelList(dvbtChannels);
|
||||
this.DataRoot.AddChannelList(dvbcChannels);
|
||||
this.DataRoot.AddChannelList(dvbsFtaChannels);
|
||||
@@ -82,6 +87,7 @@ namespace ChanSort.Loader.Philips
|
||||
nameof(ChannelInfo.AudioPid),
|
||||
nameof(ChannelInfo.ServiceTypeName)
|
||||
};
|
||||
list.ReadOnly = !allowEdit;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
@@ -132,7 +138,7 @@ namespace ChanSort.Loader.Philips
|
||||
LoadFlash(file, lowercaseFileName, dvbsFtaChannels, ftaChannelRecordLength);
|
||||
break;
|
||||
case "flash_dtvinfo_s_pkg":
|
||||
if (!(dvbsFtaChannels.Count == 0 && dvbsPkgChannels.Count > 0))
|
||||
if (dvbsPkgChannels.Count > 0)
|
||||
LoadFlash(file, lowercaseFileName, dvbsPkgChannels, pkgChannelRecordLength);
|
||||
break;
|
||||
}
|
||||
@@ -203,11 +209,9 @@ namespace ChanSort.Loader.Philips
|
||||
throw new FileLoadException($"File {path} contains invalid checksum. Expected {expectedChecksum:x4} but calculated {actualChecksum:x4}");
|
||||
|
||||
channelRecordLength = lenEntry;
|
||||
|
||||
list.ReadOnly = !sec.GetBool("allowEdit");
|
||||
|
||||
var mapping = new DataMapping(this.ini.GetSection(sectionName + "_entry"));
|
||||
sec = ini.GetSection("mgr_chan_s_fta.db_entry");
|
||||
|
||||
sec = this.ini.GetSection("mgr.db_entry:" + channelRecordLength);
|
||||
var mapping = new DataMapping(sec);
|
||||
var lenName = sec.GetInt("lenName");
|
||||
for (int i = 0; i < records; i++)
|
||||
{
|
||||
@@ -236,7 +240,7 @@ namespace ChanSort.Loader.Philips
|
||||
this.DataRoot.AddChannel(list, ch);
|
||||
}
|
||||
|
||||
this.dbFileByList[list] = path;
|
||||
this.dbFileByList[list] = Tuple.Create(path, channelRecordLength);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -459,7 +463,7 @@ namespace ChanSort.Loader.Philips
|
||||
}
|
||||
#endregion
|
||||
|
||||
public override IEnumerable<string> GetDataFilePaths() => this.dbFileByList.Values.Union(this.flashFileByList.Values.Select(tup => tup.Item1));
|
||||
public override IEnumerable<string> GetDataFilePaths() => this.dbFileByList.Values.Union(this.flashFileByList.Values).Select(tup => tup.Item1);
|
||||
|
||||
#region Save()
|
||||
public override void Save(string tvOutputFile)
|
||||
@@ -468,9 +472,10 @@ namespace ChanSort.Loader.Philips
|
||||
foreach (var listAndFile in this.dbFileByList)
|
||||
{
|
||||
var list = listAndFile.Key;
|
||||
var file = listAndFile.Value;
|
||||
var file = listAndFile.Value.Item1;
|
||||
var lenEntry = listAndFile.Value.Item2;
|
||||
var secName = Path.GetFileName(file).ToLowerInvariant();
|
||||
SaveDvb(file, secName, list);
|
||||
SaveDvb(file, secName, list, lenEntry);
|
||||
}
|
||||
|
||||
// update FLASH_* files
|
||||
@@ -486,30 +491,56 @@ namespace ChanSort.Loader.Philips
|
||||
#endregion
|
||||
|
||||
#region SaveDvb()
|
||||
private void SaveDvb(string file, string secName, ChannelList list)
|
||||
private void SaveDvb(string file, string secName, ChannelList list, int channelRecordLength)
|
||||
{
|
||||
var data = File.ReadAllBytes(file);
|
||||
var oldData = File.ReadAllBytes(file);
|
||||
|
||||
var sec = ini.GetSection(secName);
|
||||
if (!GetValuesFromDvbFileHeader(sec, data, out var lenHeader, out var lenEntry, out _, out var offChecksum))
|
||||
if (!GetValuesFromDvbFileHeader(sec, oldData, out var lenHeader, out var lenEntry, out _, out var offChecksum))
|
||||
return;
|
||||
|
||||
var mapping = new DataMapping(ini.GetSection(secName + "_entry"));
|
||||
foreach (var chan in list.Channels)
|
||||
var newData = new byte[oldData.Length];
|
||||
Array.Copy(oldData, newData, oldData.Length);
|
||||
|
||||
var mapping = new DataMapping(ini.GetSection("mgr.db_entry:" + channelRecordLength));
|
||||
|
||||
if (this.reorderPhysically)
|
||||
{
|
||||
if (chan is not Channel ch)
|
||||
continue;
|
||||
mapping.SetDataPtr(data, lenHeader + (int)ch.RecordIndex * lenEntry);
|
||||
mapping.SetWord("offProgNr", ch.NewProgramNr);
|
||||
mapping.SetWord("offFav", Math.Max(0, ch.GetPosition(1)));
|
||||
int newIndex = 0;
|
||||
foreach (var chan in list.Channels.OrderBy(c => c.NewProgramNr).ThenBy(c => c.RecordIndex))
|
||||
{
|
||||
if (chan is not Channel ch)
|
||||
continue;
|
||||
var newOff = lenHeader + newIndex * lenEntry;
|
||||
Array.Copy(oldData, lenHeader + (int)ch.RecordIndex * lenEntry, newData, newOff, lenEntry);
|
||||
mapping.SetDataPtr(newData, newOff);
|
||||
mapping.SetWord("offProgNr", ch.NewProgramNr);
|
||||
mapping.SetWord("offFav", Math.Max(0, ch.GetPosition(1)));
|
||||
mapping.SetWord("offOldProgNr", ch.NewProgramNr);
|
||||
mapping.SetWord("offRecordIndex", newIndex);
|
||||
//ch.RecordIndex = newIndex; // will be updated when saving the FLASH file
|
||||
++newIndex;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var chan in list.Channels.OrderBy(c => c.NewProgramNr).ThenBy(c => c.RecordIndex))
|
||||
{
|
||||
if (chan is not Channel ch)
|
||||
continue;
|
||||
var newOff = lenHeader + (int)ch.RecordIndex * lenEntry;
|
||||
mapping.SetDataPtr(newData, newOff);
|
||||
mapping.SetWord("offProgNr", ch.NewProgramNr);
|
||||
mapping.SetWord("offFav", Math.Max(0, ch.GetPosition(1)));
|
||||
}
|
||||
}
|
||||
|
||||
// update checksum (only 16 bits are stored)
|
||||
var checksum = CalcChecksum(data, 0, offChecksum);
|
||||
data[offChecksum + 0] = (byte)checksum;
|
||||
data[offChecksum + 1] = (byte)(checksum >> 8);
|
||||
var checksum = CalcChecksum(newData, 0, offChecksum);
|
||||
newData[offChecksum + 0] = (byte)checksum;
|
||||
newData[offChecksum + 1] = (byte)(checksum >> 8);
|
||||
|
||||
File.WriteAllBytes(file, data);
|
||||
File.WriteAllBytes(file, newData);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -523,6 +554,23 @@ namespace ChanSort.Loader.Philips
|
||||
var sec = ini.GetSection(secName + ":" + dbChannelRecordLength, true);
|
||||
var mapping = new DataMapping(sec, data);
|
||||
|
||||
// update channel index->id mapping table to match the indices in the new .db file, which is in order by the new ProgNr
|
||||
if (this.reorderPhysically)
|
||||
{
|
||||
var off = sec.GetInt("offChannelTransponderTable");
|
||||
var num = sec.GetInt("numChannelTransponderTable");
|
||||
var oldTable = new byte[num * 4];
|
||||
Array.Copy(data, off, oldTable, 0, oldTable.Length);
|
||||
int i = 0;
|
||||
foreach (var chan in list.Channels.OrderBy(c => c.NewProgramNr).ThenBy(c => c.RecordIndex))
|
||||
{
|
||||
if (chan is not Channel ch)
|
||||
continue;
|
||||
Array.Copy(oldTable, (int)ch.RecordIndex * 4, data, off + i * 4, 4);
|
||||
ch.RecordIndex = i++;
|
||||
}
|
||||
}
|
||||
|
||||
// in-place update of channel data
|
||||
foreach (var chan in list.Channels)
|
||||
{
|
||||
|
||||
@@ -72,8 +72,10 @@ namespace ChanSort.Loader.Philips
|
||||
* same as 105.0
|
||||
* e.g. 65PUS8535/12, 55PUS7334/12
|
||||
*
|
||||
* version 115.0
|
||||
* same as 110.0
|
||||
*
|
||||
* Version 0.1 and 100-110 are XML based and loaded through the XmlSerializer.
|
||||
* Version 0.1 and 100-115 are XML based and loaded through the XmlSerializer.
|
||||
* Version 1.1 and 1.2 are loaded through the BinSerializer.
|
||||
* Version 0.0, 11.1 and 45.1 are not supported yet.
|
||||
*/
|
||||
@@ -129,7 +131,7 @@ namespace ChanSort.Loader.Philips
|
||||
}
|
||||
}
|
||||
|
||||
if (majorVersion == 0 || majorVersion >= 100 && majorVersion <= 110)
|
||||
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
|
||||
return new BinarySerializer(inputFile);
|
||||
|
||||
@@ -120,4 +120,26 @@
|
||||
<data name="Cancel" xml:space="preserve">
|
||||
<value>Anuluj</value>
|
||||
</data>
|
||||
<data name="InfoIgnoreImportError" xml:space="preserve">
|
||||
<value>Telewizor może niepoprawnie pokazywać, że import się nie powiódł, ale można to zignorować.</value>
|
||||
</data>
|
||||
<data name="InfoRestartAfterImport" xml:space="preserve">
|
||||
<value>INFORMACJE: Po zaimportowaniu listy z powrotem do telewizora odłącz go i podłącz ponownie po kilku sekundach.</value>
|
||||
</data>
|
||||
<data name="WarningChecksumErrorMsg" xml:space="preserve">
|
||||
<value>OSTRZEŻENIE: W załadowanej liście wystąpiły błędy sum kontrolnych!
|
||||
|
||||
Istnieją 2 sytuacje, w których może się to zdarzyć:
|
||||
|
||||
- Wewnętrzna lista kanałów telewizora jest uszkodzona (np. po aktualizacji oprogramowania)
|
||||
Można to rozwiązać, uruchamiając nowe skanowanie kanałów lub resetując telewizor.
|
||||
Następnie ponownie wyeksportuj listę i otwórz ją za pomocą ChanSort.
|
||||
Próba edycji i importu aktualnie uszkodzonego pliku może prowadzić do nieoczekiwanego zachowania telewizora.
|
||||
|
||||
- Bad USB-Stick (złe komórki pamięci lub niezgodny format pliku)
|
||||
Spróbuj użyć pendrive'a <= 16 GB sformatowanego w systemie FAT32 (nie NTFS ani exFAT)</value>
|
||||
</data>
|
||||
<data name="WarningChechsumErrorIgnore" xml:space="preserve">
|
||||
<value>Zignoruj błąd i mimo to edytuj listę</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -41,8 +41,8 @@ namespace ChanSort.Loader.Philips
|
||||
Nevertheless a user reported that swapping DVB-S channels 1 and 2 with Onka on a TV that uses this xml-only format 110 worked for him.
|
||||
|
||||
There seem to be 3 different flavors or the "100" format:
|
||||
One has only .xml files in the channellib and s2channellib folders, does not indent lines in the .xml files, has a fixed number of bytes for channel and satellite names (padded with 0x00) and has no "Scramble" attribute.
|
||||
And a version that has dtv_cmdb_*.bin next to the .xml files, uses 4 spaces for indentation, only writes as many bytes for names as needed and has a "Scramble" attribute.
|
||||
One has only .xml files in the channellib and s2channellib folders, does not indent lines in the .xml files, has a fixed number of bytes for channel and satellite names (padded with 0x00), has no "Scramble" attribute and values 1 and 0 for "Polarization".
|
||||
And a version that has dtv_cmdb_*.bin next to the .xml files, uses 4 spaces for indentation, only writes as many bytes for names as needed, has a "Scramble" attribute and uses values 1 and 2 for "Polarization".
|
||||
While the first seems to work fine when XML nodes are reordered by their new programNr, the latter seems to get confused when the .bin and .xml files have different data record orders. This is still under investigation.
|
||||
The Philips editor does not modify these .bin files, appends 0x00 padding to the channel names, changes indentation to 2 tabs and strips the Scramble attribute. It's likely it wasn't designed for this type of list.
|
||||
|
||||
@@ -89,7 +89,7 @@ namespace ChanSort.Loader.Philips
|
||||
private readonly StringBuilder logMessages = new StringBuilder();
|
||||
private readonly IniFile ini;
|
||||
private IniFile.Section iniMapSection;
|
||||
|
||||
private string polarizationValueForHorizontal = "1";
|
||||
|
||||
#region ctor()
|
||||
public XmlSerializer(string inputFile) : base(inputFile)
|
||||
@@ -381,6 +381,7 @@ namespace ChanSort.Loader.Philips
|
||||
{
|
||||
this.iniMapSection = ini.GetSection("Map100_cmdb.bin");
|
||||
this.FileFormatVersion += "/cmdb";
|
||||
this.polarizationValueForHorizontal = "1"; // TODO validate
|
||||
}
|
||||
else if (File.Exists(Path.Combine(dir, "channelFile.bin")))
|
||||
{
|
||||
@@ -477,17 +478,13 @@ namespace ChanSort.Loader.Philips
|
||||
else
|
||||
chan.SignalSource |= SignalSource.Radio;
|
||||
|
||||
var decoderType = data.TryGet("DecoderType");
|
||||
if (decoderType == "1")
|
||||
chan.Source = "DVB-T";
|
||||
else if (decoderType == "2")
|
||||
chan.Source = "DVB-C";
|
||||
chan.Source = (chan.SignalSource & SignalSource.Sat) != 0 ? "DVB-S" : (chan.SignalSource & SignalSource.Cable) != 0 ? "DVB-C" : (chan.SignalSource & SignalSource.Antenna) != 0 ? "DVB-T" : "";
|
||||
chan.SignalSource |= LookupData.Instance.IsRadioTvOrData(chan.ServiceType);
|
||||
chan.SymbolRate = ParseInt(data.TryGet("SymbolRate"));
|
||||
if (chan.SymbolRate > 100000) // DVB-S stores values in kSym, DVB-C stores it in Sym, DVB-T stores 0
|
||||
chan.SymbolRate /= 1000;
|
||||
if (data.TryGetValue("Polarization", out var pol))
|
||||
chan.Polarity = pol == "0" ? 'H' : 'V';
|
||||
chan.Polarity = pol == polarizationValueForHorizontal ? 'H' : 'V';
|
||||
chan.Hidden |= data.TryGet("SystemHidden") == "1";
|
||||
|
||||
chan.Encrypted = data.TryGet("Scramble") == "1" || data.TryGet("Scrambled") == "1"; // v100 sometimes contains a "Scramble", v105/v110 always contain "Scrambled"
|
||||
|
||||
Reference in New Issue
Block a user