Index: action.py ================================================================== --- action.py +++ action.py @@ -43,10 +43,11 @@ "url/http": "href", "audio/x-pn-realaudio": "ram", "application/smil": "smil", "application/vnd.ms-wpl":"smil", "x-urn/st2-script": "script", # unused + "application/x-shockwave-flash": "href", # fallback } # Audio type MIME map mediafmt_t = { "audio/mpeg": "mp3", @@ -60,34 +61,36 @@ "audio/xm+zip": "mod", } # Player command placeholders for playlist formats placeholder_map = dict( - pls = "%url | %pls | %u | %l | %r", - m3u = "%m3u | %f | %g | %m", - srv = "%srv | %d | %s", + pls = "(%url | %pls | %u | %l | %r) \\b", + m3u = "(%m3u | %f | %g | %m) \\b", + srv = "(%srv | %d | %s) \\b", ) # Playlist format content probing (assert type) -playlist_content_map = { - "pls": r""" (?i)\[playlist\].*numberofentries""", - "xspf": r""" <\?xml .* ]*> .* """, - "wpl": r""" <\?wpl \s+ version="1\.0" \s* \?>""", - "jspf": r""" \{ \s* "playlist": \s* \{ """, - "json": r""" "url": \s* "\w+:// """, - "href": r""" .* """, -} +playlist_content_map = [ + ("pls", r""" (?i)\[playlist\].*numberofentries """), + ("xspf", r""" <\?xml .* ]*> .* """), + ("html", r""" <(audio|video)\b[^>]+\bsrc\s*=\s*["']?https?:// """), + ("wpl", r""" <\?wpl \s+ version="1\.0" \s* \?> """), + ("b4s", r""" """), # http://gonze.com/playlists/playlist-format-survey.html + ("jspf", r""" ^ \s* \{ \s* "playlist": \s* \{ """), + ("json", r""" "url": \s* "\w+:// """), + ("href", r""" .* """), +] # Exec wrapper # def run(cmd): - if cmd: debug(dbg.PROC, "Exec:", cmd) + debug(dbg.PROC, "Exec:", cmd) try: os.system("start \"%s\"" % cmd if conf.windows else cmd + " &") except: debug(dbg.ERR, "Command not found:", cmd) # Start web browser @@ -129,15 +132,11 @@ # Convert e.g. "text/x-scpls" MIME types to just "pls" monikers # def listfmt(t = "pls"): - if t in listfmt_t.values(): - for short,mime in listfmt_t.items(): - if mime == t: - return short - return t # "pls" + return listfmt_t.get(t, t) # e.g. "pls" or still "text/x-unknown" # Convert MIME type into list of ["audio/xyz", "audio/*", "*/*"] # for comparison against configured record/play association. def mime_app(fmt, cmd_list): @@ -168,58 +167,62 @@ for dest, rx in placeholder_map.items(): if re.search(rx, cmd, re.X): # from .pls to .m3u urls = convert_playlist(url, listfmt(source), listfmt(dest)) # insert quoted URL/filepath - return re.sub(rx, cmd, quote(urls), 2, re.X) + return re.sub(rx, quote(urls), cmd, 2, re.X) return "false" # Substitute .pls URL with local .m3u, # or direct srv address, or leave as-is. # def convert_playlist(url, source, dest): urls = [] - - print(dbg.PROC, "convert_playlist(", url, source, dest, ")") + debug(dbg.PROC, "convert_playlist(", url, source, dest, ")") - # Leave alone - is_url = re.search("\w+://", url) - if source == dest or source in ("srv", "href") or not is_url: + # Leave alone if format matches, or if "srv" URL class, or if it's a local path already + if source == dest or source in ("srv", "href") or not re.search("\w+://", url): return [url] - + # Retrieve from URL (mime, cnt) = http_probe_get(url) # Leave streaming server as is if mime == "srv": cnt = "" return [url] # Test URL path "extension" for ".pls" / ".m3u" etc. - ext = re.findall("\.(\w)$|($)", url)[0] + ext = re.findall("\.(\w)$", url) + ext = ext[0] if ext else "" # Probe MIME type and content per regex probe = None - for probe,rx in playlist_content_map.items(): + print cnt + for probe,rx in playlist_content_map: if re.search(rx, cnt, re.X|re.S): + probe = listfmt(probe) break # with `probe` set # Check ambiguity (except pseudo extension) if len(set([source, mime, probe])) > 1: - print(dbg.ERR, "Possible playlist format mismatch:", (source, mime, probe, ext)) + debug(dbg.ERR, "Possible playlist format mismatch:", (source, mime, probe, ext)) # Extract URLs from content for fmt,extractor in [ ("pls",extract_playlist.pls), ("asx",extract_playlist.asx), ("raw",extract_playlist.raw) ]: if not urls and fmt in (source, mime, probe, ext): urls = extractor(cnt) + debug(fmt, extractor, urls) - # Return asis for srv targets - if dest in ("srv", "href", "any"): + # Return original, or asis for srv targets + if not urls: + return [url] + elif dest in ("srv", "href", "any"): return urls - print urls + debug( urls ) # Otherwise convert to local file fn = tmp_fn(cnt) save(urls[0], fn, dest) return [fn] @@ -235,13 +238,16 @@ if not len(r.headers): return ("srv", r) # extract payload mime = r.headers.get("content-type", "any") - if mediafmt_t.get(mime): - mime = mediafmt_t.get(mime) - content = "".join(r.iter_lines()) + if listfmt_t.get(mime): + mime = listfmt_t.get(mime) + elif mimefmt_t.get(mime): + mime = mimefmt_t.get(mime) + return (mime, url) + content = "\n".join(r.iter_lines()) return (mime, content) # Extract URLs from playlist formats: @@ -256,12 +262,12 @@ def asx(text): return re.findall("\#]+)", content) # Save row(s) in one of the export formats, # depending on file extension: # @@ -354,12 +360,7 @@ channelname = main.current_channel except: channelname = "unknown" return (str(conf.tmp) + os.sep + "streamtuner2."+channelname+"."+stream_id+".m3u", len(stream_id) > 3 and stream_id != "XXXXXX") - -# check if there are any urls in a given file -def has_urls(tmp_fn): - if os.path.exists(tmp_fn): - return open(tmp_fn, "r").read().find("http://") > 0