From a7f89e432749cf1f5c16258050dd134ca52aeba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Koch-Kramer?= Date: Sun, 18 Mar 2018 18:10:18 +0100 Subject: [PATCH 1/6] Release of version 3.3.2 --- instaloader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instaloader.py b/instaloader.py index 5258f89..ce372ba 100755 --- a/instaloader.py +++ b/instaloader.py @@ -29,7 +29,7 @@ import requests.utils import urllib3 -__version__ = '3.3.1' +__version__ = '3.3.2' try: From 90a1b73d21bdb12a836120a299efd4413defccef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Koch-Kramer?= Date: Wed, 21 Mar 2018 22:25:40 +0100 Subject: [PATCH 2/6] Fix format_string_contains_key() AttributeError occured if no parsable field was found in the specified pattern. Reported in #84. --- instaloader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instaloader.py b/instaloader.py index ce372ba..c3571b1 100755 --- a/instaloader.py +++ b/instaloader.py @@ -130,7 +130,7 @@ def mediaid_to_shortcode(mediaid: int) -> str: def format_string_contains_key(format_string: str, key: str) -> bool: # pylint:disable=unused-variable for literal_text, field_name, format_spec, conversion in string.Formatter().parse(format_string): - if field_name == key or field_name.startswith(key + '.'): + if field_name and (field_name == key or field_name.startswith(key + '.')): return True return False From 3640e9c05680258366bc97c64cbaceb356456a13 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 22 Mar 2018 11:25:20 +0100 Subject: [PATCH 3/6] =?UTF-8?q?Replace=20:=20by=20\ua789=20(=EA=9E=89)=20i?= =?UTF-8?q?n=20pathnames=20on=20Windows?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Workaround for #84. --- instaloader.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/instaloader.py b/instaloader.py index c3571b1..1522501 100755 --- a/instaloader.py +++ b/instaloader.py @@ -6,6 +6,7 @@ import getpass import json import os import pickle +import platform import random import re import shutil @@ -127,7 +128,7 @@ def mediaid_to_shortcode(mediaid: int) -> str: return b64encode(mediaid.to_bytes(9, 'big'), b'-_').decode().replace('A', ' ').lstrip().replace(' ','A') -def format_string_contains_key(format_string: str, key: str) -> bool: +def format_string_contains_key(format_string: '_PathPattern', key: str) -> bool: # pylint:disable=unused-variable for literal_text, field_name, format_spec, conversion in string.Formatter().parse(format_string): if field_name and (field_name == key or field_name.startswith(key + '.')): @@ -440,6 +441,14 @@ class Tristate(Enum): always = 2 +class _PathPattern(str): + """Class overriding :meth:`str.format` for character substitution in paths for Windows, see issue #84.""" + + def format(self, *args: Any, **kwargs: Any) -> str: + ret = super().format(*args, **kwargs) + return ret.replace(':', '\ua789') if platform.system() == 'Windows' else ret + + class Instaloader: GRAPHQL_PAGE_LENGTH = 200 @@ -462,18 +471,19 @@ class Instaloader: self.username = None self.sleep = sleep self.quiet = quiet - self.dirname_pattern = dirname_pattern if dirname_pattern is not None else '{target}' + self.dirname_pattern = _PathPattern(dirname_pattern if dirname_pattern is not None else '{target}') if filename_pattern is not None: filename_pattern = re.sub(r"({(?:post\.)?date)([:}])", r"\1_utc\2", filename_pattern) self.filename_pattern_old = filename_pattern.replace('{date_utc}', '{date_utc:%Y-%m-%d_%H-%M-%S}') - self.filename_pattern_old = re.sub(r"(?i)({(?:post\.)?date_utc:[^}]*?)_UTC", - r"\1", self.filename_pattern_old) + self.filename_pattern_old = _PathPattern(re.sub(r"(?i)({(?:post\.)?date_utc:[^}]*?)_UTC", + r"\1", self.filename_pattern_old)) filename_pattern = re.sub(r"(?i)({(date_utc|post\.date_utc):(?![^}]*UTC[^}]*).*?)}", r"\1_UTC}", filename_pattern) - self.filename_pattern = filename_pattern.replace('{date_utc}', '{date_utc:%Y-%m-%d_%H-%M-%S_UTC}') + self.filename_pattern = _PathPattern(filename_pattern.replace('{date_utc}', + '{date_utc:%Y-%m-%d_%H-%M-%S_UTC}')) else: - self.filename_pattern = '{date_utc:%Y-%m-%d_%H-%M-%S_UTC}' - self.filename_pattern_old = '{date_utc:%Y-%m-%d_%H-%M-%S}' + self.filename_pattern = _PathPattern('{date_utc:%Y-%m-%d_%H-%M-%S_UTC}') + self.filename_pattern_old = _PathPattern('{date_utc:%Y-%m-%d_%H-%M-%S}') self.download_videos = download_videos self.download_video_thumbnails = download_video_thumbnails self.download_geotags = download_geotags From 07b30d6ebd4ebb90cf8471cd7baed4dab56f797f Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 22 Mar 2018 13:42:08 +0100 Subject: [PATCH 4/6] Log message if Instaloader is called w/out target --- instaloader.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/instaloader.py b/instaloader.py index 1522501..22b248c 100755 --- a/instaloader.py +++ b/instaloader.py @@ -32,6 +32,12 @@ import urllib3 __version__ = '3.3.2' +# NOTE: duplicated in README.rst and docs/index.rst +USAGE_STRING = """ +{0} [--comments] [--geotags] [--stories] + [--login YOUR-USERNAME] [--fast-update] + profile | "#hashtag" | :stories | :feed | :saved +{0} --help""".format(sys.argv[0]) try: # pylint:disable=wrong-import-position @@ -1591,6 +1597,14 @@ class Instaloader: # Save session if it is useful if username is not None: self.save_session_to_file(sessionfile) + # User might be confused if Instaloader does nothing + if not profilelist: + if self.is_logged_in: + # Instaloader did at least save a session file + self._log("No targets were specified, thus nothing has been downloaded.") + else: + # Instloader did not do anything + self._log("usage:"+USAGE_STRING) if self.error_log: print("\nErrors occured:", file=sys.stderr) for err in self.error_log: @@ -1598,7 +1612,7 @@ class Instaloader: def main(): - parser = ArgumentParser(description=__doc__, add_help=False, + parser = ArgumentParser(description=__doc__, add_help=False, usage=USAGE_STRING, epilog="Report issues at https://github.com/instaloader/instaloader/issues. " "The complete documentation can be found at " "https://instaloader.github.io/.") From a125b367e3b7305da8f4ef33db98cd98a438dccd Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 22 Mar 2018 14:56:29 +0100 Subject: [PATCH 5/6] Release of version 3.3.3 --- instaloader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instaloader.py b/instaloader.py index 22b248c..2c8cd06 100755 --- a/instaloader.py +++ b/instaloader.py @@ -30,7 +30,7 @@ import requests.utils import urllib3 -__version__ = '3.3.2' +__version__ = '3.3.3' # NOTE: duplicated in README.rst and docs/index.rst USAGE_STRING = """ From 6764cd961f0e6f42ff4a5299a78592f6b36dffc6 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 22 Mar 2018 16:07:19 +0100 Subject: [PATCH 6/6] Tweak documentation description html meta tags --- docs/as-module.rst | 4 ++-- docs/basic-usage.rst | 7 +++++++ docs/index.rst | 7 ++++--- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/docs/as-module.rst b/docs/as-module.rst index ed8b61e..f936abd 100644 --- a/docs/as-module.rst +++ b/docs/as-module.rst @@ -1,7 +1,7 @@ .. meta:: :description: - Instaloader can also be used as a powerful and easy-to-use - Python API for Instagram, allowing to download media and metadata. + Documentation of Instaloader module, a powerful and easy-to-use + Python library to download Instagram media and metadata. Python Module :mod:`instaloader` -------------------------------- diff --git a/docs/basic-usage.rst b/docs/basic-usage.rst index e646a5e..9175929 100644 --- a/docs/basic-usage.rst +++ b/docs/basic-usage.rst @@ -1,3 +1,10 @@ +.. meta:: + :description: + How to download pictures from Instagram. Description of basic + usage of Instaloader, free tool to download photos from public + and private profiles, hashtags, stories, feeds, saved media, and + their metadata, comments and captions. + Download Pictures from Instagram --------------------------------- diff --git a/docs/index.rst b/docs/index.rst index d3a7e37..e18ac7e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,8 +1,9 @@ .. meta:: :description: - Command line tool to download pictures (and videos) from Instagram. - Instaloader downloads public and private profiles, hashtags, user stories, - feeds, saved media, comments, geotags, captions and other metadata of each post. + Free command line tool to download photos from Instagram. + Scrapes public and private profiles, hashtags, stories, feeds, + saved media, and their metadata, comments and captions. + Written in Python. Instaloader ===========