diff --git a/modules/virginradio/browser.py b/modules/virginradio/browser.py new file mode 100644 index 0000000000000000000000000000000000000000..61adc8a233fb93cb90f45a127c1d394add4f74bb --- /dev/null +++ b/modules/virginradio/browser.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2020 Johann Broudin +# +# This file is part of a weboob module. +# +# This weboob module 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. +# +# This weboob module is distribute 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 this weboob module. If not, see . + +from weboob.tools.capabilities.streaminfo import StreamInfo +from weboob.browser import Browser + +from . import parser + +class VirginBrowser(Browser): + _RADIOS_URL = 'https://www.virginradio.fr/desktop/js/all.min.js' + _PROGRAM_URL = 'https://www.virginradio.fr/calendar/api/current.json/argv/calendar_type/emission/origine_flags/virginradio/get_current_foreign_type/TRUE' + _INFO_URL = 'https://www.virginradio.fr/radio/api/get_current_event/?id_radio=%s' + _WEBRADIOS_URL = 'https://www.virginradio.fr/webradios/' + + def radios(self): + webradios = self.open(self._WEBRADIOS_URL) + radiosjs = self.open(self._RADIOS_URL) + radios = parser.radios(webradios, radiosjs) + self._radios = radios + return radios + + def radio(self, radio): + if not self._radios: + self.radios() + + if not radio in self._radios: + return None + + return self._radios[radio] + + def current(self, radio): + r = self.open(self._INFO_URL % (radio['radio_id'])) + who, what = parser.current(r) + current = StreamInfo(0) + current.who = who + current.what = what + return current + + def description(self, radio): + description = radio['title'] + if radio['name'] == 'live': + r = self.open(self._PROGRAM_URL) + description = parser.description(r) + + return description diff --git a/modules/virginradio/module.py b/modules/virginradio/module.py index 77e903b0de02fcb688fd9dfaa9f1ad7fe856423b..17eebadbff3efd46b8635ae0ce072f961efc8b76 100644 --- a/modules/virginradio/module.py +++ b/modules/virginradio/module.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright(C) 2014 Johann Broudin +# Copyright(C) 2020 Johann Broudin # # This file is part of a weboob module. # @@ -20,13 +20,9 @@ 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 from weboob.tools.backend import Module -from weboob.browser import Browser -import re -from lxml import html - +from .browser import VirginBrowser __all__ = ['VirginRadioModule'] @@ -38,86 +34,45 @@ class VirginRadioModule(Module, CapRadio, CapCollection): VERSION = '2.1' DESCRIPTION = u'VirginRadio french radio' LICENSE = 'AGPLv3+' - BROWSER = Browser - - _RADIOS_URL = 'https://www.virginradio.fr/desktop/js/all.min.js' - _RADIOS_RE = ( - r'{id:(?P\d+),' - r'id_radio:(?P\d+),' - r'type:"[^"]*",' - r'name:"(?P[^"]*)",' - r'hls_source:"(?P[^"]*)",' - r'source:"(?P[^"]*)"' - ) - - _PROGRAM_URL = 'https://www.virginradio.fr/calendar/api/current.json/argv/calendar_type/emission/origine_flags/virginradio/get_current_foreign_type/TRUE' - _INFO_URL = 'https://www.virginradio.fr/radio/api/get_current_event/?id_radio=%s' - - _WEBRADIOS_URL = 'https://www.virginradio.fr/webradios/' - _XPATH_RADIO_NAME = '//ul/li[@class="brick"]/div/div[@data-id="%s"]/ancestor::li/div/h3/text()' - - _RADIOS = {} + BROWSER = VirginBrowser def get_radio(self, radio): - self.get_radios() if not isinstance(radio, Radio): radio = Radio(radio) - if radio.id not in self._RADIOS: + r = self.browser.radio(radio.id) + + if r is None: return None - radio.title = self._RADIOS[radio.id]['title'] - radio.description = self._RADIOS[radio.id]['title'] + radio.title = r['title'] - if radio.id == 'live': - r = self.browser.open(self._PROGRAM_URL) - info = r.json()['root_tab']['events'][0] - radio.description = "%s - %s" % (info['title'], info['tab_foreign_type']['resum']) + radio.description = self.browser.description(r) stream_hls = BaseAudioStream(0) - stream_hls.url = self._RADIOS[radio.id]['hls_source'] - stream_hls.bitrate = 128 + stream_hls.url = r['hls_source'] + stream_hls.bitrate = 135 stream_hls.format=u'aac' + stream_hls.title = u'%s %skbits/s' % (stream_hls.format, stream_hls.bitrate) stream = BaseAudioStream(0) - stream.url = self._RADIOS[radio.id]['source'] + stream.url = r['source'] stream.bitrate = 128 stream.format=u'mp3' + stream.title = u'%s %skbits/s' % (stream.format, stream.bitrate) - current = StreamInfo(0) - current.who = '' - current.what = '' - - r = self.browser.open(self._INFO_URL % (self._RADIOS[radio.id]['radio_id'])) - info = r.json()['root_tab']['event'] - if len(info) > 0: - current.who = info[0]['artist'] - current.what = info[0]['title'] radio.streams = [stream_hls, stream] - radio.current = current - return radio + radio.current = self.browser.current(r) - def get_radios(self): - webradios = self.browser.open(self._WEBRADIOS_URL) - tree = html.fromstring(webradios.content) - - if not self._RADIOS: - r = self.browser.open(self._RADIOS_URL) - for m in re.finditer(self._RADIOS_RE, r.text): - self._RADIOS[m.group('name')] = { - 'radio_id': m.group('id_radio'), - 'name': m.group('name'), - 'hls_source': m.group('hls_source'), - 'source': m.group('source'), - 'title': tree.xpath(self._XPATH_RADIO_NAME % (m.group('id_radio')))[0] } + return radio def iter_resources(self, objs, split_path): if Radio in objs: self._restrict_level(split_path) - self.get_radios() + radios = self.browser.radios() - for id in self._RADIOS: + for id in radios: yield self.get_radio(id) def iter_radios_search(self, pattern): diff --git a/modules/virginradio/parser.py b/modules/virginradio/parser.py new file mode 100644 index 0000000000000000000000000000000000000000..647812543b3cbf791e44dc8adad8cbd3a8f154a8 --- /dev/null +++ b/modules/virginradio/parser.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2020 Johann Broudin +# +# This file is part of a weboob module. +# +# This weboob module 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. +# +# This weboob module 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 this weboob module. If not, see . + +import re + +from lxml import html + +def radios(webradios, radiosjs): + radiosjs_re = ( + r'{id:(?P\d+),' + r'id_radio:(?P\d+),' + r'type:"[^"]*",' + r'name:"(?P[^"]*)",' + r'hls_source:"(?P[^"]*)",' + r'source:"(?P[^"]*)"' + ) + webradios_xpath = '//ul/li[@class="brick"]/div/div[@data-id="%s"]/ancestor::li/div/h3/text()' + + radios = {} + tree = html.fromstring(webradios.content) + for m in re.finditer(radiosjs_re, radiosjs.text): + radios[m.group('name')] = { 'radio_id': m.group('id_radio'), + 'name': m.group('name'), + 'hls_source': m.group('hls_source'), + 'source': m.group('source'), + 'title': tree.xpath(webradios_xpath % (m.group('id_radio')))[0] } + + return radios + +def current(r): + artist = '' + title = '' + info = r.json()['root_tab']['event'] + if len(info) > 0: + artist = info[0]['artist'] + title = info[0]['title'] + + return artist, title + +def description(r): + description = '' + info = r.json()['root_tab']['events'] + if len(info) > 0: + description = "%s - %s" % (info[0]['title'], info[0]['tab_foreign_type']['resum']) + + return description +