Skip to content

Commit e631b0c

Browse files
NEW discord webhook integration and updated api req logic and bug fixes
1 parent e17145d commit e631b0c

6 files changed

+260
-44
lines changed

config.example.json

+13-1
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,23 @@
22
"initialStartup": {
33
"completed": false
44
},
5+
"features": {
6+
"dailyMetrics": false,
7+
"loggingSystem:": false,
8+
"discordIntegration": {
9+
"enableFeature": false,
10+
"webhookURL": "ENTER_YOUR_WEBHOOK_LINK_HERE"
11+
}
12+
},
513
"configValues": {
614
"maxTotalFollowing": 1000,
715
"minWaitTimeSeconds": 500,
816
"maxWaitTimeSeconds": 900,
917
"queueListMaxUsers": 1000,
10-
"pendingFollowBackWaitTimeDays": 7
18+
"pendingFollowBackWaitTimeDays": 7,
19+
"minCycleFollowCount": 1,
20+
"maxCycleFollowCount": 5,
21+
"minCycleUnfollowCount": 1,
22+
"maxCycleUnfollowCount": 3
1123
}
1224
}

src/discordWebhook.js

+174
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
const axios = require("axios");
2+
const fs = require("fs");
3+
const path = require("path");
4+
5+
// Load the config from the config.json file
6+
const configPath = path.join(__dirname, "../config.json");
7+
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
8+
9+
// Check if Discord integration is enabled
10+
const discordConfig = config.features.discordIntegration;
11+
const webhookURL = discordConfig.webhookURL;
12+
const isDiscordEnabled = discordConfig.enableFeature;
13+
14+
// Helper function to convert hex to decimal
15+
function hexToDecimal(hex) {
16+
// Remove the leading '#' if present
17+
hex = hex.replace("#", "");
18+
return parseInt(hex, 16);
19+
}
20+
21+
// Function to send a message to Discord
22+
async function sendDiscordNotification(message) {
23+
if (!isDiscordEnabled) {
24+
console.log("Discord integration is disabled. Skipping notification.");
25+
return;
26+
}
27+
28+
try {
29+
await axios.post(webhookURL, {
30+
content: message, // The message you want to send
31+
});
32+
console.log("Notification sent to Discord!");
33+
} catch (error) {
34+
console.error("Error sending Discord notification:", error);
35+
}
36+
}
37+
38+
// Function to send an embed to Discord
39+
async function sendDiscordEmbed(title, description, hexColor = "#FF0000") {
40+
if (!isDiscordEnabled) {
41+
console.log(
42+
"Discord integration is disabled. Skipping embed notification."
43+
);
44+
return;
45+
}
46+
47+
const colorDecimal = hexToDecimal(hexColor); // Convert hex color to decimal
48+
49+
try {
50+
await axios.post(webhookURL, {
51+
embeds: [
52+
{
53+
title: title,
54+
description: description,
55+
color: colorDecimal, // Use the decimal color value
56+
footer: {
57+
text: "Built by www.kevintrinh.dev", // Add footer text
58+
},
59+
timestamp: new Date().toISOString(),
60+
},
61+
],
62+
});
63+
console.log("Embed notification sent to Discord!");
64+
} catch (error) {
65+
console.error("Error sending Discord embed notification:", error);
66+
}
67+
}
68+
69+
// Function to send an embed for a followed user object
70+
async function sendFollowedUserDiscordEmbed(user) {
71+
if (!isDiscordEnabled) {
72+
console.log(
73+
"Discord integration is disabled. Skipping user embed notification."
74+
);
75+
return;
76+
}
77+
78+
const colorDecimal = hexToDecimal("#55FF55"); // Green color in decimal
79+
80+
try {
81+
await axios.post(webhookURL, {
82+
embeds: [
83+
{
84+
title: `Successfully followed ${user.login} (${user.id})`,
85+
thumbnail: {
86+
url: user.avatar_url, // Set the user's avatar as the embed thumbnail
87+
},
88+
fields: [
89+
{
90+
name: "Profile URL",
91+
value: `[${user.login}](${user.html_url})`, // Embed the link to the user's profile
92+
inline: true, // Keep fields on the same line
93+
},
94+
{
95+
name: "User ID",
96+
value: user.id.toString(), // Display user ID
97+
inline: true, // Keep fields on the same line
98+
},
99+
{
100+
name: "Followed At",
101+
value: new Date().toLocaleString(), // Display current time and date
102+
inline: true, // Keep fields on the same line
103+
},
104+
],
105+
color: colorDecimal, // Use the green color
106+
footer: {
107+
text: "Built by www.kevintrinh.dev", // Add footer text
108+
},
109+
timestamp: new Date().toISOString(),
110+
},
111+
],
112+
});
113+
//console.log(`Embed notification sent to Discord for user ${user.login}!`);
114+
} catch (error) {
115+
console.error("Error sending Discord embed notification:", error);
116+
}
117+
}
118+
119+
// Function to send an embed for an unfollowed user object
120+
async function sendUnfollowedUserDiscordEmbed(user) {
121+
if (!isDiscordEnabled) {
122+
console.log(
123+
"Discord integration is disabled. Skipping unfollowed user embed notification."
124+
);
125+
return;
126+
}
127+
128+
const colorDecimal = hexToDecimal("#FF5555"); // Custom color in decimal
129+
130+
try {
131+
await axios.post(webhookURL, {
132+
embeds: [
133+
{
134+
title: `Successfully unfollowed ${user.login} (${user.id})`,
135+
thumbnail: {
136+
url: user.avatar_url, // Set the user's avatar as the embed thumbnail
137+
},
138+
fields: [
139+
{
140+
name: "Profile URL",
141+
value: `[${user.login}](${user.html_url})`, // Embed the link to the user's profile
142+
inline: true, // Single line for link
143+
},
144+
{
145+
name: "Followed On",
146+
value: new Date(user.followed_on).toLocaleString(), // Format the followed_on date
147+
inline: true, // Single line for followed date
148+
},
149+
{
150+
name: "Unfollowed On",
151+
value: new Date().toLocaleString(), // Display current time and date
152+
inline: true, // Single line for unfollowed date
153+
},
154+
],
155+
color: colorDecimal, // Use the custom color
156+
footer: {
157+
text: "Built by www.kevintrinh.dev", // Add footer text
158+
},
159+
timestamp: new Date().toISOString(),
160+
},
161+
],
162+
});
163+
//console.log(`Embed notification sent to Discord for unfollowed user ${user.login}!`);
164+
} catch (error) {
165+
console.error("Error sending Discord embed notification:", error);
166+
}
167+
}
168+
169+
module.exports = {
170+
sendDiscordNotification,
171+
sendDiscordEmbed,
172+
sendFollowedUserDiscordEmbed,
173+
sendUnfollowedUserDiscordEmbed,
174+
};

src/followUser.js

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const {
88
removeUserFromFollowQueue,
99
addUserToPendingFollowBack,
1010
} = require("./queues");
11+
const { sendFollowedUserDiscordEmbed } = require("./discordWebhook");
1112

1213
// Load the GitHub token from environment variables
1314
const YOUR_GITHUB_PERSONAL_ACCESS_TOKEN = process.env.GITHUB_TOKEN;
@@ -90,6 +91,7 @@ async function followUser(userObject) {
9091

9192
if (response.status === 204) {
9293
console.log(`Successfully followed ${username}.`);
94+
await sendFollowedUserDiscordEmbed(userObject);
9395
await addUserToPendingFollowBack(userObject);
9496
await saveUserIDToFollowed(userID);
9597
} else {

src/followersList.js

+4-6
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,12 @@ async function addUserFollowersToQueue(username) {
6565
// Calculate how many more users can be added
6666
const availableSpace = maxQueueSize - currentQueueSize;
6767

68-
// Check if the queue has reached or exceeded the maximum size
69-
if (availableSpace <= 0) {
70-
console.log("Queue has reached its maximum limit. Ignoring the request.");
71-
return;
72-
} else if (availableSpace <= 100) {
68+
// Only make an API request if more than 100 spaces are available
69+
if (availableSpace < 100) {
7370
console.log(
74-
`Queue is close to its maximum limit. Can only add ${availableSpace} more users.`
71+
`Not enough space in the queue. Available space: ${availableSpace} (NO API REQ. WAS MADE)`
7572
);
73+
return;
7674
}
7775

7876
try {

src/index.js

+63-37
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ const {
1919
addUserFollowersToQueue,
2020
getAllFollowersAndSaveToJson,
2121
} = require("./followersList");
22-
22+
const {
23+
sendDiscordNotification,
24+
sendDiscordEmbed,
25+
} = require("./discordWebhook");
2326
const MY_GITHUB_USERNAME = process.env.MY_GITHUB_USERNAME;
2427

2528
// Path to config file
@@ -37,66 +40,89 @@ async function saveConfig(config) {
3740
await fs.writeFile(configPath, data, "utf8");
3841
}
3942

43+
// Helper function to get a random integer between min and max (inclusive)
44+
function getRandomInt(min, max) {
45+
return Math.floor(Math.random() * (max - min + 1)) + min;
46+
}
47+
4048
// Main function for the processing loop
4149
async function processQueue() {
4250
const config = await loadConfig(); // Await loading of config file
4351
console.log("Starting the main processing loop...");
4452

53+
sendDiscordEmbed(
54+
"Successfully connected to webhook!",
55+
"Note that this application may result in your account getting banned. Please proceed with caution and use appropriate config settings.\n\n**Github Repo Link ➜** [Github-Followers-Bot](https://github.com/KevinTrinh1227/Github-Followers-Bot)\n**Report issues ➜** [Github Support Ticket](https://github.com/KevinTrinh1227/Github-Followers-Bot/issues)\n**My Github Page ➜** [Visit My Profile](https://github.com/KevinTrinh1227)\n\nPlease support me by **starring** and/or **forking** my repositories! Thank you for using my product!",
56+
"#55FF55"
57+
);
58+
4559
while (true) {
4660
try {
4761
const myTotalFollowing = await getTotalFollowing(MY_GITHUB_USERNAME);
62+
console.log(`\nMY TOTAL FOLLOWING IS AT: ${myTotalFollowing}`);
4863

49-
console.log(`MY TOTAL FOLLOWING IS AT: ${myTotalFollowing}`);
50-
64+
// Follow random number of users
5165
if (myTotalFollowing < config.configValues.maxTotalFollowing) {
52-
// getting the next in queue
53-
const nextFollower = await nextInFollowQueue(); // this gets user obj
54-
//console.log(nextFollower);
55-
if (nextFollower) {
56-
const nextFollowerName = nextFollower.login;
57-
const nextFollowerUserID = nextFollower.id;
58-
console.log(
59-
`Next follower name to process: ${nextFollowerName} (${nextFollowerUserID})`
60-
);
61-
62-
await addUserFollowersToQueue(nextFollowerName);
63-
await followUser(nextFollower); // follow user using entire object
64-
await removeUserFromFollowQueue(nextFollowerUserID);
65-
} else {
66-
console.log("No followers left in the queue.");
66+
const followCount = getRandomInt(
67+
config.configValues.minCycleFollowCount,
68+
config.configValues.maxCycleFollowCount
69+
); // Random number of users to follow
70+
console.log(`Attempting to follow ${followCount} users...`);
71+
72+
for (let i = 0; i < followCount; i++) {
73+
const nextFollower = await nextInFollowQueue(); // Get user object from the queue
74+
if (nextFollower) {
75+
const nextFollowerName = nextFollower.login;
76+
const nextFollowerUserID = nextFollower.id;
77+
console.log(
78+
`Next follower name to process: ${nextFollowerName} (${nextFollowerUserID})`
79+
);
80+
81+
await addUserFollowersToQueue(nextFollowerName);
82+
await followUser(nextFollower); // Follow user using the entire object
83+
await removeUserFromFollowQueue(nextFollowerUserID);
84+
} else {
85+
console.log("No followers left in the queue.");
86+
break;
87+
}
88+
await waitRandomInterval(); // Wait before processing the next user
6789
}
6890
} else {
6991
console.log(
7092
`NOT FOLLOWING ANY NEW USERS BECAUSE YOUR FOLLOWING MAX IN CONFIG.JSON IS ${config.configValues.maxTotalFollowing} and your currently at ${myTotalFollowing}`
7193
);
7294
}
7395

74-
//await unfollowUser("example-username-to-unfollow");
96+
// Unfollow random number of users
97+
const unfollowCount = getRandomInt(
98+
config.configValues.minCycleUnfollowCount,
99+
config.configValues.maxCycleUnfollowCount
100+
); // Random number of users to unfollow
101+
console.log(`Attempting to unfollow ${unfollowCount} users...`);
75102

76-
// Example: Fetch followers of a user and add them to the queue
77-
//await addUserFollowersToQueue("example-username-to-follow");
78-
await getAllFollowersAndSaveToJson(MY_GITHUB_USERNAME);
79-
await moveFollowBacksToUnfollowQueue(); // will see if we have user in both pending
80-
81-
const nextUnfollower = await nextInUnfollowQueue();
82-
console.log("\nUNFOLLOWING NOW STARTING...");
83-
if (nextUnfollower) {
84-
//console.log("Next user to unfollow:", nextUnfollower);
85-
console.log(
86-
`Next user to unfollow is ${nextUnfollower.login} (${nextUnfollower.id})`
87-
);
88-
await unfollowUser(nextUnfollower);
89-
} else {
90-
console.log("No users to unfollow.");
91-
await moveExpiredUsersToUnfollowQueue();
103+
for (let i = 0; i < unfollowCount; i++) {
104+
const nextUnfollower = await nextInUnfollowQueue();
105+
if (nextUnfollower) {
106+
console.log(
107+
`Next user to unfollow is ${nextUnfollower.login} (${nextUnfollower.id})`
108+
);
109+
await unfollowUser(nextUnfollower);
110+
} else {
111+
console.log("No users to unfollow.");
112+
break;
113+
}
114+
await waitRandomInterval(); // Wait before processing the next unfollow
92115
}
93116

117+
// Move expired users to the unfollow queue if none to unfollow
118+
await moveExpiredUsersToUnfollowQueue();
119+
94120
console.log("Waiting before the next cycle...\n\n\n");
95-
await waitRandomInterval(); // this will wait for random interval...
121+
await waitRandomInterval(); // Wait for a random interval...
96122
} catch (error) {
97123
// Log errors and continue
98124
console.error("Error in the processing loop:", error);
99-
await waitRandomInterval(); // this will wait for random interval...
125+
await waitRandomInterval(); // Wait for a random interval...
100126
}
101127
}
102128
}

src/unfollowUser.js

+4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ const currentFollowersPath = path.join(
1313
);
1414
const unfollowQueuePath = path.join(__dirname, "../data/unfollow_queue.json");
1515

16+
const { sendUnfollowedUserDiscordEmbed } = require("./discordWebhook");
17+
1618
// Path to the JSON file storing past followed and unfollowed users
1719
const pastFollowsUnfollowsPath = path.join(
1820
__dirname,
@@ -38,6 +40,8 @@ async function unfollowUser(user) {
3840
if (response.status === 204) {
3941
console.log(`Successfully unfollowed ${user.login}`);
4042

43+
sendUnfollowedUserDiscordEmbed(user);
44+
4145
// Add the unfollowedAt timestamp to the user object
4246
user.unfollowedAt = new Date().toISOString();
4347

0 commit comments

Comments
 (0)