";
+ }
+
+ return html;
+ }
+
+ function getAudioTracksHtml(item, cultures) {
+
+ var streams = item.MediaStreams.filter(function (i) {
+ return i.Type == "Audio";
+ });
+
+ var currentIndex = getParameterByName('AudioStreamIndex', video.currentSrc);
+
+ var html = '';
+
+ for (var i = 0, length = streams.length; i < length; i++) {
+
+ var stream = streams[i];
+
+ if (stream.Index == currentIndex) {
+ html += '
';
+ } else {
+ html += '
";
+ }
+
+ html += '
';
+
+ return html;
+ }
+
+ function getSubtitleTracksHtml(item, cultures) {
+
+ var streams = item.MediaStreams.filter(function (i) {
+ return i.Type == "Subtitle";
+ });
+
+ var currentIndex = getParameterByName('SubtitleStreamIndex', video.currentSrc) || -1;
+
+ var html = '';
+
+ streams.unshift({
+ Index: -1,
+ Language: "Off"
+ });
+
+ for (var i = 0, length = streams.length; i < length; i++) {
+
+ var stream = streams[i];
+
+ if (stream.Index == currentIndex) {
+ html += '
';
+ } else {
+ html += '
";
+ }
+
+ html += '
';
+
+ return html;
+ }
+
+ function getQualityFlyoutHtml(item) {
+
+ var html = '';
+
+ var currentSrc = video.currentSrc.toLowerCase();
+ var isStatic = currentSrc.indexOf('static=true') != -1;
+
+ var transcodingExtension = self.getTranscodingExtension();
+
+ var currentAudioStreamIndex = getParameterByName('AudioStreamIndex', video.currentSrc);
+
+ var options = getVideoQualityOptions(item, currentAudioStreamIndex, transcodingExtension);
+
+ if (isStatic) {
+ options[0].name = "Direct";
+ }
+
+ for (var i = 0, length = options.length; i < length; i++) {
+
+ var option = options[i];
+
+ var cssClass = "mediaFlyoutOption";
+
+ if (option.selected) {
+ cssClass += " selectedMediaFlyoutOption";
+ }
+
+ html += '
';
+
+ html += '
';
+
+ html += '
' + option.name + '
';
+
+ html += "
";
+
+ html += "
";
+ }
+
+ return html;
+ }
+
+ function getInitialSubtitleStreamIndex(mediaStreams, user) {
+
+ var i, length, mediaStream;
+
+ // Find the first forced subtitle stream
+ for (i = 0, length = mediaStreams.length; i < length; i++) {
+ mediaStream = mediaStreams[i];
+
+ if (mediaStream.Type == "Subtitle" && mediaStream.IsForced) {
+ return mediaStream.Index;
+ }
+
+ }
+
+ // If none then look at user configuration
+ if (user.Configuration.SubtitleLanguagePreference) {
+
+ for (i = 0, length = mediaStreams.length; i < length; i++) {
+ mediaStream = mediaStreams[i];
+
+ if (mediaStream.Type == "Subtitle" && mediaStream.Language == user.Configuration.SubtitleLanguagePreference) {
+
+ if (user.Configuration.UseForcedSubtitlesOnly) {
+
+ if (mediaStream.IsForced) {
+ return mediaStream.Index;
+ }
+
+ } else {
+ return mediaStream.Index;
+ }
+ }
+
+ }
+ }
+
+ return null;
+ }
+
+ function getInitialAudioStreamIndex(mediaStreams, user) {
+
+ // Find all audio streams with at least one channel
+ var audioStreams = mediaStreams.filter(function (stream) {
+ return stream.Type == "Audio" && stream.Channels;
+ });
+
+ if (user.Configuration.AudioLanguagePreference) {
+
+ for (var i = 0, length = audioStreams.length; i < length; i++) {
+ var mediaStream = audioStreams[i];
+
+ if (mediaStream.Language == user.Configuration.AudioLanguagePreference) {
+ return mediaStream.Index;
+ }
+
+ }
+ }
+
+ // Just use the first audio stream
+ return audioStreams.length ? audioStreams[0].Index : null;
+ }
+
+ function getVideoQualityOptions(item) {
+
+ var videoStream = (item.MediaStreams || []).filter(function (stream) {
+ return stream.Type == "Video";
+ })[0];
+
+ var bitrateSetting = parseInt(localStorage.getItem('preferredVideoBitrate') || '') || 1500000;
+
+ var maxAllowedWidth = Math.max(screen.height, screen.width);
+
+ var options = [];
+
+ // We have media info
+ if (videoStream && videoStream.Width) {
+
+ maxAllowedWidth = videoStream.Width;
+ }
+
+ // Some 1080- videos are reported as 1912?
+ if (maxAllowedWidth >= 1910) {
+ options.push({ name: '1080p - 20Mbps', maxWidth: 1920, bitrate: 20000000 });
+ options.push({ name: '1080p - 15Mbps', maxWidth: 1920, bitrate: 15000000 });
+ options.push({ name: '1080p - 10Mbps', maxWidth: 1920, bitrate: 10000000 });
+ options.push({ name: '1080p - 8Mbps', maxWidth: 1920, bitrate: 8000000 });
+ options.push({ name: '1080p - 6Mbps', maxWidth: 1920, bitrate: 6000000 });
+ options.push({ name: '1080p - 5Mbps', maxWidth: 1920, bitrate: 5000000 });
+ }
+ else if (maxAllowedWidth >= 1270) {
+ options.push({ name: '720p - 10Mbps', maxWidth: 1280, bitrate: 10000000 });
+ options.push({ name: '720p - 8Mbps', maxWidth: 1280, bitrate: 8000000 });
+ options.push({ name: '720p - 6Mbps', maxWidth: 1280, bitrate: 6000000 });
+ options.push({ name: '720p - 5Mbps', maxWidth: 1280, bitrate: 5000000 });
+ }
+ else if (maxAllowedWidth >= 470) {
+ options.push({ name: '480p - 4Mbps', maxWidth: 720, bitrate: 4000000 });
+ options.push({ name: '480p - 3.5Mbps', maxWidth: 720, bitrate: 3500000 });
+ options.push({ name: '480p - 3Mbps', maxWidth: 720, bitrate: 3000000 });
+ options.push({ name: '480p - 2.5Mbps', maxWidth: 720, bitrate: 2500000 });
+ options.push({ name: '480p - 2Mbps', maxWidth: 720, bitrate: 2000000 });
+ options.push({ name: '480p - 1.5Mbps', maxWidth: 720, bitrate: 1500000 });
+ }
+
+ if (maxAllowedWidth >= 1270) {
+ options.push({ name: '720p - 4Mbps', maxWidth: 1280, bitrate: 4000000 });
+ options.push({ name: '720p - 3Mbps', maxWidth: 1280, bitrate: 3000000 });
+ options.push({ name: '720p - 2Mbps', maxWidth: 1280, bitrate: 2000000 });
+ options.push({ name: '720p - 1.5Mbps', maxWidth: 1280, bitrate: 1500000 });
+ }
+
+ options.push({ name: '480p - 1.0Mbps', maxWidth: 720, bitrate: 1000000 });
+ options.push({ name: '480p - 720 kbps', maxWidth: 720, bitrate: 700000 });
+ options.push({ name: '480p - 420 kbps', maxWidth: 720, bitrate: 420000 });
+ options.push({ name: '360p', maxWidth: 640, bitrate: 400000 });
+ options.push({ name: '240p', maxWidth: 426, bitrate: 320000 });
+
+ var i, length, option;
+ var selectedIndex = -1;
+ for (i = 0, length = options.length; i < length; i++) {
+
+ option = options[i];
+
+ if (selectedIndex == -1 && option.bitrate <= bitrateSetting) {
+ selectedIndex = i;
+ }
+ }
+
+ if (selectedIndex == -1) {
+
+ selectedIndex = options.length - 1;
+ }
+
+ options[selectedIndex].selected = true;
+
+ return options;
+ }
+
+ function playVideo(item, startPosition, user) {
+
+ var mediaStreams = item.MediaStreams || [];
+
+ var baseParams = {
+ audioChannels: 2,
+ StartTimeTicks: startPosition || 0,
+ SubtitleStreamIndex: getInitialSubtitleStreamIndex(mediaStreams, user),
+ AudioStreamIndex: getInitialAudioStreamIndex(mediaStreams, user),
+ deviceId: ApiClient.deviceId(),
+ Static: false
+ };
+
+ var mp4Quality = getVideoQualityOptions(item).filter(function (opt) {
+ return opt.selected;
+ })[0];
+ mp4Quality = $.extend(mp4Quality, self.getFinalVideoParams(item, mp4Quality.maxWidth, mp4Quality.bitrate, baseParams.AudioStreamIndex, baseParams.SubtitleStreamIndex, '.mp4'));
+
+ var webmQuality = getVideoQualityOptions(item).filter(function (opt) {
+ return opt.selected;
+ })[0];
+ webmQuality = $.extend(webmQuality, self.getFinalVideoParams(item, webmQuality.maxWidth, webmQuality.bitrate, baseParams.AudioStreamIndex, baseParams.SubtitleStreamIndex, '.webm'));
+
+ var m3U8Quality = getVideoQualityOptions(item).filter(function (opt) {
+ return opt.selected;
+ })[0];
+ m3U8Quality = $.extend(m3U8Quality, self.getFinalVideoParams(item, mp4Quality.maxWidth, mp4Quality.bitrate, baseParams.AudioStreamIndex, baseParams.SubtitleStreamIndex, '.mp4'));
+
+ // Webm must be ahead of mp4 due to the issue of mp4 playing too fast in chrome
+ var prioritizeWebmOverH264 = $.browser.chrome || $.browser.msie;
+
+ var isStatic = mp4Quality.isStatic;
+
+ self.startTimeTicksOffset = isStatic ? 0 : startPosition || 0;
+
+ var seekParam = isStatic && startPosition ? '#t=' + (startPosition / 10000000) : '';
+
+ var mp4VideoUrl = ApiClient.getUrl('Videos/' + item.Id + '/stream.mp4', $.extend({}, baseParams, {
+ profile: 'baseline',
+ level: 3,
+ Static: isStatic,
+ maxWidth: mp4Quality.maxWidth,
+ videoBitrate: mp4Quality.videoBitrate,
+ audioBitrate: mp4Quality.audioBitrate,
+ VideoCodec: mp4Quality.videoCodec,
+ AudioCodec: mp4Quality.audioCodec
+
+ })) + seekParam;
+
+ var webmVideoUrl = ApiClient.getUrl('Videos/' + item.Id + '/stream.webm', $.extend({}, baseParams, {
+
+ VideoCodec: 'vpx',
+ AudioCodec: 'Vorbis',
+ maxWidth: webmQuality.maxWidth,
+ videoBitrate: webmQuality.videoBitrate,
+ audioBitrate: webmQuality.audioBitrate
+
+ })) + seekParam;
+
+ var hlsVideoUrl = ApiClient.getUrl('Videos/' + item.Id + '/stream.m3u8', $.extend({}, baseParams, {
+ profile: 'baseline',
+ level: 3,
+ timeStampOffsetMs: 0,
+ maxWidth: m3U8Quality.maxWidth,
+ videoBitrate: m3U8Quality.videoBitrate,
+ audioBitrate: m3U8Quality.audioBitrate,
+ VideoCodec: m3U8Quality.videoCodec,
+ AudioCodec: m3U8Quality.audioCodec
+
+ })) + seekParam;
+
+ var html = '';
+
+ var requiresControls = $.browser.msie || $.browser.android || ($.browser.webkit && !$.browser.chrome);
+
+ // Can't autoplay in these browsers so we need to use the full controls
+ if (requiresControls) {
+ html += '
";
-
+ var nowPlayingText = (name ? name + "\n" : "") + (seriesName || "---");
if (item.SeriesName || item.Album || item.CurrentProgram) {
- html += '
' + seriesName + '
' + name + '
';
- } else {
- html += '
' + name + '
' + seriesName + '
';
+ nowPlayingText = (seriesName ? seriesName + "\n" : "") + "\n" + (name || "---");
}
+ // Fix for apostrophes and quotes
+ var htmlTitle = trimTitle(nowPlayingText).replace(/'/g, ''').replace(/"/g, '"');
+ html += "
";
+ html += "
" + titleHtml(nowPlayingText) + "
";
+
+ var nowPlayingBar = $('#nowPlayingBar');
$('.nowPlayingMediaInfo', nowPlayingBar).html(html);
};
+ function trunc(string, len) {
+ if (string.length > 0 && string.length < len) return string;
+ var trimmed = $.trim(string).substring(0, len).split(" ").slice(0, -1).join(" ");
+ if (trimmed) {
+ trimmed += "...";
+ } else {
+ trimmed = "---"
+ }
+ return trimmed;
+ }
+
+ function trimTitle(title) {
+ return title.replace("\n---", "");
+ }
+
+ function titleHtml(title) {
+ var titles = title.split("\n");
+ return (trunc(titles[0], 30) + "
" + trunc(titles[1], 30)).replace("---", " ");
+ }
+
var getItemFields = "MediaStreams,Chapters,Path";
self.getItemsForPlayback = function (query) {
@@ -1369,20 +932,6 @@
};
- self.toggleFullscreen = function () {
- if (isFullScreen()) {
- if (document.cancelFullScreen) { document.cancelFullScreen(); }
- else if (document.mozCancelFullScreen) { document.mozCancelFullScreen(); }
- else if (document.webkitCancelFullScreen) {
- document.webkitCancelFullScreen();
- } else {
- $('.itemVideo').removeClass('fullscreenVideo');
- }
- } else {
- requestFullScreen(document.body);
- }
- };
-
self.removeFromPlaylist = function (index) {
self.playlist.remove(index);
@@ -1511,7 +1060,7 @@
self.seek = function (position) {
- changeStream(position);
+ self.changeStream(position);
};
@@ -1519,19 +1068,28 @@
if (currentMediaElement) {
currentMediaElement.volume = 0;
+ currentMediaElement.muted = true;
+ self.volumeSlider.val(0).slider('refresh');
}
};
self.unmute = function () {
+
if (currentMediaElement) {
- currentMediaElement.volume = volumeSlider.val();
+ var volume = localStorage.getItem("volume") || self.volumeSlider.val();
+ currentMediaElement.volume = volume;
+ currentMediaElement.muted = false;
+ self.volumeSlider.val(volume).slider('refresh');
}
};
self.toggleMute = function () {
if (currentMediaElement) {
- currentMediaElement.volume = currentMediaElement.volume ? 0 : volumeSlider.val();
+ var volume = localStorage.getItem("volume") || self.volumeSlider.val();
+ currentMediaElement.volume = currentMediaElement.volume ? 0 : volume;
+ currentMediaElement.muted = currentMediaElement.volume == 0;
+ self.volumeSlider.val(volume).slider('refresh');
}
};
@@ -1539,8 +1097,8 @@
if (currentMediaElement) {
currentMediaElement.volume = Math.max(currentMediaElement.volume - .02, 0);
-
- volumeSlider.val(currentMediaElement.volume).slider('refresh');
+ localStorage.setItem("volume", currentMediaElement.volume);
+ self.volumeSlider.val(currentMediaElement.volume).slider('refresh');
}
};
@@ -1548,8 +1106,8 @@
if (currentMediaElement) {
currentMediaElement.volume = Math.min(currentMediaElement.volume + .02, 1);
-
- volumeSlider.val(currentMediaElement.volume).slider('refresh');
+ localStorage.setItem("volume", currentMediaElement.volume);
+ self.volumeSlider.val(currentMediaElement.volume).slider('refresh');
}
};
@@ -1567,10 +1125,14 @@
}).trigger('ended');
- $('#nowPlayingBar').hide();
+ var footer = $('#footer');
+ footer.hide();
- if (isFullScreen()) {
- exitFullScreen();
+ if (elem.mediaType == "Video") {
+ self.resetEnhancements();
+ if (self.isFullScreen()) {
+ self.exitFullScreen();
+ }
}
};
@@ -1578,360 +1140,6 @@
return currentMediaElement;
};
- function hideFlyout(flyout) {
-
- flyout.hide().empty();
-
- $(document.body).off("mousedown.hidesearchhints");
- }
-
- function showFlyout(flyout, button) {
-
- $(document.body).off("mousedown.mediaflyout").on("mousedown.mediaflyout", function (e) {
-
- var elem = $(e.target);
-
- var flyoutId = flyout[0].id;
- var safeItems = button + ',#' + flyoutId;
-
- if (!elem.is(safeItems) && !elem.parents(safeItems).length) {
- hideFlyout(flyout);
- }
-
- });
-
- flyout.show();
- }
-
- function getChaptersFlyoutHtml(item) {
-
- var html = '';
-
- var currentTicks = getCurrentTicks();
-
- var chapters = item.Chapters || [];
-
- for (var i = 0, length = chapters.length; i < length; i++) {
-
- var chapter = chapters[i];
-
- var isSelected = false;
-
- if (currentTicks >= chapter.StartPositionTicks) {
-
- var nextChapter = chapters[i + 1];
-
- isSelected = !nextChapter || currentTicks < nextChapter.StartPositionTicks;
- }
-
- if (isSelected) {
- html += '