From 12a22ac8866a510d11bee965a289d1d2891531cb Mon Sep 17 00:00:00 2001 From: Nimisha Asthagiri Date: Mon, 17 Nov 2014 09:13:50 -0500 Subject: [PATCH] MA-135, MA-122 Support CDN and alternative sources with VAL-enabled-videos. --- .../xmodule/video_module/video_module.py | 32 ++-- .../courseware/tests/test_video_mongo.py | 153 ++++-------------- 2 files changed, 49 insertions(+), 136 deletions(-) diff --git a/common/lib/xmodule/xmodule/video_module/video_module.py b/common/lib/xmodule/xmodule/video_module/video_module.py index 0de4ed2f87..0a359370d9 100644 --- a/common/lib/xmodule/xmodule/video_module/video_module.py +++ b/common/lib/xmodule/xmodule/video_module/video_module.py @@ -176,18 +176,6 @@ class VideoModule(VideoFields, VideoTranscriptsMixin, VideoStudentViewHandlers, transcript_download_format = self.transcript_download_format if not (self.download_track and self.track) else None sources = filter(None, self.html5_sources) - # If the user comes from China use China CDN for html5 videos. - # 'CN' is China ISO 3166-1 country code. - # Video caching is disabled for Studio. User_location is always None in Studio. - # CountryMiddleware disabled for Studio. - cdn_url = getattr(settings, 'VIDEO_CDN_URL', {}).get(self.system.user_location) - - if getattr(self, 'video_speed_optimizations', True) and cdn_url: - for index, source_url in enumerate(sources): - new_url = get_video_from_cdn(cdn_url, source_url) - if new_url: - sources[index] = new_url - download_video_link = None youtube_streams = "" @@ -202,8 +190,12 @@ class VideoModule(VideoFields, VideoTranscriptsMixin, VideoStudentViewHandlers, # VAL will always give us the keys for the profiles we asked for, but # if it doesn't have an encoded video entry for that Video + Profile, the # value will map to `None` - if val_video_urls["desktop_mp4"] and self.download_video: - download_video_link = val_video_urls["desktop_mp4"] + if val_video_urls["desktop_mp4"]: + if self.download_video: + download_video_link = val_video_urls["desktop_mp4"] + # add the desktop_mp4 profile to the list of alternative sources + if val_video_urls["desktop_mp4"] not in sources: + sources.append(val_video_urls["desktop_mp4"]) if val_video_urls["youtube"]: youtube_streams = "1.00:{}".format(val_video_urls["youtube"]) except edxval_api.ValInternalError: @@ -212,6 +204,18 @@ class VideoModule(VideoFields, VideoTranscriptsMixin, VideoStudentViewHandlers, # exception and fallback to whatever we find in the VideoDescriptor. log.warning("Could not retrieve information from VAL for edx Video ID: %s.", self.edx_video_id) + # If the user comes from China use China CDN for html5 videos. + # 'CN' is China ISO 3166-1 country code. + # Video caching is disabled for Studio. User_location is always None in Studio. + # CountryMiddleware disabled for Studio. + cdn_url = getattr(settings, 'VIDEO_CDN_URL', {}).get(self.system.user_location) + + if getattr(self, 'video_speed_optimizations', True) and cdn_url: + for index, source_url in enumerate(sources): + new_url = get_video_from_cdn(cdn_url, source_url) + if new_url: + sources[index] = new_url + # If there was no edx_video_id, or if there was no download specified # for it, we fall back on whatever we find in the VideoDescriptor if not download_video_link and self.download_video: diff --git a/lms/djangoapps/courseware/tests/test_video_mongo.py b/lms/djangoapps/courseware/tests/test_video_mongo.py index 50d2a6f134..d00ee89aec 100644 --- a/lms/djangoapps/courseware/tests/test_video_mongo.py +++ b/lms/djangoapps/courseware/tests/test_video_mongo.py @@ -372,7 +372,7 @@ class TestGetHtmlMethod(BaseTestXmodule): self.item_descriptor.xmodule_runtime.render_template('video.html', expected_context) ) - def test_get_html_with_non_existant_edx_video_id(self): + def test_get_html_with_non_existent_edx_video_id(self): """ Tests the VideoModule get_html where a edx_video_id is given but a video is not found """ @@ -452,7 +452,8 @@ class TestGetHtmlMethod(BaseTestXmodule): 'edx_video_id': "mock item", 'result': { 'download_video_link': None, - 'sources': json.dumps([u'example.mp4', u'example.webm']), + # make sure the desktop_mp4 url is included as part of the alternative sources. + 'sources': json.dumps([u'example.mp4', u'example.webm', u'http://www.meowmix.com']), } } @@ -527,7 +528,7 @@ class TestGetHtmlMethod(BaseTestXmodule): edx_video_id="thundercats", encoded_videos=[ dict( - url="http://fake-video.edx.org/thundercats.mp4", + url=u"http://fake-video.edx.org/thundercats.mp4", file_size=9000, bitrate=42, profile="desktop_mp4", @@ -558,7 +559,8 @@ class TestGetHtmlMethod(BaseTestXmodule): 'edx_video_id': "thundercats", 'result': { 'download_video_link': u'http://fake-video.edx.org/thundercats.mp4', - 'sources': json.dumps([u'example.mp4', u'example.webm']), + # make sure the desktop_mp4 url is included as part of the alternative sources. + 'sources': json.dumps([u'example.mp4', u'example.webm', u"http://fake-video.edx.org/thundercats.mp4"]), } } @@ -635,30 +637,35 @@ class TestGetHtmlMethod(BaseTestXmodule): display_name="A Name" sub="a_sub_file.srt.sjson" source="{source}" download_video="{download_video}" + edx_video_id="{edx_video_id}" start_time="01:00:03" end_time="01:00:10" > {sources} """ - cases = [ - # - { - 'download_video': 'true', - 'source': 'example_source.mp4', - 'sources': """ - - - """, - 'result': { - 'download_video_link': u'example_source.mp4', - 'sources': json.dumps( - [ - u'http://cdn_example.com/example.mp4', - u'http://cdn_example.com/example.webm' - ] - ), - }, + + case_data = { + 'download_video': 'true', + 'source': 'example_source.mp4', + 'sources': """ + + + """, + 'result': { + 'download_video_link': u'example_source.mp4', + 'sources': json.dumps( + [ + u'http://cdn_example.com/example.mp4', + u'http://cdn_example.com/example.webm' + ] + ), }, + } + + # test with and without edx_video_id specified. + cases = [ + dict(case_data, edx_video_id=""), + dict(case_data, edx_video_id="vid-v1:12345"), ] initial_context = { @@ -691,106 +698,8 @@ class TestGetHtmlMethod(BaseTestXmodule): DATA = SOURCE_XML.format( download_video=data['download_video'], source=data['source'], - sources=data['sources'] - ) - self.initialize_module(data=DATA) - self.item_descriptor.xmodule_runtime.user_location = 'CN' - - context = self.item_descriptor.render('student_view').content - - expected_context = dict(initial_context) - expected_context.update({ - 'transcript_translation_url': self.item_descriptor.xmodule_runtime.handler_url( - self.item_descriptor, 'transcript', 'translation' - ).rstrip('/?'), - 'transcript_available_translations_url': self.item_descriptor.xmodule_runtime.handler_url( - self.item_descriptor, 'transcript', 'available_translations' - ).rstrip('/?'), - 'ajax_url': self.item_descriptor.xmodule_runtime.ajax_url + '/save_user_state', - 'id': self.item_descriptor.location.html_id(), - }) - expected_context.update(data['result']) - - self.assertEqual( - context, - self.item_descriptor.xmodule_runtime.render_template('video.html', expected_context) - ) - - @patch('xmodule.video_module.video_module.get_video_from_cdn') - def test_get_html_cdn_source(self, mocked_get_video): - """ - Test if sources got from CDN. - """ - def side_effect(*args, **kwargs): - cdn = { - 'http://example.com/example.mp4': 'http://cdn_example.com/example.mp4', - 'http://example.com/example.webm': 'http://cdn_example.com/example.webm', - } - return cdn.get(args[1]) - - mocked_get_video.side_effect = side_effect - - SOURCE_XML = """ - - """ - cases = [ - { - 'download_video': 'true', - 'source': 'example_source.mp4', - 'sources': """ - - - """, - 'result': { - 'download_video_link': u'example_source.mp4', - 'sources': json.dumps( - [ - u'http://cdn_example.com/example.mp4', - u'http://cdn_example.com/example.webm' - ] - ), - }, - }, - ] - - initial_context = { - 'data_dir': getattr(self, 'data_dir', None), - 'show_captions': 'true', - 'handout': None, - 'display_name': u'A Name', - 'download_video_link': None, - 'end': 3610.0, - 'id': None, - 'sources': '[]', - 'speed': 'null', - 'general_speed': 1.0, - 'start': 3603.0, - 'saved_video_position': 0.0, - 'sub': u'a_sub_file.srt.sjson', - 'track': None, - 'youtube_streams': '1.00:OEoXaMPEzfM', - 'autoplay': settings.FEATURES.get('AUTOPLAY_VIDEOS', True), - 'yt_test_timeout': 1500, - 'yt_api_url': 'www.youtube.com/iframe_api', - 'yt_test_url': 'gdata.youtube.com/feeds/api/videos/', - 'transcript_download_format': 'srt', - 'transcript_download_formats_list': [{'display_name': 'SubRip (.srt) file', 'value': 'srt'}, {'display_name': 'Text (.txt) file', 'value': 'txt'}], - 'transcript_language': u'en', - 'transcript_languages': '{"en": "English"}', - } - - for data in cases: - DATA = SOURCE_XML.format( - download_video=data['download_video'], - source=data['source'], - sources=data['sources'] + sources=data['sources'], + edx_video_id=data['edx_video_id'], ) self.initialize_module(data=DATA) self.item_descriptor.xmodule_runtime.user_location = 'CN'