From 0c348ed151869200c3e367442ed83a4fa0ac0e47 Mon Sep 17 00:00:00 2001 From: hbeham Date: Sun, 11 Aug 2019 17:27:07 +0200 Subject: [PATCH] - Sony: DVB-T and DVB-C lists are now separated into "TV", "Radio" and "Other" lists, each with their own unique numbering - Samsung ZIP: deleting a channel now really deletes it from the file, instead of marking it as deleted and assigning -1 as channel number (which appears as 65535 on some models) --- source/ChanSort.Api/Controller/Editor.cs | 2 +- source/ChanSort.Api/Model/DataRoot.cs | 13 +- source/ChanSort.Api/Model/Enums.cs | 16 ++- source/ChanSort.Api/Utils/DvbStringDecoder.cs | 8 +- source/ChanSort.Loader.Sony/Serializer.cs | 117 +++++++++++------- source/changelog.md | 5 + 6 files changed, 102 insertions(+), 59 deletions(-) diff --git a/source/ChanSort.Api/Controller/Editor.cs b/source/ChanSort.Api/Controller/Editor.cs index 5c48bf6..c5883c1 100644 --- a/source/ChanSort.Api/Controller/Editor.cs +++ b/source/ChanSort.Api/Controller/Editor.cs @@ -204,7 +204,7 @@ namespace ChanSort.Api foreach (var refList in refDataRoot.ChannelLists) { var tvList = this.DataRoot.GetChannelList(refList.SignalSource); - if (tvList == null) + if (tvList == null || tvList.SignalSource != refList.SignalSource) { log.AppendFormat("Skipped reference list {0}\r\n", refList.ShortCaption); continue; diff --git a/source/ChanSort.Api/Model/DataRoot.cs b/source/ChanSort.Api/Model/DataRoot.cs index d27a378..f7b1e6b 100644 --- a/source/ChanSort.Api/Model/DataRoot.cs +++ b/source/ChanSort.Api/Model/DataRoot.cs @@ -85,20 +85,19 @@ namespace ChanSort.Api #region GetChannelList() - public ChannelList GetChannelList(SignalSource criteriaMask) + public ChannelList GetChannelList(SignalSource searchMask) { foreach (var list in this.channelLists) { - uint searchMask = (uint)criteriaMask; - uint listMask = (uint) list.SignalSource; + var listMask = list.SignalSource; - if ((listMask & 0x000F & searchMask) != (searchMask & 0x000F)) // digital/analog + if ((listMask & SignalSource.MaskAnalogDigital) != 0 && (listMask & SignalSource.MaskAnalogDigital & searchMask) == 0) // digital/analog continue; - if ((listMask & 0x00F0 & searchMask) != (searchMask & 0x00F0)) // air/cable/sat/ip + if ((listMask & SignalSource.MaskAntennaCableSat) != 0 && (listMask & SignalSource.MaskAntennaCableSat & searchMask) == 0) // air/cable/sat/ip continue; - if ((listMask & 0x0F00 & searchMask) != (searchMask & 0x0F00)) // tv/radio + if ((listMask & SignalSource.MaskTvRadio) != 0 && (listMask & SignalSource.MaskTvRadio & searchMask) == 0) // tv/radio continue; - if ((listMask & 0xF000) != (searchMask & 0xF000)) // preset list + if ((listMask & SignalSource.MaskProvider) != 0 && (listMask & SignalSource.MaskProvider) != (searchMask & SignalSource.MaskProvider)) // preset list continue; return list; } diff --git a/source/ChanSort.Api/Model/Enums.cs b/source/ChanSort.Api/Model/Enums.cs index d27c479..e351cea 100644 --- a/source/ChanSort.Api/Model/Enums.cs +++ b/source/ChanSort.Api/Model/Enums.cs @@ -11,12 +11,12 @@ namespace ChanSort.Api [Flags] public enum SignalSource { - // bit 1+2: analog/digital + // bit 0-1: analog/digital MaskAnalogDigital = 0x0003, Analog = 0x0001, Digital = 0x0002, - // bit 4+5+6+7+8: AvInput/Antenna/Cable/Sat/IP + // bit 3-7: AvInput/Antenna/Cable/Sat/IP MaskAntennaCableSat = 0x00F8, AvInput = 0x0008, Antenna = 0x0010, @@ -26,14 +26,20 @@ namespace ChanSort.Api MaskAdInput = MaskAnalogDigital | MaskAntennaCableSat, - // bit 9+10: TV/Radio + // bit 8-9: TV/Radio MaskTvRadio = 0x0300, Tv = 0x0100, Radio = 0x0200, TvAndRadio = Tv | Radio, - // bit 13-16: Preset list selector (AstraHD+, Freesat, TivuSat, CanalDigitalSat, ... for Samsung) + // bit 12-15: Preset list selector (AstraHD+, Freesat, TivuSat, CanalDigitalSat, ... for Samsung) MaskProvider = 0xFC00, + Provider0 = 0 << 12, + Provider1 = 1 << 12, + Provider2 = 2 << 12, + Provider3 = 3 << 12, + Provider4 = 4 << 12, + StandardSat = 0 << 12, AstraHdPlus = 1 << 12, Freesat = 2 << 12, @@ -41,7 +47,7 @@ namespace ChanSort.Api CanalDigital = 4 << 12, DigitalPlus = 5 << 12, CyfraPlus = 6 << 12, - + StandardCable = 0 << 12, CablePrime = 1 << 12, diff --git a/source/ChanSort.Api/Utils/DvbStringDecoder.cs b/source/ChanSort.Api/Utils/DvbStringDecoder.cs index 1219107..1267956 100644 --- a/source/ChanSort.Api/Utils/DvbStringDecoder.cs +++ b/source/ChanSort.Api/Utils/DvbStringDecoder.cs @@ -149,9 +149,11 @@ namespace ChanSort.Api if (ch == '\0') { // read as many bytes as necessary to get a character - char[] charArray = new char[1]; - for (int byteCnt = 1; decoder.GetChars(name, i, byteCnt, charArray, 0) == 0; byteCnt++) - ++i; + char[] charArray = new char[5]; + int byteCnt; + for (byteCnt = 1; decoder.GetChars(name, i, byteCnt, charArray, 0) == 0; byteCnt++) + { + } ch = charArray[0]; } if (ch == '\0') diff --git a/source/ChanSort.Loader.Sony/Serializer.cs b/source/ChanSort.Loader.Sony/Serializer.cs index 57a3b30..41dac08 100644 --- a/source/ChanSort.Loader.Sony/Serializer.cs +++ b/source/ChanSort.Loader.Sony/Serializer.cs @@ -23,12 +23,6 @@ namespace ChanSort.Loader.Sony private const string SupportedFormatVersions = " e1.1.0 1.0.0 1.1.0 1.2.0 "; - private readonly ChannelList terrChannels = new ChannelList(SignalSource.DvbT | SignalSource.Tv | SignalSource.Radio, "DVB-T"); - private readonly ChannelList cableChannels = new ChannelList(SignalSource.DvbC | SignalSource.Tv | SignalSource.Radio, "DVB-C"); - private readonly ChannelList satChannels = new ChannelList(SignalSource.DvbS | SignalSource.Tv | SignalSource.Radio, "DVB-S"); - private readonly ChannelList satChannelsP = new ChannelList(SignalSource.DvbS | SignalSource.Tv | SignalSource.Radio, "DVB-S Preset"); - private readonly ChannelList satChannelsCi = new ChannelList(SignalSource.DvbS | SignalSource.Tv | SignalSource.Radio, "DVB-S Ci"); - private XmlDocument doc; private byte[] content; private string textContent; @@ -36,7 +30,7 @@ namespace ChanSort.Loader.Sony private bool isEFormat; private string newline; - private readonly Dictionary channeListNodes = new Dictionary(); + private readonly Dictionary channeListNodes = new Dictionary(); #region ctor() @@ -45,10 +39,15 @@ namespace ChanSort.Loader.Sony this.Features.ChannelNameEdit = ChannelNameEditMode.All; this.Features.CanDeleteChannels = true; - this.DataRoot.AddChannelList(this.terrChannels); - this.DataRoot.AddChannelList(this.cableChannels); - this.DataRoot.AddChannelList(this.satChannels); - this.DataRoot.AddChannelList(this.satChannelsP); + this.DataRoot.AddChannelList(new ChannelList(SignalSource.DvbT | SignalSource.Tv, "DVB-T TV")); + this.DataRoot.AddChannelList(new ChannelList(SignalSource.DvbT | SignalSource.Radio, "DVB-T Radio")); + this.DataRoot.AddChannelList(new ChannelList(SignalSource.DvbT, "DVB-T Other")); + this.DataRoot.AddChannelList(new ChannelList(SignalSource.DvbC | SignalSource.Tv, "DVB-C TV")); + this.DataRoot.AddChannelList(new ChannelList(SignalSource.DvbC | SignalSource.Radio, "DVB-C Radio")); + this.DataRoot.AddChannelList(new ChannelList(SignalSource.DvbC, "DVB-C Other")); + this.DataRoot.AddChannelList(new ChannelList(SignalSource.DvbS | SignalSource.Provider1, "DVB-S")); + this.DataRoot.AddChannelList(new ChannelList(SignalSource.DvbS | SignalSource.Provider2, "DVB-S Preset")); + this.DataRoot.AddChannelList(new ChannelList(SignalSource.DvbS | SignalSource.Provider3, "DVB-S Ci")); foreach (var list in this.DataRoot.ChannelLists) { @@ -119,8 +118,14 @@ namespace ChanSort.Loader.Sony if (!this.isEFormat) { - satChannels.VisibleColumnFieldNames.Remove("Hidden"); - satChannels.VisibleColumnFieldNames.Remove("Satellite"); + foreach (var list in this.DataRoot.ChannelLists) + { + if ((list.SignalSource & SignalSource.Sat) != 0) + { + list.VisibleColumnFieldNames.Remove("Hidden"); + list.VisibleColumnFieldNames.Remove("Satellite"); + } + } } } #endregion @@ -149,32 +154,38 @@ namespace ChanSort.Loader.Sony { var name = child.LocalName.ToLowerInvariant(); if (name == "sdbt") - ReadSdb(child, this.terrChannels, 0, "DvbT"); + ReadSdb(child, SignalSource.DvbT, 0, "DvbT"); else if (name == "sdbc") - ReadSdb(child, this.cableChannels, 0x10000, "DvbC"); + ReadSdb(child, SignalSource.DvbC, 0x10000, "DvbC"); else if (name == "sdbgs") - ReadSdb(child, this.satChannels, 0x20000, "DvbS"); + ReadSdb(child, SignalSource.DvbS | SignalSource.Provider1, 0x20000, "DvbS"); else if (name == "sdbps") - ReadSdb(child, this.satChannelsP, 0x30000, "DvbS"); + ReadSdb(child, SignalSource.DvbS | SignalSource.Provider2, 0x30000, "DvbS"); else if (name == "sdbcis") - ReadSdb(child, this.satChannelsCi, 0x40000, "DvbS"); + ReadSdb(child, SignalSource.DvbS | SignalSource.Provider3, 0x40000, "DvbS"); } } #endregion #region ReadSdb() - private void ReadSdb(XmlNode node, ChannelList list, int idAdjustment, string dvbSystem) + private void ReadSdb(XmlNode node, SignalSource signalSource, int idAdjustment, string dvbSystem) { - list.ReadOnly = node["Editable"]?.InnerText == "F"; - this.channeListNodes[list] = new ChannelListNodes(); + if (node["Editable"]?.InnerText == "F") + { + foreach (var list in this.DataRoot.ChannelLists) + { + if ((list.SignalSource & (SignalSource.MaskAdInput | SignalSource.MaskProvider)) == signalSource) + list.ReadOnly = true; + } + } this.ReadSatellites(node, idAdjustment); this.ReadTransponder(node, idAdjustment, dvbSystem); if (this.isEFormat) - this.ReadServicesE110(node, list, idAdjustment); + this.ReadServicesE110(node, signalSource, idAdjustment); else - this.ReadServices(node, list, idAdjustment); + this.ReadServices(node, signalSource, idAdjustment); } #endregion @@ -270,20 +281,21 @@ namespace ChanSort.Loader.Sony #endregion #region ReadServicesE110() - private void ReadServicesE110(XmlNode node, ChannelList list, int idAdjustment) + private void ReadServicesE110(XmlNode node, SignalSource signalSource, int idAdjustment) { var serviceNode = node["Service"] ?? throw new FileLoadException("Missing Service XML element"); var svcData = SplitLines(serviceNode); var dvbData = SplitLines(serviceNode["dvb_info"]); // remember the nodes that need to be updated when saving - var nodes = this.channeListNodes[list]; + var nodes = new ChannelListNodes(); nodes.Service = serviceNode; + this.channeListNodes[signalSource] = nodes; for (int i = 0, c = svcData["ui2_svl_rec_id"].Length; i < c; i++) { var recId = int.Parse(svcData["ui2_svl_rec_id"][i]); - var chan = new Channel(list.SignalSource, i, recId); + var chan = new Channel(signalSource, i, recId); chan.OldProgramNr = (int) ((uint) ParseInt(svcData["No"][i]) >> 18); chan.IsDeleted = svcData["b_deleted_by_user"][i] != "1"; var nwMask = uint.Parse(svcData["ui4_nw_mask"][i]); @@ -306,9 +318,9 @@ namespace ChanSort.Loader.Sony chan.Satellite = transp.Satellite?.Name; chan.SatPosition = transp.Satellite?.OrbitalPosition; - if ((list.SignalSource & SignalSource.Cable) != 0) + if ((signalSource & SignalSource.Cable) != 0) chan.ChannelOrTransponder = LookupData.Instance.GetDvbcChannelName(chan.FreqInMhz); - if ((list.SignalSource & SignalSource.Antenna) != 0) + if ((signalSource & SignalSource.Antenna) != 0) chan.ChannelOrTransponder = LookupData.Instance.GetDvbtTransponder(chan.FreqInMhz).ToString(); } else @@ -324,13 +336,14 @@ namespace ChanSort.Loader.Sony CopyDataValues(serviceNode, svcData, i, chan.ServiceData); + var list = this.DataRoot.GetChannelList(chan.SignalSource); this.DataRoot.AddChannel(list, chan); } } #endregion #region ReadServices() - private void ReadServices(XmlNode node, ChannelList list, int idAdjustment) + private void ReadServices(XmlNode node, SignalSource signalSource, int idAdjustment) { var serviceNode = node["Service"] ?? throw new FileLoadException("Missing Service XML element"); var svcData = SplitLines(serviceNode); @@ -339,15 +352,16 @@ namespace ChanSort.Loader.Sony var progData = SplitLines(progNode); // remember the nodes that need to be updated when saving - var nodes = this.channeListNodes[list]; + var nodes = new ChannelListNodes(); nodes.Service = serviceNode; nodes.Programme = progNode; + this.channeListNodes[signalSource] = nodes; var map = new Dictionary(); for (int i = 0, c = svcData["ServiceRowId"].Length; i < c; i++) { var rowId = int.Parse(svcData["ServiceRowId"][i]); - var chan = new Channel(list.SignalSource, i, rowId); + var chan = new Channel(signalSource, i, rowId); map[rowId] = chan; chan.OldProgramNr = -1; chan.IsDeleted = true; @@ -364,9 +378,9 @@ namespace ChanSort.Loader.Sony chan.FreqInMhz = transp.FrequencyInMhz; chan.SymbolRate = transp.SymbolRate; chan.Polarity = transp.Polarity; - if ((list.SignalSource & SignalSource.Cable) != 0) + if ((signalSource & SignalSource.Cable) != 0) chan.ChannelOrTransponder = LookupData.Instance.GetDvbcChannelName(chan.FreqInMhz); - if ((list.SignalSource & SignalSource.Cable) != 0) + if ((signalSource & SignalSource.Cable) != 0) chan.ChannelOrTransponder = LookupData.Instance.GetDvbtTransponder(chan.FreqInMhz).ToString(); } @@ -376,6 +390,7 @@ namespace ChanSort.Loader.Sony CopyDataValues(serviceNode, svcData, i, chan.ServiceData); + var list = this.DataRoot.GetChannelList(chan.SignalSource); this.DataRoot.AddChannel(list, chan); } @@ -516,9 +531,29 @@ namespace ChanSort.Loader.Sony #region Save() public override void Save(string tvOutputFile) { - // TODO handling for "e"-lists + if (this.channeListNodes.TryGetValue(SignalSource.DvbT, out var nodes)) + { + var dvbt = this.DataRoot.GetChannelList(SignalSource.DvbT | SignalSource.Tv).Channels + .Concat(this.DataRoot.GetChannelList(SignalSource.DvbT | SignalSource.Radio).Channels) + .Concat(this.DataRoot.GetChannelList(SignalSource.DvbT).Channels) + .ToList(); + this.UpdateChannelList(dvbt, nodes); + } + + if (this.channeListNodes.TryGetValue(SignalSource.DvbC, out nodes)) + { + var dvbc = this.DataRoot.GetChannelList(SignalSource.DvbC | SignalSource.Tv).Channels + .Concat(this.DataRoot.GetChannelList(SignalSource.DvbC | SignalSource.Radio).Channels) + .Concat(this.DataRoot.GetChannelList(SignalSource.DvbC).Channels) + .ToList(); + this.UpdateChannelList(dvbc, nodes); + } + foreach (var list in this.DataRoot.ChannelLists) - this.UpdateChannelList(list); + { + if ((list.SignalSource & SignalSource.DvbS) == SignalSource.DvbS && this.channeListNodes.TryGetValue(list.SignalSource, out nodes)) + this.UpdateChannelList(list.Channels, nodes); + } // by default .NET reformats the whole XML. These settings produce almost same format as the TV xml files use var xmlSettings = new XmlWriterSettings(); @@ -563,17 +598,13 @@ namespace ChanSort.Loader.Sony #endregion #region UpdateChannelList() - private void UpdateChannelList(ChannelList list) + private void UpdateChannelList(IList channels, ChannelListNodes nodes) { - var nodes = this.channeListNodes.TryGet(list); - if (nodes == null) // this list wasn't present in the file - return; - - if (this.isEFormat || list.Channels.Any(ch => ch.IsNameModified)) - this.UpdateDataInChildNodes(nodes.Service, list.Channels.OrderBy(c => c.RecordOrder), ch => true, ch => ch.ServiceData, this.GetNewValueForServiceNode); + if (this.isEFormat || channels.Any(ch => ch.IsNameModified)) + this.UpdateDataInChildNodes(nodes.Service, channels.OrderBy(c => c.RecordOrder), ch => true, ch => ch.ServiceData, this.GetNewValueForServiceNode); if (!this.isEFormat) - this.UpdateDataInChildNodes(nodes.Programme, list.Channels.OrderBy(c => c.NewProgramNr), ch => !(ch.IsDeleted || ch.NewProgramNr < 0), ch => ch.ProgrammeData, this.GetNewValueForProgrammeNode); + this.UpdateDataInChildNodes(nodes.Programme, channels.OrderBy(c => c.NewProgramNr), ch => !(ch.IsDeleted || ch.NewProgramNr < 0), ch => ch.ProgrammeData, this.GetNewValueForProgrammeNode); } #endregion diff --git a/source/changelog.md b/source/changelog.md index fdc7689..beb0af8 100644 --- a/source/changelog.md +++ b/source/changelog.md @@ -1,6 +1,11 @@ ChanSort Change Log =================== +2019-08-11 +- Sony: DVB-T and DVB-C lists are now separated into "TV", "Radio" and "Other" lists, each with their own unique numbering +- Samsung ZIP: deleting a channel now really deletes it from the file, instead of marking it as deleted + and assigning -1 as channel number (which appears as 65535 on some models) + 2019-08-05 - added partial support for Philips .xml channel lists (There are MANY different file formats, only a few are currently supported)