Skip to content

Commit

Permalink
commit
Browse files Browse the repository at this point in the history
  • Loading branch information
luluwaffless committed Oct 17, 2024
0 parents commit d3ac55f
Show file tree
Hide file tree
Showing 6 changed files with 362 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.env
package-lock.json
node_modules/
public/logs.txt
34 changes: 34 additions & 0 deletions config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export default {
users: {
3887932258: {
name: "luucc_ss",
displayName: "lulu",
preDisplay: "a",
}
/*
99060139: {
name: "JuliaMinegirl",
displayName: "julia",
preDisplay: "a"
},
99451656: {
name: "Crisminegirl",
displayName: "cris",
preDisplay: "a"
},
104607645: {
name: "TexWillerHS",
displayName: "tex",
preDisplay: "o"
},*/
},
discord: {
status: "JuliaMinegirl 🎀",
name: "rbxuserspy",
displayName: "rbx user spy :3",
description: "stalkeando a julia minegirl",
vcStatusId: "1296162311308054528",
updatesTcId: "1296158553702400040"
},
port: 80
};
134 changes: 134 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import config from "./config.js";
import fs from "node:fs";
import axios from "axios";
import dotenv from "dotenv";
import express from "express";
import { Client, GatewayIntentBits, ActivityType, ButtonBuilder, ButtonStyle, ActionRowBuilder } from "discord.js";
dotenv.config();
const app = express();
app.use(express.static("public"));
let sessionInfo = { checks: 0, users: {}, erd: 0, efd: 0, esm: 0, startTime: new Date().toISOString(), nextCheck: "" };
let tc;
Object.keys(config.users).forEach((user) => {
sessionInfo.users[user] = {
lastStatus: -1,
lastStatusBegin: "",
lastLocation: "",
placeId: null,
gameId: null,
status: 0
};
});
async function log(data) {
return fs.appendFileSync("public/logs.txt", `[${new Date().toISOString()}] ${data}\n`);
};
const send = async (c) => await tc.send(c).catch((err) => {
sessionInfo.esm += 1;
log(`❌ Line 19: Error sending message: ${error}`);
});
function timeSince(isostr) {
const timestamp = new Date(isostr).getTime();
const now = new Date().getTime();
const diff = now - timestamp;
const hours = Math.floor(diff / (1000 * 60 * 60));
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((diff % (1000 * 60)) / 1000);
let parts = [];
if (hours && hours > 0) parts.push(`${hours} hora${hours != 1 ? "s" : ""}`);
if (minutes && minutes > 0) parts.push(`${minutes} minuto${minutes != 1 ? "s" : ""}`);
if (seconds && seconds > 0) parts.push(`${seconds} segundo${seconds != 1 ? "s" : ""}`);
return parts.length > 0 ? parts.join(", ") : "agora";
};
app.get("/info", (_, res) => {
res.json(sessionInfo);
});
app.get("/config", (_, res) => {
res.json(config);
});
app.get("/check", async function (_, res) {
await check(true);
res.json(sessionInfo);
});
app.get("/user", (req, res) => {
const response = config.users[req.query.id];
response ? res.json(response) : res.sendStatus(404);
});
const statusEmoji = ['⚫', '🔵', '🟢', '🟠', '❔'];
const statusText = ['offline', 'online', 'jogando', 'no studio', 'invisível'];
async function check(individual) {
await axios.post("https://presence.roblox.com/v1/presence/users", { "userIds": Object.keys(sessionInfo.users) }, {
headers: {
"accept": "application/json",
"Content-Type": "application/json",
"Cookie": process.env.cookie
}, withCredentials: true
})
.then(function (response) {
if (response.data["userPresences"] && response.data.userPresences.length > 0) {
response.data.userPresences.forEach((presence) => {
console.log(presence);
const { userPresenceType, lastLocation, placeId, gameId, userId } = presence;
if (userPresenceType != sessionInfo.users[presence.userId].status || presence.gameId != sessionInfo.users[presence.userId].gameId) {
sessionInfo.users[userId].lastStatus = sessionInfo.users[userId].status;
sessionInfo.users[userId].status = userPresenceType;
sessionInfo.users[userId].placeId = placeId;
sessionInfo.users[userId].gameId = gameId;
if (presence.userPresenceType === 2 && placeId && gameId) {
const button = new ButtonBuilder()
.setLabel('entrar')
.setURL(`https://deepblox.onrender.com/experiences/start?placeId=${placeId}&gameInstanceId=${gameId}`)
.setStyle(ButtonStyle.Link);
const row = new ActionRowBuilder()
.addComponents(button);
send({
content: `\`🟢\` **[${config.users[userId].preDisplay} ${config.users[userId].displayName}](<https://www.roblox.com/users/${userId}/profile>)** está jogando [${lastLocation}](https://www.roblox.com/games/${placeId})${sessionInfo.users[userId].lastStatus > 0 ? `\n-# ficou ${statusText[sessionInfo.users[userId].lastStatus]}${sessionInfo.users[userId].lastStatus === 2 ? " " + sessionInfo.users[userId].lastLocation : ""} por ${timeSince(sessionInfo.users[userId].lastStatusBegin)}` : ""}`,
components: [row]
});
} else {
send(`\`${statusEmoji[userPresenceType]}\` **[${config.users[userId].preDisplay} ${config.users[userId].displayName}](<https://www.roblox.com/users/${userId}/profile>)** está ${statusText[userPresenceType]}${sessionInfo.users[userId].lastStatus > 0 ? `\n-# ficou ${statusText[sessionInfo.users[userId].lastStatus]}${sessionInfo.users[userId].lastStatus === 2 ? " " + sessionInfo.users[userId].lastLocation : ""} por ${timeSince(sessionInfo.users[userId].lastStatusBegin)}` : ""}`);
};
sessionInfo.users[userId].lastLocation = lastLocation;
sessionInfo.users[presence.userId].lastStatusBegin = new Date().toISOString();
};
});
} else {
log(`❌ Line 214: Error reading data: ${response.data}`);
};
})
.catch(function (error) {
sessionInfo.efd += 1;
log(`❌ Line 219: Error fetching data: ${error}`);
});
sessionInfo.checks += 1;
if (!individual) sessionInfo.nextCheck = new Date(new Date().getTime() + 30000).toISOString();
};
const client = new Client({ intents: [GatewayIntentBits.Guilds] });

const changeName = (n, c) => { if (c.name != n) return c.setName(n); };
client.on('ready', async function () {
tc = await client.channels.fetch(config.discord.updatesTcId);
const vc = await client.channels.fetch(config.discord.vcStatusId);
await changeName("bot: online 🟢", vc);
client.user.setPresence({
activities: [{
name: config.discord.status,
type: ActivityType.Watching
}],
status: 'online'
});
check();
setInterval(check, 30000);
app.listen(config.port, function () {
console.log("✅ http://localhost:" + config.port);
});
log("🟢 Online");
for (let evt of ['SIGTERM', 'SIGINT', 'SIGHUP']) {
process.on(evt, async function () {
process.stdin.resume();
await changeName("bot: offline 🔴", vc);
await log("🔴 Offline");
process.exit();
});
};
});
client.login(process.env.token);
15 changes: 15 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "rbxuserspy",
"version": "1.0.0",
"main": "index.js",
"type": "module",
"scripts": {
"start": "node ."
},
"dependencies": {
"axios": "^1.7.7",
"discord.js": "^14.16.3",
"dotenv": "^16.4.5",
"express": "^4.21.1"
}
}
Binary file added public/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
175 changes: 175 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=0.65">
<title>rbxuserspy by luluwaffless</title>
<script src="https://unpkg.com/twemoji@latest/dist/twemoji.min.js" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.7.1.js" integrity="sha256-eKhayi8LEQwp4NKxN+CfCh+3qOVUtJn3QNZ0TciWLP4=" crossorigin="anonymous"></script>
<style type="text/css">
body {
font-size: large;
text-align: center;
color: rgb(237, 237, 249);
background-color: hsl(333, 77%, 5%);
font-family: monospace;
}
.emoji {
width: 1em;
height: 1em;
vertical-align: middle;
}
.other {
color: #808080;
}
a {
color: #ffffff;
}
#container {
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
position: absolute;
border-radius: 10px;
padding: 10px;
border: 1px solid rgba(255, 255, 255, 0.2);
background-color: hsl(333, 77%, 10%);
box-shadow: 0px 0px 10px 5px rgba(10, 10, 20, 0.2);
}
.blue {
color: rgb(128, 128, 255);
}
.green {
color: rgb(128, 255, 128);
}
.red {
color: rgb(255, 128, 128);
}
.yellow {
color: rgb(255, 255, 128);
}
.small {
font-size: small;
color: rgb(109, 109, 121);
padding: 0;
margin: 0;
}
#grid-container {
display: flex; /* Switch to flexbox */
gap: 10px; /* Add gap between items */
}
.item {
flex: 1 1 0; /* Ensure all items have equal width */
padding: 10px;
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 10px;
background-color: hsl(333, 77%, 15%);
display: flex;
align-items: center;
justify-content: center;
white-space: nowrap;
}
.list {
text-align: left;
}
.center-item {
grid-column: span 2;
justify-self: center;
}
</style>
<link rel="icon" type="image/x-icon" href="icon.png">
</head>
<body>
<div id="container" class="containerOffline">
<div style="padding: 10px;">
<a href="#">home</a> <a class="other" href="/logs.txt">logs</a> <a class="other" href="/config">config</a><br><br>
</div>
<div class="title">
<span style="font-weight: bolder; font-size: xx-large; color: #ffffff;">rbxuserspy</span><br><span style="font-size: small; color: #808080;">by luluwaffless</span>
</div><br>
<div id="grid-container">
<div class="item">
<span>👥 <a href="#" onclick="$.ajax({url:'/check'})">Users</a>:<div class="list"><br>🔎 Checks: <span class="blue" id="checks"></span><br>👥 Users:<br><span id="users"></span><br>⌛ Next Check: <span id="nextCheck" class="yellow"></span></div></span>
</div>
<div class="item center-item">
<span>❌ Errors:<div class="list"><br>📖 Read: <span class="red" id="erd"></span><br>🌐 Fetch: <span class="red" id="efd"></span><br>💬 Message: <span class="red" id="esm"></span></div></span>
</div>
</div>
<div style="padding: 10px;">
<span class="small" >⏱️ Runtime: <span id="runtime"></span></span>
</div>
</div>
</body>
<script type="text/javascript">
twemoji.parse(
document.body,
{ base: 'https://cdn.jsdelivr.net/gh/twitter/[email protected]/assets/' }
);
</script>
<script type="text/javascript">
const info = {checks: document.getElementById("checks"), users: document.getElementById("users"), erd: document.getElementById("erd"), efd: document.getElementById("efd"), esm: document.getElementById("esm"), runtime: document.getElementById("runtime"), nextCheck: document.getElementById("nextCheck")};
function timeSince(timestamp) {
const now = new Date().getTime();
const diff = now - timestamp;
const hours = Math.floor(diff / (1000 * 60 * 60));
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((diff % (1000 * 60)) / 1000);
let parts = [];
if (hours) parts.push(hours);
if (minutes || hours) parts.push(minutes.toString().padStart(hours ? 2 : 1, '0'));
parts.push(seconds.toString().padStart(minutes || hours ? 2 : 1, '0'));
return parts.join(':');
};
function timeUntil(timestamp) {
const now = new Date().getTime();
const diff = timestamp - now;
if (diff < 1000) return 'checking...';
const hours = Math.floor(diff / (1000 * 60 * 60));
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((diff % (1000 * 60)) / 1000);
let parts = [];
if (hours) parts.push(hours);
if (minutes || hours) parts.push(minutes.toString().padStart(hours ? 2 : 1, '0'));
parts.push(seconds.toString().padStart(minutes || hours ? 2 : 1, '0'));
return parts.join(':');
};

$.ajax("/config", {
success: function(data) {
let innerHTML = [];
Object.keys(data.users).forEach(function(id) {
const user = data.users[id];
innerHTML.push(`- <a href="https://www.roblox.com/users/${id}/profile">${user.name}</a>: <a id="${id}" class="green"></a>`);
});
info.users.innerHTML = innerHTML.join("<br>");
}
});
function main() {
const statusText = ['Offline', 'Online', 'Playing', 'In Studio', 'Invisible'];
$.ajax("/info", {
success: function(data) {
const nextCheck = new Date(data.nextCheck).getTime();
const runtimeDate = new Date(data.startTime).getTime();
info.checks.innerHTML = data.checks;
info.erd.innerHTML = data.erd;
info.efd.innerHTML = data.efd;
info.esm.innerHTML = data.esm;
Object.keys(data.users).forEach(function(id) {
const user = data.users[id];
const element = document.getElementById(id);
if (user.status == 2 && user.lastLocation && user.placeId && user.gameId) {
element.innerHTML = `Playing ${user.lastLocation}`;
element.href = `roblox://experiences/start?placeId=${user.placeId}&gameInstanceId=${user.gameId}`;
} else {
element.innerHTML = statusText[user.status];
};
});
info.runtime.innerHTML = timeSince(runtimeDate);
info.nextCheck.innerHTML = timeUntil(nextCheck);
}
});
setTimeout(main, 1000);
};
main();
</script>
</html>

0 comments on commit d3ac55f

Please sign in to comment.