media-dl 2.5.2 → 2.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/bin/cli.js +146 -139
  2. package/package.json +1 -1
  3. package/readme.id.md +103 -0
  4. package/readme.md +113 -103
package/bin/cli.js CHANGED
@@ -6,7 +6,7 @@ const fs = require('fs');
6
6
  const os = require('os');
7
7
  const { C, printHeader, renderProgressBar, askQuestion, rl } = require('./ui');
8
8
 
9
- // --- KONFIGURASI VISUAL (ANSI COLORS) ---
9
+ // --- VISUAL CONFIGURATION (ANSI COLORS) ---
10
10
 
11
11
  const TOOLS_DIR = path.join(os.homedir(), '.media-dl');
12
12
 
@@ -18,13 +18,13 @@ const isTermux =
18
18
  let YTDLP_PATH = path.join(TOOLS_DIR, isWindows ? 'yt-dlp.exe' : 'yt-dlp');
19
19
  let FFMPEG_PATH = path.join(TOOLS_DIR, isWindows ? 'ffmpeg.exe' : 'ffmpeg');
20
20
 
21
- // State Aplikasi
21
+ // Application State
22
22
  let safeMode = true;
23
23
 
24
24
  if (!fs.existsSync(TOOLS_DIR)) fs.mkdirSync(TOOLS_DIR, { recursive: true });
25
25
 
26
26
  function checkTools() {
27
- // Cek jalur default lokal (internal)
27
+ // Check default local path (internal)
28
28
  const LOCAL_YT = path.join(TOOLS_DIR, isWindows ? 'yt-dlp.exe' : 'yt-dlp');
29
29
  const LOCAL_FF = path.join(TOOLS_DIR, isWindows ? 'ffmpeg.exe' : 'ffmpeg');
30
30
 
@@ -34,11 +34,11 @@ function checkTools() {
34
34
  let ytExists = isLocalYt;
35
35
  let ffExists = isLocalFf;
36
36
 
37
- // Reset path ke default sebelum pengecekan global
37
+ // Reset path to default before global check
38
38
  if (isLocalYt) YTDLP_PATH = LOCAL_YT;
39
39
  if (isLocalFf) FFMPEG_PATH = LOCAL_FF;
40
40
 
41
- // Cek Global yt-dlp hanya jika lokal tidak ada
41
+ // Check Global yt-dlp only if local is missing
42
42
  if (!isLocalYt) {
43
43
  try {
44
44
  const cmd = isWindows ? 'where yt-dlp' : 'which yt-dlp';
@@ -51,11 +51,11 @@ function checkTools() {
51
51
  ytExists = true;
52
52
  }
53
53
  } catch (e) {
54
- YTDLP_PATH = LOCAL_YT; // Kembalikan ke path lokal jika global pun tidak ada
54
+ YTDLP_PATH = LOCAL_YT; // Revert to local path if global is also missing
55
55
  }
56
56
  }
57
57
 
58
- // Cek Global ffmpeg hanya jika lokal tidak ada
58
+ // Check Global ffmpeg only if local is missing
59
59
  if (!isLocalFf) {
60
60
  try {
61
61
  const cmd = isWindows ? 'where ffmpeg' : 'which ffmpeg';
@@ -68,7 +68,7 @@ function checkTools() {
68
68
  ffExists = true;
69
69
  }
70
70
  } catch (e) {
71
- FFMPEG_PATH = LOCAL_FF; // Kembalikan ke path lokal jika global pun tidak ada
71
+ FFMPEG_PATH = LOCAL_FF; // Revert to local path if global is also missing
72
72
  }
73
73
  }
74
74
 
@@ -86,21 +86,21 @@ async function installYtdlp() {
86
86
  if (!fs.existsSync(TOOLS_DIR)) fs.mkdirSync(TOOLS_DIR, { recursive: true });
87
87
 
88
88
  printHeader('INSTALL / UPDATE YT-DLP');
89
- console.log(`${C.blue}⏳ Sedang mengunduh engine terbaru...${C.reset}`);
89
+ console.log(`${C.blue}⏳ Downloading latest engine...${C.reset}`);
90
90
  const url = isWindows
91
91
  ? 'https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe'
92
92
  : 'https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp';
93
93
 
94
94
  try {
95
95
  if (isTermux) {
96
- // Di Termux, lebih disarankan menggunakan python/pip untuk stabilitas
97
- console.log(`${C.dim}Menginstall yt-dlp via python...${C.reset}`);
96
+ // On Termux, using python/pip is recommended for stability
97
+ console.log(`${C.dim}Installing yt-dlp via python...${C.reset}`);
98
98
  execSync('pkg update && pkg install python ffmpeg -y', {
99
99
  stdio: 'inherit',
100
100
  });
101
101
  execSync('pip install -U "yt-dlp[default]"', { stdio: 'inherit' });
102
102
  console.log(
103
- `\n${C.green}✅ yt-dlp berhasil diinstal di Termux!${C.reset}`,
103
+ `\n${C.green}✅ yt-dlp installed successfully on Termux!${C.reset}`,
104
104
  );
105
105
  } else if (isWindows) {
106
106
  execSync(
@@ -113,11 +113,11 @@ async function installYtdlp() {
113
113
  execSync(`chmod a+rx "${YTDLP_PATH}"`);
114
114
  }
115
115
  if (!isTermux) {
116
- console.log(`\n${C.green}✅ yt-dlp berhasil dikonfigurasi!${C.reset}`);
116
+ console.log(`\n${C.green}✅ yt-dlp configured successfully!${C.reset}`);
117
117
  }
118
118
  } catch (e) {
119
119
  console.error(
120
- `\n${C.red}❌ Gagal mengunduh. Periksa koneksi internet Anda.${C.reset}`,
120
+ `\n${C.red}❌ Failed to download. Check your internet connection.${C.reset}`,
121
121
  );
122
122
  }
123
123
  }
@@ -125,21 +125,21 @@ async function installYtdlp() {
125
125
  async function installFfmpeg() {
126
126
  printHeader('INSTALL FFmpeg');
127
127
  console.log(
128
- `${C.dim}FFmpeg diperlukan untuk kualitas 1080p+ dan konversi MP3.${C.reset}\n`,
128
+ `${C.dim}FFmpeg is required for 1080p+ quality and MP3 conversion.${C.reset}\n`,
129
129
  );
130
130
 
131
131
  try {
132
132
  if (isTermux) {
133
133
  console.log(
134
- `${C.blue}⏳ Mendeteksi Termux: Menginstall via pkg...${C.reset}`,
134
+ `${C.blue}⏳ Termux detected: Installing via pkg...${C.reset}`,
135
135
  );
136
136
  execSync('pkg update && pkg install ffmpeg -y', { stdio: 'inherit' });
137
137
  console.log(
138
- `\n${C.green}✅ FFmpeg berhasil diinstal di Termux!${C.reset}`,
138
+ `\n${C.green}✅ FFmpeg installed successfully on Termux!${C.reset}`,
139
139
  );
140
140
  } else if (isMac) {
141
- // ... (Kode macOS Anda sudah benar)
142
- console.log(`${C.blue}⏳ Mengunduh FFmpeg untuk macOS...${C.reset}`);
141
+ // ... (Your macOS code is correct)
142
+ console.log(`${C.blue}⏳ Downloading FFmpeg for macOS...${C.reset}`);
143
143
  const zipPath = path.join(TOOLS_DIR, 'ffmpeg.zip');
144
144
  execSync(
145
145
  `curl -L -# "https://evermeet.cx/ffmpeg/getrelease/ffmpeg/zip" -o "${zipPath}"`,
@@ -148,54 +148,54 @@ async function installFfmpeg() {
148
148
  execSync(`unzip -o "${zipPath}" -d "${TOOLS_DIR}"`, { stdio: 'inherit' });
149
149
  execSync(`rm "${zipPath}"`);
150
150
  execSync(`chmod a+rx "${FFMPEG_PATH}"`);
151
- console.log(`\n${C.green}✅ FFmpeg aktif di macOS.${C.reset}`);
151
+ console.log(`\n${C.green}✅ FFmpeg active on macOS.${C.reset}`);
152
152
  } else if (isWindows) {
153
153
  console.log(
154
- `${C.blue}⏳ Mengunduh FFmpeg untuk Windows (Essentials)...${C.reset}`,
154
+ `${C.blue}⏳ Downloading FFmpeg for Windows (Essentials)...${C.reset}`,
155
155
  );
156
156
 
157
157
  const zipPath = path.join(TOOLS_DIR, 'ffmpeg.zip');
158
- // Link direct ke build essentials agar file tidak terlalu besar
158
+ // Direct link to build essentials so the file isn't too large
159
159
  const url =
160
160
  'https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip';
161
161
 
162
- // 1. Download menggunakan PowerShell
162
+ // 1. Download using PowerShell
163
163
  execSync(
164
164
  `powershell -Command "Invoke-WebRequest -Uri ${url} -OutFile '${zipPath}'"`,
165
165
  { stdio: 'inherit' },
166
166
  );
167
167
 
168
- console.log(`${C.yellow}📦 Mengekstrak FFmpeg...${C.reset}`);
168
+ console.log(`${C.yellow}📦 Extracting FFmpeg...${C.reset}`);
169
169
 
170
- // 2. Ekstrak menggunakan perintah 'tar' (Bawaan Windows 10+)
171
- // Kita hanya mengambil ffmpeg.exe dari dalam folder bin di zip tersebut
170
+ // 2. Extract using 'tar' command (Built-in Windows 10+)
171
+ // We only take ffmpeg.exe from the bin folder inside the zip
172
172
  execSync(
173
173
  `tar -xf "${zipPath}" -C "${TOOLS_DIR}" --strip-components 2 "*/bin/ffmpeg.exe" "*/bin/ffprobe.exe"`,
174
174
  { stdio: 'inherit' },
175
175
  );
176
176
 
177
- // 3. Bersihkan file zip
177
+ // 3. Clean up zip file
178
178
  if (fs.existsSync(zipPath)) fs.unlinkSync(zipPath);
179
179
 
180
180
  console.log(
181
- `\n${C.green}✅ FFmpeg berhasil diinstal di Windows!${C.reset}`,
181
+ `\n${C.green}✅ FFmpeg installed successfully on Windows!${C.reset}`,
182
182
  );
183
183
  } else {
184
- // Asumsi Linux (Ubuntu/Debian)
184
+ // Assume Linux (Ubuntu/Debian)
185
185
  console.log(
186
- `${C.blue}⏳ Mendeteksi Linux: Menginstall via apt...${C.reset}`,
186
+ `${C.blue}⏳ Linux detected: Installing via apt...${C.reset}`,
187
187
  );
188
- console.log(`${C.dim}Mungkin memerlukan password sudo.${C.reset}`);
188
+ console.log(`${C.dim}May require sudo password.${C.reset}`);
189
189
  execSync('sudo apt update && sudo apt install ffmpeg -y', {
190
190
  stdio: 'inherit',
191
191
  });
192
192
  console.log(
193
- `\n${C.green}✅ FFmpeg berhasil diinstal di Linux!${C.reset}`,
193
+ `\n${C.green}✅ FFmpeg installed successfully on Linux!${C.reset}`,
194
194
  );
195
195
  }
196
196
  } catch (e) {
197
197
  console.error(
198
- `${C.red}❌ Gagal menginstal FFmpeg secara otomatis.${C.reset}`,
198
+ `${C.red}❌ Failed to install FFmpeg automatically.${C.reset}`,
199
199
  );
200
200
  console.log(`${C.dim}Error: ${e.message}${C.reset}`);
201
201
  }
@@ -204,11 +204,10 @@ async function installFfmpeg() {
204
204
  function runSpawn(command, args) {
205
205
  return new Promise((resolve) => {
206
206
  const proc = spawn(command, args);
207
- let lastOutput = '';
208
207
 
209
208
  proc.stdout.on('data', (data) => {
210
209
  const output = data.toString();
211
- // Regex untuk menangkap progress dari yt-dlp
210
+ // Regex to capture progress from yt-dlp
212
211
  const progressMatch = output.match(
213
212
  /\[download\]\s+(\d+\.\d+)%\s+of\s+.*\s+at\s+([\d\w\./s]+)\s+ETA\s+([\d:]+)/,
214
213
  );
@@ -217,7 +216,7 @@ function runSpawn(command, args) {
217
216
  const [_, percent, speed, eta] = progressMatch;
218
217
  renderProgressBar(parseFloat(percent), speed, eta);
219
218
  } else {
220
- // Jika bukan bar, print normal (misal: info merging/ffmpeg)
219
+ // If not a bar, print normal (e.g., merging info/ffmpeg)
221
220
  if (output.trim() && !output.includes('[download]')) {
222
221
  process.stdout.write(`\n${C.dim}${output.trim()}${C.reset}\n`);
223
222
  }
@@ -232,7 +231,7 @@ function runSpawn(command, args) {
232
231
  });
233
232
 
234
233
  proc.on('close', (code) => {
235
- process.stdout.write('\n'); // Baris baru setelah selesai
234
+ process.stdout.write('\n'); // New line after completion
236
235
  resolve(code);
237
236
  });
238
237
  });
@@ -257,7 +256,7 @@ async function getEstimate(url, format) {
257
256
  return (bytes / 1024 ** 2).toFixed(2) + ' MB';
258
257
  }
259
258
  } catch (e) {}
260
- return 'Estimasi tidak tersedia';
259
+ return 'Estimate unavailable';
261
260
  }
262
261
 
263
262
  // --- DOWNLOAD ENGINE ---
@@ -265,24 +264,24 @@ async function startDownload(videoURLFromArgs = null) {
265
264
  let { ytExists, ffExists } = checkTools();
266
265
  if (!ytExists) {
267
266
  console.log(
268
- `\n${C.red}❌ Engine yt-dlp tidak ditemukan. Silakan pilih menu Update/Install.${C.reset}`,
267
+ `\n${C.red}❌ yt-dlp engine not found. Please select Update/Install menu.${C.reset}`,
269
268
  );
270
269
  await backToMenu();
271
270
  }
272
271
 
273
272
  if (!ffExists) {
274
273
  console.log(
275
- `${C.yellow}⚠️ Peringatan: FFmpeg tidak ditemukan. Video mungkin tidak tergabung dengan audio.${C.reset}`,
274
+ `${C.yellow}⚠️ Warning: FFmpeg not found. Video might not be merged with audio.${C.reset}`,
276
275
  );
277
- const cont = await askQuestion('Lanjutkan saja? (y/n): ');
276
+ const cont = await askQuestion('Continue anyway? (y/n): ');
278
277
  if (cont.toLowerCase() !== 'y') return mainMenu();
279
278
  }
280
279
 
281
280
  const videoURL =
282
- videoURLFromArgs || (await askQuestion('Masukkan Link (Video/Playlist): '));
281
+ videoURLFromArgs || (await askQuestion('Enter Link (Video/Playlist): '));
283
282
  if (!videoURL) return mainMenu();
284
283
 
285
- console.log(`${C.dim}⏳ Menganalisa tautan...${C.reset}`);
284
+ console.log(`${C.dim}⏳ Analyzing link...${C.reset}`);
286
285
  let playlistInfo = { isPlaylist: false, title: '', items: [] };
287
286
 
288
287
  try {
@@ -297,29 +296,29 @@ async function startDownload(videoURLFromArgs = null) {
297
296
  const lines = rawInfo.trim().split('\n');
298
297
  if (lines.length > 1 || videoURL.includes('playlist?list=')) {
299
298
  playlistInfo.isPlaylist = true;
300
- playlistInfo.title = lines[0].split('|')[0] || 'Unduhan Playlist';
299
+ playlistInfo.title = lines[0].split('|')[0] || 'Playlist Download';
301
300
  playlistInfo.items = lines.map((l) => l.split('|')[1]).filter(Boolean);
302
301
  }
303
302
  } catch (e) {
304
- console.log(`\n${C.red}❌ Gagal menganalisa tautan.${C.reset}`);
303
+ console.log(`\n${C.red}❌ Failed to analyze link.${C.reset}`);
305
304
  if (e.message.includes('ETIMEDOUT')) {
306
305
  console.log(
307
- `${C.yellow}⚠️ Waktu analisa habis. Periksa koneksi internet Anda.${C.reset}`,
306
+ `${C.yellow}⚠️ Analysis timed out. Check your internet connection.${C.reset}`,
308
307
  );
309
308
  } else {
310
309
  console.log(
311
- `${C.yellow}⚠️ Pastikan link valid atau tidak diprivat/dihapus.${C.reset}`,
310
+ `${C.yellow}⚠️ Ensure link is valid or not private/deleted.${C.reset}`,
312
311
  );
313
312
  }
314
313
  await backToMenu();
315
314
  }
316
315
 
317
- // --- PEMILIHAN PLAYLIST (Tetap Sama) ---
316
+ // --- PLAYLIST SELECTION (Logic remains same) ---
318
317
  let playlistSelection = null;
319
318
  if (playlistInfo.isPlaylist) {
320
- // ... (Logika tampilan playlist sama seperti sebelumnya)
319
+ // ... (Playlist display logic same as before)
321
320
  console.log(
322
- `\n${C.bgBlue}${C.bright} 📂 PLAYLIST TERDETEKSI: ${playlistInfo.title} ${C.reset}`,
321
+ `\n${C.bgBlue}${C.bright} 📂 PLAYLIST DETECTED: ${playlistInfo.title} ${C.reset}`,
323
322
  );
324
323
  playlistInfo.items.forEach((item, index) => {
325
324
  console.log(
@@ -327,11 +326,11 @@ async function startDownload(videoURLFromArgs = null) {
327
326
  );
328
327
  });
329
328
  console.log(
330
- `\n${C.dim}Contoh pilih nomor: 1,3,5-10 atau biarkan kosong untuk semua.${C.reset}`,
329
+ `\n${C.dim}Example: 1,3,5-10 or leave empty for all.${C.reset}`,
331
330
  );
332
- const selectionInput = await askQuestion('\nPilih nomor: ');
331
+ const selectionInput = await askQuestion('\nSelect numbers: ');
333
332
  if (selectionInput) {
334
- // ... (Logika parsing nomor playlist)
333
+ // ... (Playlist parsing logic)
335
334
  const selected = new Set();
336
335
  selectionInput.split(',').forEach((p) => {
337
336
  if (p.includes('-')) {
@@ -347,20 +346,20 @@ async function startDownload(videoURLFromArgs = null) {
347
346
  }
348
347
  }
349
348
 
350
- // --- MENU FORMAT UTAMA ---
351
- console.log(`\n${C.bright} [ PILIH FORMAT ]${C.reset}`);
349
+ // --- MAIN FORMAT MENU ---
350
+ console.log(`\n${C.bright} [ SELECT FORMAT ]${C.reset}`);
352
351
  console.log(` ${C.green}1.${C.reset} Video (MP4)`);
353
352
  console.log(` ${C.green}2.${C.reset} Audio Only (MP3)`);
354
- const mode = await askQuestion('Pilihan: ');
353
+ const mode = await askQuestion('Choice: ');
355
354
 
356
- // --- LOGIKA RESOLUSI OPTIMAL ---
355
+ // --- OPTIMAL RESOLUTION LOGIC ---
357
356
  let formatArg = '';
358
357
  if (mode === '1') {
359
- console.log(`\n${C.bright} [ PILIH RESOLUSI ]${C.reset}`);
358
+ console.log(`\n${C.bright} [ SELECT RESOLUTION ]${C.reset}`);
360
359
  console.log(` ${C.cyan}1.${C.reset} Best Quality (Up to 4K)`);
361
360
  console.log(` ${C.cyan}2.${C.reset} Tablet Optimal (720p)`);
362
361
  console.log(` ${C.cyan}3.${C.reset} Mobile Optimal (480p)`);
363
- const resChoice = await askQuestion('Pilihan Resolusi (1-3): ');
362
+ const resChoice = await askQuestion('Select Resolution (1-3): ');
364
363
 
365
364
  if (resChoice === '2') {
366
365
  formatArg =
@@ -373,13 +372,13 @@ async function startDownload(videoURLFromArgs = null) {
373
372
  'bestvideo[vcodec^=avc1]+bestaudio[acodec^=mp4a]/best[vcodec^=avc1]/best';
374
373
  }
375
374
  }
376
- // --- TAMPILKAN ESTIMASI ---
375
+ // --- DISPLAY ESTIMATE ---
377
376
  if (!playlistInfo.isPlaylist && mode === '1') {
378
- console.log(`${C.dim}⏳ Menghitung estimasi ukuran file...${C.reset}`);
377
+ console.log(`${C.dim}⏳ Calculating file size estimate...${C.reset}`);
379
378
  const size = await getEstimate(videoURL, formatArg);
380
- console.log(`${C.yellow}📊 Estimasi Ukuran: ${C.bright}${size}${C.reset}`);
379
+ console.log(`${C.yellow}📊 Estimated Size: ${C.bright}${size}${C.reset}`);
381
380
 
382
- const confirm = await askQuestion('Lanjutkan unduhan? (Y/n): ');
381
+ const confirm = await askQuestion('Proceed with download? (Y/n): ');
383
382
  if (confirm.toLowerCase() === 'n') return mainMenu();
384
383
  }
385
384
 
@@ -401,7 +400,7 @@ async function startDownload(videoURLFromArgs = null) {
401
400
  videoURL,
402
401
  ];
403
402
 
404
- // Integrasi Safe Mode (cite: cli.js)
403
+ // Integrate Safe Mode (cite: cli.js)
405
404
  if (safeMode) {
406
405
  args.push(
407
406
  '--rate-limit',
@@ -421,7 +420,7 @@ async function startDownload(videoURLFromArgs = null) {
421
420
  if (mode === '2') {
422
421
  if (!ffExists) {
423
422
  console.log(
424
- `${C.red}❌ Error: Anda wajib menginstal FFmpeg untuk mengunduh audio.${C.reset}`,
423
+ `${C.red}❌ Error: FFmpeg is required to download audio.${C.reset}`,
425
424
  );
426
425
  return mainMenu();
427
426
  }
@@ -432,11 +431,11 @@ async function startDownload(videoURLFromArgs = null) {
432
431
  }
433
432
 
434
433
  args.push('--no-mtime');
435
- console.log(`\n${C.bgBlue}${C.bright} 🚀 MEMULAI PROSES... ${C.reset}\n`);
434
+ console.log(`\n${C.bgBlue}${C.bright} 🚀 STARTING PROCESS... ${C.reset}\n`);
436
435
 
437
436
  const code = await runSpawn(YTDLP_PATH, args);
438
437
  if (code === 0) {
439
- console.log(`\n${C.green}✨ SELESAI! Cek folder: ${outputDir}${C.reset}`);
438
+ console.log(`\n${C.green}✨ DONE! Check folder: ${outputDir}${C.reset}`);
440
439
  try {
441
440
  execSync(
442
441
  isWindows
@@ -447,42 +446,42 @@ async function startDownload(videoURLFromArgs = null) {
447
446
  );
448
447
  } catch (e) {}
449
448
  } else {
450
- console.log(`\n${C.red}❌ Terjadi kesalahan saat mengunduh.${C.reset}`);
449
+ console.log(`\n${C.red}❌ An error occurred while downloading.${C.reset}`);
451
450
  }
452
451
  await backToMenu();
453
452
  }
454
453
 
455
454
  async function backToMenu() {
456
455
  try {
457
- await askQuestion('Tekan Enter untuk kembali ke Menu Utama...');
458
- mainMenu(); // Kembali ke menu
456
+ await askQuestion('Press Enter to return to Main Menu...');
457
+ mainMenu(); // Return to menu
459
458
  } catch (err) {
460
- // Tangani jika readline sudah tertutup (Ctrl+C ditekan sebelumnya)
459
+ // Handle if readline is already closed (Ctrl+C pressed previously)
461
460
  if (err.code === 'ERR_USE_AFTER_CLOSE') {
462
- console.log(`\n${C.dim}Program dihentikan oleh pengguna.${C.reset}`);
461
+ console.log(`\n${C.dim}Program terminated by user.${C.reset}`);
463
462
  process.exit(0);
464
463
  } else {
465
- // Jika error lain, lempar kembali agar bisa dideteksi (opsional)
464
+ // Throw other errors if necessary
466
465
  throw err;
467
466
  }
468
467
  }
469
468
  }
470
469
 
471
470
  async function showSupport() {
472
- // Menggunakan 2 parameter: Judul dan Summary
473
- printHeader('TENTANG APLIKASI', 'Media-DL Manager Pro v2.0.0 - 2026');
471
+ // Using 2 parameters: Title and Summary
472
+ printHeader('ABOUT APPLICATION', 'Media-DL Manager Pro v2.0.0 - 2026');
474
473
 
475
- // --- SEKSI FITUR ---
474
+ // --- FEATURES SECTION ---
476
475
  console.log(` ${C.bright}${C.cyan}OVERVIEW${C.reset}`);
477
- console.log(` Terima kasih telah memilih MEDIA-DL. Skrip ini dirancang`);
478
- console.log(` untuk memudahkan manajemen unduhan media secara lokal.\n`);
476
+ console.log(` Thank you for choosing MEDIA-DL. This script is designed`);
477
+ console.log(` to facilitate local media download management.\n`);
479
478
 
480
- console.log(` ${C.bright}${C.cyan}FITUR UNGGULAN${C.reset}`);
479
+ console.log(` ${C.bright}${C.cyan}KEY FEATURES${C.reset}`);
481
480
  const features = [
482
481
  {
483
482
  icon: '✦',
484
483
  title: 'High Quality',
485
- desc: 'Mendukung hingga 4K & Audio 320kbps',
484
+ desc: 'Supports up to 4K & 320kbps Audio',
486
485
  },
487
486
  {
488
487
  icon: '✦',
@@ -492,12 +491,12 @@ async function showSupport() {
492
491
  {
493
492
  icon: '✦',
494
493
  title: 'Batch Mode',
495
- desc: 'Mendukung unduhan Playlist secara massal',
494
+ desc: 'Supports bulk Playlist downloading',
496
495
  },
497
496
  {
498
497
  icon: '✦',
499
498
  title: 'Safe Guard',
500
- desc: 'Mode proteksi agar akun/IP tidak terblokir',
499
+ desc: 'Protection mode to prevent account/IP blocks',
501
500
  },
502
501
  ];
503
502
 
@@ -511,15 +510,25 @@ async function showSupport() {
511
510
 
512
511
  console.log('\n' + '─'.repeat(52));
513
512
 
514
- // --- SEKSI DUKUNGAN ---
515
- console.log(`\n ${C.bright}${C.magenta}DUKUNGAN & DONASI${C.reset}`);
516
- console.log(` Dukungan Anda sangat membantu pengembang untuk terus`);
517
- console.log(` memperbarui engine dan fitur aplikasi ini.\n`);
513
+ // --- SUPPORT SECTION ---
514
+ console.log(`\n ${C.bright}${C.magenta}SUPPORT & DONATION${C.reset}`);
515
+ console.log(` Your support helps the developer to keep updating`);
516
+ console.log(` the engine and features of this application.\n`);
518
517
 
519
- // Menampilkan Link dengan label background agar menonjol
518
+ // Display Links with background label to stand out
520
519
  const links = [
521
- { label: ' ☕ BELI KOPI ', url: 'https://app.midtrans.com/coffee' },
522
- { label: ' 🍕 BELI PIZZA', url: 'https://app.midtrans.com/pizza' },
520
+ {
521
+ label: ' BUY COFFEE (Paypal)',
522
+ url: 'https://www.paypal.com/ncp/payment/RSXEBXBQGDYN4',
523
+ },
524
+ {
525
+ label: ' ☕ BUY COFFEE (Midtrans)',
526
+ url: 'https://app.midtrans.com/coffee',
527
+ },
528
+ {
529
+ label: ' 🍕 BUY PIZZA (Midtrans)',
530
+ url: 'https://app.midtrans.com/pizza',
531
+ },
523
532
  ];
524
533
 
525
534
  links.forEach((l) => {
@@ -537,10 +546,10 @@ async function mainMenu() {
537
546
  const status = checkTools();
538
547
  const { ytExists, ffExists } = status;
539
548
 
540
- // Menggunakan 2 parameter: Judul dan Summary status singkat
541
- printHeader('MEDIA-DL PRO 2026', 'Pusat Kendali Unduhan Media Lokal');
549
+ // Using 2 parameters: Title and short summary status
550
+ printHeader('MEDIA-DL PRO 2026', 'Local Media Download Control Center');
542
551
 
543
- // --- SEKSI DASHBOARD (INFO SISTEM) ---
552
+ // --- DASHBOARD SECTION (SYSTEM INFO) ---
544
553
  const ytLabel = status.isLocalYt
545
554
  ? `${C.green}Ready (Internal)${C.reset}`
546
555
  : status.ytExists
@@ -563,14 +572,14 @@ async function mainMenu() {
563
572
 
564
573
  console.log(` ${C.cyan}━${'━'.repeat(48)}${C.reset}`);
565
574
 
566
- // --- SEKSI NAVIGASI ---
575
+ // --- NAVIGATION SECTION ---
567
576
  console.log(` ${C.bright}MAIN SERVICES${C.reset}`);
568
577
  console.log(
569
578
  ` ${C.cyan}1.${C.reset} 📥 Download Media ${C.dim}(Video, Music, Playlist)${C.reset}`,
570
579
  );
571
580
  console.log(
572
- ` ${C.cyan}2.${C.reset} 🛡️ Toggle Safe Mode ${C.dim}(Sekarang: ${
573
- safeMode ? 'Aktif' : 'Nonaktif'
581
+ ` ${C.cyan}2.${C.reset} 🛡️ Toggle Safe Mode ${C.dim}(Current: ${
582
+ safeMode ? 'Active' : 'Inactive'
574
583
  })${C.reset}`,
575
584
  );
576
585
 
@@ -579,13 +588,13 @@ async function mainMenu() {
579
588
  ` ${C.cyan}3.${C.reset} ⚙️ Maintenance & Update ${C.dim}(Update engine / Cleanup)${C.reset}`,
580
589
  );
581
590
  console.log(
582
- ` ${C.cyan}4.${C.reset} ❤️ Tentang Aplikasi ${C.dim}(Dukungan & Fitur)${C.reset}`,
591
+ ` ${C.cyan}4.${C.reset} ❤️ About Application ${C.dim}(Support & Features)${C.reset}`,
583
592
  );
584
- console.log(` ${C.cyan}0.${C.reset} 🚪 Keluar`);
593
+ console.log(` ${C.cyan}0.${C.reset} 🚪 Exit`);
585
594
 
586
595
  console.log(` ${C.cyan}━${'━'.repeat(48)}${C.reset}`);
587
596
 
588
- const choice = await askQuestion('\nPilih menu (0-4): ');
597
+ const choice = await askQuestion('\nSelect menu (0-4): ');
589
598
 
590
599
  switch (choice) {
591
600
  case '1':
@@ -593,10 +602,10 @@ async function mainMenu() {
593
602
  break;
594
603
  case '2':
595
604
  safeMode = !safeMode;
596
- // Berikan feedback visual singkat sebelum refresh menu
605
+ // Provide short visual feedback before refreshing menu
597
606
  console.log(
598
- `\n${C.yellow} 🛡️ Safe Mode telah ${
599
- safeMode ? 'DIAKTIFKAN' : 'DINONAKTIFKAN'
607
+ `\n${C.yellow} 🛡️ Safe Mode has been ${
608
+ safeMode ? 'ENABLED' : 'DISABLED'
600
609
  }${C.reset}`,
601
610
  );
602
611
  setTimeout(() => mainMenu(), 800);
@@ -610,14 +619,14 @@ async function mainMenu() {
610
619
  case '0':
611
620
  console.log(`\n${C.cyan}━${'━'.repeat(48)}${C.reset}`);
612
621
  console.log(
613
- ` ${C.bright}${C.white}Terima kasih telah menggunakan MEDIA-DL!${C.reset}`,
622
+ ` ${C.bright}${C.white}Thank you for using MEDIA-DL!${C.reset}`,
614
623
  );
615
624
  console.log(
616
- ` ${C.green}✨ Semoga Anda sukses, jaya, dan sehat selalu! ✨${C.reset}`,
625
+ ` ${C.green}✨ Wishing you success, prosperity, and good health! ✨${C.reset}`,
617
626
  );
618
627
  console.log(`${C.cyan}━${'━'.repeat(48)}${C.reset}\n`);
619
628
 
620
- // Memberikan jeda sebentar sebelum benar-benar menutup terminal
629
+ // Give a short delay before actually closing terminal
621
630
  setTimeout(() => {
622
631
  rl.close();
623
632
  process.exit(0);
@@ -625,7 +634,7 @@ async function mainMenu() {
625
634
 
626
635
  break;
627
636
  default:
628
- // Jika salah input, tampilkan kembali menu
637
+ // If input incorrect, show menu again
629
638
  mainMenu();
630
639
  break;
631
640
  }
@@ -636,7 +645,7 @@ async function cleanUp() {
636
645
  fs.rmSync(TOOLS_DIR, { recursive: true, force: true });
637
646
  }
638
647
 
639
- // RESET PATH ke default lokal agar checkTools tidak "tersesat" menggunakan path lama
648
+ // RESET PATH to local default so checkTools doesn't "get lost" using old path
640
649
  YTDLP_PATH = path.join(TOOLS_DIR, isWindows ? 'yt-dlp.exe' : 'yt-dlp');
641
650
  FFMPEG_PATH = path.join(TOOLS_DIR, isWindows ? 'ffmpeg.exe' : 'ffmpeg');
642
651
  }
@@ -646,28 +655,28 @@ async function firstTimeSetup() {
646
655
  const { ytExists, ffExists } = checkTools();
647
656
  printHeader(
648
657
  'FIRST-TIME SETUP',
649
- 'Komponen diperlukan untuk menjalankan aplikasi',
658
+ 'Components required to run the application',
650
659
  );
651
660
 
652
- console.log(`${C.white}Status Instalasi:${C.reset}`);
661
+ console.log(`${C.white}Installation Status:${C.reset}`);
653
662
  console.log(
654
663
  ` [${ytExists ? C.green + '✓' : C.red + '✗'}${
655
664
  C.reset
656
- }] Engine yt-dlp (Wajib)`,
665
+ }] yt-dlp Engine (Required)`,
657
666
  );
658
667
  console.log(
659
668
  ` [${ffExists ? C.green + '✓' : C.red + '✗'}${
660
669
  C.reset
661
- }] FFmpeg (Direkomendasikan)`,
670
+ }] FFmpeg (Recommended)`,
662
671
  );
663
672
 
664
673
  console.log(
665
- `\n${C.yellow}Aplikasi belum siap digunakan. Pilih opsi:${C.reset}`,
674
+ `\n${C.yellow}Application is not ready. Select option:${C.reset}`,
666
675
  );
667
- console.log(` ${C.cyan}1.${C.reset} Install Semua Komponen Otomatis`);
668
- console.log(` ${C.cyan}0.${C.reset} Keluar dari Aplikasi`);
676
+ console.log(` ${C.cyan}1.${C.reset} Install All Components Automatically`);
677
+ console.log(` ${C.cyan}0.${C.reset} Exit Application`);
669
678
 
670
- const choice = await askQuestion('\nPilih: ');
679
+ const choice = await askQuestion('\nSelect: ');
671
680
 
672
681
  if (choice === '1') {
673
682
  if (!ytExists) await installYtdlp();
@@ -676,13 +685,13 @@ async function firstTimeSetup() {
676
685
  const status = checkTools();
677
686
  if (status.ytExists) {
678
687
  console.log(
679
- `\n${C.green}✨ Setup Selesai! Membuka Menu Utama...${C.reset}`,
688
+ `\n${C.green}✨ Setup Complete! Opening Main Menu...${C.reset}`,
680
689
  );
681
690
  await new Promise((r) => setTimeout(r, 1500));
682
- return mainMenu(); // Berhasil, lanjut ke menu utama
691
+ return mainMenu(); // Success, proceed to main menu
683
692
  }
684
693
  } else if (choice === '0') {
685
- console.log('Menutup aplikasi...');
694
+ console.log('Closing application...');
686
695
  process.exit(0);
687
696
  }
688
697
  }
@@ -693,12 +702,9 @@ async function systemMaintenance() {
693
702
 
694
703
  while (inMaintenance) {
695
704
  const { ytExists, ffExists } = checkTools();
696
- printHeader(
697
- 'SYSTEM MAINTENANCE',
698
- 'Update engine atau bersihkan file sistem',
699
- );
705
+ printHeader('SYSTEM MAINTENANCE', 'Update engine or clean system files');
700
706
 
701
- console.log(`${C.white}Versi Terinstal:${C.reset}`);
707
+ console.log(`${C.white}Installed Versions:${C.reset}`);
702
708
  console.log(
703
709
  ` • yt-dlp : ${ytExists ? C.green + 'Ready' : C.red + 'Not Found'}${
704
710
  C.reset
@@ -710,39 +716,41 @@ async function systemMaintenance() {
710
716
  }`,
711
717
  );
712
718
 
713
- console.log(`\n${C.bright}Opsi Pemeliharaan:${C.reset}`);
719
+ console.log(`\n${C.bright}Maintenance Options:${C.reset}`);
714
720
  console.log(` ${C.cyan}1.${C.reset} Update / Reinstall Engines`);
715
- console.log(` ${C.cyan}2.${C.reset} 🗑️ Hapus Semua Tools (Reset System)`);
716
- console.log(` ${C.cyan}3.${C.reset} ⬅️ Kembali ke Menu Utama`);
721
+ console.log(` ${C.cyan}2.${C.reset} 🗑️ Delete All Tools (System Reset)`);
722
+ console.log(` ${C.cyan}3.${C.reset} ⬅️ Return to Main Menu`);
717
723
 
718
- const choice = await askQuestion('\nPilih tindakan: ');
724
+ const choice = await askQuestion('\nSelect action: ');
719
725
 
720
726
  switch (choice) {
721
727
  case '1':
722
728
  await installYtdlp();
723
729
  await installFfmpeg();
724
- await askQuestion('\nUpdate selesai. Tekan Enter...');
730
+ await askQuestion('\nUpdate complete. Press Enter...');
725
731
  break;
726
732
 
727
733
  case '2':
728
734
  const confirm = await askQuestion(
729
- `${C.bgRed}${C.white} KONFIRMASI ${C.reset} Hapus semua tools? (y/n): `,
735
+ `${C.bgRed}${C.white} CONFIRMATION ${C.reset} Delete all tools? (y/n): `,
730
736
  );
731
737
  if (confirm.toLowerCase() === 'y') {
732
- await cleanUp(); // Panggil fungsi penghapusan folder
733
- console.log(`${C.yellow}Folder .media-dl telah dihapus.${C.reset}`);
738
+ await cleanUp(); // Call folder deletion function
739
+ console.log(
740
+ `${C.yellow}Folder .media-dl has been deleted.${C.reset}`,
741
+ );
734
742
 
735
- // Cek ulang status setelah hapus
743
+ // Re-check status after deletion
736
744
  const finalCheck = checkTools();
737
745
  if (finalCheck.isLocalYt || finalCheck.isLocalFf) {
738
746
  console.log(
739
- `${C.red}Gagal menghapus beberapa file. Pastikan tidak ada proses yang mengunci file.${C.reset}`,
747
+ `${C.red}Failed to delete some files. Ensure no processes are locking them.${C.reset}`,
740
748
  );
741
749
  } else {
742
- console.log(`${C.green}Reset lokal berhasil.${C.reset}`);
750
+ console.log(`${C.green}Local reset successful.${C.reset}`);
743
751
  }
744
- await askQuestion('Tekan Enter...');
745
- return bootstrap(); // Kembali ke pengecekan awal
752
+ await askQuestion('Press Enter...');
753
+ return bootstrap(); // Return to initial check
746
754
  }
747
755
  break;
748
756
 
@@ -762,18 +770,17 @@ async function bootstrap() {
762
770
  if (!status.allReady) {
763
771
  await firstTimeSetup();
764
772
  } else {
765
- // process.argv[2] mengambil argumen pertama setelah nama perintah
773
+ // process.argv[2] takes the first argument after the command name
766
774
  const urlArgument = process.argv[2];
767
775
 
768
776
  if (urlArgument) {
769
- // Jika ada URL di terminal, langsung jalankan download
777
+ // If there is a URL in terminal, run download directly
770
778
  await startDownload(urlArgument);
771
779
  } else {
772
- // Jika tidak ada, masuk ke menu utama seperti biasa [cite: 113]
780
+ // If none, enter main menu as usual
773
781
  mainMenu();
774
782
  }
775
783
  }
776
784
  }
777
785
 
778
786
  bootstrap();
779
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "media-dl",
3
- "version": "2.5.2",
3
+ "version": "2.5.3",
4
4
  "description": "CLI Downloader video/audio lintas platform menggunakan yt-dlp.",
5
5
  "main": "bin/cli.js",
6
6
  "bin": {
package/readme.id.md ADDED
@@ -0,0 +1,103 @@
1
+ # 🚀 Media-DL Pro 2026
2
+
3
+ **The Ultimate Cross-Platform Media Engine Manager**
4
+
5
+ Media-DL Pro adalah *CLI wrapper* canggih berbasis `yt-dlp` yang dirancang untuk kecepatan, keteraturan, dan keamanan. Bukan sekadar pengunduh, ini adalah manajer media lokal yang cerdas dengan sistem instalasi otomatis.
6
+
7
+ ---
8
+
9
+ ## ✨ Fitur Unggulan Baru
10
+
11
+ ### 1. ⚡ Direct Download & Menu Mode
12
+
13
+ Sekarang kamu bisa memilih dua cara penggunaan:
14
+
15
+ * **Interactive Mode**: Cukup ketik `media-dl` untuk masuk ke menu utama yang cantik.
16
+ * **Fast Mode**: Ketik `media-dl <url>` untuk langsung masuk ke proses download tanpa basa-basi.
17
+
18
+ ### 2. 📱 Android (Termux) Ready
19
+
20
+ Dukungan penuh untuk pengguna mobile via Termux dengan script instalasi otomatis yang menyesuaikan lingkungan Linux Android.
21
+
22
+ ### 3. 🛡️ Safe Mode Guard™ (Updated)
23
+
24
+ Menghindari deteksi bot dengan:
25
+
26
+ * **Rate Limiting**: Dibatasi hingga 5 MB/s.
27
+ * **Smart Sleep**: Jeda acak 3–10 detik.
28
+ * **Modern User-Agent**: Identitas browser terbaru agar tetap aman.
29
+
30
+ ---
31
+
32
+ ## 🎞️ Platform yang Didukung
33
+
34
+ Berkat engine `yt-dlp` yang selalu diperbarui, kamu bisa mengunduh dari:
35
+
36
+ * **YouTube**: Video, Shorts, & Playlist.
37
+ * **Social Media**: TikTok, Instagram Reels, Twitter (X).
38
+ * **VOD Services**: Dan ratusan platform video lainnya.
39
+
40
+ ---
41
+
42
+ ## 📦 Instalasi
43
+
44
+ ### Prasyarat
45
+
46
+ * **Node.js**: Versi 14.0.0 atau lebih tinggi.
47
+
48
+ ### Cara Install
49
+
50
+ ```bash
51
+ npm install -g media-dl
52
+
53
+ ```
54
+
55
+ ### Penggunaan
56
+
57
+ ```bash
58
+ # Buka menu utama
59
+ media-dl
60
+
61
+ # Download langsung tanpa menu
62
+ media-dl https://www.youtube.com/watch?v=example
63
+
64
+ ```
65
+
66
+ ---
67
+
68
+ ## 🛠️ Navigasi Sistem
69
+
70
+ 1. **📥 Download Media**: Mendukung pemilihan kualitas (Video/Audio MP3) dan seleksi playlist (misal: `1,3,5-10`).
71
+ 2. **🛡️ Toggle Safe Mode**: Aktifkan perlindungan tambahan secara *on-the-fly*.
72
+ 3. **⚙️ Maintenance**: Update otomatis `yt-dlp` dan `FFmpeg` langsung dari aplikasi tanpa perlu download manual.
73
+ 4. **🗑️ Reset System**: Hapus semua engine untuk instalasi ulang yang bersih.
74
+
75
+ ---
76
+
77
+ ## 💻 Kompatibilitas Sistem
78
+
79
+ | Sistem Operasi | Status | Cara Kerja |
80
+ | --- | --- | --- |
81
+ | **Windows** | ✅ Supported | Auto-download `.exe` ke folder `~/.media-dl` |
82
+ | **macOS** | ✅ Supported | Auto-download via `curl` |
83
+ | **Linux** | ✅ Supported | Integrasi via `apt` (Debian/Ubuntu) |
84
+ | **Termux** | ✅ Supported | Integrasi via `pkg` & `pip` |
85
+
86
+ ---
87
+
88
+ ## 📂 Struktur Penyimpanan
89
+
90
+ Unduhan kamu akan tersimpan rapi di:
91
+
92
+ * **Video**: `~/Downloads/media-dl/video/`
93
+ * **Audio**: `~/Downloads/media-dl/audio/`
94
+ * **Playlist**: Sub-folder otomatis berdasarkan nama playlist.
95
+
96
+ ---
97
+
98
+ ## ❤️ Dukungan
99
+
100
+ Aplikasi ini dikembangkan oleh **Ariska Hidayat**. Jika bermanfaat, kamu bisa memberikan dukungan untuk biaya pemeliharaan server/engine:
101
+
102
+ * **☕ Traktir Kopi**: [Midtrans Coffee](https://app.midtrans.com/coffee)
103
+ * **🍕 Beli Pizza**: [Midtrans Pizza](https://app.midtrans.com/pizza)
package/readme.md CHANGED
@@ -1,103 +1,113 @@
1
- # 🚀 Media-DL Pro 2026
2
-
3
- **The Ultimate Cross-Platform Media Engine Manager**
4
-
5
- Media-DL Pro adalah *CLI wrapper* canggih berbasis `yt-dlp` yang dirancang untuk kecepatan, keteraturan, dan keamanan. Bukan sekadar pengunduh, ini adalah manajer media lokal yang cerdas dengan sistem instalasi otomatis.
6
-
7
- ---
8
-
9
- ## ✨ Fitur Unggulan Baru
10
-
11
- ### 1. ⚡ Direct Download & Menu Mode
12
-
13
- Sekarang kamu bisa memilih dua cara penggunaan:
14
-
15
- * **Interactive Mode**: Cukup ketik `media-dl` untuk masuk ke menu utama yang cantik.
16
- * **Fast Mode**: Ketik `media-dl <url>` untuk langsung masuk ke proses download tanpa basa-basi.
17
-
18
- ### 2. 📱 Android (Termux) Ready
19
-
20
- Dukungan penuh untuk pengguna mobile via Termux dengan script instalasi otomatis yang menyesuaikan lingkungan Linux Android.
21
-
22
- ### 3. 🛡️ Safe Mode Guard™ (Updated)
23
-
24
- Menghindari deteksi bot dengan:
25
-
26
- * **Rate Limiting**: Dibatasi hingga 5 MB/s.
27
- * **Smart Sleep**: Jeda acak 3–10 detik.
28
- * **Modern User-Agent**: Identitas browser terbaru agar tetap aman.
29
-
30
- ---
31
-
32
- ## 🎞️ Platform yang Didukung
33
-
34
- Berkat engine `yt-dlp` yang selalu diperbarui, kamu bisa mengunduh dari:
35
-
36
- * **YouTube**: Video, Shorts, & Playlist.
37
- * **Social Media**: TikTok, Instagram Reels, Twitter (X).
38
- * **VOD Services**: Dan ratusan platform video lainnya.
39
-
40
- ---
41
-
42
- ## 📦 Instalasi
43
-
44
- ### Prasyarat
45
-
46
- * **Node.js**: Versi 14.0.0 atau lebih tinggi.
47
-
48
- ### Cara Install
49
-
50
- ```bash
51
- npm install -g media-dl
52
-
53
- ```
54
-
55
- ### Penggunaan
56
-
57
- ```bash
58
- # Buka menu utama
59
- media-dl
60
-
61
- # Download langsung tanpa menu
62
- media-dl https://www.youtube.com/watch?v=example
63
-
64
- ```
65
-
66
- ---
67
-
68
- ## 🛠️ Navigasi Sistem
69
-
70
- 1. **📥 Download Media**: Mendukung pemilihan kualitas (Video/Audio MP3) dan seleksi playlist (misal: `1,3,5-10`).
71
- 2. **🛡️ Toggle Safe Mode**: Aktifkan perlindungan tambahan secara *on-the-fly*.
72
- 3. **⚙️ Maintenance**: Update otomatis `yt-dlp` dan `FFmpeg` langsung dari aplikasi tanpa perlu download manual.
73
- 4. **🗑️ Reset System**: Hapus semua engine untuk instalasi ulang yang bersih.
74
-
75
- ---
76
-
77
- ## 💻 Kompatibilitas Sistem
78
-
79
- | Sistem Operasi | Status | Cara Kerja |
80
- | --- | --- | --- |
81
- | **Windows** | ✅ Supported | Auto-download `.exe` ke folder `~/.media-dl` |
82
- | **macOS** | ✅ Supported | Auto-download via `curl` |
83
- | **Linux** | ✅ Supported | Integrasi via `apt` (Debian/Ubuntu) |
84
- | **Termux** | ✅ Supported | Integrasi via `pkg` & `pip` |
85
-
86
- ---
87
-
88
- ## 📂 Struktur Penyimpanan
89
-
90
- Unduhan kamu akan tersimpan rapi di:
91
-
92
- * **Video**: `~/Downloads/media-dl/video/`
93
- * **Audio**: `~/Downloads/media-dl/audio/`
94
- * **Playlist**: Sub-folder otomatis berdasarkan nama playlist.
95
-
96
- ---
97
-
98
- ## ❤️ Dukungan
99
-
100
- Aplikasi ini dikembangkan oleh **Ariska Hidayat**. Jika bermanfaat, kamu bisa memberikan dukungan untuk biaya pemeliharaan server/engine:
101
-
102
- * **☕ Traktir Kopi**: [Midtrans Coffee](https://app.midtrans.com/coffee)
103
- * **🍕 Beli Pizza**: [Midtrans Pizza](https://app.midtrans.com/pizza)
1
+ # 🚀 Media-DL Pro 2026
2
+
3
+ **The Ultimate Cross-Platform Media Engine Manager**
4
+
5
+ Media-DL Pro is an advanced *CLI wrapper* built on top of `yt-dlp`, designed for speed, structure, and security. It is not just a downloader, but a smart local media manager with an automated installation system.
6
+
7
+ ---
8
+
9
+ ## ✨ New Key Features
10
+
11
+ ### 1. ⚡ Direct Download & Menu Mode
12
+
13
+ You can now choose between two usage styles:
14
+
15
+ * **Interactive Mode**: Simply run `media-dl` to access a clean, user-friendly main menu.
16
+ * **Fast Mode**: Run `media-dl <url>` to start downloading immediately without entering the menu.
17
+
18
+ ### 2. 📱 Android (Termux) Ready
19
+
20
+ Full support for mobile users via Termux, with automatic installation scripts tailored for the Android Linux environment.
21
+
22
+ ### 3. 🛡️ Safe Mode Guard™ (Updated)
23
+
24
+ Designed to avoid bot detection through:
25
+
26
+ * **Rate Limiting**: Capped at 5 MB/s.
27
+ * **Smart Sleep**: Random delays between 3–10 seconds.
28
+ * **Modern User-Agent**: Uses up-to-date browser identifiers for safer requests.
29
+
30
+ ---
31
+
32
+ ## 🎞️ Supported Platforms
33
+
34
+ Powered by the continuously updated `yt-dlp` engine, Media-DL Pro supports downloads from:
35
+
36
+ * **YouTube**: Videos, Shorts, and Playlists.
37
+ * **Social Media**: TikTok, Instagram Reels, Twitter (X).
38
+ * **VOD Services**: And hundreds of other video platforms.
39
+
40
+ ---
41
+
42
+ ## 📦 Installation
43
+
44
+ ### Requirements
45
+
46
+ * **Node.js**: Version 14.0.0 or later.
47
+
48
+ ### Install
49
+
50
+ ```bash
51
+ npm install -g media-dl
52
+ ```
53
+
54
+ ### Usage
55
+
56
+ ```bash
57
+ # Open the main menu
58
+ media-dl
59
+
60
+ # Direct download without menu
61
+ media-dl https://www.youtube.com/watch?v=example
62
+ ```
63
+
64
+ ---
65
+
66
+ ## 🛠️ System Navigation
67
+
68
+ 1. **📥 Download Media**
69
+ Supports quality selection (Video / MP3 Audio) and playlist filtering (e.g. `1,3,5-10`).
70
+
71
+ 2. **🛡️ Toggle Safe Mode**
72
+ Enable or disable additional protection on the fly.
73
+
74
+ 3. **⚙️ Maintenance**
75
+ Automatically update `yt-dlp` and `FFmpeg` directly from the app—no manual downloads required.
76
+
77
+ 4. **🗑️ Reset System**
78
+ Remove all engines for a clean reinstallation.
79
+
80
+ ---
81
+
82
+ ## 💻 System Compatibility
83
+
84
+ | Operating System | Status | Method |
85
+ | ---------------- | ----------- | --------------------------------------- |
86
+ | **Windows** | ✅ Supported | Auto-download `.exe` into `~/.media-dl` |
87
+ | **macOS** | ✅ Supported | Auto-download via `curl` |
88
+ | **Linux** | Supported | Integrated via `apt` (Debian/Ubuntu) |
89
+ | **Termux** | ✅ Supported | Integrated via `pkg` & `pip` |
90
+
91
+ ---
92
+
93
+ ## 📂 Storage Structure
94
+
95
+ Your downloads are neatly organized under:
96
+
97
+ * **Video**: `~/Downloads/media-dl/video/`
98
+ * **Audio**: `~/Downloads/media-dl/audio/`
99
+ * **Playlists**: Automatically grouped into subfolders by playlist name.
100
+
101
+ ---
102
+
103
+ ## ❤️ Support
104
+
105
+ This project is developed and maintained by **Ariska Hidayat**.
106
+ If you find it useful, you can support ongoing development and server/engine maintenance via:
107
+
108
+ * **☕ Buy Me a Coffee (Indonesia)**:
109
+ [https://app.midtrans.com/coffee](https://app.midtrans.com/coffee)
110
+ * **🍕 Buy Me a Pizza (Indonesia)**:
111
+ [https://app.midtrans.com/pizza](https://app.midtrans.com/pizza)
112
+ * **🌍 PayPal (International)**:
113
+ [https://www.paypal.com/ncp/payment/RSXEBXBQGDYN4](https://www.paypal.com/ncp/payment/RSXEBXBQGDYN4)