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
|
# api: streamtunter2
# title: Live365
# description: Around 5000 categorized internet radio streams, some paid ad-free ones.
# type: channel
# category: radio
# version: 0.3
# priority: optional
#
# 2.1.2 broken,
# new URLs:
#
# GET /cgi-bin/mini.cgi?version=3&templateid=xml&from=web&site=web&caller=&tag=web&station_name=bofbm&_=1404610275892
# <NANOCASTER_PARAMS> (session id)
#
# GET /play?now=59&membername=&session=1404610276-475426&tag=web&s=bofbm&d=LIVE365&r=0
# &app_id=web%3ABROWSER&token=b99d7f579bacab06b9baa1502d53bedc-3101060080001248&AuthType=NORMAL
# &lid=276006-deu&SaneID=178.24.130.71-1404610229579
#
#
raise Exception
# streamtuner2 modules
from config import conf
from mygtk import mygtk
import ahttp as http
from channels import *
from config import __print__, dbg
import action
# python modules
import re
import xml.dom.minidom
from xml.sax.saxutils import unescape as entity_decode, escape as xmlentities
import gtk
import copy
import urllib
from itertools import groupby
from time import time
from xml.dom.minidom import parseString
# channel live365
class live365(ChannelPlugin):
# desc
module = "live365"
title = "Live365"
|
<
<
|
<
>
>
>
|
|
<
<
>
|
<
|
>
|
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
|
# api: streamtunter2
# title: Live365
# description: Around 5000 categorized internet radio streams, some paid ad-free ones.
# type: channel
# category: radio
# version: 0.3
# priority: optional
#
#
#
# We're currently extracting from the JavaScript;
#
# stn.set("param", "value");
#
# And using a HTML5 player direct URL now:
#
# /cgi-bin/play.pls?stationid=%s&direct=1&file=%s.pls
#
#
#
# streamtuner2 modules
from config import conf
from mygtk import mygtk
import ahttp as http
from channels import *
from config import __print__, dbg
import action
# python modules
import re
import xml.dom.minidom
from xml.sax.saxutils import unescape as entity_decode, escape as xmlentities
import gtk
import copy
import urllib
from itertools import groupby
from time import time
from xml.dom.minidom import parseString
# channel live365
class live365(ChannelPlugin):
# desc
module = "live365"
title = "Live365"
|
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
|
# fixed for now
def update_categories(self):
pass
# extract stream infos
def update_streams(self, cat):
url = "http://www.live365.com/genres/%s" % cat.lower()
html = http.get(url, feedback=self.parent.status)
# Extract from JavaScript
rx = re.compile(r"""
stn.set\( " (\w+) ", \s+ " ((?:[^"\\]+|\\.)*) "\); \s+
""", re.X|re.I|re.S|re.M)
# Group entries before adding them
ls = []
for i,g in groupby(rx.findall(html), self.group_by_station):
row = dict(g)
ls.append({
"name": row["stationName"],
"title": row["title"],
"playing": "",
"id": row["id"],
"access": row["listenerAccess"],
"status": row["status"],
"mode": row["serverMode"],
"rating": int(row["rating"]),
"rating": row["ratingCount"],
"listeners": int(row["tlh"]),
"location": row["location"],
"favicon": row["imgUrl"],
"format": self.mediatype,
"url": "urn:live365:%s:%s" % (row["id"], row["stationName"])
})
print ls
return ls
# inject session id etc. into direct audio url
def play(self, row):
if row.get("url"):
# params
id = row["id"]
name = row["name"]
# get session
mini = "http://www.live365.com/cgi-bin/mini.cgi?version=3&templateid=xml&from=web&site=web" \
+ "&caller=&tag=web&station_name=%s&_=%i111" % (name, time())
xml = parseString(http.get(mini)).getElementsByTagName("LIVE365_PLAYER_WINDOW")[0]
x = lambda name: xml.getElementsByTagName(name)[0].childNodes[0].data
# mk audio url
play = "http://www.live365.com/play?now=0&" \
+ x("NANOCASTER_PARAMS") \
+ "&token=" + x("TOKEN") \
+ "&AuthType=NORMAL&lid=276006-deu&SaneID=178.24.130.71-1406763621701"
__print__(dbg.DATA, play)
# let's see what happens
action.action.play(play, self.mediatype, self.listformat)
# itertools.groupby filter
gi = 0
def group_by_station(self, kv):
if kv[0] == "stationName":
self.gi += 1
return self.gi
# we can no longer cache all the things
def cache(self):
pass
def save(self):
pass
|
|
>
>
>
|
|
|
|
|
|
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
>
>
>
|
|
>
>
|
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
|
>
>
>
>
|
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
|
# fixed for now
def update_categories(self):
pass
# extract stream infos
def update_streams(self, cat):
# Retrieve genere index pages
html = ""
for i in [1, 17, 33, 49]:
url = "http://www.live365.com/cgi-bin/directory.cgi?first=%i&site=web&mode=3&genre=%s&charset=UTF-8&target=content" % (i, cat.lower())
html += http.get(url, feedback=self.parent.status)
# Extract from JavaScript
rx = re.compile(r"""
stn.set\( " (\w+) ", \s+ " ((?:[^"\\]+|\\.)*) "\); \s+
""", re.X|re.I|re.S|re.M)
# Group entries before adding them
ls = []
for i,row in groupby(rx.findall(html), self.group_by_station):
row = dict(row)
ls.append({
"name": row["stationName"],
"title": row["title"],
"playing": "n/a",
"id": row["id"],
"access": row["listenerAccess"],
"status": row["status"],
"mode": row["serverMode"],
"rating": int(row["rating"]),
#"rating": row["ratingCount"],
"listeners": int(row["tlh"]),
"location": row["location"],
"favicon": row["imgUrl"],
"format": self.mediatype,
"url": "%scgi-bin/play.pls?stationid=%s&direct=1&file=%s.pls" % (self.base_url, row["id"], row["stationName"])
})
return ls
# itertools.groupby filter
gi = 0
def group_by_station(self, kv):
if kv[0] == "stationName":
self.gi += 1
return self.gi
# inject session id etc. into direct audio url
def UNUSED_play(self, row):
if row.get("url"):
# params
id = row["id"]
name = row["name"]
# get mini.cgi station resource
mini_url = "http://www.live365.com/cgi-bin/mini.cgi?version=3&templateid=xml&from=web&site=web" \
+ "&caller=&tag=web&station_name=%s&_=%i111" % (name, time())
mini_r = http.get(mini_url, content=False)
mini_xml = parseString(mini_r.text).getElementsByTagName("LIVE365_PLAYER_WINDOW")[0]
mini = lambda name: mini_xml.getElementsByTagName(name)[0].childNodes[0].data
# authorize with play.cgi
play_url = ""
# mk audio url
play = "http://%s/play" % mini("STREAM_URL") \
+ "?now=0&" \
+ mini("NANOCASTER_PARAMS") \
+ "&token=" + mini("TOKEN") \
+ "&AuthType=NORMAL&lid=276006-deu&SaneID=178.24.130.71-1406763621701"
# let's see what happens
action.action.play(play, self.mediatype, self.listformat)
|