pythonyoutubepytube

Everything seems to work on its own, but when I put it together it throws RegexMatchError


I am making a program to download music to my PC, it goes straight into download folder. I made the code for python and when I run it, for some reason pytube throws RegexMatchError, however when I test each part of the code on its own it works perfectly fine. Also if possible I'd love feedback because this is basically my first coding experience on Python, so I'd like to learn more!

This is the actual code (DOESN'T WORK):

from pytube import YouTube
from moviepy.editor import *
import eyed3, os, tkinter as tk,time

def Download():
    youtubeObject = YouTube(getLink())
    youtubeObject = youtubeObject.streams.get_highest_resolution()
    try:
        youtubeObject.download(os.path.expanduser('~')+'/Downloads',filename=getName()+'.mp4')
        print("Download is completed successfully")
    except:
        print("An error has occurred")
def Convert():
    video = VideoFileClip(os.path.expanduser('~')+'/Downloads/'+getName()+'.mp4')
    video.audio.write_audiofile(os.path.expanduser('~')+'/Downloads/'+getName()+'.mp3')
    audio = eyed3.load(os.path.expanduser('~')+'/Downloads/'+getName()+'.mp3')
    return(audio)
def getLink():
    link = linkE.get()
    return link
def getName():
    name = nameE.get()
    return name
def getArtist():
    artist = artistE.get()
    return artist
def getAlbum():
    album = albumE.get()
    return album
def Terminate():
    time.sleep(5)
    root.destroy()

root = tk.Tk()
root.title("Music Downloader")

frame = tk.Frame(root,padx=20,pady=20)
frame.pack()

l1 = tk.Label(frame,text="You must fill all queries.")
l1.grid(row=0,columnspan=2,pady=10)
l2 = tk.Label(frame,text="Enter Song YouTube Link:")
l2.grid(row=1,column=0)
l3 = tk.Label(frame,text="Enter Song Name:")
l3.grid(row=2,column=0)
l4 = tk.Label(frame,text="Enter Artist:")
l4.grid(row=3,column=0)
l5 = tk.Label(frame,text="Enter Album Name:")
l5.grid(row=4,column=0)

linkE = tk.Entry(frame)
linkE.grid(row=1,column=1)
nameE = tk.Entry(frame)
nameE.grid(row=2,column=1)
artistE = tk.Entry(frame)
artistE.grid(row=3,column=1)
albumE = tk.Entry(frame)
albumE.grid(row=4,column=1)

b1 = tk.Button(frame,text="Download")
b1.grid(row=5,columnspan=2,pady=10)

Download()

audio = Convert()

audio.tag.title = getName()
audio.tag.artist = getArtist()
audio.tag.album = getAlbum()
audio.tag.save()

Terminate()

root.mainloop()

os.system("taskkill /f /im ffmpeg-win64-v4.2.2.exe")
time.sleep(3)
os.remove(os.path.expanduser('~')+'/Downloads/'+getName()+'.mp4')

(terminate will be changed with another activator so that it only triggers once process is done) (haven't added the root2 part because it doesn't work to begin with)

This is the app code (works just fine, it terminates itself time-based unlike intended after execution):

import tkinter as tk
import time

def getLink():
    link = linkE.get()
    return link
def getName():
    name = nameE.get()
    return name
def getArtist():
    artist = artistE.get()
    return artist
def getAlbum():
    album = albumE.get()
    return album
def printResults():
    time.sleep(2)
    print(getLink()+getName()+getArtist()+getAlbum())
    time.sleep(5)
    root.destroy()

root = tk.Tk()
root.title("Music Downloader")

frame = tk.Frame(root,padx=20,pady=20)
frame.pack()

l1 = tk.Label(frame,text="You must fill all queries.")
l1.grid(row=0,columnspan=2,pady=10)
l2 = tk.Label(frame,text="Enter Song YouTube Link:")
l2.grid(row=1,column=0)
l3 = tk.Label(frame,text="Enter Song Name:")
l3.grid(row=2,column=0)
l4 = tk.Label(frame,text="Enter Artist:")
l4.grid(row=3,column=0)
l5 = tk.Label(frame,text="Enter Album Name:")
l5.grid(row=4,column=0)

linkE = tk.Entry(frame)
linkE.grid(row=1,column=1)
nameE = tk.Entry(frame)
nameE.grid(row=2,column=1)
artistE = tk.Entry(frame)
artistE.grid(row=3,column=1)
albumE = tk.Entry(frame)
albumE.grid(row=4,column=1)

b1 = tk.Button(frame,text="Download",command=lambda:[getLink(),getName(),getArtist(),getAlbum(),printResults()])
b1.grid(row=5,columnspan=2,pady=10)

root.mainloop()

root2 = tk.Tk()

label = tk.Label(root2,text="Process Terminated")
label.pack(padx=50,pady=50)

root2.mainloop()

This last one is the script code (works just fine):

from pytube import YouTube
from moviepy.editor import *
import eyed3, os, time


def Download(link,name):
    youtubeObject = YouTube(link)
    youtubeObject = youtubeObject.streams.get_highest_resolution()
    try:
        youtubeObject.download(os.path.expanduser('~')+'/Downloads',filename=name+'.mp4')
        print("Download is completed successfully")
    except:
        print("An error has occurred")
def Convert(name):
    video = VideoFileClip(os.path.expanduser('~')+'/Downloads/'+name+'.mp4')
    video.audio.write_audiofile(os.path.expanduser('~')+'/Downloads/'+name+'.mp3')
    audio = eyed3.load(os.path.expanduser('~')+'/Downloads/'+name+'.mp3')
    return(audio)

link = input("Enter the YouTube video URL: ")
name = input("Enter Song Name: ")
artist = input("Enter Artist: ")
album = input("Enter Album: ")
Download(link,name)

audio = Convert(name)

audio.tag.title = name
audio.tag.artist = artist
audio.tag.album = album
audio.tag.save()

os.system("taskkill /f /im ffmpeg-win64-v4.2.2.exe")
time.sleep(3)
os.remove(os.path.expanduser('~')+'/Downloads/'+name+'.mp4')

This is the error message:

Traceback (most recent call last):
  File "c:\Users\USUARIO_01\Documents\Camilo\MusicDownloaderApp.py", line 63, in <module>
    Download()
  File "c:\Users\USUARIO_01\Documents\Camilo\MusicDownloaderApp.py", line 6, in Download
    youtubeObject = YouTube(getLink())
                    ^^^^^^^^^^^^^^^^^^
  File "c:\Users\USUARIO_01\AppData\Local\Programs\Python\Python312\Lib\site-packages\pytube\__main__.py", line 71, in __init__ 
    self.video_id = extract.video_id(url)
                    ^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\USUARIO_01\AppData\Local\Programs\Python\Python312\Lib\site-packages\pytube\extract.py", line 133, in video_id 
    return regex_search(r"(?:v=|\/)([0-9A-Za-z_-]{11}).*", url, group=1)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\USUARIO_01\AppData\Local\Programs\Python\Python312\Lib\site-packages\pytube\helpers.py", line 129, in regex_search
    raise RegexMatchError(caller="regex_search", pattern=pattern)
pytube.exceptions.RegexMatchError: regex_search: could not find match for (?:v=|\/)([0-9A-Za-z_-]{11}).*

I've found some solutions on GitHub, however they are 2022 (year) solutions regarding updates, and it involves changing some of the base code of pytube (cypher.py), so since I'm completely new to this I don't wanna screw up. Any other ideas?


Solution

  • Solved, the issue was that Download function was being called before getting inputs, so it tried to pull an empty link (which obviously doesn't work). I solved it by creating an execution function that just calls em on button activation and not suddenly.

    New code:

    from pytube import YouTube
    from moviepy.editor import *
    import eyed3, os, tkinter as tk,time
    
    def Download():
        link = getLink()
        if not link:
            print("Youtube link is required.")
            return
        youtubeObject = YouTube(link)
        youtubeObject = youtubeObject.streams.get_highest_resolution()
        try:
            youtubeObject.download(os.path.expanduser('~')+'/Downloads',filename=getName()+'.mp4')
            print("Download is completed successfully")
        except Exception as e:
            print("An error has occurred: {e}")
    def Convert():
        video = VideoFileClip(os.path.expanduser('~')+'/Downloads/'+getName()+'.mp4')
        video.audio.write_audiofile(os.path.expanduser('~')+'/Downloads/'+getName()+'.mp3')
        audio = eyed3.load(os.path.expanduser('~')+'/Downloads/'+getName()+'.mp3')
        return(audio)
    def getLink():
        link = linkE.get()
        return link
    def getName():
        name = nameE.get()
        return name
    def getArtist():
        artist = artistE.get()
        return artist
    def getAlbum():
        album = albumE.get()
        return album
    def Execute():
        Download()
        audio = Convert()
        if audio:
            audio.tag.title = getName()
        audio.tag.artist = getArtist()
        audio.tag.album = getAlbum()
        audio.tag.save()
        Terminate()
    def Terminate():
        time.sleep(5)
        name = getName()
        root.destroy()
        time.sleep(1)
        os.system("taskkill /f /im ffmpeg-win64-v4.2.2.exe")
        time.sleep(1)
        os.remove(os.path.expanduser('~')+'/Downloads/'+name+'.mp4')
        TermMsg()
    def TermMsg():
        root = tk.Tk()
        label = tk.Label(root,text="Process Completed.",padx=50,pady=50)
        label.pack()
        root.mainloop()
    
    root = tk.Tk()
    root.title("Music Downloader")
    
    frame = tk.Frame(root,padx=20,pady=20)
    frame.pack()
    
    l1 = tk.Label(frame,text="You must fill all queries.")
    l1.grid(row=0,columnspan=2,pady=10)
    l2 = tk.Label(frame,text="Enter Song YouTube Link:")
    l2.grid(row=1,column=0)
    l3 = tk.Label(frame,text="Enter Song Name:")
    l3.grid(row=2,column=0)
    l4 = tk.Label(frame,text="Enter Artist:")
    l4.grid(row=3,column=0)
    l5 = tk.Label(frame,text="Enter Album Name:")
    l5.grid(row=4,column=0)
    
    linkE = tk.Entry(frame)
    linkE.grid(row=1,column=1)
    nameE = tk.Entry(frame)
    nameE.grid(row=2,column=1)
    artistE = tk.Entry(frame)
    artistE.grid(row=3,column=1)
    albumE = tk.Entry(frame)
    albumE.grid(row=4,column=1)
    
    b1 = tk.Button(frame,text="Download",command=Execute)
    b1.grid(row=5,columnspan=2,pady=10)
    
    root.mainloop()
    

    I also added some failsafes, however I think they're useless anyways for this very particular scenario and didn't finish adding them, might in the future, but isn't important for solution.