from itertools import chain, cycle
from time import monotonic as time, sleep
from ..action import Action, QueuedActions, CandidateActions
from ..utils import random_intervals_generator
[docs]def all_users(api):
"""Iterator of all Instagram users"""
seen = set()
searched = set()
un_searched = set()
while True:
if len(un_searched) > 0:
_id = un_searched.pop()
searched.add(_id)
else:
_id = None
users = set(api.get_followers(_id) + api.get_following(_id))
for user in users:
if user.id not in searched:
un_searched.add(user.id)
if user.id not in seen:
seen.add(user.id)
yield user
[docs]class PeriodicLoginOut(Action):
"""
Log in and out of my account approx. every half hour.
This is to appear more human, as regular people close and reopen
the Instagram app regularly, and prolonged api usage without
re-logging can be flagged as bot/spam behaviour.
"""
def __init__(self, n_relogs=8, period=14400, **kwargs):
super(PeriodicLoginOut, self).__init__(**kwargs)
self.intervals = chain.from_iterable(
random_intervals_generator(n_relogs, period))
[docs] def step(self, api):
sleep(next(self.intervals))
api.switch_user(api.username, api.password)
[docs]class FollowNewUsers(CandidateActions):
"""
Follow users that are most likely to follow me back
that have no existing friendship status with me
"""
def __init__(self, *args, **kwargs):
super(FollowNewUsers, self).__init__('follow', *args, **kwargs)
[docs] def before_update(self, api):
api.get_followers()
[docs] def create_gen(self, api):
return all_users(api)
[docs] def get_score(self, api, candidate):
if candidate not in api.followers:
# Users who follow many people but are not followed by many
# people are more likely to follow back, and if they have
# lots of uploads then the likelihood increases further
score = candidate.n_followers / candidate.n_following
score -= candidate.n_posts / 1000
return score
[docs]class KeepUnderFollowLimit(QueuedActions):
"""
When maximum following (~7500) is reached,
unfollow users that have the most followers
"""
[docs] def update(self, api):
following = api.get_following()
if len(following) >= 7450:
by_popularity = sorted(following, key=lambda t: t.n_followers)
self.add(by_popularity[0].unfollow)
[docs]class UnfollowAfter(QueuedActions):
"""
Unfollow users I've been following for X amount of time
"""
def __init__(self, per_hour=30, after=604800):
super(UnfollowAfter, self).__init__(per_hour, 3600)
self.after = after
[docs] def update(self, api):
for user in api.get_following():
if time() - user.followed_me_at > self.after:
self.add('unfollow', user.id)
[docs]class UnfollowNotFollowing(QueuedActions):
"""
Unfollow users that I'm following that are not following me
"""
def __init__(self, per_hour=30):
super(UnfollowNotFollowing, self).__init__(per_hour, 3600)
[docs] def update(self, api):
followers = api.get_followers()
for user in api.get_following():
if user not in followers:
self.add('unfollow', user.id)
# class PeriodicUploads(Action):
# """
# Upload media with caption periodically
# """
# def __init__(self, post_cycle, **kwargs):
# super(PeriodicUploads, self).__init__(**kwargs)
# self.index = 0
# self.post_cycle = []
# # tuples of (datetime, path_to_media, settings_dict)
# self._post_cycle = post_cycle
#
# def begin(self, api):
# for t, path, settings in self._post_cycle:
# mini_cycle = (t,) + self.configure(api, path, settings)
# self.post_cycle.append(mini_cycle)
#
# def step(self, api):
# t, path, settings = self.post_cycle[self.index]
# if datetime.now() >= t:
# upload, media, settings = self.configure(api, path, settings)
# try:
# upload(media, **settings)
# except Exception as e:
# api.logger.error('Media at %s caused %s', path, repr(e))
# sleep(60) # wait a minute before trying again
# else:
# self.index += 1
#
# @staticmethod
# def configure(api, path, settings):
#
# if settings.pop('video', False):
#
# upload = api.upload.video
# # For videos 2 paths can be submitted to
# # also include a thumbnail for the video
# if isinstance(path, tuple):
# path, thumbnail_path = path
# thumbnail = image_from_path(thumbnail_path)
# settings['thumbnail'] = thumbnail
# else:
# upload = api.upload.photo
#
# media = image_from_path(path)
#
# return upload, media, settings