From d21fb4154ec8acbabfb77ee70e42cb9eaa2e3a7e Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sat, 28 Apr 2018 21:45:57 +0200 Subject: [PATCH] fine-tune as-module.rst --- docs/as-module.rst | 55 +++++++++++++++++++++++++------------- instaloader/__init__.py | 4 +-- instaloader/instaloader.py | 31 +-------------------- instaloader/structures.py | 43 ++++++++++++++++------------- setup.py | 2 ++ 5 files changed, 66 insertions(+), 69 deletions(-) diff --git a/docs/as-module.rst b/docs/as-module.rst index 30d99e6..5790946 100644 --- a/docs/as-module.rst +++ b/docs/as-module.rst @@ -1,6 +1,6 @@ .. meta:: :description: - Documentation of Instaloader module, a powerful and easy-to-use + Documentation of Instaloader module, a powerful and intuitive Python library to download Instagram media and metadata. Python Module :mod:`instaloader` @@ -13,9 +13,9 @@ Python Module :mod:`instaloader` .. contents:: :backlinks: none -Instaloader exposes its internally used methods as a Python module, making it a -**powerful and easy-to-use Python API for Instagram**, allowing to further -customize obtaining media and metadata. +Instaloader exposes its internally used methods and structures as a Python +module, making it a **powerful and intuitive Python API for Instagram**, +allowing to further customize obtaining media and metadata. Start with getting an instance of :class:`Instaloader`:: @@ -57,32 +57,51 @@ provided in the remainder of this document. Instagram Structures ^^^^^^^^^^^^^^^^^^^^ -.. autofunction:: load_structure_from_file - -.. autofunction:: save_structure_to_file - -``Post`` -"""""""" - -.. autofunction:: mediaid_to_shortcode - -.. autofunction:: shortcode_to_mediaid +Posts +""""" .. autoclass:: Post :no-show-inheritance: -``StoryItem`` -""""""""""""" +Additionally, the following trivial structures are defined: + +.. autoclass:: PostSidecarNode + :no-show-inheritance: + :no-members: + +.. autoclass:: PostComment + :no-show-inheritance: + :no-members: + +.. autoclass:: PostLocation + :no-show-inheritance: + :no-members: + +User Stories +"""""""""""" + +.. autoclass:: Story + :no-show-inheritance: .. autoclass:: StoryItem :no-show-inheritance: -``Profile`` -""""""""""" +Profiles +"""""""" .. autoclass:: Profile :no-show-inheritance: +Loading and Saving +"""""""""""""""""" + +:class:`Post`, :class:`StoryItem` and :class:`Profile` can be saved and loaded +to/from JSON files. + +.. autofunction:: load_structure_from_file + +.. autofunction:: save_structure_to_file + Exceptions ^^^^^^^^^^ diff --git a/instaloader/__init__.py b/instaloader/__init__.py index 7d51a70..7adc0f0 100644 --- a/instaloader/__init__.py +++ b/instaloader/__init__.py @@ -15,5 +15,5 @@ else: from .exceptions import * from .instaloader import Instaloader from .instaloadercontext import InstaloaderContext -from .structures import (Post, Profile, Story, StoryItem, load_structure_from_file, mediaid_to_shortcode, - save_structure_to_file, shortcode_to_mediaid) +from .structures import (Post, PostSidecarNode, PostComment, PostLocation, Profile, Story, StoryItem, + load_structure_from_file, save_structure_to_file) diff --git a/instaloader/instaloader.py b/instaloader/instaloader.py index 5bd6e39..a752a67 100644 --- a/instaloader/instaloader.py +++ b/instaloader/instaloader.py @@ -71,36 +71,7 @@ class _PostPathFormatter(_ArbitraryItemFormatter): class Instaloader: - """Instaloader Class. - - :: - - L = Instaloader() - - # Optionally, login or load session - L.login(USER, PASSWORD) # (login) - L.interactive_login(USER) # (ask password on terminal) - L.load_session_from_file(USER) # (load session created w/ - # `instaloader -l USERNAME`) - - :mod:`instaloader` provides the :class:`Post` structure, which represents a - picture, video or sidecar (set of multiple pictures/videos) posted in a user's - profile. :class:`Instaloader` provides methods to iterate over Posts from a - certain source:: - - for post in L.get_hashtag_posts('cat'): - # post is an instance of Post - L.download_post(post, target='#cat') - - Besides :func:`Instaloader.get_hashtag_posts`, there is - :func:`Instaloader.get_feed_posts`, :func:`Profile.get_posts` and - :func:`Profile.get_saved_posts`. - Also, :class:`Post` instances can be created with :func:`Post.from_shortcode` - and :func:`Post.from_mediaid`. - - Also, this class provides methods :meth:`Instaloader.download_profile`, - :meth:`Instaloader.download_hashtag` and many more to download targets. - """ + """Instaloader Class.""" def __init__(self, sleep: bool = True, quiet: bool = False, diff --git a/instaloader/structures.py b/instaloader/structures.py index c8a6d9c..9ec74a3 100644 --- a/instaloader/structures.py +++ b/instaloader/structures.py @@ -11,19 +11,6 @@ from .exceptions import * from .instaloadercontext import InstaloaderContext -def shortcode_to_mediaid(code: str) -> int: - if len(code) > 11: - raise InvalidArgumentException("Wrong shortcode \"{0}\", unable to convert to mediaid.".format(code)) - code = 'A' * (12 - len(code)) + code - return int.from_bytes(b64decode(code.encode(), b'-_'), 'big') - - -def mediaid_to_shortcode(mediaid: int) -> str: - if mediaid.bit_length() > 64: - raise InvalidArgumentException("Wrong mediaid {0}, unable to convert to shortcode".format(str(mediaid))) - return b64encode(mediaid.to_bytes(9, 'big'), b'-_').decode().replace('A', ' ').lstrip().replace(' ', 'A') - - PostSidecarNode = namedtuple('PostSidecarNode', ['is_video', 'display_url', 'video_url']) PostComment = namedtuple('PostComment', ['id', 'created_at_utc', 'text', 'owner']) PostLocation = namedtuple('PostLocation', ['id', 'name', 'slug', 'has_public_page', 'lat', 'lng']) @@ -74,7 +61,20 @@ class Post: @classmethod def from_mediaid(cls, context: InstaloaderContext, mediaid: int): """Create a post object from a given mediaid""" - return cls.from_shortcode(context, mediaid_to_shortcode(mediaid)) + return cls.from_shortcode(context, Post.mediaid_to_shortcode(mediaid)) + + @staticmethod + def shortcode_to_mediaid(code: str) -> int: + if len(code) > 11: + raise InvalidArgumentException("Wrong shortcode \"{0}\", unable to convert to mediaid.".format(code)) + code = 'A' * (12 - len(code)) + code + return int.from_bytes(b64decode(code.encode(), b'-_'), 'big') + + @staticmethod + def mediaid_to_shortcode(mediaid: int) -> str: + if mediaid.bit_length() > 64: + raise InvalidArgumentException("Wrong mediaid {0}, unable to convert to shortcode".format(str(mediaid))) + return b64encode(mediaid.to_bytes(9, 'big'), b'-_').decode().replace('A', ' ').lstrip().replace(' ', 'A') def _asdict(self): if self._full_metadata_dict: @@ -593,10 +593,6 @@ class StoryItem: """The mediaid is a decimal representation of the media shortcode.""" return int(self._node['id']) - @property - def shortcode(self) -> str: - return mediaid_to_shortcode(self.mediaid) - def __repr__(self): return ''.format(self.mediaid) @@ -681,7 +677,16 @@ class Story: """ Structure representing a user story with its associated items. - Provides methods for accessing story properties, as well as :meth:`Story.get_items`. + Provides methods for accessing story properties, as well as :meth:`Story.get_items` to request associated + :class:`StoryItem` nodes. Stories are returned by :meth:`Instaloader.get_stories`. + + With a logged-in :class:`Instaloader` instance `L`, you may download all your visible user stories with:: + + for story in L.get_stories(): + # story is a Story object + for item in story.get_items(): + # item is a StoryItem object + L.download_storyitem(item, ':stores') This class implements == and is hashable. diff --git a/setup.py b/setup.py index 7ebd21f..0310088 100755 --- a/setup.py +++ b/setup.py @@ -54,10 +54,12 @@ setup( 'Development Status :: 5 - Production/Stable', 'Environment :: Console', 'Intended Audience :: End Users/Desktop', + 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3 :: Only', 'Topic :: Internet', 'Topic :: Multimedia :: Graphics'