Skip to content
This repository has been archived by the owner on Feb 25, 2024. It is now read-only.

Commit

Permalink
Merge branch 'master' into test-unlike
Browse files Browse the repository at this point in the history
  • Loading branch information
ohld committed Jan 28, 2019
2 parents d350bfd + 0748a7b commit 982202f
Show file tree
Hide file tree
Showing 9 changed files with 413 additions and 9 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.8.0
current_version = 0.10.0
tag = True
commit = True
message = Change version: {current_version} -> {new_version} [ci skip]
Expand Down
19 changes: 18 additions & 1 deletion instabot/bot/bot.py
Expand Up @@ -90,6 +90,7 @@ def __init__(self,
message_delay=60,
stop_words=('shop', 'store', 'free'),
blacklist_hashtags=['#shop', '#store', '#free'],
blocked_actions_protection=True,
verbosity=True,
device=None
):
Expand Down Expand Up @@ -136,6 +137,17 @@ def __init__(self,
'unblocks': max_unblocks_per_day,
'messages': max_messages_per_day}

self.blocked_actions_protection = blocked_actions_protection

self.blocked_actions = {'likes': False,
'unlikes': False,
'follows': False,
'unfollows': False,
'comments': False,
'blocks': False,
'unblocks': False,
'messages': False}

self.max_likes_to_like = max_likes_to_like
self.min_likes_to_like = min_likes_to_like
self.max_followers_to_follow = max_followers_to_follow
Expand Down Expand Up @@ -251,13 +263,16 @@ def login(self, **args):
def prepare(self):
storage = load_checkpoint(self)
if storage is not None:
self.total, self.api.total_requests, self.start_time = storage
self.total, self.blocked_actions, self.api.total_requests, self.start_time = storage

def print_counters(self):
for key, val in self.total.items():
if val > 0:
self.logger.info("Total {}: {}{}".format(key, val,
"/" + str(self.max_per_day[key]) if self.max_per_day.get(key) else ""))
for key, val in self.blocked_actions.items():
if val:
self.logger.info("Blocked {}".format(key))
self.logger.info("Total requests: {}".format(self.api.total_requests))

def delay(self, key):
Expand Down Expand Up @@ -288,6 +303,8 @@ def reached_limit(self, key):
def reset_counters(self):
for k in self.total:
self.total[k] = 0
for k in self.blocked_actions:
self.blocked_actions[k] = False
self.start_time = datetime.datetime.now()

# getters
Expand Down
6 changes: 5 additions & 1 deletion instabot/bot/bot_checkpoint.py
Expand Up @@ -13,6 +13,7 @@ class Checkpoint(object):
"""
Checkpoint for instabot.Bot class which can store:
.total[<name>] - all Bot's counters
.blocked_actions[<name>] - Bot's blocked actions
.following (list of user_ids)
.followers (list of user_ids)
.date (of checkpoint creation)
Expand All @@ -22,6 +23,9 @@ def __init__(self, bot):
self.total = {}
for k in bot.total:
self.total[k] = bot.total[k]
self.blocked_actions = {}
for k in bot.blocked_actions:
self.blocked_actions[k] = bot.blocked_actions[k]
self.start_time = bot.start_time
self.date = datetime.now()
self.total_requests = bot.api.total_requests
Expand All @@ -33,7 +37,7 @@ def fill_followers(self, bot):
self._followers = [item["pk"] for item in bot.api.get_total_self_followers()]

def dump(self):
return (self.total, self.total_requests, self.start_time)
return (self.total, self.blocked_actions, self.total_requests, self.start_time)


def save_checkpoint(self):
Expand Down
13 changes: 13 additions & 0 deletions instabot/bot/bot_comment.py
Expand Up @@ -16,6 +16,13 @@ def comment(self, media_id, comment_text):
if self.is_commented(media_id):
return True
if not self.reached_limit('comments'):
if self.blocked_actions['comments']:
self.logger.warn('YOUR `COMMENT` ACTION IS BLOCKED')
if self.blocked_actions_protection:
from datetime import timedelta
next_reset = (self.start_time.date() + timedelta(days=1)).strftime("%Y-%m-%d %H:%M:%S")
self.logger.warn('blocked_actions_protection ACTIVE. Skipping `comment` action till, at least, {}.'.format(next_reset))
return False
self.delay('comment')
_r = self.api.comment(media_id, comment_text)
if _r == 'feedback_required':
Expand All @@ -34,6 +41,11 @@ def reply_to_comment(self, media_id, comment_text, parent_comment_id):
self.logger.info("Media is not commented yet, nothing to answer to...")
return False
if not self.reached_limit('comments'):
if self.blocked_actions['comments']:
self.logger.warn('YOUR `COMMENT` ACTION IS BLOCKED')
if self.blocked_actions_protection:
self.logger.warn('blocked_actions_protection ACTIVE. Skipping `comment` action.')
return False
self.delay('comment')
if comment_text[0] != '@':
self.logger.error("A reply must start with mention, so '@' must be the 1st char, followed by the username you're replying to")
Expand All @@ -46,6 +58,7 @@ def reply_to_comment(self, media_id, comment_text, parent_comment_id):
self.logger.error("`Comment` action has been BLOCKED...!!!")
return False
if _r:
self.logger.info('Replied to comment {} of media {}'.format(parent_comment_id, media_id))
self.total['comments'] += 1
return True
else:
Expand Down
31 changes: 28 additions & 3 deletions instabot/bot/bot_like.py
Expand Up @@ -3,12 +3,18 @@

def like(self, media_id, check_media=True):
if not self.reached_limit('likes'):
if self.blocked_actions['likes']:
self.logger.warn('YOUR `LIKE` ACTION IS BLOCKED')
if self.blocked_actions_protection:
self.logger.warn('blocked_actions_protection ACTIVE. Skipping `like` action.')
return False
self.delay('like')
if check_media and not self.check_media(media_id):
return False
_r = self.api.like(media_id)
if _r == 'feedback_required':
self.logger.error("`Like` action has been BLOCKED...!!!")
self.blocked_actions['likes'] = True
return False
if _r:
self.logger.info("Liked media %d." % media_id)
Expand All @@ -20,15 +26,34 @@ def like(self, media_id, check_media=True):


def like_comment(self, comment_id):
if self.api.like_comment(comment_id):
return True
if not self.reached_limit('likes'):
if self.blocked_actions['likes']:
self.logger.warn('YOUR `LIKE` ACTION IS BLOCKED')
if self.blocked_actions_protection:
from datetime import timedelta
next_reset = (self.start_time.date() + timedelta(days=1)).strftime("%Y-%m-%d %H:%M:%S")
self.logger.warn('blocked_actions_protection ACTIVE. Skipping `like` action till, at least, {}.'.format(next_reset))
return False
self.delay('like')
_r = self.api.like_comment(comment_id)
if _r == 'feedback_required':
self.logger.error("`Like` action has been BLOCKED...!!!")
self.blocked_actions['likes'] = True
return False
if _r:
self.logger.info("Liked comment {}.".format(comment_id))
self.total['likes'] += 1
return True
else:
self.logger.info("Out of likes for today.")
return False


def like_media_comments(self, media_id):
broken_items = []
media_comments = self.get_media_comments(media_id)
comment_ids = [item["pk"] for item in media_comments if not item["has_liked_comment"]]
self.logger.info('Found {} comments'.format(len(media_comments)))
comment_ids = [item["pk"] for item in media_comments if not item.get('has_liked_comment') or not item["has_liked_comment"]]

if not comment_ids:
self.logger.info("None comments received: comments not found or comments have been filtered.")
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -10,7 +10,7 @@

setup(
name='instabot',
version='0.8.0',
version='0.10.0',

description='Instagram bot scripts for promotion and API python wrapper.',
long_description=long_description,
Expand Down
106 changes: 106 additions & 0 deletions tests/test_bot_comment.py
@@ -0,0 +1,106 @@

import pytest
import responses

try:
from unittest.mock import patch
except ImportError:
from mock import patch

from instabot.api.config import API_URL

from .test_bot import TestBot
from .test_variables import (TEST_CAPTION_ITEM, TEST_COMMENT_ITEM)


class TestBotGet(TestBot):

@responses.activate
@pytest.mark.parametrize('blocked_actions_protection,blocked_actions', [
(True, True),
(True, False),
(False, True),
(False, False)])
@patch('time.sleep', return_value=None)
def test_comment_feedback(self, patched_time_sleep, blocked_actions_protection, blocked_actions):
self.bot.blocked_actions_protection = blocked_actions_protection
self.bot.blocked_actions['comments'] = blocked_actions
media_id = 1234567890
comment_txt = "Yeah great!"

TEST_COMMENT_ITEM['user']['pk'] = self.bot.user_id + 1

results = 3
response_data = {
"caption": TEST_CAPTION_ITEM,
"caption_is_edited": False,
"comment_count": results,
"comment_likes_enabled": True,
"comments": [TEST_COMMENT_ITEM for _ in range(results)],
"has_more_comments": False,
"has_more_headload_comments": False,
"media_header_display": "none",
"preview_comments": [],
"status": "ok"
}
responses.add(
responses.GET, '{api_url}media/{media_id}/comments/?'.format(
api_url=API_URL, media_id=media_id), json=response_data, status=200)

response_data = {
"message": "feedback_required",
"spam": True,
"feedback_title": "Sorry, this feature isn't available right now",
"feedback_message": "An error occurred while processing this request. Please try again later. We restrict certain content and actions to protect our community. Tell us if you think we made a mistake.",
"feedback_url": "repute/report_problem/instagram_comment/",
"feedback_appeal_label": "Report problem",
"feedback_ignore_label": "OK",
"feedback_action": "report_problem",
"status": "fail"}
responses.add(
responses.POST, '{api_url}media/{media_id}/comment/'.format(
api_url=API_URL, media_id=media_id
), json=response_data, status=400
)

assert not self.bot.comment(media_id, comment_txt)

@responses.activate
@pytest.mark.parametrize('blocked_actions_protection,blocked_actions', [
(True, False),
(False, False)])
@patch('time.sleep', return_value=None)
def test_comment(self, patched_time_sleep, blocked_actions_protection, blocked_actions):
self.bot.blocked_actions_protection = blocked_actions_protection
self.bot.blocked_actions['comments'] = blocked_actions
media_id = 1234567890
comment_txt = "Yeah great!"

TEST_COMMENT_ITEM['user']['pk'] = self.bot.user_id + 1

results = 3
response_data = {
"caption": TEST_CAPTION_ITEM,
"caption_is_edited": False,
"comment_count": results,
"comment_likes_enabled": True,
"comments": [TEST_COMMENT_ITEM for _ in range(results)],
"has_more_comments": False,
"has_more_headload_comments": False,
"media_header_display": "none",
"preview_comments": [],
"status": "ok"
}
responses.add(
responses.GET, '{api_url}media/{media_id}/comments/?'.format(
api_url=API_URL, media_id=media_id), json=response_data, status=200)

response_data = {
"status": "ok"}
responses.add(
responses.POST, '{api_url}media/{media_id}/comment/'.format(
api_url=API_URL, media_id=media_id
), json=response_data, status=200
)

assert self.bot.comment(media_id, comment_txt)

0 comments on commit 982202f

Please sign in to comment.