mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
fixes #295 - Add play to vlc option
This commit is contained in:
parent
c6309d5001
commit
22eb703c65
16 changed files with 545 additions and 61 deletions
Binary file not shown.
BIN
dashboard-ui/css/fonts/mblogo.eot
Normal file
BIN
dashboard-ui/css/fonts/mblogo.eot
Normal file
Binary file not shown.
BIN
dashboard-ui/css/fonts/mblogo.ttf
Normal file
BIN
dashboard-ui/css/fonts/mblogo.ttf
Normal file
Binary file not shown.
BIN
dashboard-ui/css/fonts/mblogo.woff
Normal file
BIN
dashboard-ui/css/fonts/mblogo.woff
Normal file
Binary file not shown.
|
@ -566,7 +566,8 @@ a.itemTag:hover {
|
|||
.libraryPanelHeader {
|
||||
margin: 5px 0 15px 0;
|
||||
font-size: 15px;
|
||||
font-family: Gotham;
|
||||
font-family: MBLogo;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
.libraryPanelHeader a {
|
||||
|
|
|
@ -135,7 +135,11 @@
|
|||
padding-left: 0 !important;
|
||||
margin-left: -8px;
|
||||
cursor: default;
|
||||
font-family: Gotham;
|
||||
}
|
||||
|
||||
.logoLibraryMenuButtonText {
|
||||
font-family: MBLogo;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
.viewMenuBar {
|
||||
|
|
|
@ -62,10 +62,11 @@
|
|||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Gotham';
|
||||
font-family: 'MBLogo';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Gotham'), url(fonts/gotham-book.woff) format('woff');
|
||||
font-weight: 200;
|
||||
src: url('fonts/mblogo.eot');
|
||||
src: url('fonts/mblogo.eot?#iefix') format('embedded-opentype'), url('fonts/mblogo.woff') format('woff'), url('fonts/mblogo.ttf') format('truetype');
|
||||
}
|
||||
|
||||
* {
|
||||
|
|
|
@ -108,6 +108,16 @@
|
|||
</li>
|
||||
</ul>
|
||||
|
||||
<div style="margin: 0 1em;">
|
||||
<fieldset data-role="controlgroup">
|
||||
<legend>${LabelExternalPlayers}</legend>
|
||||
<input type="checkbox" id="chkVlc" class="chkExternalPlayer" data-name="vlc" data-scheme="vlc://{0}" />
|
||||
<label for="chkVlc">Vlc</label>
|
||||
</fieldset>
|
||||
<div style="padding: 0 2px;">${LabelExternalPlayersHelp}</div>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<ul data-role="listview" class="ulForm">
|
||||
<li>
|
||||
|
|
|
@ -525,44 +525,4 @@ function ticks_to_human(str) {
|
|||
}
|
||||
};
|
||||
|
||||
})(window);
|
||||
|
||||
(function (window) {
|
||||
|
||||
function myStore(defaultObject) {
|
||||
|
||||
var self = this;
|
||||
self.localData = {};
|
||||
|
||||
self.setItem = function (name, value) {
|
||||
|
||||
if (defaultObject) {
|
||||
defaultObject.setItem(name, value);
|
||||
} else {
|
||||
self.localData[name] = value;
|
||||
}
|
||||
};
|
||||
|
||||
self.getItem = function (name) {
|
||||
|
||||
if (defaultObject) {
|
||||
return defaultObject.getItem(name);
|
||||
}
|
||||
|
||||
return self.localData[name];
|
||||
};
|
||||
|
||||
self.removeItem = function (name) {
|
||||
|
||||
if (defaultObject) {
|
||||
defaultObject.removeItem(name);
|
||||
} else {
|
||||
self.localData[name] = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
window.store = new myStore(window.localStorage);
|
||||
window.sessionStore = new myStore(window.sessionStorage);
|
||||
|
||||
})(window);
|
411
dashboard-ui/scripts/externalplayer.js
Normal file
411
dashboard-ui/scripts/externalplayer.js
Normal file
|
@ -0,0 +1,411 @@
|
|||
(function (window, store) {
|
||||
|
||||
function getExternalPlayers() {
|
||||
return JSON.parse(store.getItem('externalplayers') || '[]');
|
||||
}
|
||||
|
||||
function getUrl(player, item) {
|
||||
|
||||
return 'vlc://http://www.google.com';
|
||||
|
||||
}
|
||||
|
||||
function getCodecLimits() {
|
||||
|
||||
return {
|
||||
|
||||
maxVideoAudioChannels: 6,
|
||||
maxAudioChannels: 2,
|
||||
maxVideoLevel: 50,
|
||||
maxWidth: 1920,
|
||||
maxHeight: 1080,
|
||||
maxSampleRate: 48000
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
function canDirectStream(mediaType, mediaSource, maxBitrate) {
|
||||
|
||||
// If bitrate is unknown don't direct stream
|
||||
if (!mediaSource.Bitrate || mediaSource.Bitrate > maxBitrate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var codecLimits = getCodecLimits();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return mediaSource.Protocol == 'File';
|
||||
}
|
||||
|
||||
throw new Error('Unrecognized MediaType');
|
||||
}
|
||||
|
||||
function canPlayAudioStreamDirect(audioStream, isVideo) {
|
||||
|
||||
var audioCodec = (audioStream.Codec || '').toLowerCase().replace('-', '');
|
||||
|
||||
if (audioCodec.indexOf('aac') == -1 &&
|
||||
audioCodec.indexOf('mp3') == -1 &&
|
||||
audioCodec.indexOf('mpeg') == -1) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
var codecLimits = getCodecLimits();
|
||||
|
||||
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) {
|
||||
|
||||
if (mediaType == "Audio") {
|
||||
return false;
|
||||
}
|
||||
else if (mediaType == "Video") {
|
||||
|
||||
return mediaSource.MediaStreams.filter(function (m) {
|
||||
|
||||
return m.Type == "Video" && (m.Codec || '').toLowerCase() == 'h264';
|
||||
|
||||
}).length > 0;
|
||||
}
|
||||
|
||||
throw new Error('Unrecognized MediaType');
|
||||
}
|
||||
|
||||
function getStreamByIndex(streams, type, index) {
|
||||
return streams.filter(function (s) {
|
||||
|
||||
return s.Type == type && s.Index == index;
|
||||
|
||||
})[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';
|
||||
})[0];
|
||||
}
|
||||
|
||||
m.subtitleStream = mediaSourceId == m.Id && subtitleStreamIndex != null ?
|
||||
getStreamByIndex(m.MediaStreams, 'Subtitle', subtitleStreamIndex) :
|
||||
getStreamByIndex(m.MediaStreams, 'Subtitle', m.DefaultSubtitleStreamIndex);
|
||||
|
||||
return !mediaSourceId || m.Id == mediaSourceId;
|
||||
|
||||
});
|
||||
|
||||
// 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')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m.subtitleStream) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return canDirectStream(item.MediaType, m, maxBitrate, audioStream);
|
||||
|
||||
})[0];
|
||||
|
||||
if (source) {
|
||||
return {
|
||||
mediaSource: source,
|
||||
isStatic: true,
|
||||
streamContainer: source.Container
|
||||
};
|
||||
}
|
||||
|
||||
// Find first one with supported codec
|
||||
source = sources.filter(function (m) {
|
||||
|
||||
return isSupportedCodec(item.MediaType, m);
|
||||
|
||||
})[0];
|
||||
|
||||
source = source || sources[0];
|
||||
|
||||
var container = item.MediaType == 'Audio' ? 'mp3' : 'm3u8';
|
||||
|
||||
// Default to first one
|
||||
return {
|
||||
mediaSource: source,
|
||||
isStatic: false,
|
||||
streamContainer: container
|
||||
};
|
||||
}
|
||||
|
||||
function getStreamInfo(serverAddress, deviceId, item, startPositionTicks, maxBitrate, mediaSourceId, audioStreamIndex, subtitleStreamIndex) {
|
||||
|
||||
var mediaSourceInfo = getMediaSourceInfo(item, maxBitrate, mediaSourceId, audioStreamIndex, subtitleStreamIndex);
|
||||
|
||||
var url = getStreamUrl(serverAddress, deviceId, item.MediaType, item.Id, mediaSourceInfo, startPositionTicks, maxBitrate);
|
||||
|
||||
if (mediaSourceInfo.subtitleStream) {
|
||||
url += "&SubtitleStreamIndex=" + mediaSourceInfo.Index;
|
||||
}
|
||||
|
||||
mediaSourceInfo.url = url;
|
||||
|
||||
return mediaSourceInfo;
|
||||
}
|
||||
|
||||
function getStreamUrl(serverAddress, deviceId, mediaType, itemId, mediaSourceInfo, startPositionTicks, maxBitrate) {
|
||||
|
||||
var url;
|
||||
|
||||
var codecLimits = getCodecLimits();
|
||||
|
||||
if (mediaType == 'Audio') {
|
||||
|
||||
url = serverAddress + '/mediabrowser/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 (maxBitrate) {
|
||||
url += '&audiobitrate=' + Math.min(maxBitrate, 320000).toString();
|
||||
}
|
||||
|
||||
url += '&deviceId=' + deviceId;
|
||||
}
|
||||
|
||||
return url;
|
||||
|
||||
}
|
||||
else if (mediaType == 'Video') {
|
||||
|
||||
if (mediaSourceInfo.isStatic) {
|
||||
url = serverAddress + '/mediabrowser/videos/' + itemId + '/stream.' + mediaSourceInfo.streamContainer + '?static=true';
|
||||
}
|
||||
else {
|
||||
url = serverAddress + '/mediabrowser/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 += '&maxheight=' + codecLimits.maxHeight;
|
||||
|
||||
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 = parseInt(store.getItem('preferredVideoBitrate') || '') || 1500000;
|
||||
|
||||
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) {
|
||||
|
||||
$('.externalPlayerPostPlayFlyout').popup("close").remove();
|
||||
|
||||
var html = '<div data-role="popup" class="externalPlayerPostPlayFlyout" data-history="false" data-theme="a" data-dismissible="false">';
|
||||
|
||||
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>';
|
||||
|
||||
html += '<div style="padding:1em;">';
|
||||
|
||||
if (item.RunTimeTicks) {
|
||||
html += '<div>';
|
||||
html += '<label for="chkMarkWatched">' + Globalize.translate('OptionMarkWatched') + '</label>';
|
||||
html += '<input type="checkbox" id="chkMarkWatched" checked="checked" />';
|
||||
html += '<div class="fieldDescription">' + Globalize.translate('OptionMarkWatchedHelp') + '</div>';
|
||||
html += '</div>';
|
||||
|
||||
html += '<br/>';
|
||||
}
|
||||
|
||||
html += '<button type="button" class="btnDone" data-theme="b" data-icon="check">' + Globalize.translate('ButtonImDone') + '</button>';
|
||||
|
||||
html += '</div>';
|
||||
|
||||
html += '</div>';
|
||||
|
||||
$(document.body).append(html);
|
||||
|
||||
var elem = $('.externalPlayerPostPlayFlyout').popup({}).trigger('create').popup("open").on("popupafterclose", function () {
|
||||
|
||||
$(this).off("popupafterclose").remove();
|
||||
|
||||
});
|
||||
|
||||
$('.btnDone', elem).on('click', function () {
|
||||
|
||||
$('.externalPlayerPostPlayFlyout').popup("close").remove();
|
||||
|
||||
ApiClient.stopActiveEncodings();
|
||||
|
||||
if ($('#chkMarkWatched', elem).checked()) {
|
||||
|
||||
ApiClient.markPlayed(userId, item.Id, new Date());
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function closePlayMenu() {
|
||||
$('.externalPlayerFlyout').popup("close").remove();
|
||||
}
|
||||
|
||||
function showMenuForItem(item, userId) {
|
||||
|
||||
closePlayMenu();
|
||||
|
||||
var html = '<div data-role="popup" class="externalPlayerFlyout" data-history="false" data-theme="a">';
|
||||
|
||||
html += '<ul data-role="listview" style="min-width: 200px;">';
|
||||
html += '<li data-role="list-divider" style="padding: 1em;">' + Globalize.translate('HeaderSelectExternalPlayer') + '</li>';
|
||||
html += '</ul>';
|
||||
|
||||
html += '<div style="padding:1em;">';
|
||||
|
||||
html += getExternalPlayers().map(function (p) {
|
||||
|
||||
return '<a href="' + getPlayerUrl(item, p) + '" data-role="button" data-icon="play" class="btnExternalPlayer">' + p.name + '</a>';
|
||||
|
||||
}).join('');
|
||||
|
||||
html += '</div>';
|
||||
|
||||
html += '</div>';
|
||||
|
||||
$(document.body).append(html);
|
||||
|
||||
var elem = $('.externalPlayerFlyout').popup({}).trigger('create').popup("open").on("popupafterclose", function () {
|
||||
|
||||
$(this).off("popupafterclose").remove();
|
||||
|
||||
});
|
||||
|
||||
$('.btnExternalPlayer', elem).on('click', function () {
|
||||
|
||||
closePlayMenu();
|
||||
|
||||
setTimeout(function () {
|
||||
|
||||
showPostPlayMenu(item, userId);
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
|
||||
function showPlayMenu(itemId) {
|
||||
|
||||
var userId = Dashboard.getCurrentUserId();
|
||||
|
||||
ApiClient.getItem(userId, itemId).done(function (item) {
|
||||
|
||||
setTimeout(function () {
|
||||
|
||||
showMenuForItem(item, userId);
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
|
||||
window.ExternalPlayer = {
|
||||
|
||||
getUrl: getUrl,
|
||||
getExternalPlayers: getExternalPlayers,
|
||||
showMenu: showPlayMenu
|
||||
};
|
||||
|
||||
})(window, window.store);
|
|
@ -238,9 +238,14 @@
|
|||
|
||||
showPlayMenu: function (positionTo, itemId, itemType, isFolder, mediaType, resumePositionTicks, showAddToPlaylist) {
|
||||
|
||||
var externalPlayers = ExternalPlayer.getExternalPlayers();
|
||||
|
||||
if (!resumePositionTicks && mediaType != "Audio" && !isFolder) {
|
||||
MediaController.play(itemId);
|
||||
return;
|
||||
|
||||
if (!externalPlayers.length || mediaType != "Video") {
|
||||
MediaController.play(itemId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$('.playFlyout').popup("close").remove();
|
||||
|
@ -252,6 +257,10 @@
|
|||
|
||||
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 (resumePositionTicks) {
|
||||
html += '<li><a href="#" onclick="MediaController.play({ids:[\'' + itemId + '\'],startPositionTicks:' + resumePositionTicks + '});LibraryBrowser.closePlayMenu();">' + Globalize.translate('ButtonResume') + '</a></li>';
|
||||
}
|
||||
|
|
|
@ -234,6 +234,17 @@
|
|||
return false;
|
||||
}
|
||||
|
||||
function onExternalPlayerButtonClick() {
|
||||
|
||||
closeContextMenu();
|
||||
|
||||
var id = this.getAttribute('data-itemid');
|
||||
|
||||
ExternalPlayer.showMenu(id);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function onPlayAllFromHereButtonClick() {
|
||||
|
||||
var index = this.getAttribute('data-index');
|
||||
|
@ -358,6 +369,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
if (mediaType == 'Video' && ExternalPlayer.getExternalPlayers().length) {
|
||||
html += '<li data-icon="play"><a href="#" class="btnExternalPlayer" data-itemid="' + itemId + '">' + Globalize.translate('ButtonPlayExternalPlayer') + '</a></li>';
|
||||
}
|
||||
|
||||
if (playbackPositionTicks && mediaType != "Audio") {
|
||||
html += '<li data-icon="play"><a href="#" class="btnResume" data-ticks="' + playbackPositionTicks + '" data-itemid="' + itemId + '">' + Globalize.translate('ButtonResume') + '</a></li>';
|
||||
}
|
||||
|
@ -405,6 +420,7 @@
|
|||
$('.btnRemoveFromPlaylist', elem).on('click', onRemoveFromPlaylistButtonClick);
|
||||
$('.btnPlayAllFromHere', elem).on('click', onPlayAllFromHereButtonClick);
|
||||
$('.btnQueueAllFromHere', elem).on('click', onQueueAllFromHereButtonClick);
|
||||
$('.btnExternalPlayer', elem).on('click', onExternalPlayerButtonClick);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -332,7 +332,7 @@
|
|||
|
||||
//}
|
||||
else if ($(page).hasClass('allLibraryPage') || $(page).hasClass('type-interior')) {
|
||||
$('.libraryMenuButtonText').html('<span>MEDIA</span><span class="mediaBrowserAccent">BROWSER</span>');
|
||||
$('.libraryMenuButtonText').html('<span class="logoLibraryMenuButtonText">MEDIA</span><span class="logoLibraryMenuButtonText mediaBrowserAccent">BROWSER</span>');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,19 @@
|
|||
|
||||
function loadForm(page, userId, displayPreferences) {
|
||||
|
||||
var externalPlayers = JSON.parse(store.getItem('externalplayers') || '[]');
|
||||
|
||||
$('.chkExternalPlayer', page).each(function () {
|
||||
|
||||
var chk = this;
|
||||
chk.checked = externalPlayers.filter(function (p) {
|
||||
|
||||
return p.name == chk.getAttribute('data-name');
|
||||
|
||||
}).length > 0;
|
||||
|
||||
}).checkboxradio('refresh');
|
||||
|
||||
$('#selectThemeSong', page).val(store.getItem('enableThemeSongs-' + userId) || '').selectmenu("refresh");
|
||||
$('#selectBackdrop', page).val(store.getItem('enableBackdrops-' + userId) || '').selectmenu("refresh");
|
||||
|
||||
|
@ -36,6 +49,17 @@
|
|||
|
||||
Dashboard.showLoadingMsg();
|
||||
|
||||
var externalPlayers = $('.chkExternalPlayer:checked', page).get().map(function (i) {
|
||||
|
||||
return {
|
||||
name: i.getAttribute('data-name'),
|
||||
scheme: i.getAttribute('data-scheme')
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
store.setItem('externalplayers', JSON.stringify(externalPlayers));
|
||||
|
||||
var userId = getParameterByName('userId') || Dashboard.getCurrentUserId();
|
||||
|
||||
ApiClient.getDisplayPreferences('home', userId, 'webclient').done(function (result) {
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
var html = '<div data-role="popup" class="userMenu" data-history="false" data-theme="a">';
|
||||
|
||||
html += '<ul data-role="listview" style="min-width: 180px;">';
|
||||
html += '<li data-role="list-divider">Menu</li>';
|
||||
html += '<li data-role="list-divider">' + Globalize.translate('HeaderMenu') + '</li>';
|
||||
|
||||
html += '<li><a href="#" class="btnDeleteUser" data-userid="' + userId + '">' + Globalize.translate('ButtonDelete') + '</a></li>';
|
||||
|
||||
|
|
|
@ -1,8 +1,59 @@
|
|||
if (!window.MediaBrowser) {
|
||||
(function (window) {
|
||||
|
||||
function myStore(defaultObject) {
|
||||
|
||||
var self = this;
|
||||
self.localData = {};
|
||||
|
||||
var isDefaultAvailable;
|
||||
|
||||
if (defaultObject) {
|
||||
try {
|
||||
defaultObject.setItem('_test', '0');
|
||||
isDefaultAvailable = true;
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
self.setItem = function (name, value) {
|
||||
|
||||
if (isDefaultAvailable) {
|
||||
defaultObject.setItem(name, value);
|
||||
} else {
|
||||
self.localData[name] = value;
|
||||
}
|
||||
};
|
||||
|
||||
self.getItem = function (name) {
|
||||
|
||||
if (isDefaultAvailable) {
|
||||
return defaultObject.getItem(name);
|
||||
}
|
||||
|
||||
return self.localData[name];
|
||||
};
|
||||
|
||||
self.removeItem = function (name) {
|
||||
|
||||
if (isDefaultAvailable) {
|
||||
defaultObject.removeItem(name);
|
||||
} else {
|
||||
self.localData[name] = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
window.store = new myStore(window.localStorage);
|
||||
window.sessionStore = new myStore(window.sessionStorage);
|
||||
|
||||
})(window);
|
||||
|
||||
if (!window.MediaBrowser) {
|
||||
window.MediaBrowser = {};
|
||||
}
|
||||
|
||||
MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, window, FileReader, localStorage) {
|
||||
MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, window, FileReader, store) {
|
||||
|
||||
function generateDeviceId() {
|
||||
|
||||
|
@ -13,17 +64,14 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
|
|||
|
||||
var randomId = '';
|
||||
|
||||
if (localStorage) {
|
||||
// Since the above is not guaranteed to be unique per device, add a little more
|
||||
randomId = store.getItem('randomId');
|
||||
|
||||
// Since the above is not guaranteed to be unique per device, add a little more
|
||||
randomId = localStorage.getItem('randomId');
|
||||
if (!randomId) {
|
||||
|
||||
if (!randomId) {
|
||||
randomId = new Date().getTime();
|
||||
|
||||
randomId = new Date().getTime();
|
||||
|
||||
localStorage.setItem('randomId', randomId.toString());
|
||||
}
|
||||
store.setItem('randomId', randomId.toString());
|
||||
}
|
||||
|
||||
keys.push(randomId);
|
||||
|
@ -70,7 +118,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
|
|||
return currentUserId;
|
||||
};
|
||||
|
||||
self.accessToken = function() {
|
||||
self.accessToken = function () {
|
||||
return accessToken;
|
||||
};
|
||||
|
||||
|
@ -3226,7 +3274,7 @@ MediaBrowser.ApiClient = function ($, navigator, JSON, WebSocket, setTimeout, wi
|
|||
|
||||
};
|
||||
|
||||
}(jQuery, navigator, window.JSON, window.WebSocket, setTimeout, window, window.FileReader, window.localStorage);
|
||||
}(jQuery, navigator, window.JSON, window.WebSocket, setTimeout, window, window.FileReader, window.store);
|
||||
|
||||
/**
|
||||
* Provides a friendly way to create an api client instance using information from the browser's current url
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue