1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

fixes #712 - multi-version grouping

This commit is contained in:
Luke Pulverenti 2014-03-20 23:31:40 -04:00
parent 902d3a3649
commit 02a810cf1e
12 changed files with 163 additions and 304 deletions

View file

@ -859,7 +859,7 @@ a.itemTag:hover {
} }
.mediaInfoStream { .mediaInfoStream {
margin: 1em 2em 1em 0; margin: 1em 3em 1em 0;
display: inline-block; display: inline-block;
color: #bbb; color: #bbb;
vertical-align: top; vertical-align: top;
@ -867,7 +867,6 @@ a.itemTag:hover {
.mediaInfoStreamType { .mediaInfoStreamType {
display: block; display: block;
font-size: 16px;
color: #fff; color: #fff;
} }
@ -925,7 +924,7 @@ a.itemTag:hover {
background-color: transparent !important; background-color: transparent !important;
} }
.alternateVersionIndicator { .mediaVersionIndicator {
display: block; display: block;
position: absolute; position: absolute;
top: 5px; top: 5px;

View file

@ -320,61 +320,4 @@
.backdropPosterItem .posterItemImage { .backdropPosterItem .posterItemImage {
height: 167.625px; height: 167.625px;
} }
} }
/********************/
.ribbon-wrapper {
width: 50px;
height: 50px;
overflow: hidden;
position: absolute;
top: 0px;
left: 0px;
z-index: 999;
}
.ribbon {
font: bold 11px Sans-Serif;
color: #333;
text-align: center;
color: #eee;
text-shadow: rgba(51, 51, 51, 0.5) 0px 1px 0px;
-webkit-transform: rotate(-45deg);
-moz-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
-o-transform: rotate(-45deg);
position: relative;
padding: 2px 0;
right: 15px;
top: 5px;
width: 60px;
-webkit-box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.3);
-moz-box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.3);
box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.3);
}
.ribbon-3d {
background-color: #3344ff;
background-image: -webkit-gradient(linear, left top, left bottom, from(#BFDC7A), to(#ff0033));
background-image: -webkit-linear-gradient(top, #3344ff, #ff0033);
background-image: -moz-linear-gradient(top, #3344ff, #ff0033);
background-image: -ms-linear-gradient(top, #3344ff, #ff0033);
background-image: -o-linear-gradient(top, #3344ff, #ff0033);
}
.ribbon-blue {
background-color: #1199ff;
background-image: -webkit-gradient(linear, left top, left bottom, from(#1199ff), to(#3333ff));
background-image: -webkit-linear-gradient(top, #1199ff, #3333ff);
background-image: -moz-linear-gradient(top, #1199ff, #3333ff);
background-image: -ms-linear-gradient(top, #1199ff, #3333ff);
background-image: -o-linear-gradient(top, #1199ff, #3333ff);
}
.ribbon-red {
background-color: #ff3333;
background-image: -webkit-gradient(linear, left top, left bottom, from(#ff3333), to(#992233));
background-image: -webkit-linear-gradient(top, #ff3333, #992233);
background-image: -moz-linear-gradient(top, #ff3333, #992233);
background-image: -ms-linear-gradient(top, #ff3333, #992233);
background-image: -o-linear-gradient(top, #ff3333, #992233);
}

View file

@ -24,7 +24,7 @@
<div class="viewControls" data-role="controlgroup" data-type="horizontal"> <div class="viewControls" data-role="controlgroup" data-type="horizontal">
<button data-mini="true" data-icon="sort" data-inline="true" data-iconpos="notext" title="Sort" onclick="$('#sortPanel', $(this).parents('.page')).panel( 'toggle' );">Sort</button> <button data-mini="true" data-icon="sort" data-inline="true" data-iconpos="notext" title="Sort" onclick="$('#sortPanel', $(this).parents('.page')).panel( 'toggle' );">Sort</button>
<button data-mini="true" data-icon="filter" data-inline="true" data-iconpos="notext" title="Filter" onclick="$('#filterPanel', $(this).parents('.page')).panel( 'toggle' );">Filter</button> <button data-mini="true" data-icon="filter" data-inline="true" data-iconpos="notext" title="Filter" onclick="$('#filterPanel', $(this).parents('.page')).panel( 'toggle' );">Filter</button>
<!-- <button data-mini="true" data-icon="check" data-inline="true" data-iconpos="notext" title="Select" class="btnToggleSelections">Select</button>--> <button data-mini="true" data-icon="check" data-inline="true" data-iconpos="notext" title="Select" class="btnToggleSelections">Select</button>
</div> </div>
<div class="listTopPaging"> <div class="listTopPaging">
</div> </div>

View file

@ -152,7 +152,7 @@
<br /> <br />
<div class="tabButtons"></div> <div class="tabButtons"></div>
<div class="detailSectionContent" style="padding: 0 .7em;"> <div class="detailSectionContent" style="padding: .25em .7em 0;">
<div class="detailTab tabDetails"> <div class="detailTab tabDetails">
<p id="players"></p> <p id="players"></p>
@ -163,15 +163,12 @@
<p class="itemExternalLinks"></p> <p class="itemExternalLinks"></p>
</div> </div>
<div class="detailTab tabMediaInfo"> <div class="detailTab tabMediaInfo">
<div class="splitVersionContainer" style="border-bottom: 1px solid #444;">
<button type="button" class="btnSplitVersions" data-mini="true" data-inline="true" data-icon="delete" title="Split Versions Apart">Split Versions Apart</button>
</div>
<div id="mediaInfoContent"></div> <div id="mediaInfoContent"></div>
<div id="alternateVersionsCollapsible" class="detailSection hide">
<div class="detailSectionHeader" style="position: relative;">
Media Versions
<button type="button" class="btnSplitVersions" style="position: absolute; right: 0; top: 6px; margin-top: 0; margin-bottom: 0; display: none;" data-mini="true" data-inline="true" data-icon="delete" data-iconpos="notext" title="Split Versions Apart">Split Versions Apart</button>
</div>
<div id="alternateVersionsContent" class="detailSectionContent"></div>
</div>
</div> </div>
<div class="detailTab tabTags"> <div class="detailTab tabTags">
<p class="itemStudios"></p> <p class="itemStudios"></p>

View file

@ -32,7 +32,7 @@
<div class="viewControls" data-role="controlgroup" data-type="horizontal"> <div class="viewControls" data-role="controlgroup" data-type="horizontal">
<button data-mini="true" data-icon="sort" data-inline="true" data-iconpos="notext" title="Sort" onclick="$('#sortPanel', $(this).parents('.page')).panel( 'toggle' );">Sort</button> <button data-mini="true" data-icon="sort" data-inline="true" data-iconpos="notext" title="Sort" onclick="$('#sortPanel', $(this).parents('.page')).panel( 'toggle' );">Sort</button>
<button data-mini="true" data-icon="filter" data-inline="true" data-iconpos="notext" title="Filter" onclick="$('#filterPanel', $(this).parents('.page')).panel( 'toggle' );">Filter</button> <button data-mini="true" data-icon="filter" data-inline="true" data-iconpos="notext" title="Filter" onclick="$('#filterPanel', $(this).parents('.page')).panel( 'toggle' );">Filter</button>
<!-- <button data-mini="true" data-icon="check" data-inline="true" data-iconpos="notext" title="Select" class="btnToggleSelections">Select</button>--> <button data-mini="true" data-icon="check" data-inline="true" data-iconpos="notext" title="Select" class="btnToggleSelections">Select</button>
</div> </div>
<div class="listTopPaging"> <div class="listTopPaging">
</div> </div>

View file

@ -73,10 +73,10 @@
$('#btnPlayExternalTrailer', page).attr('href', '#'); $('#btnPlayExternalTrailer', page).attr('href', '#');
} }
if (user.Configuration.IsAdministrator) { if (user.Configuration.IsAdministrator && item.MediaVersions && item.MediaVersions.length > 1) {
$('.btnSplitVersions', page).show(); $('.splitVersionContainer', page).show();
} else { } else {
$('.btnSplitVersions', page).hide(); $('.splitVersionContainer', page).hide();
} }
}); });
@ -210,10 +210,17 @@
$('#childrenCollapsible', page).addClass('hide'); $('#childrenCollapsible', page).addClass('hide');
} }
if (item.MediaStreams && item.MediaStreams.length) { if (item.MediaVersions && item.MediaVersions.length) {
renderMediaInfo(page, item); renderMediaVersions(page, item);
} }
if (!item.Chapters || !item.Chapters.length) {
var primaryVersion = (item.MediaVersions || []).filter(function (v) {
return v.IsPrimaryVersion;
})[0];
var chapters = primaryVersion ? (primaryVersion.Chapters || []) : [];
if (!chapters.length) {
$('#scenesCollapsible', page).hide(); $('#scenesCollapsible', page).hide();
} else { } else {
$('#scenesCollapsible', page).show(); $('#scenesCollapsible', page).show();
@ -342,7 +349,7 @@
tabsHtml += '<input type="radio" name="radioDetailTab" class="radioDetailTab" id="radioDetails" value="tabDetails">'; tabsHtml += '<input type="radio" name="radioDetailTab" class="radioDetailTab" id="radioDetails" value="tabDetails">';
tabsHtml += '<label for="radioDetails" class="lblDetailTab">Details</label>'; tabsHtml += '<label for="radioDetails" class="lblDetailTab">Details</label>';
} }
if (item.MediaType == "Audio" || item.MediaType == "Video") { if (item.MediaType == "Audio" || item.MediaType == "Video") {
tabsHtml += '<input type="radio" name="radioDetailTab" class="radioDetailTab" id="radioMediaInfo" value="tabMediaInfo">'; tabsHtml += '<input type="radio" name="radioDetailTab" class="radioDetailTab" id="radioMediaInfo" value="tabMediaInfo">';
tabsHtml += '<label for="radioMediaInfo" class="lblDetailTab">Media Info</label>'; tabsHtml += '<label for="radioMediaInfo" class="lblDetailTab">Media Info</label>';
@ -1001,7 +1008,6 @@
useAverageAspectRatio: true, useAverageAspectRatio: true,
showTitle: true, showTitle: true,
centerText: true, centerText: true,
formatIndicators: true,
linkItem: false, linkItem: false,
showProgress: false, showProgress: false,
showUnplayedIndicator: false showUnplayedIndicator: false
@ -1017,7 +1023,11 @@
function renderScenes(page, item, user, limit) { function renderScenes(page, item, user, limit) {
var html = ''; var html = '';
var chapters = item.Chapters || []; var primaryVersion = (item.MediaVersions || []).filter(function (v) {
return v.IsPrimaryVersion;
})[0];
var chapters = primaryVersion ? (primaryVersion.Chapters || []) : [];
for (var i = 0, length = chapters.length; i < length; i++) { for (var i = 0, length = chapters.length; i < length; i++) {
@ -1067,13 +1077,32 @@
$('#scenesContent', page).html(html).trigger('create'); $('#scenesContent', page).html(html).trigger('create');
} }
function renderMediaInfo(page, item) { function renderMediaVersions(page, item) {
var html = item.MediaVersions.map(function (v) {
return getMediaVersionHtml(item, v);
}).join('<div style="border-top:1px solid #444;margin: 1em 0;"></div>');
if (item.MediaVersions.length > 1) {
html = '<br/>' + html;
}
$('#mediaInfoContent', page).html(html).trigger('create');
}
function getMediaVersionHtml(item, version) {
var html = ''; var html = '';
for (var i = 0, length = item.MediaStreams.length; i < length; i++) { if (version.Name && item.MediaVersions.length > 1) {
html += '<span class="mediaInfoAttribute">' + version.Name + '</span><br/>';
}
var stream = item.MediaStreams[i]; for (var i = 0, length = version.MediaStreams.length; i < length; i++) {
var stream = version.MediaStreams[i];
if (stream.Type == "Data") { if (stream.Type == "Data") {
continue; continue;
@ -1155,7 +1184,11 @@
html += '</div>'; html += '</div>';
} }
$('#mediaInfoContent', page).html(html).trigger('create'); if (version.Path) {
html += '<br/><span class="mediaInfoLabel">Path</span><span class="mediaInfoAttribute">' + version.Path + '</span>';
}
return html;
} }
function getVideosHtml(items, user, limit, moreButtonClass) { function getVideosHtml(items, user, limit, moreButtonClass) {

View file

@ -665,33 +665,11 @@
cssClass += ' ' + options.shape + 'PosterItem'; cssClass += ' ' + options.shape + 'PosterItem';
var mediaVersionCount = item.MediaVersionCount || 1;
var href = options.linkItem === false ? '#' : LibraryBrowser.getHref(item, options.context); var href = options.linkItem === false ? '#' : LibraryBrowser.getHref(item, options.context);
html += '<a data-itemid="' + item.Id + '" class="' + cssClass + '" data-alternateversioncount="' + (item.AlternateVersionCount || '0') + '" href="' + href + '">'; html += '<a data-itemid="' + item.Id + '" class="' + cssClass + '" data-mediaversioncount="' + mediaVersionCount + '" href="' + href + '">';
// Ribbon
if (item.MediaType == "Video" && options.formatIndicators) {
// This would be much better if specified in the json payload
// Another nice thing to have in the payload would be 720 vs 1080
// Then, rather than "HD" it could display the specific HD format
// "HD" doesn't do much good if you have the 720p and 1080p version
var format = "SD";
var ribbonColor = "ribbon-red";
if (item.IsHD) {
format = "HD";
ribbonColor = "ribbon-blue";
}
if (item.Video3DFormat) {
format = "3D";
ribbonColor = "ribbon-3d";
}
html += '<div class="ribbon-wrapper">';
html += '<div class="ribbon ' + ribbonColor + '">';
html += format;
html += '</div>';
html += '</div>';
}
var style = ""; var style = "";
@ -722,8 +700,8 @@
html += LibraryBrowser.getPlayedIndicatorHtml(item); html += LibraryBrowser.getPlayedIndicatorHtml(item);
} }
if (item.AlternateVersionCount) { if (mediaVersionCount > 1) {
html += '<div class="alternateVersionIndicator">' + (item.AlternateVersionCount + 1) + '</div>'; html += '<div class="mediaVersionIndicator">' + mediaVersionCount + '</div>';
} }
if (item.IsUnidentified) { if (item.IsUnidentified) {
html += '<div class="unidentifiedIndicator"><div class="ui-icon-alert ui-btn-icon-notext"></div></div>'; html += '<div class="unidentifiedIndicator"><div class="ui-icon-alert ui-btn-icon-notext"></div></div>';

View file

@ -208,7 +208,9 @@
items.push({ type: 'link', text: 'Images', url: 'edititemimages.html?id=' + id }); items.push({ type: 'link', text: 'Images', url: 'edititemimages.html?id=' + id });
if (elem.getAttribute('data-alternateversioncount') != '0') { var versionCount = parseInt(elem.getAttribute('data-mediaversioncount') || '0');
if (versionCount > 1) {
items.push({ type: 'divider' }); items.push({ type: 'divider' });
items.push({ type: 'header', text: 'Manage' }); items.push({ type: 'header', text: 'Manage' });

View file

@ -8,12 +8,12 @@
SortBy: defaultSortBy, SortBy: defaultSortBy,
SortOrder: "Ascending", SortOrder: "Ascending",
Recursive: true, Recursive: true,
Fields: "MediaStreams,DateCreated,Settings,Studios", Fields: "MediaVersions,DateCreated,Settings,Studios",
StartIndex: 0, StartIndex: 0,
IncludeItemTypes: "Movie", IncludeItemTypes: "Movie",
IsMissing: false, IsMissing: false,
IsVirtualUnaired: false, IsVirtualUnaired: false,
Limit: 300, Limit: 200,
CollapseBoxSetItems: false CollapseBoxSetItems: false
}; };
@ -214,6 +214,12 @@
var stream; var stream;
var primaryVersion = (item.MediaVersions || []).filter(function(v) {
return v.IsPrimaryVersion;
})[0] || {};
var mediaStreams = primaryVersion.MediaStreams || [];
switch (cell.type || cell.name) { switch (cell.type || cell.name) {
case 'Album Artist': case 'Album Artist':
@ -258,7 +264,7 @@
} }
case 'Audio': case 'Audio':
{ {
stream = (item.MediaStreams || []).filter(function (s) { stream = mediaStreams.filter(function (s) {
return s.Type == 'Audio'; return s.Type == 'Audio';
@ -273,7 +279,7 @@
} }
case 'Video': case 'Video':
{ {
stream = (item.MediaStreams || []).filter(function (s) { stream = mediaStreams.filter(function (s) {
return s.Type == 'Video'; return s.Type == 'Video';
@ -286,7 +292,7 @@
} }
case 'Resolution': case 'Resolution':
{ {
stream = (item.MediaStreams || []).filter(function (s) { stream = mediaStreams.filter(function (s) {
return s.Type == 'Video'; return s.Type == 'Video';
@ -299,7 +305,7 @@
} }
case 'Embedded Image': case 'Embedded Image':
{ {
if ((item.MediaStreams || []).filter(function (s) { if (mediaStreams.filter(function (s) {
return s.Type == 'Video'; return s.Type == 'Video';
@ -310,7 +316,7 @@
} }
case 'Subtitles': case 'Subtitles':
{ {
var hasSubtitles = (item.MediaStreams || []).filter(function (s) { var hasSubtitles = mediaStreams.filter(function (s) {
return s.Type == 'Subtitle'; return s.Type == 'Subtitle';

View file

@ -1,5 +1,5 @@
(function () { (function () {
videoPlayer = function(mediaPlayer, item, startPosition, user) { videoPlayer = function (mediaPlayer, item, mediaVersion, startPosition, user) {
if (mediaPlayer == null) { if (mediaPlayer == null) {
throw new Error("mediaPlayer cannot be null"); throw new Error("mediaPlayer cannot be null");
} }
@ -15,15 +15,15 @@
var self = mediaPlayer; var self = mediaPlayer;
var currentItem; var currentItem;
var currentMediaVersion;
var timeout; var timeout;
var video; var video;
var culturesPromise;
var initialVolume; var initialVolume;
var fullscreenExited = false; var fullscreenExited = false;
var idleState = true; var idleState = true;
self.initVideoPlayer = function () { self.initVideoPlayer = function () {
video = playVideo(item, startPosition, user); video = playVideo(item, mediaVersion, startPosition, user);
return video; return video;
}; };
@ -47,7 +47,7 @@
$(".ui-loader").hide(); $(".ui-loader").hide();
}; };
self.exitFullScreen = function() { self.exitFullScreen = function () {
if (document.exitFullscreen) { if (document.exitFullscreen) {
document.exitFullscreen(); document.exitFullscreen();
} else if (document.mozExitFullScreen) { } else if (document.mozExitFullScreen) {
@ -61,7 +61,7 @@
fullscreenExited = true; fullscreenExited = true;
}; };
self.isFullScreen = function() { self.isFullScreen = function () {
return document.fullscreen || document.mozFullScreen || document.webkitIsFullScreen || document.msFullscreenElement ? true : false; return document.fullscreen || document.mozFullScreen || document.webkitIsFullScreen || document.msFullscreenElement ? true : false;
}; };
@ -71,15 +71,8 @@
if (!flyout.is(':visible')) { if (!flyout.is(':visible')) {
culturesPromise = culturesPromise || ApiClient.getCultures(); flyout.html(getSubtitleTracksHtml()).trigger('create').scrollTop(0);
toggleFlyout(flyout, '#video-subtitleButton');
$("html").css("cursor", "progress");
culturesPromise.done(function (cultures) {
$("html").css("cursor", "default");
flyout.html(getSubtitleTracksHtml(currentItem, cultures)).trigger('create').scrollTop(0);
toggleFlyout(flyout, '#video-subtitleButton');
});
} else { } else {
toggleFlyout(flyout, '#video-subtitleButton'); toggleFlyout(flyout, '#video-subtitleButton');
@ -91,7 +84,7 @@
var flyout = $('#video-qualityFlyout'); var flyout = $('#video-qualityFlyout');
if (!flyout.is(':visible')) { if (!flyout.is(':visible')) {
flyout.html(getQualityFlyoutHtml(currentItem)).scrollTop(0); flyout.html(getQualityFlyoutHtml()).scrollTop(0);
} }
toggleFlyout(flyout, '#video-qualityButton'); toggleFlyout(flyout, '#video-qualityButton');
@ -102,7 +95,7 @@
var flyout = $('#video-chaptersFlyout'); var flyout = $('#video-chaptersFlyout');
if (!flyout.is(':visible')) { if (!flyout.is(':visible')) {
flyout.html(getChaptersFlyoutHtml(currentItem)).scrollTop(0); flyout.html(getChaptersFlyoutHtml()).scrollTop(0);
} }
toggleFlyout(flyout, '#video-chaptersButton'); toggleFlyout(flyout, '#video-chaptersButton');
@ -114,15 +107,8 @@
if (!flyout.is(':visible')) { if (!flyout.is(':visible')) {
culturesPromise = culturesPromise || ApiClient.getCultures(); flyout.html(getAudioTracksHtml()).trigger('create').scrollTop(0);
toggleFlyout(flyout, '#video-audioTracksButton');
$("html").css("cursor", "progress");
culturesPromise.done(function (cultures) {
$("html").css("cursor", "default");
flyout.html(getAudioTracksHtml(currentItem, cultures)).trigger('create').scrollTop(0);
toggleFlyout(flyout, '#video-audioTracksButton');
});
} else { } else {
toggleFlyout(flyout, '#video-audioTracksButton'); toggleFlyout(flyout, '#video-audioTracksButton');
} }
@ -295,13 +281,13 @@
$(document.body).off("mousedown.hidesearchhints"); $(document.body).off("mousedown.hidesearchhints");
}; };
function getChaptersFlyoutHtml(item) { function getChaptersFlyoutHtml() {
var html = ''; var html = '';
var currentTicks = self.getCurrentTicks(); var currentTicks = self.getCurrentTicks();
var chapters = item.Chapters || []; var chapters = currentMediaVersion.Chapters || [];
for (var i = 0, length = chapters.length; i < length; i++) { for (var i = 0, length = chapters.length; i < length; i++) {
@ -326,7 +312,7 @@
if (chapter.ImageTag) { if (chapter.ImageTag) {
imgUrl = ApiClient.getImageUrl(item.Id, { imgUrl = ApiClient.getImageUrl(currentMediaVersion.ItemId, {
maxwidth: 200, maxwidth: 200,
tag: chapter.ImageTag, tag: chapter.ImageTag,
type: "Chapter", type: "Chapter",
@ -354,10 +340,10 @@
return html; return html;
}; };
function getAudioTracksHtml(item, cultures) { function getAudioTracksHtml() {
var streams = item.MediaStreams.filter(function (i) { var streams = currentMediaVersion.MediaStreams.filter(function (currentStream) {
return i.Type == "Audio"; return currentStream.Type == "Audio";
}); });
var currentIndex = getParameterByName('AudioStreamIndex', video.currentSrc); var currentIndex = getParameterByName('AudioStreamIndex', video.currentSrc);
@ -378,20 +364,7 @@
html += '<div class="mediaFlyoutOptionContent">'; html += '<div class="mediaFlyoutOptionContent">';
var language = null; html += '<div class="mediaFlyoutOptionName">' + (stream.Language || 'Unknown language') + '</div>';
if (stream.Language && stream.Language != "und") {
var culture = cultures.filter(function (current) {
return current.ThreeLetterISOLanguageName.toLowerCase() == stream.Language.toLowerCase();
});
if (culture.length) {
language = culture[0].DisplayName;
}
}
html += '<div class="mediaFlyoutOptionName">' + (language || stream.Language || 'Unknown language') + '</div>';
var options = []; var options = [];
@ -437,10 +410,10 @@
return html; return html;
}; };
function getSubtitleTracksHtml(item, cultures) { function getSubtitleTracksHtml() {
var streams = item.MediaStreams.filter(function (i) { var streams = currentMediaVersion.MediaStreams.filter(function (currentStream) {
return i.Type == "Subtitle"; return currentStream.Type == "Subtitle";
}); });
var currentIndex = getParameterByName('SubtitleStreamIndex', video.currentSrc) || -1; var currentIndex = getParameterByName('SubtitleStreamIndex', video.currentSrc) || -1;
@ -470,25 +443,13 @@
html += '<div class="mediaFlyoutOptionContent">'; html += '<div class="mediaFlyoutOptionContent">';
var language = null;
var options = []; var options = [];
if (stream.Language == "Off") { if (stream.Language == "Off") {
language = "Off";
options.push('&nbsp;'); options.push('&nbsp;');
} }
else if (stream.Language && stream.Language != "und") {
var culture = cultures.filter(function (current) { html += '<div class="mediaFlyoutOptionName">' + (stream.Language || 'Unknown language') + '</div>';
return current.ThreeLetterISOLanguageName.toLowerCase() == stream.Language.toLowerCase();
});
if (culture.length) {
language = culture[0].DisplayName;
}
}
html += '<div class="mediaFlyoutOptionName">' + (language || 'Unknown language') + '</div>';
if (stream.Codec) { if (stream.Codec) {
options.push(stream.Codec); options.push(stream.Codec);
@ -524,7 +485,7 @@
return html; return html;
}; };
function getQualityFlyoutHtml(item) { function getQualityFlyoutHtml() {
var html = ''; var html = '';
@ -535,7 +496,7 @@
var currentAudioStreamIndex = getParameterByName('AudioStreamIndex', video.currentSrc); var currentAudioStreamIndex = getParameterByName('AudioStreamIndex', video.currentSrc);
var options = getVideoQualityOptions(item, currentAudioStreamIndex, transcodingExtension); var options = getVideoQualityOptions(currentMediaVersion.MediaStreams, currentAudioStreamIndex, transcodingExtension);
if (isStatic) { if (isStatic) {
options[0].name = "Direct"; options[0].name = "Direct";
@ -627,9 +588,9 @@
return audioStreams.length ? audioStreams[0].Index : null; return audioStreams.length ? audioStreams[0].Index : null;
}; };
function getVideoQualityOptions(item) { function getVideoQualityOptions(mediaStreams) {
var videoStream = (item.MediaStreams || []).filter(function (stream) { var videoStream = mediaStreams.filter(function (stream) {
return stream.Type == "Video"; return stream.Type == "Video";
})[0]; })[0];
@ -703,9 +664,9 @@
return options; return options;
}; };
function playVideo(item, startPosition, user) { function playVideo(item, mediaVersion, startPosition, user) {
var mediaStreams = item.MediaStreams || []; var mediaStreams = mediaVersion.MediaStreams || [];
var baseParams = { var baseParams = {
audioChannels: 2, audioChannels: 2,
@ -716,20 +677,20 @@
Static: false Static: false
}; };
var mp4Quality = getVideoQualityOptions(item).filter(function (opt) { var mp4Quality = getVideoQualityOptions(mediaStreams).filter(function (opt) {
return opt.selected; return opt.selected;
})[0]; })[0];
mp4Quality = $.extend(mp4Quality, self.getFinalVideoParams(item, mp4Quality.maxWidth, mp4Quality.bitrate, baseParams.AudioStreamIndex, baseParams.SubtitleStreamIndex, '.mp4')); mp4Quality = $.extend(mp4Quality, self.getFinalVideoParams(mediaVersion, mp4Quality.maxWidth, mp4Quality.bitrate, baseParams.AudioStreamIndex, baseParams.SubtitleStreamIndex, '.mp4'));
var webmQuality = getVideoQualityOptions(item).filter(function (opt) { var webmQuality = getVideoQualityOptions(mediaStreams).filter(function (opt) {
return opt.selected; return opt.selected;
})[0]; })[0];
webmQuality = $.extend(webmQuality, self.getFinalVideoParams(item, webmQuality.maxWidth, webmQuality.bitrate, baseParams.AudioStreamIndex, baseParams.SubtitleStreamIndex, '.webm')); webmQuality = $.extend(webmQuality, self.getFinalVideoParams(mediaVersion, webmQuality.maxWidth, webmQuality.bitrate, baseParams.AudioStreamIndex, baseParams.SubtitleStreamIndex, '.webm'));
var m3U8Quality = getVideoQualityOptions(item).filter(function (opt) { var m3U8Quality = getVideoQualityOptions(mediaStreams).filter(function (opt) {
return opt.selected; return opt.selected;
})[0]; })[0];
m3U8Quality = $.extend(m3U8Quality, self.getFinalVideoParams(item, mp4Quality.maxWidth, mp4Quality.bitrate, baseParams.AudioStreamIndex, baseParams.SubtitleStreamIndex, '.mp4')); m3U8Quality = $.extend(m3U8Quality, self.getFinalVideoParams(mediaVersion, 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 // Webm must be ahead of mp4 due to the issue of mp4 playing too fast in chrome
var prioritizeWebmOverH264 = $.browser.chrome || $.browser.msie; var prioritizeWebmOverH264 = $.browser.chrome || $.browser.msie;
@ -740,7 +701,7 @@
var seekParam = isStatic && startPosition ? '#t=' + (startPosition / 10000000) : ''; var seekParam = isStatic && startPosition ? '#t=' + (startPosition / 10000000) : '';
var mp4VideoUrl = ApiClient.getUrl('Videos/' + item.Id + '/stream.mp4', $.extend({}, baseParams, { var mp4VideoUrl = ApiClient.getUrl('Videos/' + mediaVersion.ItemId + '/stream.mp4', $.extend({}, baseParams, {
profile: 'baseline', profile: 'baseline',
level: 3, level: 3,
Static: isStatic, Static: isStatic,
@ -752,7 +713,7 @@
})) + seekParam; })) + seekParam;
var webmVideoUrl = ApiClient.getUrl('Videos/' + item.Id + '/stream.webm', $.extend({}, baseParams, { var webmVideoUrl = ApiClient.getUrl('Videos/' + mediaVersion.ItemId + '/stream.webm', $.extend({}, baseParams, {
VideoCodec: 'vpx', VideoCodec: 'vpx',
AudioCodec: 'Vorbis', AudioCodec: 'Vorbis',
@ -762,7 +723,7 @@
})) + seekParam; })) + seekParam;
var hlsVideoUrl = ApiClient.getUrl('Videos/' + item.Id + '/stream.m3u8', $.extend({}, baseParams, { var hlsVideoUrl = ApiClient.getUrl('Videos/' + mediaVersion.ItemId + '/stream.m3u8', $.extend({}, baseParams, {
profile: 'baseline', profile: 'baseline',
level: 3, level: 3,
timeStampOffsetMs: 0, timeStampOffsetMs: 0,
@ -842,7 +803,7 @@
$('#video-subtitleButton', videoControls).hide(); $('#video-subtitleButton', videoControls).hide();
} }
if (item.Chapters && item.Chapters.length) { if (mediaVersion.Chapters && mediaVersion.Chapters.length) {
$('#video-chaptersButton', videoControls).show(); $('#video-chaptersButton', videoControls).show();
} else { } else {
$('#video-chaptersButton', videoControls).hide(); $('#video-chaptersButton', videoControls).hide();
@ -889,9 +850,9 @@
videoElement.off("playing.once"); videoElement.off("playing.once");
ApiClient.reportPlaybackStart(Dashboard.getCurrentUserId(), item.Id, true, item.MediaType); ApiClient.reportPlaybackStart(Dashboard.getCurrentUserId(), mediaVersion.ItemId, true, item.MediaType);
self.startProgressInterval(item.Id); self.startProgressInterval(mediaVersion.ItemId);
}).on("pause", function (e) { }).on("pause", function (e) {
@ -1007,6 +968,7 @@
fullscreenExited = false; fullscreenExited = false;
currentItem = item; currentItem = item;
currentMediaVersion = mediaVersion;
return videoElement[0]; return videoElement[0];
}; };

View file

@ -8,6 +8,7 @@
var currentMediaElement; var currentMediaElement;
var currentProgressInterval; var currentProgressInterval;
var currentItem; var currentItem;
var currentMediaVersion;
var curentDurationTicks; var curentDurationTicks;
var canClientSeek; var canClientSeek;
var currentPlaylistIndex = 0; var currentPlaylistIndex = 0;
@ -53,7 +54,7 @@
var position = Math.floor(10000000 * endTime) + self.startTimeTicksOffset; var position = Math.floor(10000000 * endTime) + self.startTimeTicksOffset;
ApiClient.reportPlaybackStopped(Dashboard.getCurrentUserId(), currentItem.Id, position); ApiClient.reportPlaybackStopped(Dashboard.getCurrentUserId(), currentMediaVersion.ItemId, position);
if (currentItem.MediaType == "Video") { if (currentItem.MediaType == "Video") {
ApiClient.stopActiveEncodings(); ApiClient.stopActiveEncodings();
@ -135,7 +136,7 @@
var transcodingExtension = self.getTranscodingExtension(); var transcodingExtension = self.getTranscodingExtension();
var finalParams = self.getFinalVideoParams(currentItem, maxWidth, bitrate, audioStreamIndex, subtitleStreamIndex, transcodingExtension); var finalParams = self.getFinalVideoParams(currentMediaVersion, maxWidth, bitrate, audioStreamIndex, subtitleStreamIndex, transcodingExtension);
currentSrc = replaceQueryString(currentSrc, 'MaxWidth', finalParams.maxWidth); currentSrc = replaceQueryString(currentSrc, 'MaxWidth', finalParams.maxWidth);
currentSrc = replaceQueryString(currentSrc, 'VideoBitrate', finalParams.videoBitrate); currentSrc = replaceQueryString(currentSrc, 'VideoBitrate', finalParams.videoBitrate);
currentSrc = replaceQueryString(currentSrc, 'AudioBitrate', finalParams.audioBitrate); currentSrc = replaceQueryString(currentSrc, 'AudioBitrate', finalParams.audioBitrate);
@ -155,8 +156,8 @@
$(this).off('play.onceafterseek').on('ended.playbackstopped', self.onPlaybackStopped).on('ended.playnext', self.playNextAfterEnded); $(this).off('play.onceafterseek').on('ended.playbackstopped', self.onPlaybackStopped).on('ended.playnext', self.playNextAfterEnded);
self.startProgressInterval(currentItem.Id); self.startProgressInterval(currentMediaVersion.ItemId);
sendProgressUpdate(currentItem.Id); sendProgressUpdate(currentMediaVersion.ItemId);
}); });
@ -193,9 +194,9 @@
self.currentTimeElement.html(timeText); self.currentTimeElement.html(timeText);
}; };
self.canPlayVideoDirect = function (item, videoStream, audioStream, subtitleStream, maxWidth, bitrate) { self.canPlayVideoDirect = function (mediaVersion, videoStream, audioStream, subtitleStream, maxWidth, bitrate) {
if (item.VideoType != "VideoFile" || item.LocationType != "FileSystem") { if (mediaVersion.VideoType != "VideoFile" || mediaVersion.LocationType != "FileSystem") {
console.log('Transcoding because the content is not a video file'); console.log('Transcoding because the content is not a video file');
return false; return false;
} }
@ -228,7 +229,7 @@
return false; return false;
} }
var extension = item.Path.substring(item.Path.lastIndexOf('.') + 1).toLowerCase(); var extension = mediaVersion.Path.substring(mediaVersion.Path.lastIndexOf('.') + 1).toLowerCase();
if (extension == 'm4v') { if (extension == 'm4v') {
return $.browser.chrome; return $.browser.chrome;
@ -237,28 +238,29 @@
return extension.toLowerCase() == 'mp4'; return extension.toLowerCase() == 'mp4';
}; };
self.getFinalVideoParams = function (item, maxWidth, bitrate, audioStreamIndex, subtitleStreamIndex, transcodingExtension) { self.getFinalVideoParams = function (mediaVersion, maxWidth, bitrate, audioStreamIndex, subtitleStreamIndex, transcodingExtension) {
var videoStream = (item.MediaStreams || []).filter(function (stream) { var mediaStreams = mediaVersion.MediaStreams;
var videoStream = mediaStreams.filter(function (stream) {
return stream.Type === "Video"; return stream.Type === "Video";
})[0]; })[0];
var audioStream = (item.MediaStreams || []).filter(function (stream) { var audioStream = mediaStreams.filter(function (stream) {
return stream.Index === audioStreamIndex; return stream.Index === audioStreamIndex;
})[0]; })[0];
var subtitleStream = (item.MediaStreams || []).filter(function (stream) { var subtitleStream = mediaStreams.filter(function (stream) {
return stream.Index === subtitleStreamIndex; return stream.Index === subtitleStreamIndex;
})[0]; })[0];
var canPlayDirect = self.canPlayVideoDirect(item, videoStream, audioStream, subtitleStream, maxWidth, bitrate); var canPlayDirect = self.canPlayVideoDirect(mediaVersion, videoStream, audioStream, subtitleStream, maxWidth, bitrate);
var audioBitrate = bitrate >= 700000 ? 128000 : 64000; var audioBitrate = bitrate >= 700000 ? 128000 : 64000;
var videoBitrate = bitrate - audioBitrate; var videoBitrate = bitrate - audioBitrate;
return { return {
isStatic: canPlayDirect, isStatic: canPlayDirect,
maxWidth: maxWidth, maxWidth: maxWidth,
audioCodec: transcodingExtension == '.webm' ? 'vorbis' : 'aac', audioCodec: transcodingExtension == '.webm' ? 'vorbis' : 'aac',
@ -266,7 +268,7 @@
audioBitrate: audioBitrate, audioBitrate: audioBitrate,
videoBitrate: videoBitrate videoBitrate: videoBitrate
}; };
} };
self.canPlay = function (item, user) { self.canPlay = function (item, user) {
@ -397,6 +399,13 @@
self.playlist = items; self.playlist = items;
currentPlaylistIndex = 0; currentPlaylistIndex = 0;
}; };
function getOptimalMediaVersion(versions) {
// TODO: Implement
return versions[0];
}
self.playInternal = function (item, startPosition, user) { self.playInternal = function (item, startPosition, user) {
@ -414,17 +423,25 @@
if (item.MediaType === "Video") { if (item.MediaType === "Video") {
videoPlayer(self, item, startPosition, user);
mediaElement = self.initVideoPlayer();
currentItem = item; currentItem = item;
curentDurationTicks = item.RunTimeTicks; currentMediaVersion = getOptimalMediaVersion(item.MediaVersions);
videoPlayer(self, item, currentMediaVersion, startPosition, user);
mediaElement = self.initVideoPlayer();
curentDurationTicks = currentMediaVersion.RunTimeTicks;
mediaControls = $("#videoControls"); mediaControls = $("#videoControls");
} else if (item.MediaType === "Audio") { } else if (item.MediaType === "Audio") {
mediaElement = playAudio(item, startPosition); currentItem = item;
currentMediaVersion = getOptimalMediaVersion(item.MediaVersions);
mediaElement = playAudio(item, currentMediaVersion, startPosition);
mediaControls.show(); mediaControls.show();
curentDurationTicks = currentMediaVersion.RunTimeTicks;
} else { } else {
throw new Error("Unrecognized media type"); throw new Error("Unrecognized media type");
} }
@ -917,7 +934,7 @@
var position = Math.floor(10000000 * endTime) + self.startTimeTicksOffset; var position = Math.floor(10000000 * endTime) + self.startTimeTicksOffset;
ApiClient.reportPlaybackStopped(Dashboard.getCurrentUserId(), currentItem.Id, position); ApiClient.reportPlaybackStopped(Dashboard.getCurrentUserId(), currentMediaVersion.ItemId, position);
} }
}); });
@ -968,7 +985,7 @@
var newPercent = parseInt(this.value); var newPercent = parseInt(this.value);
var newPositionTicks = (newPercent / 100) * currentItem.RunTimeTicks; var newPositionTicks = (newPercent / 100) * currentMediaVersion.RunTimeTicks;
self.changeStream(Math.floor(newPositionTicks)); self.changeStream(Math.floor(newPositionTicks));
}; };
@ -982,7 +999,7 @@
return d >= 0 && text.lastIndexOf(pattern) === d; return d >= 0 && text.lastIndexOf(pattern) === d;
}; };
function playAudio(item, startPositionTicks) { function playAudio(item, mediaVersion, startPositionTicks) {
startPositionTicks = startPositionTicks || 0; startPositionTicks = startPositionTicks || 0;
@ -992,19 +1009,19 @@
StartTimeTicks: startPositionTicks StartTimeTicks: startPositionTicks
}; };
var mp3Url = ApiClient.getUrl('Audio/' + item.Id + '/stream.mp3', $.extend({}, baseParams, { var mp3Url = ApiClient.getUrl('Audio/' + mediaVersion.ItemId + '/stream.mp3', $.extend({}, baseParams, {
audioCodec: 'mp3' audioCodec: 'mp3'
})); }));
var aacUrl = ApiClient.getUrl('Audio/' + item.Id + '/stream.aac', $.extend({}, baseParams, { var aacUrl = ApiClient.getUrl('Audio/' + mediaVersion.ItemId + '/stream.aac', $.extend({}, baseParams, {
audioCodec: 'aac' audioCodec: 'aac'
})); }));
var webmUrl = ApiClient.getUrl('Audio/' + item.Id + '/stream.webm', $.extend({}, baseParams, { var webmUrl = ApiClient.getUrl('Audio/' + mediaVersion.ItemId + '/stream.webm', $.extend({}, baseParams, {
audioCodec: 'Vorbis' audioCodec: 'Vorbis'
})); }));
var mediaStreams = item.MediaStreams || []; var mediaStreams = mediaVersion.MediaStreams;
var isStatic = false; var isStatic = false;
var seekParam = isStatic && startPositionTicks ? '#t=' + (startPositionTicks / 10000000) : ''; var seekParam = isStatic && startPositionTicks ? '#t=' + (startPositionTicks / 10000000) : '';
@ -1091,9 +1108,9 @@
audioElement.off("play.once"); audioElement.off("play.once");
ApiClient.reportPlaybackStart(Dashboard.getCurrentUserId(), item.Id, true, item.MediaType); ApiClient.reportPlaybackStart(Dashboard.getCurrentUserId(), mediaVersion.ItemId, true, item.MediaType);
self.startProgressInterval(item.Id); self.startProgressInterval(mediaVersion.ItemId);
}).on("pause", function () { }).on("pause", function () {
@ -1114,9 +1131,6 @@
}).on("ended.playbackstopped", self.onPlaybackStopped).on('ended.playnext', self.playNextAfterEnded); }).on("ended.playbackstopped", self.onPlaybackStopped).on('ended.playnext', self.playNextAfterEnded);
currentItem = item;
curentDurationTicks = item.RunTimeTicks;
return audioElement[0]; return audioElement[0];
}; };

View file

@ -299,18 +299,6 @@
resumeButtonContainer.show(); resumeButtonContainer.show();
} }
} }
else if (value == "PlayFromChapter" && item.Chapters && item.Chapters.length) {
playFromMenu.show();
playButtonContainer.show();
if (!playFromRendered) {
playFromRendered = true;
renderPlayFromOptions(playFromMenu, item);
}
popup.popup("reposition", { tolerance: 0 });
}
else if (value == "Trailer") { else if (value == "Trailer") {
trailersElem.show(); trailersElem.show();
@ -384,65 +372,6 @@
}); });
} }
function renderPlayFromOptions(elem, item) {
var html = '';
html += '<h4 style="margin: 1em 0 .5em;">Play from scene</h4>';
html += '<div class="playMenuOptions">';
html += '<table class="tblRemoteControl tblRemoteControlNoHeader">';
html += '<tbody>';
for (var i = 0, length = item.Chapters.length; i < length; i++) {
var chapter = item.Chapters[i];
html += '<tr class="trSelectPlayTime" data-ticks="' + chapter.StartPositionTicks + '">';
var name = chapter.Name || ("Chapter " + (i + 1));
html += '<td class="tdSelectPlayTime"></td>';
html += '<td class="tdRemoteControlImage">';
var imgUrl;
if (chapter.ImageTag) {
imgUrl = ApiClient.getImageUrl(item.Id, {
maxheight: 80,
tag: chapter.ImageTag,
type: "Chapter",
index: i
});
} else {
imgUrl = "css/images/media/chapterflyout.png";
}
html += '<img src="' + imgUrl + '" />';
html += '</td>';
html += '<td>' + name + '<br/>' + Dashboard.getDisplayTime(chapter.StartPositionTicks) + '</td>';
html += '</tr>';
}
html += '</tbody>';
html += '</table>';
html += '</div>';
elem.html(html);
$('.tdSelectPlayTime', elem).html('<input type="radio" class="chkSelectPlayTime" name="chkSelectPlayTime" />');
$('.chkSelectPlayTime:first', elem).checked(true);
}
function renderSessionsInPlayMenu(sessions, options, elem, popup) { function renderSessionsInPlayMenu(sessions, options, elem, popup) {
if (!sessions.length) { if (!sessions.length) {
@ -476,10 +405,6 @@
html += '<option value="Play" selected>' + playLabel + '</label>'; html += '<option value="Play" selected>' + playLabel + '</label>';
if (item.Chapters && item.Chapters.length) {
html += '<option value="PlayFromChapter">Play from scene</label>';
}
if (item.LocalTrailerCount) { if (item.LocalTrailerCount) {
html += '<option value="Trailer">Play trailer</label>'; html += '<option value="Trailer">Play trailer</label>';
} }