Youtube Video Downloader using Python Django
Tags: webdev, django, python, beginners
Published: 2022-02-06 08:57:21

Last week, I found this cool python module named `pytube` which seems interesting to me. For those of you who don't know, `pytube` module is **_built for downloading youtube videos for free_**. After knowing its fundamentals and writing a simple python script, I try to make a Django app out of it. Here's how it is done.

***
###1. Install the Requirements 
First, let's install the tools we're going to use in this app:
```python
pip install django
pip install pytube
```
___
###2. Set-up the Environment
We need to make a project first. After making a directory for it, in our terminal again, run:
```
~/michael/YT-Saver$
# django-admin startproject <project name> .
django-admin startproject base .
# python3 manage.py startapp <app name>
python3 manage.py startapp app
```
Now let's configure our Django app in our Django project by listing our app's name in `base/settings.py/INSTALLED_APPS` so the project now can access the app:
```python
# base/settings.py
INSTALLED_APPS = [
	..... ,
	'app/apps/AppConfig',
]
```
Next, create a `urls.py` inside `app`. To connect it in our `base/urls.py`:
```python
# base/urls.py
from django.urls import path,include

urlpatterns = [
	..... ,
	path('', include('app.urls')),
]
```
___
###3. Create Views
Let's start our code by making the main heart of our app, the **_views_**. On our `app/views.py`, add the imports:
```python
# base/views.py
from django.views.generic import View
from pytube import Youtube
from django.shortcuts import render,redirect
```
And now write the main code. Let's make a class for it that takes a **_url_** but no errors if you didn't give any and returns a page:
```python
class home(View):
    def __init__(self,url=None):
        self.url = url
	    def get(self,request):
        return render(request,'app/home.html')    
```
Next step, add a new function in it for fetching the video and for downloading it:
```python
class home(View):
	....

	def post(self,request):
		# for fetching the video
		if request.POST.get('fetch-vid'):
			self.url = request.POST.get('given_url')
			video = YouTube(self.url)
			vidTitle,vidThumbnail = video.title,video.thumbnail_url
			qual,stream = [],[]
			for vid in video.streams.filter(progressive=True):
				qual.append(vid.resolution)
				stream.append(vid)
			context = {'vidTitle':vidTitle,'vidThumbnail':vidThumbnail,
						'qual':qual,'stream':stream,
						'url':self.url}
			return render(request,'app/home.html',context)

		# for downloading the video
		elif request.POST.get('download-vid'):
			self.url = request.POST.get('given_url')
			video = YouTube(self.url)
			stream = [x for x in video.streams.filter(progressive=True)]
			video_qual = video.streams[int(request.POST.get('download-vid')) - 1]
video_qual.download(output_path='../../Downloads')
			return redirect('home')

		return render(request,'app/home.html')

```
So, Are should views looks like this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fu8xjg7uqiyflr01aw11.png)
___
###4. Create Template
As we see above, we configure a `home.html` file. So now where, going to create it. Make a directory first inside our `app` directory named `templates` and another one inside it, named after our app which is `app` where we store our 'home.html' file.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/juehw8sjiyi1s1mk0ang.png)
'app/template/app/home.html':
```html
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>YT Saver</title>
</head>
<body style="align-items: center;text-align: center;height: fit-content;border: 3px solid green;">
    <h2>YT SAVER</h2>
    <b><p style="color: coral;">Save your favorite youtube videos for free!!</p></b>
    <form method="post" action="">
        {% csrf_token %}
        <!-- for fetching the video -->
        <input type="text" name="given_url" value="{{url}}" placeholder="enter url..">
        <button type="submit" name="fetch-vid" value="fetch-vid">Proceed</button>

        <br>
            <h3>{{vidTitle}}</h3>
            <img src="{{vidThumbnail}}"/>
        <br>

        <!-- for downloading the video -->
        {% for x in stream %}
            {{x.resolution}} <button type="submit" name="download-vid" value="{{forloop.counter}}">Download</button>|
        {% endfor %}
        <br><br>
    </form>
</body>
</html>
```
***
###5. Create Urls
Since we already set up our `base/urls.py` above, now we create our `app/urls.py`.:
```python
from django.urls import path
from . import views

urlpatterns = [
	path('',views.home.as_view(),name="home"),
]
```
***
###6. Test the app
And now, we can finally test our app. Let's run the app, open the terminal, and type:
```
~/michael/YT-Saver$
python manage.py runserver
```
Now, head to your browser and type for `localhost:8000` or 'CRTL + Left click' the link at the terminal.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8o9tq9k7qn6pmmoxqtxb.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e7lqdil4yomayo8sy4a5.png)

**Note:** If you're having trouble with the `Pytube` module about the `AttributeError: 'NoneType' object has no attribute 'span'`, here are some discussions in [Stack Overflow](https://stackoverflow.com/questions/70060263/pytube-attributeerror-nonetype-object-has-no-attribute-span "AttributeError") and [Github](https://github.com/pytube/pytube/issues/1218 "AttributeError") that might be helpful for you.
___
***
Well if everything works fine, you can now enjoy downloading youtube videos for free, and access them anytime you want. For more information about the `pytube` module, click [here](https://pytube.io/en/latest/ "Pytube documentation"). Have a nice day!!