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
63c5ec52
Commit
63c5ec52
authored
Aug 19, 2013
by
Anton Stupak
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add supporting failover from Youtube.
parent
7fc8fcde
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
142 additions
and
54 deletions
+142
-54
common/lib/xmodule/xmodule/js/spec/helper.coffee
+6
-1
common/lib/xmodule/xmodule/js/spec/video/general_spec.js
+40
-0
common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js
+2
-0
common/lib/xmodule/xmodule/js/src/video/01_initialize.js
+94
-53
No files found.
common/lib/xmodule/xmodule/js/spec/helper.coffee
View file @
63c5ec52
...
...
@@ -90,7 +90,12 @@ jasmine.stubbedHtml5Speeds = ['0.75', '1.0', '1.25', '1.50']
jasmine
.
stubRequests
=
->
spyOn
(
$
,
'ajax'
).
andCallFake
(
settings
)
->
if
match
=
settings
.
url
.
match
/youtube\.com\/.+\/videos\/(.+)\?v=2&alt=jsonc/
settings
.
success
data
:
jasmine
.
stubbedMetadata
[
match
[
1
]]
if
settings
.
success
settings
.
success
data
:
jasmine
.
stubbedMetadata
[
match
[
1
]]
else
{
always
:
(
callback
)
->
callback
.
call
(
window
,
{},
'success'
);
}
else
if
match
=
settings
.
url
.
match
/static(\/.*)?\/subs\/(.+)\.srt\.sjson/
settings
.
success
jasmine
.
stubbedCaption
else
if
settings
.
url
.
match
/.+\/problem_get$/
...
...
common/lib/xmodule/xmodule/js/spec/video/general_spec.js
View file @
63c5ec52
...
...
@@ -58,6 +58,46 @@
expect
(
this
.
state
.
speed
).
toEqual
(
'0.75'
);
});
});
describe
(
'Check Youtube link existence'
,
function
()
{
var
statusList
=
{
'error'
:
'html5'
,
'timeout'
:
'html5'
,
'abort'
:
'html5'
,
'parsererror'
:
'html5'
,
'success'
:
'youtube'
,
'notmodified'
:
'youtube'
};
function
stubDeffered
(
data
,
status
)
{
return
{
always
:
function
(
callback
)
{
callback
.
call
(
window
,
data
,
status
);
}
}
}
function
checkPlayer
(
videoType
,
data
,
status
)
{
this
.
state
=
new
window
.
Video
(
'#example'
);
spyOn
(
this
.
state
,
'getVideoMetadata'
)
.
andReturn
(
stubDeffered
(
data
,
status
));
this
.
state
.
initialize
(
'#example'
);
expect
(
this
.
state
.
videoType
).
toEqual
(
videoType
);
}
it
(
'if video id is incorrect'
,
function
()
{
checkPlayer
(
'html5'
,
{
error
:
{}
},
'success'
);
});
$
.
each
(
statusList
,
function
(
status
,
mode
){
it
(
'Status:'
+
status
+
', mode:'
+
mode
,
function
()
{
checkPlayer
(
mode
,
{},
status
);
});
});
});
});
describe
(
'HTML5'
,
function
()
{
...
...
common/lib/xmodule/xmodule/js/spec/video/video_player_spec.js
View file @
63c5ec52
...
...
@@ -79,6 +79,8 @@
it
(
'create Youtube player'
,
function
()
{
var
oldYT
=
window
.
YT
;
jasmine
.
stubRequests
();
window
.
YT
=
{
Player
:
function
()
{
},
PlayerState
:
oldYT
.
PlayerState
...
...
common/lib/xmodule/xmodule/js/src/video/01_initialize.js
View file @
63c5ec52
...
...
@@ -30,8 +30,7 @@ function (VideoPlayer) {
*/
return
function
(
state
,
element
)
{
_makeFunctionsPublic
(
state
);
_initialize
(
state
,
element
);
_renderElements
(
state
);
state
.
initialize
(
element
);
};
// ***************************************************************
...
...
@@ -56,59 +55,12 @@ function (VideoPlayer) {
// Old private functions. Now also public so that can be
// tested by Jasmine.
state
.
initialize
=
_
.
bind
(
initialize
,
state
);
state
.
parseSpeed
=
_
.
bind
(
parseSpeed
,
state
);
state
.
fetchMetadata
=
_
.
bind
(
fetchMetadata
,
state
);
state
.
parseYoutubeStreams
=
_
.
bind
(
parseYoutubeStreams
,
state
);
state
.
parseVideoSources
=
_
.
bind
(
parseVideoSources
,
state
);
}
// function _initialize(element)
// The function set initial configuration and preparation.
function
_initialize
(
state
,
element
)
{
// This is used in places where we instead would have to check if an element has a CSS class 'fullscreen'.
state
.
isFullScreen
=
false
;
// The parent element of the video, and the ID.
state
.
el
=
$
(
element
).
find
(
'.video'
);
state
.
id
=
state
.
el
.
attr
(
'id'
).
replace
(
/video_/
,
''
);
// We store all settings passed to us by the server in one place. These are "read only", so don't
// modify them. All variable content lives in 'state' object.
state
.
config
=
{
element
:
element
,
start
:
state
.
el
.
data
(
'start'
),
end
:
state
.
el
.
data
(
'end'
),
caption_data_dir
:
state
.
el
.
data
(
'caption-data-dir'
),
caption_asset_path
:
state
.
el
.
data
(
'caption-asset-path'
),
show_captions
:
(
state
.
el
.
data
(
'show-captions'
).
toString
().
toLowerCase
()
===
'true'
),
youtubeStreams
:
state
.
el
.
data
(
'streams'
),
sub
:
state
.
el
.
data
(
'sub'
),
mp4Source
:
state
.
el
.
data
(
'mp4-source'
),
webmSource
:
state
.
el
.
data
(
'webm-source'
),
oggSource
:
state
.
el
.
data
(
'ogg-source'
),
fadeOutTimeout
:
1400
,
availableQualities
:
[
'hd720'
,
'hd1080'
,
'highres'
]
};
if
(
!
(
_parseYouTubeIDs
(
state
)))
{
// If we do not have YouTube ID's, try parsing HTML5 video sources.
_prepareHTML5Video
(
state
);
}
_configureCaptions
(
state
);
_setPlayerMode
(
state
);
// Possible value are: 'visible', 'hiding', and 'invisible'.
state
.
controlState
=
'visible'
;
state
.
controlHideTimeout
=
null
;
state
.
captionState
=
'visible'
;
state
.
captionHideTimeout
=
null
;
state
.
getVideoMetadata
=
_
.
bind
(
getVideoMetadata
,
state
);
}
// function _renderElements(state)
...
...
@@ -228,12 +180,83 @@ function (VideoPlayer) {
state
.
setSpeed
(
$
.
cookie
(
'video_speed'
));
}
function
_setConfigurations
(
state
)
{
_configureCaptions
(
state
);
_setPlayerMode
(
state
);
// Possible value are: 'visible', 'hiding', and 'invisible'.
state
.
controlState
=
'visible'
;
state
.
controlHideTimeout
=
null
;
state
.
captionState
=
'visible'
;
state
.
captionHideTimeout
=
null
;
}
// ***************************************************************
// Public functions start here.
// These are available via the 'state' object. Their context ('this' keyword) is the 'state' object.
// The magic private function that makes them available and sets up their context is makeFunctionsPublic().
// ***************************************************************
// function initialize(element)
// The function set initial configuration and preparation.
function
initialize
(
element
)
{
var
state
=
this
;
// This is used in places where we instead would have to check if an element has a CSS class 'fullscreen'.
state
.
isFullScreen
=
false
;
// The parent element of the video, and the ID.
state
.
el
=
$
(
element
).
find
(
'.video'
);
state
.
id
=
state
.
el
.
attr
(
'id'
).
replace
(
/video_/
,
''
);
// We store all settings passed to us by the server in one place. These are "read only", so don't
// modify them. All variable content lives in 'state' object.
state
.
config
=
{
element
:
element
,
start
:
state
.
el
.
data
(
'start'
),
end
:
state
.
el
.
data
(
'end'
),
caption_data_dir
:
state
.
el
.
data
(
'caption-data-dir'
),
caption_asset_path
:
state
.
el
.
data
(
'caption-asset-path'
),
show_captions
:
(
state
.
el
.
data
(
'show-captions'
).
toString
().
toLowerCase
()
===
'true'
),
youtubeStreams
:
state
.
el
.
data
(
'streams'
),
sub
:
state
.
el
.
data
(
'sub'
),
mp4Source
:
state
.
el
.
data
(
'mp4-source'
),
webmSource
:
state
.
el
.
data
(
'webm-source'
),
oggSource
:
state
.
el
.
data
(
'ogg-source'
),
fadeOutTimeout
:
1400
,
availableQualities
:
[
'hd720'
,
'hd1080'
,
'highres'
]
};
if
(
!
(
_parseYouTubeIDs
(
state
)))
{
// If we do not have YouTube ID's, try parsing HTML5 video sources.
_prepareHTML5Video
(
state
);
_setConfigurations
(
state
);
_renderElements
(
state
);
}
else
{
state
.
getVideoMetadata
()
.
always
(
function
(
json
,
status
)
{
var
err
=
$
.
isPlainObject
(
json
.
error
)
||
(
status
!==
"success"
&&
status
!==
"notmodified"
);
if
(
err
){
// When the youtube link doesn't work for any reason
// (for example, the great firewall in china) any
// alternate sources should automatically play.
_prepareHTML5Video
(
state
);
state
.
el
.
find
(
'a.quality_control'
).
hide
();
}
_setConfigurations
(
state
);
_renderElements
(
state
);
});
}
}
// function parseYoutubeStreams(state, youtubeStreams)
//
// Take a string in the form:
...
...
@@ -297,9 +320,9 @@ function (VideoPlayer) {
this
.
metadata
=
{};
$
.
each
(
this
.
videos
,
function
(
speed
,
url
)
{
$
.
get
(
'https://gdata.youtube.com/feeds/api/videos/'
+
url
+
'?v=2&alt=jsonc'
,
(
function
(
data
)
{
_this
.
getVideoMetadata
(
url
,
function
(
data
)
{
_this
.
metadata
[
data
.
data
.
id
]
=
data
.
data
;
})
,
'jsonp'
)
;
});
});
}
...
...
@@ -329,6 +352,24 @@ function (VideoPlayer) {
}
}
function
getVideoMetadata
(
url
,
callback
)
{
var
successHandler
,
xhr
;
if
(
typeof
url
!==
'string'
)
{
url
=
this
.
videos
[
'1.0'
]
||
''
;
}
successHandler
=
(
$
.
isFunction
(
callback
))
?
callback
:
null
;
xhr
=
$
.
ajax
({
url
:
'https://gdata.youtube.com/feeds/api/videos/'
+
url
+
'?v=2&alt=jsonc'
,
timeout
:
500
,
dataType
:
'jsonp'
,
success
:
successHandler
});
return
xhr
;
}
function
stopBuffering
()
{
var
video
;
...
...
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