Я делаю консольное приложение Java для Windows, которое читает буфер обмена пользователя, и если контент является ссылкой https://youtube.com , загружает аудио в файл mp3 с помощью youtube-dl.
Я пытался использовать ProcessBuilder
для загрузки и преобразования видео в аудио, но мне не удается перенаправить вывод youtube-dl.exe на консоль.
package com.awidesky.YoutubeClipboardAutoDownlader;
import java.io.File;
import java.io.FilenameFilter;
import java.lang.ProcessBuilder.Redirect;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
public class YoutubeAudioDownloader {
private static final String youtubedlpath = new File("").getAbsolutePath() + "\\resources\\ffmpeg\\bin"; //Thread.currentThread().getContextClassLoader().getResource("ffmpeg/bin").getPath();
private static File downloadPath;
static {
if (!new File(youtubedlpath + "\\youtube-dl.exe").exists()) { throw new Error("youtube-dl.exe does not exist!"); }
}
static void download(String url, String path) throws Exception {
downloadPath = new File(path);
try {
//Main.log(downloadPath.getAbsolutePath());
ProcessBuilder pb = new ProcessBuilder(youtubedlpath + "\\youtube-dl", "-x", "--audio-format", "mp3", "--audio-quality", "0", url);
pb.directory(new File(youtubedlpath));
Process p = pb.start();
pb.redirectError(Redirect.INHERIT);
pb.redirectOutput(Redirect.INHERIT);
/*
* Thread stdout = new Thread(() -> {
*
* BufferedReader br = new BufferedReader(new
* InputStreamReader(p.getInputStream())); String line = null;
*
* try {
*
* while((line = br.readLine ()) != null) {
*
* Main.log(line);
*
* }
*
* } catch (IOException e) {
*
* // TODO Auto-generated catch block Main.log(e.toString());
*
* }
*
* });
*
* Thread stderr = new Thread(() -> {
*
* BufferedReader br = new BufferedReader(new
* InputStreamReader(p.getErrorStream())); String line = null;
*
* try {
*
* while((line = br.readLine ()) != null) {
*
* Main.log(line);
*
* }
*
* } catch (IOException e) {
*
* // TODO Auto-generated catch block Main.log(e.toString());
*
* }
*
* });
*
* stdout.start(); stderr.start();
*/
p.waitFor();
//Thread.currentThread().sleep(100);
Main.log("founding downloaded file...");
File[] fileList = new File(youtubedlpath).listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
// TODO Auto-generated method stub
return name.endsWith("mp3");
}
});
if(fileList.length ==0 ) { throw new RuntimeException("Didn't dowload any files!"); }
for(File f : fileList) {
Files.copy(f.toPath(), Paths.get(downloadPath.getAbsolutePath() + "\\" + f.getName()) ,StandardCopyOption.REPLACE_EXISTING);
Files.delete(f.toPath());
}
Main.log("Done!");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Если я получу InputStreamReader
из Process p
и использую два Thread
и while
для печати, я могу получить правильный вывод из eclipse, но я не могу получить его при запуске с java -jar YoutubeClipBoardAutoDownlaoder.jar
.
И когда я использую pb.redirectError(Redirect.INHERIT);
и pb.redirectOutput(Redirect.INHERIT);
, ни консоль eclipse, ни консоль Windows я не получаю вывода. Где я ошибся?
- Полные коды проекта находятся здесь а ниже это основной класс его.
package com.awidesky.YoutubeClipboardAutoDownlader;
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.FlavorEvent;
import java.awt.datatransfer.FlavorListener;
import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
/** Main class */
public class Main {
private static ExecutorService executorService = Executors.newFixedThreadPool(1);
private static boolean isOkToStart = false; /** I don't know why but when you copied something, <code>flavorsChanged</code> invoked twice and we should ignore the first one. */
public static void main(String[] args) throws Exception {
JFileChooser jfc = new JFileChooser();
jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
jfc.setDialogTitle("Choose directory for saving music!");
jfc.showDialog(new JFrame(), null);
File dir = jfc.getSelectedFile();
Toolkit.getDefaultToolkit().getSystemClipboard().addFlavorListener(new FlavorListener() {
@Override
public void flavorsChanged(FlavorEvent e) {
if (!isOkToStart) { isOkToStart = true; return; }
System.err.println("CLIPBOARD CHANGED");
executorService.submit(() -> {
try {
Thread.sleep(100);
String data = (String)Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.stringFlavor);
if (data.startsWith("https://www.youtu")) {
log("Receved a link from your clipboard : " + data);
YoutubeAudioDownloader.download(data, dir.getAbsolutePath());
}
} catch(Exception err) {
log(err.toString());
}
});
isOkToStart = !isOkToStart;
}
});
log("Listning clipboard...");
}
public static void log(String data) {
System.out.println(data);
}
}
Вы можете спросить меня...
Вы ДОЛЖНЫ использовать youtuve-dl?
-Неа. Единственная причина, по которой я использую это, заключается в том, что я не нашел лучшего для загрузки аудио с youtube.com.
Почему вы используете только один пул потоков?
- Избегайте длительного времени в потоке событий, и я думаю, что процессы падают, когда я запускаю несколько youtuve-dl.exe (хотя не уверен)