diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py
index 09413be7b7..2ffd5a3684 100644
--- a/cms/djangoapps/contentstore/tests/test_contentstore.py
+++ b/cms/djangoapps/contentstore/tests/test_contentstore.py
@@ -107,8 +107,8 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
expected_types is the list of elements that should appear on the page.
expected_types and component_types should be similar, but not
- exactly the same -- for example, 'videoalpha' in
- component_types should cause 'Video Alpha' to be present.
+ exactly the same -- for example, 'video' in
+ component_types should cause 'Video' to be present.
"""
store = modulestore('direct')
import_from_xml(store, 'common/test/data/', ['simple'])
@@ -143,7 +143,7 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
'Peer Grading Interface'])
def test_advanced_components_require_two_clicks(self):
- self.check_components_on_page(['videoalpha'], ['Video Alpha'])
+ self.check_components_on_page(['video'], ['Video'])
def test_malformed_edit_unit_request(self):
store = modulestore('direct')
@@ -1624,7 +1624,7 @@ class MetadataSaveTestCase(ModuleStoreTestCase):
constructor are correctly persisted.
"""
# We should start with a source field, from the XML's tag
- self.assertIn('source', own_metadata(self.descriptor))
+ self.assertIn('html5_sources', own_metadata(self.descriptor))
attrs_to_strip = {
'show_captions',
'youtube_id_1_0',
@@ -1634,6 +1634,7 @@ class MetadataSaveTestCase(ModuleStoreTestCase):
'start_time',
'end_time',
'source',
+ 'html5_sources',
'track'
}
# We strip out all metadata fields to reproduce a bug where
@@ -1646,11 +1647,11 @@ class MetadataSaveTestCase(ModuleStoreTestCase):
field.delete_from(self.descriptor)
# Assert that we correctly stripped the field
- self.assertNotIn('source', own_metadata(self.descriptor))
+ self.assertNotIn('html5_sources', own_metadata(self.descriptor))
get_modulestore(self.descriptor.location).update_metadata(
self.descriptor.location,
own_metadata(self.descriptor)
)
module = get_modulestore(self.descriptor.location).get_item(self.descriptor.location)
# Assert that get_item correctly sets the metadata
- self.assertIn('source', own_metadata(module))
+ self.assertIn('html5_sources', own_metadata(module))
diff --git a/cms/djangoapps/contentstore/views/component.py b/cms/djangoapps/contentstore/views/component.py
index 7cb503db1e..d7b41acb24 100644
--- a/cms/djangoapps/contentstore/views/component.py
+++ b/cms/djangoapps/contentstore/views/component.py
@@ -49,7 +49,6 @@ NOTE_COMPONENT_TYPES = ['notes']
ADVANCED_COMPONENT_TYPES = [
'annotatable',
'word_cloud',
- 'videoalpha',
'graphical_slider_tool'
] + OPEN_ENDED_COMPONENT_TYPES + NOTE_COMPONENT_TYPES
ADVANCED_COMPONENT_CATEGORY = 'advanced'
diff --git a/common/lib/xmodule/setup.py b/common/lib/xmodule/setup.py
index 6b106dd94d..704de15ea7 100644
--- a/common/lib/xmodule/setup.py
+++ b/common/lib/xmodule/setup.py
@@ -40,7 +40,7 @@ setup(
"timelimit = xmodule.timelimit_module:TimeLimitDescriptor",
"vertical = xmodule.vertical_module:VerticalDescriptor",
"video = xmodule.video_module:VideoDescriptor",
- "videoalpha = xmodule.videoalpha_module:VideoAlphaDescriptor",
+ "videoalpha = xmodule.video_module:VideoDescriptor",
"videodev = xmodule.backcompat_module:TranslateCustomTagDescriptor",
"videosequence = xmodule.seq_module:SequenceDescriptor",
"discussion = xmodule.discussion_module:DiscussionDescriptor",
diff --git a/common/lib/xmodule/xmodule/tests/test_editing_module.py b/common/lib/xmodule/xmodule/tests/test_editing_module.py
index 03e257940f..838a4f9ada 100644
--- a/common/lib/xmodule/xmodule/tests/test_editing_module.py
+++ b/common/lib/xmodule/xmodule/tests/test_editing_module.py
@@ -33,7 +33,7 @@ class TabsEditingDescriptorTestCase(unittest.TestCase):
},
{
'name': "Subtitles",
- 'template': "videoalpha/subtitles.html",
+ 'template': "video/subtitles.html",
},
{
'name': "Settings",
diff --git a/common/lib/xmodule/xmodule/tests/test_videoalpha.py b/common/lib/xmodule/xmodule/tests/test_video.py
similarity index 78%
rename from common/lib/xmodule/xmodule/tests/test_videoalpha.py
rename to common/lib/xmodule/xmodule/tests/test_video.py
index 76f86d6d4a..baafc05d45 100644
--- a/common/lib/xmodule/xmodule/tests/test_videoalpha.py
+++ b/common/lib/xmodule/xmodule/tests/test_video.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#pylint: disable=W0212
-"""Test for Video Alpha Xmodule functional logic.
+"""Test for Video Xmodule functional logic.
These test data read from xml, not from mongo.
We have a ModuleStoreTestCase class defined in
@@ -17,37 +17,36 @@ import unittest
from . import LogicTest
from .import get_test_system
from xmodule.modulestore import Location
-from xmodule.videoalpha_module import VideoAlphaDescriptor, _create_youtube_string
-from xmodule.video_module import VideoDescriptor
+from xmodule.video_module import VideoDescriptor, _create_youtube_string
from .test_import import DummySystem
from textwrap import dedent
-class VideoAlphaModuleTest(LogicTest):
- """Logic tests for VideoAlpha Xmodule."""
- descriptor_class = VideoAlphaDescriptor
+class VideoModuleTest(LogicTest):
+ """Logic tests for Video Xmodule."""
+ descriptor_class = VideoDescriptor
raw_model_data = {
- 'data': ''
+ 'data': ''
}
def test_parse_time_empty(self):
"""Ensure parse_time returns correctly with None or empty string."""
expected = ''
- self.assertEqual(VideoAlphaDescriptor._parse_time(None), expected)
- self.assertEqual(VideoAlphaDescriptor._parse_time(''), expected)
+ self.assertEqual(VideoDescriptor._parse_time(None), expected)
+ self.assertEqual(VideoDescriptor._parse_time(''), expected)
def test_parse_time(self):
"""Ensure that times are parsed correctly into seconds."""
expected = 247
- output = VideoAlphaDescriptor._parse_time('00:04:07')
+ output = VideoDescriptor._parse_time('00:04:07')
self.assertEqual(output, expected)
def test_parse_youtube(self):
"""Test parsing old-style Youtube ID strings into a dict."""
youtube_str = '0.75:jNCf2gIqpeE,1.00:ZwkTiUPN0mg,1.25:rsq9auxASqI,1.50:kMyNdzVHHgg'
- output = VideoAlphaDescriptor._parse_youtube(youtube_str)
+ output = VideoDescriptor._parse_youtube(youtube_str)
self.assertEqual(output, {'0.75': 'jNCf2gIqpeE',
'1.00': 'ZwkTiUPN0mg',
'1.25': 'rsq9auxASqI',
@@ -59,7 +58,7 @@ class VideoAlphaModuleTest(LogicTest):
empty string.
"""
youtube_str = '0.75:jNCf2gIqpeE'
- output = VideoAlphaDescriptor._parse_youtube(youtube_str)
+ output = VideoDescriptor._parse_youtube(youtube_str)
self.assertEqual(output, {'0.75': 'jNCf2gIqpeE',
'1.00': '',
'1.25': '',
@@ -72,8 +71,8 @@ class VideoAlphaModuleTest(LogicTest):
youtube_str = '1.00:p2Q6BrNhdh8'
youtube_str_hack = '1.0:p2Q6BrNhdh8'
self.assertEqual(
- VideoAlphaDescriptor._parse_youtube(youtube_str),
- VideoAlphaDescriptor._parse_youtube(youtube_str_hack)
+ VideoDescriptor._parse_youtube(youtube_str),
+ VideoDescriptor._parse_youtube(youtube_str_hack)
)
def test_parse_youtube_empty(self):
@@ -82,7 +81,7 @@ class VideoAlphaModuleTest(LogicTest):
that well.
"""
self.assertEqual(
- VideoAlphaDescriptor._parse_youtube(''),
+ VideoDescriptor._parse_youtube(''),
{'0.75': '',
'1.00': '',
'1.25': '',
@@ -90,12 +89,12 @@ class VideoAlphaModuleTest(LogicTest):
)
-class VideoAlphaDescriptorTest(unittest.TestCase):
- """Test for VideoAlphaDescriptor"""
+class VideoDescriptorTest(unittest.TestCase):
+ """Test for VideoDescriptor"""
def setUp(self):
system = get_test_system()
- self.descriptor = VideoAlphaDescriptor(
+ self.descriptor = VideoDescriptor(
runtime=system,
model_data={})
@@ -117,9 +116,9 @@ class VideoAlphaDescriptorTest(unittest.TestCase):
back out to XML.
"""
system = DummySystem(load_error_modules=True)
- location = Location(["i4x", "edX", "videoalpha", "default", "SampleProblem1"])
+ location = Location(["i4x", "edX", "video", "default", "SampleProblem1"])
model_data = {'location': location}
- descriptor = VideoAlphaDescriptor(system, model_data)
+ descriptor = VideoDescriptor(system, model_data)
descriptor.youtube_id_0_75 = 'izygArpw-Qo'
descriptor.youtube_id_1_0 = 'p2Q6BrNhdh8'
descriptor.youtube_id_1_25 = '1EeWXzPdhSA'
@@ -133,9 +132,9 @@ class VideoAlphaDescriptorTest(unittest.TestCase):
in the output string.
"""
system = DummySystem(load_error_modules=True)
- location = Location(["i4x", "edX", "videoalpha", "default", "SampleProblem1"])
+ location = Location(["i4x", "edX", "video", "default", "SampleProblem1"])
model_data = {'location': location}
- descriptor = VideoAlphaDescriptor(system, model_data)
+ descriptor = VideoDescriptor(system, model_data)
descriptor.youtube_id_0_75 = 'izygArpw-Qo'
descriptor.youtube_id_1_0 = 'p2Q6BrNhdh8'
descriptor.youtube_id_1_25 = '1EeWXzPdhSA'
@@ -143,9 +142,9 @@ class VideoAlphaDescriptorTest(unittest.TestCase):
self.assertEqual(_create_youtube_string(descriptor), expected)
-class VideoAlphaDescriptorImportTestCase(unittest.TestCase):
+class VideoDescriptorImportTestCase(unittest.TestCase):
"""
- Make sure that VideoAlphaDescriptor can import an old XML-based video correctly.
+ Make sure that VideoDescriptor can import an old XML-based video correctly.
"""
def assert_attributes_equal(self, video, attrs):
@@ -158,7 +157,7 @@ class VideoAlphaDescriptorImportTestCase(unittest.TestCase):
def test_constructor(self):
sample_xml = '''
-
-
+
'''
- location = Location(["i4x", "edX", "videoalpha", "default",
+ location = Location(["i4x", "edX", "video", "default",
"SampleProblem1"])
model_data = {'data': sample_xml,
'location': location}
system = DummySystem(load_error_modules=True)
- descriptor = VideoAlphaDescriptor(system, model_data)
+ descriptor = VideoDescriptor(system, model_data)
self.assert_attributes_equal(descriptor, {
'youtube_id_0_75': 'izygArpw-Qo',
'youtube_id_1_0': 'p2Q6BrNhdh8',
@@ -190,16 +189,16 @@ class VideoAlphaDescriptorImportTestCase(unittest.TestCase):
def test_from_xml(self):
module_system = DummySystem(load_error_modules=True)
xml_data = '''
-
-
+
'''
- output = VideoAlphaDescriptor.from_xml(xml_data, module_system)
+ output = VideoDescriptor.from_xml(xml_data, module_system)
self.assert_attributes_equal(output, {
'youtube_id_0_75': 'izygArpw-Qo',
'youtube_id_1_0': 'p2Q6BrNhdh8',
@@ -221,14 +220,14 @@ class VideoAlphaDescriptorImportTestCase(unittest.TestCase):
"""
module_system = DummySystem(load_error_modules=True)
xml_data = '''
-
-
+
'''
- output = VideoAlphaDescriptor.from_xml(xml_data, module_system)
+ output = VideoDescriptor.from_xml(xml_data, module_system)
self.assert_attributes_equal(output, {
'youtube_id_0_75': '',
'youtube_id_1_0': 'p2Q6BrNhdh8',
@@ -248,8 +247,8 @@ class VideoAlphaDescriptorImportTestCase(unittest.TestCase):
Make sure settings are correct if none are explicitly set in XML.
"""
module_system = DummySystem(load_error_modules=True)
- xml_data = ''
- output = VideoAlphaDescriptor.from_xml(xml_data, module_system)
+ xml_data = ''
+ output = VideoDescriptor.from_xml(xml_data, module_system)
self.assert_attributes_equal(output, {
'youtube_id_0_75': '',
'youtube_id_1_0': 'OEoXaMPEzfM',
@@ -270,16 +269,16 @@ class VideoAlphaDescriptorImportTestCase(unittest.TestCase):
"""
module_system = DummySystem(load_error_modules=True)
xml_data = """
-
-
+
"""
- output = VideoAlphaDescriptor.from_xml(xml_data, module_system)
+ output = VideoDescriptor.from_xml(xml_data, module_system)
self.assert_attributes_equal(output, {
'youtube_id_0_75': 'izygArpw-Qo',
'youtube_id_1_0': 'p2Q6BrNhdh8',
@@ -295,7 +294,7 @@ class VideoAlphaDescriptorImportTestCase(unittest.TestCase):
def test_old_video_data(self):
"""
- Ensure that Video Alpha is able to read VideoModule's model data.
+ Ensure that Video is able to read VideoModule's model data.
"""
module_system = DummySystem(load_error_modules=True)
xml_data = """
@@ -309,8 +308,7 @@ class VideoAlphaDescriptorImportTestCase(unittest.TestCase):
"""
video = VideoDescriptor.from_xml(xml_data, module_system)
- video_alpha = VideoAlphaDescriptor(module_system, video._model_data)
- self.assert_attributes_equal(video_alpha, {
+ self.assert_attributes_equal(video, {
'youtube_id_0_75': 'izygArpw-Qo',
'youtube_id_1_0': 'p2Q6BrNhdh8',
'youtube_id_1_25': '1EeWXzPdhSA',
@@ -324,17 +322,17 @@ class VideoAlphaDescriptorImportTestCase(unittest.TestCase):
})
-class VideoAlphaExportTestCase(unittest.TestCase):
+class VideoExportTestCase(unittest.TestCase):
"""
- Make sure that VideoAlphaDescriptor can export itself to XML
+ Make sure that VideoDescriptor can export itself to XML
correctly.
"""
def test_export_to_xml(self):
"""Test that we write the correct XML on export."""
module_system = DummySystem(load_error_modules=True)
- location = Location(["i4x", "edX", "videoalpha", "default", "SampleProblem1"])
- desc = VideoAlphaDescriptor(module_system, {'location': location})
+ location = Location(["i4x", "edX", "video", "default", "SampleProblem1"])
+ desc = VideoDescriptor(module_system, {'location': location})
desc.youtube_id_0_75 = 'izygArpw-Qo'
desc.youtube_id_1_0 = 'p2Q6BrNhdh8'
@@ -348,11 +346,11 @@ class VideoAlphaExportTestCase(unittest.TestCase):
xml = desc.export_to_xml(None) # We don't use the `resource_fs` parameter
expected = dedent('''\
-
+
+
''')
self.assertEquals(expected, xml)
@@ -360,10 +358,10 @@ class VideoAlphaExportTestCase(unittest.TestCase):
def test_export_to_xml_empty_parameters(self):
"""Test XML export with defaults."""
module_system = DummySystem(load_error_modules=True)
- location = Location(["i4x", "edX", "videoalpha", "default", "SampleProblem1"])
- desc = VideoAlphaDescriptor(module_system, {'location': location})
+ location = Location(["i4x", "edX", "video", "default", "SampleProblem1"])
+ desc = VideoDescriptor(module_system, {'location': location})
xml = desc.export_to_xml(None)
- expected = '\n'
+ expected = '\n'
self.assertEquals(expected, xml)
diff --git a/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py b/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py
index 90ff209c7d..c98f980c62 100644
--- a/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py
+++ b/common/lib/xmodule/xmodule/tests/test_xblock_wrappers.py
@@ -16,10 +16,9 @@ from xmodule.gst_module import GraphicalSliderToolDescriptor
from xmodule.html_module import HtmlDescriptor
from xmodule.peer_grading_module import PeerGradingDescriptor
from xmodule.poll_module import PollDescriptor
-from xmodule.video_module import VideoDescriptor
from xmodule.word_cloud_module import WordCloudDescriptor
from xmodule.crowdsource_hinter import CrowdsourceHinterDescriptor
-from xmodule.videoalpha_module import VideoAlphaDescriptor
+from xmodule.video_module import VideoDescriptor
from xmodule.seq_module import SequenceDescriptor
from xmodule.conditional_module import ConditionalDescriptor
from xmodule.randomize_module import RandomizeDescriptor
@@ -35,9 +34,8 @@ LEAF_XMODULES = (
HtmlDescriptor,
PeerGradingDescriptor,
PollDescriptor,
- VideoDescriptor,
# This is being excluded because it has dependencies on django
- #VideoAlphaDescriptor,
+ #VideoDescriptor,
WordCloudDescriptor,
)
diff --git a/common/lib/xmodule/xmodule/video_module.py b/common/lib/xmodule/xmodule/video_module.py
index 763975fc3b..c18d6d066b 100644
--- a/common/lib/xmodule/xmodule/video_module.py
+++ b/common/lib/xmodule/xmodule/video_module.py
@@ -1,20 +1,34 @@
# pylint: disable=W0223
-"""Video is ungraded Xmodule for support video content."""
+"""Video is ungraded Xmodule for support video content.
+It's new improved video module, which support additional feature:
+
+- Can play non-YouTube video sources via in-browser HTML5 video player.
+- YouTube defaults to HTML5 mode from the start.
+- Speed changes in both YouTube and non-YouTube videos happen via
+in-browser HTML5 video method (when in HTML5 mode).
+- Navigational subtitles can be disabled altogether via an attribute
+in XML.
+"""
import json
import logging
from lxml import etree
-from pkg_resources import resource_string, resource_listdir
-import datetime
-import time
+from pkg_resources import resource_string
from django.http import Http404
+from django.conf import settings
from xmodule.x_module import XModule
+from xmodule.editing_module import TabsEditingDescriptor
from xmodule.raw_module import EmptyDataRawDescriptor
-from xmodule.editing_module import MetadataOnlyEditingDescriptor
-from xblock.core import Integer, Scope, String, Float, Boolean
+from xmodule.modulestore.mongo import MongoModuleStore
+from xmodule.modulestore.django import modulestore
+from xmodule.contentstore.content import StaticContent
+from xblock.core import Scope, String, Boolean, Float, List, Integer
+
+import datetime
+import time
log = logging.getLogger(__name__)
@@ -22,51 +36,118 @@ log = logging.getLogger(__name__)
class VideoFields(object):
"""Fields for `VideoModule` and `VideoDescriptor`."""
display_name = String(
- display_name="Display Name",
- help="This name appears in the horizontal navigation at the top of the page.",
+ display_name="Display Name", help="Display name for this module.",
+ default="Video",
+ scope=Scope.settings
+ )
+ position = Integer(
+ help="Current position in the video",
+ scope=Scope.user_state,
+ default=0
+ )
+ show_captions = Boolean(
+ help="This controls whether or not captions are shown by default.",
+ display_name="Show Captions",
scope=Scope.settings,
- # it'd be nice to have a useful default but it screws up other things; so,
- # use display_name_with_default for those
- default="Video"
+ default=True
)
- data = String(
- help="XML data for the problem",
- default='',
- scope=Scope.content
+ # TODO: This should be moved to Scope.content, but this will
+ # require data migration to support the old video module.
+ youtube_id_1_0 = String(
+ help="This is the Youtube ID reference for the normal speed video.",
+ display_name="Youtube ID",
+ scope=Scope.settings,
+ default="OEoXaMPEzfM"
+ )
+ youtube_id_0_75 = String(
+ help="The Youtube ID for the .75x speed video.",
+ display_name="Youtube ID for .75x speed",
+ scope=Scope.settings,
+ default=""
+ )
+ youtube_id_1_25 = String(
+ help="The Youtube ID for the 1.25x speed video.",
+ display_name="Youtube ID for 1.25x speed",
+ scope=Scope.settings,
+ default=""
+ )
+ youtube_id_1_5 = String(
+ help="The Youtube ID for the 1.5x speed video.",
+ display_name="Youtube ID for 1.5x speed",
+ scope=Scope.settings,
+ default=""
+ )
+ start_time = Float(
+ help="Start time for the video.",
+ display_name="Start Time",
+ scope=Scope.settings,
+ default=0.0
+ )
+ end_time = Float(
+ help="End time for the video.",
+ display_name="End Time",
+ scope=Scope.settings,
+ default=0.0
+ )
+ source = String(
+ help="The external URL to download the video. This appears as a link beneath the video.",
+ display_name="Download Video",
+ scope=Scope.settings,
+ default=""
+ )
+ html5_sources = List(
+ help="A list of filenames to be used with HTML5 video. The first supported filetype will be displayed.",
+ display_name="Video Sources",
+ scope=Scope.settings,
+ default=[]
+ )
+ track = String(
+ help="The external URL to download the subtitle track. This appears as a link beneath the video.",
+ display_name="Download Track",
+ scope=Scope.settings,
+ default=""
+ )
+ sub = String(
+ help="The name of the subtitle track (for non-Youtube videos).",
+ display_name="HTML5 Subtitles",
+ scope=Scope.settings,
+ default=""
)
- position = Integer(help="Current position in the video", scope=Scope.user_state, default=0)
- show_captions = Boolean(help="This controls whether or not captions are shown by default.", display_name="Show Captions", scope=Scope.settings, default=True)
- youtube_id_1_0 = String(help="This is the Youtube ID reference for the normal speed video.", display_name="Default Speed", scope=Scope.settings, default="OEoXaMPEzfM")
- youtube_id_0_75 = String(help="The Youtube ID for the .75x speed video.", display_name="Speed: .75x", scope=Scope.settings, default="")
- youtube_id_1_25 = String(help="The Youtube ID for the 1.25x speed video.", display_name="Speed: 1.25x", scope=Scope.settings, default="")
- youtube_id_1_5 = String(help="The Youtube ID for the 1.5x speed video.", display_name="Speed: 1.5x", scope=Scope.settings, default="")
- start_time = Float(help="Time the video starts", display_name="Start Time", scope=Scope.settings, default=0.0)
- end_time = Float(help="Time the video ends", display_name="End Time", scope=Scope.settings, default=0.0)
- source = String(help="The external URL to download the video. This appears as a link beneath the video.", display_name="Download Video", scope=Scope.settings, default="")
- track = String(help="The external URL to download the subtitle track. This appears as a link beneath the video.", display_name="Download Track", scope=Scope.settings, default="")
class VideoModule(VideoFields, XModule):
- """Video Xmodule."""
+ """
+ XML source example:
+
+
+ """
video_time = 0
icon_class = 'video'
js = {
- 'coffee': [
- resource_string(__name__, 'js/src/time.coffee'),
- resource_string(__name__, 'js/src/video/display.coffee')
- ] +
- [resource_string(__name__, 'js/src/video/display/' + filename)
- for filename
- in sorted(resource_listdir(__name__, 'js/src/video/display'))
- if filename.endswith('.coffee')]
+ 'js': [
+ resource_string(__name__, 'js/src/video/01_initialize.js'),
+ resource_string(__name__, 'js/src/video/02_html5_video.js'),
+ resource_string(__name__, 'js/src/video/03_video_player.js'),
+ resource_string(__name__, 'js/src/video/04_video_control.js'),
+ resource_string(__name__, 'js/src/video/05_video_quality_control.js'),
+ resource_string(__name__, 'js/src/video/06_video_progress_slider.js'),
+ resource_string(__name__, 'js/src/video/07_video_volume_control.js'),
+ resource_string(__name__, 'js/src/video/08_video_speed_control.js'),
+ resource_string(__name__, 'js/src/video/09_video_caption.js'),
+ resource_string(__name__, 'js/src/video/10_main.js')
+ ]
}
css = {'scss': [resource_string(__name__, 'css/video/display.scss')]}
js_module_name = "Video"
- def __init__(self, *args, **kwargs):
- XModule.__init__(self, *args, **kwargs)
-
def handle_ajax(self, dispatch, data):
"""This is not being called right now and we raise 404 error."""
log.debug(u"GET {0}".format(data))
@@ -78,41 +159,59 @@ class VideoModule(VideoFields, XModule):
return json.dumps({'position': self.position})
def get_html(self):
+ if isinstance(modulestore(), MongoModuleStore):
+ caption_asset_path = StaticContent.get_base_url_path_for_course_assets(self.location) + '/subs_'
+ else:
+ # VS[compat]
+ # cdodge: filesystem static content support.
+ caption_asset_path = "/static/subs/"
+
+ get_ext = lambda filename: filename.rpartition('.')[-1]
+ sources = {get_ext(src): src for src in self.html5_sources}
+ sources['main'] = self.source
+
return self.system.render_template('video.html', {
- 'youtube_id_0_75': self.youtube_id_0_75,
- 'youtube_id_1_0': self.youtube_id_1_0,
- 'youtube_id_1_25': self.youtube_id_1_25,
- 'youtube_id_1_5': self.youtube_id_1_5,
+ 'youtube_streams': _create_youtube_string(self),
'id': self.location.html_id(),
- 'position': self.position,
- 'source': self.source,
+ 'sub': self.sub,
+ 'sources': sources,
'track': self.track,
'display_name': self.display_name_with_default,
- 'caption_asset_path': "/static/subs/",
- 'show_captions': 'true' if self.show_captions else 'false',
+ # This won't work when we move to data that
+ # isn't on the filesystem
+ 'data_dir': getattr(self, 'data_dir', None),
+ 'caption_asset_path': caption_asset_path,
+ 'show_captions': json.dumps(self.show_captions),
'start': self.start_time,
- 'end': self.end_time
+ 'end': self.end_time,
+ 'autoplay': settings.MITX_FEATURES.get('AUTOPLAY_VIDEOS', True)
})
-class VideoDescriptor(VideoFields,
- MetadataOnlyEditingDescriptor,
- EmptyDataRawDescriptor):
+class VideoDescriptor(VideoFields, TabsEditingDescriptor, EmptyDataRawDescriptor):
+ """Descriptor for `VideoModule`."""
module_class = VideoModule
+ tabs = [
+ # {
+ # 'name': "Subtitles",
+ # 'template': "video/subtitles.html",
+ # },
+ {
+ 'name': "Settings",
+ 'template': "tabs/metadata-edit-tab.html",
+ 'current': True
+ }
+ ]
+
def __init__(self, *args, **kwargs):
super(VideoDescriptor, self).__init__(*args, **kwargs)
- # If we don't have a `youtube_id_1_0`, this is an XML course
- # and we parse out the fields.
- if self.data and 'youtube_id_1_0' not in self._model_data:
- _parse_video_xml(self, self.data)
-
- @property
- def non_editable_metadata_fields(self):
- non_editable_fields = super(MetadataOnlyEditingDescriptor, self).non_editable_metadata_fields
- non_editable_fields.extend([VideoModule.start_time,
- VideoModule.end_time])
- return non_editable_fields
+ # For backwards compatibility -- if we've got XML data, parse
+ # it out and set the metadata fields
+ if self.data:
+ model_data = VideoDescriptor._parse_video_xml(self.data)
+ self._model_data.update(model_data)
+ del self.data
@classmethod
def from_xml(cls, xml_data, system, org=None, course=None):
@@ -126,102 +225,143 @@ class VideoDescriptor(VideoFields,
org and course are optional strings that will be used in the generated modules
url identifiers
"""
+ # Calling from_xml of XmlDescritor, to get right Location, when importing from XML
video = super(VideoDescriptor, cls).from_xml(xml_data, system, org, course)
- _parse_video_xml(video, video.data)
return video
+ def export_to_xml(self, resource_fs):
+ """
+ Returns an xml string representing this module.
+ """
+ xml = etree.Element('video')
+ attrs = {
+ 'display_name': self.display_name,
+ 'show_captions': json.dumps(self.show_captions),
+ 'youtube': _create_youtube_string(self),
+ 'start_time': datetime.timedelta(seconds=self.start_time),
+ 'end_time': datetime.timedelta(seconds=self.end_time),
+ 'sub': self.sub
+ }
+ for key, value in attrs.items():
+ if value:
+ xml.set(key, str(value))
-def _parse_video_xml(video, xml_data):
- """
- Parse video fields out of xml_data. The fields are set if they are
- present in the XML.
- """
- if not xml_data:
- return
+ for source in self.html5_sources:
+ ele = etree.Element('source')
+ ele.set('src', source)
+ xml.append(ele)
- xml = etree.fromstring(xml_data)
+ if self.track:
+ ele = etree.Element('track')
+ ele.set('src', self.track)
+ xml.append(ele)
- display_name = xml.get('display_name')
- if display_name:
- video.display_name = display_name
+ return etree.tostring(xml, pretty_print=True)
- youtube = xml.get('youtube')
- if youtube:
- speeds = _parse_youtube(youtube)
- if speeds['0.75']:
- video.youtube_id_0_75 = speeds['0.75']
- if speeds['1.00']:
- video.youtube_id_1_0 = speeds['1.00']
- if speeds['1.25']:
- video.youtube_id_1_25 = speeds['1.25']
- if speeds['1.50']:
- video.youtube_id_1_5 = speeds['1.50']
-
- show_captions = xml.get('show_captions')
- if show_captions:
- video.show_captions = json.loads(show_captions)
-
- source = _get_first_external(xml, 'source')
- if source:
- video.source = source
-
- track = _get_first_external(xml, 'track')
- if track:
- video.track = track
-
- start_time = _parse_time(xml.get('from'))
- if start_time:
- video.start_time = start_time
-
- end_time = _parse_time(xml.get('to'))
- if end_time:
- video.end_time = end_time
-
-
-def _get_first_external(xmltree, tag):
- """
- Returns the src attribute of the nested `tag` in `xmltree`, if it
- exists.
- """
- for element in xmltree.findall(tag):
- src = element.get('src')
- if src:
- return src
- return None
-
-
-def _parse_youtube(data):
- """
- Parses a string of Youtube IDs such as "1.0:AXdE34_U,1.5:VO3SxfeD"
- into a dictionary. Necessary for backwards compatibility with
- XML-based courses.
- """
- ret = {'0.75': '', '1.00': '', '1.25': '', '1.50': ''}
- if data == '':
+ @staticmethod
+ def _parse_youtube(data):
+ """
+ Parses a string of Youtube IDs such as "1.0:AXdE34_U,1.5:VO3SxfeD"
+ into a dictionary. Necessary for backwards compatibility with
+ XML-based courses.
+ """
+ ret = {'0.75': '', '1.00': '', '1.25': '', '1.50': ''}
+ if data == '':
+ return ret
+ videos = data.split(',')
+ for video in videos:
+ pieces = video.split(':')
+ # HACK
+ # To elaborate somewhat: in many LMS tests, the keys for
+ # Youtube IDs are inconsistent. Sometimes a particular
+ # speed isn't present, and formatting is also inconsistent
+ # ('1.0' versus '1.00'). So it's necessary to either do
+ # something like this or update all the tests to work
+ # properly.
+ ret['%.2f' % float(pieces[0])] = pieces[1]
return ret
- videos = data.split(',')
- for video in videos:
- pieces = video.split(':')
- # HACK
- # To elaborate somewhat: in many LMS tests, the keys for
- # Youtube IDs are inconsistent. Sometimes a particular
- # speed isn't present, and formatting is also inconsistent
- # ('1.0' versus '1.00'). So it's necessary to either do
- # something like this or update all the tests to work
- # properly.
- ret['%.2f' % float(pieces[0])] = pieces[1]
- return ret
+
+ @staticmethod
+ def _parse_video_xml(xml_data):
+ """
+ Parse video fields out of xml_data. The fields are set if they are
+ present in the XML.
+ """
+ xml = etree.fromstring(xml_data)
+ model_data = {}
+
+ conversions = {
+ 'show_captions': json.loads,
+ 'start_time': VideoDescriptor._parse_time,
+ 'end_time': VideoDescriptor._parse_time
+ }
+
+ # VideoModule and VideoModule use different names for
+ # these attributes -- need to convert between them
+ video_compat = {
+ 'from': 'start_time',
+ 'to': 'end_time'
+ }
+
+ sources = xml.findall('source')
+ if sources:
+ model_data['html5_sources'] = [ele.get('src') for ele in sources]
+ model_data['source'] = model_data['html5_sources'][0]
+
+ track = xml.find('track')
+ if track is not None:
+ model_data['track'] = track.get('src')
+
+ for attr, value in xml.items():
+ if attr in video_compat:
+ attr = video_compat[attr]
+ if attr == 'youtube':
+ speeds = VideoDescriptor._parse_youtube(value)
+ for speed, youtube_id in speeds.items():
+ # should have made these youtube_id_1_00 for
+ # cleanliness, but hindsight doesn't need glasses
+ normalized_speed = speed[:-1] if speed.endswith('0') else speed
+ # If the user has specified html5 sources, make sure we don't use the default video
+ if youtube_id != '' or 'html5_sources' in model_data:
+ model_data['youtube_id_{0}'.format(normalized_speed.replace('.', '_'))] = youtube_id
+ else:
+ # Convert XML attrs into Python values.
+ if attr in conversions:
+ value = conversions[attr](value)
+ model_data[attr] = value
+
+ return model_data
+
+ @staticmethod
+ def _parse_time(str_time):
+ """Converts s in '12:34:45' format to seconds. If s is
+ None, returns empty string"""
+ if not str_time:
+ return ''
+ else:
+ obj_time = time.strptime(str_time, '%H:%M:%S')
+ return datetime.timedelta(
+ hours=obj_time.tm_hour,
+ minutes=obj_time.tm_min,
+ seconds=obj_time.tm_sec
+ ).total_seconds()
-def _parse_time(str_time):
- """Converts s in '12:34:45' format to seconds. If s is
- None, returns empty string"""
- if str_time is None or str_time == '':
- return ''
- else:
- obj_time = time.strptime(str_time, '%H:%M:%S')
- return datetime.timedelta(
- hours=obj_time.tm_hour,
- minutes=obj_time.tm_min,
- seconds=obj_time.tm_sec
- ).total_seconds()
+def _create_youtube_string(module):
+ """
+ Create a string of Youtube IDs from `module`'s metadata
+ attributes. Only writes a speed if an ID is present in the
+ module. Necessary for backwards compatibility with XML-based
+ courses.
+ """
+ youtube_ids = [
+ module.youtube_id_0_75,
+ module.youtube_id_1_0,
+ module.youtube_id_1_25,
+ module.youtube_id_1_5
+ ]
+ youtube_speeds = ['0.75', '1.00', '1.25', '1.50']
+ return ','.join([':'.join(pair)
+ for pair
+ in zip(youtube_speeds, youtube_ids)
+ if pair[1]])
diff --git a/common/lib/xmodule/xmodule/videoalpha_module.py b/common/lib/xmodule/xmodule/videoalpha_module.py
deleted file mode 100644
index 176b192377..0000000000
--- a/common/lib/xmodule/xmodule/videoalpha_module.py
+++ /dev/null
@@ -1,367 +0,0 @@
-# pylint: disable=W0223
-"""VideoAlpha is ungraded Xmodule for support video content.
-It's new improved video module, which support additional feature:
-
-- Can play non-YouTube video sources via in-browser HTML5 video player.
-- YouTube defaults to HTML5 mode from the start.
-- Speed changes in both YouTube and non-YouTube videos happen via
-in-browser HTML5 video method (when in HTML5 mode).
-- Navigational subtitles can be disabled altogether via an attribute
-in XML.
-"""
-
-import json
-import logging
-
-from lxml import etree
-from pkg_resources import resource_string
-
-from django.http import Http404
-from django.conf import settings
-
-from xmodule.x_module import XModule
-from xmodule.editing_module import TabsEditingDescriptor
-from xmodule.raw_module import EmptyDataRawDescriptor
-from xmodule.modulestore.mongo import MongoModuleStore
-from xmodule.modulestore.django import modulestore
-from xmodule.contentstore.content import StaticContent
-from xblock.core import Scope, String, Boolean, Float, List, Integer
-
-import datetime
-import time
-
-log = logging.getLogger(__name__)
-
-
-class VideoAlphaFields(object):
- """Fields for `VideoAlphaModule` and `VideoAlphaDescriptor`."""
- display_name = String(
- display_name="Display Name", help="Display name for this module.",
- default="Video Alpha",
- scope=Scope.settings
- )
- position = Integer(
- help="Current position in the video",
- scope=Scope.user_state,
- default=0
- )
- show_captions = Boolean(
- help="This controls whether or not captions are shown by default.",
- display_name="Show Captions",
- scope=Scope.settings,
- default=True
- )
- # TODO: This should be moved to Scope.content, but this will
- # require data migration to support the old video module.
- youtube_id_1_0 = String(
- help="This is the Youtube ID reference for the normal speed video.",
- display_name="Youtube ID",
- scope=Scope.settings,
- default="OEoXaMPEzfM"
- )
- youtube_id_0_75 = String(
- help="The Youtube ID for the .75x speed video.",
- display_name="Youtube ID for .75x speed",
- scope=Scope.settings,
- default=""
- )
- youtube_id_1_25 = String(
- help="The Youtube ID for the 1.25x speed video.",
- display_name="Youtube ID for 1.25x speed",
- scope=Scope.settings,
- default=""
- )
- youtube_id_1_5 = String(
- help="The Youtube ID for the 1.5x speed video.",
- display_name="Youtube ID for 1.5x speed",
- scope=Scope.settings,
- default=""
- )
- start_time = Float(
- help="Start time for the video.",
- display_name="Start Time",
- scope=Scope.settings,
- default=0.0
- )
- end_time = Float(
- help="End time for the video.",
- display_name="End Time",
- scope=Scope.settings,
- default=0.0
- )
- source = String(
- help="The external URL to download the video. This appears as a link beneath the video.",
- display_name="Download Video",
- scope=Scope.settings,
- default=""
- )
- html5_sources = List(
- help="A list of filenames to be used with HTML5 video. The first supported filetype will be displayed.",
- display_name="Video Sources",
- scope=Scope.settings,
- default=[]
- )
- track = String(
- help="The external URL to download the subtitle track. This appears as a link beneath the video.",
- display_name="Download Track",
- scope=Scope.settings,
- default=""
- )
- sub = String(
- help="The name of the subtitle track (for non-Youtube videos).",
- display_name="HTML5 Subtitles",
- scope=Scope.settings,
- default=""
- )
-
-
-class VideoAlphaModule(VideoAlphaFields, XModule):
- """
- XML source example:
-
-
-
-
-
-
- """
- video_time = 0
- icon_class = 'video'
-
- js = {
- 'js': [
- resource_string(__name__, 'js/src/videoalpha/01_initialize.js'),
- resource_string(__name__, 'js/src/videoalpha/02_html5_video.js'),
- resource_string(__name__, 'js/src/videoalpha/03_video_player.js'),
- resource_string(__name__, 'js/src/videoalpha/04_video_control.js'),
- resource_string(__name__, 'js/src/videoalpha/05_video_quality_control.js'),
- resource_string(__name__, 'js/src/videoalpha/06_video_progress_slider.js'),
- resource_string(__name__, 'js/src/videoalpha/07_video_volume_control.js'),
- resource_string(__name__, 'js/src/videoalpha/08_video_speed_control.js'),
- resource_string(__name__, 'js/src/videoalpha/09_video_caption.js'),
- resource_string(__name__, 'js/src/videoalpha/10_main.js')
- ]
- }
- css = {'scss': [resource_string(__name__, 'css/videoalpha/display.scss')]}
- js_module_name = "VideoAlpha"
-
- def handle_ajax(self, dispatch, data):
- """This is not being called right now and we raise 404 error."""
- log.debug(u"GET {0}".format(data))
- log.debug(u"DISPATCH {0}".format(dispatch))
- raise Http404()
-
- def get_instance_state(self):
- """Return information about state (position)."""
- return json.dumps({'position': self.position})
-
- def get_html(self):
- if isinstance(modulestore(), MongoModuleStore):
- caption_asset_path = StaticContent.get_base_url_path_for_course_assets(self.location) + '/subs_'
- else:
- # VS[compat]
- # cdodge: filesystem static content support.
- caption_asset_path = "/static/subs/"
-
- get_ext = lambda filename: filename.rpartition('.')[-1]
- sources = {get_ext(src): src for src in self.html5_sources}
- sources['main'] = self.source
-
- return self.system.render_template('videoalpha.html', {
- 'youtube_streams': _create_youtube_string(self),
- 'id': self.location.html_id(),
- 'sub': self.sub,
- 'sources': sources,
- 'track': self.track,
- 'display_name': self.display_name_with_default,
- # This won't work when we move to data that
- # isn't on the filesystem
- 'data_dir': getattr(self, 'data_dir', None),
- 'caption_asset_path': caption_asset_path,
- 'show_captions': json.dumps(self.show_captions),
- 'start': self.start_time,
- 'end': self.end_time,
- 'autoplay': settings.MITX_FEATURES.get('AUTOPLAY_VIDEOS', True)
- })
-
-
-class VideoAlphaDescriptor(VideoAlphaFields, TabsEditingDescriptor, EmptyDataRawDescriptor):
- """Descriptor for `VideoAlphaModule`."""
- module_class = VideoAlphaModule
-
- tabs = [
- # {
- # 'name': "Subtitles",
- # 'template': "videoalpha/subtitles.html",
- # },
- {
- 'name': "Settings",
- 'template': "tabs/metadata-edit-tab.html",
- 'current': True
- }
- ]
-
- def __init__(self, *args, **kwargs):
- super(VideoAlphaDescriptor, self).__init__(*args, **kwargs)
- # For backwards compatibility -- if we've got XML data, parse
- # it out and set the metadata fields
- if self.data:
- model_data = VideoAlphaDescriptor._parse_video_xml(self.data)
- self._model_data.update(model_data)
- del self.data
-
- @classmethod
- def from_xml(cls, xml_data, system, org=None, course=None):
- """
- Creates an instance of this descriptor from the supplied xml_data.
- This may be overridden by subclasses
-
- xml_data: A string of xml that will be translated into data and children for
- this module
- system: A DescriptorSystem for interacting with external resources
- org and course are optional strings that will be used in the generated modules
- url identifiers
- """
- # Calling from_xml of XmlDescritor, to get right Location, when importing from XML
- video = super(VideoAlphaDescriptor, cls).from_xml(xml_data, system, org, course)
- return video
-
- def export_to_xml(self, resource_fs):
- """
- Returns an xml string representing this module.
- """
- xml = etree.Element('videoalpha')
- attrs = {
- 'display_name': self.display_name,
- 'show_captions': json.dumps(self.show_captions),
- 'youtube': _create_youtube_string(self),
- 'start_time': datetime.timedelta(seconds=self.start_time),
- 'end_time': datetime.timedelta(seconds=self.end_time),
- 'sub': self.sub
- }
- for key, value in attrs.items():
- if value:
- xml.set(key, str(value))
-
- for source in self.html5_sources:
- ele = etree.Element('source')
- ele.set('src', source)
- xml.append(ele)
-
- if self.track:
- ele = etree.Element('track')
- ele.set('src', self.track)
- xml.append(ele)
-
- return etree.tostring(xml, pretty_print=True)
-
- @staticmethod
- def _parse_youtube(data):
- """
- Parses a string of Youtube IDs such as "1.0:AXdE34_U,1.5:VO3SxfeD"
- into a dictionary. Necessary for backwards compatibility with
- XML-based courses.
- """
- ret = {'0.75': '', '1.00': '', '1.25': '', '1.50': ''}
- if data == '':
- return ret
- videos = data.split(',')
- for video in videos:
- pieces = video.split(':')
- # HACK
- # To elaborate somewhat: in many LMS tests, the keys for
- # Youtube IDs are inconsistent. Sometimes a particular
- # speed isn't present, and formatting is also inconsistent
- # ('1.0' versus '1.00'). So it's necessary to either do
- # something like this or update all the tests to work
- # properly.
- ret['%.2f' % float(pieces[0])] = pieces[1]
- return ret
-
- @staticmethod
- def _parse_video_xml(xml_data):
- """
- Parse video fields out of xml_data. The fields are set if they are
- present in the XML.
- """
- xml = etree.fromstring(xml_data)
- model_data = {}
-
- conversions = {
- 'show_captions': json.loads,
- 'start_time': VideoAlphaDescriptor._parse_time,
- 'end_time': VideoAlphaDescriptor._parse_time
- }
-
- # VideoModule and VideoAlphaModule use different names for
- # these attributes -- need to convert between them
- video_compat = {
- 'from': 'start_time',
- 'to': 'end_time'
- }
-
- sources = xml.findall('source')
- if sources:
- model_data['html5_sources'] = [ele.get('src') for ele in sources]
- model_data['source'] = model_data['html5_sources'][0]
-
- track = xml.find('track')
- if track is not None:
- model_data['track'] = track.get('src')
-
- for attr, value in xml.items():
- if attr in video_compat:
- attr = video_compat[attr]
- if attr == 'youtube':
- speeds = VideoAlphaDescriptor._parse_youtube(value)
- for speed, youtube_id in speeds.items():
- # should have made these youtube_id_1_00 for
- # cleanliness, but hindsight doesn't need glasses
- normalized_speed = speed[:-1] if speed.endswith('0') else speed
- # If the user has specified html5 sources, make sure we don't use the default video
- if youtube_id != '' or 'html5_sources' in model_data:
- model_data['youtube_id_{0}'.format(normalized_speed.replace('.', '_'))] = youtube_id
- else:
- # Convert XML attrs into Python values.
- if attr in conversions:
- value = conversions[attr](value)
- model_data[attr] = value
-
- return model_data
-
- @staticmethod
- def _parse_time(str_time):
- """Converts s in '12:34:45' format to seconds. If s is
- None, returns empty string"""
- if not str_time:
- return ''
- else:
- obj_time = time.strptime(str_time, '%H:%M:%S')
- return datetime.timedelta(
- hours=obj_time.tm_hour,
- minutes=obj_time.tm_min,
- seconds=obj_time.tm_sec
- ).total_seconds()
-
-
-def _create_youtube_string(module):
- """
- Create a string of Youtube IDs from `module`'s metadata
- attributes. Only writes a speed if an ID is present in the
- module. Necessary for backwards compatibility with XML-based
- courses.
- """
- youtube_ids = [
- module.youtube_id_0_75,
- module.youtube_id_1_0,
- module.youtube_id_1_25,
- module.youtube_id_1_5
- ]
- youtube_speeds = ['0.75', '1.00', '1.25', '1.50']
- return ','.join([':'.join(pair)
- for pair
- in zip(youtube_speeds, youtube_ids)
- if pair[1]])
diff --git a/lms/djangoapps/courseware/tests/test_videoalpha_mongo.py b/lms/djangoapps/courseware/tests/test_video_mongo.py
similarity index 90%
rename from lms/djangoapps/courseware/tests/test_videoalpha_mongo.py
rename to lms/djangoapps/courseware/tests/test_video_mongo.py
index 38b2b6fb8d..2927bfc37a 100644
--- a/lms/djangoapps/courseware/tests/test_videoalpha_mongo.py
+++ b/lms/djangoapps/courseware/tests/test_video_mongo.py
@@ -2,22 +2,22 @@
"""Video xmodule tests in mongo."""
from . import BaseTestXmodule
-from .test_videoalpha_xml import SOURCE_XML
+from .test_video_xml import SOURCE_XML
from django.conf import settings
-from xmodule.videoalpha_module import _create_youtube_string
+from xmodule.video_module import _create_youtube_string
class TestVideo(BaseTestXmodule):
"""Integration tests: web client + mongo."""
- CATEGORY = "videoalpha"
+ CATEGORY = "video"
DATA = SOURCE_XML
MODEL_DATA = {
'data': DATA
}
def setUp(self):
- # Since the VideoAlphaDescriptor changes `self._model_data`,
+ # Since the VideoDescriptor changes `self._model_data`,
# we need to instantiate `self.item_module` through
# `self.item_descriptor` rather than directly constructing it
super(TestVideo, self).setUp()
@@ -40,7 +40,7 @@ class TestVideo(BaseTestXmodule):
]).pop(),
404)
- def test_videoalpha_constructor(self):
+ def test_video_constructor(self):
"""Make sure that all parameters extracted correclty from xml"""
context = self.item_module.get_html()
@@ -74,7 +74,7 @@ class TestVideoNonYouTube(TestVideo):
"""Integration tests: web client + mongo."""
DATA = """
-
-
+
"""
MODEL_DATA = {
'data': DATA
}
- def test_videoalpha_constructor(self):
+ def test_video_constructor(self):
"""Make sure that if the 'youtube' attribute is omitted in XML, then
the template generates an empty string for the YouTube streams.
"""
diff --git a/lms/djangoapps/courseware/tests/test_videoalpha_xml.py b/lms/djangoapps/courseware/tests/test_video_xml.py
similarity index 74%
rename from lms/djangoapps/courseware/tests/test_videoalpha_xml.py
rename to lms/djangoapps/courseware/tests/test_video_xml.py
index e83582e131..64dbe4057b 100644
--- a/lms/djangoapps/courseware/tests/test_videoalpha_xml.py
+++ b/lms/djangoapps/courseware/tests/test_video_xml.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# pylint: disable=W0212
-"""Test for VideoAlpha Xmodule functional logic.
+"""Test for Video Xmodule functional logic.
These test data read from xml, not from mongo.
We have a ModuleStoreTestCase class defined in
@@ -20,14 +20,14 @@ import unittest
from django.conf import settings
-from xmodule.videoalpha_module import (
- VideoAlphaDescriptor, _create_youtube_string)
+from xmodule.video_module import (
+ VideoDescriptor, _create_youtube_string)
from xmodule.modulestore import Location
from xmodule.tests import get_test_system, LogicTest
SOURCE_XML = """
-
-
+
"""
-class VideoAlphaFactory(object):
- """A helper class to create videoalpha modules with various parameters
+class VideoFactory(object):
+ """A helper class to create video modules with various parameters
for testing.
"""
@@ -50,28 +50,28 @@ class VideoAlphaFactory(object):
@staticmethod
def create():
- """Method return VideoAlpha Xmodule instance."""
- location = Location(["i4x", "edX", "videoalpha", "default",
+ """Method return Video Xmodule instance."""
+ location = Location(["i4x", "edX", "video", "default",
"SampleProblem1"])
- model_data = {'data': VideoAlphaFactory.sample_problem_xml_youtube,
+ model_data = {'data': VideoFactory.sample_problem_xml_youtube,
'location': location}
system = get_test_system()
system.render_template = lambda template, context: context
- descriptor = VideoAlphaDescriptor(system, model_data)
+ descriptor = VideoDescriptor(system, model_data)
module = descriptor.xmodule(system)
return module
-class VideoAlphaModuleUnitTest(unittest.TestCase):
- """Unit tests for VideoAlpha Xmodule."""
+class VideoModuleUnitTest(unittest.TestCase):
+ """Unit tests for Video Xmodule."""
- def test_videoalpha_get_html(self):
+ def test_video_get_html(self):
"""Make sure that all parameters extracted correclty from xml"""
- module = VideoAlphaFactory.create()
+ module = VideoFactory.create()
module.runtime.render_template = lambda template, context: context
sources = {
@@ -98,18 +98,18 @@ class VideoAlphaModuleUnitTest(unittest.TestCase):
self.assertEqual(module.get_html(), expected_context)
- def test_videoalpha_instance_state(self):
- module = VideoAlphaFactory.create()
+ def test_video_instance_state(self):
+ module = VideoFactory.create()
self.assertDictEqual(
json.loads(module.get_instance_state()),
{'position': 0})
-class VideoAlphaModuleLogicTest(LogicTest):
- """Tests for logic of VideoAlpha Xmodule."""
+class VideoModuleLogicTest(LogicTest):
+ """Tests for logic of Video Xmodule."""
- descriptor_class = VideoAlphaDescriptor
+ descriptor_class = VideoDescriptor
raw_model_data = {
'data': ''
@@ -117,23 +117,23 @@ class VideoAlphaModuleLogicTest(LogicTest):
def test_parse_time(self):
"""Ensure that times are parsed correctly into seconds."""
- output = VideoAlphaDescriptor._parse_time('00:04:07')
+ output = VideoDescriptor._parse_time('00:04:07')
self.assertEqual(output, 247)
def test_parse_time_none(self):
"""Check parsing of None."""
- output = VideoAlphaDescriptor._parse_time(None)
+ output = VideoDescriptor._parse_time(None)
self.assertEqual(output, '')
def test_parse_time_empty(self):
"""Check parsing of the empty string."""
- output = VideoAlphaDescriptor._parse_time('')
+ output = VideoDescriptor._parse_time('')
self.assertEqual(output, '')
def test_parse_youtube(self):
"""Test parsing old-style Youtube ID strings into a dict."""
youtube_str = '0.75:jNCf2gIqpeE,1.00:ZwkTiUPN0mg,1.25:rsq9auxASqI,1.50:kMyNdzVHHgg'
- output = VideoAlphaDescriptor._parse_youtube(youtube_str)
+ output = VideoDescriptor._parse_youtube(youtube_str)
self.assertEqual(output, {'0.75': 'jNCf2gIqpeE',
'1.00': 'ZwkTiUPN0mg',
'1.25': 'rsq9auxASqI',
@@ -145,7 +145,7 @@ class VideoAlphaModuleLogicTest(LogicTest):
empty string.
"""
youtube_str = '0.75:jNCf2gIqpeE'
- output = VideoAlphaDescriptor._parse_youtube(youtube_str)
+ output = VideoDescriptor._parse_youtube(youtube_str)
self.assertEqual(output, {'0.75': 'jNCf2gIqpeE',
'1.00': '',
'1.25': '',
@@ -158,8 +158,8 @@ class VideoAlphaModuleLogicTest(LogicTest):
youtube_str = '1.00:p2Q6BrNhdh8'
youtube_str_hack = '1.0:p2Q6BrNhdh8'
self.assertEqual(
- VideoAlphaDescriptor._parse_youtube(youtube_str),
- VideoAlphaDescriptor._parse_youtube(youtube_str_hack)
+ VideoDescriptor._parse_youtube(youtube_str),
+ VideoDescriptor._parse_youtube(youtube_str_hack)
)
def test_parse_youtube_empty(self):
@@ -167,7 +167,7 @@ class VideoAlphaModuleLogicTest(LogicTest):
Some courses have empty youtube attributes, so we should handle
that well.
"""
- self.assertEqual(VideoAlphaDescriptor._parse_youtube(''),
+ self.assertEqual(VideoDescriptor._parse_youtube(''),
{'0.75': '',
'1.00': '',
'1.25': '',