├── .env.example ├── .gitignore ├── package.json ├── README.md ├── fill-friends-file.js ├── eris-export.js ├── create-files.js ├── yarn.lock ├── fill-friends-channels-file.js └── check-fake-friends.js /.env.example: -------------------------------------------------------------------------------- 1 | DISCORD_USER_TOKEN="" 2 | DISCORD_USER_ID="" 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Env 2 | .env 3 | 4 | # Data 5 | data/ 6 | 7 | # Node 8 | node_modules 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stop-fake-discord-friends", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "repository": "https://github.com/Androz2091/stop-fake-discord-friends.git", 6 | "author": "Androz2091 ", 7 | "license": "MIT", 8 | "dependencies": { 9 | "dotenv": "^16.0.3", 10 | "eris": "https://github.com/Androz2091/eris" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # stop-fake-discord-friends 2 | 3 | ## Why? 4 | 5 | I am friends with over 1000 users on Discord and I need to filter out the "fake" friends, the people I have never talked to. 6 | 7 | ## Run it 8 | 9 | * fill `.env` file 10 | 11 | * run `create-files.js` 12 | * run `fill-friends-file.js` 13 | * run `eris-export.js` 14 | * run `fill-friends-channels-file.js` 15 | * run `check-fake-friends.js` 16 | 17 | fake friends will appear in `data/fake-friends.txt`. 18 | -------------------------------------------------------------------------------- /fill-friends-file.js: -------------------------------------------------------------------------------- 1 | const { config } = require('dotenv'); 2 | config(); 3 | 4 | const { writeFileSync } = require('fs'); 5 | 6 | const token = process.env.DISCORD_USER_TOKEN; 7 | 8 | fetch('https://discord.com/api/v9/users/@me/relationships', { 9 | method: 'GET', 10 | headers: { 11 | Authorization: `${token}` 12 | } 13 | }).then(res => res.json()).then((friends) => { 14 | writeFileSync('data/friends.txt', friends.map(friend => friend.user.id).join('\n')); 15 | }); 16 | -------------------------------------------------------------------------------- /eris-export.js: -------------------------------------------------------------------------------- 1 | const Eris = require("eris"); 2 | 3 | const { config } = require("dotenv"); 4 | config(); 5 | 6 | const { writeFileSync } = require("fs"); 7 | 8 | const bot = new Eris(process.env.DISCORD_USER_TOKEN); 9 | 10 | bot.on("ready", () => { 11 | console.log("Exporting channels..."); 12 | writeFileSync('data/friends-channels.txt', Object.keys(bot.privateChannelMap).map(friendUserId => `${friendUserId},${bot.privateChannelMap[friendUserId]}`).join('\n')); 13 | process.exit(0); 14 | }); 15 | 16 | bot.connect(); 17 | -------------------------------------------------------------------------------- /create-files.js: -------------------------------------------------------------------------------- 1 | // create txt files if not existing 2 | const fs = require('fs'); 3 | if (!fs.existsSync('data/friends.txt')) { 4 | fs.writeFileSync('data/friends.txt', ''); 5 | } 6 | 7 | if (!fs.existsSync('data/friends-channels.txt')) { 8 | fs.writeFileSync('data/friends-channels.txt', ''); 9 | } 10 | 11 | if (!fs.existsSync('data/checked-friends.txt')) { 12 | fs.writeFileSync('data/checked-friends.txt', ''); 13 | } 14 | 15 | if (!fs.existsSync('data/fake-friends.txt')) { 16 | fs.writeFileSync('data/fake-friends.txt', ''); 17 | } 18 | 19 | if (!fs.existsSync('data/real-friends.txt')) { 20 | fs.writeFileSync('data/real-friends.txt', ''); 21 | } 22 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | dotenv@^16.0.3: 6 | version "16.0.3" 7 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07" 8 | integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ== 9 | 10 | "eris@https://github.com/Androz2091/eris": 11 | version "0.13.3" 12 | resolved "https://github.com/Androz2091/eris#f92e75c2395f1247915cef795f988a48ff915ed2" 13 | dependencies: 14 | ws "^7.2.1" 15 | optionalDependencies: 16 | opusscript "^0.0.7" 17 | tweetnacl "^1.0.1" 18 | 19 | opusscript@^0.0.7: 20 | version "0.0.7" 21 | resolved "https://registry.yarnpkg.com/opusscript/-/opusscript-0.0.7.tgz#7dd7ec55b302d26bf588e6fc3feb090b8c7da856" 22 | integrity sha512-DcBadTdYTUuH9zQtepsLjQn4Ll6rs3dmeFvN+SD0ThPnxRBRm/WC1zXWPg+wgAJimB784gdZvUMA57gDP7FdVg== 23 | 24 | tweetnacl@^1.0.1: 25 | version "1.0.3" 26 | resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" 27 | integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== 28 | 29 | ws@^7.2.1: 30 | version "7.5.9" 31 | resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" 32 | integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== 33 | -------------------------------------------------------------------------------- /fill-friends-channels-file.js: -------------------------------------------------------------------------------- 1 | const { config } = require('dotenv'); 2 | config(); 3 | 4 | const { readFileSync, writeFileSync } = require('fs'); 5 | 6 | const existingChannelsFriendsUserIds = readFileSync('data/friends-channels.txt', 'utf-8').split('\n').map(line => line.split(',')[0]); 7 | const friendsUserIds = readFileSync('data/friends.txt', 'utf-8').split('\n'); 8 | 9 | const missingFriendsUserIds = friendsUserIds.filter(friendUserId => !existingChannelsFriendsUserIds.includes(friendUserId)); 10 | 11 | const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)); 12 | 13 | const token = process.env.DISCORD_USER_TOKEN; 14 | 15 | (async () => { 16 | 17 | for (const friendUserId of missingFriendsUserIds) { 18 | const response = await fetch(`https://discord.com/api/v9/users/@me/channels`, { 19 | method: 'POST', 20 | headers: { 21 | Authorization: `${token}`, 22 | 'Content-Type': 'application/json' 23 | }, 24 | body: JSON.stringify({ 25 | recipients: [friendUserId], 26 | type: 1 27 | }) 28 | }); 29 | const json = await response.json(); 30 | const channelId = json.id; 31 | writeFileSync('data/friends-channels.txt', `\n${friendUserId},${channelId}`, { flag: 'a' }); 32 | 33 | await sleep(1000); 34 | 35 | console.log(`[progress] ${friendUserId} [${missingFriendsUserIds.indexOf(friendUserId) + 1}/${missingFriendsUserIds.length}]`) 36 | } 37 | 38 | })(); 39 | 40 | 41 | -------------------------------------------------------------------------------- /check-fake-friends.js: -------------------------------------------------------------------------------- 1 | const { config } = require('dotenv'); 2 | config(); 3 | 4 | const { readFileSync, writeFileSync } = require('fs'); 5 | 6 | const friends = readFileSync('data/friends.txt', 'utf-8').split('\n'); 7 | const channelsFriendsUserIds = readFileSync('data/friends-channels.txt', 'utf-8').split('\n').filter(line => friends.includes(line.split(',')[0])); 8 | const checkedFriends = readFileSync('data/checked-friends.txt', 'utf-8').split('\n'); 9 | 10 | const missingChannelsFriendsUserIds = channelsFriendsUserIds.filter(channelData => !checkedFriends.includes(channelData.split(',')[0])); 11 | 12 | const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)); 13 | 14 | const token = process.env.DISCORD_USER_TOKEN; 15 | 16 | (async () => { 17 | 18 | for (const channelData of missingChannelsFriendsUserIds) { 19 | 20 | const friendUserId = channelData.split(',')[0]; 21 | const channelId = channelData.split(',')[1]; 22 | 23 | const response = await fetch(`https://discord.com/api/v9/channels/${channelId}/messages?limit=50`, { 24 | headers: { 25 | Authorization: `${token}` 26 | } 27 | }); 28 | const json = await response.json(); 29 | const hasReplied = json.filter(message => message.author.id === process.env.DISCORD_USER_ID); 30 | const otherHasReplied = json.filter(message => message.author.id !== process.env.DISCORD_USER_ID); 31 | const username = otherHasReplied.length ? otherHasReplied[0].author.username : 'unknown'; 32 | 33 | if (hasReplied.length === 0) { 34 | writeFileSync('data/fake-friends.txt', `\n${friendUserId} (${hasReplied.length}/${otherHasReplied.length}) named ${username}`, { flag: 'a' }); 35 | } else { 36 | writeFileSync('data/real-friends.txt', `\n${friendUserId} (${hasReplied.length}/${otherHasReplied.length}) named ${username}`, { flag: 'a' }); 37 | } 38 | writeFileSync('data/checked-friends.txt', `\n${friendUserId}`, { flag: 'a' }); 39 | 40 | await sleep(1000); 41 | 42 | console.log(`[progress] ${friendUserId} [${channelsFriendsUserIds.indexOf(channelData) + 1}/${channelsFriendsUserIds.length}]`) 43 | } 44 | 45 | })(); 46 | 47 | 48 | --------------------------------------------------------------------------------