diff --git a/common/lib/xmodule/xmodule/js/src/video/01_initialize.js b/common/lib/xmodule/xmodule/js/src/video/01_initialize.js index 4165a1b04d..6051cc4286 100644 --- a/common/lib/xmodule/xmodule/js/src/video/01_initialize.js +++ b/common/lib/xmodule/xmodule/js/src/video/01_initialize.js @@ -723,12 +723,20 @@ function(VideoPlayer, i18n, moment, _) { } function getVideoMetadata(url, callback) { + var youTubeEndpoint; if (!(_.isString(url))) { url = this.videos['1.0'] || ''; } // Will hit the API URL to get the youtube video metadata. + youTubeEndpoint = this.config.ytMetadataEndpoint; // The new runtime supports anonymous users + // and uses an XBlock handler to get YouTube metadata + if (!youTubeEndpoint) { + // The old runtime has a full/separate LMS API for getting YouTube metadata, but it doesn't + // support anonymous users nor videos that play in a sandboxed iframe. + youTubeEndpoint = [this.config.lmsRootURL, '/courses/yt_video_metadata', '?id=', url].join(''); + } return $.ajax({ - url: [this.config.lmsRootURL, '/courses/yt_video_metadata', '?id=', url].join(''), + url: youTubeEndpoint, success: _.isFunction(callback) ? callback : null, error: function() { console.warn( diff --git a/common/lib/xmodule/xmodule/video_module/video_handlers.py b/common/lib/xmodule/xmodule/video_module/video_handlers.py index 8056305f3f..0be32e3081 100644 --- a/common/lib/xmodule/xmodule/video_module/video_handlers.py +++ b/common/lib/xmodule/xmodule/video_module/video_handlers.py @@ -377,6 +377,19 @@ class VideoStudentViewHandlers(object): return response + @XBlock.handler + def yt_video_metadata(self, request, suffix=''): + """ + Endpoint to get YouTube metadata. + This handler is only used in the Blockstore-based runtime. The old + runtime uses a similar REST API that's not an XBlock handler. + """ + from lms.djangoapps.courseware.views.views import load_metadata_from_youtube + metadata, status_code = load_metadata_from_youtube(video_id=self.youtube_id_1_0) + response = Response(json.dumps(metadata), status=status_code) + response.content_type = 'application/json' + return response + class VideoStudioViewHandlers(object): """ diff --git a/common/lib/xmodule/xmodule/video_module/video_module.py b/common/lib/xmodule/xmodule/video_module/video_module.py index 9ca7624555..7ac946e19b 100644 --- a/common/lib/xmodule/xmodule/video_module/video_module.py +++ b/common/lib/xmodule/xmodule/video_module/video_module.py @@ -415,6 +415,13 @@ class VideoBlock( 'ytTestTimeout': settings.YOUTUBE['TEST_TIMEOUT'], 'ytApiUrl': settings.YOUTUBE['API'], 'lmsRootURL': settings.LMS_ROOT_URL, + 'ytMetadataEndpoint': ( + # In the new runtime, get YouTube metadata via a handler. The handler supports anonymous users and + # can work in sandboxed iframes. In the old runtime, the JS will call the LMS's yt_video_metadata + # API endpoint directly (not an XBlock handler). + self.runtime.handler_url(self, 'yt_video_metadata') + if getattr(self.runtime, 'suppports_state_for_anonymous_users', False) else '' + ), 'transcriptTranslationUrl': self.runtime.handler_url( self, 'transcript', 'translation/__lang__' diff --git a/lms/djangoapps/courseware/tests/test_video_mongo.py b/lms/djangoapps/courseware/tests/test_video_mongo.py index e2f6b41634..2c8b9b47fa 100644 --- a/lms/djangoapps/courseware/tests/test_video_mongo.py +++ b/lms/djangoapps/courseware/tests/test_video_mongo.py @@ -111,6 +111,7 @@ class TestVideoYouTube(TestVideo): # pylint: disable=test-inherits-tests 'end': 3610.0, 'transcriptLanguage': 'en', 'transcriptLanguages': OrderedDict({'en': 'English', 'uk': u'Українська'}), + 'ytMetadataEndpoint': '', 'ytTestTimeout': 1500, 'ytApiUrl': 'https://www.youtube.com/iframe_api', 'lmsRootURL': settings.LMS_ROOT_URL, @@ -194,6 +195,7 @@ class TestVideoNonYouTube(TestVideo): # pylint: disable=test-inherits-tests 'end': 3610.0, 'transcriptLanguage': 'en', 'transcriptLanguages': OrderedDict({'en': 'English'}), + 'ytMetadataEndpoint': '', 'ytTestTimeout': 1500, 'ytApiUrl': 'https://www.youtube.com/iframe_api', 'lmsRootURL': settings.LMS_ROOT_URL, @@ -257,6 +259,7 @@ class TestGetHtmlMethod(BaseTestVideoXBlock): 'end': 3610.0, 'transcriptLanguage': 'en', 'transcriptLanguages': OrderedDict({'en': 'English'}), + 'ytMetadataEndpoint': '', 'ytTestTimeout': 1500, 'ytApiUrl': 'https://www.youtube.com/iframe_api', 'lmsRootURL': settings.LMS_ROOT_URL, @@ -2236,6 +2239,7 @@ class TestVideoWithBumper(TestVideo): # pylint: disable=test-inherits-tests 'end': 3610.0, 'transcriptLanguage': 'en', 'transcriptLanguages': OrderedDict({'en': 'English', 'uk': u'Українська'}), + 'ytMetadataEndpoint': '', 'ytTestTimeout': 1500, 'ytApiUrl': 'https://www.youtube.com/iframe_api', 'lmsRootURL': settings.LMS_ROOT_URL, @@ -2311,6 +2315,7 @@ class TestAutoAdvanceVideo(TestVideo): 'end': 3610.0, 'transcriptLanguage': 'en', 'transcriptLanguages': OrderedDict({'en': 'English', 'uk': u'Українська'}), + 'ytMetadataEndpoint': '', 'ytTestTimeout': 1500, 'ytApiUrl': 'https://www.youtube.com/iframe_api', 'lmsRootURL': settings.LMS_ROOT_URL, diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py index bf801c917b..e2c17c73a8 100644 --- a/lms/djangoapps/courseware/views/views.py +++ b/lms/djangoapps/courseware/views/views.py @@ -280,10 +280,21 @@ def yt_video_metadata(request): Will hit the youtube API if the key is available in settings :return: youtube video metadata """ - response = {} - status_code = 500 video_id = request.GET.get('id', None) - if settings.YOUTUBE_API_KEY and video_id: + metadata, status_code = load_metadata_from_youtube(video_id) + return Response(metadata, status=status_code, content_type='application/json') + + +def load_metadata_from_youtube(video_id): + """ + Get metadata about a YouTube video. + + This method is used via the standalone /courses/yt_video_metadata REST API + endpoint, or via the video XBlock as a its 'yt_video_metadata' handler. + """ + metadata = {} + status_code = 500 + if video_id and settings.YOUTUBE_API_KEY and settings.YOUTUBE_API_KEY != 'PUT_YOUR_API_KEY_HERE': yt_api_key = settings.YOUTUBE_API_KEY yt_metadata_url = settings.YOUTUBE['METADATA_URL'] yt_timeout = settings.YOUTUBE.get('TEST_TIMEOUT', 1500) / 1000 # converting milli seconds to seconds @@ -295,7 +306,7 @@ def yt_video_metadata(request): try: res_json = res.json() if res_json.get('items', []): - response = res_json + metadata = res_json else: logging.warning(u'Unable to find the items in response. Following response ' u'was received: {res}'.format(res=res.text)) @@ -310,7 +321,7 @@ def yt_video_metadata(request): else: logging.warning(u'YouTube API key or video id is None. Please make sure API key and video id is not None') - return Response(response, status=status_code, content_type='application/json') + return metadata, status_code @ensure_csrf_cookie