mirror of
https://github.com/PredatH0r/ChanSort.git
synced 2026-01-29 18:49:02 +01:00
added experimental support for LG WebOS 5.0 (e.g. OLED CX series)
- NO favorite list support - UNCLEAR behavior when the list contains channels from multiple sources (DVB-C/T/S) - so far only files with a single source are supported
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@@ -33,6 +34,7 @@
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -43,6 +45,7 @@
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>..\Release\</OutputPath>
|
||||
@@ -53,11 +56,15 @@
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject />
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
@@ -114,6 +121,9 @@
|
||||
<EmbeddedResource Include="Resources.ru.resx" />
|
||||
<EmbeddedResource Include="Resources.tr.resx" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
||||
@@ -3,18 +3,18 @@ using ChanSort.Api;
|
||||
|
||||
namespace ChanSort.Loader.GlobalClone
|
||||
{
|
||||
internal class GcChannel : ChannelInfo
|
||||
internal class GcChannel<TNode> : ChannelInfo
|
||||
{
|
||||
internal int Index;
|
||||
internal XmlNode XmlNode;
|
||||
internal TNode Node;
|
||||
internal bool IsDisabled;
|
||||
|
||||
#region ctor()
|
||||
internal GcChannel(SignalSource source, int index, XmlNode node)
|
||||
internal GcChannel(SignalSource source, int index, TNode node)
|
||||
{
|
||||
this.SignalSource = source;
|
||||
this.Index = index;
|
||||
this.XmlNode = node;
|
||||
this.Node = node;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,35 +1,219 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using ChanSort.Api;
|
||||
//using System.Text.Json;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace ChanSort.Loader.GlobalClone
|
||||
{
|
||||
internal class GcJsonSerializer : SerializerBase
|
||||
{
|
||||
private string content;
|
||||
private readonly string content;
|
||||
string xmlPrefix;
|
||||
string xmlSuffix;
|
||||
private JObject doc;
|
||||
|
||||
public GcJsonSerializer(string filename, string jsonContent) : base(filename)
|
||||
private readonly ChannelList tvList = new ChannelList(SignalSource.MaskAdInput | SignalSource.Tv, "TV");
|
||||
private readonly ChannelList radioList = new ChannelList(SignalSource.MaskAdInput | SignalSource.Radio, "Radio");
|
||||
|
||||
public GcJsonSerializer(string filename, string content) : base(filename)
|
||||
{
|
||||
this.content = jsonContent;
|
||||
this.content = content;
|
||||
|
||||
this.Features.DeleteMode = DeleteMode.FlagWithoutPrNr;
|
||||
this.Features.ChannelNameEdit = ChannelNameEditMode.All;
|
||||
this.Features.SupportedFavorites = 0;
|
||||
this.Features.CanSaveAs = true;
|
||||
this.Features.CanHaveGaps = true;
|
||||
this.Features.CanHideChannels = true;
|
||||
this.Features.CanSkipChannels = true;
|
||||
this.Features.CanLockChannels = true;
|
||||
|
||||
this.DataRoot.AddChannelList(tvList);
|
||||
this.DataRoot.AddChannelList(radioList);
|
||||
|
||||
foreach(var list in this.DataRoot.ChannelLists)
|
||||
list.VisibleColumnFieldNames.Add("Source");
|
||||
}
|
||||
|
||||
|
||||
public override void Load()
|
||||
{
|
||||
//var doc = new JsonDocument();
|
||||
var startTag = "<legacybroadcast>";
|
||||
var endTag = "</legacybroadcast>";
|
||||
var start = content.IndexOf(startTag);
|
||||
string json = null;
|
||||
if (start >= 0)
|
||||
{
|
||||
this.xmlPrefix = content.Substring(0, start + startTag.Length);
|
||||
var end = content.IndexOf(endTag, start);
|
||||
if (end >= 0)
|
||||
{
|
||||
json = content.Substring(start + startTag.Length, end - start - startTag.Length);
|
||||
this.xmlSuffix = content.Substring(end);
|
||||
}
|
||||
}
|
||||
|
||||
if (json == null)
|
||||
throw new FileLoadException($"File does not contain a {startTag}...{endTag} node");
|
||||
|
||||
this.doc = JObject.Parse(json);
|
||||
LoadSatellites();
|
||||
LoadChannels();
|
||||
}
|
||||
|
||||
#region LoadSatellites()
|
||||
private void LoadSatellites()
|
||||
{
|
||||
var satList = this.doc["satelliteList"];
|
||||
if (satList == null)
|
||||
return;
|
||||
foreach (var node in satList)
|
||||
{
|
||||
if (!(bool) node["tpListLoad"])
|
||||
continue;
|
||||
var id = int.Parse((string) node["satelliteId"]);
|
||||
var sat = new Satellite(id);
|
||||
sat.Name = (string) node["satelliteName"];
|
||||
sat.OrbitalPosition = (string) node["satLocation"];
|
||||
this.DataRoot.AddSatellite(sat);
|
||||
|
||||
LoadTransponders(node["TransponderList"], sat);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region LoadTransponders()
|
||||
private void LoadTransponders(JToken transponderList, Satellite sat)
|
||||
{
|
||||
foreach (var node in transponderList)
|
||||
{
|
||||
var id = (sat.Id << 16) + (int)node["channelIdx"];
|
||||
var tp = new Transponder(id);
|
||||
tp.Satellite = sat;
|
||||
sat.Transponder.Add(id, tp);
|
||||
|
||||
tp.FrequencyInMhz = (int) node["frequency"];
|
||||
tp.Number = (int) node["channelIdx"];
|
||||
var pol = ((string) node["polarization"]).ToLower();
|
||||
tp.Polarity = pol.StartsWith("h") ? 'H' : pol.StartsWith("V") ? 'V' : '\0';
|
||||
tp.TransportStreamId = (int) node["TSID"];
|
||||
tp.OriginalNetworkId = (int)node["ONID"];
|
||||
tp.SymbolRate = (int) node["symbolRate"];
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region LoadChannels()
|
||||
private void LoadChannels()
|
||||
{
|
||||
if (this.doc["channelList"] == null)
|
||||
throw new FileLoadException("JSON does not contain a channelList node");
|
||||
|
||||
var dec = new DvbStringDecoder(this.DefaultEncoding);
|
||||
int i = 0;
|
||||
foreach (var node in this.doc["channelList"])
|
||||
{
|
||||
var ch = new GcChannel<JToken>(SignalSource.All, i, node);
|
||||
ch.PcrPid = (int) node["pcrPid"];
|
||||
ch.IsDisabled = (bool) node["disabled"];
|
||||
ch.FreqInMhz = (int) node["frequency"];
|
||||
if (ch.FreqInMhz >= 100000 && ch.FreqInMhz < 1000000) // DVBS is given in MHz, DVBC/T in kHz
|
||||
ch.FreqInMhz /= 1000;
|
||||
ch.AudioPid = (int) node["audioPid"];
|
||||
ch.Source = (string) node["sourceIndex"];
|
||||
ch.Skip = (bool) node["skipped"];
|
||||
ch.Hidden = (bool) node["Invisible"];
|
||||
ch.IsDeleted = (bool) node["deleted"];
|
||||
//if (int.TryParse((string) node["satelliteId"], out var satId))
|
||||
ch.Satellite = (string) node["satelliteId"]; //this.DataRoot.Satellites.TryGet(satId);
|
||||
ch.Encrypted = (bool) node["scrambled"];
|
||||
var nameBytes = Convert.FromBase64String((string) node["chNameBase64"]);
|
||||
dec.GetChannelNames(nameBytes, 0, nameBytes.Length, out var name, out var shortName);
|
||||
ch.Name = name;
|
||||
ch.ShortName = shortName;
|
||||
ch.VideoPid = (int) node["videoPid"];
|
||||
var transSystem = (string) node["transSystem"];
|
||||
if (transSystem == "DVBS")
|
||||
ch.SignalSource |= SignalSource.DvbS;
|
||||
else if (transSystem == "DVBC")
|
||||
ch.SignalSource |= SignalSource.DvbC;
|
||||
else if (transSystem == "DVBT")
|
||||
ch.SignalSource |= SignalSource.DvbT;
|
||||
var tpId = (string) node["tpId"];
|
||||
if (tpId != null && tpId.Length == 10)
|
||||
ch.Transponder = this.DataRoot.Transponder.TryGet((int.Parse(tpId.Substring(0, 4)) << 16) + int.Parse(tpId.Substring(4))); // satId + freq, e.g. 0192126041
|
||||
ch.TransportStreamId = (int) node["TSID"];
|
||||
ch.OldProgramNr = (int) node["majorNumber"];
|
||||
ch.ServiceType = (int) node["serviceType"];
|
||||
ch.Lock = (bool) node["locked"];
|
||||
if (string.IsNullOrWhiteSpace(ch.Name))
|
||||
ch.Name = (string)node["channelName"];
|
||||
ch.ServiceId = (int) node["SVCID"];
|
||||
if (ch.ServiceId == 0)
|
||||
ch.ServiceId = (int) node["programNum"];
|
||||
ch.OriginalNetworkId = (int) node["ONID"];
|
||||
ch.SignalSource = LookupData.Instance.IsRadioTvOrData(ch.ServiceType);
|
||||
|
||||
if ((ch.OldProgramNr & 0x4000) != 0)
|
||||
{
|
||||
ch.OldProgramNr &= 0x3FFF;
|
||||
ch.SignalSource |= SignalSource.Radio;
|
||||
this.DataRoot.AddChannel(this.radioList, ch);
|
||||
}
|
||||
else
|
||||
this.DataRoot.AddChannel(this.tvList, ch);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
// saving
|
||||
|
||||
#region Save()
|
||||
public override void Save(string tvOutputFile)
|
||||
{
|
||||
|
||||
this.UpdateJsonDoc();
|
||||
|
||||
using var sw = new StringWriter();
|
||||
sw.Write(xmlPrefix);
|
||||
var jw = new JsonTextWriter(sw);
|
||||
{
|
||||
doc.WriteTo(jw);
|
||||
}
|
||||
sw.Write(xmlSuffix);
|
||||
File.WriteAllText(tvOutputFile, sw.ToString());
|
||||
this.FileName = tvOutputFile;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region UpdateJsonDoc()
|
||||
private void UpdateJsonDoc()
|
||||
{
|
||||
foreach (var list in this.DataRoot.ChannelLists)
|
||||
{
|
||||
foreach (var chan in list.Channels)
|
||||
{
|
||||
if (!(chan is GcChannel<JToken> ch))
|
||||
continue;
|
||||
var node = ch.Node;
|
||||
if (ch.IsNameModified)
|
||||
{
|
||||
node["channelName"] = ch.Name;
|
||||
node["chNameBase64"] = Convert.ToBase64String(Encoding.UTF8.GetBytes(ch.Name));
|
||||
}
|
||||
|
||||
node["deleted"] = ch.NewProgramNr < 0;
|
||||
node["majorNumber"] = Math.Max(ch.NewProgramNr, 0);
|
||||
node["skipped"] = ch.Skip;
|
||||
node["locked"] = ch.Lock;
|
||||
node["Invisible"] = ch.Hidden;
|
||||
node["userEditChNumber"] = true;
|
||||
node["userSelCHNo"] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,14 +14,8 @@ namespace ChanSort.Loader.GlobalClone
|
||||
{
|
||||
// files with <TLLDATA><ModelInfo><CloneVersion><MajorVersion>200</MajorVersion> .... contain all the actual channel data in JSON format inside a <legacybroadcast> element
|
||||
var content = File.ReadAllText(inputFile, Encoding.UTF8);
|
||||
var startTag = "<legacybroadcast>";
|
||||
var start = content.IndexOf(startTag);
|
||||
if (start >= 0)
|
||||
{
|
||||
var end = content.IndexOf("</legacybroadcast>", start);
|
||||
var json = content.Substring(start + startTag.Length, end - start - startTag.Length);
|
||||
if (content.Contains("<legacybroadcast>"))
|
||||
return new GcJsonSerializer(inputFile, content);
|
||||
}
|
||||
|
||||
return new GcXmlSerializer(inputFile);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace ChanSort.Loader.GlobalClone
|
||||
this.Features.ChannelNameEdit = ChannelNameEditMode.All;
|
||||
this.Features.DeleteMode = DeleteMode.FlagWithoutPrNr;
|
||||
this.Features.CanHaveGaps = true;
|
||||
this.Features.CanSaveAs = true;
|
||||
this.Features.CanSkipChannels = true;
|
||||
this.Features.CanLockChannels = true;
|
||||
this.Features.CanHideChannels = true;
|
||||
@@ -207,7 +208,7 @@ namespace ChanSort.Loader.GlobalClone
|
||||
if (itemNode.LocalName != "ITEM")
|
||||
continue;
|
||||
++i;
|
||||
GcChannel ch = new GcChannel(analog ? SignalSource.AnalogCT | SignalSource.Tv : SignalSource.Digital, i, itemNode);
|
||||
var ch = new GcChannel<XmlNode>(analog ? SignalSource.AnalogCT | SignalSource.Tv : SignalSource.Digital, i, itemNode);
|
||||
this.ParseChannelInfoNodes(itemNode, ch);
|
||||
|
||||
var list = this.DataRoot.GetChannelList(ch.SignalSource);
|
||||
@@ -217,7 +218,7 @@ namespace ChanSort.Loader.GlobalClone
|
||||
#endregion
|
||||
|
||||
#region ParseChannelInfoNode()
|
||||
private void ParseChannelInfoNodes(XmlNode itemNode, GcChannel ch, bool onlyNames = false)
|
||||
private void ParseChannelInfoNodes(XmlNode itemNode, GcChannel<XmlNode> ch, bool onlyNames = false)
|
||||
{
|
||||
bool hasHexName = false;
|
||||
int mapType = 0;
|
||||
@@ -384,13 +385,13 @@ namespace ChanSort.Loader.GlobalClone
|
||||
{
|
||||
foreach (var channel in list.Channels)
|
||||
{
|
||||
var ch = channel as GcChannel;
|
||||
var ch = channel as GcChannel<XmlNode>;
|
||||
if (ch == null) continue; // ignore proxy channels from reference lists
|
||||
var nameBytes = Encoding.UTF8.GetBytes(ch.Name);
|
||||
bool nameNeedsEncoding = nameBytes.Length != ch.Name.Length;
|
||||
string mapType = "";
|
||||
|
||||
foreach (XmlNode node in ch.XmlNode.ChildNodes)
|
||||
foreach (XmlNode node in ch.Node.ChildNodes)
|
||||
{
|
||||
switch (node.LocalName)
|
||||
{
|
||||
@@ -518,9 +519,9 @@ namespace ChanSort.Loader.GlobalClone
|
||||
continue;
|
||||
foreach (var channel in list.Channels)
|
||||
{
|
||||
var gcChannel = channel as GcChannel;
|
||||
var gcChannel = channel as GcChannel<XmlNode>;
|
||||
if (gcChannel != null)
|
||||
this.ParseChannelInfoNodes(gcChannel.XmlNode, gcChannel, true);
|
||||
this.ParseChannelInfoNodes(gcChannel.Node, gcChannel, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
4
source/ChanSort.Loader.GlobalClone/packages.config
Normal file
4
source/ChanSort.Loader.GlobalClone/packages.config
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net48" />
|
||||
</packages>
|
||||
BIN
source/DLL/Newtonsoft.Json.dll
Normal file
BIN
source/DLL/Newtonsoft.Json.dll
Normal file
Binary file not shown.
@@ -73,6 +73,7 @@
|
||||
<None Include="TestFiles\GlobalClone00001.TLL" />
|
||||
<None Include="TestFiles\GlobalClone00002.TLL" />
|
||||
<None Include="TestFiles\GlobalClone00003.TLL" />
|
||||
<None Include="TestFiles\GlobalClone200-inner.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ChanSort.Api\ChanSort.Api.csproj">
|
||||
|
||||
42788
source/Test.Loader.GlobalClone/TestFiles/GlobalClone200-inner.json
Normal file
42788
source/Test.Loader.GlobalClone/TestFiles/GlobalClone200-inner.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,9 @@
|
||||
ChanSort Change Log
|
||||
===================
|
||||
|
||||
2020-05-03
|
||||
- added experimental support for LG WebOS 5.0 (e.g. OLED CX series) - NO FAV LISTS YET
|
||||
|
||||
2020-05-02
|
||||
- added Turkish translation (thanks to Ali Haykir)
|
||||
- Philips: combined DVB-C and DVB-T into a single list with a common number domain
|
||||
|
||||
@@ -22,8 +22,8 @@ for %%l in (%languages%) do (
|
||||
)
|
||||
mkdir "%target%\ReferenceLists" 2>nul
|
||||
xcopy /sidy ChanSort\ReferenceLists\* "%target%\ReferenceLists"
|
||||
xcopy /idy ..\readme.md "%target%\readme.txt"
|
||||
xcopy /idy changelog.md "%target%\changelog.txt"
|
||||
xcopy /y ..\readme.md "%target%\readme.txt"
|
||||
xcopy /y changelog.md "%target%\changelog.txt"
|
||||
for %%f in (Utils Data DataAccess Printing XtraPrinting XtraReports XtraEditors XtraBars XtraGrid XtraLayout XtraTreeList) do call :copyDll %%f
|
||||
call :CodeSigning
|
||||
|
||||
|
||||
Reference in New Issue
Block a user