1
0
mirror of https://github.com/instaloader/instaloader.git synced 2024-10-27 05:32:30 +01:00

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:
André Koch-Kramer 2018-05-13 19:43:49 +02:00
parent e1228501d2
commit 3211d63ec1
3 changed files with 54 additions and 5 deletions

View File

@ -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)

View File

@ -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:

View File

@ -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: