diff --git a/source/ChanSort.Api/Model/Transponder.cs b/source/ChanSort.Api/Model/Transponder.cs index ad47bae..94b3c3b 100644 --- a/source/ChanSort.Api/Model/Transponder.cs +++ b/source/ChanSort.Api/Model/Transponder.cs @@ -12,6 +12,7 @@ public char Polarity { get; set; } public int OriginalNetworkId { get; set; } public int TransportStreamId { get; set; } + public SignalSource SignalSource { get; set; } public Transponder(int id) { diff --git a/source/ChanSort.Loader.Hisense/ServicelistDb/ServicelistDbSerializer.cs b/source/ChanSort.Loader.Hisense/ServicelistDb/ServicelistDbSerializer.cs index 35832e7..b21fe1f 100644 --- a/source/ChanSort.Loader.Hisense/ServicelistDb/ServicelistDbSerializer.cs +++ b/source/ChanSort.Loader.Hisense/ServicelistDb/ServicelistDbSerializer.cs @@ -623,7 +623,6 @@ left outer join {dbSchema.DvbServiceTable} digs on digs.ServiceId=s.Pid { } - public SignalSource SignalSource { get; set; } public string Source { get; set; } } diff --git a/source/ChanSort.Loader.Loewe/ChanSort.Loader.Loewe.csproj b/source/ChanSort.Loader.Loewe/ChanSort.Loader.Loewe.csproj new file mode 100644 index 0000000..b004757 --- /dev/null +++ b/source/ChanSort.Loader.Loewe/ChanSort.Loader.Loewe.csproj @@ -0,0 +1,59 @@ + + + + + Debug + AnyCPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B} + Library + Properties + ChanSort.Loader.Loewe + ChanSort.Loader.Loewe + v4.8 + 512 + true + + + + true + full + false + ..\bin\Debug\ + DEBUG;TRACE + prompt + 4 + latest + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + latest + + + + + + + + + + + + + + + + + + + + {dccffa08-472b-4d17-bb90-8f513fc01392} + ChanSort.Api + + + + \ No newline at end of file diff --git a/source/ChanSort.Loader.Loewe/Channel.cs b/source/ChanSort.Loader.Loewe/Channel.cs new file mode 100644 index 0000000..5f653fa --- /dev/null +++ b/source/ChanSort.Loader.Loewe/Channel.cs @@ -0,0 +1,15 @@ +using System.Xml; +using ChanSort.Api; + +namespace ChanSort.Loader.Loewe +{ + internal class Channel : ChannelInfo + { + public XmlElement XmlElement { get; set; } + public int PhysicalListId { get; set; } + + public Channel(int id) : base(0, id, -1, "") + { + } + } +} diff --git a/source/ChanSort.Loader.Loewe/LoewePlugin.cs b/source/ChanSort.Loader.Loewe/LoewePlugin.cs new file mode 100644 index 0000000..edee8ee --- /dev/null +++ b/source/ChanSort.Loader.Loewe/LoewePlugin.cs @@ -0,0 +1,18 @@ +using ChanSort.Api; + +namespace ChanSort.Loader.Loewe +{ + // The servicelist.db files are handled by the Hisense loader, which shares the same file format + + public class LoewePlugin : ISerializerPlugin + { + public string DllName { get; set; } + public string PluginName => "Loewe (servicelist.xml)"; + public string FileFilter => "*.xml"; + + public SerializerBase CreateSerializer(string inputFile) + { + return new Serializer(inputFile); + } + } +} diff --git a/source/ChanSort.Loader.Loewe/Properties/AssemblyInfo.cs b/source/ChanSort.Loader.Loewe/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..820d02a --- /dev/null +++ b/source/ChanSort.Loader.Loewe/Properties/AssemblyInfo.cs @@ -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.Loewe")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ChanSort.Loader.Loewe")] +[assembly: AssemblyCopyright("Copyright © 2022")] +[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("d4b9399d-5609-4f87-a4ba-5b35983a981b")] + +// 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")] diff --git a/source/ChanSort.Loader.Loewe/Serializer.cs b/source/ChanSort.Loader.Loewe/Serializer.cs new file mode 100644 index 0000000..ef6c677 --- /dev/null +++ b/source/ChanSort.Loader.Loewe/Serializer.cs @@ -0,0 +1,465 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml; +using ChanSort.Api; + +namespace ChanSort.Loader.Loewe; + +/* + * The XML used in by this loader seems like a transformed version of the SQLite3 database format used by the Hisense/Loewe loader + * + * + * The 2017 Hisense / Loewe data model for channel lists is a bit different than all other supported models and need some workarounds to be supported. + * It is based on a flat "Services" table which doesn't hold program numbers and a FavoritesList/FavoritesItem table to assign numbers + * to physical tuner lists and user favorite lists alike. + * + * Physical channel lists (e.g. for $av, Astra, Hot Bird) have their own ChannelList in the channelList dictionary and use + * ChannelInfo.NewProgramNr to hold the program number. This doesn't allow the user to add services from other lists. + * + * The user favorite lists (FAV1-FAV4) use the separate favList ChannelList filled with all services from all physical lists. + * ChannelInfo.FavIndex[0-3] holds the information for the program numbers in FAV1-4. The value -1 is used to indicate "not included". + * + * The $all list is hidden from the user and automatically updated to match the contents of all other lists (except $av and FAV1-4). + * + * The $av list is hidden from the user and not updated at all. + * + * This loader poses the following restrictions on the database: + * - a service must not appear in more than one physical channel list ($all and FAV1-4 are not part of this restriction) + * - a service can't appear more than once in any list + * + */ + +class Serializer : SerializerBase +{ + private XmlDocument doc; + private readonly StringBuilder fileInfo = new(); + + private readonly ChannelList mixedFavTv; + private readonly ChannelList mixedFavRadio; + + /// + /// Fields of the ChannelInfo that will be shown in the UI + /// + private static readonly List ColumnNames = new() + { + "OldPosition", + "Position", + "Source", + "NewProgramNr", + "Name", + "ShortName", + "Favorites", + "Skip", + "Lock", + "Hidden", + "Encrypted", + "FreqInMhz", + "OriginalNetworkId", + "TransportStreamId", + "ServiceId", + //"ServiceType", + "ServiceTypeName", + "NetworkName", + "Satellite" + // "SymbolRate" + }; + + /// + /// mapping of FavoriteList.Pid => ChannelList. + /// This dict does not include real user favorite lists (FAV1-FAV4). + /// + private readonly Dictionary channelLists = new(); + + /// + /// mapping of FavoriteList.Pid for $all and FAV1-4 => index of the internal favorite list within userFavList (0-3) + /// Pids that don't belong to the FAV1-4 are not included in this dictionary. + /// + private readonly Dictionary favListIdToFavIndex = new(); + + /// + /// mapping of Service.Pid => ChannelInfo + /// + private readonly Dictionary channelsById = new(); + + /// + /// FavoriteList.Pid of the $all list + /// + private int pidAll; + + /// + /// FavoriteList.Pid of the $av list + /// + private int pidAv; + + + + #region ctor() + + public Serializer(string inputFile) : base(inputFile) + { + Features.ChannelNameEdit = ChannelNameEditMode.All; + Features.DeleteMode = DeleteMode.NotSupported; + Features.CanSkipChannels = true; + Features.CanLockChannels = true; + Features.CanHideChannels = true; + Features.CanHaveGaps = true; + Features.FavoritesMode = FavoritesMode.MixedSource; + + this.mixedFavTv = new ChannelList(0, "TV"); + this.mixedFavTv.VisibleColumnFieldNames = ColumnNames; + this.mixedFavTv.IsMixedSourceFavoritesList = true; + + this.mixedFavRadio = new ChannelList(0, "Radio"); + this.mixedFavRadio.VisibleColumnFieldNames = ColumnNames; + this.mixedFavRadio.IsMixedSourceFavoritesList = true; + } + + #endregion + + #region Load() + + public override void Load() + { + this.doc = new XmlDocument(); + doc.Load(this.FileName); + var sl = doc["servicelist"]; + if (sl == null) + throw new FileLoadException("expected root element "); + + var tuners = sl["tuners"]; + if (tuners == null) + throw new FileLoadException("missing list"); + + var services = sl["services"]; + if (services == null) + throw new FileLoadException("missing list"); + + var favorites = sl["favorites"]; + if (favorites == null) + throw new FileLoadException("missing list"); + + LoadTuners(tuners); + LoadServices(services); + LoadFavorites(favorites); + + Features.MaxFavoriteLists = this.favListIdToFavIndex.Count; + this.channelLists.Add(0, mixedFavTv); + this.channelLists.Add(0x8000, mixedFavRadio); + } + #endregion + + #region LoadTuners() + + private void LoadTuners(XmlElement tuners) + { + int index = 0; + foreach (var child in tuners.ChildNodes) + { + if (child is not XmlElement e) + continue; + if (e.LocalName == "tuner") + LoadTunerBaseData(e, index++); + else if (e.LocalName == "dvbt2-tuner") + LoadDvbTunerData(e); + } + } + + private void LoadTunerBaseData(XmlElement e, int index) + { + var a = e.Attributes; + var id = int.Parse(a["TunerId"].InnerText); + var t = new Transponder(id); + t.OriginalNetworkId = int.Parse(a["Oid"].InnerText); + t.TransportStreamId = int.Parse(a["Tid"].InnerText); + + if (e.LocalName == "dvbt-tuner" || e.LocalName == "dvbt2-tuner") + t.SignalSource |= SignalSource.Antenna; + else if (e.LocalName == "dvbc-tuner" || e.LocalName == "dvbc2-tuner") + t.SignalSource |= SignalSource.Cable; + else if (e.LocalName == "dvbs-tuner" || e.LocalName == "dvbs2-tuner") + t.SignalSource |= SignalSource.Sat; + + DataRoot.Transponder.Add(id, t); + } + + private void LoadDvbTunerData(XmlElement e) + { + var a = e.Attributes; + var id = int.Parse(a["TunerId"].InnerText); + if (!DataRoot.Transponder.TryGetValue(id, out var t)) + return; + t.FrequencyInMhz = decimal.Parse(a["Frequency"].InnerText) / 1000; + } + + #endregion + + #region LoadServices + + private void LoadServices(XmlElement services) + { + int index = 0; + foreach (var child in services.ChildNodes) + { + if (child is not XmlElement e) + continue; + if (e.LocalName == "service") + LoadServiceBaseData(e, index++); + else if (e.LocalName == "analog-service") + LoadServiceAnalogData(e); + else if (e.LocalName == "dvb-service") + LoadServiceDigitalData(e); + } + } + + private void LoadServiceBaseData(XmlElement e, int index) + { + var a = e.Attributes; + var id = int.Parse(a["Pid"].InnerText); + var c = new Channel(id); + c.XmlElement = e; + this.channelsById[id] = c; + c.RecordOrder = index; + c.Name = a["Name"].InnerText; + c.Lock = a["ParentalLock"].InnerText == "1"; + c.Skip = a["Selectable"].InnerText == "0"; + c.ShortName = a["ShortName"].InnerText; + c.Hidden = a["Visible"].InnerText == "0"; + + ChannelList list; + switch (int.Parse(a["MediaType"].InnerText)) + { + case 1: c.SignalSource |= SignalSource.Tv; + list = mixedFavTv; + break; + case 2: c.SignalSource |= SignalSource.Radio; + list = mixedFavRadio; + break; + default: + list = mixedFavTv; + break; + } + + list.AddChannel(c); + } + + private void LoadServiceAnalogData(XmlElement e) + { + var a = e.Attributes; + var id = int.Parse(a["ServiceId"].InnerText); + if (!this.channelsById.TryGetValue(id, out var c)) + return; + c.FreqInMhz = decimal.Parse(a["Frequency"].InnerText) / 1000; + c.SignalSource |= SignalSource.Analog; + } + + private void LoadServiceDigitalData(XmlElement e) + { + var a = e.Attributes; + var id = int.Parse(a["ServiceId"].InnerText); + if (!this.channelsById.TryGetValue(id, out var c)) + return; + c.ServiceId = int.Parse(a["Sid"].InnerText); + c.SignalSource |= SignalSource.Digital; + + var transponderId = int.Parse(a["TunerId"].InnerText); + var t = DataRoot.Transponder.TryGet(transponderId); + if (t != null) + { + c.Transponder = t; + c.OriginalNetworkId = t.OriginalNetworkId; + c.TransportStreamId = t.TransportStreamId; + c.FreqInMhz = t.FrequencyInMhz; + c.SignalSource |= t.SignalSource; + } + } + #endregion + + #region LoadFavorites() + + private void LoadFavorites(XmlElement favorites) + { + foreach (var node in favorites.ChildNodes) + { + if (node is not XmlElement e) + continue; + if (e.LocalName == "favorite-list") + LoadFavoriteList(e); + else if (e.LocalName == "favorite-item") + LoadFavoriteItem(e); + else if (e.LocalName == "lcn") + LoadLcnItem(e); + } + + this.DataRoot.AddChannelList(this.mixedFavTv); + this.DataRoot.AddChannelList(this.mixedFavRadio); + } + + private void LoadFavoriteList(XmlElement e) + { + var a = e.Attributes; + var name = a["Name"].InnerText; + var creator = a["Creator"].InnerText; + var id = int.Parse(a["Pid"].InnerText); + + if (name == "$av") + this.pidAv = id; + else if (creator.StartsWith("User.") || name == "$all") + { + if (name == "$all") + this.pidAll = id; + + var idx = this.favListIdToFavIndex.Count; + this.favListIdToFavIndex[id] = idx + 1; + this.mixedFavTv.SetFavListCaption(idx, name); + this.mixedFavRadio.SetFavListCaption(idx, name); + return; + } + + var list = new ChannelList(0, name + " TV"); + list.VisibleColumnFieldNames = ColumnNames; + channelLists.Add(id, list); + DataRoot.AddChannelList(list); + if (name.StartsWith("$av")) + { + list.ShortCaption = "A/V"; + list.ReadOnly = true; + return; + } + + list = new ChannelList(0, name + " Radio"); + list.VisibleColumnFieldNames = ColumnNames; + channelLists.Add(id | 0x8000, list); + DataRoot.AddChannelList(list); + } + + private void LoadFavoriteItem(XmlElement e) + { + var a = e.Attributes; + var listId = int.Parse(a["FavoriteId"].InnerText); + var serviceId = int.Parse(a["ServiceId"].InnerText); + var channelNo = int.Parse(a["ChannelNum"].InnerText); + + if (!this.channelsById.TryGetValue(serviceId, out var c)) + return; + + if (this.favListIdToFavIndex.TryGetValue(listId, out var listIdx)) + c.SetOldPosition(listIdx, channelNo); + else + { + c.OldProgramNr = channelNo; + ((Channel)c).PhysicalListId = listId; + } + + if (listIdx == 0) + { + if ((c.SignalSource & SignalSource.Radio) != 0) + listId |= 0x8000; + var list = channelLists.TryGet(listId); + DataRoot.AddChannel(list, c); + } + } + + private void LoadLcnItem(XmlElement e) + { + var a = e.Attributes; + var listId = int.Parse(a["FavoriteId"].InnerText); + var serviceId = int.Parse(a["ServiceId"].InnerText); + var lcn = int.Parse(a["Lcn"].InnerText); + + if (!this.channelsById.TryGetValue(serviceId, out var c)) + return; + + c.ProgramNrPreset = lcn; + if (this.favListIdToFavIndex.TryGetValue(listId, out var listIdx)) + { + var list = channelLists.TryGet(listId); + list.ReadOnly = true; + } + else if (this.channelLists.TryGetValue(listId, out var list)) + { + list.ReadOnly = true; + } + } + + #endregion + + // Save + + #region Save() + + public override void Save(string tvOutputFile) + { + var fav = this.doc["servicelist"]["favorites"]; + var elements = fav.GetElementsByTagName("favorite-item"); + var items = new List(); + foreach(XmlNode node in elements) + items.Add(node); + foreach (var node in items) + node.ParentNode.RemoveChild(node); + + elements = fav.GetElementsByTagName("lcn"); + var lcn = new List(); + foreach (XmlNode node in elements) + lcn.Add(node); + foreach (var node in lcn) + node.ParentNode.RemoveChild(node); + + var idVal = 0; + var lists = new List>(); + foreach (var list in this.DataRoot.ChannelLists) + { + if (list.IsMixedSourceFavoritesList) + { + foreach (var entry in favListIdToFavIndex) + lists.Add(Tuple.Create(entry.Key, list, entry.Value)); + } + else + { + lists.Add(Tuple.Create(channelLists.FirstOrDefault(e => e.Value == list).Key, list, 0)); + } + } + + //var listIds = this.channelLists.Keys.Union(this.favListIdToFavIndex.Keys).OrderBy(k => k).ToList(); + foreach (var tuple in lists) + { + var listId = tuple.Item1 & 0x7FFF; + var list = tuple.Item2; + var favIndex = tuple.Item3; + foreach (var chan in list.Channels) + { + if (chan is not Channel c || c.IsProxy) + continue; + + var chno = c.GetPosition(favIndex); + if (chno < 0) + continue; + + var e = doc.CreateElement("favorite-item"); + e.SetAttribute("Active", "0"); + e.SetAttribute("Attribute", "0"); + e.SetAttribute("ChannelNum", chno.ToString()); + e.SetAttribute("FavoriteId", listId.ToString()); + e.SetAttribute("Id", (++idVal).ToString()); + e.SetAttribute("OriginalFavoriteId", listId.ToString()); + e.SetAttribute("Selectable", "-1"); + e.SetAttribute("ServiceId", c.RecordIndex.ToString()); + e.SetAttribute("ServiceName", ""); + e.SetAttribute("Visible", "-1"); + fav.AppendChild(e); + } + } + + foreach (XmlNode item in lcn) + fav.AppendChild(item); + + doc.Save(tvOutputFile); + this.FileName = tvOutputFile; + } + + #endregion + +} + diff --git a/source/ChanSort.Loader.Philips/XmlSerializer.cs b/source/ChanSort.Loader.Philips/XmlSerializer.cs index fc9d127..8926de3 100644 --- a/source/ChanSort.Loader.Philips/XmlSerializer.cs +++ b/source/ChanSort.Loader.Philips/XmlSerializer.cs @@ -159,7 +159,7 @@ namespace ChanSort.Loader.Philips // ChannelMap_100/ChannelList/chanLst.bin // + optionally // ChannelMap_100/ChannelList/channelFile.bin - // ChannelMap_100/ChannelList/Favorite.xml + // ChannelMap_105/ChannelList/Favorite.xml // ChannelMap_100/ChannelList/satInfo.bin var dataFiles = new[] { @"channellib\DVBC.xml", @"channellib\DVBT.xml", @"s2channellib\DVBS.xml", @"s2channellib\DVBSall.xml", @"Favorite.xml" }; diff --git a/source/ChanSort.sln b/source/ChanSort.sln index e3eafc7..278f882 100644 --- a/source/ChanSort.sln +++ b/source/ChanSort.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29025.244 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.32112.339 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChanSort", "ChanSort\ChanSort.csproj", "{5FAFDABC-A52F-498C-BD2F-AFFC4119797A}" ProjectSection(ProjectDependencies) = postProject @@ -94,6 +94,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChanSort.Loader.CmdbBin", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChanSort.Loader.Android", "ChanSort.Loader.Android\ChanSort.Loader.Android.csproj", "{5088DB0D-6BDE-4678-8C50-A14E6A294A45}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChanSort.Loader.Loewe", "ChanSort.Loader.Loewe\ChanSort.Loader.Loewe.csproj", "{D4B9399D-5609-4F87-A4BA-5B35983A981B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution All_Debug|Any CPU = All_Debug|Any CPU @@ -1131,6 +1133,36 @@ Global {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 + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.All_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.All_Debug|Any CPU.Build.0 = Debug|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.All_Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.All_Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.All_Debug|x86.ActiveCfg = Debug|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.All_Debug|x86.Build.0 = Debug|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.All_Release|Any CPU.ActiveCfg = Release|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.All_Release|Any CPU.Build.0 = Release|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.All_Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.All_Release|Mixed Platforms.Build.0 = Release|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.All_Release|x86.ActiveCfg = Release|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.All_Release|x86.Build.0 = Release|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.Debug|x86.ActiveCfg = Debug|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.Debug|x86.Build.0 = Debug|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.NoDevExpress_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.NoDevExpress_Debug|Any CPU.Build.0 = Debug|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.NoDevExpress_Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.NoDevExpress_Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.NoDevExpress_Debug|x86.ActiveCfg = Debug|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.NoDevExpress_Debug|x86.Build.0 = Debug|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.Release|Any CPU.Build.0 = Release|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.Release|x86.ActiveCfg = Release|Any CPU + {D4B9399D-5609-4F87-A4BA-5B35983A981B}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/source/ChanSort/ChanSort.csproj b/source/ChanSort/ChanSort.csproj index 7e4579a..c51a940 100644 --- a/source/ChanSort/ChanSort.csproj +++ b/source/ChanSort/ChanSort.csproj @@ -555,6 +555,10 @@ {e972d8a1-2f5f-421c-ac91-cff45e5191be} ChanSort.Loader.LG + + {d4b9399d-5609-4f87-a4ba-5b35983a981b} + ChanSort.Loader.Loewe + {484028b6-3aae-4f7e-a88a-76beeb70203b} ChanSort.Loader.M3u @@ -575,6 +579,10 @@ {e6279ff8-362a-41e6-ac0d-d0861d43f01c} ChanSort.Loader.SatcoDX + + {4e68f218-5135-4d92-8c17-14faa5d4cbf3} + ChanSort.Loader.Sharp + {70e29c6b-b926-4859-9548-23375bf1e1b5} ChanSort.Loader.Sony diff --git a/source/ChanSort/MainForm.cs b/source/ChanSort/MainForm.cs index 94bec8c..f2836d5 100644 --- a/source/ChanSort/MainForm.cs +++ b/source/ChanSort/MainForm.cs @@ -1996,7 +1996,7 @@ namespace ChanSort.Ui private void ExportExcelList() { - const string header = "List;Pr#;Channel Name;Favorites;Lock;Skip;Hide;Encrypted;Satellite;Ch/Tp;Freq;ONID;TSID;SymRate;SID;VPID;APID"; + const string header = "List;Pr#;Channel Name;Favorites;Lock;Skip;Hide;Encrypted;Satellite;Ch/Tp;Freq;Pol;SymRate;ONID;TSID;SID;VPID;APID"; const char sep = '\t'; var sb = new StringBuilder(); sb.AppendLine(header.Replace(';', sep)); @@ -2017,9 +2017,10 @@ namespace ChanSort.Ui sb.Append('"').Append(channel.Satellite).Append('"').Append(sep); sb.Append(channel.ChannelOrTransponder).Append(sep); sb.Append(channel.FreqInMhz).Append(sep); + sb.Append(channel.Polarity).Append(sep); + sb.Append(channel.SymbolRate).Append(sep); sb.Append(channel.OriginalNetworkId).Append(sep); sb.Append(channel.TransportStreamId).Append(sep); - sb.Append(channel.SymbolRate).Append(sep); sb.Append(channel.ServiceId).Append(sep); sb.Append(channel.VideoPid).Append(sep); sb.Append(channel.AudioPid); diff --git a/source/ChanSort/Properties/licenses.licx b/source/ChanSort/Properties/licenses.licx index e69de29..6e5093b 100644 --- a/source/ChanSort/Properties/licenses.licx +++ b/source/ChanSort/Properties/licenses.licx @@ -0,0 +1,5 @@ +DevExpress.XtraEditors.ButtonEdit, DevExpress.XtraEditors.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a +DevExpress.XtraBars.BarManager, DevExpress.XtraBars.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a +DevExpress.XtraEditors.CheckEdit, DevExpress.XtraEditors.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a +DevExpress.XtraEditors.PictureEdit, DevExpress.XtraEditors.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a +DevExpress.XtraEditors.Repository.RepositoryItemTextEdit, DevExpress.XtraEditors.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a diff --git a/source/changelog.md b/source/changelog.md index fb956b1..84af5ab 100644 --- a/source/changelog.md +++ b/source/changelog.md @@ -1,8 +1,13 @@ ChanSort Change Log =================== -TBD +2022-03-20 - Philips \*Table and \*.dat format: now showing "Encrypted" information +- added ChangHong LED40D3000ISX dtv_cmdb_2.bin format (1489 KB size) +- added experimental support for Loewe servicelist.xml format +- added polarity information to Excel export (and changed column order slightly) +- added missing Romanian translation files to the .zip + 2021-10-24 - LG webOS 5 and 6: Improved support for DVB-C lists which changed channel numbers after import diff --git a/source/makeDistribZip.cmd b/source/makeDistribZip.cmd index d684bde..319344c 100644 --- a/source/makeDistribZip.cmd +++ b/source/makeDistribZip.cmd @@ -3,7 +3,7 @@ setlocal setlocal enabledelayedexpansion cd /d %~dp0 -set languages=cs de es hu pl pt ru tr +set languages=cs de es hu pl pt ro ru tr set curdate=%date:~6,4%-%date:~3,2%-%date:~0,2% set target=%cd%\..\..\ChanSort_%curdate% set DXversion=21.1