Reputation:
So I make a List in a Background Worker with Start and End time etc for processing a TV Show list I put the Channel Name for the TV Show in it too. So now I wanna process the Channel's List aswell and it has the Channel Name and the Channel Livestream.
How can I make it so I add the Channel Stream to the List made in the Background Worker?
Code:
'Guide and Channel Information;
Public Class Channel
Public Property Channel As String
Public Property Stream As String
Public Property Genre As String
Public Property StartTime As String
Public Property EndTime As String
Public Property Programme As String
Public Property Description As String
Public Overrides Function ToString() As String
Return Channel
Return Stream
Return Genre
Return StartTime
Return EndTime
Return Programme
Return Description
End Function
End Class
'Make a List for the Guide Information;
Public Guide As New List(Of Channel)
Private Sub ProcessGuide_DoWork(sender As Object, e As DoWorkEventArgs) Handles ProcessGuide.DoWork
Try
Dim nodelist As XmlNodeList
Dim node As XmlNode
'Create the XML Document;
Dim xmld As XmlDocument
xmld = New XmlDocument()
'Load the XMLTV File;
xmld.Load("http://104.233.125.128/gmtplus0.xmltv")
'Loop through the Programme Nodes;
nodelist = xmld.SelectNodes("/tv/programme")
For Each node In nodelist
'Here I am adding the Channel etc, But I will also need the stream etc added which is why I have a sub later on in the code to get and add the Stream. But how do I add it to this same Guide List?
Guide.Add(New Channel() With {
.Channel = node.Attributes.GetNamedItem("channel").Value,
.StartTime = node.Attributes.GetNamedItem("start").Value,
.EndTime = node.Attributes.GetNamedItem("stop").Value,
.Programme = node.ChildNodes.Item(0).InnerText,
.Description = node.ChildNodes.Item(1).InnerText
})
Next
ProcessChannels.RunWorkerAsync()
Catch ex As Exception
'Error trapping
Console.Write(ex.ToString(), "TTTTTdsg")
End Try
End Sub
'Process the Channel Information;
Dim AllChannels As List(Of Channel) = New List(Of Channel)()
Dim EntertainmentChannels As List(Of Channel) = New List(Of Channel)()
Dim KidsChannels As List(Of Channel) = New List(Of Channel)()
Dim SportsChannels As List(Of Channel) = New List(Of Channel)()
Dim DocumentaryChannels As List(Of Channel) = New List(Of Channel)()
Dim NewsChannels As List(Of Channel) = New List(Of Channel)()
Dim MusicChannels As List(Of Channel) = New List(Of Channel)()
Public Sub ProcessChannels_DoWork(sender As Object, e As DoWorkEventArgs) Handles ProcessChannels.DoWork
'Try to Load the Channel Data;
Try
'Connect to the Proxy Source and Prepare the Response;
Dim source As Net.HttpWebRequest = Net.WebRequest.Create("http://gameshare.io/pragma/channels.php")
Dim response As Net.HttpWebResponse = source.GetResponse
'Load the HTML and Convert the JSON to a Readable Array;
Dim reader As IO.StreamReader = New IO.StreamReader(response.GetResponseStream())
Dim html As String = reader.ReadToEnd
Dim json = JsonConvert.DeserializeObject(html)
'=========================================================
'=========================================================
'Here is where I need to not add the Guide info to a NEW Channel/Guide/List I need to add it to the same one
'that is made in ProcessGuide_DoWork but how?
'Process All Channels;
For i As Integer = 0 To json("Quantity").ToString - 1
For Each Row In json("All Channels")
AllChannels.Add(New Channel() With {
.Channel = Row(i)("title").ToString,
.Stream = Row(i)("stream").ToString
})
Next
Next
'Process Enterainment Channels
For i As Integer = 0 To json("EQuantity").ToString - 1
For Each Row In json("Entertainment")
EntertainmentChannels.Add(New Channel() With {
.Channel = Row(i)("title").ToString,
.Stream = Row(i)("stream").ToString
})
Next
Next
'Process Kids Channels;
For i As Integer = 0 To json("KQuantity").ToString - 1
For Each Row In json("Kids")
KidsChannels.Add(New Channel() With {
.Channel = Row(i)("title").ToString,
.Stream = Row(i)("stream").ToString
})
Next
Next
'Process Sports Channels;
For i As Integer = 0 To json("SQuantity").ToString - 1
For Each Row In json("Sports")
SportsChannels.Add(New Channel() With {
.Channel = Row(i)("title").ToString,
.Stream = Row(i)("stream").ToString
})
Next
Next
'Process Documentary Channels;
For i As Integer = 0 To json("DQuantity").ToString - 1
For Each Row In json("Documentary")
DocumentaryChannels.Add(New Channel() With {
.Channel = Row(i)("title").ToString,
.Stream = Row(i)("stream").ToString
})
Next
Next
'Process News Channels;
For i As Integer = 0 To json("NQuantity").ToString - 1
For Each Row In json("News")
NewsChannels.Add(New Channel() With {
.Channel = Row(i)("title").ToString,
.Stream = Row(i)("stream").ToString
})
Next
Next
'Process Music Channels;
For i As Integer = 0 To json("MQuantity").ToString - 1
For Each Row In json("Music")
MusicChannels.Add(New Channel() With {
.Channel = Row(i)("title").ToString,
.Stream = Row(i)("stream").ToString
})
Next
Next
'Add all the Channels to the Channels ComboBox;
ChannelsBox.Items.AddRange(allchannels.ToArray)
'The Channels are now ready to be used, Tell the user to Select a Channel;
ChannelsBox.Text = "Select a Channel..."
Catch ex As Exception
'Channel Data couldn't be loaded;
ErrorImage.Width = "640"
ErrorImage.Height = "391"
ErrorImage.Visible = True
End Try
End Sub
Upvotes: 1
Views: 79
Reputation: 38875
Your code needs to be significantly reworked. First, you should turn on Option Strict
; code like this will not compile since it uses late-binding:
For Each Row In json("All Channels")
Fundamentally, once you parse the XML, you have one entry in the list for each channel. You cannot then iterate the json TV show list and plug them into that list: there are many TV shows for each channel. You don't have an array or list to store the multiple shows per channel.
There is also no need for a BackGroundWorker. Rather than looping thru an Object
and manually creating those lists, if you deserialize to a typed object JSON.NET will create all those lists for you in just a few ticks.
So, you need one class to link a URL to a channel (TVGChannel
) and one class to contain the data for a TV broadcast. One of the properties for the show list/Guide is the channel it is one. The XML data includes a Category
for each show which would seem to be more interesting than a channel category.
Hopefully, the channel
element in the XML really is designed to specify a channel indicated by title
in the json and it is not an accident of the data that they match. It looks more like it is supposed to reference something in the channel section in the same XML, but those just have URLs.
Public Enum ProgrammeGenre
Entertainment
Kids
Sports
Documentary
News
Music
Other
End Enum
Public Class Programme
Public Property Name As String
Public Property Title As String ' episode Title
Public Property Description As String
Public Property Channel As TVGChannel
Public Property Genre As ProgrammeGenre
Public Property StartTime As DateTime
Public Property EndTime As DateTime
Public Property Category As String
Public Property EpisodeId As String
Public Property Stars As Decimal
Public Sub New()
Genre = ProgrammeGenre.Other
End Sub
End Class
As you can see, I expanded it for a few other elements and changed some types, most notably the start and end times to DateTime
. The Category
property stores the category from the XML, while the Genre
is the result of which list it is in:
thisPrgURL = myProgrammes(n).Channel.stream
Public Class TVGChannel
Public Property stream As String
Public Property title As String
Public Overrides Function ToString() As String
Return title
End Function
End Class
Public Class TVGContainer
'Public Property Quantity As String
'...
<JsonProperty("All Channels")>
Private Property _AllChannels As TVGChannel()()
' none of these are really very useful:
Public Property Entertainment As TVGChannel()()
Public Property Kids As TVGChannel()()
Public Property Sports As TVGChannel()()
Public Property Documentary As TVGChannel()()
Public Property News As TVGChannel()()
Public Property Music As TVGChannel()()
Friend ReadOnly Property AllChannels As TVGChannel()
Get
Return _AllChannels(0)
End Get
End Property
End Class
None of those ?Quantity
properties are of much value and the only role for the channel list subsets is for the Genre property on Programme
- they could all be commented out. I dunno why they provide them as a jagged array; I didnt want to have to deal with it, so the JSON will go into _AllChannels
when it is deserialized, but the code will use the AllChannels
property.
Private myPrograms As List(Of Programme)
Private ChannelGuide As TVGContainer
You need to have the Guide built before you process the XML so the channels are available to assign to each show:
Private Sub ParseGuide()
Dim jstr = from whereever
ChannelGuide = JsonConvert.DeserializeObject(Of TVGContainer)(jstr)
End Sub
By deserialing to a typed object, there is no need to parse all that stuff one by one, and it should be much (much) faster; ChannelGuide
will contain all those arrays.
I made significant changes to how the XML is processed. Most were in the interest of speed, less maintenance or more reliable processing:
Private Sub ParseXMLTV()
Dim nodelist As XmlNodeList
Dim node As XmlNode
Dim xmld As New XmlDocument()
xmld.Load("http://104.233.125.128/gmtplus0.xmltv")
myPrograms = New List(Of Programme)
nodelist = xmld.SelectNodes("/tv/programme")
Dim p As Programme
For Each node In nodelist
p = New Programme()
Dim dt = DateTimeOffset.ParseExact(node.Attributes.GetNamedItem("start").Value,
"yyyyMMddHHmmss KKKK", CultureInfo.InvariantCulture).DateTime
p.StartTime = dt
dt = DateTimeOffset.ParseExact(node.Attributes.GetNamedItem("stop").Value,
"yyyyMMddHHmmss KKKK", CultureInfo.InvariantCulture).DateTime
p.EndTime = dt
' now, find the channel indicated
Dim ch = node.Attributes.GetNamedItem("channel").Value
If String.IsNullOrEmpty(ch) = False Then
Dim tvgc = ChannelGuide.AllChannels.FirstOrDefault(Function(q) q.title = ch)
If tvgc IsNot Nothing Then
p.Channel = tvgc
Else
' ToDo: add an UNKNOWN channel to avoid NRE
End If
End If
p.Genre = GetGenre(ch)
For Each n As XmlNode In node.ChildNodes
Select Case n.Name
Case "title"
p.Name = n.InnerText
Case "sub-title"
p.Title = n.InnerText
Case "desc"
p.Description = n.InnerText
Case "star-rating"
p.Stars = Convert.ToDecimal(n.InnerText.Split(" "c)(0))
Case "episode-num"
p.EpisodeId = n.InnerText
Case "category"
p.Category = n.InnerText
End Select
Next
myPrograms.Add(p)
Next
End Sub
Private Function GetGenre(ch As String) As ProgrammeGenre
' this is not needed - the XML provides a show category
' "Drama" or "SitCom" is more interesting than `Entertainment`
If ChannelGuide.Documentary(0).
FirstOrDefault(Function(f) f.title = ch) IsNot Nothing Then
Return ProgrammeGenre.Documentary
ElseIf ChannelGuide.Entertainment(0).
FirstOrDefault(Function(f) f.title = ch) IsNot Nothing Then
Return ProgrammeGenre.Entertainment
ElseIf ...
' repeat for others
Else
Return ProgrammeGenre.Other
End If
End Function
ParseGuide()
If ChannelGuide IsNot Nothing AndAlso ChannelGuide.AllChannels.Count > 0 Then
ParseXMLTV()
End If
dgvTV.DataSource = myPrograms
The whole thing take 6 seconds to run (including download times and posting to the DGV), so there isnt really a reason for a BackGroundWorker
. It would be faster without the cruft of fishing out the show Genre based on a channel category...and there are a lot of both of them that are missing.
The EndTime
, Category
, Episode ID and Star Rating are all scrolled off to the right.
The DateTime
parsing may need work, but I have no idea where I can find the docs for this API.
Upvotes: 1