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) 
  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
)