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

⌈⌋ ⎇ branch:  streamtuner2


Check-in [5b63504d79]

Overview
Comment:Implement resolve_urn() and handlers to look up "urn:xxx:iii" stream urls pripr playback. (Currently just used by reciva and delicast. Now allows to remove channel.row() override.)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 5b63504d79422112f000d55d431ba5e85c0dc5ec
User & Date: mario on 2016-11-06 11:39:30
Other Links: manifest | tags
Context
2016-11-06
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
11:39
Implement resolve_urn() and handlers to look up "urn:xxx:iii" stream urls pripr playback. (Currently just used by reciva and delicast. Now allows to remove channel.row() override.) check-in: 5b63504d79 user: mario tags: trunk
01:57
Keep some notes about how to specify application paths on Windows. check-in: 2fb9158589 user: mario tags: trunk
Changes

Modified action.py from [8f35066d04] to [f35a591c53].

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

# 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={}, append=None):
    if audioformat in handler:
        handler[audioformat](row, audioformat, source, assoc)


    else:
        cmd = mime_app(audioformat, assoc)
        cmd = interpol(cmd, source, row)
        if append:
            cmd = re.sub('(["\']?\s*)$', " " + append + "\\1", cmd)
        run(cmd)








>
>

|
>


















>
>







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

# 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
#  - may contain both "audio/x-service" handlers to convert playlist formsts
#  - and "urn:service" resolvers (which fetch an #id/page to extract actual stram url)
handler = {
    # "audio/soundcloud": playlist_callback(),
    # "urn:reciva": stream_resolve(),
}



# 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={}, append=None):
    if audioformat in handler:
        handler[audioformat](row, audioformat, source, assoc)
    elif row.get("url", "").startswith("urn:"):
        row = resolve_urn(row);
    else:
        cmd = mime_app(audioformat, assoc)
        cmd = interpol(cmd, source, row)
        if append:
            cmd = re.sub('(["\']?\s*)$', " " + append + "\\1", cmd)
        run(cmd)

185
186
187
188
189
190
191












192
193
194
195
196
197
198
def mime_app(fmt, cmd_list):
    major = fmt[:fmt.find("/")]
    for match in [ fmt, major + "/*", "*/*", "video/*", "audio/*" ]:
        if cmd_list.get(match):
            return cmd_list[match]
    log.ERR("No audio player for stream type found")















# 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.







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







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
def mime_app(fmt, cmd_list):
    major = fmt[:fmt.find("/")]
    for match in [ fmt, major + "/*", "*/*", "video/*", "audio/*" ]:
        if cmd_list.get(match):
            return cmd_list[match]
    log.ERR("No audio player for stream type found")


# Is called upon rows containing an url starting with "urn:service:#id",
# calls the handler from the channel plugin to look up the page and find
# the actual streaming url
def resolve_urn(row):
    if row["url"].startswith("urn:"):
        urn_service = ":".join(row["url"].split(":")[:2])
        if urn_service in handler:
            row = handler[urn_service](row)
        else:
            log.WARN("There's currently no action.handler[] for %s:#id streaming addresses (likely disabled channel plugin)." % urn_service)
    return row


# 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.