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

3.0.5621.2

This commit is contained in:
Luke Pulverenti 2015-05-25 13:32:22 -04:00
parent 2e982826bb
commit 4e86a39f8c
25 changed files with 651 additions and 550 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 148 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Before After
Before After

View file

@ -175,10 +175,8 @@
<div>
<fieldset data-role="controlgroup">
<legend>${LabelExternalPlayers}</legend>
<!--<input type="checkbox" id="chkGoodplayer" class="chkExternalPlayer" data-name="GoodPlayer" data-scheme="goodplayer://{0}" />
<label for="chkGoodplayer">GoodPlayer</label>-->
<input type="checkbox" id="chkVlc" class="chkExternalPlayer" data-name="Vlc" data-scheme="vlc://{0}" />
<label for="chkVlc">Vlc</label>
<input type="checkbox" id="chkExternalVideoPlayer" />
<label for="chkExternalVideoPlayer">${OptionEnableExternalVideoPlayers}</label>
</fieldset>
<div style="padding: 0 2px;">${LabelExternalPlayersHelp}</div>
</div>

View file

@ -809,11 +809,9 @@
});
}
if ($.browser.chrome) {
requirejs(["thirdparty/cast_sender"], function () {
initializeChromecast();
});
}
})(window, window.chrome, console);

View file

@ -1012,8 +1012,7 @@
}
};
$(document).on('pagebeforeshowready', "#dashboardPage", DashboardPage.onPageShow)
.on('pagehide', "#dashboardPage", DashboardPage.onPageHide);
$(document).on('pageshowready', "#dashboardPage", DashboardPage.onPageShow).on('pagehide', "#dashboardPage", DashboardPage.onPageHide);
(function ($, document, window) {
@ -1308,7 +1307,7 @@ $(document).on('pagebeforeshowready', "#dashboardPage", DashboardPage.onPageShow
result.CustomPrefs[welcomeTourKey] = welcomeDismissValue;
ApiClient.updateDisplayPreferences('dashboard', result, userId, 'dashboard');
$(page).off('pagebeforeshow.checktour');
$(page).off('.checktour');
});
}
@ -1373,7 +1372,7 @@ $(document).on('pagebeforeshowready', "#dashboardPage", DashboardPage.onPageShow
takeTour(page, Dashboard.getCurrentUserId());
});
}).on('pagebeforeshowready.checktour', "#dashboardPage", function () {
}).on('pageshowready.checktour', "#dashboardPage", function () {
var page = this;
@ -1389,7 +1388,7 @@ $(document).on('pagebeforeshowready', "#dashboardPage", DashboardPage.onPageShow
(function () {
$(document).on('pagebeforeshowready', ".type-interior", function () {
$(document).on('pageshowready', ".type-interior", function () {
var page = this;

View file

@ -1,315 +1,301 @@
(function (window, store) {
function getExternalPlayers() {
return JSON.parse(store.getItem('externalplayers') || '[]');
function getDeviceProfile(serverAddress, deviceId, item, startPositionTicks, maxBitrate, mediaSourceId, audioStreamIndex, subtitleStreamIndex) {
var bitrateSetting = AppSettings.maxStreamingBitrate();
var profile = {};
profile.MaxStreamingBitrate = bitrateSetting;
profile.MaxStaticBitrate = 40000000;
profile.MusicStreamingTranscodingBitrate = Math.min(bitrateSetting, 192000);
profile.DirectPlayProfiles = [];
profile.DirectPlayProfiles.push({
Container: 'mkv,mov,mp4,m4v,wmv',
Type: 'Video'
});
profile.DirectPlayProfiles.push({
Container: 'aac,mp3,flac,wma',
Type: 'Audio'
});
profile.TranscodingProfiles = [];
profile.TranscodingProfiles.push({
Container: 'ts',
Type: 'Video',
AudioCodec: 'aac',
VideoCodec: 'h264',
Context: 'Streaming',
Protocol: 'hls'
});
profile.TranscodingProfiles.push({
Container: 'aac',
Type: 'Audio',
AudioCodec: 'aac',
Context: 'Streaming',
Protocol: 'hls'
});
profile.ContainerProfiles = [];
var audioConditions = [];
var maxAudioChannels = '6';
audioConditions.push({
Condition: 'LessThanEqual',
Property: 'AudioChannels',
Value: maxAudioChannels
});
profile.CodecProfiles = [];
profile.CodecProfiles.push({
Type: 'Audio',
Conditions: audioConditions
});
profile.CodecProfiles.push({
Type: 'VideoAudio',
Codec: 'mp3',
Conditions: [{
Condition: 'LessThanEqual',
Property: 'AudioChannels',
Value: maxAudioChannels
}]
});
profile.CodecProfiles.push({
Type: 'VideoAudio',
Codec: 'aac',
Conditions: [
{
Condition: 'LessThanEqual',
Property: 'AudioChannels',
Value: maxAudioChannels
}
]
});
profile.CodecProfiles.push({
Type: 'Video',
Codec: 'h264',
Conditions: [
{
Condition: 'EqualsAny',
Property: 'VideoProfile',
Value: 'high|main|baseline|constrained baseline'
},
{
Condition: 'LessThanEqual',
Property: 'VideoLevel',
Value: '41'
}]
});
// Subtitle profiles
profile.SubtitleProfiles = [];
profile.ResponseProfiles = [];
return profile;
}
function getUrl(player, item) {
function validatePlaybackInfoResult(result) {
return 'vlc://http://www.google.com';
if (result.ErrorCode) {
}
function getCodecLimits(maxBitrate) {
var maxWidth;
if (maxBitrate <= 1000000) {
maxWidth = 720;
}
else if (maxBitrate <= 5000000) {
maxWidth = 1280;
} else {
maxWidth = 1280;
}
return {
maxVideoAudioChannels: 6,
maxAudioChannels: 2,
maxVideoLevel: 50,
maxWidth: maxWidth,
maxSampleRate: 48000
};
}
function canDirectStream(mediaType, mediaSource, maxBitrate) {
// If bitrate is unknown don't direct stream
if (!mediaSource.Bitrate || mediaSource.Bitrate > maxBitrate) {
MediaController.showPlaybackInfoErrorMessage(result.ErrorCode);
return false;
}
var codecLimits = getCodecLimits(maxBitrate);
if (mediaType == "Audio") {
return true;
}
else if (mediaType == "Video") {
var videoStream = mediaSource.MediaStreams.filter(function (s) {
return s.Type == 'Video';
})[0];
if (!videoStream) {
return false;
}
if (videoStream.Width && videoStream.Width > codecLimits.maxWidth) {
return false;
}
if (mediaSource.VideoType != 'VideoFile') {
return false;
}
return mediaSource.Protocol == 'File';
}
throw new Error('Unrecognized MediaType');
}
function canPlayAudioStreamDirect(audioStream, isVideo, maxBitrate) {
var audioCodec = (audioStream.Codec || '').toLowerCase().replace('-', '');
if (audioCodec.indexOf('aac') == -1 &&
audioCodec.indexOf('mp3') == -1 &&
audioCodec.indexOf('mpeg') == -1) {
return false;
}
var codecLimits = getCodecLimits(maxBitrate);
var maxChannels = isVideo ? codecLimits.maxVideoAudioChannels : codecLimits.maxAudioChannels;
if (!audioStream.Channels || audioStream.Channels > maxChannels) {
return false;
}
if (!audioStream.SampleRate || audioStream.SampleRate > codecLimits.maxSampleRate) {
return false;
}
var bitrate = audioStream.BitRate;
if (!bitrate) {
return false;
}
if (isVideo) {
if (audioCodec.indexOf('aac') != -1 && bitrate > 768000) {
return false;
}
if (audioCodec.indexOf('mp3') != -1 || audioCodec.indexOf('mpeg') != -1) {
if (bitrate > 320000) {
return false;
}
}
} else {
if (bitrate > 320000) {
return false;
}
}
return true;
}
function isSupportedCodec(mediaType, mediaSource) {
function getOptimalMediaSource(mediaType, versions) {
if (mediaType == "Audio") {
return false;
}
else if (mediaType == "Video") {
var optimalVersion = versions.filter(function (v) {
return mediaSource.MediaStreams.filter(function (m) {
v.enableDirectPlay = MediaController.supportsDirectPlay(v);
return m.Type == "Video" && (m.Codec || '').toLowerCase() == 'h264';
return v.enableDirectPlay;
}).length > 0;
}
})[0];
throw new Error('Unrecognized MediaType');
}
if (!optimalVersion) {
optimalVersion = versions.filter(function (v) {
function getStreamByIndex(streams, type, index) {
return streams.filter(function (s) {
return s.Type == type && s.Index == index;
return v.SupportsDirectStream;
})[0];
}
function getMediaSourceInfo(item, maxBitrate, mediaSourceId, audioStreamIndex, subtitleStreamIndex) {
var sources = item.MediaSources.filter(function (m) {
m.audioStream = mediaSourceId == m.Id && audioStreamIndex != null ?
getStreamByIndex(m.MediaStreams, 'Audio', audioStreamIndex) :
getStreamByIndex(m.MediaStreams, 'Audio', m.DefaultAudioStreamIndex);
if (item.MediaType == "Audio" && !m.audioStream) {
m.audioStream = m.MediaStreams.filter(function (s) {
return s.Type == 'Audio';
return optimalVersion || versions.filter(function (s) {
return s.SupportsTranscoding;
})[0];
}
m.subtitleStream = mediaSourceId == m.Id && subtitleStreamIndex != null ?
getStreamByIndex(m.MediaStreams, 'Subtitle', subtitleStreamIndex) :
getStreamByIndex(m.MediaStreams, 'Subtitle', m.DefaultSubtitleStreamIndex);
var currentMediaSource;
var currentItem;
var basePlayerState;
var progressInterval;
return !mediaSourceId || m.Id == mediaSourceId;
function getVideoStreamInfo(item) {
var deferred = $.Deferred();
Dashboard.showModalLoadingMsg();
var deviceProfile = getDeviceProfile();
var startPosition = 0;
MediaController.getPlaybackInfo(item.Id, deviceProfile, startPosition).done(function (playbackInfoResult) {
if (validatePlaybackInfoResult(playbackInfoResult)) {
var mediaSource = getOptimalMediaSource(item.MediaType, playbackInfoResult.MediaSources);
if (mediaSource) {
if (mediaSource.RequiresOpening) {
MediaController.getLiveStream(item.Id, playbackInfoResult.PlaySessionId, deviceProfile, startPosition, mediaSource, null, null).done(function (openLiveStreamResult) {
openLiveStreamResult.MediaSource.enableDirectPlay = MediaController.supportsDirectPlay(openLiveStreamResult.MediaSource);
playInternalPostMediaSourceSelection(item, openLiveStreamResult.MediaSource, startPosition, deferred);
});
} else {
playInternalPostMediaSourceSelection(item, mediaSource, startPosition, deferred);
}
} else {
Dashboard.hideModalLoadingMsg();
MediaController.showPlaybackInfoErrorMessage('NoCompatibleStream');
}
}
});
// Find first one that can be direct streamed
var source = sources.filter(function (m) {
var audioStream = m.audioStream;
if (!audioStream || !canPlayAudioStreamDirect(audioStream, item.MediaType == 'Video', maxBitrate)) {
return false;
return deferred.promise();
}
if (m.subtitleStream && m.subtitleStream.IsExternal) {
return false;
function playInternalPostMediaSourceSelection(item, mediaSource, startPosition, deferred) {
Dashboard.hideModalLoadingMsg();
currentItem = item;
currentMediaSource = mediaSource;
basePlayerState = {
PlayState: {
}
return canDirectStream(item.MediaType, m, maxBitrate, audioStream);
})[0];
if (source) {
return {
mediaSource: source,
isStatic: true,
streamContainer: source.Container
};
var streamInfo = MediaPlayer.createStreamInfo('Video', item, mediaSource, startPosition);
var currentSrc = streamInfo.url;
var audioStreamIndex = getParameterByName('AudioStreamIndex', currentSrc);
if (audioStreamIndex) {
basePlayerState.PlayState.AudioStreamIndex = parseInt(audioStreamIndex);
}
basePlayerState.PlayState.SubtitleStreamIndex = self.currentSubtitleStreamIndex;
basePlayerState.PlayState.PlayMethod = getParameterByName('static', currentSrc) == 'true' ?
'DirectStream' :
'Transcode';
basePlayerState.PlayState.LiveStreamId = getParameterByName('LiveStreamId', currentSrc);
basePlayerState.PlayState.PlaySessionId = getParameterByName('PlaySessionId', currentSrc);
basePlayerState.PlayState.MediaSourceId = mediaSource.Id;
basePlayerState.PlayState.CanSeek = false;
basePlayerState.NowPlayingItem = MediaPlayer.getNowPlayingItemForReporting(item, mediaSource);
deferred.resolveWith(null, [streamInfo]);
}
// Find first one with supported codec
source = sources.filter(function (m) {
function getPlayerState(positionTicks) {
return isSupportedCodec(item.MediaType, m);
var state = basePlayerState;
})[0];
state.PlayState.PositionTicks = positionTicks;
source = source || sources[0];
return state;
}
var container = item.MediaType == 'Audio' ? 'mp3' : 'm3u8';
function onPlaybackStart() {
// Default to first one
return {
mediaSource: source,
isStatic: false,
streamContainer: container
closePlayMenu();
var state = getPlayerState();
var info = {
ItemId: state.NowPlayingItem.Id,
NowPlayingItem: state.NowPlayingItem
};
info = $.extend(info, state.PlayState);
ApiClient.reportPlaybackStart(info);
// This is really just a ping to let the server know we're still playing
progressInterval = setInterval(function () {
onPlaybackProgress(null);
}, 10000);
setTimeout(function () {
showPostPlayMenu(currentItem);
}, 500);
}
function getStreamInfo(serverAddress, deviceId, item, startPositionTicks, maxBitrate, mediaSourceId, audioStreamIndex, subtitleStreamIndex) {
function onPlaybackProgress(positionTicks) {
var mediaSourceInfo = getMediaSourceInfo(item, maxBitrate, mediaSourceId, audioStreamIndex, subtitleStreamIndex);
var state = getPlayerState(positionTicks);
var url = getStreamUrl(serverAddress, deviceId, item.MediaType, item.Id, mediaSourceInfo, startPositionTicks, maxBitrate);
var info = {
ItemId: state.NowPlayingItem.Id,
NowPlayingItem: state.NowPlayingItem
};
if (mediaSourceInfo.subtitleStream && mediaSourceInfo.subtitleStream.IsExternal) {
url += "&SubtitleStreamIndex=" + mediaSourceInfo.Index;
info = $.extend(info, state.PlayState);
ApiClient.reportPlaybackProgress(info);
}
mediaSourceInfo.url = url;
function onPlaybackStopped(positionTicks) {
return mediaSourceInfo;
var state = getPlayerState(positionTicks);
var stopInfo = {
itemId: state.NowPlayingItem.Id,
mediaSourceId: state.PlayState.MediaSourceId,
positionTicks: state.PlayState.PositionTicks
};
if (state.PlayState.LiveStreamId) {
stopInfo.LiveStreamId = state.PlayState.LiveStreamId;
}
function getStreamUrl(serverAddress, deviceId, mediaType, itemId, mediaSourceInfo, startPositionTicks, maxBitrate) {
var url;
var codecLimits = getCodecLimits(maxBitrate);
if (mediaType == 'Audio') {
url = serverAddress + '/audio/' + itemId + '/stream.' + mediaSourceInfo.streamContainer;
url += '?mediasourceid=' + mediaSourceInfo.mediaSource.Id;
if (mediaSourceInfo.isStatic) {
url += '&static=true';
} else {
url += '&maxaudiochannels=' + codecLimits.maxAudioChannels;
if (startPositionTicks) {
url += '&startTimeTicks=' + startPositionTicks.toString();
if (state.PlayState.PlaySessionId) {
stopInfo.PlaySessionId = state.PlayState.PlaySessionId;
}
if (maxBitrate) {
url += '&audiobitrate=' + Math.min(maxBitrate, 320000).toString();
ApiClient.reportPlaybackStopped(stopInfo);
if (progressInterval) {
clearInterval(progressInterval);
progressInterval = null;
}
}
url += '&deviceId=' + deviceId;
}
return url;
}
else if (mediaType == 'Video') {
if (mediaSourceInfo.isStatic) {
url = serverAddress + '/videos/' + itemId + '/stream.' + mediaSourceInfo.streamContainer + '?static=true';
}
else {
url = serverAddress + '/videos/' + itemId + '/stream.' + mediaSourceInfo.streamContainer + '?static=false';
}
url += '&maxaudiochannels=' + codecLimits.maxVideoAudioChannels;
if (maxBitrate) {
var audioRate = 320000;
url += '&audiobitrate=' + audioRate.toString();
url += '&videobitrate=' + (maxBitrate - audioRate).toString();
}
url += '&profile=high';
url += '&level=41';
url += '&maxwidth=' + codecLimits.maxWidth;
url += '&videoCodec=h264';
url += '&audioCodec=aac';
url += '&mediasourceid=' + mediaSourceInfo.mediaSource.Id;
url += '&deviceId=' + deviceId;
return url;
}
throw new Error('Unrecognized MediaType');
}
function getVideoUrl(item) {
var maxBitrate = AppSettings.maxStreamingBitrate();
var info = getStreamInfo(ApiClient.serverAddress(), ApiClient.deviceId(), item, null, maxBitrate);
return info.url;
}
function getPlayerUrl(item, player) {
return player.scheme.replace('{0}', getVideoUrl(item));
}
function showPostPlayMenu(item, userId) {
function showPostPlayMenu(item) {
$('.externalPlayerPostPlayFlyout').popup("close").remove();
@ -379,23 +365,24 @@
$('.externalPlayerPostPlayFlyout').popup("close").remove();
ApiClient.stopActiveEncodings();
var position = 0;
if ($('#radioMarkInProgress', elem).checked()) {
var pct = $(".playstateSlider", elem).val();
var ticks = item.RunTimeTicks * (Number(pct) * .01);
ApiClient.markPlayed(userId, item.Id, new Date());
position = ticks;
}
else if (autoMarkWatched || $('#radioMarkWatched', elem).checked()) {
ApiClient.markPlayed(userId, item.Id, new Date());
position = currentMediaSource.RunTimeTicks;
}
else if ($('#radioMarkUnwatched', elem).checked()) {
ApiClient.markUnplayed(userId, item.Id);
position = 0;
}
onPlaybackStopped(position);
});
$(".playstateSlider", elem).on("change", function (e) {
@ -417,11 +404,11 @@
$('.externalPlayerFlyout').popup("close").remove();
}
function showMenuForItem(item, userId) {
function showMenuForItem(item, players) {
closePlayMenu();
var html = '<div data-role="popup" class="externalPlayerFlyout" data-theme="a">';
var html = '<div data-role="popup" class="externalPlayerFlyout" data-theme="a" data-dismissible="false">';
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>';
@ -429,9 +416,9 @@
html += '<div style="padding:1em;">';
html += getExternalPlayers().map(function (p) {
html += players.map(function (p) {
return '<a href="' + getPlayerUrl(item, p) + '" data-role="button" data-icon="play" class="btnExternalPlayer">' + p.name + '</a>';
return '<a href="' + p.url + '" data-role="button" data-icon="play" class="btnExternalPlayer" data-theme="b" data-mini="true">' + p.name + '</a>';
}).join('');
@ -449,12 +436,7 @@
$('.btnExternalPlayer', elem).on('click', function () {
closePlayMenu();
setTimeout(function () {
showPostPlayMenu(item, userId);
}, 500);
ExternalPlayer.onPlaybackStart();
});
}
@ -464,18 +446,41 @@
ApiClient.getItem(userId, itemId).done(function (item) {
setTimeout(function () {
getVideoStreamInfo(item).done(function (streamInfo) {
showMenuForItem(item, userId);
setTimeout(function () {
ExternalPlayer.showPlayerSelectionMenu(item, streamInfo.url, streamInfo.mimeType);
}, 500);
});
});
}
function getExternalPlayers(url, mimeType) {
var deferred = $.Deferred();
var players = [
{ name: 'Vlc', url: 'vlc://' + url, id: 'vlc' }
];
deferred.resolveWith(null, [players]);
return deferred.promise();
}
function showPlayerSelectionMenu(item, url, mimeType) {
ExternalPlayer.getExternalPlayers(url, mimeType).done(function (players) {
showMenuForItem(item, players);
});
}
window.ExternalPlayer = {
getUrl: getUrl,
showMenu: showPlayMenu,
onPlaybackStart: onPlaybackStart,
onPlaybackStopped: onPlaybackStopped,
getExternalPlayers: getExternalPlayers,
showMenu: showPlayMenu
showPlayerSelectionMenu: showPlayerSelectionMenu
};
})(window, window.appStorage);

View file

@ -177,8 +177,7 @@
html += '</div>';
}
$(elem).html(html).lazyChildren();
$(elem).createCardMenus();
$(elem).html(html).lazyChildren().createCardMenus();
});
}
@ -213,8 +212,7 @@
html += '</div>';
}
$(elem).html(html).lazyChildren();
$(elem).createCardMenus();
$(elem).html(html).lazyChildren().createCardMenus();
});
}
@ -316,8 +314,7 @@
html += '</div>';
}
$(elem).html(html).lazyChildren();
$(elem).createCardMenus();
$(elem).html(html).lazyChildren().createCardMenus();
});
}
@ -406,8 +403,7 @@
});
html += '</div>';
var elem = $('#channel' + channel.Id + '', page).html(html).lazyChildren().trigger('create');
$(elem).createCardMenus();
$('#channel' + channel.Id + '', page).html(html).lazyChildren().trigger('create').createCardMenus();
});
}

View file

@ -232,13 +232,20 @@
return html;
},
playInExternalPlayer: function(id) {
Dashboard.loadExternalPlayer().done(function () {
ExternalPlayer.showMenu(id);
});
},
showPlayMenu: function (positionTo, itemId, itemType, isFolder, mediaType, resumePositionTicks, showAddToPlaylist) {
var externalPlayers = ExternalPlayer.getExternalPlayers();
var externalPlayers = AppSettings.enableExternalPlayers();
if (!resumePositionTicks && mediaType != "Audio" && !isFolder) {
if (!externalPlayers.length || mediaType != "Video") {
if (!externalPlayers || mediaType != "Video") {
MediaController.play(itemId);
return;
}
@ -253,8 +260,8 @@
html += '<li><a href="#" onclick="MediaController.play(\'' + itemId + '\');LibraryBrowser.closePlayMenu();">' + Globalize.translate('ButtonPlay') + '</a></li>';
if (!isFolder && externalPlayers.length) {
html += '<li><a href="#" onclick="LibraryBrowser.closePlayMenu();ExternalPlayer.showMenu(\'' + itemId + '\');">' + Globalize.translate('ButtonPlayExternalPlayer') + '</a></li>';
if (!isFolder && externalPlayers) {
html += '<li><a href="#" onclick="LibraryBrowser.closePlayMenu();LibraryBrowser.playInExternalPlayer(\'' + itemId + '\');">' + Globalize.translate('ButtonPlayExternalPlayer') + '</a></li>';
}
if (resumePositionTicks) {

View file

@ -284,7 +284,7 @@
var id = this.getAttribute('data-itemid');
ExternalPlayer.showMenu(id);
LibraryBrowser.playInExternalPlayer(id);
return false;
}
@ -420,7 +420,7 @@
}
}
if (mediaType == 'Video' && ExternalPlayer.getExternalPlayers().length) {
if (mediaType == 'Video' && AppSettings.enableExternalPlayers()) {
html += '<li data-icon="play"><a href="#" class="btnExternalPlayer" data-itemid="' + itemId + '">' + Globalize.translate('ButtonPlayExternalPlayer') + '</a></li>';
}

View file

@ -30,13 +30,14 @@
html += '<button id="btnCast" class="btnCast btnDefaultCast headerButton headerButtonRight" type="button" data-role="none" style="display:none;"><div class="headerSelectedPlayer"></div><div class="btnCastImage"></div></button>';
}
html += '<button onclick="Search.showSearchPanel($.mobile.activePage);" type="button" data-role="none" class="headerButton headerButtonRight headerSearchButton" style="display:none;"><div class="fa fa-search" style="font-size:21px;"></div></button>';
html += '<div class="viewMenuSearch hide"><form class="viewMenuSearchForm">';
html += '<button onclick="Search.showSearchPanel();" type="button" data-role="none" class="headerButton headerButtonRight headerSearchButton" style="display:none;"><div class="fa fa-search" style="font-size:21px;"></div></button>';
html += '<div class="viewMenuSearch hide">';
html += '<form class="viewMenuSearchForm">';
html += '<input type="text" data-role="none" data-type="search" class="headerSearchInput" autocomplete="off" spellcheck="off" />';
html += '<div class="searchInputIcon fa fa-search"></div>';
html += '<button data-role="none" type="button" data-iconpos="notext" class="imageButton btnCloseSearch"><i class="fa fa-close"></i></button>';
html += '</form></div>';
html += '</form>';
html += '</div>';
html += '<button class="headerButton headerButtonRight headerUserButton" type="button" data-role="none" onclick="Dashboard.showUserFlyout(this);">';
@ -50,8 +51,8 @@
html += '</div>';
$(document.body).prepend(html);
$('.viewMenuBar').trigger('create').lazyChildren();
$(document.body).append(html);
$('.viewMenuBar').lazyChildren();
$(document).trigger('headercreated');
bindMenuEvents();
@ -100,18 +101,21 @@
if (AppInfo.isTouchPreferred) {
$('.libraryMenuButton').on('click', function () {
showLibraryMenu(false);
});
$('.dashboardMenuButton').on('click', function () {
showDashboardMenu(false);
});
$('.libraryMenuButton').on('click', showLibraryMenu);
$('.dashboardMenuButton').on('click', showDashboardMenu);
} else {
$('.libraryMenuButton').createHoverTouch().on('hovertouch', showLibraryMenu);
$('.dashboardMenuButton').createHoverTouch().on('hovertouch', showDashboardMenu);
}
// Have to wait for document ready here because otherwise
// we may see the jQM redirect back and forth problem
$(initViewMenuBarHeadroom);
}
function initViewMenuBarHeadroom() {
// grab an element
var viewMenuBar = document.getElementsByClassName("viewMenuBar")[0];
initHeadRoom(viewMenuBar);
@ -478,19 +482,16 @@
function updateContextText(page) {
var name = $(page)[0].getAttribute('data-contextname');
var jPage = $(page);
var name = jPage.attr('data-contextname');
if (name) {
$('.libraryMenuButtonText').html('<span>' + name + '</span>');
}
//else if ($(page).hasClass('type-interior')) {
// $('.libraryMenuButtonText').html('<span>' + 'Dashboard' + '</span>');
//}
else if ($(page).hasClass('allLibraryPage') || $(page).hasClass('type-interior')) {
else if (jPage.hasClass('allLibraryPage') || jPage.hasClass('type-interior')) {
$('.libraryMenuButtonText').html('<span class="logoLibraryMenuButtonText">EMBY</span>');
}
}
@ -511,7 +512,7 @@
function buildViewMenuBar(page) {
if ($(page).hasClass('standalonePage')) {
$('.viewMenuBar').remove();
$('.viewMenuBar').hide();
return;
}
@ -519,7 +520,7 @@
$('.viewMenuBar').remove();
}
var viewMenuBar = $('.viewMenuBar');
var viewMenuBar = $('.viewMenuBar').show();
if (!$('.viewMenuBar').length) {
renderHeader();
@ -539,24 +540,55 @@
updateViewMenuBarHeadroom(page, viewMenuBar);
requiresViewMenuRefresh = false;
}
}
// The first time we create the view menu bar, wait until doc ready + login validated
// Otherwise we run into the jQM redirect back and forth problem
var updateViewMenuBarBeforePageShow = false;
$(document).on('pageinit', ".page", function () {
var page = this;
$('.libraryViewNav', page).wrapInner('<div class="libraryViewNavInner"></div>');
$('.libraryViewNav a', page).each(function () {
this.innerHTML = '<span class="libraryViewNavLinkContent">' + this.innerHTML + '</span>';
$(function () {
onPageInitDocumentReady(page);
});
}).on('pagebeforeshowready', ".page", function () {
var page = this;
if (updateViewMenuBarBeforePageShow) {
onPageBeforeShowDocumentReady(page);
}
}).one('pageshowready', ".page", function () {
var page = this;
$(function () {
onPageBeforeShowDocumentReady(page);
updateViewMenuBarBeforePageShow = true;
});
}).on('pageshowready', ".page", function () {
var page = this;
onPageShowDocumentReady(page);
});
function onPageInitDocumentReady(page) {
$('.libraryViewNav', page).wrapInner('<div class="libraryViewNavInner"></div>');
$('.libraryViewNav a', page).each(function () {
this.innerHTML = '<span class="libraryViewNavLinkContent">' + this.innerHTML + '</span>';
});
}
function onPageBeforeShowDocumentReady(page) {
buildViewMenuBar(page);
var jpage = $(page);
@ -587,11 +619,9 @@
} else {
$(document.body).removeClass('dashboardDocument').removeClass('libraryDocument');
}
}
}).on('pageshow', ".libraryPage", function () {
var page = this;
function onPageShowDocumentReady(page) {
var elem = $('.libraryViewNavInner .ui-btn-active:visible', page);
if (elem.length) {
@ -600,7 +630,7 @@
// Scroll back up so in case vertical scroll was messed with
$(document).scrollTop(0);
}
});
}
function initHeadRoom(elem) {

View file

@ -229,7 +229,7 @@
self.play = function (options) {
doWithPlaybackValidation(function() {
doWithPlaybackValidation(function () {
if (typeof (options) === 'string') {
options = { ids: [options] };
}
@ -480,6 +480,82 @@
}, 300);
};
self.getPlaybackInfo = function (itemId, deviceProfile, startPosition, mediaSource, audioStreamIndex, subtitleStreamIndex, liveStreamId) {
var postData = {
DeviceProfile: deviceProfile
};
var query = {
UserId: Dashboard.getCurrentUserId(),
StartTimeTicks: startPosition || 0
};
if (audioStreamIndex != null) {
query.AudioStreamIndex = audioStreamIndex;
}
if (subtitleStreamIndex != null) {
query.SubtitleStreamIndex = subtitleStreamIndex;
}
if (mediaSource) {
query.MediaSourceId = mediaSource.Id;
}
if (liveStreamId) {
query.LiveStreamId = liveStreamId;
}
return ApiClient.ajax({
url: ApiClient.getUrl('Items/' + itemId + '/PlaybackInfo', query),
type: 'POST',
data: JSON.stringify(postData),
contentType: "application/json",
dataType: "json"
});
}
self.getLiveStream = function (itemId, playSessionId, deviceProfile, startPosition, mediaSource, audioStreamIndex, subtitleStreamIndex) {
var postData = {
DeviceProfile: deviceProfile,
OpenToken: mediaSource.OpenToken
};
var query = {
UserId: Dashboard.getCurrentUserId(),
StartTimeTicks: startPosition || 0,
ItemId: itemId,
PlaySessionId: playSessionId
};
if (audioStreamIndex != null) {
query.AudioStreamIndex = audioStreamIndex;
}
if (subtitleStreamIndex != null) {
query.SubtitleStreamIndex = subtitleStreamIndex;
}
return ApiClient.ajax({
url: ApiClient.getUrl('LiveStreams/Open', query),
type: 'POST',
data: JSON.stringify(postData),
contentType: "application/json",
dataType: "json"
});
};
self.supportsDirectPlay = function (mediaSource) {
if (mediaSource.SupportsDirectPlay && mediaSource.Protocol == 'Http' && !mediaSource.RequiredHttpHeaders.length) {
// TODO: Need to verify the host is going to be reachable
return true;
}
return false;
};
}
window.MediaController = new mediaController();

View file

@ -605,10 +605,11 @@
});
});
var idleHandlerTimeout;
function idleHandler() {
if (timeout) {
window.clearTimeout(timeout);
if (idleHandlerTimeout) {
window.clearTimeout(idleHandlerTimeout);
}
if (idleState == true) {
@ -618,7 +619,7 @@
idleState = false;
timeout = window.setTimeout(function () {
idleHandlerTimeout = window.setTimeout(function () {
idleState = true;
$('.hiddenOnIdle').addClass("inactive");
$('#videoPlayer').addClass('idlePlayer');
@ -978,11 +979,10 @@
function bindEventsForPlayback() {
var hideElementsOnIdle = !$.browser.mobile;
var hideElementsOnIdle = true;
if (hideElementsOnIdle) {
$('.itemVideo').off('mousemove.videoplayer keydown.videoplayer scroll.videoplayer', idleHandler);
$('.itemVideo').on('mousemove.videoplayer keydown.videoplayer scroll.videoplayer', idleHandler).trigger('mousemove');
$('.itemVideo').off('mousemove.videoplayer keydown.videoplayer scroll.videoplayer mousedown.videoplayer', idleHandler).on('mousemove.videoplayer keydown.videoplayer scroll.videoplayer mousedown.videoplayer', idleHandler).trigger('mousemove');
}
$(document).on('webkitfullscreenchange.videoplayer mozfullscreenchange.videoplayer msfullscreenchange.videoplayer fullscreenchange.videoplayer', function (e) {
@ -1012,14 +1012,14 @@
function unbindEventsForPlayback() {
$(document).off('webkitfullscreenchange.videoplayer mozfullscreenchange.videoplayer msfullscreenchange.videoplayer fullscreenchange.videoplayer');
$(document).off('.videoplayer');
// Stop playback on browser back button nav
$(window).off("popstate.videoplayer");
$(document.body).off("mousemove.videoplayer");
$('.itemVideo').off('mousemove.videoplayer keydown.videoplayer scroll.videoplayer');
$('.itemVideo').off('mousemove.videoplayer keydown.videoplayer scroll.videoplayer mousedown.videoplayer');
}
self.canAutoPlayVideo = function () {
@ -1084,7 +1084,7 @@
self.playVideoInternal = function (item, mediaSource, startPosition, streamInfo) {
var videoUrl = streamInfo.url;
var contentType = streamInfo.contentType;
var contentType = streamInfo.mimeType;
var startPositionInSeekParam = streamInfo.startPositionInSeekParam;
self.startTimeTicksOffset = streamInfo.startTimeTicksOffset;
@ -1296,7 +1296,6 @@
}).on("dblclick.mediaplayerevent", function () {
self.toggleFullscreen();
});
bindEventsForPlayback();

View file

@ -183,7 +183,7 @@
Protocol: 'hls'
});
if (canPlayAac) {
if (canPlayAac && $.browser.safari) {
profile.TranscodingProfiles.push({
Container: 'aac',
Type: 'Audio',
@ -471,7 +471,7 @@
subtitleStreamIndex = parseInt(subtitleStreamIndex);
}
getPlaybackInfo(self.currentItem.Id, deviceProfile, ticks, self.currentMediaSource, audioStreamIndex, subtitleStreamIndex, liveStreamId).done(function (result) {
MediaController.getPlaybackInfo(self.currentItem.Id, deviceProfile, ticks, self.currentMediaSource, audioStreamIndex, subtitleStreamIndex, liveStreamId).done(function (result) {
if (validatePlaybackInfoResult(result)) {
@ -685,22 +685,11 @@
});
};
function supportsDirectPlay(mediaSource) {
if (mediaSource.SupportsDirectPlay && mediaSource.Protocol == 'Http' && !mediaSource.RequiredHttpHeaders.length) {
// TODO: Need to verify the host is going to be reachable
return true;
}
return false;
}
function getOptimalMediaSource(mediaType, versions) {
var optimalVersion = versions.filter(function (v) {
v.enableDirectPlay = supportsDirectPlay(v);
v.enableDirectPlay = MediaController.supportsDirectPlay(v);
return v.enableDirectPlay;
@ -719,71 +708,6 @@
})[0];
}
function getPlaybackInfo(itemId, deviceProfile, startPosition, mediaSource, audioStreamIndex, subtitleStreamIndex, liveStreamId) {
var postData = {
DeviceProfile: deviceProfile
};
var query = {
UserId: Dashboard.getCurrentUserId(),
StartTimeTicks: startPosition || 0
};
if (audioStreamIndex != null) {
query.AudioStreamIndex = audioStreamIndex;
}
if (subtitleStreamIndex != null) {
query.SubtitleStreamIndex = subtitleStreamIndex;
}
if (mediaSource) {
query.MediaSourceId = mediaSource.Id;
}
if (liveStreamId) {
query.LiveStreamId = liveStreamId;
}
return ApiClient.ajax({
url: ApiClient.getUrl('Items/' + itemId + '/PlaybackInfo', query),
type: 'POST',
data: JSON.stringify(postData),
contentType: "application/json",
dataType: "json"
});
}
function getLiveStream(itemId, playSessionId, deviceProfile, startPosition, mediaSource, audioStreamIndex, subtitleStreamIndex) {
var postData = {
DeviceProfile: deviceProfile,
OpenToken: mediaSource.OpenToken
};
var query = {
UserId: Dashboard.getCurrentUserId(),
StartTimeTicks: startPosition || 0,
ItemId: itemId,
PlaySessionId: playSessionId
};
if (audioStreamIndex != null) {
query.AudioStreamIndex = audioStreamIndex;
}
if (subtitleStreamIndex != null) {
query.SubtitleStreamIndex = subtitleStreamIndex;
}
return ApiClient.ajax({
url: ApiClient.getUrl('LiveStreams/Open', query),
type: 'POST',
data: JSON.stringify(postData),
contentType: "application/json",
dataType: "json"
});
}
self.createStreamInfo = function (type, item, mediaSource, startPosition) {
var mediaUrl;
@ -867,7 +791,7 @@
return {
url: mediaUrl,
contentType: contentType,
mimeType: contentType,
startTimeTicksOffset: startTimeTicksOffset,
startPositionInSeekParam: startPositionInSeekParam,
playMethod: playMethod
@ -900,7 +824,7 @@
Dashboard.showModalLoadingMsg();
}
getPlaybackInfo(item.Id, deviceProfile, startPosition).done(function (playbackInfoResult) {
MediaController.getPlaybackInfo(item.Id, deviceProfile, startPosition).done(function (playbackInfoResult) {
if (validatePlaybackInfoResult(playbackInfoResult)) {
@ -910,9 +834,9 @@
if (mediaSource.RequiresOpening) {
getLiveStream(item.Id, playbackInfoResult.PlaySessionId, deviceProfile, startPosition, mediaSource, null, null).done(function (openLiveStreamResult) {
MediaController.getLiveStream(item.Id, playbackInfoResult.PlaySessionId, deviceProfile, startPosition, mediaSource, null, null).done(function (openLiveStreamResult) {
openLiveStreamResult.MediaSource.enableDirectPlay = supportsDirectPlay(openLiveStreamResult.MediaSource);
openLiveStreamResult.MediaSource.enableDirectPlay = MediaController.supportsDirectPlay(openLiveStreamResult.MediaSource);
playInternalPostMediaSourceSelection(item, openLiveStreamResult.MediaSource, startPosition, callback);
});
@ -1474,8 +1398,17 @@
if (item) {
state.NowPlayingItem = state.NowPlayingItem || {};
var nowPlayingItem = state.NowPlayingItem;
state.NowPlayingItem = self.getNowPlayingItemForReporting(item, mediaSource);
}
return state;
};
self.getNowPlayingItemForReporting = function (item, mediaSource) {
var nowPlayingItem = {};
nowPlayingItem.RunTimeTicks = mediaSource.RunTimeTicks;
nowPlayingItem.Id = item.Id;
nowPlayingItem.MediaType = item.MediaType;
@ -1540,9 +1473,8 @@
nowPlayingItem.LogoItemId = item.ParentLogoItemId;
nowPlayingItem.LogoImageTag = item.ParentLogoImageTag;
}
}
return state;
return nowPlayingItem;
};
self.beginPlayerUpdates = function () {

View file

@ -2,21 +2,10 @@
function loadForm(page, userId, displayPreferences) {
var externalPlayers = JSON.parse(appStorage.getItem('externalplayers') || '[]');
$('#selectMaxBitrate', page).val(AppSettings.maxStreamingBitrate()).selectmenu("refresh");
$('#selectMaxChromecastBitrate', page).val(AppSettings.maxChromecastBitrate()).selectmenu("refresh");
$('.chkExternalPlayer', page).each(function () {
var chk = this;
chk.checked = externalPlayers.filter(function (p) {
return p.name == chk.getAttribute('data-name');
}).length > 0;
}).checkboxradio('refresh');
$('#chkExternalVideoPlayer', page).checked(AppSettings.enableExternalPlayers()).checkboxradio("refresh");
$('#selectThemeSong', page).val(appStorage.getItem('enableThemeSongs-' + userId) || '').selectmenu("refresh");
$('#selectBackdrop', page).val(appStorage.getItem('enableBackdrops-' + userId) || '').selectmenu("refresh");
@ -55,16 +44,7 @@
Dashboard.showLoadingMsg();
var externalPlayers = $('.chkExternalPlayer:checked', page).get().map(function (i) {
return {
name: i.getAttribute('data-name'),
scheme: i.getAttribute('data-scheme')
};
});
appStorage.setItem('externalplayers', JSON.stringify(externalPlayers));
AppSettings.enableExternalPlayers($('#chkExternalVideoPlayer', page).checked());
AppSettings.maxStreamingBitrate($('#selectMaxBitrate', page).val());
AppSettings.maxChromecastBitrate($('#selectMaxChromecastBitrate', page).val());
@ -133,6 +113,14 @@
}
return parseInt(store.getItem('chromecastBitrate') || '') || 3000000;
},
enableExternalPlayers: function (val) {
if (val != null) {
store.setItem('externalplayers', val.toString());
}
return store.getItem('externalplayers') == 'true';
}
};

View file

@ -58,9 +58,11 @@
var self = this;
self.showSearchPanel = function (page) {
self.showSearchPanel = function () {
$('.viewMenuSearch').removeClass('hide');
var viewMenuSearch = $('.viewMenuSearch');
viewMenuSearch.removeClass('hide');
$('.headerSearchInput').focus();
};
}

View file

@ -191,7 +191,6 @@ var Dashboard = {
} else {
loginPage = 'login.html';
}
Dashboard.navigate(loginPage);
}
@ -1491,6 +1490,25 @@ var Dashboard = {
Dashboard.ready(function () {
$(page).trigger(name);
});
},
loadExternalPlayer: function () {
var deferred = DeferredBuilder.Deferred();
require(['scripts/externalplayer.js'], function () {
if (Dashboard.isRunningInCordova()) {
require(['thirdparty/cordova/externalplayer.js'], function () {
deferred.resolve();
});
} else {
deferred.resolve();
}
});
return deferred.promise();
}
};
@ -1560,6 +1578,10 @@ var AppInfo = {};
else {
AppInfo.enableFooterNotifications = true;
AppInfo.enableSupporterMembership = true;
if (!$.browser.android && !$.browser.ipad && !$.browser.iphone) {
AppInfo.enableAppLayouts = true;
}
}
AppInfo.enableUserImage = true;
@ -1576,6 +1598,7 @@ var AppInfo = {};
.on("websocketmessage.dashboard", Dashboard.onWebSocketMessageReceived)
.on('requestfail.dashboard', Dashboard.onRequestFail);
}
//localStorage.clear();
function createConnectionManager(appInfo) {
@ -1771,9 +1794,6 @@ var AppInfo = {};
$(document.body).append(footerHtml);
var footerElem = $('.footer', document.body);
footerElem.trigger('create');
$(window).on("beforeunload", function () {
var apiClient = window.ApiClient;
@ -1928,20 +1948,6 @@ $(document).on('pagecreate', ".page", function () {
$('.localnav a, .libraryViewNav a').attr('data-transition', 'none');
}).on('pageshow', ".page", function () {
var page = this;
var require = this.getAttribute('data-require');
if (require) {
requirejs(require.split(','), function () {
Dashboard.firePageEvent(page, 'pageshowready');
});
} else {
Dashboard.firePageEvent(page, 'pageshowready');
}
}).on('pagebeforeshow', ".page", function () {
var page = this;
@ -1956,7 +1962,21 @@ $(document).on('pagecreate', ".page", function () {
Dashboard.firePageEvent(page, 'pagebeforeshowready');
}
}).on('pagebeforeshowready', ".page", function () {
}).on('pageshow', ".page", function () {
var page = this;
var require = this.getAttribute('data-require');
if (require) {
requirejs(require.split(','), function () {
Dashboard.firePageEvent(page, 'pageshowbeginready');
});
} else {
Dashboard.firePageEvent(page, 'pageshowbeginready');
}
}).on('pageshowbeginready', ".page", function () {
var page = $(this);
@ -1977,9 +1997,6 @@ $(document).on('pagecreate', ".page", function () {
Dashboard.ensureToolsMenu(page, user);
}
});
Dashboard.ensureHeader(page);
Dashboard.ensurePageTitle(page);
}
else {
@ -1989,7 +2006,7 @@ $(document).on('pagecreate', ".page", function () {
if (isConnectMode) {
if (!Dashboard.isServerlessPage()) {
Dashboard.logout(true);
Dashboard.logout();
return;
}
}
@ -1997,13 +2014,15 @@ $(document).on('pagecreate', ".page", function () {
if (!isConnectMode && this.id !== "loginPage" && !page.hasClass('forgotPasswordPage') && !page.hasClass('wizardPage')) {
console.log('Not logged into server. Redirecting to login.');
Dashboard.logout(true);
Dashboard.logout();
return;
}
}
Dashboard.firePageEvent(page, 'pageshowready');
Dashboard.ensureHeader(page);
Dashboard.ensurePageTitle(page);
}
if (apiClient && !apiClient.isWebSocketOpen()) {
Dashboard.refreshSystemInfoFromServer();

View file

@ -2,11 +2,13 @@
globalScope.AjaxApi = {
param: function(params) {
param: function (params) {
return jQuery.param(params);
},
ajax: function(request) {
ajax: function (request) {
request.timeout = request.timeout || 30000;
try {
return jQuery.ajax(request);

View file

@ -0,0 +1,50 @@
(function () {
function showPlayerSelectionMenu(item, url, mimeType) {
window.plugins.launcher.launch({
uri: url,
dataType: mimeType
}, function () {
console.log('plugin launch success');
ExternalPlayer.onPlaybackStart();
}, function () {
console.log('plugin launch error');
ExternalPlayer.onPlaybackStart();
});
}
function getExternalPlayers(url, mimeType) {
var deferred = $.Deferred();
window.plugins.launcher.canLaunch({
uri: url,
dataType: mimeType,
getAppList: true
}, function (data) {
console.log('plugin canLaunch succcess');
var players = data.appList.map(function (p) {
});
deferred.resolveWith(null, [players]);
}, function () {
console.log('plugin canLaunch error');
deferred.reject();
});
deferred.resolveWith(null, [players]);
return deferred.promise();
}
window.ExternalPlayer.getExternalPlayers = getExternalPlayers;
window.ExternalPlayer.showPlayerSelectionMenu = showPlayerSelectionMenu;
})();