Spaces:
Running
Running
update CRUD
Browse files- Dockerfile +1 -0
- app.js +43 -14
- files/files.json +0 -1
- files.json → list.json +0 -0
Dockerfile
CHANGED
|
@@ -15,6 +15,7 @@ COPY . .
|
|
| 15 |
|
| 16 |
# Buat folder "files" & atur permission dengan benar
|
| 17 |
RUN mkdir -p /app/files && chmod -R 777 /app/files
|
|
|
|
| 18 |
|
| 19 |
# Expose port API
|
| 20 |
EXPOSE 7860
|
|
|
|
| 15 |
|
| 16 |
# Buat folder "files" & atur permission dengan benar
|
| 17 |
RUN mkdir -p /app/files && chmod -R 777 /app/files
|
| 18 |
+
RUN touch /app/list.json && chmod 666 /app/list.json
|
| 19 |
|
| 20 |
# Expose port API
|
| 21 |
EXPOSE 7860
|
app.js
CHANGED
|
@@ -9,7 +9,7 @@ const { execSync } = require("child_process");
|
|
| 9 |
|
| 10 |
const FILE_DIR = path.join(__dirname, "files");
|
| 11 |
const EXPIRATION_TIME = 24 * 60 * 60 * 1000; // 24 jam dalam milidetik
|
| 12 |
-
const META_FILE = path.join(__dirname, "
|
| 13 |
|
| 14 |
// Load metadata file (kalau ada)
|
| 15 |
let fileData = {};
|
|
@@ -59,32 +59,61 @@ app.post("/upload", upload.single("file"), (req, res) => {
|
|
| 59 |
const filePath = req.file.filename;
|
| 60 |
const customExpiration = req.body.expires_in ? parseInt(req.body.expires_in) * 1000 : EXPIRATION_TIME;
|
| 61 |
const expiresAt = Date.now() + customExpiration;
|
| 62 |
-
fileData[filePath] =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
fs.writeFile(META_FILE, JSON.stringify(fileData, null, 2), (err) => {
|
| 64 |
if (err) console.error("Gagal menulis ke api.json:", err);
|
| 65 |
});
|
| 66 |
|
| 67 |
res.json({
|
| 68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
file_url: `${req.protocol}://${req.get("host")}/files/${filePath}`,
|
| 70 |
-
|
|
|
|
| 71 |
});
|
| 72 |
});
|
| 73 |
|
| 74 |
-
app.get("/files", (req, res) => {
|
| 75 |
-
|
| 76 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
|
|
|
|
|
|
|
|
|
| 83 |
|
| 84 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
});
|
| 86 |
});
|
| 87 |
|
|
|
|
| 88 |
app.delete("/files/:filename", (req, res) => {
|
| 89 |
const filePath = path.join(uploadDir, req.params.filename);
|
| 90 |
|
|
@@ -181,7 +210,7 @@ setInterval(() => {
|
|
| 181 |
|
| 182 |
Object.keys(fileData).forEach(filename => {
|
| 183 |
const filePath = path.join(FILE_DIR, filename);
|
| 184 |
-
if (fileData[filename] <= now) {
|
| 185 |
if (fs.existsSync(filePath)) {
|
| 186 |
fs.unlinkSync(filePath);
|
| 187 |
console.log(`🗑️ File expired dihapus: ${filename}`);
|
|
|
|
| 9 |
|
| 10 |
const FILE_DIR = path.join(__dirname, "files");
|
| 11 |
const EXPIRATION_TIME = 24 * 60 * 60 * 1000; // 24 jam dalam milidetik
|
| 12 |
+
const META_FILE = path.join(__dirname, "list.json");
|
| 13 |
|
| 14 |
// Load metadata file (kalau ada)
|
| 15 |
let fileData = {};
|
|
|
|
| 59 |
const filePath = req.file.filename;
|
| 60 |
const customExpiration = req.body.expires_in ? parseInt(req.body.expires_in) * 1000 : EXPIRATION_TIME;
|
| 61 |
const expiresAt = Date.now() + customExpiration;
|
| 62 |
+
fileData[filePath] = {
|
| 63 |
+
isPrivate: false,
|
| 64 |
+
uploader: "Anonymous",
|
| 65 |
+
file_name: req.file.originalname,
|
| 66 |
+
file_url: `${req.protocol}://${req.get("host")}/files/${filePath}`,
|
| 67 |
+
file_size: req.file.size,
|
| 68 |
+
file_type: req.file.mimetype,
|
| 69 |
+
uploadTime: Date.now(),
|
| 70 |
+
expiredAt: expiresAt
|
| 71 |
+
};
|
| 72 |
fs.writeFile(META_FILE, JSON.stringify(fileData, null, 2), (err) => {
|
| 73 |
if (err) console.error("Gagal menulis ke api.json:", err);
|
| 74 |
});
|
| 75 |
|
| 76 |
res.json({
|
| 77 |
+
status: true,
|
| 78 |
+
file_name: req.file.originalname,
|
| 79 |
+
file_size: req.file.size,
|
| 80 |
+
file_type: req.file.mimetype,
|
| 81 |
+
uploadTime: Date.now(),
|
| 82 |
file_url: `${req.protocol}://${req.get("host")}/files/${filePath}`,
|
| 83 |
+
expires_in: fileData[filename] ? formatRemainingTime(fileData[filename].expiredAt) : "Unknown"
|
| 84 |
+
// Format sesuai sisa waktu
|
| 85 |
});
|
| 86 |
});
|
| 87 |
|
| 88 |
+
app.get("/files/browse", (req, res) => {
|
| 89 |
+
const page = parseInt(req.query.page) || 1;
|
| 90 |
+
const limit = 5;
|
| 91 |
+
|
| 92 |
+
// Filter hanya file yang isPrivate = false
|
| 93 |
+
const publicFiles = Object.keys(fileData).filter(filename => fileData[filename]?.isPrivate === false);
|
| 94 |
+
|
| 95 |
+
const startIndex = (page - 1) * limit;
|
| 96 |
+
const endIndex = startIndex + limit;
|
| 97 |
|
| 98 |
+
const paginatedFiles = publicFiles.slice(startIndex, endIndex).map(filename => ({
|
| 99 |
+
filename,
|
| 100 |
+
file_url: `${req.protocol}://${req.get("host")}/files/${filename}`,
|
| 101 |
+
expires_in: formatRemainingTime(fileData[filename]?.expiredAt),
|
| 102 |
+
file_size: fileData[filename]?.file_size,
|
| 103 |
+
file_type: fileData[filename]?.file_type,
|
| 104 |
+
uploadTime: fileData[filename]?.uploadTime
|
| 105 |
+
}));
|
| 106 |
|
| 107 |
+
res.json({
|
| 108 |
+
success: true,
|
| 109 |
+
current_page: page,
|
| 110 |
+
total_pages: Math.ceil(publicFiles.length / limit),
|
| 111 |
+
total_files: publicFiles.length,
|
| 112 |
+
files: paginatedFiles
|
| 113 |
});
|
| 114 |
});
|
| 115 |
|
| 116 |
+
|
| 117 |
app.delete("/files/:filename", (req, res) => {
|
| 118 |
const filePath = path.join(uploadDir, req.params.filename);
|
| 119 |
|
|
|
|
| 210 |
|
| 211 |
Object.keys(fileData).forEach(filename => {
|
| 212 |
const filePath = path.join(FILE_DIR, filename);
|
| 213 |
+
if (fileData[filename].expiredAt <= now) {
|
| 214 |
if (fs.existsSync(filePath)) {
|
| 215 |
fs.unlinkSync(filePath);
|
| 216 |
console.log(`🗑️ File expired dihapus: ${filename}`);
|
files/files.json
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
{}
|
|
|
|
|
|
files.json → list.json
RENAMED
|
File without changes
|