mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
fix audio tracks
This commit is contained in:
parent
08122a5e93
commit
b3d91930d3
6 changed files with 154 additions and 17 deletions
|
@ -358,4 +358,23 @@ video::-webkit-media-text-track-background {
|
||||||
#videoPlayer:not(.idlePlayer) video:not([controls])::-webkit-media-text-track-display {
|
#videoPlayer:not(.idlePlayer) video:not([controls])::-webkit-media-text-track-display {
|
||||||
/*Style the text itself*/
|
/*Style the text itself*/
|
||||||
margin-top: -2.5em;
|
margin-top: -2.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.videoSubtitles {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 99997;
|
||||||
|
bottom: 10%;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 400%;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.videoSubtitlesInner {
|
||||||
|
max-width: 70%;
|
||||||
|
background-color: rgba(0,0,0,.8);
|
||||||
|
padding: .25em;
|
||||||
|
margin: auto;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
|
@ -1189,6 +1189,13 @@ paper-input + .fieldDescription {
|
||||||
margin-bottom: 30px !important;
|
margin-bottom: 30px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ui-content {
|
||||||
|
border-width: 0;
|
||||||
|
overflow: visible;
|
||||||
|
overflow-x: hidden;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
.page > .ui-content, .pageWithAbsoluteTabs .pageTabContent {
|
.page > .ui-content, .pageWithAbsoluteTabs .pageTabContent {
|
||||||
/* Need this so that the audio player doesn't cover content, but also for unveil lazy loading. */
|
/* Need this so that the audio player doesn't cover content, but also for unveil lazy loading. */
|
||||||
padding-bottom: 160px;
|
padding-bottom: 160px;
|
||||||
|
|
|
@ -242,3 +242,7 @@ div.cardBox {
|
||||||
.localSyncStatus .labelSyncStatus {
|
.localSyncStatus .labelSyncStatus {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.videoSubtitles {
|
||||||
|
font-size: 300%;
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
function onEnded() {
|
function onEnded() {
|
||||||
|
destroyCustomTrack();
|
||||||
Events.trigger(self, 'ended');
|
Events.trigger(self, 'ended');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +32,7 @@
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
updateSubtitleText(this.currentTime * 1000);
|
||||||
|
|
||||||
Events.trigger(self, 'timeupdate');
|
Events.trigger(self, 'timeupdate');
|
||||||
}
|
}
|
||||||
|
@ -68,6 +70,8 @@
|
||||||
|
|
||||||
function onError(e) {
|
function onError(e) {
|
||||||
|
|
||||||
|
destroyCustomTrack();
|
||||||
|
|
||||||
var elem = e.target;
|
var elem = e.target;
|
||||||
var errorCode = elem.error ? elem.error.code : '';
|
var errorCode = elem.error ? elem.error.code : '';
|
||||||
console.log('Media element error code: ' + errorCode);
|
console.log('Media element error code: ' + errorCode);
|
||||||
|
@ -271,6 +275,9 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
self.stop = function () {
|
self.stop = function () {
|
||||||
|
|
||||||
|
destroyCustomTrack();
|
||||||
|
|
||||||
if (mediaElement) {
|
if (mediaElement) {
|
||||||
mediaElement.pause();
|
mediaElement.pause();
|
||||||
|
|
||||||
|
@ -421,6 +428,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
function setTracks(elem, tracks) {
|
function setTracks(elem, tracks) {
|
||||||
|
|
||||||
var html = tracks.map(function (t) {
|
var html = tracks.map(function (t) {
|
||||||
|
|
||||||
var defaultAttribute = t.isDefault ? ' default' : '';
|
var defaultAttribute = t.isDefault ? ' default' : '';
|
||||||
|
@ -430,9 +438,7 @@
|
||||||
|
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|
||||||
if (html) {
|
elem.innerHTML = html;
|
||||||
elem.innerHTML = html;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.currentSrc = function () {
|
self.currentSrc = function () {
|
||||||
|
@ -503,20 +509,127 @@
|
||||||
return supportsTextTracks;
|
return supportsTextTracks;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function enableNativeTrackSupport(track) {
|
||||||
|
|
||||||
|
if (browserInfo.safari) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroyCustomTrack() {
|
||||||
|
|
||||||
|
var videoSubtitlesElem = document.querySelector('.videoSubtitles');
|
||||||
|
if (videoSubtitlesElem) {
|
||||||
|
videoSubtitlesElem.parentNode.removeChild(videoSubtitlesElem);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentSubtitlesElement = null;
|
||||||
|
currentTrackEvents = null;
|
||||||
|
customTrackIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchSubtitles(track) {
|
||||||
|
|
||||||
|
return ApiClient.ajax({
|
||||||
|
url: track.url.replace('.vtt', '.js'),
|
||||||
|
type: 'GET',
|
||||||
|
dataType: 'json'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTrackForCustomDisplay(track) {
|
||||||
|
|
||||||
|
if (!track) {
|
||||||
|
destroyCustomTrack();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if already playing this track, skip
|
||||||
|
if (customTrackIndex == track.index) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
destroyCustomTrack();
|
||||||
|
customTrackIndex = track.index;
|
||||||
|
|
||||||
|
// download the track json
|
||||||
|
fetchSubtitles(track).then(function (data) {
|
||||||
|
|
||||||
|
// show in ui
|
||||||
|
console.log('downloaded ' + data.TrackEvents.length + ' track events');
|
||||||
|
currentTrackEvents = data.TrackEvents;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentSubtitlesElement;
|
||||||
|
var currentTrackEvents;
|
||||||
|
var customTrackIndex = -1;
|
||||||
|
var lastCustomTrackMs = 0;
|
||||||
|
function updateSubtitleText(timeMs) {
|
||||||
|
|
||||||
|
var trackEvents = currentTrackEvents;
|
||||||
|
if (!trackEvents) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!currentSubtitlesElement) {
|
||||||
|
var videoSubtitlesElem = document.querySelector('.videoSubtitles');
|
||||||
|
if (!videoSubtitlesElem) {
|
||||||
|
videoSubtitlesElem = document.createElement('div');
|
||||||
|
videoSubtitlesElem.classList.add('videoSubtitles');
|
||||||
|
videoSubtitlesElem.innerHTML = '<div class="videoSubtitlesInner"></div>';
|
||||||
|
document.body.appendChild(videoSubtitlesElem);
|
||||||
|
}
|
||||||
|
currentSubtitlesElement = videoSubtitlesElem.querySelector('.videoSubtitlesInner');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastCustomTrackMs > 0) {
|
||||||
|
if (Math.abs(lastCustomTrackMs - timeMs) < 500) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var positionTicks = timeMs * 10000;
|
||||||
|
for (var i = 0, length = trackEvents.length; i < length; i++) {
|
||||||
|
|
||||||
|
var caption = trackEvents[i];
|
||||||
|
if (positionTicks >= caption.StartPositionTicks && positionTicks <= caption.EndPositionTicks) {
|
||||||
|
currentSubtitlesElement.innerHTML = caption.Text;
|
||||||
|
currentSubtitlesElement.classList.remove('hide');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentSubtitlesElement.innerHTML = '';
|
||||||
|
currentSubtitlesElement.classList.add('hide');
|
||||||
|
}
|
||||||
|
|
||||||
self.setCurrentTrackElement = function (streamIndex) {
|
self.setCurrentTrackElement = function (streamIndex) {
|
||||||
|
|
||||||
console.log('Setting new text track index to: ' + streamIndex);
|
console.log('Setting new text track index to: ' + streamIndex);
|
||||||
|
|
||||||
var allTracks = mediaElement.textTracks; // get list of tracks
|
|
||||||
|
|
||||||
var modes = ['disabled', 'showing', 'hidden'];
|
|
||||||
var expectedId = 'textTrack' + streamIndex;
|
|
||||||
|
|
||||||
var track = streamIndex == -1 ? null : currentTrackList.filter(function (t) {
|
var track = streamIndex == -1 ? null : currentTrackList.filter(function (t) {
|
||||||
return t.index == streamIndex;
|
return t.index == streamIndex;
|
||||||
})[0];
|
})[0];
|
||||||
var trackIndex = streamIndex == -1 || !track ? -1 : currentTrackList.indexOf(track);
|
|
||||||
|
|
||||||
|
if (enableNativeTrackSupport(track)) {
|
||||||
|
|
||||||
|
setTrackForCustomDisplay(null);
|
||||||
|
} else {
|
||||||
|
setTrackForCustomDisplay(track);
|
||||||
|
|
||||||
|
// null these out to disable the player's native display (handled below)
|
||||||
|
streamIndex = -1;
|
||||||
|
track = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var expectedId = 'textTrack' + streamIndex;
|
||||||
|
var trackIndex = streamIndex == -1 || !track ? -1 : currentTrackList.indexOf(track);
|
||||||
|
var modes = ['disabled', 'showing', 'hidden'];
|
||||||
|
|
||||||
|
var allTracks = mediaElement.textTracks; // get list of tracks
|
||||||
for (var i = 0; i < allTracks.length; i++) {
|
for (var i = 0; i < allTracks.length; i++) {
|
||||||
|
|
||||||
var currentTrack = allTracks[i];
|
var currentTrack = allTracks[i];
|
||||||
|
|
|
@ -261,13 +261,6 @@ div.ui-mobile-viewport {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui-content {
|
|
||||||
border-width: 0;
|
|
||||||
overflow: visible;
|
|
||||||
overflow-x: hidden;
|
|
||||||
padding: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Buttons and icons */
|
/* Buttons and icons */
|
||||||
.ui-btn, ul[data-role="listview"] a + a {
|
.ui-btn, ul[data-role="listview"] a + a {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
paper-button.block {
|
paper-button.block {
|
||||||
display: block;
|
display: block;
|
||||||
|
margin: .25em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
paper-button.blue {
|
paper-button.blue {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue