I am facing an issue when it comes to my Java application. The app downloads Music from Youtube using yt-dlp, it is basically a GUI version of yt-dlp. The issue I have is only present on MacOs, it works as intended on Windows. Here is a snippet of my download method code (This is a MacOs specific method, as I have already mentioned before I only encounter the issue on MacOs not on Windows, thus I am not providing any code specific for Windows):
The download method:
private void download() {
Process process = null;
try {
ProcessBuilder processBuilder;
String command =
"'Project/src/Zasoby/yt-dlp'" + " -f bestaudio " +
"-x --audio-format " + chosenFormat
+ " --no-playlist --output '" + outputPath + "/%(title)s.%(ext)s ''"
+ linkYT + "'";
processBuilder = new ProcessBuilder("bash", "-c", command);
processBuilder.inheritIO();
process = processBuilder.start();
process.waitFor();
int exitCode = process.exitValue();
System.out.println(exitCode + " EXIT CODE"); // a log for exit codes
if (exitCode != 0) {
InfoFrame ef = new InfoFrame(2);
ef.setVisible(true);
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
The problem is that whenever I try to execute a command using the ProcessBuilder when not in my IDE (in my IDE it works just fine - the path 'Project/src/Zasoby/yt-dlp' is recognized and the program stars downloading Music), instead while executing the program via a .jar File, the program cannot find the yt-dlp program via its provided path.
So far I have tried providing Paths using a getFilePath method I wrote in order to make sure I do not need to specify a "semi-full" path which obviously would not work on a different MacOs computer.
The getFilePath method:
private Path getFilePath(String resourcePath) {
try {
InputStream inputStream = getResourceAsStream(resourcePath);
Path tempFilePath = Files.createTempFile("temp", null);
Files.copy(inputStream, tempFilePath, StandardCopyOption.REPLACE_EXISTING);
return tempFilePath.toAbsolutePath();
} catch (IOException e) {
throw new RuntimeException("Failed to get resource file path: " + resourcePath, e);
}
}
The modified command String in the download method:
Path ytDlpPathMac = getFilePath("Zasoby/yt-dlp");
String command =
ytDlpPathMac.toString() + " -f bestaudio " +
"-x --audio-format " + chosenFormat
+ " --no-playlist --output '" + outputPath + "/%(title)s.%(ext)s ''"
+ linkYT + "'";
Additionally the path "Zasoby/yt-dlp" is a "Path From Content Root", the full Path in the project is"Project/src/Zasoby/yt-dlp" - if that helps.I have already tried other solutions from other Questions on the forum, however none of them fixed the issue.
I have tried debugging the code using Xdebug tool on MacOs and the output I am getting is that ".. directory does not exist" - when using both of the approaches, the one with the "semi-full" path and the one with the getFilePath method. As I have previously mentioned this only happens on Mac, so maybe there is a different way of handling Paths on MacOs than on Windows when it comes to Java itself.
I don't know what you mean by the term "semi-full path", but if you want to run an external program, then that program must be
Project/src/Zasoby/yt-dlp
is a relative path. Whether it works for launching the program depends on the working directory from which the Java program is launched (not necessarily the folder containing the JAR file or any class files), against which that relative path will be resolved. This is not particular to using a JAR file or to any operating system; it's just thatProject/src/Zasoby/yt-dlp
happens to be correct for the working directory used when you launch from your IDE.Additionally, however, it looks like
yt-dlp
provides Windows and Unix wrapper scripts, namedyt-dlp.cmd
andyt-dlp.sh
, respectively. You can ignore the.cmd
extension on Windows, but you cannot ignore the.sh
extension on MacOS or Linux.As for your
getFilePath()
method, it appears to be trying to copy a singleyt-dlp
binary out of the JAR, onto the filesystem, so that it can be executed from there. There are numerous reasons why that probably won't work, among them:yt-dlp
being packaged into your JAR in the first place. It's possible to make such an arrangement, but I would not expect that to be done by default.yt-dlp
application consists of multiple files and directories, but you are copying out only one.You have a few main options:
Rely on
yt-dlp
being installed in the system's executable search path, so that you can launch it without specifying any path.Provide a way to configure your application with the correct (full) path to
yt-dlp
, and execute it via its full path.Provide a way for your application to discover the correct path. Typically this would be by relying on a known relationship between the location of the JAR and the location of
yt-dlp
. Then you can launch it via a correct path.Some of those options are more likely based on bundling
yt-dlp
with your wrapper application (but not in the JAR). Others are more oriented toward pairing your application with a separate installation ofyt-dlp
.