Merge pull request #22837 from open-craft/youtube-metadata-new-runtime

Add way to get YouTube metadata that doesn't require a session cookie
This commit is contained in:
David Ormsbee
2020-01-17 11:02:05 -05:00
committed by GitHub
5 changed files with 50 additions and 6 deletions

View File

@@ -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(

View File

@@ -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):
"""

View File

@@ -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__'

View File

@@ -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,

View File

@@ -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