diff --git a/pod/import_video/views.py b/pod/import_video/views.py
index 77b711ee45..a807b10e9e 100644
--- a/pod/import_video/views.py
+++ b/pod/import_video/views.py
@@ -2,7 +2,6 @@
More information on this module at: https://www.esup-portail.org/wiki/x/BQCnSw
"""
-
import logging
import os
import requests
@@ -42,9 +41,9 @@
from pod.main.views import in_maintenance
from pod.main.utils import secure_post_request, display_message_with_icon
-# For Youtube download
-from pytube import YouTube
-from pytube.exceptions import PytubeError, VideoUnavailable
+# For Youtube download, use PyTubeFix in replacement of PyTube
+from pytubefix import YouTube
+from pytubefix.exceptions import PytubeFixError, VideoUnavailable
# To convert old BBB presentation
from pod.main.tasks import task_start_bbb_presentation_encode_and_upload_to_pod
@@ -734,8 +733,8 @@ def get_mediacad_api_description(type_source_url: TypeSourceURL) -> str:
def upload_youtube_recording_to_pod(request, record_id: int):
"""Upload Youtube recording to Pod.
- Use PyTube with its API
- More information: https://pytube.io/en/latest/api.html
+ Use PyTubeFix with its API
+ More information: https://pytubefix.readthedocs.io/en/latest/
Args:
request (Request): HTTP request
record_id (Integer): id record in the database
@@ -750,12 +749,12 @@ def upload_youtube_recording_to_pod(request, record_id: int):
# Manage source URL from video playback
source_url = request.POST.get("source_url")
- # Use pytube to download Youtube file
+ # Use pytubefix to download Youtube file
+ # Manage Proof of Origin Token generation
+ # See https://pytubefix.readthedocs.io/en/latest/user/po_token.html
yt_video = YouTube(
source_url,
- # on_complete_callback=complete_func,
- # use_oauth=True,
- # allow_oauth_cache=True
+ 'WEB'
)
# Publish date (format: 2023-05-13 00:00:00)
# Event date (format: 2023-05-13)
@@ -799,7 +798,8 @@ def upload_youtube_recording_to_pod(request, record_id: int):
save_video(request.user, dest_path, recording_title, description, date_evt)
return True
- except VideoUnavailable:
+ except VideoUnavailable as ptfvu:
+ log.error("upload_youtube_recording_to_pod - VideoUnavailable - %s" % ptfvu)
msg = {}
msg["error"] = _("YouTube error")
msg["message"] = _(
@@ -810,9 +810,10 @@ def upload_youtube_recording_to_pod(request, record_id: int):
"Try changing the access rights to the video directly in Youtube."
)
raise ValueError(msg)
- except PytubeError as pterror:
+ except PytubeFixError as ptferror:
+ log.error("upload_youtube_recording_to_pod - PytubeFixError - %s" % ptferror)
msg = {}
- msg["error"] = _("YouTube error ā%sā" % (mark_safe(pterror)))
+ msg["error"] = _("YouTube error ā%sā" % (mark_safe(ptferror)))
msg["message"] = "%s\n%s" % (
_("YouTube content is inaccessible."),
_("This content does not appear to be publicly available."),
@@ -891,7 +892,7 @@ def upload_peertube_recording_to_pod(request, record_id: int) -> bool: # noqa:
else:
pt_video_json = json.loads(response.content.decode("utf-8"))
# URL
- pt_video_url = pt_video_json["url"]
+ pt_video_url = source_url
# UUID, useful for the filename
pt_video_uuid = pt_video_json["uuid"]
pt_video_name = pt_video_json["name"]
@@ -905,7 +906,12 @@ def upload_peertube_recording_to_pod(request, record_id: int) -> bool: # noqa:
# Evant date (format: 2023-05-23)
date_evt = pt_video_created_at[0:10]
# Source video file
- source_video_url = pt_video_json["files"][0]["fileDownloadUrl"]
+ if not pt_video_json["files"]:
+ # Source video file for a playlist
+ source_video_url = pt_video_json["streamingPlaylists"][0]["files"][0]["fileDownloadUrl"]
+ else:
+ # Source video file for a video
+ source_video_url = pt_video_json["files"][0]["fileDownloadUrl"]
# Verify that video exists and not oversized
verify_video_exists_and_size(source_video_url)
diff --git a/pod/video/models.py b/pod/video/models.py
index 08261ce885..9a240a78bb 100644
--- a/pod/video/models.py
+++ b/pod/video/models.py
@@ -1014,18 +1014,28 @@ def get_player_height(self) -> int:
def get_thumbnail_url(self, size="x720") -> str:
"""Get a thumbnail url for the video, with defined max size."""
request = None
+ # Initialize default thumbnail URL
+ thumbnail_url = "".join(
+ [
+ "//",
+ get_current_site(request).domain,
+ static(DEFAULT_THUMBNAIL),
+ ]
+ )
if self.thumbnail and self.thumbnail.file_exist():
# Do not serve thumbnail url directly, as it can lead to the video URL
- im = get_thumbnail(self.thumbnail.file, size, crop="center", quality=80)
- return im.url
+ # Handle exception to avoid sending an error email
+ try:
+ im = get_thumbnail(self.thumbnail.file, size, crop="center", quality=80)
+ thumbnail_url = im.url
+ except Exception as e:
+ logger.error(
+ "An error occured during get_thumbnail_url"
+ " for video %s: %s" % (self.id, e)
+ )
+ return thumbnail_url
else:
- return "".join(
- [
- "//",
- get_current_site(request).domain,
- static(DEFAULT_THUMBNAIL),
- ]
- )
+ return thumbnail_url
@property
def get_thumbnail_admin(self):
@@ -1033,8 +1043,12 @@ def get_thumbnail_admin(self):
# fix title for xml description
title = re.sub(r"[\x00-\x08\x0B-\x0C\x0E-\x1F]", "", self.title)
if self.thumbnail and self.thumbnail.file_exist():
- im = get_thumbnail(self.thumbnail.file, "100x100", crop="center", quality=72)
- thumbnail_url = im.url
+ # Handle exception to avoid sending an error email
+ try:
+ im = get_thumbnail(self.thumbnail.file, "100x100", crop="center", quality=72)
+ thumbnail_url = im.url
+ except Exception:
+ thumbnail_url = static(DEFAULT_THUMBNAIL)
#
else:
@@ -1054,8 +1068,12 @@ def get_thumbnail_card(self) -> str:
"""Return thumbnail image card of current video."""
thumbnail_url = ""
if self.thumbnail and self.thumbnail.file_exist():
- im = get_thumbnail(self.thumbnail.file, "x170", crop="center", quality=72)
- thumbnail_url = im.url
+ # Handle exception to avoid sending an error email
+ try:
+ im = get_thumbnail(self.thumbnail.file, "x170", crop="center", quality=72)
+ thumbnail_url = im.url
+ except Exception:
+ thumbnail_url = static(DEFAULT_THUMBNAIL)
#
else:
diff --git a/requirements.txt b/requirements.txt
index b67ad8056b..0a517e13c4 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -30,7 +30,7 @@ qrcode
ralph-malph==3.8.0
pydantic==1.10.13
bleach==6.0.0
-pytube==15.0.0
+pytubefix==8.12.0
django-redis-sessions
paramiko~=3.1.0
djangorestframework-simplejwt==5.3.0