const express = require("express"); const cors = require("cors"); const multer = require("multer"); const fs = require("fs"); const path = require("path"); const os = require("os"); const { execSync } = require("child_process"); const { formatDate, formatSize} = require("./function.js"); const FILE_DIR = path.join(__dirname, "files"); const EXPIRATION_TIME = 24 * 60 * 60 * 1000; // 24 jam dalam milidetik const META_FILE = path.join(__dirname, "list.json"); // Load metadata file (kalau ada) let fileData = {}; if (fs.existsSync(META_FILE)) { fileData = JSON.parse(fs.readFileSync(META_FILE)); } function formatRemainingTime(expiresAt) { const remainingMs = expiresAt - Date.now(); if (remainingMs <= 0) return "Expired"; const hours = Math.floor(remainingMs / (1000 * 60 * 60)); const minutes = Math.floor((remainingMs % (1000 * 60 * 60)) / (1000 * 60)); const seconds = Math.floor((remainingMs % (1000 * 60)) / 1000); return `${hours}h ${minutes}m ${seconds}s`; } const app = express(); const port = process.env.PORT || 7860; const uploadDir = path.join(__dirname, "files"); if (!fs.existsSync(uploadDir)) { fs.mkdirSync(uploadDir, { recursive: true }); } app.use(cors()); app.use("/files", express.static(uploadDir)); const storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, FILE_DIR); }, filename: (req, file, cb) => { const uniqueName = `${file.originalname}`; cb(null, uniqueName); } }); const upload = multer({ storage }); app.post("/upload", upload.single("file"), (req, res) => { if (!req.file) { return res.status(400).json({ success: false, message: "No file uploaded" }); } const filePath = req.file.filename; const customExpiration = req.body.expires_in ? parseInt(req.body.expires_in) * 1000 : req.params.expires_in ? parseInt(req.params.expires_in) * 1000 : EXPIRATION_TIME; const expiresAt = Date.now() + customExpiration; fileData[filePath] = { isPrivate: false, uploader: "Anonymous", file_name: req.file.originalname, file_url: `${req.protocol}://${req.get("host")}/files/${filePath}`, file_size: req.file.size, fileSize: formatSize(req.file.size), file_type: req.file.mimetype, uploadTime: Date.now(), uploadTimeFormat: formatDate(Date.now()), expiredAt: expiresAt, expired: formatDate(expiresAt) }; fs.writeFile(META_FILE, JSON.stringify(fileData, null, 2), (err) => { if (err) console.error("Gagal menulis ke api.json:", err); }); res.json({ status: true, file_name: req.file.originalname, file_size: req.file.size, file_type: req.file.mimetype, uploadTime: Date.now(), file_url: `${req.protocol}://${req.get("host")}/files/${filePath}`, expires_in: fileData[filePath] ? formatRemainingTime(fileData[filePath].expiredAt) : "Unknown" // Format sesuai sisa waktu }); }); app.get("/files/browse", (req, res) => { const page = parseInt(req.query.page) || 1; const limit = 5; // Filter hanya file yang isPrivate = false const publicFiles = Object.keys(fileData).filter(filename => fileData[filename]?.isPrivate === false); const startIndex = (page - 1) * limit; const endIndex = startIndex + limit; const paginatedFiles = publicFiles.slice(startIndex, endIndex).map(filename => ({ filename, file_url: `${req.protocol}://${req.get("host")}/files/${filename}`, expires_in: formatRemainingTime(fileData[filename]?.expiredAt), file_size: fileData[filename]?.fileSize, file_type: fileData[filename]?.file_type, uploadTime: fileData[filename]?.uploadTimeFormat })); res.json({ success: true, current_page: page, total_pages: Math.ceil(publicFiles.length / limit), total_files: publicFiles.length, files: paginatedFiles }); }); app.delete("/files/:filename", (req, res) => { const filePath = path.join(uploadDir, req.params.filename); fs.unlink(filePath, err => { if (err) return res.status(404).json({ success: false, message: "File not found" }); res.json({ success: true, message: "File deleted successfully!" }); }); }); app.get("/", (req, res) => { res.json({ success: true, message: "Welcome to Temporary Cloud File API 🚀", usage: { upload_file: { method: "POST", endpoint: "/upload", description: "Upload a file", body: "FormData (key: file)", params: "expires_in: number", response: { success: true, file_url: "string", expires_in: "string" } }, list_files: { method: "GET", endpoint: "/files/browse", description: "Get all uploaded files", response: { success: true, current_page: "number", total_pages: "number", total_files: "number", files: [{ filename: "string", file_url: "string", expires_in: "number", file_size: "number", file_type: "number", uploadTime: "number", }] } }, delete_file: { method: "DELETE", endpoint: "/files/:filename", description: "Delete a file", response: { success: true, message: "File deleted successfully!" } }, check_server: { method: "GET", endpoint: "/status", description: "Check server status (RAM, CPU, uptime, etc.)" } }, author: "rizxyu", github: "https://github.com/rizxyu" }); }); app.get("/status", (req, res) => { const uptime = process.uptime(); const memoryUsage = process.memoryUsage(); const cpuLoad = os.loadavg(); let diskUsage = "Not available"; try { diskUsage = execSync("df -h / | tail -1 | awk '{print $3 \" used / \" $2 \" total (\" $5 \" used)\"}'").toString().trim(); } catch (err) { diskUsage = "Error fetching disk usage"; } res.json({ success: true, server_time: new Date().toISOString(), uptime: `${Math.floor(uptime / 3600)}h ${Math.floor((uptime % 3600) / 60)}m ${Math.floor(uptime % 60)}s`, memory: { total: `${(os.totalmem() / 1024 / 1024).toFixed(2)} MB`, used: `${(memoryUsage.rss / 1024 / 1024).toFixed(2)} MB` }, cpu: { cores: os.cpus().length, load_avg: cpuLoad.map(load => load.toFixed(2)) }, disk: diskUsage, node_version: process.version }); }); setInterval(() => { const now = Date.now(); let updatedFileData = {}; Object.keys(fileData).forEach(filename => { const filePath = path.join(FILE_DIR, filename); if (fileData[filename].expiredAt <= now) { if (fs.existsSync(filePath)) { fs.unlinkSync(filePath); console.log(`🗑️ File expired dihapus: ${filename}`); } } else { updatedFileData[filename] = fileData[filename]; } }); // Update metadata file hanya jika ada perubahan if (Object.keys(updatedFileData).length !== Object.keys(fileData).length) { fileData = updatedFileData; fs.writeFileSync(META_FILE, JSON.stringify(fileData, null, 2)); } }, 60 * 60 * 1000); // Cek tiap 1 jam app.listen(port, () => { console.log("Listening on http://localhost:" + port); });