From 3a428cf3b618a202b520b85df1345517b9700310 Mon Sep 17 00:00:00 2001 From: OndraRehounek <ondra.rehounek@seznam.cz> Date: Thu, 28 Apr 2022 10:35:25 +0200 Subject: [PATCH] article mixin: YouTube block with poster (without migrations) --- district/models.py | 1 - shared/blocks.py | 45 +++++++++++++++++++ shared/static/shared/css/helpers.css | 15 +++++++ .../styleguide/2.3.x/blocks/video_block.html | 38 ++++++++++++---- 4 files changed, 90 insertions(+), 9 deletions(-) diff --git a/district/models.py b/district/models.py index 42200779..3d877d89 100644 --- a/district/models.py +++ b/district/models.py @@ -910,7 +910,6 @@ class DistrictCenterPage( CalendarMixin, ExtendedMetadataPageMixin, SubpageMixin, MetadataPageMixin, Page ): ### FIELDS - # TODO tohle by šlo asi nahradit DistrictCustomPage perex = models.TextField("Perex", blank=True, null=True) background_photo = models.ForeignKey( diff --git a/shared/blocks.py b/shared/blocks.py index 4a3ba423..9a668e80 100644 --- a/shared/blocks.py +++ b/shared/blocks.py @@ -1,10 +1,14 @@ import logging import re +import urllib +from django.core.files.images import ImageFile from django.forms.utils import ErrorList from wagtail.core import blocks from wagtail.core.blocks.struct_block import StructBlockValidationError +from wagtail.core.models import Collection from wagtail.images.blocks import ImageChooserBlock +from wagtail.images.models import Image logger = logging.getLogger(__name__) @@ -67,6 +71,11 @@ class ProgramItemBlock(blocks.StructBlock): class YouTubeVideoBlock(blocks.StructBlock): + poster_image = ImageChooserBlock( + label="Náhled videa (automatické pole)", + required=False, + help_text="Není třeba vyplňovat, náhled bude " "dohledán automaticky.", + ) video_url = blocks.URLBlock( label="Odkaz na video", required=False, @@ -118,6 +127,9 @@ class YouTubeVideoBlock(blocks.StructBlock): value["video_id"] = self.convert_youtube_link_to_video_id( value["video_url"] ) + value["poster_image"] = self.get_wagtail_image_id_for_youtube_poster( + value["video_id"] + ) value["video_url"] = "" @@ -138,3 +150,36 @@ class YouTubeVideoBlock(blocks.StructBlock): "Nepodařilo se získat video ID z YouTube URL", extra={"url": url} ) return "" + + @classmethod + def get_wagtail_image_id_for_youtube_poster(cls, video_id) -> int or None: + image_url = "https://img.youtube.com/vi/{}/hqdefault.jpg".format(video_id) + + img_path = "/tmp/{}.jpg".format(video_id) + urllib.request.urlretrieve(image_url, img_path) + file = ImageFile(open(img_path, "rb"), name=img_path) + + return cls.get_image_id(file, "YT_poster_v_{}".format(video_id)) + + @classmethod + def get_image_id(cls, file: ImageFile, image_title: str) -> int: + try: + image = Image.objects.get(title=image_title) + except Image.DoesNotExist: + image = Image( + title=image_title, file=file, collection=cls.get_posters_collection() + ) + image.save() + return image.id + + @staticmethod + def get_posters_collection() -> Collection: + collection_name = "YouTube nahledy" + + try: + collection = Collection.objects.get(name=collection_name) + except Collection.DoesNotExist: + root_collection = Collection.get_first_root_node() + collection = root_collection.add_child(name=collection_name) + + return collection diff --git a/shared/static/shared/css/helpers.css b/shared/static/shared/css/helpers.css index 781d11ac..fb46e09f 100644 --- a/shared/static/shared/css/helpers.css +++ b/shared/static/shared/css/helpers.css @@ -20,3 +20,18 @@ table caption { width: 100%; height: 100%; } + +.youtube-poster { + position: relative; +} +.youtube-poster i { + cursor: pointer; + left: 50%; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + transition: color 0.25s ease-in-out; +} +.youtube-poster:hover i { + color: white; +} diff --git a/shared/templates/styleguide/2.3.x/blocks/video_block.html b/shared/templates/styleguide/2.3.x/blocks/video_block.html index 31ab43a6..00948f9d 100644 --- a/shared/templates/styleguide/2.3.x/blocks/video_block.html +++ b/shared/templates/styleguide/2.3.x/blocks/video_block.html @@ -1,10 +1,32 @@ {% load wagtailimages_tags %} -<div class="content-block responsive-object ratio-16-9 w-full mb-10"> - <iframe - src="https://www.youtube-nocookie.com/embed/{{ self.video_id }}" - title="YouTube video player" - frameborder="0" - allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" - allowfullscreen - ></iframe> +<div class="mb-10 text-center youtube-poster" id="ytVideo{{ self.video_id }}PosterContainer"> + {% image self.poster_image width-720 as img %} + <img src="{{ img.url }}" alt="{{ img.alt }}" class="w-full object-cover mb-2"> + <small class="font-bold"> + Spuštěním videa dojde k načtení obsahu třetích stran z portálu YouTube. + </small> + <i class="ico--youtube text-9xl"></i> </div> + +<div + class="content-block responsive-object ratio-16-9 mb-10 w-full" + id="ytVideo{{ self.video_id }}IframeContainer" + style="display: none" +> + +</div> + +{# Script, který při kliknutí na poster načte iframe s YouTube videem (v Enhanced Privacy Mode) #} +{# Záměrně je přímo na bloku, protože málokterý článek bude mít více videí a naopak většina článků YT videa nemá #} +<script> + (function () { + const posterContainer = document.getElementById('ytVideo{{ self.video_id }}PosterContainer') + const videoContainer = document.getElementById('ytVideo{{ self.video_id }}IframeContainer') + + posterContainer.onclick = function () { + videoContainer.innerHTML = '<iframe src="https://www.youtube-nocookie.com/embed/{{ self.video_id }}?autoplay=1" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen ></iframe>' + videoContainer.style.display = 'block' + posterContainer.style.display = 'none' + } + })() +</script> -- GitLab