mirror of
https://github.com/PredatH0r/ChanSort.git
synced 2026-03-13 07:20:17 +01:00
- moved all files to a "source" subdirectory to tidy up the GitHub project page
- started to write a readme.md
This commit is contained in:
120
source/ChanSort.Api/Controller/ChlFileSerializer.cs
Normal file
120
source/ChanSort.Api/Controller/ChlFileSerializer.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace ChanSort.Api
|
||||
{
|
||||
/// <summary>
|
||||
/// Reader for SamToolBox reference lists (*.chl)
|
||||
/// The file has no header, each line represents a channel and fields are separated by semi-colon:
|
||||
/// Number;Channel Name[;Transponder Index]
|
||||
/// </summary>
|
||||
public class ChlFileSerializer
|
||||
{
|
||||
private static readonly char[] Separators = new[] { ';' };
|
||||
private readonly StringBuilder warnings = new StringBuilder();
|
||||
private int lineNumber;
|
||||
private DataRoot dataRoot;
|
||||
private ChannelList channelList;
|
||||
|
||||
#region Load()
|
||||
public string Load(string fileName, DataRoot root, ChannelList list)
|
||||
{
|
||||
if (list.ReadOnly)
|
||||
return "The current channel list is read-only";
|
||||
|
||||
this.lineNumber = 0;
|
||||
this.dataRoot = root;
|
||||
this.channelList = list;
|
||||
this.warnings.Remove(0, this.warnings.Length);
|
||||
|
||||
foreach (var channel in this.channelList.Channels)
|
||||
channel.NewProgramNr = -1;
|
||||
|
||||
using (var stream = new StreamReader(fileName, Encoding.Default))
|
||||
{
|
||||
ReadChannelsFromStream(stream);
|
||||
}
|
||||
return this.warnings.ToString();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ReadChannelsFromStream()
|
||||
|
||||
private void ReadChannelsFromStream(TextReader stream)
|
||||
{
|
||||
string line;
|
||||
while ((line = stream.ReadLine()) != null)
|
||||
{
|
||||
++lineNumber;
|
||||
ParseChannel(line);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ParseChannel()
|
||||
|
||||
private void ParseChannel(string line)
|
||||
{
|
||||
var parts = line.Split(Separators);
|
||||
if (parts.Length < 2) return;
|
||||
int progNr;
|
||||
Transponder transponder = null;
|
||||
if (!int.TryParse(parts[0], out progNr)) return;
|
||||
if (parts.Length >= 3)
|
||||
{
|
||||
int transponderIndex;
|
||||
if (int.TryParse(parts[2], out transponderIndex))
|
||||
{
|
||||
transponder = this.dataRoot.Transponder.TryGet(transponderIndex);
|
||||
if (transponder == null)
|
||||
warnings.AppendFormat("Line #{0,4}: invalid transponder index {1}\r\n", this.lineNumber, transponderIndex);
|
||||
}
|
||||
}
|
||||
|
||||
string name = parts[1].Replace("\"", "");
|
||||
if (name.Trim().Length == 0)
|
||||
return;
|
||||
|
||||
int found = 0;
|
||||
var channels = channelList.GetChannelByName(name);
|
||||
if (transponder != null)
|
||||
channels = channels.Where(chan => chan.Transponder == transponder);
|
||||
|
||||
foreach(var channel in channels)
|
||||
{
|
||||
if (channel.NewProgramNr != -1)
|
||||
continue;
|
||||
++found;
|
||||
if (found > 1)
|
||||
break;
|
||||
channel.NewProgramNr = progNr;
|
||||
}
|
||||
|
||||
if (found == 0)
|
||||
this.warnings.AppendFormat("Line {0,4}: Pr# {1,4}, channel '{2}' could not be found\r\n", this.lineNumber, progNr, name);
|
||||
if (found > 1)
|
||||
this.warnings.AppendFormat("Line {0,4}: Pr# {1,4}, channel '{2}' found multiple times\r\n", this.lineNumber, progNr, name);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Save()
|
||||
public void Save(string fileName, ChannelList list)
|
||||
{
|
||||
using (var writer = new StreamWriter(fileName, false, Encoding.UTF8))
|
||||
{
|
||||
foreach (var channel in list.Channels.OrderBy(c => c.NewProgramNr))
|
||||
{
|
||||
if (channel.NewProgramNr == -1) continue;
|
||||
|
||||
writer.Write(channel.NewProgramNr);
|
||||
writer.Write(';');
|
||||
writer.Write(channel.Name);
|
||||
writer.WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
284
source/ChanSort.Api/Controller/CsvFileSerializer.cs
Normal file
284
source/ChanSort.Api/Controller/CsvFileSerializer.cs
Normal file
@@ -0,0 +1,284 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
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
|
||||
{
|
||||
private readonly HashSet<ChannelList> clearedLists = new HashSet<ChannelList>();
|
||||
private readonly DataRoot dataRoot;
|
||||
private readonly string fileName;
|
||||
private readonly bool addChannels;
|
||||
|
||||
#region ctor()
|
||||
public CsvFileSerializer(string fileName, DataRoot dataRoot, bool addChannels)
|
||||
{
|
||||
this.fileName = fileName;
|
||||
this.dataRoot = dataRoot;
|
||||
this.addChannels = addChannels;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Load()
|
||||
public void Load()
|
||||
{
|
||||
this.clearedLists.Clear();
|
||||
using (var stream = new StreamReader(fileName))
|
||||
this.ReadChannelsFromStream(stream);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ReadChannelsFromStream()
|
||||
|
||||
public void ReadChannelsFromStream(TextReader stream)
|
||||
{
|
||||
int lineNr = 0;
|
||||
string line = "";
|
||||
try
|
||||
{
|
||||
while ((line = stream.ReadLine()) != null)
|
||||
{
|
||||
++lineNr;
|
||||
this.ReadChannel(line);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new FileLoadException(string.Format("Error in reference file line #{0}: {1}", lineNr, line), ex);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ReadChannel()
|
||||
|
||||
private void ReadChannel(string line)
|
||||
{
|
||||
var parts = CsvFile.Parse(line, ',');
|
||||
if (parts.Count < 5) return;
|
||||
int programNr;
|
||||
if (!int.TryParse(parts[1], out programNr)) return;
|
||||
string uid = parts[3];
|
||||
SignalSource signalSource = GetSignalSource(ref programNr, uid, parts);
|
||||
if (signalSource == 0)
|
||||
return;
|
||||
|
||||
string name = parts[4];
|
||||
ChannelList channelList = this.GetInitiallyClearedChannelList(signalSource);
|
||||
if (channelList == null)
|
||||
return;
|
||||
|
||||
IEnumerable<ChannelInfo> channels = FindChannels(channelList, name, uid);
|
||||
var channel = channels == null ? null : channels.FirstOrDefault(c => c.NewProgramNr == -1);
|
||||
if (channel != null)
|
||||
{
|
||||
if (!this.addChannels)
|
||||
{
|
||||
channel.NewProgramNr = programNr;
|
||||
if ((channel.SignalSource & SignalSource.Analog) != 0)
|
||||
{
|
||||
channel.Name = name;
|
||||
channel.IsNameModified = true;
|
||||
}
|
||||
if (parts.Count >= 7)
|
||||
ApplyFlags(channel, parts[6]);
|
||||
}
|
||||
}
|
||||
else if (parts.Count >= 6) // create proxy channel when using the new ref-list format
|
||||
{
|
||||
channel = new ChannelInfo(signalSource, uid, programNr, name);
|
||||
if (addChannels)
|
||||
{
|
||||
channel.NewProgramNr = -1;
|
||||
channel.OldProgramNr = programNr;
|
||||
}
|
||||
channelList.AddChannel(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;
|
||||
string 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;
|
||||
|
||||
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
|
||||
bool 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 GetInitiallyClearedChannelList()
|
||||
private ChannelList GetInitiallyClearedChannelList(SignalSource signalSource)
|
||||
{
|
||||
var channelList = dataRoot.GetChannelList(signalSource);
|
||||
if (channelList == null || channelList.ReadOnly)
|
||||
return null;
|
||||
if (!this.addChannels && !this.clearedLists.Contains(channelList))
|
||||
{
|
||||
foreach (var channel in channelList.Channels)
|
||||
channel.NewProgramNr = -1;
|
||||
this.clearedLists.Add(channelList);
|
||||
}
|
||||
return channelList;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region FindChannels()
|
||||
private IEnumerable<ChannelInfo> FindChannels(ChannelList channelList, string name, string uid)
|
||||
{
|
||||
// if there's only a single channel with the given name, use it regardless of UID (allows for a changed freq/tranpsonder)
|
||||
IList<ChannelInfo> list = channelList.GetChannelByName(name).ToList();
|
||||
if (list.Count == 1)
|
||||
return list;
|
||||
|
||||
string[] uidParts;
|
||||
if (uid.StartsWith("C") && (uidParts = uid.Split('-')).Length <= 4)
|
||||
{
|
||||
// older CSV files didn't use the Transponder as part of the UID, which is necessary
|
||||
// to distinguish between DVB-T channels with identical (onid,tsid,sid), which may be received
|
||||
// from multiple regional transmitters on different transponders
|
||||
int onid = int.Parse(uidParts[1]);
|
||||
int tsid = int.Parse(uidParts[2]);
|
||||
int sid = int.Parse(uidParts[3]);
|
||||
return channelList.Channels.Where(c =>
|
||||
c.OriginalNetworkId == onid &&
|
||||
c.TransportStreamId == tsid &&
|
||||
c.ServiceId == sid
|
||||
).ToList();
|
||||
}
|
||||
|
||||
var byUidList = channelList.GetChannelByUid(uid);
|
||||
return byUidList;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ApplyFlags()
|
||||
private void ApplyFlags(ChannelInfo channel, string flags)
|
||||
{
|
||||
channel.Lock = false;
|
||||
channel.Skip = false;
|
||||
channel.Hidden = false;
|
||||
|
||||
foreach (char 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 Save()
|
||||
public void Save()
|
||||
{
|
||||
using (StreamWriter stream = new StreamWriter(fileName))
|
||||
{
|
||||
Save(stream);
|
||||
}
|
||||
}
|
||||
|
||||
public void Save(StreamWriter stream)
|
||||
{
|
||||
foreach (var channelList in dataRoot.ChannelLists)
|
||||
{
|
||||
foreach (var channel in channelList.Channels.Where(ch => ch.NewProgramNr != -1).OrderBy(ch => ch.NewProgramNr))
|
||||
{
|
||||
string line = string.Format("{0},{1},{2},{3},\"{4}\",{5},{6}",
|
||||
"", // past: channel.RecordIndex,
|
||||
channel.NewProgramNr,
|
||||
"", // past: channel.TransportStreamId,
|
||||
channel.Uid,
|
||||
channel.Name,
|
||||
this.EncodeSignalSource(channel.SignalSource),
|
||||
this.EncodeFavoritesAndFlags(channel));
|
||||
stream.WriteLine(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region EncodeSignalSource()
|
||||
private object EncodeSignalSource(SignalSource signalSource)
|
||||
{
|
||||
StringBuilder 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 sb.Append('S');
|
||||
|
||||
if ((signalSource & SignalSource.Radio) != 0) sb.Append('R');
|
||||
else sb.Append('T');
|
||||
|
||||
sb.Append((int)signalSource >> 12);
|
||||
return sb.ToString();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region EncodeFavoritesAndFlags()
|
||||
private string EncodeFavoritesAndFlags(ChannelInfo channel)
|
||||
{
|
||||
StringBuilder 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
|
||||
}
|
||||
}
|
||||
401
source/ChanSort.Api/Controller/Editor.cs
Normal file
401
source/ChanSort.Api/Controller/Editor.cs
Normal file
@@ -0,0 +1,401 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace ChanSort.Api
|
||||
{
|
||||
public class Editor
|
||||
{
|
||||
public DataRoot DataRoot;
|
||||
public ChannelList ChannelList;
|
||||
public int SubListIndex;
|
||||
private UnsortedChannelMode unsortedChannelMode;
|
||||
|
||||
#region AddChannels()
|
||||
|
||||
public ChannelInfo AddChannels(IList<ChannelInfo> channels)
|
||||
{
|
||||
int count = channels.Count(channel => channel.GetPosition(this.SubListIndex) == -1);
|
||||
if (count == 0) return null;
|
||||
|
||||
ChannelInfo lastInsertedChannel = null;
|
||||
int progNr = this.ChannelList.InsertProgramNumber;
|
||||
int relativeChannelNumber = 0;
|
||||
int progNrCopy = progNr; // prevent "access to modified closure" warning
|
||||
foreach (
|
||||
var channel in
|
||||
this.ChannelList.Channels.Where(c => c.GetPosition(this.SubListIndex) >= progNrCopy)
|
||||
.OrderBy(c => c.GetPosition(this.SubListIndex)))
|
||||
{
|
||||
var curPos = channel.GetPosition(this.SubListIndex);
|
||||
int gap = count - (curPos - progNr - relativeChannelNumber);
|
||||
if (gap > 0)
|
||||
{
|
||||
channel.SetPosition(this.SubListIndex, curPos + gap);
|
||||
++relativeChannelNumber;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var channel in channels)
|
||||
{
|
||||
if (channel.GetPosition(this.SubListIndex) != -1)
|
||||
{
|
||||
// TODO notify user
|
||||
continue;
|
||||
}
|
||||
|
||||
channel.SetPosition(this.SubListIndex, progNr++);
|
||||
lastInsertedChannel = channel;
|
||||
}
|
||||
this.ChannelList.InsertProgramNumber += count;
|
||||
|
||||
this.DataRoot.NeedsSaving |= lastInsertedChannel != null;
|
||||
return lastInsertedChannel;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region RemoveChannels()
|
||||
|
||||
public void RemoveChannels(IList<ChannelInfo> channels, bool closeGap)
|
||||
{
|
||||
if (channels.Count == 0) return;
|
||||
|
||||
this.ChannelList.InsertProgramNumber = channels[0].GetPosition(this.SubListIndex);
|
||||
var orderedChannelList =
|
||||
this.ChannelList.Channels.Where(c => c.GetPosition(this.SubListIndex) != -1)
|
||||
.OrderBy(c => c.GetPosition(this.SubListIndex));
|
||||
foreach (var channel in channels)
|
||||
{
|
||||
if (channel.GetPosition(this.SubListIndex) == -1)
|
||||
continue;
|
||||
if (closeGap)
|
||||
{
|
||||
int prevNr = channel.GetPosition(this.SubListIndex);
|
||||
foreach (var channel2 in orderedChannelList)
|
||||
{
|
||||
if (channel2.GetPosition(this.SubListIndex) > channel.GetPosition(this.SubListIndex))
|
||||
{
|
||||
// ignore deleted and proxy channels (prevNr<0), broken channels (==0) and channels after a gap
|
||||
if (prevNr <= 0 || channel2.GetPosition(this.SubListIndex) != prevNr + 1)
|
||||
break;
|
||||
prevNr = channel2.GetPosition(this.SubListIndex);
|
||||
channel2.ChangePosition(this.SubListIndex, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
channel.SetPosition(this.SubListIndex, -1);
|
||||
}
|
||||
|
||||
this.DataRoot.NeedsSaving = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MoveChannels()
|
||||
|
||||
public void MoveChannels(IList<ChannelInfo> channels, bool up)
|
||||
{
|
||||
if (channels.Count == 0)
|
||||
return;
|
||||
if (up && channels[0].GetPosition(this.SubListIndex) <= this.ChannelList.FirstProgramNumber)
|
||||
return;
|
||||
|
||||
int delta = (up ? -1 : +1);
|
||||
foreach (var channel in (up ? channels : channels.Reverse()))
|
||||
{
|
||||
int newProgramNr = channel.GetPosition(this.SubListIndex) + delta;
|
||||
ChannelInfo channelAtNewPos =
|
||||
this.ChannelList.Channels.FirstOrDefault(ch => ch.GetPosition(this.SubListIndex) == newProgramNr);
|
||||
if (channelAtNewPos != null)
|
||||
channelAtNewPos.ChangePosition(this.SubListIndex, -delta);
|
||||
channel.ChangePosition(this.SubListIndex, delta);
|
||||
}
|
||||
this.DataRoot.NeedsSaving = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SortSelectedChannels(), ChannelComparerForSortingByName()
|
||||
|
||||
public void SortSelectedChannels(List<ChannelInfo> selectedChannels)
|
||||
{
|
||||
if (selectedChannels.Count == 0) return;
|
||||
var sortedChannels = new List<ChannelInfo>(selectedChannels);
|
||||
sortedChannels.Sort(this.ChannelComparerForSortingByName);
|
||||
var programNumbers = selectedChannels.Select(ch => ch.GetPosition(this.SubListIndex)).ToList();
|
||||
for (int i = 0; i < sortedChannels.Count; i++)
|
||||
sortedChannels[i].SetPosition(this.SubListIndex, programNumbers[i]);
|
||||
|
||||
this.DataRoot.NeedsSaving = true;
|
||||
}
|
||||
|
||||
private int ChannelComparerForSortingByName(ChannelInfo channel1, ChannelInfo channel2)
|
||||
{
|
||||
return channel1.Name.CompareTo(channel2.Name);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SetSlotNumber()
|
||||
|
||||
public void SetSlotNumber(IList<ChannelInfo> channels, int slot, bool swap, bool closeGap)
|
||||
{
|
||||
if (channels.Count == 0) return;
|
||||
if (swap)
|
||||
{
|
||||
foreach (var channel in channels)
|
||||
{
|
||||
if (slot != -1)
|
||||
{
|
||||
var others = this.ChannelList.GetChannelByNewProgNr(slot);
|
||||
foreach (var other in others)
|
||||
other.SetPosition(this.SubListIndex, channel.GetPosition(this.SubListIndex));
|
||||
}
|
||||
channel.SetPosition(this.SubListIndex, slot++);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.RemoveChannels(channels, closeGap);
|
||||
this.ChannelList.InsertProgramNumber = slot;
|
||||
this.AddChannels(channels);
|
||||
}
|
||||
this.DataRoot.NeedsSaving = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region RenumberChannels()
|
||||
|
||||
public void RenumberChannels(List<ChannelInfo> channels)
|
||||
{
|
||||
if (channels.Count == 0) return;
|
||||
int progNr = channels.Min(ch => ch.GetPosition(this.SubListIndex));
|
||||
foreach (var channel in channels)
|
||||
{
|
||||
if (channel.GetPosition(this.SubListIndex) == progNr)
|
||||
{
|
||||
++progNr;
|
||||
continue;
|
||||
}
|
||||
|
||||
var list = new List<ChannelInfo>();
|
||||
list.Add(channel);
|
||||
this.RemoveChannels(list, false);
|
||||
this.ChannelList.InsertProgramNumber = progNr++;
|
||||
this.AddChannels(list);
|
||||
this.DataRoot.NeedsSaving = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region ApplyReferenceList()
|
||||
|
||||
public void ApplyReferenceList(DataRoot refDataRoot)
|
||||
{
|
||||
foreach (var channelList in this.DataRoot.ChannelLists)
|
||||
{
|
||||
foreach (var channel in channelList.Channels)
|
||||
channel.SetPosition(this.SubListIndex, -1);
|
||||
}
|
||||
|
||||
StringBuilder log = new StringBuilder();
|
||||
foreach (var refList in refDataRoot.ChannelLists)
|
||||
{
|
||||
var tvList = this.DataRoot.GetChannelList(refList.SignalSource);
|
||||
if (tvList == null)
|
||||
{
|
||||
log.AppendFormat("Skipped reference list {0}\r\n", refList.ShortCaption);
|
||||
continue;
|
||||
}
|
||||
foreach (var refChannel in refList.Channels)
|
||||
{
|
||||
var tvChannels = tvList.GetChannelByUid(refChannel.Uid);
|
||||
ChannelInfo tvChannel = tvChannels.FirstOrDefault(c => c.GetPosition(this.SubListIndex) == -1);
|
||||
if (tvChannel != null)
|
||||
{
|
||||
tvChannel.SetPosition(this.SubListIndex, refChannel.OldProgramNr);
|
||||
tvChannel.Favorites = refChannel.Favorites & DataRoot.SupportedFavorites;
|
||||
tvChannel.Skip = refChannel.Skip;
|
||||
tvChannel.Lock = refChannel.Lock;
|
||||
tvChannel.Hidden = refChannel.Hidden;
|
||||
tvChannel.IsDeleted = refChannel.IsDeleted;
|
||||
if ((tvChannel.SignalSource & SignalSource.Analog) != 0)
|
||||
{
|
||||
tvChannel.Name = refChannel.Name;
|
||||
tvChannel.IsNameModified = true;
|
||||
}
|
||||
if (this.DataRoot.SortedFavorites)
|
||||
{
|
||||
if (refDataRoot.SortedFavorites)
|
||||
{
|
||||
var c = Math.Min(refChannel.FavIndex.Count, tvChannel.FavIndex.Count);
|
||||
for (int i = 0; i < c; i++)
|
||||
tvChannel.FavIndex[i] = refChannel.FavIndex[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ApplyPrNrToFavLists(tvChannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tvChannel = new ChannelInfo(refChannel.SignalSource, refChannel.Uid, refChannel.OldProgramNr,
|
||||
refChannel.Name);
|
||||
tvList.AddChannel(tvChannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region AutoNumberingForUnassignedChannels()
|
||||
|
||||
public void AutoNumberingForUnassignedChannels(UnsortedChannelMode mode)
|
||||
{
|
||||
this.unsortedChannelMode = mode;
|
||||
foreach (var list in DataRoot.ChannelLists)
|
||||
{
|
||||
var sortedChannels = list.Channels.OrderBy(ChanSortCriteria).ToList();
|
||||
int maxProgNr = 0;
|
||||
|
||||
foreach (var appChannel in sortedChannels)
|
||||
{
|
||||
if (appChannel.RecordIndex < 0)
|
||||
continue;
|
||||
|
||||
if (appChannel.NewProgramNr == -1 && mode == UnsortedChannelMode.MarkDeleted)
|
||||
continue;
|
||||
|
||||
int progNr = GetNewPogramNr(appChannel, ref maxProgNr);
|
||||
appChannel.NewProgramNr = progNr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region ChanSortCriteria()
|
||||
|
||||
private string ChanSortCriteria(ChannelInfo channel)
|
||||
{
|
||||
// explicitly sorted
|
||||
if (channel.GetPosition(this.SubListIndex) != -1)
|
||||
return channel.GetPosition(this.SubListIndex).ToString("d4");
|
||||
|
||||
// eventually hide unsorted channels
|
||||
if (this.unsortedChannelMode == UnsortedChannelMode.MarkDeleted)
|
||||
return "Z";
|
||||
|
||||
// eventually append in old order
|
||||
if (this.unsortedChannelMode == UnsortedChannelMode.AppendInOrder)
|
||||
return "B" + channel.OldProgramNr.ToString("d4");
|
||||
|
||||
// sort alphabetically, with "." and "" on the bottom
|
||||
if (channel.Name == ".")
|
||||
return "B";
|
||||
if (channel.Name == "")
|
||||
return "C";
|
||||
return "A" + channel.Name;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetNewPogramNr()
|
||||
|
||||
private int GetNewPogramNr(ChannelInfo appChannel, ref int maxPrNr)
|
||||
{
|
||||
int prNr = appChannel.NewProgramNr;
|
||||
if (prNr > maxPrNr)
|
||||
maxPrNr = prNr;
|
||||
if (prNr == -1)
|
||||
{
|
||||
if (appChannel.OldProgramNr != -1 && this.unsortedChannelMode != UnsortedChannelMode.MarkDeleted)
|
||||
prNr = ++maxPrNr;
|
||||
}
|
||||
return prNr;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
#region SetFavorites()
|
||||
public void SetFavorites(List<ChannelInfo> list, Favorites favorites, bool set)
|
||||
{
|
||||
bool sortedFav = this.DataRoot.SortedFavorites;
|
||||
int favIndex = 0;
|
||||
if (sortedFav)
|
||||
{
|
||||
for (int mask = (int) favorites; (mask & 1) == 0; mask >>= 1)
|
||||
++favIndex;
|
||||
}
|
||||
|
||||
if (set)
|
||||
{
|
||||
int maxPosition = 0;
|
||||
if (sortedFav)
|
||||
{
|
||||
foreach (var channel in this.ChannelList.Channels)
|
||||
maxPosition = Math.Max(maxPosition, channel.FavIndex[favIndex]);
|
||||
}
|
||||
|
||||
foreach (var channel in list)
|
||||
{
|
||||
if (sortedFav && channel.FavIndex[favIndex] == -1)
|
||||
channel.FavIndex[favIndex] = ++maxPosition;
|
||||
channel.Favorites |= favorites;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var channel in list)
|
||||
{
|
||||
if (sortedFav && channel.FavIndex[favIndex] != -1)
|
||||
{
|
||||
channel.FavIndex[favIndex] = -1;
|
||||
// TODO close gap by pulling down higher numbers
|
||||
}
|
||||
channel.Favorites &= ~favorites;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ApplyPrNrToFavLists()
|
||||
public void ApplyPrNrToFavLists()
|
||||
{
|
||||
if (!this.DataRoot.SortedFavorites)
|
||||
return;
|
||||
|
||||
foreach (var list in this.DataRoot.ChannelLists)
|
||||
{
|
||||
foreach(var channel in list.Channels)
|
||||
this.ApplyPrNrToFavLists(channel);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the number inside the favorites list to the same number as Pr#
|
||||
/// </summary>
|
||||
/// <param name="tvChannel"></param>
|
||||
private void ApplyPrNrToFavLists(ChannelInfo tvChannel)
|
||||
{
|
||||
var supMask = (int)this.DataRoot.SupportedFavorites;
|
||||
var refMask = (int)tvChannel.Favorites;
|
||||
for (int i = 0; supMask != 0; i++)
|
||||
{
|
||||
tvChannel.FavIndex[i] = (refMask & 0x01) == 0 ? -1 : tvChannel.OldProgramNr;
|
||||
supMask >>= 1;
|
||||
refMask >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
21
source/ChanSort.Api/Controller/ISerializerPlugin.cs
Normal file
21
source/ChanSort.Api/Controller/ISerializerPlugin.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
namespace ChanSort.Api
|
||||
{
|
||||
public interface ISerializerPlugin
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the plugin, as displayed in the OpenFileDialog file-type selection combo box
|
||||
/// </summary>
|
||||
string PluginName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Semicolon separated list of supported file types (e.g. "xxLM*.TTL;xxLV*.TTL")
|
||||
/// </summary>
|
||||
string FileFilter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create an object that can read/write the file
|
||||
/// </summary>
|
||||
/// <exception cref="System.IO.IOException">file is not of any supported type</exception>
|
||||
SerializerBase CreateSerializer(string inputFile);
|
||||
}
|
||||
}
|
||||
84
source/ChanSort.Api/Controller/SerializerBase.cs
Normal file
84
source/ChanSort.Api/Controller/SerializerBase.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using System.Text;
|
||||
|
||||
namespace ChanSort.Api
|
||||
{
|
||||
public abstract class SerializerBase
|
||||
{
|
||||
public class SupportedFeatures
|
||||
{
|
||||
public bool ChannelNameEdit { get; set; }
|
||||
public bool CleanUpChannelData { get; set; }
|
||||
public bool DeviceSettings { get; set; }
|
||||
public bool CanDeleteChannels { get; set; }
|
||||
public bool CanHaveGaps { get; set; }
|
||||
|
||||
public SupportedFeatures()
|
||||
{
|
||||
this.CanDeleteChannels = true;
|
||||
this.CanHaveGaps = true;
|
||||
}
|
||||
}
|
||||
|
||||
private Encoding defaultEncoding;
|
||||
|
||||
public string FileName { get; set; }
|
||||
public DataRoot DataRoot { get; protected set; }
|
||||
public SupportedFeatures Features { get; private set; }
|
||||
|
||||
protected SerializerBase(string inputFile)
|
||||
{
|
||||
this.Features = new SupportedFeatures();
|
||||
this.FileName = inputFile;
|
||||
this.DataRoot = new DataRoot();
|
||||
this.defaultEncoding = Encoding.GetEncoding("iso-8859-9");
|
||||
}
|
||||
|
||||
public abstract string DisplayName { get; }
|
||||
public abstract void Load();
|
||||
public abstract void Save(string tvOutputFile);
|
||||
|
||||
public virtual Encoding DefaultEncoding
|
||||
{
|
||||
get { return this.defaultEncoding; }
|
||||
set { this.defaultEncoding = value; }
|
||||
}
|
||||
|
||||
public virtual void EraseChannelData() { }
|
||||
|
||||
public virtual string GetFileInformation()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("File name: ").AppendLine(this.FileName);
|
||||
sb.AppendLine();
|
||||
foreach (var list in this.DataRoot.ChannelLists)
|
||||
{
|
||||
sb.Append(list.ShortCaption).AppendLine("-----");
|
||||
sb.Append("number of channels: ").AppendLine(list.Count.ToString());
|
||||
sb.Append("number of predefined channel numbers: ").AppendLine(list.PresetProgramNrCount.ToString());
|
||||
sb.Append("number of duplicate program numbers: ").AppendLine(list.DuplicateProgNrCount.ToString());
|
||||
sb.Append("number of duplicate channel identifiers: ").AppendLine(list.DuplicateUidCount.ToString());
|
||||
int deleted = 0;
|
||||
int hidden = 0;
|
||||
int skipped = 0;
|
||||
foreach (var channel in list.Channels)
|
||||
{
|
||||
if (channel.IsDeleted)
|
||||
++deleted;
|
||||
if (channel.Hidden)
|
||||
++hidden;
|
||||
if (channel.Skip)
|
||||
++skipped;
|
||||
}
|
||||
sb.Append("number of deleted channels: ").AppendLine(deleted.ToString());
|
||||
sb.Append("number of hidden channels: ").AppendLine(hidden.ToString());
|
||||
sb.Append("number of skipped channels: ").AppendLine(skipped.ToString());
|
||||
sb.AppendLine();
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public virtual void ShowDeviceSettingsForm(object parentWindow) { }
|
||||
|
||||
public virtual string CleanUpChannelData() { return ""; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user