4 from .common
import InfoExtractor
11 from ..utils
.traversal
import traverse_obj
14 class NintendoIE(InfoExtractor
):
15 _VALID_URL
= r
'https?://(?:www\.)?nintendo\.com/(?:(?P<locale>\w{2}(?:-\w{2})?)/)?nintendo-direct/(?P<slug>[^/?#]+)'
17 'url': 'https://www.nintendo.com/nintendo-direct/09-04-2019/',
20 'id': '2oPmiviVePUA1IqAZzjuVh',
21 'display_id': '09-04-2019',
22 'title': 'Nintendo Direct 9.4.2019',
23 'timestamp': 1567580400,
24 'description': 'md5:8aac2780361d8cb772b6d1de66d7d6f4',
25 'upload_date': '20190904',
27 '_old_archive_ids': ['nintendo J2bXdmaTE6fe3dWJTPcc7m23FNbc_A1V'],
30 'url': 'https://www.nintendo.com/en-ca/nintendo-direct/08-31-2023/',
33 'id': '2TB2w2rJhNYF84qQ9E57hU',
34 'display_id': '08-31-2023',
35 'title': 'Super Mario Bros. Wonder Direct 8.31.2023',
36 'timestamp': 1693465200,
37 'description': 'md5:3067c5b824bcfdae9090a7f38ab2d200',
38 'tags': ['Mild Fantasy Violence', 'In-Game Purchases'],
39 'upload_date': '20230831',
43 'url': 'https://www.nintendo.com/us/nintendo-direct/50-fact-extravaganza/',
47 'channel_follower_count': int,
49 'description': 'Learn new details about Super Smash Bros. for Wii U, which launches on November 21.',
51 'availability': 'public',
52 'thumbnail': 'https://i.ytimg.com/vi_webp/j0BBGzfw0pQ/maxresdefault.webp',
53 'timestamp': 1414047600,
54 'channel_id': 'UCGIY_O-8vW4rfX98KlMkvRg',
55 'chapters': 'count:53',
56 'heatmap': 'count:100',
57 'upload_date': '20141023',
58 'uploader_id': '@NintendoAmerica',
59 'playable_in_embed': True,
60 'categories': ['Gaming'],
61 'display_id': '50-fact-extravaganza',
62 'channel': 'Nintendo of America',
63 'tags': ['Comic Mischief', 'Cartoon Violence', 'Mild Suggestive Themes'],
65 'channel_url': 'https://www.youtube.com/channel/UCGIY_O-8vW4rfX98KlMkvRg',
67 'uploader_url': 'https://www.youtube.com/@NintendoAmerica',
69 'live_status': 'not_live',
70 'uploader': 'Nintendo of America',
71 'title': '50-FACT Extravaganza',
75 def _create_asset_url(self
, path
):
76 return urljoin('https://assets.nintendo.com/', urllib
.parse
.quote(path
))
78 def _real_extract(self
, url
):
79 locale
, slug
= self
._match
_valid
_url
(url
).group('locale', 'slug')
81 language
, _
, country
= (locale
or 'US').rpartition('-')
82 parsed_locale
= f
'{language.lower() or "en"}_{country.upper()}'
83 self
.write_debug(f
'Using locale {parsed_locale} (from {locale})', only_once
=True)
85 response
= self
._download
_json
('https://graph.nintendo.com/', slug
, query
={
86 'operationName': 'NintendoDirect',
87 'variables': json
.dumps({
88 'locale': parsed_locale
,
90 }, separators
=(',', ':')),
91 'extensions': json
.dumps({
94 'sha256Hash': '969b16fe9f08b686fa37bc44d1fd913b6188e65794bb5e341c54fa683a8004cb'
96 }, separators
=(',', ':')),
98 # API returns `{"data": {"direct": null}}` if no matching id
99 direct_info
= traverse_obj(response
, ('data', 'direct', {dict}
))
101 raise ExtractorError(f
'No Nintendo Direct with id {slug} exists', expected
=True)
103 errors
= ', '.join(traverse_obj(response
, ('errors', ..., 'message')))
105 raise ExtractorError(f
'GraphQL API error: {errors or "Unknown error"}')
107 result
= traverse_obj(direct_info
, {
109 'title': ('name', {str}
),
110 'timestamp': ('startDate', {unified_timestamp}
),
111 'description': ('description', 'text', {str}
),
112 'age_limit': ('contentRating', 'order', {int}
),
113 'tags': ('contentDescriptors', ..., 'label', {str}
),
114 'thumbnail': ('thumbnail', {self
._create
_asset
_url
}),
116 result
['display_id'] = slug
118 asset_id
= traverse_obj(direct_info
, ('video', 'publicId', {str}
))
120 youtube_id
= traverse_obj(direct_info
, ('liveStream', {str}
))
122 self
.raise_no_formats('Could not find any video formats', video_id
=slug
)
124 return self
.url_result(youtube_id
, **result
, url_transparent
=True)
126 if asset_id
.startswith('Legacy Videos/'):
127 result
['_old_archive_ids'] = [make_archive_id(self
, asset_id
[14:])]
128 result
['formats'] = self
._extract
_m
3u8_formats
(
129 self
._create
_asset
_url
(f
'/video/upload/sp_full_hd/v1/{asset_id}.m3u8'), slug
)