From 29529521698d72588d75db58a48e67d301b02468 Mon Sep 17 00:00:00 2001 From: fr500 Date: Thu, 15 Sep 2016 18:12:00 -0500 Subject: [PATCH] (ems) add itch.io template --- pkg/emscripten/itch/index.html | 148 ++++++++++++ pkg/emscripten/itch/itch.css | 99 ++++++++ pkg/emscripten/itch/itch.js | 401 +++++++++++++++++++++++++++++++++ 3 files changed, 648 insertions(+) create mode 100644 pkg/emscripten/itch/index.html create mode 100644 pkg/emscripten/itch/itch.css create mode 100644 pkg/emscripten/itch/itch.js diff --git a/pkg/emscripten/itch/index.html b/pkg/emscripten/itch/index.html new file mode 100644 index 0000000000..565eca97b2 --- /dev/null +++ b/pkg/emscripten/itch/index.html @@ -0,0 +1,148 @@ + + + + + RetroArch Web Player + + + + + + + + + + + + + + + +
+
+
+ + RetroArch Logo +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+

For now, we recommend you use Google Chrome for the best possible performance.

+ +
+ + + + + + + + + + diff --git a/pkg/emscripten/itch/itch.css b/pkg/emscripten/itch/itch.css new file mode 100644 index 0000000000..d5e6b52d89 --- /dev/null +++ b/pkg/emscripten/itch/itch.css @@ -0,0 +1,99 @@ +/** + * RetroArch Web Player + * + * This provides the basic styling for the RetroArch web player. + */ + +/** + * Make sure the background of the player is black. + */ +.webplayer-container { + background-color: black; +} + +/** + * Webplayer Preview when not loaded. + */ +.webplayer-preview { + margin: 0 auto; + cursor: wait; + opacity: 0.2; + transition: all 0.8s; + -webkit-animation: loading 0.8s ease-in-out infinite alternate; + -moz-animation: loading 0.8s ease-in-out infinite alternate; + animation: loading 0.8s ease-in-out infinite alternate; +} +.webplayer-preview.loaded { + cursor: pointer; + opacity: 1; + -webkit-animation: loaded 0.8s ease-in-out; + -moz-animation: loaded 0.8s ease-in-out; + animation: loaded 0.8s ease-in-out; +} +@keyframes loaded { + from { + opacity: 0.2; + } + to { + opacity: 1; + } +} +@-moz-keyframes loaded { + from { + opacity: 0.2; + } + to { + opacity: 1; + } +} +@-webkit-keyframes loaded { + from { + opacity: 0.2; + } + to { + opacity: 1; + } +} +@keyframes loading{ + from { + opacity: 0.2; + } + to { + opacity: 0.35; + } +} +@-moz-keyframes loading{ + from { + opacity: 0.2; + } + to { + opacity: 0.35; + } +} +@-webkit-keyframes loading { + from { + opacity: 0.2; + } + to { + opacity: 0.35; + } +} + +/** + * Disable the border around the player. + */ +canvas.webplayer { + border: none; + outline: none; +} + +textarea { + font-family: monospace; + font-size: 0.7em; + height: 95%; + width: 95%; + border-style: none; + border-color: transparent; + overflow: auto; + resize: none; +} diff --git a/pkg/emscripten/itch/itch.js b/pkg/emscripten/itch/itch.js new file mode 100644 index 0000000000..ba42e4274b --- /dev/null +++ b/pkg/emscripten/itch/itch.js @@ -0,0 +1,401 @@ +/** + * RetroArch Web Player + * + * This provides the basic JavaScript for the RetroArch web player. + */ +var dropbox = false; +var client = new Dropbox.Client({ key: "il6e10mfd7pgf8r" }); +var XFS; +var BrowserFS = browserfs; + +var showError = function(error) { + switch (error.status) { + case Dropbox.ApiError.INVALID_TOKEN: + // If you're using dropbox.js, the only cause behind this error is that + // the user token expired. + // Get the user through the authentication flow again. + break; + + case Dropbox.ApiError.NOT_FOUND: + // The file or folder you tried to access is not in the user's Dropbox. + // Handling this error is specific to your application. + break; + + case Dropbox.ApiError.OVER_QUOTA: + // The user is over their Dropbox quota. + // Tell them their Dropbox is full. Refreshing the page won't help. + break; + + case Dropbox.ApiError.RATE_LIMITED: + // Too many API requests. Tell the user to try again later. + // Long-term, optimize your code to use fewer API calls. + break; + + case Dropbox.ApiError.NETWORK_ERROR: + // An error occurred at the XMLHttpRequest layer. + // Most likely, the user's network connection is down. + // API calls will not succeed until the user gets back online. + break; + + case Dropbox.ApiError.INVALID_PARAM: + case Dropbox.ApiError.OAUTH_ERROR: + case Dropbox.ApiError.INVALID_METHOD: + default: + // Caused by a bug in dropbox.js, in your application, or in Dropbox. + // Tell the user an error occurred, ask them to refresh the page. + } +}; + +function dropboxInit() +{ + document.getElementById('btnRun').disabled = true; + document.getElementById('btnDrop').disabled = true; + $('#icnDrop').removeClass('fa-dropbox'); + $('#icnDrop').addClass('fa-spinner fa-spin'); + + + client.authDriver(new Dropbox.AuthDriver.Redirect()); + client.authenticate({ rememberUser: true }, function(error, client) + { + if (error) + { + return showError(error); + } + dropboxSync(client, dropboxSyncComplete); + }); +} + +function dropboxSyncComplete() +{ + document.getElementById('btnRun').disabled = false; + $('#icnDrop').removeClass('fa-spinner').removeClass('fa-spin'); + $('#icnDrop').addClass('fa-dropbox'); + console.log("WEBPLAYER: Sync successful"); + + setupFileSystem("dropbox"); + setupFolderStructure(); + preLoadingComplete(); +} + +var afs; + +function dropboxSync(dropboxClient, cb) +{ + var dbfs = new BrowserFS.FileSystem.Dropbox(dropboxClient); + // Wrap in afsFS. + afs = new BrowserFS.FileSystem.AsyncMirror( + new BrowserFS.FileSystem.InMemory(), dbfs); + + afs.initialize(function(err) + { + // Initialize it as the root file system. + //BrowserFS.initialize(afs); + cb(); + }); +} + +function preLoadingComplete() +{ + /* Make the Preview image clickable to start RetroArch. */ + $('.webplayer-preview').addClass('loaded').click(function () { + startRetroArch(); + return false; + }); +} + + +function setupFileSystem(backend) +{ + /* create a mountable filesystem that will server as a root + mountpoint for browserfs */ + var mfs = new BrowserFS.FileSystem.MountableFileSystem(); + + /* create an XmlHttpRequest filesystem for the bundled data */ + var xfs1 = new BrowserFS.FileSystem.XmlHttpRequest + (".index-xhr", "https://bot.libretro.com/assets/frontend/bundle/"); + /* create an XmlHttpRequest filesystem for core assets */ + var xfs2 = new BrowserFS.FileSystem.XmlHttpRequest + (".index-xhr", "https://bot.libretro.com/assets/cores/"); + + console.log("WEBPLAYER: Initializing Filesystem"); + if(backend == "browser") + { + console.log("WEBPLAYER: Initializing LocalStorage"); + + /* create a local filesystem */ + var lsfs = new BrowserFS.FileSystem.LocalStorage(); + + /* mount the filesystems onto mfs */ + mfs.mount('/home/web_user/retroarch/userdata', lsfs); + + /* create a memory filesystem for content only + var imfs = new BrowserFS.FileSystem.InMemory();*/ + + /* mount the filesystems onto mfs + mfs.mount('/home/web_user/retroarch/userdata/content/', imfs);*/ + } + else + { + /* mount the filesystems onto mfs */ + mfs.mount('/home/web_user/retroarch/userdata', afs); + } + + mfs.mount('/home/web_user/retroarch/bundle', xfs1); + mfs.mount('/home/web_user/retroarch/userdata/content/downloads', xfs2); + BrowserFS.initialize(mfs); + var BFS = new BrowserFS.EmscriptenFS(); + FS.mount(BFS, {root: '/home'}, '/home'); + console.log("WEBPLAYER: " + backend + " filesystem initialized"); +} + +/** + * Retrieve the value of the given GET parameter. + */ +function getParam(name) { + var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href); + if (results) { + return results[1] || null; + } +} + +function setupFolderStructure() +{ + FS.createPath('/', '/home/web_user', true, true); +} + +function stat(path) +{ + try{ + FS.stat(path); + } + catch(err) + { + console.log("WEBPLAYER: file " + path + " doesn't exist"); + return false; + } + return true; +} + +function startRetroArch() +{ + $('.webplayer').show(); + $('.webplayer-preview').hide(); + document.getElementById('btnDrop').disabled = true; + document.getElementById('btnRun').disabled = true; + + $('#btnFullscreen').removeClass('disabled'); + $('#btnMenu').removeClass('disabled'); + $('#btnAdd').removeClass('disabled'); + $('#btnRom').removeClass('disabled'); + + document.getElementById("btnAdd").disabled = false; + document.getElementById("btnRom").disabled = false; + document.getElementById("btnMenu").disabled = false; + document.getElementById("btnFullscreen").disabled = false; + + Module['callMain'](Module['arguments']); + document.getElementById('canvas').focus(); +} + +function selectFiles(files) +{ + $('#btnAdd').addClass('disabled'); + $('#icnAdd').removeClass('fa-plus'); + $('#icnAdd').addClass('fa-spinner spinning'); + var count = files.length; + + for (var i = 0; i < files.length; i++) + { + filereader = new FileReader(); + filereader.file_name = files[i].name; + filereader.readAsArrayBuffer(files[i]); + filereader.onload = function(){uploadData(this.result, this.file_name)}; + filereader.onloadend = function(evt) + { + console.log("WEBPLAYER: File: " + this.file_name + " Upload Complete"); + if (evt.target.readyState == FileReader.DONE) + { + $('#btnAdd').removeClass('disabled'); + $('#icnAdd').removeClass('fa-spinner spinning'); + $('#icnAdd').addClass('fa-plus'); + } + } + } +} + +function uploadData(data,name) +{ + var dataView = new Uint8Array(data); + FS.createDataFile('/', name, dataView, true, false); + + var data = FS.readFile(name,{ encoding: 'binary' }); + FS.writeFile('/home/web_user/retroarch/userdata/content/' + name, data ,{ encoding: 'binary' }); + FS.unlink(name); +} + +var Module = +{ + noInitialRun: true, + arguments: ["-v", "--menu"], + preRun: [], + postRun: [], + print: (function() + { + var element = document.getElementById('output'); + element.value = ''; // clear browser cache + return function(text) + { + text = Array.prototype.slice.call(arguments).join(' '); + element.value += text + "\n"; + element.scrollTop = 99999; // focus on bottom + }; + })(), + + printErr: function(text) + { + var text = Array.prototype.slice.call(arguments).join(' '); + var element = document.getElementById('output'); + element.value += text + "\n"; + element.scrollTop = 99999; // focus on bottom + }, + canvas: document.getElementById('canvas'), + totalDependencies: 0, + monitorRunDependencies: function(left) + { + this.totalDependencies = Math.max(this.totalDependencies, left); + } +}; + +function switchCore(corename) { + localStorage.setItem("core", corename); +} + +function switchStorage() { + if (localStorage.getItem("backend") == "dropbox") + { + localStorage.setItem("backend", "browser"); + location.reload(); + } + else + { + localStorage.setItem("backend", "dropbox"); + location.reload(); + } +} + +// When the browser has loaded everything. +$(function() { + /** + * Attempt to disable some default browser keys. + */ + var keys = { + 9: "tab", + 13: "enter", + 16: "shift", + 18: "alt", + 27: "esc", + 33: "rePag", + 34: "avPag", + 35: "end", + 36: "home", + 37: "left", + 38: "up", + 39: "right", + 40: "down", + 112: "F1", + 113: "F2", + 114: "F3", + 115: "F4", + 116: "F5", + 117: "F6", + 118: "F7", + 119: "F8", + 120: "F9", + 121: "F10", + 122: "F11", + 123: "F12" + }; + window.addEventListener('keydown', function (e) { + if (keys[e.which]) { + e.preventDefault(); + } + }); + + // Switch the core when selecting one. + $('#core-selector a').click(function () { + var coreChoice = $(this).data('core'); + switchCore(coreChoice); + }); + + // Find which core to load. + var core = localStorage.getItem("core", core); + if (!core) { + core = 'gambatte'; + } + // Make the core the selected core in the UI. + var coreTitle = $('#core-selector a[data-core="' + core + '"]').addClass('active').text(); + $('#dropdownMenu1').text(coreTitle); + + // Load the Core's related JavaScript. + $.getScript(core + '_libretro.js', function () + { + // Activate the Start RetroArch button. + $('#btnRun').removeClass('disabled'); + $('#icnRun').removeClass('fa-spinner').removeClass('fa-spin'); + $('#icnRun').addClass('fa-play'); + + document.getElementById("btnRun").disabled = false; + + if (localStorage.getItem("backend") == "dropbox") + { + $('#icnDrop').removeClass('fa-globe'); + $('#icnDrop').addClass('fa-dropbox'); + dropboxInit(); + } + else + { + $('#icnDrop').addClass('fa-globe'); + $('#icnDrop').removeClass('fa-dropbox'); + preLoadingComplete(); + setupFileSystem("browser"); + setupFolderStructure(); + } + }); + }); + +function keyPress(k) +{ + kp(k, "keydown"); + setInterval(function(){kp(k, "keyup")}, 1000); +} + +kp = function(k, event) { + var oEvent = document.createEvent('KeyboardEvent'); + + // Chromium Hack + Object.defineProperty(oEvent, 'keyCode', { + get : function() { + return this.keyCodeVal; + } + }); + Object.defineProperty(oEvent, 'which', { + get : function() { + return this.keyCodeVal; + } + }); + + if (oEvent.initKeyboardEvent) { + oEvent.initKeyboardEvent(event, true, true, document.defaultView, false, false, false, false, k, k); + } else { + oEvent.initKeyEvent(event, true, true, document.defaultView, false, false, false, false, k, 0); + } + + oEvent.keyCodeVal = k; + + if (oEvent.keyCode !== k) { + alert("keyCode mismatch " + oEvent.keyCode + "(" + oEvent.which + ")"); + } + + document.dispatchEvent(oEvent); + document.getElementById('canvas').focus(); +}