(function (document, setTimeout, clearTimeout, screen, localStorage, $, setInterval, window) { function mediaPlayer() { var self = this; var testableAudioElement = document.createElement('audio'); var testableVideoElement = document.createElement('video'); var currentMediaElement; var currentProgressInterval; var positionSlider; var isPositionSliderActive; var currentTimeElement; var currentItem; var volumeSlider; var muteButton; var unmuteButton; var startTimeTicksOffset; var curentDurationTicks; var isStaticStream; var culturesPromise; var timeout; var idleState = true; self.playlist = []; var currentPlaylistIndex = 0; function requestFullScreen(element) { // Supports most browsers and their versions. var requestMethod = element.requestFullScreen || element.webkitRequestFullScreen || element.mozRequestFullScreen || element.msRequestFullScreen; if (requestMethod) { // Native full screen. requestMethod.call(element); } else { $('.itemVideo').addClass('fullscreenVideo'); } } function isFullScreen() { return document.fullscreenEnabled || document.mozFullscreenEnabled || document.webkitIsFullScreen || document.mozFullScreen ? true : false; } $(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange', function () { var nowPlayingBar = ('#nowPlayingBar'); $('.itemVideo').unbind('mousemove keydown scroll', idleHandler); if (isFullScreen()) { $('.itemVideo').addClass('fullscreenVideo'); idleState = true; $('.itemVideo').bind('mousemove keydown scroll', idleHandler).trigger('mousemove'); } else { $(".mediaButton,.currentTime,.nowPlayingMediaInfo,.mediaSlider,.barBackground", nowPlayingBar).removeClass("highPosition"); $('.itemVideo').removeClass('fullscreenVideo'); } }); $(window).on("beforeunload", function () { var item = currentItem; var media = currentMediaElement; // Try to report playback stopped before the browser closes if (item && media && currentProgressInterval) { var endTime = currentMediaElement.currentTime; var position = Math.floor(10000000 * endTime) + startTimeTicksOffset; ApiClient.reportPlaybackStopped(Dashboard.getCurrentUserId(), currentItem.Id, position); } }); function replaceQueryString(url, param, value) { var re = new RegExp("([?|&])" + param + "=.*?(&|$)", "i"); if (url.match(re)) return url.replace(re, '$1' + param + "=" + value + '$2'); else return url + '&' + param + "=" + value; } function updateVolumeButtons(vol) { if (vol) { muteButton.show(); unmuteButton.hide(); } else { muteButton.hide(); unmuteButton.show(); } } function getCurrentTicks(mediaElement) { return Math.floor(10000000 * (mediaElement || currentMediaElement).currentTime) + startTimeTicksOffset; } function onPlaybackStopped() { $(this).off('ended.playbackstopped'); currentTimeElement.empty(); var endTime = this.currentTime; this.currentTime = 0; clearProgressInterval(); var position = Math.floor(10000000 * endTime) + startTimeTicksOffset; ApiClient.reportPlaybackStopped(Dashboard.getCurrentUserId(), currentItem.Id, position); if (currentItem.MediaType == "Video") { ApiClient.stopActiveEncodings(); } } function playNextAfterEnded() { $(this).off('ended.playnext'); self.nextTrack(); } function startProgressInterval(itemId) { clearProgressInterval(); var intervalTime = ApiClient.isWebSocketOpen() ? 4000 : 20000; currentProgressInterval = setInterval(function () { if (currentMediaElement) { sendProgressUpdate(itemId); } }, intervalTime); } function sendProgressUpdate(itemId) { ApiClient.reportPlaybackProgress(Dashboard.getCurrentUserId(), itemId, getCurrentTicks(), currentMediaElement.paused, currentMediaElement.volume == 0); } function clearProgressInterval() { if (currentProgressInterval) { clearTimeout(currentProgressInterval); currentProgressInterval = null; } } function changeStream(ticks, params) { var element = currentMediaElement; if (isStaticStream && params == null) { element.currentTime = ticks / (1000 * 10000); } else { params = params || {}; var currentSrc = element.currentSrc; currentSrc = replaceQueryString(currentSrc, 'starttimeticks', ticks); if (params.AudioStreamIndex != null) { currentSrc = replaceQueryString(currentSrc, 'AudioStreamIndex', params.AudioStreamIndex); } if (params.SubtitleStreamIndex != null) { currentSrc = replaceQueryString(currentSrc, 'SubtitleStreamIndex', params.SubtitleStreamIndex); } if (params.MaxWidth != null) { currentSrc = replaceQueryString(currentSrc, 'MaxWidth', params.MaxWidth); } if (params.VideoBitrate != null) { currentSrc = replaceQueryString(currentSrc, 'VideoBitrate', params.VideoBitrate); } clearProgressInterval(); $(element).off('ended.playbackstopped').off('ended.playnext').on("play.onceafterseek", function () { $(this).off('play.onceafterseek').on('ended.playbackstopped', onPlaybackStopped).on('ended.playnext', playNextAfterEnded); startProgressInterval(currentItem.Id); sendProgressUpdate(currentItem.Id); }); ApiClient.stopActiveEncodings().done(function () { startTimeTicksOffset = ticks; element.src = currentSrc; }); } } function onPositionSliderChange() { isPositionSliderActive = false; var newPercent = parseInt(this.value); var newPositionTicks = (newPercent / 100) * currentItem.RunTimeTicks; changeStream(Math.floor(newPositionTicks)); } $(function () { muteButton = $('#muteButton'); unmuteButton = $('#unmuteButton'); currentTimeElement = $('.currentTime'); volumeSlider = $('.volumeSlider').on('change', function () { var vol = this.value; updateVolumeButtons(vol); currentMediaElement.volume = vol; }); $(".jqueryuislider").slider({ orientation: "horizontal" }); positionSlider = $(".positionSlider").on('mousedown', function () { isPositionSliderActive = true; }); if ($.browser.mozilla) { positionSlider.on('change', onPositionSliderChange); } else { positionSlider.on('change', function () { isPositionSliderActive = true; setCurrentTimePercent(parseInt(this.value), currentItem); }).on('changed', onPositionSliderChange); } (function (el, timeout) { var timer, trig = function () { el.trigger("changed"); }; el.bind("change", function () { if (timer) { clearTimeout(timer); } timer = setTimeout(trig, timeout); }); })(positionSlider, 500); $('#chaptersFlyout').on('click', '.mediaFlyoutOption', function () { var ticks = parseInt(this.getAttribute('data-positionticks')); changeStream(ticks); hideFlyout($('#chaptersFlyout')); }); $('#audioTracksFlyout').on('click', '.mediaFlyoutOption', function () { if (!$(this).hasClass('selectedMediaFlyoutOption')) { var index = parseInt(this.getAttribute('data-index')); changeStream(getCurrentTicks(), { AudioStreamIndex: index }); } hideFlyout($('#audioTracksFlyout')); }); $('#subtitleFlyout').on('click', '.mediaFlyoutOption', function () { if (!$(this).hasClass('selectedMediaFlyoutOption')) { var index = parseInt(this.getAttribute('data-index')); changeStream(getCurrentTicks(), { SubtitleStreamIndex: index }); } hideFlyout($('#subtitleFlyout')); }); $('#qualityFlyout').on('click', '.mediaFlyoutOption', function () { if (!$(this).hasClass('selectedMediaFlyoutOption')) { var maxWidth = parseInt(this.getAttribute('data-maxwidth')); var videoBitrate = parseInt(this.getAttribute('data-videobitrate')); changeStream(getCurrentTicks(), { MaxWidth: maxWidth, VideoBitrate: videoBitrate }); } hideFlyout($('#qualityFlyout')); }); }); function endsWith(text, pattern) { text = text.toLowerCase(); pattern = pattern.toLowerCase(); var d = text.length - pattern.length; return d >= 0 && text.lastIndexOf(pattern) === d; } function setCurrentTimePercent(percent, item) { var position = (percent / 100) * curentDurationTicks; setCurrentTime(position, item, false); } function setCurrentTime(ticks, item, updateSlider) { // Convert to ticks ticks = Math.floor(ticks); var timeText = Dashboard.getDisplayTime(ticks); if (curentDurationTicks) { timeText += " / " + Dashboard.getDisplayTime(curentDurationTicks); if (updateSlider) { var percent = ticks / curentDurationTicks; percent *= 100; positionSlider.val(percent); positionSlider.removeAttr('disabled'); } } else { positionSlider.attr('disabled', 'disabled'); } currentTimeElement.html(timeText); } function playAudio(item, params) { var baseParams = { audioChannels: 2, audioBitrate: 128000 }; $.extend(baseParams, params); var mp3Url = ApiClient.getUrl('Audio/' + item.Id + '/stream.mp3', $.extend({}, baseParams, { audioCodec: 'mp3' })); var aacUrl = ApiClient.getUrl('Audio/' + item.Id + '/stream.aac', $.extend({}, baseParams, { audioCodec: 'aac' })); var webmUrl = ApiClient.getUrl('Audio/' + item.Id + '/stream.webm', $.extend({}, baseParams, { audioCodec: 'Vorbis' })); var mediaStreams = item.MediaStreams || []; for (var i = 0, length = mediaStreams.length; i < length; i++) { var stream = mediaStreams[i]; if (stream.Type == "Audio") { // Stream statically when possible if (endsWith(item.Path, ".aac") && stream.BitRate <= 256000) { aacUrl += "&static=true"; } else if (endsWith(item.Path, ".mp3") && stream.BitRate <= 256000) { mp3Url += "&static=true"; } break; } } var html = ''; var requiresControls = $.browser.android || ($.browser.webkit && !$.browser.chrome); // Can't autoplay in these browsers so we need to use the full controls if (requiresControls) { html += '