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

⌈⌋ branch:  streamtuner2


Check-in [026af5c9fb]

Overview
Comment:Fix xiph search URL and by_format mapping.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 026af5c9fb5dda5d427a234f79144afe1167d512
User & Date: mario on 2015-05-02 23:44:06
Other Links: manifest | tags
Context
2015-05-02
23:44
Better plugin comments for user interface. check-in: 85c2fd4f56 user: mario tags: trunk
23:44
Fix xiph search URL and by_format mapping. check-in: 026af5c9fb user: mario tags: trunk
20:03
Add combined unhtml() utility function for raw page extractors. check-in: 6f314952b9 user: mario tags: trunk
Changes

Modified channels/xiph.py from [10274b4d66] to [e7ab9f6f02].

1
2
3
4

5
6
7

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22



23
24
25
26


27
28
29

30

31
32
33
34







35
36
37
38
39
40
41
1
2
3

4
5
6

7
8
9
10
11
12
13
14
15
16
17
18
19



20
21
22
23
24
25

26
27
28


29
30
31




32
33
34
35
36
37
38
39
40
41
42
43
44
45



-
+


-
+












-
-
-
+
+
+



-
+
+

-
-
+

+
-
-
-
-
+
+
+
+
+
+
+






# encoding: UTF-8
# api: streamtuner2
# title: Xiph.org
# description: ICEcast radio directory. Now utilizes a cached JSON API.
# description: ICEcast radios. Scans per JSON API, slow XML, or raw directory.
# type: channel
# url: http://dir.xiph.org/
# version: 0.4
# version: 0.5
# category: radio
# config: 
#    { name: xiph_min_bitrate, value: 64, type: int, description: "Minimum bitrate; filter lesser quality streams.", category: filter }
#    { name: xiph_source, value: cache, 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
#   w7irO4Oj+rdywNNNucmERsLUVndR8uYRU13PCew6hpgP8W02xMpIsik++qk5oweW6y3yob8WnXacZDKJWh1Cp4OtRUHsh19TUlUGViv09RGqKAenU5QnLKm+rK88LjgcUnxmr/h8iNO5XYJBRAQZ/qiVeptGWjty
#   5cClDWLwugQRIRiU5UdPCoD6S89jhV6pks9WG6fuwtBtF5v72vC1v+B86SsM+jD56hjnyiM0lRrAbofeXjQJLdE/78jbXSU5166I6f5VeeDdKdq6GtlSd0QkVU+8XsQhlt9W6izbZ5aMKWgtp2WT/yUHd0xSYU7i
#   dsPQ+1WMKIsJD08wEV2HGLeRyNMjawqRxhuKBfdgz1m7fI/4mVX+ZGxmgniOoJv+QZHGAMC7p60ZnHkC8HfzZmLTBCd9af9ccnqMc9HTdmFe4kLkJbH/4h0xVtcu+SP/C78AL6btab6woPcAAAAASUVORK5CYII=
#
# Xiph.org maintains the Ogg streaming standard and Vorbis
# audio compression format, amongst others.  The ICEcast
# server is an alternative to SHOUTcast.
# Xiph.org maintains the Ogg streaming standard and Vorbis,
# Opus, FLAC audio, and Theora video compression formats.
# The ICEcast server is a modern alternative to SHOUTcast.
#
# It also provides a directory listing of known internet
# radio stations, only a handful of them using Ogg though.
# The category list is hardwired in this plugin.
# The category list is hardwired in this plugin. And there
# are three station fetching modes now:
#
# And there are three fetch-modes now:
#  → "Cache" retrieves a refurbished JSON station list,
#  → "JSON cache" retrieves a refurbished JSON station list,
#    both sliceable genres and searchable.
#
#  → "XML" fetches the olden YP.XML once, buffers it,
#    and tries to uncover per-genre categories from it.
#  → "HTML" extracts from the raw dir.xiph.org directory,
#    where homepages and listener/max infos are available.
#  → "Clunky XML" fetches the olden YP.XML, which is really
#    slow, then slices out genres. No search.
#
#  → "Forbidden Fruits" extracts from dir.xiph.org HTML pages,
#    with homepages and listener/max infos available. Search
#    is also possible.
#


from config import *
from uikit import uikit
import ahttp
from channels import *
import xml.dom.minidom
174
175
176
177
178
179
180

181
182
183
184




185
186
187
188
189
190


191
192
193
194
195
196
197
178
179
180
181
182
183
184
185
186



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205







+

-
-
-
+
+
+
+






+
+






  # Fetch directly from website. Which Xiph does not approve of; but
  # hey, it's a fallback option here. And the only way to actually
  # uncover station homepages.
  #@use_rx
  def from_raw_html(self, cat, search=None, use_rx=False):

      # Build request URL
      by_format = {t.lower(): t for t in self.categories[-1]}
      if search:
          return []
      elif cat in ("Ogg_Vorbis", "NSV", "WebM", "Opus"):
          url = "http://dir.xiph.org/by_format/{}".format(cat)
          url = "http://dir.xiph.org/search?search={}".format(search)
          cat = "search"
      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 = []
205
206
207
208
209
210
211

212

213
214
215
216
217
218
219
213
214
215
216
217
218
219
220

221
222
223
224
225
226
227
228







+
-
+






          .*? "listeners">\[(\d+)
          .*? "stream-description">(.*?)<
          .*? Tags: (.*?) </div>
          .*? href="(/listen/\d+/listen.xspf)"
          .*? class="format"\s+title="([^"]+)"
          .*? /by_format/([^"]+)
      """, html, re.X|re.S)
      print ls
      
            
      # 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),
483
484
485
486
487
488
489

490

491
492
493
494
495
496
497
492
493
494
495
496
497
498
499

500
501
502
503
504
505
506
507







+
-
+






        ],
        "ska",
        [
            "punkrock",
            "oi"
        ],
        "darkwave",
        "/FORMAT",
        "Ogg_Vorbis", "NSV", "WebM", "Opus",
        ["Ogg_Vorbis", "Ogg_Theora", "Opus", "NSV", "WebM"],
    ]



# Helper functions for XML extraction mode

# Shortcut to get text content from XML subnode by name