SatIndex grabber now working. default tip
authorStephaneLenclud
Sat, 06 Oct 2018 14:07:31 +0200
changeset 9b77b09f680e7
parent 8 adff2dec03a0
SatIndex grabber now working.
KingOfSat.cs
MainForm.Designer.cs
MainForm.cs
MainForm.resx
SatIndex.cs
     1.1 --- a/KingOfSat.cs	Thu Oct 04 19:25:35 2018 +0200
     1.2 +++ b/KingOfSat.cs	Sat Oct 06 14:07:31 2018 +0200
     1.3 @@ -282,6 +282,12 @@
     1.4                          channel.Category = "Documentaries";
     1.5                      }
     1.6  
     1.7 +                    if (channel.Category == "Travel")
     1.8 +                    {
     1.9 +                        channel.Category = "Documentaries";
    1.10 +                    }
    1.11 +
    1.12 +
    1.13                      if (channel.Category == "Lifestyle")
    1.14                      {
    1.15                          channel.Category = "General";
     2.1 --- a/MainForm.Designer.cs	Thu Oct 04 19:25:35 2018 +0200
     2.2 +++ b/MainForm.Designer.cs	Sat Oct 06 14:07:31 2018 +0200
     2.3 @@ -28,34 +28,89 @@
     2.4          /// </summary>
     2.5          private void InitializeComponent()
     2.6          {
     2.7 -            this.buttonGenerate = new System.Windows.Forms.Button();
     2.8 +            this.iButtoKingOfSat = new System.Windows.Forms.Button();
     2.9 +            this.iButtonSatIndex = new System.Windows.Forms.Button();
    2.10 +            this.statusStrip1 = new System.Windows.Forms.StatusStrip();
    2.11 +            this.toolStripStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
    2.12 +            this.toolStripProgressBar = new System.Windows.Forms.ToolStripProgressBar();
    2.13 +            this.toolStripStatusLabelSpring = new System.Windows.Forms.ToolStripStatusLabel();
    2.14 +            this.statusStrip1.SuspendLayout();
    2.15              this.SuspendLayout();
    2.16              // 
    2.17 -            // buttonGenerate
    2.18 +            // iButtoKingOfSat
    2.19              // 
    2.20 -            this.buttonGenerate.Location = new System.Drawing.Point(192, 138);
    2.21 -            this.buttonGenerate.Name = "buttonGenerate";
    2.22 -            this.buttonGenerate.Size = new System.Drawing.Size(75, 23);
    2.23 -            this.buttonGenerate.TabIndex = 0;
    2.24 -            this.buttonGenerate.Text = "Generate";
    2.25 -            this.buttonGenerate.UseVisualStyleBackColor = true;
    2.26 -            this.buttonGenerate.Click += new System.EventHandler(this.buttonGenerate_Click);
    2.27 +            this.iButtoKingOfSat.Location = new System.Drawing.Point(192, 138);
    2.28 +            this.iButtoKingOfSat.Name = "iButtoKingOfSat";
    2.29 +            this.iButtoKingOfSat.Size = new System.Drawing.Size(75, 23);
    2.30 +            this.iButtoKingOfSat.TabIndex = 0;
    2.31 +            this.iButtoKingOfSat.Text = "KingOfSat";
    2.32 +            this.iButtoKingOfSat.UseVisualStyleBackColor = true;
    2.33 +            this.iButtoKingOfSat.Click += new System.EventHandler(this.buttonGenerate_Click);
    2.34 +            // 
    2.35 +            // iButtonSatIndex
    2.36 +            // 
    2.37 +            this.iButtonSatIndex.Location = new System.Drawing.Point(192, 177);
    2.38 +            this.iButtonSatIndex.Name = "iButtonSatIndex";
    2.39 +            this.iButtonSatIndex.Size = new System.Drawing.Size(75, 23);
    2.40 +            this.iButtonSatIndex.TabIndex = 1;
    2.41 +            this.iButtonSatIndex.Text = "SatIndex";
    2.42 +            this.iButtonSatIndex.UseVisualStyleBackColor = true;
    2.43 +            this.iButtonSatIndex.Click += new System.EventHandler(this.iButtonSatIndex_Click);
    2.44 +            // 
    2.45 +            // statusStrip1
    2.46 +            // 
    2.47 +            this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
    2.48 +            this.toolStripStatusLabel,
    2.49 +            this.toolStripStatusLabelSpring,
    2.50 +            this.toolStripProgressBar});
    2.51 +            this.statusStrip1.Location = new System.Drawing.Point(0, 499);
    2.52 +            this.statusStrip1.Name = "statusStrip1";
    2.53 +            this.statusStrip1.Size = new System.Drawing.Size(727, 22);
    2.54 +            this.statusStrip1.TabIndex = 2;
    2.55 +            this.statusStrip1.Text = "statusStrip1";
    2.56 +            // 
    2.57 +            // toolStripStatusLabel
    2.58 +            // 
    2.59 +            this.toolStripStatusLabel.Name = "toolStripStatusLabel";
    2.60 +            this.toolStripStatusLabel.Size = new System.Drawing.Size(39, 17);
    2.61 +            this.toolStripStatusLabel.Text = "Ready";
    2.62 +            // 
    2.63 +            // toolStripProgressBar
    2.64 +            // 
    2.65 +            this.toolStripProgressBar.Name = "toolStripProgressBar";
    2.66 +            this.toolStripProgressBar.Size = new System.Drawing.Size(100, 16);
    2.67 +            // 
    2.68 +            // toolStripStatusLabelSpring
    2.69 +            // 
    2.70 +            this.toolStripStatusLabelSpring.Name = "toolStripStatusLabelSpring";
    2.71 +            this.toolStripStatusLabelSpring.Size = new System.Drawing.Size(571, 17);
    2.72 +            this.toolStripStatusLabelSpring.Spring = true;
    2.73              // 
    2.74              // MainForm
    2.75              // 
    2.76              this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
    2.77              this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    2.78              this.ClientSize = new System.Drawing.Size(727, 521);
    2.79 -            this.Controls.Add(this.buttonGenerate);
    2.80 +            this.Controls.Add(this.statusStrip1);
    2.81 +            this.Controls.Add(this.iButtonSatIndex);
    2.82 +            this.Controls.Add(this.iButtoKingOfSat);
    2.83              this.Name = "MainForm";
    2.84              this.Text = "Sattelite Channel Generator";
    2.85 +            this.statusStrip1.ResumeLayout(false);
    2.86 +            this.statusStrip1.PerformLayout();
    2.87              this.ResumeLayout(false);
    2.88 +            this.PerformLayout();
    2.89  
    2.90          }
    2.91  
    2.92          #endregion
    2.93  
    2.94 -        private System.Windows.Forms.Button buttonGenerate;
    2.95 +        private System.Windows.Forms.Button iButtoKingOfSat;
    2.96 +        private System.Windows.Forms.Button iButtonSatIndex;
    2.97 +        private System.Windows.Forms.StatusStrip statusStrip1;
    2.98 +        private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel;
    2.99 +        private System.Windows.Forms.ToolStripProgressBar toolStripProgressBar;
   2.100 +        private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelSpring;
   2.101      }
   2.102  }
   2.103  
     3.1 --- a/MainForm.cs	Thu Oct 04 19:25:35 2018 +0200
     3.2 +++ b/MainForm.cs	Sat Oct 06 14:07:31 2018 +0200
     3.3 @@ -15,7 +15,13 @@
     3.4  
     3.5  namespace SatChanGen
     3.6  {
     3.7 -    public partial class MainForm : Form
     3.8 +    public struct ProgressReport
     3.9 +    {
    3.10 +        public int Max { get; set; }
    3.11 +        public int Value { get; set; }
    3.12 +    }
    3.13 +
    3.14 +    public partial class MainForm : Form, IProgress<ProgressReport>
    3.15      {
    3.16          public MainForm()
    3.17          {
    3.18 @@ -40,5 +46,67 @@
    3.19              //Export to XML for MediaPortal to import
    3.20              MediaPortal.Export(channels, tuners, "channels.xml", false);
    3.21          }
    3.22 +
    3.23 +        /// <summary>
    3.24 +        /// 
    3.25 +        /// </summary>
    3.26 +        /// <param name="sender"></param>
    3.27 +        /// <param name="e"></param>
    3.28 +        private async void iButtonSatIndex_Click(object sender, EventArgs e)
    3.29 +        {
    3.30 +            await Task.Run(() => FetchSatIndexChannels());
    3.31 +        }
    3.32 +
    3.33 +        /// <summary>
    3.34 +        /// 
    3.35 +        /// </summary>
    3.36 +        private void FetchSatIndexChannels()
    3.37 +        {
    3.38 +            List<Channel> channels = new List<Channel>();
    3.39 +
    3.40 +            channels.AddRange(SatIndex.Parse(this, channels, "http://www.satindex.de/tv/1/1/", "19.2°E", true));
    3.41 +            //channels.AddRange(KingOfSat.Parse(channels, "http://en.kingofsat.net/pack-hdplus.php", "19.2°E", true));
    3.42 +            //channels.AddRange(KingOfSat.Parse(channels, "http://en.kingofsat.net/pack-arddigital.php", "19.2°E", true));
    3.43 +            //channels.AddRange(KingOfSat.Parse(channels, "http://en.kingofsat.net/pack-zdfvision.php", "19.2°E", true));
    3.44 +            //channels.AddRange(KingOfSat.Parse(channels, "http://en.kingofsat.net/pack-tntsat.php", "19.2°E", true, "TNTSAT"));
    3.45 +
    3.46 +            //Discard non HD channels we don't need
    3.47 +            channels = SatIndex.CleanChannelList(channels);
    3.48 +
    3.49 +            //Declare tuner cards so that we don't need to create mapping manually after import
    3.50 +            List<string> tuners = new List<string>() { "3", "4" };
    3.51 +
    3.52 +            //Export to XML for MediaPortal to import
    3.53 +            MediaPortal.Export(channels, tuners, "channels.xml", false);
    3.54 +
    3.55 +        }
    3.56 +
    3.57 +        /// <summary>
    3.58 +        /// 
    3.59 +        /// </summary>
    3.60 +        /// <param name="aProgress"></param>
    3.61 +        public void Report(ProgressReport aProgress)
    3.62 +        {
    3.63 +            MethodInvoker methodInvokerDelegate = delegate ()
    3.64 +                {
    3.65 +                    toolStripProgressBar.Maximum = aProgress.Max;
    3.66 +                    toolStripProgressBar.Value = aProgress.Value;
    3.67 +                    toolStripStatusLabel.Text = aProgress.Value + " / " + aProgress.Max;
    3.68 +                };
    3.69 +
    3.70 +            //This will be true if Current thread is not UI thread.
    3.71 +            if (InvokeRequired)
    3.72 +            {
    3.73 +                Invoke(methodInvokerDelegate);
    3.74 +            }
    3.75 +            else
    3.76 +            {
    3.77 +                methodInvokerDelegate();
    3.78 +            } 
    3.79 +                    
    3.80 +        }
    3.81 +
    3.82 +
    3.83 +
    3.84      }
    3.85  }
     4.1 --- a/MainForm.resx	Thu Oct 04 19:25:35 2018 +0200
     4.2 +++ b/MainForm.resx	Sat Oct 06 14:07:31 2018 +0200
     4.3 @@ -117,4 +117,7 @@
     4.4    <resheader name="writer">
     4.5      <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
     4.6    </resheader>
     4.7 +  <metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
     4.8 +    <value>17, 17</value>
     4.9 +  </metadata>
    4.10  </root>
    4.11 \ No newline at end of file
     5.1 --- a/SatIndex.cs	Thu Oct 04 19:25:35 2018 +0200
     5.2 +++ b/SatIndex.cs	Sat Oct 06 14:07:31 2018 +0200
     5.3 @@ -1,12 +1,470 @@
     5.4 -using System;
     5.5 +using CsQuery;
     5.6 +using System;
     5.7  using System.Collections.Generic;
     5.8 +using System.Diagnostics;
     5.9  using System.Linq;
    5.10 +using System.Net;
    5.11  using System.Text;
    5.12 +using System.Text.RegularExpressions;
    5.13  using System.Threading.Tasks;
    5.14  
    5.15  namespace SatChanGen
    5.16  {
    5.17      class SatIndex
    5.18      {
    5.19 +        public static Channel ParseChannel(string aUrl)
    5.20 +        {
    5.21 +            Channel channel = new Channel();
    5.22 +
    5.23 +            string satIndex = new WebClient().DownloadString(aUrl);
    5.24 +            //Debug.Write(satIndex);
    5.25 +            CQ dom = satIndex;
    5.26 +
    5.27 +            channel.Name = WebUtility.HtmlDecode(dom.Find("td.chdet1:contains('Name')").Next().Text());
    5.28 +            //Convert from default encoding to UTF8
    5.29 +            //We spend a lot of time trying to get this right until we found our answer in the following thread.
    5.30 +            //http://stackoverflow.com/questions/14057434/how-can-i-transform-string-to-utf-8-in-c
    5.31 +            //byte[] bytes = Encoding.Default.GetBytes(channel.Name);
    5.32 +            //channel.Name = Encoding.UTF8.GetString(bytes);
    5.33 +            //
    5.34 +            channel.Satellite = WebUtility.HtmlDecode(dom.Find("td.chdet1:contains('Satellit')").Next().Text());
    5.35 +            channel.OrbitalPosition = WebUtility.HtmlDecode(dom.Find("td.chdet1:contains('Position')").Next().Text());
    5.36 +            // Frequency, remove dots and unit
    5.37 +            channel.Frequency = WebUtility.HtmlDecode(dom.Find("td.chdet1:contains('Frequenz')").Next().Text());
    5.38 +            channel.Frequency = channel.Frequency.Replace(" MHz", "").Replace(".", "");
    5.39 +            // Just get 'H' or 'V' I guess
    5.40 +            channel.Polarisation = WebUtility.HtmlDecode(dom.Find("td.chdet1:contains('Polarisation')").Next().Text()).Substring(0,1);
    5.41 +            channel.Transponder = WebUtility.HtmlDecode(dom.Find("td.chdet1:contains('Transponder:')").Next().Text());
    5.42 +            channel.TransponderID = WebUtility.HtmlDecode(dom.Find("td.chdet1:contains('Transponder ID')").Next().Text()).Replace(".", "");
    5.43 +            channel.Beam = "Astra";
    5.44 +            channel.Standard = WebUtility.HtmlDecode(dom.Find("td.chdet1:contains('Art')").Next().Text());
    5.45 +            channel.Modulation = WebUtility.HtmlDecode(dom.Find("td.chdet1:contains('Modulation')").Next().Text());
    5.46 +            channel.SymbolRate = WebUtility.HtmlDecode(dom.Find("td.chdet1:contains('Symbolrate')").Next().Text());
    5.47 +            channel.SymbolRate = channel.SymbolRate.Replace(" kSym/s", "").Replace(".", "");
    5.48 +            channel.FEC = WebUtility.HtmlDecode(dom.Find("td.chdet1:contains('FEC')").Next().Text());
    5.49 +            channel.Provider = WebUtility.HtmlDecode(dom.Find("td.chdet1:contains('Provider')").Next().Text());
    5.50 +
    5.51 +            channel.Bitrate = WebUtility.HtmlDecode(dom.Find("td.chdet1:contains('Video Bitrate')").Next().Text());
    5.52 +            channel.NetworkID = WebUtility.HtmlDecode(dom.Find("td.chdet1:contains('Netzwerk ID')").Next().Text());
    5.53 +
    5.54 +            channel.SID = WebUtility.HtmlDecode(dom.Find("td.chdet1:contains('Service ID')").Next().Text());
    5.55 +            channel.VPID = WebUtility.HtmlDecode(dom.Find("td.chdet1:contains('Video Pid')").Next().Text());
    5.56 +            channel.PCR = WebUtility.HtmlDecode(dom.Find("td.chdet1:contains('PCR Pid')").Next().Text());
    5.57 +            channel.PMT = WebUtility.HtmlDecode(dom.Find("td.chdet1:contains('PMT Pid')").Next().Text());
    5.58 +            channel.TXT = WebUtility.HtmlDecode(dom.Find("td.chdet1:contains('Videotext Pid')").Next().Text()).Replace(" (kein Videotext)","");
    5.59 +
    5.60 +            // We should get 4 entries:
    5.61 +            // - Category
    5.62 +            // - Country
    5.63 +            // - HD/SD TV
    5.64 +            // - Free/Pay TV
    5.65 +            CQ properties = dom.Find(".standart2");
    5.66 +            channel.Category = WebUtility.HtmlDecode(properties[0].InnerText).Trim();
    5.67 +            channel.Country = WebUtility.HtmlDecode(properties[1].InnerText).Trim();
    5.68 +
    5.69 +            return channel;
    5.70 +        }
    5.71 +
    5.72 +
    5.73 +        //*[@id="container"]/div[2]/table[3]/tbody/tr/td/table[2]/tbody/tr/td
    5.74 +        public static List<Channel> Parse(IProgress<ProgressReport> aProgress, List<Channel> aChannels, string aUrl, string aOrbitalPosition, bool aUseChannelIdForName = false, string aCategoryOverride = "")
    5.75 +        {
    5.76 +            //Create our list of channels
    5.77 +            List<Channel> channels = new List<Channel>();
    5.78 +            //To avoid duplicated name
    5.79 +            Dictionary<string, int> names = new Dictionary<string, int>();
    5.80 +
    5.81 +            string satIndex = new WebClient().DownloadString(aUrl);
    5.82 +            //Debug.Write(satIndex);
    5.83 +
    5.84 +            CQ dom = satIndex;
    5.85 +
    5.86 +            CQ channelsTd = dom.Find(".freq1");
    5.87 +
    5.88 +            ProgressReport report = new ProgressReport();
    5.89 +            report.Max = channelsTd.Count();
    5.90 +            report.Value = 0;
    5.91 +            aProgress.Report(report);
    5.92 +
    5.93 +            foreach ( IDomObject td in channelsTd)
    5.94 +            {
    5.95 +                string channelUrl = "https://www.satindex.de" + td.FirstChild.GetAttribute("href");
    5.96 +
    5.97 +                Channel channel = ParseChannel(channelUrl);
    5.98 +
    5.99 +                //Make sure our channel name looks descent
   5.100 +                channel.Name = CleanChannelName(channel.Name);
   5.101 +                //Make sure the resulting name is unique to avoid having multiple tuning detail for a single channel
   5.102 +                if (names.ContainsKey(channel.Name))
   5.103 +                {
   5.104 +                    names[channel.Name]++;
   5.105 +                    channel.Name += " " + names[channel.Name];
   5.106 +                }
   5.107 +                else
   5.108 +                {
   5.109 +                    names.Add(channel.Name, 1);
   5.110 +                }
   5.111 +                
   5.112 +                // Add it to our collection
   5.113 +                channels.Add(channel);
   5.114 +                // Report progress
   5.115 +                report.Value++;
   5.116 +                aProgress.Report(report);
   5.117 +            }
   5.118 +
   5.119 +            return channels;
   5.120 +
   5.121 +
   5.122 +            //Get all the Frequency tables in our page
   5.123 +            // Why is this not working? 
   5.124 +            //CQ sats = dom["#container > div:nth-child(2) > table:nth-child(16) > tbody > tr > td > table:nth-child(8) > tbody > tr > td > table"];
   5.125 +            // As a workaround we did the following
   5.126 +            CQ sats = dom["#container"]["div:nth-child(2)"]["table:nth-child(16)"]["tbody"]["tr"]["td"]["table:nth-child(8)"]["tbody"]["tr"]["td"]["table"];
   5.127 +
   5.128 +            List<IDomObject> transponders = sats.ToList();
   5.129 +
   5.130 +
   5.131 +
   5.132 +            foreach (IDomObject frq in transponders)
   5.133 +            {
   5.134 +                Channel common = new Channel();
   5.135 +
   5.136 +                //Parse channel details
   5.137 +                //common.OrbitalPosition = aOrbitalPosition;
   5.138 +                //string wsm1 = WebUtility.HtmlDecode(frq.Cq().Find(".wsm1").Get(0).InnerText).Trim();
   5.139 +
   5.140 +                /*
   5.141 +                common.Satellite = "Astra 19.2° East";
   5.142 +                common.Frequency = WebUtility.HtmlDecode(frq.Cq().Find("tbody > tr > td:nth-child(3)").Get(0).InnerText);
   5.143 +                common.Polarisation = WebUtility.HtmlDecode(frq.Cq().Find("tbody > tr > td:nth-child(4)").Get(0).InnerText);
   5.144 +                common.Transponder = WebUtility.HtmlDecode(frq.Cq().Find("tbody > tr > td:nth-child(5) > a").Get(0).InnerText);
   5.145 +                common.Beam = WebUtility.HtmlDecode(frq.Cq().Find("tbody > tr > td:nth-child(6) > a").Get(0).InnerText);
   5.146 +                common.Standard = WebUtility.HtmlDecode(frq.Cq().Find("tbody > tr > td:nth-child(7)").Get(0).InnerText);
   5.147 +                common.Modulation = WebUtility.HtmlDecode(frq.Cq().Find("tbody > tr > td:nth-child(8)").Get(0).InnerText);
   5.148 +                common.SymbolRate = WebUtility.HtmlDecode(frq.Cq().Find("tbody > tr > td:nth-child(9) > a").Get(0).InnerText);
   5.149 +                common.FEC = WebUtility.HtmlDecode(frq.Cq().Find("tbody > tr > td:nth-child(9) > a:nth-child(2)").Get(0).InnerText);
   5.150 +                try
   5.151 +                {
   5.152 +                    common.Provider = WebUtility.HtmlDecode(frq.Cq().Find("tbody > tr > td:nth-child(10) > b").Get(0).InnerText);
   5.153 +                }
   5.154 +                catch (Exception)
   5.155 +                {
   5.156 +                }
   5.157 +
   5.158 +                common.Bitrate = WebUtility.HtmlDecode(frq.Cq().Find("tbody > tr > td:nth-child(10)").Get(0).InnerText);
   5.159 +                if (common.Bitrate.Substring(0, ", ".Length) == ", ")
   5.160 +                {
   5.161 +                    common.Bitrate = common.Bitrate.Substring(", ".Length, common.Bitrate.Length - ", ".Length);
   5.162 +                }
   5.163 +                //
   5.164 +                common.NetworkID = WebUtility.HtmlDecode(frq.Cq().Find("tbody > tr > td:nth-child(11)").Get(0).InnerText);
   5.165 +                //common.NetworkID = common.NetworkID.Substring("NID:".Length, common.NetworkID.Length - "NID:".Length);
   5.166 +                //
   5.167 +                common.TransponderID = WebUtility.HtmlDecode(frq.Cq().Find("tbody > tr > td:nth-child(12)").Get(0).InnerText);
   5.168 +                //common.TransponderID = common.TransponderID.Substring("TID:".Length, common.TransponderID.Length - "TID:".Length);
   5.169 +
   5.170 +                //We got common properties for the coming channels
   5.171 +                //Debug.Write(common.ToString());
   5.172 +
   5.173 +                //Now get all the channels for that frequency
   5.174 +                //Channel common = new Channel();
   5.175 +                */
   5.176 +
   5.177 +                CQ channelsTableRows = frq.Cq().Find("tbody").Children("tr");
   5.178 +
   5.179 +
   5.180 +                //CQ channelsDiv = frq.Cq().Next("div");
   5.181 +                //CQ channelsTableRows = channelsDiv.Find("table.fl > tbody").Children("tr");
   5.182 +
   5.183 +                foreach (IDomObject row in channelsTableRows)
   5.184 +                {
   5.185 +                    Channel channel = new Channel();
   5.186 +                    //Initialize this channel with common properties on this frequency
   5.187 +                    channel.Copy(common);
   5.188 +
   5.189 +                    //Try and parse channel name
   5.190 +                    CQ cqChannelName = row.Cq().Find("td:nth-child(3) > a");
   5.191 +                    if (cqChannelName.Length == 0)
   5.192 +                    {
   5.193 +                        cqChannelName = row.Cq().Find("td:nth-child(3) > i");
   5.194 +                        if (cqChannelName.Length == 0)
   5.195 +                        {
   5.196 +                            //Can't get channel name
   5.197 +                            Debug.Write("WARNING: Can't find channel name! Skipping this channel");
   5.198 +                            continue;
   5.199 +                        }
   5.200 +                    }
   5.201 +
   5.202 +                    string channelName = "";
   5.203 +                    if (cqChannelName.Get(0).HasAttribute("title") && aUseChannelIdForName)
   5.204 +                    {
   5.205 +                        //We want to use the channel ID
   5.206 +                        channelName = cqChannelName.Get(0).GetAttribute("title");
   5.207 +                    }
   5.208 +                    else
   5.209 +                    {
   5.210 +                        channelName = cqChannelName.Get(0).InnerText;
   5.211 +                    }
   5.212 +
   5.213 +                    //Decode HTML
   5.214 +                    channel.Name = WebUtility.HtmlDecode(channelName);
   5.215 +                    //Convert from default encoding to UTF8
   5.216 +                    //We spend a lot of time trying to get this right until we found our answer in the following thread.
   5.217 +                    //http://stackoverflow.com/questions/14057434/how-can-i-transform-string-to-utf-8-in-c
   5.218 +                    byte[] bytes = Encoding.Default.GetBytes(channel.Name);
   5.219 +                    channel.Name = Encoding.UTF8.GetString(bytes);
   5.220 +
   5.221 +
   5.222 +
   5.223 +                    if (channel.Name == "Name" || channel.Name == "Sorted by name")
   5.224 +                    {
   5.225 +                        //Skipping header rows
   5.226 +                        continue;
   5.227 +                    }
   5.228 +
   5.229 +                    //Make sure our channel name looks descent
   5.230 +                    channel.Name = CleanChannelName(channel.Name);
   5.231 +                    //Make sure the resulting name is unique to avoid having multiple tuning detail for a single channel
   5.232 +                    if (names.ContainsKey(channel.Name))
   5.233 +                    {
   5.234 +                        names[channel.Name]++;
   5.235 +                        channel.Name += " " + names[channel.Name];
   5.236 +                    }
   5.237 +                    else
   5.238 +                    {
   5.239 +                        names.Add(channel.Name, 1);
   5.240 +                    }
   5.241 +
   5.242 +                    //
   5.243 +                    //We don't want channels we already have
   5.244 +                    Channel existingChannel = aChannels.Find(c => c.Name == channel.Name);
   5.245 +                    if (existingChannel != null)
   5.246 +                    {
   5.247 +                        continue;
   5.248 +                    }
   5.249 +
   5.250 +
   5.251 +                    //So we have a channel name get the other properties then
   5.252 +                    channel.Country = WebUtility.HtmlDecode(row.Cq().Find("td:nth-child(4)").Get(0).InnerText).Trim();
   5.253 +                    channel.Category = WebUtility.HtmlDecode(row.Cq().Find("td:nth-child(5)").Get(0).InnerText).Trim();
   5.254 +                    if (channel.Category == "")
   5.255 +                    {
   5.256 +                        channel.Category = "Other";
   5.257 +                    }
   5.258 +
   5.259 +                    //Override category if needed
   5.260 +                    if (aCategoryOverride != "")
   5.261 +                    {
   5.262 +                        channel.Category = aCategoryOverride;
   5.263 +                    }
   5.264 +
   5.265 +                    //Skip the packages
   5.266 +                    //Skip the encryptions
   5.267 +                    channel.SID = WebUtility.HtmlDecode(row.Cq().Find("td:nth-child(8)").Get(0).InnerText).Trim();
   5.268 +                    channel.VPID = WebUtility.HtmlDecode(row.Cq().Find("td:nth-child(9)").Get(0).InnerText).Trim();
   5.269 +                    //Skip audios
   5.270 +                    channel.PMT = WebUtility.HtmlDecode(row.Cq().Find("td:nth-child(11)").Get(0).InnerText).Trim();
   5.271 +                    channel.PCR = WebUtility.HtmlDecode(row.Cq().Find("td:nth-child(11)").Get(0).InnerText).Trim();
   5.272 +                    channel.TXT = WebUtility.HtmlDecode(row.Cq().Find("td:nth-child(11)").Get(0).InnerText).Trim();
   5.273 +
   5.274 +                    //Append that new channel to our list
   5.275 +                    channels.Add(channel);
   5.276 +
   5.277 +                    //Show it in debug output
   5.278 +                    Debug.Write(channel);
   5.279 +                } //For each channel
   5.280 +            } //For each frequency
   5.281 +
   5.282 +            return channels;
   5.283 +        }
   5.284 +
   5.285 +        //
   5.286 +        public static string CleanChannelName(string aName)
   5.287 +        {
   5.288 +            aName = aName.Trim();
   5.289 +            string[] remove = { " Germany", " Deutschland", " (Germany)", " (Deutschland)" };
   5.290 +
   5.291 +            foreach (string item in remove)
   5.292 +            {
   5.293 +                //if (aName.EndsWith(item))
   5.294 +                if (aName.Contains(item))
   5.295 +                {
   5.296 +                    aName = aName.Substring(0, aName.LastIndexOf(item));
   5.297 +                    break; //only allow one match at most
   5.298 +                }
   5.299 +            }
   5.300 +
   5.301 +            string[] removePrefix = { "Id: " };
   5.302 +
   5.303 +            foreach (string item in removePrefix)
   5.304 +            {
   5.305 +                if (aName.StartsWith(item))
   5.306 +                {
   5.307 +                    aName = aName.Substring(item.Length, aName.Length - item.Length);
   5.308 +                    break; //only allow one match at most
   5.309 +                }
   5.310 +            }
   5.311 +
   5.312 +
   5.313 +
   5.314 +            aName = aName.Trim();
   5.315 +            return aName;
   5.316 +        }
   5.317 +
   5.318 +        //
   5.319 +        public static List<Channel> CleanChannelList(List<Channel> aChannels)
   5.320 +        {
   5.321 +            //Create our list of channels
   5.322 +            List<Channel> channels = new List<Channel>();
   5.323 +
   5.324 +            foreach (Channel channel in aChannels)
   5.325 +            {
   5.326 +                Channel hdChannel = aChannels.Find(c => c.Name == channel.Name + " HD");
   5.327 +                if (hdChannel == null
   5.328 +                    && !(channel.Name.Contains("Bundesliga") && !channel.Name.Contains("HD")) //We don't want non HD bundesliga
   5.329 +                    && !(channel.Name.StartsWith("Sky Sport") && !channel.Name.Contains("HD")) //We don't want non HD Sky Sport
   5.330 +                    )
   5.331 +                {
   5.332 +
   5.333 +                    if (channel.Category == "Allgemein"
   5.334 +                        && channel.Name.Contains("Sky"))
   5.335 +                    {
   5.336 +                        channel.Category = "Movies & Series";
   5.337 +                    }
   5.338 +
   5.339 +                    if (channel.Name == "SYFY HD")
   5.340 +                    {
   5.341 +                        channel.Category = "Movies & Series";
   5.342 +                    }
   5.343 +
   5.344 +                    // Patch Bundesliga channel names by removing Sport, cause they are way too long names
   5.345 +                    if (channel.Name.Contains("Bundesliga"))
   5.346 +                    {
   5.347 +                        channel.Name = channel.Name.Replace("Sport ", "");
   5.348 +                    }
   5.349 +
   5.350 +                    //Patch some missing or bad categories
   5.351 +                    if (channel.Name.Contains("Bundesliga")
   5.352 +                        || channel.Name.Contains("Sport"))
   5.353 +                    {
   5.354 +                        channel.Category = "Sport";
   5.355 +                    }
   5.356 +
   5.357 +                    if (channel.Name.Contains("Sky Select"))
   5.358 +                    {
   5.359 +                        channel.Category = "Pay per view";
   5.360 +                    }
   5.361 +
   5.362 +                    if (channel.Name.Contains("TNT")
   5.363 +                        || channel.Name.Contains("13th"))
   5.364 +                    {
   5.365 +                        channel.Category = "Movies & Series";
   5.366 +                    }
   5.367 +
   5.368 +                    if (channel.Category =="Kinderprogramm")
   5.369 +                    {
   5.370 +                        channel.Category = "Kids";
   5.371 +                    }
   5.372 +
   5.373 +                    if (channel.Category == "Hinweistafel")
   5.374 +                    {
   5.375 +                        channel.Category = "General";
   5.376 +                    }
   5.377 +
   5.378 +                    if (channel.Name.StartsWith("Sky Atlantic")
   5.379 +                        || channel.Name.StartsWith("SyFy")
   5.380 +                        || channel.Name.StartsWith("Fox"))
   5.381 +                    {
   5.382 +                        channel.Category = "Series";
   5.383 +                    }
   5.384 +
   5.385 +                    //Collapse some categories
   5.386 +                    if (channel.Category == "Entertainment"                        
   5.387 +                        || channel.Category == "Kultur"
   5.388 +                        || channel.Category == "Verschiedenes")
   5.389 +                    {
   5.390 +                        channel.Category = "General";
   5.391 +                    }
   5.392 +
   5.393 +                    if (channel.Category == "Musik"
   5.394 +                        || channel.Name.Contains("Music")
   5.395 +                        || channel.Name.Contains("Musik"))
   5.396 +                    {
   5.397 +                        channel.Category = "Music";
   5.398 +                    }
   5.399 +
   5.400 +
   5.401 +
   5.402 +                    if (channel.Category == "Porn"
   5.403 +                        || channel.Category == "Erotik"
   5.404 +                        || channel.Name.Contains("Blue Movie")
   5.405 +                        || Regex.IsMatch(channel.Name,"Sex", RegexOptions.IgnoreCase)
   5.406 +                        || Regex.IsMatch(channel.Name, "Erotik", RegexOptions.IgnoreCase)
   5.407 +                        || Regex.IsMatch(channel.Name, "Girl", RegexOptions.IgnoreCase)
   5.408 +                        || Regex.IsMatch(channel.Name, "Eros", RegexOptions.IgnoreCase)
   5.409 +                        || Regex.IsMatch(channel.Name, "Gay", RegexOptions.IgnoreCase)
   5.410 +                        || Regex.IsMatch(channel.Name, "frauen", RegexOptions.IgnoreCase)
   5.411 +                        || Regex.IsMatch(channel.Name, "Maenner", RegexOptions.IgnoreCase)
   5.412 +                        || Regex.IsMatch(channel.Name, "bunny", RegexOptions.IgnoreCase)
   5.413 +                        || Regex.IsMatch(channel.Name, "date", RegexOptions.IgnoreCase)
   5.414 +                        )
   5.415 +                    {
   5.416 +                        channel.Category = "Erotic";
   5.417 +                    }
   5.418 +
   5.419 +                    if (channel.Category == "Presentations"
   5.420 +                        || channel.Category == "Nachrichten")
   5.421 +                    {
   5.422 +                        channel.Category = "News";
   5.423 +                    }
   5.424 +
   5.425 +                    if (channel.Category == "History"
   5.426 +                        || channel.Category == "Dokus / Reportagen")
   5.427 +                    {
   5.428 +                        channel.Category = "Documentaries";
   5.429 +                    }
   5.430 +
   5.431 +                    if (channel.Category == "Travel"
   5.432 +                        || channel.Category == "Urlaub / Reisen")
   5.433 +                    {
   5.434 +                        channel.Category = "Documentaries";
   5.435 +                    }
   5.436 +
   5.437 +
   5.438 +                    if (channel.Category == "Lifestyle"
   5.439 +                        || channel.Category == "Allgemein"
   5.440 +                        || channel.Category == "Other"
   5.441 +                        || channel.Category == "Cultural")
   5.442 +                    {
   5.443 +                        channel.Category = "General";
   5.444 +                    }
   5.445 +
   5.446 +                    if (channel.Category == "Movies"
   5.447 +                        || channel.Category == "Spielfilme")
   5.448 +                    {
   5.449 +                        channel.Category = "Movies & Series";
   5.450 +                    }
   5.451 +
   5.452 +                    if (channel.Category == "Series")
   5.453 +                    {
   5.454 +                        channel.Category = "Movies & Series";
   5.455 +                    }
   5.456 +
   5.457 +                    if (channel.Category == "Regional Programm")
   5.458 +                    {
   5.459 +                        channel.Category = "Regional";
   5.460 +                    }
   5.461 +
   5.462 +                    //No corresponding HD channel, keep it then
   5.463 +                    channels.Add(channel);
   5.464 +                }
   5.465 +                else
   5.466 +                {
   5.467 +                    Debug.Write("WARNING: Found HD channel for " + channel.Name + ". Discarding it!\n");
   5.468 +                }
   5.469 +            }
   5.470 +
   5.471 +            return channels;
   5.472 +        }
   5.473      }
   5.474  }