[radiofrance] site changed / backend rewritten using browser2
This commit is contained in:
parent
ec22de45ad
commit
cfb603c6ad
4 changed files with 170 additions and 329 deletions
|
|
@ -17,172 +17,20 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from weboob.deprecated.browser import Browser, Page
|
||||
from weboob.tools.json import json
|
||||
from weboob.capabilities.video import BaseVideo
|
||||
from weboob.deprecated.browser.decorators import id2url
|
||||
from weboob.browser import PagesBrowser, URL
|
||||
from .pages import PlayerPage, TimelinePage
|
||||
|
||||
from time import time
|
||||
import re
|
||||
from urlparse import parse_qs
|
||||
__all__ = ['RadioFranceBrowser']
|
||||
|
||||
|
||||
__all__ = ['RadioFranceBrowser', 'RadioFranceVideo']
|
||||
class RadioFranceBrowser(PagesBrowser):
|
||||
timeline = URL('sites/default/files/(?P<json_url>.*).json', TimelinePage)
|
||||
player_page = URL('(?P<player>.*)', PlayerPage)
|
||||
|
||||
def get_radio_url(self, radio, player):
|
||||
self.BASEURL = 'http://www.%s.fr/' % radio
|
||||
return self.player_page.go(player=player).get_url()
|
||||
|
||||
class RadioFranceVideo(BaseVideo):
|
||||
RADIO_DOMAINS = ('franceinter', 'franceculture', 'fipradio', 'franceinfo')
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
BaseVideo.__init__(self, *args, **kwargs)
|
||||
self.ext = u'mp3'
|
||||
|
||||
@classmethod
|
||||
def id2url(cls, _id):
|
||||
radio_id, replay_id = _id.split('-', 2)
|
||||
radio_domain = 'fipradio' if radio_id == 'fip' else radio_id
|
||||
return 'http://www.%s.fr/player/reecouter?play=%s' % \
|
||||
(radio_domain, replay_id)
|
||||
|
||||
|
||||
class PlayerPage(Page):
|
||||
URL = r'^http://www\.(?P<rdomain>%s)\.fr/player/reecouter\?play=(?P<replay_id>\d+)$' \
|
||||
% '|'.join(RadioFranceVideo.RADIO_DOMAINS)
|
||||
MP3_REGEXP = re.compile(r'sites%2Fdefault.+.(?:MP3|mp3)')
|
||||
|
||||
def get_url(self):
|
||||
radio_domain = self.groups[0]
|
||||
player = self.parser.select(self.document.getroot(), '#rfPlayer embed', 1)
|
||||
urlparams = parse_qs(player.attrib['src'])
|
||||
return 'http://www.%s.fr/%s' % (radio_domain, urlparams['urlAOD'][0])
|
||||
|
||||
|
||||
class ReplayPage(Page):
|
||||
URL = r'^http://www\.(?P<rdomain>%s)\.fr/(?:emission|diffusion)-.+$' \
|
||||
% '|'.join(RadioFranceVideo.RADIO_DOMAINS)
|
||||
# the url does not always end with id-yyy-mm-dd, sometimes no mm or dd
|
||||
URL2 = r'^http://www\.(?P<rdomain>%s)\.fr/[a-z\-]+/[0-9a-z\-]+/[0-9a-z\-]+-[0-9\-]+' \
|
||||
% 'franceinfo'
|
||||
|
||||
def get_id(self):
|
||||
radio_domain = self.groups[0]
|
||||
for node in self.parser.select(self.document.getroot(), 'div.node-rf_diffusion'):
|
||||
match = re.match(r'^node-(\d+)$', node.attrib.get('id', ''))
|
||||
if match:
|
||||
player_id = match.groups()[0]
|
||||
return (radio_domain, player_id)
|
||||
# if we failed, try another way (used in FIP)
|
||||
# but it might not be as accurate for others
|
||||
# (some pages have more than one of these)
|
||||
# so it's only used as a fallback
|
||||
for node in self.parser.select(self.document.getroot(), 'a.rf-player-open'):
|
||||
match = re.match(r'^/player/reecouter\?play=(\d+)$', node.attrib.get('href', ''))
|
||||
if match:
|
||||
player_id = match.groups()[0]
|
||||
return (radio_domain, player_id)
|
||||
# at least for franceinfo
|
||||
for node in self.parser.select(self.document.getroot(), '#article .emission-player a.play'):
|
||||
match = re.match(r'^song-(\d+)$', node.attrib.get('rel', ''))
|
||||
if match:
|
||||
player_id = match.groups()[0]
|
||||
return (radio_domain, player_id)
|
||||
|
||||
|
||||
class DataPage(Page):
|
||||
def get_current(self):
|
||||
document = self.document
|
||||
title = ''
|
||||
for metas in self.parser.select(document.getroot(), 'div.metas'):
|
||||
ftitle = unicode(metas.text_content()).strip()
|
||||
if ftitle:
|
||||
title = ftitle
|
||||
# Another format (used by FIP)
|
||||
artist = document.findtext('//div[@class="metas"]//span[@class="author"]')
|
||||
if artist:
|
||||
artist = unicode(artist).strip()
|
||||
ftitle = document.findtext('//div[@class="subtitle"]')
|
||||
title = unicode(ftitle).strip() if ftitle else title
|
||||
else:
|
||||
artist = ''
|
||||
|
||||
return (artist, title)
|
||||
|
||||
|
||||
class RssPage(Page):
|
||||
def get_title(self):
|
||||
titles = []
|
||||
for heading in self.parser.select(self.document.getroot(), 'h1, h2, h3, h4'):
|
||||
# Remove newlines/multiple spaces
|
||||
words = heading.text_content()
|
||||
if words:
|
||||
for word in unicode(words).split():
|
||||
titles.append(word)
|
||||
if len(titles):
|
||||
return ' '.join(titles)
|
||||
|
||||
|
||||
class RadioFranceBrowser(Browser):
|
||||
DOMAIN = None
|
||||
ENCODING = 'UTF-8'
|
||||
PAGES = {r'http://.*/player/direct': DataPage,
|
||||
r'http://players.tv-radio.com/radiofrance/metadatas/([a-z]+)RSS.html': RssPage,
|
||||
PlayerPage.URL: PlayerPage,
|
||||
ReplayPage.URL: ReplayPage,
|
||||
ReplayPage.URL2: ReplayPage}
|
||||
|
||||
def id2domain(self, _id):
|
||||
"""
|
||||
Get the main website domain for a Radio ID.
|
||||
"""
|
||||
# FIP is the only one to use "fip" but "fipradio" for the domain.
|
||||
if _id == 'fip':
|
||||
_id = 'fipradio'
|
||||
return 'www.%s.fr' % _id
|
||||
|
||||
def get_current_playerjs(self, _id):
|
||||
self.location('http://%s/player/direct' % self.id2domain(_id))
|
||||
assert self.is_on_page(DataPage)
|
||||
|
||||
return self.page.get_current()
|
||||
|
||||
def get_current_rss(self, _id):
|
||||
self.location('http://players.tv-radio.com/radiofrance/metadatas/%sRSS.html' % _id)
|
||||
assert self.is_on_page(RssPage)
|
||||
|
||||
return self.page.get_title()
|
||||
|
||||
def get_current_direct(self, _id):
|
||||
json_data = self.openurl('http://%s/sites/default/files/direct.json?_=%s' % (self.id2domain(_id), int(time())))
|
||||
data = json.load(json_data)
|
||||
title = unicode(data['rf_titre_antenne']['titre'])
|
||||
artist = unicode(data['rf_titre_antenne']['interprete'])
|
||||
return (artist, title)
|
||||
|
||||
def get_current_direct_large(self, _id):
|
||||
json_data = self.openurl('http://%s/sites/default/files/import_si/si_titre_antenne/FIP_player_current.json'
|
||||
% self.id2domain(_id))
|
||||
data = json.load(json_data)
|
||||
artist = unicode(data['current']['song']['interpreteMorceau'])
|
||||
title = unicode(data['current']['song']['titre'])
|
||||
return (artist, title)
|
||||
|
||||
@id2url(RadioFranceVideo.id2url)
|
||||
def get_video(self, url):
|
||||
radio_domain = replay_id = None
|
||||
match = re.match(PlayerPage.URL, url)
|
||||
if match:
|
||||
radio_domain, replay_id = match.groups()
|
||||
elif re.match(ReplayPage.URL, url) or re.match(ReplayPage.URL2, url):
|
||||
self.location(url)
|
||||
assert self.is_on_page(ReplayPage)
|
||||
radio_domain, replay_id = self.page.get_id()
|
||||
if radio_domain and replay_id:
|
||||
radio_id = 'fip' if radio_domain == 'fipradio' else radio_domain
|
||||
_id = '%s-%s' % (radio_id, replay_id)
|
||||
return RadioFranceVideo(_id)
|
||||
|
||||
@id2url(RadioFranceVideo.id2url)
|
||||
def get_url(self, url):
|
||||
self.location(url)
|
||||
assert self.is_on_page(PlayerPage)
|
||||
return self.page.get_url()
|
||||
def get_current(self, radio, json_url):
|
||||
self.BASEURL = 'http://www.%s.fr/' % radio
|
||||
return self.timeline.go(json_url=json_url).get_current()
|
||||
|
|
|
|||
|
|
@ -19,20 +19,21 @@
|
|||
|
||||
|
||||
from weboob.capabilities.base import NotLoaded
|
||||
from weboob.capabilities.video import CapVideo
|
||||
from weboob.capabilities.radio import CapRadio, Radio
|
||||
from weboob.capabilities.audiostream import BaseAudioStream
|
||||
from weboob.tools.capabilities.streaminfo import StreamInfo
|
||||
from weboob.capabilities.collection import CapCollection, CollectionNotFound, Collection
|
||||
from weboob.tools.backend import Module
|
||||
|
||||
from .browser import RadioFranceBrowser, RadioFranceVideo
|
||||
from .browser import RadioFranceBrowser
|
||||
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
__all__ = ['RadioFranceModule']
|
||||
|
||||
|
||||
class RadioFranceModule(Module, CapRadio, CapCollection, CapVideo):
|
||||
class RadioFranceModule(Module, CapRadio, CapCollection):
|
||||
NAME = 'radiofrance'
|
||||
MAINTAINER = u'Laurent Bachelier'
|
||||
EMAIL = 'laurent@bachelier.name'
|
||||
|
|
@ -41,166 +42,113 @@ class RadioFranceModule(Module, CapRadio, CapCollection, CapVideo):
|
|||
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', True),
|
||||
'franceculture': (u'France Culture', True),
|
||||
'franceinfo': (u'France Info', False),
|
||||
'fbidf': (u'France Bleu Île-de-France (Paris)', True),
|
||||
'fip': (u'FIP', True),
|
||||
'francemusique': (u'France Musique', True),
|
||||
'lemouv': (u'Le Mouv\'', True),
|
||||
'fbalsace': (u'France Bleu Alsace (Strasbourg)', False),
|
||||
'fbarmorique': (u'France Bleu Armorique (Rennes)', False),
|
||||
'fbauxerre': (u'France Bleu Auxerre', False),
|
||||
'fbazur': (u'France Bleu Azur (Nice)', False),
|
||||
'fbbassenormandie': (u'France Bleu Basse Normandie (Caen)', False),
|
||||
'fbbearn': (u'France Bleu Bearn (Pau)', False),
|
||||
'fbbelfort': (u'France Bleu Belfort', False),
|
||||
'fbberry': (u'France Bleu Berry (Châteauroux)', False),
|
||||
'fbbesancon': (u'France Bleu Besancon', False),
|
||||
'fbbourgogne': (u'France Bleu Bourgogne (Dijon)', False),
|
||||
'fbbreizizel': (u'France Bleu Breiz Izel (Quimper)', False),
|
||||
'fbchampagne': (u'France Bleu Champagne (Reims)', False),
|
||||
'fbcotentin': (u'France Bleu Cotentin (Cherbourg)', False),
|
||||
'fbcreuse': (u'France Bleu Creuse (Gueret)', False),
|
||||
'fbdromeardeche': (u'France Bleu Drome Ardeche (Valence)', False),
|
||||
'fbfrequenzamora': (u'France Bleu Frequenza Mora (Bastia - Corse)', False),
|
||||
'fbgardlozere': (u'France Bleu Gard Lozère (Nîmes)', False),
|
||||
'fbgascogne': (u'France Bleu Gascogne (Mont-de-Marsan)', False),
|
||||
'fbgironde': (u'France Bleu Gironde (Bordeaux)', False),
|
||||
'fbhautenormandie': (u'France Bleu Haute Normandie (Rouen)', False),
|
||||
'fbherault': (u'France Bleu Hérault (Montpellier)', False),
|
||||
'fbisere': (u'France Bleu Isère (Grenoble)', False),
|
||||
'fblarochelle': (u'France Bleu La Rochelle', False),
|
||||
'fblimousin': (u'France Bleu Limousin (Limoges)', False),
|
||||
'fbloireocean': (u'France Bleu Loire Océan (Nantes)', False),
|
||||
'fblorrainenord': (u'France Bleu Lorraine Nord (Metz)', False),
|
||||
'fbmayenne': (u'France Bleu Mayenne (Laval)', False),
|
||||
'fbnord': (u'France Bleu Nord (Lille)', False),
|
||||
'fborleans': (u'France Bleu Orléans', False),
|
||||
'fbpaysbasque': (u'France Bleu Pays Basque (Bayonne)', False),
|
||||
'fbpaysdauvergne': (u'France Bleu Pays d\'Auvergne (Clermont-Ferrand)', False),
|
||||
'fbpaysdesavoie': (u'France Bleu Pays de Savoie (Chambery)', False),
|
||||
'fbperigord': (u'France Bleu Périgord (Périgueux)', False),
|
||||
'fbpicardie': (u'France Bleu Picardie (Amiens)', False),
|
||||
'fbpoitou': (u'France Bleu Poitou (Poitiers)', False),
|
||||
'fbprovence': (u'France Bleu Provence (Aix-en-Provence)', False),
|
||||
'fbroussillon': (u'France Bleu Roussillon (Perpigan)', False),
|
||||
'fbsudlorraine': (u'France Bleu Sud Lorraine (Nancy)', False),
|
||||
'fbtoulouse': (u'France Bleu Toulouse', False),
|
||||
'fbtouraine': (u'France Bleu Touraine (Tours)', False),
|
||||
'fbvaucluse': (u'France Bleu Vaucluse (Avignon)', False),
|
||||
_RADIOS = {'franceinter': (u'France Inter', 'player', 'lecteur_commun_json/timeline'),
|
||||
'franceculture': (u'France Culture', 'player', 'lecteur_commun_json/timeline'),
|
||||
'franceinfo': (u'France Info', 'player', 'lecteur_commun_json/timeline'),
|
||||
'fbidf': (u'France Bleu Île-de-France (Paris)', 'station/france-bleu-107-1', 'lecteur_commun_json/timeline-9753'),
|
||||
'fipradio': (u'FIP', 'player', 'import_si/si_titre_antenne/FIP_player_current'),
|
||||
'francemusique': (u'France Musique', 'player', 'lecteur_commun_json/reecoute-%s' % int(time.mktime(datetime.now().replace(hour=14, minute=0, second=0).timetuple()))),
|
||||
'mouv': (u'Le Mouv\'', 'player', 'lecteur_commun_json/timeline'),
|
||||
'fbalsace': (u'France Bleu Alsace (Strasbourg)', 'player/station/france-bleu-alsace', 'lecteur_commun_json/timeline-13085'),
|
||||
'fbarmorique': (u'France Bleu Armorique (Rennes)', 'player/station/france-bleu-armorique', 'lecteur_commun_json/timeline-13087'),
|
||||
'fbauxerre': (u'France Bleu Auxerre', 'player/station/france-bleu-auxerre', 'lecteur_commun_json/timeline-11219'),
|
||||
'fbazur': (u'France Bleu Azur (Nice)', 'player/station/france-bleu-azur', 'lecteur_commun_json/timeline-13089'),
|
||||
'fbbassenormandie': (u'France Bleu Basse Normandie (Caen)', 'player/station/france-bleu-bassenormandie', 'lecteur_commun_json/timeline-13091'),
|
||||
'fbbearn': (u'France Bleu Bearn (Pau)', 'player/station/france-bleu-bearn', 'lecteur_commun_json/timeline-13093'),
|
||||
'fbbelfort': (u'France Bleu Belfort', 'player/station/france-bleu-belfort', 'lecteur_commun_json/timeline-13095'),
|
||||
'fbberry': (u'France Bleu Berry (Châteauroux)', 'player/station/france-bleu-berry', 'lecteur_commun_json/timeline-11223'),
|
||||
'fbbesancon': (u'France Bleu Besancon', 'player/station/france-bleu-besancon', 'lecteur_commun_json/timeline-13097'),
|
||||
'fbbourgogne': (u'France Bleu Bourgogne (Dijon)', 'player/station/france-bleu-bourgogne', 'lecteur_commun_json/timeline-13099'),
|
||||
'fbbreizizel': (u'France Bleu Breiz Izel (Quimper)', 'player/station/france-bleu-breizizel', 'lecteur_commun_json/timeline-13101'),
|
||||
'fbchampagne': (u'France Bleu Champagne (Reims)', 'player/station/france-bleu-champagne', 'lecteur_commun_json/timeline-13103'),
|
||||
'fbcotentin': (u'France Bleu Cotentin (Cherbourg)', 'player/station/france-bleu-cotentin', 'lecteur_commun_json/timeline-13105'),
|
||||
'fbcreuse': (u'France Bleu Creuse (Gueret)', 'player/station/france-bleu-creuse', 'lecteur_commun_json/timeline-13107'),
|
||||
'fbdromeardeche': (u'France Bleu Drome Ardeche (Valence)', 'player/station/france-bleu-dromeardeche', 'lecteur_commun_json/timeline-13109'),
|
||||
'fbelsass': (u'France Bleu Elsass', '/player/station/france-bleu-elsass', 'lecteur_commun_json/timeline-19370'),
|
||||
'fbgardlozere': (u'France Bleu Gard Lozère (Nîmes)', 'player/station/france-bleu-gardlozere', 'lecteur_commun_json/timeline-13111'),
|
||||
'fbgascogne': (u'France Bleu Gascogne (Mont-de-Marsan)', 'player/station/france-bleu-gascogne', 'lecteur_commun_json/timeline-13113'),
|
||||
'fbgironde': (u'France Bleu Gironde (Bordeaux)', 'player/station/france-bleu-gironde', 'lecteur_commun_json/timeline-13115'),
|
||||
'fbhautenormandie': (u'France Bleu Haute Normandie (Rouen)', 'player/station/france-bleu-hautenormandie', 'lecteur_commun_json/timeline-13117'),
|
||||
'fbherault': (u'France Bleu Hérault (Montpellier)', 'player/station/france-bleu-herault', 'lecteur_commun_json/timeline-11231'),
|
||||
'fbisere': (u'France Bleu Isère (Grenoble)', 'player/station/france-bleu-isere', 'lecteur_commun_json/timeline-13119'),
|
||||
'fblarochelle': (u'France Bleu La Rochelle', 'player/station/france-bleu-larochelle', 'lecteur_commun_json/timeline-13121'),
|
||||
'fblimousin': (u'France Bleu Limousin (Limoges)', 'player/station/france-bleu-limousin', 'lecteur_commun_json/timeline-13123'),
|
||||
'fbloireocean': (u'France Bleu Loire Océan (Nantes)', 'player/station/france-bleu-loireocean', 'lecteur_commun_json/timeline-13125'),
|
||||
'fblorrainenord': (u'France Bleu Lorraine Nord (Metz)', 'player/station/france-bleu-lorrainenord', 'lecteur_commun_json/timeline-13127'),
|
||||
'fbmaine': (u'France Bleu Maine', '/player/station/france-bleu-maine', 'lecteur_commun_json/timeline-13129'),
|
||||
'fbmayenne': (u'France Bleu Mayenne (Laval)', 'player/station/france-bleu-mayenne', 'lecteur_commun_json/timeline-13131'),
|
||||
'fbnord': (u'France Bleu Nord (Lille)', 'player/station/france-bleu-nord', 'lecteur_commun_json/timeline-11235'),
|
||||
'fborleans': (u'France Bleu Orléans', 'player/station/france-bleu-orleans', 'lecteur_commun_json/timeline-13133'),
|
||||
'fbpaysbasque': (u'France Bleu Pays Basque (Bayonne)', 'player/station/france-bleu-paysbasque', 'lecteur_commun_json/timeline-13135'),
|
||||
'fbpaysdauvergne': (u'France Bleu Pays d\'Auvergne (Clermont-Ferrand)', 'player/station/france-bleu-paysdauvergne', 'lecteur_commun_json/timeline-11237'),
|
||||
'fbpaysdesavoie': (u'France Bleu Pays de Savoie (Chambery)', 'player/station/france-bleu-paysdesavoie', 'lecteur_commun_json/timeline-11239'),
|
||||
'fbperigord': (u'France Bleu Périgord (Périgueux)', 'player/station/france-bleu-perigord', 'lecteur_commun_json/timeline-13137'),
|
||||
'fbpicardie': (u'France Bleu Picardie (Amiens)', 'player/station/france-bleu-picardie', 'lecteur_commun_json/timeline-13139'),
|
||||
'fbpoitou': (u'France Bleu Poitou (Poitiers)', 'player/station/france-bleu-poitou', 'lecteur_commun_json/timeline-13141'),
|
||||
'fbprovence': (u'France Bleu Provence (Aix-en-Provence)', 'player/station/france-bleu-provence', 'lecteur_commun_json/timeline-11241'),
|
||||
'fbrcfm': (u'France Bleu RCFM', 'player/station/france-bleu-rcfm', 'lecteur_commun_json/timeline-13143'),
|
||||
'fbsaintetienneloire': (u'France Bleu Saint-Etienne Loire', 'player/station/france-bleu-saint-etienne-loire', 'lecteur_commun_json/timeline-60434'),
|
||||
'fbroussillon': (u'France Bleu Roussillon', 'player/station/france-bleu-roussillon', 'lecteur_commun_json/timeline-11243'),
|
||||
'fbsudlorraine': (u'France Bleu Sud Lorraine (Nancy)', 'player/station/france-bleu-sudlorraine', 'lecteur_commun_json/timeline-13145'),
|
||||
'fbtoulouse': (u'France Bleu Toulouse', 'player/station/france-bleu-toulouse', 'lecteur_commun_json/timeline-13147'),
|
||||
'fbtouraine': (u'France Bleu Touraine (Tours)', 'player/station/france-bleu-touraine', 'lecteur_commun_json/timeline-13149'),
|
||||
'fbvaucluse': (u'France Bleu Vaucluse (Avignon)', 'player/station/france-bleu-vaucluse', 'lecteur_commun_json/timeline-13151'),
|
||||
}
|
||||
|
||||
_PLAYERJS_RADIOS = ('franceinter',
|
||||
'franceculture',
|
||||
'franceinfo',
|
||||
'lemouv',
|
||||
)
|
||||
|
||||
_DIRECTJSON_RADIOS = ('lemouv', )
|
||||
_LARGEDIRECTJSON_RADIOS = ('fip', )
|
||||
_RSS_RADIOS = ('francemusique', )
|
||||
|
||||
def iter_resources(self, objs, split_path):
|
||||
if Radio in objs:
|
||||
if split_path == [u'francebleu']:
|
||||
for _id in sorted(self._RADIOS.iterkeys()):
|
||||
for _id, item in sorted(self._RADIOS.iteritems()):
|
||||
if _id.startswith('fb'):
|
||||
yield self.get_radio(_id)
|
||||
yield Collection([_id], iter(item).next())
|
||||
elif len(split_path) == 0:
|
||||
for _id in sorted(self._RADIOS.iterkeys()):
|
||||
for _id, item in sorted(self._RADIOS.iteritems()):
|
||||
if not _id.startswith('fb'):
|
||||
yield self.get_radio(_id)
|
||||
yield Collection([_id], iter(item).next())
|
||||
yield Collection([u'francebleu'], u'France Bleu')
|
||||
else:
|
||||
raise CollectionNotFound(split_path)
|
||||
|
||||
def iter_radios_search(self, pattern):
|
||||
for radio in self.iter_resources_flat((Radio, ), []):
|
||||
if pattern.lower() in radio.title.lower() or pattern.lower() in radio.description.lower():
|
||||
yield radio
|
||||
|
||||
def get_radio(self, radio):
|
||||
|
||||
def create_stream(url, hd=True):
|
||||
stream = BaseAudioStream(0)
|
||||
if hd:
|
||||
stream.bitrate = 128
|
||||
else:
|
||||
stream.bitrate = 32
|
||||
url = url.replace('midfi128', 'lofi32')
|
||||
|
||||
stream.format = u'mp3'
|
||||
stream.title = u'%s kbits/s' % (stream.bitrate)
|
||||
stream.url = url
|
||||
return stream
|
||||
|
||||
if not isinstance(radio, Radio):
|
||||
radio = Radio(radio)
|
||||
|
||||
if radio.id not in self._RADIOS:
|
||||
return None
|
||||
|
||||
title, hd = self._RADIOS[radio.id]
|
||||
title, player_url, json_url = self._RADIOS[radio.id]
|
||||
radio.title = title
|
||||
radio.description = title
|
||||
radio_name = radio.id if not radio.id.startswith('fb') else 'francebleu'
|
||||
url = self.browser.get_radio_url(radio_name, player_url)
|
||||
|
||||
if hd:
|
||||
url = self._MP3_HD_URL % (radio.id, radio.id)
|
||||
else:
|
||||
url = self._MP3_URL % (radio.id, radio.id)
|
||||
|
||||
# This should be asked demand, but is required for now as Radioob
|
||||
# does not require it.
|
||||
self.fillobj(radio, ('current', ))
|
||||
|
||||
stream = BaseAudioStream(0)
|
||||
if hd:
|
||||
stream.bitrate = 128
|
||||
else:
|
||||
stream.bitrate = 32
|
||||
stream.format = u'mp3'
|
||||
stream.title = u'%s kbits/s' % (stream.bitrate)
|
||||
stream.url = url
|
||||
radio.streams = [stream]
|
||||
radio.streams = [create_stream(url), create_stream(url, False)]
|
||||
return radio
|
||||
|
||||
def fill_radio(self, radio, fields):
|
||||
if 'current' in fields:
|
||||
artist = title = None
|
||||
if radio.id in self._PLAYERJS_RADIOS:
|
||||
artist, title = self.browser.get_current_playerjs(radio.id)
|
||||
if title.endswith(u'par %s' % artist):
|
||||
artist = None
|
||||
if radio.id in self._DIRECTJSON_RADIOS:
|
||||
dartist, dtitle = self.browser.get_current_direct(radio.id)
|
||||
if dartist:
|
||||
artist = dartist
|
||||
if dtitle:
|
||||
if title:
|
||||
title = u"%s [%s]" % (dtitle, title)
|
||||
else:
|
||||
title = dtitle
|
||||
elif radio.id in self._LARGEDIRECTJSON_RADIOS:
|
||||
dartist, dtitle = self.browser.get_current_direct_large(radio.id)
|
||||
if dartist:
|
||||
artist = dartist
|
||||
if dtitle:
|
||||
title = dtitle
|
||||
if radio.id in self._RSS_RADIOS:
|
||||
title = self.browser.get_current_rss(radio.id)
|
||||
if title:
|
||||
if not radio.current or radio.current is NotLoaded:
|
||||
radio.current = StreamInfo(0)
|
||||
radio.current.what = title
|
||||
radio.current.who = artist
|
||||
title, player_url, json_url = self._RADIOS[radio.id]
|
||||
radio_name = radio.id if not radio.id.startswith('fb') else 'francebleu'
|
||||
artist, title = self.browser.get_current(radio_name, json_url)
|
||||
if not radio.current or radio.current is NotLoaded:
|
||||
radio.current = StreamInfo(0)
|
||||
radio.current.what = title
|
||||
radio.current.who = artist
|
||||
return radio
|
||||
|
||||
# TODO
|
||||
# http://www.franceculture.fr/recherche/key%3DYOURSEARCH%2526type%3Demission
|
||||
# http://www.franceinter.fr/recherche/key%3DYOURSEARCH%2526tri%3Dpertinence%2526theme%3Ddefault%2526type%3Demission
|
||||
#def search_videos(self, *args, **kwargs):
|
||||
# return []
|
||||
|
||||
def get_video(self, _id):
|
||||
with self.browser:
|
||||
video = self.browser.get_video(_id)
|
||||
return video
|
||||
|
||||
def fill_video(self, video, fields):
|
||||
if 'url' in fields:
|
||||
with self.browser:
|
||||
video.url = unicode(self.browser.get_url(video.id))
|
||||
|
||||
return video
|
||||
|
||||
OBJECTS = {Radio: fill_radio,
|
||||
RadioFranceVideo: fill_video}
|
||||
OBJECTS = {Radio: fill_radio}
|
||||
|
|
|
|||
62
modules/radiofrance/pages.py
Normal file
62
modules/radiofrance/pages.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright(C) 2013 Bezleputh
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
from weboob.browser.pages import HTMLPage, JsonPage
|
||||
from weboob.browser.filters.standard import CleanText
|
||||
import time
|
||||
|
||||
|
||||
class PlayerPage(HTMLPage):
|
||||
def get_url(self):
|
||||
return CleanText('//a[@id="player"][1]/@href')(self.doc)
|
||||
|
||||
|
||||
class TimelinePage(JsonPage):
|
||||
def get_current(self):
|
||||
if 'current' in self.doc:
|
||||
emission_title = self.doc['current']['emission']['titre']
|
||||
song_title = self.doc['current']['song']['titre']
|
||||
title = '%s: %s' % (emission_title, song_title)
|
||||
person = self.doc['current']['song']['interpreteMorceau']
|
||||
return person, title
|
||||
elif 'diffusions' in self.doc:
|
||||
now = int(time.time())
|
||||
for item in self.doc['diffusions']:
|
||||
if item['debut'] < now and item['fin'] > now:
|
||||
title = u'%s: %s' % (item['title_emission'], item['title_diff'])
|
||||
person = u''
|
||||
return person, title
|
||||
return u'', u''
|
||||
else:
|
||||
now = int(time.time())
|
||||
for item in self.doc:
|
||||
if item['debut'] < now and item['fin'] > now:
|
||||
emission = ''
|
||||
if 'diffusions' in item and item['diffusions']:
|
||||
emission = item['diffusions'][0]['title']
|
||||
|
||||
title = item['title_emission']
|
||||
if emission:
|
||||
title = u'%s: %s' % (title, emission)
|
||||
|
||||
person = u''
|
||||
if 'personnes' in item:
|
||||
person = u','.join(item['personnes'])
|
||||
return person, title
|
||||
return u'', u''
|
||||
|
|
@ -29,35 +29,18 @@ class RadioFranceTest(BackendTest):
|
|||
def test_get_radios(self):
|
||||
l = list(self.backend.iter_resources(objs=[Radio], split_path=[]))
|
||||
self.assertTrue(0 < len(l) < 30)
|
||||
for radio in l:
|
||||
name = radio.split_path[-1]
|
||||
if name != 'francebleu':
|
||||
streams = self.backend.get_radio(name).streams
|
||||
self.assertTrue(len(streams) > 0)
|
||||
|
||||
l = list(self.backend.iter_resources(objs=[Radio], split_path=['francebleu']))
|
||||
self.assertTrue(len(l) > 30)
|
||||
|
||||
for radio in l:
|
||||
streams = self.backend.get_radio(radio.split_path[-1]).streams
|
||||
self.assertTrue(len(streams) > 0)
|
||||
|
||||
l = list(self.backend.iter_resources(objs=[BaseVideo], split_path=[]))
|
||||
self.assertEquals(len(l), 0)
|
||||
|
||||
def test_get_video(self):
|
||||
# this should be available up to 24/10/2014 15h00
|
||||
urls = ('http://www.franceinter.fr/emission-vivre-avec-les-betes-y-arthus-bertrand-felins-g-tsai-s-envoler-conte-boreal-reha-hutin-30-m',
|
||||
'http://www.franceinter.fr/player/reecouter?play=263735',
|
||||
'franceinter-263735')
|
||||
for url in urls:
|
||||
vid = self.backend.get_video(url)
|
||||
assert vid.id == urls[-1]
|
||||
self.backend.fillobj(vid, ['url'])
|
||||
assert vid.url.lower().endswith('.mp3')
|
||||
|
||||
# france culture (no expiration known)
|
||||
vid = self.backend.get_video('http://www.franceculture.fr/emission-la-dispute-expositions-paul-strand-youssef-nabil-et-dorothee-smith-2012-02-01')
|
||||
assert vid.id
|
||||
self.backend.fillobj(vid, ['url'])
|
||||
assert vid.url.lower().endswith('.mp3')
|
||||
|
||||
# fip (no expiration known)
|
||||
# getting the proper ID is hard, hence the tests with many urls for the same content
|
||||
urls = ('http://www.fipradio.fr/diffusion-club-jazzafip-du-13-mars',
|
||||
'http://www.fipradio.fr/player/reecouter?play=20686',
|
||||
'fip-20686')
|
||||
for url in urls:
|
||||
vid = self.backend.get_video(url)
|
||||
assert vid.id == urls[-1]
|
||||
self.backend.fillobj(vid, ['url'])
|
||||
assert vid.url.lower().endswith('.mp3')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue