3 from .common
import InfoExtractor
4 from ..utils
import ExtractorError
5 from ..compat
import compat_urlparse
8 class TuneInBaseIE(InfoExtractor
):
9 _API_BASE_URL
= 'http://tunein.com/tuner/tune/'
11 def _real_extract(self
, url
):
12 content_id
= self
._match
_id
(url
)
14 content_info
= self
._download
_json
(
15 self
._API
_BASE
_URL
+ self
._API
_URL
_QUERY
% content_id
,
16 content_id
, note
='Downloading JSON metadata')
18 title
= content_info
['Title']
19 thumbnail
= content_info
.get('Logo')
20 location
= content_info
.get('Location')
21 streams_url
= content_info
.get('StreamUrl')
23 raise ExtractorError('No downloadable streams found', expected
=True)
24 if not streams_url
.startswith('http://'):
25 streams_url
= compat_urlparse
.urljoin(url
, streams_url
)
27 streams
= self
._download
_json
(
28 streams_url
, content_id
, note
='Downloading stream data',
29 transform_source
=lambda s
: re
.sub(r
'^\s*\((.*)\);\s*$', r
'\1', s
))['Streams']
33 for stream
in streams
:
34 if stream
.get('Type') == 'Live':
36 reliability
= stream
.get('Reliability')
38 'Reliability: %d%%' % reliability
39 if reliability
is not None else None)
42 0 if reliability
is None or reliability
> 90
44 'abr': stream
.get('Bandwidth'),
45 'ext': stream
.get('MediaType').lower(),
46 'acodec': stream
.get('MediaType'),
48 'url': stream
.get('Url'),
49 'source_preference': reliability
,
50 'format_note': format_note
,
57 'thumbnail': thumbnail
,
63 class TuneInClipIE(TuneInBaseIE
):
64 IE_NAME
= 'tunein:clip'
65 _VALID_URL
= r
'https?://(?:www\.)?tunein\.com/station/.*?audioClipId\=(?P<id>\d+)'
66 _API_URL_QUERY
= '?tuneType=AudioClip&audioclipId=%s'
69 'url': 'http://tunein.com/station/?stationId=246119&audioClipId=816',
70 'md5': '99f00d772db70efc804385c6b47f4e77',
79 class TuneInStationIE(TuneInBaseIE
):
80 IE_NAME
= 'tunein:station'
81 _VALID_URL
= r
'https?://(?:www\.)?tunein\.com/(?:radio/.*?-s|station/.*?StationId=|embed/player/s)(?P<id>\d+)'
82 _EMBED_REGEX
= [r
'<iframe[^>]+src=["\'](?P
<url
>(?
:https?
://)?tunein\
.com
/embed
/player
/[pst
]\d
+)']
83 _API_URL_QUERY = '?tuneType
=Station
&stationId
=%s'
86 def suitable(cls, url):
87 return False if TuneInClipIE.suitable(url) else super(TuneInStationIE, cls).suitable(url)
90 'url
': 'http
://tunein
.com
/radio
/Jazz24
-885-s34682
/',
93 'title
': 'Jazz
24 on
88.5 Jazz24
- KPLU
-HD2
',
95 'location
': 'Tacoma
, WA
',
98 'skip_download
': True, # live stream
101 'url
': 'http
://tunein
.com
/embed
/player
/s6404
/',
102 'only_matching
': True,
106 class TuneInProgramIE(TuneInBaseIE):
107 IE_NAME = 'tunein
:program
'
108 _VALID_URL = r'https?
://(?
:www\
.)?tunein\
.com
/(?
:radio
/.*?
-p|program
/.*?ProgramId
=|embed
/player
/p
)(?P
<id>\d
+)'
109 _API_URL_QUERY = '?tuneType
=Program
&programId
=%s'
112 'url
': 'http
://tunein
.com
/radio
/Jazz
-24-p2506
/',
115 'title
': 'Jazz
24 on
91.3 WUKY
-HD3
',
117 'location
': 'Lexington
, KY
',
120 'skip_download
': True, # live stream
123 'url
': 'http
://tunein
.com
/embed
/player
/p191660
/',
124 'only_matching
': True,
128 class TuneInTopicIE(TuneInBaseIE):
129 IE_NAME = 'tunein
:topic
'
130 _VALID_URL = r'https?
://(?
:www\
.)?tunein\
.com
/(?
:topic
/.*?TopicId
=|embed
/player
/t
)(?P
<id>\d
+)'
131 _API_URL_QUERY = '?tuneType
=Topic
&topicId
=%s'
134 'url
': 'http
://tunein
.com
/topic
/?TopicId
=101830576',
135 'md5
': 'c31a39e6f988d188252eae7af0ef09c9
',
138 'title
': 'Votez pour moi du
29 octobre
2015 (29/10/15)',
140 'location
': 'Belgium
',
143 'url
': 'http
://tunein
.com
/embed
/player
/t101830576
/',
144 'only_matching
': True,
148 class TuneInShortenerIE(InfoExtractor):
149 IE_NAME = 'tunein
:shortener
'
150 IE_DESC = False # Do not list
151 _VALID_URL = r'https?
://tun\
.in/(?P
<id>[A
-Za
-z0
-9]+)'
155 'url
': 'http
://tun
.in/ser7s
',
158 'title
': 'Jazz
24 on
88.5 Jazz24
- KPLU
-HD2
',
160 'location
': 'Tacoma
, WA
',
163 'skip_download
': True, # live stream
167 def _real_extract(self, url):
168 redirect_id = self._match_id(url)
169 # The server doesn't support HEAD requests
170 urlh
= self
._request
_webpage
(
171 url
, redirect_id
, note
='Downloading redirect page')
173 self
.to_screen('Following redirect: %s' % url
)
174 return self
.url_result(url
)