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

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


Check-in [20f1c3edda]

Overview
Comment:Support custom audio handlers for soundcloud etc. Example plugin to register them (only `soundcli` so far).
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 20f1c3edda3c9bab09e079568b3e2865d9d96e71
User & Date: mario on 2015-05-23 15:29:09
Other Links: manifest | tags
Context
2015-05-23
15:45
Fix swapped boolean and integer options in set_plugin_defaults() check-in: 5020c93825 user: mario tags: trunk
15:29
Support custom audio handlers for soundcloud etc. Example plugin to register them (only `soundcli` so far). check-in: 20f1c3edda user: mario tags: trunk
15:28
Simplify favicon callbacks, use channel= instead of artifical pixstore= tuple. update_rows() itself extracts liststore and indicies now. Introduce `img_resize` channel option for `img` banner rescaling in favicon module. check-in: 867c9f9f94 user: mario tags: trunk
Changes

Added contrib/cfg_soundcloud.py version [1301f5ed6f].























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
# api: streamtuner2
# title: Soundcloud player
# description: Just sets a new configuration option for `soundcli`
# version: -1
# url: http://elephly.net/soundcli.html
# priority: once
# type: config
# category: player
# 
# You only need to run this plugin once. It just adds an
# entry for "audio/soundcloud" in the player config list.

from config import *

# just once
class cfg_soundcloud(object):

    module = "cfg_soundcloud"
    fmt = "audio/soundcloud"
    cmd = "xterm -e \"soundcli stream %srv\""

    def __init__(self, *a, **kw):
        conf.play.setdefault(self.fmt, self.cmd)
        print self.module
        conf.plugins[self.module] = False


Modified contrib/reddit.py from [2555b583aa] to [a3ed237dfe].

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
# encoding: UTF-8
# api: streamtuner2
# title: redditβ›±
# description: Music recommendations from reddit /r/music and associated subreddits.
# version: 0.7
# type: channel
# url: http://reddit.com/r/Music
# category: playlist
# config:
#   { name: reddit_pages, type: int, value: 2, description: Number of pages to fetch. }
#   { name: kill_soundcloud, type: boolean, value: 1, description: Filter soundcloud/spotify/bandcamp (only web links). }
# png:
#   iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJ1BMVEUAAAAcICX/AABHSk1jZ299hYz/bmajq6//lY/d0M3C1+3T7P38+/iaLhuGAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF
#   HUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQffBRUXIyQbWArCAAAAh0lEQVQI12Pg3g0BDLtXrVq1eveq3Qy7gIxCU9dqEGO11/ZKbzBDenUIUM3u7cGi1UDFW0TE55wsdpZikAw/
#   eebMnMmHGVxqDuUc0zzpynD4zIk5J3vOSDNsOQMG1gy7bI5HTq85Ws2wu/jM9PIzrkArdhmXlzuuXg00eVd5+epVqxmgrtgNAOWeS1KYtcY4AAAAAElFTkSuQmCC
# priority: extra
#
# Just imports Youtube links from music-related subreddits.
# Those are usually new bands or fresh releases, or favorite
# user selections. The category/subreddit list is filtered
# for a minimum quote of usable links (namely Youtube URLs,

# Soundcloud/Spotify/Bandcamp and weblinks aren't playable.)


#
# This plugin currently uses the old reddit API, which might
# be obsolete by August. It's thus a temporary channel, as
# migrating to OAuth or regressing to plain HTML extraction
# is not very enticing.






|















|
>
|
>
>







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
# encoding: UTF-8
# api: streamtuner2
# title: redditβ›±
# description: Music recommendations from reddit /r/music and associated subreddits.
# version: 0.8
# type: channel
# url: http://reddit.com/r/Music
# category: playlist
# config:
#   { name: reddit_pages, type: int, value: 2, description: Number of pages to fetch. }
#   { name: kill_soundcloud, type: boolean, value: 1, description: Filter soundcloud/spotify/bandcamp (only web links). }
# png:
#   iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJ1BMVEUAAAAcICX/AABHSk1jZ299hYz/bmajq6//lY/d0M3C1+3T7P38+/iaLhuGAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF
#   HUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQffBRUXIyQbWArCAAAAh0lEQVQI12Pg3g0BDLtXrVq1eveq3Qy7gIxCU9dqEGO11/ZKbzBDenUIUM3u7cGi1UDFW0TE55wsdpZikAw/
#   eebMnMmHGVxqDuUc0zzpynD4zIk5J3vOSDNsOQMG1gy7bI5HTq85Ws2wu/jM9PIzrkArdhmXlzuuXg00eVd5+epVqxmgrtgNAOWeS1KYtcY4AAAAAElFTkSuQmCC
# priority: extra
#
# Just imports Youtube links from music-related subreddits.
# Those are usually new bands or fresh releases, or favorite
# user selections. The category/subreddit list is filtered
# for a minimum quote of usable links (namely Youtube URLs).
#
# If you have a custom audio player available for Soundcloud,
# Spotify or Bandcamp, you can enable to retain such links.
# (For example configure `soundcli` for "audio/soundcloud".)
#
# This plugin currently uses the old reddit API, which might
# be obsolete by August. It's thus a temporary channel, as
# migrating to OAuth or regressing to plain HTML extraction
# is not very enticing.


42
43
44
45
46
47
48

49
50
51
52
53
54
55
class reddit (ChannelPlugin):

    # control attributes
    has_search = False
    listformat = "srv"
    audioformat = "video/youtube"
    titles = dict(playing="submitter", listeners="votes", bitrate=False)

    
    # just subreddit names to extract from
    categories = [
        # static radio list
        "radioreddit πŸ“Ÿ",

        # major subreddits







>







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class reddit (ChannelPlugin):

    # control attributes
    has_search = False
    listformat = "srv"
    audioformat = "video/youtube"
    titles = dict(playing="submitter", listeners="votes", bitrate=False)
    img_resize = 24  # scale down reddit preview `img` artwork
    
    # just subreddit names to extract from
    categories = [
        # static radio list
        "radioreddit πŸ“Ÿ",

        # major subreddits
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273

274






275


276

277
278


279

280
281
282
283
284
285
286
287
288
289

290
291
292
293
294
295
296

            # find links in text posts
            text_urls = re.findall("\]\((https?://(?:www\.)?youtu[^\"\'\]\)]+)", row.get("selftext", ""))
            url_ext = (re.findall("\.(\w+)$", row["url"]) or [None])[0]
            listformat = "href"
            state = "gtk-media-play"

            # Youtube
            if re.search("youtu", row["url"]):
                format = "video/youtube"
                listformat = "srv"
            # direct MP3/Ogg
            elif url_ext in ("mp3", "ogg", "flac", "aac", "aacp"):
                format = "audio/" + url_ext
                listformat = "srv"
            # playlists?
            elif url_ext in ("m3u", "pls", "xspf"):
                listformat = url_ext
                format = "audio/x-unknown"
            # links from selftext
            elif text_urls:
                row["url"] = text_urls[0]
                format = "video/youtube"
            # filter out Soundcloud etc.
            elif re.search("soundcloud|spotify|bandcamp", row["url"]):
                if conf.kill_soundcloud:
                    continue

                format = "url/http"






                listformat = "srv"


                state = "gtk-media-pause"

            # pure web links etc.
            else:


                continue


            # repack into streams list
            r.append(dict(
                title = row["title"],
                url = row["url"],
                genre = re.findall("\[(.+?)\]", row["title"] + "[-]")[0],
                playing = row["author"],
                listeners = row["score"],
                homepage = "http://reddit.com{}".format(row["permalink"]),
                img = row.get("thumbnail", ""),

                format = format,
                listformat = listformat,
                state = state,
            ))
        return r        









|
|














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










>







251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274


275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312

            # find links in text posts
            text_urls = re.findall("\]\((https?://(?:www\.)?youtu[^\"\'\]\)]+)", row.get("selftext", ""))
            url_ext = (re.findall("\.(\w+)$", row["url"]) or [None])[0]
            listformat = "href"
            state = "gtk-media-play"

            # Youtube URLs
            if re.search("youtu\.?be|vimeo|dailymotion", row["url"]):
                format = "video/youtube"
                listformat = "srv"
            # direct MP3/Ogg
            elif url_ext in ("mp3", "ogg", "flac", "aac", "aacp"):
                format = "audio/" + url_ext
                listformat = "srv"
            # playlists?
            elif url_ext in ("m3u", "pls", "xspf"):
                listformat = url_ext
                format = "audio/x-unknown"
            # links from selftext
            elif text_urls:
                row["url"] = text_urls[0]
                format = "video/youtube"
            # check for specific web links (Soundcloud etc.)


            else:
                listformat = "srv"
                format = None
                for urltype in ("soundcloud", "spotify", "bandcamp", "mixcloud"):
                    if row["url"].find(urltype) > 0:
                        # is a specific player configured?
                        fmt = "audio/" + urltype
                        if fmt in conf.play:
                            state = "gtk-media-forward"
                            format = fmt
                        # retain it as web link?
                        elif not conf.kill_soundcloud:
                            state = "gtk-media-pause"
                            format = "url/http"
                        break
                # else skip entry completely
                if not format:
                    log.DATA_SKIP(format, row["url"])
                    continue
            #log.DATA(format, row["url"])

            # repack into streams list
            r.append(dict(
                title = row["title"],
                url = row["url"],
                genre = re.findall("\[(.+?)\]", row["title"] + "[-]")[0],
                playing = row["author"],
                listeners = row["score"],
                homepage = "http://reddit.com{}".format(row["permalink"]),
                img = row.get("thumbnail", ""),
                #img_resize = 24,
                format = format,
                listformat = listformat,
                state = state,
            ))
        return r