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

425 lines
13 KiB
JavaScript
Raw Normal View History

2015-06-25 17:50:56 -04:00
(function (window) {
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
function getDeviceProfile(serverAddress, deviceId, item, startPositionTicks, maxBitrate, mediaSourceId, audioStreamIndex, subtitleStreamIndex) {
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
var bitrateSetting = AppSettings.maxStreamingBitrate();
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
var profile = {};
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
profile.MaxStreamingBitrate = bitrateSetting;
2016-02-22 12:20:38 -05:00
profile.MaxStaticBitrate = 100000000;
profile.MusicStreamingTranscodingBitrate = 192000;
2014-09-16 23:04:10 -04:00
2015-05-25 13:32:22 -04:00
profile.DirectPlayProfiles = [];
2014-09-16 23:04:10 -04:00
2015-05-25 13:32:22 -04:00
profile.DirectPlayProfiles.push({
2016-02-22 12:20:38 -05:00
Container: 'm4v,3gp,ts,mpegts,mov,xvid,vob,mkv,wmv,asf,ogm,ogv,m2v,avi,mpg,mpeg,mp4,webm,wtv,dvr-ms',
2015-05-25 13:32:22 -04:00
Type: 'Video'
});
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
profile.DirectPlayProfiles.push({
2016-02-22 12:20:38 -05:00
Container: 'aac,mp3,mpa,wav,wma,mp2,ogg,oga,webma,ape,opus,flac',
2015-05-25 13:32:22 -04:00
Type: 'Audio'
});
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
profile.TranscodingProfiles = [];
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
profile.TranscodingProfiles.push({
2016-02-22 12:20:38 -05:00
Container: 'mkv',
2015-05-25 13:32:22 -04:00
Type: 'Video',
2016-02-22 12:20:38 -05:00
AudioCodec: 'aac,mp3,ac3',
2015-05-25 13:32:22 -04:00
VideoCodec: 'h264',
2016-02-22 12:20:38 -05:00
Context: 'Streaming'
2015-05-25 13:32:22 -04:00
});
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
profile.TranscodingProfiles.push({
2016-02-22 12:20:38 -05:00
Container: 'mp3',
2015-05-25 13:32:22 -04:00
Type: 'Audio',
2016-02-22 12:20:38 -05:00
AudioCodec: 'mp3',
2015-05-25 13:32:22 -04:00
Context: 'Streaming',
2016-02-22 12:20:38 -05:00
Protocol: 'http'
2015-05-25 13:32:22 -04:00
});
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
profile.ContainerProfiles = [];
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
profile.CodecProfiles = [];
2014-09-16 23:04:10 -04:00
2015-05-25 13:32:22 -04:00
// Subtitle profiles
2016-02-22 12:20:38 -05:00
// External vtt or burn in
2015-05-25 13:32:22 -04:00
profile.SubtitleProfiles = [];
2015-12-14 10:43:03 -05:00
profile.SubtitleProfiles.push({
Format: 'srt',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'subrip',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'ass',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'ssa',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'pgs',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'pgssub',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'dvdsub',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'vtt',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'sub',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'idx',
Method: 'Embed'
});
2016-02-22 12:20:38 -05:00
profile.SubtitleProfiles.push({
Format: 'smi',
Method: 'Embed'
});
2015-12-14 10:43:03 -05:00
2015-05-25 13:32:22 -04:00
profile.ResponseProfiles = [];
2014-09-16 21:38:50 -04:00
2015-05-25 13:32:22 -04:00
return profile;
2014-09-15 23:33:30 -04:00
}
2015-05-25 13:32:22 -04:00
var currentMediaSource;
var currentItem;
var basePlayerState;
var progressInterval;
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
function getVideoStreamInfo(item) {
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
var deferred = $.Deferred();
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
var deviceProfile = getDeviceProfile();
var startPosition = 0;
2014-09-15 23:33:30 -04:00
2015-09-20 12:16:06 -04:00
MediaPlayer.tryStartPlayback(deviceProfile, item, startPosition, function (mediaSource) {
2014-09-15 23:33:30 -04:00
2015-09-20 12:16:06 -04:00
playInternalPostMediaSourceSelection(item, mediaSource, startPosition, deferred);
2015-05-25 13:32:22 -04:00
});
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
return deferred.promise();
}
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
function playInternalPostMediaSourceSelection(item, mediaSource, startPosition, deferred) {
2014-09-15 23:33:30 -04:00
2015-12-14 10:43:03 -05:00
Dashboard.hideLoadingMsg();
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
currentItem = item;
currentMediaSource = mediaSource;
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
basePlayerState = {
PlayState: {
2014-09-15 23:33:30 -04:00
}
2015-05-25 13:32:22 -04:00
};
2014-09-15 23:33:30 -04:00
2015-12-14 10:43:03 -05:00
MediaPlayer.createStreamInfo('Video', item, mediaSource, startPosition).then(function (streamInfo) {
2014-09-15 23:33:30 -04:00
2015-09-21 11:43:10 -04:00
var currentSrc = streamInfo.url;
2014-09-15 23:33:30 -04:00
2015-09-21 11:43:10 -04:00
var audioStreamIndex = getParameterByName('AudioStreamIndex', currentSrc);
2014-09-15 23:33:30 -04:00
2015-09-21 11:43:10 -04:00
if (audioStreamIndex) {
basePlayerState.PlayState.AudioStreamIndex = parseInt(audioStreamIndex);
}
basePlayerState.PlayState.SubtitleStreamIndex = self.currentSubtitleStreamIndex;
basePlayerState.PlayState.PlayMethod = getParameterByName('static', currentSrc) == 'true' ?
'DirectStream' :
'Transcode';
2014-09-15 23:33:30 -04:00
2015-09-21 11:43:10 -04:00
basePlayerState.PlayState.LiveStreamId = getParameterByName('LiveStreamId', currentSrc);
basePlayerState.PlayState.PlaySessionId = getParameterByName('PlaySessionId', currentSrc);
2014-09-15 23:33:30 -04:00
2015-09-21 11:43:10 -04:00
basePlayerState.PlayState.MediaSourceId = mediaSource.Id;
basePlayerState.PlayState.CanSeek = false;
basePlayerState.NowPlayingItem = MediaPlayer.getNowPlayingItemForReporting(item, mediaSource);
2014-09-15 23:33:30 -04:00
2015-09-21 11:43:10 -04:00
deferred.resolveWith(null, [streamInfo]);
});
2014-09-15 23:33:30 -04:00
}
2015-05-25 13:32:22 -04:00
function getPlayerState(positionTicks) {
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
var state = basePlayerState;
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
state.PlayState.PositionTicks = positionTicks;
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
return state;
2014-09-15 23:33:30 -04:00
}
2015-05-25 13:32:22 -04:00
function onPlaybackStart() {
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
closePlayMenu();
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
var state = getPlayerState();
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
var info = {
ItemId: state.NowPlayingItem.Id,
NowPlayingItem: state.NowPlayingItem
};
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
info = $.extend(info, state.PlayState);
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
ApiClient.reportPlaybackStart(info);
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
// This is really just a ping to let the server know we're still playing
progressInterval = setInterval(function () {
onPlaybackProgress(null);
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
}, 10000);
2014-09-15 23:33:30 -04:00
2015-05-26 11:31:50 -04:00
// Need a timeout because we can't show a popup at the same time as the previous one is closing
// Bumping it up to 1000 because the post play menu is hiding for some reason on android
2015-05-25 13:32:22 -04:00
setTimeout(function () {
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
showPostPlayMenu(currentItem);
2015-05-26 11:31:50 -04:00
}, 1000);
2015-05-25 13:32:22 -04:00
}
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
function onPlaybackProgress(positionTicks) {
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
var state = getPlayerState(positionTicks);
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
var info = {
ItemId: state.NowPlayingItem.Id,
NowPlayingItem: state.NowPlayingItem
};
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
info = $.extend(info, state.PlayState);
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
ApiClient.reportPlaybackProgress(info);
}
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
function onPlaybackStopped(positionTicks) {
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
var state = getPlayerState(positionTicks);
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
var stopInfo = {
itemId: state.NowPlayingItem.Id,
mediaSourceId: state.PlayState.MediaSourceId,
positionTicks: state.PlayState.PositionTicks
};
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
if (state.PlayState.LiveStreamId) {
stopInfo.LiveStreamId = state.PlayState.LiveStreamId;
2014-09-15 23:33:30 -04:00
}
2015-05-25 13:32:22 -04:00
if (state.PlayState.PlaySessionId) {
stopInfo.PlaySessionId = state.PlayState.PlaySessionId;
}
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
ApiClient.reportPlaybackStopped(stopInfo);
2014-09-15 23:33:30 -04:00
2015-05-25 13:32:22 -04:00
if (progressInterval) {
clearInterval(progressInterval);
progressInterval = null;
}
2014-09-15 23:33:30 -04:00
}
2015-05-25 13:32:22 -04:00
function showPostPlayMenu(item) {
2014-09-15 23:33:30 -04:00
2015-09-04 12:20:54 -04:00
require(['jqmpopup', 'jqmlistview'], function () {
2015-09-01 00:15:10 -04:00
$('.externalPlayerPostPlayFlyout').popup("close").remove();
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
var html = '<div data-role="popup" class="externalPlayerPostPlayFlyout" data-history="false" data-theme="a" data-dismissible="false">';
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
html += '<ul data-role="listview" style="min-width: 220px;">';
html += '<li data-role="list-divider" style="padding: 1em;text-align:center;">' + Globalize.translate('HeaderExternalPlayerPlayback') + '</li>';
html += '</ul>';
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
html += '<div style="padding:1em;">';
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
var autoMarkWatched = item.RunTimeTicks;
2014-09-16 21:38:50 -04:00
2015-09-01 00:15:10 -04:00
if (item.RunTimeTicks && item.RunTimeTicks >= 3000000000) {
2014-09-16 21:38:50 -04:00
2015-09-01 00:15:10 -04:00
autoMarkWatched = false;
2014-09-16 21:38:50 -04:00
2015-09-01 00:15:10 -04:00
html += '<fieldset data-role="controlgroup">';
html += '<legend>' + Globalize.translate('LabelMarkAs') + '</legend>';
html += '<label for="radioMarkUnwatched">' + Globalize.translate('OptionUnwatched') + '</label>';
html += '<input type="radio" id="radioMarkUnwatched" name="radioGroupMarkPlaystate" class="radioPlaystate" />';
html += '<label for="radioMarkWatched">' + Globalize.translate('OptionWatched') + '</label>';
html += '<input type="radio" id="radioMarkWatched" checked="checked" name="radioGroupMarkPlaystate" class="radioPlaystate" />';
html += '<label for="radioMarkInProgress">' + Globalize.translate('OptionInProgress') + '</label>';
html += '<input type="radio" id="radioMarkInProgress" name="radioGroupMarkPlaystate" class="radioPlaystate" />';
html += '</fieldset>';
2014-09-16 21:38:50 -04:00
2015-09-01 00:15:10 -04:00
html += '<br/>';
2014-09-16 21:38:50 -04:00
2015-09-01 00:15:10 -04:00
html += '<p style="margin-top: 0;">' + Globalize.translate('LabelResumePoint') + '</p>';
2014-09-16 21:38:50 -04:00
2015-09-01 00:15:10 -04:00
html += '<div class="sliderContainer" style="display:block;margin-top:4px;">';
html += '<input class="playstateSlider" type="range" step=".001" min="0" max="100" value="0" style="display:none;" data-theme="a" data-highlight="true" />';
html += '</div>';
html += '<div class="sliderValue" style="text-align:center;margin:2px 0 4px;">0:00:00</div>';
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
html += '<br/>';
}
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
html += '<button type="button" class="btnDone" data-theme="b" data-icon="check">' + Globalize.translate('ButtonImDone') + '</button>';
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
html += '</div>';
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
html += '</div>';
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
$(document.body).append(html);
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
var elem = $('.externalPlayerPostPlayFlyout').popup({}).trigger('create').popup("open").on("popupafterclose", function () {
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
$(this).off("popupafterclose").remove();
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
});
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
$('.radioPlaystate', elem).on('change', function () {
2014-09-16 21:38:50 -04:00
2015-09-01 00:15:10 -04:00
if ($('#radioMarkInProgress', elem).checked()) {
2014-09-16 21:38:50 -04:00
2015-09-01 00:15:10 -04:00
$('.playstateSlider', elem).slider('enable');
2014-09-16 21:38:50 -04:00
2015-09-01 00:15:10 -04:00
} else {
$('.playstateSlider', elem).slider('disable');
}
2014-09-16 21:38:50 -04:00
2015-09-01 00:15:10 -04:00
}).trigger('change');
2014-09-16 21:38:50 -04:00
2015-09-01 00:15:10 -04:00
$('.btnDone', elem).on('click', function () {
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
$('.externalPlayerPostPlayFlyout').popup("close").remove();
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
var position = 0;
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
if ($('#radioMarkInProgress', elem).checked()) {
2014-09-16 21:38:50 -04:00
2015-09-01 00:15:10 -04:00
var pct = $(".playstateSlider", elem).val();
var ticks = item.RunTimeTicks * (Number(pct) * .01);
2014-09-16 21:38:50 -04:00
2015-09-01 00:15:10 -04:00
position = ticks;
}
else if (autoMarkWatched || $('#radioMarkWatched', elem).checked()) {
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
position = currentMediaSource.RunTimeTicks;
}
else if ($('#radioMarkUnwatched', elem).checked()) {
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
position = 0;
}
onPlaybackStopped(position);
});
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
$(".playstateSlider", elem).on("change", function (e) {
2014-09-16 21:38:50 -04:00
2015-09-01 00:15:10 -04:00
var pct = $(this).val();
2014-09-16 21:38:50 -04:00
2015-09-01 00:15:10 -04:00
var time = item.RunTimeTicks * (Number(pct) * .01);
2014-09-16 21:38:50 -04:00
2015-09-01 00:15:10 -04:00
var tooltext = Dashboard.getDisplayTime(time);
2014-09-16 21:38:50 -04:00
2015-09-01 00:15:10 -04:00
$('.sliderValue', elem).html(tooltext);
2014-09-16 21:38:50 -04:00
2015-12-23 12:46:01 -05:00
console.log("slidin", pct, self.currentDurationTicks, time);
2014-09-16 21:38:50 -04:00
2015-09-01 00:15:10 -04:00
});
2014-09-16 21:38:50 -04:00
});
2014-09-15 23:33:30 -04:00
}
function closePlayMenu() {
$('.externalPlayerFlyout').popup("close").remove();
}
2015-05-25 13:32:22 -04:00
function showMenuForItem(item, players) {
2014-09-15 23:33:30 -04:00
2015-09-04 12:20:54 -04:00
require(['jqmpopup', 'jqmlistview'], function () {
2015-09-01 00:15:10 -04:00
closePlayMenu();
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
var html = '<div data-role="popup" class="externalPlayerFlyout" data-theme="a" data-dismissible="false">';
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
html += '<ul data-role="listview" style="min-width: 200px;">';
html += '<li data-role="list-divider" style="padding: 1em;text-align:center;">' + Globalize.translate('HeaderSelectExternalPlayer') + '</li>';
html += '</ul>';
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
html += '<div style="padding:1em;">';
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
html += players.map(function (p) {
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
return '<a href="' + p.url + '" data-role="button" data-icon="play" class="btnExternalPlayer" data-theme="b" data-mini="true">' + p.name + '</a>';
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
}).join('');
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
html += '</div>';
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
html += '</div>';
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
$(document.body).append(html);
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
var elem = $('.externalPlayerFlyout').popup({}).trigger('create').popup("open").on("popupafterclose", function () {
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
$(this).off("popupafterclose").remove();
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
});
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
$('.btnExternalPlayer', elem).on('click', function () {
2014-09-15 23:33:30 -04:00
2015-09-01 00:15:10 -04:00
ExternalPlayer.onPlaybackStart();
});
2014-09-15 23:33:30 -04:00
});
}
function showPlayMenu(itemId) {
var userId = Dashboard.getCurrentUserId();
2015-12-14 10:43:03 -05:00
ApiClient.getItem(userId, itemId).then(function (item) {
2014-09-15 23:33:30 -04:00
2015-12-14 10:43:03 -05:00
getVideoStreamInfo(item).then(function (streamInfo) {
2015-05-25 13:32:22 -04:00
setTimeout(function () {
ExternalPlayer.showPlayerSelectionMenu(item, streamInfo.url, streamInfo.mimeType);
}, 500);
});
});
}
function getExternalPlayers(url, mimeType) {
var players = [
{ name: 'Vlc', url: 'vlc://' + url, id: 'vlc' }
];
2016-02-26 23:39:11 -05:00
return Promise.resolve(players);
2015-05-25 13:32:22 -04:00
}
function showPlayerSelectionMenu(item, url, mimeType) {
2014-09-15 23:33:30 -04:00
2015-12-14 10:43:03 -05:00
ExternalPlayer.getExternalPlayers(url, mimeType).then(function (players) {
2015-05-25 13:32:22 -04:00
showMenuForItem(item, players);
2014-09-15 23:33:30 -04:00
});
}
window.ExternalPlayer = {
2015-05-25 13:32:22 -04:00
showMenu: showPlayMenu,
onPlaybackStart: onPlaybackStart,
2014-09-15 23:33:30 -04:00
getExternalPlayers: getExternalPlayers,
2015-05-25 13:32:22 -04:00
showPlayerSelectionMenu: showPlayerSelectionMenu
2014-09-15 23:33:30 -04:00
};
2015-06-25 17:50:56 -04:00
})(window);