]+\bdata-video-id\s*=\s*[^>]+>)', webpage, 'video element', fatal=False)
+ if not video:
+ if new_url == url:
+ raise ExtractorError('Redirect loop: ' + url)
+ return self.url_result(new_url)
+ video = extract_attributes(video)
+ video_data = video.get('data-settings') or '{}'
+ video_data = self._parse_json(video_data, video_id)['video']
+ info = self._extract_video_info(video_data)
+
+ return merge_dicts({
+ 'display_id': video_id,
+ }, info)
class IGNArticleIE(IGNBaseIE):
- _VALID_URL = r'https?://.+?\.ign\.com/(?:articles(?:/\d{4}/\d{2}/\d{2})?|(?:[a-z]{2}/)?feature/\d+)/(?P
[^/?]+)'
+ _VALID_URL = r'https?://.+?\.ign\.com/(?:articles(?:/\d{4}/\d{2}/\d{2})?|(?:[a-z]{2}/)?(?:[\w-]+/)*?feature/\d+)/(?P[^/?]+)'
_PAGE_TYPE = 'article'
_TESTS = [{
'url': 'http://me.ign.com/en/feature/15775/100-little-things-in-gta-5-that-will-blow-your-mind',
'info_dict': {
- 'id': '524497489e4e8ff5848ece34',
+ 'id': '72113',
'title': '100 Little Things in GTA 5 That Will Blow Your Mind',
},
'playlist': [
@@ -186,34 +260,43 @@ class IGNArticleIE(IGNBaseIE):
'info_dict': {
'id': '5ebbd138523268b93c9141af17bec937',
'ext': 'mp4',
- 'title': 'GTA 5 Video Review',
+ 'title': 'Grand Theft Auto V Video Review',
'description': 'Rockstar drops the mic on this generation of games. Watch our review of the masterly Grand Theft Auto V.',
'timestamp': 1379339880,
'upload_date': '20130916',
+ 'tags': 'count:12',
+ 'thumbnail': 'https://assets1.ignimgs.com/thumbs/userUploaded/2021/8/16/gta-v-heistsjpg-e94705-1629138553533.jpeg',
+ 'display_id': 'grand-theft-auto-v-video-review',
+ 'duration': 501,
},
},
{
'info_dict': {
'id': '638672ee848ae4ff108df2a296418ee2',
'ext': 'mp4',
- 'title': '26 Twisted Moments from GTA 5 in Slow Motion',
+ 'title': 'GTA 5 In Slow Motion',
'description': 'The twisted beauty of GTA 5 in stunning slow motion.',
'timestamp': 1386878820,
'upload_date': '20131212',
+ 'duration': 202,
+ 'tags': 'count:25',
+ 'display_id': 'gta-5-in-slow-motion',
+ 'thumbnail': 'https://assets1.ignimgs.com/vid/thumbnails/user/2013/11/03/GTA-SLO-MO-1.jpg',
},
},
],
'params': {
- 'playlist_items': '2-3',
'skip_download': True,
},
+ 'expected_warnings': ['Backend fetch failed'],
}, {
'url': 'http://www.ign.com/articles/2014/08/15/rewind-theater-wild-trailer-gamescom-2014?watch',
'info_dict': {
'id': '53ee806780a81ec46e0790f8',
'title': 'Rewind Theater - Wild Trailer Gamescom 2014',
},
- 'playlist_count': 2,
+ 'playlist_count': 1,
+ 'expected_warnings': ['Backend fetch failed'],
}, {
# videoId pattern
'url': 'http://www.ign.com/articles/2017/06/08/new-ducktales-short-donalds-birthday-doesnt-go-as-planned',
@@ -236,18 +319,84 @@ class IGNArticleIE(IGNBaseIE):
'only_matching': True,
}]
+ def _checked_call_api(self, slug):
+ try:
+ return self._call_api(slug)
+ except ExtractorError as e:
+ if isinstance(e.cause, urllib.error.HTTPError):
+ e.cause.args = e.cause.args or [
+ e.cause.geturl(), e.cause.getcode(), e.cause.reason]
+ if e.cause.code == 404:
+ raise ExtractorError(
+ 'Content not found: expired?', cause=e.cause,
+ expected=True)
+ elif e.cause.code == 503:
+ self.report_warning(error_to_compat_str(e.cause))
+ return
+ raise
+
def _real_extract(self, url):
display_id = self._match_id(url)
- article = self._call_api(display_id)
+ article = self._checked_call_api(display_id)
- def entries():
- media_url = try_get(article, lambda x: x['mediaRelations'][0]['media']['metadata']['url'])
- if media_url:
- yield self.url_result(media_url, IGNIE.ie_key())
- for content in (article.get('content') or []):
- for video_url in re.findall(r'(?:\[(?:ignvideo\s+url|youtube\s+clip_id)|