media-dl 1.0.5 → 1.0.6
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.
- package/bin/cli.js +51 -103
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ const os = require('os');
|
|
|
8
8
|
|
|
9
9
|
const rl = readline.createInterface({
|
|
10
10
|
input: process.stdin,
|
|
11
|
-
output: process.stdout
|
|
11
|
+
output: process.stdout
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
const TOOLS_DIR = path.join(os.homedir(), '.media-dl');
|
|
@@ -21,66 +21,48 @@ const FFMPEG_PATH = path.join(TOOLS_DIR, isWindows ? 'ffmpeg.exe' : 'ffmpeg');
|
|
|
21
21
|
if (!fs.existsSync(TOOLS_DIR)) fs.mkdirSync(TOOLS_DIR, { recursive: true });
|
|
22
22
|
|
|
23
23
|
function askQuestion(query) {
|
|
24
|
-
return new Promise(
|
|
24
|
+
return new Promise(resolve => rl.question(query, resolve));
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
function checkTools() {
|
|
28
28
|
return {
|
|
29
29
|
ytExists: fs.existsSync(YTDLP_PATH),
|
|
30
|
-
ffExists: fs.existsSync(FFMPEG_PATH)
|
|
30
|
+
ffExists: fs.existsSync(FFMPEG_PATH)
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
async function installYtdlp() {
|
|
35
35
|
console.log('\n⏳ Mengunduh yt-dlp...');
|
|
36
|
-
const url = isWindows
|
|
36
|
+
const url = isWindows
|
|
37
37
|
? 'https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe'
|
|
38
38
|
: 'https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp';
|
|
39
|
-
|
|
40
39
|
try {
|
|
41
40
|
if (isWindows) {
|
|
42
|
-
execSync(
|
|
43
|
-
`powershell -Command "Invoke-WebRequest -Uri ${url} -OutFile '${YTDLP_PATH}'"`,
|
|
44
|
-
{ stdio: 'inherit' }
|
|
45
|
-
);
|
|
41
|
+
execSync(`powershell -Command "Invoke-WebRequest -Uri ${url} -OutFile '${YTDLP_PATH}'"`, { stdio: 'inherit' });
|
|
46
42
|
} else {
|
|
47
43
|
execSync(`curl -L -# "${url}" -o "${YTDLP_PATH}"`, { stdio: 'inherit' });
|
|
48
44
|
execSync(`chmod a+rx "${YTDLP_PATH}"`);
|
|
49
45
|
}
|
|
50
46
|
console.log('✅ yt-dlp berhasil diinstal.');
|
|
51
|
-
} catch (e) {
|
|
52
|
-
console.error('❌ Gagal mengunduh yt-dlp.');
|
|
53
|
-
}
|
|
47
|
+
} catch (e) { console.error('❌ Gagal mengunduh yt-dlp.'); }
|
|
54
48
|
}
|
|
55
49
|
|
|
56
50
|
async function installFfmpeg() {
|
|
57
|
-
console.log('\n⏳ Mengunduh FFmpeg (Diperlukan untuk
|
|
51
|
+
console.log('\n⏳ Mengunduh FFmpeg (Diperlukan untuk konversi)...');
|
|
58
52
|
try {
|
|
59
53
|
if (isMac) {
|
|
60
54
|
const zipPath = path.join(TOOLS_DIR, 'ffmpeg.zip');
|
|
61
|
-
execSync(
|
|
62
|
-
`curl -L -# "https://evermeet.cx/ffmpeg/getrelease/ffmpeg/zip" -o "${zipPath}"`,
|
|
63
|
-
{ stdio: 'inherit' }
|
|
64
|
-
);
|
|
65
|
-
console.log('📦 Mengekstrak FFmpeg...');
|
|
55
|
+
execSync(`curl -L -# "https://evermeet.cx/ffmpeg/getrelease/ffmpeg/zip" -o "${zipPath}"`, { stdio: 'inherit' });
|
|
66
56
|
execSync(`unzip -o "${zipPath}" -d "${TOOLS_DIR}"`, { stdio: 'inherit' });
|
|
67
57
|
execSync(`rm "${zipPath}"`);
|
|
68
58
|
execSync(`chmod a+rx "${FFMPEG_PATH}"`);
|
|
69
59
|
console.log('✅ FFmpeg berhasil disiapkan.');
|
|
70
|
-
} else {
|
|
71
|
-
console.log(
|
|
72
|
-
'📝 Untuk Windows, silakan unduh manual dan letakkan ffmpeg.exe di: ' +
|
|
73
|
-
TOOLS_DIR
|
|
74
|
-
);
|
|
75
60
|
}
|
|
76
|
-
} catch (e) {
|
|
77
|
-
console.error('❌ Gagal mengunduh FFmpeg secara otomatis.');
|
|
78
|
-
}
|
|
61
|
+
} catch (e) { console.error('❌ Gagal instal FFmpeg.'); }
|
|
79
62
|
}
|
|
80
63
|
|
|
81
64
|
async function startDownload() {
|
|
82
65
|
let { ytExists, ffExists } = checkTools();
|
|
83
|
-
|
|
84
66
|
if (!ytExists) {
|
|
85
67
|
console.log('\n⚠️ yt-dlp belum terpasang.');
|
|
86
68
|
const ans = await askQuestion('Instal sekarang? (y/n): ');
|
|
@@ -89,80 +71,53 @@ async function startDownload() {
|
|
|
89
71
|
}
|
|
90
72
|
|
|
91
73
|
const videoURL = await askQuestion('\n🔗 Masukkan Link: ');
|
|
92
|
-
|
|
93
74
|
console.log('\n[PILIH FORMAT]');
|
|
94
|
-
console.log('1. Audio (MP3)
|
|
95
|
-
console.log('2. Video MP4 (
|
|
75
|
+
console.log('1. Audio (MP3)');
|
|
76
|
+
console.log('2. Video MP4 (Sangat Kompatibel Mac/QuickTime)');
|
|
96
77
|
const mode = await askQuestion('Pilihan: ');
|
|
97
78
|
|
|
98
|
-
const
|
|
99
|
-
|
|
79
|
+
const baseDir = path.join(os.homedir(), 'Downloads', 'media-dl');
|
|
80
|
+
const subFolder = (mode === '1') ? 'audio' : 'video';
|
|
81
|
+
const finalOutputDir = path.join(baseDir, subFolder);
|
|
82
|
+
if (!fs.existsSync(finalOutputDir)) fs.mkdirSync(finalOutputDir, { recursive: true });
|
|
100
83
|
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
'-o',
|
|
106
|
-
`${outputDir}/%(title).100s.%(ext)s`,
|
|
107
|
-
videoURL,
|
|
108
|
-
];
|
|
84
|
+
// Filter Format: Prioritaskan AVC1 + AAC
|
|
85
|
+
const qtFormat = 'bestvideo[vcodec^=avc1]+bestaudio[acodec^=mp4a]/best[vcodec^=avc1]/best';
|
|
86
|
+
|
|
87
|
+
let args = ['--ffmpeg-location', FFMPEG_PATH, '-o', `${finalOutputDir}/%(title).100s.%(ext)s`, videoURL];
|
|
109
88
|
|
|
110
89
|
if (mode === '1') {
|
|
111
|
-
if (!ffExists) {
|
|
112
|
-
console.log(
|
|
113
|
-
'❌ MP3 butuh FFmpeg. Silakan instal FFmpeg terlebih dahulu.'
|
|
114
|
-
);
|
|
115
|
-
return mainMenu();
|
|
116
|
-
}
|
|
90
|
+
if (!ffExists) { console.log('❌ Butuh FFmpeg.'); return mainMenu(); }
|
|
117
91
|
args.unshift('-x', '--audio-format', 'mp3');
|
|
118
92
|
} else {
|
|
119
|
-
console.log('\n[PILIH
|
|
120
|
-
console.log('1. Terbaik (
|
|
121
|
-
console.log('2. 1080p (
|
|
122
|
-
console.log('3. 720p');
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
if (
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
formatCode =
|
|
135
|
-
'bestvideo[height<=480][ext=mp4]+bestaudio[ext=m4a]/best[height<=480][ext=mp4]/best';
|
|
136
|
-
|
|
137
|
-
args.unshift('-f', formatCode);
|
|
138
|
-
|
|
139
|
-
if (!ffExists) {
|
|
140
|
-
console.log(
|
|
141
|
-
'⚠️ FFmpeg tidak terdeteksi. Hanya bisa mengunduh kualitas standar.'
|
|
142
|
-
);
|
|
143
|
-
args = [
|
|
144
|
-
'-f',
|
|
145
|
-
'best[ext=mp4]',
|
|
146
|
-
'-o',
|
|
147
|
-
`${outputDir}/%(title).100s.%(ext)s`,
|
|
148
|
-
videoURL,
|
|
149
|
-
];
|
|
93
|
+
console.log('\n[PILIH KUALITAS]');
|
|
94
|
+
console.log('1. Terbaik (Auto-Conversion ke MP4)');
|
|
95
|
+
console.log('2. 1080p (Pasti MP4)');
|
|
96
|
+
console.log('3. 720p (Pasti MP4)');
|
|
97
|
+
const res = await askQuestion('Pilih: ');
|
|
98
|
+
|
|
99
|
+
let fCode = qtFormat;
|
|
100
|
+
if (res === '2') fCode = 'bestvideo[height<=1080][vcodec^=avc1]+bestaudio[acodec^=mp4a]/best[height<=1080]/best';
|
|
101
|
+
if (res === '3') fCode = 'bestvideo[height<=720][vcodec^=avc1]+bestaudio[acodec^=mp4a]/best[height<=720]/best';
|
|
102
|
+
|
|
103
|
+
args.unshift('-f', fCode);
|
|
104
|
+
|
|
105
|
+
// FITUR BARU: Jika FFmpeg ada, paksa konversi ke MP4 agar pasti bisa dibuka QuickTime
|
|
106
|
+
if (ffExists) {
|
|
107
|
+
args.unshift('--recode-video', 'mp4');
|
|
150
108
|
}
|
|
151
109
|
}
|
|
152
110
|
|
|
153
|
-
console.log('\n🚀 Memulai proses...');
|
|
111
|
+
console.log('\n🚀 Memulai proses (dan konversi jika perlu)...');
|
|
154
112
|
const download = spawn(YTDLP_PATH, args);
|
|
155
|
-
|
|
156
113
|
download.stdout.on('data', (data) => process.stdout.write(data));
|
|
157
114
|
download.stderr.on('data', (data) => process.stderr.write(data));
|
|
158
115
|
|
|
159
116
|
download.on('close', (code) => {
|
|
160
117
|
if (code === 0) {
|
|
161
|
-
console.log(`\n✅
|
|
162
|
-
execSync(isMac ? `open "${
|
|
163
|
-
} else {
|
|
164
|
-
console.log('\n❌ Terjadi kesalahan selama proses download.');
|
|
165
|
-
}
|
|
118
|
+
console.log(`\n✅ BERHASIL! File tersimpan di: ${finalOutputDir}`);
|
|
119
|
+
execSync(isMac ? `open "${finalOutputDir}"` : `explorer "${finalOutputDir}"`);
|
|
120
|
+
} else { console.log('\n❌ Gagal saat mendownload atau mengonversi.'); }
|
|
166
121
|
mainMenu();
|
|
167
122
|
});
|
|
168
123
|
}
|
|
@@ -172,33 +127,26 @@ async function mainMenu() {
|
|
|
172
127
|
console.log('\n====================================');
|
|
173
128
|
console.log(' MEDIA-DL MANAGER 2026 ');
|
|
174
129
|
console.log('====================================');
|
|
175
|
-
console.log(` OS : ${process.platform}`);
|
|
176
|
-
console.log(` yt-dlp : ${ytExists ? '✅' : '❌'}`);
|
|
177
|
-
console.log(` ffmpeg : ${ffExists ? '✅' : '❌'}`);
|
|
130
|
+
console.log(` OS : ${process.platform} | yt-dlp: ${ytExists?'✅':'❌'} | ffmpeg: ${ffExists?'✅':'❌'}`);
|
|
178
131
|
console.log('------------------------------------');
|
|
179
132
|
console.log(' 1. 📥 Download Media');
|
|
180
133
|
console.log(' 2. ⚙️ Update yt-dlp');
|
|
181
134
|
console.log(' 3. 🔨 Instal FFmpeg (macOS)');
|
|
182
135
|
console.log(' 4. 🗑️ Uninstall & Hapus Data');
|
|
183
136
|
console.log(' 5. 🚪 Keluar');
|
|
184
|
-
|
|
137
|
+
|
|
185
138
|
const choice = await askQuestion('\nPilih menu: ');
|
|
186
139
|
if (choice === '1') await startDownload();
|
|
187
|
-
else if (choice === '2') {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
if (confirm.toLowerCase() === 'y')
|
|
196
|
-
fs.rmSync(TOOLS_DIR, { recursive: true, force: true });
|
|
140
|
+
else if (choice === '2') { await installYtdlp(); mainMenu(); }
|
|
141
|
+
else if (choice === '3') { await installFfmpeg(); mainMenu(); }
|
|
142
|
+
else if (choice === '4') {
|
|
143
|
+
const confirm = await askQuestion('Hapus semua? (y/n): ');
|
|
144
|
+
if (confirm.toLowerCase() === 'y') {
|
|
145
|
+
fs.rmSync(TOOLS_DIR, { recursive: true, force: true });
|
|
146
|
+
console.log('✅ Folder tools dibersihkan.');
|
|
147
|
+
}
|
|
197
148
|
mainMenu();
|
|
198
|
-
} else {
|
|
199
|
-
rl.close();
|
|
200
|
-
process.exit(0);
|
|
201
|
-
}
|
|
149
|
+
} else { rl.close(); process.exit(0); }
|
|
202
150
|
}
|
|
203
151
|
|
|
204
|
-
mainMenu();
|
|
152
|
+
mainMenu();
|