Skip to content

Commit

Permalink
✨New feature / 🐛 Bugfix / 🔨 Refactoring
Browse files Browse the repository at this point in the history
## New feature
- Unfollow users who aren't following back

## Fix
- Boolean arguments
- Follow/unfollow sources from file
- Unfollow users who are following back

## Refactoring
- Formatting
- String formats
  • Loading branch information
João PV Correia committed Jan 12, 2022
1 parent 7f6fa03 commit 8a6b6af
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 87 deletions.
107 changes: 60 additions & 47 deletions GithubAPIBot.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def followings(self):
def followings(self, value):
self.__followings = value

def getUsers(self, url="", maxAction=None):
def getUsers(self, url="", maxAction=None, following=False):
users = []

try:
Expand Down Expand Up @@ -167,7 +167,12 @@ def getUsers(self, url="", maxAction=None):
break

# Add username if it's not being followed already
if not (user["login"] in self.followings):
if (
not following
and not (user["login"] in self.followings)
or following
and (user["login"] in self.followings)
):
users.append(user["login"])

# Check if we already have enough usernames
Expand All @@ -177,65 +182,73 @@ def getUsers(self, url="", maxAction=None):

return users

def getFollowers(self, username=None):
def getFollowers(self, username=None, following=None):
if username == None:
username = self.username
print("\nGrabbing " + username + "'s followers\n")
print(f"\nGrabbing {username}'s followers.\n")
self.usersToAction.extend(
self.getUsers("https://api.github.com/users/" + username + "/followers", self.maxAction)
self.getUsers(
url=f"https://api.github.com/users/{username}/followers",
maxAction=self.maxAction,
following=following,
)
)

def getFollowings(self, username=None, maxAction=None):
def getFollowings(self, username=None):
if username == None:
username = self.username
print("\nGrabbing " + username + "'s followings.\n")
self.followings.extend(self.getUsers("https://api.github.com/users/" + username + "/following", maxAction))
print(f"\nGrabbing {username}'s followings.\n")
self.followings.extend(self.getUsers(url=f"https://api.github.com/users/{username}/following"))

def run(self, action):
# Users to follow/unfollow must not exceed the given max
if self.maxAction != None:
self.usersToAction = self.usersToAction[: min(len(self.usersToAction), int(self.maxAction))]

# Start follow/unfollow
print("\nStarting to " + action + ".\n")
users = tqdm(
self.usersToAction,
initial=1,
dynamic_ncols=True,
smoothing=True,
bar_format="[PROGRESS] {n_fmt}/{total_fmt} |{l_bar}{bar}|",
leave=False,
)
for user in users:
if len(self.usersToAction) == 0:
print(f"Nothing to {action}")
else:

# Follow/unfollow user
try:
if action == "follow":
res = self.session.put("https://api.github.com/user/following/" + user)
else:
res = self.session.delete("https://api.github.com/user/following/" + user)
except requests.exceptions.RequestException as e:
raise SystemExit(e)
# Users to follow/unfollow must not exceed the given max
if self.maxAction != None:
self.usersToAction = self.usersToAction[: min(len(self.usersToAction), int(self.maxAction))]

# Unsuccessful
if res.status_code != 204:
sleepSeconds = random.randint(self.sleepSecondsLimitedMin, self.sleepSecondsLimitedMax)
# Successful
else:
sleepSeconds = random.randint(self.sleepSecondsActionMin, self.sleepSecondsActionMax)

# Sleep
sleepSecondsObj = list(range(0, sleepSeconds))
sleepSecondsBar = tqdm(
sleepSecondsObj,
# Start follow/unfollow
print(f"\nStarting to {action}.\n")
users = tqdm(
self.usersToAction,
initial=1,
dynamic_ncols=True,
smoothing=True,
bar_format="[SLEEPING] {n_fmt}s/{total_fmt}s |{l_bar}{bar}|",
bar_format="[PROGRESS] {n_fmt}/{total_fmt} |{l_bar}{bar}|",
leave=False,
)
for second in sleepSecondsBar:
time.sleep(1)

print("\n\nFinished " + action + "ing!")
for user in users:

# Follow/unfollow user
try:
if action == "follow":
res = self.session.put(f"https://api.github.com/user/following/{user}")
else:
res = self.session.delete(f"https://api.github.com/user/following/{user}")
except requests.exceptions.RequestException as e:
raise SystemExit(e)

# Unsuccessful
if res.status_code != 204:
sleepSeconds = random.randint(self.sleepSecondsLimitedMin, self.sleepSecondsLimitedMax)
# Successful
else:
sleepSeconds = random.randint(self.sleepSecondsActionMin, self.sleepSecondsActionMax)

# Sleep
sleepSecondsObj = list(range(0, sleepSeconds))
sleepSecondsBar = tqdm(
sleepSecondsObj,
dynamic_ncols=True,
smoothing=True,
bar_format="[SLEEPING] {n_fmt}s/{total_fmt}s |{l_bar}{bar}|",
)
for second in sleepSecondsBar:
time.sleep(1)

print(f"\n\nFinished {action}ing!")

def follow(self):
self.run("follow")
Expand Down
32 changes: 14 additions & 18 deletions bot_follow.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,17 @@

# Arguments
parser = argparse.ArgumentParser()
parser.add_argument("-t", "--user-target", help="Target user to grab followers from")
parser.add_argument("-t", "--user-target", help="Follow the followers of a target user")
parser.add_argument("-f", "--file", help="Follow users from a pre-generated file")
parser.add_argument("-p", "--popular", help="Follow the most popular users' followers from a given country")
parser.add_argument("-m", "--max-follow", help="Max number of followers to follow")
parser.add_argument("-p", "--popular", help="Follow the followers of the most popular users from a given country")
parser.add_argument("-m", "--max-follow", help="Max number of users to follow")
parser.add_argument("-smin", "--sleep-min", help="Min number of range to randomize sleep seconds between actions")
parser.add_argument("-smax", "--sleep-max", help="Max number of range to randomize sleep seconds between actions")
parser.add_argument(
"-smin", "--sleep-min", help="Min number of range to randomize sleep seconds between actions", action="store_true"
"-slmin", "--sleep-min-limited", help="Min number of range to randomize sleep seconds when account limited"
)
parser.add_argument(
"-smax", "--sleep-max", help="Max number of range to randomize sleep seconds between actions", action="store_true"
)
parser.add_argument(
"-slmin",
"--sleep-min-limited",
help="Min number of range to randomize sleep seconds when account limited",
action="store_true",
)
parser.add_argument(
"-slmax",
"--sleep-max-limited",
help="Max number of range to randomize sleep seconds when account limited",
action="store_true",
"-slmax", "--sleep-max-limited", help="Max number of range to randomize sleep seconds when account limited"
)
args = parser.parse_args()

Expand Down Expand Up @@ -84,7 +74,13 @@

# Grab users from given file
if args.file:
bot.usersToAction.extend(args.file)
with open(args.file, "r+") as file:
try:
fileUsers = json.load(file)
except:
raise ValueError("\n JSON file is in incorrect format.")
fileUsersNotFollowed = [v for v in bot.followings if v not in fileUsers]
bot.usersToAction.extend(fileUsersNotFollowed)


# Write users to be followed to file
Expand Down
49 changes: 27 additions & 22 deletions bot_unfollow.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,18 @@

# Arguments
parser = argparse.ArgumentParser()
parser.add_argument("-a", "--all", help="Unfollow all your followers")
parser.add_argument("-f", "--file", help="Followers File to Unfollow")
parser.add_argument("-a", "--all", help="Unfollow all your followings", action="store_true")
parser.add_argument("-fo", "--followers", help="Only unfollow users who already follow you", action="store_true")
parser.add_argument("-nf", "--non-followers", help="Only unfollow users who don't follow you back", action="store_true")
parser.add_argument("-f", "--file", help="File with usernames to Unfollow")
parser.add_argument("-m", "--max-unfollow", help="Max Number of People to Unfollow")
parser.add_argument("-smin", "--sleep-min", help="Min Number of range to randomize sleep seconds between actions")
parser.add_argument("-smax", "--sleep-max", help="Max Number of range to randomize sleep seconds between actions")
parser.add_argument(
"-smin", "--sleep-min", help="Min Number of range to randomize sleep seconds between actions", action="store_true"
"-slmin", "--sleep-min-limited", help="Min Number of range to randomize sleep seconds when account limited"
)
parser.add_argument(
"-smax", "--sleep-max", help="Max Number of range to randomize sleep seconds between actions", action="store_true"
)
parser.add_argument(
"-slmin",
"--sleep-min-limited",
help="Min Number of range to randomize sleep seconds when account limited",
action="store_true",
)
parser.add_argument(
"-slmax",
"--sleep-max-limited",
help="Max Number of range to randomize sleep seconds when account limited",
action="store_true",
"-slmax", "--sleep-max-limited", help="Max Number of range to randomize sleep seconds when account limited"
)
args = parser.parse_args()

Expand All @@ -51,16 +43,29 @@
)


# Grab all users to unfollow from given user
# Grab all following users
if args.all:
bot.usersToAction.extend(bot.followings)
else:
# Grab users from given file
# Grab following users from given file
if args.file:
bot.usersToAction.extend(args.file)
# Grab all users who already follow back
if args.file:
bot.usersToAction.extend(args.file)
with open(args.file, "r+") as file:
try:
fileUsers = json.load(file)
except:
raise ValueError("\n JSON file is in incorrect format.")
followedFileUsers = [v for v in bot.followings if v in fileUsers]
bot.usersToAction.extend(followedFileUsers)

# Grab following users who are followers
if args.followers:
bot.getFollowers(following=True)

# Grab following users who aren't followers
if args.non_followers:
bot.getFollowers(following=True)
nonFollowersFollowings = [v for v in bot.followings if v not in bot.usersToAction]
bot.usersToAction.extend(nonFollowersFollowings)


# Write users to be unfollowed to file
Expand Down

0 comments on commit 8a6b6af

Please sign in to comment.