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:
parent
902d3a3649
commit
02a810cf1e
12 changed files with 163 additions and 304 deletions
|
@ -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;
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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>';
|
||||||
|
|
|
@ -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' });
|
||||||
|
|
|
@ -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';
|
||||||
|
|
||||||
|
|
|
@ -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(' ');
|
options.push(' ');
|
||||||
}
|
}
|
||||||
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];
|
||||||
};
|
};
|
||||||
|
|
|
@ -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];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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>';
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue