mirror of
https://github.com/PredatH0r/ChanSort.git
synced 2026-01-20 06:12:03 +01:00
- Philips ChannelMap_45: TV did not remember last selected favorite list when first fav list was created by ChanSort.
- Philips ChannelMap_100 and later: "Channel" XML elements inside the DVB*.xml files are now reordered by program nr. - Philips ChannelMap_105 and 110: fixed saving favorite lists (keeping FavoriteNumber="0" in DVB*.xml and only setting the numbers in Favorites.xml) - m3u: keep original end-of-line characters (CRLF or LF) - m3u: detect whether channel names are prefixed with a program number or not, and save the file in the same way.
This commit is contained in:
@@ -90,6 +90,20 @@ namespace ChanSort.Api
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GetBool()
|
||||
public bool GetBool(string key, bool defaultValue = false)
|
||||
{
|
||||
var val = GetString(key)?.ToLowerInvariant();
|
||||
if (val == null)
|
||||
return defaultValue;
|
||||
if (val == "false" || val == "off" || val == "no" || val == "0")
|
||||
return false;
|
||||
if (val == "true" || val == "on" || val == "yes" || val == "1")
|
||||
return true;
|
||||
return defaultValue;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ParseNumber()
|
||||
private int ParseNumber(string value)
|
||||
{
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace ChanSort.Loader.M3u
|
||||
|
||||
private Encoding overrideEncoding;
|
||||
private string newLine = "\r\n";
|
||||
private bool allChannelsPrefixedWithProgNr = true;
|
||||
private List<string> headerLines = new List<string>();
|
||||
private List<string> trailingLines = new List<string>(); // comment and blank lines after the last URI line
|
||||
|
||||
@@ -55,7 +56,7 @@ namespace ChanSort.Loader.M3u
|
||||
overrideEncoding = new UTF8Encoding(false);
|
||||
|
||||
// detect line separator
|
||||
int idx = Array.IndexOf(content, '\n');
|
||||
int idx = Array.IndexOf(content, (byte)'\n');
|
||||
this.newLine = idx >= 1 && content[idx-1] == '\r' ? "\r\n" : "\n";
|
||||
|
||||
var rdr = new StreamReader(new MemoryStream(content), overrideEncoding ?? this.DefaultEncoding);
|
||||
@@ -126,6 +127,7 @@ namespace ChanSort.Loader.M3u
|
||||
|
||||
if (extInfLine != null)
|
||||
{
|
||||
bool extInfContainsProgNr = false;
|
||||
extInfTrackNameIndex = FindExtInfTrackName(extInfLine);
|
||||
if (extInfTrackNameIndex >= 0)
|
||||
{
|
||||
@@ -135,10 +137,13 @@ namespace ChanSort.Loader.M3u
|
||||
{
|
||||
progNr = this.ParseInt(match.Groups[1].Value);
|
||||
name = match.Groups[2].Value;
|
||||
extInfContainsProgNr = true;
|
||||
}
|
||||
}
|
||||
this.allChannelsPrefixedWithProgNr &= extInfContainsProgNr;
|
||||
}
|
||||
|
||||
|
||||
if (progNr == 0)
|
||||
progNr = this.allChannels.Count + 1;
|
||||
|
||||
@@ -231,7 +236,10 @@ namespace ChanSort.Loader.M3u
|
||||
foreach (var line in chan.Lines)
|
||||
{
|
||||
if (line.StartsWith("#EXTINF:"))
|
||||
file.WriteLine($"{line.Substring(0, chan.ExtInfTrackNameIndex)}{chan.NewProgramNr}. {chan.Name}");
|
||||
{
|
||||
var progNrPrefix = this.allChannelsPrefixedWithProgNr ? chan.NewProgramNr + ". " : "";
|
||||
file.WriteLine($"{line.Substring(0, chan.ExtInfTrackNameIndex)}{progNrPrefix}{chan.Name}");
|
||||
}
|
||||
else
|
||||
file.WriteLine(line);
|
||||
}
|
||||
|
||||
@@ -56,9 +56,9 @@ namespace ChanSort.Loader.Philips
|
||||
|
||||
private ChanLstBin chanLstBin;
|
||||
private readonly StringBuilder logMessages = new StringBuilder();
|
||||
private readonly List<int> favListIndexToId = new();
|
||||
private readonly Dictionary<int, int> favListIdToIndex = new();
|
||||
private readonly ChannelList favChannels = new ChannelList(SignalSource.All, "Favorites");
|
||||
private const int FavListCount = 8;
|
||||
private bool mustFixFavListIds;
|
||||
|
||||
#region ctor()
|
||||
public BinarySerializer(string inputFile) : base(inputFile)
|
||||
@@ -647,40 +647,45 @@ namespace ChanSort.Loader.Philips
|
||||
this.favChannels.AddChannel(chan);
|
||||
}
|
||||
}
|
||||
this.Features.SupportedFavorites = (Favorites)0xFF;
|
||||
this.Features.SortedFavorites = true;
|
||||
this.Features.MixedSourceFavorites = true;
|
||||
this.Features.AllowGapsInFavNumbers = false;
|
||||
|
||||
|
||||
using var conn = new SQLiteConnection($"Data Source={listDb}");
|
||||
conn.Open();
|
||||
|
||||
// older versions of ChanSort wrote invalid "list_id" values starting at 0 instead of 1 and going past 8.
|
||||
// if everything is in the range of 1-8, this code keeps the current ids. otherwise it remaps them to 1-8.
|
||||
using var cmd = conn.CreateCommand();
|
||||
cmd.CommandText = "select list_id, list_name from List";
|
||||
this.Features.SupportedFavorites = 0;
|
||||
this.Features.SortedFavorites = true;
|
||||
cmd.CommandText = "select min(list_id), max(list_id) from List";
|
||||
using (var r = cmd.ExecuteReader())
|
||||
{
|
||||
int i = 0;
|
||||
while (r.Read() && i < ChannelInfo.MAX_FAV_LISTS)
|
||||
{
|
||||
this.favListIndexToId.Add(r.GetInt32(0));
|
||||
this.favListIdToIndex.Add(r.GetInt32(0), i);
|
||||
this.DataRoot.SetFavListCaption(i, r.GetString(1));
|
||||
this.Features.SupportedFavorites |= (Favorites) (1 << i);
|
||||
i++;
|
||||
}
|
||||
r.Read();
|
||||
mustFixFavListIds = !r.IsDBNull(0) && (r.GetInt16(0) < 1 || r.GetInt16(1) > 8);
|
||||
if (mustFixFavListIds)
|
||||
logMessages.AppendLine("invalid list_id values in list.db will be corrected");
|
||||
}
|
||||
|
||||
for (; i < 8; i++)
|
||||
cmd.CommandText = "select list_id, list_name from List order by list_id";
|
||||
var listIds = new List<int>();
|
||||
using (var r = cmd.ExecuteReader())
|
||||
{
|
||||
var listIndex = 0;
|
||||
while (r.Read())
|
||||
{
|
||||
this.favListIndexToId.Add(-i-1);
|
||||
this.favListIdToIndex.Add(-i-1, i);
|
||||
this.DataRoot.SetFavListCaption(i, "Fav " + (i+1));
|
||||
this.Features.SupportedFavorites |= (Favorites)(1 << i);
|
||||
var listId = r.GetInt16(0);
|
||||
listIds.Add(listId);
|
||||
if (!this.mustFixFavListIds)
|
||||
listIndex = listId - 1;
|
||||
this.DataRoot.SetFavListCaption(listIndex, r.GetString(1));
|
||||
++listIndex;
|
||||
}
|
||||
}
|
||||
|
||||
for (int listIndex = 0; listIndex < this.favListIndexToId.Count; listIndex++)
|
||||
for (int listIndex = 0; listIndex < listIds.Count; listIndex++)
|
||||
{
|
||||
cmd.CommandText = $"select channel_id from FavoriteChannels where fav_list_id={favListIndexToId[listIndex]} order by rank";
|
||||
cmd.CommandText = $"select channel_id from FavoriteChannels where fav_list_id={listIds[listIndex]} order by rank";
|
||||
using var r = cmd.ExecuteReader();
|
||||
int seq = 0;
|
||||
while (r.Read())
|
||||
@@ -997,29 +1002,30 @@ namespace ChanSort.Loader.Philips
|
||||
conn.Open();
|
||||
using var trans = conn.BeginTransaction();
|
||||
using var cmd = conn.CreateCommand();
|
||||
for (int favListIndex = 0; favListIndex < this.favListIndexToId.Count; favListIndex++)
|
||||
cmd.CommandText = "delete from FavoriteChannels";
|
||||
cmd.ExecuteNonQuery();
|
||||
if (this.mustFixFavListIds)
|
||||
{
|
||||
var favListId = favListIndexToId[favListIndex];
|
||||
string sqlInsertOrUpdateList;
|
||||
if (favListId >= 0)
|
||||
{
|
||||
cmd.CommandText = $"delete from FavoriteChannels where fav_list_id={favListId}";
|
||||
cmd.ExecuteNonQuery();
|
||||
sqlInsertOrUpdateList = "update List set list_name=@name, list_version=list_version+1 where list_id=@id";
|
||||
}
|
||||
else
|
||||
{
|
||||
favListId = favListIndexToId.Count == 0 ? 1 : favListIndexToId.Max() + 1;
|
||||
favListIndexToId[favListIndex] = favListId;
|
||||
favListIdToIndex[favListId] = favListIndex;
|
||||
sqlInsertOrUpdateList = "insert into List (list_id, list_name, list_version) values (@id,@name,1)";
|
||||
}
|
||||
cmd.CommandText = "delete from List";
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
var incFavList = (ini.GetSection("Map" + chanLstBin.VersionMajor)?.GetBool("incrementFavListVersion", true) ?? true)
|
||||
? ", list_version=list_version+1"
|
||||
: "";
|
||||
|
||||
for (int favListIndex = 0; favListIndex < FavListCount; favListIndex++)
|
||||
{
|
||||
var favListId = favListIndex + 1;
|
||||
cmd.CommandText = $"select count(1) from List where list_id={favListId}";
|
||||
cmd.CommandText = (long) cmd.ExecuteScalar() == 0 ?
|
||||
"insert into List (list_id, list_name, list_version) values (@id,@name,1)" :
|
||||
"update List set list_name=@name" + incFavList + " where list_id=@id";
|
||||
|
||||
cmd.CommandText = sqlInsertOrUpdateList;
|
||||
cmd.Parameters.Add(new SQLiteParameter("@id", DbType.Int16));
|
||||
cmd.Parameters.Add(new SQLiteParameter("@name", DbType.String));
|
||||
cmd.Parameters["@id"].Value = favListId;
|
||||
cmd.Parameters["@name"].Value = DataRoot.GetFavListCaption(favListIndex);
|
||||
cmd.Parameters["@name"].Value = DataRoot.GetFavListCaption(favListIndex) ?? "Fav " + (favListIndex + 1);
|
||||
cmd.ExecuteNonQuery();
|
||||
|
||||
cmd.CommandText = "insert into FavoriteChannels(fav_list_id, channel_id, rank) values (@listId,@channelId,@rank)";
|
||||
@@ -1049,7 +1055,7 @@ namespace ChanSort.Loader.Philips
|
||||
cmd.ExecuteNonQuery();
|
||||
|
||||
// make sure the last_watched_channel_id is valid in the list
|
||||
cmd.CommandText = "update List set last_watched_channel_id=(select min(channel_id) from FavoriteChannels f where f.fav_list_id=List.list_id)";
|
||||
cmd.CommandText = @"update List set last_watched_channel_id=(select channel_id from FavoriteChannels f where f.fav_list_id=List.list_id order by rank limit 1) where last_watched_channel_id not in (select channel_id from FavoriteChannels f where f.fav_list_id=List.list_id)";
|
||||
cmd.ExecuteNonQuery();
|
||||
|
||||
trans.Commit();
|
||||
|
||||
@@ -88,3 +88,17 @@ lenSatName=64
|
||||
offUnk1=48
|
||||
offUnk2=68
|
||||
offPolarity=72
|
||||
|
||||
[Map45]
|
||||
incrementFavListVersion=true
|
||||
|
||||
[Map100]
|
||||
setFavoriteNumber=true
|
||||
|
||||
[Map105]
|
||||
incrementFavListVersion=true
|
||||
setFavoriteNumber=false
|
||||
|
||||
[Map110]
|
||||
incrementFavListVersion=true
|
||||
setFavoriteNumber=false
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
@@ -59,6 +60,7 @@ namespace ChanSort.Loader.Philips
|
||||
private readonly List<FileData> fileDataList = new List<FileData>();
|
||||
private ChanLstBin chanLstBin;
|
||||
private readonly StringBuilder logMessages = new StringBuilder();
|
||||
private readonly IniFile ini;
|
||||
|
||||
|
||||
#region ctor()
|
||||
@@ -103,6 +105,9 @@ namespace ChanSort.Loader.Philips
|
||||
|
||||
|
||||
this.favChannels.IsMixedSourceFavoritesList = true;
|
||||
|
||||
string iniFile = Assembly.GetExecutingAssembly().Location.Replace(".dll", ".ini");
|
||||
this.ini = new IniFile(iniFile);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -490,42 +495,23 @@ namespace ChanSort.Loader.Philips
|
||||
}
|
||||
|
||||
foreach (var file in this.fileDataList)
|
||||
{
|
||||
if (Path.GetFileName(file.path).ToLowerInvariant().StartsWith("dvb"))
|
||||
this.ReorderNodes(file);
|
||||
this.SaveFile(file);
|
||||
}
|
||||
|
||||
this.chanLstBin?.Save(this.FileName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SaveFile()
|
||||
private void SaveFile(FileData file)
|
||||
{
|
||||
// by default .NET reformats the whole XML. These settings produce almost same format as the TV xml files use
|
||||
var xmlSettings = new XmlWriterSettings();
|
||||
xmlSettings.Encoding = new UTF8Encoding(false);
|
||||
xmlSettings.CheckCharacters = false;
|
||||
xmlSettings.Indent = true;
|
||||
xmlSettings.IndentChars = file.indent;
|
||||
xmlSettings.NewLineHandling = NewLineHandling.None;
|
||||
xmlSettings.NewLineChars = file.newline;
|
||||
xmlSettings.OmitXmlDeclaration = false;
|
||||
|
||||
string xml;
|
||||
using (var sw = new StringWriter())
|
||||
using (var w = new CustomXmlWriter(sw, xmlSettings, false))
|
||||
{
|
||||
file.doc.WriteTo(w);
|
||||
w.Flush();
|
||||
xml = sw.ToString();
|
||||
}
|
||||
|
||||
var enc = new UTF8Encoding(false, false);
|
||||
File.WriteAllText(file.path, xml, enc);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region UpdateChannelList()
|
||||
private void UpdateChannelList(ChannelList list)
|
||||
{
|
||||
var sec = ini.GetSection("Map" + (this.chanLstBin?.VersionMajor ?? 0));
|
||||
var setFavoriteNumber = sec?.GetBool("setFavoriteNumber", false) ?? false;
|
||||
|
||||
foreach (var channel in list.Channels)
|
||||
{
|
||||
var ch = channel as Channel;
|
||||
@@ -539,7 +525,7 @@ namespace ChanSort.Loader.Philips
|
||||
}
|
||||
|
||||
if (ch.Format == 1)
|
||||
this.UpdateChannelFormat1(ch);
|
||||
this.UpdateChannelFormat1(ch, setFavoriteNumber);
|
||||
else if (ch.Format == 2)
|
||||
this.UpdateChannelFormat2(ch);
|
||||
}
|
||||
@@ -547,22 +533,28 @@ namespace ChanSort.Loader.Philips
|
||||
#endregion
|
||||
|
||||
#region UpdateChannelFormat1 and 2
|
||||
private void UpdateChannelFormat1(Channel ch)
|
||||
private void UpdateChannelFormat1(Channel ch, bool setFavoriteNumber)
|
||||
{
|
||||
ch.SetupNode.Attributes["ChannelNumber"].Value = ch.NewProgramNr.ToString();
|
||||
var attr = ch.SetupNode.Attributes["UserReorderChannel"]; // introduced with format 110
|
||||
if (attr != null)
|
||||
attr.InnerText = "1";
|
||||
|
||||
if (ch.IsNameModified)
|
||||
{
|
||||
ch.SetupNode.Attributes["ChannelName"].InnerText = EncodeName(ch.Name, (ch.SetupNode.Attributes["ChannelName"].InnerText.Length + 1) / 5, true);
|
||||
attr = ch.SetupNode.Attributes["UserModifiedName"];
|
||||
var attr = ch.SetupNode.Attributes["UserModifiedName"];
|
||||
if (attr != null)
|
||||
attr.InnerText = "1";
|
||||
}
|
||||
|
||||
ch.SetupNode.Attributes["FavoriteNumber"].Value = Math.Max(ch.FavIndex[0], 0).ToString();
|
||||
// ChannelMap_100 supports a single fav list and stores the favorite number directly here in the channel.
|
||||
// ChannelMap_105 and later always store the value 0 in the channel and instead use a separate Favorites.xml file.
|
||||
ch.SetupNode.Attributes["FavoriteNumber"].Value = setFavoriteNumber ? Math.Max(ch.FavIndex[0], 0).ToString() : "0";
|
||||
|
||||
if (ch.OldProgramNr != ch.NewProgramNr)
|
||||
{
|
||||
var attr = ch.SetupNode.Attributes["UserReorderChannel"]; // introduced with format 110, but not always present
|
||||
if (attr != null)
|
||||
attr.InnerText = "1";
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateChannelFormat2(Channel ch)
|
||||
@@ -588,10 +580,14 @@ namespace ChanSort.Loader.Philips
|
||||
var attr = favListNode.Attributes?["Name"];
|
||||
if (attr != null)
|
||||
attr.InnerText = EncodeName(this.DataRoot.GetFavListCaption(index - 1), (attr.InnerText.Length + 1)/5, false);
|
||||
|
||||
attr = favListNode.Attributes?["Version"];
|
||||
if (attr != null && int.TryParse(attr.Value, out var version))
|
||||
attr.InnerText = (version + 1).ToString();
|
||||
|
||||
// increment fav list version, unless disabled in .ini file
|
||||
if (chanLstBin != null && (ini.GetSection("Map" + chanLstBin.VersionMajor)?.GetBool("incrementFavListVersion", true) ?? true))
|
||||
{
|
||||
attr = favListNode.Attributes?["Version"];
|
||||
if (attr != null && int.TryParse(attr.Value, out var version))
|
||||
attr.InnerText = (version + 1).ToString();
|
||||
}
|
||||
|
||||
foreach (var ch in favChannels.Channels.OrderBy(ch => ch.GetPosition(index)))
|
||||
{
|
||||
@@ -628,6 +624,61 @@ namespace ChanSort.Loader.Philips
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ReorderNodes
|
||||
private void ReorderNodes(FileData file)
|
||||
{
|
||||
if (file.formatVersion != 1)
|
||||
return;
|
||||
|
||||
var nodes = file.doc.DocumentElement.GetElementsByTagName("Channel");
|
||||
var list = new List<XmlElement>();
|
||||
foreach(var node in nodes)
|
||||
list.Add((XmlElement)node);
|
||||
foreach (var node in list)
|
||||
file.doc.DocumentElement.RemoveChild(node);
|
||||
foreach(var node in list.OrderBy(elem => int.Parse(elem["Setup"].Attributes["ChannelNumber"].InnerText)))
|
||||
file.doc.DocumentElement.AppendChild(node);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SaveFile()
|
||||
private void SaveFile(FileData file)
|
||||
{
|
||||
// by default .NET reformats the whole XML. These settings produce almost same format as the TV xml files use
|
||||
var xmlSettings = new XmlWriterSettings();
|
||||
xmlSettings.Encoding = new UTF8Encoding(false);
|
||||
xmlSettings.CheckCharacters = false;
|
||||
xmlSettings.Indent = true;
|
||||
xmlSettings.IndentChars = file.indent;
|
||||
xmlSettings.NewLineHandling = NewLineHandling.None;
|
||||
xmlSettings.NewLineChars = file.newline;
|
||||
xmlSettings.OmitXmlDeclaration = true;
|
||||
|
||||
string xml;
|
||||
using (var sw = new StringWriter())
|
||||
{
|
||||
// write unmodified XML declaration (the DVB*.xml files use a different one than the Favorite.xml file)
|
||||
var i = file.textContent.IndexOf("?>");
|
||||
if (i >= 0)
|
||||
sw.Write(file.textContent.Substring(0, i + 2 + file.newline.Length));
|
||||
|
||||
using (var w = new CustomXmlWriter(sw, xmlSettings, false))
|
||||
{
|
||||
file.doc.WriteTo(w);
|
||||
w.Flush();
|
||||
xml = sw.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
// append trailing newline, if the original file had one
|
||||
if (file.textContent.EndsWith(file.newline) && !xml.EndsWith(file.newline))
|
||||
xml += file.newline;
|
||||
|
||||
var enc = new UTF8Encoding(false, false);
|
||||
File.WriteAllText(file.path, xml, enc);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public override string GetFileInformation()
|
||||
{
|
||||
return base.GetFileInformation() + this.logMessages.Replace("\n", "\r\n");
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
ChanSort Change Log
|
||||
===================
|
||||
|
||||
2021-02-24
|
||||
- Philips ChannelMap\_45: TV did not remember last selected favorite list when first fav list was created by ChanSort.
|
||||
- Philips ChannelMap\_100 and later: "Channel" XML elements inside the DVB\*.xml files are now reordered by program nr.
|
||||
- Philips ChannelMap\_105 and 110: fixed saving favorite lists (keeping FavoriteNumber="0" in DVB\*.xml and only
|
||||
setting the numbers in Favorites.xml)
|
||||
- m3u: keep original end-of-line characters (CRLF or LF)
|
||||
- m3u: detect whether channel names are prefixed with a program number or not, and save the file in the same way.
|
||||
|
||||
2021-02-17_2
|
||||
- Philips ChannelMap\_105 and 110: fixed broken favorites.xml file and DVB\*.xml when channels were renamed
|
||||
|
||||
|
||||
Reference in New Issue
Block a user