ExtractorError,
decode_base_n,
encode_base_n,
+ filter_dict,
float_or_none,
format_field,
get_element_by_attribute,
_ENCODING_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'
-def _pk_to_id(id):
+def _pk_to_id(media_id):
"""Source: https://stackoverflow.com/questions/24437823/getting-instagram-post-url-from-media-id"""
- return encode_base_n(int(id.split('_')[0]), table=_ENCODING_CHARS)
+ return encode_base_n(int(media_id.split('_')[0]), table=_ENCODING_CHARS)
def _id_to_pk(shortcode):
'height': self._get_dimension('height', node),
'http_headers': {
'Referer': 'https://www.instagram.com/',
- }
+ },
}
elif not video_id:
continue
return {}
formats = [{
- 'format_id': format.get('id'),
- 'url': format.get('url'),
- 'width': format.get('width'),
- 'height': format.get('height'),
+ 'format_id': fmt.get('id'),
+ 'url': fmt.get('url'),
+ 'width': fmt.get('width'),
+ 'height': fmt.get('height'),
'vcodec': vcodec,
- } for format in videos_list or []]
+ } for fmt in videos_list or []]
if dash_manifest_raw:
formats.extend(self._parse_mpd_formats(self._parse_xml(dash_manifest_raw, media_id), mpd_id='dash'))
thumbnails = [{
'url': thumbnail.get('url'),
'width': thumbnail.get('width'),
- 'height': thumbnail.get('height')
+ 'height': thumbnail.get('height'),
} for thumbnail in traverse_obj(product_media, ('image_versions2', 'candidates')) or []]
return {
'id': media_id,
'duration': float_or_none(product_media.get('video_duration')),
'formats': formats,
- 'thumbnails': thumbnails
+ 'thumbnails': thumbnails,
}
def _extract_product(self, product_info):
'__post_extractor': self.extract_comments(_pk_to_id(product_info.get('pk'))),
'http_headers': {
'Referer': 'https://www.instagram.com/',
- }
+ },
}
carousel_media = product_info.get('carousel_media')
if carousel_media:
return {
**info_dict,
- **self._extract_product_media(product_info)
+ **self._extract_product_media(product_info),
}
def _get_comments(self, video_id):
'comment_count': int,
'comments': list,
},
- 'add_ie': ['Instagram']
+ 'add_ie': ['Instagram'],
}]
def _real_extract(self, url):
class InstagramIE(InstagramBaseIE):
- _VALID_URL = r'(?P<url>https?://(?:www\.)?instagram\.com(?:/[^/]+)?/(?:p|tv|reel)/(?P<id>[^/?#&]+))'
+ _VALID_URL = r'(?P<url>https?://(?:www\.)?instagram\.com(?:/[^/]+)?/(?:p|tv|reels?(?!/audio/))/(?P<id>[^/?#&]+))'
_EMBED_REGEX = [r'<iframe[^>]+src=(["\'])(?P<url>(?:https?:)?//(?:www\.)?instagram\.com/p/[^/]+/embed.*?)\1']
_TESTS = [{
'url': 'https://instagram.com/p/aye83DjauH/?foo=bar#abc',
}, {
'url': 'https://www.instagram.com/marvelskies.fc/reel/CWqAgUZgCku/',
'only_matching': True,
+ }, {
+ 'url': 'https://www.instagram.com/reels/Cop84x6u7CP/',
+ 'only_matching': True,
}]
@classmethod
return {
'id': video_id,
'formats': formats,
- 'title': media.get('title') or 'Video by %s' % username,
+ 'title': media.get('title') or f'Video by {username}',
'description': description,
'duration': float_or_none(media.get('video_duration')),
'timestamp': traverse_obj(media, 'taken_at_timestamp', 'date', expected_type=int_or_none),
'thumbnails': thumbnails,
'http_headers': {
'Referer': 'https://www.instagram.com/',
- }
+ },
}
gis_tmpls = [self._gis_tmpl]
else:
gis_tmpls = [
- '%s' % rhx_gis,
+ f'{rhx_gis}',
'',
- '%s:%s' % (rhx_gis, csrf_token),
- '%s:%s:%s' % (rhx_gis, csrf_token, self.get_param('http_headers')['User-Agent']),
+ f'{rhx_gis}:{csrf_token}',
+ '{}:{}:{}'.format(rhx_gis, csrf_token, self.get_param('http_headers')['User-Agent']),
]
# try all of the ways to generate a GIS query, and not only use the
try:
json_data = self._download_json(
'https://www.instagram.com/graphql/query/', uploader_id,
- 'Downloading JSON page %d' % page_num, headers={
+ f'Downloading JSON page {page_num}', headers={
'X-Requested-With': 'XMLHttpRequest',
'X-Instagram-GIS': hashlib.md5(
- ('%s:%s' % (gis_tmpl, variables)).encode('utf-8')).hexdigest(),
+ (f'{gis_tmpl}:{variables}').encode()).hexdigest(),
}, query={
'query_hash': self._QUERY_HASH,
'variables': variables,
class InstagramUserIE(InstagramPlaylistBaseIE):
+ _WORKING = False
_VALID_URL = r'https?://(?:www\.)?instagram\.com/(?P<id>[^/]{2,})/?(?:$|[?#])'
IE_DESC = 'Instagram user profile'
IE_NAME = 'instagram:user'
'extract_flat': True,
'skip_download': True,
'playlistend': 5,
- }
+ },
}]
- _QUERY_HASH = '42323d64886122307be10013ad2dcc44',
+ _QUERY_HASH = ('42323d64886122307be10013ad2dcc44',)
@staticmethod
def _parse_timeline_from(data):
# returns a dictionary of variables to add to the timeline query based
# on the GraphQL of the original page
return {
- 'id': data['entry_data']['ProfilePage'][0]['graphql']['user']['id']
+ 'id': data['entry_data']['ProfilePage'][0]['graphql']['user']['id'],
}
'extract_flat': True,
'skip_download': True,
'playlistend': 50,
- }
+ },
}]
- _QUERY_HASH = 'f92f56d47dc7a55b606908374b43a314',
+ _QUERY_HASH = ('f92f56d47dc7a55b606908374b43a314',)
@staticmethod
def _parse_timeline_from(data):
# on the GraphQL of the original page
return {
'tag_name':
- data['entry_data']['TagPage'][0]['graphql']['hashtag']['name']
+ data['entry_data']['TagPage'][0]['graphql']['hashtag']['name'],
}
'id': '18090946048123978',
'title': 'Rare',
},
- 'playlist_mincount': 50
+ 'playlist_mincount': 50,
}]
def _real_extract(self, url):
user_info = self._search_json(r'"user":', story_info, 'user info', story_id, fatal=False)
if not user_info:
self.raise_login_required('This content is unreachable')
- user_id = user_info.get('id')
+ user_id = traverse_obj(user_info, 'pk', 'id', expected_type=str)
story_info_url = user_id if username != 'highlights' else f'highlight:{story_id}'
+ if not story_info_url: # user id is only mandatory for non-highlights
+ raise ExtractorError('Unable to extract user id')
+
videos = traverse_obj(self._download_json(
f'{self._API_BASE_URL}/feed/reels_media/?reel_ids={story_info_url}',
story_id, errnote=False, fatal=False, headers=self._API_HEADERS), 'reels')
if not videos:
self.raise_login_required('You need to log in to access this content')
- full_name = traverse_obj(videos, (f'highlight:{story_id}', 'user', 'full_name'), (str(user_id), 'user', 'full_name'))
+ full_name = traverse_obj(videos, (f'highlight:{story_id}', 'user', 'full_name'), (user_id, 'user', 'full_name'))
story_title = traverse_obj(videos, (f'highlight:{story_id}', 'title'))
if not story_title:
story_title = f'Story by {username}'
- highlights = traverse_obj(videos, (f'highlight:{story_id}', 'items'), (str(user_id), 'items'))
+ highlights = traverse_obj(videos, (f'highlight:{story_id}', 'items'), (user_id, 'items'))
info_data = []
for highlight in highlights:
highlight_data = self._extract_product(highlight)
if highlight_data.get('formats'):
info_data.append({
- **highlight_data,
'uploader': full_name,
'uploader_id': user_id,
+ **filter_dict(highlight_data),
})
return self.playlist_result(info_data, playlist_id=story_id, playlist_title=story_title)