Skip to content

Commit 8a6b6af

Browse files
author
João PV Correia
committed
✨New feature / 🐛 Bugfix / 🔨 Refactoring
## 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
1 parent 7f6fa03 commit 8a6b6af

File tree

3 files changed

+101
-87
lines changed

3 files changed

+101
-87
lines changed

GithubAPIBot.py

Lines changed: 60 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ def followings(self):
133133
def followings(self, value):
134134
self.__followings = value
135135

136-
def getUsers(self, url="", maxAction=None):
136+
def getUsers(self, url="", maxAction=None, following=False):
137137
users = []
138138

139139
try:
@@ -167,7 +167,12 @@ def getUsers(self, url="", maxAction=None):
167167
break
168168

169169
# Add username if it's not being followed already
170-
if not (user["login"] in self.followings):
170+
if (
171+
not following
172+
and not (user["login"] in self.followings)
173+
or following
174+
and (user["login"] in self.followings)
175+
):
171176
users.append(user["login"])
172177

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

178183
return users
179184

180-
def getFollowers(self, username=None):
185+
def getFollowers(self, username=None, following=None):
181186
if username == None:
182187
username = self.username
183-
print("\nGrabbing " + username + "'s followers\n")
188+
print(f"\nGrabbing {username}'s followers.\n")
184189
self.usersToAction.extend(
185-
self.getUsers("https://api.github.com/users/" + username + "/followers", self.maxAction)
190+
self.getUsers(
191+
url=f"https://api.github.com/users/{username}/followers",
192+
maxAction=self.maxAction,
193+
following=following,
194+
)
186195
)
187196

188-
def getFollowings(self, username=None, maxAction=None):
197+
def getFollowings(self, username=None):
189198
if username == None:
190199
username = self.username
191-
print("\nGrabbing " + username + "'s followings.\n")
192-
self.followings.extend(self.getUsers("https://api.github.com/users/" + username + "/following", maxAction))
200+
print(f"\nGrabbing {username}'s followings.\n")
201+
self.followings.extend(self.getUsers(url=f"https://api.github.com/users/{username}/following"))
193202

194203
def run(self, action):
195-
# Users to follow/unfollow must not exceed the given max
196-
if self.maxAction != None:
197-
self.usersToAction = self.usersToAction[: min(len(self.usersToAction), int(self.maxAction))]
198-
199-
# Start follow/unfollow
200-
print("\nStarting to " + action + ".\n")
201-
users = tqdm(
202-
self.usersToAction,
203-
initial=1,
204-
dynamic_ncols=True,
205-
smoothing=True,
206-
bar_format="[PROGRESS] {n_fmt}/{total_fmt} |{l_bar}{bar}|",
207-
leave=False,
208-
)
209-
for user in users:
204+
if len(self.usersToAction) == 0:
205+
print(f"Nothing to {action}")
206+
else:
210207

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

220-
# Unsuccessful
221-
if res.status_code != 204:
222-
sleepSeconds = random.randint(self.sleepSecondsLimitedMin, self.sleepSecondsLimitedMax)
223-
# Successful
224-
else:
225-
sleepSeconds = random.randint(self.sleepSecondsActionMin, self.sleepSecondsActionMax)
226-
227-
# Sleep
228-
sleepSecondsObj = list(range(0, sleepSeconds))
229-
sleepSecondsBar = tqdm(
230-
sleepSecondsObj,
212+
# Start follow/unfollow
213+
print(f"\nStarting to {action}.\n")
214+
users = tqdm(
215+
self.usersToAction,
216+
initial=1,
231217
dynamic_ncols=True,
232218
smoothing=True,
233-
bar_format="[SLEEPING] {n_fmt}s/{total_fmt}s |{l_bar}{bar}|",
219+
bar_format="[PROGRESS] {n_fmt}/{total_fmt} |{l_bar}{bar}|",
220+
leave=False,
234221
)
235-
for second in sleepSecondsBar:
236-
time.sleep(1)
237-
238-
print("\n\nFinished " + action + "ing!")
222+
for user in users:
223+
224+
# Follow/unfollow user
225+
try:
226+
if action == "follow":
227+
res = self.session.put(f"https://api.github.com/user/following/{user}")
228+
else:
229+
res = self.session.delete(f"https://api.github.com/user/following/{user}")
230+
except requests.exceptions.RequestException as e:
231+
raise SystemExit(e)
232+
233+
# Unsuccessful
234+
if res.status_code != 204:
235+
sleepSeconds = random.randint(self.sleepSecondsLimitedMin, self.sleepSecondsLimitedMax)
236+
# Successful
237+
else:
238+
sleepSeconds = random.randint(self.sleepSecondsActionMin, self.sleepSecondsActionMax)
239+
240+
# Sleep
241+
sleepSecondsObj = list(range(0, sleepSeconds))
242+
sleepSecondsBar = tqdm(
243+
sleepSecondsObj,
244+
dynamic_ncols=True,
245+
smoothing=True,
246+
bar_format="[SLEEPING] {n_fmt}s/{total_fmt}s |{l_bar}{bar}|",
247+
)
248+
for second in sleepSecondsBar:
249+
time.sleep(1)
250+
251+
print(f"\n\nFinished {action}ing!")
239252

240253
def follow(self):
241254
self.run("follow")

bot_follow.py

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,17 @@
88

99
# Arguments
1010
parser = argparse.ArgumentParser()
11-
parser.add_argument("-t", "--user-target", help="Target user to grab followers from")
11+
parser.add_argument("-t", "--user-target", help="Follow the followers of a target user")
1212
parser.add_argument("-f", "--file", help="Follow users from a pre-generated file")
13-
parser.add_argument("-p", "--popular", help="Follow the most popular users' followers from a given country")
14-
parser.add_argument("-m", "--max-follow", help="Max number of followers to follow")
13+
parser.add_argument("-p", "--popular", help="Follow the followers of the most popular users from a given country")
14+
parser.add_argument("-m", "--max-follow", help="Max number of users to follow")
15+
parser.add_argument("-smin", "--sleep-min", help="Min number of range to randomize sleep seconds between actions")
16+
parser.add_argument("-smax", "--sleep-max", help="Max number of range to randomize sleep seconds between actions")
1517
parser.add_argument(
16-
"-smin", "--sleep-min", help="Min number of range to randomize sleep seconds between actions", action="store_true"
18+
"-slmin", "--sleep-min-limited", help="Min number of range to randomize sleep seconds when account limited"
1719
)
1820
parser.add_argument(
19-
"-smax", "--sleep-max", help="Max number of range to randomize sleep seconds between actions", action="store_true"
20-
)
21-
parser.add_argument(
22-
"-slmin",
23-
"--sleep-min-limited",
24-
help="Min number of range to randomize sleep seconds when account limited",
25-
action="store_true",
26-
)
27-
parser.add_argument(
28-
"-slmax",
29-
"--sleep-max-limited",
30-
help="Max number of range to randomize sleep seconds when account limited",
31-
action="store_true",
21+
"-slmax", "--sleep-max-limited", help="Max number of range to randomize sleep seconds when account limited"
3222
)
3323
args = parser.parse_args()
3424

@@ -84,7 +74,13 @@
8474

8575
# Grab users from given file
8676
if args.file:
87-
bot.usersToAction.extend(args.file)
77+
with open(args.file, "r+") as file:
78+
try:
79+
fileUsers = json.load(file)
80+
except:
81+
raise ValueError("\n JSON file is in incorrect format.")
82+
fileUsersNotFollowed = [v for v in bot.followings if v not in fileUsers]
83+
bot.usersToAction.extend(fileUsersNotFollowed)
8884

8985

9086
# Write users to be followed to file

bot_unfollow.py

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,18 @@
77

88
# Arguments
99
parser = argparse.ArgumentParser()
10-
parser.add_argument("-a", "--all", help="Unfollow all your followers")
11-
parser.add_argument("-f", "--file", help="Followers File to Unfollow")
10+
parser.add_argument("-a", "--all", help="Unfollow all your followings", action="store_true")
11+
parser.add_argument("-fo", "--followers", help="Only unfollow users who already follow you", action="store_true")
12+
parser.add_argument("-nf", "--non-followers", help="Only unfollow users who don't follow you back", action="store_true")
13+
parser.add_argument("-f", "--file", help="File with usernames to Unfollow")
1214
parser.add_argument("-m", "--max-unfollow", help="Max Number of People to Unfollow")
15+
parser.add_argument("-smin", "--sleep-min", help="Min Number of range to randomize sleep seconds between actions")
16+
parser.add_argument("-smax", "--sleep-max", help="Max Number of range to randomize sleep seconds between actions")
1317
parser.add_argument(
14-
"-smin", "--sleep-min", help="Min Number of range to randomize sleep seconds between actions", action="store_true"
18+
"-slmin", "--sleep-min-limited", help="Min Number of range to randomize sleep seconds when account limited"
1519
)
1620
parser.add_argument(
17-
"-smax", "--sleep-max", help="Max Number of range to randomize sleep seconds between actions", action="store_true"
18-
)
19-
parser.add_argument(
20-
"-slmin",
21-
"--sleep-min-limited",
22-
help="Min Number of range to randomize sleep seconds when account limited",
23-
action="store_true",
24-
)
25-
parser.add_argument(
26-
"-slmax",
27-
"--sleep-max-limited",
28-
help="Max Number of range to randomize sleep seconds when account limited",
29-
action="store_true",
21+
"-slmax", "--sleep-max-limited", help="Max Number of range to randomize sleep seconds when account limited"
3022
)
3123
args = parser.parse_args()
3224

@@ -51,16 +43,29 @@
5143
)
5244

5345

54-
# Grab all users to unfollow from given user
46+
# Grab all following users
5547
if args.all:
5648
bot.usersToAction.extend(bot.followings)
5749
else:
58-
# Grab users from given file
50+
# Grab following users from given file
5951
if args.file:
60-
bot.usersToAction.extend(args.file)
61-
# Grab all users who already follow back
62-
if args.file:
63-
bot.usersToAction.extend(args.file)
52+
with open(args.file, "r+") as file:
53+
try:
54+
fileUsers = json.load(file)
55+
except:
56+
raise ValueError("\n JSON file is in incorrect format.")
57+
followedFileUsers = [v for v in bot.followings if v in fileUsers]
58+
bot.usersToAction.extend(followedFileUsers)
59+
60+
# Grab following users who are followers
61+
if args.followers:
62+
bot.getFollowers(following=True)
63+
64+
# Grab following users who aren't followers
65+
if args.non_followers:
66+
bot.getFollowers(following=True)
67+
nonFollowersFollowings = [v for v in bot.followings if v not in bot.usersToAction]
68+
bot.usersToAction.extend(nonFollowersFollowings)
6469

6570

6671
# Write users to be unfollowed to file

0 commit comments

Comments
 (0)