diff --git a/main.js b/main.js
index 68df403..b5952d1 100644
--- a/main.js
+++ b/main.js
@@ -70,9 +70,9 @@ ipcMain.handle('check-dependencies', async () => {
});
// IPC Handler: Get Video Details
-ipcMain.handle('get-video-info', async (event, url) => {
+ipcMain.handle('get-video-info', async (event, { url, browser }) => {
try {
- const info = await downloader.getVideoInfo(url);
+ const info = await downloader.getVideoInfo(url, browser);
return { success: true, info };
} catch (error) {
return { success: false, error: error.message };
@@ -80,13 +80,24 @@ ipcMain.handle('get-video-info', async (event, url) => {
});
// IPC Handler: Download Media
-ipcMain.handle('download-media', async (event, { url, format, quality }) => {
+ipcMain.handle('download-media', async (event, { url, format, quality, browser }) => {
try {
- await downloader.downloadMedia(url, format, quality, selectedOutputDir, (percent, status) => {
+ const stats = await downloader.downloadMedia(url, format, quality, selectedOutputDir, browser, (percent, status) => {
if (mainWindow) {
mainWindow.webContents.send('download-progress', { percent, status });
}
});
+ return { success: true, stats };
+ } catch (error) {
+ return { success: false, error: error.message };
+ }
+});
+
+// IPC Handler: Open Path in File Explorer
+ipcMain.handle('open-path', async (event, folderPath) => {
+ try {
+ const { shell } = require('electron');
+ await shell.openPath(folderPath);
return { success: true };
} catch (error) {
return { success: false, error: error.message };
diff --git a/preload.js b/preload.js
index 737c22c..a4496a1 100644
--- a/preload.js
+++ b/preload.js
@@ -3,11 +3,12 @@ const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('api', {
checkDependencies: () => ipcRenderer.invoke('check-dependencies'),
onDependencyStatus: (callback) => ipcRenderer.on('dependency-status', (_, data) => callback(data)),
- getVideoInfo: (url) => ipcRenderer.invoke('get-video-info', url),
- downloadMedia: (url, format, quality) => ipcRenderer.invoke('download-media', { url, format, quality }),
+ getVideoInfo: (url, browser) => ipcRenderer.invoke('get-video-info', { url, browser }),
+ downloadMedia: (url, format, quality, browser) => ipcRenderer.invoke('download-media', { url, format, quality, browser }),
onDownloadProgress: (callback) => ipcRenderer.on('download-progress', (_, data) => callback(data)),
selectDirectory: () => ipcRenderer.invoke('select-directory'),
getDownloadsFolder: () => ipcRenderer.invoke('get-downloads-folder'),
+ openPath: (path) => ipcRenderer.invoke('open-path', path),
minimizeWindow: () => ipcRenderer.send('window-minimize'),
closeWindow: () => ipcRenderer.send('window-close')
});
diff --git a/src/index.html b/src/index.html
index d0fa45e..8219765 100644
--- a/src/index.html
+++ b/src/index.html
@@ -3,11 +3,13 @@
- VibeDownloader - Premium YouTube & MP3 Downloader
+ VibeDownloader - Premium Social Media & MP3 Downloader
+
+
@@ -64,12 +66,12 @@
VibeDownloader
- YouTube videolarını saniyeler içinde yüksek kaliteli MP4 veya MP3 olarak indirin
+ YouTube, X/Twitter, Instagram, TikTok ve tüm popüler sitelerden video/ses indirin
diff --git a/src/renderer.js b/src/renderer.js
index 6f09434..5b00151 100644
--- a/src/renderer.js
+++ b/src/renderer.js
@@ -9,6 +9,8 @@ const urlInput = document.getElementById('url-input');
const analyzeBtn = document.getElementById('analyze-btn');
const outputPath = document.getElementById('output-path');
const changeFolderBtn = document.getElementById('change-folder-btn');
+const useCookiesCheckbox = document.getElementById('use-cookies');
+const cookieBrowserSelect = document.getElementById('cookie-browser');
const errorCard = document.getElementById('error-card');
const errorMessage = document.getElementById('error-message');
@@ -167,7 +169,8 @@ analyzeBtn.addEventListener('click', async () => {
analyzeIcon.style.display = 'inline-block';
try {
- const result = await window.api.getVideoInfo(url);
+ const browser = useCookiesCheckbox.checked ? cookieBrowserSelect.value : null;
+ const result = await window.api.getVideoInfo(url, browser);
if (result.success) {
analyzedUrl = url;
currentVideoData = result.info;
@@ -245,7 +248,8 @@ downloadBtn.addEventListener('click', async () => {
});
try {
- const result = await window.api.downloadMedia(analyzedUrl, currentFormat, currentQuality);
+ const browser = useCookiesCheckbox.checked ? cookieBrowserSelect.value : null;
+ const result = await window.api.downloadMedia(analyzedUrl, currentFormat, currentQuality, browser);
if (result.success) {
downloadStatus.textContent = 'Tamamlandı!';
downloadPercent.textContent = '100%';
@@ -263,6 +267,39 @@ downloadBtn.addEventListener('click', async () => {
// Success gradient transitions
downloadProgressBar.style.background = 'linear-gradient(90deg, #00ff87 0%, #60efff 100%)';
downloadProgressBar.style.boxShadow = '0 0 15px rgba(0, 255, 135, 0.6)';
+
+ // Trigger premium SweetAlert2 modal
+ Swal.fire({
+ title: 'İndirme Tamamlandı! 🎉',
+ html: `
+
+
Dosya Adı: ${currentVideoData.title}
+
Platform / Paylaşan: ${currentVideoData.uploader || 'Bilinmiyor'}
+
Dosya Boyutu: ${result.stats.size}
+
İndirme Süresi: ${result.stats.duration}
+
Format ve Kalite: ${currentFormat} (${currentQuality === '320' || currentQuality === '1080' ? 'En Yüksek' : currentQuality})
+
Kaydedilen Klasör:
${result.stats.outputDir}
+
+ `,
+ icon: 'success',
+ background: 'rgba(23, 20, 38, 0.95)',
+ color: '#fff',
+ confirmButtonText: 'Klasörü Aç 📂',
+ showCancelButton: true,
+ cancelButtonText: 'Yeni İndirme 🔄',
+ confirmButtonColor: '#7000ff',
+ cancelButtonColor: 'rgba(255, 255, 255, 0.1)',
+ backdrop: 'rgba(0, 0, 0, 0.6)'
+ }).then((swalResult) => {
+ if (swalResult.isConfirmed) {
+ window.api.openPath(result.stats.outputDir);
+ } else {
+ // Go back to step 1
+ backBtn.click();
+ urlInput.value = '';
+ downloadProgressPanel.style.display = 'none';
+ }
+ });
} else {
showError(result.error);
downloadProgressPanel.style.display = 'none';
diff --git a/utils/downloader.js b/utils/downloader.js
index 694a68f..6463355 100644
--- a/utils/downloader.js
+++ b/utils/downloader.js
@@ -169,12 +169,17 @@ async function checkDependencies(onStatusUpdate) {
}
// Get video metadata (title, thumbnail, duration, etc.)
-function getVideoInfo(url) {
+function getVideoInfo(url, browser) {
console.log(`[DEBUG] Fetching info for URL: ${url}`);
return new Promise((resolve, reject) => {
- // Adding '--no-playlist' prevents yt-dlp from crawling the entire playlist (which hangs/takes extremely long)
- console.log(`[DEBUG] Spawning process: ${YTDLP_PATH} --no-playlist -j ${url}`);
- const proc = spawn(YTDLP_PATH, ['--no-playlist', '-j', url]);
+ let args = ['--no-playlist', '-j'];
+ if (browser) {
+ args.push('--cookies-from-browser', browser);
+ }
+ args.push(url);
+
+ console.log(`[DEBUG] Spawning process: ${YTDLP_PATH} ${args.join(' ')}`);
+ const proc = spawn(YTDLP_PATH, args);
let stdout = '';
let stderr = '';
@@ -206,11 +211,13 @@ function getVideoInfo(url) {
}
// Download video or convert to MP3
-function downloadMedia(url, format, quality, outputDir, onProgress) {
- console.log(`[DEBUG] Media download requested. Format: ${format}, Quality: ${quality}, Target Dir: ${outputDir}`);
+function downloadMedia(url, format, quality, outputDir, browser, onProgress) {
+ console.log(`[DEBUG] Media download requested. Format: ${format}, Quality: ${quality}, Target Dir: ${outputDir}, Browser Cookies: ${browser || 'none'}`);
return new Promise((resolve, reject) => {
let args = [];
const outputTemplate = path.join(outputDir, '%(title)s.%(ext)s');
+ const startTime = Date.now();
+ let totalSize = 'Bilinmiyor';
if (format === 'mp3') {
const q = quality ? `${quality}K` : '320K'; // '320K', '256K', '192K'
@@ -220,25 +227,35 @@ function downloadMedia(url, format, quality, outputDir, onProgress) {
'-x',
'--audio-format', 'mp3',
'--audio-quality', q,
- '-o', outputTemplate,
- url
+ '-o', outputTemplate
];
} else {
const res = quality || '1080'; // '1080', '720', '480'
args = [
'--no-playlist',
'--ffmpeg-location', FFMPEG_PATH,
- '-f', `bv*[height<=${res}][ext=mp4]+ba[ext=m4a]/b[height<=${res}][ext=mp4] / bv*[height<=${res}]+ba/b[height<=${res}]`,
- '-o', outputTemplate,
- url
+ '-f', `bv*[height<=${res}][ext=mp4]+ba[ext=m4a]/b[height<=${res}][ext=mp4]/bv*[height<=${res}]+ba/b[height<=${res}]/bestvideo+bestaudio/best`,
+ '-o', outputTemplate
];
}
+ if (browser) {
+ args.push('--cookies-from-browser', browser);
+ }
+ args.push(url);
+
console.log(`[DEBUG] Spawning downloader process: ${YTDLP_PATH} ${args.join(' ')}`);
const proc = spawn(YTDLP_PATH, args);
proc.stdout.on('data', (data) => {
const line = data.toString();
+
+ // Parse total size: e.g. [download] 1.2% of 8.37MiB at...
+ const sizeMatch = line.match(/of\s+(\d+(?:\.\d+)?\s*[a-zA-Z]+)/);
+ if (sizeMatch) {
+ totalSize = sizeMatch[1];
+ }
+
const match = line.match(/\[download\]\s+(\d+\.\d+)%/);
if (match && onProgress) {
const percent = parseFloat(match[1]);
@@ -256,7 +273,12 @@ function downloadMedia(url, format, quality, outputDir, onProgress) {
proc.on('close', (code) => {
console.log(`[DEBUG] Downloader process exited with code ${code}`);
if (code === 0) {
- resolve();
+ const durationSec = ((Date.now() - startTime) / 1000).toFixed(1);
+ resolve({
+ size: totalSize,
+ duration: `${durationSec} saniye`,
+ outputDir: outputDir
+ });
} else {
reject(new Error(`Download exited with code ${code}`));
}