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

βŒˆβŒ‹ βŽ‡ branch:  streamtuner2


Check-in [a1c4d0960a]

Overview
Comment:Experimental Xiph.org JSON API (doesn't work)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | xiphjson
Files: files | file ages | folders
SHA1: a1c4d0960a024d6e5e49b92f906df68da969f26f
User & Date: mario on 2014-04-27 23:33:05
Other Links: branch diff | manifest | tags
Context
2014-05-04
02:15
Utilize caching interface on IO for Xiph.orgΒ΄s JSON API check-in: 4e7851c986 user: mario tags: xiphjson
2014-04-27
23:33
Experimental Xiph.org JSON API (doesn't work) check-in: a1c4d0960a user: mario tags: xiphjson
22:48
Fully replace ahttp.ajax with ahttp.get() wrapper check-in: b9af78503d user: mario tags: trunk
Changes

Modified channels/xiph.py from [04e8c2b58d] to [59dd45edfc].

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
46
47
48
49
50
51
#
# api: streamtuner2
# title: Xiph.org
# description: Xiph/ICEcast radio directory
# version: 0.1
#
#
# Xiph.org maintains the Ogg streaming standard and Vorbis audio compression
# format, amongst others. The ICEcast server is an alternative to SHOUTcast.
# But it turns out, that Xiph lists only MP3 streams, no OGG. And the directory
# is less encompassing than Shoutcast.
#


#
#
#



# streamtuner2 modules
from config import conf
from mygtk import mygtk
import ahttp as http
from channels import *
from config import __print__, dbg


# python modules
import re
from xml.sax.saxutils import unescape as entity_decode, escape as xmlentities
import xml.dom.minidom



          
# I wonder what that is for                                             ---------------------------------------
class xiph (ChannelPlugin):

        # desc
        api = "streamtuner2"
        module = "xiph"
        title = "Xiph.org"
        version = 0.1
        homepage = "http://dir.xiph.org/"
        base_url = "http://dir.xiph.org/"

        yp = "yp.xml"
        listformat = "url/http"
        config = [
           {"name":"xiph_min_bitrate", "value":64, "type":"int", "description":"minimum bitrate, filter anything below", "category":"filter"}
        ]

        # content
        categories = ["all", [],           ]




|




<
<

>
>
|











>



|
|











|

|
>
|







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
46
47
48
49
50
51
52
53
#
# api: streamtuner2
# title: Xiph.org
# description: Xiph/ICEcast radio directory
# version: 0.2
#
#
# Xiph.org maintains the Ogg streaming standard and Vorbis audio compression
# format, amongst others. The ICEcast server is an alternative to SHOUTcast.


#
# It meanwhile provides a JSOL dump, which is faster to download and process.
# So we'll use that over the older yp.xml. (Sadly it also doesn't output
# homepage URLs, listeners, etc.)
#
#



# streamtuner2 modules
from config import conf
from mygtk import mygtk
import ahttp as http
from channels import *
from config import __print__, dbg
import json

# python modules
import re
#from xml.sax.saxutils import unescape as entity_decode, escape as xmlentities
#import xml.dom.minidom



          
# I wonder what that is for                                             ---------------------------------------
class xiph (ChannelPlugin):

        # desc
        api = "streamtuner2"
        module = "xiph"
        title = "Xiph.org"
        version = 0.2
        homepage = "http://dir.xiph.org/"
        base_url = "http://api.dir.xiph.org/"
        json = "experimental/full"
        old_yp = "yp.xml"
        listformat = "url/http"
        config = [
           {"name":"xiph_min_bitrate", "value":64, "type":"int", "description":"minimum bitrate, filter anything below", "category":"filter"}
        ]

        # content
        categories = ["all", [],           ]
117
118
119
120
121
122
123
124




125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
        def update_streams(self, cat, search=""):

            # there is actually just a single category to download,
            # all else are virtual
            if (cat == "all"):
            
                #-- get data
                yp = http.get(self.base_url + self.yp)




                
                #-- extract
                l = []
                __print__( dbg.DATA, "xml.dom.minidom parses yp.xml" )
                for entry in xml.dom.minidom.parseString(yp).getElementsByTagName("entry"):
                    bitrate = self.bitrate(self.x(entry, "bitrate"))
                    if conf.xiph_min_bitrate and bitrate and bitrate >= int(conf.xiph_min_bitrate):
                      l.append({
                        "title": str(self.x(entry, "server_name")),
                        "url": str(self.x(entry, "listen_url")),
                        "format": self.mime_fmt(str(self.x(entry, "server_type"))[6:]),
                        "bitrate": bitrate,
                        "channels": str(self.x(entry, "channels")),
                        "samplerate": str(self.x(entry, "samplerate")),
                        "genre": str(self.x(entry, "genre")),
                        "playing": str(self.x(entry, "current_song")),
                        "listeners": 0,
                        "max": 0,              # this information is in the html view, but not in the yp.xml (seems pretty static, we might as well make it a built-in list)
                        "homepage": "",
                      })
                
            # filter out a single subtree
            else:
                rx = re.compile(self.filter.get(cat.lower(), cat.lower()))
                l = []







|
>
>
>
>



|
|
|


|
|
|
|
|
|
|
|

|







119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
        def update_streams(self, cat, search=""):

            # there is actually just a single category to download,
            # all else are virtual
            if (cat == "all"):
            
                #-- get data
                data = http.get(self.base_url + self.json)
                data = re.sub('":NaN,', '":0,', data)   # the output is JSOL, not valid JSON
                data = re.sub('[\\\\]"(?!,)', '\'', data)   # and some invalid string escaping
                data = re.sub('[\\\\]{1}', '', data)   # and all other backslashes to be safe
                data = data.decode("latin-1")
                
                #-- extract
                l = []
                __print__( dbg.DATA, "processing dir.xiph.org/experimental/full JSON" )
                for e in json.loads(data):
                    bitrate = e["bitrate"]
                    if conf.xiph_min_bitrate and bitrate and bitrate >= int(conf.xiph_min_bitrate):
                      l.append({
                        "title": e["stream_name"],
                        "url": e["listen_url"],
                        "format": "audio/mpeg",
                        "bitrate": int(e["bitrate"]),
                        "channels": e["channels"],
                        "samplerate": e["samplerate"],
                        "genre": e["genre"],
                        "playing": e["current_song"],
                        "listeners": 0,
                        "max": 0,
                        "homepage": "",
                      })
                
            # filter out a single subtree
            else:
                rx = re.compile(self.filter.get(cat.lower(), cat.lower()))
                l = []