DEV Community

Cover image for Online Video Sharing Website - Django Project
Madhuban Khatri
Madhuban Khatri

Posted on

Online Video Sharing Website - Django Project

Hello Developers,
Do you use Online Video Sharing Website like YouTube or Vimeo?
And how to create websites like them?

Here is the example of Online Video Sharing Website:-

I am providing the source code of this project and give me feedback to this website. In this project , I disabled Deactivate Account section of this project so write a code for this section and send it to me.

On this website User can:-

  • Create Account
  • Watch Videos after Login
  • Subscribe others
  • Like the videos
  • Commenting them
  • See Dashboard where users can analysis their videos.
  • Update their Profiles
  • Deactivate Account (Write the Code for this section and send it to me)

You have to create a Django Project using this command.

django-admin startproject video_sharing
Enter fullscreen mode Exit fullscreen mode

Create an App in this project

python manage.py startapp main
Enter fullscreen mode Exit fullscreen mode

settings.py

# Application definition

INSTALLED_APPS = [
    ...
    'main', #add your app here

]

STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'main/static')
]



# Media Settings
MEDIA_ROOT = 'D:\\django_projects\\video_sharing\\main\\static\\media'
MEDIA_URL = 'media/'

Enter fullscreen mode Exit fullscreen mode

project/urls.py

from django.contrib import admin
from django.urls import path, include

from django.conf import settings
from django.conf.urls.static import static

admin.site.site_header = "Viral Video Admin Panel"
admin.site.site_title = "Viral Video Admin Portal"
admin.site.index_title = "Welcome to Video Viral!"

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('main.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Enter fullscreen mode Exit fullscreen mode

main/models.py

from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class VideoPost(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=100)
    desc = models.TextField()
    video_file = models.FileField(upload_to='videos/')
    thumbnail = models.ImageField(upload_to='videos/thumbnail/', default='none')
    category = models.CharField(max_length=50, default='none')
    pub_date = models.DateField(auto_now_add=True)
    likes = models.ManyToManyField(User, related_name='likes')
    video_views = models.ManyToManyField(User, related_name='video_views')

    def __str__(self):
        return self.title




class UserData(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    about = models.TextField()
    profile_pic = models.ImageField(upload_to='pic/', default='pic/default.jpg')
    subscribers = models.ManyToManyField(User, related_name='subscribers')




class Comment(models.Model):
    post = models.ForeignKey(VideoPost, on_delete=models.CASCADE)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    comment = models.CharField(max_length=300)

    def __str__(self):
        return self.user.username

Enter fullscreen mode Exit fullscreen mode

main/admin.py

from django.contrib import admin
from .models import VideoPost, Comment, UserData

# Register your models here.
admin.site.register(VideoPost)
admin.site.register(Comment)
admin.site.register(UserData)
Enter fullscreen mode Exit fullscreen mode

Add Models as Tables in Django Database like this,

python manage.py makemigrations
python manage.py migrate
Enter fullscreen mode Exit fullscreen mode

You have to create a super user to access Database like this,

python manage.py createsuperuser
Enter fullscreen mode Exit fullscreen mode

main/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('', views.home, name='home'),
    path('video/<int:video_id>/', views.watch_video, name='watch_video'),
    path('video/add_comment/', views.add_comment, name='add_comment'),
    path('video/add_like/<int:video_id>/', views.add_like, name='add_like'),
    path('<str:session_username>/profile/', views.profile, name='profile'),
    path('<str:session_username>/dashboard/', views.dashboard, name='dashboard'),
    path('add_subscriber/<viewer>/', views.add_sub, name='add_subscriber'),
    path('upload/', views.upload_video, name='upload'),
    path('edit_video/<int:video_id>', views.edit_video, name='edit_video'),
    path('delete_video/', views.delete_video, name='delete_video'),
    path('update_details/', views.update_details, name='update_details'),
    path('signup/', views.signup, name='signup'),
    path('login/', views.user_login, name='login'),
    path('logout/', views.user_logout, name='logout'),

    path('search/', views.search, name='search'),
]
Enter fullscreen mode Exit fullscreen mode

main/views.py

from django.shortcuts import render, redirect
from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
from django.urls import reverse_lazy, reverse
from django.contrib.auth.models import User
from .models import VideoPost, Comment, UserData
from django.contrib.auth import authenticate, login, logout
from django.contrib import messages
from django.core.exceptions import ObjectDoesNotExist

# Create your views here.
def home(request):
    if not request.user.is_authenticated:
        demo_videos = VideoPost.objects.all().order_by('-id')[:5]
        params = {'videos': demo_videos}
        return render(request, 'welcome.html', params)
    else:
        all_videos = VideoPost.objects.all().order_by('-id')
        params = {'all_videos': all_videos}
        return render(request, 'home.html', params)

def search(request):
    query = request.GET['search_query']
    try:
        user_obj = User.objects.filter(username__icontains=query)
    except:
         user_obj = User.objects.none()
    params = {'user_obj': user_obj}

    return render(request, 'search_page.html', params)

def upload_video(request):
    if request.method == 'POST':
        title = request.POST['title']
        desc = request.POST['desc']
        video_file = request.FILES['fileName']
        thumb_nail = request.FILES['thumbnail_img']
        cate = request.POST['category']
        user_obj = User.objects.get(username=request.user)
        upload_video = VideoPost(user=user_obj, title=title, desc=desc, video_file=video_file, thumbnail=thumb_nail, category=cate)
        upload_video.save()
        messages.success(request, 'Video has been uploaded.')

    return render(request, 'upload_video.html')


def watch_video(request, video_id):
    try:
        video_obj = VideoPost.objects.get(id=video_id)
    except ObjectDoesNotExist:
        return render(request, '404.html')
    try:
        session_obj = User.objects.get(username=request.user.username)
    except:
        messages.warning(request, 'You are not login to watch this video.')
        return redirect('home')

    video_comments = Comment.objects.filter(post=video_obj).order_by('-id')


    # Increase Views of Video if User visit this page

    if request.user not in video_obj.video_views.all():
        video_obj.video_views.add(request.user)



    # Increase Likes of Video if User like this video

    is_liked = False
    if session_obj in video_obj.likes.all():
        is_liked = True
    else:
        is_liked = False
    params = {'video':video_obj, 'comments': video_comments, 'is_liked':is_liked}
    return render(request, 'watch_video.html', params)





def add_comment(request):
    if request.method == 'GET':
        video_id = request.GET['video_id']
        comment = request.GET['comment_text']
        video_obj = VideoPost.objects.get(id=video_id)
        session_obj = User.objects.get(username=request.user.username)
        video_comments = Comment.objects.filter(post=video_obj).order_by('-id')
        create_comment = Comment.objects.create(post=video_obj, user=session_obj, comment=comment)
        create_comment.save()

    return JsonResponse({'comment':create_comment.comment, 'count_comments':video_comments.count()})





def add_like(request, video_id):
    user_obj = User.objects.get(username=request.user.username)
    video_obj = VideoPost.objects.get(id=video_id)
    is_liked = False
    if user_obj in video_obj.likes.all():
        video_obj.likes.remove(user_obj)
        is_liked = True
    else:
        video_obj.likes.add(user_obj)
        is_liked = False
    return JsonResponse({'is_liked':is_liked,'likes_count':video_obj.likes.all().count()})




def profile(request, session_username):
    try:
        session_obj = User.objects.get(username=session_username)
    except ObjectDoesNotExist:
        return render(request, '404.html')
    profile_data = UserData.objects.get_or_create(user=session_obj)[0]
    user_posts = VideoPost.objects.filter(user=session_obj).order_by('-id')


    # Category wise Posts

    video_cat_science = VideoPost.objects.filter(user=session_obj, category='Science & Techanology').order_by('-id')
    video_cat_blogs = VideoPost.objects.filter(user=session_obj, category='Blogs').order_by('-id')
    video_cat_fashion = VideoPost.objects.filter(user=session_obj, category='Fashion').order_by('-id')
    video_cat_education = VideoPost.objects.filter(user=session_obj, category='Education').order_by('-id')
    video_cat_food = VideoPost.objects.filter(user=session_obj, category='Food').order_by('-id')

    subscribed = False
    if request.user in profile_data.subscribers.all():
        subscribed = True
    else:
        subscribed = False
    params = {'subscribed':subscribed,'session_obj':session_obj,'user_data':profile_data, 'videos': user_posts, 'sci': video_cat_science, 'blogs': video_cat_blogs, 'fashion': video_cat_fashion, 'edu':video_cat_education, 'food': video_cat_food}
    return render(request, 'profile.html', params)

def dashboard(request, session_username):
    user_videos = VideoPost.objects.filter(user__username=request.user.username).order_by('-id')
    user_data = UserData.objects.get_or_create(user=User.objects.get(username=request.user.username))[0]
    user_video_likes = 0
    user_videos_views = 0

    for video in user_videos:
        user_video_likes += video.likes.count()
        user_videos_views += video.video_views.count()


    params = {'videos': user_videos, 'user_data': user_data, 'total_likes':user_video_likes, 'total_views': user_videos_views}
    return render(request, 'dashboard.html', params)


def add_sub(request, viewer):
    viewer_obj = UserData.objects.get_or_create(user=User.objects.get(username=viewer))[0]
    subscriber_obj = User.objects.get(username=request.user.username)

    subscribed = False
    if subscriber_obj in viewer_obj.subscribers.all():
        viewer_obj.subscribers.remove(subscriber_obj)
        subscribed = True
    else:
        viewer_obj.subscribers.add(subscriber_obj)
        subscribed = False

    return JsonResponse({'is_subscribed': subscribed, 'viewer_obj':viewer_obj.subscribers.all().count()})



def edit_video(request, video_id):
    if request.method == 'POST':
        new_title = request.POST['new_title']
        new_desc = request.POST['new_desc']
        new_cate = request.POST['new_cate']

        video_obj = VideoPost.objects.get(id=video_id)
        video_obj.title = new_title
        video_obj.desc = new_desc
        video_obj.category = new_cate
        video_obj.save()

        return HttpResponseRedirect(reverse('dashboard', args=[str(request.user.username)]))
    else:
        return HttpResponse('get')




def update_details(request):
    if request.method == 'POST':
        user_data = UserData.objects.get(user=request.user)

        aboutText = request.POST['about_text']
        try:
            imgFile = request.FILES['img_field']
            if imgFile:
                user_data.profile_pic = imgFile

        except:
            print('some error occured')


        user_data.about = aboutText
        user_data.save()

        return HttpResponseRedirect(reverse('dashboard', args=[str(request.user.username)]))
    return redirect('dashboard')



def delete_video(request):
    if request.method == 'GET':
        vid = request.GET['videoId']
        video_obj = VideoPost.objects.get(id=vid)
        video_obj.delete()

        user_videos = VideoPost.objects.filter(user__username=request.user.username)
        user_video_likes = 0
        for video in user_videos:
            user_video_likes += video.likes.count()
        return JsonResponse({'video_id': vid, 'videosCount': user_videos.count(), 'videosLikes': user_video_likes})
    else:
        return JsonResponse({'status': 'not ok'})




def signup(request):
    if request.method == 'POST':
        first_name = request.POST['fname']
        last_name = request.POST['lname']
        mail = request.POST['mail']
        pwd = request.POST['pwd']
        new_user = User.objects.create_user(f'{first_name.lower()}123', mail, pwd)
        new_user.first_name = first_name
        new_user.last_name = last_name
        new_user.save()
        messages.success(request, 'Account has been created successfully.')
    return redirect('home')


def user_login(request):
    if not request.user.is_authenticated:

        if request.method == 'POST':
            uname = request.POST['uname']
            pwd = request.POST['pwd']

            check_user = authenticate(username = uname, password = pwd)
            if check_user is not None:
                login(request, check_user)
                return redirect('home')
            else:
                messages.warning(request, 'Invalid Username or Password.')
                return redirect('home')
        return redirect('home')

    else:
        return redirect('home')



def user_logout(request):
    logout(request)
    return redirect('home')

Enter fullscreen mode Exit fullscreen mode

Templates Work

Create a templates folder in main app and create some HTML templates in this folder.

base.html

<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!--Animation-->
     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"/>

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <title>ViralVideo</title>
  </head>
  <body>

{% load static %}
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
      <div class="container-fluid">
        <a class="navbar-brand" href="{% url 'home' %}">ViralVideo</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarSupportedContent">
          <ul class="navbar-nav me-auto mb-2 mb-lg-0">
            <li class="nav-item">
              <a class="nav-link active" aria-current="page" href="{% url 'home' %}">Home</a>
            </li>
            <form class="d-flex" action="{% url 'search' %}" method="get">
              <input class="form-control me-2 mx-4" name="search_query" style="width: 700px;" type="search" placeholder="Search User" aria-label="Search">
              <button class="btn btn-outline-success" type="submit">Search</button>
            </form>
          </ul>

          {% if not user.is_authenticated %}
            <button class="btn btn-outline-success mx-3" data-bs-toggle="modal" data-bs-target="#loginModal">Login</button>
            <button class="btn btn-outline-warning" data-bs-toggle="modal" data-bs-target="#signupModal">Signup</button>
          {% else %}
          <div class="btn-group mx-4">
            <button type="button" class="btn btn-secondary dropdown-toggle" data-bs-toggle="dropdown" data-bs-display="static" aria-expanded="false">
              @{{request.user}}
            </button>
            <ul class="dropdown-menu dropdown-menu-end dropdown-menu-lg-start">
              <a href="{% url 'profile' request.user.username %}" style="text-decoration:none;"><li><button class="dropdown-item" type="button">Your Channel</button></li></a>
              <a href="{% url 'dashboard' request.user.username %}" style="text-decoration:none;"><li><button class="dropdown-item" type="button">Dashboard</button></li></a>
              <a href="{% url 'upload' %}" style="text-decoration:none;"><li><button class="dropdown-item" type="button">Upload Video</button></li></a>
              <li><hr class="dropdown-divider"></li>
              <a href="{% url 'logout' %}" style="text-decoration:none;"><li class="text-danger"><button class="dropdown-item text-danger" type="button">Logout</button></li></a>
            </ul>
          </div>
          {% endif %}
        </div>
      </div>
    </nav>

    {% if messages %}
      {% for message in messages %}
      <div class="alert alert-{{message.tags}} alert-dismissible fade show" role="alert">
        <strong>{{message}}</strong>
        <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
      </div>
      {% endfor %}
    {% endif %}

    {% block body%}{% endblock %}

<!-- Option 1: Bootstrap Bundle with Popper -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script>


  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

welcome.html

{% extends 'base.html' %}
{% load static %}

{% block body %}

    <!--Signup Modal-->
    <div class="modal fade" id="signupModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
      <div class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title" id="exampleModalLabel">Sign Up</h5>
            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
          </div>
          <div class="modal-body">
            <form action="{% url 'signup' %}" method="post">
              {% csrf_token %}
              <div class="mb-3">
                <label for="fname" class="form-label">First Name</label>
                <input type="text" class="form-control" id="fname" name="fname">
              </div>
              <div class="mb-3">
                <label for="lname" class="form-label">Last Name</label>
                <input type="text" class="form-control" id="lname" name="lname">
              </div>
              <div class="mb-3">
                <label for="exampleInputEmail1" class="form-label">Email address</label>
                <input type="email" class="form-control" id="exampleInputEmail1" name="mail" aria-describedby="emailHelp">
              </div>
              <div class="mb-3">
                <label for="exampleInputPassword1" class="form-label">Password</label>
                <input type="password" class="form-control" name="pwd" id="exampleInputPassword1">
              </div>
               <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
                <button type="submit" class="btn btn-primary">Sign Up</button>
              </div>
            </form>
          </div>

        </div>
      </div>
    </div>

    <!--Login Modal-->
    <div class="modal fade" id="loginModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
      <div class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title" id="exampleModalLabel">Login</h5>
            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
          </div>
          <div class="modal-body">
            <form action="{% url 'login' %}" method="post">
              {% csrf_token %}
              <div class="mb-3">
                <label for="exampleInputEmail1" class="form-label">User Name</label>
                <input type="text" class="form-control" name="uname" id="exampleInputEmail1" aria-describedby="emailHelp">
              </div>
              <div class="mb-3">
                <label for="exampleInputPassword1" class="form-label">Password</label>
                <input type="password" class="form-control" name="pwd" id="exampleInputPassword1">
              </div>
              <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
                <button type="submit" class="btn btn-primary">Login</button>
              </div>

            </form>
          </div>

        </div>
      </div>
    </div>

    <!--Welcome Content-->
    <div class="container-fluid my-2">
      <div class="card bg-success text-white" style="height: 400px;">
        <img src="{% static 'img/bg.jpg' %}" class="card-img" style="height: 400px;" alt="...">

      </div>
    </div>

    <div class="container my-3">
      {% for video in videos %}
      <div class="card mb-3" style="max-width: 540px;">
        <div class="row g-0">
          <div class="col-md-4">
            <img src="{% static video.thumbnail.url %}" width="208rem" alt="image">
          </div>
          <div class="col-md-8m mx-4 w-50">
            <div class="card-body">
              <a href="{% url 'watch_video' video.id %}" style="text-decoration: none;">
                <h5 class="card-title">{{video.title}}</h5>
              </a>
              <p class="card-text">{{video.desc}}</p>
              <p class="card-text"><small class="text-muted">{{video.pub_date}}</small></p>
            </div>
          </div>
        </div>
      </div>
      {% endfor %}
    </div>



{% endblock %}
Enter fullscreen mode Exit fullscreen mode

home.html

{% extends 'base.html' %}
{% load static %}

{% block body %}
    <div class="container-fluid">
      <div class="card bg-light text-white">
        <img src="{% static 'img/bg2.jpg' %}" class="card-img" style="height: 350px;" alt="...">
        <div class="card-img-overlay">
          <h2 style="margin-top: 150px; margin-left: 350px;">Viral Your Video Here and get more audience</h2>
        </div>
      </div>
    </div>

    <div class="container">
      <div class="row my-4">

        {% for video in all_videos %}
        <div class="col-3">

          <a href="{% url 'watch_video' video.id %}" style="text-decoration: none;">
            <img src="{% static video.thumbnail.url %}" class="w-100">
          </a>
          <a href="{% url 'watch_video' video.id %}" style="text-decoration: none;">
            <h6>{{video.title}}</h6>  
          </a>
          <span class="text-muted">{{video.video_views.all.count}} views • {{video.pub_date}}</span>

        </div>
        {% endfor %}


      <hr>

    </div>


{% endblock %}    
Enter fullscreen mode Exit fullscreen mode

upload.html

{% extends 'base.html' %}
{% load static %}

{% block body%}

<div class="container border py-4 my-4 w-75">
    <form action="{% url 'upload' %}" method="post" enctype="multipart/form-data">
        {% csrf_token %}
        <div class="mb-3">
            <label for="title" class="form-label">Title</label>
            <input type="text" name="title" class="form-control" id="title" required>
        </div>

        <div class="mb-3">
            <label for="desc" class="form-label">Description</label>
            <textarea class="form-control" name="desc" id="desc" style="height: 200px;" required></textarea>
        </div>

        <div class="mb-3">
            <label for="filename" class="form-label">Select Video File</label>
            <input type="file" name="fileName" class="form-control" id="filename" accept="video/*" required>
        </div>

        <div class="mb-3">
            <label for="thumb" class="form-label">Select Thumbnail</label>
            <input type="file" name="thumbnail_img" class="form-control" id="thumb" accept="image/*" required>
        </div>

        <div class="mb-3">
            <label for="title" class="form-label">Select Category</label>
            <select class="form-control" name="category">
                <option>Science & Techanology</option>
                <option>Fashion</option>
                <option>Food</option>
                <option>Education</option>
                <option>Blogs</option>
            </select>
        </div>


        <button type="submit" class="btn btn-primary">Upload</button>
    </form>
</div>

{% endblock %}
Enter fullscreen mode Exit fullscreen mode

watch_video.html

{% extends 'base.html' %}
{% load static %}

{% block body %}
<div class="row">
  <div class="col-8">
    <div class="container py-2 my-4 w-auto" style="position: absolute; left:100px;">
      <div id="carouselExampleSlidesOnly" class="carousel slide" data-bs-ride="carousel">
        <div class="carousel-inner">
          <div class="carousel-item active">

            <video width="750" controls>
              <source src="{% static video.video_file.url %}" type="video/mp4">
            </video>

            </div>

          </div>
        </div>

        <div class="card w-auto">
          <div class="card-body">
            <h5 class="card-title">{{video.title}}</h5>
            <span class="badge rounded-pill bg-info text-dark">{{video.category}}</span>
            <div class="row">
              <div class="col-8">
                <span class="text-muted">{{video.video_views.all.count}} views • {{video.pub_date}}</span>
              </div>
              <div class="col">

              {% if is_liked %}

              <a id="like_btn" class="btn btn-outline-danger mx-3"><span id="count_likes">{{video.likes.all.count}}</span>&nbsp&nbsp<span id="like_icon"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-heart-fill" viewBox="0 0 16 16">
                <path fill-rule="evenodd" d="M8 1.314C12.438-3.248 23.534 4.735 8 15-7.534 4.736 3.562-3.248 8 1.314z"/>
              </svg>
              </span></a>
              {% else %}

              <a id="like_btn" class="btn btn-outline-danger mx-3"><span id="count_likes">{{video.likes.all.count}}</span>&nbsp&nbsp<span id="like_icon"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-heart" viewBox="0 0 16 16">
                <path d="M8 2.748l-.717-.737C5.6.281 2.514.878 1.4 3.053c-.523 1.023-.641 2.5.314 4.385.92 1.815 2.834 3.989 6.286 6.357 3.452-2.368 5.365-4.542 6.286-6.357.955-1.886.838-3.362.314-4.385C13.486.878 10.4.28 8.717 2.01L8 2.748zM8 15C-7.333 4.868 3.279-3.04 7.824 1.143c.06.055.119.112.176.171a3.12 3.12 0 0 1 .176-.17C12.72-3.042 23.333 4.867 8 15z"/>
              </svg>
              </span></a>
              {% endif %}

          </div>
        </div>
      </div>
    </div>

    <div class="card my-2">
      <div class="card-header">
          <h6><b>DESCRIPTION</b></h6>
      </div>

      <div class="card-body">
        <pre><p>{{video.desc}}</p></pre>
      </div>
    </div>

  </div>
</div>



<div class="col-3" style="margin-left: 0px; width: 400px;">

  <div class="container my-3">
    <h3>Up Next</h3>

    <div class="list-group my-2">
      {% for v in video.user.videopost_set.all %}
      <a href="{% url 'watch_video' v.id %}" class="list-group-item list-group-item-action" aria-current="true">
        <div class="d-flex w-100 justify-content-between">
          <h5 class="mb-1">{{v.title}}</h5>
          <small>{{v.pub_date}}</small>
        </div>
        <p class="mb-1">{{v.desc}}</p>
        <small>Donec id elit non mi porta.</small>
      </a>
      {% endfor %}


    </div>

  </div>

  <div class="container my-4">
    <!--Comments of this video-->
    <div class="accordion accordion-flush" id="accordionFlushExample">
      <div class="accordion-item">
        <h2 class="accordion-header" id="flush-headingTwo">
          <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#flush-collapseTwo" aria-expanded="false" aria-controls="flush-collapseTwo">
            <b>COMMENTS (<span id='count_comment'>{{comments.count}}</span>)</b>
          </button>
        </h2>
        <div id="flush-collapseTwo" class="accordion-collapse collapse" aria-labelledby="flush-headingTwo" data-bs-parent="#accordionFlushExample">
          <div class="container my-2">
            <ul class="list-group" id="menu">
              {% for comment in comments %}
              <b>{{comment}}</b>  
              <li class="list-group-item">{{comment.comment}}</li>
              {% endfor %}
            </ul>
          </div>
          <div class="accordion-body">
            <form id="my_form">
              <textarea class="form-control" name="comment" id="comment" placeholder="Write your comment..."></textarea>
              <input class="btn btn-outline-success my-3" id="send_btn" type="submit" value="Comment">
            </form>

          </div>
        </div>
      </div>

    </div>
  </div>

</div>
</div>


<script type="text/javascript">

var send_btn = $('#send_btn');
send_btn.on('click', function(event){
  event.preventDefault();
  var comment = $('#comment').val();
  var ul_menu = $('#menu');
  var count_comment = $('#count_comment');

  $.ajax({
    type: 'GET',
    url: '{% url "add_comment" %}',
    data: {comment_text: comment, video_id: '{{video.id}}'},
    dataType: 'json',
    success: function(data){
      if(data.comment)
      {
        var comment_res = data.comment;
        var li_html = "<b>{{request.user}}</b><li class='list-group-item'>"+comment_res+"</li>";

        ul_menu.prepend(li_html);
        count_comment.text(data.count_comments);
        $('#my_form').trigger('reset');

      }

    }

  });
});
</script>


<script type="text/javascript">
var like_btn = $('#like_btn');
like_btn.on('click', function(event){
  event.preventDefault();
  var count_likes = $('#count_likes');
  var like_icon = $('#like_icon');

  $.ajax({
    url: '{% url "add_like" video.id %}',
    data: {},
    dataType: 'json',
    success: function(data){
      if(data.is_liked)
      {
        like_icon.html('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-heart" viewBox="0 0 16 16"><path d="M8 2.748l-.717-.737C5.6.281 2.514.878 1.4 3.053c-.523 1.023-.641 2.5.314 4.385.92 1.815 2.834 3.989 6.286 6.357 3.452-2.368 5.365-4.542 6.286-6.357.955-1.886.838-3.362.314-4.385C13.486.878 10.4.28 8.717 2.01L8 2.748zM8 15C-7.333 4.868 3.279-3.04 7.824 1.143c.06.055.119.112.176.171a3.12 3.12 0 0 1 .176-.17C12.72-3.042 23.333 4.867 8 15z"/></svg>');
        count_likes.text(data.likes_count);
      }
      else
      {

        like_icon.html('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-heart-fill" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8 1.314C12.438-3.248 23.534 4.735 8 15-7.534 4.736 3.562-3.248 8 1.314z"/>');
       count_likes.text(data.likes_count);
     }

   }
 });
});

</script>

{% endblock %}
Enter fullscreen mode Exit fullscreen mode

profile.html

{% extends 'base.html' %}
{% load static %}

{% block body %}
<!--Profile Image and Name-->
<div class="container my-4">
  <div class="container">
    <div class="row">
      <div class="col-3">
        <img src="{% static user_data.profile_pic.url %}" class="img-thumbnail" style="width: 150px;height: 200px;"> 

      </div>
      <div class="col">
        <h2 style="margin-top: 80px;" >{{session_obj.first_name}} {{session_obj.last_name}}</h2>
        <span class="text-muted"><span class="text-muted" id="count">{{user_data.subscribers.count}}</span> Subscribers</span>
        {% if session_obj != request.user %}
        {% if subscribed %}
        <a id="sub_btn" class="btn btn-outline-danger mx-3">Unsubscribe</a>
        {% else %}
        <a id="sub_btn" class="btn btn-outline-danger mx-3">Subscribe</a>
        {% endif %}
        {% endif %}
      </div>

    </div>
  </div>
</div>
<!--End of Profile Image and Name-->

<hr>
<div class="container">
  <ul class="nav nav-tabs" id="myTab" role="tablist">
    <li class="nav-item" role="presentation">
      <a class="nav-link active" id="home-tab" data-bs-toggle="tab" href="#home" role="tab" aria-controls="home" aria-selected="true">Home</a>
    </li>
    <li class="nav-item" role="presentation">
      <a class="nav-link" id="profile-tab" data-bs-toggle="tab" href="#profile" role="tab" aria-controls="profile" aria-selected="false">Videos</a>
    </li>
    <li class="nav-item" role="presentation">
      <a class="nav-link" id="contact-tab" data-bs-toggle="tab" href="#contact" role="tab" aria-controls="contact" aria-selected="false">About</a>
    </li>
  </ul>
  <div class="tab-content" id="myTabContent">
    <div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab">
      <h3 class="my-3">Category wise videos</h3>
      <hr>

      {% if sci %}
      <div class="row">
        <h4 class="text-primary">Science & Technology</h4>

        {% for v in sci %}
        <div class="col-3">
          <a href="{% url 'watch_video' v.id %}" style="text-decoration: none;"><img src="{% static v.thumbnail.url %}" style="width: 100%;" class="img-thumbnail"></a>
          <a href="{% url 'watch_video' v.id %}" style="text-decoration: none;"><h6>{{v.title}}</h6></a>
          <span class="text-muted">{{v.video_views.all.count}} views • {{v.pub_date}}</span>
        </div>
        {% endfor %}

      </div>
      <hr>
      {% endif %}



      {% if blogs %}
      <div class="row">
        <h4 class="text-primary">Blogs</h4>

        {% for v in blogs %}
        <div class="col-3">
          <a href="{% url 'watch_video' v.id %}" style="text-decoration: none;"><img src="{% static v.thumbnail.url %}" style="width: 100%;" class="img-thumbnail"></a>
          <a href="{% url 'watch_video' v.id %}" style="text-decoration: none;"><h6>{{v.title}}</h6></a>
          <span class="text-muted">{{v.video_views.all.count}} views • {{v.pub_date}}</span>
        </div>
        {% endfor %}

      </div>
      <hr>
      {% endif %}




      {% if food %}
      <div class="row">
        <h4 class="text-primary">Food</h4>

        {% for v in food%}
        <div class="col-3">
          <a href="{% url 'watch_video' v.id %}" style="text-decoration: none;"><img src="{% static v.thumbnail.url %}" class="img-thumbnail w-75"></a>
          <a href="{% url 'watch_video' v.id %}" style="text-decoration: none;"><h6>{{v.title}}</h6></a>
          <span class="text-muted">{{v.video_views.all.count}} views • {{v.pub_date}}</span>
        </div>
        {% endfor %}       

      </div>
      <hr>
      {% endif %}


      {% if edu %}
      <div class="row">
        <h4 class="text-primary">Education</h4>

        {% for v in edu%}
        <div class="col-3">
          <a href="{% url 'watch_video' v.id %}" style="text-decoration: none;"><img src="{% static v.thumbnail.url %}" class="img-thumbnail w-75"></a>
          <a href="{% url 'watch_video' v.id %}" style="text-decoration: none;"><h6>{{v.title}}</h6></a>
          <span class="text-muted">{{v.video_views.all.count}} views • {{v.pub_date}}</span>
        </div>
        {% endfor %}       

      </div>
      <hr>
      {% endif %}


      {% if fashion %}
      <div class="row">
        <h4 class="text-primary">Fashion</h4>

        {% for v in fashion %}
        <div class="col-3">
          <a href="{% url 'watch_video' v.id %}" style="text-decoration: none;"><img src="{% static v.thumbnail.url %}" class="img-thumbnail w-75"></a>
          <a href="{% url 'watch_video' v.id %}" style="text-decoration: none;"><h4>{{v.title}}</h4></a>
          <span class="text-muted">{{v.video_views.all.count}} views • {{v.pub_date}}</span>
        </div>
        {% endfor %}       

      </div>
      <hr>
      {% endif %}



    </div>
    <div class="tab-pane fade" id="profile" role="tabpanel" aria-labelledby="profile-tab">
      <div class="container">
        <h3 class="my-3">Uploads</h3>
        <div class="row my-3">
          {% if videos %}
          {% for video in videos %}
          <div class="col-3">
            <a href="{% url 'watch_video' video.id %}" style="text-decoration: none;"><img src="{% static video.thumbnail.url %}" style="width: 100%;" class="img-thumbnail"></a>
            <a href="{% url 'watch_video' video.id %}" style="text-decoration: none;"><h6>{{video.title}}</h6></a>
            <span class="text-muted">{{video.video_views.all.count}} views • {{video.pub_date}}</span>
          </div>
          {% endfor %}
          {% else %}
          <h3>No Videos.</h3>
          {% endif %}
        </div>
        <hr>

      </div>
    </div>


    <div class="tab-pane fade" id="contact" role="tabpanel" aria-labelledby="contact-tab">
      <div class="container my-4">
        <p><b>Description</b></p>
        <pre style="font-family: tahoma; letter-spacing: 1px;"><p>{{user_data.about}}</p></pre>
        <hr>

        <p><b>Details</b></p>
        <p>Email: </p>
        <a href="mailto:{{session_obj.email}}"><p>{{session_obj.email}}</p></a>
        <hr>

        <p><b>Links: </b></p>
        <p>Instagram</p>
        <p>Github</p>
        <p>Twitter</p>
        <p>Facebook</p>
        <hr>
      </div>
    </div>
  </div>
</div>


<script type="text/javascript">
var btn = $('#sub_btn');
var count = $('#count');  
// btn.text('Subscribe');
btn.on('click', function(event){
  event.preventDefault();

  $.ajax({
    type: 'GET',
    url: '{% url "add_subscriber" session_obj.username %}',
    dataType: 'json',
    success: function(data){
      if(data.is_subscribed)
      {
          // alert(data.is_subscribed);
          btn.text('Subscribe');
          count.text(data.viewer_obj);
          console.log(data.viewer_obj);
        }
        else
        {
         // alert(data.is_subscribed); 
         btn.text('Unsubscribe');
         count.text(data.viewer_obj);
         console.log(data.viewer_obj);
       }
     }

   });
});


</script>
{% endblock %}
Enter fullscreen mode Exit fullscreen mode

dashboard.html

{% extends 'base.html' %}
{% load static %}

{% block body %}
<div class="container my-3 py-3">
    <div class="row">
        <div class="col-sm-3">
            <div class="card" style="width: 15rem;">
                <div class="card border border-danger bg-danger text-light" style="width: 15rem;">
                    <div class="card-body">
                        <h2 class="card-title text-center"><span id="text_v_likes">{{total_likes}}</span> Likes</h2>
                    </div>
                </div>
            </div>
        </div>
        <div class="col-sm-3">
            <div class="card" style="width: 15rem;">
                <div class="card border border-danger bg-danger text-light" style="width: 15rem;">
                    <div class="card-body">
                        <h2 class="card-title text-center">{{user_data.subscribers.all.count}} Subscribers</h2>
                    </div>
                </div>
            </div>
        </div>
        <div class="col-sm-3">
            <div class="card" style="width: 15rem;">
                <div class="card border border-danger bg-danger text-light" style="width: 15rem;">
                    <div class="card-body">
                        <h2 class="card-title text-center"><span id='text_v_count'>{{videos.count}}</span> Videos</h2>
                    </div>
                </div>
            </div>
        </div>
        <div class="col-sm-3">
            <div class="card" style="width: 15rem;">
                <div class="card border border-danger bg-danger text-light" style="width: 15rem;">
                    <div class="card-body">
                        <h2 class="card-title text-center"><span id='text_v_count'>{{total_views}}</span> Views</h2>
                    </div>
                </div>
            </div>
        </div>
    </div>

</div>



<div class="container">
    <div class="d-flex align-items-start">
        <div class="nav flex-column nav-pills px-4 py-4 me-3 border" id="v-pills-tab" role="tablist" aria-orientation="vertical">
            <a class="nav-link active h5" id="v-pills-home-tab" data-bs-toggle="pill" href="#v-pills-home" role="tab" aria-controls="v-pills-home" aria-selected="true">Videos</a>
            <a class="nav-link h5" id="v-pills-profile-tab" data-bs-toggle="pill" href="#v-pills-profile" role="tab" aria-controls="v-pills-profile" aria-selected="false">Profile</a>
        </div>


        <div class="tab-content" id="v-pills-tabContent">
            <div class="tab-pane fade show active" id="v-pills-home" role="tabpanel" aria-labelledby="v-pills-home-tab">
                <div class="container">
                    {% for video in videos %}
                    <div class="card my-3 border-dark" id="{{video.id}}">
                        <h5 class="card-header">{{video.title}}</h5>
                        <div class="card-body">
                            <img src="{% static video.thumbnail.url %}" class="img-thumbnail w-25">         
                            <p class="card-text">{{video.desc|truncatewords:5}}</p>
                            <a href="{% url 'watch_video' video.id %}" class="btn btn-primary">Watch Now</a>
                            <span class="mx-4">
                                <button class="btn btn-danger">
                                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-heart" viewBox="0 0 16 16">
                                        <path d="M8 2.748l-.717-.737C5.6.281 2.514.878 1.4 3.053c-.523 1.023-.641 2.5.314 4.385.92 1.815 2.834 3.989 6.286 6.357 3.452-2.368 5.365-4.542 6.286-6.357.955-1.886.838-3.362.314-4.385C13.486.878 10.4.28 8.717 2.01L8 2.748zM8 15C-7.333 4.868 3.279-3.04 7.824 1.143c.06.055.119.112.176.171a3.12 3.12 0 0 1 .176-.17C12.72-3.042 23.333 4.867 8 15z"/>
                                    </svg>
                                    <b>{{video.likes.count}}</b>
                                </button>

                                <button class="btn btn-warning">
                                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eye-fill" viewBox="0 0 16 16">
                                        <path d="M10.5 8a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0z"/>
                                        <path d="M0 8s3-5.5 8-5.5S16 8 16 8s-3 5.5-8 5.5S0 8 0 8zm8 3.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7z"/>
                                    </svg>
                                    <b>{{video.video_views.count}}</b>
                                </button>

                                <button class="btn btn-info">
                                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-vector-pen" viewBox="0 0 16 16">
                                        <path fill-rule="evenodd" d="M10.646.646a.5.5 0 0 1 .708 0l4 4a.5.5 0 0 1 0 .708l-1.902 1.902-.829 3.313a1.5 1.5 0 0 1-1.024 1.073L1.254 14.746 4.358 4.4A1.5 1.5 0 0 1 5.43 3.377l3.313-.828L10.646.646zm-1.8 2.908l-3.173.793a.5.5 0 0 0-.358.342l-2.57 8.565 8.567-2.57a.5.5 0 0 0 .34-.357l.794-3.174-3.6-3.6z"/>
                                        <path fill-rule="evenodd" d="M2.832 13.228L8 9a1 1 0 1 0-1-1l-4.228 5.168-.026.086.086-.026z"/>
                                    </svg>
                                    <b>{{video.comment_set.all.count}}</b>
                                </button>

                            </span>
                            <a class="btn btn-outline-danger mx-2 del_btn" id="{{video.id}}" style="float: right;">Delete</a>
                            <a href="#" class="btn btn-outline-success mx-2" data-bs-toggle="modal" data-bs-target="#exampleModal{{video.id}}" style="float: right;">Edit</a>
                            <!-- Button trigger modal -->


                            <!-- Edit Video Modal -->
                            <div class="modal fade" id="exampleModal{{video.id}}" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
                                <div class="modal-dialog">
                                    <div class="modal-content">
                                        <div class="modal-header">
                                            <h5 class="modal-title" id="exampleModalLabel">Edit Video Details</h5>
                                            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                                        </div>
                                        <div class="modal-body">
                                            <form action="{% url 'edit_video' video.id %}" method="post">
                                                {% csrf_token %}
                                                <div class="form-floating">
                                                    <input type="text" placeholder="Title" name="new_title" class="form-control my-2 new_title" id="new_title{{video.id}}" value="{{video.title}}">
                                                    <label for="floatingInput" >Title</label>
                                                </div>
                                                <div class="form-floating">
                                                    <textarea class="form-control my-2 new_desc" id="new_desc{{video.id}}" placeholder="Description" name="new_desc" style="height: 300px;">{{video.desc}}</textarea>
                                                    <label for="floatingInput">Description</label>
                                                </div>
                                                <div class="form-floating">
                                                <select name="new_cate" class="form-control new_cate" id="new_cate{{video.id}}" name="category">
                                                    <option>{{video.category}}</option>
                                                    <option>Science & Techanology</option>
                                                    <option>Fashion</option>
                                                    <option>Food</option>
                                                    <option>Education</option>
                                                    <option>Blogs</option>
                                                </select>
                                                <label for="floatingInput">Category</label>
                                                </div>
                                                <div class="modal-footer">
                                                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
                                                    <button type="submit" id="edit_btn{{video.id}}" class="btn btn-primary edit_btn">Save changes</button>
                                                </div>
                                            </form>
                                        </div>

                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                    {% endfor %}

                </div>
            </div>


            <div class="tab-pane fade " style="width:800px;" id="v-pills-profile" role="tabpanel" aria-labelledby="v-pills-profile-tab">
                <div class="container">

                    <div class="container">
                        <h3>Additional Data</h3>
                        <form action="{% url 'update_details' %}" method="post" enctype="multipart/form-data">
                            {% csrf_token %}
                        <div class="row">
                            <div class="col-sm-8 my-auto">

                                    <input type="file" name="img_field" accept="image/*" class="form-control">

                                </div>
                                <div class="col-sm-4">
                                    <b><label>Current Profile Pic</label></b>

                                    <img src="{% static user_data.profile_pic.url %}" class="rounded" style="width: 150px; height: 200px;" alt="{{user_data.profile_pic}}">

                                </div>
                            </div>

                            <div class="row">
                                <div class="col-sm-8">
                                    <b><label for="about_text">About</label></b>
                                    <textarea placeholder="About yourself..." class="form-control" style="height: 100px;" name="about_text">{{user_data.about}}</textarea>
                                </div>
                            </div>
                            <input type="submit" id="update_btn" value="Update" class="btn btn-outline-success my-3">
                        </form>
                    </div>
                    <hr>
                    <div class="container">
                        <h3 class="text-danger">Danger Zone</h3>
                        <form>
                            <input type="text" name="" placeholder="Type Your Username to Verify" class="form-control">
                            <input type="submit" name="" value="Deactivate Your Account" class="btn btn-outline-danger my-3">
                        </form>

                    </div>

                </div>
            </div>



        </div>
    </div>
</div>





<script type="text/javascript">
var btn = $('.del_btn');
btn.on('click',function(event){
    event.preventDefault();
    var vid = $(this).attr('id');
    var v_count = $('#text_v_count');
    var v_likes = $('#text_v_likes');

        $.ajax({
            type: 'GET',
            url: '{% url "delete_video" %}',
            data: {videoId: vid},
            dataType: 'json',
            success: function(data){
                if(data.video_id)
                {
                    var vid = data.video_id;
                    $('div').remove('#'+vid);
                    v_count.text(data.videosCount);
                    v_likes.text(data.videosLikes);
                }


            }
        }); 
    });


</script>

{% endblock %}

Enter fullscreen mode Exit fullscreen mode

search_page.html

{% extends 'base.html' %}
{% load static %}
{% block body %}
<div class="container my-4">
    <h3>Search Results: </h3>
    {% if user_obj %}
    <div class="row">
    {% for user in user_obj %}
    <div class="col-4">
    <div class="card my-3" style="width: 18rem;">
        <img src="{% static user.userdata.profile_pic.url %}" class="img-thumbnail card-img-top" style="height: 250px;" alt="...">
        <div class="card-body">
            <h5 class="card-title">{{user.username}}</h5>
            <p class="card-text">{{user.userdata.about|truncatewords:6}}</p>
            <a href="{% url 'profile' user.username %}" class="btn btn-primary">View Profile</a>
        </div>
    </div>
    </div>
    {% endfor %}
    </div>
    {% else %}
    <div class="container">
        <h5>No Results Found.</h5>
    </div>
    {% endif %}
</div>  
{% endblock %}
Enter fullscreen mode Exit fullscreen mode

404.html

{% extends 'base.html' %}
{% block body %}

    <div class="container py-4 w-25 text-center bg-danger" style="margin-left: 40%; margin-top: 100px;">
        <h1 class="animate__animated animate__swing">404</h1>
        Not Found
    </div>


{% endblock %}

Enter fullscreen mode Exit fullscreen mode

That's it.

If you face any problem related to the source code than comment below.

I have worked very hard on this project. So I request you to support my hard work.

Top comments (10)

Collapse
 
khanhazii2124 profile image
capapk

Thanks for the detailed tutorial.
I started my website to share CapCut Templates on WordPress and its slow a bit, Now i am trying to make custom page so i can meet google Core Web Vitals.

Collapse
 
pro_capcut profile image
Capcut Pro

Thanks for the detailed tutorial.
I started my website to share CapCut Templates on WordPress and its slow a bit, Now i am trying to make custom page so i can meet google Core Web Vitals.

Collapse
 
say_whaaaaaattt profile image
Hypertext

Good good

Collapse
 
madhubankhatri profile image
Madhuban Khatri

Thanks

Collapse
 
mikemka profile image
микемка

def watch_video(request, video_id):
try:
video_obj = VideoPost.objects.get(id=video_id)
except ObjectDoesNotExist:
return render(request, '404.html')

use django.shortcuts.get_object_or_404()

Collapse
 
gksvg profile image
Guatam Kumar

Nice Work bro

Collapse
 
madhubankhatri profile image
Madhuban Khatri

Thanks..

Collapse
 
primestar_ace profile image
PRIME STAR ACE

Hello sir thank for the tutorial am a new developer...could you please share the static files for the project...thanks

Collapse
 
shaidsifat profile image
shaid sifat

nice

Collapse
 
henry_william_1e6cb574213 profile image
Henry William • Edited

Amazing work keep it up.