Diff
Differences From Artifact [cff583b758]:
- File
channels/xiph.py
— part of check-in
[f9c725e90b]
at
2020-05-10 15:17:41
on branch trunk
— Adapt Xiph plugin for BETA/dir-test.xoph.org rollout. It's fairly terrible:
homepages gone, bitrate unavailable, case-sensitive category segregration.
On the upside: direct streaming server urls.
The 'cache' mode is likely broken soon, since the experimental JSON API is gone.
For now using `.title()` on /genre/{} search. Adapted guess_format to recognize AAC. Subtitle is used in lieu of On Air: text for playing= (user: mario, size: 16022) [annotate] [blame] [check-ins using]
To Artifact [5e8e93fcb4]:
- File channels/xiph.py — part of check-in [08803f2b56] at 2020-05-11 16:24:20 on branch trunk — Add duplicate filter for Xiph. (user: mario, size: 16663) [annotate] [blame] [check-ins using]
1 2 3 4 5 6 | # encoding: UTF-8 # api: streamtuner2 # title: Xiph.org # description: ICEcast radios. Scans per JSON API, slow XML, or raw directory. # type: channel # url: http://dir.xiph.org/ | | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # encoding: UTF-8 # api: streamtuner2 # title: Xiph.org # description: ICEcast radios. Scans per JSON API, slow XML, or raw directory. # type: channel # url: http://dir.xiph.org/ # version: 0.8 # category: radio # config: # { name: xiph_source, value: buffy, type: select, select: "cache=JSON cache srv|xml=Clunky XML blob|buffy=Buffy YP.XML|web=Forbidden fruits", description: "Source for station list extraction." } # { name: xiph_filter, value: 1, type: bool, description: "Filter duplicate stations from list." } # priority: standard # png: # iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAg5JREFUOI2lk1tIE2AUx3+7CG1tlmlG1rSEHrKgEUF7yO40taQiRj10I4qKkOaT4hIUItuTkC8hpJAQtJCICrFpzEKw # h61eQorGNBOTzbEt16ZrnR5Wq3mZD/3heziX//983znngyyov+eSbHEA5WKBhs4BKVy9gsqajqwiCwo0dA5IQX5u2s4moliMPPV1nCeDzxgNBFDHE2wsKMPzsGVefobjcnO7RMfeMuL341ZBrNEGRmPqqjdvsbbf # w7irO4Oj+rdywNNNucmERsLUVndR8uYRU13PCew6hpgP8W02xMpIsik++qk5oweW6y3yob8WnXacZDKJWh1Cp4OtRUHsh19TUlUGViv09RGqKAenU5QnLKm+rK88LjgcUnxmr/h8iNO5XYJBRAQZ/qiVeptGWjty # 5cClDWLwugQRIRiU5UdPCoD6S89jhV6pks9WG6fuwtBtF5v72vC1v+B86SsM+jD56hjnyiM0lRrAbofeXjQJLdE/78jbXSU5166I6f5VeeDdKdq6GtlSd0QkVU+8XsQhlt9W6izbZ5aMKWgtp2WT/yUHd0xSYU7i # dsPQ+1WMKIsJD08wEV2HGLeRyNMjawqRxhuKBfdgz1m7fI/4mVX+ZGxmgniOoJv+QZHGAMC7p60ZnHkC8HfzZmLTBCd9af9ccnqMc9HTdmFe4kLkJbH/4h0xVtcu+SP/C78AL6btab6woPcAAAAASUVORK5CYII= |
185 186 187 188 189 190 191 | # uncover station homepages. #@use_rx def from_raw_html(self, cat, search=None, use_rx=False): # Build request URL by_format = {t.lower(): t for t in self.categories[-1]} if search: | | | | 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | # uncover station homepages. #@use_rx def from_raw_html(self, cat, search=None, use_rx=False): # Build request URL by_format = {t.lower(): t for t in self.categories[-1]} if search: url = "http://dir.xiph.org/search?q={}".format(search) cat = "search" elif by_format.get(cat): url = "http://dir.xiph.org/codecs/{}".format(by_format[cat].title()) elif cat: url = "http://dir.xiph.org/genres/{}".format(cat.title()) # Collect all result pages html = ahttp.get(url) for i in range(1,9): m = re.search('href="[?]cursor=(\w+)">Next</a>', html) if not m: break self.status(i/5.1) html += ahttp.get(url, {"cursor": m.group(1)}) try: html = html.encode("raw_unicode_escape").decode("utf-8") |
240 241 242 243 244 245 246 | listformat = "srv", listeners = to_int(ls["listeners"]), bitrate = 0, #bitrate(ls["bits"]), format = mime_fmt(guess_format(ls["fmt"])), tags = unhtml(ls["tags"]) )) #log.DATA(r) | > > > > > | > > > > > > > > > | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | listformat = "srv", listeners = to_int(ls["listeners"]), bitrate = 0, #bitrate(ls["bits"]), format = mime_fmt(guess_format(ls["fmt"])), tags = unhtml(ls["tags"]) )) #log.DATA(r) return self.filter_duplicates(r) # strip entries by title+playing from Xiph BETA result list def filter_duplicates(self, entries): if "xiph_filter" not in conf or not int(conf.xiph_filter): return entries seen = [] filt_r = filter(lambda row: row["title"] not in seen and not seen.append(row["title"]), entries) return filt_r for row in entries: curr = (row["title"], row["playing"]) if not curr in seen: filt_r.append(row) seen.append(curr) return filt_r # Regex dict def rx_all(self, fields, src, flags=re.X): row = {} for k, v in fields.items(): m = re.search(v, src, flags) if m: |