mirror of
https://github.com/PredatH0r/ChanSort.git
synced 2026-02-28 09:10:42 +01:00
- Panasonic: added exerimental support for channel\_list.xml lists (Panasonic Android TVs, 2019 and later)
Unfortunately the only information included in this format is the channel number and a truncated channel name.
This commit is contained in:
@@ -101,6 +101,7 @@
|
||||
<Compile Include="Serializer.cs" />
|
||||
<Compile Include="PanasonicPlugin.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="XmlSerializer.cs" />
|
||||
<Service Include="{94E38DFF-614B-4cbd-B67C-F211BB35CE8B}" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -111,6 +112,9 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="ChanSort.Loader.Panasonic.ini">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[channel_list.xml]
|
||||
reorderRecordsByChannelNumber=true
|
||||
setIsModified=false
|
||||
@@ -1,15 +1,30 @@
|
||||
using ChanSort.Api;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using ChanSort.Api;
|
||||
|
||||
namespace ChanSort.Loader.Panasonic
|
||||
{
|
||||
public class PanasonicPlugin : ISerializerPlugin
|
||||
{
|
||||
public string DllName { get; set; }
|
||||
public string PluginName => "Panasonic (*.db, *.bin)";
|
||||
public string FileFilter => "*.db;*.bin";
|
||||
public string PluginName => "Panasonic (*.db, *.bin, *.xml)";
|
||||
public string FileFilter => "*.db;*.bin;*.xml";
|
||||
|
||||
public SerializerBase CreateSerializer(string inputFile)
|
||||
{
|
||||
if (Path.GetExtension(inputFile).ToLowerInvariant() == ".xml")
|
||||
{
|
||||
var data = File.ReadAllBytes(inputFile);
|
||||
var header = Encoding.ASCII.GetBytes("<ChannelList>\n<ChannelInfo IsModified=");
|
||||
for (int i = 0; i < header.Length; i++)
|
||||
{
|
||||
if (data[i] != header[i])
|
||||
return null;
|
||||
}
|
||||
|
||||
return new XmlSerializer(inputFile);
|
||||
}
|
||||
|
||||
return new Serializer(inputFile);
|
||||
}
|
||||
}
|
||||
|
||||
182
source/ChanSort.Loader.Panasonic/XmlSerializer.cs
Normal file
182
source/ChanSort.Loader.Panasonic/XmlSerializer.cs
Normal file
@@ -0,0 +1,182 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
using ChanSort.Api;
|
||||
|
||||
namespace ChanSort.Loader.Panasonic
|
||||
{
|
||||
/*
|
||||
|
||||
Panasonic Android TVs (2020 and later) use the same unstandardized compressed .bin binary format as many Philips lists and some Sharp TVs.
|
||||
Additionally it exports a .xml file with very limited information that only includes channel numbers and channel names truncated at 8 characters.
|
||||
|
||||
This truncation makes it impossible for a user to distinguish between channels that have longer names like "Sky Bundesliga ...", therefore
|
||||
this loader adds the "SvlId" as the ShortName. This SvlId is probably a "service list id" and refers to a a data record inside the .bin file.
|
||||
|
||||
*/
|
||||
class XmlSerializer : SerializerBase
|
||||
{
|
||||
private readonly Dictionary<string, ChannelList> channelLists = new();
|
||||
public XmlDocument doc;
|
||||
public readonly IniFile ini;
|
||||
|
||||
#region ctor()
|
||||
public XmlSerializer(string inputFile) : base(inputFile)
|
||||
{
|
||||
this.Features.ChannelNameEdit = ChannelNameEditMode.None;
|
||||
this.Features.CanSkipChannels = false;
|
||||
this.Features.CanLockChannels = false;
|
||||
this.Features.CanHideChannels = false;
|
||||
this.Features.DeleteMode = DeleteMode.NotSupported;
|
||||
this.Features.CanSaveAs = true;
|
||||
this.Features.AllowGapsInFavNumbers = true;
|
||||
this.Features.CanEditFavListNames = false;
|
||||
|
||||
string iniFile = Assembly.GetExecutingAssembly().Location.Replace(".dll", ".ini");
|
||||
this.ini = new IniFile(iniFile);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GetOrCreateList()
|
||||
private ChannelList GetOrCreateList(string name)
|
||||
{
|
||||
if (this.channelLists.TryGetValue(name, out var list))
|
||||
return list;
|
||||
|
||||
list = new ChannelList(SignalSource.All, name);
|
||||
this.channelLists[name] = list;
|
||||
var cols = list.VisibleColumnFieldNames;
|
||||
cols.Clear();
|
||||
cols.Add("Position");
|
||||
cols.Add("OldPosition");
|
||||
cols.Add(nameof(ChannelInfo.Name));
|
||||
cols.Add(nameof(ChannelInfo.ShortName));
|
||||
this.DataRoot.AddChannelList(list);
|
||||
return list;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Load()
|
||||
public override void Load()
|
||||
{
|
||||
bool fail = false;
|
||||
try
|
||||
{
|
||||
doc = new XmlDocument();
|
||||
var content = File.ReadAllBytes(this.FileName);
|
||||
var textContent = Encoding.UTF8.GetString(content);
|
||||
|
||||
var settings = new XmlReaderSettings
|
||||
{
|
||||
CheckCharacters = false,
|
||||
IgnoreProcessingInstructions = true,
|
||||
ValidationFlags = XmlSchemaValidationFlags.None,
|
||||
DtdProcessing = DtdProcessing.Ignore
|
||||
};
|
||||
using var reader = XmlReader.Create(new StringReader(textContent), settings);
|
||||
doc.Load(reader);
|
||||
}
|
||||
catch
|
||||
{
|
||||
fail = true;
|
||||
}
|
||||
|
||||
var root = doc.FirstChild;
|
||||
if (root is XmlDeclaration)
|
||||
root = root.NextSibling;
|
||||
if (fail || root == null || root.LocalName != "ChannelList" || !root.HasChildNodes || root.ChildNodes[0].LocalName != "ChannelInfo")
|
||||
throw new FileLoadException("File is not a supported Panasonic XML file");
|
||||
|
||||
foreach (XmlNode child in root.ChildNodes)
|
||||
{
|
||||
switch (child.LocalName)
|
||||
{
|
||||
case "ChannelInfo":
|
||||
this.ReadChannel(child);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ReadChannel()
|
||||
private void ReadChannel(XmlNode node)
|
||||
{
|
||||
var channelType = node.Attributes?["ChannelType"]?.InnerText;
|
||||
var list = this.GetOrCreateList(channelType);
|
||||
var chan = new XmlChannel(list.Count, node);
|
||||
DataRoot.AddChannel(list, chan);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Save()
|
||||
|
||||
public override void Save(string tvOutputFile)
|
||||
{
|
||||
var sec = ini.GetSection("channel_list.xml");
|
||||
var reorder = sec?.GetBool("reorderRecordsByChannelNumber", true) ?? true;
|
||||
var setIsModified = sec?.GetBool("setIsModified", false) ?? false;
|
||||
|
||||
foreach (var list in this.DataRoot.ChannelLists)
|
||||
{
|
||||
var seq = reorder ? list.Channels.OrderBy(c => c.NewProgramNr).ThenBy(c => c.RecordIndex).ToList() : list.Channels;
|
||||
XmlNode prevNode = null;
|
||||
foreach (var chan in seq)
|
||||
{
|
||||
if (chan is not XmlChannel ch)
|
||||
continue;
|
||||
ch.Node.Attributes["ChannelNumber"].InnerText = ch.NewProgramNr.ToString();
|
||||
if (setIsModified && ch.NewProgramNr != ch.OldProgramNr)
|
||||
ch.Node.Attributes["IsModified"].InnerText = "1";
|
||||
if (reorder)
|
||||
{
|
||||
var parent = ch.Node.ParentNode;
|
||||
parent.RemoveChild(ch.Node);
|
||||
parent.InsertAfter(ch.Node, prevNode);
|
||||
prevNode = ch.Node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var xmlSettings = new XmlWriterSettings();
|
||||
xmlSettings.Encoding = new UTF8Encoding(false);
|
||||
xmlSettings.CheckCharacters = false;
|
||||
xmlSettings.Indent = true;
|
||||
xmlSettings.IndentChars = "";
|
||||
xmlSettings.NewLineHandling = NewLineHandling.None;
|
||||
xmlSettings.NewLineChars = "\n";
|
||||
xmlSettings.OmitXmlDeclaration = true;
|
||||
using var w = XmlWriter.Create(tvOutputFile, xmlSettings);
|
||||
doc.WriteTo(w);
|
||||
this.FileName = tvOutputFile;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region class XmlChannel
|
||||
|
||||
class XmlChannel : ChannelInfo
|
||||
{
|
||||
internal XmlNode Node;
|
||||
|
||||
public XmlChannel(int index, XmlNode node) : base(0, index, 0, null)
|
||||
{
|
||||
this.Node = node;
|
||||
|
||||
this.OldProgramNr = int.Parse(node.Attributes["ChannelNumber"]?.InnerText);
|
||||
this.Name = node.Attributes["ChannelName"].InnerText;
|
||||
var svlId = node.Attributes["SvlId"].InnerText;
|
||||
this.ShortName = $"SvlId: {svlId}";
|
||||
}
|
||||
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ namespace ChanSort.Ui
|
||||
if (disposing)
|
||||
{
|
||||
this.components?.Dispose();
|
||||
this.serializer.Dispose();
|
||||
this.serializer?.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ ChanSort Change Log
|
||||
- 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)
|
||||
|
||||
2021-09-13
|
||||
- Panasonic: added exerimental support for channel\_list.xml lists (Panasonic Android TVs, 2019 and later)
|
||||
Unfortunately the only information included in this format is the channel number and a truncated channel name.
|
||||
- column order is now preserved between program starts even when lists with different supported columns
|
||||
were loaded and columns reordered.
|
||||
- added option to enabled/disable auto-loading of the last opened list when starting the program
|
||||
|
||||
Reference in New Issue
Block a user