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