0

我正在使用 Python 制作这个 youtube 下载器 GUI:它会询问 URL,为您提供可能的质量设置列表,并使用 youtube-dl 下载选定的视频文件和最佳音频文件。但是,当我告诉 ffmpeg 合并两个单独的下载文件时,它什么也没做,控制台中也没有说什么。有什么我想念的吗?

这是代码的相关部分(从第 153 行开始):

            #Adding input arguments for ffmpeg
            ffmpeg_video = ffmpeg.input(self.video_title)
            ffmpeg_audio = ffmpeg.input(self.audio_title)
            output_ffmpeg_title = './videos/' + self.youtube_title
            #Merging with ffmpeg
            out = ffmpeg.output(ffmpeg_video, ffmpeg_audio, output_ffmpeg_title, vcodec='copy', acodec='aac')
            out.run

这是完整的代码:

import youtube_dl
import tkinter as tk
import operator
import ffmpeg
class GUI:
    def __init__(self):
        #Creating initial window
        self.window = tk.Tk()
        self.window.title('YTDL')
        self.window.geometry('300x70')
        
        self.urlbox = tk.Entry(self.window)
        self.urlbox.pack(padx=5,pady=5)
        #Creating download button, which will open the format selection window
        downbutton = tk.Button(self.window, text="Download", command= self.check_url)
        downbutton.pack(padx=5, pady=5)
        #Creating a variable to keep track of the point in the GUI options selection
        self.format_select_process = False
        
        self.window.mainloop()
    def check_url(self):
        #Saving selected URL to variable
        self.selected_url = self.urlbox.get()
        self.urlbox.delete(0, 'end')
        #If something was written in the URL box, try to go the next step
        if len(self.selected_url) != 0:
            self.get_formats(self.selected_url)
        else:
            print('URL box is empty!')
    def get_formats(self, x):
        with youtube_dl.YoutubeDL() as ydl:
            meta = ydl.extract_info(x, download=False)
            #Save formats from 'meta' to 'self.formats'
            self.formats = meta.get('formats', [meta])
            self.youtube_title = meta.get('title', [meta])
            #Creating two dictionaries for the list of format sizes and extensions
            self.f_list_size_dict = {}
            self.f_list_ext_dict = {}
            #Creating audio format list
            self.audio_format_list = []
        #For every format in self.formats, add its format, extension, fps and filesize to self.f_list
        for f in self.formats:
            self.f_list = '-' + f['format']+ ' -' + f['ext'] + ' -' + str(f['fps']) + ' ' + str(f['filesize'])
            if 'audio only' in f['format']:
                #Add an element to each dictonary whose name is the format ID and whose value is its filesize/extension
                self.f_list_size_dict[f['format'].split(' -')[0]] = f['filesize']
                self.f_list_ext_dict[f['format'].split(' -')[0]] = f['ext']
                #Add to the audio format list the current audio format ID
                self.audio_format_list.append(f['format'].split(' -')[0])
        print('Audio format list:')
        print(self.audio_format_list)
        print('Size list dict:')
        print(self.f_list_size_dict)
        print('Ext list size dict:')
        print(self.f_list_ext_dict)
        """
        #Making a new list which only contains the audio format IDs
        self.audio_format_list = str(self.f_list_size_dict.keys()).split('([')[1]
        self.audio_format_list = self.audio_format_list.split('])')[0]
        self.audio_format_list = self.audio_format_list.replace("'", "")
        self.audio_format_list = self.audio_format_list.split(', ')
        print('Cleaned up audio format list:')
        print(self.audio_format_list)
        """
        #Here the program starts looking for the best audio format
        #In the try block, the program gets the best audio format's ID from the size dict and extension from the ext dict
        #In the except block, the program gets the ID from the audio format list and the extension from the ext dict
        try:
            self.highest_audio = max(self.f_list_size_dict.items(), key=operator.itemgetter(1))[0]
            self.highest_audio_ext = self.f_list_ext_dict.get(self.highest_audio)
            print('Best audio format ID: ' + self.highest_audio)
            print('Best audio format extension: ' + self.highest_audio_ext)
        except:
            self.highest_audio = max(self.audio_format_list)
            self.highest_audio_ext = self.f_list_ext_dict.get(self.highest_audio)
            print(self.highest_audio)
            print(self.highest_audio_ext)
        #Going to next sted of the code, which renders the format choice window
        self.format_select()
    def format_select(self):
        self.window.withdraw()
        format_select_window = tk.Toplevel()
        format_select_window.attributes('-topmost', True)
        format_select_window.geometry("300x350")
        format_select_window_label = tk.Label(format_select_window, text="Select the video format")
        format_select_window_label.pack(padx=5, pady=5)
        format_select_window.protocol('WM_DELETE_WINDOW', lambda: exit())

        self.format_listbox = tk.Listbox(format_select_window, height=15, width=40, yscrollcommand=1)
        self.format_listbox.pack(padx=10, pady=10)
        for index, item in enumerate(self.f_list):
            self.f_list_lenght = index
        download_button = tk.Button(format_select_window, text='Download', command=self.download)
        download_button.pack(padx=10, pady=10)
        #Adding options to the listbox
        for f in self.formats:
            #If it is adding an audio only format, it will add the ID, filesize (if possible with try block) and extension
            if 'audio only' in f['format'] + ' ' + str(f['fps']) + ' FPS ' + f['ext']:
                try:
                    mb_filesize = round(f['filesize'] / 1024 / 1024, 2)
                    self.format_listbox.insert(self.f_list_lenght, f['format'] + ' ' + str(mb_filesize) + ' MiB  ' + f['ext']) 
                except:
                    self.format_listbox.insert(self.f_list_lenght, f['format'] + '  ' + f['ext'])
            #If it is adding a video format, it will add the ID, FPS, filesize (if possible with the try block) and extension
            else:
                try:
                    mb_filesize = round(f['filesize'] / 1024 / 1024, 2)
                    self.format_listbox.insert(self.f_list_lenght, f['format'] + ' ' + str(f['fps']) + ' FPS' + ' ' + str(mb_filesize) + ' MiB  ' + f['ext'])
                except:
                    self.format_listbox.insert(self.f_list_lenght, f['format'] + ' ' + str(f['fps']) + ' FPS  ' + f['ext'])
    def download(self):
        #Getting the list position of the selected format
        selected_format_list_position = self.format_listbox.curselection()
        #Getting the text of the selected format list item
        selected_format = self.format_listbox.get(selected_format_list_position)
        print('Selected format: ' + selected_format)
        #Cutting from the selected format list item text everything past ' -' to only get the format's ID
        selected_format_id = selected_format.split(' -')[0]
        print('Selected format ID: ' + selected_format_id)
        #Converting the ID to string
        final_selected_format_id = str(selected_format_id)
        print('Final selected format: ' + final_selected_format_id)
        #Cutting from the selected format list item text everything before '  ' to only get the extension
        final_ext = selected_format.split('  ')[1]
        print('Final video extension: ' + final_ext)
        if 'audio only' in selected_format:
            #Creating the download options dictionary (not working):
            #Setting the download location to the videos folder,
            #preventing the program from downloading a whole playlist,
            #telling youtube-dl to extract audio ('x'),
            #giving youtube-dl the requested format (which is only audio).
            self.ydl_opts = {'outtmpl':'./videos/%(title)s.%(ext)s', 'noplaylist': True, 'x': True, 'format': final_selected_format_id}
            #Downloading
            with youtube_dl.YoutubeDL(self.ydl_opts) as ydl:
                ydl.download([self.selected_url])
        elif 'audio only' not in selected_format:
            #Adding '+bestaudio' to the selected format ID (which is only a video ID in this case)
            final_selected_format_id_video_audio = str(selected_format_id) + '+bestaudio'
            #Creating the download options dictionary:
            #Setting the download location to the videos folder,
            #preventing the program from downloading a whole playlist,
            #giving youtube-dl the requested format with audio.
            self.ydl_opts = {'outtmpl':'./videos/%(title)s.%(ext)s', 'noplaylist': True, 'format': final_selected_format_id_video_audio}
            #Predicting the video file title and location for future ffmpeg merge
            self.video_title = './videos/' + self.youtube_title + '.f' + str(selected_format_id) + '.' + final_ext
            print('Video file title: ' + self.video_title)
            #Predicting the audio file title and location for future ffmpeg merge
            self.audio_title = './videos/' + self.youtube_title + '.f' + str(self.highest_audio) + '.' + self.highest_audio_ext
            print('Audio file title: ' + self.audio_title)
            #Downloading with youtube-dl
            with youtube_dl.YoutubeDL(self.ydl_opts) as ydl:
                ydl.download([self.selected_url])
            #Adding input arguments for ffmpeg
            ffmpeg_video = ffmpeg.input(self.video_title)
            ffmpeg_audio = ffmpeg.input(self.audio_title)
            output_ffmpeg_title = './videos/' + self.youtube_title
            #Merging with ffmpeg
            ffmpeg.output(ffmpeg_video, ffmpeg_audio, output_ffmpeg_title, vcodec='copy', acodec='aac')
GUI()

如果有更好的方法在 Python 中将 ffmpeg 与 youtube-dl 集成,请告诉我。

4

1 回答 1

0
  • 在您的完整代码中,run()缺少功能。
  • 尝试这个

ffmpeg.output(ffmpeg_video, ffmpeg_audio, output_ffmpeg_title, vcodec='copy', acodec='aac').run()

于 2021-04-24T14:22:39.307 回答