Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions nau_openedx_extensions/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,17 @@ def ready(self):
"""
Method to perform actions after apps registry is ended
"""
# Override the default Video xBlock the _poster private function.
# Override the class was giving more work because of the html dependencies
# was being loaded from the new package. So it was more easy just replace the
# method implementation.
from xmodule.video_block.video_block import \
VideoBlock # pylint: disable=import-error,import-outside-toplevel # noqa

from nau_openedx_extensions import signals # pylint: disable=import-outside-toplevel,unused-import # noqa
from nau_openedx_extensions.xblocks.video_block import \
get_educast_poster_factory # pylint: disable=import-outside-toplevel # noqa

# Replace the method in the original VideoBlock class
prev_poster_func = VideoBlock._poster # pylint: disable=protected-access
VideoBlock._poster = get_educast_poster_factory(prev_poster_func) # pylint: disable=protected-access
Empty file.
Empty file.
85 changes: 85 additions & 0 deletions nau_openedx_extensions/xblocks/tests/test_video_block.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
"""
Test cases for the customized VideoBlock _poster method for Educast videos.
"""
from django.test import TestCase

from nau_openedx_extensions.xblocks.video_block import get_educast_poster_factory


class FakeVideoBlock():
"""
A fake VideoBlock XBlock class for testing
"""
def __init__(self):
self.html5_sources = {}


class TestVideoBlock(TestCase):
"""
Test cases for the customized VideoBlock _poster method for Educast videos.
"""
def test_get_educast_poster_https(self):
"""
Test the customized _poster method for VideoBlock.
"""
# Create a mock previous _poster method
def mock_prev_poster(self): # pylint: disable=unused-argument
return None

# Create the customized _poster method
customized_poster_method = get_educast_poster_factory(mock_prev_poster)

# Create an instance of VideoBlock and set html5_sources
video_block = FakeVideoBlock()
video_block.html5_sources = ['https://dev.educast.fccn.pt/vod/clips/bum66sthd/streaming.m3u8']

# Call the customized _poster method
poster_url = customized_poster_method(video_block)

# Verify the poster URL is as expected
expected_url = 'https://dev.educast.fccn.pt/img/clips/bum66sthd/delivery/cover'
self.assertEqual(poster_url, expected_url)

def test_get_educast_poster_http(self):
"""
Test the customized _poster method for VideoBlock.
"""
# Create a mock previous _poster method
def mock_prev_poster(self): # pylint: disable=unused-argument
return None

# Create the customized _poster method
customized_poster_method = get_educast_poster_factory(mock_prev_poster)

# Create an instance of VideoBlock and set html5_sources
video_block = FakeVideoBlock()
video_block.html5_sources = ['http://educast.fccn.pt/vod/clips/fdgfdgfdgfdg/streaming.m3u8']

# Call the customized _poster method
poster_url = customized_poster_method(video_block)

# Verify the poster URL is as expected
expected_url = 'http://educast.fccn.pt/img/clips/fdgfdgfdgfdg/delivery/cover'
self.assertEqual(poster_url, expected_url)

def test_get_educast_poster_no_protocol(self):
"""
Test the customized _poster method for VideoBlock.
"""
# Create a mock previous _poster method
def mock_prev_poster(self): # pylint: disable=unused-argument
return None

# Create the customized _poster method
customized_poster_method = get_educast_poster_factory(mock_prev_poster)

# Create an instance of VideoBlock and set html5_sources
video_block = FakeVideoBlock()
video_block.html5_sources = ['//educast.fccn.pt/vod/clips/aaaaaa/streaming.m3u8']

# Call the customized _poster method
poster_url = customized_poster_method(video_block)

# Verify the poster URL is as expected
expected_url = '//educast.fccn.pt/img/clips/aaaaaa/delivery/cover'
self.assertEqual(poster_url, expected_url)
31 changes: 31 additions & 0 deletions nau_openedx_extensions/xblocks/video_block.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""
Custom video block extensions for NAU Open edX.
"""
import re


def get_educast_poster_factory(prev_poster_func):
"""
Factory to create a customized _poster method for VideoBlock.
This allows us to inject custom logic while retaining access to the original method.
"""

def get_educast_poster(self):
"""
Override the default poster URL logic to customize the poster image.
"""
poster_url = prev_poster_func(self)
if not poster_url and self.html5_sources:
video_src = next(iter(self.html5_sources), None)
is_educast = 'educast.fccn.pt' in video_src # to work for both educast staging and production
if is_educast:
# from video src like https://staging.educast.fccn.pt/vod/clips/bum66sthd/streaming.m3u8
# extract the server base url https://educast.fccn.pt or http://educast.fccn.pt or //educast.fccn.pt
server_base_url = re.match(r'^(https?://[^/]+|//[^/]+)', video_src).group(1)
# extract the educast video id like bumu66sthd
educast_video_id = re.search(r'/clips/([^/]+)/', video_src).group(1)
# construct poster url like https://educast.fccn.pt/img/clips/jpojtray/delivery/cover
poster_url = f"{server_base_url}/img/clips/{educast_video_id}/delivery/cover"
return poster_url

return get_educast_poster