2025年9月20日 星期六

抓YT音樂影片且轉成mp3 (Python)

 抓YT音樂影片且轉成mp3 (Python)







import tkinter as tk

from tkinter import messagebox, filedialog

from pytubefix import YouTube

from pytubefix.cli import on_progress # pytubefix 提供的進度回調函數

import ssl

import os

import threading


# 解決 pytubefix 在某些環境下可能遇到的 SSL 憑證問題

ssl._create_default_https_context = ssl._create_stdlib_context


class YouTubeDownloaderApp:

    def __init__(self, master):

        self.master = master

        master.title("YouTube MP3 下載器 (pytubefix)")

        master.geometry("500x200")

        master.resizable(False, False)


        # 網址輸入框

        self.url_label = tk.Label(master, text="YouTube 影片網址:")

        self.url_label.pack(pady=(20, 5))


        self.url_entry = tk.Entry(master, width=60)

        self.url_entry.pack(pady=5)

        # 預設一個範例網址

        self.url_entry.insert(0, 'https://www.youtube.com/watch?v=R93ce4FZGbc') # 您可以替換為任何 YouTube 網址


        # 下載按鈕

        self.download_button = tk.Button(master, text="下載 MP3", command=self.start_download_thread)

        self.download_button.pack(pady=10)


        # 狀態訊息標籤

        self.status_label = tk.Label(master, text="等待輸入網址...", fg="blue")

        self.status_label.pack(pady=5)


    def download_mp3(self, url):

        """實際執行 MP3 下載的函數"""

        try:

            self.status_label.config(text="正在處理網址...", fg="orange")

            

            # 建立 YouTube 物件並設定進度回調函數

            # 我們使用一個 lambda 函數來包裹 on_progress,以便在 Tkinter 中更新狀態

            yt = YouTube(url, on_progress_callback=lambda stream, chunk, bytes_remaining: self.update_progress(stream, chunk, bytes_remaining))

            

            self.status_label.config(text=f"找到影片: {yt.title},開始下載...", fg="orange")

            

            # 選擇純音頻流(因為您提到了 MP3 音樂)

            audio_stream = yt.streams.filter(only_audio=True).first()


            if not audio_stream:

                raise Exception("找不到可下載的音頻流。")

            

            # 彈出視窗讓使用者選擇儲存路徑和檔案名稱

            file_path = filedialog.asksaveasfilename(

                defaultextension=".mp3",

                initialfile=f"{yt.title}.mp3",

                title="選擇儲存 MP3 的位置",

                filetypes=[("MP3 files", "*.mp3")]

            )


            if not file_path:

                self.status_label.config(text="下載已取消。", fg="red")

                return


            self.status_label.config(text="下載中,請稍候...", fg="blue")

            

            # 下載音頻

            audio_stream.download(output_path=os.path.dirname(file_path), filename=os.path.basename(file_path))

            

            self.status_label.config(text=f"下載完成!", fg="green")

            messagebox.showinfo("下載完成", f"'{yt.title}' 已成功下載!")


        except Exception as e:

            self.status_label.config(text=f"下載失敗: {e}", fg="red")

            messagebox.showerror("下載錯誤", f"下載影片時發生錯誤: {e}")

        finally:

            self.download_button.config(state=tk.NORMAL) # 重新啟用按鈕


    def update_progress(self, stream, chunk, bytes_remaining):

        """自定義的進度回調函數,用於更新 Tkinter 狀態標籤"""

        total_size = stream.filesize

        bytes_downloaded = total_size - bytes_remaining

        percentage = (bytes_downloaded / total_size) * 100

        self.status_label.config(text=f"下載中: {percentage:.2f}%...", fg="blue")

        self.master.update_idletasks() # 強制更新 GUI 以顯示最新進度


    def start_download_thread(self):

        """在單獨的執行緒中啟動下載,避免 GUI 凍結"""

        url = self.url_entry.get()

        if not url:

            messagebox.showwarning("警告", "請輸入 YouTube 影片網址!")

            return

        

        self.download_button.config(state=tk.DISABLED) # 禁用按鈕防止重複點擊

        self.status_label.config(text="準備下載...", fg="blue")


        # 創建並啟動新執行緒

        download_thread = threading.Thread(target=self.download_mp3, args=(url,))

        download_thread.start()


# 啟動應用程式

if __name__ == "__main__":

    root = tk.Tk()

    app = YouTubeDownloaderApp(root)

    root.mainloop()



//=====================================================

import tkinter as tk
from tkinter import ttk, messagebox, filedialog
from pytubefix import YouTube
import ssl
import os
import threading

# 解決 pytubefix 在某些環境下可能遇到的 SSL 憑證問題
ssl._create_default_https_context = ssl._create_stdlib_context

class YouTubeDownloaderApp:
    def __init__(self, master):
        self.master = master
        master.title("YouTube MP3 下載器 (pytubefix)")
        master.geometry("500x250")
        master.resizable(False, False)

        # 網址輸入框
        self.url_label = tk.Label(master, text="YouTube 影片網址:")
        self.url_label.pack(pady=(20, 5))

        self.url_entry = tk.Entry(master, width=60)
        self.url_entry.pack(pady=5)
        # 預設一個範例網址
        self.url_entry.insert(0, 'https://www.youtube.com/watch?v=R93ce4FZGbc')

        # 下載按鈕
        self.download_button = tk.Button(master, text="下載 MP3", command=self.start_download_thread)
        self.download_button.pack(pady=10)

        # 狀態訊息標籤
        self.status_label = tk.Label(master, text="等待輸入網址...", fg="blue")
        self.status_label.pack(pady=5)
        
        # 進度條
        self.progress_bar = ttk.Progressbar(
            master,
            orient="horizontal",
            length=400,
            mode="determinate"
        )
        self.progress_bar.pack(pady=10)
        self.progress_bar['value'] = 0

    def download_mp3(self, url):
        """實際執行 MP3 下載的函數"""
        try:
            self.status_label.config(text="正在處理網址...", fg="orange")
            self.progress_bar['value'] = 0
            
            # 建立 YouTube 物件並設定進度回調函數
            yt = YouTube(url, on_progress_callback=self.update_progress)
            
            self.status_label.config(text=f"找到影片: {yt.title},開始下載...", fg="orange")
            
            # 選擇純音頻流
            audio_stream = yt.streams.filter(only_audio=True).first()

            if not audio_stream:
                raise Exception("找不到可下載的音頻流。")
            
            # 彈出視窗讓使用者選擇儲存路徑和檔案名稱
            file_path = filedialog.asksaveasfilename(
                defaultextension=".mp3",
                initialfile=f"{yt.title}.mp3",
                title="選擇儲存 MP3 的位置",
                filetypes=[("MP3 files", "*.mp3")]
            )

            if not file_path:
                self.status_label.config(text="下載已取消。", fg="red")
                self.progress_bar['value'] = 0
                return

            self.status_label.config(text="下載中,請稍候...", fg="blue")
            
            # 下載音頻
            audio_stream.download(output_path=os.path.dirname(file_path), filename=os.path.basename(file_path))
            
            self.status_label.config(text=f"下載完成!", fg="green")
            self.progress_bar['value'] = 100
            messagebox.showinfo("下載完成", f"'{yt.title}' 已成功下載!")

        except Exception as e:
            self.status_label.config(text=f"下載失敗: {e}", fg="red")
            self.progress_bar['value'] = 0
            messagebox.showerror("下載錯誤", f"下載影片時發生錯誤: {e}")
        finally:
            self.download_button.config(state=tk.NORMAL) # 重新啟用按鈕

    def update_progress(self, stream, chunk, bytes_remaining):
        """用於更新 Tkinter 狀態標籤和進度條"""
        total_size = stream.filesize
        bytes_downloaded = total_size - bytes_remaining
        percentage = (bytes_downloaded / total_size) * 100
        
        # 更新進度條
        self.progress_bar['value'] = percentage
        
        # 更新狀態標籤
        self.status_label.config(text=f"下載中: {percentage:.2f}%...")
        self.master.update_idletasks() # 強制更新 GUI 以顯示最新進度

    def start_download_thread(self):
        """在單獨的執行緒中啟動下載,避免 GUI 凍結"""
        url = self.url_entry.get()
        if not url:
            messagebox.showwarning("警告", "請輸入 YouTube 影片網址!")
            return
        
        self.download_button.config(state=tk.DISABLED) # 禁用按鈕防止重複點擊
        self.status_label.config(text="準備下載...", fg="blue")

        # 創建並啟動新執行緒
        download_thread = threading.Thread(target=self.download_mp3, args=(url,))
        download_thread.start()

# 啟動應用程式
if __name__ == "__main__":
    root = tk.Tk()
    app = YouTubeDownloaderApp(root)
    root.mainloop()

沒有留言:

張貼留言

ESP32 (ESP-IDF in VS Code) MFRC522 + MQTT + PYTHON TKinter +SQLite

 ESP32 (ESP-IDF in VS Code) MFRC522 + MQTT + PYTHON TKinter +SQLite  ESP32 VS Code 程式 ; PlatformIO Project Configuration File ; ;   Build op...