From ec4e50d8dfc1f23e2f5e634437e04be80a89be98 Mon Sep 17 00:00:00 2001 From: Horst Beham Date: Fri, 3 Jan 2020 01:26:48 +0100 Subject: [PATCH] - updated readme - m3u: handling of additional #EXT instructions --- readme.md | 30 +++++---- readme_de.md | 30 +++++---- source/ChanSort.Api/Model/ChannelList.cs | 2 +- source/ChanSort.Loader.M3u/Channel.cs | 1 + source/ChanSort.Loader.M3u/Serializer.cs | 86 +++++++++++++++++++----- 5 files changed, 105 insertions(+), 44 deletions(-) diff --git a/readme.md b/readme.md index f9880fb..2069d78 100644 --- a/readme.md +++ b/readme.md @@ -11,8 +11,8 @@ About ChanSort -------------- ChanSort is a Windows application that allows you to reorder your TV's channel list. Most modern TVs can transfer channel lists via USB stick, which you can plug into your PC. -ChanSort supports various file formats from **Philips** (new), **Sony** (new), **ITT, Medion, Nabo, ok., PEAQ, Schaub-Lorenz, Silva-Schneider, Telefunken** (new), -Hisense, Samsung, LG, Panasonic, Toshiba and the Linux VDR project. +ChanSort supports various file formats from Samsung, LG, Panasonic, Sony, Philips, Hisense, Toshiba, +ITT/Medion/Nabo/ok./PEAQ/Schaub-Lorenz/Silva-Schneider/Telefunken, Linux VDR, **SAT>IP .m3u** (new). ![screenshot](http://beham.biz/chansort/ChanSort-en.png) @@ -24,7 +24,7 @@ Features - Side-by-side view of new/sorted list and original/complete list (similar to playlist and library) - Rename or delete channels - Manage favorites, parental lock, channel skipping (when zapping), channel hiding -- User interface in English, German and partially in Turkish and Portuguese +- User interface in English, German, Spanish, and partially in Turkish, Portuguese and Russian - Unicode character support for channel names (Latin, Cyrillic, Greek, ...) Some features may not be available on all TV models and channel types (analog, digital, sat, cable, ...) @@ -39,8 +39,7 @@ Hisense is the only manufacturer who provided technical information and a test d System requirements ------------------- -- [Microsoft .NET Framework 4.0 (Full)](http://www.microsoft.com/en-us/download/details.aspx?id=17851): - included in Win8, required for Win7, Vista and XP SP3 +- [Microsoft .NET Framework 4.6 or later](https://dotnet.microsoft.com/download/dotnet-framework) - [Microsoft Visual C++ 2010 Redistributable Package (x86)](http://www.microsoft.com/en-us/download/details.aspx?id=8328): required to edit SQLite lists (Hisense, Panasonic, Toshiba and Samsung .zip format) - USB stick/SD-card to transfer the channel list between your TV and PC (FAT32 file system recommended) @@ -49,11 +48,6 @@ System requirements Supported TV models ------------------- -**Hisense** -2016 "Smart" models with a channel.db file, i.e. H65M5500 -2017 models with a servicelist.db file -Special thanks to Hisense for supporting ChanSort with technical information and a test device! - **Samsung** .scm files: B (2009)*, B (2013), C, D, E, F, H, J series .zip files: H, J, K, M, N and Q, R series @@ -89,6 +83,15 @@ Viera models with an svl.bin or svl.db channel list (most models since 2011) **Sony** Android-TVs "sdb.xml" files using formats "FormateVer" 1.1.0 and KDL 2012/2014 files using "FormatVer" 1.0.0, 1.1.0 and 1.2.0 +**Philips** +Philips uses countless incompatible file formats for various TV models. +ChanSort currently supports 2 different versions of .xml files, other formats are not supported. + +**Hisense** +2016 "Smart" models with a channel.db file, i.e. H65M5500 +2017 models with a servicelist.db file +Special thanks to Hisense for supporting ChanSort with technical information and a test device! + **Toshiba** Models that export a .zip file containing chmgt.db, dvbSysData.db and dvbMainData.db files. (e.g. RL, SL, TL, UL, VL, WL, XL, YL models of series 8xx/9xx) @@ -96,14 +99,13 @@ Models that export a .zip file containing chmgt.db, dvbSysData.db and dvbMainDat **ITT, Medion, Nabo, ok., PEAQ, Schaub-Lorenz, Silva-Schneider, Telefunken** These brands use .sdx files (currently only satellite lists are supported) -**Philips** -Philips uses countless incompatible file formats for various TV models. -ChanSort currently supports 2 different versions of .xml files, other formats are not supported. - **VDR (Linux Video Disk Recorder)** Supports the channels.conf file format. Implementation for this was provided by TCr82 from the VDR project. +**m3u (SAT>IP)** +Supports SAT>IP .m3u files with extended information holding channel names and program numbers. + License (GPLv3) --------------- GNU General Public Licence, Version 3: http://www.gnu.org/licenses/gpl.html diff --git a/readme_de.md b/readme_de.md index dc7eb5e..bc49f61 100644 --- a/readme_de.md +++ b/readme_de.md @@ -11,8 +11,8 @@ Links -------------- ChanSort ist eine Windows-Anwendung, die das Sortieren von Fernsehsenderlisten erlaubt. Die meisten modernen Fernseher können Senderlisten auf einen USB-Stick übertragen, den man danach am PC anschließt. -ChanSort unterstützt diverse Dateiformate von **Philips** (neu), **Sony** (new), **ITT, Medion, Nabo, ok., PEAQ, Schaub-Lorenz, Silva-Schneider, Telefunken** (new), -Hisense, Samsung, LG, Panasonic, Toshiba und dem Linux VDR Projekt. +ChanSort unterstützt diverse Dateiformate von Samsung, LG, Panasonic, Sony, Philips, Hisense, Toshiba, +Medion/Nabo/ok./PEAQ/Schaub-Lorenz/Silva-Schneider/Telefunken, Linux VDR und SAT>IP .m3u. ![screenshot](http://beham.biz/chansort/ChanSort-de.png) @@ -24,7 +24,7 @@ Funktionen - Nebeneinander-Ansicht von umsortierter und ursprünglicher Liste (ähnlich wie Playlist und Medienbibliothek) - Umbenennen und Löschen von Sendern - Verwalten von Favoriten, Kindersperre, Überspringen und Verstecken von Sendern -- Benutzeroberfläche in Deutsch, Englisch und teilweise in Türkisch und Portugiesisch +- Benutzeroberfläche in Deutsch, Englisch, Spanisch und teilweise in Türkisch, Portugiesisch und Russisch - Unicode-Zeichensatzunterstützung für Sendernamen (latein, kyrillisch, griechisch, ...) Manche Funktionen sind nicht bei allen TV-Modellen und Empfangsarten verfügbar (analog, digital, Sat, Kabel, ...) @@ -39,8 +39,7 @@ Hisense ist der einzige Hersteller, der Informationen und ein Testger Systemvoraussetzungen ------------------- -- [Microsoft .NET Framework 4.0 (Full)](http://www.microsoft.com/en-us/download/details.aspx?id=17851): - In Win8 enthalten, Nachinstallation bei Win7, Vista and XP SP3 erforderlich +- [Microsoft .NET Framework 4.6 (oder neuer)](https://dotnet.microsoft.com/download/dotnet-framework) - [Microsoft Visual C++ 2010 Redistributable Package (x86)](http://www.microsoft.com/en-us/download/details.aspx?id=8328): Wird benötigt um SQLite-Senderlisten zu bearbeiten (Hisense, Panasonic, Toshiba und Samsung J-Serie) - USB Stick/SD-Karte zur Übertragung der Senderliste zwischen TV und PC (FAT32-Formatierung empfohlen) @@ -49,10 +48,6 @@ Systemvoraussetzungen Unterstützte TV-Modelle --------------------- -**Hisense** -Smart-Modelle (2016) mit channel.db Dateiformat, z.B. H65M5500 -Besonderen Dank an Hisense für die Bereitstellung von technischen Informationen und einem Testgerät! - **Samsung** .scm Dateien: Serien B (2009)*, B (2013), C, D, E, F, H, J .zip Dateien: Serien H, J, K, M, N, Q, R @@ -85,21 +80,28 @@ Viera-Modelle mit svl.bin oder svl.db Dateien (die meisten Modelle seit 2011) **Sony** Android-TV "sdb.xml" Dateien mit Versionen "FormateVer" 1.1.0 und KDL 2012/2014 mit "FormatVer" 1.0.0, 1.1.0 and 1.2.0 -**ITT, Medion, Nabo, ok., PEAQ, Schaub-Lorenz, Silva-Schneider, Telefunken** -Die Marken nutzen .sdx Dateien (derzeit wird nur Satellitenempfang unterstützt) +**Philips** +Philips verwendet unzählige unterschiedliche Dateiformate für diverse TV-Modelle. +ChanSort unterstützt derzeit 2 Varianten von .xml-Dateien. Andere Formate werden nicht unterstützt. + +**Hisense** +Smart-Modelle (2016) mit channel.db Dateiformat, z.B. H65M5500 +2017 Modelle mit einem servicelist.db Dateiformat +Besonderen Dank an Hisense für die Bereitstellung von technischen Informationen und einem Testgerät! **Toshiba** Modelle, die eine .zip-Datei mit folgendem Inhalt: chmgt.db, dvbSysData.db und dvbMainData.db. (z.B. RL, SL, TL, UL, VL, WL, XL, YL models of series 8xx/9xx) -**Philips** -Philips verwendet unzählige unterschiedliche Dateiformate für diverse TV-Modelle. -ChanSort unterstützt derzeit 2 Varianten von .xml-Dateien. Andere Formate werden nicht unterstützt. +**ITT, Medion, Nabo, ok., PEAQ, Schaub-Lorenz, Silva-Schneider, Telefunken** +Die Marken nutzen .sdx Dateien (derzeit wird nur Satellitenempfang unterstützt) **VDR (Linux Video Disk Recorder)** Unterstützung des channels.conf Dateiformats. Die Implementation hierfür wurde vom Mitglied "TCr82" des VDR Projekts beigesteuert. +**m3u (SAT>IP)** + Lizenz (GPLv3) --------------- GNU General Public Licence, Version 3: http://www.gnu.org/licenses/gpl.html diff --git a/source/ChanSort.Api/Model/ChannelList.cs b/source/ChanSort.Api/Model/ChannelList.cs index d162ac7..cce962c 100644 --- a/source/ChanSort.Api/Model/ChannelList.cs +++ b/source/ChanSort.Api/Model/ChannelList.cs @@ -30,7 +30,7 @@ namespace ChanSort.Api this.VisibleColumnFieldNames = DefaultVisibleColumns.ToList(); // create copy of default list, so it can be modified } - public string ShortCaption { get; } + public string ShortCaption { get; set; } public SignalSource SignalSource { get; } public IList Channels { get; } = new List(); public int Count => Channels.Count; diff --git a/source/ChanSort.Loader.M3u/Channel.cs b/source/ChanSort.Loader.M3u/Channel.cs index 4eac44e..d53af55 100644 --- a/source/ChanSort.Loader.M3u/Channel.cs +++ b/source/ChanSort.Loader.M3u/Channel.cs @@ -6,6 +6,7 @@ namespace ChanSort.Loader.M3u internal class Channel : ChannelInfo { public List Lines { get; } + public int ExtInfTrackNameIndex { get; set; } public Channel(int index, int progNr, string name, List lines) : base(SignalSource.IP, index, progNr, name) { diff --git a/source/ChanSort.Loader.M3u/Serializer.cs b/source/ChanSort.Loader.M3u/Serializer.cs index bad1f1c..8891fb1 100644 --- a/source/ChanSort.Loader.M3u/Serializer.cs +++ b/source/ChanSort.Loader.M3u/Serializer.cs @@ -15,13 +15,12 @@ namespace ChanSort.Loader.M3u */ class Serializer : SerializerBase { - private static readonly Regex ExtInfRegex = new Regex(@"^#EXTINF:\d+,(?:(\d+)\. )?(.*)$"); - + private static readonly Regex ExtInfTrackName = new Regex(@"^(?:(\d+). )?(.*)$"); private readonly ChannelList allChannels = new ChannelList(SignalSource.IP, "All"); private Encoding overrideEncoding; private string newLine = "\r\n"; - private string headerLine; + private List headerLines = new List(); private List trailingLines = new List(); // comment and blank lines after the last URI line #region ctor() @@ -40,7 +39,7 @@ namespace ChanSort.Loader.M3u base.DefaultEncoding = new UTF8Encoding(false); this.allChannels.VisibleColumnFieldNames = new List() { - "OldPosition", "Position", "Name", "FreqInMhz", "Polarity", "SymbolRate", "VideoPid", "AudioPid", "Satellite" + "OldPosition", "Position", "Name", "FreqInMhz", "Polarity", "SymbolRate", "VideoPid", "AudioPid", "Satellite", "Provider" }; } #endregion @@ -60,17 +59,44 @@ namespace ChanSort.Loader.M3u this.newLine = idx >= 1 && content[idx] - 1 == '\r' ? "\r\n" : "\n"; var rdr = new StreamReader(new MemoryStream(content), overrideEncoding ?? this.DefaultEncoding); - this.headerLine = rdr.ReadLine()?.TrimEnd(); - if (this.headerLine == null || this.headerLine != "#EXTM3U") + string line = rdr.ReadLine()?.TrimEnd(); + if (line == null || line != "#EXTM3U") throw new FileLoadException("Unsupported .m3u file: " + this.FileName); + this.headerLines.Add(line); + // read lines until a non-comment non-empty line is found and then create a channel for the block int lineNr = 1; - string line, extInfLine = null; + string extInfLine = null; + string extGrp = null; var lines = new List(); while ((line = rdr.ReadLine()) != null) { ++lineNr; + + // text encoding (non-standard) + if (line.StartsWith("#EXTENC:")) + { + this.headerLines.Add(line); + continue; + } + + // playlist display title + if (line.StartsWith("#PLAYLIST:")) + { + this.headerLines.Add(line); + this.allChannels.ShortCaption = line.Substring(10); + continue; + } + + // begins a named group + if (line.StartsWith("#EXTGRP:")) + { + extGrp = line.Substring(8); + continue; + } + + // everything else is assumed to belong to the next resource/URI that will follow lines.Add(line); if (line.Trim() == "") @@ -81,7 +107,7 @@ namespace ChanSort.Loader.M3u if (!line.StartsWith("#")) { - ReadChannel(lineNr, line, extInfLine, lines); + ReadChannel(lineNr, line, extInfLine, extGrp, lines); lines = new List(); extInfLine = null; } @@ -92,19 +118,24 @@ namespace ChanSort.Loader.M3u #endregion #region ReadChannel() - private void ReadChannel(int uriLineNr, string uriLine, string extInfLine, List allLines) + private void ReadChannel(int uriLineNr, string uriLine, string extInfLine, string group, List allLines) { int progNr = 0; string name = ""; + int extInfTrackNameIndex = -1; if (extInfLine != null) { - var match = ExtInfRegex.Match(extInfLine); - if (match.Success) + extInfTrackNameIndex = FindExtInfTrackName(extInfLine); + if (extInfTrackNameIndex >= 0) { - if (!string.IsNullOrEmpty(match.Groups[2].Value)) + name = extInfLine.Substring(extInfTrackNameIndex); + var match = ExtInfTrackName.Match(name); + if (!string.IsNullOrEmpty(match.Groups[1].Value)) + { progNr = this.ParseInt(match.Groups[1].Value); - name = match.Groups[2].Value; + name = match.Groups[2].Value; + } } } @@ -112,6 +143,8 @@ namespace ChanSort.Loader.M3u progNr = this.allChannels.Count + 1; var chan = new Channel(uriLineNr, progNr, name, allLines); + chan.ExtInfTrackNameIndex = extInfTrackNameIndex; + chan.Provider = group; try { @@ -158,13 +191,36 @@ namespace ChanSort.Loader.M3u } #endregion + #region FindExtInfTrackName() + /// + /// parse track name from lines that may look like: + /// #EXTINF:<length>[ key="value" ...],<TrackName> + /// + private int FindExtInfTrackName(string extInfLine) + { + bool inQuote = false; + for (int i = 0, c = extInfLine.Length; i < c; i++) + { + var ch = extInfLine[i]; + if (ch == ',' && !inQuote) + return i + 1; + if (ch == '"') + inQuote = !inQuote; + } + + return -1; + } + + #endregion + #region Save() public override void Save(string tvOutputFile) { using var file = new StreamWriter(new FileStream(tvOutputFile, FileMode.Create), this.overrideEncoding ?? this.DefaultEncoding); file.NewLine = this.newLine; - file.WriteLine(this.headerLine); + foreach(var line in this.headerLines) + file.WriteLine(line); foreach (ChannelInfo channel in this.allChannels.GetChannelsByNewOrder()) { @@ -174,7 +230,7 @@ namespace ChanSort.Loader.M3u foreach (var line in chan.Lines) { if (line.StartsWith("#EXTINF:")) - file.WriteLine($"#EXTINF:0,{chan.NewProgramNr}. {chan.Name}"); + file.WriteLine($"{line.Substring(0, chan.ExtInfTrackNameIndex)}{chan.NewProgramNr}. {chan.Name}"); else file.WriteLine(line); }