Change download of stories when not using :stories
If using --stories or --stories-only the stories got donwloaded along with the profiles one by one. Now, the stories get downloaded in a similar aproach like when using the :stories target, i.e. download_stories() gets only called once. Profile.has_highlight_reels is broken and now always returns true. This fixes #153.
This commit is contained in:
parent
1739844758
commit
50a5330fec
@ -121,8 +121,9 @@ def _main(instaloader: Instaloader, targetlist: List[str],
|
|||||||
if target[0] == '@':
|
if target[0] == '@':
|
||||||
instaloader.context.log("Retrieving followees of %s..." % target[1:])
|
instaloader.context.log("Retrieving followees of %s..." % target[1:])
|
||||||
profile = Profile.from_username(instaloader.context, target[1:])
|
profile = Profile.from_username(instaloader.context, target[1:])
|
||||||
followees = profile.get_followees()
|
for followee in profile.get_followees():
|
||||||
profiles.update([followee.username for followee in followees])
|
instaloader.save_profile_id(followee)
|
||||||
|
profiles.add(followee)
|
||||||
elif target[0] == '#':
|
elif target[0] == '#':
|
||||||
instaloader.download_hashtag(hashtag=target[1:], max_count=max_count, fast_update=fast_update,
|
instaloader.download_hashtag(hashtag=target[1:], max_count=max_count, fast_update=fast_update,
|
||||||
post_filter=post_filter)
|
post_filter=post_filter)
|
||||||
@ -135,26 +136,32 @@ def _main(instaloader: Instaloader, targetlist: List[str],
|
|||||||
instaloader.download_saved_posts(fast_update=fast_update, max_count=max_count,
|
instaloader.download_saved_posts(fast_update=fast_update, max_count=max_count,
|
||||||
post_filter=post_filter)
|
post_filter=post_filter)
|
||||||
else:
|
else:
|
||||||
profiles.add(target)
|
profiles.add(instaloader.check_profile_id(target))
|
||||||
if len(profiles) > 1:
|
if len(profiles) > 1:
|
||||||
instaloader.context.log("Downloading {} profiles: {}".format(len(profiles), ' '.join(profiles)))
|
instaloader.context.log("Downloading {} profiles: {}".format(len(profiles),
|
||||||
# Iterate through profiles list and download them
|
' '.join([p.username for p in profiles])))
|
||||||
for target in profiles:
|
if not stories_only:
|
||||||
with instaloader.context.error_catcher(target):
|
# Iterate through profiles list and download them
|
||||||
try:
|
for target in profiles:
|
||||||
instaloader.download_profile(target, profile_pic, profile_pic_only, fast_update,
|
with instaloader.context.error_catcher(target):
|
||||||
stories, stories_only, post_filter=post_filter,
|
try:
|
||||||
storyitem_filter=storyitem_filter)
|
instaloader.download_profile(target, profile_pic, profile_pic_only,
|
||||||
except ProfileNotExistsException as err:
|
fast_update, post_filter=post_filter)
|
||||||
if instaloader.context.is_logged_in:
|
except ProfileNotExistsException as err:
|
||||||
instaloader.context.log(err)
|
if instaloader.context.is_logged_in and not stories_only:
|
||||||
instaloader.context.log("Trying again anonymously, helps in case you are just blocked.")
|
instaloader.context.log(err)
|
||||||
with instaloader.anonymous_copy() as anonymous_loader:
|
instaloader.context.log("Trying again anonymously, helps in case you are just blocked.")
|
||||||
with instaloader.context.error_catcher():
|
with instaloader.anonymous_copy() as anonymous_loader:
|
||||||
anonymous_loader.download_profile(target, profile_pic, profile_pic_only,
|
with instaloader.context.error_catcher():
|
||||||
fast_update, post_filter=post_filter)
|
anonymous_loader.download_profile(target, profile_pic, profile_pic_only,
|
||||||
else:
|
fast_update, post_filter=post_filter)
|
||||||
raise
|
else:
|
||||||
|
raise
|
||||||
|
if stories or stories_only:
|
||||||
|
with instaloader.context.error_catcher("Download stories"):
|
||||||
|
instaloader.context.log("Downloading stories")
|
||||||
|
instaloader.download_stories(userids=list(profiles), fast_update=fast_update,
|
||||||
|
filename_target=None, storyitem_filter=storyitem_filter)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("\nInterrupted by user.", file=sys.stderr)
|
print("\nInterrupted by user.", file=sys.stderr)
|
||||||
# Save session if it is useful
|
# Save session if it is useful
|
||||||
|
@ -11,7 +11,7 @@ from contextlib import contextmanager, suppress
|
|||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from typing import Callable, Iterator, List, Optional, Any
|
from typing import Any, Callable, Iterator, List, Optional, Union
|
||||||
|
|
||||||
from .exceptions import *
|
from .exceptions import *
|
||||||
from .instaloadercontext import InstaloaderContext
|
from .instaloadercontext import InstaloaderContext
|
||||||
@ -410,25 +410,26 @@ class Instaloader:
|
|||||||
|
|
||||||
@_requires_login
|
@_requires_login
|
||||||
def download_stories(self,
|
def download_stories(self,
|
||||||
userids: Optional[List[int]] = None,
|
userids: Optional[List[Union[int, Profile]]] = None,
|
||||||
fast_update: bool = False,
|
fast_update: bool = False,
|
||||||
filename_target: str = ':stories',
|
filename_target: Optional[str] = ':stories',
|
||||||
storyitem_filter: Optional[Callable[[StoryItem], bool]] = None) -> None:
|
storyitem_filter: Optional[Callable[[StoryItem], bool]] = None) -> None:
|
||||||
"""
|
"""
|
||||||
Download available stories from user followees or all stories of users whose ID are given.
|
Download available stories from user followees or all stories of users whose ID are given.
|
||||||
Does not mark stories as seen.
|
Does not mark stories as seen.
|
||||||
To use this, one needs to be logged in
|
To use this, one needs to be logged in
|
||||||
|
|
||||||
:param userids: List of user IDs to be processed in terms of downloading their stories
|
:param userids: List of user IDs or Profiles to be processed in terms of downloading their stories
|
||||||
: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
|
||||||
|
or None if profile name should be used instead
|
||||||
:param storyitem_filter: function(storyitem), which returns True if given StoryItem should be downloaded
|
:param storyitem_filter: function(storyitem), which returns True if given StoryItem should be downloaded
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not userids:
|
if not userids:
|
||||||
self.context.log("Retrieving all visible stories...")
|
self.context.log("Retrieving all visible stories...")
|
||||||
|
|
||||||
for user_story in self.get_stories(userids):
|
for user_story in self.get_stories([p if isinstance(p, int) else p.userid for p in userids]):
|
||||||
name = user_story.owner_username
|
name = user_story.owner_username
|
||||||
self.context.log("Retrieving stories from profile {}.".format(name))
|
self.context.log("Retrieving stories from profile {}.".format(name))
|
||||||
totalcount = user_story.itemcount
|
totalcount = user_story.itemcount
|
||||||
@ -440,7 +441,7 @@ class Instaloader:
|
|||||||
self.context.log("[%3i/%3i] " % (count, totalcount), end="", flush=True)
|
self.context.log("[%3i/%3i] " % (count, totalcount), end="", flush=True)
|
||||||
count += 1
|
count += 1
|
||||||
with self.context.error_catcher('Download story from user {}'.format(name)):
|
with self.context.error_catcher('Download story from user {}'.format(name)):
|
||||||
downloaded = self.download_storyitem(item, filename_target)
|
downloaded = self.download_storyitem(item, filename_target if filename_target else name)
|
||||||
if fast_update and not downloaded:
|
if fast_update and not downloaded:
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -611,6 +612,24 @@ class Instaloader:
|
|||||||
if fast_update and not downloaded:
|
if fast_update and not downloaded:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
def _get_id_filename(self, profile_name: str) -> str:
|
||||||
|
if ((format_string_contains_key(self.dirname_pattern, 'profile') or
|
||||||
|
format_string_contains_key(self.dirname_pattern, 'target'))):
|
||||||
|
return '{0}/id'.format(self.dirname_pattern.format(profile=profile_name.lower(),
|
||||||
|
target=profile_name.lower()))
|
||||||
|
else:
|
||||||
|
return '{0}/{1}_id'.format(self.dirname_pattern.format(), profile_name.lower())
|
||||||
|
|
||||||
|
def save_profile_id(self, profile: Profile):
|
||||||
|
"""
|
||||||
|
Store ID of profile locally.
|
||||||
|
"""
|
||||||
|
os.makedirs(self.dirname_pattern.format(profile=profile.username,
|
||||||
|
target=profile.username), exist_ok=True)
|
||||||
|
with open(self._get_id_filename(profile.username), 'w') as text_file:
|
||||||
|
text_file.write(str(profile.userid) + "\n")
|
||||||
|
self.context.log("Stored ID {0} for profile {1}.".format(profile.userid, profile.username))
|
||||||
|
|
||||||
def check_profile_id(self, profile_name: str) -> Profile:
|
def check_profile_id(self, profile_name: str) -> Profile:
|
||||||
"""
|
"""
|
||||||
Consult locally stored ID of profile with given name, check whether ID matches and whether name
|
Consult locally stored ID of profile with given name, check whether ID matches and whether name
|
||||||
@ -623,12 +642,7 @@ class Instaloader:
|
|||||||
with suppress(ProfileNotExistsException):
|
with suppress(ProfileNotExistsException):
|
||||||
profile = Profile.from_username(self.context, profile_name)
|
profile = Profile.from_username(self.context, profile_name)
|
||||||
profile_exists = profile is not None
|
profile_exists = profile is not None
|
||||||
if ((format_string_contains_key(self.dirname_pattern, 'profile') or
|
id_filename = self._get_id_filename(profile_name)
|
||||||
format_string_contains_key(self.dirname_pattern, 'target'))):
|
|
||||||
id_filename = '{0}/id'.format(self.dirname_pattern.format(profile=profile_name.lower(),
|
|
||||||
target=profile_name.lower()))
|
|
||||||
else:
|
|
||||||
id_filename = '{0}/{1}_id'.format(self.dirname_pattern.format(), profile_name.lower())
|
|
||||||
try:
|
try:
|
||||||
with open(id_filename, 'rb') as id_file:
|
with open(id_filename, 'rb') as id_file:
|
||||||
profile_id = int(id_file.read())
|
profile_id = int(id_file.read())
|
||||||
@ -657,15 +671,11 @@ class Instaloader:
|
|||||||
except (FileNotFoundError, ValueError):
|
except (FileNotFoundError, ValueError):
|
||||||
pass
|
pass
|
||||||
if profile_exists:
|
if profile_exists:
|
||||||
os.makedirs(self.dirname_pattern.format(profile=profile_name.lower(),
|
self.save_profile_id(profile)
|
||||||
target=profile_name.lower()), exist_ok=True)
|
|
||||||
with open(id_filename, 'w') as text_file:
|
|
||||||
text_file.write(str(profile.userid) + "\n")
|
|
||||||
self.context.log("Stored ID {0} for profile {1}.".format(profile.userid, profile_name))
|
|
||||||
return profile
|
return profile
|
||||||
raise ProfileNotExistsException("Profile {0} does not exist.".format(profile_name))
|
raise ProfileNotExistsException("Profile {0} does not exist.".format(profile_name))
|
||||||
|
|
||||||
def download_profile(self, profile_name: str,
|
def download_profile(self, profile_name: Union[str, Profile],
|
||||||
profile_pic: bool = True, profile_pic_only: bool = False,
|
profile_pic: bool = True, profile_pic_only: bool = False,
|
||||||
fast_update: bool = False,
|
fast_update: bool = False,
|
||||||
download_stories: bool = False, download_stories_only: bool = False,
|
download_stories: bool = False, download_stories_only: bool = False,
|
||||||
@ -676,7 +686,10 @@ class Instaloader:
|
|||||||
# Get profile main page json
|
# Get profile main page json
|
||||||
# check if profile does exist or name has changed since last download
|
# check if profile does exist or name has changed since last download
|
||||||
# and update name and json data if necessary
|
# and update name and json data if necessary
|
||||||
profile = self.check_profile_id(profile_name.lower())
|
if isinstance(profile_name, str):
|
||||||
|
profile = self.check_profile_id(profile_name.lower())
|
||||||
|
else:
|
||||||
|
profile = profile_name
|
||||||
|
|
||||||
profile_name = profile.username
|
profile_name = profile.username
|
||||||
|
|
||||||
|
@ -526,10 +526,11 @@ class Profile:
|
|||||||
@property
|
@property
|
||||||
def has_highlight_reels(self) -> bool:
|
def has_highlight_reels(self) -> bool:
|
||||||
"""
|
"""
|
||||||
This becomes `True` if the :class:`Profile` has any stories currently available,
|
Always returns `True` since :issue:`153`.
|
||||||
even if not viewable by the viewer.
|
|
||||||
|
Before broken, this indicated whether the :class:`Profile` had available stories.
|
||||||
"""
|
"""
|
||||||
return self._iphone_struct['has_highlight_reels']
|
return True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def has_public_story(self) -> bool:
|
def has_public_story(self) -> bool:
|
||||||
|
Loading…
Reference in New Issue
Block a user