mirror of
https://github.com/instaloader/instaloader.git
synced 2024-11-04 09:22:29 +01:00
Also Download Highlight Cover Pictures
Instaloader.download_highlights(), as well as the Instaloader CLI with --highlight option, now also downloads the cover picture of each highlight. This closes #323, where it was suggested.
This commit is contained in:
parent
534497bea5
commit
fe258f1abb
@ -358,42 +358,56 @@ class Instaloader:
|
|||||||
self.context.log('geo', end=' ', flush=True)
|
self.context.log('geo', end=' ', flush=True)
|
||||||
|
|
||||||
@_retry_on_connection_error
|
@_retry_on_connection_error
|
||||||
def download_profilepic(self, profile: Profile, _attempt: int = 1) -> None:
|
def download_title_pic(self, url: str, target: Union[str, Path], name_suffix: str, owner_profile: Profile,
|
||||||
"""Downloads and saves profile pic."""
|
_attempt: int = 1) -> None:
|
||||||
|
"""Downloads and saves a picture that does not have an association with a Post or StoryItem, such as a
|
||||||
|
Profile picture or a Highlight cover picture. Modification time is taken from the HTTP response headers.
|
||||||
|
|
||||||
|
.. versionadded:: 4.3"""
|
||||||
|
|
||||||
def _epoch_to_string(epoch: datetime) -> str:
|
def _epoch_to_string(epoch: datetime) -> str:
|
||||||
return epoch.strftime('%Y-%m-%d_%H-%M-%S_UTC')
|
return epoch.strftime('%Y-%m-%d_%H-%M-%S_UTC')
|
||||||
|
|
||||||
profile_pic_response = self.context.get_raw(profile.profile_pic_url)
|
http_response = self.context.get_raw(url)
|
||||||
date_object = None # type: Optional[datetime]
|
date_object = None # type: Optional[datetime]
|
||||||
if 'Last-Modified' in profile_pic_response.headers:
|
if 'Last-Modified' in http_response.headers:
|
||||||
date_object = datetime.strptime(profile_pic_response.headers["Last-Modified"], '%a, %d %b %Y %H:%M:%S GMT')
|
date_object = datetime.strptime(http_response.headers["Last-Modified"], '%a, %d %b %Y %H:%M:%S GMT')
|
||||||
profile_pic_bytes = None
|
pic_bytes = None
|
||||||
profile_pic_identifier = _epoch_to_string(date_object)
|
pic_identifier = _epoch_to_string(date_object)
|
||||||
else:
|
else:
|
||||||
profile_pic_bytes = profile_pic_response.content
|
pic_bytes = http_response.content
|
||||||
profile_pic_identifier = md5(profile_pic_bytes).hexdigest()[:16]
|
pic_identifier = md5(pic_bytes).hexdigest()[:16]
|
||||||
profile_pic_extension = 'jpg'
|
pic_extension = 'jpg'
|
||||||
if ((format_string_contains_key(self.dirname_pattern, 'profile') or
|
if ((format_string_contains_key(self.dirname_pattern, 'profile') or
|
||||||
format_string_contains_key(self.dirname_pattern, 'target'))):
|
format_string_contains_key(self.dirname_pattern, 'target'))):
|
||||||
filename = '{0}/{1}_profile_pic.{2}'.format(self.dirname_pattern.format(profile=profile.username.lower(),
|
filename = '{0}/{1}_{2}.{3}'.format(self.dirname_pattern.format(profile=owner_profile.username.lower(),
|
||||||
target=profile.username.lower()),
|
target=target),
|
||||||
profile_pic_identifier, profile_pic_extension)
|
pic_identifier, name_suffix, pic_extension)
|
||||||
else:
|
else:
|
||||||
filename = '{0}/{1}_{2}_profile_pic.{3}'.format(self.dirname_pattern.format(), profile.username.lower(),
|
filename = '{0}/{1}_{2}_{3}.{4}'.format(self.dirname_pattern.format(), target,
|
||||||
profile_pic_identifier, profile_pic_extension)
|
pic_identifier, name_suffix, pic_extension)
|
||||||
content_length = profile_pic_response.headers.get('Content-Length', None)
|
content_length = http_response.headers.get('Content-Length', None)
|
||||||
if os.path.isfile(filename) and (not self.context.is_logged_in or
|
if os.path.isfile(filename) and (not self.context.is_logged_in or
|
||||||
(content_length is not None and
|
(content_length is not None and
|
||||||
os.path.getsize(filename) >= int(content_length))):
|
os.path.getsize(filename) >= int(content_length))):
|
||||||
self.context.log(filename + ' already exists')
|
self.context.log(filename + ' already exists')
|
||||||
return None
|
return None
|
||||||
os.makedirs(os.path.dirname(filename), exist_ok=True)
|
os.makedirs(os.path.dirname(filename), exist_ok=True)
|
||||||
self.context.write_raw(profile_pic_bytes if profile_pic_bytes else profile_pic_response, filename)
|
self.context.write_raw(pic_bytes if pic_bytes else http_response, filename)
|
||||||
if date_object:
|
if date_object:
|
||||||
os.utime(filename, (datetime.now().timestamp(), date_object.timestamp()))
|
os.utime(filename, (datetime.now().timestamp(), date_object.timestamp()))
|
||||||
self.context.log('') # log output of _get_and_write_raw() does not produce \n
|
self.context.log('') # log output of _get_and_write_raw() does not produce \n
|
||||||
|
|
||||||
|
def download_profilepic(self, profile: Profile) -> None:
|
||||||
|
"""Downloads and saves profile pic."""
|
||||||
|
self.download_title_pic(profile.profile_pic_url, profile.username.lower(), 'profile_pic', profile)
|
||||||
|
|
||||||
|
def download_highlight_cover(self, highlight: Highlight, target: Union[str, Path]) -> None:
|
||||||
|
"""Downloads and saves Highlight cover picture.
|
||||||
|
|
||||||
|
.. versionadded:: 4.3"""
|
||||||
|
self.download_title_pic(highlight.cover_url, target, 'cover', highlight.owner_profile)
|
||||||
|
|
||||||
@_requires_login
|
@_requires_login
|
||||||
def save_session_to_file(self, filename: Optional[str] = None) -> None:
|
def save_session_to_file(self, filename: Optional[str] = None) -> None:
|
||||||
"""Saves internally stored :class:`requests.Session` object.
|
"""Saves internally stored :class:`requests.Session` object.
|
||||||
@ -646,6 +660,9 @@ class Instaloader:
|
|||||||
|
|
||||||
.. versionadded:: 4.1
|
.. versionadded:: 4.1
|
||||||
|
|
||||||
|
.. versionchanged:: 4.3
|
||||||
|
Also downloads and saves the Highlight's cover pictures.
|
||||||
|
|
||||||
:param user: ID or Profile of the user whose highlights should get downloaded.
|
:param user: ID or Profile of the user whose highlights should get downloaded.
|
||||||
:param fast_update: If true, abort when first already-downloaded picture is encountered
|
:param fast_update: If true, abort when first already-downloaded picture is encountered
|
||||||
:param filename_target: Replacement for {target} in dirname_pattern and filename_pattern
|
:param filename_target: Replacement for {target} in dirname_pattern and filename_pattern
|
||||||
@ -655,7 +672,11 @@ class Instaloader:
|
|||||||
"""
|
"""
|
||||||
for user_highlight in self.get_highlights(user):
|
for user_highlight in self.get_highlights(user):
|
||||||
name = user_highlight.owner_username
|
name = user_highlight.owner_username
|
||||||
|
highlight_target = (filename_target
|
||||||
|
if filename_target
|
||||||
|
else Path(name) / Path(user_highlight.title)) # type: Union[str, Path]
|
||||||
self.context.log("Retrieving highlights \"{}\" from profile {}".format(user_highlight.title, name))
|
self.context.log("Retrieving highlights \"{}\" from profile {}".format(user_highlight.title, name))
|
||||||
|
self.download_highlight_cover(user_highlight, highlight_target)
|
||||||
totalcount = user_highlight.itemcount
|
totalcount = user_highlight.itemcount
|
||||||
count = 1
|
count = 1
|
||||||
for item in user_highlight.get_items():
|
for item in user_highlight.get_items():
|
||||||
@ -666,9 +687,7 @@ class Instaloader:
|
|||||||
count += 1
|
count += 1
|
||||||
with self.context.error_catcher('Download highlights \"{}\" from user {}'.format(user_highlight.title,
|
with self.context.error_catcher('Download highlights \"{}\" from user {}'.format(user_highlight.title,
|
||||||
name)):
|
name)):
|
||||||
downloaded = self.download_storyitem(item, filename_target
|
downloaded = self.download_storyitem(item, highlight_target)
|
||||||
if filename_target
|
|
||||||
else Path(name) / Path(user_highlight.title))
|
|
||||||
if fast_update and not downloaded:
|
if fast_update and not downloaded:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user