Replace deleted field has_highlight_reel
Since the property has_highlight_reel is no longer available throught the previously used graphql query, this information needs to be obtained in another way. Therefore the properties has_highlight_reels, has_public_story and has_viewable_story were added to the Profile class. Since has_public_story can be obtained throught graphql queries without being rate limited when invoked anonymously, the ability to use an anonymous copy of the context was added to to the InstaloaderContext class. Fixes #116
This commit is contained in:
parent
e1228501d2
commit
3211d63ec1
@ -701,7 +701,7 @@ class Instaloader:
|
||||
|
||||
# Download stories, if requested
|
||||
if download_stories or download_stories_only:
|
||||
if profile.has_highlight_reel:
|
||||
if profile.has_viewable_story:
|
||||
with self.context.error_catcher("Download stories of {}".format(profile_name)):
|
||||
self.download_stories(userids=[profile.userid], filename_target=profile_name,
|
||||
fast_update=fast_update, storyitem_filter=storyitem_filter)
|
||||
|
@ -69,6 +69,16 @@ class InstaloaderContext:
|
||||
# Can be set to True for testing, disables supression of InstaloaderContext._error_catcher
|
||||
self.raise_all_errors = False
|
||||
|
||||
@contextmanager
|
||||
def anonymous_copy(self):
|
||||
session = self._session
|
||||
username = self.username
|
||||
self._session = self.get_anonymous_session()
|
||||
self.username = None
|
||||
yield self
|
||||
self.username = username
|
||||
self._session = session
|
||||
|
||||
@property
|
||||
def is_logged_in(self) -> bool:
|
||||
"""True, if this Instaloader instance is logged in."""
|
||||
@ -212,7 +222,10 @@ class InstaloaderContext:
|
||||
return 0
|
||||
return round(min(self.query_timestamps) + sliding_window - current_time) + 6
|
||||
is_graphql_query = 'query_hash' in params and 'graphql/query' in path
|
||||
if is_graphql_query:
|
||||
# some queries are not rate limited if invoked anonymously:
|
||||
query_not_limited = is_graphql_query and not self.is_logged_in \
|
||||
and params['query_hash'] in ['9ca88e465c3f866a76f7adee3871bdd8']
|
||||
if is_graphql_query and not query_not_limited:
|
||||
waittime = graphql_query_waittime()
|
||||
if waittime > 0:
|
||||
self.log('\nToo many queries in the last time. Need to wait {} seconds.'.format(waittime))
|
||||
@ -228,7 +241,7 @@ class InstaloaderContext:
|
||||
while resp.is_redirect:
|
||||
redirect_url = resp.headers['location']
|
||||
self.log('\nHTTP redirect from https://{0}/{1} to {2}'.format(host, path, redirect_url))
|
||||
if redirect_url.index('https://{}/'.format(host)) == 0:
|
||||
if redirect_url.startswith('https://{}/'.format(host)):
|
||||
resp = sess.get(redirect_url if redirect_url.endswith('/') else redirect_url + '/',
|
||||
params=params, allow_redirects=False)
|
||||
else:
|
||||
|
@ -358,6 +358,8 @@ class Profile:
|
||||
def __init__(self, context: InstaloaderContext, node: Dict[str, Any]):
|
||||
assert 'username' in node
|
||||
self._context = context
|
||||
self._has_highlight_reels = None
|
||||
self._has_public_story = None
|
||||
self._node = node
|
||||
self._rhx_gis = None
|
||||
|
||||
@ -484,8 +486,42 @@ class Profile:
|
||||
return self._metadata('has_blocked_viewer')
|
||||
|
||||
@property
|
||||
def has_highlight_reel(self) -> bool:
|
||||
return self._metadata('has_highlight_reel')
|
||||
def has_highlight_reels(self) -> bool:
|
||||
"""
|
||||
This becomes `True` if the :class:`Profile` has any stories currently available,
|
||||
even if not viewable by the viewer.
|
||||
"""
|
||||
if not self._has_highlight_reels:
|
||||
with self._context.anonymous_copy() as anonymous_context:
|
||||
data = anonymous_context.get_json(path='api/v1/users/{}/info/'.format(self.userid),
|
||||
params={}, host='i.instagram.com')
|
||||
self._has_highlight_reels = data['user']['has_highlight_reels']
|
||||
return self._has_highlight_reels
|
||||
|
||||
@property
|
||||
def has_public_story(self) -> bool:
|
||||
if not self._has_public_story:
|
||||
self._obtain_metadata()
|
||||
# query not rate limited if invoked anonymously:
|
||||
with self._context.anonymous_copy() as anonymous_context:
|
||||
data = anonymous_context.graphql_query('9ca88e465c3f866a76f7adee3871bdd8',
|
||||
{'user_id': self.userid, 'include_chaining': False,
|
||||
'include_reel': False, 'include_suggested_users': False,
|
||||
'include_logged_out_extras': True,
|
||||
'include_highlight_reels': False},
|
||||
'https://www.instagram.com/{}/'.format(self.username),
|
||||
self._rhx_gis)
|
||||
self._has_public_story = data['data']['user']['has_public_story']
|
||||
return self._has_public_story
|
||||
|
||||
@property
|
||||
def has_viewable_story(self) -> bool:
|
||||
"""
|
||||
Some stories are private. This property determines if the :class:`Profile`
|
||||
has at least one story which can be viewed using the associated :class:`InstaloaderContext`,
|
||||
i.e. the viewer has privileges to view it.
|
||||
"""
|
||||
return self.has_public_story or self.followed_by_viewer and self.has_highlight_reels
|
||||
|
||||
@property
|
||||
def has_requested_viewer(self) -> bool:
|
||||
|
Loading…
Reference in New Issue
Block a user