From d1714c0fb04f0e44aa8584320029c30419059826 Mon Sep 17 00:00:00 2001 From: Roger Philibert Date: Tue, 13 Aug 2013 00:57:12 +0200 Subject: [PATCH] new radio backend: difm Signed-off-by: Roger Philibert --- modules/difm/__init__.py | 24 +++++++ modules/difm/backend.py | 141 +++++++++++++++++++++++++++++++++++++++ modules/difm/favicon.png | Bin 0 -> 3341 bytes 3 files changed, 165 insertions(+) create mode 100644 modules/difm/__init__.py create mode 100644 modules/difm/backend.py create mode 100644 modules/difm/favicon.png diff --git a/modules/difm/__init__.py b/modules/difm/__init__.py new file mode 100644 index 00000000..add930c0 --- /dev/null +++ b/modules/difm/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 Roger Philibert +# +# This file is part of weboob. +# +# weboob is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# weboob is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with weboob. If not, see . + + +from .backend import DIFMBackend + + +__all__ = ['DIFMBackend'] diff --git a/modules/difm/backend.py b/modules/difm/backend.py new file mode 100644 index 00000000..bff6d002 --- /dev/null +++ b/modules/difm/backend.py @@ -0,0 +1,141 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 Roger Philibert +# +# This file is part of weboob. +# +# weboob is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# weboob is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with weboob. If not, see . + + +from weboob.capabilities.radio import ICapRadio, Radio, Stream, Emission +from weboob.capabilities.collection import ICapCollection +from weboob.tools.backend import BaseBackend +from weboob.tools.browser import StandardBrowser +from weboob.tools.misc import to_unicode + + +__all__ = ['DIFMBackend'] + + +class DIFMBackend(BaseBackend, ICapRadio, ICapCollection): + NAME = 'difm' + MAINTAINER = u'Roger Philibert' + EMAIL = 'roger.philibert@gmail.com' + VERSION = '0.h' + DESCRIPTION = u'Digitally Imported web radio' + LICENSE = 'AGPLv3+' + BROWSER = StandardBrowser + + # http://tobiass.eu/api + # http://mpd.wikia.com/wiki/Hack:di.fm-playlists + FORMATS = {('AAC', 64): 'public1', ('AAC', 32): 'public2', ('MP3', 96): 'public3', ('WMA', 40): 'public5'} + + def __init__(self, *a, **kw): + super(DIFMBackend, self).__init__(*a, **kw) + self.RADIOS = {} + + def _get_playlist_url(self, radio_key, format): + return 'http://listen.di.fm/%s/%s.pls' % (self.FORMATS[format], radio_key) + + def _get_info_url(self, radio_key): + self._fetch_radio_list() + + return 'http://api.audioaddict.com/v1/di/track_history/channel/%s' % self.RADIOS[radio_key]['id'] + + def create_default_browser(self): + return self.create_browser(parser='json') + + def _fetch_radio_list(self): + if not self.RADIOS: + document = self.browser.location('http://listen.di.fm/public3') + for info in document: + key = info['key'] + self.RADIOS[key] = {} + self.RADIOS[key]['id'] = info['id'] + self.RADIOS[key]['description'] = info['description'] + self.RADIOS[key]['name'] = info['name'] + + return self.RADIOS + + def iter_radios_search(self, pattern): + self._fetch_radio_list() + + pattern = pattern.lower() + for radio_key in self.RADIOS: + radio_dict = self.RADIOS[radio_key] + if pattern in radio_dict['name'].lower() or pattern in radio_dict['description'].lower(): + yield self.get_radio(radio_key) + + def iter_resources(self, objs, split_path): + self._fetch_radio_list() + + if Radio in objs: + self._restrict_level(split_path) + + for radio_key in self.RADIOS: + yield self.get_radio(radio_key) + + def get_current(self, radio_key): + document = self.browser.location(self._get_info_url(radio_key)) + + artist = title = 'Advertising' + for last in document: + if 'ad' in last: + continue + + artist = last.get('artist', '') or 'Unknown' + title = last.get('title', '') or 'Unknown' + + artist = to_unicode(artist.strip()) + title = to_unicode(title.strip()) + break + + return artist, title + + def get_radio(self, radio): + self._fetch_radio_list() + + if not isinstance(radio, Radio): + radio = Radio(radio) + + if not radio.id in self.RADIOS: + return None + + radio_dict = self.RADIOS[radio.id] + radio.title = radio_dict['name'] + radio.description = radio_dict['description'] + + artist, title = self.get_current(radio.id) + current = Emission(0) + current.artist = artist + current.title = title + radio.current = current + + radio.streams = [] + for format in self.FORMATS: + stream = Stream(0) + stream.title = u'%s %skbps' % format + stream.url = self._get_playlist_url(radio.id, format) + radio.streams.append(stream) + return radio + + def fill_radio(self, radio, fields): + if 'current' in fields: + if not radio.current: + radio.current = Emission(0) + radio.current.artist, radio.current.title = self.get_current(radio.id) + return radio + + OBJECTS = {Radio: fill_radio} + diff --git a/modules/difm/favicon.png b/modules/difm/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..38af0bb3d0b846d7e1fc60ee1b0583285c77be1f GIT binary patch literal 3341 zcmV+o4f67dP)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{01S0WL_t(|+U1)`a2#h9$A8^D zGa6~MTb5WVUukxnVmbKU#Z6j&6ZVvzM^hnk=@<t>X({lm~THuxSAlhTu#W zeAWh+`XFgT+J;=G5(BVIupMxm+&({3*3T6%9^jbtIHI&q|V+koE7b{cNz@%xylmfOafkmZYnottfwfk2j$? zg167WsSfCmUz@co0~VFR{mbQX7kXj$Ir#J<49q}Qnp6R42cko8u@`FRLD-O2l!k=| zOUq$(CDatdt}}4_l0G|>n&yT~*ia4MzYW$^L+605HAi7EnL96-x&mxyiNY(#B>1gW zP*wnW0fAv&02Y+M*H^=;O4!>VMI3FDt7W_2P(aVQWv;L%Xi4!UVPVd!E5HG|V(_1n z0>AauvUqJJEGdUM5dqfxVwhJX_pK_1oyXy$R>g1H$u9oO3#5q5m9hnfvl;@13xbXV zR|X;4BFmQM`>wyP8tz&QYv%cQvAqr|B2ZN%d}xVIEhG&5`+{zQj;Cb#-l5!Ee?kQW zOvQLcjZ<*ET>v?e5CK!3 zR8t}kupNjFLR0s(gKJg_Fn~D)LjKK5bnQTstl2rBjihWyC6oeRPeNOtguZ7vEG|?0 zuB(Q*h4PA>$Kk_P=;$9mT^a_I<%?^8JZ~@wT?3FzGb3wE1z095n*-ljFQGtIY42Ak zq-_7Q@stqyN=zxSISLQ1hK)5+LQM%gR14L`u>1_Xdlu?D#|OxOrBrKVfN;v58S9U$ z056v7s^rq3zZaImCl^O5z;P|rA6E+O8c^I9+lztt^msM&|F)?dV8&WvrXiLXa4Wjuq>$V& z{8uDTs2?y#qJDqe$A+M#&jmBWaaNgNwn7I@D9jV;*Hwu*Zm1Dasx0({wQc42=BSk8 zd5#ByMg|_)wqF*1;S^waRtgE_S652dTK82|CYZv7yrk9pW*!9)0wo2EE@&sI#;dA-RF=*)#Fn-tqhnk@&dNsCW z3ZDtcvz7%6NPqN_ zEPtU#f{)kcvP>T*GI`0YDZl{2LAAat)8A+;Aq)TT4q3f+o*15o^0os5amDueD{#6C zPPW5|4q3l@P_%g>E@2=qD-8L>CvE%p&58mnQ&rrWd9t_{zqSKky#*GOO7M{73*8ly z;3qra$OT!trAH_qPbtQyB7kMe!y--aaed% zJ5Rvc+9OXY%@@{mj8SuptAK)_XlhlFsxr?q`9WXs=#YTyowM-%d3A~g5`Ncay51VJ zluFAB^xd}Gavw~Lj{}woD=XlqTSd1|v@6?`7eHkZ>~DlW?o-V%mKTi)f+hKSaOO(d zisSlD^#=Ae3fMXaa@P(|yDlG3`HJk1s|242H_8iCWmZIB>oQ$4+~#dfF`VjDx*eN{kOM0#dWIgu8CzH$`qTOnnvM<@8kwNT&6GSOS(;2;Gmj>%sBV%ynkGeBaOwFMSGo8lZnz*`#-P z^6&LhaeXKJ^^ihh%MxKqb%{^KCslxh;(GTvDI$^bYxS944oa)1JK_9g*Q!&eh2ZeIuw*Q)j9H86_95;|#XDwK9K z9O)i}H&2UOc%}7ZVFk0Npg^{W+c&JU0&TrwijS^?O*Pv5;xhQrU4H*Q=1!A`k~&~9 z5uFWL!iY$oGD&^s_{e=-yTVCZb$?S-otwE49hPWydHYb(p9#z@R4O{rK5<*CB&_lJ z_Bwe~(1hpSgT0MXnlZXjI;!M0uEA@jl?5F4p9Q7zg1)%U-t9Qxm&QR$6&*~B_JtvZ z)6eeFv6!Kx`iSeRbx*?;9hq5HF0f78;u5Dj6;2^br&PS}N!qiZ0MBK=;?Dd&Y!TTQ z&M21B?#YgcEaNf8yO(K%cDPl&#Ns^o?nd}Vt%%ebcQT#l?)E?v{OS$i%(j(k-wmh4 z22XWl=LyqNfPpyvBWqM@9&S$GPm)peW+xk?|c}MXoBJzwa zOW?`d{NsBCL4``=740J%f;Bw_7;x`$xNV`{_rbtdzms$edpA@U|I?&%2SgxZL3qX=lt}0_i4vRdjq-i zIye4XqwtT9C6sqwpgHPioR>a<-@U6jUk7cFV$j!+xRjzzTVY;|OjwM>x{IX6Habu;CiLgf)aT4KJBBW2Y&sgdWIoO zZSl%N|BzPB(qJT{LB*CO%ExEBl%A@J;4g=S+PR{vj@!^Y)gfT~`(br;JnL_-gSGSZ zx&2LWuv!1NcD?}7G=xWOy*W&SrXiQFDS-!9>9wIo8+hfY@1D78Z0v7>pYPOQqd7WK z5O30aIi^y2IHmnSBFSMMS9l!hzfYU*_tI>oDbLs%ty& z>M{S=?A}KI+`!vs)d+pRL6vB>dz!Eu4w|B;kFHaEe%c0q+ArRJJ<8e4Np$8O%L{}> z*$|+s%3%*hM;AUPJK*A8`1eVHOmv9rw#F)@leT|+cd9EA8Y2tbv2gs@>=~Bzucz>n z7H3(kOj$oyz*Bck-fz26R;H|v>K XbH2nBn08;#00000NkvXXu0mjfK^Rhy literal 0 HcmV?d00001