mirror of
https://github.com/instaloader/instaloader.git
synced 2024-11-19 16:52:30 +01:00
Use different exit codes for different failures (#2243)
This commit is contained in:
parent
14f1c3cb82
commit
65b12d650c
@ -314,6 +314,40 @@ when they were downloaded::
|
|||||||
|
|
||||||
instaloader --post-metadata-txt="{likes} likes, {comments} comments." <target>/*.json.xz
|
instaloader --post-metadata-txt="{likes} likes, {comments} comments." <target>/*.json.xz
|
||||||
|
|
||||||
|
.. _exit_codes:
|
||||||
|
|
||||||
|
Exit codes
|
||||||
|
^^^^^^^^^^
|
||||||
|
|
||||||
|
Different exit codes are used to indicate different kinds of error:
|
||||||
|
|
||||||
|
0
|
||||||
|
No error, all downloads were successful.
|
||||||
|
|
||||||
|
1
|
||||||
|
A non-fatal error happened. One or more posts, or even one or more
|
||||||
|
profiles could not be downloaded, but execution was not stopped. The
|
||||||
|
errors are repeated at the end of the log for easy access.
|
||||||
|
|
||||||
|
2
|
||||||
|
Command-line error. An unrecognized option was passed, or an invalid
|
||||||
|
combination of options, for example. No interaction with Instagram
|
||||||
|
was made.
|
||||||
|
|
||||||
|
3
|
||||||
|
Login error. It was not possible to login. Downloads were not
|
||||||
|
attempted.
|
||||||
|
|
||||||
|
4
|
||||||
|
Fatal download error. Downloads were interrupted and no further
|
||||||
|
attempts were made. Happens when a response with one of the status
|
||||||
|
codes in the :option:`--abort-on` option were passed, or when
|
||||||
|
Instagram logs the user out during downloads.
|
||||||
|
|
||||||
|
5
|
||||||
|
Interrupted by the user. Happens when the user presses Control-C or
|
||||||
|
sends SIGINT to the process.
|
||||||
|
|
||||||
.. _instaloader-as-cronjob:
|
.. _instaloader-as-cronjob:
|
||||||
|
|
||||||
Instaloader as Cronjob
|
Instaloader as Cronjob
|
||||||
|
@ -27,16 +27,26 @@ Exceptions
|
|||||||
|
|
||||||
.. autoexception:: LoginRequiredException
|
.. autoexception:: LoginRequiredException
|
||||||
|
|
||||||
|
.. autoexception:: LoginException
|
||||||
|
|
||||||
|
.. versionadded:: 4.12
|
||||||
|
|
||||||
.. autoexception:: TwoFactorAuthRequiredException
|
.. autoexception:: TwoFactorAuthRequiredException
|
||||||
|
|
||||||
.. versionadded:: 4.2
|
.. versionadded:: 4.2
|
||||||
|
|
||||||
|
.. versionchanged:: 4.12
|
||||||
|
Inherits LoginException
|
||||||
|
|
||||||
.. autoexception:: InvalidArgumentException
|
.. autoexception:: InvalidArgumentException
|
||||||
|
|
||||||
.. autoexception:: BadResponseException
|
.. autoexception:: BadResponseException
|
||||||
|
|
||||||
.. autoexception:: BadCredentialsException
|
.. autoexception:: BadCredentialsException
|
||||||
|
|
||||||
|
.. versionchanged:: 4.12
|
||||||
|
Inherits LoginException
|
||||||
|
|
||||||
.. autoexception:: PostChangedException
|
.. autoexception:: PostChangedException
|
||||||
|
|
||||||
.. autoexception:: QueryReturnedNotFoundException
|
.. autoexception:: QueryReturnedNotFoundException
|
||||||
|
@ -7,10 +7,11 @@ import re
|
|||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
from argparse import ArgumentParser, ArgumentTypeError, SUPPRESS
|
from argparse import ArgumentParser, ArgumentTypeError, SUPPRESS
|
||||||
|
from enum import IntEnum
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from . import (AbortDownloadException, BadCredentialsException, Instaloader, InstaloaderException,
|
from . import (AbortDownloadException, BadCredentialsException, Instaloader, InstaloaderException,
|
||||||
InvalidArgumentException, Post, Profile, ProfileNotExistsException, StoryItem,
|
InvalidArgumentException, LoginException, Post, Profile, ProfileNotExistsException, StoryItem,
|
||||||
TwoFactorAuthRequiredException, __version__, load_structure_from_file)
|
TwoFactorAuthRequiredException, __version__, load_structure_from_file)
|
||||||
from .instaloader import (get_default_session_filename, get_default_stamps_filename)
|
from .instaloader import (get_default_session_filename, get_default_stamps_filename)
|
||||||
from .instaloadercontext import default_user_agent
|
from .instaloadercontext import default_user_agent
|
||||||
@ -22,6 +23,15 @@ except ImportError:
|
|||||||
bc3_library = False
|
bc3_library = False
|
||||||
|
|
||||||
|
|
||||||
|
class ExitCode(IntEnum):
|
||||||
|
SUCCESS = 0
|
||||||
|
NON_FATAL_ERROR = 1
|
||||||
|
INIT_FAILURE = 2
|
||||||
|
LOGIN_FAILURE = 3
|
||||||
|
DOWNLOAD_ABORTED = 4
|
||||||
|
USER_ABORTED = 5
|
||||||
|
UNEXPECTED_ERROR = 99
|
||||||
|
|
||||||
def usage_string():
|
def usage_string():
|
||||||
# NOTE: duplicated in README.rst and docs/index.rst
|
# NOTE: duplicated in README.rst and docs/index.rst
|
||||||
argv0 = os.path.basename(sys.argv[0])
|
argv0 = os.path.basename(sys.argv[0])
|
||||||
@ -84,9 +94,8 @@ def get_cookies_from_instagram(domain, browser, cookie_file='', cookie_name=''):
|
|||||||
}
|
}
|
||||||
|
|
||||||
if browser not in supported_browsers:
|
if browser not in supported_browsers:
|
||||||
print("Loading cookies from the specified browser failed")
|
raise InvalidArgumentException("Loading cookies from the specified browser failed\n"
|
||||||
print("Supported browsers are Chrome, Firefox, Edge, Brave, Opera and Safari")
|
"Supported browsers are Chrome, Firefox, Edge, Brave, Opera and Safari")
|
||||||
return {}
|
|
||||||
|
|
||||||
cookies = {}
|
cookies = {}
|
||||||
browser_cookies = list(supported_browsers[browser](cookie_file=cookie_file))
|
browser_cookies = list(supported_browsers[browser](cookie_file=cookie_file))
|
||||||
@ -98,7 +107,8 @@ def get_cookies_from_instagram(domain, browser, cookie_file='', cookie_name=''):
|
|||||||
if cookies:
|
if cookies:
|
||||||
print(f"Cookies loaded successfully from {browser}")
|
print(f"Cookies loaded successfully from {browser}")
|
||||||
else:
|
else:
|
||||||
print(f"No cookies found for Instagram in {browser}, Are you logged in succesfully in {browser}?")
|
raise LoginException(f"No cookies found for Instagram in {browser}, "
|
||||||
|
f"Are you logged in succesfully in {browser}?")
|
||||||
|
|
||||||
if cookie_name:
|
if cookie_name:
|
||||||
return cookies.get(cookie_name, {})
|
return cookies.get(cookie_name, {})
|
||||||
@ -112,7 +122,7 @@ def import_session(browser, instaloader, cookiefile):
|
|||||||
instaloader.context.update_cookies(cookie)
|
instaloader.context.update_cookies(cookie)
|
||||||
username = instaloader.test_login()
|
username = instaloader.test_login()
|
||||||
if not username:
|
if not username:
|
||||||
raise SystemExit(f"Not logged in. Are you logged in successfully in {browser}?")
|
raise LoginException(f"Not logged in. Are you logged in successfully in {browser}?")
|
||||||
instaloader.context.username = username
|
instaloader.context.username = username
|
||||||
print(f"{username} has been successfully logged in.")
|
print(f"{username} has been successfully logged in.")
|
||||||
next_step_text = (f"Next: Run instaloader --login={username} as it is required to download high quality media "
|
next_step_text = (f"Next: Run instaloader --login={username} as it is required to download high quality media "
|
||||||
@ -133,7 +143,7 @@ def _main(instaloader: Instaloader, targetlist: List[str],
|
|||||||
max_count: Optional[int] = None, post_filter_str: Optional[str] = None,
|
max_count: Optional[int] = None, post_filter_str: Optional[str] = None,
|
||||||
storyitem_filter_str: Optional[str] = None,
|
storyitem_filter_str: Optional[str] = None,
|
||||||
browser: Optional[str] = None,
|
browser: Optional[str] = None,
|
||||||
cookiefile: Optional[str] = None) -> None:
|
cookiefile: Optional[str] = None) -> ExitCode:
|
||||||
"""Download set of profiles, hashtags etc. and handle logging in and session files if desired."""
|
"""Download set of profiles, hashtags etc. and handle logging in and session files if desired."""
|
||||||
# Parse and generate filter function
|
# Parse and generate filter function
|
||||||
post_filter = None
|
post_filter = None
|
||||||
@ -152,7 +162,7 @@ def _main(instaloader: Instaloader, targetlist: List[str],
|
|||||||
if browser and bc3_library:
|
if browser and bc3_library:
|
||||||
import_session(browser.lower(), instaloader, cookiefile)
|
import_session(browser.lower(), instaloader, cookiefile)
|
||||||
elif browser and not bc3_library:
|
elif browser and not bc3_library:
|
||||||
raise SystemExit("browser_cookie3 library is needed to load cookies from browsers")
|
raise InvalidArgumentException("browser_cookie3 library is needed to load cookies from browsers")
|
||||||
# Login, if desired
|
# Login, if desired
|
||||||
if username is not None:
|
if username is not None:
|
||||||
if not re.match(r"^[A-Za-z0-9._]+$", username):
|
if not re.match(r"^[A-Za-z0-9._]+$", username):
|
||||||
@ -189,6 +199,7 @@ def _main(instaloader: Instaloader, targetlist: List[str],
|
|||||||
# Try block for KeyboardInterrupt (save session on ^C)
|
# Try block for KeyboardInterrupt (save session on ^C)
|
||||||
profiles = set()
|
profiles = set()
|
||||||
anonymous_retry_profiles = set()
|
anonymous_retry_profiles = set()
|
||||||
|
exit_code = ExitCode.SUCCESS
|
||||||
try:
|
try:
|
||||||
# Generate set of profiles, already downloading non-profile targets
|
# Generate set of profiles, already downloading non-profile targets
|
||||||
for target in targetlist:
|
for target in targetlist:
|
||||||
@ -294,8 +305,10 @@ def _main(instaloader: Instaloader, targetlist: List[str],
|
|||||||
latest_stamps=latest_stamps)
|
latest_stamps=latest_stamps)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("\nInterrupted by user.", file=sys.stderr)
|
print("\nInterrupted by user.", file=sys.stderr)
|
||||||
|
exit_code = ExitCode.USER_ABORTED
|
||||||
except AbortDownloadException as exc:
|
except AbortDownloadException as exc:
|
||||||
print("\nDownload aborted: {}.".format(exc), file=sys.stderr)
|
print("\nDownload aborted: {}.".format(exc), file=sys.stderr)
|
||||||
|
exit_code = ExitCode.DOWNLOAD_ABORTED
|
||||||
# Save session if it is useful
|
# Save session if it is useful
|
||||||
if instaloader.context.is_logged_in:
|
if instaloader.context.is_logged_in:
|
||||||
instaloader.save_session_to_file(sessionfile)
|
instaloader.save_session_to_file(sessionfile)
|
||||||
@ -307,6 +320,8 @@ def _main(instaloader: Instaloader, targetlist: List[str],
|
|||||||
else:
|
else:
|
||||||
# Instaloader did not do anything
|
# Instaloader did not do anything
|
||||||
instaloader.context.log("usage:" + usage_string())
|
instaloader.context.log("usage:" + usage_string())
|
||||||
|
exit_code = ExitCode.INIT_FAILURE
|
||||||
|
return exit_code
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@ -488,10 +503,10 @@ def main():
|
|||||||
print("--login=USERNAME required to download stories.", file=sys.stderr)
|
print("--login=USERNAME required to download stories.", file=sys.stderr)
|
||||||
args.stories = False
|
args.stories = False
|
||||||
if args.stories_only:
|
if args.stories_only:
|
||||||
raise SystemExit(1)
|
raise InvalidArgumentException()
|
||||||
|
|
||||||
if ':feed-all' in args.profile or ':feed-liked' in args.profile:
|
if ':feed-all' in args.profile or ':feed-liked' in args.profile:
|
||||||
raise SystemExit(":feed-all and :feed-liked were removed. Use :feed as target and "
|
raise InvalidArgumentException(":feed-all and :feed-liked were removed. Use :feed as target and "
|
||||||
"eventually --post-filter=viewer_has_liked.")
|
"eventually --post-filter=viewer_has_liked.")
|
||||||
|
|
||||||
post_metadata_txt_pattern = '\n'.join(args.post_metadata_txt) if args.post_metadata_txt else None
|
post_metadata_txt_pattern = '\n'.join(args.post_metadata_txt) if args.post_metadata_txt else None
|
||||||
@ -502,18 +517,18 @@ def main():
|
|||||||
post_metadata_txt_pattern = ''
|
post_metadata_txt_pattern = ''
|
||||||
storyitem_metadata_txt_pattern = ''
|
storyitem_metadata_txt_pattern = ''
|
||||||
else:
|
else:
|
||||||
raise SystemExit("--no-captions and --post-metadata-txt or --storyitem-metadata-txt given; "
|
raise InvalidArgumentException("--no-captions and --post-metadata-txt or --storyitem-metadata-txt "
|
||||||
"That contradicts.")
|
"given; That contradicts.")
|
||||||
|
|
||||||
if args.no_resume and args.resume_prefix:
|
if args.no_resume and args.resume_prefix:
|
||||||
raise SystemExit("--no-resume and --resume-prefix given; That contradicts.")
|
raise InvalidArgumentException("--no-resume and --resume-prefix given; That contradicts.")
|
||||||
resume_prefix = (args.resume_prefix if args.resume_prefix else 'iterator') if not args.no_resume else None
|
resume_prefix = (args.resume_prefix if args.resume_prefix else 'iterator') if not args.no_resume else None
|
||||||
|
|
||||||
if args.no_pictures and args.fast_update:
|
if args.no_pictures and args.fast_update:
|
||||||
raise SystemExit('--no-pictures and --fast-update cannot be used together.')
|
raise InvalidArgumentException('--no-pictures and --fast-update cannot be used together.')
|
||||||
|
|
||||||
if args.login and args.load_cookies:
|
if args.login and args.load_cookies:
|
||||||
raise SystemExit('--load-cookies and --login cannot be used together.')
|
raise InvalidArgumentException('--load-cookies and --login cannot be used together.')
|
||||||
|
|
||||||
# Determine what to download
|
# Determine what to download
|
||||||
download_profile_pic = not args.no_profile_pic or args.profile_pic_only
|
download_profile_pic = not args.no_profile_pic or args.profile_pic_only
|
||||||
@ -538,7 +553,7 @@ def main():
|
|||||||
iphone_support=not args.no_iphone,
|
iphone_support=not args.no_iphone,
|
||||||
title_pattern=args.title_pattern,
|
title_pattern=args.title_pattern,
|
||||||
sanitize_paths=args.sanitize_paths)
|
sanitize_paths=args.sanitize_paths)
|
||||||
_main(loader,
|
exit_code = _main(loader,
|
||||||
args.profile,
|
args.profile,
|
||||||
username=args.login.lower() if args.login is not None else None,
|
username=args.login.lower() if args.login is not None else None,
|
||||||
password=args.password,
|
password=args.password,
|
||||||
@ -557,8 +572,18 @@ def main():
|
|||||||
browser=args.load_cookies,
|
browser=args.load_cookies,
|
||||||
cookiefile=args.cookiefile)
|
cookiefile=args.cookiefile)
|
||||||
loader.close()
|
loader.close()
|
||||||
|
if loader.has_stored_errors:
|
||||||
|
exit_code = ExitCode.NON_FATAL_ERROR
|
||||||
|
except InvalidArgumentException as err:
|
||||||
|
print(err, file=sys.stderr)
|
||||||
|
exit_code = ExitCode.INIT_FAILURE
|
||||||
|
except LoginException as err:
|
||||||
|
print(err, file=sys.stderr)
|
||||||
|
exit_code = ExitCode.LOGIN_FAILURE
|
||||||
except InstaloaderException as err:
|
except InstaloaderException as err:
|
||||||
raise SystemExit("Fatal error: %s" % err) from err
|
print("Fatal error: %s" % err)
|
||||||
|
exit_code = ExitCode.UNEXPECTED_ERROR
|
||||||
|
sys.exit(exit_code)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -33,7 +33,11 @@ class LoginRequiredException(InstaloaderException):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TwoFactorAuthRequiredException(InstaloaderException):
|
class LoginException(InstaloaderException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TwoFactorAuthRequiredException(LoginException):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@ -45,7 +49,7 @@ class BadResponseException(InstaloaderException):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BadCredentialsException(InstaloaderException):
|
class BadCredentialsException(LoginException):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@ -643,11 +643,16 @@ class Instaloader:
|
|||||||
def login(self, user: str, passwd: str) -> None:
|
def login(self, user: str, passwd: str) -> None:
|
||||||
"""Log in to instagram with given username and password and internally store session object.
|
"""Log in to instagram with given username and password and internally store session object.
|
||||||
|
|
||||||
:raises InvalidArgumentException: If the provided username does not exist.
|
|
||||||
:raises BadCredentialsException: If the provided password is wrong.
|
:raises BadCredentialsException: If the provided password is wrong.
|
||||||
:raises ConnectionException: If connection to Instagram failed.
|
|
||||||
:raises TwoFactorAuthRequiredException: First step of 2FA login done, now call
|
:raises TwoFactorAuthRequiredException: First step of 2FA login done, now call
|
||||||
:meth:`Instaloader.two_factor_login`."""
|
:meth:`Instaloader.two_factor_login`.
|
||||||
|
:raises LoginException: An error happened during login (for example, an invalid response was received).
|
||||||
|
Or if the provided username does not exist.
|
||||||
|
|
||||||
|
.. versionchanged:: 4.12
|
||||||
|
Raises LoginException instead of ConnectionException when an error happens.
|
||||||
|
Raises LoginException instead of InvalidArgumentException when the username does not exist.
|
||||||
|
"""
|
||||||
self.context.login(user, passwd)
|
self.context.login(user, passwd)
|
||||||
|
|
||||||
def two_factor_login(self, two_factor_code) -> None:
|
def two_factor_login(self, two_factor_code) -> None:
|
||||||
@ -1582,11 +1587,16 @@ class Instaloader:
|
|||||||
def interactive_login(self, username: str) -> None:
|
def interactive_login(self, username: str) -> None:
|
||||||
"""Logs in and internally stores session, asking user for password interactively.
|
"""Logs in and internally stores session, asking user for password interactively.
|
||||||
|
|
||||||
:raises LoginRequiredException: when in quiet mode.
|
:raises InvalidArgumentException: when in quiet mode.
|
||||||
:raises InvalidArgumentException: If the provided username does not exist.
|
:raises LoginException: If the provided username does not exist.
|
||||||
:raises ConnectionException: If connection to Instagram failed."""
|
:raises ConnectionException: If connection to Instagram failed.
|
||||||
|
|
||||||
|
.. versionchanged:: 4.12
|
||||||
|
Raises InvalidArgumentException instead of LoginRequiredException when in quiet mode.
|
||||||
|
Raises LoginException instead of InvalidArgumentException when the username does not exist.
|
||||||
|
"""
|
||||||
if self.context.quiet:
|
if self.context.quiet:
|
||||||
raise LoginRequiredException("Quiet mode requires given password or valid session file.")
|
raise InvalidArgumentException("Quiet mode requires given password or valid session file.")
|
||||||
try:
|
try:
|
||||||
password = None
|
password = None
|
||||||
while password is None:
|
while password is None:
|
||||||
@ -1605,3 +1615,10 @@ class Instaloader:
|
|||||||
except BadCredentialsException as err:
|
except BadCredentialsException as err:
|
||||||
print(err, file=sys.stderr)
|
print(err, file=sys.stderr)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_stored_errors(self) -> bool:
|
||||||
|
"""Returns whether any error has been reported and stored to be repeated at program termination.
|
||||||
|
|
||||||
|
.. versionadded: 4.12"""
|
||||||
|
return self.context.has_stored_errors
|
||||||
|
@ -151,6 +151,13 @@ class InstaloaderContext:
|
|||||||
if repeat_at_end:
|
if repeat_at_end:
|
||||||
self.error_log.append(msg)
|
self.error_log.append(msg)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_stored_errors(self) -> bool:
|
||||||
|
"""Returns whether any error has been reported and stored to be repeated at program termination.
|
||||||
|
|
||||||
|
.. versionadded: 4.12"""
|
||||||
|
return bool(self.error_log)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Print error log and close session"""
|
"""Print error log and close session"""
|
||||||
if self.error_log and not self.quiet:
|
if self.error_log and not self.quiet:
|
||||||
@ -242,11 +249,16 @@ class InstaloaderContext:
|
|||||||
def login(self, user, passwd):
|
def login(self, user, passwd):
|
||||||
"""Not meant to be used directly, use :meth:`Instaloader.login`.
|
"""Not meant to be used directly, use :meth:`Instaloader.login`.
|
||||||
|
|
||||||
:raises InvalidArgumentException: If the provided username does not exist.
|
|
||||||
:raises BadCredentialsException: If the provided password is wrong.
|
:raises BadCredentialsException: If the provided password is wrong.
|
||||||
:raises ConnectionException: If connection to Instagram failed.
|
|
||||||
:raises TwoFactorAuthRequiredException: First step of 2FA login done, now call
|
:raises TwoFactorAuthRequiredException: First step of 2FA login done, now call
|
||||||
:meth:`Instaloader.two_factor_login`."""
|
:meth:`Instaloader.two_factor_login`.
|
||||||
|
:raises LoginException: An error happened during login (for example, and invalid response).
|
||||||
|
Or if the provided username does not exist.
|
||||||
|
|
||||||
|
.. versionchanged:: 4.12
|
||||||
|
Raises LoginException instead of ConnectionException when an error happens.
|
||||||
|
Raises LoginException instead of InvalidArgumentException when the username does not exist.
|
||||||
|
"""
|
||||||
# pylint:disable=import-outside-toplevel
|
# pylint:disable=import-outside-toplevel
|
||||||
import http.client
|
import http.client
|
||||||
# pylint:disable=protected-access
|
# pylint:disable=protected-access
|
||||||
@ -277,7 +289,7 @@ class InstaloaderContext:
|
|||||||
resp_json = login.json()
|
resp_json = login.json()
|
||||||
|
|
||||||
except json.decoder.JSONDecodeError as err:
|
except json.decoder.JSONDecodeError as err:
|
||||||
raise ConnectionException(
|
raise LoginException(
|
||||||
"Login error: JSON decode fail, {} - {}.".format(login.status_code, login.reason)
|
"Login error: JSON decode fail, {} - {}.".format(login.status_code, login.reason)
|
||||||
) from err
|
) from err
|
||||||
if resp_json.get('two_factor_required'):
|
if resp_json.get('two_factor_required'):
|
||||||
@ -289,31 +301,31 @@ class InstaloaderContext:
|
|||||||
resp_json['two_factor_info']['two_factor_identifier'])
|
resp_json['two_factor_info']['two_factor_identifier'])
|
||||||
raise TwoFactorAuthRequiredException("Login error: two-factor authentication required.")
|
raise TwoFactorAuthRequiredException("Login error: two-factor authentication required.")
|
||||||
if resp_json.get('checkpoint_url'):
|
if resp_json.get('checkpoint_url'):
|
||||||
raise ConnectionException("Login: Checkpoint required. Point your browser to "
|
raise LoginException("Login: Checkpoint required. Point your browser to "
|
||||||
"https://www.instagram.com{} - "
|
"https://www.instagram.com{} - "
|
||||||
"follow the instructions, then retry.".format(resp_json.get('checkpoint_url')))
|
"follow the instructions, then retry.".format(resp_json.get('checkpoint_url')))
|
||||||
if resp_json['status'] != 'ok':
|
if resp_json['status'] != 'ok':
|
||||||
if 'message' in resp_json:
|
if 'message' in resp_json:
|
||||||
raise ConnectionException("Login error: \"{}\" status, message \"{}\".".format(resp_json['status'],
|
raise LoginException("Login error: \"{}\" status, message \"{}\".".format(resp_json['status'],
|
||||||
resp_json['message']))
|
resp_json['message']))
|
||||||
else:
|
else:
|
||||||
raise ConnectionException("Login error: \"{}\" status.".format(resp_json['status']))
|
raise LoginException("Login error: \"{}\" status.".format(resp_json['status']))
|
||||||
if 'authenticated' not in resp_json:
|
if 'authenticated' not in resp_json:
|
||||||
# Issue #472
|
# Issue #472
|
||||||
if 'message' in resp_json:
|
if 'message' in resp_json:
|
||||||
raise ConnectionException("Login error: Unexpected response, \"{}\".".format(resp_json['message']))
|
raise LoginException("Login error: Unexpected response, \"{}\".".format(resp_json['message']))
|
||||||
else:
|
else:
|
||||||
raise ConnectionException("Login error: Unexpected response, this might indicate a blocked IP.")
|
raise LoginException("Login error: Unexpected response, this might indicate a blocked IP.")
|
||||||
if not resp_json['authenticated']:
|
if not resp_json['authenticated']:
|
||||||
if resp_json['user']:
|
if resp_json['user']:
|
||||||
# '{"authenticated": false, "user": true, "status": "ok"}'
|
# '{"authenticated": false, "user": true, "status": "ok"}'
|
||||||
raise BadCredentialsException('Login error: Wrong password.')
|
raise BadCredentialsException('Login error: Wrong password.')
|
||||||
else:
|
else:
|
||||||
# '{"authenticated": false, "user": false, "status": "ok"}'
|
# '{"authenticated": false, "user": false, "status": "ok"}'
|
||||||
# Raise InvalidArgumentException rather than BadCredentialException, because BadCredentialException
|
# Raise LoginException rather than BadCredentialException, because BadCredentialException
|
||||||
# triggers re-asking of password in Instaloader.interactive_login(), which makes no sense if the
|
# triggers re-asking of password in Instaloader.interactive_login(), which makes no sense if the
|
||||||
# username is invalid.
|
# username is invalid.
|
||||||
raise InvalidArgumentException('Login error: User {} does not exist.'.format(user))
|
raise LoginException('Login error: User {} does not exist.'.format(user))
|
||||||
# '{"authenticated": true, "user": true, "userId": ..., "oneTapPrompt": false, "status": "ok"}'
|
# '{"authenticated": true, "user": true, "userId": ..., "oneTapPrompt": false, "status": "ok"}'
|
||||||
session.headers.update({'X-CSRFToken': login.cookies['csrftoken']})
|
session.headers.update({'X-CSRFToken': login.cookies['csrftoken']})
|
||||||
self._session = session
|
self._session = session
|
||||||
|
Loading…
Reference in New Issue
Block a user