- basic support for Enigma2 (Dreambox, Vu+,...) channel lists

- dynamic number of favorite lists (still limited to 64 due to bitmask)
This commit is contained in:
Horst Beham
2021-03-07 16:12:21 +01:00
parent bc4b650f20
commit cb1fb9db5d
17 changed files with 608 additions and 23 deletions

View File

@@ -5,8 +5,6 @@ namespace ChanSort.Api
{
public class ChannelInfo
{
public const int MAX_FAV_LISTS = 16;
private string uid;
private string serviceTypeName;
private int newProgramNr;
@@ -106,13 +104,8 @@ namespace ChanSort.Api
{
this.OldProgramNr = -1;
this.NewProgramNr = -1;
this.FavIndex = new List<int>(MAX_FAV_LISTS);
this.OldFavIndex = new List<int>(MAX_FAV_LISTS);
for (int i = 0; i < MAX_FAV_LISTS; i++)
{
this.FavIndex.Add(-1);
this.OldFavIndex.Add(-1);
}
this.FavIndex = new List<int>();
this.OldFavIndex = new List<int>();
this.Name = "";
this.ShortName = "";
}
@@ -315,7 +308,7 @@ namespace ChanSort.Api
/// </summary>
public int GetPosition(int subListIndex)
{
return subListIndex == 0 ? this.NewProgramNr : this.FavIndex[subListIndex - 1];
return subListIndex < 0 ? -1 : subListIndex == 0 ? this.NewProgramNr : subListIndex - 1 < this.FavIndex.Count ? this.FavIndex[subListIndex - 1] : -1;
}
/// <summary>
@@ -323,7 +316,7 @@ namespace ChanSort.Api
/// </summary>
public int GetOldPosition(int subListIndex)
{
return subListIndex == 0 ? this.OldProgramNr : this.OldFavIndex[subListIndex - 1];
return subListIndex < 0 ? -1 : subListIndex == 0 ? this.OldProgramNr : subListIndex - 1 < this.OldFavIndex.Count ? this.OldFavIndex[subListIndex - 1] : -1;
}
/// <summary>
@@ -331,10 +324,14 @@ namespace ChanSort.Api
/// </summary>
public void SetPosition(int subListIndex, int newPos)
{
if (subListIndex < 0)
return;
if (subListIndex == 0)
this.NewProgramNr = newPos;
else
{
for (int i=this.FavIndex.Count; i<=subListIndex;i++)
this.FavIndex.Add(-1);
this.FavIndex[subListIndex - 1] = newPos;
int mask = 1 << (subListIndex - 1);
if (newPos == -1)
@@ -349,10 +346,16 @@ namespace ChanSort.Api
/// </summary>
public void SetOldPosition(int subListIndex, int oldPos)
{
if (subListIndex < 0)
return;
if (subListIndex == 0)
this.OldProgramNr = oldPos;
else
{
for (int i = this.OldFavIndex.Count; i <= subListIndex; i++)
this.OldFavIndex.Add(-1);
this.OldFavIndex[subListIndex - 1] = oldPos;
}
}
/// <summary>
@@ -363,7 +366,11 @@ namespace ChanSort.Api
if (subListIndex == 0)
this.NewProgramNr += delta;
else
this.FavIndex[subListIndex - 1] += delta;
{
for (int i = this.FavIndex.Count; i <= subListIndex; i++)
this.FavIndex.Add(-1);
this.FavIndex[subListIndex - 1] += delta;
}
}
#endregion
}

View File

@@ -12,6 +12,8 @@ namespace ChanSort.Api
private int insertProgramNr = 1;
private int duplicateUidCount;
private int duplicateProgNrCount;
public int FavListCount { get; set; }
public static List<string> DefaultVisibleColumns { get; set; } = new List<string>(); // initialized by MainForm

View File

@@ -17,7 +17,6 @@ namespace ChanSort.Api
public bool IsEmpty => this.channelLists.Count == 0;
public bool NeedsSaving { get; set; }
public Favorites SupportedFavorites => this.loader.Features.SupportedFavorites;
public bool SortedFavorites => this.loader.Features.SortedFavorites;
public bool MixedSourceFavorites => this.loader.Features.MixedSourceFavorites;
@@ -111,6 +110,12 @@ namespace ChanSort.Api
{
foreach (var list in this.ChannelLists)
{
if (list.FavListCount == 0)
{
for (ulong m = (ulong) this.loader.Features.SupportedFavorites; m != 0; m >>= 1)
++list.FavListCount;
}
if (list.IsMixedSourceFavoritesList)
{
loader.Features.SortedFavorites = true; // all mixed source favorite lists must support ordering
@@ -142,7 +147,7 @@ namespace ChanSort.Api
int c = 0;
if (this.MixedSourceFavorites || this.SortedFavorites)
{
for (int m = (int) this.SupportedFavorites; m != 0; m >>= 1)
for (ulong m = (ulong) this.SupportedFavorites; m != 0; m >>= 1)
++c;
}
@@ -265,7 +270,7 @@ namespace ChanSort.Api
var hasCaption = favListCaptions.TryGetValue(favIndex, out var caption);
if (!asTabCaption)
return caption;
var letter = (char)('A' + favIndex);
var letter = favIndex < 26 ? ((char)('A' + favIndex)).ToString() : (favIndex + 1).ToString();
return hasCaption && !string.IsNullOrEmpty(caption) ? letter + ": " + caption : "Fav " + letter;
}
#endregion

View File

@@ -76,7 +76,7 @@ namespace ChanSort.Api
#endregion
[Flags]
public enum Favorites : byte { A = 0x01, B = 0x02, C = 0x04, D = 0x08, E = 0x10, F=0x20, G=0x40, H=0x80 }
public enum Favorites : long { A = 0x01, B = 0x02, C = 0x04, D = 0x08, E = 0x10, F=0x20, G=0x40, H=0x80 }
public enum UnsortedChannelMode
{

View File

@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{4AD7F77E-617C-4741-82AE-E7A41C85EE4D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ChanSort.Loader.Enigma2</RootNamespace>
<AssemblyName>ChanSort.Loader.Enigma2</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<LangVersion>latest</LangVersion>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>latest</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>latest</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Channel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Enigma2Plugin.cs" />
<Compile Include="Serializer.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ChanSort.Api\ChanSort.Api.csproj">
<Project>{dccffa08-472b-4d17-bb90-8f513fc01392}</Project>
<Name>ChanSort.Api</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -0,0 +1,29 @@
using ChanSort.Api;
namespace ChanSort.Loader.Enigma2
{
internal class Channel : ChannelInfo
{
/// <summary>
/// first two fields of the lamedb entry
/// </summary>
public string Prefix { get; set; }
/// <summary>
/// For DVB-S it is the orbital position * 10 (e.g. 192 for Astra 19.2E) * 65536
/// </summary>
public int DvbNamespace { get; set; }
public int ServiceNumber { get; set; }
/// <summary>
/// all fields after the DVB-namespace in the lamedb entry
/// </summary>
public string Suffix { get; set; }
/// <summary>
/// #DESCRIPTION of the userbouquet entry
/// </summary>
public string Description { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
using ChanSort.Api;
namespace ChanSort.Loader.Enigma2
{
public class Enigma2Plugin : ISerializerPlugin
{
public string DllName { get; set; }
public string PluginName => "Enigma2 (Linux Receiver)";
public string FileFilter => "bouquets.*";
public SerializerBase CreateSerializer(string inputFile)
{
return new Serializer(inputFile);
}
}
}

View File

@@ -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.Enigma2")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ChanSort.Loader.Enigma2")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[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("4ad7f77e-617c-4741-82ae-e7a41c85ee4d")]
// 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")]

View File

@@ -0,0 +1,369 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using ChanSort.Api;
namespace ChanSort.Loader.Enigma2
{
/*
* This class loads "userbouquet.*" channel lists from Enigma2 Linux set-top-boxes (Dreambox, Vu+, ...)
*
* lamedb version 4 format: https://www.satsupreme.com/showthread.php/194074-Lamedb-format-explained
* userbouqet.* format: https://www.opena.tv/english-section/43964-iptv-service-4097-service-1-syntax.html#post376271
*/
internal class Serializer : SerializerBase
{
private static readonly Encoding utf8WithoutBom = new UTF8Encoding(false);
private ChannelList tv = new ChannelList(SignalSource.Digital | SignalSource.Tv, "TV");
private ChannelList radio = new ChannelList(SignalSource.Digital | SignalSource.Radio, "Radio");
private readonly List<string> favListFileNames = new();
private readonly Dictionary<string, Transponder> transponderByLamedbId = new();
private readonly Dictionary<string, Channel> channelsByBouquetId = new();
private DvbStringDecoder decoder;
private readonly StringBuilder log = new();
#region ctor()
public Serializer(string inputFile) : base(inputFile)
{
this.FileName = Path.Combine(Path.GetDirectoryName(inputFile), "lamedb");
this.Features.ChannelNameEdit = ChannelNameEditMode.None;
this.Features.DeleteMode = DeleteMode.Physically;
this.Features.CanSkipChannels = false;
this.Features.CanLockChannels = false;
this.Features.CanHideChannels = false;
this.Features.MixedSourceFavorites = true;
this.Features.SortedFavorites = true;
this.Features.SupportedFavorites = 0; // dynamically added
this.Features.CanSaveAs = false;
this.tv.IsMixedSourceFavoritesList = true;
this.DataRoot.AddChannelList(this.tv);
this.radio.IsMixedSourceFavoritesList = true;
this.DataRoot.AddChannelList(this.radio);
// hide columns for fields that don't exist in Silva-Schneider channel list
foreach (var list in this.DataRoot.ChannelLists)
{
list.VisibleColumnFieldNames.Remove("PcrPid");
list.VisibleColumnFieldNames.Remove("VideoPid");
list.VisibleColumnFieldNames.Remove("AudioPid");
list.VisibleColumnFieldNames.Remove("Lock");
list.VisibleColumnFieldNames.Remove("Skip");
list.VisibleColumnFieldNames.Remove("Hidden");
list.VisibleColumnFieldNames.Remove("Encrypted");
list.VisibleColumnFieldNames.Remove("Favorites");
list.VisibleColumnFieldNames.Remove("ServiceType");
list.VisibleColumnFieldNames.Add("ServiceTypeName");
}
}
#endregion
#region Load()
public override void Load()
{
this.decoder = new DvbStringDecoder(this.DefaultEncoding);
this.LoadLamedb();
int favId = 0;
foreach(var file in Directory.GetFiles(Path.GetDirectoryName(this.FileName), "userbouquet.*"))
this.LoadBouquet(file, ref favId);
}
#endregion
#region LoadLamedb()
private void LoadLamedb()
{
var path = Path.Combine(Path.GetDirectoryName(this.FileName), "lamedb");
if (!File.Exists(path))
throw new FileLoadException($"Could not find required file \"{path}\"");
using var r = new StreamReader(File.OpenRead(path), utf8WithoutBom);
var line = r.ReadLine();
if (line != "eDVB services /4/")
throw new FileLoadException($"lamedb version 4 is required");
string mode = null;
Transponder tp = null;
int tpId = 0, chanId = 0;
while ((line = r.ReadLine()) != null)
{
if (line.Trim() == "")
continue;
if (line == "transponders")
mode = line;
else if (line == "services")
mode = "services";
else if (line == "end")
mode = null;
else if (mode == "transponders")
tp = ReadLamedbTransponderLine(line, tp, ref tpId);
else if (mode == "services")
ReadLamedbServiceLine(line, r, ref chanId);
}
}
#endregion
#region ReadLamedbTransponderLine
private Transponder ReadLamedbTransponderLine(string line, Transponder tp, ref int tpId)
{
if (line == "/")
return tp;
if (!line.StartsWith("\t"))
{
tp = new Transponder(++tpId);
this.transponderByLamedbId[line] = tp;
var parts = line.Split(':');
tp.Number = FromHex(parts[0]);
tp.TransportStreamId = FromHex(parts[1]);
tp.OriginalNetworkId = FromHex(parts[2]);
}
else
{
if (line[1] == 's')
{
var parts = line.Substring(3).Split(':');
tp.FrequencyInMhz = int.Parse(parts[0]) / 1000;
tp.SymbolRate = int.Parse(parts[1]) / 1000;
tp.Polarity = "HVLR"[int.Parse(parts[2])];
tp.Satellite = GetOrCreateSatellite(int.Parse(parts[4]));
}
}
return tp;
}
#endregion
#region GetOrCreateSatellite
private Satellite GetOrCreateSatellite(int orbitalPos)
{
if (this.DataRoot.Satellites.TryGetValue(orbitalPos, out var sat))
return sat;
sat = new Satellite(orbitalPos);
sat.OrbitalPosition = $"{(float) Math.Abs(orbitalPos) / 10:0.0}{(orbitalPos<0?'W':'E')}";
sat.Name = sat.OrbitalPosition;
this.DataRoot.Satellites.Add(orbitalPos, sat);
return sat;
}
#endregion
#region ReadLamedbServiceLine
private void ReadLamedbServiceLine(string line, StreamReader r, ref int chanId)
{
var line2 = r.ReadLine();
var line3 = r.ReadLine();
if (line2 == null || line3 == null)
return;
var ch = new Channel();
ch.SignalSource = SignalSource.Digital;
// line 1: SID:DvbNamespace:TSID:ONID:ServiceType:ServiceNumber
var parts = line.Split(':');
ch.RecordIndex = chanId;
ch.RecordOrder = chanId;
ch.OldProgramNr = ++chanId;
ch.NewProgramNr = chanId;
ch.IsDeleted = false;
ch.ServiceId = FromHex(parts[0]);
ch.DvbNamespace = FromHex(parts[1]);
ch.TransportStreamId = FromHex(parts[2]);
ch.OriginalNetworkId = FromHex(parts[3]);
ch.ServiceType = int.Parse(parts[4]);
ch.ServiceNumber = int.Parse(parts[5]);
ch.SignalSource |= LookupData.Instance.IsRadioTvOrData(ch.ServiceType);
var tpId = parts[1] + ":" + parts[2] + ":" + parts[3];
if (this.transponderByLamedbId.TryGetValue(tpId, out var tp))
{
ch.Satellite = tp.Satellite?.Name;
ch.SymbolRate = tp.SymbolRate;
ch.FreqInMhz = tp.FrequencyInMhz;
ch.Polarity = tp.Polarity;
}
// line 2: channel name (in raw DVB encoding)
var rawName = new byte[line2.Length];
for (int i = 0, c = rawName.Length; i < c; i++)
rawName[i] = (byte)line2[i];
this.decoder.GetChannelNames(rawName, 0, rawName.Length, out var longName, out var shortName);
ch.Name = longName;
ch.ShortName = shortName;
// line 3: provider and other info
parts = line3.Split(',');
foreach (var part in parts)
{
var keyVal = part.Split(new char[] {':'}, 2);
switch (keyVal[0])
{
case "p":
ch.Provider = keyVal[1];
break;
}
}
this.DataRoot.AddChannel(this.tv, ch);
this.channelsByBouquetId[$"{ch.DvbNamespace}:{ch.OriginalNetworkId}:{ch.TransportStreamId}:{ch.ServiceId}"] = ch;
}
#endregion
#region LoadBoquet
private void LoadBouquet(string file, ref int favIndex)
{
ChannelList list;
if (file.EndsWith(".tv"))
list = this.tv;
else if (file.EndsWith(".radio"))
list = this.radio;
else
return;
using var r = new StreamReader(File.OpenRead(file), utf8WithoutBom);
var line = r.ReadLine();
if (line == null || !line.StartsWith("#NAME "))
{
log.AppendLine($"{file} does not start with #NAME");
return;
}
this.DataRoot.SetFavListCaption(favIndex, line.Substring(6));
this.Features.SupportedFavorites = (Favorites)((int)this.Features.SupportedFavorites<<1)|Favorites.A;
int lineNr = 0;
int progNr = 0;
Channel ch = null;
while ((line = r.ReadLine()) != null)
{
++lineNr;
if (line.Trim() == "")
continue;
if (line.Contains(":FROM") && line.Contains("ORDER BY")) // ignore the root-level bouquet that only references other bouquet files
return;
if (line.StartsWith("#DESCRIPTION "))
{
if (ch != null)
ch.Description = line.Substring(13);
continue;
}
if (!line.StartsWith("#SERVICE "))
continue;
var parts = line.Substring(9).Split(':');
if (parts[0] != "1") // ignore non-DVB
continue;
if (parts[1] != "0") // ignore special-purpose rows
continue;
var prefix = parts[0] + ":" + parts[1];
// parts[2] = DVB service type
var sid = FromHex(parts[3]);
var tsid = FromHex(parts[4]);
var onid = FromHex(parts[5]);
var dvbNamespace = FromHex(parts[6]);
var suffix = "";
for (int i = 7; i < parts.Length; i++)
suffix += ":" + parts[i];
var key = $"{dvbNamespace}:{onid}:{tsid}:{sid}";
if (!this.channelsByBouquetId.TryGetValue(key, out ch))
{
log.AppendLine($"{file} line {lineNr}: service not found in lamedb");
continue;
}
ch.Prefix = prefix;
ch.Suffix = suffix;
ch.SetOldPosition(1+favIndex, ++progNr);
}
this.favListFileNames.Add(file);
++favIndex;
}
#endregion
#region FromHex()
private int FromHex(string str)
{
int result = 0;
foreach (var ch in str)
{
if (Char.IsWhiteSpace(ch))
continue;
result <<= 4;
if (ch >= '0' && ch <= '9')
result += ch - '0';
else if (ch >= 'A' && ch <= 'F')
result += ch - 'A' + 10;
else if (ch >= 'a' && ch <= 'f')
result += ch - 'a' + 10;
else
throw new ArgumentException(str + " contains invalid hex characters");
}
return result;
}
#endregion
#region GetDataFilePaths()
public override IEnumerable<string> GetDataFilePaths()
{
var list = new List<string>(this.favListFileNames.Count + 1);
list.Add(this.FileName); // lamedb
list.AddRange(this.favListFileNames); // userbouquet*
return list;
}
#endregion
#region Save()
public override void Save(string tvOutputFile)
{
for (int favIndex = 0; favIndex < this.favListFileNames.Count; favIndex++)
{
var file = this.favListFileNames[favIndex];
using var w = new StreamWriter(File.OpenWrite(file), utf8WithoutBom);
w.WriteLine($"#NAME {this.DataRoot.GetFavListCaption(favIndex)}");
foreach (var ch in this.tv.Channels.OrderBy(c => c.GetPosition(favIndex+1)))
{
if (!(ch is Channel c) || c.GetPosition(favIndex + 1) < 0)
continue;
w.WriteLine($"#SERVICE {c.Prefix}:{c.ServiceType:X}:{c.ServiceId:X}:{c.TransportStreamId:X}:{c.OriginalNetworkId:X}:{c.DvbNamespace:X}{c.Suffix}");
if (c.Description != null)
w.WriteLine($"#DESCRIPTION {c.Description}");
}
}
}
#endregion
#region GetFileInformation()
public override string GetFileInformation()
{
var sb = new StringBuilder();
sb.Append(base.GetFileInformation());
sb.AppendLine();
sb.Append(this.log);
return sb.ToString();
}
#endregion
}
}

View File

@@ -245,7 +245,7 @@ namespace ChanSort.Loader.Philips
ch.Lock = mapping.GetByte("offLocked") != 0;
ch.Favorites = mapping.GetByte("offIsFav") != 0 ? Favorites.A : 0;
if (ch.Favorites != 0)
ch.OldFavIndex[0] = ch.OldProgramNr;
ch.SetOldPosition(1, ch.OldProgramNr);
this.DataRoot.AddChannel(list, ch);
}

View File

@@ -360,7 +360,7 @@ namespace ChanSort.Loader.Philips
chan.Lock = data.TryGet("ChannelLock") == "1";
chan.Hidden = data.TryGet("UserHidden") == "1";
var fav = ParseInt(data.TryGet("FavoriteNumber"));
chan.OldFavIndex[0] = fav == 0 ? -1 : fav;
chan.SetOldPosition(1, fav == 0 ? -1 : fav);
chan.OriginalNetworkId = ParseInt(data.TryGet("Onid"));
chan.TransportStreamId = ParseInt(data.TryGet("Tsid"));
chan.ServiceId = ParseInt(data.TryGet("Sid"));

View File

@@ -94,7 +94,7 @@ namespace ChanSort.Loader.Samsung.Scm
else if (sortedFavorites != FavoritesIndexMode.Boolean && favValue != -1)
fav |= mask;
if (sortedFavorites == FavoritesIndexMode.IndividuallySorted)
this.OldFavIndex[favIndex] = favValue;
this.SetOldPosition(1+favIndex, favValue);
mask <<= 1;
++favIndex;
}

View File

@@ -616,8 +616,8 @@ namespace ChanSort.Loader.Samsung.Zip
// update favorites
for (int i=0, mask=1; i<5; i++, mask <<= 1)
{
int oldPos = channel.OldFavIndex[i];
int newPos = ((int)channel.Favorites & mask) != 0 ? channel.FavIndex[i] : -1;
int oldPos = channel.GetOldPosition(1+i);
int newPos = ((int)channel.Favorites & mask) != 0 ? channel.GetPosition(1+i) : -1;
if (newPos >= 0)
{

View File

@@ -69,6 +69,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChanSort.Loader.Grundig", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test.Loader.M3u", "Test.Loader.M3u\Test.Loader.M3u.csproj", "{052692BF-D782-4888-B34D-89D6B1379340}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChanSort.Loader.Enigma2", "ChanSort.Loader.Enigma2\ChanSort.Loader.Enigma2.csproj", "{4AD7F77E-617C-4741-82AE-E7A41C85EE4D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -379,6 +381,18 @@ Global
{052692BF-D782-4888-B34D-89D6B1379340}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{052692BF-D782-4888-B34D-89D6B1379340}.Release|x86.ActiveCfg = Release|Any CPU
{052692BF-D782-4888-B34D-89D6B1379340}.Release|x86.Build.0 = Release|Any CPU
{4AD7F77E-617C-4741-82AE-E7A41C85EE4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4AD7F77E-617C-4741-82AE-E7A41C85EE4D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4AD7F77E-617C-4741-82AE-E7A41C85EE4D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{4AD7F77E-617C-4741-82AE-E7A41C85EE4D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{4AD7F77E-617C-4741-82AE-E7A41C85EE4D}.Debug|x86.ActiveCfg = Debug|x86
{4AD7F77E-617C-4741-82AE-E7A41C85EE4D}.Debug|x86.Build.0 = Debug|x86
{4AD7F77E-617C-4741-82AE-E7A41C85EE4D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4AD7F77E-617C-4741-82AE-E7A41C85EE4D}.Release|Any CPU.Build.0 = Release|Any CPU
{4AD7F77E-617C-4741-82AE-E7A41C85EE4D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{4AD7F77E-617C-4741-82AE-E7A41C85EE4D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{4AD7F77E-617C-4741-82AE-E7A41C85EE4D}.Release|x86.ActiveCfg = Release|Any CPU
{4AD7F77E-617C-4741-82AE-E7A41C85EE4D}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -482,6 +482,14 @@
<Project>{DCCFFA08-472B-4D17-BB90-8F513FC01392}</Project>
<Name>ChanSort.Api</Name>
</ProjectReference>
<ProjectReference Include="..\ChanSort.Loader.Enigma2\ChanSort.Loader.Enigma2.csproj">
<Project>{4ad7f77e-617c-4741-82ae-e7a41c85ee4d}</Project>
<Name>ChanSort.Loader.Enigma2</Name>
</ProjectReference>
<ProjectReference Include="..\ChanSort.Loader.Grundig\ChanSort.Loader.Grundig.csproj">
<Project>{4d5af0a3-1b96-42c8-910d-0c4852ea22f4}</Project>
<Name>ChanSort.Loader.Grundig</Name>
</ProjectReference>
<ProjectReference Include="..\ChanSort.Loader.Hisense\ChanSort.Loader.Hisense.csproj">
<Project>{d093e7ee-d3ad-4e7b-af82-c6918ca017fb}</Project>
<Name>ChanSort.Loader.Hisense</Name>
@@ -506,6 +514,10 @@
<Project>{a1c9a98d-368a-44e8-9b7f-7eaca46c9ec5}</Project>
<Name>ChanSort.Loader.Samsung</Name>
</ProjectReference>
<ProjectReference Include="..\ChanSort.Loader.SatcoDX\ChanSort.Loader.SatcoDX.csproj">
<Project>{e6279ff8-362a-41e6-ac0d-d0861d43f01c}</Project>
<Name>ChanSort.Loader.SatcoDX</Name>
</ProjectReference>
<ProjectReference Include="..\ChanSort.Loader.Sony\ChanSort.Loader.Sony.csproj">
<Project>{70e29c6b-b926-4859-9548-23375bf1e1b5}</Project>
<Name>ChanSort.Loader.Sony</Name>

View File

@@ -244,8 +244,8 @@ namespace ChanSort.Ui
extension.Append(ext);
extension.Append(";");
}
++numberOfFilters;
}
++numberOfFilters;
}
if (extension.Length > 0)
extension.Remove(extension.Length - 1, 1);

View File

@@ -18,6 +18,18 @@ namespace ChanSort.Ui
private SerializerBase serializer;
private readonly string[] closeButtonText;
class MixedSourceList
{
public ChannelList ChannelList { get; }
public int FavIndex { get; }
public MixedSourceList(ChannelList list, int favIndex)
{
ChannelList = list;
FavIndex = favIndex;
}
}
public ReferenceListForm(MainForm main)
{
this.main = main;
@@ -113,7 +125,13 @@ namespace ChanSort.Ui
this.comboSource.Properties.Items.Clear();
foreach (var list in serializer.DataRoot.ChannelLists)
{
if (!list.IsMixedSourceFavoritesList && list.Channels.Count > 0)
if (list.Channels.Count == 0)
continue;
if (list.IsMixedSourceFavoritesList)
{
this.comboSource.Properties.Items.Add(new MixedSourceList(list, i))
}
else
this.comboSource.Properties.Items.Add(list);
}