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