Implement settings (via Clay)
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
|||||||
/.clangd
|
/.clangd
|
||||||
/build
|
/build
|
||||||
/.lock*
|
/.lock*
|
||||||
|
/node_modules
|
||||||
|
/package-lock.json
|
||||||
|
|||||||
21
package.json
21
package.json
@@ -1,24 +1,29 @@
|
|||||||
{
|
{
|
||||||
"author": "RandyTheSilly",
|
"author": "RandyTheSilly",
|
||||||
"dependencies": {},
|
"dependencies": {
|
||||||
|
"@rebble/clay": "^1.0.8"
|
||||||
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"jellyfin",
|
"jellyfin",
|
||||||
"plex",
|
"plex",
|
||||||
"sleep"
|
"sleep",
|
||||||
|
"timeline",
|
||||||
|
"health"
|
||||||
],
|
],
|
||||||
"capabilities": [
|
"capabilities": [
|
||||||
"health"
|
"health",
|
||||||
|
"configurable"
|
||||||
],
|
],
|
||||||
"name": "1-more-episode",
|
"name": "1-more-episode",
|
||||||
"pebble": {
|
"pebble": {
|
||||||
"displayName": "1 More Episode",
|
"displayName": "1 More Episode",
|
||||||
"enableMultiJS": true,
|
"enableMultiJS": true,
|
||||||
"messageKeys": [
|
"messageKeys": [
|
||||||
"JS_READY",
|
"CLAY_API_HOST",
|
||||||
"SLEEP_TIMESTAMP",
|
"CLAY_API_KEY",
|
||||||
"API_IS_PLEX",
|
"CLAY_API_IS_JELLYFIN",
|
||||||
"API_KEY",
|
"PKJS_READY",
|
||||||
"API_HOST"
|
"PKJS_SLEEP_TIMESTAMP"
|
||||||
],
|
],
|
||||||
"projectType": "native",
|
"projectType": "native",
|
||||||
"resources": {
|
"resources": {
|
||||||
|
|||||||
12
src/c/main.c
12
src/c/main.c
@@ -16,18 +16,14 @@ static TextLayer *s_pin_notice_layer;
|
|||||||
// declare time tracking statics
|
// declare time tracking statics
|
||||||
static time_t s_sleep_timestamp;
|
static time_t s_sleep_timestamp;
|
||||||
|
|
||||||
static void send_to_pkjs() {
|
static void send_sleep_time_to_pkjs() {
|
||||||
DictionaryIterator *out;
|
DictionaryIterator *out;
|
||||||
AppMessageResult result = app_message_outbox_begin(&out);
|
AppMessageResult result = app_message_outbox_begin(&out);
|
||||||
if (result != APP_MSG_OK) {
|
if (result != APP_MSG_OK) {
|
||||||
text_layer_set_text(s_last_episode_layer, "outbox_begin failure");
|
text_layer_set_text(s_last_episode_layer, "outbox_begin failure");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dict_write_uint32(out, MESSAGE_KEY_SLEEP_TIMESTAMP, s_sleep_timestamp);
|
dict_write_uint32(out, MESSAGE_KEY_PKJS_SLEEP_TIMESTAMP, s_sleep_timestamp);
|
||||||
dict_write_uint8(out, MESSAGE_KEY_API_IS_PLEX, 0);
|
|
||||||
dict_write_cstring(out, MESSAGE_KEY_API_KEY, "");
|
|
||||||
dict_write_cstring(out, MESSAGE_KEY_API_HOST, "");
|
|
||||||
|
|
||||||
result = app_message_outbox_send();
|
result = app_message_outbox_send();
|
||||||
if (result != APP_MSG_OK) {
|
if (result != APP_MSG_OK) {
|
||||||
text_layer_set_text(s_last_episode_layer, "outbox_send failure");
|
text_layer_set_text(s_last_episode_layer, "outbox_send failure");
|
||||||
@@ -36,12 +32,12 @@ static void send_to_pkjs() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void inbox_received_handler(DictionaryIterator *iter, void *context) {
|
static void inbox_received_handler(DictionaryIterator *iter, void *context) {
|
||||||
Tuple *ready_tuple = dict_find(iter, MESSAGE_KEY_JS_READY);
|
Tuple *ready_tuple = dict_find(iter, MESSAGE_KEY_PKJS_READY);
|
||||||
if (ready_tuple) {
|
if (ready_tuple) {
|
||||||
s_js_ready = true;
|
s_js_ready = true;
|
||||||
}
|
}
|
||||||
APP_LOG(APP_LOG_LEVEL_INFO, "Received JS_READY, calling PKJS...");
|
APP_LOG(APP_LOG_LEVEL_INFO, "Received JS_READY, calling PKJS...");
|
||||||
send_to_pkjs();
|
send_sleep_time_to_pkjs();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void inbox_dropped_handler(AppMessageResult reason, void *context) {
|
static void inbox_dropped_handler(AppMessageResult reason, void *context) {
|
||||||
|
|||||||
37
src/pkjs/config.js
Normal file
37
src/pkjs/config.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
module.exports = [
|
||||||
|
{
|
||||||
|
"type": "heading",
|
||||||
|
"defaultValue": "1 More Episode | Settings"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "section",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "heading",
|
||||||
|
"defaultValue": "API Credentials"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "input",
|
||||||
|
"messageKey": "CLAY_API_HOST",
|
||||||
|
"label": "API Host",
|
||||||
|
"description": "Example: https://jellyfin.example.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "input",
|
||||||
|
"messageKey": "CLAY_API_KEY",
|
||||||
|
"label": "API Key"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "toggle",
|
||||||
|
"messageKey": "CLAY_API_IS_JELLYFIN",
|
||||||
|
"defaultValue": true,
|
||||||
|
"label": "Jellyfin Support",
|
||||||
|
"description": "Toggle off if using Plex. If using Jellyfin, leave on :D"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "submit",
|
||||||
|
"defaultValue": "Save Settings"
|
||||||
|
}
|
||||||
|
];
|
||||||
@@ -1,24 +1,29 @@
|
|||||||
|
var Clay = require('@rebble/clay');
|
||||||
|
var clayConfig = require('./config');
|
||||||
|
var clay = new Clay(clayConfig);
|
||||||
|
|
||||||
Pebble.addEventListener("ready", function () {
|
Pebble.addEventListener("ready", function () {
|
||||||
Pebble.sendAppMessage({ JS_READY: 1 });
|
Pebble.sendAppMessage({ PKJS_READY: 1 });
|
||||||
});
|
});
|
||||||
|
|
||||||
Pebble.addEventListener("appmessage", function (dict) {
|
Pebble.addEventListener("appmessage", function (dict) {
|
||||||
if (dict.payload["API_HOST"]) {
|
if (dict.payload["PKJS_SLEEP_TIMESTAMP"]) {
|
||||||
if (dict.payload["API_IS_PLEX"] == 0) {
|
var sleepTimestamp = dict.payload["PKJS_SLEEP_TIMESTAMP"];
|
||||||
callAPI(dict.payload["API_HOST"] + "/System/ActivityLog/Entries", false, dict.payload["API_KEY"]);
|
var cfg = JSON.parse(localStorage.getItem('clay-settings'));
|
||||||
|
// TODO report last episode as "Configure app settings!" if CLAY_API_HOST or CLAY_API_KEY is empty
|
||||||
|
if (cfg.CLAY_API_IS_JELLYFIN == true) {
|
||||||
|
callAPI(cfg.CLAY_API_HOST + "/System/ActivityLog/Entries", cfg.CLAY_API_KEY, true, sleepTimestamp);
|
||||||
} else {
|
} else {
|
||||||
// The official history endpoint doesn't seem to return history w/o Plex Pass.
|
// The official history endpoint doesn't seem to return history w/o Plex Pass.
|
||||||
// If someone with Plex Pass wants to give it a shot, I'd be happy to accept a PR adding this as an option.
|
// If someone with Plex Pass wants to give it a shot, I'd be happy to accept a PR adding this as an option.
|
||||||
// Until then, I'm using Tautulli because it's free.
|
// Until then, I'm using Tautulli because it's free.
|
||||||
//callAPI(dict.payload["API_HOST"] + "/status/sessions/history/all", true, dict.payload["API_KEY"]);
|
//callAPI(cfg.CLAY_API_HOST + "/status/sessions/history/all", cfg.CLAY_API_KEY, false, dict.payload["API_KEY"], sleepTimestamp);
|
||||||
callAPI(dict.payload["API_HOST"] + "/api/v2?apikey=" + dict.payload["API_KEY"] + "&cmd=get_history", true, NULL);
|
callAPI(cfg.CLAY_API_HOST + "/api/v2?apikey=" + cfg.CLAY_API_KEY + "&cmd=get_history", null, false, sleepTimestamp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function callAPI(fullURL, isPlex, apiKey) {
|
function callAPI(fullURL, apiKey, isJellyfin, sleepTimestamp) {
|
||||||
console.log("callAPI URL:", fullURL, "isPlex:", isPlex);
|
|
||||||
|
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState === 4) {
|
if (xhr.readyState === 4) {
|
||||||
@@ -28,7 +33,7 @@ function callAPI(fullURL, isPlex, apiKey) {
|
|||||||
|
|
||||||
xhr.open("GET", fullURL, true);
|
xhr.open("GET", fullURL, true);
|
||||||
xhr.setRequestHeader("Accept", "application/json");
|
xhr.setRequestHeader("Accept", "application/json");
|
||||||
if (!isPlex) {
|
if (isJellyfin) {
|
||||||
xhr.setRequestHeader("Authorization", 'MediaBrowser Token="' + apiKey + '"');
|
xhr.setRequestHeader("Authorization", 'MediaBrowser Token="' + apiKey + '"');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user