mirror of
https://github.com/SEPPDROID/JellyCAT.git
synced 2025-12-09 21:33:00 +00:00
Done for tonight, project is becoming to big for "ctrl+z version control"... Start using GIT
This commit is contained in:
582
app/application.js
Normal file
582
app/application.js
Normal file
@@ -0,0 +1,582 @@
|
||||
// /\_/|
|
||||
// { ' ' } JellyCAT
|
||||
// \____\
|
||||
|
||||
atv.config = {
|
||||
doesJavaScriptLoadRoot: true
|
||||
};
|
||||
|
||||
atv.onAppEntry = function () {
|
||||
fetchSettings(function() {
|
||||
overrideConsoleLog();
|
||||
console.log("Successfully overwritten console log, sending logs to JCATHOST now.")
|
||||
console.log("Received ATVCSETTINGS From JCATHOST.");
|
||||
console.log("Starting JellyCAT-JS on AppleTV...")
|
||||
jcatMain();
|
||||
});
|
||||
}
|
||||
|
||||
atv.onAppExit = function() {
|
||||
console.log('Exiting App!');
|
||||
};
|
||||
|
||||
// ***************************************************
|
||||
// JellyCAT Main | Main JS app function
|
||||
// Help
|
||||
|
||||
function jcatMain(){
|
||||
atvutils.loadURL("https://" + atv.jcathost.SigHost + "/xml/home.xml");
|
||||
}
|
||||
|
||||
// ***************************************************
|
||||
// JellyCAT Logger | Jclogger
|
||||
// Function to override console.log, console.error, and console.warn and send logs to the JellyCAT stHack server
|
||||
// We shall never send any sensitive information!!
|
||||
function overrideConsoleLog() {
|
||||
var originalConsoleLog = console.log;
|
||||
var originalConsoleError = console.error;
|
||||
var originalConsoleWarn = console.warn;
|
||||
|
||||
console.log = function () {
|
||||
// Call the original console.log
|
||||
originalConsoleLog.apply(console, arguments);
|
||||
|
||||
// Send the log to the server
|
||||
logToServer("LOG: " + JSON.stringify(arguments));
|
||||
};
|
||||
|
||||
console.error = function () {
|
||||
// Call the original console.error
|
||||
originalConsoleError.apply(console, arguments);
|
||||
|
||||
// Send the error to the server
|
||||
logToServer("ERROR: " + JSON.stringify(arguments));
|
||||
};
|
||||
|
||||
console.warn = function () {
|
||||
// Call the original console.warn
|
||||
originalConsoleWarn.apply(console, arguments);
|
||||
|
||||
// Send the warning to the server
|
||||
logToServer("WARNING: " + JSON.stringify(arguments));
|
||||
};
|
||||
}
|
||||
|
||||
// Function to log console information to the server
|
||||
function logToServer(logData) {
|
||||
var logEndpoint = "https://" + atv.jcathost.SigHost + "/log";
|
||||
|
||||
var logRequest = new XMLHttpRequest();
|
||||
logRequest.open("POST", logEndpoint, true);
|
||||
logRequest.setRequestHeader("Content-Type", "application/json");
|
||||
|
||||
var logPayload = {
|
||||
timestamp: new Date().toISOString(),
|
||||
logData: logData
|
||||
};
|
||||
|
||||
logRequest.send(JSON.stringify(logPayload));
|
||||
}
|
||||
|
||||
// ***************************************************
|
||||
// JellyCAT Host fetcher
|
||||
// Function to fetch information we need from the host server
|
||||
// Function to fetch JSON from the HTTP URL using XMLHttpRequest
|
||||
|
||||
function fetchSettings(callback) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', 'http://jcathost.dns/atvcsettings', true);
|
||||
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4) {
|
||||
if (xhr.status === 200) {
|
||||
try {
|
||||
var data = JSON.parse(xhr.responseText);
|
||||
|
||||
// Store all properties in atv.jcathost
|
||||
atv.jcathost = {
|
||||
SigHost: data.sig_host,
|
||||
SigHostPort: data.sig_host_p,
|
||||
HostIP: data.host_ip,
|
||||
System: data.system,
|
||||
Version: data.version,
|
||||
HelloMessage: data.hello,
|
||||
// Add other properties as needed
|
||||
};
|
||||
|
||||
// Execute the callback after setting atv.jcathost
|
||||
callback();
|
||||
} catch (jsonError) {
|
||||
console.error('Error parsing JSON:', jsonError);
|
||||
}
|
||||
} else {
|
||||
console.error('Error fetching settings. Status:', xhr.status);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
// ***************************************************
|
||||
// ATVUtils - a JavaScript helper library for Apple TV
|
||||
// Copied & Edited in full from:
|
||||
// https://kortv.com/appletv/js/application.js
|
||||
// https://github.com/wahlmanj/sample-aTV/blob/master/js/application.js
|
||||
|
||||
var atvutils = ATVUtils = {
|
||||
makeRequest: function(url, method, headers, body, callback) {
|
||||
if ( !url ) {
|
||||
throw "loadURL requires a url argument";
|
||||
}
|
||||
|
||||
var method = method || "GET",
|
||||
headers = headers || {},
|
||||
body = body || "";
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function() {
|
||||
try {
|
||||
if (xhr.readyState == 4 ) {
|
||||
if ( xhr.status == 200) {
|
||||
callback(xhr.responseXML);
|
||||
} else {
|
||||
console.log("makeRequest received HTTP status " + xhr.status + " for " + url);
|
||||
callback(null);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('makeRequest caught exception while processing request for ' + url + '. Aborting. Exception: ' + e);
|
||||
xhr.abort();
|
||||
callback(null);
|
||||
}
|
||||
}
|
||||
xhr.open(method, url, true);
|
||||
|
||||
for(var key in headers) {
|
||||
xhr.setRequestHeader(key, headers[key]);
|
||||
}
|
||||
|
||||
xhr.send();
|
||||
return xhr;
|
||||
},
|
||||
|
||||
makeErrorDocument: function(message, description) {
|
||||
if ( !message ) {
|
||||
message = "";
|
||||
}
|
||||
if ( !description ) {
|
||||
description = "";
|
||||
}
|
||||
|
||||
var errorXML = '<?xml version="1.0" encoding="UTF-8"?> \
|
||||
<atv> \
|
||||
<body> \
|
||||
<dialog id="com.sample.error-dialog"> \
|
||||
<title><![CDATA[' + message + ']]></title> \
|
||||
<description><![CDATA[' + description + ']]></description> \
|
||||
</dialog> \
|
||||
</body> \
|
||||
</atv>';
|
||||
|
||||
return atv.parseXML(errorXML);
|
||||
},
|
||||
|
||||
siteUnavailableError: function() {
|
||||
// TODO: localize
|
||||
return this.makeErrorDocument("JellyCAT is currently unavailable. Try again later.", "Check JCHOST for log information.");
|
||||
},
|
||||
|
||||
loadError: function(message, description) {
|
||||
atv.loadXML(this.makeErrorDocument(message, description));
|
||||
},
|
||||
|
||||
loadAndSwapError: function(message, description) {
|
||||
atv.loadAndSwapXML(this.makeErrorDocument(message, description));
|
||||
},
|
||||
|
||||
loadURLInternal: function(url, method, headers, body, loader) {
|
||||
var me = this,
|
||||
xhr,
|
||||
proxy = new atv.ProxyDocument;
|
||||
|
||||
proxy.show();
|
||||
|
||||
proxy.onCancel = function() {
|
||||
if ( xhr ) {
|
||||
xhr.abort();
|
||||
}
|
||||
};
|
||||
|
||||
xhr = me.makeRequest(url, method, headers, body, function(xml) {
|
||||
try {
|
||||
loader(proxy, xml);
|
||||
} catch(e) {
|
||||
console.error("Caught exception in for " + url + ". " + e);
|
||||
loader(me.siteUnavailableError());
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
loadURL: function( options ) { //url, method, headers, body, processXML) {
|
||||
var me = this;
|
||||
if( typeof( options ) === "string" ) {
|
||||
var url = options;
|
||||
} else {
|
||||
var url = options.url,
|
||||
method = options.method || null,
|
||||
headers = options.headers || null,
|
||||
body = options.body || null,
|
||||
processXML = options.processXML || null;
|
||||
}
|
||||
|
||||
this.loadURLInternal(url, method, headers, body, function(proxy, xml) {
|
||||
if(typeof(processXML) == "function") processXML.call(this, xml);
|
||||
try {
|
||||
proxy.loadXML(xml, function(success) {
|
||||
if ( !success ) {
|
||||
console.log("loadURL failed to load " + url);
|
||||
proxy.loadXML(me.siteUnavailableError());
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("loadURL caught exception while loading " + url + ". " + e);
|
||||
proxy.loadXML(me.siteUnavailableError());
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// loadAndSwapURL can only be called from page-level JavaScript of the page that wants to be swapped out.
|
||||
loadAndSwapURL: function( options ) { //url, method, headers, body, processXML) {
|
||||
var me = this;
|
||||
if( typeof( options ) === "string" ) {
|
||||
var url = options;
|
||||
} else {
|
||||
var url = options.url,
|
||||
method = options.method || null,
|
||||
headers = options.headers || null,
|
||||
body = options.body || null,
|
||||
processXML = options.processXML || null;
|
||||
}
|
||||
|
||||
this.loadURLInternal(url, method, headers, body, function(proxy, xml) {
|
||||
if(typeof(processXML) == "function") processXML.call(this, xml);
|
||||
try {
|
||||
proxy.loadXML(xml, function(success) {
|
||||
if ( success ) {
|
||||
atv.unloadPage();
|
||||
} else {
|
||||
console.log("loadAndSwapURL failed to load " + url);
|
||||
proxy.loadXML(me.siteUnavailableError(), function(success) {
|
||||
if ( success ) {
|
||||
atv.unloadPage();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.error("loadAndSwapURL caught exception while loading " + url + ". " + e);
|
||||
proxy.loadXML(me.siteUnavailableError(), function(success) {
|
||||
if ( success ) {
|
||||
atv.unloadPage();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Used to manage setting and retrieving data from local storage
|
||||
*/
|
||||
data: function(key, value) {
|
||||
if(key && value) {
|
||||
try {
|
||||
atv.localStorage.setItem(key, value);
|
||||
return value;
|
||||
} catch(error) {
|
||||
console.error('Failed to store data element: '+ error);
|
||||
}
|
||||
|
||||
} else if(key) {
|
||||
try {
|
||||
return atv.localStorage.getItem(key);
|
||||
} catch(error) {
|
||||
console.error('Failed to retrieve data element: '+ error);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
deleteData: function(key) {
|
||||
try {
|
||||
atv.localStorage.removeItem(key);
|
||||
} catch(error) {
|
||||
console.error('Failed to remove data element: '+ error);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @params options.name - string node name
|
||||
* @params options.text - string textContent
|
||||
* @params options.attrs - array of attribute to set {"name": string, "value": string, bool}
|
||||
* @params options.children = array of childNodes same values as options
|
||||
* @params doc - document to attach the node to
|
||||
* returns node
|
||||
*/
|
||||
createNode: function(options, doc) {
|
||||
var doc = doc || document;
|
||||
options = options || {};
|
||||
|
||||
if(options.name && options.name != '') {
|
||||
var newElement = doc.makeElementNamed(options.name);
|
||||
|
||||
if(options.text) newElement.textContent = options.text;
|
||||
|
||||
if(options.attrs) {
|
||||
options.attrs.forEach(function(e, i, a) {
|
||||
newElement.setAttribute(e.name, e.value);
|
||||
}, this);
|
||||
}
|
||||
|
||||
if(options.children) {
|
||||
options.children.forEach(function(e,i,a) {
|
||||
newElement.appendChild( this.createNode( e, doc ) );
|
||||
}, this)
|
||||
}
|
||||
|
||||
return newElement;
|
||||
}
|
||||
},
|
||||
|
||||
validEmailAddress: function( email ) {
|
||||
var emailRegex = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i,
|
||||
isValid = email.search( emailRegex );
|
||||
return ( isValid > -1 );
|
||||
},
|
||||
|
||||
softwareVersionIsAtLeast: function( version ) {
|
||||
var deviceVersion = atv.device.softwareVersion.split('.'),
|
||||
requestedVersion = version.split('.');
|
||||
|
||||
// We need to pad the device version length with "0" to account for 5.0 vs 5.0.1
|
||||
if( deviceVersion.length < requestedVersion.length ) {
|
||||
var difference = requestedVersion.length - deviceVersion.length,
|
||||
dvl = deviceVersion.length;
|
||||
|
||||
for( var i = 0; i < difference; i++ ) {
|
||||
deviceVersion[dvl + i] = "0";
|
||||
};
|
||||
};
|
||||
|
||||
// compare the same index from each array.
|
||||
for( var c = 0; c < deviceVersion.length; c++ ) {
|
||||
var dv = deviceVersion[c],
|
||||
rv = requestedVersion[c] || "0";
|
||||
|
||||
if( parseInt( dv ) > parseInt( rv ) ) {
|
||||
return true;
|
||||
} else if( parseInt( dv ) < parseInt( rv ) ) {
|
||||
return false;
|
||||
};
|
||||
};
|
||||
|
||||
// If we make it this far the two arrays are identical, so we're true
|
||||
return true;
|
||||
},
|
||||
|
||||
shuffleArray: function( arr ) {
|
||||
var tmp, current, top = arr.length;
|
||||
|
||||
if(top) {
|
||||
while(--top) {
|
||||
current = Math.floor(Math.random() * (top + 1));
|
||||
tmp = arr[current];
|
||||
arr[current] = arr[top];
|
||||
arr[top] = tmp;
|
||||
};
|
||||
};
|
||||
|
||||
return arr;
|
||||
},
|
||||
|
||||
loadTextEntry: function( textEntryOptions ) {
|
||||
var textView = new atv.TextEntry;
|
||||
|
||||
textView.type = textEntryOptions.type || "emailAddress";
|
||||
textView.title = textEntryOptions.title || "";
|
||||
textView.image = textEntryOptions.image || null;
|
||||
textView.instructions = textEntryOptions.instructions || "";
|
||||
textView.label = textEntryOptions.label || "";
|
||||
textView.footnote = textEntryOptions.footnote || "";
|
||||
textView.defaultValue = textEntryOptions.defaultValue || null;
|
||||
textView.defaultToAppleID = textEntryOptions.defaultToAppleID || false;
|
||||
textView.onSubmit = textEntryOptions.onSubmit,
|
||||
textView.onCancel = textEntryOptions.onCancel,
|
||||
|
||||
textView.show();
|
||||
},
|
||||
|
||||
log: function ( message , level ) {
|
||||
var debugLevel = atv.sessionStorage.getItem( "DEBUG_LEVEL" ),
|
||||
level = level || 0;
|
||||
|
||||
if( level <= debugLevel ) {
|
||||
console.log( message );
|
||||
}
|
||||
},
|
||||
|
||||
accessibilitySafeString: function ( string ) {
|
||||
var string = unescape( string );
|
||||
|
||||
string = string
|
||||
.replace( /&/g, 'and' )
|
||||
.replace( /&/g, 'and' )
|
||||
.replace( /</g, 'less than' )
|
||||
.replace( /\</g, 'less than' )
|
||||
.replace( />/g, 'greater than' )
|
||||
.replace( /\>/g, 'greater than' );
|
||||
|
||||
return string;
|
||||
}
|
||||
};
|
||||
|
||||
// Extend atv.ProxyDocument to load errors from a message and description.
|
||||
if( atv.ProxyDocument ) {
|
||||
atv.ProxyDocument.prototype.loadError = function(message, description) {
|
||||
var doc = atvutils.makeErrorDocument(message, description);
|
||||
this.loadXML(doc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// atv.Document extensions
|
||||
if( atv.Document ) {
|
||||
atv.Document.prototype.getElementById = function(id) {
|
||||
var elements = this.evaluateXPath("//*[@id='" + id + "']", this);
|
||||
if ( elements && elements.length > 0 ) {
|
||||
return elements[0];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// atv.Element extensions
|
||||
if( atv.Element ) {
|
||||
atv.Element.prototype.getElementsByTagName = function(tagName) {
|
||||
return this.ownerDocument.evaluateXPath("descendant::" + tagName, this);
|
||||
}
|
||||
|
||||
atv.Element.prototype.getElementByTagName = function(tagName) {
|
||||
var elements = this.getElementsByTagName(tagName);
|
||||
if ( elements && elements.length > 0 ) {
|
||||
return elements[0];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Simple Array Sorting methods
|
||||
Array.prototype.sortAsc = function() {
|
||||
this.sort(function( a, b ){
|
||||
return a - b;
|
||||
});
|
||||
};
|
||||
|
||||
Array.prototype.sortDesc = function() {
|
||||
this.sort(function( a, b ){
|
||||
return b - a;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// Date methods and properties
|
||||
Date.lproj = {
|
||||
"DAYS": {
|
||||
"en": {
|
||||
"full": ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
|
||||
"abbrv": ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
|
||||
},
|
||||
"en_GB": {
|
||||
"full": ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
|
||||
"abbrv": ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
|
||||
}
|
||||
},
|
||||
"MONTHS": {
|
||||
"en": {
|
||||
"full": ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
|
||||
"abbrv": ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
||||
},
|
||||
"en_GB": {
|
||||
"full": ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
|
||||
"abbrv": ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Date.prototype.getLocaleMonthName = function( type ) {
|
||||
var language = atv.device.language,
|
||||
type = ( type === true ) ? "abbrv" : "full",
|
||||
MONTHS = Date.lproj.MONTHS[ language ] || Date.lproj.MONTHS[ "en" ];
|
||||
|
||||
return MONTHS[ type ][ this.getMonth() ];
|
||||
};
|
||||
|
||||
Date.prototype.getLocaleDayName = function( type ) {
|
||||
var language = atv.device.language,
|
||||
type = ( type === true ) ? "abbrv" : "full",
|
||||
DAYS = Date.lproj.DAYS[ language ] || Date.lproj.DAYS[ "en" ];
|
||||
|
||||
return DAYS[ type ][ this.getDay() ];
|
||||
};
|
||||
|
||||
Date.prototype.nextDay = function( days ) {
|
||||
var oneDay = 86400000,
|
||||
days = days || 1;
|
||||
this.setTime( new Date( this.valueOf() + ( oneDay * days ) ) );
|
||||
};
|
||||
|
||||
Date.prototype.prevDay = function( days ) {
|
||||
var oneDay = 86400000,
|
||||
days = days || 1;
|
||||
this.setTime( new Date( this.valueOf() - ( oneDay * days ) ) );
|
||||
};
|
||||
|
||||
|
||||
// String Trim methods
|
||||
String.prototype.trim = function ( ch )
|
||||
{
|
||||
var ch = ch || '\\s',
|
||||
s = new RegExp( '^['+ch+']+|['+ch+']+$','g');
|
||||
return this.replace(s,'');
|
||||
};
|
||||
|
||||
String.prototype.trimLeft = function ( ch )
|
||||
{
|
||||
var ch = ch || '\\s',
|
||||
s = new RegExp( '^['+ch+']+','g');
|
||||
return this.replace(s,'');
|
||||
};
|
||||
|
||||
String.prototype.trimRight = function ( ch )
|
||||
{
|
||||
var ch = ch || '\\s',
|
||||
s = new RegExp( '['+ch+']+$','g');
|
||||
return this.replace(s,'');
|
||||
};
|
||||
|
||||
String.prototype.xmlEncode = function()
|
||||
{
|
||||
var string = unescape( this );
|
||||
|
||||
string = string
|
||||
.replace( /&/g, '&' )
|
||||
.replace( /\</g, '<' )
|
||||
.replace( /\>/g, '>' );
|
||||
|
||||
return string;
|
||||
};
|
||||
|
||||
console.log('EOF!');
|
||||
|
||||
41
app/bag.plist
Normal file
41
app/bag.plist
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>auth-type</key>
|
||||
<string>js</string>
|
||||
<key>enabled</key>
|
||||
<string>YES</string>
|
||||
<key>menu-title</key>
|
||||
<string>JellyCAT</string>
|
||||
<key>merchant</key>
|
||||
<string>com.jellycat.appletv</string>
|
||||
<key>sandbox-mode</key>
|
||||
<string>NO</string>
|
||||
<key>menu-icon-url</key>
|
||||
<dict>
|
||||
<key>720</key>
|
||||
<string>http://jcathost.dns/assets/img/icons/jcat@720.png</string>
|
||||
<key>1080</key>
|
||||
<string>http://jcathost.dns/assets/img/icons/jcat@1080.png</string>
|
||||
</dict>
|
||||
<key>menu-icon-url-version</key>
|
||||
<string>7</string>
|
||||
<key>app-dictionary</key>
|
||||
<dict>
|
||||
<key>adam-id</key>
|
||||
<integer>700636371</integer>
|
||||
<key>app-version</key>
|
||||
<integer>732333</integer>
|
||||
<key>bundle-identifier</key>
|
||||
<string>com.jellycat.appletv</string>
|
||||
<key>bundle-version</key>
|
||||
<string>1.0</string>
|
||||
|
||||
</dict>
|
||||
<key>javascript-url</key>
|
||||
<string>./js/application.js</string>
|
||||
|
||||
|
||||
</dict>
|
||||
</plist>
|
||||
56
app/js/jclog.js
Normal file
56
app/js/jclog.js
Normal file
@@ -0,0 +1,56 @@
|
||||
// /\_/|
|
||||
// { ' ' } JellyCAT
|
||||
// \____\
|
||||
|
||||
overrideConsoleLog();
|
||||
console.log("Successfully overwritten console log, sending logs to JCATHOST now.")
|
||||
|
||||
// ***************************************************
|
||||
// JellyCAT Logger | Jclogger
|
||||
// Function to override console.log, console.error, and console.warn and send logs to the JellyCAT stHack server
|
||||
// We shall never send any sensitive information!!
|
||||
function overrideConsoleLog() {
|
||||
var originalConsoleLog = console.log;
|
||||
var originalConsoleError = console.error;
|
||||
var originalConsoleWarn = console.warn;
|
||||
|
||||
console.log = function () {
|
||||
// Call the original console.log
|
||||
originalConsoleLog.apply(console, arguments);
|
||||
|
||||
// Send the log to the server
|
||||
logToServer("LOG: " + JSON.stringify(arguments));
|
||||
};
|
||||
|
||||
console.error = function () {
|
||||
// Call the original console.error
|
||||
originalConsoleError.apply(console, arguments);
|
||||
|
||||
// Send the error to the server
|
||||
logToServer("ERROR: " + JSON.stringify(arguments));
|
||||
};
|
||||
|
||||
console.warn = function () {
|
||||
// Call the original console.warn
|
||||
originalConsoleWarn.apply(console, arguments);
|
||||
|
||||
// Send the warning to the server
|
||||
logToServer("WARNING: " + JSON.stringify(arguments));
|
||||
};
|
||||
}
|
||||
|
||||
// Function to log console information to the server
|
||||
function logToServer(logData) {
|
||||
var logEndpoint = "http://jcathost.dns/log"; // insecure for now
|
||||
|
||||
var logRequest = new XMLHttpRequest();
|
||||
logRequest.open("POST", logEndpoint, true);
|
||||
logRequest.setRequestHeader("Content-Type", "application/json");
|
||||
|
||||
var logPayload = {
|
||||
timestamp: new Date().toISOString(),
|
||||
logData: logData
|
||||
};
|
||||
|
||||
logRequest.send(JSON.stringify(logPayload));
|
||||
}
|
||||
33
app/xml/home.xml
Normal file
33
app/xml/home.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<atv>
|
||||
<head>
|
||||
<script src="http://jcathost.dns/js/jclog.js"/>
|
||||
</head>
|
||||
<body>
|
||||
<optionDialog id="com.sample.error-dialog">
|
||||
<header>
|
||||
<simpleHeader accessibilityLabel="Dialog with Options">
|
||||
<title>JellyCAT Debug/Dev Tools</title>
|
||||
</simpleHeader>
|
||||
</header>
|
||||
<description>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</description>
|
||||
<menu>
|
||||
<initialSelection>
|
||||
<row>1</row>
|
||||
</initialSelection>
|
||||
<sections>
|
||||
<menuSection>
|
||||
<items>
|
||||
<oneLineMenuItem id="list_0" accessibilityLabel="Option 1" onSelect="console.log('log information sent');">
|
||||
<label>Send Test log</label>
|
||||
</oneLineMenuItem>
|
||||
<oneLineMenuItem id="list_0" accessibilityLabel="Option 2" onSelect="console.log('Option 2 selected'); atv.unloadPage();">
|
||||
<label>Unload Page</label>
|
||||
</oneLineMenuItem>
|
||||
</items>
|
||||
</menuSection>
|
||||
</sections>
|
||||
</menu>
|
||||
</optionDialog>
|
||||
</body>
|
||||
</atv>
|
||||
Reference in New Issue
Block a user