vgtv.py (10882B)
1 # coding: utf-8 2 from __future__ import unicode_literals 3 4 import re 5 6 from .common import InfoExtractor 7 from .xstream import XstreamIE 8 from ..utils import ( 9 ExtractorError, 10 float_or_none, 11 try_get, 12 ) 13 14 15 class VGTVIE(XstreamIE): 16 IE_DESC = 'VGTV, BTTV, FTV, Aftenposten and Aftonbladet' 17 _GEO_BYPASS = False 18 19 _HOST_TO_APPNAME = { 20 'vgtv.no': 'vgtv', 21 'bt.no/tv': 'bttv', 22 'aftenbladet.no/tv': 'satv', 23 'fvn.no/fvntv': 'fvntv', 24 'aftenposten.no/webtv': 'aptv', 25 'ap.vgtv.no/webtv': 'aptv', 26 'tv.aftonbladet.se': 'abtv', 27 # obsolete URL schemas, kept in order to save one HTTP redirect 28 'tv.aftonbladet.se/abtv': 'abtv', 29 'www.aftonbladet.se/tv': 'abtv', 30 } 31 32 _APP_NAME_TO_VENDOR = { 33 'vgtv': 'vgtv', 34 'bttv': 'bt', 35 'satv': 'sa', 36 'fvntv': 'fvn', 37 'aptv': 'ap', 38 'abtv': 'ab', 39 } 40 41 _VALID_URL = r'''(?x) 42 (?:https?://(?:www\.)? 43 (?P<host> 44 %s 45 ) 46 /? 47 (?: 48 (?:\#!/)?(?:video|live)/| 49 embed?.*id=| 50 a(?:rticles)?/ 51 )| 52 (?P<appname> 53 %s 54 ):) 55 (?P<id>\d+) 56 ''' % ('|'.join(_HOST_TO_APPNAME.keys()), '|'.join(_APP_NAME_TO_VENDOR.keys())) 57 58 _TESTS = [ 59 { 60 # streamType: vod 61 'url': 'http://www.vgtv.no/#!/video/84196/hevnen-er-soet-episode-10-abu', 62 'md5': 'b8be7a234cebb840c0d512c78013e02f', 63 'info_dict': { 64 'id': '84196', 65 'ext': 'mp4', 66 'title': 'Hevnen er søt: Episode 10 - Abu', 67 'description': 'md5:e25e4badb5f544b04341e14abdc72234', 68 'thumbnail': r're:^https?://.*\.jpg', 69 'duration': 648.000, 70 'timestamp': 1404626400, 71 'upload_date': '20140706', 72 'view_count': int, 73 }, 74 }, 75 { 76 # streamType: wasLive 77 'url': 'http://www.vgtv.no/#!/live/100764/opptak-vgtv-foelger-em-kvalifiseringen', 78 'info_dict': { 79 'id': '100764', 80 'ext': 'flv', 81 'title': 'OPPTAK: VGTV følger EM-kvalifiseringen', 82 'description': 'md5:3772d9c0dc2dff92a886b60039a7d4d3', 83 'thumbnail': r're:^https?://.*\.jpg', 84 'duration': 9103.0, 85 'timestamp': 1410113864, 86 'upload_date': '20140907', 87 'view_count': int, 88 }, 89 'params': { 90 # m3u8 download 91 'skip_download': True, 92 }, 93 'skip': 'Video is no longer available', 94 }, 95 { 96 # streamType: wasLive 97 'url': 'http://www.vgtv.no/#!/live/113063/direkte-v75-fra-solvalla', 98 'info_dict': { 99 'id': '113063', 100 'ext': 'mp4', 101 'title': 'V75 fra Solvalla 30.05.15', 102 'description': 'md5:b3743425765355855f88e096acc93231', 103 'thumbnail': r're:^https?://.*\.jpg', 104 'duration': 25966, 105 'timestamp': 1432975582, 106 'upload_date': '20150530', 107 'view_count': int, 108 }, 109 'params': { 110 # m3u8 download 111 'skip_download': True, 112 }, 113 }, 114 { 115 'url': 'http://www.aftenposten.no/webtv/#!/video/21039/trailer-sweatshop-i-can-t-take-any-more', 116 'md5': 'fd828cd29774a729bf4d4425fe192972', 117 'info_dict': { 118 'id': '21039', 119 'ext': 'mp4', 120 'title': 'TRAILER: «SWEATSHOP» - I can´t take any more', 121 'description': 'md5:21891f2b0dd7ec2f78d84a50e54f8238', 122 'duration': 66, 123 'timestamp': 1417002452, 124 'upload_date': '20141126', 125 'view_count': int, 126 }, 127 'params': { 128 # m3u8 download 129 'skip_download': True, 130 }, 131 }, 132 { 133 'url': 'http://www.bt.no/tv/#!/video/100250/norling-dette-er-forskjellen-paa-1-divisjon-og-eliteserien', 134 'only_matching': True, 135 }, 136 { 137 'url': 'http://ap.vgtv.no/webtv#!/video/111084/de-nye-bysyklene-lettere-bedre-gir-stoerre-hjul-og-feste-til-mobil', 138 'only_matching': True, 139 }, 140 { 141 # geoblocked 142 'url': 'http://www.vgtv.no/#!/video/127205/inside-the-mind-of-favela-funk', 143 'only_matching': True, 144 }, 145 { 146 'url': 'https://tv.aftonbladet.se/video/36015/vulkanutbrott-i-rymden-nu-slapper-nasa-bilderna', 147 'only_matching': True, 148 }, 149 { 150 'url': 'http://tv.aftonbladet.se/abtv/articles/36015', 151 'only_matching': True, 152 }, 153 { 154 'url': 'https://www.aftonbladet.se/tv/a/36015', 155 'only_matching': True, 156 }, 157 { 158 'url': 'abtv:140026', 159 'only_matching': True, 160 }, 161 { 162 'url': 'http://www.vgtv.no/video/84196/hevnen-er-soet-episode-10-abu', 163 'only_matching': True, 164 }, 165 ] 166 167 def _real_extract(self, url): 168 mobj = re.match(self._VALID_URL, url) 169 video_id = mobj.group('id') 170 host = mobj.group('host') 171 appname = self._HOST_TO_APPNAME[host] if host else mobj.group('appname') 172 vendor = self._APP_NAME_TO_VENDOR[appname] 173 174 data = self._download_json( 175 'http://svp.vg.no/svp/api/v1/%s/assets/%s?appName=%s-website' 176 % (vendor, video_id, appname), 177 video_id, 'Downloading media JSON') 178 179 if data.get('status') == 'inactive': 180 raise ExtractorError( 181 'Video %s is no longer available' % video_id, expected=True) 182 183 info = { 184 'formats': [], 185 } 186 if len(video_id) == 5: 187 if appname == 'bttv': 188 info = self._extract_video_info('btno', video_id) 189 190 streams = data['streamUrls'] 191 stream_type = data.get('streamType') 192 is_live = stream_type == 'live' 193 formats = [] 194 195 hls_url = streams.get('hls') 196 if hls_url: 197 formats.extend(self._extract_m3u8_formats( 198 hls_url, video_id, 'mp4', 199 entry_protocol='m3u8' if is_live else 'm3u8_native', 200 m3u8_id='hls', fatal=False)) 201 202 hds_url = streams.get('hds') 203 if hds_url: 204 hdcore_sign = 'hdcore=3.7.0' 205 f4m_formats = self._extract_f4m_formats( 206 hds_url + '?%s' % hdcore_sign, video_id, f4m_id='hds', fatal=False) 207 if f4m_formats: 208 for entry in f4m_formats: 209 # URLs without the extra param induce an 404 error 210 entry.update({'extra_param_to_segment_url': hdcore_sign}) 211 formats.append(entry) 212 213 mp4_urls = streams.get('pseudostreaming') or [] 214 mp4_url = streams.get('mp4') 215 if mp4_url: 216 mp4_urls.append(mp4_url) 217 for mp4_url in mp4_urls: 218 format_info = { 219 'url': mp4_url, 220 } 221 mobj = re.search(r'(\d+)_(\d+)_(\d+)', mp4_url) 222 if mobj: 223 tbr = int(mobj.group(3)) 224 format_info.update({ 225 'width': int(mobj.group(1)), 226 'height': int(mobj.group(2)), 227 'tbr': tbr, 228 'format_id': 'mp4-%s' % tbr, 229 }) 230 formats.append(format_info) 231 232 info['formats'].extend(formats) 233 234 if not info['formats']: 235 properties = try_get( 236 data, lambda x: x['streamConfiguration']['properties'], list) 237 if properties and 'geoblocked' in properties: 238 raise self.raise_geo_restricted( 239 countries=[host.rpartition('.')[-1].partition('/')[0].upper()]) 240 241 self._sort_formats(info['formats']) 242 243 info.update({ 244 'id': video_id, 245 'title': self._live_title(data['title']) if is_live else data['title'], 246 'description': data['description'], 247 'thumbnail': data['images']['main'] + '?t[]=900x506q80', 248 'timestamp': data['published'], 249 'duration': float_or_none(data['duration'], 1000), 250 'view_count': data['displays'], 251 'is_live': is_live, 252 }) 253 return info 254 255 256 class BTArticleIE(InfoExtractor): 257 IE_NAME = 'bt:article' 258 IE_DESC = 'Bergens Tidende Articles' 259 _VALID_URL = r'https?://(?:www\.)?bt\.no/(?:[^/]+/)+(?P<id>[^/]+)-\d+\.html' 260 _TEST = { 261 'url': 'http://www.bt.no/nyheter/lokalt/Kjemper-for-internatet-1788214.html', 262 'md5': '2acbe8ad129b3469d5ae51b1158878df', 263 'info_dict': { 264 'id': '23199', 265 'ext': 'mp4', 266 'title': 'Alrekstad internat', 267 'description': 'md5:dc81a9056c874fedb62fc48a300dac58', 268 'thumbnail': r're:^https?://.*\.jpg', 269 'duration': 191, 270 'timestamp': 1289991323, 271 'upload_date': '20101117', 272 'view_count': int, 273 }, 274 } 275 276 def _real_extract(self, url): 277 webpage = self._download_webpage(url, self._match_id(url)) 278 video_id = self._search_regex( 279 r'<video[^>]+data-id="(\d+)"', webpage, 'video id') 280 return self.url_result('bttv:%s' % video_id, 'VGTV') 281 282 283 class BTVestlendingenIE(InfoExtractor): 284 IE_NAME = 'bt:vestlendingen' 285 IE_DESC = 'Bergens Tidende - Vestlendingen' 286 _VALID_URL = r'https?://(?:www\.)?bt\.no/spesial/vestlendingen/#!/(?P<id>\d+)' 287 _TESTS = [{ 288 'url': 'http://www.bt.no/spesial/vestlendingen/#!/86588', 289 'md5': 'd7d17e3337dc80de6d3a540aefbe441b', 290 'info_dict': { 291 'id': '86588', 292 'ext': 'mov', 293 'title': 'Otto Wollertsen', 294 'description': 'Vestlendingen Otto Fredrik Wollertsen', 295 'timestamp': 1430473209, 296 'upload_date': '20150501', 297 }, 298 'skip': '404 Error', 299 }, { 300 'url': 'http://www.bt.no/spesial/vestlendingen/#!/86255', 301 'md5': 'a2893f8632e96389f4bdf36aa9463ceb', 302 'info_dict': { 303 'id': '86255', 304 'ext': 'mov', 305 'title': 'Du må tåle å fryse og være sulten', 306 'description': 'md5:b8046f4d022d5830ddab04865791d063', 307 'upload_date': '20150321', 308 'timestamp': 1426942023, 309 }, 310 }] 311 312 def _real_extract(self, url): 313 return self.url_result('bttv:%s' % self._match_id(url), 'VGTV')