pythonffmpegpytube

FFmpeg error while converting from MP4 to MP3 in Python


When I try to convert videos from a YouTube playlist, it gives me an error:

File "C:\Users\fonti\AppData\Local\Programs\Python\Python310\lib\site-packages\ffmpy.py", line 106, in run raise FFRuntimeError(self.cmd, self.process.returncode, out[0], out[1]) ffmpy.FFRuntimeError: C:/ffmpeg/bin/ffmpeg.exe -i "Nightcore - To Be Human // lyrics.mp4" "Nightcore - To Be Human // lyrics.mp3" exited with status 1

The code I'm using:

from pytube import Playlist
import ffmpy
from ffmpy import FFmpeg

playlistLink = input("Introduz o link da Playlist: ")
playlist = Playlist(playlistLink)   

diretório = 'E'
while diretório != 'M' and diretório != 'V':
    diretório = input("Vais baixar música ou vídeos? (M/V)")
    if diretório == 'M':
        downloadDirectory = "C:/Users/fonti/Documents/Projetos Python/Youtube/Músicas"
    elif diretório == 'V':
        downloadDirectory = "C:/Users/fonti/Documents/Projetos Python/Youtube/Vídeos"

print("Número total de vídeos a baixar: ", len(playlist.video_urls))    

print("\n\n Links dos vídeos:\n")

for url in playlist.video_urls:
    print(url) 

def MP3():
    for video in playlist.videos:

        audio = video.streams.get_audio_only()
    
        audio.download(downloadDirectory)

        videoTitle = video.title
    
        new_filename = videoTitle + '.mp3'
        default_filename = videoTitle + '.mp4'
    
        print(default_filename+'\n\n'+new_filename)

        ff = ffmpy.FFmpeg(
            executable = 'C:/ffmpeg/bin/ffmpeg.exe',
            inputs={default_filename : None},
            outputs={new_filename : None}
        )
        ff.run()


def MP4():
    for video in playlist.videos:
        print('Downloading : {} with url : {}'.format(video.title, video.watch_url))
        video.streams.\
            filter(type='video', progressive=True, file_extension='mp4').\
            order_by('resolution').\
            desc().\
            first().\
            download(downloadDirectory)

escolha = 'E'
while escolha != 'V' and escolha != 'A':
    escolha = input("Queres formato de vídeo ou áudio (V/A)? ")
    if escolha == 'V':
        MP4()
    elif escolha == 'A':
        MP3()
    else:
        print("Escolha inválida")

If I try to download the videos from the playlist, it works fine. But when I try to download the audios, it gives me the error.


Solution

  • We may use full path so FFmpeg can find the files.
    We may join downloadDirectory with videoTitle for creating full path:

    def MP3():
            ...
            videoTitle = video.title
    
            videoTitle = os.path.join(downloadDirectory, videoTitle)
    
            new_filename = videoTitle + '.mp3'
            ...
    

    Complete code sample:

    from pytube import Playlist
    import ffmpy
    from ffmpy import FFmpeg
    import os
    
    playlistLink = 'https://www.youtube.com/playlist?list=PLS1QulWo1RIaJECMeUT4LFwJ-ghgoSH6n' #input("Introduz o link da Playlist: ")
    playlist = Playlist(playlistLink)   
    
    diretório = 'E'
    while diretório != 'M' and diretório != 'V':
        diretório = 'M' #input("Vais baixar música ou vídeos? (M/V)")
        if diretório == 'M':
            downloadDirectory = "C:/Users/fonti/Documents/Projetos Python/Youtube/Músicas"
        elif diretório == 'V':
            downloadDirectory = "C:/Users/fonti/Documents/Projetos Python/Youtube/Vídeos"
    
    print("Número total de vídeos a baixar: ", len(playlist.video_urls))    
    
    print("\n\n Links dos vídeos:\n")
    
    for url in playlist.video_urls:
        print(url) 
    
    def MP3():
        for video in playlist.videos:
    
            audio = video.streams.get_audio_only()
        
            audio.download(downloadDirectory)
    
            videoTitle = video.title
    
            videoTitle = os.path.join(downloadDirectory, videoTitle)  # Concatenate the directory and the file name
        
            new_filename = videoTitle + '.mp3'
            default_filename = videoTitle + '.mp4'        
        
            print(default_filename+'\n\n'+new_filename)
    
            ff = ffmpy.FFmpeg(
                executable = 'C:/ffmpeg/bin/ffmpeg.exe',
                inputs={default_filename : None},
                outputs={new_filename : None}
            )
            ff.run()
    
    
    def MP4():
        for video in playlist.videos:
            print('Downloading : {} with url : {}'.format(video.title, video.watch_url))
            video.streams.\
                filter(type='video', progressive=True, file_extension='mp4').\
                order_by('resolution').\
                desc().\
                first().\
                download(downloadDirectory)
    
    escolha = 'E'
    while escolha != 'V' and escolha != 'A':
        escolha = 'A' #input("Queres formato de vídeo ou áudio (V/A)? ")
        if escolha == 'V':
            MP4()
        elif escolha == 'A':
            MP3()
        else:
            print("Escolha inválida")
    

    More robust solution, is searching for the .mp4 file in the folder, and delete it after converting to mp3:

    from pytube import Playlist
    import ffmpy
    from ffmpy import FFmpeg
    import os
    import glob
    
    playlistLink = 'https://www.youtube.com/playlist?list=PLS1QulWo1RIaJECMeUT4LFwJ-ghgoSH6n' #input("Introduz o link da Playlist: ")
    playlist = Playlist(playlistLink)   
    
    diretório = 'E'
    while diretório != 'M' and diretório != 'V':
        diretório = 'M' #input("Vais baixar música ou vídeos? (M/V)")
        if diretório == 'M':
            downloadDirectory = "C:/Users/fonti/Documents/Projetos Python/Youtube/Músicas"
        elif diretório == 'V':
            downloadDirectory = "C:/Users/fonti/Documents/Projetos Python/Youtube/Vídeos"
    
    print("Número total de vídeos a baixar: ", len(playlist.video_urls))    
    
    print("\n\n Links dos vídeos:\n")
    
    for url in playlist.video_urls:
        print(url) 
    
    def MP3():
        # Delete all mp4 files in Músicas folder
        mp4_files = glob.glob(os.path.join(downloadDirectory, '*.mp4'))  # dir C:/Users/fonti/Documents/Projetos Python/Youtube/Músicas/*.mp4
        for f in mp4_files:
            os.remove(f)
    
        for video in playlist.videos:
    
            audio = video.streams.get_audio_only()
        
            audio.download(downloadDirectory)
    
            videoTitle = video.title
            videoTitle = videoTitle.strip() # use the strip() method to remove trailing and leading spaces https://stackoverflow.com/a/10443548/4926757
           
            # List all mp4 files in the directory.
            videoTitle = glob.glob(os.path.join(downloadDirectory, '*.mp4'))  # dir C:/Users/fonti/Documents/Projetos Python/Youtube/Músicas/*.mp4
            
            #videoTitle = os.path.join(downloadDirectory, videoTitle)  # Concatenate the directory and the file name
        
            #new_filename = videoTitle + '.mp3'
            #default_filename = videoTitle + '.mp4'
    
            default_filename = videoTitle[0]  # Suppused to be only one mp4 file in the folder.
            new_filename = default_filename.replace('.mp4', '.mp3')  # Remplace .mp4 with .mp3
        
            print(default_filename+'\n\n'+new_filename)
    
            ff = ffmpy.FFmpeg(
                executable = 'C:/ffmpeg/bin/ffmpeg.exe',
                inputs={default_filename : None},
                outputs={new_filename : None}
            )
            ff.run()
    
            os.remove(default_filename)  # Delete the mp4 file
    
    
    def MP4():
        for video in playlist.videos:
            print('Downloading : {} with url : {}'.format(video.title, video.watch_url))
            video.streams.\
                filter(type='video', progressive=True, file_extension='mp4').\
                order_by('resolution').\
                desc().\
                first().\
                download(downloadDirectory)
    
    escolha = 'E'
    while escolha != 'V' and escolha != 'A':
        escolha = 'A' #input("Queres formato de vídeo ou áudio (V/A)? ")
        if escolha == 'V':
            MP4()
        elif escolha == 'A':
            MP3()
        else:
            print("Escolha inválida")