Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
b883d527
Commit
b883d527
authored
Oct 13, 2015
by
Chris Rodriguez
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Adding closed captions (not draggable)
parent
dcc86a3b
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
304 additions
and
66 deletions
+304
-66
cms/static/cms/js/require-config.js
+1
-1
common/lib/xmodule/xmodule/css/video/display.scss
+43
-22
common/lib/xmodule/xmodule/js/fixtures/video_all.html
+1
-0
common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js
+71
-19
common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js
+4
-2
common/lib/xmodule/xmodule/js/src/video/03_video_player.js
+2
-1
common/lib/xmodule/xmodule/js/src/video/09_video_caption.js
+0
-0
common/test/acceptance/pages/lms/video/video.py
+94
-5
common/test/acceptance/pages/studio/video/video.py
+5
-5
common/test/acceptance/tests/video/test_studio_video_editor.py
+1
-1
common/test/acceptance/tests/video/test_studio_video_module.py
+0
-1
common/test/acceptance/tests/video/test_video_module.py
+80
-8
lms/envs/common.py
+1
-1
lms/templates/video.html
+1
-0
No files found.
cms/static/cms/js/require-config.js
View file @
b883d527
...
...
@@ -283,7 +283,7 @@ require.config({
"osda"
:{
exports
:
"osda"
,
deps
:
[
"annotator"
,
"annotator-harvardx"
,
"video.dev"
,
"vjs.youtube"
,
"rangeslider"
,
"share-annotator"
,
"richText-annotator"
,
"reply-annotator"
,
"tags-annotator"
,
"flagging-annotator"
,
"grouping-annotator"
,
"diacritic-annotator"
,
"openseadragon"
,
"jquery-Watch"
,
"catch"
,
"handlebars"
,
"URI"
]
}
,
}
// end of annotation tool files
}
});
common/lib/xmodule/xmodule/css/video/display.scss
View file @
b883d527
...
...
@@ -247,6 +247,22 @@ html:not('.afontgarde') .icon-fallback-img {
}
}
.closed-captions
{
position
:
absolute
;
width
:
85%
;
left
:
5%
;
top
:
70%
;
text-align
:
center
;
}
.closed-captions.is-visible
{
max-height
:
(
$baseline
*
3
);
border-radius
:
(
$baseline
/
5
);
padding
:
8px
(
$baseline
/
2
)
8px
(
$baseline
*
1
.5
);
background
:
rgba
(
0
,
0
,
0
,
.75
);
color
:
$yellow
;
}
.video-player
{
overflow
:
hidden
;
min-height
:
300px
;
...
...
@@ -701,39 +717,44 @@ html:not('.afontgarde') .icon-fallback-img {
.subtitles
{
@include
float
(
left
);
overflow
:
auto
;
margin
:
0
;
max-height
:
460px
;
width
:
flex-grid
(
3
,
9
);
padding
:
0
;
font-size
:
14px
;
list-style
:
none
;
visibility
:
visible
;
li
{
@extend
%ui-fake-link
;
margin-bottom
:
8px
;
border
:
0
;
.subtitles-menu
{
height
:
100%
;
margin
:
0
;
padding
:
0
;
color
:
#0074b5
;
// AA compliant
line-height
:
lh
();
list-style
:
none
;
&
.current
{
color
:
#333
;
font-weight
:
700
;
}
li
{
@extend
%ui-fake-link
;
margin-bottom
:
8px
;
border
:
0
;
padding
:
0
;
color
:
#0074b5
;
// AA compliant
line-height
:
lh
();
&
.focused
{
outline
:
#000
dotted
thin
;
outline-offset
:
-1px
;
}
&
.current
{
color
:
#333
;
font-weight
:
700
;
}
&
:hover
,
&
:focus
{
text-decoration
:
underline
;
}
&
.focused
{
outline
:
#000
dotted
thin
;
outline-offset
:
-1px
;
}
&
:hover
,
&
:focus
{
text-decoration
:
underline
;
}
&
:empty
{
margin-bottom
:
0
;
&
:empty
{
margin-bottom
:
0
;
}
}
}
}
...
...
common/lib/xmodule/xmodule/js/fixtures/video_all.html
View file @
b883d527
...
...
@@ -17,6 +17,7 @@
<div
id=
"id"
></div>
</section>
<div
class=
"video-player-post"
></div>
<div
class=
"closed-captions"
></div>
<section
class=
"video-controls is-hidden"
>
<div
class=
"slider"
></div>
<div>
...
...
common/lib/xmodule/xmodule/js/spec/video/video_caption_spec.js
View file @
b883d527
...
...
@@ -48,6 +48,12 @@
});
});
it
(
'adds the captioning control to the video player'
,
function
()
{
state
=
jasmine
.
initializePlayer
();
expect
(
$
(
'.video'
)).
toContain
(
'.toggle-captions'
);
expect
(
$
(
'.video'
)).
toContain
(
'.closed-captions'
);
});
it
(
'fetch the transcript in HTML5 mode'
,
function
()
{
runs
(
function
()
{
state
=
jasmine
.
initializePlayer
();
...
...
@@ -122,16 +128,16 @@
it
(
'bind the mouse movement'
,
function
()
{
state
=
jasmine
.
initializePlayer
();
expect
(
$
(
'.subtitles'
)).
toHandle
(
'mouseover'
);
expect
(
$
(
'.subtitles'
)).
toHandle
(
'mouseout'
);
expect
(
$
(
'.subtitles'
)).
toHandle
(
'mousemove'
);
expect
(
$
(
'.subtitles'
)).
toHandle
(
'mousewheel'
);
expect
(
$
(
'.subtitles'
)).
toHandle
(
'DOMMouseScroll'
);
expect
(
$
(
'.subtitles
-menu
'
)).
toHandle
(
'mouseover'
);
expect
(
$
(
'.subtitles
-menu
'
)).
toHandle
(
'mouseout'
);
expect
(
$
(
'.subtitles
-menu
'
)).
toHandle
(
'mousemove'
);
expect
(
$
(
'.subtitles
-menu
'
)).
toHandle
(
'mousewheel'
);
expect
(
$
(
'.subtitles
-menu
'
)).
toHandle
(
'DOMMouseScroll'
);
});
it
(
'bind the scroll'
,
function
()
{
state
=
jasmine
.
initializePlayer
();
expect
(
$
(
'.subtitles'
))
expect
(
$
(
'.subtitles
-menu
'
))
.
toHandleWith
(
'scroll'
,
state
.
videoControl
.
showControls
);
});
...
...
@@ -158,14 +164,61 @@
});
});
describe
(
'renderCaptions'
,
function
()
{
describe
(
'is rendered'
,
function
()
{
var
KEY
=
$
.
ui
.
keyCode
,
keyPressEvent
=
function
(
key
)
{
return
$
.
Event
(
'keydown'
,
{
keyCode
:
key
});
};
it
(
'toggles the captions on control click'
,
function
()
{
state
=
jasmine
.
initializePlayer
();
$
(
'.toggle-captions'
).
click
();
expect
(
$
(
'.toggle-captions'
)).
toHaveClass
(
'is-active'
);
expect
(
$
(
'.closed-captions'
)).
toHaveClass
(
'is-visible'
);
$
(
'.toggle-captions'
).
click
();
expect
(
$
(
'.toggle-captions'
)).
not
.
toHaveClass
(
'is-active'
);
expect
(
$
(
'.closed-captions'
)).
not
.
toHaveClass
(
'is-visible'
);
});
it
(
'toggles the captions on keypress ENTER'
,
function
()
{
state
=
jasmine
.
initializePlayer
();
$
(
'.toggle-captions'
).
focus
().
trigger
(
keyPressEvent
(
KEY
.
ENTER
));
expect
(
$
(
'.toggle-captions'
)).
toHaveClass
(
'is-active'
);
expect
(
$
(
'.closed-captions'
)).
toHaveClass
(
'is-visible'
);
$
(
'.toggle-captions'
).
focus
().
trigger
(
keyPressEvent
(
KEY
.
ENTER
));
expect
(
$
(
'.toggle-captions'
)).
not
.
toHaveClass
(
'is-active'
);
expect
(
$
(
'.closed-captions'
)).
not
.
toHaveClass
(
'is-visible'
);
});
it
(
'toggles the captions on keypress SPACE'
,
function
()
{
state
=
jasmine
.
initializePlayer
();
$
(
'.toggle-captions'
).
focus
().
trigger
(
keyPressEvent
(
KEY
.
SPACE
));
expect
(
$
(
'.toggle-captions'
)).
toHaveClass
(
'is-active'
);
expect
(
$
(
'.closed-captions'
)).
toHaveClass
(
'is-visible'
);
$
(
'.toggle-captions'
).
focus
().
trigger
(
keyPressEvent
(
KEY
.
SPACE
));
expect
(
$
(
'.toggle-captions'
)).
not
.
toHaveClass
(
'is-active'
);
expect
(
$
(
'.closed-captions'
)).
not
.
toHaveClass
(
'is-visible'
);
});
});
});
describe
(
'renderLanguageMenu'
,
function
()
{
describe
(
'is rendered'
,
function
()
{
var
KEY
=
$
.
ui
.
keyCode
,
keyPressEvent
=
function
(
key
)
{
return
$
.
Event
(
'keydown'
,
{
keyCode
:
key
});
};
keyPressEvent
=
function
(
key
)
{
return
$
.
Event
(
'keydown'
,
{
keyCode
:
key
});
};
it
(
'if languages more than 1'
,
function
()
{
state
=
jasmine
.
initializePlayer
();
...
...
@@ -364,9 +417,8 @@
});
it
(
'show explanation message'
,
function
()
{
expect
(
$
(
'.subtitles li'
)).
toHaveHtml
(
'Caption will be displayed when you start playing '
+
'the video.'
expect
(
$
(
'.subtitles-menu li'
)).
toHaveHtml
(
'Transcript will be displayed when you start playing the video.'
);
});
...
...
@@ -444,7 +496,7 @@
runs
(
function
()
{
$
(
window
).
trigger
(
jQuery
.
Event
(
'mousemove'
));
jasmine
.
Clock
.
tick
(
state
.
config
.
captionsFreezeTime
);
$
(
'.subtitles'
).
trigger
(
jQuery
.
Event
(
'mouseenter'
));
$
(
'.subtitles
-menu
'
).
trigger
(
jQuery
.
Event
(
'mouseenter'
));
jasmine
.
Clock
.
tick
(
state
.
config
.
captionsFreezeTime
);
});
});
...
...
@@ -459,7 +511,7 @@
describe
(
'when the cursor is moving'
,
function
()
{
it
(
'reset the freezing timeout'
,
function
()
{
runs
(
function
()
{
$
(
'.subtitles'
).
trigger
(
jQuery
.
Event
(
'mousemove'
));
$
(
'.subtitles
-menu
'
).
trigger
(
jQuery
.
Event
(
'mousemove'
));
expect
(
window
.
clearTimeout
).
toHaveBeenCalled
();
});
});
...
...
@@ -468,7 +520,7 @@
describe
(
'when the mouse is scrolling'
,
function
()
{
it
(
'reset the freezing timeout'
,
function
()
{
runs
(
function
()
{
$
(
'.subtitles'
).
trigger
(
jQuery
.
Event
(
'mousewheel'
));
$
(
'.subtitles
-menu
'
).
trigger
(
jQuery
.
Event
(
'mousewheel'
));
expect
(
window
.
clearTimeout
).
toHaveBeenCalled
();
});
});
...
...
@@ -486,7 +538,7 @@
describe
(
'always'
,
function
()
{
beforeEach
(
function
()
{
$
(
'.subtitles'
).
trigger
(
jQuery
.
Event
(
'mouseout'
));
$
(
'.subtitles
-menu
'
).
trigger
(
jQuery
.
Event
(
'mouseout'
));
});
it
(
'reset the freezing timeout'
,
function
()
{
...
...
@@ -501,9 +553,9 @@
describe
(
'when the player is playing'
,
function
()
{
beforeEach
(
function
()
{
state
.
videoCaption
.
playing
=
true
;
$
(
'.subtitles li[data-index]:first'
)
$
(
'.subtitles
-menu
li[data-index]:first'
)
.
addClass
(
'current'
);
$
(
'.subtitles'
).
trigger
(
jQuery
.
Event
(
'mouseout'
));
$
(
'.subtitles
-menu
'
).
trigger
(
jQuery
.
Event
(
'mouseout'
));
});
it
(
'scroll the transcript'
,
function
()
{
...
...
@@ -514,7 +566,7 @@
describe
(
'when the player is not playing'
,
function
()
{
beforeEach
(
function
()
{
state
.
videoCaption
.
playing
=
false
;
$
(
'.subtitles'
).
trigger
(
jQuery
.
Event
(
'mouseout'
));
$
(
'.subtitles
-menu
'
).
trigger
(
jQuery
.
Event
(
'mouseout'
));
});
it
(
'does not scroll the transcript'
,
function
()
{
...
...
common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js
View file @
b883d527
...
...
@@ -92,7 +92,8 @@ function (VideoPlayer) {
showinfo
:
0
,
enablejsapi
:
1
,
modestbranding
:
1
,
html5
:
1
html5
:
1
,
cc_load_policy
:
0
},
videoId
:
'cogebirgzzM'
,
events
:
events
...
...
@@ -118,7 +119,8 @@ function (VideoPlayer) {
rel
:
0
,
showinfo
:
0
,
enablejsapi
:
1
,
modestbranding
:
1
modestbranding
:
1
,
cc_load_policy
:
0
},
videoId
:
'abcdefghijkl'
,
events
:
jasmine
.
any
(
Object
)
...
...
common/lib/xmodule/xmodule/js/src/video/03_video_player.js
View file @
b883d527
...
...
@@ -139,7 +139,8 @@ function (HTML5Video, Resizer) {
rel
:
0
,
showinfo
:
0
,
enablejsapi
:
1
,
modestbranding
:
1
modestbranding
:
1
,
cc_load_policy
:
0
};
if
(
!
state
.
isFlashMode
())
{
...
...
common/lib/xmodule/xmodule/js/src/video/09_video_caption.js
View file @
b883d527
This diff is collapsed.
Click to expand it.
common/test/acceptance/pages/lms/video/video.py
View file @
b883d527
...
...
@@ -16,6 +16,7 @@ log = logging.getLogger('VideoPage')
VIDEO_BUTTONS
=
{
'transcript'
:
'.lang'
,
'transcript_button'
:
'.toggle-transcript'
,
'cc_button'
:
'.toggle-captions'
,
'volume'
:
'.volume'
,
'play'
:
'.video_control.play'
,
'pause'
:
'.video_control.pause'
,
...
...
@@ -28,10 +29,12 @@ VIDEO_BUTTONS = {
}
CSS_CLASS_NAMES
=
{
'c
losed_captions
'
:
'.video.closed'
,
'c
aptions_closed
'
:
'.video.closed'
,
'captions_rendered'
:
'.video.is-captions-rendered'
,
'captions'
:
'.subtitles'
,
'captions_text'
:
'.subtitles > li'
,
'captions_text'
:
'.subtitles li'
,
'captions_text_getter'
:
'.subtitles li[role="link"][data-index="1"]'
,
'closed_captions'
:
'.closed-captions'
,
'error_message'
:
'.video .video-player h3'
,
'video_container'
:
'.video'
,
'video_sources'
:
'.video-player video source'
,
...
...
@@ -293,6 +296,18 @@ class VideoPage(PageObject):
"""
self
.
_captions_visibility
(
False
)
def
show_closed_captions
(
self
):
"""
Make closed captions visible.
"""
self
.
_closed_captions_visibility
(
True
)
def
hide_closed_captions
(
self
):
"""
Make closed captions invisible.
"""
self
.
_closed_captions_visibility
(
False
)
def
is_captions_visible
(
self
):
"""
Get current visibility sate of captions.
...
...
@@ -302,8 +317,20 @@ class VideoPage(PageObject):
"""
self
.
wait_for_ajax
()
caption_state_selector
=
self
.
get_element_selector
(
CSS_CLASS_NAMES
[
'closed_captions'
])
return
not
self
.
q
(
css
=
caption_state_selector
)
.
present
caption_state_selector
=
self
.
get_element_selector
(
CSS_CLASS_NAMES
[
'captions'
])
return
self
.
q
(
css
=
caption_state_selector
)
.
visible
def
is_closed_captions_visible
(
self
):
"""
Get current visibility sate of closed captions.
Returns:
bool: True means captions are visible, False means captions are not visible
"""
self
.
wait_for_ajax
()
closed_caption_state_selector
=
self
.
get_element_selector
(
CSS_CLASS_NAMES
[
'closed_captions'
])
return
self
.
q
(
css
=
closed_caption_state_selector
)
.
visible
@wait_for_js
def
_captions_visibility
(
self
,
captions_new_state
):
...
...
@@ -327,7 +354,24 @@ class VideoPage(PageObject):
# Verify that captions state is toggled/changed
EmptyPromise
(
lambda
:
self
.
is_captions_visible
()
==
captions_new_state
,
"Captions are {state}"
.
format
(
state
=
state
))
.
fulfill
()
"Transcripts are {state}"
.
format
(
state
=
state
))
.
fulfill
()
@wait_for_js
def
_closed_captions_visibility
(
self
,
closed_captions_new_state
):
"""
Set the video closed captioning visibility state.
Arguments:
closed_captions_new_state (bool): True means show closed captioning
"""
states
=
{
True
:
'shown'
,
False
:
'hidden'
}
state
=
states
[
closed_captions_new_state
]
self
.
click_player_button
(
'cc_button'
)
# Make sure that the captions are visible
EmptyPromise
(
lambda
:
self
.
is_closed_captions_visible
()
==
closed_captions_new_state
,
"Closed captions are {state}"
.
format
(
state
=
state
))
.
fulfill
()
@property
def
captions_text
(
self
):
...
...
@@ -346,6 +390,31 @@ class VideoPage(PageObject):
return
' '
.
join
(
subs
)
@property
def
closed_captions_text
(
self
):
"""
Extract closed captioning text.
Returns:
str: closed captions Text.
"""
self
.
wait_for_closed_captions
()
closed_captions_selector
=
self
.
get_element_selector
(
CSS_CLASS_NAMES
[
'closed_captions'
])
subs
=
self
.
q
(
css
=
closed_captions_selector
)
.
html
return
' '
.
join
(
subs
)
def
click_first_line_in_transcript
(
self
):
"""
Clicks a line in the transcript updating the current caption.
"""
self
.
wait_for_captions
()
captions_selector
=
self
.
q
(
css
=
CSS_CLASS_NAMES
[
'captions_text_getter'
])
captions_selector
.
click
()
@property
def
speed
(
self
):
"""
Get current video speed value.
...
...
@@ -494,6 +563,12 @@ class VideoPage(PageObject):
response
=
requests
.
get
(
url
,
**
kwargs
)
return
response
.
status_code
<
400
,
response
.
headers
,
response
.
content
def
get_cookie
(
self
,
cookie_name
):
"""
Searches for and returns `cookie_name`
"""
return
self
.
browser
.
get_cookie
(
cookie_name
)
def
downloaded_transcript_contains_text
(
self
,
transcript_format
,
text_to_search
):
"""
Download the transcript in format `transcript_format` and check that it contains the text `text_to_search`
...
...
@@ -837,6 +912,20 @@ class VideoPage(PageObject):
captions_rendered_selector
=
self
.
get_element_selector
(
CSS_CLASS_NAMES
[
'captions_rendered'
])
self
.
wait_for_element_presence
(
captions_rendered_selector
,
'Captions Rendered'
)
def
wait_for_closed_captions
(
self
):
"""
Wait until closed captions are rendered completely.
"""
cc_rendered_selector
=
self
.
get_element_selector
(
CSS_CLASS_NAMES
[
'closed_captions'
])
self
.
wait_for_element_visibility
(
cc_rendered_selector
,
'Closed captions rendered'
)
def
wait_for_closed_captions_to_be_hidden
(
self
):
"""
Waits for the closed captions to be turned off completely.
"""
cc_rendered_selector
=
self
.
get_element_selector
(
CSS_CLASS_NAMES
[
'closed_captions'
])
self
.
wait_for_element_invisibility
(
cc_rendered_selector
,
'Closed captions hidden'
)
def
_parse_time_str
(
time_str
):
"""
...
...
common/test/acceptance/pages/studio/video/video.py
View file @
b883d527
...
...
@@ -13,11 +13,11 @@ from selenium.webdriver.common.keys import Keys
CLASS_SELECTORS
=
{
'video_container'
:
'
div
.video'
,
'video_container'
:
'.video'
,
'video_init'
:
'.is-initialized'
,
'video_xmodule'
:
'.xmodule_VideoModule'
,
'video_spinner'
:
'.video-wrapper .spinner'
,
'video_controls'
:
'
section
.video-controls'
,
'video_controls'
:
'.video-controls'
,
'attach_asset'
:
'.upload-dialog > input[type="file"]'
,
'upload_dialog'
:
'.wrapper-modal-window-assetupload'
,
'xblock'
:
'.add-xblock-component'
,
...
...
@@ -264,7 +264,7 @@ class VideoComponentPage(VideoPage):
line_number (int): caption line number
"""
caption_line_selector
=
".subtitles
>
li[data-index='{index}']"
.
format
(
index
=
line_number
-
1
)
caption_line_selector
=
".subtitles li[data-index='{index}']"
.
format
(
index
=
line_number
-
1
)
self
.
q
(
css
=
caption_line_selector
)
.
results
[
0
]
.
send_keys
(
Keys
.
ENTER
)
def
is_caption_line_focused
(
self
,
line_number
):
...
...
@@ -275,7 +275,7 @@ class VideoComponentPage(VideoPage):
line_number (int): caption line number
"""
caption_line_selector
=
".subtitles
>
li[data-index='{index}']"
.
format
(
index
=
line_number
-
1
)
caption_line_selector
=
".subtitles li[data-index='{index}']"
.
format
(
index
=
line_number
-
1
)
attributes
=
self
.
q
(
css
=
caption_line_selector
)
.
attrs
(
'class'
)
return
'focused'
in
attributes
...
...
@@ -504,7 +504,7 @@ class VideoComponentPage(VideoPage):
As all the captions lines are exactly same so only getting partial lines will work.
"""
self
.
wait_for_captions
()
selector
=
'.subtitles
>
li:nth-child({})'
selector
=
'.subtitles li:nth-child({})'
return
' '
.
join
([
self
.
q
(
css
=
selector
.
format
(
i
))
.
text
[
0
]
for
i
in
range
(
1
,
6
)])
def
set_url_field
(
self
,
url
,
field_number
):
...
...
common/test/acceptance/tests/video/test_studio_video_editor.py
View file @
b883d527
...
...
@@ -142,7 +142,7 @@ class VideoEditorTest(CMSVideoBaseTest):
self
.
open_advanced_tab
()
self
.
video
.
upload_translation
(
'1mb_transcripts.srt'
,
'uk'
)
self
.
save_unit_settings
()
self
.
assertTrue
(
self
.
video
.
is_captions_visible
()
)
self
.
video
.
wait_for
(
self
.
video
.
is_captions_visible
,
'Captions are visible'
,
timeout
=
10
)
unicode_text
=
"Привіт, edX вітає вас."
.
decode
(
'utf-8'
)
self
.
assertIn
(
unicode_text
,
self
.
video
.
captions_lines
())
...
...
common/test/acceptance/tests/video/test_studio_video_module.py
View file @
b883d527
...
...
@@ -255,7 +255,6 @@ class CMSVideoTest(CMSVideoBaseTest):
Then when I view the video it does show the captions
"""
self
.
_create_course_unit
(
subtitles
=
True
)
self
.
assertTrue
(
self
.
video
.
is_captions_visible
())
def
test_captions_toggling
(
self
):
...
...
common/test/acceptance/tests/video/test_video_module.py
View file @
b883d527
...
...
@@ -212,9 +212,9 @@ class YouTubeVideoTest(VideoBaseTest):
# Verify that video has rendered in "Youtube" mode
self
.
assertTrue
(
self
.
video
.
is_video_rendered
(
'youtube'
))
def
test_
cc
_button_wo_english_transcript
(
self
):
def
test_
transcript
_button_wo_english_transcript
(
self
):
"""
Scenario:
CC
button works correctly w/o english transcript in Youtube mode
Scenario:
Transcript
button works correctly w/o english transcript in Youtube mode
Given the course has a Video component in "Youtube" mode
And I have defined a non-english transcript for the video
And I have uploaded a non-english transcript file to assets
...
...
@@ -226,13 +226,38 @@ class YouTubeVideoTest(VideoBaseTest):
self
.
navigate_to_video
()
self
.
video
.
show_captions
()
# Verify that we see "好 各位同学" text in the
captions
# Verify that we see "好 各位同学" text in the
transcript
unicode_text
=
"好 各位同学"
.
decode
(
'utf-8'
)
self
.
assertIn
(
unicode_text
,
self
.
video
.
captions_text
)
def
test_cc_button_transcripts_and_sub_fields_empty
(
self
):
def
test_cc_button
(
self
):
"""
Scenario: CC button works correctly with transcript in YouTube mode
Given the course has a video component in "Youtube" mode
And I have defined a transcript for the video
Then I see the closed captioning element over the video
"""
Scenario: CC button works correctly if transcripts and sub fields are empty,
data
=
{
'transcripts'
:
{
'zh'
:
'chinese_transcripts.srt'
}}
self
.
metadata
=
self
.
metadata_for_mode
(
'youtube'
,
data
)
self
.
assets
.
append
(
'chinese_transcripts.srt'
)
self
.
navigate_to_video
()
# Show captions and make sure they're visible and cookie is set
self
.
video
.
show_closed_captions
()
self
.
video
.
wait_for_closed_captions
()
self
.
assertTrue
(
self
.
video
.
is_closed_captions_visible
)
self
.
video
.
reload_page
()
self
.
assertTrue
(
self
.
video
.
is_closed_captions_visible
)
# Hide captions and make sure they're hidden and cookie is unset
self
.
video
.
hide_closed_captions
()
self
.
video
.
wait_for_closed_captions_to_be_hidden
()
self
.
video
.
reload_page
()
self
.
video
.
wait_for_closed_captions_to_be_hidden
()
def
test_transcript_button_transcripts_and_sub_fields_empty
(
self
):
"""
Scenario: Transcript button works correctly if transcripts and sub fields are empty,
but transcript file exists in assets (Youtube mode of Video component)
Given the course has a Video component in "Youtube" mode
And I have uploaded a .srt.sjson file to assets
...
...
@@ -247,11 +272,11 @@ class YouTubeVideoTest(VideoBaseTest):
# Verify that we see "Welcome to edX." text in the captions
self
.
assertIn
(
'Welcome to edX.'
,
self
.
video
.
captions_text
)
def
test_
cc
_button_hidden_no_translations
(
self
):
def
test_
transcript
_button_hidden_no_translations
(
self
):
"""
Scenario:
CC
button is hidden if no translations
Scenario:
Transcript
button is hidden if no translations
Given the course has a Video component in "Youtube" mode
Then the "
CC
" button is hidden
Then the "
Transcript
" button is hidden
"""
self
.
navigate_to_video
()
self
.
assertFalse
(
self
.
video
.
is_button_shown
(
'transcript_button'
))
...
...
@@ -522,6 +547,16 @@ class YouTubeVideoTest(VideoBaseTest):
timeout
=
5
)
def
_verify_closed_caption_text
(
self
,
text
):
"""
Scenario: returns True if the captions are visible, False is else
"""
self
.
video
.
wait_for
(
lambda
:
(
text
in
self
.
video
.
closed_captions_text
),
u'Closed captions contain "{}" text'
.
format
(
text
),
timeout
=
5
)
def
test_video_language_menu_working
(
self
):
"""
Scenario: Language menu works correctly in Video component
...
...
@@ -554,6 +589,43 @@ class YouTubeVideoTest(VideoBaseTest):
self
.
video
.
select_language
(
'en'
)
self
.
_verify_caption_text
(
'Welcome to edX.'
)
def
test_video_language_menu_working_closed_captions
(
self
):
"""
Scenario: Language menu works correctly in Video component, checks closed captions
Given the course has a Video component in "Youtube" mode
And I have defined multiple language transcripts for the videos
And I make sure captions are closed
And I see video menu "language" with correct items
And I select language with code "en"
Then I see "Welcome to edX." text in the closed captions
And I select language with code "zh"
Then I see "我们今天要讲的题目是" text in the closed captions
"""
self
.
assets
.
extend
([
'chinese_transcripts.srt'
,
'subs_3_yD_cEKoCk.srt.sjson'
])
data
=
{
'transcripts'
:
{
"zh"
:
"chinese_transcripts.srt"
},
'sub'
:
'3_yD_cEKoCk'
}
self
.
metadata
=
self
.
metadata_for_mode
(
'youtube'
,
additional_data
=
data
)
# go to video
self
.
navigate_to_video
()
self
.
video
.
show_closed_captions
()
correct_languages
=
{
'en'
:
'English'
,
'zh'
:
'Chinese'
}
self
.
assertEqual
(
self
.
video
.
caption_languages
,
correct_languages
)
# we start the video, then pause it to activate the transcript
self
.
video
.
click_player_button
(
'play'
)
self
.
video
.
wait_for_position
(
'0:01'
)
self
.
video
.
click_player_button
(
'pause'
)
self
.
video
.
select_language
(
'en'
)
self
.
video
.
click_first_line_in_transcript
()
self
.
_verify_closed_caption_text
(
'Welcome to edX.'
)
self
.
video
.
select_language
(
'zh'
)
unicode_text
=
"我们今天要讲的题目是"
.
decode
(
'utf-8'
)
self
.
video
.
click_first_line_in_transcript
()
self
.
_verify_closed_caption_text
(
unicode_text
)
def
test_multiple_videos_in_sequentials_load_and_work
(
self
):
"""
Scenario: Multiple videos in sequentials all load and work, switching between sequentials
...
...
lms/envs/common.py
View file @
b883d527
...
...
@@ -1284,7 +1284,7 @@ main_vendor_js = base_vendor_js + [
'js/vendor/jquery.ba-bbq.min.js'
,
'js/vendor/afontgarde/modernizr.fontface-generatedcontent.js'
,
'js/vendor/afontgarde/afontgarde.js'
,
'js/vendor/afontgarde/edx-icons.js'
,
'js/vendor/afontgarde/edx-icons.js'
]
# Common files used by both RequireJS code and non-RequireJS code
...
...
lms/templates/video.html
View file @
b883d527
...
...
@@ -26,6 +26,7 @@
<h3
class=
"hidden"
>
${_('No playable video sources found.')}
</h3>
</section>
<div
class=
"video-player-post"
></div>
<div
class=
"closed-captions"
></div>
<section
class=
"video-controls is-hidden"
>
<div>
<div
class=
"vcr"
><div
class=
"vidtime"
>
0:00 / 0:00
</div></div>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment