123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636 |
- const express = require("express");
- const fs = require("node:fs");
- const path = require("node:path");
- const supabase = require("@supabase/supabase-js");
- const cookie_parser = require("cookie-parser");
- const multer = require("multer");
- const app = express();
- require("dotenv").config();
- const webhookURL = process.env.WEBHOOK_URL;
- const utils = require("./utils.js");
- const url = "https://skibidihub.buttplugstudios.xyz"
- let ipBlacklist = JSON.parse(fs.readFileSync("./ipbans.json"));
- fs.watch("./ipbans.json", () => {
- console.log("Reloading IP Bans...");
- ipBlacklist = JSON.parse(fs.readFileSync("./ipbans.json"));
- });
- const port = 3000;
- const storage = multer.diskStorage({
- destination: function (req, file, cb) {
- try {
- // Validations
- if (!utils.checkBodyVideo(req.body)) throw new Error("invalid video body");
- if (!utils.checkToken(req, "/api/upload multer")) throw new Error("unauthorized");
- if(!req.skibidihub_id) req.skibidihub_id = utils.nanoid(7);
- console.log("Video ID:", req.skibidihub_id);
- // Check if the directory exists, and create it if it doesn't
- const dir = path.join(__dirname, "videos", req.skibidihub_id);
- if (!utils.videoExists(req.skibidihub_id)) {
- console.log("Directory does not exist, creating:", dir);
- fs.mkdirSync(dir, { recursive: true });
- }
- // Set the destination path for multer
- cb(null, dir);
- } catch (err) {
- console.log("Error in destination function:", err);
- cb(err);
- }
- },
- filename: function (req, file, cb) {
- let filename;
- if (file.fieldname === "video") {
- filename = "video.mp4";
- } else if (file.fieldname === "thumbnail") {
- filename = "thumbnail.jpg";
- }
- console.log("Saving file with filename:", filename);
- cb(null, filename);
- }
- });
- const upload = multer({
- storage: storage,
- limits: { fileSize: 1000000 * 250 /* 250MB in bytes */ }
- });
- const client = supabase.createClient(
- process.env.SUPABASE_URL,
- process.env.SUPABASE_KEY
- );
- const ipwareObject = require("@fullerstack/nax-ipware");
- const sunset = JSON.parse(fs.readFileSync(path.join(__dirname, "sunset.json")));
- const ipware = new ipwareObject.Ipware();
- app.use(function(req, res, next) {
- req.ipInfo = ipware.getClientIP(req);
- if (new Date().getTime() >= sunset.timestamp && sunset.sunset == true) {
- if(req.path == "/assets/piss baby.mp4") {
- if (ipBlacklist.includes(req.ipInfo.ip)) {
- res.setHeader("Cache-Control", "no-cache");
- return res.sendFile(path.join(__dirname, path.join("www", "down.html")));
- }
- } else {
- return res.sendFile(path.join(__dirname, path.join("www", "sunset.html")));
- }
- }
- if(ipBlacklist.includes(req.ipInfo.ip)) {
- res.setHeader("Cache-Control", "no-cache");
- return res.sendFile(path.join(__dirname, path.join("www", "down.html")));
- }
- next();
- });
- app.use(express.static("www")); // Static folder
- app.use(express.json()); // JSON body parser
- app.use(cookie_parser()); // Cookie parser
- // User facing URL's
- app.get("/", (req, res) => {
- res.sendFile(path.join(__dirname, path.join("www", "index.html")));
- });
- app.get("/login", (req, res) => {
- res.sendFile(path.join(__dirname, path.join("www", "login.html")));
- });
- app.get("/upload", (req, res) => {
- res.sendFile(path.join(__dirname, path.join("www", "upload.html")));
- })
- app.get("/contact", (req, res) => {
- res.sendFile(path.join(__dirname, path.join("www", "contact.html")));
- })
- app.get("/editProfile", (req, res) => {
- res.sendFile(path.join(__dirname, path.join("www", "editProfile.html")));
- });
- app.get("/search", (req, res) => {
- res.sendFile(path.join(__dirname, path.join("www", "search.html")));
- });
- app.set('view engine', 'ejs');
- app.get("/video/:id", async (req, res) => {
- if(utils.discordCheck(req) && utils.videoExists(req.params.id)) {
- const videoInfo = await utils.videoInfo(req.params.id);
- if(isNaN(videoInfo)) {
- return res.render("video", {
- video: `${url}/api/video/${req.params.id}.mp4`,
- video_name: videoInfo.title,
- description: videoInfo.description,
- url: url,
- author_url: `${url}/api/oembed/?author_name=${videoInfo.uploader}&author_url=${url}/user/${encodeURIComponent(videoInfo.uploader)}`
- })
- }
- }
- if(!utils.videoExists(req.params.id) && utils.checkToken(req, "/video/:id")) {
- return res.sendFile(path.join(__dirname, path.join("www", "404.html")));
- }
- res.sendFile(path.join(__dirname, path.join("www", "video.html")));
- });
- app.get("/user/:user", (req, res) => {
- if(!utils.checkToken(req, "/user/:user")) {
- return res.sendFile(path.join(__dirname, path.join("www", "user.html")));
- }
- // Check if user exists
- client.from("users").select().eq("name", decodeURIComponent(req.params.user)).then(data => {
- if(data.error) {
- return res.sendFile(path.join(__dirname, path.join("www", "404.html")));
- } else if (data.status != 200) {
- return res.sendFile(path.join(__dirname, path.join("www", "404.html")));
- }
- if(!data.data[0]) return res.sendFile(path.join(__dirname, path.join("www", "404.html")));
- res.sendFile(path.join(__dirname, path.join("www", "user.html")));
- })
- });
- // API //
- function handleVideoAPI(req, res) {
- if(!utils.checkToken(req, "/api/video/:id") && !utils.discordCheck(req)) {
- return res.sendFile(
- path.join(
- __dirname,
- path.join("www", path.join("assets", path.join("troll", "video.mp4")))
- )
- );
- }
- const videoPath = path.join(__dirname, path.join("videos", path.join(req.params.id, "video.mp4")));
- if(!fs.existsSync(videoPath)) return res.sendStatus(404);
- const stat = fs.statSync(videoPath);
- const fileSize = stat.size;
- const range = req.headers.range;
- console.log('Requested Range:', range); // Log the range for debugging
- if (range) {
- const parts = range.replace(/bytes=/, "").split("-");
- let start = parseInt(parts[0], 10);
- let end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;
- // Handle the case where range is 0-1
- if (start === 0 && end === 1) {
- end = 1;
- }
- const chunksize = (end - start) + 1;
- const file = fs.createReadStream(videoPath, {start, end});
- const head = {
- 'Content-Range': `bytes ${start}-${end}/${fileSize}`,
- 'Accept-Ranges': 'bytes',
- 'Content-Length': chunksize,
- 'Content-Type': 'video/mp4',
- };
- res.writeHead(206, head);
- file.pipe(res);
- } else {
- const head = {
- 'Content-Length': fileSize,
- 'Content-Type': 'video/mp4',
- 'Accept-Ranges': 'bytes',
- };
- res.writeHead(200, head);
- fs.createReadStream(videoPath).pipe(res);
- }
- }
- // Get an mp4 file according to its video ID.
- app.get('/api/video/:id*.mp4', handleVideoAPI);
- app.get("/api/video/:id", handleVideoAPI);
- // OEmbed
- const oembed = (provider_name, provider_url, author_name, author_url, url) => {
- const baseObject = {
- version: '1.0',
- };
- if (provider_name && provider_url) {
- baseObject.provider_name = provider_name;
- baseObject.provider_url = provider_url;
- }
- if (author_name) {
- baseObject.author_name = author_name;
- }
- if (author_url) {
- baseObject.author_url = author_url;
- }
- if (url) {
- baseObject.url = url;
- }
- return baseObject;
- };
- app.get('/api/oembed', (req, res) => {
- const {
- provider_name,
- provider_url,
- author_name,
- author_url,
- url,
- } = req.query;
- return res.status(200).send(oembed(provider_name, provider_url, author_name, author_url, url));
- });
- // Get a videos thumbnail according to its video ID.
- app.get("/api/thumbnail/:id", (req, res) => {
- if (!utils.checkToken(req, "/api/thumbnail/:id")) {
- let images = fs.readdirSync(
- path.join(__dirname, path.join("www", path.join("assets", "troll")))
- );
- res.sendFile(
- path.join(
- __dirname,
- path.join(
- "www",
- path.join(
- "assets",
- path.join("troll", images[utils.getRandomInt(images.length - 1)])
- )
- )
- )
- );
- return;
- }
- const thumbnail = utils.getThumbnail(req.params.id);
- if(thumbnail) return res.sendFile(thumbnail);
- if(!thumbnail) return res.sendStatus(404);
- });
- // Get a videos thumbnail according to its video ID.
- app.get("/api/webhookThumbnail/:id", (req, res) => {
- const thumbnail = utils.getThumbnail(req.params.id);
- if(thumbnail) return res.sendFile(thumbnail);
- if(!thumbnail) return res.sendStatus(404);
- });
- // Get the info for a video according to its video ID.
- app.get("/api/videoInfo/:id", async (req, res) => {
- if(!utils.checkToken(req, "/api/videoInfo/:id")) {
- let newData = {};
- newData.title = utils.fakeTitleList[utils.getRandomInt(utils.fakeTitleList.length)]
- newData.description = "SIGN IN to see this EPIC content"
- newData.likes = "69"
- newData.dislikes = "0"
- newData.uploader = "SIGN IN to see this EPIC content"
- newData.uploaded_at = new Date().toISOString().toString();
- return res.send(newData);
- }
- if(!utils.videoExists(req.params.id)) return res.sendStatus(404);
- const videoInfo = await utils.videoInfo(req.params.id);
- if(isNaN(videoInfo)) {
- return res.send(videoInfo);
- } else {
- return res.sendStatus(videoInfo);
- }
- });
- // Pulls the user information from the database and returns it.
- app.get("/api/userInfo/:id", (req, res) => {
- if(!utils.checkToken(req, "/api/userInfo/:id")) {
- let data = {
- name: "SIGN IN to see this EPIC CONTENT",
- subscribers: 999,
- social_score: 999,
- description: "SIGN IN to see this EPIC content",
- verified: true
- }
- return res.send(data);
- }
- client.from("users").select().eq("name", decodeURIComponent(req.params.id)).then(data => {
- if(data.error) {
- return res.sendStatus(400);
- } else if (data.status != 200) {
- return res.sendStatus(data.status);
- }
- if(!data.data[0]) return res.sendStatus(400);
- return res.send(data.data[0]);
- })
- })
- // Subscribes to a user
- app.get("/api/subscribe/:id", async (req, res) => {
- if(!utils.checkToken(req)) return res.sendStatus(401);
- if(!utils.userExists(decodeURIComponent(req.params.id))) return res.sendStatus(400);
- const subscribersData = await client
- .from("users")
- .select("subscribers")
- .eq("name", decodeURIComponent(req.params.id));
- const subscribers = subscribersData["data"][0]["subscribers"] + 1;
- client.from("users").update({
- subscribers: subscribers
- }).eq("name", decodeURIComponent(req.params.id)).then(data => {
- if(data.error) {
- return res.sendStatus(400);
- } else if (data.status != 204) {
- return res.sendStatus(data.status);
- }
- return res.sendStatus(200);
- })
- });
- // Login endpoints (Just handles user creation)
- app.post("/api/login", async (req, res) => {
- if(!req.body.user) return res.sendStatus(400);
- const ipInfo = ipware.getClientIP(req);
- // If user doesn't exist, create the user.
- if(!await utils.userExists(req.body.user)) {
- console.log(`User ${req.body.user} doesn't exist. Creating the user...`);
- await client.from("users").insert({
- name: req.body.user
- }).then(data => {
- if(data.error) {
- return res.status(500).send(data);
- } else if(data.status != 201) {
- return res.status(500).send(data);
- }
- console.log(`User created successfully. IP: ${ipInfo.ip}`);
- return res.sendStatus(200);
- });
- } else {
- console.log(`User ${req.body.user} already exists. Logging in... IP: ${ipInfo.ip}`);
- return res.sendStatus(200);
- }
- });
- app.post("/api/editUser", async (req, res) => {
- // Validate request
- const user = utils.checkUserToken(req, "/api/editUser");
- if(!user.value) return res.status(401).json({message: "you need to login to edit your user page"});
- if(!req.body.description && !req.body.website) return res.status(400).json({message: "invalid form data"});
- if(req.body.website && !utils.isValidUrl(req.body.website)) return res.status(400).json({message: "invalid website"});
-
- // Update user
- await client.from("users").update({
- description: req.body.description,
- website: req.body.website,
- }).eq("name", user.user).then(data => {
- if(data.error) {
- return res.status(500).send(data);
- } else if(data.status != 204) {
- return res.status(500).send(data);
- }
- return res.sendStatus(200);
- })
- });
- // Get the comments for a video according to its video ID.
- app.get("/api/comments/:videoID", (req, res) => {
- if(!utils.checkToken(req, "/api/comments/:videoID")) {
- let comments = [];
- for(let i = 0; i < 8; i++) {
- let comment = {};
- comment.text = utils.fakeCommentList[utils.getRandomInt(utils.fakeCommentList.length)]
- comment.commenter = "SIGN IN to see this EPIC content!";
- let date = new Date();
- date.setTime(1005286084);
- comment.created_at = date.toISOString();
- comments.push(comment);
- }
- return res.send(comments);
- }
- if(!utils.videoExists(req.params.videoID)) return res.sendStatus(404);
- client
- .from("comments")
- .select()
- .eq("video_id", req.params.videoID)
- .then((data) => {
- if (data.error) {
- res.sendStatus(400);
- } else if (data.status != 200) {
- res.sendStatus(data.status);
- }
-
- res.send(data["data"]);
- });
- });
- // Get a list of all videos
- app.get("/api/getAllVideos", (req, res) => {
- if(!utils.checkToken(req, "/api/getAllVideos/")) {
- let newData = [];
- for(let i = 0; i < 12; i++) {
- let temp = {};
- temp.description = "SIGN IN to see this EPIC content"
- temp.title = utils.fakeTitleList[utils.getRandomInt(utils.fakeTitleList.length)]
- temp.uploader = "SIGN IN to see this EPIC content";
- temp.id = utils.nanoid(7);
- newData.push(temp);
- }
- return res.send(newData);
- }
- client
- .from("videos")
- .select()
- .then((data) => {
- if (data.error) {
- return res.sendStatus(400);
- } else if (data.status != 200) {
- return res.sendStatus(data.status);
- }
- return res.send(data["data"]);
- });
- });
- // Search endpoint
- app.post("/api/search", (req, res) => {
- if(!utils.checkToken(req)) return res.sendStatus(401);
- if(!req.body.query) return res.sendStatus(400);
- client
- .from("videos")
- .select()
- .then((response) => {
- if (response.error) {
- return res.sendStatus(400);
- } else if (response.status != 200) {
- return res.sendStatus(response.status);
- }
- let results = [];
- response.data.forEach(video => {
- if(video.title.startsWith(req.body.query.toLowerCase()) || video.uploader.startsWith(req.body.query.toLowerCase())) results.push(video);
- })
- return res.send(results);
- });
- })
- // Send a comment
- app.post("/api/comment", async (req, res) => {
- if (!utils.checkToken(req, "/api/comment")) return res.sendStatus(401);
-
- // Sanity chekcs
- if(!req.body.commenter) return res.sendStatus(400);
- if(!req.body.videoID) return res.sendStatus(400);
- if(!req.body.text) return res.sendStatus(400);
-
- if(req.body.text.trim() == "") return res.sendStatus(400);
- if(!utils.videoExists(req.body.videoID)) return res.sendStatus(404);
- client
- .from("comments")
- .insert({
- commenter: req.body.commenter,
- video_id: req.body.videoID,
- text: req.body.text,
- })
- .then((data) => {
- res.send(data);
- // Discord webhook
- utils.sendWebhook(
- "new comment guys",
- "New COMMENT!!!!!",
- [
- {
- "id": 220464536,
- "description": req.body.text.trim(),
- "fields": [],
- "title": `New comment on video ${req.body.videoID}!`,
- "author": {
- "name": req.body.commenter,
- "url": `http://skibidihub.buttplugstudios.xyz/user/${encodeURIComponent(req.body.commenter)}`
- },
- "url": `http://skibidihub.buttplugstudios.xyz/video/${req.body.videoID}`,
- "color": 917248
- }
- ],
- webhookURL
- )
- });
- });
- // Like a video
- app.post("/api/like/:id", async (req, res) => {
- if(!utils.checkToken(req, "/api/like/:id")) return res.sendStatus(401);
- if(!utils.videoExists(req.params.id)) return res.sendStatus(404);
- const likesData = await client
- .from("videos")
- .select("likes")
- .eq("id", req.params.id);
-
- const likes = likesData["data"][0]["likes"] + 1;
- const video = await client
- .from("videos")
- .update({ likes: likes })
- .eq("id", req.params.id);
-
- res.send(video);
- });
- // Dislike a video
- app.post("/api/dislike/:id", async (req, res) => {
- if(!utils.checkToken(req, "/api/dislike/:id")) return res.sendStatus(401);
- if(!utils.videoExists(req.params.id)) return res.sendStatus(404);
- const dislikesData = await client
- .from("videos")
- .select("dislikes")
- .eq("id", req.params.id);
-
- const dislikes = dislikesData["data"][0]["dislikes"] + 1;
- const video = await client
- .from("videos")
- .update({ dislikes: dislikes })
- .eq("id", req.params.id);
- res.send(video);
- });
- app.get("/api/userVideos/:id", async (req, res) => {
- const data = await client
- .from("videos")
- .select()
- .eq("uploader", decodeURIComponent(req.params.id));
- res.send(data);
- });
- app.get("/api/sunset", async (req, res) => {
- const file = fs.readFileSync(path.join(__dirname, "sunset.json"))
- return res.send(JSON.parse(file))
- })
- app.post("/api/upload", upload.fields([
- { name: 'video' }, { name: 'thumbnail' }
- ]), utils.multerErrorHandler, async (req, res) => {
- if(!utils.checkBodyVideo(req.body)) return res.status(400).json({ message: "invalid video body" });
- if(!utils.checkToken(req, "/api/upload")) return res.status(401).json({ message: "SIGN IN to UPLOAD videos!!!" });
- await client.from("videos").insert({
- id: req.skibidihub_id,
- likes: 0,
- dislikes: 0,
- description: req.body.description,
- title: req.body.title,
- uploader: req.body.uploader
- }).then(data => {
- res.status(201).json({
- "id": req.skibidihub_id
- })
- // Discord webhook
- utils.sendWebhook(
- `new video guys <@&1274653503448678440> \`\`${req.skibidihub_id}\`\``,
- "New UPLOAD!!!!",
- [
- {
- "id": 220464536,
- "description": req.body.description,
- "fields": [],
- "title": req.body.title,
- "author": {
- "name": req.body.uploader,
- "url": `http://skibidihub.buttplugstudios.xyz/user/${encodeURIComponent(req.body.uploader)}`
- },
- "url": `http://skibidihub.buttplugstudios.xyz/video/${req.skibidihub_id}`,
- "color": 9830655,
- "image": {
- "url": `https://skibidihub.buttplugstudios.xyz/api/webhookThumbnail/${req.skibidihub_id}`
- }
- }
- ],
- webhookURL
- )
- })
- })
- // Start App
- app.listen(port, () => {
- console.log(`skibidihub listening on port ${port}`);
- });
|