diff --git a/app/assets/img/jfserver.png b/app/assets/img/jfserver.png
new file mode 100644
index 0000000..138b2b6
Binary files /dev/null and b/app/assets/img/jfserver.png differ
diff --git a/app/js/about.js b/app/js/about.js
new file mode 100644
index 0000000..5b8218d
--- /dev/null
+++ b/app/js/about.js
@@ -0,0 +1,81 @@
+// /\_/|
+// { ' ' } JellyCAT
+// \____\
+
+//----------------------------DOMView--------------------------------------------
+
+var JCATAboutXML = '\n' +
+ '\n' +
+ ' \n' +
+ ' \n' +
+ ' \n' +
+ ' \n' +
+ ' JellyCAT About\n' +
+ ' \n' +
+ ' \n' +
+ ' \n' +
+ ' Close\n' +
+ ' \n' +
+ ' \n' +
+ ' \n' +
+ ' \n' +
+ '';
+
+
+JCATAboutXML = JCATAboutXML
+ .replace(/\$atvcsettings\.hello/g, atv.jcathost.HelloMessage)
+ .replace(/\$atvcsettings\.system/g, atv.jcathost.System)
+ .replace(/\$atvcsettings\.version/g, atv.jcathost.Version)
+ .replace(/\$atvcsettings\.sighost/g, atv.jcathost.SigHost)
+ .replace(/\$atvcsettings\.hostip/g, atv.jcathost.HostIP);
+
+
+function generateJCATAboutXML() {
+ var doc = atv.parseXML( JCATAboutXML );
+
+ console.log( "Creating the view --> " );
+ DomViewManager.createView( "JcatAboutView" );
+
+ console.log( "Loading the view --> " );
+ DomViewManager.loadView( "JcatAboutView", doc );
+
+ console.log( "View is loaded" );
+}
\ No newline at end of file
diff --git a/app/js/jcathostinfo.js b/app/js/jcathostinfo.js
index 773b1d3..71d3511 100644
--- a/app/js/jcathostinfo.js
+++ b/app/js/jcathostinfo.js
@@ -42,7 +42,7 @@ var JCATHOSTInfoXML = '\n' +
'$atvcsettings.hostip\n' +
']]>\n' +
' \n' +
- ' \n' +
+ ' \n' +
' About\n' +
' \n' +
' \n' +
@@ -71,232 +71,4 @@ function generateJCATHOSTInfoXML() {
DomViewManager.loadView( "JcathostInfoView", doc );
console.log( "View is loaded" );
-}
-
-// ***************************************************
-// DOMView | Wrapper
-// https://github.com/wahlmanj/sample-aTV/blob/dba73806c21183fb35d6edca94b960691d8e5d66/js/views/DOMView/DOMView.js
-
-/**
- * This wrapper makes it easier to handle the DOM View JS calls.
- * The actual calls for DOMView are:
- * view = new atv.DOMView()
- * view.onUnload - similar to onPageUnload
- * view.load ( XMLDOC, function(sucess) { ... } ) - pushes the view onto the stack the callback function is called back and gives you a success or fail call.
- * view.unload - removes the view from the stack.
- */
-var DomViewManager = ( function() {
- var views = {},
- ViewNames = [],
- config = {},
- callbackEvents = {},
- optionDialogXML = {};
-
-
- function _saveView( name, view ) {
- if( name && view ) {
- views[ name ] = view;
- _addViewToList( name );
-
- } else {
- console.error( "When saving a view, both name and view are required" );
- };
- };
-
- function _deleteView( name ) {
- if( views[ name ] ) {
- delete views[ name ];
- _removeViewFromList( name );
- };
- };
-
- function _retrieveView( name ) {
- if( name ) {
- return views[ name ] || null;
- } else {
- console.error( "When attempting to retrieve a view name is required.");
- };
- return null;
- };
-
- function _addViewToList( name ) {
- var index = ViewNames.indexOf( name );
- if( index == -1 ) {
- ViewNames.push( name );
- };
- };
-
- function _removeViewFromList( name ) {
- var index = ViewNames.indexOf( name );
- if( index > -1 ) {
- ViewNames.splice( index, 1 );
- };
- };
-
- function _createDialogXML( dialogOptions ) {
- var doc = atv.parseXML( optionDialogXML ),
- title = dialogOptions.title,
- description = dialogOptions.description,
- initialSelection = dialogOptions.initialSelection || 0,
- options = dialogOptions.options || [];
-
-
- // fill in the title, accessibility label
- doc.rootElement.getElementByTagName( 'title' ).textContent = title;
- doc.rootElement.getElementByTagName( 'simpleHeader' ).setAttribute( 'accessibilityLabel', title +". "+ description );
-
- // fill in the description
- doc.rootElement.getElementByTagName( 'description' ).textContent = description;
-
- // fill in the initial selection
- doc.rootElement.getElementByTagName( 'row' ).textContent = initialSelection;
-
- // fill in the options
- var items = doc.rootElement.getElementByTagName( 'items' );
- options.forEach( function ( option, index ) {
- // save option callbacks
- RegisterCallbackEvent( "DialogOption_"+index, option.callback );
-
- // create the option
- var newOptionButton = ATVUtils.createNode({
- "name": "oneLineMenuItem",
- "attrs": [{
- "name": "id",
- "value": "DialogOption_"+ index
- }, {
- "name": "accessibilityLabel",
- "value": option.label
- }, {
- "name": "onSelect",
- "value": "DomViewManager.fireCallback( 'DialogOption_"+ index +"' );"
- }],
- "children": [{
- "name": "label",
- "text": option.label
- }]
- },
- doc );
-
- // append it to the items.
- items.appendChild( newOptionButton );
- });
-
- return doc;
-
- }
-
- function ListSavedViews() {
- return ViewNames;
- };
-
- function setConfig(property, value) {
- console.log( " ===> Setting: "+ property +" = "+ value +" <=== " );
- config[ property ] = value;
- };
-
- function getConfig(property) {
- var value = config[property];
- return (value) ? value: null;
- };
-
- // Create a new DomView
- function CreateView( name, dialogOptions ) {
- if( name ) {
- var view = new atv.DOMView();
-
- _saveView( name, view );
-
- if( typeof( dialogOptions ) === "object" ) {
- var doc = _createDialogXML( dialogOptions );
- };
-
- setConfig( name+"_doc", doc )
-
- view.onUnload = function() {
- console.log(" == DOMView onUnload called == " );
- FireCallbackEvent("ONUNLOADVIEW", {
- "name": name,
- "view": this
- });
- };
-
- } else {
- console.error("When attempting to create a DOM view, name is required.");
- };
- };
-
- function RemoveView( name ) {
- // unload the view, remove the view from the view list, remove the view name
- UnloadView( name );
- _deleteView( name );
- };
-
- function LoadView( name, doc ) {
- try {
- var view = _retrieveView( name ),
- doc = doc || getConfig( name+"_doc" );
-
- if( !view )
- {
- CreateView( name );
- view = _retrieveView( name );
- }
-
- console.log( "We load the view: "+ name +" : "+ view );
- view.load(doc, function(success) {
- console.log("DOMView succeeded " + success);
- if( success )
- {
- console.log("=== Saving Document: "+ name +"_doc ===");
- view.doc = doc.serializeToString();
- FireCallbackEvent( "ONLOADSUCCESS", { "view": name } )
- }
- else
- {
- var msg = "Unable to load view."
- FireCallbackEvent( "ONLOADERROR", { "id": "LOADERROR", "view":name, "msg": msg } );
- }
- });
- } catch ( error ) {
- console.error( "LOAD ERROR: "+ error );
- };
- };
-
- function UnloadView( name ) {
- var view = _retrieveView( name );
- view.unload();
- };
-
- function RegisterCallbackEvent( name, callback ) {
- console.log(" ---- Registering Callback: " + name + " with callback type: " + typeof(callback));
- if (typeof callback === "function") {
- callbackEvents[name] = callback;
- } else {
- console.error("When attempting to register a callback event, a callback function is required.");
- };
- };
-
- function FireCallbackEvent( name, parameters, scope ) {
- var scope = scope || this,
- parameters = parameters || {};
-
- if (callbackEvents[name] && typeof callbackEvents[name] === "function") {
- callbackEvents[name].call(scope, parameters)
- };
- };
-
- return {
- "createView": CreateView,
- "removeView": RemoveView,
- "loadView": LoadView,
- "unloadView": UnloadView,
- "listViews": ListSavedViews,
- "registerCallback": RegisterCallbackEvent,
- "fireCallback": FireCallbackEvent
- };
-
-})();
-
-
-// ------ End DOM View Manager --------
-
+}
\ No newline at end of file
diff --git a/app/js/jcm.js b/app/js/jcm.js
index 1e30a41..6ac2ef2 100644
--- a/app/js/jcm.js
+++ b/app/js/jcm.js
@@ -717,5 +717,234 @@ function handleNavbarNavigate( event ) {
}
+// ***************************************************
+// DOMView | Wrapper
+// https://github.com/wahlmanj/sample-aTV/blob/dba73806c21183fb35d6edca94b960691d8e5d66/js/views/DOMView/DOMView.js
+
+/**
+ * This wrapper makes it easier to handle the DOM View JS calls.
+ * The actual calls for DOMView are:
+ * view = new atv.DOMView()
+ * view.onUnload - similar to onPageUnload
+ * view.load ( XMLDOC, function(sucess) { ... } ) - pushes the view onto the stack the callback function is called back and gives you a success or fail call.
+ * view.unload - removes the view from the stack.
+ */
+var DomViewManager = ( function() {
+ var views = {},
+ ViewNames = [],
+ config = {},
+ callbackEvents = {},
+ optionDialogXML = {};
+
+
+ function _saveView( name, view ) {
+ if( name && view ) {
+ views[ name ] = view;
+ _addViewToList( name );
+
+ } else {
+ console.error( "When saving a view, both name and view are required" );
+ };
+ };
+
+ function _deleteView( name ) {
+ if( views[ name ] ) {
+ delete views[ name ];
+ _removeViewFromList( name );
+ };
+ };
+
+ function _retrieveView( name ) {
+ if( name ) {
+ return views[ name ] || null;
+ } else {
+ console.error( "When attempting to retrieve a view name is required.");
+ };
+ return null;
+ };
+
+ function _addViewToList( name ) {
+ var index = ViewNames.indexOf( name );
+ if( index == -1 ) {
+ ViewNames.push( name );
+ };
+ };
+
+ function _removeViewFromList( name ) {
+ var index = ViewNames.indexOf( name );
+ if( index > -1 ) {
+ ViewNames.splice( index, 1 );
+ };
+ };
+
+ function _createDialogXML( dialogOptions ) {
+ var doc = atv.parseXML( optionDialogXML ),
+ title = dialogOptions.title,
+ description = dialogOptions.description,
+ initialSelection = dialogOptions.initialSelection || 0,
+ options = dialogOptions.options || [];
+
+
+ // fill in the title, accessibility label
+ doc.rootElement.getElementByTagName( 'title' ).textContent = title;
+ doc.rootElement.getElementByTagName( 'simpleHeader' ).setAttribute( 'accessibilityLabel', title +". "+ description );
+
+ // fill in the description
+ doc.rootElement.getElementByTagName( 'description' ).textContent = description;
+
+ // fill in the initial selection
+ doc.rootElement.getElementByTagName( 'row' ).textContent = initialSelection;
+
+ // fill in the options
+ var items = doc.rootElement.getElementByTagName( 'items' );
+ options.forEach( function ( option, index ) {
+ // save option callbacks
+ RegisterCallbackEvent( "DialogOption_"+index, option.callback );
+
+ // create the option
+ var newOptionButton = ATVUtils.createNode({
+ "name": "oneLineMenuItem",
+ "attrs": [{
+ "name": "id",
+ "value": "DialogOption_"+ index
+ }, {
+ "name": "accessibilityLabel",
+ "value": option.label
+ }, {
+ "name": "onSelect",
+ "value": "DomViewManager.fireCallback( 'DialogOption_"+ index +"' );"
+ }],
+ "children": [{
+ "name": "label",
+ "text": option.label
+ }]
+ },
+ doc );
+
+ // append it to the items.
+ items.appendChild( newOptionButton );
+ });
+
+ return doc;
+
+ }
+
+ function ListSavedViews() {
+ return ViewNames;
+ };
+
+ function setConfig(property, value) {
+ console.log( " ===> Setting: "+ property +" = "+ value +" <=== " );
+ config[ property ] = value;
+ };
+
+ function getConfig(property) {
+ var value = config[property];
+ return (value) ? value: null;
+ };
+
+ // Create a new DomView
+ function CreateView( name, dialogOptions ) {
+ if( name ) {
+
+ var view = new atv.DOMView();
+ // console.log("This log prevents occasional hanging for some reason...")
+
+ _saveView( name, view );
+
+ if( typeof( dialogOptions ) === "object" ) {
+ var doc = _createDialogXML( dialogOptions );
+ };
+
+ setConfig( name+"_doc", doc )
+
+ view.onUnload = function() {
+ console.log(" == DOMView onUnload called == " );
+ FireCallbackEvent("ONUNLOADVIEW", {
+ "name": name,
+ "view": this
+ });
+ };
+
+ } else {
+ console.error("When attempting to create a DOM view, name is required.");
+ };
+ };
+
+ function RemoveView( name ) {
+ // unload the view, remove the view from the view list, remove the view name
+ UnloadView( name );
+ _deleteView( name );
+ };
+
+ function LoadView( name, doc ) {
+ try {
+ var view = _retrieveView( name ),
+ doc = doc || getConfig( name+"_doc" );
+
+ if( !view )
+ {
+ CreateView( name );
+ view = _retrieveView( name );
+ }
+
+ console.log( "We load the view: "+ name +" : "+ view );
+ view.load(doc, function(success) {
+ console.log("DOMView succeeded " + success);
+ if( success )
+ {
+ console.log("=== Saving Document: "+ name +"_doc ===");
+ view.doc = doc.serializeToString();
+ FireCallbackEvent( "ONLOADSUCCESS", { "view": name } )
+ }
+ else
+ {
+ var msg = "Unable to load view."
+ FireCallbackEvent( "ONLOADERROR", { "id": "LOADERROR", "view":name, "msg": msg } );
+ }
+ });
+ } catch ( error ) {
+ console.error( "LOAD ERROR: "+ error );
+ };
+ };
+
+ function UnloadView( name ) {
+ var view = _retrieveView( name );
+ view.unload();
+ };
+
+ function RegisterCallbackEvent( name, callback ) {
+ console.log(" ---- Registering Callback: " + name + " with callback type: " + typeof(callback));
+ if (typeof callback === "function") {
+ callbackEvents[name] = callback;
+ } else {
+ console.error("When attempting to register a callback event, a callback function is required.");
+ };
+ };
+
+ function FireCallbackEvent( name, parameters, scope ) {
+ var scope = scope || this,
+ parameters = parameters || {};
+
+ if (callbackEvents[name] && typeof callbackEvents[name] === "function") {
+ callbackEvents[name].call(scope, parameters)
+ };
+ };
+
+ return {
+ "createView": CreateView,
+ "removeView": RemoveView,
+ "loadView": LoadView,
+ "unloadView": UnloadView,
+ "listViews": ListSavedViews,
+ "registerCallback": RegisterCallbackEvent,
+ "fireCallback": FireCallbackEvent
+ };
+
+})();
+
+
+// ------ End DOM View Manager --------
+
console.log('Reached EOF!');
diff --git a/app/js/jellyfin-setup.js b/app/js/jellyfin-setup.js
new file mode 100644
index 0000000..5713802
--- /dev/null
+++ b/app/js/jellyfin-setup.js
@@ -0,0 +1,70 @@
+// /\_/|
+// { ' ' } JellyCAT
+// \____\
+
+// Function to show text entry page
+showTextEntryPage = function(input_type, input_title, input_instructions, callback_submit, callback_cancel, defaultvalue) {
+ var textEntry = new atv.TextEntry();
+
+ textEntry.type = input_type;
+ textEntry.title = input_title;
+ textEntry.instructions = input_instructions;
+ textEntry.defaultValue = defaultvalue;
+ textEntry.defaultToAppleID = false;
+ // textEntry.image =
+ textEntry.onSubmit = callback_submit;
+ textEntry.onCancel = callback_cancel;
+
+ textEntry.show();
+};
+
+// Function to set server address
+function setServerAddress() {
+ showTextEntryPage(
+ "emailAddress",
+ "Set Jellyfin Server Address",
+ "Enter the address of the Jellyfin server:",
+ function(value) {
+ // Save server address to localStorage
+ atv.localStorage['jellyfin_server_address'] = value;
+ },
+ function() {
+
+ },
+ atv.localStorage['jellyfin_server_address'] || ""
+ );
+}
+
+// Function to set username
+function setUsername() {
+ showTextEntryPage(
+ "emailAddress",
+ "Set Username",
+ "Enter your username:",
+ function(value) {
+ // Save username to localStorage
+ atv.localStorage['jellyfin_username'] = value;
+ },
+ function() {
+
+ },
+ atv.localStorage['jellyfin_username'] || ""
+ );
+}
+
+// Function to set password
+function setPassword() {
+ showTextEntryPage(
+ "password",
+ "Set Password",
+ "Enter your password:",
+ function(value) {
+ // Save password to localStorage
+ atv.localStorage['jellyfin_password'] = value;
+ },
+ function() {
+
+ },
+ atv.localStorage['jellyfin_password'] || ""
+ );
+}
diff --git a/app/js/storagetest.js b/app/js/storagetest.js
index f948743..9359bb5 100644
--- a/app/js/storagetest.js
+++ b/app/js/storagetest.js
@@ -4,7 +4,7 @@
function printSessionStorage() {
- var keys = ['test', 'exampleKey2', 'exampleKey3'];
+ var keys = ['test', 'exampleKey'];
keys.forEach(function(key) {
var value = atv.sessionStorage.getItem(key);
@@ -18,7 +18,7 @@ function printSessionStorage() {
function printLocalStorage() {
- var keys = ['test', 'exampleKey2', 'exampleKey3'];
+ var keys = ['test', 'jellyfin_server_address', 'jellyfin_username', 'jellyfin_password', 'jellyfin_auth'];
keys.forEach(function(key) {
var value = atv.localStorage.getItem(key);
diff --git a/app/xml/dvt/devtools.xml b/app/xml/dvt/devtools.xml
index 8600583..49bc973 100644
--- a/app/xml/dvt/devtools.xml
+++ b/app/xml/dvt/devtools.xml
@@ -3,6 +3,7 @@
+
diff --git a/app/xml/server-settings.xml b/app/xml/server-settings.xml
new file mode 100644
index 0000000..fa6debd
--- /dev/null
+++ b/app/xml/server-settings.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+ Jellyfin Server Settings
+
+
+
+
+ http://jcathost.dns/assets/img/jfserver.png
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/xml/settings.xml b/app/xml/settings.xml
index d8f836d..fdfa4cf 100644
--- a/app/xml/settings.xml
+++ b/app/xml/settings.xml
@@ -2,6 +2,7 @@
+
@@ -24,14 +25,16 @@
-
-
-
+
+
+ Set Jellyfin Server and User
+ http://jcathost.dns/assets/img/jfserver.png
+
-
+
-
+
@@ -45,7 +48,7 @@
-
+
diff --git a/main.go b/main.go
index e47053a..48c1fe2 100644
--- a/main.go
+++ b/main.go
@@ -26,7 +26,7 @@ func main() {
// Default information store
JellyCAT = JcatDefaults{
- Version: "0.1.2revA",
+ Version: "0.1.2revB",
Name: "JellyCAT Serving stHack",
HostName: config.CertName,
HostIP: config.HijackIP,