Files
ChanSort/source/ChanSort.Api/Controller/CsvFileSerializer.cs
hbeham 0a71f34639 CsvFileSerializer and RefSerializer are now back in the .Api project. CSV, TXT and CHL files can now be loaded and edited like any other supported channel list.
Eleminated redundant code that was used for loading/applying reference lists in CSV or TXT/CHL format.
2016-05-05 03:06:11 +02:00

335 lines
9.3 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace ChanSort.Api
{
/// <summary>
/// Reads a reference list from a .csv file with the format
/// [dummy1],ProgramNr,[dummy2],UID,ChannelName[,SignalSource,FavAndFlags]
/// </summary>
public class CsvFileSerializer : SerializerBase
{
private static readonly List<string> Columns = new List<string>
{
"OldPosition",
"Position",
"Name",
"OriginalNetworkId",
"TransportStreamId",
"ServiceId",
"Favorites",
"Skip",
"Lock",
"Hidden"
};
#region ctor()
public CsvFileSerializer(string fileName) : base(fileName)
{
this.Features.ChannelNameEdit = ChannelNameEditMode.All;
this.Features.CanSkipChannels = true;
this.Features.CanDeleteChannels = true;
this.Features.CanHaveGaps = true;
this.Features.EncryptedFlagEdit = false;
this.DataRoot.SortedFavorites = false;
this.DataRoot.SupportedFavorites = Favorites.A | Favorites.B | Favorites.C | Favorites.D | Favorites.E;
}
#endregion
public override string DisplayName => "ChanSort .csv Reference List Loader";
#region Load()
public override void Load()
{
using (var stream = new StreamReader(this.FileName))
{
var lineNr = 0;
var line = "";
try
{
while ((line = stream.ReadLine()) != null)
this.ReadChannel(line, ++lineNr);
}
catch (Exception ex)
{
throw new FileLoadException($"Error in reference file line #{lineNr}: {line}", ex);
}
}
}
#endregion
#region ReadChannel()
private void ReadChannel(string line, int lineNr)
{
var parts = CsvFile.Parse(line, ',');
if (parts.Count < 5) return;
int programNr;
if (!int.TryParse(parts[1], out programNr)) return;
var uid = parts[3];
if (uid.StartsWith("S")) // remove satellite orbital position from UID ... not all TV models provide this information
uid = "S" + uid.Substring(uid.IndexOf('-'));
var signalSource = GetSignalSource(ref programNr, uid, parts);
if (signalSource == 0)
return;
var channelList = this.GetChannelList(signalSource);
if (channelList == null)
return;
var name = parts[4];
var channel = new ChannelInfo(signalSource, lineNr, programNr, name);
var uidParts = uid.Split('-');
if (uidParts.Length >= 4)
{
int val;
if (int.TryParse(uidParts[1], out val))
channel.OriginalNetworkId = val;
if (int.TryParse(uidParts[2], out val))
channel.TransportStreamId = val;
if (int.TryParse(uidParts[3], out val))
channel.ServiceId = val;
}
if (parts.Count >= 7)
ApplyFlags(channel, parts[6]);
this.DataRoot.AddChannel(channelList, channel);
}
#endregion
#region GetSignalSource()
private static SignalSource GetSignalSource(ref int slot, string uid, IList<string> parts)
{
// new lists store a bitmask which defines the type of channel and list it came from
if (parts.Count >= 6 && parts[5].Length >= 4)
{
SignalSource s = 0;
var code = parts[5];
if (code[0] == 'A') s |= SignalSource.Analog;
else if (code[0] == 'D') s |= SignalSource.Digital;
if (code[1] == 'A') s |= SignalSource.Antenna;
else if (code[1] == 'C') s |= SignalSource.Cable;
else if (code[1] == 'S') s |= SignalSource.Sat;
else if (code[1] == 'I') s |= SignalSource.IP;
if (code[2] == 'T') s |= SignalSource.Tv;
else if (code[2] == 'R') s |= SignalSource.Radio;
s |= (SignalSource) (int.Parse(code.Substring(3)) << 12);
return s;
}
// compatibility for older lists
var isTv = slot < 0x4000;
slot &= 0x3FFFF;
SignalSource signalSource;
switch (uid[0])
{
case 'S':
signalSource = SignalSource.DvbS;
break;
case 'C':
signalSource = SignalSource.DvbCT;
break;
case 'A':
signalSource = SignalSource.AnalogCT;
break;
case 'H':
signalSource = SignalSource.HdPlusD;
break;
default:
return 0;
}
signalSource |= isTv ? SignalSource.Tv : SignalSource.Radio;
return signalSource;
}
#endregion
#region GetChannelList()
private ChannelList GetChannelList(SignalSource signalSource)
{
var channelList = this.DataRoot.GetChannelList(signalSource);
if (channelList == null)
{
channelList = new ChannelList(signalSource, CreateCaption(signalSource));
channelList.VisibleColumnFieldNames = Columns;
this.DataRoot.AddChannelList(channelList);
}
return channelList;
}
#endregion
#region CreateCaption()
private string CreateCaption(SignalSource signalSource)
{
var sb = new StringBuilder();
if ((signalSource & SignalSource.DvbT) == SignalSource.DvbT)
sb.Append("DVB-T");
else if ((signalSource & SignalSource.DvbC) == SignalSource.DvbC)
sb.Append("DVB-C");
else if ((signalSource & SignalSource.DvbS) == SignalSource.DvbS)
sb.Append("DVB-S");
else if ((signalSource & SignalSource.IP) == SignalSource.IP)
sb.Append("IP");
else if ((signalSource & SignalSource.Digital) == SignalSource.Digital)
sb.Append("DVB");
else if ((signalSource & SignalSource.Analog) == SignalSource.Analog)
sb.Append("Analog");
sb.Append(" ");
if ((signalSource & SignalSource.Tv) == SignalSource.Tv)
sb.Append("TV");
else if ((signalSource & SignalSource.Radio) == SignalSource.Radio)
sb.Append("Radio");
else
sb.Append("Data");
return sb.ToString();
}
#endregion
#region ApplyFlags()
private void ApplyFlags(ChannelInfo channel, string flags)
{
channel.Lock = false;
channel.Skip = false;
channel.Hidden = false;
foreach (var c in flags)
{
switch (c)
{
case '1':
channel.Favorites |= Favorites.A;
break;
case '2':
channel.Favorites |= Favorites.B;
break;
case '3':
channel.Favorites |= Favorites.C;
break;
case '4':
channel.Favorites |= Favorites.D;
break;
case '5':
channel.Favorites |= Favorites.E;
break;
case 'L':
channel.Lock = true;
break;
case 'S':
channel.Skip = true;
break;
case 'H':
channel.Hidden = true;
break;
case 'D':
channel.IsDeleted = true;
break;
}
}
}
#endregion
#region EncodeSignalSource()
private static string EncodeSignalSource(SignalSource signalSource)
{
var sb = new StringBuilder();
if ((signalSource & SignalSource.Analog) != 0) sb.Append('A');
else sb.Append('D');
if ((signalSource & SignalSource.Antenna) != 0) sb.Append('A');
else if ((signalSource & SignalSource.Cable) != 0) sb.Append('C');
else if ((signalSource & SignalSource.Sat) != 0) sb.Append('S');
else sb.Append("I");
if ((signalSource & SignalSource.Radio) != 0) sb.Append('R');
else sb.Append('T');
sb.Append((int) signalSource >> 12);
return sb.ToString();
}
#endregion
#region EncodeFavoritesAndFlags()
private static string EncodeFavoritesAndFlags(ChannelInfo channel)
{
var sb = new StringBuilder();
if ((channel.Favorites & Favorites.A) != 0) sb.Append('1');
if ((channel.Favorites & Favorites.B) != 0) sb.Append('2');
if ((channel.Favorites & Favorites.C) != 0) sb.Append('3');
if ((channel.Favorites & Favorites.D) != 0) sb.Append('4');
if ((channel.Favorites & Favorites.E) != 0) sb.Append('5');
if (channel.Lock) sb.Append('L');
if (channel.Skip) sb.Append('S');
if (channel.Hidden) sb.Append('H');
if (channel.IsDeleted) sb.Append('D');
return sb.ToString();
}
#endregion
#region Save()
public override void Save(string tvDataFile)
{
Save(tvDataFile, this.DataRoot);
this.FileName = tvDataFile;
}
public static void Save(string tvDataFile, DataRoot dataRoot)
{
using (var stream = new StreamWriter(tvDataFile))
{
Save(stream, dataRoot);
}
}
public static void Save(StreamWriter stream, DataRoot dataRoot)
{
foreach (var channelList in dataRoot.ChannelLists)
{
if (channelList.IsMixedSourceFavoritesList) // these pseudo-lists would create dupes for all channels
continue;
foreach (var channel in channelList.GetChannelsByNewOrder())
{
if (channel.NewProgramNr == -1)
continue;
var line = string.Format("{0},{1},{2},{3},\"{4}\",{5},{6}",
"", // past: channel.RecordIndex,
channel.NewProgramNr,
"", // past: channel.TransportStreamId,
channel.Uid,
channel.Name,
EncodeSignalSource(channel.SignalSource),
EncodeFavoritesAndFlags(channel));
stream.WriteLine(line);
}
}
}
#endregion
}
}