mirror of
https://github.com/instaloader/instaloader.git
synced 2024-09-11 16:22:24 +02:00
Evaluate --only-if filter smarter
If --only-if='likes>1000 or viewer_has_liked' is given, it is not neccessary to evaluate viewer_has_liked if the post has more than 1000 likes. The new implementation smartly handles this case.
This commit is contained in:
parent
ce38f5880f
commit
8cf1997460
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
"""Download pictures (or videos) along with their captions and other metadata from Instagram."""
|
"""Download pictures (or videos) along with their captions and other metadata from Instagram."""
|
||||||
import ast
|
import ast
|
||||||
import copy
|
|
||||||
import getpass
|
import getpass
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
@ -132,35 +131,29 @@ def format_string_contains_key(format_string: str, key: str) -> bool:
|
|||||||
def filterstr_to_filterfunc(filter_str: str, logged_in: bool) -> Callable[['Post'], bool]:
|
def filterstr_to_filterfunc(filter_str: str, logged_in: bool) -> Callable[['Post'], bool]:
|
||||||
"""Takes an --only-if=... filter specification and makes a filter_func Callable out of it."""
|
"""Takes an --only-if=... filter specification and makes a filter_func Callable out of it."""
|
||||||
|
|
||||||
class VerifyFilter(ast.NodeVisitor):
|
# The filter_str is parsed, then all names occurring in its AST are replaced by loads to post.<name>. A
|
||||||
|
# function Post->bool is returned which evaluates the filter with the post as 'post' in its namespace.
|
||||||
|
|
||||||
|
class TransformFilterAst(ast.NodeTransformer):
|
||||||
def visit_Name(self, node: ast.Name):
|
def visit_Name(self, node: ast.Name):
|
||||||
# pylint:disable=invalid-name
|
# pylint:disable=invalid-name,no-self-use
|
||||||
if not isinstance(node.ctx, ast.Load):
|
if not isinstance(node.ctx, ast.Load):
|
||||||
raise InvalidArgumentException("Invalid filter: Modifying variables ({}) not allowed.".format(node.id))
|
raise InvalidArgumentException("Invalid filter: Modifying variables ({}) not allowed.".format(node.id))
|
||||||
if not hasattr(Post, node.id):
|
if not hasattr(Post, node.id):
|
||||||
raise InvalidArgumentException("Invalid filter: Name {} is not defined.".format(node.id))
|
raise InvalidArgumentException("Invalid filter: Name {} is not defined.".format(node.id))
|
||||||
if node.id in Post.LOGIN_REQUIRING_PROPERTIES and not logged_in:
|
if node.id in Post.LOGIN_REQUIRING_PROPERTIES and not logged_in:
|
||||||
raise InvalidArgumentException("Invalid filter: Name {} requires being logged in.".format(node.id))
|
raise InvalidArgumentException("Invalid filter: Name {} requires being logged in.".format(node.id))
|
||||||
return self.generic_visit(node)
|
new_node = ast.Attribute(ast.copy_location(ast.Name('post', ast.Load()), node), node.id,
|
||||||
|
ast.copy_location(ast.Load(), node))
|
||||||
|
return ast.copy_location(new_node, node)
|
||||||
|
|
||||||
filter_ast = ast.parse(filter_str, filename='<--only-if parameter>', mode='eval')
|
input_filename = '<--only-if parameter>'
|
||||||
VerifyFilter().visit(filter_ast)
|
compiled_filter = compile(TransformFilterAst().visit(ast.parse(filter_str, filename=input_filename, mode='eval')),
|
||||||
|
filename=input_filename, mode='eval')
|
||||||
|
|
||||||
def filterfunc(post: 'Post') -> bool:
|
def filterfunc(post: 'Post') -> bool:
|
||||||
class EvaluatePostAttributes(ast.NodeTransformer):
|
|
||||||
def visit_Name(self, node: ast.Name):
|
|
||||||
# pylint:disable=invalid-name,no-self-use
|
|
||||||
obj = post.__getattribute__(node.id)
|
|
||||||
if isinstance(obj, str):
|
|
||||||
new_node = ast.Str(obj)
|
|
||||||
elif isinstance(obj, int) and not isinstance(obj, bool):
|
|
||||||
new_node = ast.Num(obj)
|
|
||||||
else: # True, False or None
|
|
||||||
new_node = ast.NameConstant(obj)
|
|
||||||
return ast.copy_location(new_node, node)
|
|
||||||
ast_obj = EvaluatePostAttributes().visit(copy.deepcopy(filter_ast))
|
|
||||||
# pylint:disable=eval-used
|
# pylint:disable=eval-used
|
||||||
return bool(eval(compile(ast_obj, '', 'eval'), {}))
|
return bool(eval(compiled_filter, {'post': post}))
|
||||||
|
|
||||||
return filterfunc
|
return filterfunc
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user