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

⌈⌋ branch:  streamtuner2


Check-in [08a43fb795]

Overview
Comment:Support .QTL output format
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 08a43fb795240f30a0a59b2e6ed531833182f7c0
User & Date: mario on 2016-11-20 16:09:18
Other Links: manifest | tags
Context
2016-11-20
16:43
More detailed Win installer scripts, as provided by Oliver. Plus *.ico file for packaging. check-in: 3670ccbb4b user: mario tags: trunk
16:09
Support .QTL output format check-in: 08a43fb795 user: mario tags: trunk
16:05
new plugin: liveradio.ie check-in: 979614a6d9 user: mario tags: trunk
Changes

Modified action.py from [e425666e38] to [c3fda330b1].

102
103
104
105
106
107
108

109
110
111
112
113
114
115
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116







+






   ("xspf", r""" <\?xml .* <playlist .* ((?i)http://xspf\.org)/ns/0/ """),
   ("m3u",  r""" ^ \s* \#(EXT)?M3U """),
   ("asx" , r""" (?i) <asx\b """),
   ("smil", r""" <smil[^>]*> .* <seq> """),
   ("html", r""" (?i)<(audio|video)\b[^>]+\bsrc\s*=\s*["']?https?:// """),
   ("wpl",  r""" <\?wpl \s+ version="1\.0" \s* \?> """),
   ("b4s",  r""" <WinampXML> """),   # http://gonze.com/playlists/playlist-format-survey.html
   ("qtl",  r""" <?quicktime\d+type="application/x-quicktime-media-link"\d*?> """),
   ("jspf", r""" ^ \s* \{ \s* "playlist": \s* \{ """),
   ("asf",  r""" ^ \[Reference\] .*? ^Ref\d+= """),
   ("url",  r""" ^ \[InternetShortcut\] .*? ^URL= """),
("desktop", r""" ^ \[Desktop Entry\] .*? ^Link= """),
   ("json", r""" "url": \s* "\w+:\\?/\\?/ """),
   ("jamj", r""" "audio": \s* "\w+:\\?/\\?/ """),
   ("gvp",  r""" ^gvp_version:1\.\d+$ """),
143
144
145
146
147
148
149
150



151
152
153
154
155
156
157
144
145
146
147
148
149
150

151
152
153
154
155
156
157
158
159
160







-
+
+
+






        log.EXEC(cmd)
        os.system(cmd)
    except:
        log.ERR("Command not found:", cmd)

# Open help browser, chm, or streamtuner2 pages
def help(*args):
    for path in [p for p in ("./help", "/usr/share/doc/streamtuner2/help") if os.path.exists(p)]:
    for path in ("./help", "/usr/share/doc/streamtuner2/help", "./usr/share/doc/streamtuner2"):
        if not os.path.exists(path):
            continue
        if conf.windows:
            return run(("%s/help.chm" % path).replace("/", '\\'))
        else:
            return run("yelp %s" % path)
    return browser("http://fossil.include-once.org/streamtuner2/doc/tip/help/html/index.html")

# Invokes player/recorder for stream url and format
532
533
534
535
536
537
538




539
540
541
542
543
544
545
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552







+
+
+
+






            genre = r" (?x) \"(?:genre|keywords|category)\" \s*:\s* \"([^\"]+)\" ",
            unesc = "json",
        ),
        "asf": dict(
            url   = r" (?m) ^ \s*Ref\d+ = (\w+://[^\s]+) ",
            unesc = "xml",
        ),
        "qtl": dict(
            url   = r" <embed\s+src=[\"\']([^\"\']+)[\"\']\s*/>",
            unesc = "xml",
        ),
        "url": dict(
            url   = r"(?m) ^URL=(\w+://.+)",
        ),
        "desktop": dict(
            url   = r"(?m) ^URL=(\w+://.+)",
            title = r"(?m) ^Name=(.+)",
            genre = r"(?m) ^Categories=(.+)",
738
739
740
741
742
743
744






745
746
747
748
749
750
751
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764







+
+
+
+
+
+






    def asx(self, rows):
        txt = """<asx version="3.0">\n"""
        for row in rows:
            txt += """\t<entry>\n\t\t<title>%s</title>\n\t\t<ref href="%s"/>\n\t</entry>\n""" % (xmlentities(row["title"]), xmlentities(row["url"]))
        txt += """</asx>\n"""
        return txt


    # QTL
    def qtl(self, rows):
        return """<?xml version="1.0"?>\n<?quicktime type="application/x-quicktime-media-link"?>\n"""\
            + "<embed src=\"%s\" />\n" % xmlentities(rows[0]["url"])


    # SMIL
    def smil(self, rows):
        txt = """<smil>\n<head>\n\t<meta name="title" content="%s"/>\n</head>\n<body>\n\t<seq>\n""" % (rows[0]["title"])
        for row in rows:
            if row.get("url"):
                txt += """\t\t<{} src="{}"/>\n""".format(row.get("format", "audio").split("/")[0], row["url"])

Modified st2.py from [8350cc9006] to [05596eca4a].

338
339
340
341
342
343
344
345

346
347
348
349
350
351
352
338
339
340
341
342
343
344

345
346
347
348
349
350
351
352







-
+






    # Save stream to file (.m3u)
    def save_as(self, widget):
        row = self.row()
        default_fn = row["title"] + ".m3u"
        fn = uikit.save_file("Save Stream", None, default_fn, [(".m3u","*m3u"),(".pls","*pls"),(".xspf","*xspf"),(".jspf","*jspf"),(".smil","*smil"),(".asx","*asx"),("all files","*")])
        if fn:
            source = row.get("listformat", self.channel().listformat)
            dest = (re.findall("\.(m3u|pls|xspf|jspf|json|smil|asx|wpl)8?$", fn) or ["pls"])[0]
            dest = (re.findall("\.(m3u|pls|xspf|jspf|json|smil|asx|wpl|qtl)8?$", fn) or ["pls"])[0]
            action.save_playlist(source=source, multiply=True).file(rows=[row], fn=fn, dest=dest)
        pass

    # Save current stream URL into clipboard
    def menu_copy(self, w):
        gtk.clipboard_get().set_text(self.selected("url"))