diff --git a/ApiClient.js b/ApiClient.js index 97c26ec78a..765cae6128 100644 --- a/ApiClient.js +++ b/ApiClient.js @@ -2191,20 +2191,6 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi }); }; - /** - * Gets a list of all available conrete BaseItem types from the server - */ - self.getItemTypes = function (options) { - - var url = self.getUrl("Library/ItemTypes", options); - - return self.ajax({ - type: "GET", - url: url, - dataType: "json" - }); - }; - /** * Constructs a url for a user image * @param {String} userId @@ -3805,7 +3791,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi * @param {String} userId * @param {String} itemId */ - self.reportPlaybackStart = function (userId, itemId, canSeek, queueableMediaTypes) { + self.reportPlaybackStart = function (userId, itemId, mediaSourceId, canSeek, queueableMediaTypes) { if (!userId) { throw new Error("null userId"); @@ -3823,6 +3809,10 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi var deferred = $.Deferred(); var msg = [itemId, canSeek, queueableMediaTypes]; + + if (mediaSourceId) { + msg.push(mediaSourceId); + } self.sendWebSocketMessage("PlaybackStart", msg.join('|')); @@ -3830,10 +3820,16 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi return deferred.promise(); } - var url = self.getUrl("Users/" + userId + "/PlayingItems/" + itemId, { + var params = { CanSeek: canSeek, QueueableMediaTypes: queueableMediaTypes - }); + }; + + if (mediaSourceId) { + params.mediaSourceId = mediaSourceId; + } + + var url = self.getUrl("Users/" + userId + "/PlayingItems/" + itemId, params); return self.ajax({ type: "POST", @@ -3846,7 +3842,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi * @param {String} userId * @param {String} itemId */ - self.reportPlaybackProgress = function (userId, itemId, positionTicks, isPaused, isMuted) { + self.reportPlaybackProgress = function (userId, itemId, mediaSourceId, positionTicks, isPaused, isMuted) { if (!userId) { throw new Error("null userId"); @@ -3860,7 +3856,12 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi var deferred = $.Deferred(); - var msgData = itemId + "|" + (positionTicks == null ? "" : positionTicks) + "|" + (isPaused == null ? "" : isPaused) + "|" + (isMuted == null ? "" : isMuted); + var msgData = itemId; + + msgData += "|" + (positionTicks == null ? "" : positionTicks); + msgData += "|" + (isPaused == null ? "" : isPaused); + msgData += "|" + (isMuted == null ? "" : isMuted); + msgData += "|" + (mediaSourceId == null ? "" : mediaSourceId); self.sendWebSocketMessage("PlaybackProgress", msgData); @@ -3877,6 +3878,10 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi params.positionTicks = positionTicks; } + if (mediaSourceId) { + params.mediaSourceId = mediaSourceId; + } + var url = self.getUrl("Users/" + userId + "/PlayingItems/" + itemId + "/Progress", params); return self.ajax({ @@ -3890,7 +3895,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi * @param {String} userId * @param {String} itemId */ - self.reportPlaybackStopped = function (userId, itemId, positionTicks) { + self.reportPlaybackStopped = function (userId, itemId, mediaSourceId, positionTicks) { if (!userId) { throw new Error("null userId"); @@ -3904,20 +3909,26 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi var deferred = $.Deferred(); - self.sendWebSocketMessage("PlaybackStopped", itemId + "|" + (positionTicks == null ? "" : positionTicks)); + var msg = itemId; + msg += "|" + (positionTicks == null ? "" : positionTicks); + msg += "|" + (mediaSourceId == null ? "" : mediaSourceId); + + self.sendWebSocketMessage("PlaybackStopped", msg); deferred.resolveWith(null, []); return deferred.promise(); } - var params = { - - }; + var params = {}; if (positionTicks) { params.positionTicks = positionTicks; } + if (mediaSourceId) { + params.mediaSourceId = mediaSourceId; + } + var url = self.getUrl("Users/" + userId + "/PlayingItems/" + itemId, params); return self.ajax({ diff --git a/dashboard-ui/css/librarybrowser.css b/dashboard-ui/css/librarybrowser.css index e210b0f657..ba6615ba09 100644 --- a/dashboard-ui/css/librarybrowser.css +++ b/dashboard-ui/css/librarybrowser.css @@ -866,7 +866,6 @@ a.itemTag:hover { } .mediaInfoStreamType { - font-size: 16px; display: block; color: #fff; } @@ -874,14 +873,12 @@ a.itemTag:hover { .mediaInfoAttribute { color: #fff; display: inline-block; - width: 110px; } .mediaInfoLabel { color: #aaa; margin-right: 1em; display: inline-block; - width: 90px; } .posterRibbon { @@ -929,7 +926,7 @@ a.itemTag:hover { background-color: transparent !important; } -.mediaVersionIndicator { +.mediaSourceIndicator { display: block; position: absolute; top: 5px; diff --git a/dashboard-ui/css/mediaplayer-video.css b/dashboard-ui/css/mediaplayer-video.css index 56dff52da7..51156157a1 100644 --- a/dashboard-ui/css/mediaplayer-video.css +++ b/dashboard-ui/css/mediaplayer-video.css @@ -33,7 +33,7 @@ #videoControls { z-index: 99999; - padding: 0 20px 10px; + padding: 0 20px 5px; height: 80px; position: absolute; top: auto; diff --git a/dashboard-ui/css/mediaplayer.css b/dashboard-ui/css/mediaplayer.css index 3ed4d78b89..5070af2039 100644 --- a/dashboard-ui/css/mediaplayer.css +++ b/dashboard-ui/css/mediaplayer.css @@ -1,13 +1,13 @@ /* Now playing bar */ .nowPlayingBar { - padding: 6px 0 24px 0; + padding: 6px 0 20px 0; border-top: 2px solid green; } .nowPlayingBar .barBackground { border-top: 2px solid green; position: absolute; - margin: -8px -0.5em -26px !important; + margin: -8px -0.5em -22px !important; width: 100%; height: 100%; } @@ -251,4 +251,4 @@ input[type="range"]::-ms-fill-upper { .positionSliderContainer { width: 300px; } -} \ No newline at end of file +} diff --git a/dashboard-ui/scripts/itembynamedetailpage.js b/dashboard-ui/scripts/itembynamedetailpage.js index ba20a2787a..b1d7b4901a 100644 --- a/dashboard-ui/scripts/itembynamedetailpage.js +++ b/dashboard-ui/scripts/itembynamedetailpage.js @@ -398,7 +398,8 @@ Recursive: true, Fields: "AudioInfo,SeriesInfo,ParentId,PrimaryImageAspectRatio", Limit: LibraryBrowser.getDefaultPageSize(), - StartIndex: 0 + StartIndex: 0, + CollapseBoxSetItems: false }; query = $.extend(query, options || {}); diff --git a/dashboard-ui/scripts/itemdetailpage.js b/dashboard-ui/scripts/itemdetailpage.js index 6bf282d884..ddd8f02ef2 100644 --- a/dashboard-ui/scripts/itemdetailpage.js +++ b/dashboard-ui/scripts/itemdetailpage.js @@ -73,7 +73,7 @@ $('#btnPlayExternalTrailer', page).attr('href', '#'); } - if (user.Configuration.IsAdministrator && item.MediaVersions && item.MediaVersions.length > 1) { + if (user.Configuration.IsAdministrator && item.MediaSources && item.MediaSources.length > 1) { $('.splitVersionContainer', page).show(); } else { $('.splitVersionContainer', page).hide(); @@ -210,15 +210,11 @@ $('#childrenCollapsible', page).addClass('hide'); } - if (item.MediaVersions && item.MediaVersions.length) { - renderMediaVersions(page, item); + if (item.MediaSources && item.MediaSources.length) { + renderMediaSources(page, item); } - var primaryVersion = (item.MediaVersions || []).filter(function (v) { - return v.IsPrimaryVersion; - - })[0]; - var chapters = primaryVersion ? (primaryVersion.Chapters || []) : []; + var chapters = item.Chapters || []; if (!chapters.length) { $('#scenesCollapsible', page).hide(); @@ -247,13 +243,6 @@ renderAdditionalParts(page, item, user); } - if (!item.AlternateVersionCount) { - $('#alternateVersionsCollapsible', page).addClass('hide'); - } else { - $('#alternateVersionsCollapsible', page).removeClass('hide'); - renderAlternateVersions(page, item, user); - } - $('#themeSongsCollapsible', page).hide(); $('#themeVideosCollapsible', page).hide(); @@ -350,7 +339,7 @@ tabsHtml += ''; } - if (item.MediaType == "Audio" || item.MediaType == "Video") { + if (item.MediaSources && item.MediaSources.length) { tabsHtml += ''; tabsHtml += ''; } @@ -985,49 +974,10 @@ }); } - function renderAlternateVersions(page, item, user) { - - var url = ApiClient.getUrl("Videos/" + item.Id + "/Versions", { - userId: user.Id - }); - - $.getJSON(url).done(function (items) { - - if (items.length) { - - $('#alternateVersionsCollapsible', page).show(); - - var html = LibraryBrowser.getPosterViewHtml({ - items: items.map(function (i) { - var extended = $.extend({}, item, i); - extended.Id = item.Id; - return extended; - }), - shape: "portrait", - context: 'movies', - useAverageAspectRatio: true, - showTitle: true, - centerText: true, - linkItem: false, - showProgress: false, - showUnplayedIndicator: false - }); - - $('#alternateVersionsContent', page).html(html).trigger('create'); - } else { - $('#alternateVersionsCollapsible', page).hide(); - } - }); - } - function renderScenes(page, item, user, limit) { var html = ''; - var primaryVersion = (item.MediaVersions || []).filter(function (v) { - return v.IsPrimaryVersion; - - })[0]; - var chapters = primaryVersion ? (primaryVersion.Chapters || []) : []; + var chapters = item.Chapters || []; for (var i = 0, length = chapters.length; i < length; i++) { @@ -1077,26 +1027,26 @@ $('#scenesContent', page).html(html).trigger('create'); } - function renderMediaVersions(page, item) { + function renderMediaSources(page, item) { - var html = item.MediaVersions.map(function (v) { + var html = item.MediaSources.map(function (v) { - return getMediaVersionHtml(item, v); + return getMediaSourceHtml(item, v); }).join('
'); - if (item.MediaVersions.length > 1) { + if (item.MediaSources.length > 1) { html = '
' + html; } $('#mediaInfoContent', page).html(html).trigger('create'); } - function getMediaVersionHtml(item, version) { + function getMediaSourceHtml(item, version) { var html = ''; - if (version.Name && item.MediaVersions.length > 1) { + if (version.Name && item.MediaSources.length > 1) { html += '' + version.Name + '
'; } @@ -1342,7 +1292,7 @@ var id = getParameterByName('id'); - Dashboard.confirm("Are you sure you wish to split the versions apart into separate items?", "Split Versions Apart", function (confirmResult) { + Dashboard.confirm("Are you sure you wish to split the media sources into separate items?", "Split Media Apart", function (confirmResult) { if (confirmResult) { @@ -1350,7 +1300,7 @@ $.ajax({ type: "DELETE", - url: ApiClient.getUrl("Videos/" + id + "/AlternateVersions") + url: ApiClient.getUrl("Videos/" + id + "/AlternateSources") }).done(function () { diff --git a/dashboard-ui/scripts/librarybrowser.js b/dashboard-ui/scripts/librarybrowser.js index 722a954baf..407fbc525e 100644 --- a/dashboard-ui/scripts/librarybrowser.js +++ b/dashboard-ui/scripts/librarybrowser.js @@ -6,7 +6,7 @@ getDefaultPageSize: function () { - var saved = localStorage.getItem('pagesize'); + var saved = localStorage.getItem('pagesize_'); if (saved) { return parseInt(saved); @@ -665,11 +665,11 @@ cssClass += ' ' + options.shape + 'PosterItem'; - var mediaVersionCount = item.MediaVersionCount || 1; + var mediaSourceCount = item.MediaSourceCount || 1; var href = options.linkItem === false ? '#' : LibraryBrowser.getHref(item, options.context); - html += ''; + html += ''; var style = ""; @@ -700,8 +700,8 @@ html += LibraryBrowser.getPlayedIndicatorHtml(item); } - if (mediaVersionCount > 1) { - html += '
' + mediaVersionCount + '
'; + if (mediaSourceCount > 1) { + html += '
' + mediaSourceCount + '
'; } if (item.IsUnidentified) { html += '
'; diff --git a/dashboard-ui/scripts/librarylist.js b/dashboard-ui/scripts/librarylist.js index 14d49af957..23488ac7a2 100644 --- a/dashboard-ui/scripts/librarylist.js +++ b/dashboard-ui/scripts/librarylist.js @@ -175,7 +175,7 @@ function splitVersions(id, page) { - Dashboard.confirm("Are you sure you wish to split the versions apart into separate items?", "Split Versions Apart", function (confirmResult) { + Dashboard.confirm("Are you sure you wish to split the media sources into separate items?", "Split Media Apart", function (confirmResult) { if (confirmResult) { @@ -183,7 +183,7 @@ $.ajax({ type: "DELETE", - url: ApiClient.getUrl("Videos/" + id + "/AlternateVersions") + url: ApiClient.getUrl("Videos/" + id + "/AlternateSources") }).done(function () { @@ -208,8 +208,8 @@ items.push({ type: 'link', text: 'Images', url: 'edititemimages.html?id=' + id }); - var versionCount = parseInt(elem.getAttribute('data-mediaversioncount') || '0'); - + var versionCount = parseInt(elem.getAttribute('data-mediasourcecount') || '0'); + if (versionCount > 1) { items.push({ type: 'divider' }); diff --git a/dashboard-ui/scripts/libraryreport.js b/dashboard-ui/scripts/libraryreport.js index bc894428a6..a66f43ff34 100644 --- a/dashboard-ui/scripts/libraryreport.js +++ b/dashboard-ui/scripts/libraryreport.js @@ -8,7 +8,7 @@ SortBy: defaultSortBy, SortOrder: "Ascending", Recursive: true, - Fields: "MediaVersions,DateCreated,Settings,Studios", + Fields: "MediaSources,DateCreated,Settings,Studios", StartIndex: 0, IncludeItemTypes: "Movie", IsMissing: false, @@ -207,19 +207,27 @@ function getItemCellsHtml(item, headercells) { + var primaryVersion = (item.MediaSources || [])[0] || {}; + + var mediaStreams = primaryVersion.MediaStreams || []; + + var videoStream = mediaStreams.filter(function (s) { + + return s.Type == 'Video'; + + })[0]; + + var audioStream = mediaStreams.filter(function (s) { + + return s.Type == 'Audio'; + + })[0]; + return headercells.map(function (cell) { var html = ''; html += ''; - var stream; - - var primaryVersion = (item.MediaVersions || []).filter(function(v) { - return v.IsPrimaryVersion; - })[0] || {}; - - var mediaStreams = primaryVersion.MediaStreams || []; - switch (cell.type || cell.name) { case 'Album Artist': @@ -264,52 +272,30 @@ } case 'Audio': { - stream = mediaStreams.filter(function (s) { + if (audioStream) { - return s.Type == 'Audio'; - - })[0]; - - if (stream) { - - var name = (stream.Codec || '').toUpperCase(); - html += name == 'DCA' ? (stream.Profile || '').toUpperCase() : name; + var name = (audioStream.Codec || '').toUpperCase(); + html += name == 'DCA' ? (audioStream.Profile || '').toUpperCase() : name; } break; } case 'Video': { - stream = mediaStreams.filter(function (s) { - - return s.Type == 'Video'; - - })[0]; - - if (stream) { - html += (stream.Codec || '').toUpperCase(); + if (videoStream) { + html += (videoStream.Codec || '').toUpperCase(); } break; } case 'Resolution': { - stream = mediaStreams.filter(function (s) { - - return s.Type == 'Video'; - - })[0]; - - if (stream && stream.Width) { - html += stream.Width + "*" + (stream.Height || "-"); + if (videoStream && videoStream.Width) { + html += videoStream.Width + "*" + (videoStream.Height || "-"); } break; } case 'Embedded Image': { - if (mediaStreams.filter(function (s) { - - return s.Type == 'Video'; - - }).length) { + if (videoStream) { html += '
'; } break; diff --git a/dashboard-ui/scripts/mediaplayer-video.js b/dashboard-ui/scripts/mediaplayer-video.js index 0a7b6a5095..c9a36eb536 100644 --- a/dashboard-ui/scripts/mediaplayer-video.js +++ b/dashboard-ui/scripts/mediaplayer-video.js @@ -1,5 +1,5 @@ (function () { - videoPlayer = function (mediaPlayer, item, mediaVersion, startPosition, user) { + videoPlayer = function (mediaPlayer, item, mediaSource, startPosition, user) { if (mediaPlayer == null) { throw new Error("mediaPlayer cannot be null"); } @@ -15,7 +15,7 @@ var self = mediaPlayer; var currentItem; - var currentMediaVersion; + var currentMediaSource; var timeout; var video; var initialVolume; @@ -24,7 +24,7 @@ var remoteFullscreen = false; self.initVideoPlayer = function () { - video = playVideo(item, mediaVersion, startPosition, user); + video = playVideo(item, mediaSource, startPosition, user); return video; }; @@ -319,7 +319,7 @@ var currentTicks = self.getCurrentTicks(); - var chapters = currentMediaVersion.Chapters || []; + var chapters = currentItem.Chapters || []; for (var i = 0, length = chapters.length; i < length; i++) { @@ -344,7 +344,7 @@ if (chapter.ImageTag) { - imgUrl = ApiClient.getImageUrl(currentMediaVersion.ItemId, { + imgUrl = ApiClient.getImageUrl(currentItem.Id, { maxwidth: 200, tag: chapter.ImageTag, type: "Chapter", @@ -374,7 +374,7 @@ function getAudioTracksHtml() { - var streams = currentMediaVersion.MediaStreams.filter(function (currentStream) { + var streams = currentMediaSource.MediaStreams.filter(function (currentStream) { return currentStream.Type == "Audio"; }); @@ -444,7 +444,7 @@ function getSubtitleTracksHtml() { - var streams = currentMediaVersion.MediaStreams.filter(function (currentStream) { + var streams = currentMediaSource.MediaStreams.filter(function (currentStream) { return currentStream.Type == "Subtitle"; }); @@ -528,7 +528,7 @@ var currentAudioStreamIndex = getParameterByName('AudioStreamIndex', video.currentSrc); - var options = getVideoQualityOptions(currentMediaVersion.MediaStreams, currentAudioStreamIndex, transcodingExtension); + var options = getVideoQualityOptions(currentMediaSource.MediaStreams, currentAudioStreamIndex, transcodingExtension); if (isStatic) { options[0].name = "Direct"; @@ -696,9 +696,9 @@ return options; }; - function playVideo(item, mediaVersion, startPosition, user) { + function playVideo(item, mediaSource, startPosition, user) { - var mediaStreams = mediaVersion.MediaStreams || []; + var mediaStreams = mediaSource.MediaStreams || []; var baseParams = { audioChannels: 2, @@ -706,23 +706,24 @@ SubtitleStreamIndex: getInitialSubtitleStreamIndex(mediaStreams, user), AudioStreamIndex: getInitialAudioStreamIndex(mediaStreams, user), deviceId: ApiClient.deviceId(), - Static: false + Static: false, + mediaSourceId: mediaSource.Id }; var mp4Quality = getVideoQualityOptions(mediaStreams).filter(function (opt) { return opt.selected; })[0]; - mp4Quality = $.extend(mp4Quality, self.getFinalVideoParams(mediaVersion, mp4Quality.maxWidth, mp4Quality.bitrate, baseParams.AudioStreamIndex, baseParams.SubtitleStreamIndex, '.mp4')); + mp4Quality = $.extend(mp4Quality, self.getFinalVideoParams(mediaSource, mp4Quality.maxWidth, mp4Quality.bitrate, baseParams.AudioStreamIndex, baseParams.SubtitleStreamIndex, '.mp4')); var webmQuality = getVideoQualityOptions(mediaStreams).filter(function (opt) { return opt.selected; })[0]; - webmQuality = $.extend(webmQuality, self.getFinalVideoParams(mediaVersion, webmQuality.maxWidth, webmQuality.bitrate, baseParams.AudioStreamIndex, baseParams.SubtitleStreamIndex, '.webm')); + webmQuality = $.extend(webmQuality, self.getFinalVideoParams(mediaSource, webmQuality.maxWidth, webmQuality.bitrate, baseParams.AudioStreamIndex, baseParams.SubtitleStreamIndex, '.webm')); var m3U8Quality = getVideoQualityOptions(mediaStreams).filter(function (opt) { return opt.selected; })[0]; - m3U8Quality = $.extend(m3U8Quality, self.getFinalVideoParams(mediaVersion, mp4Quality.maxWidth, mp4Quality.bitrate, baseParams.AudioStreamIndex, baseParams.SubtitleStreamIndex, '.mp4')); + m3U8Quality = $.extend(m3U8Quality, self.getFinalVideoParams(mediaSource, 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; @@ -733,7 +734,7 @@ var seekParam = isStatic && startPosition ? '#t=' + (startPosition / 10000000) : ''; - var mp4VideoUrl = ApiClient.getUrl('Videos/' + mediaVersion.ItemId + '/stream.mp4', $.extend({}, baseParams, { + var mp4VideoUrl = ApiClient.getUrl('Videos/' + item.Id + '/stream.mp4', $.extend({}, baseParams, { profile: 'baseline', level: 3, Static: isStatic, @@ -745,7 +746,7 @@ })) + seekParam; - var webmVideoUrl = ApiClient.getUrl('Videos/' + mediaVersion.ItemId + '/stream.webm', $.extend({}, baseParams, { + var webmVideoUrl = ApiClient.getUrl('Videos/' + item.Id + '/stream.webm', $.extend({}, baseParams, { VideoCodec: 'vpx', AudioCodec: 'Vorbis', @@ -755,7 +756,7 @@ })) + seekParam; - var hlsVideoUrl = ApiClient.getUrl('Videos/' + mediaVersion.ItemId + '/stream.m3u8', $.extend({}, baseParams, { + var hlsVideoUrl = ApiClient.getUrl('Videos/' + item.Id + '/stream.m3u8', $.extend({}, baseParams, { profile: 'baseline', level: 3, timeStampOffsetMs: 0, @@ -835,7 +836,7 @@ $('#video-subtitleButton', videoControls).hide(); } - if (mediaVersion.Chapters && mediaVersion.Chapters.length) { + if (item.Chapters && item.Chapters.length) { $('#video-chaptersButton', videoControls).show(); } else { $('#video-chaptersButton', videoControls).hide(); @@ -882,9 +883,9 @@ videoElement.off("playing.once"); - ApiClient.reportPlaybackStart(Dashboard.getCurrentUserId(), mediaVersion.ItemId, true, item.MediaType); + ApiClient.reportPlaybackStart(Dashboard.getCurrentUserId(), item.Id, mediaSource.Id, true, item.MediaType); - self.startProgressInterval(mediaVersion.ItemId); + self.startProgressInterval(item.Id, mediaSource.Id); }).on("pause", function (e) { @@ -1000,7 +1001,7 @@ fullscreenExited = false; currentItem = item; - currentMediaVersion = mediaVersion; + currentMediaSource = mediaSource; return videoElement[0]; }; diff --git a/dashboard-ui/scripts/mediaplayer.js b/dashboard-ui/scripts/mediaplayer.js index 4aaf83d412..26be435159 100644 --- a/dashboard-ui/scripts/mediaplayer.js +++ b/dashboard-ui/scripts/mediaplayer.js @@ -8,7 +8,7 @@ var currentMediaElement; var currentProgressInterval; var currentItem; - var currentMediaVersion; + var currentMediaSource; var curentDurationTicks; var canClientSeek; var currentPlaylistIndex = 0; @@ -54,7 +54,7 @@ var position = Math.floor(10000000 * endTime) + self.startTimeTicksOffset; - ApiClient.reportPlaybackStopped(Dashboard.getCurrentUserId(), currentMediaVersion.ItemId, position); + ApiClient.reportPlaybackStopped(Dashboard.getCurrentUserId(), currentItem.Id, currentMediaSource.Id, position); if (currentItem.MediaType == "Video") { ApiClient.stopActiveEncodings(); @@ -72,7 +72,7 @@ self.nextTrack(); }; - self.startProgressInterval = function (itemId) { + self.startProgressInterval = function (itemId, mediaSourceId) { clearProgressInterval(); @@ -81,7 +81,7 @@ currentProgressInterval = setInterval(function () { if (currentMediaElement) { - sendProgressUpdate(itemId); + sendProgressUpdate(itemId, mediaSourceId); } }, intervalTime); @@ -136,7 +136,7 @@ var transcodingExtension = self.getTranscodingExtension(); - var finalParams = self.getFinalVideoParams(currentMediaVersion, maxWidth, bitrate, audioStreamIndex, subtitleStreamIndex, transcodingExtension); + var finalParams = self.getFinalVideoParams(currentMediaSource, maxWidth, bitrate, audioStreamIndex, subtitleStreamIndex, transcodingExtension); currentSrc = replaceQueryString(currentSrc, 'MaxWidth', finalParams.maxWidth); currentSrc = replaceQueryString(currentSrc, 'VideoBitrate', finalParams.videoBitrate); currentSrc = replaceQueryString(currentSrc, 'AudioBitrate', finalParams.audioBitrate); @@ -156,8 +156,8 @@ $(this).off('play.onceafterseek').on('ended.playbackstopped', self.onPlaybackStopped).on('ended.playnext', self.playNextAfterEnded); - self.startProgressInterval(currentMediaVersion.ItemId); - sendProgressUpdate(currentMediaVersion.ItemId); + self.startProgressInterval(currentItem.Id, currentMediaSource.Id); + sendProgressUpdate(currentItem.Id, currentMediaSource.Id); }); @@ -194,9 +194,9 @@ self.currentTimeElement.html(timeText); }; - self.canPlayVideoDirect = function (mediaVersion, videoStream, audioStream, subtitleStream, maxWidth, bitrate) { + self.canPlayVideoDirect = function (mediaSource, videoStream, audioStream, subtitleStream, maxWidth, bitrate) { - if (mediaVersion.VideoType != "VideoFile" || mediaVersion.LocationType != "FileSystem") { + if (mediaSource.VideoType != "VideoFile" || mediaSource.LocationType != "FileSystem") { console.log('Transcoding because the content is not a video file'); return false; } @@ -229,7 +229,7 @@ return false; } - var extension = mediaVersion.Path.substring(mediaVersion.Path.lastIndexOf('.') + 1).toLowerCase(); + var extension = mediaSource.Path.substring(mediaSource.Path.lastIndexOf('.') + 1).toLowerCase(); if (extension == 'm4v') { return $.browser.chrome; @@ -238,9 +238,9 @@ return extension.toLowerCase() == 'mp4'; }; - self.getFinalVideoParams = function (mediaVersion, maxWidth, bitrate, audioStreamIndex, subtitleStreamIndex, transcodingExtension) { + self.getFinalVideoParams = function (mediaSource, maxWidth, bitrate, audioStreamIndex, subtitleStreamIndex, transcodingExtension) { - var mediaStreams = mediaVersion.MediaStreams; + var mediaStreams = mediaSource.MediaStreams; var videoStream = mediaStreams.filter(function (stream) { return stream.Type === "Video"; @@ -254,7 +254,7 @@ return stream.Index === subtitleStreamIndex; })[0]; - var canPlayDirect = self.canPlayVideoDirect(mediaVersion, videoStream, audioStream, subtitleStream, maxWidth, bitrate); + var canPlayDirect = self.canPlayVideoDirect(mediaSource, videoStream, audioStream, subtitleStream, maxWidth, bitrate); var audioBitrate = bitrate >= 700000 ? 128000 : 64000; @@ -404,7 +404,7 @@ return parseInt(localStorage.getItem('preferredVideoBitrate') || '') || 1500000; }; - function getOptimalMediaVersion(mediaType, versions) { + function getOptimalMediaSource(mediaType, versions) { var optimalVersion; @@ -449,23 +449,23 @@ if (item.MediaType === "Video") { currentItem = item; - currentMediaVersion = getOptimalMediaVersion(item.MediaType, item.MediaVersions); + currentMediaSource = getOptimalMediaSource(item.MediaType, item.MediaSources); - videoPlayer(self, item, currentMediaVersion, startPosition, user); + videoPlayer(self, item, currentMediaSource, startPosition, user); mediaElement = self.initVideoPlayer(); - curentDurationTicks = currentMediaVersion.RunTimeTicks; + curentDurationTicks = currentMediaSource.RunTimeTicks; mediaControls = $("#videoControls"); } else if (item.MediaType === "Audio") { currentItem = item; - currentMediaVersion = getOptimalMediaVersion(item.MediaType, item.MediaVersions); + currentMediaSource = getOptimalMediaSource(item.MediaType, item.MediaSources); - mediaElement = playAudio(item, currentMediaVersion, startPosition); + mediaElement = playAudio(item, currentMediaSource, startPosition); mediaControls.show(); - curentDurationTicks = currentMediaVersion.RunTimeTicks; + curentDurationTicks = currentMediaSource.RunTimeTicks; } else { throw new Error("Unrecognized media type"); @@ -957,7 +957,7 @@ var position = Math.floor(10000000 * endTime) + self.startTimeTicksOffset; - ApiClient.reportPlaybackStopped(Dashboard.getCurrentUserId(), currentMediaVersion.ItemId, position); + ApiClient.reportPlaybackStopped(Dashboard.getCurrentUserId(), currentItem.Id, currentMediaSource.Id, position); } }); @@ -984,9 +984,9 @@ return url + '&' + param + "=" + value; }; - function sendProgressUpdate(itemId) { + function sendProgressUpdate(itemId, mediaSourceId) { - ApiClient.reportPlaybackProgress(Dashboard.getCurrentUserId(), itemId, self.getCurrentTicks(), currentMediaElement.paused, currentMediaElement.volume == 0); + ApiClient.reportPlaybackProgress(Dashboard.getCurrentUserId(), itemId, mediaSourceId, self.getCurrentTicks(), currentMediaElement.paused, currentMediaElement.volume == 0); }; function clearProgressInterval() { @@ -1008,7 +1008,7 @@ var newPercent = parseInt(this.value); - var newPositionTicks = (newPercent / 100) * currentMediaVersion.RunTimeTicks; + var newPositionTicks = (newPercent / 100) * currentMediaSource.RunTimeTicks; self.changeStream(Math.floor(newPositionTicks)); }; @@ -1022,29 +1022,30 @@ return d >= 0 && text.lastIndexOf(pattern) === d; }; - function playAudio(item, mediaVersion, startPositionTicks) { + function playAudio(item, mediaSource, startPositionTicks) { startPositionTicks = startPositionTicks || 0; var baseParams = { audioChannels: 2, audioBitrate: 128000, - StartTimeTicks: startPositionTicks + StartTimeTicks: startPositionTicks, + mediaSourceId: mediaSource.Id }; - var mp3Url = ApiClient.getUrl('Audio/' + mediaVersion.ItemId + '/stream.mp3', $.extend({}, baseParams, { + var mp3Url = ApiClient.getUrl('Audio/' + item.Id + '/stream.mp3', $.extend({}, baseParams, { audioCodec: 'mp3' })); - var aacUrl = ApiClient.getUrl('Audio/' + mediaVersion.ItemId + '/stream.aac', $.extend({}, baseParams, { + var aacUrl = ApiClient.getUrl('Audio/' + item.Id + '/stream.aac', $.extend({}, baseParams, { audioCodec: 'aac' })); - var webmUrl = ApiClient.getUrl('Audio/' + mediaVersion.ItemId + '/stream.webm', $.extend({}, baseParams, { + var webmUrl = ApiClient.getUrl('Audio/' + item.Id + '/stream.webm', $.extend({}, baseParams, { audioCodec: 'Vorbis' })); - var mediaStreams = mediaVersion.MediaStreams; + var mediaStreams = mediaSource.MediaStreams; var isStatic = false; var seekParam = isStatic && startPositionTicks ? '#t=' + (startPositionTicks / 10000000) : ''; @@ -1056,11 +1057,11 @@ if (stream.Type == "Audio") { // Stream statically when possible - if (endsWith(mediaVersion.Path, ".aac") && stream.BitRate <= 256000) { + if (endsWith(mediaSource.Path, ".aac") && stream.BitRate <= 256000) { aacUrl += "&static=true" + seekParam; isStatic = true; } - else if (endsWith(mediaVersion.Path, ".mp3") && stream.BitRate <= 256000) { + else if (endsWith(mediaSource.Path, ".mp3") && stream.BitRate <= 256000) { mp3Url += "&static=true" + seekParam; isStatic = true; } @@ -1131,9 +1132,9 @@ audioElement.off("play.once"); - ApiClient.reportPlaybackStart(Dashboard.getCurrentUserId(), mediaVersion.ItemId, true, item.MediaType); + ApiClient.reportPlaybackStart(Dashboard.getCurrentUserId(), item.Id, mediaSource.Id, true, item.MediaType); - self.startProgressInterval(mediaVersion.ItemId); + self.startProgressInterval(item.Id, mediaSource.Id); }).on("pause", function () { @@ -1200,7 +1201,7 @@ return (trunc(titles[0], 30) + "
" + trunc(titles[1], 30)).replace("---", " "); }; - var getItemFields = "MediaVersions"; + var getItemFields = "MediaSources,Chapters"; } window.MediaPlayer = new mediaPlayer(); diff --git a/packages.config b/packages.config index 0bdea523e3..7396527bb3 100644 --- a/packages.config +++ b/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file