sealedtx / java-youtube-downloader

Simple, almost zero-dependency java parser for retrieving youtube video metadata
Other
413 stars 115 forks source link

Only average quality #129

Open MavenW opened 1 month ago

MavenW commented 1 month ago

Well the thing is that for some reason the downloaded videos only appear in medium quality even if you select the highest quality format, I don't know if it is an error or if that is the behavior

sealedtx commented 1 month ago

provide code snippet you use to download video and example of video url

MavenW commented 1 month ago

Hi, yes it is the code: public List getVideoWithAudioFormats() { if (currentVideo == null) { throw new IllegalStateException("Video info not loaded. Call getVideoInfo first."); } return currentVideo.videoWithAudioFormats(); }

public List<VideoFormat> getVideoFormats() {
    if (currentVideo == null) {
        throw new IllegalStateException("Video info not loaded. Call getVideoInfo first.");
    }
    return currentVideo.videoFormats();
}

public List<AudioFormat> getAudioFormats() {
    if (currentVideo == null) {
        throw new IllegalStateException("Video info not loaded. Call getVideoInfo first.");
    }
    return currentVideo.audioFormats();
}

public Format getBestVideoWithAudioFormat() {
    if (currentVideo == null) {
        throw new IllegalStateException("Video info not loaded. Call getVideoInfo first.");
    }
    return currentVideo.bestVideoWithAudioFormat();
}

public Format getBestVideoFormat() {
    if (currentVideo == null) {
        throw new IllegalStateException("Video info not loaded. Call getVideoInfo first.");
    }
    return currentVideo.bestVideoFormat();
}

public Format getBestAudioFormat() {
    if (currentVideo == null) {
        throw new IllegalStateException("Video info not loaded. Call getVideoInfo first.");
    }
    return currentVideo.bestAudioFormat();
}

public List<Format> getFormatsByExtension(Extension extension) {
    if (currentVideo == null) {
        throw new IllegalStateException("Video info not loaded. Call getVideoInfo first.");
    }
    return currentVideo.findFormats(format -> format.extension() == extension);
}

public Format getFormatByItag(int itag) {
    if (currentVideo == null) {
        throw new IllegalStateException("Video info not loaded. Call getVideoInfo first.");
    }
    return currentVideo.findFormatByItag(itag);
}

public List<VideoWithAudioFormat> getAvailableFormats() {
    if (currentVideo == null) {
        throw new IllegalStateException("Video info not loaded. Call getVideoInfo first.");
    }
    return currentVideo.videoWithAudioFormats();
}

public Format selectFormat(int formatIndex) {
    List<VideoWithAudioFormat> formats = getAvailableFormats();
    if (formatIndex < 0 || formatIndex >= formats.size()) {
        return currentVideo.bestVideoWithAudioFormat();
    }
    return formats.get(formatIndex);
}

public File downloadVideo(Format selectedFormat, File outputDir) throws YoutubeException {
    if (currentVideo == null) {
        throw new IllegalStateException("Video info not loaded. Call getVideoInfo first.");
    }

    // Verificar el formato seleccionado antes de la descarga
    System.out.println("Formato seleccionado: " + selectedFormat.itag()+ " - " + selectedFormat.extension());
    System.out.println("Formato seleccionado: " + selectedFormat.url());
    System.out.println("Formato seleccionado: " + selectedFormat.bitrate());
    System.out.println("Formato seleccionado: " + selectedFormat.mimeType());
    System.out.println("Formato seleccionado: " + selectedFormat.type());
    System.out.println("Formato seleccionado: " + selectedFormat.lastModified());

    outputDir.mkdirs(); // Asegura que el directorio exista
    RequestVideoFileDownload downloadRequest = new RequestVideoFileDownload(selectedFormat)
        .saveTo(outputDir)
        .renameTo(sanitizeFileName(currentVideo.details().title()))
        .overwriteIfExists(true);

    System.out.println("Descargando video...");
    Response<File> downloadResponse = downloader.downloadVideoFile(downloadRequest);

    // Verificar el archivo descargado
    File downloadedFile = downloadResponse.data();
    System.out.println("Archivo descargado: " + downloadedFile.getAbsolutePath());

    return downloadedFile;
}

private static String sanitizeFileName(String fileName) {
    return fileName.replaceAll("[\\\\/:*?\"<>|]", "_");
}

Here I insert and display the formats in a comboBox

if (outputDirectory != null && !outputDirectory.isEmpty()) { txtRutaSalida.setText(outputDirectory); // Suponiendo que tienes un campo de texto para mostrar la ruta seleccionada

        // Obtener la URL del video desde el campo de texto
        String videoUrl = txtUrlVideo.getText();
        if (videoUrl == null || videoUrl.trim().isEmpty()) {
            JOptionPane.showMessageDialog(this, "Por favor ingrese una URL de video.", "Error", JOptionPane.ERROR_MESSAGE);
            return;
        }

        try {
            String videoId = downloader.extractVideoId(videoUrl);
            if (videoId.isEmpty()) {
                JOptionPane.showMessageDialog(this, "No se pudo extraer el ID del video de la URL proporcionada.", "Error", JOptionPane.ERROR_MESSAGE);
                return;
            }

            VideoInfo videoInfo = downloader.getVideoInfo(videoId);

            txtTitulo.setText(videoInfo.details().title());

            DefaultComboBoxModel<FormatDTO> model = new DefaultComboBoxModel<>();
            model.addElement(new FormatDTO(-1, "Seleccionar")); // Elemento predeterminado

            // Agregar formatos de video con audio
            List<VideoWithAudioFormat> videoWithAudioFormats = downloader.getVideoWithAudioFormats();
            for (int i = 0; i < videoWithAudioFormats.size(); i++) {
                VideoWithAudioFormat format = videoWithAudioFormats.get(i);
                FormatDTO formatDTO = new FormatDTO(i, "Video+Audio: " + format.videoQuality() + " - " + format.extension());
                model.addElement(formatDTO);
            }

            // Agregar formatos de video sin audio
            List<VideoFormat> videoFormats = downloader.getVideoFormats();
            for (int i = 0; i < videoFormats.size(); i++) {
                VideoFormat format = videoFormats.get(i);
                FormatDTO formatDTO = new FormatDTO(videoWithAudioFormats.size() + i, "Video: " + format.videoQuality() + " - " + format.extension());
                model.addElement(formatDTO);
            }

            // Agregar formatos de audio
            List<AudioFormat> audioFormats = downloader.getAudioFormats();
            for (int i = 0; i < audioFormats.size(); i++) {
                AudioFormat format = audioFormats.get(i);
                FormatDTO formatDTO = new FormatDTO(videoWithAudioFormats.size() + videoFormats.size() + i, "Audio: " + format.audioQuality() + " - " + format.extension());
                model.addElement(formatDTO);
            }

            cmbFormatos.setModel(model);

        } catch (YoutubeException e) {
            JOptionPane.showMessageDialog(this, "Error al obtener la información del video: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
        }
    }

private void btnDescargarActionPerformed(java.awt.event.ActionEvent evt) {
FormatDTO selectedFormat = (FormatDTO) cmbFormatos.getSelectedItem(); if (selectedFormat == null || selectedFormat.getIndex() == -1) { JOptionPane.showMessageDialog(this, "Por favor seleccione un formato.", "Error", JOptionPane.ERROR_MESSAGE); return; }

    try {
        Format format = downloader.selectFormat(selectedFormat.getIndex());
        File outputDir = new File(outputDirectory);
        File downloadedFile = downloader.downloadVideo(format, outputDir);
        JOptionPane.showMessageDialog(this, "Video descargado exitosamente: " + downloadedFile.getAbsolutePath(), "Éxito", JOptionPane.INFORMATION_MESSAGE);
    } catch (YoutubeException e) {
        JOptionPane.showMessageDialog(this, "Error al descargar el video: " + e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
    }
}

Screenshot_69 Screenshot_70

sealedtx commented 1 month ago

I believe there is bug somewhere in your code near selectFormat(formatIndex):

public Format selectFormat(int formatIndex) {
    List<VideoWithAudioFormat> formats = getAvailableFormats();
    if (formatIndex < 0 || formatIndex >= formats.size()) {
        return currentVideo.bestVideoWithAudioFormat(); <-------- it returns here 
    }
    return formats.get(formatIndex);
}

bestVideoWithAudioFormat - returns format with video and audio and it always has lower quality - thats how youtube returns it If you want high quality you should select only from video formats (without audio)

I've just tested with your video and I can download both low (video+audio) and high (video only) quality.

MavenW commented 4 weeks ago

Thanks for your comments, you helped me a lot. Now I have an error, and it is that when testing with an 8k video, and when obtaining the best video format, I find an exception: Error parsing format: unknown itag 571

code: public static void main(String[] args) throws YoutubeException { DownloaderVideoFinal dow = new DownloaderVideoFinal(); String id = dow.extractVideoId("https://youtu.be/QqI9eKQnFL4?si=r01eXHpPxQI0sdUI"); dow.getVideoInfo(id); VideoFormat formato = (VideoFormat) dow.getBestVideoFormat(); File oupuString = null; dow.downloadVideo(formato, oupuString); } public String extractVideoId(String urlVideo) { System.out.println("YouTube Video Downloader"); System.out.print("URL del video de YouTube: " + urlVideo); Pattern pattern = Pattern.compile("(?<=watch\?v=|/videos/|embed\/|youtu.be\/|\/v\/|\/e\/|watch\?v%3D|watch\?feature=player_embedded&v=|%2Fvideos%2F|embed%u200C%u200B2F|youtu.be%2F|%2Fv%2F)[^#\&\?\n]*"); Matcher matcher = pattern.matcher(urlVideo); return matcher.find() ? matcher.group() : ""; } public VideoInfo getVideoInfo(String videoId) throws YoutubeException { RequestVideoInfo request = new RequestVideoInfo(videoId); Response response = downloader.getVideoInfo(request); currentVideo = response.data(); return currentVideo; }

private File downloadVideo(VideoFormat videoFormat, File outputDir) throws YoutubeException {
    if (currentVideo == null) {
        throw new IllegalStateException("Video info not loaded. Call getVideoInfo first.");
    }

    outputDir.mkdirs(); // Asegura que el directorio exista
    String fileName = sanitizeFileName(currentVideo.details().title()) + "." + videoFormat.extension(); // Usa la extensión del formato
    RequestVideoFileDownload downloadRequest = new RequestVideoFileDownload(videoFormat)
            .saveTo(outputDir)
            .renameTo(fileName)
            .overwriteIfExists(true);

    System.out.println("Descargando video...");
    Response<File> downloadResponse = downloader.downloadVideoFile(downloadRequest);

    // Verificar el archivo descargado
    File downloadedFile = downloadResponse.data();
    System.out.println("Archivo descargado: " + downloadedFile.getAbsolutePath());

    return downloadedFile;
}
sealedtx commented 4 weeks ago

@MavenW added missing itags for 8k videos in 3.2.4 version, update and check