jellyfin-web/dashboard-ui/scripts/mediaplayer-video.js

1202 lines
39 KiB
JavaScript
Raw Normal View History

(function () {
2014-06-21 22:52:31 -07:00
function createVideoPlayer(self) {
var timeout;
var initialVolume;
var fullscreenExited = false;
var idleState = true;
var remoteFullscreen = false;
var muteButton = null;
var unmuteButton = null;
var volumeSlider = null;
var positionSlider;
var isPositionSliderActive;
var currentTimeElement;
2014-06-11 12:31:33 -07:00
self.currentSubtitleStreamIndex = null;
2014-06-11 19:38:40 -07:00
self.getCurrentSubtitleStream = function () {
return self.getSubtitleStream(self.currentSubtitleStreamIndex);
};
self.getSubtitleStream = function (index) {
return self.currentMediaSource.MediaStreams.filter(function (s) {
return s.Type == 'Subtitle' && s.Index == index;
})[0];
};
self.remoteFullscreen = function () {
if (remoteFullscreen) {
exitFullScreenToWindow();
} else {
enterFullScreen();
}
remoteFullscreen = !remoteFullscreen;
};
self.toggleFullscreen = function () {
if (self.isFullScreen()) {
if (document.cancelFullScreen) {
document.cancelFullScreen();
}
else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
}
else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
}
else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen();
}
2014-05-29 12:34:20 -07:00
$('#videoPlayer').removeClass('fullscreenVideo');
} else {
requestFullScreen(document.body);
}
};
self.resetEnhancements = function () {
$("#mediaPlayer").hide();
2014-10-09 15:22:04 -07:00
$('#videoPlayer').removeClass('fullscreenVideo').removeClass('idlePlayer');
2014-06-28 12:35:30 -07:00
$('.hiddenOnIdle').removeClass("inactive");
$("video").remove();
};
2014-03-20 20:31:40 -07:00
self.exitFullScreen = function () {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.mozExitFullScreen) {
document.mozExitFullScreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
}
2014-05-29 12:34:20 -07:00
$('#videoPlayer').removeClass('fullscreenVideo');
fullscreenExited = true;
2014-03-17 07:48:16 -07:00
};
2014-03-20 20:31:40 -07:00
self.isFullScreen = function () {
return document.fullscreen || document.mozFullScreen || document.webkitIsFullScreen || document.msFullscreenElement ? true : false;
2014-03-17 07:48:16 -07:00
};
2014-07-02 11:34:08 -07:00
function onFlyoutClose() {
$('.itemVideo').css('visibility', 'visible');
}
function onPopupOpen(elem) {
elem.popup("open").parents(".ui-popup-container").css("margin-top", 30);
if ($.browser.safari) {
$('.itemVideo').css('visibility', 'hidden');
}
}
self.showSubtitleMenu = function () {
2014-06-28 12:35:30 -07:00
var elem = $('.videoSubtitlePopup').html(getSubtitleTracksHtml())
.trigger('create')
2014-07-02 11:34:08 -07:00
.popup("option", "positionTo", $('.videoSubtitleButton'))
.off('popupafterclose', onFlyoutClose)
.on('popupafterclose', onFlyoutClose);
2014-07-02 11:34:08 -07:00
onPopupOpen(elem);
};
self.showQualityFlyout = function () {
2014-06-28 12:35:30 -07:00
var elem = $('.videoQualityPopup').html(getQualityFlyoutHtml())
.trigger('create')
2014-07-02 11:34:08 -07:00
.popup("option", "positionTo", $('.videoQualityButton'))
.off('popupafterclose', onFlyoutClose)
.on('popupafterclose', onFlyoutClose);
2014-07-02 11:34:08 -07:00
onPopupOpen(elem);
};
self.showChaptersFlyout = function () {
2014-06-28 12:35:30 -07:00
var elem = $('.videoChaptersPopup').html(getChaptersFlyoutHtml())
.trigger('create')
2014-07-02 11:34:08 -07:00
.popup("option", "positionTo", $('.videoChaptersButton'))
.off('popupafterclose', onFlyoutClose)
.on('popupafterclose', onFlyoutClose);
2014-07-02 11:34:08 -07:00
onPopupOpen(elem);
};
self.showAudioTracksFlyout = function () {
2014-06-28 12:35:30 -07:00
var elem = $('.videoAudioPopup').html(getAudioTracksHtml())
.trigger('create')
2014-07-02 11:34:08 -07:00
.popup("option", "positionTo", $('.videoAudioButton'))
.off('popupafterclose', onFlyoutClose)
.on('popupafterclose', onFlyoutClose);
2014-07-02 11:34:08 -07:00
onPopupOpen(elem);
};
2014-05-07 22:04:39 -07:00
self.setAudioStreamIndex = function (index) {
self.changeStream(self.getCurrentTicks(), { AudioStreamIndex: index });
};
self.setSubtitleStreamIndex = function (index) {
2014-06-11 19:38:40 -07:00
if (!self.supportsTextTracks()) {
2014-07-19 21:46:29 -07:00
2014-06-11 19:38:40 -07:00
self.changeStream(self.getCurrentTicks(), { SubtitleStreamIndex: index });
self.currentSubtitleStreamIndex = index;
return;
}
var currentStream = self.getCurrentSubtitleStream();
var newStream = self.getSubtitleStream(index);
if (!currentStream && !newStream) return;
var selectedTrackElementIndex = -1;
if (currentStream && !newStream) {
2015-03-30 12:57:37 -07:00
if (currentStream.DeliveryMethod != 'External') {
2014-06-11 19:38:40 -07:00
// Need to change the transcoded stream to remove subs
self.changeStream(self.getCurrentTicks(), { SubtitleStreamIndex: -1 });
}
}
else if (!currentStream && newStream) {
2015-03-30 12:57:37 -07:00
if (newStream.DeliveryMethod == 'External') {
2014-06-11 19:38:40 -07:00
selectedTrackElementIndex = index;
} else {
// Need to change the transcoded stream to add subs
self.changeStream(self.getCurrentTicks(), { SubtitleStreamIndex: index });
}
}
else if (currentStream && newStream) {
2015-03-30 12:57:37 -07:00
if (newStream.DeliveryMethod == 'External') {
selectedTrackElementIndex = index;
2014-06-14 19:58:00 -07:00
2015-03-30 12:57:37 -07:00
if (currentStream.DeliveryMethod != 'External') {
self.changeStream(self.getCurrentTicks(), { SubtitleStreamIndex: -1 });
}
} else {
// Need to change the transcoded stream to add subs
self.changeStream(self.getCurrentTicks(), { SubtitleStreamIndex: index });
}
}
2014-06-11 19:38:40 -07:00
self.setCurrentTrackElement(selectedTrackElementIndex);
2014-07-19 21:46:29 -07:00
2014-06-11 19:38:40 -07:00
self.currentSubtitleStreamIndex = index;
};
self.setCurrentTrackElement = function (index) {
2014-08-25 19:30:52 -07:00
var modes = ['disabled', 'showing', 'hidden'];
2014-06-11 19:38:40 -07:00
var textStreams = self.currentMediaSource.MediaStreams.filter(function (s) {
2015-03-30 12:57:37 -07:00
return s.DeliveryMethod == 'External';
2014-06-11 19:38:40 -07:00
});
2014-07-19 21:46:29 -07:00
var newStream = textStreams.filter(function (s) {
return s.Index == index;
})[0];
var trackIndex = newStream ? textStreams.indexOf(newStream) : -1;
console.log('Setting new text track index to: ' + trackIndex);
2014-06-21 22:52:31 -07:00
var allTracks = self.currentMediaElement.textTracks; // get list of tracks
2014-06-11 19:38:40 -07:00
for (var i = 0; i < allTracks.length; i++) {
2014-07-19 21:46:29 -07:00
var mode;
2014-06-11 19:38:40 -07:00
2014-07-19 21:46:29 -07:00
if (trackIndex == i) {
2014-08-25 19:30:52 -07:00
mode = 1; // show this track
2014-06-11 19:38:40 -07:00
} else {
2014-08-25 19:30:52 -07:00
mode = 0; // hide all other tracks
2014-06-11 19:38:40 -07:00
}
2014-07-19 21:46:29 -07:00
console.log('Setting track ' + i + ' mode to: ' + mode);
2014-08-25 19:30:52 -07:00
// Safari uses integers for the mode property
// http://www.jwplayer.com/html5/scripting/
var useNumericMode = false;
if (!isNaN(allTracks[i].mode)) {
useNumericMode = true;
}
if (useNumericMode) {
allTracks[i].mode = mode;
} else {
allTracks[i].mode = modes[mode];
}
2014-06-11 19:38:40 -07:00
}
2014-05-07 22:04:39 -07:00
};
2014-06-14 19:58:00 -07:00
self.updateTextStreamUrls = function (startPositionTicks) {
if (!self.supportsTextTracks()) {
return;
}
2014-06-21 22:52:31 -07:00
var allTracks = self.currentMediaElement.textTracks; // get list of tracks
2014-06-18 09:08:54 -07:00
for (var i = 0; i < allTracks.length; i++) {
var track = allTracks[i];
// This throws an error in IE, but is fine in chrome
// In IE it's not necessary anyway because changing the src seems to be enough
try {
while (track.cues.length) {
track.removeCue(track.cues[0]);
}
} catch (e) {
console.log('Error removing cue from textTrack');
}
}
2014-06-21 22:52:31 -07:00
$('track', self.currentMediaElement).each(function () {
2014-06-14 19:58:00 -07:00
var currentSrc = this.src;
currentSrc = replaceQueryString(currentSrc, 'startPositionTicks', startPositionTicks);
this.src = currentSrc;
2014-06-14 19:58:00 -07:00
});
};
2014-06-28 12:35:30 -07:00
self.updateNowPlayingInfo = function (item) {
if (!item) {
throw new Error('item cannot be null');
}
var mediaControls = $("#videoPlayer");
var state = self.getPlayerStateInternal(self.currentMediaElement, item, self.currentMediaSource);
var url = "";
if (state.NowPlayingItem.PrimaryImageTag) {
url = ApiClient.getScaledImageUrl(state.NowPlayingItem.PrimaryImageItemId, {
type: "Primary",
width: 150,
tag: state.NowPlayingItem.PrimaryImageTag
});
}
else if (state.NowPlayingItem.PrimaryImageTag) {
url = ApiClient.getScaledImageUrl(state.NowPlayingItem.PrimaryImageItemId, {
type: "Primary",
width: 150,
tag: state.NowPlayingItem.PrimaryImageTag
});
}
else if (state.NowPlayingItem.BackdropImageTag) {
url = ApiClient.getScaledImageUrl(state.NowPlayingItem.BackdropItemId, {
type: "Backdrop",
height: 300,
tag: state.NowPlayingItem.BackdropImageTag,
index: 0
});
}
else if (state.NowPlayingItem.ThumbImageTag) {
url = ApiClient.getScaledImageUrl(state.NowPlayingItem.ThumbImageItemId, {
type: "Thumb",
height: 300,
tag: state.NowPlayingItem.ThumbImageTag
});
}
var nowPlayingTextElement = $('.nowPlayingText', mediaControls);
var nameHtml = self.getNowPlayingNameHtml(state);
if (nameHtml.indexOf('<br/>') != -1) {
nowPlayingTextElement.addClass('nowPlayingDoubleText');
} else {
nowPlayingTextElement.removeClass('nowPlayingDoubleText');
}
if (url) {
$('.nowPlayingImage', mediaControls).html('<img src="' + url + '" />');
} else {
$('.nowPlayingImage', mediaControls).html('');
}
if (state.NowPlayingItem.LogoItemId) {
url = ApiClient.getScaledImageUrl(state.NowPlayingItem.LogoItemId, {
type: "Logo",
2014-06-28 19:30:20 -07:00
height: 42,
2014-06-28 12:35:30 -07:00
tag: state.NowPlayingItem.LogoImageTag
});
$('.videoTopControlsLogo', mediaControls).html('<img src="' + url + '" />');
} else {
$('.videoTopControlsLogo', mediaControls).html('');
}
nowPlayingTextElement.html(nameHtml);
};
function onPositionSliderChange() {
isPositionSliderActive = false;
var newPercent = parseInt(this.value);
2014-06-11 12:31:33 -07:00
var newPositionTicks = (newPercent / 100) * self.currentMediaSource.RunTimeTicks;
self.changeStream(Math.floor(newPositionTicks));
}
$(function () {
var parent = $("#mediaPlayer");
muteButton = $('.muteButton', parent);
unmuteButton = $('.unmuteButton', parent);
currentTimeElement = $('.currentTime', parent);
positionSlider = $(".positionSlider", parent).on('slidestart', function (e) {
isPositionSliderActive = true;
}).on('slidestop', onPositionSliderChange);
volumeSlider = $('.volumeSlider', parent).on('slidestop', function () {
var vol = this.value;
updateVolumeButtons(vol);
self.setVolume(vol * 100);
});
2014-06-28 12:35:30 -07:00
$('.videoChaptersPopup').on('click', '.mediaPopupOption', function () {
2015-03-04 13:37:35 -07:00
var ticks = parseInt(this.getAttribute('data-positionticks') || '0');
self.changeStream(ticks);
2014-06-28 12:35:30 -07:00
$('.videoChaptersPopup').popup('close');
});
2014-06-28 12:35:30 -07:00
$('.videoAudioPopup').on('click', '.mediaPopupOption', function () {
2014-06-28 12:35:30 -07:00
if (!$(this).hasClass('selectedMediaPopupOption')) {
var index = parseInt(this.getAttribute('data-index'));
2014-05-07 22:04:39 -07:00
self.setAudioStreamIndex(index);
}
2014-06-28 12:35:30 -07:00
$('.videoAudioPopup').popup('close');
});
2014-06-28 12:35:30 -07:00
$('.videoSubtitlePopup').on('click', '.mediaPopupOption', function () {
2014-07-19 21:46:29 -07:00
$('.videoSubtitlePopup').popup('close');
2014-06-28 12:35:30 -07:00
if (!$(this).hasClass('selectedMediaPopupOption')) {
2014-07-19 21:46:29 -07:00
var index = parseInt(this.getAttribute('data-index'));
2014-05-07 22:04:39 -07:00
self.setSubtitleStreamIndex(index);
}
});
2014-06-28 12:35:30 -07:00
$('.videoQualityPopup').on('click', '.mediaPopupOption', function () {
2014-06-28 12:35:30 -07:00
if (!$(this).hasClass('selectedMediaPopupOption')) {
var bitrate = parseInt(this.getAttribute('data-bitrate'));
2014-09-16 18:38:50 -07:00
AppSettings.maxStreamingBitrate(bitrate);
self.changeStream(self.getCurrentTicks(), {
Bitrate: bitrate
});
}
2014-06-28 12:35:30 -07:00
$('.videoQualityPopup').popup('close');
});
var trackChange = false;
var tooltip = $('<div id="slider-tooltip"></div>');
2014-06-28 12:35:30 -07:00
$(".videoControls .positionSliderContainer .slider").on("change", function (e) {
if (!trackChange) return;
var pct = $(this).val();
2014-03-31 14:43:49 -07:00
var time = self.currentDurationTicks * (Number(pct) * .01);
var tooltext = Dashboard.getDisplayTime(time);
tooltip.text(tooltext);
2014-03-31 14:43:49 -07:00
console.log("slidin", pct, self.currentDurationTicks, time);
}).on("slidestart", function (e) {
trackChange = true;
2014-06-28 12:35:30 -07:00
var handle = $(".videoControls .positionSliderContainer .ui-slider-handle");
handle.after(tooltip);
}).on("slidestop", function (e) {
trackChange = false;
tooltip.remove();
});
2014-06-21 22:52:31 -07:00
2014-06-28 12:35:30 -07:00
$('.videoSubtitleButton').on('click', function () {
self.showSubtitleMenu();
});
$('.videoQualityButton').on('click', function () {
2014-06-25 08:12:39 -07:00
self.showQualityFlyout();
2014-06-21 22:52:31 -07:00
});
2014-06-28 12:35:30 -07:00
$('.videoAudioButton').on('click', function () {
self.showAudioTracksFlyout();
});
$('.videoChaptersButton').on('click', function () {
self.showChaptersFlyout();
});
});
function idleHandler() {
2014-06-21 22:52:31 -07:00
if (timeout) {
window.clearTimeout(timeout);
}
if (idleState == true) {
2014-06-28 12:35:30 -07:00
$('.hiddenOnIdle').removeClass("inactive");
2014-10-09 15:22:04 -07:00
$('#videoPlayer').removeClass('idlePlayer');
}
idleState = false;
timeout = window.setTimeout(function () {
idleState = true;
2014-06-28 12:35:30 -07:00
$('.hiddenOnIdle').addClass("inactive");
2014-10-09 15:22:04 -07:00
$('#videoPlayer').addClass('idlePlayer');
}, 4000);
}
function updateVolumeButtons(vol) {
if (vol) {
muteButton.show();
unmuteButton.hide();
} else {
muteButton.hide();
unmuteButton.show();
}
}
function requestFullScreen(element) {
// Supports most browsers and their versions.
var requestMethod = element.requestFullscreen || element.webkitRequestFullscreen || element.webkitRequestFullScreen || element.mozRequestFullScreen;
if (requestMethod) { // Native full screen.
requestMethod.call(element);
} else {
enterFullScreen();
}
}
function enterFullScreen() {
2014-03-17 07:48:16 -07:00
var player = $("#videoPlayer");
2014-05-29 12:34:20 -07:00
player.addClass("fullscreenVideo");
remoteFullscreen = true;
}
function exitFullScreenToWindow() {
2014-03-17 07:48:16 -07:00
var player = $("#videoPlayer");
2014-05-29 12:34:20 -07:00
player.removeClass("fullscreenVideo");
remoteFullscreen = false;
}
2014-03-20 20:31:40 -07:00
function getChaptersFlyoutHtml() {
2014-06-28 12:35:30 -07:00
var item = self.currentItem;
var currentTicks = self.getCurrentTicks();
2014-06-28 12:35:30 -07:00
var chapters = item.Chapters || [];
2014-06-28 12:35:30 -07:00
var html = '';
html += '<div class="videoPlayerPopupContent">';
2014-07-02 11:34:08 -07:00
html += '<ul data-role="listview" data-inset="true"><li data-role="list-divider">' + Globalize.translate('HeaderScenes') + '</li>';
2014-06-28 12:35:30 -07:00
html += '</ul>';
2014-06-28 12:35:30 -07:00
html += '<div class="videoPlayerPopupScroller">';
html += '<ul data-role="listview" data-inset="true">';
2014-06-28 12:35:30 -07:00
var index = 0;
2014-06-28 12:35:30 -07:00
html += chapters.map(function (chapter) {
2014-06-28 12:35:30 -07:00
var cssClass = "mediaPopupOption";
2014-06-28 12:35:30 -07:00
var selected = false;
2014-06-28 12:35:30 -07:00
if (currentTicks >= chapter.StartPositionTicks) {
var nextChapter = chapters[index + 1];
selected = !nextChapter || currentTicks < nextChapter.StartPositionTicks;
}
2014-06-28 12:35:30 -07:00
var optionHtml = '<li><a data-positionticks="' + chapter.StartPositionTicks + '" class="' + cssClass + '" href="#" style="padding-top:0;padding-bottom:0;">';
2014-06-28 12:35:30 -07:00
var imgUrl = "css/images/media/chapterflyout.png";
if (chapter.ImageTag) {
2014-06-28 12:35:30 -07:00
optionHtml += '<img src="' + imgUrl + '" style="visibility:hidden;" />';
imgUrl = ApiClient.getScaledImageUrl(item.Id, {
width: 160,
tag: chapter.ImageTag,
type: "Chapter",
2014-06-28 12:35:30 -07:00
index: index
});
2014-06-28 12:35:30 -07:00
optionHtml += '<div class="videoChapterPopupImage" style="background-image:url(\'' + imgUrl + '\');"></div>';
} else {
2014-06-28 12:35:30 -07:00
optionHtml += '<img src="' + imgUrl + '" />';
}
2014-06-28 12:35:30 -07:00
// TODO: Add some indicator if selected = true
2014-06-28 12:35:30 -07:00
optionHtml += '<p style="margin:12px 0 0;">';
2014-06-28 12:35:30 -07:00
var textLines = [];
textLines.push(chapter.Name);
textLines.push(Dashboard.getDisplayTime(chapter.StartPositionTicks));
2014-06-28 12:35:30 -07:00
optionHtml += textLines.join('<br/>');
2014-06-28 12:35:30 -07:00
optionHtml += '</p>';
2014-06-28 12:35:30 -07:00
optionHtml += '</a></li>';
index++;
return optionHtml;
}).join('');
html += '</ul>';
html += '</div>';
html += '</div>';
return html;
}
2014-03-20 20:31:40 -07:00
function getAudioTracksHtml() {
2014-04-06 10:53:23 -07:00
2014-06-11 12:31:33 -07:00
var streams = self.currentMediaSource.MediaStreams.filter(function (currentStream) {
2014-03-20 20:31:40 -07:00
return currentStream.Type == "Audio";
});
2014-10-22 21:26:01 -07:00
var currentIndex = getParameterByName('AudioStreamIndex', self.getCurrentSrc(self.currentMediaElement));
var html = '';
2014-06-28 12:35:30 -07:00
html += '<div class="videoPlayerPopupContent">';
2014-07-02 11:34:08 -07:00
html += '<ul data-role="listview" data-inset="true"><li data-role="list-divider">' + Globalize.translate('HeaderAudioTracks') + '</li>';
2014-06-28 12:35:30 -07:00
html += '</ul>';
2014-06-28 12:35:30 -07:00
html += '<div class="videoPlayerPopupScroller">';
html += '<ul data-role="listview" data-inset="true">';
2014-06-28 12:35:30 -07:00
html += streams.map(function (stream) {
2014-06-28 12:35:30 -07:00
var cssClass = "mediaPopupOption";
var selected = stream.Index == currentIndex;
if (selected) {
cssClass += ' selectedMediaPopupOption';
}
2014-06-28 12:35:30 -07:00
var optionHtml = '<li><a data-index="' + stream.Index + '" class="' + cssClass + '" href="#">';
2014-06-28 12:35:30 -07:00
optionHtml += '<p style="margin:0;">';
2014-06-28 12:35:30 -07:00
if (selected) {
optionHtml += '<img src="css/images/checkmarkgreen.png" style="width:18px;border-radius:3px;margin-right:.5em;vertical-align:middle;" />';
}
2014-06-28 12:35:30 -07:00
var textLines = [];
2014-07-02 11:34:08 -07:00
textLines.push(stream.Language || Globalize.translate('LabelUnknownLanguage'));
2014-06-28 12:35:30 -07:00
var attributes = [];
if (stream.Codec) {
2014-06-28 12:35:30 -07:00
attributes.push(stream.Codec);
}
if (stream.Profile) {
2014-06-28 12:35:30 -07:00
attributes.push(stream.Profile);
}
if (stream.BitRate) {
2014-06-28 12:35:30 -07:00
attributes.push((Math.floor(stream.BitRate / 1000)) + ' kbps');
}
if (stream.Channels) {
2014-06-28 12:35:30 -07:00
attributes.push(stream.Channels + ' ch');
}
if (stream.IsDefault) {
2014-06-28 12:35:30 -07:00
attributes.push('(D)');
}
2014-06-28 12:35:30 -07:00
if (attributes.length) {
textLines.push(attributes.join('&nbsp;&#149;&nbsp;'));
}
2014-06-28 12:35:30 -07:00
optionHtml += textLines.join('<br/>');
2014-06-28 12:35:30 -07:00
optionHtml += '</p>';
optionHtml += '</a></li>';
return optionHtml;
}).join('');
html += '</ul>';
html += '</div>';
html += '</div>';
return html;
}
2014-03-20 20:31:40 -07:00
function getSubtitleTracksHtml() {
2014-06-11 12:31:33 -07:00
var streams = self.currentMediaSource.MediaStreams.filter(function (currentStream) {
2014-03-20 20:31:40 -07:00
return currentStream.Type == "Subtitle";
});
2014-06-11 19:38:40 -07:00
var currentIndex = self.currentSubtitleStreamIndex || -1;
streams.unshift({
Index: -1,
Language: "Off"
});
2014-06-28 12:35:30 -07:00
var html = '';
html += '<div class="videoPlayerPopupContent">';
2014-07-02 11:34:08 -07:00
html += '<ul data-role="listview" data-inset="true"><li data-role="list-divider">' + Globalize.translate('HeaderSubtitles') + '</li>';
2014-06-28 12:35:30 -07:00
html += '</ul>';
2014-06-28 12:35:30 -07:00
html += '<div class="videoPlayerPopupScroller">';
html += '<ul data-role="listview" data-inset="true">';
2014-06-28 12:35:30 -07:00
html += streams.map(function (stream) {
2014-06-28 12:35:30 -07:00
var cssClass = "mediaPopupOption";
var selected = stream.Index == currentIndex;
if (selected) {
cssClass += ' selectedMediaPopupOption';
}
2014-06-28 12:35:30 -07:00
var optionHtml = '<li><a data-index="' + stream.Index + '" class="' + cssClass + '" href="#">';
2014-06-28 12:35:30 -07:00
optionHtml += '<p style="margin:0;">';
2014-06-28 12:35:30 -07:00
if (selected) {
optionHtml += '<img src="css/images/checkmarkgreen.png" style="width:18px;border-radius:3px;margin-right:.5em;vertical-align:middle;" />';
}
2014-06-28 12:35:30 -07:00
var textLines = [];
2014-07-02 11:34:08 -07:00
textLines.push(stream.Language || Globalize.translate('LabelUnknownLanguage'));
if (stream.Codec) {
2014-06-28 12:35:30 -07:00
textLines.push(stream.Codec);
}
2014-06-28 12:35:30 -07:00
var attributes = [];
if (stream.IsDefault) {
2014-06-28 12:35:30 -07:00
attributes.push('Default');
}
if (stream.IsForced) {
2014-06-28 12:35:30 -07:00
attributes.push('Forced');
}
if (stream.IsExternal) {
2014-06-28 12:35:30 -07:00
attributes.push('External');
}
2014-06-28 12:35:30 -07:00
if (attributes.length) {
textLines.push(attributes.join('&nbsp;&#149;&nbsp;'));
}
2014-06-28 12:35:30 -07:00
optionHtml += textLines.join('<br/>');
2014-06-28 12:35:30 -07:00
optionHtml += '</p>';
optionHtml += '</a></li>';
return optionHtml;
}).join('');
html += '</ul>';
html += '</div>';
html += '</div>';
return html;
}
2014-03-20 20:31:40 -07:00
function getQualityFlyoutHtml() {
2014-10-22 21:26:01 -07:00
var currentSrc = self.getCurrentSrc(self.currentMediaElement).toLowerCase();
var isStatic = currentSrc.indexOf('static=true') != -1;
var videoStream = self.currentMediaSource.MediaStreams.filter(function (stream) {
return stream.Type == "Video";
})[0];
var videoWidth = videoStream ? videoStream.Width : null;
var options = self.getVideoQualityOptions(videoWidth);
if (isStatic) {
options[0].name = "Direct";
}
2014-06-28 12:35:30 -07:00
var html = '';
2014-07-02 11:34:08 -07:00
2014-06-28 12:35:30 -07:00
html += '<div class="videoPlayerPopupContent">';
2014-07-02 11:34:08 -07:00
html += '<ul data-role="listview" data-inset="true"><li data-role="list-divider">' + Globalize.translate('HeaderVideoQuality') + '</li>';
2014-06-28 12:35:30 -07:00
html += '</ul>';
html += '<div class="videoPlayerPopupScroller">';
html += '<ul data-role="listview" data-inset="true">';
2014-06-28 12:35:30 -07:00
html += options.map(function (option) {
2014-06-28 12:35:30 -07:00
var cssClass = "mediaPopupOption";
if (option.selected) {
2014-06-28 12:35:30 -07:00
cssClass += ' selectedMediaPopupOption';
}
var optionHtml = '<li><a data-bitrate="' + option.bitrate + '" class="' + cssClass + '" href="#">';
2014-06-28 12:35:30 -07:00
optionHtml += '<p style="margin:0;">';
2014-06-28 12:35:30 -07:00
if (option.selected) {
optionHtml += '<img src="css/images/checkmarkgreen.png" style="width:18px;border-radius:3px;margin-right:.5em;vertical-align:middle;" />';
}
2014-06-28 12:35:30 -07:00
optionHtml += option.name;
2014-06-28 12:35:30 -07:00
optionHtml += '</p>';
optionHtml += '</a></li>';
return optionHtml;
}).join('');
html += '</ul>';
html += '</div>';
html += '</div>';
return html;
}
2014-06-21 22:52:31 -07:00
function bindEventsForPlayback() {
var hideElementsOnIdle = !$.browser.mobile;
2014-07-16 20:17:14 -07:00
if (hideElementsOnIdle) {
2014-06-21 22:52:31 -07:00
$('.itemVideo').off('mousemove.videoplayer keydown.videoplayer scroll.videoplayer', idleHandler);
$('.itemVideo').on('mousemove.videoplayer keydown.videoplayer scroll.videoplayer', idleHandler).trigger('mousemove');
}
$(document).on('webkitfullscreenchange.videoplayer mozfullscreenchange.videoplayer fullscreenchange.videoplayer', function (e) {
2014-06-21 22:52:31 -07:00
if (self.isFullScreen()) {
enterFullScreen();
idleState = true;
} else {
exitFullScreenToWindow();
}
fullscreenExited = self.isFullScreen() == false;
}).on("msfullscreenchange.videoplayer", function (e) {
fullscreenExited = self.isFullScreen() == false;
}).on("keyup.videoplayer", function (e) {
if (fullscreenExited) {
$("#videoPlayer", $("#mediaPlayer")).removeClass("fullscreenVideo");
fullscreenExited = false;
return;
}
if (e.keyCode == 27) {
self.stop();
}
});
// Stop playback on browser back button nav
$(window).one("popstate.videoplayer", function () {
self.stop();
return;
});
if (hideElementsOnIdle) {
$(document.body).on("mousemove.videplayer", "#itemVideo", function () {
2014-06-21 22:52:31 -07:00
idleHandler(this);
});
}
2014-06-21 22:52:31 -07:00
}
function unbindEventsForPlayback() {
$(document).off('webkitfullscreenchange.videoplayer mozfullscreenchange.videoplayer fullscreenchange.videoplayer').off("msfullscreenchange.videoplayer").off("keyup.videoplayer");
// Stop playback on browser back button nav
$(window).off("popstate.videoplayer");
$(document.body).off("mousemove.videplayer");
2014-06-21 22:52:31 -07:00
$('.itemVideo').off('mousemove.videoplayer keydown.videoplayer scroll.videoplayer');
}
2014-08-01 19:34:45 -07:00
self.canAutoPlayVideo = function () {
if ($.browser.msie || $.browser.mobile) {
return false;
}
return true;
};
2014-08-10 15:13:17 -07:00
// Replace audio version
self.cleanup = function (playerElement) {
if (playerElement.tagName.toLowerCase() == 'video') {
currentTimeElement.html('--:--');
unbindEventsForPlayback();
}
};
2015-03-28 21:56:39 -07:00
self.playVideo = function (item, mediaSource, startPosition) {
2015-04-07 21:01:52 -07:00
var streamInfo = self.createStreamInfo('Video', item, mediaSource, startPosition);
var videoUrl = streamInfo.url;
var contentType = streamInfo.contentType;
var startPositionInSeekParam = streamInfo.startPositionInSeekParam;
self.startTimeTicksOffset = streamInfo.startTimeTicksOffset;
var mediaStreams = mediaSource.MediaStreams || [];
2014-06-11 12:31:33 -07:00
var subtitleStreams = mediaStreams.filter(function (s) {
return s.Type == 'Subtitle';
});
2015-03-26 00:13:35 -07:00
// Get Video Poster (Code from librarybrowser.js)
var screenWidth = Math.max(screen.height, screen.width);
var posterCode = '';
2015-03-26 00:13:35 -07:00
if (item.BackdropImageTags && item.BackdropImageTags.length) {
2015-03-26 01:06:34 -07:00
posterCode = ' poster="' + ApiClient.getScaledImageUrl(item.Id, {
2015-03-26 00:13:35 -07:00
type: "Backdrop",
index: 0,
maxWidth: screenWidth,
tag: item.BackdropImageTags[0]
2015-03-26 01:06:34 -07:00
}) + '"';
2015-03-26 00:13:35 -07:00
}
else if (item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) {
2015-03-26 01:06:34 -07:00
posterCode = ' poster="' + ApiClient.getScaledImageUrl(item.ParentBackdropItemId, {
2015-03-26 00:13:35 -07:00
type: 'Backdrop',
index: 0,
maxWidth: screenWidth,
tag: item.ParentBackdropImageTags[0]
2015-03-26 01:06:34 -07:00
}) + '"';
2015-03-26 00:13:35 -07:00
}
2014-06-28 12:35:30 -07:00
//======================================================================================>
// Create video player
var html = '';
2014-08-01 19:34:45 -07:00
var requiresNativeControls = !self.canAutoPlayVideo();
// Can't autoplay in these browsers so we need to use the full controls
2014-06-28 12:35:30 -07:00
if (requiresNativeControls) {
2015-04-03 11:04:25 -07:00
html += '<video class="itemVideo" id="itemVideo" preload="none" autoplay="autoplay" crossorigin="anonymous" controls="controls"' + posterCode + '>';
} else {
2014-05-29 12:34:20 -07:00
2014-04-14 20:54:52 -07:00
// Chrome 35 won't play with preload none
2015-04-03 11:04:25 -07:00
html += '<video class="itemVideo" id="itemVideo" preload="metadata" crossorigin="anonymous" autoplay' + posterCode + '>';
}
html += '<source type="' + contentType + '" src="' + videoUrl + '" />';
2015-03-30 12:57:37 -07:00
var textStreams = subtitleStreams.filter(function (s) {
return s.DeliveryMethod == 'External';
});
2014-06-11 12:31:33 -07:00
2015-03-30 12:57:37 -07:00
for (var i = 0, length = textStreams.length; i < length; i++) {
2014-06-11 12:31:33 -07:00
2015-03-30 12:57:37 -07:00
var textStream = textStreams[i];
2015-04-01 19:47:59 -07:00
var textStreamUrl = !textStream.IsExternalUrl ? ApiClient.getUrl(textStream.DeliveryUrl) : textStream.DeliveryUrl;
2015-03-30 12:57:37 -07:00
var defaultAttribute = textStream.Index == mediaSource.DefaultSubtitleStreamIndex ? ' default' : '';
2014-06-11 12:31:33 -07:00
2015-03-30 12:57:37 -07:00
html += '<track kind="subtitles" src="' + textStreamUrl + '" srclang="' + (textStream.Language || 'und') + '"' + defaultAttribute + '></track>';
2014-06-11 12:31:33 -07:00
}
html += '</video>';
2014-06-21 22:52:31 -07:00
var mediaPlayerContainer = $("#mediaPlayer").show();
2014-06-28 12:35:30 -07:00
var videoControls = $('.videoControls', mediaPlayerContainer);
//show stop button
$('#video-playButton', videoControls).hide();
$('#video-pauseButton', videoControls).show();
$('.videoTrackControl').hide();
2014-06-21 22:52:31 -07:00
var videoElement = $('#videoElement', mediaPlayerContainer).prepend(html);
2014-06-28 12:35:30 -07:00
$('.videoQualityButton', videoControls).show();
2014-06-11 12:31:33 -07:00
if (mediaStreams.filter(function (s) {
return s.Type == "Audio";
}).length) {
2014-06-28 12:35:30 -07:00
$('.videoAudioButton').show();
} else {
2014-06-28 12:35:30 -07:00
$('.videoAudioButton').hide();
}
2014-06-11 12:31:33 -07:00
if (subtitleStreams.length) {
2014-06-28 12:35:30 -07:00
$('.videoSubtitleButton').show();
} else {
2014-06-28 12:35:30 -07:00
$('.videoSubtitleButton').hide();
}
if (item.Chapters && item.Chapters.length) {
2014-06-28 12:35:30 -07:00
$('.videoChaptersButton').show();
} else {
2014-06-28 12:35:30 -07:00
$('.videoChaptersButton').hide();
}
2014-06-28 12:35:30 -07:00
if (requiresNativeControls) {
$('#video-fullscreenButton', videoControls).hide();
} else {
$('#video-fullscreenButton', videoControls).show();
}
2014-06-28 12:35:30 -07:00
if ($.browser.mobile) {
$('.volumeSliderContainer', videoControls).addClass('hide');
$('.muteButton', videoControls).addClass('hide');
$('.unmuteButton', videoControls).addClass('hide');
} else {
$('.volumeSliderContainer', videoControls).removeClass('hide');
$('.muteButton', videoControls).removeClass('hide');
$('.unmuteButton', videoControls).removeClass('hide');
}
if (requiresNativeControls) {
videoControls.addClass('hide');
} else {
videoControls.removeClass('hide');
}
var video = $("video", videoElement);
initialVolume = self.getSavedVolume();
video.each(function () {
this.volume = initialVolume;
});
volumeSlider.val(initialVolume).slider('refresh');
updateVolumeButtons(initialVolume);
2015-04-20 11:35:33 -07:00
video.one("playing.mediaplayerevent", function (e) {
2014-07-16 20:17:14 -07:00
2014-10-07 18:37:45 -07:00
// TODO: This is not working in chrome. Is it too early?
2014-07-16 20:17:14 -07:00
// Appending #t=xxx to the query string doesn't seem to work with HLS
if (startPositionInSeekParam && this.currentSrc && this.currentSrc.toLowerCase().indexOf('.m3u8') != -1) {
2015-04-20 11:35:33 -07:00
var element = this;
setTimeout(function () {
element.currentTime = startPositionInSeekParam;
}, 3000);
2014-07-16 20:17:14 -07:00
}
}).on("volumechange.mediaplayerevent", function (e) {
var vol = this.volume;
updateVolumeButtons(vol);
2014-06-21 22:52:31 -07:00
}).one("playing.mediaplayerevent", function () {
2014-08-10 15:13:17 -07:00
// For some reason this is firing at the start, so don't bind until playback has begun
$(this).on("ended.playbackstopped", self.onPlaybackStopped).one('ended.playnext', self.playNextAfterEnded);
self.onPlaybackStart(this, item, mediaSource);
2014-06-21 22:52:31 -07:00
}).on("pause.mediaplayerevent", function (e) {
$('#video-playButton', videoControls).show();
$('#video-pauseButton', videoControls).hide();
$("#pause", videoElement).show().addClass("fadeOut");
setTimeout(function () {
$("#pause", videoElement).hide().removeClass("fadeOut");
}, 300);
2014-06-21 22:52:31 -07:00
}).on("playing.mediaplayerevent", function (e) {
$('#video-playButton', videoControls).hide();
$('#video-pauseButton', videoControls).show();
$("#play", videoElement).show().addClass("fadeOut");
setTimeout(function () {
$("#play", videoElement).hide().removeClass("fadeOut");
}, 300);
2014-06-21 22:52:31 -07:00
}).on("timeupdate.mediaplayerevent", function () {
if (!isPositionSliderActive) {
self.setCurrentTime(self.getCurrentTicks(this), positionSlider, currentTimeElement);
}
2014-06-21 22:52:31 -07:00
}).on("error.mediaplayerevent", function () {
2014-07-01 14:13:32 -07:00
self.stop();
var errorCode = this.error ? this.error.code : '';
console.log('Html5 Video error code: ' + errorCode);
2014-07-02 11:34:08 -07:00
var errorMsg = Globalize.translate('MessageErrorPlayingVideo');
2014-03-17 18:45:28 -07:00
if (item.Type == "TvChannel") {
2014-07-21 18:29:06 -07:00
errorMsg += '<p>';
errorMsg += Globalize.translate('MessageEnsureOpenTuner');
errorMsg += '</p>';
}
2014-08-14 06:24:30 -07:00
if ($.browser.msie && !$.browser.mobile && !self.canPlayWebm()) {
2014-07-21 18:29:06 -07:00
errorMsg += '<p>';
errorMsg += '<a href="https://tools.google.com/dlpage/webmmf/" target="_blank">';
errorMsg += Globalize.translate('MessageInternetExplorerWebm');
errorMsg += '</a>';
errorMsg += '</p>';
2014-07-01 14:13:32 -07:00
}
Dashboard.alert({
2014-07-21 18:29:06 -07:00
title: Globalize.translate('HeaderVideoError'),
message: errorMsg
});
2014-06-21 22:52:31 -07:00
}).on("click.mediaplayerevent", function (e) {
if (this.paused) {
self.unpause();
} else {
self.pause();
}
2014-06-21 22:52:31 -07:00
}).on("dblclick.mediaplayerevent", function () {
self.toggleFullscreen();
2014-08-10 15:13:17 -07:00
});
2014-06-21 22:52:31 -07:00
bindEventsForPlayback();
2014-06-21 22:52:31 -07:00
mediaPlayerContainer.trigger("create");
fullscreenExited = false;
2014-06-11 12:31:33 -07:00
self.currentSubtitleStreamIndex = mediaSource.DefaultSubtitleStreamIndex;
2014-06-28 12:35:30 -07:00
$('body').addClass('bodyWithPopupOpen');
return video[0];
2014-06-21 22:52:31 -07:00
};
self.updatePlaylistUi = function () {
var index = self.currentPlaylistIndex(null),
length = self.playlist.length,
requiresNativeControls = !self.canAutoPlayVideo(),
controls = $(requiresNativeControls ? '.videoAdvancedControls' : '.videoControls');
2015-03-23 10:19:21 -07:00
if (length < 2) {
$('.videoTrackControl').hide();
return;
}
if (index === 0) {
$('.previousTrackButton', controls).attr('disabled', 'disabled');
} else {
$('.previousTrackButton', controls).removeAttr('disabled');
}
if ((index + 1) >= length) {
$('.nextTrackButton', controls).attr('disabled', 'disabled');
} else {
$('.nextTrackButton', controls).removeAttr('disabled');
}
$('.videoTrackControl', controls).show();
};
2014-06-21 22:52:31 -07:00
}
createVideoPlayer(MediaPlayer);
})();