Skip to content

Commit

Permalink
Bugfix import video and thumbnail (#1253)
Browse files Browse the repository at this point in the history
* Replace pytube by pytubefix library, and generate PO token; manage the lack of URL field in Peertube
* Handle exception to avoid sending an error email, for get_thumbnail function
* Manage playlist when import video from Peertube
  • Loading branch information
LoicBonavent authored Jan 24, 2025
1 parent bf63ca2 commit 2bb32d7
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 29 deletions.
36 changes: 21 additions & 15 deletions pod/import_video/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
More information on this module at: https://www.esup-portail.org/wiki/x/BQCnSw
"""

import logging
import os
import requests
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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"] = _(
Expand All @@ -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."),
Expand Down Expand Up @@ -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"]
Expand All @@ -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)
Expand Down
44 changes: 31 additions & 13 deletions pod/video/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1014,27 +1014,41 @@ 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):
thumbnail_url = ""
# 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)
# <img src="{{ im.url }}" width="{{ im.width }}"
# height="{{ im.height }}" loading="lazy">
else:
Expand All @@ -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)
# <img src="{{ im.url }}" width="{{ im.width }}"
# height="{{ im.height }}" loading="lazy">
else:
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 2bb32d7

Please sign in to comment.