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

⌈⌋ branch:  streamtuner2


Check-in [e4fa4859c6]

Overview
Comment:Implement new .resolve_urn() hook (replacing .row() override), which is added automatically now in ChannelPlugin init.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: e4fa4859c664fe4856869de74639f0b09c650f25
User & Date: mario on 2016-11-06 11:42:32
Other Links: manifest | tags
Context
2016-11-06
11:43
Show player config screenshot also in config_apps/placeholder page. check-in: 2a46669362 user: mario tags: trunk
11:42
Implement new .resolve_urn() hook (replacing .row() override), which is added automatically now in ChannelPlugin init. check-in: e4fa4859c6 user: mario tags: trunk
11:40
Also perform an action.resolve_urn() right when accessing a row. Thus the stremaing lsits get updated on any .row() acccess (= now centrally covered). check-in: 2859a51985 user: mario tags: trunk
Changes

Modified contrib/delicast.py from [f07d91d0e9] to [ecaaf5255a].

1
2
3
4
5
6
7
8
9
10
11
12
13
..
24
25
26
27
28
29
30

31
32
33
34
35
36
37
..
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
..
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# encoding: UTF-8
# api: streamtuner2
# title: Delicast
# description: directory of streaming media
# url: http://delicast.com/
# version: 0.3
# type: channel
# category: radio
# config: -
# png:
#    iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAA
#    AmJLR0QA/4ePzL8AAAAHdElNRQffBB4UJAsX77G0AAAANUlEQVQY02OwQwMMdv/BAEUASCFEoAIIEZIEIGYjBCAUwpb/6O5ACEABGQJ2cFsQIlB3oAEA6iVo+vl+BbQA
#    AAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMDQtMzBUMjI6MzY6MDMrMDI6MDAFLUvfAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE1LTA0LTMwVDIyOjM2OjAzKzAyOjAwdHDz
................................................................................
# page (50 stations) is fetched.


import re
from config import *
from channels import *
import ahttp



# Delayed streaming URL discovery
class delicast (ChannelPlugin):

    # control flags
    has_search = False
................................................................................
    categories = ["60s", "70s", "80s", "90s", "Alternative", "Blues",
    "Chillout", "Christian", "Classical", "Community", "Country", "Culture",
    "Dance", "Disco", "Easy listening", "Electronic", "Folk", "Funk",
    "Gospel", "Hiphop", "House Indie", "Information", "Jazz", "Latin",
    "Lounge", "Love", "Metal", "Oldies", "Pop", "R n b", "Reggae", "Rock",
    "Romantic", "Soul", "Sports", "Student", "Talk", "Techno", "Trance",
    "Urban", "World music"]


    # static
    def update_categories(self):
        pass


    # Fetch entries
................................................................................
                    genre = cat,
             #      genre = unhtml(tags),
                ))
        return r
      

    # Update `url` on station data access (incurs a delay for playing or recording)
    def row(self):
        r = ChannelPlugin.row(self)
        if r.get("url") == "urn:delicast":
            html = ahttp.get(r["homepage"])
            ls = re.findall("^var url = \"(.+)\";", html, re.M)
            r["url"] = ls[0]
        return r






|







 







>







 







|







 







|
|
<


|
|

1
2
3
4
5
6
7
8
9
10
11
12
13
..
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
..
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
..
79
80
81
82
83
84
85
86
87

88
89
90
91
92
# encoding: UTF-8
# api: streamtuner2
# title: Delicast
# description: directory of streaming media
# url: http://delicast.com/
# version: 0.4
# type: channel
# category: radio
# config: -
# png:
#    iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAA
#    AmJLR0QA/4ePzL8AAAAHdElNRQffBB4UJAsX77G0AAAANUlEQVQY02OwQwMMdv/BAEUASCFEoAIIEZIEIGYjBCAUwpb/6O5ACEABGQJ2cFsQIlB3oAEA6iVo+vl+BbQA
#    AAAldEVYdGRhdGU6Y3JlYXRlADIwMTUtMDQtMzBUMjI6MzY6MDMrMDI6MDAFLUvfAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE1LTA0LTMwVDIyOjM2OjAzKzAyOjAwdHDz
................................................................................
# page (50 stations) is fetched.


import re
from config import *
from channels import *
import ahttp
import action


# Delayed streaming URL discovery
class delicast (ChannelPlugin):

    # control flags
    has_search = False
................................................................................
    categories = ["60s", "70s", "80s", "90s", "Alternative", "Blues",
    "Chillout", "Christian", "Classical", "Community", "Country", "Culture",
    "Dance", "Disco", "Easy listening", "Electronic", "Folk", "Funk",
    "Gospel", "Hiphop", "House Indie", "Information", "Jazz", "Latin",
    "Lounge", "Love", "Metal", "Oldies", "Pop", "R n b", "Reggae", "Rock",
    "Romantic", "Soul", "Sports", "Student", "Talk", "Techno", "Trance",
    "Urban", "World music"]
    

    # static
    def update_categories(self):
        pass


    # Fetch entries
................................................................................
                    genre = cat,
             #      genre = unhtml(tags),
                ))
        return r
      

    # Update `url` on station data access (incurs a delay for playing or recording)
    def resolve_urn(self, row):
        if row.get("url").startswith("urn:delicast"):

            html = ahttp.get(r["homepage"])
            ls = re.findall("^var url = \"(.+)\";", html, re.M)
            row["url"] = ls[0]
        return row

Modified contrib/reciva.py from [56fdd75c9a] to [12c0c0ed91].

1
2
3
4
5
6
7
8
9
10
11
..
25
26
27
28
29
30
31

32
33
34
35
36
37
38
..
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
..
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
# encoding: UTF-8
# api: streamtuner2
# title: Reciva
# url: https://radios.reciva.com/stations/genre/34?&start=100&count=50
# description: Home internet radio app and diverse station database.
# version: 0.4
# type: channel
# category: radio
# config: -
# priority: contrib
# png:
................................................................................
# going to be used implicitly.
#


import re
from pq import pq
import ahttp

from config import *
from channels import *


# Reciva directory
class reciva (ChannelPlugin):

................................................................................
    has_search = True
    categories = ['60s', '70s', '80s', '90s', 'Adult', ['Adult Contemporary'], 'Alternative', 'Ambient', 'Bluegrass', 'Blues', 'Bollywood', 'Christian', ['Christian Contemporary'], 'Classic Rock', 'Classical', 'College', 'Comedy', 'Contemporary', 'Country', 'Dance', 'Discussion', 'Easy', 'Electronica', 'Experimental', 'Folk', 'Gospel', 'Greek', 'Hip Hop', 'Indian', 'Indie', ['Indie Rock'], 'Jazz', 'Jungle', 'Kids', 'Latin Hits', 'New Age', 'News', ['News Talk', 'News Updates'], 'Oldies', 'Pop', 'Public', 'Punk', 'Rap', 'Reggae', 'Religious', 'Rock', 'Short Wave Radio', 'Soft Rock', 'Spanish', 'Sports', 'Talk', 'Top 40', 'Unknown', 'Varied', 'World', ['World Africa', 'World Asia', 'World Caribbean', 'World Europe', 'World Mediterranean', 'World Middle East', 'World Tropical']]
    catmap = { 'classical': '14', 'dance': '18', 'bluegrass': '52', 'contemporary': '16', 'pop': '34', 'spanish': '66', 'college': '15', 'rap': '38', 'ambient': '69', 'talk': '43', 'alternative': '9', 'religious': '39', 'blues': '10', 'folk': '23', 'classic rock': '13', '90s': '7', 'adult contemporary': '8', 'oldies': '33', 'indie rock': '54', 'electronica': '21', 'unknown': '45', 'discussion': '19', 'news talk': '31', 'world mediterranean': '55', 'sports': '42', 'new age': '51', 'indie': '27', 'indian': '65', 'easy': '20', '80s': '6', 'world africa': '67', 'comedy': '62', 'public': '35', 'jungle': '72', 'reggae': '48', 'world middle east': '50', 'christian': '11', 'world caribbean': '68', '60s': '58', 'world europe': '56', 'jazz': '28', '70s': '5', 'soft rock': '41', 'top 40': '44', 'adult': '57', 'news': '30', 'bollywood': '60', 'world tropical': '53', 'latin hits': '29', 'varied': '46', 'christian contemporary': '12', 'kids': '59', 'short wave radio': '73', 'world': '49', 'world asia': '47', 'country': '17', 'news updates': '32', 'punk': '36', 'greek': '25', 'hip hop': '26', 'rock': '40', 'gospel': '24', 'experimental': '22' }
    titles = dict( genre="Genre", title="Station", playing="Location", bitrate="Bitrate", listeners=False )
    base_url = "https://radios.reciva.com/stations/genre/%s?&start=0&count=%s"
    
    
    # init
    def __init__(self, parent):
        ChannelPlugin.__init__(self, parent)
        self.login()


    # update list
    def update_categories(self):
        self.categories = []
        html = ahttp.get(self.base_url % (1, 1))
        for c in re.findall('id="cg-(\d+)">([\w\d\s]+)</a></li>', html):
            self.catmap[c[1].lower()] = c[0]
            self.categories.append(c[1])
................................................................................
                })

        # done    
        return entries


    # Fetch real `url` on stream access/playback (delay)
    def row(self):
        r = ChannelPlugin.row(self)
        if not r["url"].startswith("http"):

            html = ahttp.get("https://radios.reciva.com/streamer?stationid=%s&streamnumber=0" % r["id"])
            ls = re.findall("""(?:<iframe src=|iframe\()['"]([^'"]+)['"]""", html)
            if ls:
                r["url"] = ls[0]
            else:
                log.ERR("No stream found for reciva station #%s", row["id"])
        return r


    # Option login
    def login(self):
        lap = conf.netrc(varhosts = ("reciva.com", "radios.reciva.com"))
        if lap:
            log.LOGIN("Reciva account:", lap)
            ahttp.get(
                "https://radios.reciva.com/account/login",
                {
                    "username": lap[0] or lap[1],
                    "password": lap[2]
                },
                timeout=2
            )



|







 







>







 







<
<
<
<
<
<







 







|
<
|
>
|









|











1
2
3
4
5
6
7
8
9
10
11
..
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
..
43
44
45
46
47
48
49






50
51
52
53
54
55
56
..
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
# encoding: UTF-8
# api: streamtuner2
# title: Reciva
# url: https://radios.reciva.com/
# description: Home internet radio app and diverse station database.
# version: 0.4
# type: channel
# category: radio
# config: -
# priority: contrib
# png:
................................................................................
# going to be used implicitly.
#


import re
from pq import pq
import ahttp
import action
from config import *
from channels import *


# Reciva directory
class reciva (ChannelPlugin):

................................................................................
    has_search = True
    categories = ['60s', '70s', '80s', '90s', 'Adult', ['Adult Contemporary'], 'Alternative', 'Ambient', 'Bluegrass', 'Blues', 'Bollywood', 'Christian', ['Christian Contemporary'], 'Classic Rock', 'Classical', 'College', 'Comedy', 'Contemporary', 'Country', 'Dance', 'Discussion', 'Easy', 'Electronica', 'Experimental', 'Folk', 'Gospel', 'Greek', 'Hip Hop', 'Indian', 'Indie', ['Indie Rock'], 'Jazz', 'Jungle', 'Kids', 'Latin Hits', 'New Age', 'News', ['News Talk', 'News Updates'], 'Oldies', 'Pop', 'Public', 'Punk', 'Rap', 'Reggae', 'Religious', 'Rock', 'Short Wave Radio', 'Soft Rock', 'Spanish', 'Sports', 'Talk', 'Top 40', 'Unknown', 'Varied', 'World', ['World Africa', 'World Asia', 'World Caribbean', 'World Europe', 'World Mediterranean', 'World Middle East', 'World Tropical']]
    catmap = { 'classical': '14', 'dance': '18', 'bluegrass': '52', 'contemporary': '16', 'pop': '34', 'spanish': '66', 'college': '15', 'rap': '38', 'ambient': '69', 'talk': '43', 'alternative': '9', 'religious': '39', 'blues': '10', 'folk': '23', 'classic rock': '13', '90s': '7', 'adult contemporary': '8', 'oldies': '33', 'indie rock': '54', 'electronica': '21', 'unknown': '45', 'discussion': '19', 'news talk': '31', 'world mediterranean': '55', 'sports': '42', 'new age': '51', 'indie': '27', 'indian': '65', 'easy': '20', '80s': '6', 'world africa': '67', 'comedy': '62', 'public': '35', 'jungle': '72', 'reggae': '48', 'world middle east': '50', 'christian': '11', 'world caribbean': '68', '60s': '58', 'world europe': '56', 'jazz': '28', '70s': '5', 'soft rock': '41', 'top 40': '44', 'adult': '57', 'news': '30', 'bollywood': '60', 'world tropical': '53', 'latin hits': '29', 'varied': '46', 'christian contemporary': '12', 'kids': '59', 'short wave radio': '73', 'world': '49', 'world asia': '47', 'country': '17', 'news updates': '32', 'punk': '36', 'greek': '25', 'hip hop': '26', 'rock': '40', 'gospel': '24', 'experimental': '22' }
    titles = dict( genre="Genre", title="Station", playing="Location", bitrate="Bitrate", listeners=False )
    base_url = "https://radios.reciva.com/stations/genre/%s?&start=0&count=%s"
    
    






    # update list
    def update_categories(self):
        self.categories = []
        html = ahttp.get(self.base_url % (1, 1))
        for c in re.findall('id="cg-(\d+)">([\w\d\s]+)</a></li>', html):
            self.catmap[c[1].lower()] = c[0]
            self.categories.append(c[1])
................................................................................
                })

        # done    
        return entries


    # Fetch real `url` on stream access/playback (delay)
    def resolve_urn(self, r):

        if r["url"].startswith("urn:"):
            id = r["url"].split(":")[2]
            html = ahttp.get("https://radios.reciva.com/streamer?stationid=%s&streamnumber=0" % id)
            ls = re.findall("""(?:<iframe src=|iframe\()['"]([^'"]+)['"]""", html)
            if ls:
                r["url"] = ls[0]
            else:
                log.ERR("No stream found for reciva station #%s", row["id"])
        return r


    # Option login
    def init2(self, *p):
        lap = conf.netrc(varhosts = ("reciva.com", "radios.reciva.com"))
        if lap:
            log.LOGIN("Reciva account:", lap)
            ahttp.get(
                "https://radios.reciva.com/account/login",
                {
                    "username": lap[0] or lap[1],
                    "password": lap[2]
                },
                timeout=2
            )