1
0
mirror of https://github.com/instaloader/instaloader.git synced 2024-10-03 22:07:11 +02:00

Add support for loading structures directly from python json objects (#1092)

This commit is contained in:
anokhovd 2021-04-22 21:12:42 +03:00 committed by GitHub
parent 3837b642b0
commit fa19b95107
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 23 deletions

View File

@ -77,6 +77,10 @@ Loading and Saving
:class:`Post`, :class:`StoryItem`, :class:`Profile`, :class:`Hashtag` and
:class:`FrozenNodeIterator` can be saved and loaded to/from JSON files.
.. autofunction:: load_structure
.. autofunction:: load_structure_from_file
.. autofunction:: get_json_structure
.. autofunction:: save_structure_to_file

View File

@ -17,4 +17,5 @@ from .instaloader import Instaloader
from .instaloadercontext import InstaloaderContext, RateController
from .nodeiterator import NodeIterator, FrozenNodeIterator, resumable_iteration
from .structures import (Hashtag, Highlight, Post, PostSidecarNode, PostComment, PostCommentAnswer, PostLocation,
Profile, Story, StoryItem, TopSearchResults, load_structure_from_file, save_structure_to_file)
Profile, Story, StoryItem, TopSearchResults, load_structure_from_file, save_structure_to_file,
load_structure, get_json_structure)

View File

@ -1540,6 +1540,20 @@ class TopSearchResults:
JsonExportable = Union[Post, Profile, StoryItem, Hashtag, FrozenNodeIterator]
def get_json_structure(structure: JsonExportable) -> dict:
"""Returns Instaloader JSON structure for a :class:`Post`, :class:`Profile`, :class:`StoryItem`, :class:`Hashtag`
or :class:`FrozenNodeIterator` so that it can be loaded by :func:`load_structure`.
:param structure: :class:`Post`, :class:`Profile`, :class:`StoryItem` or :class:`Hashtag`
.. versionadded:: 4.8
"""
return {
'node': structure._asdict(),
'instaloader': {'version': __version__, 'node_type': structure.__class__.__name__}
}
def save_structure_to_file(structure: JsonExportable, filename: str) -> None:
"""Saves a :class:`Post`, :class:`Profile`, :class:`StoryItem`, :class:`Hashtag` or :class:`FrozenNodeIterator` to a
'.json' or '.json.xz' file such that it can later be loaded by :func:`load_structure_from_file`.
@ -1550,8 +1564,7 @@ def save_structure_to_file(structure: JsonExportable, filename: str) -> None:
:param structure: :class:`Post`, :class:`Profile`, :class:`StoryItem` or :class:`Hashtag`
:param filename: Filename, ends in '.json' or '.json.xz'
"""
json_structure = {'node': structure._asdict(),
'instaloader': {'version': __version__, 'node_type': structure.__class__.__name__}}
json_structure = get_json_structure(structure)
compress = filename.endswith('.xz')
if compress:
with lzma.open(filename, 'wt', check=lzma.CHECK_NONE) as fp:
@ -1561,6 +1574,34 @@ def save_structure_to_file(structure: JsonExportable, filename: str) -> None:
json.dump(json_structure, fp=fp, indent=4, sort_keys=True)
def load_structure(context: InstaloaderContext, json_structure: dict) -> JsonExportable:
"""Loads a :class:`Post`, :class:`Profile`, :class:`StoryItem`, :class:`Hashtag` or :class:`FrozenNodeIterator` from
a json structure.
:param context: :attr:`Instaloader.context` linked to the new object, used for additional queries if neccessary.
:param json_structure: Instaloader JSON structure
.. versionadded:: 4.8
"""
if 'node' in json_structure and 'instaloader' in json_structure and \
'node_type' in json_structure['instaloader']:
node_type = json_structure['instaloader']['node_type']
if node_type == "Post":
return Post(context, json_structure['node'])
elif node_type == "Profile":
return Profile(context, json_structure['node'])
elif node_type == "StoryItem":
return StoryItem(context, json_structure['node'])
elif node_type == "Hashtag":
return Hashtag(context, json_structure['node'])
elif node_type == "FrozenNodeIterator":
return FrozenNodeIterator(**json_structure['node'])
elif 'shortcode' in json_structure:
# Post JSON created with Instaloader v3
return Post.from_shortcode(context, json_structure['shortcode'])
raise InvalidArgumentException("Passed json structure is not an Instaloader JSON")
def load_structure_from_file(context: InstaloaderContext, filename: str) -> JsonExportable:
"""Loads a :class:`Post`, :class:`Profile`, :class:`StoryItem`, :class:`Hashtag` or :class:`FrozenNodeIterator` from
a '.json' or '.json.xz' file that has been saved by :func:`save_structure_to_file`.
@ -1575,23 +1616,4 @@ def load_structure_from_file(context: InstaloaderContext, filename: str) -> Json
fp = open(filename, 'rt')
json_structure = json.load(fp)
fp.close()
if 'node' in json_structure and 'instaloader' in json_structure and \
'node_type' in json_structure['instaloader']:
node_type = json_structure['instaloader']['node_type']
if node_type == "Post":
return Post(context, json_structure['node'])
elif node_type == "Profile":
return Profile(context, json_structure['node'])
elif node_type == "StoryItem":
return StoryItem(context, json_structure['node'])
elif node_type == "Hashtag":
return Hashtag(context, json_structure['node'])
elif node_type == "FrozenNodeIterator":
return FrozenNodeIterator(**json_structure['node'])
else:
raise InvalidArgumentException("{}: Not an Instaloader JSON.".format(filename))
elif 'shortcode' in json_structure:
# Post JSON created with Instaloader v3
return Post.from_shortcode(context, json_structure['shortcode'])
else:
raise InvalidArgumentException("{}: Not an Instaloader JSON.".format(filename))
return load_structure(context, json_structure)