mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
vulcanize
This commit is contained in:
parent
07df993238
commit
55e40bdcf7
52 changed files with 12309 additions and 33 deletions
46
dashboard-ui/cordova/android/androidcredentials.js
vendored
Normal file
46
dashboard-ui/cordova/android/androidcredentials.js
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
(function () {
|
||||
|
||||
function updateCredentials() {
|
||||
|
||||
console.log('sending updated credentials to ApiClientBridge');
|
||||
|
||||
var json = JSON.stringify(ConnectionManager.credentialProvider().credentials());
|
||||
var credentials = JSON.parse(json);
|
||||
|
||||
for (var i = 0, length = credentials.Servers.length; i < length; i++) {
|
||||
var server = credentials.Servers[i];
|
||||
|
||||
if (server.DateLastAccessed != null) {
|
||||
server.DateLastAccessed = new Date(server.DateLastAccessed).toISOString();
|
||||
}
|
||||
}
|
||||
|
||||
json = JSON.stringify(credentials);
|
||||
ApiClientBridge.updateCredentials(json);
|
||||
}
|
||||
|
||||
function initNativeConnectionManager() {
|
||||
|
||||
console.log('initNativeConnectionManager');
|
||||
|
||||
var capabilities = ConnectionManager.capabilities();
|
||||
|
||||
ApiClientBridge.init(AppInfo.appName, AppInfo.appVersion, AppInfo.deviceId, AppInfo.deviceName, JSON.stringify(capabilities));
|
||||
|
||||
//initAjax();
|
||||
}
|
||||
|
||||
Events.on(ConnectionManager.credentialProvider(), 'credentialsupdated', updateCredentials);
|
||||
|
||||
updateCredentials();
|
||||
initNativeConnectionManager();
|
||||
|
||||
window.AndroidAjax = {
|
||||
|
||||
onResponse: function (id, status, response) {
|
||||
|
||||
Events.trigger(AndroidAjax, 'response' + id, [status, response]);
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
70
dashboard-ui/cordova/android/appstorage.js
vendored
Normal file
70
dashboard-ui/cordova/android/appstorage.js
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
(function (globalScope, localStorage, sessionStorage) {
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function preferencesStore() {
|
||||
|
||||
var self = this;
|
||||
|
||||
self.setItem = function (name, value) {
|
||||
|
||||
AndroidSharedPreferences.set(name, value);
|
||||
};
|
||||
|
||||
self.getItem = function (name) {
|
||||
|
||||
return AndroidSharedPreferences.get(name);
|
||||
};
|
||||
|
||||
self.removeItem = function (name) {
|
||||
|
||||
AndroidSharedPreferences.remove(name);
|
||||
};
|
||||
}
|
||||
|
||||
globalScope.appStorage = new preferencesStore();
|
||||
globalScope.sessionStore = new myStore(sessionStorage);
|
||||
|
||||
})(window, window.localStorage, window.sessionStorage);
|
14
dashboard-ui/cordova/android/filesystem.js
vendored
Normal file
14
dashboard-ui/cordova/android/filesystem.js
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
(function () {
|
||||
|
||||
window.FileSystemBridge = {
|
||||
|
||||
fileExists: function (path) {
|
||||
return NativeFileSystem.fileExists(path);
|
||||
},
|
||||
|
||||
translateFilePath: function (path) {
|
||||
return 'file://' + NativeFileSystem.translateFilePath(path);
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
61
dashboard-ui/cordova/android/iap.js
vendored
Normal file
61
dashboard-ui/cordova/android/iap.js
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
(function () {
|
||||
|
||||
var unlockId = "com.mb.android.unlock";
|
||||
var updatedProducts = [];
|
||||
|
||||
function updateProductInfo(id, owned, price) {
|
||||
|
||||
updatedProducts = updatedProducts.filter(function (r) {
|
||||
return r.id != id;
|
||||
});
|
||||
|
||||
var product = {
|
||||
id: id,
|
||||
owned: owned,
|
||||
price: price
|
||||
};
|
||||
|
||||
updatedProducts.push(product);
|
||||
|
||||
Events.trigger(IapManager, 'productupdated', [product]);
|
||||
}
|
||||
|
||||
function getProduct(id) {
|
||||
var products = updatedProducts.filter(function (r) {
|
||||
return r.id == id;
|
||||
});
|
||||
|
||||
return products.length ? products[0] : null;
|
||||
}
|
||||
|
||||
function isPurchaseAvailable(id) {
|
||||
|
||||
return NativeIapManager.isStoreAvailable();
|
||||
}
|
||||
|
||||
function beginPurchase(id) {
|
||||
return MainActivity.beginPurchase(id);
|
||||
}
|
||||
|
||||
function onPurchaseComplete(result) {
|
||||
|
||||
if (result) {
|
||||
refreshPurchases();
|
||||
}
|
||||
}
|
||||
|
||||
function refreshPurchases() {
|
||||
NativeIapManager.isPurchased(unlockId, "window.IapManager.updateProduct");
|
||||
}
|
||||
|
||||
window.IapManager = {
|
||||
isPurchaseAvailable: isPurchaseAvailable,
|
||||
getProductInfo: getProduct,
|
||||
updateProduct: updateProductInfo,
|
||||
beginPurchase: beginPurchase,
|
||||
onPurchaseComplete: onPurchaseComplete
|
||||
};
|
||||
|
||||
refreshPurchases();
|
||||
|
||||
})();
|
111
dashboard-ui/cordova/android/immersive.js
vendored
Normal file
111
dashboard-ui/cordova/android/immersive.js
vendored
Normal file
|
@ -0,0 +1,111 @@
|
|||
(function () {
|
||||
|
||||
function onSuccess() {
|
||||
console.log('Immersive mode succeeded');
|
||||
}
|
||||
|
||||
function onError() {
|
||||
console.log('Immersive mode failed');
|
||||
}
|
||||
|
||||
//// Is this plugin supported?
|
||||
//AndroidFullScreen.isSupported();
|
||||
|
||||
//// Is immersive mode supported?
|
||||
//AndroidFullScreen.isImmersiveModeSupported(onSuccess, onError);
|
||||
|
||||
//// The width of the screen in immersive mode
|
||||
//AndroidFullScreen.immersiveWidth(trace, onError);
|
||||
|
||||
//// The height of the screen in immersive mode
|
||||
//AndroidFullScreen.immersiveHeight(trace, onError);
|
||||
|
||||
//// Hide system UI until user interacts
|
||||
//AndroidFullScreen.leanMode(onSuccess, onError);
|
||||
|
||||
//// Show system UI
|
||||
//AndroidFullScreen.showSystemUI(onSuccess, onError);
|
||||
|
||||
//// Extend your app underneath the system UI (Android 4.4+ only)
|
||||
//AndroidFullScreen.showUnderSystemUI(onSuccess, onError);
|
||||
|
||||
//// Hide system UI and keep it hidden (Android 4.4+ only)
|
||||
//AndroidFullScreen.immersiveMode(onSuccess, onError);
|
||||
|
||||
var currentPlayer;
|
||||
|
||||
function onPlaybackStart(e, state) {
|
||||
|
||||
var player = this;
|
||||
|
||||
if (player.isLocalPlayer && state.NowPlayingItem && state.NowPlayingItem.MediaType == 'Video') {
|
||||
AndroidFullScreen.immersiveMode(onSuccess, onError);
|
||||
}
|
||||
}
|
||||
|
||||
function onPlaybackStopped(e, state) {
|
||||
|
||||
var player = this;
|
||||
|
||||
if (player.isLocalPlayer && state.NowPlayingItem && state.NowPlayingItem.MediaType == 'Video') {
|
||||
|
||||
if (!AppSettings.enableFullScreen()) {
|
||||
AndroidFullScreen.showSystemUI(onSuccess, onError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function bindToPlayer(player) {
|
||||
|
||||
releaseCurrentPlayer();
|
||||
|
||||
currentPlayer = player;
|
||||
|
||||
if (!player.isLocalPlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(player).on('playbackstart.fullscreen', onPlaybackStart)
|
||||
.on('playbackstop.fullscreen', onPlaybackStopped);
|
||||
}
|
||||
|
||||
function releaseCurrentPlayer() {
|
||||
|
||||
if (currentPlayer) {
|
||||
|
||||
$(currentPlayer).off('.fullscreen');
|
||||
}
|
||||
}
|
||||
|
||||
function updateFromSetting(leaveFullScreen) {
|
||||
|
||||
if (AppSettings.enableFullScreen()) {
|
||||
AndroidFullScreen.immersiveMode(onSuccess, onError);
|
||||
}
|
||||
else if (leaveFullScreen) {
|
||||
AndroidFullScreen.showSystemUI(onSuccess, onError);
|
||||
}
|
||||
}
|
||||
|
||||
Dashboard.ready(function () {
|
||||
|
||||
console.log('binding fullscreen to MediaController');
|
||||
|
||||
$(MediaController).on('playerchange', function () {
|
||||
|
||||
bindToPlayer(MediaController.getCurrentPlayer());
|
||||
});
|
||||
|
||||
bindToPlayer(MediaController.getCurrentPlayer());
|
||||
|
||||
updateFromSetting(false);
|
||||
|
||||
$(AppSettings).on('settingupdated', function (e, key) {
|
||||
|
||||
if (key == 'enableFullScreen') {
|
||||
updateFromSetting(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
})();
|
17
dashboard-ui/cordova/android/localassetmanager.js
vendored
Normal file
17
dashboard-ui/cordova/android/localassetmanager.js
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
(function () {
|
||||
|
||||
function getLocalMediaSource(serverId, itemId) {
|
||||
var json = ApiClientBridge.getLocalMediaSource(serverId, itemId);
|
||||
|
||||
if (json) {
|
||||
return JSON.parse(json);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
window.LocalAssetManager = {
|
||||
getLocalMediaSource: getLocalMediaSource
|
||||
};
|
||||
|
||||
})();
|
163
dashboard-ui/cordova/android/mediasession.js
vendored
Normal file
163
dashboard-ui/cordova/android/mediasession.js
vendored
Normal file
|
@ -0,0 +1,163 @@
|
|||
(function () {
|
||||
|
||||
// Reports media playback to the device for lock screen control
|
||||
|
||||
var currentPlayer;
|
||||
var lastPlayerState;
|
||||
var lastUpdateTime = 0;
|
||||
|
||||
function updatePlayerState(state, eventName) {
|
||||
|
||||
if (!state.NowPlayingItem) {
|
||||
hideMediaControls();
|
||||
return;
|
||||
}
|
||||
|
||||
// dummy this up
|
||||
if (eventName == 'init') {
|
||||
eventName = 'positionchange';
|
||||
}
|
||||
|
||||
lastPlayerState = state;
|
||||
|
||||
var playState = state.PlayState || {};
|
||||
|
||||
var nameHtml = MediaController.getNowPlayingNameHtml(state.NowPlayingItem) || '';
|
||||
var parts = nameHtml.split('<br/>');
|
||||
|
||||
var artist = parts.length == 1 ? '' : parts[0];
|
||||
var title = parts[parts.length - 1];
|
||||
var album = state.NowPlayingItem.Album || '';
|
||||
var duration = state.NowPlayingItem.RunTimeTicks ? (state.NowPlayingItem.RunTimeTicks / 10000000) : 0;
|
||||
var position = playState.PositionTicks ? (playState.PositionTicks / 10000000) : 0;
|
||||
var itemId = state.NowPlayingItem.Id;
|
||||
|
||||
var isPaused = playState.IsPaused || false;
|
||||
var canSeek = playState.CanSeek || false;
|
||||
|
||||
var url = '';
|
||||
var imgHeight = 400;
|
||||
|
||||
var nowPlayingItem = state.NowPlayingItem;
|
||||
|
||||
if (nowPlayingItem.PrimaryImageTag) {
|
||||
|
||||
url = ApiClient.getScaledImageUrl(nowPlayingItem.PrimaryImageItemId, {
|
||||
type: "Primary",
|
||||
height: imgHeight,
|
||||
tag: nowPlayingItem.PrimaryImageTag
|
||||
});
|
||||
} else if (nowPlayingItem.ThumbImageTag) {
|
||||
|
||||
url = ApiClient.getScaledImageUrl(nowPlayingItem.ThumbImageItemId, {
|
||||
type: "Thumb",
|
||||
height: imgHeight,
|
||||
tag: nowPlayingItem.ThumbImageTag
|
||||
});
|
||||
}
|
||||
else if (nowPlayingItem.BackdropImageTag) {
|
||||
|
||||
url = ApiClient.getScaledImageUrl(nowPlayingItem.BackdropItemId, {
|
||||
type: "Backdrop",
|
||||
height: imgHeight,
|
||||
tag: nowPlayingItem.BackdropImageTag,
|
||||
index: 0
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Don't go crazy reporting position changes
|
||||
if (eventName == 'positionchange') {
|
||||
if (lastUpdateTime) {
|
||||
// Only report if this item hasn't been reported yet, or if there's an actual playback change.
|
||||
// Don't report on simple time updates
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var isLocalPlayer = MediaController.getPlayerInfo().isLocalPlayer || false;
|
||||
|
||||
MainActivity.updateMediaSession(eventName, isLocalPlayer, itemId, title, artist, album, parseInt(duration), parseInt(position), url, canSeek, isPaused);
|
||||
lastUpdateTime = new Date().getTime();
|
||||
}
|
||||
|
||||
function onStateChanged(e, state) {
|
||||
|
||||
updatePlayerState(state, e.type);
|
||||
}
|
||||
|
||||
function onPlaybackStart(e, state) {
|
||||
|
||||
console.log('nowplaying event: ' + e.type);
|
||||
|
||||
var player = this;
|
||||
|
||||
player.beginPlayerUpdates();
|
||||
|
||||
onStateChanged.call(player, e, state);
|
||||
}
|
||||
|
||||
function onPlaybackStopped(e, state) {
|
||||
|
||||
console.log('nowplaying event: ' + e.type);
|
||||
var player = this;
|
||||
|
||||
player.endPlayerUpdates();
|
||||
|
||||
hideMediaControls();
|
||||
}
|
||||
|
||||
function releaseCurrentPlayer() {
|
||||
|
||||
if (currentPlayer) {
|
||||
|
||||
$(currentPlayer).off('.cordovaremote');
|
||||
currentPlayer.endPlayerUpdates();
|
||||
currentPlayer = null;
|
||||
|
||||
hideMediaControls();
|
||||
}
|
||||
}
|
||||
|
||||
function hideMediaControls() {
|
||||
MainActivity.hideMediaSession();
|
||||
lastUpdateTime = 0;
|
||||
}
|
||||
|
||||
function bindToPlayer(player) {
|
||||
|
||||
releaseCurrentPlayer();
|
||||
|
||||
currentPlayer = player;
|
||||
|
||||
console.log('binding remotecontrols to MediaPlayer');
|
||||
|
||||
player.getPlayerState().done(function (state) {
|
||||
|
||||
if (state.NowPlayingItem) {
|
||||
player.beginPlayerUpdates();
|
||||
}
|
||||
|
||||
onStateChanged.call(player, { type: 'init' }, state);
|
||||
});
|
||||
|
||||
$(player).on('playbackstart.cordovaremote', onPlaybackStart)
|
||||
.on('playbackstop.cordovaremote', onPlaybackStopped)
|
||||
.on('playstatechange.cordovaremote', onStateChanged)
|
||||
.on('positionchange.cordovaremote', onStateChanged);
|
||||
}
|
||||
|
||||
Dashboard.ready(function () {
|
||||
|
||||
console.log('binding remotecontrols to MediaController');
|
||||
|
||||
$(MediaController).on('playerchange', function () {
|
||||
|
||||
bindToPlayer(MediaController.getCurrentPlayer());
|
||||
});
|
||||
|
||||
bindToPlayer(MediaController.getCurrentPlayer());
|
||||
|
||||
});
|
||||
|
||||
})();
|
31
dashboard-ui/cordova/android/nativedirectorychooser.js
vendored
Normal file
31
dashboard-ui/cordova/android/nativedirectorychooser.js
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
(function () {
|
||||
|
||||
var currentDeferred;
|
||||
function chooseDirectory() {
|
||||
var deferred = DeferredBuilder.Deferred();
|
||||
AndroidDirectoryChooser.chooseDirectory();
|
||||
currentDeferred = deferred;
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
function onChosen(path) {
|
||||
|
||||
var deferred = currentDeferred;
|
||||
|
||||
if (deferred) {
|
||||
if (path) {
|
||||
deferred.resolveWith(null, [path]);
|
||||
} else {
|
||||
deferred.reject();
|
||||
}
|
||||
|
||||
currentDeferred = null;
|
||||
}
|
||||
}
|
||||
|
||||
window.NativeDirectoryChooser = {
|
||||
chooseDirectory: chooseDirectory,
|
||||
onChosen: onChosen
|
||||
};
|
||||
|
||||
})();
|
165
dashboard-ui/cordova/android/vlcplayer.js
vendored
Normal file
165
dashboard-ui/cordova/android/vlcplayer.js
vendored
Normal file
|
@ -0,0 +1,165 @@
|
|||
(function () {
|
||||
|
||||
function vlcRenderer(type) {
|
||||
|
||||
var self = this;
|
||||
|
||||
function onEnded() {
|
||||
$(self).trigger('ended');
|
||||
}
|
||||
|
||||
function onTimeUpdate() {
|
||||
$(self).trigger('timeupdate');
|
||||
}
|
||||
|
||||
function onVolumeChange() {
|
||||
$(self).trigger('volumechange');
|
||||
}
|
||||
|
||||
function onPlaying() {
|
||||
$(self).trigger('playing');
|
||||
}
|
||||
|
||||
function onPlay() {
|
||||
$(self).trigger('play');
|
||||
}
|
||||
|
||||
function onPause() {
|
||||
$(self).trigger('pause');
|
||||
}
|
||||
|
||||
function onClick() {
|
||||
$(self).trigger('click');
|
||||
}
|
||||
|
||||
function onDblClick() {
|
||||
$(self).trigger('dblclick');
|
||||
}
|
||||
|
||||
function onError() {
|
||||
|
||||
var errorCode = this.error ? this.error.code : '';
|
||||
console.log('Media element error code: ' + errorCode);
|
||||
|
||||
$(self).trigger('error');
|
||||
}
|
||||
|
||||
var playerState = {};
|
||||
|
||||
self.currentTime = function (val) {
|
||||
|
||||
if (val != null) {
|
||||
AndroidVlcPlayer.sendVlcCommand("setposition", val.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
return playerState.currentTime;
|
||||
};
|
||||
|
||||
self.duration = function (val) {
|
||||
|
||||
if (playerState) {
|
||||
return playerState.duration;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
self.stop = function () {
|
||||
AndroidVlcPlayer.sendVlcCommand("stop", null);
|
||||
};
|
||||
|
||||
self.pause = function () {
|
||||
AndroidVlcPlayer.sendVlcCommand("pause", null);
|
||||
};
|
||||
|
||||
self.unpause = function () {
|
||||
AndroidVlcPlayer.sendVlcCommand("unpause", null);
|
||||
};
|
||||
|
||||
self.volume = function (val) {
|
||||
if (playerState) {
|
||||
if (val != null) {
|
||||
AndroidVlcPlayer.sendVlcCommand("setvolume", (val * 100).toString());
|
||||
return;
|
||||
}
|
||||
|
||||
return playerState.volume;
|
||||
}
|
||||
};
|
||||
|
||||
self.setCurrentSrc = function (val) {
|
||||
|
||||
if (!val) {
|
||||
self.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == 'audio') {
|
||||
AndroidVlcPlayer.playAudioVlc(val);
|
||||
} else {
|
||||
AndroidVlcPlayer.playVideoVlc(val);
|
||||
}
|
||||
|
||||
playerState.currentSrc = val;
|
||||
};
|
||||
|
||||
self.currentSrc = function () {
|
||||
if (playerState) {
|
||||
return playerState.currentSrc;
|
||||
}
|
||||
};
|
||||
|
||||
self.paused = function () {
|
||||
|
||||
if (playerState) {
|
||||
return playerState.paused;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
self.destroy = function () {
|
||||
|
||||
AndroidVlcPlayer.destroyVlc();
|
||||
playerState = {};
|
||||
};
|
||||
|
||||
self.setPoster = function (url) {
|
||||
};
|
||||
|
||||
self.report = function (eventName, duration, position, isPaused, volume) {
|
||||
|
||||
var state = playerState;
|
||||
|
||||
state.duration = duration;
|
||||
state.currentTime = position;
|
||||
state.paused = isPaused;
|
||||
state.volume = (volume || 0) / 100;
|
||||
|
||||
if (eventName == 'playbackstop') {
|
||||
onEnded();
|
||||
}
|
||||
else if (eventName == 'volumechange') {
|
||||
onVolumeChange();
|
||||
}
|
||||
else if (eventName == 'positionchange') {
|
||||
onTimeUpdate();
|
||||
}
|
||||
else if (eventName == 'paused') {
|
||||
onPause();
|
||||
}
|
||||
else if (eventName == 'unpaused') {
|
||||
onPlaying();
|
||||
}
|
||||
else if (eventName == 'playing') {
|
||||
onPlaying();
|
||||
}
|
||||
};
|
||||
|
||||
window.AudioRenderer.Current = self;
|
||||
}
|
||||
|
||||
window.AudioRenderer = vlcRenderer;
|
||||
|
||||
})();
|
24
dashboard-ui/cordova/back.js
vendored
Normal file
24
dashboard-ui/cordova/back.js
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
(function () {
|
||||
|
||||
Dashboard.exit = function () {
|
||||
|
||||
if (navigator.app && navigator.app.exitApp) {
|
||||
navigator.app.exitApp();
|
||||
} else {
|
||||
Dashboard.logout();
|
||||
}
|
||||
};
|
||||
|
||||
function onBackKeyDown(e) {
|
||||
if (Dashboard.exitOnBack()) {
|
||||
e.preventDefault();
|
||||
Dashboard.exit();
|
||||
}
|
||||
else {
|
||||
history.back();
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("backbutton", onBackKeyDown, false);
|
||||
|
||||
})();
|
664
dashboard-ui/cordova/chromecast.js
vendored
Normal file
664
dashboard-ui/cordova/chromecast.js
vendored
Normal file
|
@ -0,0 +1,664 @@
|
|||
(function () {
|
||||
|
||||
function chromecastPlayer() {
|
||||
|
||||
var self = this;
|
||||
|
||||
var PlayerName = "Chromecast";
|
||||
var ApplicationID = "2D4B1DA3";
|
||||
var currentWebAppSession;
|
||||
var currentDevice;
|
||||
var currentDeviceId;
|
||||
|
||||
// MediaController needs this
|
||||
self.name = PlayerName;
|
||||
|
||||
self.getItemsForPlayback = function (query) {
|
||||
|
||||
var userId = Dashboard.getCurrentUserId();
|
||||
|
||||
query.Limit = query.Limit || 100;
|
||||
query.ExcludeLocationTypes = "Virtual";
|
||||
|
||||
return ApiClient.getItems(userId, query);
|
||||
};
|
||||
|
||||
var castPlayer = {};
|
||||
|
||||
$(castPlayer).on("connect", function (e) {
|
||||
|
||||
console.log('cc: connect');
|
||||
// Reset this so the next query doesn't make it appear like content is playing.
|
||||
self.lastPlayerData = {};
|
||||
});
|
||||
|
||||
$(castPlayer).on("playbackstart", function (e, data) {
|
||||
|
||||
console.log('cc: playbackstart');
|
||||
|
||||
var state = self.getPlayerStateInternal(data);
|
||||
$(self).trigger("playbackstart", [state]);
|
||||
});
|
||||
|
||||
$(castPlayer).on("playbackstop", function (e, data) {
|
||||
|
||||
console.log('cc: playbackstop');
|
||||
var state = self.getPlayerStateInternal(data);
|
||||
|
||||
$(self).trigger("playbackstop", [state]);
|
||||
|
||||
// Reset this so the next query doesn't make it appear like content is playing.
|
||||
self.lastPlayerData = {};
|
||||
});
|
||||
|
||||
$(castPlayer).on("playbackprogress", function (e, data) {
|
||||
|
||||
console.log('cc: positionchange');
|
||||
var state = self.getPlayerStateInternal(data);
|
||||
|
||||
$(self).trigger("positionchange", [state]);
|
||||
});
|
||||
|
||||
var endpointInfo;
|
||||
function getEndpointInfo() {
|
||||
|
||||
if (endpointInfo) {
|
||||
|
||||
var deferred = $.Deferred();
|
||||
deferred.resolveWith(null, [endpointInfo]);
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
return ApiClient.getJSON(ApiClient.getUrl('System/Endpoint')).done(function (info) {
|
||||
|
||||
endpointInfo = info;
|
||||
});
|
||||
}
|
||||
|
||||
function sendMessageToDevice(message) {
|
||||
|
||||
var bitrateSetting = AppSettings.maxChromecastBitrate();
|
||||
|
||||
message = $.extend(message, {
|
||||
userId: Dashboard.getCurrentUserId(),
|
||||
deviceId: ApiClient.deviceId(),
|
||||
accessToken: ApiClient.accessToken(),
|
||||
serverAddress: ApiClient.serverAddress(),
|
||||
maxBitrate: bitrateSetting,
|
||||
receiverName: currentDevice.getFriendlyName(),
|
||||
supportsAc3: AppSettings.enableChromecastAc3()
|
||||
});
|
||||
|
||||
getEndpointInfo().done(function (endpoint) {
|
||||
|
||||
if (endpoint.IsLocal || endpoint.IsInNetwork) {
|
||||
ApiClient.getPublicSystemInfo().done(function (info) {
|
||||
|
||||
message.serverAddress = info.LocalAddress;
|
||||
sendMessageInternal(message);
|
||||
});
|
||||
} else {
|
||||
sendMessageInternal(message);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function sendMessageInternal(message) {
|
||||
currentWebAppSession.sendText(JSON.stringify(message));
|
||||
}
|
||||
|
||||
self.play = function (options) {
|
||||
|
||||
Dashboard.getCurrentUser().done(function (user) {
|
||||
|
||||
if (options.items) {
|
||||
|
||||
self.playWithCommand(options, 'PlayNow');
|
||||
|
||||
} else {
|
||||
|
||||
self.getItemsForPlayback({
|
||||
|
||||
Ids: options.ids.join(',')
|
||||
|
||||
}).done(function (result) {
|
||||
|
||||
options.items = result.Items;
|
||||
self.playWithCommand(options, 'PlayNow');
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
self.playWithCommand = function (options, command) {
|
||||
|
||||
if (!options.items) {
|
||||
ApiClient.getItem(Dashboard.getCurrentUserId(), options.ids[0]).done(function (item) {
|
||||
|
||||
options.items = [item];
|
||||
self.playWithCommand(options, command);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the items to smaller stubs to send the minimal amount of information
|
||||
options.items = options.items.map(function (i) {
|
||||
|
||||
return {
|
||||
Id: i.Id,
|
||||
Name: i.Name,
|
||||
Type: i.Type,
|
||||
MediaType: i.MediaType,
|
||||
IsFolder: i.IsFolder
|
||||
};
|
||||
});
|
||||
|
||||
sendMessageToDevice({
|
||||
options: options,
|
||||
command: command
|
||||
});
|
||||
};
|
||||
|
||||
self.unpause = function () {
|
||||
sendMessageToDevice({
|
||||
command: 'Unpause'
|
||||
});
|
||||
};
|
||||
|
||||
self.pause = function () {
|
||||
sendMessageToDevice({
|
||||
command: 'Pause'
|
||||
});
|
||||
};
|
||||
|
||||
self.shuffle = function (id) {
|
||||
|
||||
var userId = Dashboard.getCurrentUserId();
|
||||
|
||||
ApiClient.getItem(userId, id).done(function (item) {
|
||||
|
||||
self.playWithCommand({
|
||||
|
||||
items: [item]
|
||||
|
||||
}, 'Shuffle');
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
self.instantMix = function (id) {
|
||||
|
||||
var userId = Dashboard.getCurrentUserId();
|
||||
|
||||
ApiClient.getItem(userId, id).done(function (item) {
|
||||
|
||||
self.playWithCommand({
|
||||
|
||||
items: [item]
|
||||
|
||||
}, 'InstantMix');
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
self.canQueueMediaType = function (mediaType) {
|
||||
return mediaType == "Audio";
|
||||
};
|
||||
|
||||
self.queue = function (options) {
|
||||
self.playWithCommnd(options, 'PlayLast');
|
||||
};
|
||||
|
||||
self.queueNext = function (options) {
|
||||
self.playWithCommand(options, 'PlayNext');
|
||||
};
|
||||
|
||||
self.stop = function () {
|
||||
sendMessageToDevice({
|
||||
command: 'Stop'
|
||||
});
|
||||
};
|
||||
|
||||
self.displayContent = function (options) {
|
||||
|
||||
sendMessageToDevice({
|
||||
options: options,
|
||||
command: 'DisplayContent'
|
||||
});
|
||||
};
|
||||
|
||||
self.mute = function () {
|
||||
sendMessageToDevice({
|
||||
command: 'Mute'
|
||||
});
|
||||
};
|
||||
|
||||
self.unMute = function () {
|
||||
self.setVolume(getCurrentVolume() + 2);
|
||||
};
|
||||
|
||||
self.toggleMute = function () {
|
||||
|
||||
var state = self.lastPlayerData || {};
|
||||
state = state.PlayState || {};
|
||||
|
||||
if (state.IsMuted) {
|
||||
self.unMute();
|
||||
} else {
|
||||
self.mute();
|
||||
}
|
||||
};
|
||||
|
||||
function getBaseTargetInfo() {
|
||||
var target = {};
|
||||
|
||||
target.playerName = PlayerName;
|
||||
target.playableMediaTypes = ["Audio", "Video"];
|
||||
target.isLocalPlayer = false;
|
||||
target.appName = PlayerName;
|
||||
target.supportedCommands = [
|
||||
"VolumeUp",
|
||||
"VolumeDown",
|
||||
"Mute",
|
||||
"Unmute",
|
||||
"ToggleMute",
|
||||
"SetVolume",
|
||||
"SetAudioStreamIndex",
|
||||
"SetSubtitleStreamIndex",
|
||||
"DisplayContent"
|
||||
];
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
function convertDeviceToTarget(device) {
|
||||
|
||||
var target = getBaseTargetInfo();
|
||||
|
||||
target.name = target.deviceName = device.getFriendlyName();
|
||||
target.id = device.getId();
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
function isChromecast(name) {
|
||||
|
||||
name = (name || '').toLowerCase();
|
||||
var validTokens = ['nexusplayer', 'chromecast', 'eurekadongle'];
|
||||
|
||||
return validTokens.filter(function (t) {
|
||||
|
||||
return name.replace(' ', '').indexOf(t) != -1;
|
||||
|
||||
}).length > 0;
|
||||
}
|
||||
|
||||
self.getTargets = function () {
|
||||
|
||||
return ConnectSDKHelper.getDeviceList().filter(function (d) {
|
||||
|
||||
return isChromecast(d.getModelName()) || isChromecast(d.getFriendlyName());
|
||||
|
||||
}).map(convertDeviceToTarget);
|
||||
};
|
||||
|
||||
self.seek = function (position) {
|
||||
|
||||
position = parseInt(position);
|
||||
position = position / 10000000;
|
||||
|
||||
sendMessageToDevice({
|
||||
options: {
|
||||
position: position
|
||||
},
|
||||
command: 'Seek'
|
||||
});
|
||||
};
|
||||
|
||||
self.setAudioStreamIndex = function (index) {
|
||||
sendMessageToDevice({
|
||||
options: {
|
||||
index: index
|
||||
},
|
||||
command: 'SetAudioStreamIndex'
|
||||
});
|
||||
};
|
||||
|
||||
self.setSubtitleStreamIndex = function (index) {
|
||||
sendMessageToDevice({
|
||||
options: {
|
||||
index: index
|
||||
},
|
||||
command: 'SetSubtitleStreamIndex'
|
||||
});
|
||||
};
|
||||
|
||||
self.nextTrack = function () {
|
||||
sendMessageToDevice({
|
||||
options: {},
|
||||
command: 'NextTrack'
|
||||
});
|
||||
};
|
||||
|
||||
self.previousTrack = function () {
|
||||
sendMessageToDevice({
|
||||
options: {},
|
||||
command: 'PreviousTrack'
|
||||
});
|
||||
};
|
||||
|
||||
self.beginPlayerUpdates = function () {
|
||||
// Setup polling here
|
||||
};
|
||||
|
||||
self.endPlayerUpdates = function () {
|
||||
// Stop polling here
|
||||
};
|
||||
|
||||
function getCurrentVolume() {
|
||||
var state = self.lastPlayerData || {};
|
||||
state = state.PlayState || {};
|
||||
|
||||
return state.VolumeLevel == null ? 100 : state.VolumeLevel;
|
||||
}
|
||||
|
||||
self.volumeDown = function () {
|
||||
|
||||
sendMessageToDevice({
|
||||
options: {},
|
||||
command: 'VolumeDown'
|
||||
});
|
||||
};
|
||||
|
||||
self.volumeUp = function () {
|
||||
|
||||
sendMessageToDevice({
|
||||
options: {},
|
||||
command: 'VolumeUp'
|
||||
});
|
||||
};
|
||||
|
||||
self.setVolume = function (vol) {
|
||||
|
||||
vol = Math.min(vol, 100);
|
||||
vol = Math.max(vol, 0);
|
||||
|
||||
sendMessageToDevice({
|
||||
options: {
|
||||
volume: vol
|
||||
},
|
||||
command: 'SetVolume'
|
||||
});
|
||||
};
|
||||
|
||||
self.getPlayerState = function () {
|
||||
|
||||
var deferred = $.Deferred();
|
||||
|
||||
var result = self.getPlayerStateInternal();
|
||||
|
||||
deferred.resolveWith(null, [result]);
|
||||
|
||||
return deferred.promise();
|
||||
};
|
||||
|
||||
self.lastPlayerData = {};
|
||||
|
||||
self.getPlayerStateInternal = function (data) {
|
||||
|
||||
data = data || self.lastPlayerData;
|
||||
self.lastPlayerData = data;
|
||||
|
||||
console.log(JSON.stringify(data));
|
||||
return data;
|
||||
};
|
||||
|
||||
function onMessage(message) {
|
||||
|
||||
if (message.type == 'playbackerror') {
|
||||
|
||||
var errorCode = message.data;
|
||||
|
||||
setTimeout(function () {
|
||||
Dashboard.alert({
|
||||
message: Globalize.translate('MessagePlaybackError' + errorCode),
|
||||
title: Globalize.translate('HeaderPlaybackError')
|
||||
});
|
||||
}, 300);
|
||||
|
||||
}
|
||||
else if (message.type == 'connectionerror') {
|
||||
|
||||
setTimeout(function () {
|
||||
Dashboard.alert({
|
||||
message: Globalize.translate('MessageChromecastConnectionError'),
|
||||
title: Globalize.translate('HeaderError')
|
||||
});
|
||||
}, 300);
|
||||
|
||||
}
|
||||
else if (message.type && message.type.indexOf('playback') == 0) {
|
||||
$(castPlayer).trigger(message.type, [message.data]);
|
||||
}
|
||||
}
|
||||
|
||||
function handleMessage(message) {
|
||||
// message could be either a string or an object
|
||||
if (typeof message === 'string') {
|
||||
onMessage(JSON.parse(message));
|
||||
} else {
|
||||
onMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
function handleSessionDisconnect() {
|
||||
console.log("session disconnected");
|
||||
|
||||
cleanupSession();
|
||||
MediaController.removeActivePlayer(PlayerName);
|
||||
}
|
||||
|
||||
function onWebAppSessionConnect(webAppSession, device) {
|
||||
|
||||
currentWebAppSession = webAppSession;
|
||||
|
||||
console.log('session.connect succeeded');
|
||||
webAppSession.setWebAppSessionListener();
|
||||
|
||||
MediaController.setActivePlayer(PlayerName, convertDeviceToTarget(device));
|
||||
currentDevice = device;
|
||||
currentDeviceId = device.getId();
|
||||
|
||||
$(castPlayer).trigger('connect');
|
||||
|
||||
sendIdentifyMessage();
|
||||
}
|
||||
|
||||
function setupWebAppSession(device, session, connectToSession) {
|
||||
|
||||
// hold on to a reference
|
||||
var currentSession = session.acquire();
|
||||
|
||||
currentSession.on('message', handleMessage);
|
||||
currentSession.on('disconnect', handleSessionDisconnect);
|
||||
|
||||
if (connectToSession || $.browser.safari) {
|
||||
currentSession.connect().success(function () {
|
||||
|
||||
onWebAppSessionConnect(currentSession, device);
|
||||
|
||||
}).error(handleSessionError);
|
||||
} else {
|
||||
onWebAppSessionConnect(currentSession, device);
|
||||
}
|
||||
}
|
||||
|
||||
function sendIdentifyMessage() {
|
||||
sendMessageToDevice({
|
||||
options: {},
|
||||
command: 'Identify'
|
||||
});
|
||||
}
|
||||
|
||||
function handleSessionError() {
|
||||
cleanupSession();
|
||||
}
|
||||
|
||||
function cleanupSession() {
|
||||
|
||||
var session = currentWebAppSession;
|
||||
|
||||
if (session) {
|
||||
// Clean up listeners
|
||||
session.off("message");
|
||||
session.off("disconnect");
|
||||
|
||||
// Release session to free up memory
|
||||
session.disconnect();
|
||||
session.release();
|
||||
}
|
||||
|
||||
currentWebAppSession = null;
|
||||
}
|
||||
|
||||
function tryLaunchWebSession(device) {
|
||||
|
||||
console.log('calling launchWebApp');
|
||||
device.getWebAppLauncher().launchWebApp(ApplicationID).success(function (session) {
|
||||
|
||||
console.log('launchWebApp success. calling onSessionConnected');
|
||||
setupWebAppSession(device, session, true);
|
||||
|
||||
}).error(function (err1) {
|
||||
|
||||
console.log('launchWebApp error:' + JSON.stringify(err1));
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function tryJoinWebSession(device, enableRetry) {
|
||||
|
||||
// First try to join existing session. If it fails, launch a new one
|
||||
|
||||
console.log('calling joinWebApp');
|
||||
device.getWebAppLauncher().joinWebApp(ApplicationID).success(function (session) {
|
||||
|
||||
console.log('joinWebApp success. calling onSessionConnected');
|
||||
setupWebAppSession(device, session, false);
|
||||
|
||||
}).error(function (err) {
|
||||
|
||||
console.log('joinWebApp error: ' + JSON.stringify(err));
|
||||
|
||||
if (enableRetry) {
|
||||
tryJoinWebSession(device, false);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('calling launchWebApp');
|
||||
tryLaunchWebSession(device);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function launchWebApp(device) {
|
||||
|
||||
if (currentWebAppSession) {
|
||||
cleanupSession();
|
||||
}
|
||||
|
||||
tryJoinWebSession(device, true);
|
||||
}
|
||||
|
||||
function onDeviceReady(device) {
|
||||
|
||||
device.off("ready");
|
||||
|
||||
console.log('creating webAppSession');
|
||||
|
||||
launchWebApp(device);
|
||||
}
|
||||
|
||||
self.tryPair = function (target) {
|
||||
|
||||
var deferred = $.Deferred();
|
||||
|
||||
var device = ConnectSDKHelper.getDeviceList().filter(function (d) {
|
||||
|
||||
return d.getId() == target.id;
|
||||
})[0];
|
||||
|
||||
if (device) {
|
||||
|
||||
self.tryPairWithDevice(device, deferred);
|
||||
|
||||
} else {
|
||||
deferred.reject();
|
||||
}
|
||||
|
||||
return deferred.promise();
|
||||
};
|
||||
|
||||
self.tryPairWithDevice = function (device, deferred) {
|
||||
|
||||
console.log('Will attempt to connect to Chromecast');
|
||||
|
||||
device.on("disconnect", function () {
|
||||
device.off("ready");
|
||||
device.off("disconnect");
|
||||
});
|
||||
|
||||
if (device.isReady()) {
|
||||
console.log('Device is already ready, calling onDeviceReady');
|
||||
onDeviceReady(device);
|
||||
} else {
|
||||
|
||||
console.log('Binding device ready handler');
|
||||
|
||||
device.on("ready", function () {
|
||||
console.log('device.ready fired');
|
||||
onDeviceReady(device);
|
||||
});
|
||||
|
||||
console.log('Calling device.connect');
|
||||
device.connect();
|
||||
}
|
||||
};
|
||||
|
||||
$(MediaController).on('playerchange', function (e, newPlayer, newTarget) {
|
||||
|
||||
if (newTarget.id != currentDeviceId) {
|
||||
if (currentWebAppSession) {
|
||||
console.log('Disconnecting from chromecast');
|
||||
//currentDevice.disconnect();
|
||||
cleanupSession();
|
||||
currentDevice = null;
|
||||
currentDeviceId = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function onResume() {
|
||||
|
||||
var deviceId = currentDeviceId;
|
||||
|
||||
if (deviceId) {
|
||||
self.tryPair({
|
||||
id: deviceId
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("resume", onResume, false);
|
||||
}
|
||||
|
||||
MediaController.registerPlayer(new chromecastPlayer());
|
||||
|
||||
})();
|
36
dashboard-ui/cordova/connectsdk.js
vendored
Normal file
36
dashboard-ui/cordova/connectsdk.js
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
(function () {
|
||||
|
||||
function initSdk() {
|
||||
|
||||
var manager = ConnectSDK.discoveryManager;
|
||||
|
||||
//manager.setPairingLevel(ConnectSDK.PairingLevel.OFF);
|
||||
manager.setAirPlayServiceMode(ConnectSDK.AirPlayServiceMode.Media);
|
||||
|
||||
// Show devices that support playing videos and pausing
|
||||
//manager.setCapabilityFilters([
|
||||
// new ConnectSDK.CapabilityFilter(["MediaPlayer.Display.Video", "MediaControl.Pause"])
|
||||
//]);
|
||||
|
||||
manager.on('devicelistchanged', onDeviceListChanged);
|
||||
|
||||
manager.startDiscovery();
|
||||
|
||||
requirejs(['cordova/chromecast', 'cordova/generaldevice']);
|
||||
}
|
||||
|
||||
function onDeviceListChanged(list) {
|
||||
}
|
||||
|
||||
function getDeviceList() {
|
||||
return ConnectSDK.discoveryManager.getDeviceList();
|
||||
}
|
||||
|
||||
window.ConnectSDKHelper = {
|
||||
|
||||
getDeviceList: getDeviceList
|
||||
};
|
||||
|
||||
Dashboard.ready(initSdk);
|
||||
|
||||
})();
|
23
dashboard-ui/cordova/externalplayer.js
vendored
Normal file
23
dashboard-ui/cordova/externalplayer.js
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
(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();
|
||||
});
|
||||
}
|
||||
|
||||
window.ExternalPlayer.showPlayerSelectionMenu = showPlayerSelectionMenu;
|
||||
|
||||
})();
|
14
dashboard-ui/cordova/filesystem.js
vendored
Normal file
14
dashboard-ui/cordova/filesystem.js
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
(function () {
|
||||
|
||||
window.FileSystemBridge = {
|
||||
|
||||
fileExists: function (path) {
|
||||
return false;
|
||||
},
|
||||
|
||||
translateFilePath: function (path) {
|
||||
return 'file://' + path;
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
675
dashboard-ui/cordova/generaldevice.js
vendored
Normal file
675
dashboard-ui/cordova/generaldevice.js
vendored
Normal file
|
@ -0,0 +1,675 @@
|
|||
(function () {
|
||||
|
||||
function connectSDKPlayer() {
|
||||
|
||||
var self = this;
|
||||
|
||||
var PlayerName = "ConnectSDK";
|
||||
var currentDevice;
|
||||
var currentDeviceId;
|
||||
var currentMediaControl;
|
||||
|
||||
// MediaController needs this
|
||||
self.name = PlayerName;
|
||||
|
||||
self.getItemsForPlayback = function (query) {
|
||||
|
||||
var userId = Dashboard.getCurrentUserId();
|
||||
|
||||
query.Limit = query.Limit || 100;
|
||||
query.ExcludeLocationTypes = "Virtual";
|
||||
|
||||
return ApiClient.getItems(userId, query);
|
||||
};
|
||||
|
||||
var castPlayer = {};
|
||||
|
||||
$(castPlayer).on("playbackstart", function (e, data) {
|
||||
|
||||
console.log('cc: playbackstart');
|
||||
|
||||
var state = self.getPlayerStateInternal(data);
|
||||
$(self).trigger("playbackstart", [state]);
|
||||
});
|
||||
|
||||
$(castPlayer).on("playbackstop", function (e, data) {
|
||||
|
||||
console.log('cc: playbackstop');
|
||||
var state = self.getPlayerStateInternal(data);
|
||||
|
||||
$(self).trigger("playbackstop", [state]);
|
||||
|
||||
// Reset this so the next query doesn't make it appear like content is playing.
|
||||
self.lastPlayerData = {};
|
||||
});
|
||||
|
||||
$(castPlayer).on("playbackprogress", function (e, data) {
|
||||
|
||||
console.log('cc: positionchange');
|
||||
var state = self.getPlayerStateInternal(data);
|
||||
|
||||
$(self).trigger("positionchange", [state]);
|
||||
});
|
||||
|
||||
self.play = function (options) {
|
||||
|
||||
Dashboard.getCurrentUser().done(function (user) {
|
||||
|
||||
if (options.items) {
|
||||
|
||||
self.playWithCommand(options, 'PlayNow');
|
||||
|
||||
} else {
|
||||
|
||||
self.getItemsForPlayback({
|
||||
|
||||
Ids: options.ids.join(',')
|
||||
|
||||
}).done(function (result) {
|
||||
|
||||
options.items = result.Items;
|
||||
self.playWithCommand(options, 'PlayNow');
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
self.playWithCommand = function (options, command) {
|
||||
|
||||
if (!options.items) {
|
||||
ApiClient.getItem(Dashboard.getCurrentUserId(), options.ids[0]).done(function (item) {
|
||||
|
||||
options.items = [item];
|
||||
self.playWithCommand(options, command);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
playItemInternal(items[0], null, serverAddress);
|
||||
};
|
||||
|
||||
function validatePlaybackInfoResult(result) {
|
||||
|
||||
if (result.ErrorCode) {
|
||||
|
||||
MediaController.showPlaybackInfoErrorMessage(result.ErrorCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getOptimalMediaSource(mediaType, versions) {
|
||||
|
||||
var optimalVersion = versions.filter(function (v) {
|
||||
|
||||
v.enableDirectPlay = MediaController.supportsDirectPlay(v);
|
||||
|
||||
return v.enableDirectPlay;
|
||||
|
||||
})[0];
|
||||
|
||||
if (!optimalVersion) {
|
||||
optimalVersion = versions.filter(function (v) {
|
||||
|
||||
return v.SupportsDirectStream;
|
||||
|
||||
})[0];
|
||||
}
|
||||
|
||||
return optimalVersion || versions.filter(function (s) {
|
||||
return s.SupportsTranscoding;
|
||||
})[0];
|
||||
}
|
||||
|
||||
function playItemInternal(item, startPosition) {
|
||||
|
||||
if (item == null) {
|
||||
throw new Error("item cannot be null");
|
||||
}
|
||||
|
||||
if (item.MediaType !== 'Audio' && item.MediaType !== 'Video') {
|
||||
throw new Error("Unrecognized media type");
|
||||
}
|
||||
|
||||
if (item.IsPlaceHolder) {
|
||||
MediaController.showPlaybackInfoErrorMessage('PlaceHolder');
|
||||
return;
|
||||
}
|
||||
|
||||
var deviceProfile = self.getDeviceProfile();
|
||||
|
||||
if (item.MediaType === "Video") {
|
||||
|
||||
Dashboard.showModalLoadingMsg();
|
||||
}
|
||||
|
||||
MediaController.getPlaybackInfo(item.Id, deviceProfile, startPosition).done(function (playbackInfoResult) {
|
||||
|
||||
if (validatePlaybackInfoResult(playbackInfoResult)) {
|
||||
|
||||
var mediaSource = getOptimalMediaSource(item.MediaType, playbackInfoResult.MediaSources);
|
||||
|
||||
if (mediaSource) {
|
||||
|
||||
if (mediaSource.RequiresOpening) {
|
||||
|
||||
getLiveStream(item.Id, playbackInfoResult.PlaySessionId, deviceProfile, startPosition, mediaSource, null, null).done(function (openLiveStreamResult) {
|
||||
|
||||
openLiveStreamResult.MediaSource.enableDirectPlay = supportsDirectPlay(openLiveStreamResult.MediaSource);
|
||||
|
||||
playInternalPostMediaSourceSelection(item, openLiveStreamResult.MediaSource, startPosition, callback);
|
||||
});
|
||||
|
||||
} else {
|
||||
playInternalPostMediaSourceSelection(item, mediaSource, startPosition, callback);
|
||||
}
|
||||
} else {
|
||||
Dashboard.hideModalLoadingMsg();
|
||||
MediaController.showPlaybackInfoErrorMessage('NoCompatibleStream');
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function playInternalPostMediaSourceSelection(item, mediaSource, startPosition, deferred) {
|
||||
|
||||
Dashboard.hideModalLoadingMsg();
|
||||
|
||||
var streamInfo = MediaPlayer.createStreamInfo('Video', item, mediaSource, startPosition);
|
||||
|
||||
currentDevice.getMediaPlayer().playMedia(
|
||||
streamInfo.url,
|
||||
streamInfo.MimeType,
|
||||
{
|
||||
title: item.Name,
|
||||
description: item.Overview || '',
|
||||
shouldLoop: false
|
||||
}
|
||||
).success(function (launchSession, mediaControl) {
|
||||
|
||||
console.log("Video launch successful");
|
||||
currentMediaControl = mediaControl && mediaControl.acquire();
|
||||
|
||||
}).error(function (err) {
|
||||
|
||||
console.log("error: " + err.message);
|
||||
});
|
||||
|
||||
deferred.resolveWith(null, [streamInfo]);
|
||||
}
|
||||
|
||||
self.unpause = function () {
|
||||
if (currentMediaControl) {
|
||||
currentMediaControl.pause();
|
||||
}
|
||||
};
|
||||
|
||||
self.pause = function () {
|
||||
if (currentMediaControl) {
|
||||
currentMediaControl.pause();
|
||||
}
|
||||
};
|
||||
|
||||
self.shuffle = function (id) {
|
||||
|
||||
var userId = Dashboard.getCurrentUserId();
|
||||
|
||||
ApiClient.getItem(userId, id).done(function (item) {
|
||||
|
||||
self.playWithCommand({
|
||||
|
||||
items: [item]
|
||||
|
||||
}, 'Shuffle');
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
self.instantMix = function (id) {
|
||||
|
||||
var userId = Dashboard.getCurrentUserId();
|
||||
|
||||
ApiClient.getItem(userId, id).done(function (item) {
|
||||
|
||||
self.playWithCommand({
|
||||
|
||||
items: [item]
|
||||
|
||||
}, 'InstantMix');
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
self.canQueueMediaType = function (mediaType) {
|
||||
return mediaType == "Audio";
|
||||
};
|
||||
|
||||
self.queue = function (options) {
|
||||
self.playWithCommnd(options, 'PlayLast');
|
||||
};
|
||||
|
||||
self.queueNext = function (options) {
|
||||
self.playWithCommand(options, 'PlayNext');
|
||||
};
|
||||
|
||||
self.stop = function () {
|
||||
if (currentMediaControl) {
|
||||
currentMediaControl.stop();
|
||||
}
|
||||
};
|
||||
|
||||
self.displayContent = function (options) {
|
||||
|
||||
// TODO
|
||||
};
|
||||
|
||||
self.mute = function () {
|
||||
if (currentDevice) {
|
||||
currentDevice.getVolumeControl().setMute(true);
|
||||
}
|
||||
};
|
||||
|
||||
self.unMute = function () {
|
||||
self.setVolume(getCurrentVolume() + 2);
|
||||
};
|
||||
|
||||
self.toggleMute = function () {
|
||||
|
||||
var state = self.lastPlayerData || {};
|
||||
state = state.PlayState || {};
|
||||
|
||||
if (state.IsMuted) {
|
||||
self.unMute();
|
||||
} else {
|
||||
self.mute();
|
||||
}
|
||||
};
|
||||
|
||||
self.getDeviceProfile = function () {
|
||||
|
||||
var qualityOption = self.getVideoQualityOptions().filter(function (q) {
|
||||
return q.selected;
|
||||
})[0];
|
||||
|
||||
var bitrateSetting = AppSettings.maxStreamingBitrate();
|
||||
|
||||
var profile = {};
|
||||
|
||||
profile.MaxStreamingBitrate = bitrateSetting;
|
||||
profile.MaxStaticBitrate = 40000000;
|
||||
profile.MusicStreamingTranscodingBitrate = Math.min(bitrateSetting, 192000);
|
||||
|
||||
profile.DirectPlayProfiles = [];
|
||||
profile.DirectPlayProfiles.push({
|
||||
Container: 'mp4,m4v',
|
||||
Type: 'Video',
|
||||
VideoCodec: 'h264',
|
||||
AudioCodec: 'aac,mp3,ac3'
|
||||
});
|
||||
profile.DirectPlayProfiles.push({
|
||||
Container: 'mov',
|
||||
Type: 'Video'
|
||||
});
|
||||
|
||||
profile.DirectPlayProfiles.push({
|
||||
Container: 'mp3',
|
||||
Type: 'Audio'
|
||||
});
|
||||
|
||||
profile.DirectPlayProfiles.push({
|
||||
Container: 'aac',
|
||||
Type: 'Audio'
|
||||
});
|
||||
|
||||
profile.TranscodingProfiles = [];
|
||||
profile.TranscodingProfiles.push({
|
||||
Container: 'mp3',
|
||||
Type: 'Audio',
|
||||
AudioCodec: 'mp3',
|
||||
Context: 'Streaming',
|
||||
Protocol: 'http'
|
||||
});
|
||||
|
||||
if (self.canPlayHls()) {
|
||||
profile.TranscodingProfiles.push({
|
||||
Container: 'ts',
|
||||
Type: 'Video',
|
||||
AudioCodec: 'aac',
|
||||
VideoCodec: 'h264',
|
||||
Context: 'Streaming',
|
||||
Protocol: 'hls'
|
||||
});
|
||||
}
|
||||
|
||||
profile.TranscodingProfiles.push({
|
||||
Container: 'mp4',
|
||||
Type: 'Video',
|
||||
AudioCodec: 'aac',
|
||||
VideoCodec: 'h264',
|
||||
Context: 'Streaming',
|
||||
Protocol: 'http'
|
||||
});
|
||||
|
||||
profile.ContainerProfiles = [];
|
||||
|
||||
profile.CodecProfiles = [];
|
||||
profile.CodecProfiles.push({
|
||||
Type: 'Audio',
|
||||
Conditions: [{
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'AudioChannels',
|
||||
Value: '2'
|
||||
}]
|
||||
});
|
||||
|
||||
profile.CodecProfiles.push({
|
||||
Type: 'VideoAudio',
|
||||
Codec: 'aac,mp3',
|
||||
Conditions: [
|
||||
{
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'AudioChannels',
|
||||
Value: '6'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
profile.CodecProfiles.push({
|
||||
Type: 'Video',
|
||||
Codec: 'h264',
|
||||
Conditions: [
|
||||
{
|
||||
Condition: 'NotEquals',
|
||||
Property: 'IsAnamorphic',
|
||||
Value: 'true',
|
||||
IsRequired: false
|
||||
},
|
||||
{
|
||||
Condition: 'EqualsAny',
|
||||
Property: 'VideoProfile',
|
||||
Value: 'high|main|baseline|constrained baseline'
|
||||
},
|
||||
{
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'VideoLevel',
|
||||
Value: '41'
|
||||
},
|
||||
{
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'Width',
|
||||
Value: qualityOption.maxWidth
|
||||
}]
|
||||
});
|
||||
|
||||
// Subtitle profiles
|
||||
profile.SubtitleProfiles = [];
|
||||
profile.ResponseProfiles = [];
|
||||
|
||||
profile.ResponseProfiles.push({
|
||||
Type: 'Video',
|
||||
Container: 'm4v',
|
||||
MimeType: 'video/mp4'
|
||||
});
|
||||
|
||||
//profile.ResponseProfiles.push({
|
||||
// Type: 'Video',
|
||||
// Container: 'mkv',
|
||||
// MimeType: 'video/webm'
|
||||
//});
|
||||
|
||||
return profile;
|
||||
};
|
||||
|
||||
function getBaseTargetInfo() {
|
||||
var target = {};
|
||||
|
||||
target.playableMediaTypes = ["Audio", "Video"];
|
||||
target.isLocalPlayer = false;
|
||||
target.supportedCommands = [
|
||||
"VolumeUp",
|
||||
"VolumeDown",
|
||||
"Mute",
|
||||
"Unmute",
|
||||
"ToggleMute",
|
||||
"SetVolume"
|
||||
];
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
function convertDeviceToTarget(device) {
|
||||
|
||||
var target = getBaseTargetInfo();
|
||||
|
||||
target.appName = target.name = target.deviceName = device.getFriendlyName();
|
||||
target.playerName = PlayerName;
|
||||
target.id = device.getId();
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
function isValid(device) {
|
||||
|
||||
var validTokens = ['AirPlay', 'Airplay', 'airplay'];
|
||||
|
||||
return validTokens.filter(function (t) {
|
||||
|
||||
return device.hasService(t);
|
||||
|
||||
}).length > 0;
|
||||
}
|
||||
|
||||
self.getTargets = function () {
|
||||
|
||||
return ConnectSDKHelper.getDeviceList().filter(function (d) {
|
||||
|
||||
return isValid(d);
|
||||
|
||||
}).map(convertDeviceToTarget);
|
||||
};
|
||||
|
||||
self.seek = function (position) {
|
||||
|
||||
position = parseInt(position);
|
||||
position = position / 10000000;
|
||||
|
||||
// TODO
|
||||
};
|
||||
|
||||
self.setAudioStreamIndex = function (index) {
|
||||
// TODO
|
||||
};
|
||||
|
||||
self.setSubtitleStreamIndex = function (index) {
|
||||
// TODO
|
||||
};
|
||||
|
||||
self.nextTrack = function () {
|
||||
// TODO
|
||||
};
|
||||
|
||||
self.previousTrack = function () {
|
||||
// TODO
|
||||
};
|
||||
|
||||
self.beginPlayerUpdates = function () {
|
||||
// Setup polling here
|
||||
};
|
||||
|
||||
self.endPlayerUpdates = function () {
|
||||
// Stop polling here
|
||||
};
|
||||
|
||||
function getCurrentVolume() {
|
||||
var state = self.lastPlayerData || {};
|
||||
state = state.PlayState || {};
|
||||
|
||||
return state.VolumeLevel == null ? 100 : state.VolumeLevel;
|
||||
}
|
||||
|
||||
self.volumeDown = function () {
|
||||
|
||||
if (currentDevice) {
|
||||
currentDevice.getVolumeControl().volumeDown();
|
||||
}
|
||||
};
|
||||
|
||||
self.volumeUp = function () {
|
||||
|
||||
if (currentDevice) {
|
||||
currentDevice.getVolumeControl().volumeUp();
|
||||
}
|
||||
};
|
||||
|
||||
self.setVolume = function (vol) {
|
||||
|
||||
vol = Math.min(vol, 100);
|
||||
vol = Math.max(vol, 0);
|
||||
|
||||
if (currentDevice) {
|
||||
currentDevice.getVolumeControl().setVolume(vol / 100);
|
||||
}
|
||||
};
|
||||
|
||||
self.getPlayerState = function () {
|
||||
|
||||
var deferred = $.Deferred();
|
||||
|
||||
var result = self.getPlayerStateInternal();
|
||||
|
||||
deferred.resolveWith(null, [result]);
|
||||
|
||||
return deferred.promise();
|
||||
};
|
||||
|
||||
self.lastPlayerData = {};
|
||||
|
||||
self.getPlayerStateInternal = function (data) {
|
||||
|
||||
data = data || self.lastPlayerData;
|
||||
self.lastPlayerData = data;
|
||||
|
||||
console.log(JSON.stringify(data));
|
||||
return data;
|
||||
};
|
||||
|
||||
function handleSessionDisconnect() {
|
||||
console.log("session disconnected");
|
||||
|
||||
cleanupSession();
|
||||
MediaController.removeActivePlayer(PlayerName);
|
||||
}
|
||||
|
||||
function cleanupSession() {
|
||||
|
||||
}
|
||||
|
||||
function launchWebApp(device) {
|
||||
|
||||
if (currentDevice) {
|
||||
cleanupSession();
|
||||
}
|
||||
|
||||
console.log('session.connect succeeded');
|
||||
|
||||
MediaController.setActivePlayer(PlayerName, convertDeviceToTarget(device));
|
||||
currentDevice = device;
|
||||
currentDeviceId = device.getId();
|
||||
}
|
||||
|
||||
function onDeviceReady(device) {
|
||||
|
||||
device.off("ready");
|
||||
|
||||
console.log('creating webAppSession');
|
||||
|
||||
launchWebApp(device);
|
||||
}
|
||||
|
||||
self.tryPair = function (target) {
|
||||
|
||||
var deferred = $.Deferred();
|
||||
|
||||
var device = ConnectSDKHelper.getDeviceList().filter(function (d) {
|
||||
|
||||
return d.getId() == target.id;
|
||||
})[0];
|
||||
|
||||
if (device) {
|
||||
|
||||
self.tryPairWithDevice(device, deferred);
|
||||
|
||||
} else {
|
||||
deferred.reject();
|
||||
}
|
||||
|
||||
return deferred.promise();
|
||||
};
|
||||
|
||||
self.tryPairWithDevice = function (device, deferred) {
|
||||
|
||||
console.log('Will attempt to connect to Connect Device');
|
||||
|
||||
device.on("disconnect", function () {
|
||||
device.off("ready");
|
||||
device.off("disconnect");
|
||||
});
|
||||
|
||||
if (device.isReady()) {
|
||||
console.log('Device is already ready, calling onDeviceReady');
|
||||
onDeviceReady(device);
|
||||
} else {
|
||||
|
||||
console.log('Binding device ready handler');
|
||||
|
||||
device.on("ready", function () {
|
||||
console.log('device.ready fired');
|
||||
onDeviceReady(device);
|
||||
});
|
||||
|
||||
console.log('Calling device.connect');
|
||||
device.connect();
|
||||
}
|
||||
};
|
||||
|
||||
$(MediaController).on('playerchange', function (e, newPlayer, newTarget) {
|
||||
|
||||
if (currentDevice) {
|
||||
if (newTarget.id != currentDeviceId) {
|
||||
if (currentDevice) {
|
||||
console.log('Disconnecting from connect device');
|
||||
//currentDevice.disconnect();
|
||||
cleanupSession();
|
||||
currentDevice = null;
|
||||
currentDeviceId = null;
|
||||
currentMediaControl = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function onResume() {
|
||||
|
||||
var deviceId = currentDeviceId;
|
||||
|
||||
if (deviceId) {
|
||||
self.tryPair({
|
||||
id: deviceId
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("resume", onResume, false);
|
||||
}
|
||||
|
||||
MediaController.registerPlayer(new connectSDKPlayer());
|
||||
|
||||
})();
|
131
dashboard-ui/cordova/iap.js
vendored
Normal file
131
dashboard-ui/cordova/iap.js
vendored
Normal file
|
@ -0,0 +1,131 @@
|
|||
(function () {
|
||||
|
||||
var unlockAlias = "premium features";
|
||||
var unlockAppProductId = 'appunlock';
|
||||
|
||||
var updatedProducts = [];
|
||||
|
||||
function updateProductInfo(product) {
|
||||
|
||||
updatedProducts = updatedProducts.filter(function (r) {
|
||||
return r.id != product.id;
|
||||
});
|
||||
|
||||
updatedProducts.push(product);
|
||||
|
||||
Events.trigger(IapManager, 'productupdated', [product]);
|
||||
}
|
||||
|
||||
function normalizeId(id) {
|
||||
|
||||
// This is what i named it in itunes
|
||||
id = id.replace('premiumunlock', 'appunlock');
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
function getProduct(id) {
|
||||
|
||||
id = normalizeId(id);
|
||||
|
||||
var products = updatedProducts.filter(function (r) {
|
||||
return r.id == id;
|
||||
});
|
||||
|
||||
return products.length ? products[0] : null;
|
||||
}
|
||||
|
||||
function isPurchaseAvailable(id) {
|
||||
var product = getProduct(id);
|
||||
|
||||
return product != null && product.valid /*&& product.canPurchase*/;
|
||||
}
|
||||
|
||||
function beginPurchase(id) {
|
||||
id = normalizeId(id);
|
||||
store.order(id);
|
||||
}
|
||||
|
||||
function validateProduct(product, callback) {
|
||||
|
||||
// product attributes:
|
||||
// https://github.com/j3k0/cordova-plugin-purchase/blob/master/doc/api.md#validation-error-codes
|
||||
|
||||
callback(true, {
|
||||
|
||||
});
|
||||
|
||||
//callback(true, { ... transaction details ... }); // success!
|
||||
|
||||
//// OR
|
||||
//callback(false, {
|
||||
// error: {
|
||||
// code: store.PURCHASE_EXPIRED,
|
||||
// message: "XYZ"
|
||||
// }
|
||||
//});
|
||||
|
||||
//// OR
|
||||
//callback(false, "Impossible to proceed with validation");
|
||||
}
|
||||
|
||||
function initializeStore() {
|
||||
|
||||
// Let's set a pretty high verbosity level, so that we see a lot of stuff
|
||||
// in the console (reassuring us that something is happening).
|
||||
store.verbosity = store.INFO;
|
||||
|
||||
store.validator = validateProduct;
|
||||
|
||||
// iOS
|
||||
store.register({
|
||||
id: unlockAppProductId,
|
||||
alias: unlockAlias,
|
||||
type: store.NON_CONSUMABLE
|
||||
});
|
||||
|
||||
// When purchase of the full version is approved,
|
||||
// show some logs and finish the transaction.
|
||||
store.when(unlockAppProductId).approved(function (order) {
|
||||
log('You just unlocked the FULL VERSION!');
|
||||
order.finish();
|
||||
});
|
||||
|
||||
store.when(unlockAppProductId).verified(function (p) {
|
||||
log("verified");
|
||||
p.finish();
|
||||
});
|
||||
|
||||
// The play button can only be accessed when the user
|
||||
// owns the full version.
|
||||
store.when(unlockAppProductId).updated(function (product) {
|
||||
|
||||
if (product.loaded && product.valid && product.state == store.APPROVED) {
|
||||
console.log('finishing previously created transaction');
|
||||
product.finish();
|
||||
}
|
||||
updateProductInfo(product);
|
||||
});
|
||||
|
||||
// When every goes as expected, it's time to celebrate!
|
||||
// The "ready" event should be welcomed with music and fireworks,
|
||||
// go ask your boss about it! (just in case)
|
||||
store.ready(function () {
|
||||
|
||||
console.log("Store ready");
|
||||
});
|
||||
|
||||
// After we've done our setup, we tell the store to do
|
||||
// it's first refresh. Nothing will happen if we do not call store.refresh()
|
||||
store.refresh();
|
||||
}
|
||||
|
||||
window.IapManager = {
|
||||
isPurchaseAvailable: isPurchaseAvailable,
|
||||
getProductInfo: getProduct,
|
||||
beginPurchase: beginPurchase
|
||||
};
|
||||
|
||||
initializeStore();
|
||||
|
||||
})();
|
120
dashboard-ui/cordova/imagestore.js
vendored
Normal file
120
dashboard-ui/cordova/imagestore.js
vendored
Normal file
|
@ -0,0 +1,120 @@
|
|||
(function () {
|
||||
|
||||
function setImageIntoElement(elem, url) {
|
||||
|
||||
if (elem.tagName === "DIV") {
|
||||
|
||||
elem.style.backgroundImage = "url('" + url + "')";
|
||||
|
||||
} else {
|
||||
elem.setAttribute("src", url);
|
||||
}
|
||||
}
|
||||
|
||||
var fileSystem;
|
||||
function getFileSystem() {
|
||||
|
||||
var deferred = DeferredBuilder.Deferred();
|
||||
|
||||
if (fileSystem) {
|
||||
deferred.resolveWith(null, [fileSystem]);
|
||||
} else {
|
||||
requestFileSystem(PERSISTENT, 0, function (fs) {
|
||||
fileSystem = fs;
|
||||
deferred.resolveWith(null, [fileSystem]);
|
||||
});
|
||||
}
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
function indexedDbBlobImageStore() {
|
||||
|
||||
var self = this;
|
||||
|
||||
function getCacheKey(url) {
|
||||
|
||||
// Try to strip off the domain to share the cache between local and remote connections
|
||||
var index = url.indexOf('://');
|
||||
|
||||
if (index != -1) {
|
||||
url = url.substring(index + 3);
|
||||
|
||||
index = url.indexOf('/');
|
||||
|
||||
if (index != -1) {
|
||||
url = url.substring(index + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return CryptoJS.MD5(url).toString();
|
||||
}
|
||||
|
||||
function normalizeReturnUrl(url) {
|
||||
if ($.browser.safari) {
|
||||
|
||||
// Use the embedded server for iOS8, and also if we don't know the iOS version, just to be safe
|
||||
//if ($.browser.iOSVersion == 8 || !$.browser.iOSVersion)
|
||||
{
|
||||
return url.replace('file://', '');
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
self.getImageUrl = function (originalUrl) {
|
||||
|
||||
if ($.browser.android && originalUrl.indexOf('tag=') != -1) {
|
||||
originalUrl += "&format=webp";
|
||||
}
|
||||
|
||||
var deferred = DeferredBuilder.Deferred();
|
||||
var key = getCacheKey(originalUrl);
|
||||
|
||||
console.log('getImageUrl:' + originalUrl);
|
||||
|
||||
getFileSystem().done(function (fileSystem) {
|
||||
var path = fileSystem.root.toURL() + "/emby/cache/" + key;
|
||||
|
||||
resolveLocalFileSystemURL(path, function (fileEntry) {
|
||||
var localUrl = normalizeReturnUrl(fileEntry.toURL());
|
||||
console.log('returning cached file: ' + localUrl);
|
||||
deferred.resolveWith(null, [localUrl]);
|
||||
|
||||
}, function () {
|
||||
|
||||
console.log('downloading: ' + originalUrl);
|
||||
var ft = new FileTransfer();
|
||||
ft.download(originalUrl, path, function (entry) {
|
||||
|
||||
var localUrl = normalizeReturnUrl(entry.toURL());
|
||||
|
||||
console.log(localUrl);
|
||||
deferred.resolveWith(null, [localUrl]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise();
|
||||
};
|
||||
|
||||
self.setImageInto = function (elem, url) {
|
||||
|
||||
function onFail() {
|
||||
setImageIntoElement(elem, url);
|
||||
}
|
||||
|
||||
self.getImageUrl(url).done(function (localUrl) {
|
||||
|
||||
setImageIntoElement(elem, localUrl);
|
||||
|
||||
}).fail(onFail);
|
||||
};
|
||||
|
||||
window.ImageStore = self;
|
||||
}
|
||||
|
||||
new indexedDbBlobImageStore();
|
||||
|
||||
})();
|
38
dashboard-ui/cordova/ios/actionsheet.js
vendored
Normal file
38
dashboard-ui/cordova/ios/actionsheet.js
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
(function () {
|
||||
|
||||
function show(options) {
|
||||
|
||||
// items
|
||||
// positionTo
|
||||
// showCancel
|
||||
// title
|
||||
|
||||
var innerOptions = {
|
||||
'title': options.title,
|
||||
'buttonLabels': options.items.map(function (i) {
|
||||
return i.name;
|
||||
})
|
||||
};
|
||||
|
||||
// Show cancel unless the caller explicitly set it to false
|
||||
if (options.showCancel !== false) {
|
||||
innerOptions.addCancelButtonWithLabel = Globalize.translate('ButtonCancel');
|
||||
}
|
||||
|
||||
// Depending on the buttonIndex, you can now call shareViaFacebook or shareViaTwitter
|
||||
// of the SocialSharing plugin (https://github.com/EddyVerbruggen/SocialSharing-PhoneGap-Plugin)
|
||||
window.plugins.actionsheet.show(innerOptions, function (index) {
|
||||
|
||||
if (options.callback) {
|
||||
|
||||
if (index >= 1) {
|
||||
options.callback(options.items[index - 1].id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.ActionSheetElement = {
|
||||
show: show
|
||||
};
|
||||
})();
|
21
dashboard-ui/cordova/ios/orientation.js
vendored
Normal file
21
dashboard-ui/cordova/ios/orientation.js
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
(function () {
|
||||
|
||||
function forceScroll() {
|
||||
|
||||
var doc = $(document);
|
||||
|
||||
// Try to make it react quicker to the orientation change
|
||||
doc.scrollTop(doc.scrollTop() + 1);
|
||||
}
|
||||
|
||||
function onOrientationChange() {
|
||||
|
||||
forceScroll();
|
||||
for (var i = 0; i <= 500; i += 100) {
|
||||
setTimeout(forceScroll, i);
|
||||
}
|
||||
}
|
||||
|
||||
$(window).on('orientationchange', onOrientationChange);
|
||||
|
||||
})();
|
251
dashboard-ui/cordova/registrationservices.js
vendored
Normal file
251
dashboard-ui/cordova/registrationservices.js
vendored
Normal file
|
@ -0,0 +1,251 @@
|
|||
(function () {
|
||||
|
||||
function isAndroid() {
|
||||
|
||||
var platform = (device.platform || '').toLowerCase();
|
||||
|
||||
return platform.indexOf('android') != -1;
|
||||
}
|
||||
|
||||
function getPremiumUnlockFeatureId() {
|
||||
|
||||
if (isAndroid()) {
|
||||
return "com.mb.android.unlock";
|
||||
}
|
||||
|
||||
return 'appunlock';
|
||||
}
|
||||
|
||||
function validatePlayback(deferred) {
|
||||
|
||||
// Don't require validation on android
|
||||
if (isAndroid()) {
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
validateFeature(getPremiumUnlockFeatureId(), deferred);
|
||||
}
|
||||
|
||||
function validateLiveTV(deferred) {
|
||||
|
||||
if (!isAndroid()) {
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
validateFeature(getPremiumUnlockFeatureId(), deferred);
|
||||
}
|
||||
|
||||
function validateServerManagement(deferred) {
|
||||
deferred.resolve();
|
||||
}
|
||||
|
||||
function getRegistrationInfo(feature, enableSupporterUnlock) {
|
||||
|
||||
if (!enableSupporterUnlock) {
|
||||
var deferred = $.Deferred();
|
||||
deferred.resolveWith(null, [{}]);
|
||||
return deferred.promise();
|
||||
}
|
||||
return ConnectionManager.getRegistrationInfo(feature, ApiClient);
|
||||
}
|
||||
|
||||
function validateFeature(id, deferred) {
|
||||
|
||||
var info = IapManager.getProductInfo(id) || {};
|
||||
|
||||
if (info.owned) {
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
var productInfo = {
|
||||
enableSupporterUnlock: isAndroid(),
|
||||
enableAppUnlock: IapManager.isPurchaseAvailable(id),
|
||||
id: id,
|
||||
price: info.price
|
||||
};
|
||||
|
||||
var prefix = isAndroid() ? 'android' : 'ios';
|
||||
|
||||
// Get supporter status
|
||||
getRegistrationInfo(prefix + 'appunlock', productInfo.enableSupporterUnlock).done(function (registrationInfo) {
|
||||
|
||||
if (registrationInfo.IsRegistered) {
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
showInAppPurchaseInfo(productInfo, registrationInfo, deferred);
|
||||
|
||||
}).fail(function () {
|
||||
deferred.reject();
|
||||
});
|
||||
}
|
||||
|
||||
function getInAppPurchaseElement(info) {
|
||||
|
||||
cancelInAppPurchase();
|
||||
|
||||
var html = '';
|
||||
html += '<div class="inAppPurchaseOverlay" style="background-image:url(css/images/splash.jpg);top:0;left:0;right:0;bottom:0;position:fixed;background-position:center center;background-size:100% 100%;background-repeat:no-repeat;z-index:999999;">';
|
||||
html += '<div class="inAppPurchaseOverlayInner" style="background:rgba(10,10,10,.8);width:100%;height:100%;color:#eee;">';
|
||||
|
||||
|
||||
html += '<div class="inAppPurchaseForm" style="margin: 0 auto;padding: 30px 1em 0;">';
|
||||
|
||||
html += '<h1 style="color:#fff;">' + Globalize.translate('HeaderUnlockApp') + '</h1>';
|
||||
|
||||
html += '<p style="margin:2em 0;">';
|
||||
|
||||
if (info.enableSupporterUnlock && info.enableAppUnlock) {
|
||||
html += Globalize.translate('MessageUnlockAppWithPurchaseOrSupporter');
|
||||
}
|
||||
else if (info.enableSupporterUnlock) {
|
||||
html += Globalize.translate('MessageUnlockAppWithSupporter');
|
||||
} else if (info.enableAppUnlock) {
|
||||
html += Globalize.translate('MessageUnlockAppWithPurchase');
|
||||
} else {
|
||||
html += '<span style="color:red;">';
|
||||
html += Globalize.translate('MessagePaymentServicesUnavailable');
|
||||
html += '</span>';
|
||||
}
|
||||
html += '</p>';
|
||||
|
||||
if (info.enableSupporterUnlock) {
|
||||
html += '<p style="margin:2em 0;">';
|
||||
html += Globalize.translate('MessageToValidateSupporter');
|
||||
html += '</p>';
|
||||
}
|
||||
|
||||
if (info.enableAppUnlock) {
|
||||
|
||||
var unlockText = Globalize.translate('ButtonUnlockWithPurchase');
|
||||
if (info.price) {
|
||||
unlockText = Globalize.translate('ButtonUnlockPrice', info.price);
|
||||
}
|
||||
html += '<button class="btn btnActionAccent btnAppUnlock" data-role="none" type="button"><span>' + unlockText + '</span><i class="fa fa-check"></i></button>';
|
||||
}
|
||||
|
||||
if (info.enableSupporterUnlock) {
|
||||
html += '<button class="btn btnSignInSupporter" data-role="none" type="button"><span>' + Globalize.translate('ButtonUnlockWithSupporter') + '</span><i class="fa fa-check"></i></button>';
|
||||
}
|
||||
|
||||
html += '<button class="btn btnCancel" data-role="none" type="button"><span>' + Globalize.translate('ButtonCancel') + '</span><i class="fa fa-close"></i></button>';
|
||||
|
||||
html += '</div>';
|
||||
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
$(document.body).append(html);
|
||||
|
||||
return $('.inAppPurchaseOverlay');
|
||||
}
|
||||
|
||||
function cancelInAppPurchase() {
|
||||
|
||||
$('.inAppPurchaseOverlay').remove();
|
||||
}
|
||||
|
||||
var currentDisplayingProductInfo = null;
|
||||
var currentDisplayingDeferred = null;
|
||||
|
||||
function clearCurrentDisplayingInfo() {
|
||||
currentDisplayingProductInfo = null;
|
||||
currentDisplayingDeferred = null;
|
||||
}
|
||||
|
||||
function showInAppPurchaseInfo(info, serverRegistrationInfo, deferred) {
|
||||
|
||||
var elem = getInAppPurchaseElement(info);
|
||||
|
||||
currentDisplayingProductInfo = info;
|
||||
currentDisplayingDeferred = deferred;
|
||||
|
||||
$('.btnAppUnlock', elem).on('click', function () {
|
||||
|
||||
IapManager.beginPurchase(info.id);
|
||||
});
|
||||
|
||||
$('.btnCancel', elem).on('click', function () {
|
||||
|
||||
clearCurrentDisplayingInfo();
|
||||
cancelInAppPurchase();
|
||||
|
||||
deferred.reject();
|
||||
});
|
||||
$('.btnSignInSupporter', elem).on('click', function () {
|
||||
|
||||
clearCurrentDisplayingInfo();
|
||||
|
||||
Dashboard.alert({
|
||||
message: Globalize.translate('MessagePleaseSignInLocalNetwork'),
|
||||
callback: function () {
|
||||
cancelInAppPurchase();
|
||||
Dashboard.logout();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onProductUpdated(e, product) {
|
||||
|
||||
var currentInfo = currentDisplayingProductInfo;
|
||||
var deferred = currentDisplayingDeferred;
|
||||
|
||||
if (currentInfo && deferred) {
|
||||
if (product.owned && product.id == currentInfo.id) {
|
||||
|
||||
clearCurrentDisplayingInfo();
|
||||
cancelInAppPurchase();
|
||||
deferred.resolve();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.RegistrationServices = {
|
||||
|
||||
renderPluginInfo: function (page, pkg, pluginSecurityInfo) {
|
||||
|
||||
|
||||
},
|
||||
|
||||
addRecurringFields: function (page, period) {
|
||||
|
||||
},
|
||||
|
||||
initSupporterForm: function (page) {
|
||||
|
||||
$('.recurringSubscriptionCancellationHelp', page).html('');
|
||||
},
|
||||
|
||||
validateFeature: function (name) {
|
||||
var deferred = DeferredBuilder.Deferred();
|
||||
|
||||
if (name == 'playback') {
|
||||
validatePlayback(deferred);
|
||||
} else if (name == 'livetv') {
|
||||
validateLiveTV(deferred);
|
||||
} else if (name == 'manageserver') {
|
||||
validateServerManagement(deferred);
|
||||
} else {
|
||||
deferred.resolve();
|
||||
}
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
};
|
||||
|
||||
function onIapManagerLoaded() {
|
||||
Events.on(IapManager, 'productupdated', onProductUpdated);
|
||||
}
|
||||
|
||||
if (isAndroid()) {
|
||||
requirejs(['cordova/android/iap'], onIapManagerLoaded);
|
||||
} else {
|
||||
requirejs(['cordova/iap'], onIapManagerLoaded);
|
||||
}
|
||||
|
||||
})();
|
173
dashboard-ui/cordova/remotecontrols.js
vendored
Normal file
173
dashboard-ui/cordova/remotecontrols.js
vendored
Normal file
|
@ -0,0 +1,173 @@
|
|||
(function () {
|
||||
|
||||
// Reports media playback to the device for lock screen control
|
||||
|
||||
var currentPlayer;
|
||||
var lastPlayerState;
|
||||
|
||||
function updatePlayerState(state) {
|
||||
|
||||
if (!state.NowPlayingItem) {
|
||||
hideNowPlayingBar();
|
||||
return;
|
||||
}
|
||||
|
||||
lastPlayerState = state;
|
||||
|
||||
var playState = state.PlayState || {};
|
||||
|
||||
var nameHtml = MediaController.getNowPlayingNameHtml(state.NowPlayingItem) || '';
|
||||
var parts = nameHtml.split('<br/>');
|
||||
|
||||
var artist = parts.length == 1 ? '' : parts[0];
|
||||
var title = parts[parts.length - 1];
|
||||
var album = state.NowPlayingItem.Album || '';
|
||||
var duration = state.NowPlayingItem.RunTimeTicks ? (state.NowPlayingItem.RunTimeTicks / 10000000) : 0;
|
||||
var elapsedTime = playState.PositionTicks ? (playState.PositionTicks / 10000000) : 0;
|
||||
|
||||
var url = '';
|
||||
var imgHeight = 100;
|
||||
|
||||
var nowPlayingItem = state.NowPlayingItem;
|
||||
|
||||
if (nowPlayingItem.PrimaryImageTag) {
|
||||
|
||||
url = ApiClient.getScaledImageUrl(nowPlayingItem.PrimaryImageItemId, {
|
||||
type: "Primary",
|
||||
height: imgHeight,
|
||||
tag: nowPlayingItem.PrimaryImageTag
|
||||
});
|
||||
}
|
||||
else if (nowPlayingItem.BackdropImageTag) {
|
||||
|
||||
url = ApiClient.getScaledImageUrl(nowPlayingItem.BackdropItemId, {
|
||||
type: "Backdrop",
|
||||
height: imgHeight,
|
||||
tag: nowPlayingItem.BackdropImageTag,
|
||||
index: 0
|
||||
});
|
||||
|
||||
} else if (nowPlayingItem.ThumbImageTag) {
|
||||
|
||||
url = ApiClient.getScaledImageUrl(nowPlayingItem.ThumbImageItemId, {
|
||||
type: "Thumb",
|
||||
height: imgHeight,
|
||||
tag: nowPlayingItem.ThumbImageTag
|
||||
});
|
||||
}
|
||||
|
||||
var params = [artist, title, album, url, duration, elapsedTime];
|
||||
try {
|
||||
window.remoteControls.updateMetas(onUpdateMetasSuccess, onUpdateMetasFail, params);
|
||||
} catch (err) {
|
||||
onUpdateMetasFail(err);
|
||||
}
|
||||
}
|
||||
|
||||
function onStateChanged(e, state) {
|
||||
|
||||
updatePlayerState(state);
|
||||
}
|
||||
|
||||
function onPlaybackStart(e, state) {
|
||||
|
||||
console.log('nowplaying event: ' + e.type);
|
||||
|
||||
var player = this;
|
||||
|
||||
player.beginPlayerUpdates();
|
||||
|
||||
onStateChanged.call(player, e, state);
|
||||
}
|
||||
|
||||
function onPlaybackStopped(e, state) {
|
||||
|
||||
console.log('nowplaying event: ' + e.type);
|
||||
var player = this;
|
||||
|
||||
player.endPlayerUpdates();
|
||||
|
||||
hideNowPlayingBar();
|
||||
}
|
||||
|
||||
function releaseCurrentPlayer() {
|
||||
|
||||
if (currentPlayer) {
|
||||
|
||||
$(currentPlayer).off('.cordovaremote');
|
||||
currentPlayer.endPlayerUpdates();
|
||||
currentPlayer = null;
|
||||
|
||||
hideNowPlayingBar();
|
||||
}
|
||||
}
|
||||
|
||||
function hideNowPlayingBar() {
|
||||
|
||||
var artist = "";
|
||||
var title = "";
|
||||
var album = "";
|
||||
var image = "";
|
||||
var duration = 0;
|
||||
var elapsedTime = 0;
|
||||
|
||||
var params = [artist, title, album, image, duration, elapsedTime];
|
||||
|
||||
try {
|
||||
window.remoteControls.updateMetas(onUpdateMetasSuccess, onUpdateMetasFail, params);
|
||||
} catch (err) {
|
||||
onUpdateMetasFail(err);
|
||||
}
|
||||
}
|
||||
|
||||
function onUpdateMetasSuccess() {
|
||||
|
||||
console.log('onUpdateMetasSuccess');
|
||||
}
|
||||
|
||||
function onUpdateMetasFail(fail) {
|
||||
|
||||
console.log('onUpdateMetasFail: ' + fail);
|
||||
}
|
||||
|
||||
function bindToPlayer(player) {
|
||||
|
||||
releaseCurrentPlayer();
|
||||
|
||||
currentPlayer = player;
|
||||
|
||||
if (!player.isLocalPlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('binding remotecontrols to MediaPlayer');
|
||||
|
||||
player.getPlayerState().done(function (state) {
|
||||
|
||||
if (state.NowPlayingItem) {
|
||||
player.beginPlayerUpdates();
|
||||
}
|
||||
|
||||
onStateChanged.call(player, { type: 'init' }, state);
|
||||
});
|
||||
|
||||
$(player).on('playbackstart.cordovaremote', onPlaybackStart)
|
||||
.on('playbackstop.cordovaremote', onPlaybackStopped)
|
||||
.on('playstatechange.cordovaremote', onStateChanged)
|
||||
.on('positionchange.cordovaremote', onStateChanged);
|
||||
}
|
||||
|
||||
Dashboard.ready(function () {
|
||||
|
||||
console.log('binding remotecontrols to MediaController');
|
||||
|
||||
$(MediaController).on('playerchange', function () {
|
||||
|
||||
bindToPlayer(MediaController.getCurrentPlayer());
|
||||
});
|
||||
|
||||
bindToPlayer(MediaController.getCurrentPlayer());
|
||||
|
||||
});
|
||||
|
||||
})();
|
179
dashboard-ui/cordova/serverdiscovery.js
vendored
Normal file
179
dashboard-ui/cordova/serverdiscovery.js
vendored
Normal file
|
@ -0,0 +1,179 @@
|
|||
(function (globalScope) {
|
||||
|
||||
function stringToArrayBuffer(string) {
|
||||
// UTF-16LE
|
||||
var buf = new ArrayBuffer(string.length * 2);
|
||||
var bufView = new Uint16Array(buf);
|
||||
for (var i = 0, strLen = string.length; i < strLen; i++) {
|
||||
bufView[i] = string.charCodeAt(i);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
function arrayBufferToString(buf) {
|
||||
return String.fromCharCode.apply(null, new Uint16Array(buf));
|
||||
}
|
||||
|
||||
function getResultCode(result) {
|
||||
|
||||
if (result != null && result.resultCode != null) {
|
||||
return result.resultCode;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function closeSocket(socketId) {
|
||||
|
||||
try {
|
||||
chrome.sockets.udp.close(socketId);
|
||||
} catch (err) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function findServersInternal(timeoutMs) {
|
||||
|
||||
var deferred = DeferredBuilder.Deferred();
|
||||
|
||||
var servers = [];
|
||||
|
||||
// Expected server properties
|
||||
// Name, Id, Address, EndpointAddress (optional)
|
||||
|
||||
var chrome = globalScope.chrome;
|
||||
|
||||
if (!chrome) {
|
||||
deferred.resolveWith(null, [servers]);
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
var timeout;
|
||||
var socketId;
|
||||
|
||||
function onTimerExpired() {
|
||||
deferred.resolveWith(null, [servers]);
|
||||
|
||||
if (socketId) {
|
||||
chrome.sockets.udp.onReceive.removeListener(onReceive);
|
||||
closeSocket(socketId);
|
||||
}
|
||||
}
|
||||
|
||||
function startTimer() {
|
||||
|
||||
console.log('starting udp receive timer with timeout ms: ' + timeoutMs);
|
||||
|
||||
timeout = setTimeout(onTimerExpired, timeoutMs);
|
||||
}
|
||||
|
||||
function onReceive(info) {
|
||||
|
||||
try {
|
||||
|
||||
console.log('ServerDiscovery message received');
|
||||
|
||||
console.log(info);
|
||||
|
||||
if (info != null && info.socketId == socketId) {
|
||||
var json = arrayBufferToString(info.data);
|
||||
console.log('Server discovery json: ' + json);
|
||||
var server = JSON.parse(json);
|
||||
|
||||
server.RemoteAddress = info.remoteAddress;
|
||||
|
||||
if (info.remotePort) {
|
||||
server.RemoteAddress += ':' + info.remotePort;
|
||||
}
|
||||
|
||||
servers.push(server);
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.log('Error receiving server info: ' + err);
|
||||
}
|
||||
}
|
||||
|
||||
var port = 7359;
|
||||
console.log('chrome.sockets.udp.create');
|
||||
|
||||
startTimer();
|
||||
|
||||
chrome.sockets.udp.create(function (createInfo) {
|
||||
|
||||
if (!createInfo) {
|
||||
console.log('create fail');
|
||||
return;
|
||||
}
|
||||
if (!createInfo.socketId) {
|
||||
console.log('create fail');
|
||||
return;
|
||||
}
|
||||
|
||||
socketId = createInfo.socketId;
|
||||
|
||||
console.log('chrome.sockets.udp.bind');
|
||||
chrome.sockets.udp.bind(createInfo.socketId, '0.0.0.0', 0, function (bindResult) {
|
||||
|
||||
if (getResultCode(bindResult) != 0) {
|
||||
console.log('bind fail: ' + bindResult);
|
||||
return;
|
||||
}
|
||||
|
||||
var data = stringToArrayBuffer('who is EmbyServer?');
|
||||
|
||||
console.log('chrome.sockets.udp.send');
|
||||
|
||||
chrome.sockets.udp.send(createInfo.socketId, data, '255.255.255.255', port, function (sendResult) {
|
||||
|
||||
if (getResultCode(sendResult) != 0) {
|
||||
console.log('send fail: ' + sendResult);
|
||||
|
||||
} else {
|
||||
chrome.sockets.udp.onReceive.addListener(onReceive);
|
||||
console.log('sendTo: success ' + port);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
globalScope.ServerDiscovery = {
|
||||
|
||||
findServers: function (timeoutMs) {
|
||||
|
||||
var deferred = DeferredBuilder.Deferred();
|
||||
|
||||
deviceReadyPromise.done(function () {
|
||||
|
||||
try {
|
||||
findServersInternal(timeoutMs).done(function (result) {
|
||||
|
||||
deferred.resolveWith(null, [result]);
|
||||
|
||||
}).fail(function () {
|
||||
|
||||
deferred.resolveWith(null, [[]]);
|
||||
});
|
||||
} catch (err) {
|
||||
deferred.resolveWith(null, [[]]);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise();
|
||||
}
|
||||
};
|
||||
|
||||
var deviceReadyDeferred = DeferredBuilder.Deferred();
|
||||
var deviceReadyPromise = deviceReadyDeferred.promise();
|
||||
|
||||
document.addEventListener("deviceready", function () {
|
||||
|
||||
deviceReadyDeferred.resolve();
|
||||
|
||||
}, false);
|
||||
|
||||
|
||||
})(window);
|
28
dashboard-ui/cordova/volume.js
vendored
Normal file
28
dashboard-ui/cordova/volume.js
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
(function () {
|
||||
|
||||
// Handle the volume down button
|
||||
//
|
||||
function onVolumeDownKeyDown() {
|
||||
|
||||
MediaController.volumeDown();
|
||||
}
|
||||
|
||||
// Handle the volume up button
|
||||
//
|
||||
function onVolumeUpKeyDown() {
|
||||
|
||||
MediaController.volumeUp();
|
||||
}
|
||||
|
||||
$(MediaController).on('playerchange', function (e, newPlayer, newTarget) {
|
||||
|
||||
document.removeEventListener("volumedownbutton", onVolumeDownKeyDown, false);
|
||||
document.removeEventListener("volumeupbutton", onVolumeUpKeyDown, false);
|
||||
|
||||
if (!newPlayer.localPlayer) {
|
||||
document.addEventListener("volumedownbutton", onVolumeDownKeyDown, false);
|
||||
document.addEventListener("volumeupbutton", onVolumeUpKeyDown, false);
|
||||
}
|
||||
});
|
||||
|
||||
})();
|
87
dashboard-ui/cordova/wakeonlan.js
vendored
Normal file
87
dashboard-ui/cordova/wakeonlan.js
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
(function (globalScope) {
|
||||
|
||||
function getResultCode(result) {
|
||||
|
||||
if (result != null && result.resultCode != null) {
|
||||
return result.resultCode;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function closeSocket(socketId) {
|
||||
|
||||
try {
|
||||
chrome.sockets.udp.close(socketId);
|
||||
} catch (err) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function stringToArrayBuffer(string) {
|
||||
// UTF-16LE
|
||||
var buf = new ArrayBuffer(string.length * 2);
|
||||
var bufView = new Uint16Array(buf);
|
||||
for (var i = 0, strLen = string.length; i < strLen; i++) {
|
||||
bufView[i] = string.charCodeAt(i);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
// https://github.com/agnat/node_wake_on_lan/blob/master/wake_on_lan.js
|
||||
|
||||
globalScope.WakeOnLan = {
|
||||
|
||||
send: function (info) {
|
||||
|
||||
var deferred = DeferredBuilder.Deferred();
|
||||
|
||||
var chrome = globalScope.chrome;
|
||||
|
||||
if (!chrome) {
|
||||
deferred.resolve();
|
||||
return deferred.promise();
|
||||
}
|
||||
|
||||
var port = info.Port || 9;
|
||||
|
||||
//chrome.sockets.udp.create(function (createInfo) {
|
||||
|
||||
// if (!createInfo) {
|
||||
// console.log('create fail');
|
||||
// return;
|
||||
// }
|
||||
// if (!createInfo.socketId) {
|
||||
// console.log('create fail');
|
||||
// return;
|
||||
// }
|
||||
|
||||
// var socketId = createInfo.socketId;
|
||||
|
||||
// console.log('chrome.sockets.udp.bind');
|
||||
// chrome.sockets.udp.bind(createInfo.socketId, '0.0.0.0', 0, function (bindResult) {
|
||||
|
||||
// if (getResultCode(bindResult) != 0) {
|
||||
// console.log('bind fail: ' + bindResult);
|
||||
// deferred.resolve();
|
||||
// closeSocket(socketId);
|
||||
// }
|
||||
|
||||
// var data = stringToArrayBuffer('who is EmbyServer?');
|
||||
|
||||
// console.log('chrome.sockets.udp.send');
|
||||
|
||||
// chrome.sockets.udp.send(createInfo.socketId, data, '255.255.255.255', port, function (sendResult) {
|
||||
|
||||
// deferred.resolve();
|
||||
// closeSocket(socketId);
|
||||
// });
|
||||
// });
|
||||
//});
|
||||
|
||||
deferred.resolve();
|
||||
return deferred.promise();
|
||||
}
|
||||
};
|
||||
|
||||
})(window);
|
Loading…
Add table
Add a link
Reference in a new issue