Internet radio browser GUI for music/video streams from various directory services.

⌈⌋ ⎇ branch:  streamtuner2


Diff

Differences From Artifact [6ec5e242b7]:

To Artifact [c7435085e0]:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
# encoding: UTF-8
# api: streamtuner2
# title: Xiph.org
# description: ICEcast radios. Scans per JSON API, slow XML, or raw directory.
# type: channel
# url: http://dir.xiph.org/
# version: 0.5
# category: radio
# config: 
#    { name: xiph_source, value: web, type: select, select: "cache=JSON cache srv|xml=Clunky XML blob|web=Forbidden fruits", description: "Source for station list extraction." }
# priority: standard
# png:
#   iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAg5JREFUOI2lk1tIE2AUx3+7CG1tlmlG1rSEHrKgEUF7yO40taQiRj10I4qKkOaT4hIUItuTkC8hpJAQtJCICrFpzEKw
#   h61eQorGNBOTzbEt16ZrnR5Wq3mZD/3heziX//983znngyyov+eSbHEA5WKBhs4BKVy9gsqajqwiCwo0dA5IQX5u2s4moliMPPV1nCeDzxgNBFDHE2wsKMPzsGVefobjcnO7RMfeMuL341ZBrNEGRmPqqjdvsbbf






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
# encoding: UTF-8
# api: streamtuner2
# title: Xiph.org
# description: ICEcast radios. Scans per JSON API, slow XML, or raw directory.
# type: channel
# url: http://dir.xiph.org/
# version: 0.6
# category: radio
# config: 
#    { name: xiph_source, value: web, type: select, select: "cache=JSON cache srv|xml=Clunky XML blob|web=Forbidden fruits", description: "Source for station list extraction." }
# priority: standard
# png:
#   iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAg5JREFUOI2lk1tIE2AUx3+7CG1tlmlG1rSEHrKgEUF7yO40taQiRj10I4qKkOaT4hIUItuTkC8hpJAQtJCICrFpzEKw
#   h61eQorGNBOTzbEt16ZrnR5Wq3mZD/3heziX//983znngyyov+eSbHEA5WKBhs4BKVy9gsqajqwiCwo0dA5IQX5u2s4moliMPPV1nCeDzxgNBFDHE2wsKMPzsGVefobjcnO7RMfeMuL341ZBrNEGRmPqqjdvsbbf
191
192
193
194
195
196
197
198
199
200
201
202

203
204

205
206
207
208
209
210
211
212

213
214
215
216
217
218
219
220

221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237











238
239
240
241
242
243
244
      elif by_format.get(cat):
          url = "http://dir.xiph.org/by_format/{}".format(by_format[cat])
      elif cat:
          url = "http://dir.xiph.org/by_genre/{}".format(cat.title())

      # Collect all result pages
      html = ahttp.get(url)
      for i in range(1,4):
          if html.find('page={}">{}</a></li>'.format(i, i+1)) < 0:
              break
          self.status(i/5.1)
          html += ahttp.get(url, {"search": cat.title(), "page": i})

      try: html = html.encode("raw_unicode_escape").decode("utf-8")
      except: pass


      # Find streams
      r = []
      #for row in re.findall("""<tr class="row[01]">(.+?)</tr>""", html, re.X|re.S):
      #    pass
      ls = re.findall("""
          <tr\s+class="row[01]">
          .*? class="name">

               <a\s+href="(.*?)"[^>]*>
                (.*?)</a>
          .*? "listeners">\[(\d+)
          .*? "stream-description">(.*?)<
          .*? Tags: (.*?) </div>
          .*? href="(/listen/\d+/listen.xspf)"
          .*? class="format"\s+title="([^"]+)"
          .*? /by_format/([^"]+)

      """, html, re.X|re.S)
            
      # Assemble
      for homepage, title, listeners, playing, tags, url, bits, fmt in ls:
          r.append(dict(
              genre = unhtml(tags),
              title = unhtml(title),
              homepage = ahttp.fix_url(homepage),
              playing = unhtml(playing),
              url = "http://dir.xiph.org{}".format(url),
              listformat = "xspf",
              listeners = int(listeners),
              bitrate = bitrate(bits),
              format = mime_fmt(guess_format(fmt)),
          ))
      return r














  # Static list of categories
  genres = [
        "pop",
        [
            "top40", "90s", "80s", "britpop", "disco", "urban", "party",







|




>
|
|
>



<
<
|
|
|
>
|
|
|
|
|
|
|
|
>
|
|
<
<

|
|
|
|
|

|
|
|



>
>
>
>
>
>
>
>
>
>
>







191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209


210
211
212
213
214
215
216
217
218
219
220
221
222
223
224


225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
      elif by_format.get(cat):
          url = "http://dir.xiph.org/by_format/{}".format(by_format[cat])
      elif cat:
          url = "http://dir.xiph.org/by_genre/{}".format(cat.title())

      # Collect all result pages
      html = ahttp.get(url)
      for i in range(1,5):
          if html.find('page={}">{}</a></li>'.format(i, i+1)) < 0:
              break
          self.status(i/5.1)
          html += ahttp.get(url, {"search": cat.title(), "page": i})
      try:
          html = html.encode("raw_unicode_escape").decode("utf-8")
      except:
          pass

      # Find streams
      r = []


      rows = re.findall("""<tr\s+class="row\d*">(.+?)</tr>""", html, re.S)
      for html in rows:
          ls = self.rx_all(
               dict(
                  homepage = """ class="name">  <a\s+href="(.*?)" """,
                  title = """ class="name">  <a[^>]*> (.*?)</a> """,
                  listeners = """ "listeners">\[(\d+) """,
                  playing = """ "stream-description">(.*?)< """,
                  tags = """ (?s) Tags: (.*?) </div> """,
                  url = """ href="(/listen/\d+/listen.xspf)" """,
                  bits = """ class="format"\s+title="([^"]+)" """,
                  fmt = """ /by_format/([^"]+) """,
              ),
              html
          )


          r.append(dict(
              genre = unhtml(ls["tags"]),
              title = unhtml(ls["title"]),
              homepage = ahttp.fix_url(ls["homepage"]),
              playing = unhtml(ls["playing"]),
              url = "http://dir.xiph.org{}".format(ls["url"]),
              listformat = "xspf",
              listeners = int(ls["listeners"]),
              bitrate = bitrate(ls["bits"]),
              format = mime_fmt(guess_format(ls["fmt"])),
          ))
      return r

  # Regex dict
  def rx_all(self, fields, src, flags=re.X):
      row = {}
      for k, v in fields.items():
          m = re.search(v, src, flags)
          if m:
              row[k] = m.group(1)
          else:
              row[k] = ""
      return row
     


  # Static list of categories
  genres = [
        "pop",
        [
            "top40", "90s", "80s", "britpop", "disco", "urban", "party",