Spaces:
Running
Running
| 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); | |
| }); |