I'm trying to develop a small application for downloading songs from YouTube, with youtube_dl and kivy.

However, when I press the download button, the screen freezes while youtube_dl finishes downloading. Only after the download is finished does the screen become "alive" again.

Is there any way to solve this? I tried threading which worked on pytube but with youtube_dl it doesn't work properly.

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.uix.widget import Widget
from kivy.config import Config
from kivy.core.window import Window
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.lang import Builder
from kivy.base import runTouchApp
from kivy.uix.button import Button
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.dropdown import DropDown
from kivy.uix.image import AsyncImage
from kivy.uix.behaviors import ButtonBehavior
from kivy.properties import ObjectProperty, StringProperty
import requests
import pytube
from kivy.uix.popup import Popup
from kivy.uix.image import Image
from time import sleep
import youtube_dl
import threading
import os
from kivy.utils import get_color_from_hex
from kivy.clock import Clock

Window.fullscreen = False

Config.set('graphics', 'resizable', 1)
Config.set('graphics', 'width', '600')
Config.set('graphics', 'height', '700')
Config.write()

class YoutubeDownloader(BoxLayout):
    link_ = ObjectProperty()  # This is objectProperty which == Url TextInput
    male = ObjectProperty()

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        checkbox_is_active = ObjectProperty(False)
        self.chck_state = 'normal'  # Down if checked Normal if Uncheck
        self.title = '' # Music title
        self.thumbnail_url = '' #Music Image thumbnail url
        self.playlist_urls = [] # This List conaints All Music Urls from playlist
        self.playlist_size = 0
        self.single_url = []
        self.convert_return_value = 0 # if this variable = 1 it means convert finished succesfully
        self.is_playlist = False

    def checkbox_is_clicked(self):
        '''This function Check state of checkbox'''
        x = self.ids.chck_box.state
        self.chck_state = x
        return 1

    def convert(self):
        main_url = self.link_.text
        if self.chck_state == 'normal':
            try:
                self.remove_widget(self.ids.music_name)
                self.remove_widget(self.ids.img_button)
                yt = pytube.YouTube(main_url)
                self.title = yt.title
                self.thumbnail_url = yt.thumbnail_url
                self.single_url = main_url

                music_name_label = self.ids.music_name
                music_asyncImage = self.ids.img_button
                music_asyncImage.source = self.thumbnail_url
                music_name_label.text = self.title
                self.convert_return_value = 1
                self.is_playlist = False

            except:
                popwind = Popup(
                title='Error!', content=Label(
                    text='Please Enter Valid Url or if its playlist\nplease click playlist checkkbutton\nand convert'), size_hint=(
                    0.8, 0.2))
                popwind.open()
                self.convert_return_value = 0

        elif self.chck_state == 'down':
            try:
                self.ids.music_name.text = ''
                self.ids.img_button.source = ''
                playlist = pytube.Playlist(main_url)
                playlist.populate_video_urls()

                self.playlist_urls = playlist.video_urls

                self.playlist_size = len(playlist.video_urls)

                self.ids.music_name.text = 'Playlist size: {}'.format(self.playlist_size)
                music_asyncImage = self.ids.img_button
                music_asyncImage.source = pytube.YouTube(self.playlist_urls[0]).thumbnail_url
                self.convert_return_value = 1
                self.is_playlist = True

            except:
                popwind = Popup(
                title='Error!', content=Label(
                    text='Please Enter Valid Url or if its Single song\nplease unclick playlist checkkbutton\nand convert'), size_hint=(
                    0.8, 0.2))
                popwind.open()
                self.convert_return_value = 0

    def download_mp3(self):
        if self.convert_return_value == 1 and self.is_playlist == False:
            self.ids.music_name.text = 'Download In Progress Please Wait'
            self.ids.img_button.source = ''
            self.ids.img_button.anim_delay = 0
            self.ids.img_button.source = 'download.gif'
            try:
                download = threading.Thread(target=self.download_video_mp3_mp4(self.link_.text, self.title))
                download.start()
            except:
                pass

            # try:
            #     download = threading.Thread(target=self.download_video_mp3_mp4(self.link_.text, 'test download'))
            #     download.start()
            # except:
            #     pass
            self.ids.music_name.text = 'Download Finished succesfully'
            self.ids.img_button.source = 'down_complete.png'

        elif self.convert_return_value == 0:
            popwind = Popup(
            title='Error!', content=Label(
                text='Download is Not Ready!!\nPlease corectly fill all Fields and CheckBoxes'), size_hint=(
                0.8, 0.2))
            popwind.open()

    def download_video_mp3_mp4(self, song_url, song_title): # For single song
        # yt = pytube.YouTube(self.link_.text)
        # yt.streams.first().download()
        #
        # self.ids.music_name.text = 'Download Finished succesfully'
        # self.ids.img_button.source = 'down_complete.png'
        """
        Download a song using youtube url and song title
        """

        outtmpl = song_title + '.%(ext)s'
        ydl_opts = {
            'format': 'bestaudio/best',
            'outtmpl': outtmpl,
            'postprocessors': [
                {'key': 'FFmpegExtractAudio','preferredcodec': 'mp3',
                 'preferredquality': '192',
                },
                {'key': 'FFmpegMetadata'},
            ],
        }

        youtube_dl.YoutubeDL(ydl_opts).extract_info(song_url, download=True)
            # self.ids.music_name.text = 'Download Finished succesfully'
            # self.ids.img_button.source = 'down_complete.png'

    def download_video(self):
        if self.convert_return_value == 1 and self.is_playlist == False:
            pass
        elif self.convert_return_value == 0:
            popwind = Popup(
            title='Error!', content=Label(
                text='Download is Not Ready!!\nPlease corectly fill all Fields and CheckBoxes'), size_hint=(
                0.8, 0.2))
            popwind.open()

class KivyApp(App):
    def build(self):
        self.title = 'Youtube Downloader'

        return YoutubeDownloader()

0 Answers