]>
Commit | Line | Data |
---|---|---|
2c25a2bd NJ |
1 | # coding: utf-8 |
2 | from __future__ import unicode_literals | |
3 | ||
4 | import json | |
2c25a2bd NJ |
5 | |
6 | from .common import InfoExtractor | |
7 | from ..utils import ExtractorError | |
bd3f9eca | 8 | from ..compat import compat_urlparse |
2c25a2bd NJ |
9 | |
10 | ||
bd3f9eca | 11 | class TuneInBaseIE(InfoExtractor): |
12 | _API_BASE_URL = 'http://tunein.com/tuner/tune/' | |
2c25a2bd NJ |
13 | |
14 | def _real_extract(self, url): | |
bd3f9eca | 15 | content_id = self._match_id(url) |
16 | ||
17 | content_info = self._download_json( | |
18 | self._API_BASE_URL + self._API_URL_QUERY % content_id, | |
19 | content_id, note='Downloading JSON metadata') | |
20 | ||
21 | title = content_info['Title'] | |
22 | thumbnail = content_info.get('Logo') | |
23 | location = content_info.get('Location') | |
24 | streams_url = content_info.get('StreamUrl') | |
2c25a2bd | 25 | if not streams_url: |
bd3f9eca | 26 | raise ExtractorError('No downloadable streams found', expected=True) |
27 | if not streams_url.startswith('http://'): | |
28 | streams_url = compat_urlparse.urljoin(url, streams_url) | |
29 | ||
2c25a2bd | 30 | stream_data = self._download_webpage( |
bd3f9eca | 31 | streams_url, content_id, note='Downloading stream data') |
2c25a2bd NJ |
32 | streams = json.loads(self._search_regex( |
33 | r'\((.*)\);', stream_data, 'stream info'))['Streams'] | |
34 | ||
35 | is_live = None | |
36 | formats = [] | |
37 | for stream in streams: | |
38 | if stream.get('Type') == 'Live': | |
39 | is_live = True | |
ec3a6a31 PH |
40 | reliability = stream.get('Reliability') |
41 | format_note = ( | |
42 | 'Reliability: %d%%' % reliability | |
43 | if reliability is not None else None) | |
2c25a2bd | 44 | formats.append({ |
ec3a6a31 PH |
45 | 'preference': ( |
46 | 0 if reliability is None or reliability > 90 | |
47 | else 1), | |
2c25a2bd | 48 | 'abr': stream.get('Bandwidth'), |
ec3a6a31 | 49 | 'ext': stream.get('MediaType').lower(), |
2c25a2bd NJ |
50 | 'acodec': stream.get('MediaType'), |
51 | 'vcodec': 'none', | |
52 | 'url': stream.get('Url'), | |
ec3a6a31 PH |
53 | 'source_preference': reliability, |
54 | 'format_note': format_note, | |
2c25a2bd NJ |
55 | }) |
56 | self._sort_formats(formats) | |
57 | ||
58 | return { | |
bd3f9eca | 59 | 'id': content_id, |
2c25a2bd NJ |
60 | 'title': title, |
61 | 'formats': formats, | |
62 | 'thumbnail': thumbnail, | |
63 | 'location': location, | |
64 | 'is_live': is_live, | |
65 | } | |
bd3f9eca | 66 | |
67 | ||
68 | class TuneInClipIE(TuneInBaseIE): | |
69 | IE_NAME = 'tunein:clip' | |
70 | _VALID_URL = r'https?://(?:www\.)?tunein\.com/station/.*?audioClipId\=(?P<id>\d+)' | |
71 | _API_URL_QUERY = '?tuneType=AudioClip&audioclipId=%s' | |
72 | ||
73 | _TESTS = [ | |
74 | { | |
75 | 'url': 'http://tunein.com/station/?stationId=246119&audioClipId=816', | |
76 | 'md5': '99f00d772db70efc804385c6b47f4e77', | |
77 | 'info_dict': { | |
78 | 'id': '816', | |
79 | 'title': '32m', | |
80 | 'ext': 'mp3', | |
81 | }, | |
82 | }, | |
83 | ] | |
84 | ||
85 | ||
86 | class TuneInStationIE(TuneInBaseIE): | |
87 | IE_NAME = 'tunein:station' | |
88 | _VALID_URL = r'https?://(?:www\.)?tunein\.com/(?:radio/.*?-s|station/.*?StationId\=)(?P<id>\d+)' | |
89 | _API_URL_QUERY = '?tuneType=Station&stationId=%s' | |
90 | ||
91 | @classmethod | |
92 | def suitable(cls, url): | |
93 | return False if TuneInClipIE.suitable(url) else super(TuneInStationIE, cls).suitable(url) | |
94 | ||
95 | _TESTS = [ | |
96 | { | |
97 | 'url': 'http://tunein.com/radio/Jazz24-885-s34682/', | |
98 | 'info_dict': { | |
99 | 'id': '34682', | |
100 | 'title': 'Jazz 24 on 88.5 Jazz24 - KPLU-HD2', | |
101 | 'ext': 'mp3', | |
102 | 'location': 'Tacoma, WA', | |
103 | }, | |
104 | 'params': { | |
105 | 'skip_download': True, # live stream | |
106 | }, | |
107 | }, | |
108 | ] | |
109 | ||
110 | ||
111 | class TuneInProgramIE(TuneInBaseIE): | |
112 | IE_NAME = 'tunein:program' | |
113 | _VALID_URL = r'https?://(?:www\.)?tunein\.com/(?:radio/.*?-p|program/.*?ProgramId\=)(?P<id>\d+)' | |
114 | _API_URL_QUERY = '?tuneType=Program&programId=%s' | |
115 | ||
116 | _TESTS = [ | |
117 | { | |
118 | 'url': 'http://tunein.com/radio/Jazz-24-p2506/', | |
119 | 'info_dict': { | |
120 | 'id': '2506', | |
121 | 'title': 'Jazz 24 on 91.3 WUKY-HD3', | |
122 | 'ext': 'mp3', | |
123 | 'location': 'Lexington, KY', | |
124 | }, | |
125 | 'params': { | |
126 | 'skip_download': True, # live stream | |
127 | }, | |
128 | }, | |
129 | ] | |
130 | ||
131 | ||
132 | class TuneInTopicIE(TuneInBaseIE): | |
133 | IE_NAME = 'tunein:topic' | |
134 | _VALID_URL = r'https?://(?:www\.)?tunein\.com/topic/.*?TopicId\=(?P<id>\d+)' | |
135 | _API_URL_QUERY = '?tuneType=Topic&topicId=%s' | |
136 | ||
137 | _TESTS = [ | |
138 | { | |
139 | 'url': 'http://tunein.com/topic/?TopicId=101830576', | |
140 | 'md5': 'c31a39e6f988d188252eae7af0ef09c9', | |
141 | 'info_dict': { | |
142 | 'id': '101830576', | |
143 | 'title': 'Votez pour moi du 29 octobre 2015 (29/10/15)', | |
144 | 'ext': 'mp3', | |
145 | 'location': 'Belgium', | |
146 | }, | |
147 | }, | |
148 | ] | |
149 | ||
150 | ||
151 | class TuneInShortenerIE(InfoExtractor): | |
152 | IE_NAME = 'tunein:shortener' | |
153 | IE_DESC = False # Do not list | |
154 | _VALID_URL = r'https?://tun\.in/(?P<id>[A-Za-z0-9]+)' | |
155 | ||
156 | _TEST = { | |
157 | # test redirection | |
158 | 'url': 'http://tun.in/ser7s', | |
159 | 'info_dict': { | |
160 | 'id': '34682', | |
161 | 'title': 'Jazz 24 on 88.5 Jazz24 - KPLU-HD2', | |
162 | 'ext': 'mp3', | |
163 | 'location': 'Tacoma, WA', | |
164 | }, | |
165 | 'params': { | |
166 | 'skip_download': True, # live stream | |
167 | }, | |
168 | } | |
169 | ||
170 | def _real_extract(self, url): | |
171 | redirect_id = self._match_id(url) | |
172 | # The server doesn't support HEAD requests | |
173 | urlh = self._request_webpage( | |
174 | url, redirect_id, note='Downloading redirect page') | |
175 | url = urlh.geturl() | |
176 | self.to_screen('Following redirect: %s' % url) | |
177 | return self.url_result(url) |