Profile: Cache iphone data structure if queried
Profile.get_profile_pic_url() and Profile.has_highlight_reels did the same query without remembering the response, resulting in that query being made twice when downloading stories and profile pic of a profile.
This commit is contained in:
parent
b9c7713d6a
commit
a3eb93c21a
@ -266,7 +266,7 @@ class Instaloader:
|
|||||||
def _epoch_to_string(epoch: datetime) -> str:
|
def _epoch_to_string(epoch: datetime) -> str:
|
||||||
return epoch.strftime('%Y-%m-%d_%H-%M-%S')
|
return epoch.strftime('%Y-%m-%d_%H-%M-%S')
|
||||||
|
|
||||||
profile_pic_url = profile.get_profile_pic_url()
|
profile_pic_url = profile.profile_pic_url
|
||||||
with self.context.get_anonymous_session() as anonymous_session:
|
with self.context.get_anonymous_session() as anonymous_session:
|
||||||
date_object = datetime.strptime(anonymous_session.head(profile_pic_url).headers["Last-Modified"],
|
date_object = datetime.strptime(anonymous_session.head(profile_pic_url).headers["Last-Modified"],
|
||||||
'%a, %d %b %Y %H:%M:%S GMT')
|
'%a, %d %b %Y %H:%M:%S GMT')
|
||||||
|
@ -374,10 +374,13 @@ class Profile:
|
|||||||
def __init__(self, context: InstaloaderContext, node: Dict[str, Any]):
|
def __init__(self, context: InstaloaderContext, node: Dict[str, Any]):
|
||||||
assert 'username' in node
|
assert 'username' in node
|
||||||
self._context = context
|
self._context = context
|
||||||
self._has_highlight_reels = None
|
|
||||||
self._has_public_story = None
|
self._has_public_story = None
|
||||||
self._node = node
|
self._node = node
|
||||||
self._rhx_gis = None
|
self._rhx_gis = None
|
||||||
|
self._iphone_struct_ = None
|
||||||
|
if 'iphone_struct' in node:
|
||||||
|
# if loaded from JSON with load_structure_from_file()
|
||||||
|
self._iphone_struct_ = node['iphone_struct']
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_username(cls, context: InstaloaderContext, username: str):
|
def from_username(cls, context: InstaloaderContext, username: str):
|
||||||
@ -424,6 +427,8 @@ class Profile:
|
|||||||
json_node.pop('edge_media_collections', None)
|
json_node.pop('edge_media_collections', None)
|
||||||
json_node.pop('edge_owner_to_timeline_media', None)
|
json_node.pop('edge_owner_to_timeline_media', None)
|
||||||
json_node.pop('edge_saved_media', None)
|
json_node.pop('edge_saved_media', None)
|
||||||
|
if self._iphone_struct_:
|
||||||
|
json_node['iphone_struct'] = self._iphone_struct_
|
||||||
return json_node
|
return json_node
|
||||||
|
|
||||||
def _obtain_metadata(self):
|
def _obtain_metadata(self):
|
||||||
@ -448,6 +453,15 @@ class Profile:
|
|||||||
d = d[key]
|
d = d[key]
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _iphone_struct(self) -> Dict[str, Any]:
|
||||||
|
if not self._iphone_struct_:
|
||||||
|
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._iphone_struct_ = data['user']
|
||||||
|
return self._iphone_struct_
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def userid(self) -> int:
|
def userid(self) -> int:
|
||||||
"""User ID"""
|
"""User ID"""
|
||||||
@ -519,12 +533,7 @@ class Profile:
|
|||||||
This becomes `True` if the :class:`Profile` has any stories currently available,
|
This becomes `True` if the :class:`Profile` has any stories currently available,
|
||||||
even if not viewable by the viewer.
|
even if not viewable by the viewer.
|
||||||
"""
|
"""
|
||||||
if not self._has_highlight_reels:
|
return self._iphone_struct['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
|
@property
|
||||||
def has_public_story(self) -> bool:
|
def has_public_story(self) -> bool:
|
||||||
@ -563,17 +572,21 @@ class Profile:
|
|||||||
def requested_by_viewer(self) -> bool:
|
def requested_by_viewer(self) -> bool:
|
||||||
return self._metadata('requested_by_viewer')
|
return self._metadata('requested_by_viewer')
|
||||||
|
|
||||||
def get_profile_pic_url(self) -> str:
|
@property
|
||||||
|
def profile_pic_url(self) -> str:
|
||||||
"""Return URL of profile picture"""
|
"""Return URL of profile picture"""
|
||||||
try:
|
try:
|
||||||
with self._context.get_anonymous_session() as anonymous_session:
|
return self._iphone_struct['hd_profile_pic_url_info']['url']
|
||||||
data = self._context.get_json(path='api/v1/users/{0}/info/'.format(self.userid), params={},
|
|
||||||
host='i.instagram.com', session=anonymous_session)
|
|
||||||
return data["user"]["hd_profile_pic_url_info"]["url"]
|
|
||||||
except (InstaloaderException, KeyError) as err:
|
except (InstaloaderException, KeyError) as err:
|
||||||
self._context.error('{} Unable to fetch high quality profile pic.'.format(err))
|
self._context.error('{} Unable to fetch high quality profile pic.'.format(err))
|
||||||
return self._metadata("profile_pic_url_hd")
|
return self._metadata("profile_pic_url_hd")
|
||||||
|
|
||||||
|
def get_profile_pic_url(self) -> str:
|
||||||
|
""".. deprecated:: 4.0.3
|
||||||
|
|
||||||
|
Use :attr:`profile_pic_url`."""
|
||||||
|
return self.profile_pic_url
|
||||||
|
|
||||||
def get_posts(self) -> Iterator[Post]:
|
def get_posts(self) -> Iterator[Post]:
|
||||||
"""Retrieve all posts from a profile."""
|
"""Retrieve all posts from a profile."""
|
||||||
self._obtain_metadata()
|
self._obtain_metadata()
|
||||||
|
Loading…
Reference in New Issue
Block a user