Check-in [2116c28445]
Overview
Comment: | Extended generic JSON extractor, to understand a few common field aliases. Add fallbacks for mime_app lookup in case */* is absent. Simplified %rowfield injection, which is commonly unused anyway. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
2116c28445ebb68ab3ccc133c6185029 |
User & Date: | mario on 2015-04-26 22:24:17 |
Other Links: | manifest | tags |
Context
2015-04-26
| ||
23:49 | Document changes, fixes, new features in 2.1.7 check-in: 3cc9821dbb user: mario tags: trunk, 2.1.7 | |
22:24 | Extended generic JSON extractor, to understand a few common field aliases. Add fallbacks for mime_app lookup in case */* is absent. Simplified %rowfield injection, which is commonly unused anyway. check-in: 2116c28445 user: mario tags: trunk | |
22:22 | Uneeded windows desktop shortcut. check-in: 90605cbddc user: mario tags: trunk | |
Changes
Modified action.py from [18fc32c37f] to [aa42f204ad].
1 2 3 | # encoding: UTF-8 # api: streamtuner2 # type: functions | | | | 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). # |
︙ | ︙ | |||
174 175 176 177 178 179 180 | 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): major = fmt[:fmt.find("/")] | | > | < | | | | | | 174 175 176 177 178 179 180 181 182 183 184 185 186 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 | 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): 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. # 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 fn_or_urls = convert_playlist(url, listfmt(source), listfmt(dest), local_file=True, row=row) # insert quoted URL/filepath return re.sub(rx, quote(fn_or_urls), cmd, 2, re.X) return "/bin/false" # Substitute .pls URL with local .m3u, or direct srv addresses, or leaves URL asis. # · Takes a single input `url` (and original row{} as template). # · But returns a list of [urls] after playlist extraction. # · If repackaging as .m3u/.pls/.xspf, returns the local [fn]. # |
︙ | ︙ | |||
347 348 349 350 351 352 353 | # Extract only URLs from given source type def rows(self, fmt=None): if not fmt: fmt = self.probe_fmt() log.DATA("input extractor/regex:", fmt, len(self.src)) # specific extractor implementations | | | 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 | # Extract only URLs from given source type def rows(self, fmt=None): if not fmt: fmt = self.probe_fmt() log.DATA("input extractor/regex:", fmt, len(self.src)) # specific extractor implementations if hasattr(self, fmt): try: return getattr(self, fmt)() except Exception as e: log.WARN("Native {} parser failed on input (improper encoding, etc)".format(fmt), e) # regex scheme rules = self.extr_urls[fmt] |
︙ | ︙ | |||
452 453 454 455 456 457 458 | ), "jamj": dict( url = r" (?x) \"audio\" \s*:\s* \"(\w+:\\?/\\?/[^\"\s]+)\" ", title = r" (?x) \"name\" \s*:\s* \"([^\"]+)\" ", unesc = "json", ), "json": dict( | | | > > > | 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 | ), "jamj": dict( url = r" (?x) \"audio\" \s*:\s* \"(\w+:\\?/\\?/[^\"\s]+)\" ", title = r" (?x) \"name\" \s*:\s* \"([^\"]+)\" ", unesc = "json", ), "json": dict( url = r" (?x) \"(?:url|audio|stream)\" \s*:\s* \"(\w+:\\?/\\?/[^\"\s]+)\" ", title = r" (?x) \"(?:title|name|station)\" \s*:\s* \"([^\"]+)\" ", playing = r" (?x) \"(?:playing|current|description)\" \s*:\s* \"([^\"]+)\" ", homepage= r" (?x) \"(?:homepage|website|info)\" \s*:\s* \"([^\"]+)\" ", genre = r" (?x) \"(?:genre|keywords|category)\" \s*:\s* \"([^\"]+)\" ", unesc = "json", ), "asf": dict( url = r" (?m) ^ \s*Ref\d+ = (\w+://[^\s]+) ", unesc = "xml", ), "url": dict( |
︙ | ︙ | |||
485 486 487 488 489 490 491 | def pls(self): fieldmap = dict(file="url", title="title") rows = {} for field,num,value in re.findall("^\s* ([a-z_-]+) (\d+) \s*=\s* (.*) $", self.src, re.M|re.I|re.X): if not num in rows: rows[num] = {} field = fieldmap.get(field.lower()) | | | 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 | def pls(self): fieldmap = dict(file="url", title="title") rows = {} for field,num,value in re.findall("^\s* ([a-z_-]+) (\d+) \s*=\s* (.*) $", self.src, re.M|re.I|re.X): if not num in rows: rows[num] = {} field = fieldmap.get(field.lower()) if field and len(value): rows[num][field] = value.strip() return [rows[str(i)] for i in sorted(map(int, rows.keys()))] # Add placeholder fields to extracted row def mkrow(self, row, title=None): url = row.get("url", "") |
︙ | ︙ |