mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
restored audio and subtitle menus
This commit is contained in:
parent
cd0260b41e
commit
8414228858
6 changed files with 245 additions and 35 deletions
BIN
dashboard-ui/css/images/media/audioflyout.png
Normal file
BIN
dashboard-ui/css/images/media/audioflyout.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
dashboard-ui/css/images/media/subtitleflyout.png
Normal file
BIN
dashboard-ui/css/images/media/subtitleflyout.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 789 B |
|
@ -663,7 +663,6 @@ progress {
|
|||
progress::-moz-progress-bar {
|
||||
border-radius: 5px;
|
||||
background-image: -moz-linear-gradient( center bottom, rgb(43,194,83) 37%, rgb(84,240,84) 69% );
|
||||
s;
|
||||
}
|
||||
|
||||
/* Chrome */
|
||||
|
@ -894,6 +893,10 @@ input[type="range"]::-ms-fill-upper {
|
|||
width: 250px;
|
||||
}
|
||||
|
||||
.audioTracksFlyout {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.mediaFlyoutOption {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
|
@ -912,13 +915,21 @@ input[type="range"]::-ms-fill-upper {
|
|||
|
||||
.mediaFlyoutOptionImage {
|
||||
display: inline-block;
|
||||
width: 40%;
|
||||
width: 15%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.mediaFlyoutOptionImage + .mediaFlyoutOptionContent {
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
width: 85%;
|
||||
}
|
||||
|
||||
.chaptersFlyout .mediaFlyoutOptionImage {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.chaptersFlyout .mediaFlyoutOptionImage + .mediaFlyoutOptionContent {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
|
|
|
@ -188,11 +188,11 @@ function humane_elapsed(firstDateStr, secondDateStr) {
|
|||
|
||||
}
|
||||
|
||||
function getParameterByName(name) {
|
||||
function getParameterByName(name, url) {
|
||||
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
|
||||
var regexS = "[\\?&]" + name + "=([^&#]*)";
|
||||
var regex = new RegExp(regexS);
|
||||
var results = regex.exec(window.location.search);
|
||||
var results = regex.exec(url || window.location.search);
|
||||
if (results == null)
|
||||
return "";
|
||||
else
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
var startTimeTicksOffset;
|
||||
var curentDurationTicks;
|
||||
var isStaticStream;
|
||||
var culturesPromise;
|
||||
|
||||
self.playing = '';
|
||||
self.queue = [];
|
||||
|
@ -69,6 +70,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
function getCurrentTicks(mediaElement) {
|
||||
return Math.floor(10000000 * (mediaElement || currentMediaElement).currentTime) + startTimeTicksOffset;
|
||||
}
|
||||
|
||||
function onPlaybackStopped() {
|
||||
|
||||
currentTimeElement.hide();
|
||||
|
@ -102,9 +107,8 @@
|
|||
}
|
||||
|
||||
function sendProgressUpdate(itemId) {
|
||||
var position = Math.floor(10000000 * currentMediaElement.currentTime) + startTimeTicksOffset;
|
||||
|
||||
ApiClient.reportPlaybackProgress(Dashboard.getCurrentUserId(), itemId, position);
|
||||
ApiClient.reportPlaybackProgress(Dashboard.getCurrentUserId(), itemId, getCurrentTicks());
|
||||
}
|
||||
|
||||
function clearProgressInterval() {
|
||||
|
@ -115,24 +119,27 @@
|
|||
}
|
||||
}
|
||||
|
||||
function seek(ticks) {
|
||||
function changeStream(ticks, params) {
|
||||
|
||||
var element = currentMediaElement;
|
||||
|
||||
if (isStaticStream) {
|
||||
if (isStaticStream && params == null) {
|
||||
|
||||
element.currentTime = ticks / (1000 * 10000);
|
||||
|
||||
} else {
|
||||
|
||||
params = params || {};
|
||||
|
||||
var currentSrc = element.currentSrc;
|
||||
|
||||
if (currentSrc.toLowerCase().indexOf('starttimeticks') == -1) {
|
||||
|
||||
currentSrc += "&starttimeticks=" + ticks;
|
||||
|
||||
} else {
|
||||
currentSrc = replaceQueryString(currentSrc, 'starttimeticks', ticks);
|
||||
|
||||
if (params.AudioStreamIndex != null) {
|
||||
currentSrc = replaceQueryString(currentSrc, 'AudioStreamIndex', params.AudioStreamIndex);
|
||||
}
|
||||
if (params.SubtitleStreamIndex != null) {
|
||||
currentSrc = replaceQueryString(currentSrc, 'SubtitleStreamIndex', params.SubtitleStreamIndex);
|
||||
}
|
||||
|
||||
clearProgressInterval();
|
||||
|
@ -158,7 +165,7 @@
|
|||
|
||||
var newPositionTicks = (newPercent / 100) * currentItem.RunTimeTicks;
|
||||
|
||||
seek(newPositionTicks);
|
||||
changeStream(newPositionTicks);
|
||||
}
|
||||
|
||||
$(function () {
|
||||
|
@ -213,10 +220,32 @@
|
|||
|
||||
var ticks = parseInt(this.getAttribute('data-positionticks'));
|
||||
|
||||
seek(ticks);
|
||||
changeStream(ticks);
|
||||
|
||||
hideFlyout($('#chaptersFlyout'));
|
||||
});
|
||||
|
||||
$('#audioTracksFlyout').on('click', '.mediaFlyoutOption', function () {
|
||||
|
||||
if (!$(this).hasClass('selectedMediaFlyoutOption')) {
|
||||
var index = parseInt(this.getAttribute('data-index'));
|
||||
|
||||
changeStream(getCurrentTicks(), { AudioStreamIndex: index });
|
||||
}
|
||||
|
||||
hideFlyout($('#audioTracksFlyout'));
|
||||
});
|
||||
|
||||
$('#subtitleFlyout').on('click', '.mediaFlyoutOption', function () {
|
||||
|
||||
if (!$(this).hasClass('selectedMediaFlyoutOption')) {
|
||||
var index = parseInt(this.getAttribute('data-index'));
|
||||
|
||||
changeStream(getCurrentTicks(), { SubtitleStreamIndex: index });
|
||||
}
|
||||
|
||||
hideFlyout($('#subtitleFlyout'));
|
||||
});
|
||||
});
|
||||
|
||||
function endsWith(text, pattern) {
|
||||
|
@ -385,9 +414,7 @@
|
|||
|
||||
if (!isPositionSliderActive) {
|
||||
|
||||
var ticks = startTimeTicksOffset + this.currentTime * 1000 * 10000;
|
||||
|
||||
setCurrentTime(ticks, item, true);
|
||||
setCurrentTime(getCurrentTicks(this), item, true);
|
||||
}
|
||||
|
||||
}).on("ended.playbackstopped", onPlaybackStopped);
|
||||
|
@ -484,6 +511,7 @@
|
|||
$('#mediaElement', nowPlayingBar).html(html);
|
||||
|
||||
$('#qualityButton', nowPlayingBar).show();
|
||||
|
||||
$('#audioTracksButton', nowPlayingBar).show();
|
||||
|
||||
if (item.MediaStreams.filter(function (i) {
|
||||
|
@ -552,9 +580,7 @@
|
|||
|
||||
if (!isPositionSliderActive) {
|
||||
|
||||
var ticks = startTimeTicksOffset + this.currentTime * 1000 * 10000;
|
||||
|
||||
setCurrentTime(ticks, item, true);
|
||||
setCurrentTime(getCurrentTicks(this), item, true);
|
||||
}
|
||||
|
||||
}).on("ended.playbackstopped", onPlaybackStopped);
|
||||
|
@ -569,10 +595,14 @@
|
|||
|
||||
function getInitialAudioStreamIndex(mediaStreams, user) {
|
||||
|
||||
var audioStreams = mediaStreams.filter(function (stream) {
|
||||
return stream.Type == "Audio";
|
||||
});
|
||||
|
||||
if (user.Configuration.AudioLanguagePreference) {
|
||||
|
||||
for (var i = 0, length = mediaStreams.length; i < length; i++) {
|
||||
var mediaStream = mediaStreams[i];
|
||||
for (var i = 0, length = audioStreams.length; i < length; i++) {
|
||||
var mediaStream = audioStreams[i];
|
||||
|
||||
if (mediaStream.Type == "Audio" && mediaStream.Language == user.Configuration.AudioLanguagePreference) {
|
||||
return mediaStream.Index;
|
||||
|
@ -581,7 +611,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
// Just use the first audio stream
|
||||
return audioStreams.length ? audioStreams[0].Index : null;
|
||||
}
|
||||
|
||||
function getInitialSubtitleStreamIndex(mediaStreams, user) {
|
||||
|
@ -951,7 +982,7 @@
|
|||
|
||||
var html = '';
|
||||
|
||||
var currentTicks = Math.floor(10000000 * currentMediaElement.currentTime) + startTimeTicksOffset;
|
||||
var currentTicks = getCurrentTicks();
|
||||
|
||||
for (var i = 0, length = item.Chapters.length; i < length; i++) {
|
||||
|
||||
|
@ -1004,14 +1035,174 @@
|
|||
return html;
|
||||
}
|
||||
|
||||
function getAudioTracksHtml(item, cultures) {
|
||||
|
||||
var streams = item.MediaStreams.filter(function (i) {
|
||||
return i.Type == "Audio";
|
||||
});
|
||||
|
||||
var currentIndex = getParameterByName('AudioStreamIndex', currentMediaElement.currentSrc);
|
||||
|
||||
var html = '';
|
||||
|
||||
for (var i = 0, length = streams.length; i < length; i++) {
|
||||
|
||||
var stream = streams[i];
|
||||
|
||||
if (stream.Index == currentIndex) {
|
||||
html += '<div data-index="' + stream.Index + '" class="mediaFlyoutOption selectedMediaFlyoutOption">';
|
||||
} else {
|
||||
html += '<div data-index="' + stream.Index + '" class="mediaFlyoutOption">';
|
||||
}
|
||||
|
||||
html += '<img class="mediaFlyoutOptionImage" src="css/images/media/audioflyout.png" />';
|
||||
|
||||
html += '<div class="mediaFlyoutOptionContent">';
|
||||
|
||||
var language = null;
|
||||
|
||||
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 || 'Unknown language') + '</div>';
|
||||
|
||||
var options = [];
|
||||
|
||||
if (stream.Codec) {
|
||||
options.push(stream.Codec);
|
||||
}
|
||||
if (stream.Profile) {
|
||||
options.push(stream.Profile);
|
||||
}
|
||||
|
||||
if (stream.BitRate) {
|
||||
options.push((parseInt(stream.BitRate / 1000)) + ' kbps');
|
||||
}
|
||||
|
||||
if (stream.Channels) {
|
||||
options.push(stream.Channels + ' ch');
|
||||
}
|
||||
|
||||
if (options.length) {
|
||||
html += '<div class="mediaFlyoutOptionSecondaryText">' + options.join(' • ') + '</div>';
|
||||
}
|
||||
|
||||
options = [];
|
||||
|
||||
if (stream.IsDefault) {
|
||||
options.push('Default');
|
||||
}
|
||||
if (stream.IsForced) {
|
||||
options.push('Forced');
|
||||
}
|
||||
|
||||
if (options.length) {
|
||||
html += '<div class="mediaFlyoutOptionSecondaryText">' + options.join(' • ') + '</div>';
|
||||
}
|
||||
|
||||
html += "</div>";
|
||||
|
||||
html += "</div>";
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function getSubtitleTracksHtml(item, cultures) {
|
||||
|
||||
var streams = item.MediaStreams.filter(function (i) {
|
||||
return i.Type == "Subtitle";
|
||||
});
|
||||
|
||||
var currentIndex = getParameterByName('SubtitleStreamIndex', currentMediaElement.currentSrc);
|
||||
|
||||
var html = '';
|
||||
|
||||
for (var i = 0, length = streams.length; i < length; i++) {
|
||||
|
||||
var stream = streams[i];
|
||||
|
||||
if (stream.Index == currentIndex) {
|
||||
html += '<div data-index="' + stream.Index + '" class="mediaFlyoutOption selectedMediaFlyoutOption">';
|
||||
} else {
|
||||
html += '<div data-index="' + stream.Index + '" class="mediaFlyoutOption">';
|
||||
}
|
||||
|
||||
html += '<img class="mediaFlyoutOptionImage" src="css/images/media/audioflyout.png" />';
|
||||
|
||||
html += '<div class="mediaFlyoutOptionContent">';
|
||||
|
||||
var language = null;
|
||||
|
||||
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 || 'Unknown language') + '</div>';
|
||||
|
||||
var options = [];
|
||||
|
||||
if (stream.Codec) {
|
||||
options.push(stream.Codec);
|
||||
}
|
||||
|
||||
if (options.length) {
|
||||
html += '<div class="mediaFlyoutOptionSecondaryText">' + options.join(' • ') + '</div>';
|
||||
}
|
||||
|
||||
options = [];
|
||||
|
||||
if (stream.IsDefault) {
|
||||
options.push('Default');
|
||||
}
|
||||
if (stream.IsForced) {
|
||||
options.push('Forced');
|
||||
}
|
||||
if (stream.IsExternal) {
|
||||
options.push('External');
|
||||
}
|
||||
|
||||
if (options.length) {
|
||||
html += '<div class="mediaFlyoutOptionSecondaryText">' + options.join(' • ') + '</div>';
|
||||
}
|
||||
|
||||
html += "</div>";
|
||||
|
||||
html += "</div>";
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
self.showAudioTracksFlyout = function () {
|
||||
|
||||
var flyout = $('#audioTracksFlyout');
|
||||
|
||||
if (!flyout.is(':visible')) {
|
||||
|
||||
culturesPromise = culturesPromise || ApiClient.getCultures();
|
||||
|
||||
culturesPromise.done(function (cultures) {
|
||||
|
||||
showFlyout(flyout, '#audioTracksButton');
|
||||
|
||||
flyout.html(getAudioTracksHtml(currentItem, cultures)).scrollTop(0);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1023,7 +1214,7 @@
|
|||
|
||||
showFlyout(flyout, '#chaptersButton');
|
||||
|
||||
flyout.html(getChaptersFlyoutHtml(currentItem));
|
||||
flyout.html(getChaptersFlyoutHtml(currentItem)).scrollTop(0);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1044,8 +1235,15 @@
|
|||
|
||||
if (!flyout.is(':visible')) {
|
||||
|
||||
culturesPromise = culturesPromise || ApiClient.getCultures();
|
||||
|
||||
culturesPromise.done(function (cultures) {
|
||||
|
||||
showFlyout(flyout, '#subtitleButton');
|
||||
|
||||
flyout.html(getSubtitleTracksHtml(currentItem, cultures)).scrollTop(0);
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1118,19 +1118,20 @@ $(function () {
|
|||
footerHtml += '<button id="muteButton" onclick="MediaPlayer.mute();" class="imageButton mediaButton volumeButton" title="Volume" type="button"><img src="css/images/media/volume.png" /></button>';
|
||||
footerHtml += '<button id="unmuteButton" onclick="MediaPlayer.unmute();" class="imageButton mediaButton volumeButton" title="Volume" type="button"><img src="css/images/media/mute.png" /></button>';
|
||||
footerHtml += '<input type="range" class="mediaSlider volumeSlider" step=".05" min="0" max="1" value="0" />';
|
||||
footerHtml += '<button onclick="MediaPlayer.toggleFullscreen();" id="fullscreenButton" class="imageButton mediaButton fullscreenButton" title="Fullscreen" type="button"><img src="css/images/media/fullscreen.png" /></button>';
|
||||
|
||||
footerHtml += '<button onclick="MediaPlayer.showQualityFlyout();" id="qualityButton" class="imageButton mediaButton qualityButton" title="Quality" type="button"><img src="css/images/media/quality.png" /></button>';
|
||||
footerHtml += '<div class="mediaFlyoutContainer"><div id="qualityFlyout" style="display:none;" class="mediaPlayerFlyout">Coming soon</div></div>';
|
||||
footerHtml += '<div class="mediaFlyoutContainer"><div id="qualityFlyout" style="display:none;" class="mediaPlayerFlyout"></div></div>';
|
||||
|
||||
footerHtml += '<button onclick="MediaPlayer.showAudioTracksFlyout();" id="audioTracksButton" class="imageButton mediaButton audioTracksButton" title="Audio tracks" type="button"><img src="css/images/media/audiotrack.png" /></button>';
|
||||
footerHtml += '<div class="mediaFlyoutContainer"><div id="audioTracksFlyout" style="display:none;" class="mediaPlayerFlyout">Coming soon</div></div>';
|
||||
footerHtml += '<div class="mediaFlyoutContainer"><div id="audioTracksFlyout" style="display:none;" class="mediaPlayerFlyout audioTracksFlyout"></div></div>';
|
||||
|
||||
footerHtml += '<button onclick="MediaPlayer.showSubtitleMenu();" id="subtitleButton" class="imageButton mediaButton subtitleButton" title="Subtitles" type="button"><img src="css/images/media/subtitles.png" /></button>';
|
||||
footerHtml += '<div class="mediaFlyoutContainer"><div id="subtitleFlyout" style="display:none;" class="mediaPlayerFlyout">Coming soon</div></div>';
|
||||
footerHtml += '<div class="mediaFlyoutContainer"><div id="subtitleFlyout" style="display:none;" class="mediaPlayerFlyout subtitleFlyout"></div></div>';
|
||||
|
||||
footerHtml += '<button onclick="MediaPlayer.showChaptersFlyout();" id="chaptersButton" class="imageButton mediaButton chaptersButton" title="Scenes" type="button"><img src="css/images/media/chapters.png" /></button>';
|
||||
footerHtml += '<div class="mediaFlyoutContainer"><div id="chaptersFlyout" style="display:none;" class="mediaPlayerFlyout chaptersFlyout">Coming soon</div></div>';
|
||||
footerHtml += '<div class="mediaFlyoutContainer"><div id="chaptersFlyout" style="display:none;" class="mediaPlayerFlyout chaptersFlyout"></div></div>';
|
||||
|
||||
footerHtml += '<button onclick="MediaPlayer.toggleFullscreen();" id="fullscreenButton" class="imageButton mediaButton fullscreenButton" title="Fullscreen" type="button"><img src="css/images/media/fullscreen.png" /></button>';
|
||||
|
||||
footerHtml += '</div>';
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue