1 sortSources = (sources) ->
3 console.error('sortSources() called with null source list')
6 qualities = ['2160', '1440', '1080', '720', '540', '480', '360', '240']
7 pref = String(USEROPTS.default_quality)
8 if USEROPTS.default_quality == 'best'
10 idx = qualities.indexOf(pref)
14 qualityOrder = qualities.slice(idx).concat(qualities.slice(0, idx).reverse())
15 qualityOrder.unshift('auto')
18 for quality in qualityOrder
22 sources[quality].forEach((source) ->
23 source.quality = quality
24 if source.contentType == 'video/flv'
29 sourceOrder = sourceOrder.concat(nonflv)
30 flvOrder = flvOrder.concat(flv)
32 return sourceOrder.concat(flvOrder).map((source) ->
33 type: source.contentType
36 label: getSourceLabel(source)
39 getSourceLabel = (source) ->
40 if source.res is 'auto'
43 return "#{source.quality}p #{source.contentType.split('/')[1]}"
45 waitUntilDefined(window, 'videojs', =>
46 videojs.options.flash.swf = '/video-js.swf'
49 window.VideoJSPlayer = class VideoJSPlayer extends Player
50 constructor: (data) ->
51 if not (this instanceof VideoJSPlayer)
52 return new VideoJSPlayer(data)
57 waitUntilDefined(window, 'videojs', =>
62 if @mediaType == 'cm' and data.meta.textTracks
63 attrs.crossorigin = 'anonymous'
66 .addClass('video-js vjs-default-skin embed-responsive-item')
70 @sources = sortSources(data.meta.direct)
71 if @sources.length == 0
72 console.error('VideoJSPlayer::constructor(): data.meta.direct
79 # TODO: Refactor VideoJSPlayer to use a preLoad()/load()/postLoad() pattern
80 # VideoJSPlayer should provide the core functionality and logic for specific
81 # dependent player types (gdrive) should be an extension
82 if data.meta.gdrive_subtitles
83 data.meta.gdrive_subtitles.available.forEach((subt) ->
84 label = subt.lang_original
86 label += " (#{subt.name})"
88 src: "/gdvtt/#{data.id}/#{subt.lang}/#{subt.name}.vtt?\
89 vid=#{data.meta.gdrive_subtitles.vid}"
96 if data.meta.textTracks
97 data.meta.textTracks.forEach((track) ->
105 if track.default? and track.default
108 $('<track/>').attr(attrs).appendTo(video)
111 @player = videojs(video[0],
112 # https://github.com/Dash-Industry-Forum/dash.js/issues/2184
113 autoplay: @sources[0].type != 'application/dash+xml',
116 videoJsResolutionSwitcher:
117 default: @sources[0].res
120 # Have to use updateSrc instead of <source> tags
121 # see: https://github.com/videojs/video.js/issues/3428
122 @player.updateSrc(@sources)
123 @player.on('error', =>
124 err = @player.error()
125 if err and err.code == 4
126 console.error('Caught error, trying next source')
127 # Does this really need to be done manually?
129 if @sourceIdx < @sources.length
130 @player.src(@sources[@sourceIdx])
132 console.error('Out of sources, video will not play')
133 if @mediaType is 'gd' and not window.hasDriveUserscript
134 window.promptToInstallDriveUserscript()
137 @player.on('ended', ->
139 socket.emit('playNext')
142 @player.on('pause', =>
148 @player.on('play', =>
154 # Workaround for IE-- even after seeking completes, the loading
156 @player.on('seeked', =>
157 $('.vjs-waiting').removeClass('vjs-waiting')
160 # Workaround for Chrome-- it seems that the click bindings for
161 # the subtitle menu aren't quite set up until after the ready
162 # event finishes, so set a timeout for 1ms to force this code
163 # not to run until the ready() function returns.
165 $('#ytapiplayer .vjs-subtitles-button .vjs-menu-item').each((i, elem) ->
166 textNode = elem.childNodes[0]
167 if textNode.textContent == localStorage.lastSubtitle
171 if elem.attributes['aria-checked'].value == 'true'
172 localStorage.lastSubtitle = textNode.textContent
179 @setMediaProperties(data)
180 # Note: VideoJS does have facilities for loading new videos into the
181 # existing player object, however it appears to be pretty glitchy when
182 # a video can't be played (either previous or next video). It's safer
183 # to just reset the entire thing.
189 if @player and @player.readyState() > 0
194 if @player and @player.readyState() > 0
198 if @player and @player.readyState() > 0
199 @player.currentTime(time)
201 setVolume: (volume) ->
203 @player.volume(volume)
206 if @player and @player.readyState() > 0
207 cb(@player.currentTime())
212 if @player and @player.readyState() > 0