Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stop youtube-dl download inside a thread using Python 3

I have a function that downloads videos from specific URLs and I launch this function through a thread to avoid GUI freezing, but I want a function to stop or pause the download. How to do this? Here is the code:

def download_videos(self):
     ydl1 = youtube_dl.YoutubeDL(self.get_opts())
     if self.get_Urls().__len__() > 0:
         ydl1.download(self.get_Urls())

def downloadVideoThrd(self):
    self.t1 = threading.Thread(target=self.download_videos())
    self.t1.start()
like image 390
zafer Avatar asked Nov 16 '22 21:11

zafer


1 Answers

You can use these two options. Use multiprocessing library instead threading or raise SystemExit exception in the subthread

Note: When i tested youtube-dl, it is resume downloading from where it is left. That's why when we start to download same url, youtube-dl will resume, but downloaded file need to be in the filesystem

Here is the first option, in this solution, we not use thread, we use subprocess because we can send any signal to the subprocess and handle this signal whatever we want.

import multiprocessing
import time
import ctypes,signal,os
import youtube_dl

class Stop_Download(Exception): # This is our own special Exception class
    pass

def usr1_handler(signum,frame): # When signal comes, run this func
    raise Stop_Download

def download_videos(resume_event):
     signal.signal(signal.SIGUSR1,usr1_handler)

     def download(link):
         ydl1 = youtube_dl.YoutubeDL()
         ydl1.download([link])

     try:
         download(link)

     except Stop_Download: #catch this special exception and do what ever you want
         print("Stop_Download exception")
         resume_event.wait() # wait for event to resume or kill this process by sys.exit()
         print("resuming")
         download(link)

def downloadVideoThrd():
    resume_event=multiprocessing.Event()
    p1 = multiprocessing.Process(target=download_videos,args=(resume_event,))
    p1.start()
    print("mp start")
    time.sleep(5)
    os.kill(p1.pid,signal.SIGUSR1) # pause the download
    time.sleep(5)
    down_event.set() #resume downlaod
    time.sleep(5)
    os.kill(p1.pid,signal.SIGUSR2) # stop the download

downloadVideoThrd()

Here is the second solution, you can also check this for more detail about killing the thread. We will raise a SystemExit exception in the subthread by main thread. We can both stop or pause thread. To pause thread you can use threading.Event() class. To stop the thread(not process) you can use sys.exit()

import ctypes,time, threading
import youtube_dl,

def download_videos(self):
    try:
        ydl1 = youtube_dl.YoutubeDL(self.get_opts())
        if self.get_Urls().__len__() > 0:
            ydl1.download(self.get_Urls())
    except SystemExit:
        print("stopped")
        #do whatever here

def downloadVideoThrd(self):
    self.t1 = threading.Thread(target=self.download_videos)
    self.t1.start()
    time.sleep(4)     
    """
    raise SystemExit exception in self.t1 thread
    """    
    ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(self.t1.ident),
                                            ctypes.py_object(SystemExit))
like image 193
Veysel Olgun Avatar answered Dec 28 '22 08:12

Veysel Olgun