Disk Space alanı eklendi.
This commit is contained in:
@@ -1,13 +1,33 @@
|
|||||||
<script>
|
<script>
|
||||||
import { Link } from "svelte-routing";
|
import { Link } from "svelte-routing";
|
||||||
import { createEventDispatcher, onDestroy } from "svelte";
|
import { createEventDispatcher, onDestroy, onMount, tick } from "svelte";
|
||||||
import { movieCount } from "../stores/movieStore.js";
|
import { movieCount } from "../stores/movieStore.js";
|
||||||
import { tvShowCount } from "../stores/tvStore.js";
|
import { tvShowCount } from "../stores/tvStore.js";
|
||||||
|
import { apiFetch } from "../utils/api.js";
|
||||||
|
|
||||||
export let menuOpen = false;
|
export let menuOpen = false;
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
let hasMovies = false;
|
let hasMovies = false;
|
||||||
let hasShows = false;
|
let hasShows = false;
|
||||||
|
// Svelte store kullanarak reaktivite sağla
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
const diskSpaceStore = writable({ totalGB: '0', usedGB: '0', usedPercent: 0 });
|
||||||
|
let diskSpace;
|
||||||
|
|
||||||
|
// Store subscription'ı temizlemek için
|
||||||
|
let unsubscribeDiskSpace;
|
||||||
|
|
||||||
|
// Store'u değişkene bağla
|
||||||
|
unsubscribeDiskSpace = diskSpaceStore.subscribe(value => {
|
||||||
|
diskSpace = value;
|
||||||
|
console.log('🔄 Disk space updated from store:', diskSpace);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Disk space'i reaktif olarak güncellemek için bir fonksiyon
|
||||||
|
function updateDiskSpace(newData) {
|
||||||
|
diskSpaceStore.update(current => Object.assign({}, current, newData));
|
||||||
|
console.log('🔄 Disk space update called with:', newData);
|
||||||
|
}
|
||||||
|
|
||||||
const unsubscribeMovie = movieCount.subscribe((count) => {
|
const unsubscribeMovie = movieCount.subscribe((count) => {
|
||||||
hasMovies = (count ?? 0) > 0;
|
hasMovies = (count ?? 0) > 0;
|
||||||
@@ -20,12 +40,80 @@
|
|||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
unsubscribeMovie();
|
unsubscribeMovie();
|
||||||
unsubscribeTv();
|
unsubscribeTv();
|
||||||
|
if (unsubscribeDiskSpace) {
|
||||||
|
unsubscribeDiskSpace();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Menü öğesine tıklanınca sidebar'ı kapat
|
// Menü öğesine tıklanınca sidebar'ı kapat
|
||||||
function handleLinkClick() {
|
function handleLinkClick() {
|
||||||
dispatch("closeMenu");
|
dispatch("closeMenu");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disk space bilgilerini al
|
||||||
|
async function fetchDiskSpace() {
|
||||||
|
try {
|
||||||
|
const response = await apiFetch('/api/disk-space');
|
||||||
|
if (response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
console.log('Disk space data received:', data);
|
||||||
|
updateDiskSpace(data);
|
||||||
|
} else {
|
||||||
|
console.error('Disk space API error:', response.status, response.statusText);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Disk space fetch error:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Component yüklendiğinde disk space bilgilerini al
|
||||||
|
onMount(() => {
|
||||||
|
console.log('🔌 Sidebar component mounted');
|
||||||
|
fetchDiskSpace();
|
||||||
|
|
||||||
|
// WebSocket bağlantısı kur
|
||||||
|
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||||
|
// Server port'unu doğru almak için
|
||||||
|
const currentHost = window.location.host;
|
||||||
|
// Eğer client farklı portta çalışıyorsa, server port'unu manuel belirt
|
||||||
|
const wsHost = currentHost.includes(':3000') ? currentHost.replace(':3000', ':3001') : currentHost;
|
||||||
|
const wsUrl = `${wsProtocol}//${wsHost}`;
|
||||||
|
console.log('🔌 Connecting to WebSocket at:', wsUrl);
|
||||||
|
|
||||||
|
// WebSocket bağlantısını global olarak saklayalım
|
||||||
|
window.diskSpaceWs = new WebSocket(wsUrl);
|
||||||
|
|
||||||
|
window.diskSpaceWs.onmessage = (event) => {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
console.log('WebSocket message received:', data);
|
||||||
|
if (data.type === 'diskSpace') {
|
||||||
|
console.log('Disk space update received:', data.data);
|
||||||
|
updateDiskSpace(data.data);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('WebSocket message parse error:', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.diskSpaceWs.onopen = () => {
|
||||||
|
console.log('WebSocket connected for disk space updates');
|
||||||
|
};
|
||||||
|
|
||||||
|
window.diskSpaceWs.onerror = (error) => {
|
||||||
|
console.error('WebSocket error:', error);
|
||||||
|
};
|
||||||
|
|
||||||
|
window.diskSpaceWs.onclose = () => {
|
||||||
|
console.log('WebSocket disconnected');
|
||||||
|
};
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
if (window.diskSpaceWs && (window.diskSpaceWs.readyState === WebSocket.OPEN || window.diskSpaceWs.readyState === WebSocket.CONNECTING)) {
|
||||||
|
window.diskSpaceWs.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="sidebar" class:open={menuOpen}>
|
<div class="sidebar" class:open={menuOpen}>
|
||||||
@@ -108,4 +196,31 @@
|
|||||||
Trash
|
Trash
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Disk Space Alanı - Sidebar'ın en altında -->
|
||||||
|
<div class="disk-space">
|
||||||
|
<div class="disk-space-header">
|
||||||
|
<i class="fa-solid fa-hard-drive icon"></i>
|
||||||
|
<span class="disk-space-title">Disk Space</span>
|
||||||
|
</div>
|
||||||
|
<div class="disk-space-info">
|
||||||
|
<div class="disk-space-text">
|
||||||
|
<span class="disk-space-values">
|
||||||
|
{#if diskSpace.usedFormatted && diskSpace.totalFormatted}
|
||||||
|
{diskSpace.usedFormatted} / {diskSpace.totalFormatted}
|
||||||
|
{:else}
|
||||||
|
{diskSpace.usedGB} GB / {diskSpace.totalGB} GB
|
||||||
|
{/if}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="disk-space-bar-container">
|
||||||
|
<div class="disk-space-bar">
|
||||||
|
<div
|
||||||
|
class="disk-space-bar-fill {diskSpace.usedPercent < 50 ? 'low' : diskSpace.usedPercent < 80 ? 'medium' : 'high'}"
|
||||||
|
style="width: {diskSpace.usedPercent}%"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -31,13 +31,14 @@ body,
|
|||||||
.app {
|
.app {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 220px 1fr;
|
grid-template-columns: 220px 1fr;
|
||||||
height: 100%;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100vh;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* =======================================================
|
/* =======================================================
|
||||||
@@ -48,6 +49,9 @@ body,
|
|||||||
border-right: 1px solid var(--border);
|
border-right: 1px solid var(--border);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
height: 100vh;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar .logo {
|
.sidebar .logo {
|
||||||
@@ -59,6 +63,7 @@ body,
|
|||||||
|
|
||||||
.sidebar .menu {
|
.sidebar .menu {
|
||||||
padding-top: 6px;
|
padding-top: 6px;
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar .menu .item {
|
.sidebar .menu .item {
|
||||||
@@ -603,3 +608,85 @@ img.thumb.loaded {
|
|||||||
gap: 6px;
|
gap: 6px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* =======================================================
|
||||||
|
💾 DISK SPACE
|
||||||
|
======================================================= */
|
||||||
|
.sidebar .disk-space {
|
||||||
|
margin-top: auto;
|
||||||
|
padding: 16px;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .disk-space-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: #222;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .disk-space-header .icon {
|
||||||
|
width: 16px;
|
||||||
|
text-align: center;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .disk-space-title {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .disk-space-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .disk-space-text {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
text-align: left;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .disk-space-values {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .disk-space-bar-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 8px;
|
||||||
|
background: #e5e5e5;
|
||||||
|
border-radius: 99px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .disk-space-bar {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .disk-space-bar-fill {
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, #f5b333 0%, #e2a62f 100%);
|
||||||
|
border-radius: 99px;
|
||||||
|
transition: width 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disk space renkleri - kullanım oranına göre */
|
||||||
|
.sidebar .disk-space-bar-fill.low {
|
||||||
|
background: linear-gradient(90deg, #4caf50 0%, #388e3c 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .disk-space-bar-fill.medium {
|
||||||
|
background: linear-gradient(90deg, #ff9800 0%, #f57c00 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .disk-space-bar-fill.high {
|
||||||
|
background: linear-gradient(90deg, #f44336 0%, #d32f2f 100%);
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { WebSocketServer } from "ws";
|
|||||||
import { fileURLToPath } from "url";
|
import { fileURLToPath } from "url";
|
||||||
import { exec } from "child_process";
|
import { exec } from "child_process";
|
||||||
import crypto from "crypto"; // 🔒 basit token üretimi için
|
import crypto from "crypto"; // 🔒 basit token üretimi için
|
||||||
|
import { getSystemDiskInfo } from "./utils/diskSpace.js";
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename);
|
||||||
@@ -2082,6 +2083,20 @@ function broadcastFileUpdate(rootFolder) {
|
|||||||
wss.clients.forEach((c) => c.readyState === 1 && c.send(data));
|
wss.clients.forEach((c) => c.readyState === 1 && c.send(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function broadcastDiskSpace() {
|
||||||
|
if (!wss) return;
|
||||||
|
getSystemDiskInfo(DOWNLOAD_DIR).then(diskInfo => {
|
||||||
|
console.log("🔄 Broadcasting disk space:", diskInfo);
|
||||||
|
const data = JSON.stringify({
|
||||||
|
type: "diskSpace",
|
||||||
|
data: diskInfo
|
||||||
|
});
|
||||||
|
wss.clients.forEach((c) => c.readyState === 1 && c.send(data));
|
||||||
|
}).catch(err => {
|
||||||
|
console.error("❌ Disk space broadcast error:", err.message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function broadcastSnapshot() {
|
function broadcastSnapshot() {
|
||||||
if (!wss) return;
|
if (!wss) return;
|
||||||
const data = JSON.stringify({ type: "progress", torrents: snapshot() });
|
const data = JSON.stringify({ type: "progress", torrents: snapshot() });
|
||||||
@@ -2343,6 +2358,9 @@ app.post("/api/transfer", requireAuth, upload.single("torrent"), (req, res) => {
|
|||||||
upsertInfoFile(entry.savePath, infoUpdate);
|
upsertInfoFile(entry.savePath, infoUpdate);
|
||||||
broadcastFileUpdate(rootFolder);
|
broadcastFileUpdate(rootFolder);
|
||||||
|
|
||||||
|
// Torrent tamamlandığında disk space bilgisini güncelle
|
||||||
|
broadcastDiskSpace();
|
||||||
|
|
||||||
broadcastSnapshot();
|
broadcastSnapshot();
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -2755,6 +2773,9 @@ app.delete("/api/file", requireAuth, (req, res) => {
|
|||||||
torrents.delete(matchedInfoHash);
|
torrents.delete(matchedInfoHash);
|
||||||
console.log(`🧹 Torrent kaydı da temizlendi: ${matchedInfoHash}`);
|
console.log(`🧹 Torrent kaydı da temizlendi: ${matchedInfoHash}`);
|
||||||
broadcastSnapshot();
|
broadcastSnapshot();
|
||||||
|
|
||||||
|
// Torrent silindiğinde disk space bilgisini güncelle
|
||||||
|
broadcastDiskSpace();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
broadcastSnapshot();
|
broadcastSnapshot();
|
||||||
@@ -3501,7 +3522,18 @@ const server = app.listen(PORT, () =>
|
|||||||
|
|
||||||
wss = new WebSocketServer({ server });
|
wss = new WebSocketServer({ server });
|
||||||
wss.on("connection", (ws) => {
|
wss.on("connection", (ws) => {
|
||||||
|
console.log("🔌 New WebSocket connection established");
|
||||||
ws.send(JSON.stringify({ type: "progress", torrents: snapshot() }));
|
ws.send(JSON.stringify({ type: "progress", torrents: snapshot() }));
|
||||||
|
// Bağlantı kurulduğunda disk space bilgisi gönder
|
||||||
|
broadcastDiskSpace();
|
||||||
|
|
||||||
|
ws.on("close", () => {
|
||||||
|
console.log("🔌 WebSocket connection closed");
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on("error", (error) => {
|
||||||
|
console.error("🔌 WebSocket error:", error);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- ⏱️ Her 2 saniyede bir aktif torrent durumu yayınla ---
|
// --- ⏱️ Her 2 saniyede bir aktif torrent durumu yayınla ---
|
||||||
@@ -3511,6 +3543,27 @@ setInterval(() => {
|
|||||||
}
|
}
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
|
||||||
|
// --- ⏱️ Her 30 saniyede bir disk space bilgisi yayınla ---
|
||||||
|
setInterval(() => {
|
||||||
|
broadcastDiskSpace();
|
||||||
|
}, 30000);
|
||||||
|
|
||||||
|
// --- Disk space bilgisi ---
|
||||||
|
app.get("/api/disk-space", requireAuth, async (req, res) => {
|
||||||
|
try {
|
||||||
|
// Downloads klasörü yoksa oluştur
|
||||||
|
if (!fs.existsSync(DOWNLOAD_DIR)) {
|
||||||
|
fs.mkdirSync(DOWNLOAD_DIR, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
const diskInfo = await getSystemDiskInfo(DOWNLOAD_DIR);
|
||||||
|
res.json(diskInfo);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("❌ Disk space error:", err.message);
|
||||||
|
res.status(500).json({ error: err.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
client.on("error", (err) => {
|
client.on("error", (err) => {
|
||||||
if (!String(err).includes("uTP"))
|
if (!String(err).includes("uTP"))
|
||||||
console.error("WebTorrent error:", err.message);
|
console.error("WebTorrent error:", err.message);
|
||||||
|
|||||||
243
server/utils/diskSpace.js
Normal file
243
server/utils/diskSpace.js
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import { exec } from 'child_process';
|
||||||
|
import { promisify } from 'util';
|
||||||
|
|
||||||
|
const execAsync = promisify(exec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disk alanı bilgilerini hesaplar
|
||||||
|
* @param {string} path - Kontrol edilecek dizin yolu
|
||||||
|
* @returns {Promise<Object>} Disk alanı bilgileri
|
||||||
|
*/
|
||||||
|
export async function getDiskSpace(path = '/') {
|
||||||
|
console.log("🔍 Getting disk space for path:", path);
|
||||||
|
try {
|
||||||
|
// Linux/macOS için df komutu kullan
|
||||||
|
if (process.platform !== 'win32') {
|
||||||
|
const escapedPath = path.replace(/(["\\$`])/g, '\\$1');
|
||||||
|
const blockFlag = process.platform === 'darwin' ? '-k' : '-k';
|
||||||
|
const { stdout } = await execAsync(`df ${blockFlag} "${escapedPath}"`);
|
||||||
|
console.log("📊 df command output:", stdout);
|
||||||
|
const lines = stdout.trim().split('\n');
|
||||||
|
|
||||||
|
if (lines.length >= 2) {
|
||||||
|
// Çoğu dağıtımda veriler ikinci satırda
|
||||||
|
const data = lines[lines.length - 1].trim().split(/\s+/);
|
||||||
|
console.log("📋 Parsed df data:", data);
|
||||||
|
if (data.length < 5) {
|
||||||
|
throw new Error("df output could not be parsed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// df -k çıktısı 1K-blocks döndürür
|
||||||
|
const totalBlocks = parseFloat(data[1]) || 0;
|
||||||
|
const usedBlocks = parseFloat(data[2]) || 0;
|
||||||
|
const availableBlocks = parseFloat(data[3]) || 0;
|
||||||
|
const usedPercent = parseFloat((data[4] || '').replace('%', '')) || 0;
|
||||||
|
|
||||||
|
const total = totalBlocks * 1024;
|
||||||
|
const used = usedBlocks * 1024;
|
||||||
|
const available = availableBlocks * 1024;
|
||||||
|
|
||||||
|
console.log("📏 Calculated sizes (bytes):", { total, used, available, usedPercent });
|
||||||
|
|
||||||
|
const totalFormatted = formatBytes(total);
|
||||||
|
const usedFormatted = formatBytes(used);
|
||||||
|
const availableFormatted = formatBytes(available);
|
||||||
|
|
||||||
|
const result = {
|
||||||
|
total,
|
||||||
|
used,
|
||||||
|
available,
|
||||||
|
usedPercent,
|
||||||
|
totalGB: (total / (1024 * 1024 * 1024)).toFixed(2),
|
||||||
|
usedGB: (used / (1024 * 1024 * 1024)).toFixed(2),
|
||||||
|
availableGB: (available / (1024 * 1024 * 1024)).toFixed(2),
|
||||||
|
// Dinamik formatlanmış değerler
|
||||||
|
totalFormatted: totalFormatted.formatted,
|
||||||
|
usedFormatted: usedFormatted.formatted,
|
||||||
|
availableFormatted: availableFormatted.formatted,
|
||||||
|
totalValue: totalFormatted.value,
|
||||||
|
totalUnit: totalFormatted.unit,
|
||||||
|
usedValue: usedFormatted.value,
|
||||||
|
usedUnit: usedFormatted.unit
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log("✅ Final disk space result:", result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Windows için wmic komutu kullan
|
||||||
|
const { stdout } = await execAsync('wmic logicaldisk get size,freespace,caption');
|
||||||
|
const lines = stdout.trim().split('\n');
|
||||||
|
|
||||||
|
for (let i = 1; i < lines.length; i++) {
|
||||||
|
const line = lines[i].trim();
|
||||||
|
if (line) {
|
||||||
|
const parts = line.split(/\s+/);
|
||||||
|
if (parts.length >= 3) {
|
||||||
|
const caption = parts[0];
|
||||||
|
const freeSpace = parseInt(parts[1]);
|
||||||
|
const size = parseInt(parts[parts.length - 1]);
|
||||||
|
|
||||||
|
if (size > 0) {
|
||||||
|
const used = size - freeSpace;
|
||||||
|
const usedPercent = (used / size) * 100;
|
||||||
|
|
||||||
|
const totalFormatted = formatBytes(size);
|
||||||
|
const usedFormatted = formatBytes(used);
|
||||||
|
const availableFormatted = formatBytes(freeSpace);
|
||||||
|
|
||||||
|
return {
|
||||||
|
total: size,
|
||||||
|
used,
|
||||||
|
available: freeSpace,
|
||||||
|
usedPercent,
|
||||||
|
totalGB: (size / (1024 * 1024 * 1024)).toFixed(2),
|
||||||
|
usedGB: (used / (1024 * 1024 * 1024)).toFixed(2),
|
||||||
|
availableGB: (freeSpace / (1024 * 1024 * 1024)).toFixed(2),
|
||||||
|
// Dinamik formatlanmış değerler
|
||||||
|
totalFormatted: totalFormatted.formatted,
|
||||||
|
usedFormatted: usedFormatted.formatted,
|
||||||
|
availableFormatted: availableFormatted.formatted,
|
||||||
|
totalValue: totalFormatted.value,
|
||||||
|
totalUnit: totalFormatted.unit,
|
||||||
|
usedValue: usedFormatted.value,
|
||||||
|
usedUnit: usedFormatted.unit,
|
||||||
|
drive: caption
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback olarak Node.js fs.statSync kullan
|
||||||
|
const stats = fs.statSync(path);
|
||||||
|
return {
|
||||||
|
total: 0,
|
||||||
|
used: 0,
|
||||||
|
available: 0,
|
||||||
|
usedPercent: 0,
|
||||||
|
totalGB: '0',
|
||||||
|
usedGB: '0',
|
||||||
|
availableGB: '0',
|
||||||
|
error: 'Disk bilgileri alınamadı'
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Disk space error:', error.message);
|
||||||
|
return {
|
||||||
|
total: 0,
|
||||||
|
used: 0,
|
||||||
|
available: 0,
|
||||||
|
usedPercent: 0,
|
||||||
|
totalGB: '0',
|
||||||
|
usedGB: '0',
|
||||||
|
availableGB: '0',
|
||||||
|
error: error.message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boyut string'ini byte'a çevirir (örn: "10G" -> 10737418240)
|
||||||
|
* @param {string} sizeStr - Boyut string'i
|
||||||
|
* @returns {number} Byte cinsinden boyut
|
||||||
|
*/
|
||||||
|
function parseSize(sizeStr) {
|
||||||
|
const units = {
|
||||||
|
'K': 1024,
|
||||||
|
'M': 1024 * 1024,
|
||||||
|
'G': 1024 * 1024 * 1024,
|
||||||
|
'T': 1024 * 1024 * 1024 * 1024
|
||||||
|
};
|
||||||
|
|
||||||
|
const match = sizeStr.match(/^(\d+(?:\.\d+)?)(K|M|G|T)?$/i);
|
||||||
|
if (!match) return 0;
|
||||||
|
|
||||||
|
const value = parseFloat(match[1]);
|
||||||
|
const unit = match[2] ? match[2].toUpperCase() : '';
|
||||||
|
|
||||||
|
const result = value * (units[unit] || 1);
|
||||||
|
console.log(`🔍 parseSize: ${sizeStr} -> ${result} bytes`);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Byte cinsinden boyutu insan tarafından okunabilir formata çevirir
|
||||||
|
* @param {number} bytes - Byte cinsinden boyut
|
||||||
|
* @returns {Object} Formatlanmış boyut bilgisi
|
||||||
|
*/
|
||||||
|
function formatBytes(bytes) {
|
||||||
|
if (bytes === 0) return { value: 0, unit: 'GB', formatted: '0 GB' };
|
||||||
|
|
||||||
|
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
||||||
|
const threshold = 1024;
|
||||||
|
const unitIndex = Math.floor(Math.log(bytes) / Math.log(threshold));
|
||||||
|
const unit = units[unitIndex];
|
||||||
|
const value = bytes / Math.pow(threshold, unitIndex);
|
||||||
|
|
||||||
|
// Eğer GB veya daha büyükse, 2 ondalık basamak kullan
|
||||||
|
// Aksi takdirde tam sayı olarak göster
|
||||||
|
const decimals = unitIndex >= 3 ? 2 : 0;
|
||||||
|
const formattedValue = value.toFixed(decimals);
|
||||||
|
|
||||||
|
return {
|
||||||
|
value: parseFloat(formattedValue),
|
||||||
|
unit,
|
||||||
|
formatted: `${formattedValue} ${unit}`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Downloads klasörünün boyutunu hesaplar
|
||||||
|
* @param {string} downloadsPath - Downloads klasörü yolu
|
||||||
|
* @returns {Promise<Object>} Klasör boyut bilgileri
|
||||||
|
*/
|
||||||
|
export async function getDownloadsSize(downloadsPath) {
|
||||||
|
try {
|
||||||
|
if (!downloadsPath || !fs.existsSync(downloadsPath)) {
|
||||||
|
return {
|
||||||
|
bytes: 0,
|
||||||
|
GB: '0',
|
||||||
|
MB: '0'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const escapedDownloadsPath = downloadsPath.replace(/(["\\$`])/g, '\\$1');
|
||||||
|
const { stdout } = await execAsync(`du -sb "${escapedDownloadsPath}"`);
|
||||||
|
const sizeInBytes = parseInt(stdout.trim().split('\t')[0]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
bytes: sizeInBytes,
|
||||||
|
GB: (sizeInBytes / (1024 * 1024 * 1024)).toFixed(2),
|
||||||
|
MB: (sizeInBytes / (1024 * 1024)).toFixed(2)
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Downloads size error:', error.message);
|
||||||
|
return {
|
||||||
|
bytes: 0,
|
||||||
|
GB: '0',
|
||||||
|
MB: '0',
|
||||||
|
error: error.message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sistem genelinde disk kullanım özetini döndürür
|
||||||
|
* @param {string} downloadsPath - Downloads klasörü yolu
|
||||||
|
* @returns {Promise<Object>} Kapsamlı disk bilgileri
|
||||||
|
*/
|
||||||
|
export async function getSystemDiskInfo(downloadsPath) {
|
||||||
|
console.log("🔍 Getting system disk info for:", downloadsPath);
|
||||||
|
const diskSpace = await getDiskSpace(downloadsPath);
|
||||||
|
const downloadsSize = await getDownloadsSize(downloadsPath);
|
||||||
|
|
||||||
|
console.log("📊 Disk space result:", diskSpace);
|
||||||
|
console.log("📁 Downloads size result:", downloadsSize);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...diskSpace,
|
||||||
|
downloads: downloadsSize,
|
||||||
|
timestamp: new Date().toISOString()
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user