From b57bbe2af0654ed184151abe89df9b0e55be9d99 Mon Sep 17 00:00:00 2001 From: fireattack Date: Fri, 21 Aug 2020 12:37:38 -0500 Subject: [PATCH] Get higher Post video and StoryItem image quality if logged-in (#712) --- instaloader/instaloadercontext.py | 2 +- instaloader/structures.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/instaloader/instaloadercontext.py b/instaloader/instaloadercontext.py index bf2e0ef..8c37e1a 100644 --- a/instaloader/instaloadercontext.py +++ b/instaloader/instaloadercontext.py @@ -471,7 +471,7 @@ class InstaloaderContext: .. versionadded:: 4.2.1""" with copy_session(self._session, self.request_timeout) as tempsession: - tempsession.headers['User-Agent'] = 'Instagram 123.1.0.26.115 (iPhone12,1; iOS 13_3; en_US; en-US; ' \ + tempsession.headers['User-Agent'] = 'Instagram 146.0.0.27.125 (iPhone12,1; iOS 13_3; en_US; en-US; ' \ 'scale=2.00; 1656x3584; 190542906)' for header in ['Host', 'Origin', 'X-Instagram-AJAX', 'X-Requested-With']: tempsession.headers.pop(header, None) diff --git a/instaloader/structures.py b/instaloader/structures.py index 6c53071..6753b11 100644 --- a/instaloader/structures.py +++ b/instaloader/structures.py @@ -328,6 +328,12 @@ class Post: def video_url(self) -> Optional[str]: """URL of the video, or None.""" if self.is_video: + if self._context.is_logged_in: + try: + url = self._iphone_struct['video_versions'][0]['url'] + return url + except (InstaloaderException, KeyError, IndexError) as err: + self._context.error('{} Unable to fetch high quality video version of {}.'.format(err, self)) return self._field('video_url') return None @@ -916,11 +922,17 @@ class StoryItem: self._context = context self._node = node self._owner_profile = owner_profile + self._iphone_struct_ = None + if 'iphone_struct' in node: + # if loaded from JSON with load_structure_from_file() + self._iphone_struct_ = node['iphone_struct'] def _asdict(self): node = self._node if self._owner_profile: node['owner'] = self._owner_profile._asdict() + if self._iphone_struct_: + node['iphone_struct'] = self._iphone_struct_ return node @property @@ -945,6 +957,15 @@ class StoryItem: def __hash__(self) -> int: return hash(self.mediaid) + @property + def _iphone_struct(self) -> Dict[str, Any]: + if not self._context.is_logged_in: + raise LoginRequiredException("--login required to access iPhone media info endpoint.") + if not self._iphone_struct_: + data = self._context.get_iphone_json(path='api/v1/media/{}/info/'.format(self.mediaid), params={}) + self._iphone_struct_ = data['items'][0] + return self._iphone_struct_ + @property def owner_profile(self) -> Profile: """:class:`Profile` instance of the story item's owner.""" @@ -996,6 +1017,13 @@ class StoryItem: @property def url(self) -> str: """URL of the picture / video thumbnail of the StoryItem""" + if self.typename == "GraphStoryImage" and self._context.is_logged_in: + try: + orig_url = self._iphone_struct['image_versions2']['candidates'][0]['url'] + url = re.sub(r'&se=\d+(&?)', r'\1', orig_url) + return url + except (InstaloaderException, KeyError, IndexError) as err: + self._context.error('{} Unable to fetch high quality image version of {}.'.format(err, self)) return self._node['display_resources'][-1]['src'] @property