2 from __future__
import unicode_literals
6 from .common
import InfoExtractor
7 from ..utils
import ExtractorError
8 from ..compat
import compat_urlparse
11 class TuneInBaseIE(InfoExtractor
):
12 _API_BASE_URL
= 'http://tunein.com/tuner/tune/'
15 def _extract_urls(webpage
):
17 r
'<iframe[^>]+src=["\'](?P
<url
>(?
:https?
://)?tunein\
.com
/embed
/player
/[pst
]\d
+)',
20 def _real_extract(self, url):
21 content_id = self._match_id(url)
23 content_info = self._download_json(
24 self._API_BASE_URL + self._API_URL_QUERY % content_id,
25 content_id, note='Downloading JSON metadata
')
27 title = content_info['Title
']
28 thumbnail = content_info.get('Logo
')
29 location = content_info.get('Location
')
30 streams_url = content_info.get('StreamUrl
')
32 raise ExtractorError('No downloadable streams found
', expected=True)
33 if not streams_url.startswith('http
://'):
34 streams_url = compat_urlparse.urljoin(url, streams_url)
36 streams = self._download_json(
37 streams_url, content_id, note='Downloading stream data
',
38 transform_source=lambda s: re.sub(r'^\s
*\
((.*)\
);\s
*$
', r'\
1', s))['Streams
']
42 for stream in streams:
43 if stream.get('Type
') == 'Live
':
45 reliability = stream.get('Reliability
')
47 'Reliability
: %d%%' % reliability
48 if reliability is not None else None)
51 0 if reliability is None or reliability > 90
53 'abr
': stream.get('Bandwidth
'),
54 'ext
': stream.get('MediaType
').lower(),
55 'acodec
': stream.get('MediaType
'),
57 'url
': stream.get('Url
'),
58 'source_preference
': reliability,
59 'format_note
': format_note,
61 self._sort_formats(formats)
65 'title
': self._live_title(title) if is_live else title,
67 'thumbnail
': thumbnail,
73 class TuneInClipIE(TuneInBaseIE):
74 IE_NAME = 'tunein
:clip
'
75 _VALID_URL = r'https?
://(?
:www\
.)?tunein\
.com
/station
/.*?audioClipId\
=(?P
<id>\d
+)'
76 _API_URL_QUERY = '?tuneType
=AudioClip
&audioclipId
=%s'
79 'url
': 'http
://tunein
.com
/station
/?stationId
=246119&audioClipId
=816',
80 'md5
': '99f00d772db70efc804385c6b47f4e77
',
89 class TuneInStationIE(TuneInBaseIE):
90 IE_NAME = 'tunein
:station
'
91 _VALID_URL = r'https?
://(?
:www\
.)?tunein\
.com
/(?
:radio
/.*?
-s|station
/.*?StationId
=|embed
/player
/s
)(?P
<id>\d
+)'
92 _API_URL_QUERY = '?tuneType
=Station
&stationId
=%s'
95 def suitable(cls, url):
96 return False if TuneInClipIE.suitable(url) else super(TuneInStationIE, cls).suitable(url)
99 'url
': 'http
://tunein
.com
/radio
/Jazz24
-885-s34682
/',
102 'title
': 'Jazz
24 on
88.5 Jazz24
- KPLU
-HD2
',
104 'location
': 'Tacoma
, WA
',
107 'skip_download
': True, # live stream
110 'url
': 'http
://tunein
.com
/embed
/player
/s6404
/',
111 'only_matching
': True,
115 class TuneInProgramIE(TuneInBaseIE):
116 IE_NAME = 'tunein
:program
'
117 _VALID_URL = r'https?
://(?
:www\
.)?tunein\
.com
/(?
:radio
/.*?
-p|program
/.*?ProgramId
=|embed
/player
/p
)(?P
<id>\d
+)'
118 _API_URL_QUERY = '?tuneType
=Program
&programId
=%s'
121 'url
': 'http
://tunein
.com
/radio
/Jazz
-24-p2506
/',
124 'title
': 'Jazz
24 on
91.3 WUKY
-HD3
',
126 'location
': 'Lexington
, KY
',
129 'skip_download
': True, # live stream
132 'url
': 'http
://tunein
.com
/embed
/player
/p191660
/',
133 'only_matching
': True,
137 class TuneInTopicIE(TuneInBaseIE):
138 IE_NAME = 'tunein
:topic
'
139 _VALID_URL = r'https?
://(?
:www\
.)?tunein\
.com
/(?
:topic
/.*?TopicId
=|embed
/player
/t
)(?P
<id>\d
+)'
140 _API_URL_QUERY = '?tuneType
=Topic
&topicId
=%s'
143 'url
': 'http
://tunein
.com
/topic
/?TopicId
=101830576',
144 'md5
': 'c31a39e6f988d188252eae7af0ef09c9
',
147 'title
': 'Votez pour moi du
29 octobre
2015 (29/10/15)',
149 'location
': 'Belgium
',
152 'url
': 'http
://tunein
.com
/embed
/player
/t101830576
/',
153 'only_matching
': True,
157 class TuneInShortenerIE(InfoExtractor):
158 IE_NAME = 'tunein
:shortener
'
159 IE_DESC = False # Do not list
160 _VALID_URL = r'https?
://tun\
.in/(?P
<id>[A
-Za
-z0
-9]+)'
164 'url
': 'http
://tun
.in/ser7s
',
167 'title
': 'Jazz
24 on
88.5 Jazz24
- KPLU
-HD2
',
169 'location
': 'Tacoma
, WA
',
172 'skip_download
': True, # live stream
176 def _real_extract(self, url):
177 redirect_id = self._match_id(url)
178 # The server doesn't support HEAD requests
179 urlh
= self
._request
_webpage
(
180 url
, redirect_id
, note
='Downloading redirect page')
182 self
.to_screen('Following redirect: %s' % url
)
183 return self
.url_result(url
)