From 271a387ba5533ddbb69908c674d5fb448c68edb9 Mon Sep 17 00:00:00 2001 From: Laurent Bachelier Date: Wed, 1 Feb 2012 22:52:28 +0100 Subject: [PATCH] Rewrite lemouv/franceinter into radiofrance * Support for France Inter and Le Mouv', and many new radios. * For some radios only, the current emission is fetched. Previously it was wrong for all two of them. * New icon. * Fix typo in LICENSE. * Fix code style. * Use fillobj() instead of duplicate code. * Since there is not much left of the originals, I made myself the maintainer. --- modules/franceinter/backend.py | 102 -------------- modules/franceinter/favicon.png | Bin 1004 -> 0 bytes modules/franceinter/test.py | 28 ---- modules/lemouv/__init__.py | 24 ---- modules/lemouv/backend.py | 105 --------------- modules/lemouv/favicon.png | Bin 1597 -> 0 bytes .../{franceinter => radiofrance}/__init__.py | 6 +- modules/radiofrance/backend.py | 126 ++++++++++++++++++ modules/radiofrance/favicon.png | Bin 0 -> 1967 bytes modules/{lemouv => radiofrance}/test.py | 9 +- 10 files changed, 134 insertions(+), 266 deletions(-) delete mode 100644 modules/franceinter/backend.py delete mode 100644 modules/franceinter/favicon.png delete mode 100644 modules/franceinter/test.py delete mode 100644 modules/lemouv/__init__.py delete mode 100644 modules/lemouv/backend.py delete mode 100644 modules/lemouv/favicon.png rename modules/{franceinter => radiofrance}/__init__.py (84%) create mode 100644 modules/radiofrance/backend.py create mode 100644 modules/radiofrance/favicon.png rename modules/{lemouv => radiofrance}/test.py (84%) diff --git a/modules/franceinter/backend.py b/modules/franceinter/backend.py deleted file mode 100644 index dc17fcbd..00000000 --- a/modules/franceinter/backend.py +++ /dev/null @@ -1,102 +0,0 @@ -# * -*- coding: utf-8 -*- - -# Copyright(C) 2011 Johann Broudin -# -# 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, CollectionNotFound -from weboob.tools.backend import BaseBackend -from weboob.tools.browser import BaseBrowser, BasePage - - -__all__ = ['FranceInterBackend'] - - -class XMLinfos(BasePage): - def get_current(self): - emissions = self.parser.select(self.document.getroot(), 'item') - if len(emissions) == 0: - return 'No emission' - return emissions[0].find('titreemission').text - -class FranceInterBrowser(BaseBrowser): - DOMAIN = u'metadatas.tv-radio.com' - ENCODING = 'iso-8859-1' - PAGES = {r'.*metadatas/franceinterRSS\.xml': XMLinfos} - - def get_current(self, radio): - self.location('/metadatas/franceinterRSS.xml') - assert self.is_on_page(XMLinfos) - - return self.page.get_current() - -class FranceInterBackend(BaseBackend, ICapRadio, ICapCollection): - NAME = 'franceinter' - MAINTAINER = 'Johann Broudin' - EMAIL = 'johann.broudin@6-8.fr' - VERSION = '0.a' - DESCRIPTION = u'The france inter french radio' - LICENCE = 'AGPLv3+' - BROWSER = FranceInterBrowser - - _RADIOS = {'franceinter': (u'france inter', u'france inter', u'http://mp3.live.tv-radio.com/franceinter/all/franceinterhautdebit.mp3')} - - def iter_resources(self, splited_path): - if len(splited_path) > 0: - raise CollectionNotFound() - - for id in self._RADIOS.iterkeys(): - yield self.get_radio(id) - - def iter_radios_search(self, pattern): - for radio in self.iter_resources([]): - if pattern.lower() in radio.title.lower() or pattern.lower() in radio.description.lower(): - yield radio - - def get_radio(self, radio): - if not isinstance(radio, Radio): - radio = Radio(radio) - - if not radio.id in self._RADIOS: - return None - - title, description, url = self._RADIOS[radio.id] - radio.title = title - radio.description = description - - emission = self.browser.get_current(radio.id) - current = Emission(0) - current.title = unicode(emission) - current.artist = None - radio.current = current - - stream = Stream(0) - stream.title = u'128kbits/s' - stream.url = url - radio.streams = [stream] - return radio - - def fill_radio(self, radio, fields): - if 'current' in fields: - if not radio.current: - radio.current = Emission(0) - radio.current.artist = self.browser.get_current(radio.id) - radio.current.title = None - return radio - - OBJECTS = {Radio: fill_radio} diff --git a/modules/franceinter/favicon.png b/modules/franceinter/favicon.png deleted file mode 100644 index f4bf54f57b012972acd81a081cd5c5ecc043b43d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1004 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|*pj^6U4S$Y z{B+)352QE?JR*x37`TN&n2}-D90{Nxdx@v7EBkF0E&)*$%Z7!qKq1-8kcblJ{M_8s zyb>Unfx)>bHL)Z$MWH;iBtya7(>EYRFO{8vf!W#9#WAGf*4tU9wYLPy9N&NbOtVJn z9u8|ok!Wk}jT*ul?j5_CckQ0KZ=c+a+sym+@hrG{ z^}w@bpDK%(Ow5+u6j3<4UtR6Qo1D$P>n6W_`{d@#L~~~0x3HCet*%iC@2mi><}c*&_?e*FYL&xGmIm)u@^%0}++IeyQ}Jo57LDVZy8 z{=Y5l`{?U24uyzGtO^_6{G9pbof{MW6iI)g*Z#?@OqHg;sV{Qd8Wb+J6CGR)}f7 ziK)_QKFEAymCxmdgN_N=+!d9KeSHo0?gjj=xb@>JcSJ;hU98^I>n~ZRO>0=S>c+1* zlbO$)XI{R%;kfW~zYAJyET| z=8yXQ*qSF&H}YVr+3bbg%j0%TefC%O#OZF^Imd6U-(Mx+^~Cett5b9I^~3okHUDmi zUuns^>+Z8XcjdB*YjVzQ-@5dL)05@JH&?y+b0_B7rA2(kjb^2#Po6JN{QO~oU(?T@ zS$^hblY)b_!j5dZ>gOfUvo)v6>X#gY!tdYC{)HD`{Sju^wCTjfz)LSf@~^Gh{Pby7 z^VZ$o_wKJ={O&00&W#J-@nmKF<8b&D(|K}hMV8Cy3F2!{a=_B9fYyG-tzI!rZ. - - -from weboob.tools.test import BackendTest - -class FranceInterTest(BackendTest): - BACKEND = 'franceinter' - - def test_franceinter(self): - l = list(self.backend.iter_resources([])) - self.assertTrue(len(l) > 0) diff --git a/modules/lemouv/__init__.py b/modules/lemouv/__init__.py deleted file mode 100644 index bd413c3c..00000000 --- a/modules/lemouv/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# * -*- coding: utf-8 -*- - -# Copyright(C) 2011 Johann Broudin -# -# 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 LeMouvBackend - - -__all__ = ['LeMouvBackend'] diff --git a/modules/lemouv/backend.py b/modules/lemouv/backend.py deleted file mode 100644 index 586680c0..00000000 --- a/modules/lemouv/backend.py +++ /dev/null @@ -1,105 +0,0 @@ -# * -*- coding: utf-8 -*- - -# Copyright(C) 2011 Johann Broudin -# -# 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, CollectionNotFound -from weboob.tools.backend import BaseBackend -from weboob.tools.browser import BaseBrowser, BasePage - - -__all__ = ['LeMouvBackend'] - - -class XMLinfos(BasePage): - def get_current(self): - try: - for channel in self.parser.select(self.document.getroot(), 'channel'): - title = channel.find('item/song_title').text - artist = channel.find('item/artist_name').text - except AttributeError: - title = "Not defined" - artist = "Not defined" - - return unicode(artist).strip(), unicode(title).strip() - -class LeMouvBrowser(BaseBrowser): - DOMAIN = u'statique.lemouv.fr' - PAGES = {r'.*/files/rfPlayer/mouvRSS\.xml': XMLinfos} - - def get_current(self, radio): - self.location('/files/rfPlayer/mouvRSS.xml') - assert self.is_on_page(XMLinfos) - - return self.page.get_current() - -class LeMouvBackend(BaseBackend, ICapRadio, ICapCollection): - NAME = 'lemouv' - MAINTAINER = 'Johann Broudin' - EMAIL = 'johann.broudin@6-8.fr' - VERSION = '0.a' - DESCRIPTION = u'The le mouv\' french radio' - LICENCE = 'AGPLv3+' - BROWSER = LeMouvBrowser - - _RADIOS = {'lemouv': (u'le mouv\'', u'le mouv', u'http://mp3.live.tv-radio.com/lemouv/all/lemouvhautdebit.mp3')} - - def iter_resources(self, splited_path): - if len(splited_path) > 0: - raise CollectionNotFound() - - for id in self._RADIOS.iterkeys(): - yield self.get_radio(id) - - def iter_radios_search(self, pattern): - for radio in self.iter_resources([]): - if pattern.lower() in radio.title.lower() or pattern.lower() in radio.description.lower(): - yield radio - - def get_radio(self, radio): - if not isinstance(radio, Radio): - radio = Radio(radio) - - if not radio.id in self._RADIOS: - return None - - title, description, url = self._RADIOS[radio.id] - radio.title = title - radio.description = description - - artist, title = self.browser.get_current(radio.id) - current = Emission(0) - current.artist = artist - current.title = title - radio.current = current - - stream = Stream(0) - stream.title = u'128kbits/s' - stream.url = url - radio.streams = [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.browser.get_current(radio.id) - return radio - - OBJECTS = {Radio: fill_radio} diff --git a/modules/lemouv/favicon.png b/modules/lemouv/favicon.png deleted file mode 100644 index 4650bb82d130476f37a26105195d7ecd93cd9cfd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1597 zcmV-D2EzG?P)Px#24YJ`L;wH)0002_L%V+f000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipV+ z5Cs%fn}eVL0013nR9JLFZ*6U5Zgc_CX>@2HM@dakWG-a~000G) zNkl=#%evC|s zWY$c|prh$Hh$EB9D^1fh9YhiFC!l4D0RknjKknjv4|W%bg|*#xX5PGW z&O7hDd%t_`x#yg>2JDcMi-L<&C)}KL0CWI!0CWJ{n!14NZ*{r{=m6*d=m6*d=m6*d z=m6*d=m6*dSgi$`CBqAnS8{a^&;if^aJLv>kB$_ElIFmf<>d%+X_LT;ed zI~)LjUz~M)-vkIrcg_+xc~SBaDYorSUv>ZhiUJ0Ml?25ALG!^k2J#1WtOpocXjgix zougRgc{n<~<2_(lfB61a!Jo>2kUs4=$RYFuQ)_((;7YUoj)O!X*?rGmlutR9TT=0#R#n0J~ z1wVA1D2F|J372o&8M?g5MLfWFqU4K~!^QRDIG+LkR6QO$b6gYN+s zK7-&?DBCW2fcHBs3&mlNT2Lpn`pZyt4!pSmwjKnZuJHa#@Om^{y9o(vVPAph49^$^ zDKA3j&e~_?pM+I;aJCe#-h_Z&U=D!f2{3l3wfC+E);HOa8ds=){sn;vq8I}xUJLyP zN}J+x2uc*Zws?zifSm|2rDe8sn6QB8UZ3u!N zO%pCYbBtF1;Z&hdijlgK>yppfE&0_65E%?zjSvwmKnD(DynSTjvfL-EDhQ(4?^W#5wHP< z^@FGoC*=X5s;=>&v)XHiRdQ%=71*9KO5d)seZMU)`27yd&4k<4O}(ST0hl>j^7FFb zr$VTz5tEshrLt4SmLOGz`{_2gQw>LpAUVtayQV%1CLh6PTioBjCrpWSA^_7yN)U?5 z#Mh*5(_q9RAp^`BBL?3<>VW!5F8EA`;qO88ux82!4@ivB>XKr>ql=SM;SEW!YcWg+ zhag`tdWbDBHVk$yhRj5*eZp8+J6i. -from .backend import FranceInterBackend +from .backend import RadioFranceBackend -__all__ = ['FranceInterBackend'] +__all__ = ['RadioFranceBackend'] diff --git a/modules/radiofrance/backend.py b/modules/radiofrance/backend.py new file mode 100644 index 00000000..07cc4e3d --- /dev/null +++ b/modules/radiofrance/backend.py @@ -0,0 +1,126 @@ +# * -*- coding: utf-8 -*- + +# Copyright(C) 2011-2012 Johann Broudin, Laurent Bachelier +# +# 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, CollectionNotFound +from weboob.tools.backend import BaseBackend +from weboob.tools.browser import BaseBrowser, BasePage + + +__all__ = ['RadioFranceBackend'] + + +class DataPage(BasePage): + def get_title(self): + for metas in self.parser.select(self.document.getroot(), 'div.metas'): + title = unicode(metas.text_content()).strip() + if len(title): + return title + + +class RadioFranceBrowser(BaseBrowser): + DOMAIN = None + ENCODING = 'UTF-8' + PAGES = {r'/playerjs/direct/donneesassociees/html\?guid=$': DataPage} + + def get_current_playerjs(self, id): + self.location('http://www.%s.fr/playerjs/direct/donneesassociees/html?guid=' % id) + assert self.is_on_page(DataPage) + + return self.page.get_title() + + +class RadioFranceBackend(BaseBackend, ICapRadio, ICapCollection): + NAME = 'radiofrance' + MAINTAINER = 'Laurent Bachelier' + EMAIL = 'laurent@bachelier.name' + VERSION = '0.a' + DESCRIPTION = u'The radios of Radio France (Inter, Culture, Le Mouv\', etc.)' + LICENSE = 'AGPLv3+' + BROWSER = RadioFranceBrowser + + _MP3_URL = u'http://mp3.live.tv-radio.com/%s/all/%s.mp3' + _MP3_HD_URL = u'http://mp3.live.tv-radio.com/%s/all/%shautdebit.mp3' + _RADIOS = {'franceinter': u'France Inter', + 'franceculture': u'France Culture', + 'franceinfo': u'France Info', + 'fbidf': u'France Bleu Ile-de-France', + 'fip': u'FIP', + 'francemusique': u'France Musique', + 'lemouv': u'Le Mouv\'', + } + + _PLAYERJS_RADIOS = ('franceinter', + 'franceculture', + 'franceinfo', + 'lemouv', + ) + + _SD_RADIOS = ('franceinfo', ) + + def iter_resources(self, splited_path): + if len(splited_path) > 0: + raise CollectionNotFound() + + for id in self._RADIOS.iterkeys(): + yield self.get_radio(id) + + def iter_radios_search(self, pattern): + for radio in self.iter_resources([]): + if pattern.lower() in radio.title.lower() or pattern.lower() in radio.description.lower(): + yield radio + + def get_radio(self, radio): + if not isinstance(radio, Radio): + radio = Radio(radio) + + if not radio.id in self._RADIOS: + return None + + title = self._RADIOS[radio.id] + radio.title = title + radio.description = title + + if radio.id in self._SD_RADIOS: + url = self._MP3_URL % (radio.id, radio.id) + else: + url = self._MP3_HD_URL % (radio.id, radio.id) + + self.fillobj(radio, ('current', )) + + stream = Stream(0) + stream.title = u'128kbits/s' + stream.url = url + radio.streams = [stream] + return radio + + def fill_radio(self, radio, fields): + if 'current' in fields: + if not radio.current: + radio.current = Emission(0) + if radio.id in self._PLAYERJS_RADIOS: + radio.current.artist = None + radio.current.title = self.browser.get_current_playerjs(radio.id) + else: + radio.current.artist = None + radio.current.title = None + return radio + + OBJECTS = {Radio: fill_radio} diff --git a/modules/radiofrance/favicon.png b/modules/radiofrance/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..b52359d4364673024124d23d0cf85a2a91fd08a1 GIT binary patch literal 1967 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 BsIve7 literal 0 HcmV?d00001 diff --git a/modules/lemouv/test.py b/modules/radiofrance/test.py similarity index 84% rename from modules/lemouv/test.py rename to modules/radiofrance/test.py index 422e7eaf..77893cc9 100644 --- a/modules/lemouv/test.py +++ b/modules/radiofrance/test.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright(C) 2010-2011 Romain Bignon +# Copyright(C) 2011-2012 Romain Bignon, Laurent Bachelier # # This file is part of weboob. # @@ -20,9 +20,10 @@ from weboob.tools.test import BackendTest -class LeMouvTest(BackendTest): - BACKEND = 'lemouv' - def test_lemouv(self): +class RadioFranceTest(BackendTest): + BACKEND = 'radiofrance' + + def test_get_radios(self): l = list(self.backend.iter_resources([])) self.assertTrue(len(l) > 0)