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
3a740c04
Commit
3a740c04
authored
Feb 25, 2014
by
jmclaus
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
BLD-844: Add possibility to download transcripts in different formats.
parent
2c9585ea
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
422 additions
and
31 deletions
+422
-31
CHANGELOG.rst
+2
-0
cms/static/sass/elements/_xmodules.scss
+9
-0
common/lib/xmodule/xmodule/css/video/accessible_menu.scss
+133
-0
common/lib/xmodule/xmodule/css/video/display.scss
+13
-4
common/lib/xmodule/xmodule/js/fixtures/video_all.html
+17
-0
common/lib/xmodule/xmodule/js/spec/video/video_accessible_menu_spec.js
+0
-0
common/lib/xmodule/xmodule/js/src/video/035_video_accessible_menu.js
+0
-0
common/lib/xmodule/xmodule/js/src/video/10_main.js
+3
-0
common/lib/xmodule/xmodule/video_module/video_module.py
+51
-14
common/test/data/uploads/subs_OEoXaMPEzfM.srt.sjson
+1
-1
lms/djangoapps/courseware/features/video.feature
+21
-0
lms/djangoapps/courseware/features/video.py
+99
-4
lms/djangoapps/courseware/tests/test_video_handlers.py
+42
-6
lms/djangoapps/courseware/tests/test_video_mongo.py
+8
-1
lms/templates/video.html
+23
-1
No files found.
CHANGELOG.rst
View file @
3a740c04
...
...
@@ -5,6 +5,8 @@ These are notable changes in edx-platform. This is a rolling list of changes,
in roughly chronological order, most recent first. Add your entries at or near
the top. Include a label indicating the component affected.
Blades: Add .txt and .srt options to the "download transcript" button. BLD-844.
Blades: Fix bug when transcript cutting off view in full view mode. BLD-852.
Blades: Show start time or starting position on slider and VCR. BLD-823.
...
...
cms/static/sass/elements/_xmodules.scss
View file @
3a740c04
...
...
@@ -22,6 +22,15 @@
.video-controls
.add-fullscreen
{
display
:
none
!
important
;
// nasty, but needed to override the bad specificity of the xmodule css selectors
}
.video-tracks
{
.a11y-menu-container
{
.a11y-menu-list
{
bottom
:
100%
;
top
:
auto
;
}
}
}
}
}
...
...
common/lib/xmodule/xmodule/css/video/accessible_menu.scss
0 → 100644
View file @
3a740c04
$gray
:
rgb
(
127
,
127
,
127
);
$blue
:
rgb
(
0
,
159
,
230
);
$gray-d1
:
shade
(
$gray
,
20%
);
$gray-l2
:
tint
(
$gray
,
40%
);
$gray-l3
:
tint
(
$gray
,
60%
);
$blue-s1
:
saturate
(
$blue
,
15%
);
%use-font-awesome
{
font-family
:
FontAwesome
;
-webkit-font-smoothing
:
antialiased
;
display
:
inline-block
;
speak
:
none
;
}
.a11y-menu-container
{
position
:
relative
;
&
.open
{
.a11y-menu-list
{
display
:
block
;
}
}
.a11y-menu-list
{
top
:
100%
;
margin
:
0
;
padding
:
0
;
display
:
none
;
position
:
absolute
;
z-index
:
10
;
list-style
:
none
;
background-color
:
$white
;
border
:
1px
solid
#eee
;
li
{
margin
:
0
;
padding
:
0
;
border-bottom
:
1px
solid
#eee
;
color
:
$white
;
cursor
:
pointer
;
a
{
display
:
block
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
color
:
$gray-l2
;
font-size
:
14px
;
line-height
:
23px
;
&
:hover
{
color
:
$gray-d1
;
}
}
&
.active
{
a
{
color
:
$blue
;
}
}
&
:last-child
{
box-shadow
:
none
;
border-bottom
:
0
;
margin-top
:
0
;
}
}
}
}
// Video track button specific styles
.video-tracks
{
.a11y-menu-container
{
display
:
inline-block
;
vertical-align
:
top
;
border-left
:
1px
solid
#eee
;
&
.open
{
>
a
{
background-color
:
$action-primary-active-bg
;
color
:
$very-light-text
;
&
:after
{
color
:
$very-light-text
;
}
}
}
>
a
{
@include
transition
(
all
0
.25s
ease-in-out
0s
);
@include
font-size
(
12
);
display
:
block
;
border-radius
:
0
3px
3px
0
;
background-color
:
$very-light-text
;
padding
:
(
$baseline
*.
75
$baseline
*
1
.25
$baseline
*.
75
$baseline
*.
75
);
color
:
$gray-l2
;
min-width
:
1
.5em
;
line-height
:
14px
;
text-align
:
center
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
&
:after
{
@extend
%use-font-awesome
;
content
:
"\f0d7"
;
position
:
absolute
;
right
:
(
$baseline
*.
5
);
top
:
33%
;
color
:
$lighter-base-font-color
;
}
}
.a11y-menu-list
{
right
:
0
;
li
{
font-size
:
em
(
14
);
a
{
border
:
0
;
display
:
block
;
padding
:
lh
(
.5
);
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
}
}
}
}
common/lib/xmodule/xmodule/css/video/display.scss
View file @
3a740c04
...
...
@@ -46,13 +46,15 @@ div.video {
.video-sources
,
.video-tracks
{
display
:
inline-block
;
vertical-align
:
top
;
margin
:
(
$baseline
*.
75
)
(
$baseline
/
2
)
0
0
;
a
{
>
a
{
@include
transition
(
all
0
.25s
ease-in-out
0s
);
@include
font-size
(
14
);
display
:
inline-block
;
border-radius
:
3px
3px
3px
3px
;
line-height
:
14px
;
float
:
left
;
border-radius
:
3px
;
background-color
:
$very-light-text
;
padding
:
(
$baseline
*.
75
);
color
:
$lighter-base-font-color
;
...
...
@@ -62,7 +64,14 @@ div.video {
color
:
$very-light-text
;
}
}
}
.video-tracks
{
>
a
{
border-radius
:
3px
0
0
3px
;
}
>
a
.external-track
{
border-radius
:
3px
;
}
}
}
...
...
common/lib/xmodule/xmodule/js/fixtures/video_all.html
View file @
3a740c04
...
...
@@ -69,6 +69,23 @@
</div>
<div
class=
"focus_grabber last"
></div>
<ul
class=
"wrapper-downloads"
>
<li
class=
"video-tracks"
>
<div
class=
"a11y-menu-container"
>
<a
class=
"a11y-menu-button"
href=
"#"
title=
".srt"
>
.srt
</a>
<ol
class=
"a11y-menu-list"
>
<li
class=
"a11y-menu-item"
>
<a
class=
"a11y-menu-item-link"
href=
"#txt"
title=
"Text (.txt) file"
data-value=
"txt"
>
Text (.txt) file
</a>
</li>
<li
class=
"a11y-menu-item active"
>
<a
class=
"a11y-menu-item-link"
href=
"#srt"
title=
"SubRip (.srt) file"
data-value=
"srt"
>
SubRip (.srt) file
</a>
</li>
</ol>
</div>
</li>
</ul>
</div>
</div>
</div>
...
...
common/lib/xmodule/xmodule/js/spec/video/video_accessible_menu_spec.js
0 → 100644
View file @
3a740c04
This diff is collapsed.
Click to expand it.
common/lib/xmodule/xmodule/js/src/video/035_video_accessible_menu.js
0 → 100644
View file @
3a740c04
This diff is collapsed.
Click to expand it.
common/lib/xmodule/xmodule/js/src/video/10_main.js
View file @
3a740c04
...
...
@@ -42,6 +42,7 @@ require(
[
'video/01_initialize.js'
,
'video/025_focus_grabber.js'
,
'video/035_video_accessible_menu.js'
,
'video/04_video_control.js'
,
'video/05_video_quality_control.js'
,
'video/06_video_progress_slider.js'
,
...
...
@@ -52,6 +53,7 @@ require(
function
(
Initialize
,
FocusGrabber
,
VideoAccessibleMenu
,
VideoControl
,
VideoQualityControl
,
VideoProgressSlider
,
...
...
@@ -87,6 +89,7 @@ function (
state
.
modules
=
[
FocusGrabber
,
VideoAccessibleMenu
,
VideoControl
,
VideoQualityControl
,
VideoProgressSlider
,
...
...
common/lib/xmodule/xmodule/video_module/video_module.py
View file @
3a740c04
...
...
@@ -13,6 +13,7 @@ in XML.
import
json
import
logging
from
operator
import
itemgetter
from
HTMLParser
import
HTMLParser
from
lxml
import
etree
from
pkg_resources
import
resource_string
...
...
@@ -155,6 +156,15 @@ class VideoFields(object):
scope
=
Scope
.
preferences
,
default
=
"en"
)
transcript_download_format
=
String
(
help
=
"Transcript file format to download by user."
,
scope
=
Scope
.
preferences
,
values
=
[
{
"display_name"
:
"SubRip (.srt) file"
,
"value"
:
"srt"
},
{
"display_name"
:
"Text (.txt) file"
,
"value"
:
"txt"
}
],
default
=
'srt'
,
)
speed
=
Float
(
help
=
"The last speed that was explicitly set by user for the video."
,
scope
=
Scope
.
user_state
,
...
...
@@ -193,6 +203,7 @@ class VideoModule(VideoFields, XModule):
resource_string
(
module
,
'js/src/video/025_focus_grabber.js'
),
resource_string
(
module
,
'js/src/video/02_html5_video.js'
),
resource_string
(
module
,
'js/src/video/03_video_player.js'
),
resource_string
(
module
,
'js/src/video/035_video_accessible_menu.js'
),
resource_string
(
module
,
'js/src/video/04_video_control.js'
),
resource_string
(
module
,
'js/src/video/05_video_quality_control.js'
),
resource_string
(
module
,
'js/src/video/06_video_progress_slider.js'
),
...
...
@@ -202,20 +213,33 @@ class VideoModule(VideoFields, XModule):
resource_string
(
module
,
'js/src/video/10_main.js'
)
]
}
css
=
{
'scss'
:
[
resource_string
(
module
,
'css/video/display.scss'
)]}
css
=
{
'scss'
:
[
resource_string
(
module
,
'css/video/display.scss'
),
resource_string
(
module
,
'css/video/accessible_menu.scss'
),
]}
js_module_name
=
"Video"
def
handle_ajax
(
self
,
dispatch
,
data
):
accepted_keys
=
[
'speed'
,
'saved_video_position'
,
'transcript_language'
]
if
dispatch
==
'save_user_state'
:
accepted_keys
=
[
'speed'
,
'saved_video_position'
,
'transcript_language'
,
'transcript_download_format'
,
]
conversions
=
{
'speed'
:
json
.
loads
,
'saved_video_position'
:
lambda
v
:
RelativeTime
.
isotime_to_timedelta
(
v
),
}
if
dispatch
==
'save_user_state'
:
for
key
in
data
:
if
hasattr
(
self
,
key
)
and
key
in
accepted_keys
:
if
key
==
'saved_video_position'
:
relative_position
=
RelativeTime
.
isotime_to_timedelta
(
data
[
key
])
self
.
saved_video_position
=
relative_position
if
key
in
conversions
:
value
=
conversions
[
key
](
data
[
key
])
else
:
setattr
(
self
,
key
,
json
.
loads
(
data
[
key
]))
value
=
data
[
key
]
setattr
(
self
,
key
,
value
)
if
key
==
'speed'
:
self
.
global_speed
=
self
.
speed
...
...
@@ -228,6 +252,7 @@ class VideoModule(VideoFields, XModule):
def
get_html
(
self
):
track_url
=
None
transcript_download_format
=
self
.
transcript_download_format
get_ext
=
lambda
filename
:
filename
.
rpartition
(
'.'
)[
-
1
]
sources
=
{
get_ext
(
src
):
src
for
src
in
self
.
html5_sources
}
...
...
@@ -241,7 +266,8 @@ class VideoModule(VideoFields, XModule):
if
self
.
download_track
:
if
self
.
track
:
track_url
=
self
.
track
elif
self
.
sub
:
transcript_download_format
=
None
elif
self
.
sub
or
self
.
transcripts
:
track_url
=
self
.
runtime
.
handler_url
(
self
,
'transcript'
)
.
rstrip
(
'/?'
)
+
'/download'
if
not
self
.
transcripts
:
...
...
@@ -289,13 +315,15 @@ class VideoModule(VideoFields, XModule):
# configuration setting field.
'yt_test_timeout'
:
1500
,
'yt_test_url'
:
settings
.
YOUTUBE_TEST_URL
,
'transcript_download_format'
:
transcript_download_format
,
'transcript_download_formats_list'
:
self
.
descriptor
.
fields
[
'transcript_download_format'
]
.
values
,
'transcript_language'
:
transcript_language
,
'transcript_languages'
:
json
.
dumps
(
sorted_languages
),
'transcript_translation_url'
:
self
.
runtime
.
handler_url
(
self
,
'transcript'
)
.
rstrip
(
'/?'
)
+
'/translation'
,
'transcript_available_translations_url'
:
self
.
runtime
.
handler_url
(
self
,
'transcript'
)
.
rstrip
(
'/?'
)
+
'/available_translations'
,
})
def
get_transcript
(
self
):
def
get_transcript
(
self
,
format
=
'srt'
):
"""
Returns transcript in *.srt format.
...
...
@@ -307,12 +335,18 @@ class VideoModule(VideoFields, XModule):
lang
=
self
.
transcript_language
subs_id
=
self
.
sub
if
lang
==
'en'
else
self
.
youtube_id_1_0
data
=
asset
(
self
.
location
,
subs_id
,
lang
)
.
data
str_subs
=
generate_srt_from_sjson
(
json
.
loads
(
data
),
speed
=
1.0
)
if
format
==
'txt'
:
text
=
json
.
loads
(
data
)[
'text'
]
str_subs
=
HTMLParser
()
.
unescape
(
"
\n
"
.
join
(
text
))
mime_type
=
'text/plain'
else
:
str_subs
=
generate_srt_from_sjson
(
json
.
loads
(
data
),
speed
=
1.0
)
mime_type
=
'application/x-subrip'
if
not
str_subs
:
log
.
debug
(
'generate_srt_from_sjson produces no subtitles'
)
raise
ValueError
return
str_subs
return
str_subs
,
format
,
mime_type
@XBlock.handler
def
transcript
(
self
,
request
,
dispatch
):
...
...
@@ -350,7 +384,7 @@ class VideoModule(VideoFields, XModule):
elif
dispatch
==
'download'
:
try
:
subs
=
self
.
get_transcript
(
)
subs
,
format
,
mime_type
=
self
.
get_transcript
(
format
=
self
.
transcript_download_format
)
except
(
NotFoundError
,
ValueError
,
KeyError
):
log
.
debug
(
"Video@download exception"
)
response
=
Response
(
status
=
404
)
...
...
@@ -358,10 +392,13 @@ class VideoModule(VideoFields, XModule):
response
=
Response
(
subs
,
headerlist
=
[
(
'Content-Disposition'
,
'attachment; filename="{0}.srt"'
.
format
(
self
.
transcript_language
)),
(
'Content-Disposition'
,
'attachment; filename="{filename}.{format}"'
.
format
(
filename
=
self
.
transcript_language
,
format
=
format
,
)),
]
)
response
.
content_type
=
"application/x-subrip"
response
.
content_type
=
mime_type
elif
dispatch
==
'available_translations'
:
available_translations
=
[]
...
...
common/test/data/uploads/subs_OEoXaMPEzfM.srt.sjson
View file @
3a740c04
...
...
@@ -94,7 +94,7 @@
114220
],
"text": [
"
LILA FISHER:
Hi, welcome to Edx.",
"Hi, welcome to Edx.",
"I'm Lila Fisher, an Edx fellow helping to put",
"together these courses.",
"As you know, our courses are entirely online.",
...
...
lms/djangoapps/courseware/features/video.feature
View file @
3a740c04
...
...
@@ -155,3 +155,24 @@ Feature: LMS Video component
Then
I see video aligned correctly with enabled transcript
And
I click video button
"CC"
Then
I see video aligned correctly without enabled transcript
# 19
Scenario
:
Download Transcript button works correctly in Video component
Given
I am registered for the course
"test_course"
And it has a video "A" in "Youtube" mode in position "1" of sequential
:
|
sub
|
download_track
|
|
OEoXaMPEzfM
|
true
|
And a video "B" in "Youtube" mode in position "2" of sequential
:
|
sub
|
download_track
|
|
OEoXaMPEzfM
|
true
|
And a video "C" in "Youtube" mode in position "3" of sequential
:
|
track
|
download_track
|
|
http://example.org/
|
true
|
And
I open the section with videos
And
I can download transcript in
"srt"
format
And
I select the transcript format
"txt"
And
I can download transcript in
"txt"
format
When
I open video
"B"
Then
I can download transcript in
"txt"
format
When
I open video
"C"
Then
menu
"download_transcript"
doesn't exist
lms/djangoapps/courseware/features/video.py
View file @
3a740c04
...
...
@@ -3,12 +3,13 @@
from
lettuce
import
world
,
step
import
json
import
os
import
requests
from
common
import
i_am_registered_for_the_course
,
section_location
,
visit_scenario_item
from
django.utils.translation
import
ugettext
as
_
from
django.conf
import
settings
from
cache_toolbox.core
import
del_cached_content
from
xmodule.contentstore.content
import
StaticContent
import
os
from
xmodule.contentstore.django
import
contentstore
TEST_ROOT
=
settings
.
COMMON_TEST_DATA_ROOT
LANGUAGES
=
settings
.
ALL_LANGUAGES
...
...
@@ -32,17 +33,57 @@ VIDEO_BUTTONS = {
'play'
:
'.video_control.play'
,
'pause'
:
'.video_control.pause'
,
'fullscreen'
:
'.add-fullscreen'
,
'download_transcript'
:
'.video-tracks > a'
,
}
VIDEO_MENUS
=
{
'language'
:
'.lang .menu'
,
'speed'
:
'.speed .menu'
,
'download_transcript'
:
'.video-tracks .a11y-menu-list'
,
}
coursenum
=
'test_course'
sequence
=
{}
class
ReuqestHandlerWithSessionId
(
object
):
def
get
(
self
,
url
):
"""
Sends a request.
"""
kwargs
=
dict
()
session_id
=
[{
i
[
'name'
]:
i
[
'value'
]}
for
i
in
world
.
browser
.
cookies
.
all
()
if
i
[
'name'
]
==
u'sessionid'
]
if
session_id
:
kwargs
.
update
({
'cookies'
:
session_id
[
0
]
})
response
=
requests
.
get
(
url
,
**
kwargs
)
self
.
response
=
response
self
.
status_code
=
response
.
status_code
self
.
headers
=
response
.
headers
self
.
content
=
response
.
content
return
self
def
is_success
(
self
):
"""
Returns `True` if the response was succeed, otherwise, returns `False`.
"""
if
self
.
status_code
<
400
:
return
True
return
False
def
check_header
(
self
,
name
,
value
):
"""
Returns `True` if the response header exist and has appropriate value,
otherwise, returns `False`.
"""
if
value
in
self
.
headers
.
get
(
name
,
''
):
return
True
return
False
def
add_video_to_course
(
course
,
player_mode
,
hashes
,
display_name
=
'Video'
):
category
=
'video'
...
...
@@ -80,15 +121,23 @@ def add_video_to_course(course, player_mode, hashes, display_name='Video'):
if
hashes
:
kwargs
[
'metadata'
]
.
update
(
hashes
[
0
])
course_location
=
world
.
scenario_dict
[
'COURSE'
]
.
location
course_location
=
world
.
scenario_dict
[
'COURSE'
]
.
location
conversions
=
{
'transcripts'
:
json
.
loads
,
'download_track'
:
json
.
loads
,
'download_video'
:
json
.
loads
,
}
for
key
in
kwargs
[
'metadata'
]:
if
key
in
conversions
:
kwargs
[
'metadata'
][
key
]
=
conversions
[
key
](
kwargs
[
'metadata'
][
key
])
if
'sub'
in
kwargs
[
'metadata'
]:
filename
=
_get_sjson_filename
(
kwargs
[
'metadata'
][
'sub'
],
'en'
)
_upload_file
(
filename
,
course_location
)
if
'transcripts'
in
kwargs
[
'metadata'
]:
kwargs
[
'metadata'
][
'transcripts'
]
=
json
.
loads
(
kwargs
[
'metadata'
][
'transcripts'
])
for
lang
,
filename
in
kwargs
[
'metadata'
][
'transcripts'
]
.
items
():
_upload_file
(
filename
,
course_location
)
...
...
@@ -322,6 +371,10 @@ def upload_to_assets(_step, filename):
def
is_hidden_button
(
_step
,
button
):
assert
not
world
.
css_visible
(
VIDEO_BUTTONS
[
button
])
@step
(
'menu "([^"]*)" doesn
\'
t exist$'
)
def
is_hidden_menu
(
_step
,
menu
):
assert
world
.
is_css_not_present
(
VIDEO_MENUS
[
menu
])
@step
(
'I see video aligned correctly (with(?:out)?) enabled transcript$'
)
def
video_alignment
(
_step
,
transcript_visibility
):
...
...
@@ -345,3 +398,45 @@ def video_alignment(_step, transcript_visibility):
)
assert
all
([
width
,
height
])
@step
(
'I can download transcript in "([^"]*)" format$'
)
def
i_can_download_transcript
(
_step
,
format
):
button
=
world
.
css_find
(
'.video-tracks .a11y-menu-button'
)
.
first
assert
button
.
text
.
strip
()
==
'.'
+
format
formats
=
{
'srt'
:
{
'content'
:
'0
\n
00:00:00,270'
,
'mime_type'
:
'application/x-subrip'
},
'txt'
:
{
'content'
:
'Hi, welcome to Edx.'
,
'mime_type'
:
'text/plain'
},
}
url
=
world
.
css_find
(
VIDEO_BUTTONS
[
'download_transcript'
])[
0
][
'href'
]
request
=
ReuqestHandlerWithSessionId
()
assert
request
.
get
(
url
)
.
is_success
()
assert
request
.
check_header
(
'content-type'
,
formats
[
format
][
'mime_type'
])
assert
request
.
content
.
startswith
(
formats
[
format
][
'content'
])
@step
(
'I select the transcript format "([^"]*)"$'
)
def
select_transcript_format
(
_step
,
format
):
button
=
world
.
css_find
(
'.video-tracks .a11y-menu-button'
)
.
first
button
.
mouse_over
()
assert
button
.
text
.
strip
()
==
'...'
menu_selector
=
VIDEO_MENUS
[
'download_transcript'
]
menu_items
=
world
.
css_find
(
menu_selector
+
' a'
)
for
item
in
menu_items
:
if
item
[
'data-value'
]
==
format
:
item
.
click
()
world
.
wait_for_ajax_complete
()
break
assert
world
.
css_find
(
menu_selector
+
' .active a'
)[
0
][
'data-value'
]
==
format
assert
button
.
text
.
strip
()
==
'.'
+
format
lms/djangoapps/courseware/tests/test_video_handlers.py
View file @
3a740c04
...
...
@@ -110,7 +110,7 @@ class TestVideo(BaseTestXmodule):
data
=
[
{
'speed'
:
2.0
},
{
'saved_video_position'
:
"00:00:10"
},
{
'transcript_language'
:
json
.
dumps
(
'uk'
)
},
{
'transcript_language'
:
'uk'
},
]
for
sample
in
data
:
response
=
self
.
clients
[
self
.
users
[
0
]
.
username
]
.
post
(
...
...
@@ -129,7 +129,7 @@ class TestVideo(BaseTestXmodule):
self
.
assertEqual
(
self
.
item_descriptor
.
saved_video_position
,
timedelta
(
0
,
10
))
self
.
assertEqual
(
self
.
item_descriptor
.
transcript_language
,
'en'
)
self
.
item_descriptor
.
handle_ajax
(
'save_user_state'
,
{
'transcript_language'
:
json
.
dumps
(
"uk"
)
})
self
.
item_descriptor
.
handle_ajax
(
'save_user_state'
,
{
'transcript_language'
:
"uk"
})
self
.
assertEqual
(
self
.
item_descriptor
.
transcript_language
,
'uk'
)
def
tearDown
(
self
):
...
...
@@ -173,11 +173,20 @@ class TestVideoTranscriptTranslation(TestVideo):
response
=
self
.
item
.
transcript
(
request
=
request
,
dispatch
=
'download'
)
self
.
assertEqual
(
response
.
status
,
'404 Not Found'
)
@patch
(
'xmodule.video_module.VideoModule.get_transcript'
,
return_value
=
'Subs!'
)
def
test_download_exist
(
self
,
__
):
@patch
(
'xmodule.video_module.VideoModule.get_transcript'
,
return_value
=
(
'Subs!'
,
'srt'
,
'application/x-subrip'
)
)
def
test_download_
srt_
exist
(
self
,
__
):
request
=
Request
.
blank
(
'/download?language=en'
)
response
=
self
.
item
.
transcript
(
request
=
request
,
dispatch
=
'download'
)
self
.
assertEqual
(
response
.
body
,
'Subs!'
)
self
.
assertEqual
(
response
.
headers
[
'Content-Type'
],
'application/x-subrip'
)
@patch
(
'xmodule.video_module.VideoModule.get_transcript'
,
return_value
=
(
'Subs!'
,
'txt'
,
'text/plain'
))
def
test_download_txt_exist
(
self
,
__
):
self
.
item
.
transcript_format
=
'txt'
request
=
Request
.
blank
(
'/download?language=en'
)
response
=
self
.
item
.
transcript
(
request
=
request
,
dispatch
=
'download'
)
self
.
assertEqual
(
response
.
body
,
'Subs!'
)
self
.
assertEqual
(
response
.
headers
[
'Content-Type'
],
'text/plain'
)
def
test_download_en_no_sub
(
self
):
request
=
Request
.
blank
(
'/download?language=en'
)
...
...
@@ -309,7 +318,7 @@ class TestVideoTranscriptsDownload(TestVideo):
self
.
item_descriptor
.
render
(
'student_view'
)
self
.
item
=
self
.
item_descriptor
.
xmodule_runtime
.
xmodule_instance
def
test_good_transcript
(
self
):
def
test_good_
srt_
transcript
(
self
):
good_sjson
=
_create_file
(
content
=
textwrap
.
dedent
(
"""
\
{
"start": [
...
...
@@ -329,7 +338,7 @@ class TestVideoTranscriptsDownload(TestVideo):
_upload_sjson_file
(
good_sjson
,
self
.
item
.
location
)
self
.
item
.
sub
=
_get_subs_id
(
good_sjson
.
name
)
text
=
self
.
item
.
get_transcript
()
text
,
format
,
download
=
self
.
item
.
get_transcript
()
expected_text
=
textwrap
.
dedent
(
"""
\
0
00:00:00,270 --> 00:00:02,720
...
...
@@ -343,6 +352,33 @@ class TestVideoTranscriptsDownload(TestVideo):
self
.
assertEqual
(
text
,
expected_text
)
def
test_good_txt_transcript
(
self
):
good_sjson
=
_create_file
(
content
=
textwrap
.
dedent
(
"""
\
{
"start": [
270,
2720
],
"end": [
2720,
5430
],
"text": [
"Hi, welcome to Edx.",
"Let's start with what is on your screen right now."
]
}
"""
))
_upload_sjson_file
(
good_sjson
,
self
.
item
.
location
)
self
.
item
.
sub
=
_get_subs_id
(
good_sjson
.
name
)
text
,
format
,
mime_type
=
self
.
item
.
get_transcript
(
format
=
"txt"
)
expected_text
=
textwrap
.
dedent
(
"""
\
Hi, welcome to Edx.
Let's start with what is on your screen right now."""
)
self
.
assertEqual
(
text
,
expected_text
)
def
test_not_found_error
(
self
):
with
self
.
assertRaises
(
NotFoundError
):
self
.
item
.
get_transcript
()
...
...
lms/djangoapps/courseware/tests/test_video_mongo.py
View file @
3a740c04
# -*- coding: utf-8 -*-
"""Video xmodule tests in mongo."""
from
mock
import
patch
,
PropertyMock
import
json
from
.
import
BaseTestXmodule
from
.test_video_xml
import
SOURCE_XML
...
...
@@ -41,6 +40,8 @@ class TestVideoYouTube(TestVideo):
'youtube_streams'
:
create_youtube_string
(
self
.
item_descriptor
),
'yt_test_timeout'
:
1500
,
'yt_test_url'
:
'https://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'
:
'en'
,
'transcript_languages'
:
'{"en": "English", "uk": "Ukrainian"}'
,
'transcript_translation_url'
:
self
.
item_descriptor
.
xmodule_runtime
.
handler_url
(
...
...
@@ -103,6 +104,8 @@ class TestVideoNonYouTube(TestVideo):
'autoplay'
:
settings
.
FEATURES
.
get
(
'AUTOPLAY_VIDEOS'
,
True
),
'yt_test_timeout'
:
1500
,
'yt_test_url'
:
'https://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'
:
'en'
,
'transcript_languages'
:
'{"en": "English"}'
,
'transcript_translation_url'
:
self
.
item_descriptor
.
xmodule_runtime
.
handler_url
(
...
...
@@ -191,6 +194,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
'autoplay'
:
settings
.
FEATURES
.
get
(
'AUTOPLAY_VIDEOS'
,
True
),
'yt_test_timeout'
:
1500
,
'yt_test_url'
:
'https://gdata.youtube.com/feeds/api/videos/'
,
'transcript_download_formats_list'
:
[{
'display_name'
:
'SubRip (.srt) file'
,
'value'
:
'srt'
},
{
'display_name'
:
'Text (.txt) file'
,
'value'
:
'txt'
}],
}
for
data
in
cases
:
...
...
@@ -208,6 +212,7 @@ class TestGetHtmlMethod(BaseTestXmodule):
context
=
self
.
item_descriptor
.
render
(
'student_view'
)
.
content
expected_context
.
update
({
'transcript_download_format'
:
None
if
self
.
item_descriptor
.
track
and
self
.
item_descriptor
.
download_track
else
'srt'
,
'transcript_languages'
:
'{"en": "English"}'
,
'transcript_language'
:
'en'
,
'transcript_translation_url'
:
self
.
item_descriptor
.
xmodule_runtime
.
handler_url
(
...
...
@@ -305,6 +310,8 @@ class TestGetHtmlMethod(BaseTestXmodule):
'autoplay'
:
settings
.
FEATURES
.
get
(
'AUTOPLAY_VIDEOS'
,
True
),
'yt_test_timeout'
:
1500
,
'yt_test_url'
:
'https://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'
:
'en'
,
'transcript_languages'
:
'{"en": "English"}'
,
}
...
...
lms/templates/video.html
View file @
3a740c04
...
...
@@ -112,7 +112,29 @@
% endif
% if track:
<li
class=
"video-tracks"
>
${('
<a
href=
"%s"
>
' + _('Download timed transcript') + '
</a>
') % track}
% if transcript_download_format:
${('
<a
href=
"%s"
>
' + _('Download transcript') + '
</a>
') % track
}
<div
class=
"a11y-menu-container"
>
<a
class=
"a11y-menu-button"
href=
"#"
title=
"${'.' + transcript_download_format}"
>
${'.' + transcript_download_format}
</a>
<ol
class=
"a11y-menu-list"
>
% for item in transcript_download_formats_list:
% if item['value'] == transcript_download_format:
<li
class=
"a11y-menu-item active"
>
% else:
<li
class=
"a11y-menu-item"
>
% endif
<a
class=
"a11y-menu-item-link"
href=
"#${item['value']}"
title=
"${_('{file_format}'.format(file_format=item['display_name']))}"
data-value=
"${item['value']}"
>
${_('{file_format}'.format(file_format=item['display_name']))}
</a>
</li>
% endfor
</ol>
</div>
% else:
${('
<a
href=
"%s"
class=
"external-track"
>
' + _('Download transcript') + '
</a>
') % track
}
% endif
</li>
% endif
</ul>
...
...
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