''dsmplayer.wxb''

'//////////////////////////////////////////////////////////////////////////////////
'// create access for poscasts                                                   //
'// Dirk Noack @2025                                                             //
'//////////////////////////////////////////////////////////////////////////////////

Const ID_TIMER_WGET = wxNewId()

wxFileSystem_AddHandler(New wxInternetFSHandler())
wxFileSystem_AddHandler(New wxLocalFSHandler())
'this is not implemented yet
'wxInitAllImageHandlers()

Dim episode As String = ""
Dim podText As Table = {}
Dim wgetPrc As wxProcess
Dim checkCertAll As Integer = TRUE
Dim wgetTimer As wxTimer
Dim wgetBar As wxGenericProgressDialog
Dim updDialog As wxDialog
Dim podFeeds As Table = {}
Dim podcastDL As wxArrayString = New wxArrayString()
Dim itemrect As wxRect = wxRect(0, 0, 0, 0)

'load the podcast playlist from database
Sub loadPlaylistPodcast()
  Dim url As String = ""
  Dim con As Integer = checkConnection()
  If !con Then Return

  dbc = wxDbConnection("DBQ=IPTV.db;DefaultDir=.;Driver=SQLITE3;")
  If dbc.IsOpen() Then
    dbc.ExecSql("PRAGMA synchronous = OFF")
    dbc.ExecSql("PRAGMA journal_mode = MEMORY")
    dbc.ExecSql("PRAGMA cache_size = 1000000")
    dbc.ExecSql("PRAGMA locking_mode = EXCLUSIVE")
    dbc.ExecSql("PRAGMA temp_store = MEMORY")
    dbc.ExecSql("SET CHARACTER_SET 'utf8'")

    Dim cfg As wxFileConfig = wxFileConfig("", "", playerIni)
    cfg.SetPath("/Podcast")

    Dim recSet As wxDbRecordset
    If busyInfo Then ~busyInfo
    busyInfo = wxBusyInfo(_("Read podcast info..."))

    lcPod.Freeze()
    lcPod.DeleteAllItems()
    lcPod.Thaw()

    Dim root = lcPod.GetRootItem()
    Dim pItem As wxTreeListItem

    recSet = wxDbRecordset(dbc, "select * from podcast")
    Dim cnt As Integer = recSet.GetRowCount()
    If cnt > 3000 Then busyInfo = wxBusyInfo(_("Loading podcasts..."))

    cnt = 0
    Dim urls As List = []
    Dim active As Integer

    recSet.MoveFirst()
    While Not recSet.IsEOF()
      pItem = lcPod.AppendItem(root, recSet.FieldPos(1))  'podcast
      lcPod.SetItemColText(pItem, 2, recSet.FieldPos(2))  'genre
      url = recSet.FieldPos(3)
      lcPod.SetItemColText(pItem, 4, url)                 'adress
      lcPod.SetItemColText(pItem, 5, recSet.FieldPos(4))  'icon

      active = IIf(recSet.FieldPos(5)= "", 0, Val(recSet.FieldPos(5))) 'podcast active
      lcPod.SetItemColText(pItem, 6, recSet.FieldPos(6))               'max counter
      lcPod.SetItemColText(pItem, 7, IIf(recSet.FieldPos(7)= "", 0, Val(recSet.FieldPos(7))))       'rec
      lcPod.SetItemColText(pItem, 8, IIf(recSet.FieldPos(8)= Nothing, 0, Val(recSet.FieldPos(8))))  'cert

      If url <> "" Then
        urls.Append(url)
        podText[url]= ""
        podFeeds[url]= pItem

        If active Then lcPod.CheckItem(pItem, TRUE)
      End If

      recSet.MoveNext()

      If cnt % 200 = 0 Then wxSafeYield(musicFrame, TRUE)
      cnt += 1
    Wend

    recSet.Close()
    dbc.Close()

    For i = 1 To urls.Count()
      readUrl(urls[i])
    Next


    urls = Nothing
    If busyInfo Then ~busyInfo
    busyinfo = Nothing
  End If
End Sub


Sub readUrl(path As String)
  If !wxFileExists(wgetPath) Then selectDownloadReader()
  If !wxFileExists(wgetPath) Then Return

  Dim active As Integer
  Dim counter As Integer
  Dim checkCert As Integer
  Dim Item As wxTreeListItem

  dbc = wxDbConnection("DBQ=IPTV.db;DefaultDir=.;Driver=SQLITE3;")
  If dbc.IsOpen() Then
    Dim Name = dbc.ExecSql("Select name FROM podcast WHERE adress=" &Chr(34) &path &Chr(34) &" COLLATE NOCASE")
    'check if the podcast exist in the database
    If Name <> "" Then
      counter = dbc.ExecSql("SELECT counter FROM podcast where adress=" &Chr(34) &path &Chr(34) &" COLLATE NOCASE")
      active = dbc.ExecSql("SELECT active FROM podcast where adress=" &Chr(34) &path &Chr(34))
      checkCert = dbc.ExecSql("SELECT cert FROM podcast where adress=" &Chr(34) &path &Chr(34))

    Else

      'it is a new podcast
      Item = lcPod.GetSelection()
      active = lcPod.GetCheckedState(Item)
      counter = lcPod.GetItemText(Item, 6)
      checkCert = lcPod.GetItemText(Item, 8)
    End If

    dbc.Close()
  End If

  If active Then
    podText[path] = ""

    Dim opt As String = " -O- --no-verbose "
    If !CheckCert Or !CheckcertAll Then opt = " --no-check-certificate" &opt

    Dim rssProcess = New wxProcessWithFlags(wxPROCESS_REDIRECT)
    Connect(rssProcess, wxEVT_END_PROCESS, "onEndRSSProcess")
    Dim pid = wxExecute(wgetPath  &opt &path, wxEXEC_ASYNC, rssProcess)

    If pid > 0 Then
      'read the stream from the process
      Dim inStream As wxInputStream = rssProcess.GetInputStream()
      Dim errStream As wxInputStream = rssProcess.GetErrorStream()

      If inStream And inStream.IsOk() Then
        Dim buffer As String = ""
        Dim err As String = ""

        While !inStream.Eof()
          buffer &= inStream.Read(8)
        Wend

        While !errStream.Eof()
          err &= errStream.Read(8)
        Wend

        If buffer = "" And err <> "" Then
          Dim message As String = _("An error occurred while loading the feed from the page")
          err = LCase(err)
          Dim at = InStr(err, "error")
          If at Then err = Trim(err[at: ])

          If InStr(err, "--no-check-certificate") Then
            err = err[: RInstr(err, "\n")]
            
            Dim message1 As String = _("Run this page once without certificate check?")
            Dim message2 As StrIng = _("You can generally disable certificate verification in the RSS settings.")
            Dim message3 As String = _("Disabling the check may cause security issues.")
            
            Dim dl = wxGenericMessageDialog(Nothing, message &"\n" &path &"\n" &" " &"\n" &err &"\n" &" " &"\n" &message1 &"\n" &" " &"\n" &_("Note:") &
            "\n" &message2 &"\n" &" " &"\n" &_("Caution:") &"\n" & message3, _("Attention"), wxYES_NO|wxNO_DEFAULT|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)

            'wxYes = 5103 in wxGenericMessageDialog
            If dl.ShowModal() = 5103 Then
              dbc = wxDbConnection("DBQ=IPTV.db;DefaultDir=.;Driver=SQLITE3;")
              If dbc.IsOpen() Then
                dbc.ExecSql("UPDATE podcast SET cert=" &Chr(34) &FALSE &Chr(34) &" WHERE adress =" &Chr(34) &path &Chr(34))
                dbc.Close()
              End If

              If Item.IsOk() Then lcPod.SetItemColText(Item, 7, FALSE)
              readUrl(path)
              Return
            End If

          Elseif InStr(err, "forbidden") Then
            message = _("No access to the podcast.") &"\n" &path &"\n" &" " &"\n" &err
            delCurPodcast(message, podFeeds[path])
            Return

          Else
            message = message &"\n" &path &"\n" &" " &"\n" &err
            delCurPodcast(message, podFeeds[path])
            Return
          End If
        End If

        If buffer[3: 5]= "xml" Then
          readXML(buffer, path, counter)

        Elseif InStr(buffer[: 50], "html") Then
          readHTML(buffer, path, counter)

        End If
      End If
    End If
  End If
End Sub


Sub onEndRSSProcess(event As wxProcessEvent)
End Sub


Sub delCurPodcAst(message As String, Item As wxTreeListItem)
  Dim dl = wxGenericMessageDialog(Nothing, message, _("Attention"), wxOK|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
  dl.ShowModal()

  Dim path As String = lcPod.GetItemText(Item, 4)
  setPodcastInfo(path, FALSE)
  lcPod.DeleteItem(Item)
  podFeeds[path]= Nothing
End Sub


'insert the podcast episode adress to the podcast database
Sub url2DB(mainUrl As String, url As String)
  Dim opened As Integer = IIf(dbp.IsOpen(), TRUE, FALSE)
  
  If !opened Then dbp = wxDbConnection("DBQ=podcasts.db;DefaultDir=.;Driver=SQLITE3;")
  If dbp.IsOpen() Then
    Dim murl As String = dbp.ExecSql("SELECT mainurl FROM podcasts where url=" &Chr(34) &url &Chr(34) &" COLLATE NOCASE")
    If murl = "" Then dbp.ExecSql("Insert INTO podcasts values(" &Chr(34) &mainUrl &Chr(34) &"," &Chr(34) &url &Chr(34) &"," &"0);")
  End If
  If !opened Then dbp.Close()
End Sub


Sub readXML(buffer As String, path As String, counter As Integer)
  Dim noLog = wxLogNull()
  Dim sInStream As wxStringInputStream = wxStringInputStream(buffer)
  If !sInstream.IsOk() Then Return

  Dim xml As wxXmlDocument = wxXmlDocumentFromStream(sInStream)
  If xml.IsOk() Then
    Dim root As wxXmlNode = xml.DetachRoot()
    Dim child = root.GetChildren()
    Dim podDatetime As wxDateTime

    'start reading the nodes
    Dim nd As wxXmlNode
    Dim xmlItem As wxXmlNode
    Dim Item As wxTreeListItem
    Dim xmlData = Nothing
    Dim attr As wxXmlAttribute
    Dim fileUrl As String = ""
    Dim title As String = ""
    Dim genre As String = ""
    Dim image As String = ""
    Dim duration As String = ""
    Dim urlFlag As Integer = FALSE
    Dim cnt As Integer = 0
    Dim i As Integer = 0
    Dim content As String = ""
    Dim heard As Integer = FALSE
    Dim at As Integer
    Dim s As String
    Dim Type As String

    'open the podcasts database
    dbp = wxDbConnection("DBQ=podcasts.db;DefaultDir=.;Driver=SQLITE3;")

    xmlData = child.GetNodeContent()
    title = ""

    nd = child.GetChildren()
    While nd
      If (counter > 0) And (i >= counter) Then isBroken = TRUE

      If isBroken Then
        isBroken = FALSE
        Break
      End If
      
      podDatetime = Nothing
      episode = ""
      image = ""

      xmlData = nd.GetNodeContent()

      Select Case LCase(nd.GetName())
      Case "title"
        s = wxString_FromUTF8(xmlData)
        title = IIf(s = "", xmldata, s)
        lcPod.SetItemText(podFeeds[path], title)

      Case "description", "content", "summary"
        s = wxString_FromUTF8(xmlData)
        podText[path] = IIf(s = "", xmldata, s)

      Case "category", "itunes:category"
        If xmlData <> "" Then
          genre = xmlData
        Else
          genre = nd.GetAttributeString("text")
        End If

        lcPod.SetItemColText(podFeeds[path], 2, genre)

      Case "image"
        'read the podcast image
        xmlItem = nd.GetChildren()

        While xmlItem
          xmlData = xmlItem.GetNodeContent()

          If xmlItem.GetType() = wxXML_ELEMENT_NODE Then
            If xmlItem.GetName() = "url" Then

              lcPod.SetItemColText(podFeeds[path], 5, xmlData)
              If dbc.IsOpen() Then dbc.ExecSql("UPDATE podcast SET icon=" &Chr(34) &xmlData &Chr(34) &" WHERE adress =" &Chr(34) &path &Chr(34))
            End If
          End If

          Deallocate(xmlItem)
          xmlItem = xmlItem.GetNext()
        Wend

      Case "itunes:image"
        'sometimes no image is set and itunes:image is used as podcast image
        image =  nd.GetAttributeString("url")
        If image = "" Then image = nd.GetAttributeString("href")

        at = InStr(image, "?")
        If at Then image = image[: at - 1]

'needed?
'        attr = nd.GetAttributes()
'        While attr
'          data = attr.GetValue()
'          If (Left(data, 4)= "http") Or (attr.GetName()= "href") Then
'            image = data
'            at = InStr(image, "?")
'            If at Then image = image[: at - 1]
'          End If
'
'          Deallocate(attr)
'          attr = attr.GetNext()
'        Wend

        lcPod.SetItemColText(podFeeds[path], 5, image)
        If dbc.IsOpen() Then dbc.ExecSql("UPDATE podcast SET icon=" &Chr(34) &image &Chr(34) &" WHERE adress =" &Chr(34) &path &Chr(34))
        image = ""

      'search for episodes
      Case "item"
        content = ""
        xmlItem = nd.GetChildren()

        While xmlItem
          xmlData = xmlItem.GetNodeContent()

          If xmlItem.GetType() = wxXML_ELEMENT_NODE Then
            Select Case LCase(xmlItem.GetName())
            Case "title"
              If xmlData = "" Then
                Deallocate(xmlItem)
                xmlItem = xmlItem.GetNext()
              End If

              s = wxString_FromUTF8(Trim(xmlData))
              episode = IIf(s = "", Trim(xmldata), s)

            Case "description", "content", "summary"
              xmlData = removeSpecialChars(xmlData)
              s = wxString_FromUTF8(xmlData)
              content = IIf(s = "", xmldata, s)

            Case "pubdate", "updated"
              If xmlData <> "" Then
                podDatetime = wxDateTime_wxDateTime() 

                If InStr(xmlData, " ") Then
                  podDatetime.ParseDateTime(xmlData)
                Else
                  podDatetime.ParseISOCombined(xmlData)
                End If
              End If

            Case "media:content", "itunes:image"
              If Left(xmldata, 4)= "http" Then
                image = xmldata

              Else
                image =  xmlItem.GetAttributeString("url")
                If image = "" Then image = xmlItem.GetAttributeString("href")

                at = InStr(image, "?")
                If at Then image = image[: at - 1]
              End If

            Case "duration", "itunes:duration"
              duration = xmldata

              'duaration is in seconds, format it
              If !InStr(duration, ":") Then
                duration = getTimeFromSec(duration, FALSE)

              Else
                duration = getTimeFromString(duration, TRUE, FALSE)
              End If

            Case "enclosure", "alternateenclosure"
              urlFlag = FALSE

              fileUrl = xmlItem.GetAttributeString("url")
              If fileUrl = "" Then fileUrl = xmlItem.GetAttributeString("uri")

              Type = xmlItem.GetAttributeString("type")
              If InStr(Type, "audio") Or InStr(Type, "mpeg") Then urlFlag = TRUE
              If !urlFlag Then fileUrl = ""
            End Select
          End If

          If cnt%100 = 0 Then wxYield()
          cnt += 1

          Deallocate(xmlItem)
          xmlItem = xmlItem.GetNext()
        Wend

        If fileurl <> "" Then
          at = InStr(fileUrl, "?")
          If at Then fileUrl = fileUrl[: at - 1]

          heard  = FALSE
          If counter = -1 Then
            If dbp.IsOpen() Then heard = dbp.ExecSql("SELECT heard FROM podcasts where url=" &Chr(34) &fileurl &Chr(34) &" COLLATE NOCASE")

            If heard Then
              podDatetime = wxDateTimeEmpty()
              episode = ""
              duration = ""
              content = ""
              fileUrl = ""
              image = ""

              Deallocate(nd)
              nd = nd.GetNext()
              i += 1
              Continue
            End If
          End If

          Item = lcPod.AppendItem(podFeeds[path], episode)

          If image <> "" Then lcPod.SetItemColText(Item, 5, image)
          lcPod.SetItemColText(Item, 1, duration)
          If podDateTime <> Nothing Then lcPod.SetItemColText(Item, 3, podDatetime.FormatISODate() &" " &podDatetime.FormatISOTime()) '("%d.%m.%y %H:%M:%S"))
          lcPod.SetItemColText(Item, 4, fileUrl)
          podText[fileUrl]= Trim(content)

          'append the url to the podcast database
          url2DB(path, fileUrl)

          podDatetime = wxDateTimeEmpty()
          episode = ""
          duration = ""
          content = ""
          fileUrl = ""
          image = ""
          Deallocate(Item)
          Item = Nothing

          i += 1
        End If
      End Select

      Deallocate(nd)
      nd = nd.GetNext()
    Wend

    xmlData = Nothing

    isbroken = FALSE
    dbp.Close()
  End If

  ~nolog
End Sub


'cannot create the htmlparser in wxbasic
'so source code is searched directly
Sub readHTML(buffer As String, path As String, counter)
  Dim bufferL = LCase(buffer)
  Dim fileUrl As String = ""
  Dim url As String = ""
  Dim at As Integer
  Dim at1 As Integer
  Dim Item As wxTreeListItem
  Dim title As String = ""
  Dim genre As String = ""
  Dim description As String = ""
  Dim image As String = ""
  Dim buffer1 As String = ""
  Dim buffer1L As String = ""
  Dim cnt As Integer = 1
  Dim cdate As String = ""
  Dim podDatetime As wxDateTime
  Dim imgUrl As wxFileName = wxFileName("")
  Dim s As String
  Dim heard As Integer
  dbp = wxDbConnection("DBQ=podcasts.db;DefaultDir=.;Driver=SQLITE3;")

  at = InStr(bufferL, "html_tag_start")
  'html with embedded html tags
  'find the main title and desctiption
  If at Then
    at1 = InStr(at, bufferL, "html_tag_end")
    'hold the buffer, work with an abridged text
    buffer1 = buffer[at + 14: at1]
    buffer1L = LCase(buffer1)

    'shorten the buffer from the end of the html tag
    buffer = buffer[at1: ]

    'search for the podcast title
    at = InStr(buffer1L, Chr(34) &"name" &Chr(34))
    If at Then
      title = buffer1[at + 7: InStr(at, buffer1, ",") - 1]
      title = wordbetween(title, Chr(34), Chr(34))
      s = wxString_FromUTF8(title)
      title = IIf(s = "", title, s)

      If title = "" Then
        delCurPodcast(_("Cannot read the podcast!"), podFeeds[path])
        Return
      End If

      lcPod.SetItemText(podFeeds[path], title)
    End If

    'search for the genre
    at = InStr(buffer1L, Chr(34) &"genre" &Chr(34))
    If at Then
      genre = buffer1[at + 8: InStr(at, buffer1, ",") - 1]
      genre = wordbetween(genre, Chr(34), Chr(34))
      lcPod.SetItemColText(podFeeds[path], 5, image)
    End If

    'search for the image
    at = InStr(buffer1L, Chr(34) &"image" &Chr(34))
    If at Then
      image = checkImageUrl(buffer1[at + 8: InStr(at, buffer1, ",") - 1])
      lcPod.SetItemColText(podFeeds[path], 5, image)
    End If

    'search for the podcast description
    at = InStr(buffer1L, Chr(34) &"description" &Chr(34))
    If at Then podText[path] = checkDescription(buffer1[at + 13: InStr(at + 13, buffer1, Chr(34) &",") - 1])

    'find the episodes begin and shorten the buffer
    buffer = buffer[InStr(buffer, "[{"): ]
    buffer = removeSpecialChars(buffer)
    bufferL = LCase(buffer)

    'show for episodes
    'search for the stream url
    at = InStr(bufferL, Chr(34) &"streamurl" &Chr(34))
    While at
      cdate = ""
  
      If (counter > 0) And (cnt = counter) Then isBroken = TRUE

      If isBroken Then
        isBroken = FALSE
        Break
      End If

      url = buffer[at + 12: InStr(at, bufferL, ",") - 1]
      url = wordbetween(url, Chr(34), Chr(34))
      If Right(url, 12)= "?source=feed" Then url = Left(url, Len(url) - 12)

      heard  = FALSE
      If counter = -1 Then
        If dbp.IsOpen() Then heard = dbp.ExecSql("SELECT heard FROM podcasts where url=" &Chr(34) &fileurl &Chr(34) &" COLLATE NOCASE")
        If heard Then
          at = InStr(at + 1, bufferL, Chr(34) &"streamurl" &Chr(34))
          Continue
        End If
      End If

      'avoid duplicate urls
      If fileUrl <> url Then
        fileUrl = url
        url = ""
        Item = Nothing
      End If

      'the url is an mp3 or m4a
      If Right(fileUrl, 3)= "mp3" Or Right(fileUrl, 3)= "m4a" Then
        'find the episode title
        at1 = InStr(at, bufferL, Chr(34) &"title" &Chr(34))
        If at1 Then
          ptitle = buffer[at1 + 8: InStr(at1, buffer, ",") - 1]
          ptitle = wxString_FromUTF8(wordbetween(ptitle, Chr(34), Chr(34)))
        End If

        s = wxString_FromUTF8(pTitle)
        pTitle = IIf(s = "", pTitle, s)

        episode = pTitle
        oldPTitle = pTitle

        'append the episode
        If (fileUrl <> url) Then Item = lcPod.AppendItem(podFeeds[path], pTitle)
        lcPod.SetItemColText(Item, 4, fileUrl)

        'search for the image
        at1 = InStr(at - 1, bufferL, Chr(34) &"image" &Chr(34))
        If at1 Then
          image = checkImageUrl(buffer[at1 + 8: InStr(at1, buffer, Chr(34) &"," &Chr(34))])
          lcPod.SetItemColText(Item, 5, image)
        End If

        url2DB(path, fileUrl)

        'find the release date
        at1 = InStr(at, bufferL, Chr(34) &"releasedate" &Chr(34))
        If at1 Then
          cdate = buffer[at1 + 14: InStr(at1, buffer, ",") - 1]
          cdate = wordbetween(cdate, Chr(34), Chr(34))

          podDatetime = wxDateTime_wxDateTime() 

          If InStr(cdate, " ") Then
            podDatetime.ParseDateTime(cdate)
          Else
            podDatetime.ParseISOCombined(cdate)
          End If
          'append the date to the item
          If Item Then lcPod.SetItemColText(Item, 3, podDatetime.FormatISODate() &" " &podDatetime.FormatISOTime())

          podDateTime = Nothing
        End If
        
        'find the episode description
        at1 = RInstr(at - 1, bufferL, Chr(34) &"summary" &Chr(34))
        If at1 Then podText[fileUrl] = checkDescription(buffer[at1 + 10: InStr(at1 + 11, buffer, Chr(34))])

        at1 = RInstr(at - 1, bufferL, Chr(34) &"duration" &Chr(34))
        If at1 Then lcPod.SetItemColText(Item, 1, getTimeFromSec(buffer[at1 + 11: InStr(at1 + 1, buffer, ",") - 1], FALSE))

        If cnt %100 = 0 Then wxYield()
        cnt += 1
      End If

      at = InStr(at + 1, bufferL, Chr(34) &"streamurl" &Chr(34))
    Wend
    lcPod.SetItemText(podFeeds[path], title)

  Else

    Dim cName, cloud As String = ""
    For i = 1 To 11
      Select Case i
      Case 1: cName = "mixcloud.com": cloud = "Mixcloud"
      Case 2: cName = "soundcloud.com": cloud = "SoundCloud"
      Case 3: cName = "spotify.com": cloud = "Spotify"
      Case 4: cName = "apple-music": cloud = "Apple Music"
      Case 5: cName = "music.amazon": cloud = "Amazon Music"
      Case 6: cName = "music.youtube.com": cloud = "Youtube Music"
      Case 7: cName = "tidal.com": cloud = "Tidal"
      Case 8: cName = "qobuz.com": cloud = "Qobuz"
      Case 9: cName = "napster.com": cloud = "Napster"
      Case 10: cName = "plus.rtl": cloud = "RTL Plus"
      Case 11: cName = "deezer.com": cloud = "Deezer"
      End Select

      at = InStr(path, cname)
      If at Then
        Exit For
      Else
        cloud = ""
      End If
    Next

    If cloud <> "" Then
      delCurPodcast(_("This is a link from" &" " &cloud &"!") &"\n" &_("dsmPlayer cannot play tracks from" &" " &cloud &"."), podFeeds[path])
      Return
    End If

'    at  = InStr(buffer, "<script type=")
'    If !at Then
      at1 = InStr(bufferL, Chr(34) &"title" &Chr(34))
        
      If at1 Then
        title = removeSpecialChars(buffer[at1 + 8: InStr(at1, buffer, ",") - 1])
        title = wordbetween(title, Chr(34), Chr(34))
      End If

      If title = "" Then
        delCurPodcast(_("Cannot read the podcast!"), podFeeds[path])
        Return

      Else

        s = wxString_FromUTF8(title)
        title = IIf(s = "", title, s)
      End If


      'search for the genre
      at = InStr(bufferL, Chr(34) &"genre" &Chr(34))
      If at Then
        genre = wordbetween(buffer[at + 8: InStr(at, buffer, ",") - 1], Chr(34), Chr(34))
        lcPod.SetItemColText(podFeeds[path], 2, genre)
      End If

      'search for the podcast image
      at = InStr(bufferL, Chr(34) &"og:image" &Chr(34))
      If at Then
        image = checkImageUrl(buffer[at + 17: InStr(at, buffer, "/>" ) - 1])
        lcPod.SetItemColText(podFeeds[path], 5, image)

      Else

        at = InStr(bufferL, Chr(34) &"image" &Chr(34))
        If at Then
          image = checkImageUrl(buffer[at + 8: InStr(at, buffer, Chr(34) &"," &Chr(34))])
          lcPod.SetItemColText(podFeeds[path], 5, image)
        End If
      End If

      'search for the podcast description
      at = InStr(bufferL, Chr(34) &"description" &Chr(34))
      If at Then podText[path]= checkDescription(buffer[at + 13:  InStr(at + 30, buffer, Chr(34)) ])

      Dim oldFileUrl As String = ""
      Dim oldEpisode As String = ""
      Dim fn As wxFileName = wxFileName("")
      Dim text As String = ""

      'search for episodes
      at = InStr(bufferL, Chr(34) &"url" &Chr(34))
      While at
        If (counter > 0) And (cnt = counter) Then isBroken = TRUE

        If isBroken Then
          isBroken = FALSE
          Break
        End If

        fileUrl = buffer[at + 5: InStr(at, bufferL, ",") - 1]
        fileUrl = wordbetween(fileUrl, Chr(34), Chr(34))

        heard  = FALSE
        If counter = -1 Then
          If dbp.IsOpen() Then heard = dbp.ExecSql("SELECT heard FROM podcasts where url=" &Chr(34) &fileurl &Chr(34) &" COLLATE NOCASE")
          If heard Then
            at = InStr(at + 1, bufferL, Chr(34) &"url" &Chr(34))
            Continue
          End If
        End If

        If Right(fileUrl, 3)= "mp3" Or Right(fileUrl, 3)= "m4a" Then
          at1 = RInstr(at - 1, bufferL, Chr(34) &"cliptitle" &Chr(34))
          If at1 Then
            'add the episode
            text = checkDescription(buffer[at1 + 12: InStr(at1 + 1, bufferL, "{")])
            s = wxString_FromUTF8(text)
            episode = IIf(s = "", text, s)
          End If

          'omit duplicate entries
          fn.AssignPath(fileurl)
          If (oldFileUrl = fn.GetName()) Or (oldEpisode = episode) Then
            at = InStr(at + 1, bufferL, Chr(34) &"url" &Chr(34))
            Continue
          End If

          Item = lcPod.AppendItem(podFeeds[path], episode)
          lcPod.SetItemColText(Item, 4, fileUrl)

          'search for the episode image
          at1 = RInstr(at - 1, bufferL, Chr(34) &"image" &Chr(34))
          If at1 Then
            image = checkImageUrl(buffer[at1 + 8: InStr(at1, buffer, Chr(34) &"," &Chr(34))])
            lcPod.SetItemColText(Item, 5, image)
          End If

          url2DB(path, fileUrl)

          'find the episode description
          at1 = RInstr(at - 1, bufferL, Chr(34) &"summary" &Chr(34))
          If at1 Then
            text = checkDescription(buffer[at1 + 10: InStr(at1 + 11, buffer, Chr(34) &"," &Chr(34))])
            s = wxString_FromUTF8(text)
            description = IIf(s = "", text, s)
            podText[fileUrl]= description
          End If

          'find the episode duration
          at1 = RInstr(at - 1, bufferL, Chr(34) &"cliplength" &Chr(34))
          If at1 Then lcPod.SetItemColText(Item, 1, getTimeFromSec(wordbetween(buffer[at1 + 13: InStr(at1 + 1, buffer, "{")], Chr(34), Chr(34)), FALSE))

          'find the episode date
          at1 = RInstr(at - 1, bufferL, Chr(34) &"publishdate" &Chr(34))
          If at1 Then
            cdate = buffer[at1 + 14: InStr(at1, buffer, ",") - 1]
            cdate = wordbetween(cdate, Chr(34), Chr(34))

            podDatetime = wxDateTime_wxDateTime() 

            If InStr(cdate, " ") Then
              podDatetime.ParseDateTime(cdate)
            Else
              podDatetime.ParseISOCombined(cdate)
            End If

            'append the date to the item
            lcPod.SetItemColText(Item, 3, podDatetime.FormatISODate() &" " &podDatetime.FormatISOTime())

            podDateTime = Nothing
          End If

          oldFileUrl = fn.GetName()
          oldEpisode = episode

          If cnt %100 = 0 Then wxYield()
          cnt += 1

          Deallocate(Item)
          Item = Nothing
        End If

        at = InStr(at + 1, bufferL, Chr(34) &"url" &Chr(34))
      Wend

      lcPod.SetItemText(podFeeds[path], title)

'    Else
''      delCurPodcast(_("Cannot read the podcast!"), podFeeds[path])
'    End If
  End If

  dbp.Close()
  lcpod.Update()
  lcPod.Layout()
End Sub


Function checkDescription(text As String)
  Dim at = InStr(text, "/>")
  If at Then text = text[: at - 1]

  text = removeSpecialChars(text)
  text = wordbetween(text, Chr(34), Chr(34))

  Dim s As String = wxString_FromUTF8(text)

  Return IIf(s = "", text, s)
End Function


'check the image url
'some URLs have other information appended to the file name
Function checkImageUrl(url As String)
  Dim at = InStr(url, Chr(34) &":" &Chr(34))
  If at Then url = url[at + 2: ]

  at = InStr(url, "?")
  If at Then url = url[: at - 1] &Chr(34)

  at = InStr(url, "~")
  If at Then
    Dim fn As wxFileName = wxFileName(url)
    fn.AssignPath(url)
    url = url[: at - 1] &"." &fn.GetExt()
  End If

  url = wordbetween(url, Chr(34), Chr(34))

  'check if the begin of the url is valid
  Dim uri As wxURI = wxURI(url)
  If !(uri.HasScheme() And uri.HasPath()) Then url = ""

  Return url
End Function


Function removeSpecialChars(buffer As String)
  Dim at1 As Integer
  Dim buffer1 As String
  Dim s As wxString = wxString(buffer)

  'remove images
  Dim at As Integer = InStr(buffer, "<img ")
  While at
    at = InStr(at + 1, buffer, "/>")
    s.Replace(buffer[: at + 2 ] , "")
    buffer = s.GetData()

    at = InStr(buffer, "<img ")
  Wend

  'replace ASCII linebreak with html linebreak
  s.Replace(Chr(10), "<br>")

  'replace text linebreak with html linebreak
  s.Replace(Chr(92) &"n" , "<br>")

  'remove carriage return
  s.Replace(Chr(92) &"r" , "")

  'replace unichar character
  at = InStr(buffer, Chr(92) &"u")
  While at
    s.Replace(buffer[at - 1: InStr(at, buffer, " ")], "")
    buffer = s.GetData()
    at = InStr(at + 1, buffer, Chr(92) &"u")
  Wend

  'replace the abbreviation for a quotation mark with "'"
  s.Replace(Chr(92) &Chr(34) , "'")

  Return s.GetData()
End Function


'find a podcast item by url
'return the item or the previous item, if 'prev' is true
Function FindPodcAstItem(url As String, prev As Integer)
  Dim child As wxTreeListItem = lcpod.GetFirstItem()
  Dim nc As wxTreeListItem
  Dim oldnc As wxTreeListItem
  Dim fUrl As String

  While child.IsOk()
    nc = lcPod.GetFirstChild(child)

    While nc.IsOk()
      fUrl = lcpod.GetItemText(nc, 4)

      If fUrl = url Then Return IIf(prev, oldnc, nc)
      oldnc = nc

      Deallocate(nc)
      nc = lcpod.GetNextSibling(nc)
    Wend

    oldnc = nc
    Deallocate(child)
    child = lcPod.GetNextSibling(child)
  Wend

  Return Nothing
End Function


'check for internet connection
Function checkConnection()
  Dim http As wxHTTP = wxHTTP()
  If !http.Connect("www.google.com") Then
    Dim dlg = wxGenericMessageDialog(Nothing, _("There seems to be no internet connection."), _("Notice"), wxOK|wxCENTRE|wxICON_INFORMATION|wxDIALOG_NO_PARENT)
    dlg.ShowModal()
    ~dlg
    Return FALSE
  End If

  Return TRUE
End Function


'play a podcast
Sub podcAstPlay(Item As wxTreeListItem)
  If item and Item.IsOk() Then podUrl = lcpod.GetItemText(Item, 4)
  If podUrl = "" Then Return

  If phiolaPrc Then
    'currently we must kill phiola completely and restart it
    'so this command has no effect here
     If !phiolaPrc.Open(Chr(34) &phiolaPath &Chr(34) &" remote start " &Chr(34) &podUrl &Chr(34) &" -id " &wxGetProcessId()) Then
      readStream()
    End If

  Else

    Dim con As Integer = checkConnection()
    If !con Then Return
    Dim podcast As wxTreeListItem = findPodcastItem(podUrl, FALSE)
    Dim a = lcpod.GetItemParent(lcpod.GetItemParent(podcast))

    'if a is not ok, it is a child of the root item,
    'so it's a podcast adress and not an episode
    If !a.IsOk() Then
      Dim dlg = wxGenericMessageDialog(Nothing, _("This is not an episode to listen to"), _("Notice"), wxOK|wxCENTRE|wxICON_INFORMATION|wxDIALOG_NO_PARENT)
      dlg.ShowModal()
      ~dlg
      Return
    End If

    pTitle = lcPod.GetItemText(podcast, 0)
    podLen = getTimeFromString(lcPod.GetItemText(podcast, 1), FALSE, FALSE)
    podUrl = lcPod.GetItemText(podcast, 4)

    'start loading animation
    loadLinePos = 0
    If !loadingTimer.IsRunning() Then loadingTimer.Start(30)

    If podPos Then
      phiola("", podUrl, "-seek " &podPos  &" -vol " &IIf(muted, 0, volume) &" -connect_timeout " &timeout &" -recv_timeout " &timeout &" -remote_id " &wxGetProcessId())
    Else
      phiola("", podUrl, "-vol " &IIf(muted, 0, volume) &" -connect_timeout " &timeout &" -recv_timeout " &timeout &" -remote_id " &wxGetProcessId())
    End If
  End If
  wxYield()

  musicTaskMenu.Enable(ID_PLAY_MEDIA, FALSE)
  musicTaskMenu.Enable(ID_PAUSE_MEDIA, TRUE)
  musicTaskMenu.Enable(ID_STOP_MEDIA, TRUE)
  musicTaskMenu.Enable(ID_NEXT_MEDIA, TRUE)
  musicTaskMenu.Enable(ID_PREV_MEDIA, TRUE)
  musicTaskMenu.Enable(ID_MUTE_MEDIA, TRUE)

  If busyInfo Then ~busyInfo
  busyInfo = Nothing
End Sub


'show a menu for the selected podcast
Sub onPodMenu(event As wxTreeListEvent)
  'we will show the menu on the top item only
  Dim Item As wxTreeListItem = event.GetItem()
  Dim url As String = lcpod.GetItemText(Item, 4)
  Dim a = lcpod.GetItemParent(lcpod.GetItemParent(Item))
  Dim point = lcPod.ScreenToClientPoint(wxGetMousePosition())

  'if a is not ok, it is a child of the root item,
  'so it's a podcast, not an episode
  If !a.IsOk() Then
    If lcPod.GetCheckedState(Item) Then lcPod.PopupMenuPoint(podMenu, point)

  Else

    lcPod.PopupMenuPoint(podItemMenu, point)
  End If
End Sub


'draw the selected item background to ensure visibility
Sub onErasePodBack(event As wxEraseEvent)
  Dim dc = event.GetDC()
  If !dc Then dc = wxClientDC(lcPod)
  Dim Item As wxTreeListItem = lcpod.GetSelection()

  If Item.IsOk() Then
    dc.SetBrush(wxWHITE_BRUSH)
    dc.DrawRectangle(itemRect.GetX(), itemRect.GetY(), itemrect.GetWidth(), itemrect.GetHeight())
  End If
End Sub


'hold the selected item rect for drawing
Sub SetItemRect()
  Dim dv = lcPod.GetDataView()
  Dim sel = dv.GetSelection()
  itemRect = dv.GetItemRect(sel)
End Sub


'a podcast selection was changed
Sub onPodcastSelectionChanged(event As wxTreeListEvent)
  'prevent loading on item check
  setItemRect()

  Dim p As wxPoint = lcPod.ScreenToClientPoint(wxGetMousePosition())
  If (itemRect.GetX()+ (20 / Scale))> p.GetX() Then
    event.Veto()
    Return
  End If
  itemrect.SetX(0)
  itemrect.SetWidth(lcPod.GetClientSizeWidth())

  'get the item
  Dim Item As wxTreeListItem = event.GetItem()
  Dim url As String = lcpod.GetItemText(Item, 4)
  Dim active As String = TRUE
  
  Dim a = lcpod.GetItemParent(lcpod.GetItemParent(event.GetItem()))
  'if a is not ok, it is a child of the root item,
  'so it's a podcast adress and not an episode
  If !a.IsOk() Then active = lcPod.GetCheckedState(Item)

  'only podcasts may be deleted, not episodes
  Dim win = wxFindWindowByName("deleteweb")
  If win Then win.Enable( !a.IsOk())
  win = wxFindWindowByName("editweb")
  If win Then win.Enable( !a.IsOk())

  dbp = wxDbConnection("DBQ=podcasts.db;DefaultDir=.;Driver=SQLITE3;")
  If dbp.IsOpen() Then
    Dim heard As Integer = FALSE
    Dim murl As String = dbp.ExecSql("SELECT mainurl FROM podcasts where url=" &Chr(34) &url &Chr(34) &" COLLATE NOCASE")
    If murl <> "" Then
      heard = dbp.ExecSql("SELECT heard FROM podcasts where url=" &Chr(34) &url &Chr(34) &" COLLATE NOCASE")
      podItemMenu.Check(ID_SET_HEARD, heard)
    End If
    dbp.Close()
  End If

  'delete temporary image file from old podcast, if exist
  If wxFileExists(wxFileName_GetTempDir() &DELIMITER_CHAR &"image.png") Then Kill(wxFileName_GetTempDir() &DELIMITER_CHAR &"image.png")

'  we can also display the podcast info only if the context menu is not displayed
'  Dim state = wxGetMouseState()
'  If !state.RightIsDown() Then 
  setPodcastInfo(url, active)
  lcpod.refresh()
End Sub


Sub setPodcastInfo(url As String, IsActive As Integer)
  Dim Item As wxTreeListItem = lcPod.GetSelection()
  Dim path As String = lcPod.GetItemText(Item, 5)
  Dim image As wxImage = wxEmptyImage()

  'load the image to max 250 pixels
  'the image is automatically adjusted in proportion
  image.SetOptionInt(wxIMAGE_OPTION_MAX_WIDTH, 250)
  image.SetOptionInt(wxIMAGE_OPTION_MAX_HEIGHT, 250)
  Dim noLog = wxLogNull()

  Dim fn As wxFileName = wxFileName(path)
  Dim ext = fn.GetExt()
  Dim Type As Integer = GetBitmapType(path)
  
  Dim opt As String = IIf(Val(lcPod.GetItemText(Item, 7)), "", "--no-check-certificate ")

  If IsActive Then
    'can not load png from stream, why?
    'so we must save the file temporary and read it from this
    'some PNG files are actually JPG files
    If (ext = "png") Or (Type = -1) Then
      Dim prc = New wxProcessWithFlags(wxPROCESS_REDIRECT)
      Connect(prc, wxEVT_END_PROCESS, "onEndDownloadImageProcess")

      'download the image to the tmp directory
      'handle it after the process has ended
      Dim pid As Integer = wxExecute(Chr(34) &wgetPath &Chr(34) &" -qO " &wxFileName_GetTempDir() &DELIMITER_CHAR &"image " &opt &path, wxEXEC_ASYNC, prc)

    Else

      prc = New wxProcessWithFlags(wxPROCESS_REDIRECT)
      Connect(prc, wxEVT_END_PROCESS, "onEndInfoProcess")

      pid = wxExecute(Chr(34) &wgetPath &Chr(34) &" -qO- " &opt &path, wxEXEC_ASYNC, prc)
      If pid Then
        'read the stream from the process
        Dim inStream As wxInputStream = prc.GetInputStream()
        If inStream And inStream.IsOk() Then image.LoadStreamFile(inStream, Type)'wxBITMAP_TYPE_ANY)
      End If

      'set the info
      SetInfo(image, Type, TRUE)
    End If

  Else

      SetInfo(image, Type, FALSE)
  End If

  ~noLog
End Sub


'the download process has ended
Sub onEndDownloadImageProcess(event As wxProcessEvent)
  Dim noLog = wxLogNull()
  Dim image As wxImage = wxEmptyImage()
  Dim Type As Integer = wxBITMAP_TYPE_JPEG

  'load the image to max 250 pixels
  'the image is automatically adjusted in proportion
  image.SetOptionInt(wxIMAGE_OPTION_MAX_WIDTH, 250)
  image.SetOptionInt(wxIMAGE_OPTION_MAX_HEIGHT, 250)

  If wxFileExists(wxFileName_GetTempDir() &DELIMITER_CHAR &"image") Then
    Dim file As wxFileInputStream = wxFileInputStream(wxFileName_GetTempDir() &DELIMITER_CHAR &"image")
    Dim buffer = ""
    Dim b = ""

    'read 100 bytes of the file
    If file.Ok() Then
      For i = 1 To 1200
        b = file.Read(1)
        If (Asc(b) > 31) And (Asc(b) < 255) Then buffer &= b
      Next
    End If

    'check the buffer for filetype information
    'it would be easier to use wxBITMAP_TYPE_ANY, but we need the correct filetype for wxMemoryFSHandler

    If InStr(buffer, "JFIF") Then
      Type = wxBITMAP_TYPE_JPEG

    Elseif InStr(buffer, "PNG") Then
      Type = wxBITMAP_TYPE_PNG

    Elseif InStr(buffer, "GIF") Then
      Type = wxBITMAP_TYPE_GIF

    Elseif InStr(buffer, "BM") Then
      Type = wxBITMAP_TYPE_BMP

    End If
    ~file

    image.LoadFile(wxFileName_GetTempDir() &DELIMITER_CHAR &"image", Type)
  End If

  SetInfo(image, Type, TRUE)
  ~noLog
End Sub


Sub SetInfo(image As wxImage, Type As Integer, active As Integer)
  Dim Item As wxTreeListItem = lcpod.GetSelection()
  Dim url = lcPod.GetItemText(Item, 4)

  If image.IsOk() Then
    If Type = -1 Then Type = wxBITMAP_TYPE_JPEG
    wxMemoryFSHandler_AddImageFile(Chr(34) &"image" &Chr(34), image, Type)
  End If
  
  Dim content As String = ""
  If active Then content = IIf(podText[url]= Nothing, "", podText[url])
  Dim htmlWin As wxHtmlWindow = DynamicCast("wxHtmlWindow", musicFrame.FindWindowByName("htmlwin"))

  'refresh the HTML window from memory
  Dim page = "<!DOCTYPE html><html><head>" &
  "<meta charset=" &Chr(34) &"UTF-8" &Chr(34) &">" &
  "<body bgcolor=" &"RGB(" &musicBackcolour.Red() &"," &musicBackcolour.Green() &"," &musicBackcolour.Blue() &")>" &
  "<font COLOR=" &"RGB(" &musicFontcolour.Red() &"," &musicFontcolour.Green() &"," &musicFontcolour.Blue() &")>" &
  IIf(image.IsOk(), 
  "<div align=" &Chr(34) &"center" &Chr(34) &">" &
  "<img src=memory:" &Chr(34) &"image" &Chr(34) &">" &
  "</div>", "") &"<br><br>" &content &"</body></head></html>"

  wxMemoryFSHandler_AddFile("test.html", page)
  htmlWin.SetPage(page)
  htmlWin.Refresh()

  wxMemoryFSHandler_RemoveFile("test.html")
  If image.IsOk() Then wxMemoryFSHandler_RemoveFile(Chr(34) &"image" &Chr(34))
  
  'delete temoprary file, if exists
  If wxFileExists(wxFileName_GetTempDir() &DELIMITER_CHAR &"image") Then Kill(wxFileName_GetTempDir() &DELIMITER_CHAR &"image")
  
  If busyInfo Then
    ~busyInfo
    busyInfo = Nothing
  End If
End Sub


'load url from treelistctrl
Sub onPodcastItemActivated(event As wxTreeListEvent)' Handles lcPod.treelistitemactivated
  Dim a = lcpod.GetItemParent(lcpod.GetItemParent(event.GetItem()))
  'if a is not ok, it is a child of the root item,
  'so it's a podcast adress and not an episode
  If !a.IsOk() Then Return

	'get the index from the new selected item
	timerMedia.Stop()
	rects["mPos"].SetX(rects["mSlider"].GetX() - 5)
	musicFrame.RefreshRect(rects["mSlider"])

  Dim podItem = event.GetItem()
	podPos = 0
  podUrl = lcPod.GetItemText(podItem, 4)
	podLen = getTimeFromString(lcPod.GetItemText(podItem, 1), FALSE, FALSE)

	'remote start -seek is not implemented yet
	'so we must kill phiola and start it again
	If phiolaPrc Then
		killphiola()

	Else

		podcastPlay(podItem)
	End If
End Sub


'a podcast is checked/unchecked
Sub onPodcastItemChecked(event As wxTreeListEvent)
  'get the item
  Dim Item As wxTreeListItem = event.GetItem()

  'if a is not ok, it is a child of the root item,
  'so it's a podcast adress and not an episode
  Dim a = lcpod.GetItemParent(lcpod.GetItemParent(Item))
  If !a.IsOk() Then
    If podFeeds[lcPod.GetItemText(Item, 4)] = Nothing Then Return
    Dim url As String = lcPod.GetItemText(Item, 4)
    Dim episode As String
    Dim active As Integer = lcPod.GetCheckedState(Item)

    'write the active flag to the database
    dbp = wxDbConnection("DBQ=IPTV.db;DefaultDir=.;Driver=SQLITE3;")
    If dbp.IsOpen() Then dbp.ExecSql("UPDATE podcast SET active=" &active &" WHERE adress =" &Chr(34) &url &Chr(34))

    Disconnect(lcPod, wxEVT_TREELIST_SELECTION_CHANGED)
    If !active Then
      podText[url]= ""
      setPodcastInfo(url, FALSE)

      Item = lcPod.GetFirstChild(podFeeds[url])
      While Item.IsOk()
        episode = lcPod.GetItemText(Item, 4)
        'if the episode is played then stop playing
        If episode = podUrl Then
          If isPlayed Then stopmedia()
          podlen = 0
          podPos = 0
          podUrl = ""
        End If

        'remove description
        podText.Remove(episode)

        'delete the item
        lcPod.DeleteItem(Item)

        'get the next item
        Item = lcPod.GetFirstChild(podFeeds[url])
      Wend
      Connect(lcPod, -1, wxEVT_TREELIST_SELECTION_CHANGED, "onPodcastSelectionChanged")

    Else

      readUrl(url)
      If dbc.IsOpen() Then dbc.Close()

      setPodcastInfo(url, TRUE)
    End If
  End If
End Sub


Sub onPodcastDownload(event As wxCommandEvent)
  Dim Item As wxTreeListItem = lcPod.GetSelection()
  Dim url As String = lcPod.GetItemText(Item, 4)

  'add the episode url to the arraystring
  podcastDL.Add(url)

  Dim path As String = recordPathPod &DELIMITER_CHAR &lcPod.GetItemText(lcpod.GetItemParent(Item))
  createDownloadDialog(path)
End Sub


'downloas all podcasts is selected
Sub onPodcastDownloadAll(event As wxCommandEvent)
  Dim child As wxTreeListItem = lcPod.GetFirstChild(lcPod.GetSelection())
  While child.IsOk()
    podCastDl.Add(lcpod.GetItemText(child, 4))
    lcPod.UncheckItem(child)

    Deallocate(child)
    child = lcPod.GetNextSibling(child)
  Wend

  'create the download dialog
   Dim path As String = recordPathPod &DELIMITER_CHAR &lcPod.GetItemText(lcPod.GetSelection())
   createDownloadDialog(path)
End Sub


'download checked poscasts ist selected
Sub onPodcastDownloadChecked(event As wxCommandEvent)
  Dim child As wxTreeListItem = lcPod.GetFirstChild(lcPod.GetSelection())
  While child.IsOk()
    If lcPod.GetCheckedState(child) Then podCastDl.Add(lcpod.GetItemText(child, 4))
    lcPod.UncheckItem(child)

    Deallocate(child)
    child = lcPod.GetNextSibling(child)
  Wend

  'create the download dialog
  Dim path As String = recordPathPod &DELIMITER_CHAR &lcPod.GetItemText(lcPod.GetSelection())
  createDownloadDialog(path)
End Sub


'create the download dialog
Sub createDownloadDialog(path As String)
  updDialog = wxDialog(musicFrame, -1, "", wxDefaultPosition, wxSize(600, 150), wxCAPTION|wxSYSTEM_MENU|wxMINIMIZE_BOX|wxCLOSE_BOX|wxRESIZE_BORDER|wxCENTER)
  updDialog.SetName(path)
  Dim textFile As wxStaticText = wxStaticText(updDialog, -1, _("File"))
  textFile.SetName("textFile")
  'wxST_ELLIPSIZE_END = 16
  textFile.SetWindowStyle(16)
  Dim gaugeFile As wxGauge = wxGauge(updDialog, -1, podcastDl.Count(), wxDefaultPosition, wxDefaultSize, wxGA_SMOOTH)
  gaugeFile.SetName("gaugeFile")
  Dim gaugePos As wxGauge = wxGauge(updDialog, -1, 0, wxDefaultPosition, wxDefaultSize, wxGA_SMOOTH)
  gaugePos.SetName("gaugePos")
  Dim cb As wxButton = wxButton(updDialog, -1, _("Cancel"), wxPoint(0, updDialog.GetSizeHeight() - 30), wxSize(updDialog.GetSizeWidth(), 25))
  Connect(updDialog, -1, wxEVT_CLOSE_WINDOW, "onCloseUpdDialog")
  Connect(cb, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onDownloadCancel")

  Dim boxsizerV As wxBoxSizer = wxBoxSizer(wxVERTICAL)
  Dim boxsizerH As wxBoxSizer = wxBoxSizer(wxHORIZONTAL)
  boxsizerV.AddSpacer(10)
  boxsizerV.AddWindow(textFile, 0, wxLEFT)
  boxsizerV.AddSpacer(5)
  boxsizerV.AddWindow(gaugeFile, 0, wxGROW)
  boxsizerV.AddSpacer(5)
  boxsizerV.AddWindow(gaugePos, 0, wxGROW)
  boxsizerV.AddSpacer(10)
  boxsizerV.AddWindow(cb, 0, wxGROW)
  boxsizerV.AddSpacer(10)
  boxSizerH.AddSpacer(10)
  boxSizerH.AddSizer(boxSizerV, 1, 0)
  boxSizerH.AddSpacer(10)
  
  updDialog.SetAutoLayout(TRUE)
  updDialog.SetSizer(boxSizerH)
  upddialog.Refresh()
  updDialog.Show(TRUE)

  'create the timer for getting download informations from wget
  wgetTimer = New wxTimer(musicFrame, ID_TIMER_WGET)
  Connect(musicFrame, ID_TIMER_WGET, wxEVT_TIMER, "onWgetTimer")
  wgetTimer.Start(300)

  'download the episodes
  If podcastDl.Count() Then podcastDownload(path)
End Sub


'download episodes
Sub podcastDownload(path As String)
  Dim FileName As wxFileName = wxFileName(path &DELIMITER_CHAR)
  If !FileName.DirExists() Then FileName.MkDir(0777, wxPATH_MKDIR_FULL)

  wgetPrc = wxProcess(musicFrame, -1)
  wgetPrc.Redirect()
  Connect(wgetPrc, -1, wxEVT_END_PROCESS, "onEndDownloadPodcast")

  Dim url As String = podcastDl.Item(0)
  Dim Item As wxTreeListItem = findPodcastItem(url, FALSE)
  FileName.AssignPath(url)

  'create a filename from the podcast title
  Dim ftext As String = lcPod.GetItemText(Item, 0)
  'remove text before ":" to avoid errors
  Dim at = InStr(ftext, ":")
  If at Then ftext = Trim(ftext[at + 1: ])
  ftext = Replace(ftext, "/", "_")
  ftext = Replace(ftext, "#", "")
 'wget automitically remove quotation marks- CHR(34)

  Dim fn As String = path &DELIMITER_CHAR &ftext &"." &FileName.GetExt()
  Dim st As wxStaticText = DynamicCast("wxStaticText", musicFrame.FindWindowByName("textFile"))
  Dim gF As wxGauge = DynamicCast("wxGauge", musicFrame.FindWindowByName("gaugeFile"))
  Dim cnt As Integer = gf.GetRange() - podcastDL.Count()+ 1
  st.SetLabel("(" &_("File") &" " &cnt &"/" &gf.GetRange() &") " &wxFileNameFromPath(fn))
  gf.SetValue(cnt)
  gf.Update()

  Dim pid = wxExecute(Chr(34) &wgetPath &Chr(34) &" --timeout=15 --no-check-certificate " &url &" -O " &Chr(34) &fn &Chr(34), wxEXEC_ASYNC, wgetPrc)
  If !pid Then
    ~wgetPrc
    wgetPrc = Nothing
  End If
End Sub


Sub onWgetTimer(event As wxTimerEvent)
  If wgetPrc And wgetPrc.IsInputOpened() Then
    Dim inStream As wxInputStream = wgetPrc.GetInputStream()
    Dim errStream As wxInputStream = wgetPrc.GetErrorStream()

    'read the input and error streams
    While wgetPrc.IsInputAvailable()
      instream.Read(1)
    Wend

    'wget write download progress to stderr
    Dim err As String = ""
    While wgetPrc.IsErrorAvailable()
      err &= errStream.Read(1)
    Wend

    Dim gp As wxGauge = DynamicCast("wxGauge", musicFrame.FindWindowByName("gaugePos"))
    Dim at As Integer = InStr(err, "Length:")
    If at Then
      'Byte to MB conversion
      Dim podSize As Integer = Val(err[at + 8: InStr(at + 8, err, " ")])* 0.00000095367432
      gp.SetRange(podSize)
    End If

    Dim pos As Integer = -1
    at = InStr(err, "K ...")
    If at Then
      Dim lText As String = Trim(err[RInstr(at, err, "\n"): at])
      'KB to MB conversion
      If Right(lText, 1)= "K" Then pos = lText[: Len(lText) - 1]* 0.0009765625
    End If

    If pos > 0 Then
      gp.SetValue(pos)
      gp.Update()
    End If
  End If
End Sub


Sub onEndDownloadPodcast(event As wxProcessEvent)
  Dim exitcode As Integer = event.GetExitCode()
  'exitcode = -1 the download has broken
  'nothing to handle here

  Dim inStream As wxInputStream = wgetPrc.GetInputStream()
  Dim errStream As wxInputStream = wgetPrc.GetErrorStream()


  'exitcode = 0 wget ended normally
  If exitcode = 0 Then
    Dim gp As wxGauge = DynamicCast("wxGauge", musicFrame.FindWindowByName("gaugePos"))
    gp.SetValue(gp.GetRange())
    gp.Update()
  
  'exitcode > 0 wget return an error
  '8 = wrong adress
  Elseif exitcode > 0 Then
    'read the input and error streams
    While wgetPrc.IsInputAvailable()
      instream.Read(1)
    Wend

    'wget write download progress to stderr
    Dim err As String = ""
    While wgetPrc.IsErrorAvailable()
      err &= errStream.Read(1)
    Wend

    Dim message As String = _("The file could not be downloaded.")
    Dim at As Integer
    at = InStr(LCase(err), "error")
    If at Then message &= "\n" &Trim(err[at - 1: ])
    Dim col As wxColour = wxColour(255, 128, 128)
    
    Dim p = lcPod.ScreenToClientPoint(wxGetMousePosition())
    'use wxRichToolTip for end download message
    Dim rt = wxRichToolTip(_("Note"), message)
    rt.SetBackgroundColour(col)
    rt.SetStandardIcon()
    rt.SetTipKind(wxTipKind_Auto)
    rt.SetTimeout(5000)
    rt.ShowFor(musicFrame, wxRect(p.GetX(), p.GetY(), 100, 100))
  End If
  
  wgetPrc = Nothing

  podcastDl.RemoveAt(0)
  If podcastDl.Count() Then
    podcastDownload(updDialog.GetName())

  Else

    If updDialog Then updDialog.Close(TRUE)
  End If
End Sub


Sub onDownloadCancel(event As wxCommandEvent)
  updDialog.Close(TRUE)
End Sub


Sub onCloseUpdDialog(event As wxCloseEvent)
  If wgetTimer Then
    wgetTimer.Stop()
    ~wgetTimer
    wgetTimer = Nothing
  End If

  podcastDl.Clear()
  updDialog.Destroy()
  updDialog = Nothing
  If wgetPrc Then wxProcess_Kill(wgetPrc.GetPid(), wxSIGKILL)
  wxSafeYield(musicFrame)
End Sub


Sub onPodcastSelectAll(event As wxCommandEvent)
  Dim child As wxTreeListItem = lcPod.GetFirstChild(lcPod.GetSelection())
  While child.IsOk()
    lcPod.CheckItem(child)
    Deallocate(child)
    child = lcPod.GetNextSibling(child)
  Wend
End Sub


'reload the podcast and set all episodes to unheard
Sub onPodcastReload(event As wxCommandEvent)
  'store the selection state
  Dim selItem As wxTreeListItem = lcPod.GetSelection()
  'no url set, nothing to load
  If podFeeds[lcPod.GetItemText(selItem, 4)] = Nothing Then Return
  Dim IsExpanded As Integer = lcPod.IsExpanded(selItem)
  Dim url As String = lcPod.GetItemText(selItem, 4)
  Dim episode As String

  'delete episodes
  Dim Item = lcPod.GetFirstChild(podFeeds[url])
  While Item.IsOk()
    episode = lcPod.GetItemText(Item, 4)

    'if the episode is played then stop playing
    If episode = podUrl Then
      If isPlayed Then stopmedia()
      podlen = 0
      podPos = 0
      podUrl = ""
    End If

    'remove description
    podText.Remove(episode)

    'delete the item
    lcPod.DeleteItem(Item)

    'get the next item
    Item = lcPod.GetFirstChild(podFeeds[url])
  Wend

  readUrl(url)
  If IsExpanded Then lcPod.Expand(selItem)
End Sub


Sub onPodSetMax(event As wxCommandEvent)
  Dim sd = wxDialog(musicFrame, -1, _("Show episodes"))
  Dim selItem As wxTreeListItem = lcPod.GetSelection()
  Dim url As String = lcPod.GetItemText(selItem, 4)
  Dim counter As Integer = lcPod.GetItemText(selItem, 6)

  Dim sBox As wxStaticBox = wxStaticBox(sd, -1, _("Set episodes to display:"))
  Dim gb As wxGridBagSizer = wxGridBagSizer(10, 10)

  Dim rb1 As wxRadioButton = wxRadioButton(sBox, -1, _("All available"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP)
  gb.AddWindow(rb1, wxGBPosition(1, 1), wxDefaultSpan, 0|wxALIGN_CENTER_VERTICAL, 10)
  Dim rb2 As wxRadioButton = wxRadioButton(sBox, -1, _("Only the last"))
  gb.AddWindow(rb2, wxGBPosition(2, 1), wxDefaultSpan, 0|wxALIGN_CENTER_VERTICAL, 10)
  Dim maxPods = wxSpinCtrl(sBox, -1, IIf(counter > 0, counter, 10), wxDefaultPosition, wxSize(80, 25), wxSP_ARROW_KEYS, 0, 100)
  gb.AddWindow(maxPods, wxGBPosition(2, 2), wxDefaultSpan, 0|wxALIGN_CENTER_VERTICAL, 10)
  Dim rb3 As wxRadioButton = wxRadioButton(sBox, -1, _("Only unheard"))
  gb.AddWindow(rb3, wxGBPosition(3, 1), wxDefaultSpan, 0|wxALIGN_CENTER_VERTICAL, 10)
  gb.AddSpacer(5, 10, wxGBPosition(4, 1))
  gb.AddSpacer(10, 10, wxGBPosition(4, 3))
  gb.AddGrowableCol(2, 1)

  If counter > 0 Then
    rb2.SetValue(TRUE)
  Elseif counter = -1 Then
    rb3.SetValue(TRUE)
  End If

  sbox.SetAutoLayout(TRUE)
  sBox.SetSizerAndFit(gb)

  Dim bx As wxBoxSizer = wxBoxSizer(wxHORIZONTAL)
  Dim buttonOK = wxButton(sd, wxID_OK, _("Ok"))
  Dim buttonCancel = wxButton(sd, wxID_CANCEL, _("Cancel"))
  bx.AddWindow(buttonOk, 1, 0)
  bx.AddWindow(buttonCancel, 1, 0)

  Dim gb1 As wxGridBagSizer = wxGridBagSizer()
  gb1.AddSpacer(2, 2, wxGBPosition(1, 1))
  gb1.AddWindow(sbox, wxGBPosition(2, 2), wxDefaultSpan, wxEXPAND|wxALL)
  gb1.AddSizer(bx, wxGBPosition(3, 2), wxDefaultSpan, wxEXPAND)
  gb1.AddSpacer(10, 5, wxGBPosition(4, 3))

  sd.SetAutoLayout(TRUE)
  sd.SetSizerAndFit(gb1)

  If sd.ShowModal()= wxID_OK Then

    If rb1.GetValue() Then
      'all
      counter = 0

    Elseif rb2.GetValue() Then
      'by counter
      counter = maxPods.GetValue()

    Else
      'not heard
      counter = -1
    End If

    dbc = wxDbConnection("DBQ=IPTV.db;DefaultDir=.;Driver=SQLITE3;")
    If dbc.IsOpen() Then
      dbc.ExecSql("UPDATE podcast SET counter=" &counter &" WHERE adress =" &Chr(34) &url &Chr(34))
      dbc.Close()
    End If
    lcPod.SetItemColText(selItem, 6, counter)

    Dim isExpand = lcPod.IsExpanded(selItem)
    Disconnect(lcPod, wxEVT_TREELIST_SELECTION_CHANGED)

    lcpod.Freeze()
    Dim cnt As Integer = 1
    
    'delete all children
    'wxTreeListCtrl.DeleteChildren(item) is not implemented
    Dim Item = lcPod.GetFirstChild(selItem)
    While Item.IsOk()
      podText[lcPod.GetItemText(Item, 4)]= Nothing
      lcPod.DeleteItem(Item)
      Item = lcPod.GetFirstChild(selItem)
    Wend

    'read the podcast again
    readUrl(url)

    If isExpand Then lcPod.Expand(selItem)

    lcpod.Thaw()

    Connect(lcPod, -1, wxEVT_TREELIST_SELECTION_CHANGED, "onPodcastSelectionChanged")
  End If

  sd.Destroy()
End Sub


Sub removeHeard(url As String)
  Dim Item As wxTreeItemId = findPodcastItem(url, FALSE)
  Dim counter As Integer = lcPod.GetItemText(Item, 6)

  If counter = -1 Then
    Dim heard As Integer = FALSE
    Dim child As wxTreeListItem = lcpod.GetFirstItem()
    Dim nc As wxTreeListItem
    Dim fUrl As String
    dbp = wxDbConnection("DBQ=podcasts.db;DefaultDir=.;Driver=SQLITE3;")

    While child.IsOk()
      If lcpod.GetItemText(child, 4)= url Then
        nc = lcPod.GetFirstChild(child)
        While nc.IsOk()
          heard = FALSE
          fUrl = lcpod.GetItemText(nc, 4)
          If dbp.IsOpen() Then heard = dbp.ExecSql("SELECT heard FROM podcasts where url=" &Chr(34) &furl &Chr(34) &" COLLATE NOCASE")
          If heard Then lcPod.DeleteItem(nc)

          Deallocate(nc)
          nc = lcpod.GetNextSibling(nc)
        Wend
      End If

      Deallocate(child)
      child = lcPod.GetNextSibling(child)
    Wend


    dbp.Close()
  End If
End Sub


Sub onPodcastHeard(event As wxCommandEvent)
  setEpisodeHeard(event.IsChecked(), lcPod.GetSelection())
End Sub

Sub SetEpisodeHeard(heard As Integer, Item As wxTreeListItem)
  Dim url As String = lcPod.GetItemText(Item, 4)

  dbp = wxDbConnection("DBQ=podcasts.db;DefaultDir=.;Driver=SQLITE3;")
  dbp.ExecSql("SET CHARACTER_SET 'utf8'")
  If dbp.IsOpen() Then
    dbp.ExecSql("UPDATE podcasts SET heard=" &heard &" WHERE url=" &Chr(34) &url &Chr(34))
    dbp.Close()
  End If

  Dim urle As String = lcPod.GetItemText(lcPod.GetItemParent(Item), 4)
  Dim counter As Integer = lcPod.GetItemText(lcPod.GetItemParent(Item), 6)

  If counter = -1 Then
    podText[urle]= Nothing
    lcPod.DeleteItem(Item)
  End If
End Sub


Sub onPodHeardChecked(event As wxCommandEvent)
  Dim heard As Integer = (event.GetID()= ID_SET_HEARD_SEL)
  Dim Item As wxTreeListItem = lcPod.GetSelection()
  Dim url As String = lcpod.GetItemText(Item, 4)
  Dim urle As String = ""
  Dim counter As Integer = lcPod.GetItemText(Item, 6)

  dbp = wxDbConnection("DBQ=podcasts.db;DefaultDir=.;Driver=SQLITE3;")
  dbp.ExecSql("SET CHARACTER_SET 'utf8'")

  If dbp.IsOpen() Then
    lcPod.Freeze()
    dbp.BeginTransaction()
    
    Dim child As wxTreeListItem = lcPod.GetFirstChild(lcPod.GetSelection())
    Dim nextChild As wxTreeListItem
    While child.IsOk()
      nextChild = lcPod.GetNextSibling(child)

      If lcPod.GetCheckedState(child) Then
        dbp.ExecSql("UPDATE podcasts SET heard=" &heard &" WHERE url=" &Chr(34) &lcpod.GetItemText(child, 4) &Chr(34))

        If counter = -1 Then
          urle = lcPod.GetItemText(lcPod.GetItemParent(child), 4)
          podText[urle]= Nothing

          lcPod.DeleteItem(child)
        Else

          lcPod.UncheckItem(child)
        End If
      End If

      child = nextChild
    Wend

    dbp.Commit()
    dbp.Close()
    lcPod.Thaw()
  End If
End Sub


Sub onPodHeardAll(event As wxCommandEvent)
  Dim heard As Integer = (event.GetID()= ID_SET_HEARD_ALL)
  Dim Item As wxTreeListItem = lcPod.GetSelection()
  Dim url As String = lcpod.GetItemText(Item, 4)
  Dim urle As String = ""
  Dim counter As Integer = lcPod.GetItemText(Item, 6)

  dbp = wxDbConnection("DBQ=podcasts.db;DefaultDir=.;Driver=SQLITE3;")
  dbp.ExecSql("SET CHARACTER_SET 'utf8'")

  If dbp.IsOpen() Then
    dbp.ExecSql("UPDATE podcasts SET heard=" &heard &" from (Select * from podcasts WHERE mainurl=" &Chr(34) &url &Chr(34) &")")

    If counter = -1 Then
      lcPod.Freeze()

      'remove all episodes from list
      Dim child As wxTreeListItem = lcPod.GetFirstChild(Item)
      While child.IsOk()
        If counter = -1 Then
          urle = lcPod.GetItemText(lcPod.GetItemParent(child), 4)
          podText[urle]= Nothing
        End If

        lcPod.DeleteItem(child)
        Deallocate(child)
        child = lcPod.GetNextSibling(child)
      Wend

      If !heard Then
        'reload episodes
        readUrl(url)
        lcPod.Refresh()
        lcPod.Expand(Item)
        If podUrl <> "" Then lcPod.Select(findPodcastItem(podUrl, FALSE))
      End If

      lcPod.Thaw()
    End If

    dbp.Close()
  End If
End Sub


'create a new database for podcasts
Sub createPodcastDB()
  If !FileExists(playerPath &DELIMITER_CHAR &"podcasts.db") Then
    Dim file = FOpen(playerPath &DELIMITER_CHAR &"podcasts.db", "w" )
    FClose(file)
  End If

  Dim db As wxDbEngine = wxDbEngine()
  If db.Open("DBQ=podcasts.db;DefaultDir=.;Driver=SQLITE3;") Then
    If !db.TableExists("podcasts") Then
      db.ExecSql("create table podcasts(" &
      "mainurl text Not Null," &
      "url text Not Null," &
      "heard integer Not Null);")
    End If

    db.Close()

  Else
  
    Dim dlg = wxGenericMessageDialog(Nothing, _("Cannot open the podcast database"), _("Attention"), wxOK|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
    dlg.ShowModal()
    ~dlg
  End If
End Sub


Sub onPodSort(event As wxTreeListEvent)
  Dim col As Integer = event.GetColumn()
  If oldCol <> col Then
    sort_ascending = TRUE
  Else
    sort_ascending = !sort_ascending
  End If
  oldCol = col

  lcPod.SetSortColumn(col, sort_ascending)
End Sub
