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

⌈⌋ ⎇ branch:  streamtuner2


Diff

Differences From Artifact [a715d3203a]:

  • File ahttp.py — part of check-in [1beab0563e] at 2014-04-10 04:31:02 on branch py3 — * Fixed gtk_list_store_get_value: assertion `column < list_store->n_columns' by removing {width:20} reference from treeview datamap. * row.setdefault() for absent search_col/set and deleted state * More __print__/dbg colorization * Disabled pson.filter_data in favour of str casting in mygtk.columns() * Removed streamactions.popup PY2/PY3 workaround with named args * More .iteritems() removal (user: mario, size: 5600) [annotate] [blame] [check-ins using]

To Artifact [4f43fe032b]:


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
54
55
56
57
58


59
60
61

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76





77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
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
206
207
208
209
210
211
212
213
#
#


from compat2and3 import urllib2, urlencode, urlparse, cookielib, StringIO, xrange, PY3
from gzip import GzipFile
from config import conf, __print__, dbg


#-- url download                            ---------------------------------------------



#-- chains to progress meter and status bar in main window
feedback = None

# sets either text or percentage, so may take two parameters
def progress_feedback(*args):

  # use reset values if none given
  if not args:
     args = ["", 1.0]

  # send to main win
  if feedback:
    try: [feedback(d) for d in args]
    except: pass



















#-- GET
def get(url, maxsize=1<<19, feedback="old"):
    __print__( dbg.HTTP, "GET", url)

    # statusbar info
    progress_feedback(url, 0.0)
    
    # read
    content = ""
    f = urllib2.urlopen(url)
    max = 222000  # mostly it's 200K, but we don't get any real information
    read_size = 1
    
    # multiple steps
    while (read_size and len(content) < maxsize):
    
        # partial read


        add = f.read(8192)
        content = content + add
        read_size = len(add)


        # set progress meter
        progress_feedback(float(len(content)) / float(max))

    # done
    
    # clean statusbar
    progress_feedback()
        
    # fin
    __print__( dbg.INFO, "Content-Length", len(content) )
    return content










#-- fix invalid URLs
def fix_url(url):
    if url is None:
        url = ""
    if len(url):
        # remove whitespace
        url = url.strip()
        # add scheme
        if (url.find("://") < 0):
            url = "http://" + url
        # add mandatory path
        if (url.find("/", 10) < 0):
            url = url + "/"
    return url




# default HTTP headers for AJAX/POST request
default_headers = {
    "User-Agent": "streamtuner2/2.1 (X11; U; Linux AMD64; en; rv:1.5.0.1) like WinAmp/2.1 but not like Googlebot/2.1", #"Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.2.6) Gecko/20100628 Ubuntu/10.04 (lucid) Firefox/3.6.6",
    "Accept": "*/*;q=0.5, audio/*, url/*",
    "Accept-Language": "en-US,en,de,es,fr,it,*;q=0.1",
    "Accept-Encoding": "gzip,deflate",
    "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.1",
    "Keep-Alive": "115",
    "Connection": "keep-alive",
   #"Content-Length", "56",
   #"Cookie": "s_pers=%20s_getnr%3D1278607170446-Repeat%7C1341679170446%3B%20s_nrgvo%3DRepeat%7C1341679170447%3B; s_sess=%20s_cc%3Dtrue%3B%20s_sq%3Daolshtcst%252Caolsvc%253D%252526pid%25253Dsht%25252520%2525253A%25252520SHOUTcast%25252520Radio%25252520%2525257C%25252520Search%25252520Results%252526pidt%25253D1%252526oid%25253Dfunctiononclick%25252528event%25252529%2525257BshowMoreGenre%25252528%25252529%2525253B%2525257D%252526oidt%25253D2%252526ot%25253DDIV%3B; aolDemoChecked=1.849061",
    "Pragma": "no-cache",
    "Cache-Control": "no-cache",
}



# simulate ajax calls
def ajax(url, post, referer=""):
    
    # request
    headers = default_headers
    headers.update({
        "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
        "X-Requested-With": "XMLHttpRequest",
        "Referer": (referer if referer else url),
    })
    if type(post) == dict:
        post = urlencode(post)
    request = urllib2.Request(url, post, headers)
    
    # open url
    __print__( dbg.INFO, vars(request) )
    progress_feedback(url, 0.2)
    r = urllib2.urlopen(request)
    
    # get data
    __print__( dbg.HTTP, r.info() )
    progress_feedback(0.5)
    data = r.read()
    progress_feedback()
    return data



# http://techknack.net/python-urllib2-handlers/    
class ContentEncodingProcessor(urllib2.BaseHandler):
  """A handler to add gzip capabilities to urllib2 requests """

  # add headers to requests
  def http_request(self, req):
    req.add_header("Accept-Encoding", "gzip, deflate")
    return req

  # decode
  def http_response(self, req, resp):
    old_resp = resp
    # gzip
    if resp.headers.get("content-encoding") == "gzip":
        gz = GzipFile(
                    fileobj=StringIO(resp.read()),
                    mode="r"
                  )
        resp = urllib2.addinfourl(gz, old_resp.headers, old_resp.url, old_resp.code)
        resp.msg = old_resp.msg
    # deflate
    if resp.headers.get("content-encoding") == "deflate":
        gz = StringIO( deflate(resp.read()) )
        resp = urllib2.addinfourl(gz, old_resp.headers, old_resp.url, old_resp.code)  # 'class to add info() and geturl() methods to an open file.'
        resp.msg = old_resp.msg
    return resp

# deflate support
import zlib
def deflate(data):   # zlib only provides the zlib compress format, not the deflate format;
  try:               # so on top of all there's this workaround:
    return zlib.decompress(data, -zlib.MAX_WBITS)
  except zlib.error:
    return zlib.decompress(data)







#-- init for later use
if urllib2:

    # config 1
    handlers = [None, None, None]
    
    # base
    handlers[0] = urllib2.HTTPHandler()
    if conf.debug:
        handlers[0].set_http_debuglevel(3)
        
    # content-encoding
    handlers[1] = ContentEncodingProcessor()
    
    # store cookies at runtime
    cj = cookielib.CookieJar()
    handlers[2] = urllib2.HTTPCookieProcessor( cj )
    
    # inject into urllib2
    urllib2.install_opener( urllib2.build_opener(*handlers) )




# alternative function names
AJAX=ajax
POST=ajax
GET=get
URL=fix_url









|
|
<





















>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|



|

|
|
|
|
|
|
<
<

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

|

<
<





>
>
>
>
>




















<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68


69
70
71
72
73
74
75
76
77
78
79
80

81
82
83


84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113





















































































































#
#


from compat2and3 import urllib2, urlencode, urlparse, cookielib, StringIO, xrange, PY3
from gzip import GzipFile
from config import conf, __print__, dbg
import requests
import copy




#-- chains to progress meter and status bar in main window
feedback = None

# sets either text or percentage, so may take two parameters
def progress_feedback(*args):

  # use reset values if none given
  if not args:
     args = ["", 1.0]

  # send to main win
  if feedback:
    try: [feedback(d) for d in args]
    except: pass




# default HTTP headers for AJAX/POST request
default_headers = {
    "User-Agent": "streamtuner2/2.1 (X11; U; Linux AMD64; en; rv:1.5.0.1) like WinAmp/2.1 but not like Googlebot/2.1", #"Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.2.6) Gecko/20100628 Ubuntu/10.04 (lucid) Firefox/3.6.6",
    "Accept": "*/*;q=0.5, audio/*, url/*",
    "Accept-Language": "en-US,en,de,es,fr,it,*;q=0.1",
    "Accept-Encoding": "gzip,deflate",
    "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.1",
    "Keep-Alive": "115",
    "Connection": "keep-alive",
    "Pragma": "no-cache",
    "Cache-Control": "no-cache",
}



#-- GET
def get(url, params={}, referer="", post=0, ajax=0, binary=0):
    __print__( dbg.HTTP, "GET", url)

    # statusbar info
    progress_feedback(url, 0.1)
    
    # combine headers
    headers = copy.copy(default_headers)
    if ajax:
        headers["X-Requested-With"] = "XMLHttpRequest"
    if referer:
        headers["Referer"] = (referer if referer else url)


    
    # read
    if post:
        __print__("POST")
        r = requests.post(url, params=params, headers=headers)
    else:    
        __print__("GET")
        r = requests.get(url, params=params, headers=headers)
        
    # result
    progress_feedback(0.9)
    content = (r.content if binary else r.text)

    
    # finish, clean statusbar
    progress_feedback()


    __print__( dbg.INFO, "Content-Length", len(content) )
    return content




# simulate ajax calls
def ajax(url, params, referer="", binary=0):
    get(url, params, referer, binary, ajax=1)



#-- fix invalid URLs
def fix_url(url):
    if url is None:
        url = ""
    if len(url):
        # remove whitespace
        url = url.strip()
        # add scheme
        if (url.find("://") < 0):
            url = "http://" + url
        # add mandatory path
        if (url.find("/", 10) < 0):
            url = url + "/"
    return url