diff --git a/app/YtManagerApp/models.py b/app/YtManagerApp/models.py index 93d3913..08a920c 100644 --- a/app/YtManagerApp/models.py +++ b/app/YtManagerApp/models.py @@ -1,4 +1,5 @@ import logging +import mimetypes import os from typing import Callable, Union, Any, Optional @@ -218,6 +219,19 @@ class Video(models.Model): if file.startswith(file_pattern): yield os.path.join(directory, file) + def find_video(self): + """ + Finds the video file from the downloaded files, and + returns + :return: Tuple containing file path and mime type + """ + for file in self.get_files(): + mime, _ = mimetypes.guess_type(file) + if mime is not None and mime.startswith('video/'): + return (file, mime) + + return None, None + def delete_files(self): if self.downloaded_path is not None: from YtManagerApp.management.jobs.delete_video import schedule_delete_video diff --git a/app/YtManagerApp/templates/YtManagerApp/index_videos.html b/app/YtManagerApp/templates/YtManagerApp/index_videos.html index cd10cbf..16e1468 100644 --- a/app/YtManagerApp/templates/YtManagerApp/index_videos.html +++ b/app/YtManagerApp/templates/YtManagerApp/index_videos.html @@ -6,13 +6,17 @@ {% for video in videos %}
- Thumbnail + + Thumbnail +
{% if not video.watched %} New {% endif %} - {{ video.name }} + + {{ video.name }} +

{{ video.views | intcomma }} views diff --git a/app/YtManagerApp/templates/YtManagerApp/video.html b/app/YtManagerApp/templates/YtManagerApp/video.html new file mode 100644 index 0000000..823e002 --- /dev/null +++ b/app/YtManagerApp/templates/YtManagerApp/video.html @@ -0,0 +1,83 @@ +{% extends "YtManagerApp/master_default.html" %} +{% load static %} +{% load humanize %} +{% load ratings %} + +{% block body %} + +

+ +

{{ object.name }}

+ +
+ +
+ {% if video_mime != None %} + + {% else %} + + {% endif %} + +
+

+ {{ object.views | intcomma }} views + + {{ object.publish_date | naturaltime }} +

+
+ {% starrating object.rating %} +
+
+ +
+ {{ object.description | linebreaks | urlize }} +
+ +

+
+ +
+
Manage video
+

+ + Watch on YouTube + +

+ + {% if object.watched %} +

+ + Mark not watched + +

+ {% else %} +

+ + Mark watched + +

+ {% endif %} + + {% if object.downloaded_path %} +

+ + Delete downloaded + +

+ {% else %} +

+ + Download + +

+ {% endif %} +
+
+ +
+ +{% endblock %} diff --git a/app/YtManagerApp/urls.py b/app/YtManagerApp/urls.py index dc487c1..8b383e4 100644 --- a/app/YtManagerApp/urls.py +++ b/app/YtManagerApp/urls.py @@ -18,13 +18,14 @@ from django.conf.urls import include from django.conf.urls.static import static from django.urls import path +from YtManagerApp.views.video import VideoDetailView, video_detail_view +from .views import first_time from .views.actions import SyncNowView, DeleteVideoFilesView, DownloadVideoFilesView, MarkVideoWatchedView, \ MarkVideoUnwatchedView from .views.auth import ExtendedLoginView, RegisterView, RegisterDoneView from .views.index import index, ajax_get_tree, ajax_get_videos, CreateFolderModal, UpdateFolderModal, DeleteFolderModal, \ CreateSubscriptionModal, UpdateSubscriptionModal, DeleteSubscriptionModal, ImportSubscriptionsModal from .views.settings import SettingsView, AdminSettingsView -from .views import first_time urlpatterns = [ # Authentication URLs @@ -60,8 +61,10 @@ urlpatterns = [ path('', index, name='home'), path('settings/', SettingsView.as_view(), name='settings'), path('admin_settings/', AdminSettingsView.as_view(), name='admin_settings'), + path('video//', VideoDetailView.as_view(), name='video'), + path('video-src//', video_detail_view, name='video-src'), - # First time setup + # First time setup path('first_time/step0_welcome', first_time.Step0WelcomeView.as_view(), name='first_time_0'), path('first_time/step1_apikey', first_time.Step1ApiKeyView.as_view(), name='first_time_1'), path('first_time/step2_admin', first_time.Step2SetupAdminUserView.as_view(), name='first_time_2'), diff --git a/app/YtManagerApp/views/video.py b/app/YtManagerApp/views/video.py new file mode 100644 index 0000000..f2e073b --- /dev/null +++ b/app/YtManagerApp/views/video.py @@ -0,0 +1,30 @@ +from django.contrib.auth.decorators import login_required +from django.contrib.auth.mixins import LoginRequiredMixin +from django.http import HttpRequest, StreamingHttpResponse, FileResponse +from django.urls import reverse, reverse_lazy +from django.views import View +from django.views.generic import DetailView + +from YtManagerApp.models import Video + + +class VideoDetailView(LoginRequiredMixin, DetailView): + template_name = 'YtManagerApp/video.html' + model = Video + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + video, mime = self.object.find_video() + if video is not None: + context['video_mime'] = mime + + return context + + +@login_required +def video_detail_view(request: HttpRequest, pk): + video = Video.objects.get(id = pk) + video_file, _ = video.find_video() + + f = open(video_file, 'rb') + return FileResponse(f)