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

⌈⌋ ⎇ branch:  streamtuner2


Check-in [a73f762152]

Overview
Comment:Remove url= attribute in main entry points in favour of row{}
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: a73f7621529f65ad13c6110de93b80607645d586
User & Date: mario on 2015-05-24 16:58:51
Other Links: manifest | tags
Context
2015-05-24
16:59
Add missing quotes for streamripper default option. check-in: 4a3b5153d8 user: mario tags: trunk
16:58
Remove url= attribute in main entry points in favour of row{} check-in: a73f762152 user: mario tags: trunk
16:58
Undo {expand:False} attribute for CellRendererPixbuf check-in: a4d0e74658 user: mario tags: trunk
Changes

Modified action.py from [0cb40c6df9] to [2fb5f0a4d6].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# encoding: UTF-8
# api: streamtuner2
# type: functions
# category: io
# title: play/record actions
# description: Starts audio applications, guesses MIME types for URLs
# version: 1.0
# priority: core
#
# Multimedia interface for starting audio players, recording app,
# or web browser (listed as "url/http" association in players).
# It maps audio MIME types, and extracts/converts playlist types
# (PLS, M3U, XSPF, SMIL, JSPF, ASX, raw urls).
#






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
# encoding: UTF-8
# api: streamtuner2
# type: functions
# category: io
# title: play/record actions
# description: Starts audio applications, guesses MIME types for URLs
# version: 1.1
# priority: core
#
# Multimedia interface for starting audio players, recording app,
# or web browser (listed as "url/http" association in players).
# It maps audio MIME types, and extracts/converts playlist types
# (PLS, M3U, XSPF, SMIL, JSPF, ASX, raw urls).
#
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
]

# Preferred probing order of known formats
playlist_fmt_prio = [
   "pls", "xspf", "asx", "smil", "jamj", "json", "m3u", "asf", "raw"
]

# custom stream domain handlers
handler = {
    # "soundcloud": callback(),
}



# Exec wrapper
def run(cmd):
    log.EXEC(cmd)
    try:    os.system("start \"%s\"" % cmd if conf.windows else cmd + " &")
    except: log.ERR("Command not found:", cmd)

# Open help browser, streamtuner2 pages
def help(*args):
    run("yelp /usr/share/doc/streamtuner2/help/")

# Invokes player/recorder for stream url and format
def run_fmt_url(row={}, audioformat="audio/mpeg", source="pls", url=None, assoc={}):
    if not url:
        url = row["url"]
    if audioformat in handler:
        handler[audioformat](row, audioformat, source, url, assoc)
    else:
        cmd = mime_app(audioformat, assoc)
        cmd = interpol(cmd, url, source, row)
        run(cmd)

# Start web browser
def browser(url):
    run_fmt_url({}, "url/http", "srv", url, conf.play)

# Calls player for stream url and format
def play(row={}, audioformat="audio/mpeg", source="pls", url=None):
    run_fmt_url(row, audioformat, source, url, conf.play)

# Call streamripper / youtube-dl / wget
def record(row={}, audioformat="audio/mpeg", source="href", url=None):
    run_fmt_url(row, audioformat, source, url, conf.record)


# OS shell command escaping
#
def quote(ins):
    if type(ins) is list:
        return " ".join(["%r" % str(s) for s in ins])







|

|















|
<
<

|


|







|
|


|
|







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
]

# Preferred probing order of known formats
playlist_fmt_prio = [
   "pls", "xspf", "asx", "smil", "jamj", "json", "m3u", "asf", "raw"
]

# custom stream domain (with faux audioformat) handlers
handler = {
    # "audio/soundcloud": callback(),
}



# Exec wrapper
def run(cmd):
    log.EXEC(cmd)
    try:    os.system("start \"%s\"" % cmd if conf.windows else cmd + " &")
    except: log.ERR("Command not found:", cmd)

# Open help browser, streamtuner2 pages
def help(*args):
    run("yelp /usr/share/doc/streamtuner2/help/")

# Invokes player/recorder for stream url and format
def run_fmt_url(row={}, audioformat="audio/mpeg", source="pls", assoc={}):


    if audioformat in handler:
        handler[audioformat](row, audioformat, source, assoc)
    else:
        cmd = mime_app(audioformat, assoc)
        cmd = interpol(cmd, source, row)
        run(cmd)

# Start web browser
def browser(url):
    run_fmt_url({}, "url/http", "srv", url, conf.play)

# Calls player for stream url and format
def play(row={}, audioformat="audio/mpeg", source="pls"):
    run_fmt_url(row, audioformat, source, conf.play)

# Call streamripper / youtube-dl / wget
def record(row={}, audioformat="audio/mpeg", source="href"):
    run_fmt_url(row, audioformat, source, conf.record)


# OS shell command escaping
#
def quote(ins):
    if type(ins) is list:
        return " ".join(["%r" % str(s) for s in ins])
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
214
215
216
217
218
219
220

# Replaces instances of %m3u, %pls, %srv in a command string
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
#  · Also understands short aliases %l, %f, %d.
#  · And can embed %title or %genre placeholders.
#  · Replace .pls URL with local .m3u file depending on map.
#
def interpol(cmd, url, source="pls", row={}):

    # Inject other meta fields (%title, %genre, %playing, %format, etc.)
    row = copy.copy(row)
    for field in set(re.findall("%(\w+)", cmd)).intersection(row.keys()):
        cmd = cmd.replace("%"+field, "%r" % row.get(field))

    # Add default %pls if cmd has no %url placeholder
    if cmd.find("%") < 0:
        cmd = cmd + " %pls"
        # "pls" as default requires no conversion for most channels, and seems broadly supported by players

    # Playlist type placeholders (%pls, %m3u, %xspf, etc.)
    for dest, rx in placeholder_map.items():
        if re.search(rx, cmd, re.X):
            # from .pls to .m3u
            if not conf.playlist_asis:



                url = convert_playlist(url, listfmt(source), listfmt(dest), local_file=True, row=row)
            # insert quoted URL/filepath
            return re.sub(rx, quote(url), cmd, 2, re.X)

    return "/bin/false"


# Substitute streaming address with desired playlist format







|














|
|
>
>
>
|







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
214
215
216
217
218
219
220
221

# Replaces instances of %m3u, %pls, %srv in a command string
# ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
#  · Also understands short aliases %l, %f, %d.
#  · And can embed %title or %genre placeholders.
#  · Replace .pls URL with local .m3u file depending on map.
#
def interpol(cmd, source="pls", row={}):

    # Inject other meta fields (%title, %genre, %playing, %format, etc.)
    row = copy.copy(row)
    for field in set(re.findall("%(\w+)", cmd)).intersection(row.keys()):
        cmd = cmd.replace("%"+field, "%r" % row.get(field))

    # Add default %pls if cmd has no %url placeholder
    if cmd.find("%") < 0:
        cmd = cmd + " %pls"
        # "pls" as default requires no conversion for most channels, and seems broadly supported by players

    # Playlist type placeholders (%pls, %m3u, %xspf, etc.)
    for dest, rx in placeholder_map.items():
        if re.search(rx, cmd, re.X):
            # no conversion
            if conf.playlist_asis:
                url = row["url"]
            # e.g. from .m3u to .pls
            else:
                url = convert_playlist(row["url"], listfmt(source), listfmt(dest), local_file=True, row=row)
            # insert quoted URL/filepath
            return re.sub(rx, quote(url), cmd, 2, re.X)

    return "/bin/false"


# Substitute streaming address with desired playlist format
707
708
709
710
711
712
713

714

715
716
717
718
719
720
721
722
723
724
725
726
727
728



# Generate filename for temporary .pls/m3u, with unique id
def tmp_fn(row, ext="pls"):
    # use original url for generating a hash sum
    stream_url_hash = abs(hash(str(row)))

    try: channelname = main.current_channel

    except: channelname = "unknown"
    # return temp filename
    fn = "%s/%s.%s.%s" % (str(conf.tmp), channelname, stream_url_hash, ext)
    tmp_files.append(fn)
    return fn

# Collect generated filenames
tmp_files = []

# Callback from main / after gtk_main_quit
def cleanup_tmp_files():
    if not int(conf.reuse_m3u):
        [os.remove(fn) for fn in set(tmp_files)]








>
|
>
|













708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731



# Generate filename for temporary .pls/m3u, with unique id
def tmp_fn(row, ext="pls"):
    # use original url for generating a hash sum
    stream_url_hash = abs(hash(str(row)))
    try:
        channelname = main.current_channel
    except:
        channelname = "unknown"
    # return temp filename
    fn = "%s/%s.%s.%s" % (str(conf.tmp), channelname, stream_url_hash, ext)
    tmp_files.append(fn)
    return fn

# Collect generated filenames
tmp_files = []

# Callback from main / after gtk_main_quit
def cleanup_tmp_files():
    if not int(conf.reuse_m3u):
        [os.remove(fn) for fn in set(tmp_files)]