Restructure directory

This commit is contained in:
Tyler
2019-05-21 12:01:35 -04:00
parent 528a22ae7d
commit e5aec34450
12 changed files with 59 additions and 49 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

52
plugin/manifest.json Normal file
View File

@ -0,0 +1,52 @@
{
"Actions": [
{
"Icon": "images/actions/ssh",
"Name": "SSH",
"States": [
{
"Image": "ssh",
"TitleAlignment": "bottom",
"FontSize": "16"
}
],
"SupportedInMultiActions": false,
"Tooltip": "Execute a command over SSH",
"UUID": "tf.meow.remote.ssh",
"PropertyInspectorPath": "pi/index_pi.html"
},
{
"Icon": "images/actions/website",
"Name": "Website",
"States": [
{
"Image": "website",
"TitleAlignment": "bottom",
"FontSize": "16"
}
],
"SupportedInMultiActions": false,
"Tooltip": "Open a website on a remote computer",
"UUID": "tf.meow.remote.website",
"PropertyInspectorPath": "pi/index_pi_server.html"
}
],
"Author": "Meow.tf",
"Category": "Remote",
"CodePathWin": "remote.exe",
"Description": "Control remote systems over SSH or Daemon, executing commands, opening URLs, etc.",
"Name": "Remote",
"Icon": "images/pluginIcon",
"URL": "https://www.elgato.com/gaming/stream-deck",
"Version": "1.2",
"SDKVersion": 2,
"OS": [
{
"Platform": "windows",
"MinimumVersion": "10"
}
],
"Software": {
"MinimumVersion": "4.2"
}
}

1483
plugin/pi/css/sdpi.css Normal file

File diff suppressed because it is too large Load Diff

66
plugin/pi/index_pi.html Normal file
View File

@ -0,0 +1,66 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,minimal-ui,viewport-fit=cover">
<meta name=apple-mobile-web-app-capable content=yes>
<meta name=apple-mobile-web-app-status-bar-style content=black>
<title>Property Inspector Samples PI</title>
<link rel="stylesheet" href="css/sdpi.css">
<!--link rel="stylesheet"
media="screen and (max-width: 1025px)"
href="css/local.css" -->
</head>
<body>
<div class="sdpi-wrapper">
<div class="sdpi-item" id="host" title="IP or Hostname of the server, with optional port.">
<div class="sdpi-item-label">SSH IP/Host</div>
<input class="sdpi-item-value" id="ssh_host" value="" placeholder="e.g. 192.168.61.1:21" required>
</div>
<div class="sdpi-item" id="user" title="SSH Username">
<div class="sdpi-item-label">Username</div>
<input class="sdpi-item-value" id="ssh_user" value="" required>
</div>
<div class="sdpi-item" id="ssh_password_container">
<div class="sdpi-item-label">Password</div>
<input type="password" id="ssh_password" class="sdpi-item-value" value="">
</div>
<div class="sdpi-item" id="my_private_file_selector">
<div class="sdpi-item-label">SSH Key</div>
<div class="sdpi-item-group file" id="filepickergroup">
<input class="sdpi-item-value" type="file" id="ssh_key">
<label class="sdpi-file-info" for="ssh_key">no file...</label>
<label class="sdpi-file-label" for="ssh_key">Choose file...</label>
</div>
</div>
<div class="sdpi-item" id="ssh_key_passphrase_container" style="display: none;">
<div class="sdpi-item-label">Key Passphrase</div>
<input type="password" id="ssh_key_passphrase" class="sdpi-item-value" value="">
</div>
<div class="sdpi-item" id="command">
<div class="sdpi-item-label">Command</div>
<input class="sdpi-item-value" id="ssh_command" value="" placeholder="" required>
</div>
</div>
<!-- <script src="echomd.js"></script> -->
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/node-forge@0.7.0/dist/forge.min.js"></script>
<script src="index_pi.js"></script>
</body>
</html>

274
plugin/pi/index_pi.js Normal file
View File

@ -0,0 +1,274 @@
// this is our global websocket, used to communicate from/to Stream Deck software
// and some info about our plugin, as sent by Stream Deck software
var websocket = null,
uuid = null,
actionInfo = {},
settings = {},
isQT = navigator.appVersion.includes('QtWebEngine'); // 'oninput'; // change this, if you want interactive elements act on any change, or while they're modified
function connectSocket (
inPort,
inUUID,
inMessageType,
inApplicationInfo,
inActionInfo
) {
connectElgatoStreamDeckSocket(
inPort,
inUUID,
inMessageType,
inApplicationInfo,
inActionInfo
);
}
function connectElgatoStreamDeckSocket (inPort, inUUID, inRegisterEvent, inInfo, inActionInfo) {
uuid = inUUID;
// please note: the incoming arguments are of type STRING, so
// in case of the inActionInfo, we must parse it into JSON first
actionInfo = JSON.parse(inActionInfo); // cache the info
inInfo = JSON.parse(inInfo);
websocket = new WebSocket('ws://localhost:' + inPort);
/** Since the PI doesn't have access to your OS native settings
* Stream Deck sends some color settings to PI
* We use these to adjust some styles (e.g. highlight-colors for checkboxes)
*/
addDynamicStyles(inInfo.colors, 'connectElgatoStreamDeckSocket');
/** let's see, if we have some settings */
settings = getPropFromString(actionInfo, 'payload.settings');
console.log(settings, actionInfo);
initPropertyInspector(5);
// if connection was established, the websocket sends
// an 'onopen' event, where we need to register our PI
websocket.onopen = function () {
var json = {
event: inRegisterEvent,
uuid: inUUID
};
websocket.send(JSON.stringify(json));
};
websocket.onmessage = function (evt) {
// Received message from Stream Deck
var jsonObj = JSON.parse(evt.data);
var event = jsonObj['event'];
};
}
function initPropertyInspector(initDelay) {
if (actionInfo['action'] == 'tf.meow.remote.website') {
$('#url_container').show();
$('#url_background_container').show();
}
Object.keys(settings).forEach(function (item) {
$('#' + item).val(settings[item]);
});
$('input').each(function() {
var $this = $(this),
id = $this.attr('id');
let $item = $this.closest('.sdpi-item');
$this.on('change', function(e) {
const type = $this.attr('type');
if (type) {
const info = $item.find('.sdpi-file-info');
if (info) {
const s = decodeURIComponent($this.val().replace(/^C:\\fakepath\\/, '')).split('/').pop();
info.text(s.length > 28
? s.substr(0, 10)
+ '...'
+ s.substr(s.length - 10, s.length)
: s);
}
}
let val = $this.val();
switch (type) {
case 'checkbox':
if (val == 'false' || val == 'true') {
val = (/^true$/i).test(val);
}
break;
}
updateSetting(id, val);
});
});
$('#ssh_key').change(function(e) {
if (e.target.files.length < 1) {
// Hide passphrase field
$('#ssh_key_passphrase_container').hide();
$('#ssh_password_container').show();
} else {
$('#ssh_password_container').hide();
}
var f = e.target.files[0];
var reader = new FileReader();
// Closure to capture the file information.
reader.onload = function(e) {
var result = e.target.result;
var pki = forge.pki;
try {
pki.privateKeyFromPem(result);
$('#ssh_key_passphrase_container').hide();
} catch (ex) {
if (ex.message.indexOf('PEM is encrypted.') !== -1) {
$('#ssh_key_passphrase_container').show();
} else {
// Show error message?
}
}
};
// Read in the image file as a data URL.
reader.readAsText(f);
});
}
if (!isQT) {
document.addEventListener('DOMContentLoaded', function () {
initPropertyInspector(100);
});
}
/** Stream Deck software passes system-highlight color information
* to Property Inspector. Here we 'inject' the CSS styles into the DOM
* when we receive this information. */
function addDynamicStyles (clrs, fromWhere) {
const node = document.getElementById('#sdpi-dynamic-styles') || document.createElement('style');
if (!clrs.mouseDownColor) clrs.mouseDownColor = fadeColor(clrs.highlightColor, -100);
const clr = clrs.highlightColor.slice(0, 7);
const clr1 = fadeColor(clr, 100);
const clr2 = fadeColor(clr, 60);
const metersActiveColor = fadeColor(clr, -60);
node.setAttribute('id', 'sdpi-dynamic-styles');
node.innerHTML = `
input[type="radio"]:checked + label span,
input[type="checkbox"]:checked + label span {
background-color: ${clrs.highlightColor};
}
input[type="radio"]:active:checked + label span,
input[type="radio"]:active + label span,
input[type="checkbox"]:active:checked + label span,
input[type="checkbox"]:active + label span {
background-color: ${clrs.mouseDownColor};
}
input[type="radio"]:active + label span,
input[type="checkbox"]:active + label span {
background-color: ${clrs.buttonPressedBorderColor};
}
td.selected,
td.selected:hover,
li.selected:hover,
li.selected {
color: white;
background-color: ${clrs.highlightColor};
}
.sdpi-file-label > label:active,
.sdpi-file-label.file:active,
label.sdpi-file-label:active,
label.sdpi-file-info:active,
input[type="file"]::-webkit-file-upload-button:active,
button:active {
background-color: ${clrs.buttonPressedBackgroundColor};
color: ${clrs.buttonPressedTextColor};
border-color: ${clrs.buttonPressedBorderColor};
}
::-webkit-progress-value,
meter::-webkit-meter-optimum-value {
background: linear-gradient(${clr2}, ${clr1} 20%, ${clr} 45%, ${clr} 55%, ${clr2})
}
::-webkit-progress-value:active,
meter::-webkit-meter-optimum-value:active {
background: linear-gradient(${clr}, ${clr2} 20%, ${metersActiveColor} 45%, ${metersActiveColor} 55%, ${clr})
}
`;
document.body.appendChild(node);
};
/** UTILITIES */
/** get a JSON property from a (dot-separated) string
* Works on nested JSON, e.g.:
* jsn = {
* propA: 1,
* propB: 2,
* propC: {
* subA: 3,
* subB: {
* testA: 5,
* testB: 'Hello'
* }
* }
* }
* getPropFromString(jsn,'propC.subB.testB') will return 'Hello';
*/
const getPropFromString = (jsn, str, sep = '.') => {
const arr = str.split(sep);
return arr.reduce((obj, key) =>
(obj && obj.hasOwnProperty(key)) ? obj[key] : undefined, jsn);
};
/*
Quick utility to lighten or darken a color (doesn't take color-drifting, etc. into account)
Usage:
fadeColor('#061261', 100); // will lighten the color
fadeColor('#200867'), -100); // will darken the color
*/
function fadeColor (col, amt) {
const min = Math.min, max = Math.max;
const num = parseInt(col.replace(/#/g, ''), 16);
const r = min(255, max((num >> 16) + amt, 0));
const g = min(255, max((num & 0x0000FF) + amt, 0));
const b = min(255, max(((num >> 8) & 0x00FF) + amt, 0));
return '#' + (g | (b << 8) | (r << 16)).toString(16).padStart(6, 0);
}
function updateSetting(setting, value) {
if (!settings) {
settings = {};
}
settings[setting] = value;
setSettings(settings);
}
function setSettings(settings) {
var json = {
"event": "setSettings",
"context": uuid,
"payload": settings
};
if (websocket) {
websocket.send(JSON.stringify(json));
} else {
console.log('Update:', json);
}
}

View File

@ -0,0 +1,47 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no,minimal-ui,viewport-fit=cover">
<meta name=apple-mobile-web-app-capable content=yes>
<meta name=apple-mobile-web-app-status-bar-style content=black>
<title>StreamDeck Remote - Server</title>
<link rel="stylesheet" href="css/sdpi.css">
</head>
<body>
<div class="sdpi-wrapper">
<div class="sdpi-item" id="host" title="IP or Hostname of the server, with optional port.">
<div class="sdpi-item-label">Host</div>
<input class="sdpi-item-value" id="remote_host" value="" placeholder="e.g. 192.168.61.1:21" required>
</div>
<div class="sdpi-item" id="ssh_password_container">
<div class="sdpi-item-label">Token</div>
<input type="text" id="remote_token" class="sdpi-item-value" value="" required>
</div>
<div class="sdpi-item" id="url_container" style="display: none;">
<div class="sdpi-item-label">URL</div>
<input type="text" id="url" class="sdpi-item-value" value="" required>
</div>
<div id="url_background_container" type="checkbox" class="sdpi-item" style="display: none;">
<div class="sdpi-item-label">Options</div>
<input class="sdpi-item-value" id="background" type="checkbox" value="true">
<label for="background"><span></span>Access in background</label>
</div>
</div>
<!-- <script src="echomd.js"></script> -->
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="index_pi.js"></script>
</body>
</html>