mirror of
https://github.com/themitosan/fpPS4-Temmie-s-Launcher.git
synced 2024-06-15 18:57:39 -04:00
Push project files
This commit is contained in:
parent
ae65a19fc0
commit
6f610687c2
188
App/css/style.css
Normal file
188
App/css/style.css
Normal file
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
Styles.css
|
||||
*/
|
||||
html, body {
|
||||
color: #fff;
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
font-family: monospace;
|
||||
background-color: #000;
|
||||
text-shadow: 2px 2px 4px #000;
|
||||
}
|
||||
input[type='button'], input[type='checkbox'] {
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
input[disabled="disabled"], input[disabled] {
|
||||
cursor: no-drop;
|
||||
}
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
border-radius: 4px;
|
||||
margin: 6px 0px 6px 0px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 4px;
|
||||
background: #e7e7e7;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
border-radius: 4px;
|
||||
background: #f0f0f0;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:active {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/*
|
||||
Divs
|
||||
*/
|
||||
.DIV_LIST {
|
||||
top: 38px;
|
||||
left: 0px;
|
||||
position: absolute;
|
||||
width: calc(100% - 280px);
|
||||
height: calc(100% - 286px);
|
||||
background-image: linear-gradient(146deg, #090f1b, #162a50);
|
||||
}
|
||||
.DIV_LOG {
|
||||
left: 0px;
|
||||
bottom: 0px;
|
||||
width: 100%;
|
||||
height: 248px;
|
||||
position: absolute;
|
||||
background-size: auto 50%;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url('../img/logo.png');
|
||||
}
|
||||
.DIV_ACTIONS {
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 22px;
|
||||
padding: 8px;
|
||||
position: absolute;
|
||||
background-image: linear-gradient(45deg, #28467f, #1c325f);
|
||||
}
|
||||
.DIV_OPTIONS {
|
||||
top: 38px;
|
||||
right: 0px;
|
||||
padding: 6px;
|
||||
width: 268px;
|
||||
position: absolute;
|
||||
height: calc(100% - 298px);
|
||||
background-image: linear-gradient(0deg, #162a50, #2a4a86);
|
||||
}
|
||||
.DIV_TITLE {
|
||||
font-size: 28px;
|
||||
margin-top: 10px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.DIV_LIST_INTERNAL {
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
transition: 0.4s;
|
||||
position: absolute;
|
||||
background-size: cover;
|
||||
background-color: #0000;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.GAME_ENTRY {
|
||||
margin: 6px;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
max-height: 92px;
|
||||
flex-wrap: nowrap;
|
||||
border-radius: 6px;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
width: calc(100% - 12px);
|
||||
backdrop-filter: blur(4px) invert(0.1);
|
||||
background-image: linear-gradient(90deg, #3a4b6b82, #0000);
|
||||
}
|
||||
.GAME_ENTRY:hover {
|
||||
box-shadow: 0px 0px 10px #0006;
|
||||
background-image: linear-gradient(90deg, #3a4b6b82, #3a4b6b82);
|
||||
}
|
||||
.GAME_ENTRY:active {
|
||||
box-shadow: 0px 0px 10px #0006 inset;
|
||||
backdrop-filter: invert(0.68) blur(6px);
|
||||
}
|
||||
.GAME_DETAILS {
|
||||
cursor: pointer;
|
||||
width: calc(100% - 88px);
|
||||
}
|
||||
.DIV_RUN_BTN {
|
||||
bottom: 4px;
|
||||
position: absolute;
|
||||
width: calc(100% - 12px);
|
||||
}
|
||||
|
||||
/*
|
||||
Images
|
||||
*/
|
||||
.GAME_ICON {
|
||||
width: 66px;
|
||||
margin: 6px;
|
||||
cursor: pointer;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
/*
|
||||
Input
|
||||
*/
|
||||
.APP_LOG {
|
||||
color: #0f0;
|
||||
height: 100%;
|
||||
resize: none;
|
||||
border: none;
|
||||
cursor: text;
|
||||
outline: none;
|
||||
width: calc(100% - 4px);
|
||||
background-repeat: no-repeat;
|
||||
text-shadow: 2px 2px 2px #000;
|
||||
background-image: linear-gradient(180deg, #000000db, #090f1b);
|
||||
}
|
||||
.BTN_RUN {
|
||||
left: 8px;
|
||||
width: 100%;
|
||||
bottom: 18px;
|
||||
height: 50px;
|
||||
font-size: 18px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
/*
|
||||
Labels
|
||||
*/
|
||||
.LABEL_checkbox {
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
font-style: italic;
|
||||
}
|
||||
.LABEL_emuColor {
|
||||
color: #fffb8e;
|
||||
}
|
||||
.LABEL_gameTtitle {
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/*
|
||||
Misc
|
||||
*/
|
||||
.none {
|
||||
display: none;
|
||||
}
|
BIN
App/img/404.png
Normal file
BIN
App/img/404.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.3 KiB |
BIN
App/img/404_BG.png
Normal file
BIN
App/img/404_BG.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
BIN
App/img/logo.png
Normal file
BIN
App/img/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 172 KiB |
70
App/index.htm
Normal file
70
App/index.htm
Normal file
|
@ -0,0 +1,70 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>fpPS4 Temmie's Launcher</title>
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!-- Top Menu -->
|
||||
<div class="DIV_ACTIONS">
|
||||
|
||||
<input type="button" class="APP_btn" onclick="APP.gameList.selectPath();" value="Select game path">
|
||||
<input type="button" class="APP_btn" onclick="APP.gameList.openFolder();" value="Open game folder">
|
||||
<input type="button" class="APP_btn" onclick="APP.gameList.load();" value="Refresh game list">
|
||||
<input type="button" class="APP_btn" onclick="APP.about();" value="About">
|
||||
|
||||
</div>
|
||||
|
||||
<!-- fpPS4 Options -->
|
||||
<div class="DIV_OPTIONS" id="DIV_OPTIONS">
|
||||
|
||||
<div class="DIV_TITLE"><label class="LABEL_emuColor">fp</label>PS4 Options</div>
|
||||
|
||||
<div id="DIV_HACK_LIST">
|
||||
<!-- Hacks goes here -->
|
||||
</div>
|
||||
|
||||
<!-- Run fpPS4 -->
|
||||
<div class="DIV_RUN_BTN">
|
||||
<input type="button" class="BTN_RUN" id="BTN_KILL" onclick="APP.emuManager.killEmu();" disabled="disabled" value="Stop fpPS4">
|
||||
<input type="button" class="BTN_RUN" id="BTN_RUN" onclick="APP.emuManager.runGame();" disabled="disabled" value="Run fpPS4">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Game List -->
|
||||
<div class="DIV_LIST" id="DIV_LIST">
|
||||
<div class="DIV_LIST_INTERNAL" id="DIV_LIST_INTERNAL">
|
||||
<!-- Games goes here -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Log -->
|
||||
<div class="DIV_LOG" id="DIV_LOG">
|
||||
<textarea class="APP_LOG" id="APP_LOG" disabled="disabled"></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Hidden Stuff -->
|
||||
<div class="none">
|
||||
|
||||
<!-- Folder loader -->
|
||||
<input type="file" id="APP_FOLDER_LOADER" nwdirectory/>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script type="text/javascript" src="js/TMS.js"></script>
|
||||
<script type="text/javascript" src="js/filemanager.js"></script>
|
||||
<script type="text/javascript" src="js/gamelist.js"></script>
|
||||
<script type="text/javascript" src="js/settings.js"></script>
|
||||
<script type="text/javascript" src="js/design.js"></script>
|
||||
<script type="text/javascript" src="js/emumanager.js"></script>
|
||||
<script type="text/javascript" src="js/main.js"></script>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
308
App/js/TMS.js
Normal file
308
App/js/TMS.js
Normal file
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
TMS.js - By @TheMitoSan
|
||||
|
||||
This file is an original replacement - Because I don't want to deal with jQuery
|
||||
anymore!
|
||||
|
||||
Original source / motivation: http://youmightnotneedjquery.com/
|
||||
*******************************************************************************
|
||||
*/
|
||||
tmsTemp = {};
|
||||
tmsTemp['logWarnings'] = false;
|
||||
/*
|
||||
Warn if something goes wrong
|
||||
*/
|
||||
tmsTemp['warn'] = function(warnText){
|
||||
if (TMS.logWarnings === true){
|
||||
console.warn(warnText);
|
||||
};
|
||||
};
|
||||
/*
|
||||
CSS
|
||||
*/
|
||||
tmsTemp['css'] = function(elementId, cssChanges){
|
||||
var canStart = true, eReason = '';
|
||||
const elId = document.getElementById(elementId);
|
||||
if (elId === null){
|
||||
canStart = false;
|
||||
eReason = eReason + '\nDOM does not exist! (' + elementId + ')';
|
||||
};
|
||||
if (typeof cssChanges !== 'object'){
|
||||
canStart = false;
|
||||
eReason = eReason + '\nYou must insert an object for CSS data (Current type: ' + typeof cssChanges + ')';
|
||||
};
|
||||
// End
|
||||
if (canStart === true){
|
||||
Object.keys(cssChanges).forEach(function(cItem){
|
||||
elId.style[cItem] = cssChanges[cItem];
|
||||
});
|
||||
} else {
|
||||
TMS.warn('TMS - Unable to apply CSS data!' + eReason);
|
||||
};
|
||||
};
|
||||
/*
|
||||
Animate
|
||||
|
||||
elementId = HTML DOM id
|
||||
cssChanges = Object {width: x, height, y}
|
||||
animationTime = Number (Min: 0)
|
||||
animationEase = CSS for transition option, like cubic-bezier
|
||||
*/
|
||||
tmsTemp['animate'] = function(elementId, cssChanges, animationTime, animationEase){
|
||||
var canStart = true, eReason = transitionString = '';
|
||||
const elId = document.getElementById(elementId);
|
||||
if (elId === null){
|
||||
canStart = false;
|
||||
eReason = eReason + '\nDOM does not exist! (' + elementId + ')';
|
||||
}
|
||||
if (typeof cssChanges !== 'object'){
|
||||
canStart = false;
|
||||
eReason = eReason + '\nYou must insert an object for CSS data (Current type: ' + typeof cssChanges + ')';
|
||||
}
|
||||
if (typeof animationTime !== 'number'){
|
||||
canStart = false;
|
||||
eReason = eReason + '\nYou must insert a number on animation time (Current type: ' + typeof animationTime + ')';
|
||||
}
|
||||
// End
|
||||
if (canStart === true){
|
||||
if (animationEase === undefined){
|
||||
animationEase = '';
|
||||
}
|
||||
if (animationTime < 0){
|
||||
animationTime = 0;
|
||||
}
|
||||
Object.keys(cssChanges).forEach(function(cItem){
|
||||
elId.style[cItem] = cssChanges[cItem];
|
||||
transitionString = transitionString + cItem + ' ' + (animationTime / 1000) + 's ';
|
||||
elId.style['transition'] = transitionString + animationEase;
|
||||
});
|
||||
setTimeout(function(){
|
||||
elId.style['transition'] = 'none 0s';
|
||||
}, (animationTime + 1));
|
||||
} else {
|
||||
TMS.warn('TMS - Unable to animate!' + eReason);
|
||||
}
|
||||
}
|
||||
/*
|
||||
Focus Element
|
||||
sTimeout = time [ms]
|
||||
*/
|
||||
tmsTemp['focus'] = function(elementId, sTimeout){
|
||||
const elId = document.getElementById(elementId);
|
||||
if (elId !== null){
|
||||
if (sTimeout !== undefined && parseInt(sTimeout) !== NaN){
|
||||
setTimeout(function(){
|
||||
elId.focus();
|
||||
}, sTimeout);
|
||||
} else {
|
||||
elId.focus();
|
||||
};
|
||||
} else {
|
||||
TMS.warn('TMS - Unable to focus element because it does not exist! (' + elementId + ')');
|
||||
};
|
||||
};
|
||||
/*
|
||||
Disable Element
|
||||
*/
|
||||
tmsTemp['disableElement'] = function(idList){
|
||||
var disableList = [];
|
||||
if (typeof idList === 'object'){
|
||||
disableList = idList;
|
||||
} else {
|
||||
disableList.push(idList);
|
||||
};
|
||||
// End
|
||||
disableList.forEach(function(cItem){
|
||||
const elId = document.getElementById(cItem);
|
||||
if (elId !== null){
|
||||
elId.disabled = 'disabled';
|
||||
// If is <input>
|
||||
if (elId.type === 'button'){
|
||||
TMS.css(cItem, {'filter': 'grayscale(1) blur(0.8px)', 'cursor': 'not-allowed', 'opacity': '0.6'});
|
||||
};
|
||||
} else {
|
||||
TMS.warn('TMS - Unable to disable element because it does not exist! (' + cItem + ')');
|
||||
};
|
||||
});
|
||||
};
|
||||
/*
|
||||
Enable Element
|
||||
*/
|
||||
tmsTemp['enableElement'] = function(elementId){
|
||||
const elId = document.getElementById(elementId);
|
||||
if (elId !== null){
|
||||
elId.disabled = '';
|
||||
// If is <input>
|
||||
if (elId.type === 'button'){
|
||||
TMS.css(elementId, {'filter': 'grayscale(0) blur(0px)', 'cursor': 'pointer', 'opacity': '1'});
|
||||
};
|
||||
} else {
|
||||
TMS.warn('TMS - Unable to enable element because it does not exist! (' + elementId + ')');
|
||||
};
|
||||
};
|
||||
/*
|
||||
Get CSS data
|
||||
Returns the attr value from CSS propriety
|
||||
*/
|
||||
tmsTemp['getCssData'] = function(elementId, cssAttrName){
|
||||
var elId = document.getElementById(elementId),
|
||||
result = '';
|
||||
if (elId !== null){
|
||||
result = elId.style[cssAttrName];
|
||||
} else {
|
||||
TMS.warn('TMS - Unable to get element because it does not exist! (' + elementId + ')');
|
||||
};
|
||||
return result;
|
||||
};
|
||||
/*
|
||||
Scroll top
|
||||
Usage: elementObjects = {HTML_DOM_ID_0: scrollInt, HTML_DOM_ID_1: scrollInt2} and goes on
|
||||
*/
|
||||
tmsTemp['scrollTop'] = function(elementObjects){
|
||||
Object.keys(elementObjects).forEach(function(cItem){
|
||||
const elId = document.getElementById(cItem);
|
||||
if (elId !== null){
|
||||
elId.scrollTop = elementObjects[cItem];
|
||||
} else {
|
||||
TMS.warn('TMS - Unable to scroll element because it does not exist! (' + elementId + ')');
|
||||
};
|
||||
});
|
||||
};
|
||||
/*
|
||||
Append data
|
||||
*/
|
||||
tmsTemp['append'] = function(elementId, newData){
|
||||
const elId = document.getElementById(elementId);
|
||||
if (elId !== null){
|
||||
var pHTML = elId.innerHTML;
|
||||
elId.innerHTML = pHTML + newData;
|
||||
} else {
|
||||
TMS.warn('TMS - Unable to append element data because parent DOM does not exist! (' + elementId + ')');
|
||||
};
|
||||
};
|
||||
/*
|
||||
Add Class
|
||||
*/
|
||||
tmsTemp['addClass'] = function(elementId, className){
|
||||
const elId = document.getElementById(elementId);
|
||||
if (elId !== null){
|
||||
elId.classList.add(className);
|
||||
} else {
|
||||
TMS.warn('TMS - Unable to add class because DOM does not exist! (' + elementId + ')');
|
||||
};
|
||||
};
|
||||
/*
|
||||
Add Class
|
||||
*/
|
||||
tmsTemp['removeClass'] = function(elementId, className){
|
||||
const elId = document.getElementById(elementId);
|
||||
if (elId !== null){
|
||||
elId.classList.remove(className);
|
||||
} else {
|
||||
TMS.warn('TMS - Unable to remove class because DOM does not exist! (' + elementId + ')');
|
||||
};
|
||||
};
|
||||
/*
|
||||
Clear
|
||||
Removes all HTML inside
|
||||
*/
|
||||
tmsTemp['clear'] = function(elementId){
|
||||
const elId = document.getElementById(elementId);
|
||||
if (elId !== null){
|
||||
elId.innerHTML = '';
|
||||
} else {
|
||||
TMS.warn('TMS - Unable to clear inner data because DOM does not exist! (' + elementId + ')');
|
||||
};
|
||||
};
|
||||
/*
|
||||
triggerClick
|
||||
*/
|
||||
tmsTemp['triggerClick'] = function(elementId){
|
||||
const elId = document.getElementById(elementId);
|
||||
if (elId !== null){
|
||||
elId.click();
|
||||
} else {
|
||||
TMS.warn('TMS - Unable to clear inner data because DOM does not exist! (' + elementId + ')');
|
||||
};
|
||||
};
|
||||
/*
|
||||
fadeIn
|
||||
*/
|
||||
tmsTemp['fadeIn'] = function(elementId, animationTime){
|
||||
const elId = document.getElementById(elementId), tagType = {
|
||||
'DIV': 'block',
|
||||
'IMG': 'inline'
|
||||
};
|
||||
if (elId !== null){
|
||||
var dTime = 1000, dMode = 'block', finalOpacity = 1, eStyles = getComputedStyle(elId);
|
||||
if (animationTime !== undefined && animationTime !== NaN){
|
||||
dTime = parseInt(animationTime);
|
||||
if (dTime < 0){
|
||||
dTime = 1;
|
||||
};
|
||||
};
|
||||
if (tagType[elId.tagType] !== undefined){
|
||||
dMode = tagType[elId.tagType];
|
||||
};
|
||||
if (eStyles.opacity !== ''){
|
||||
finalOpacity = eStyles.opacity;
|
||||
};
|
||||
TMS.css(elementId, {'display': dMode, 'opacity': finalOpacity, 'transition': 'opacity ' + dTime + 'ms'});
|
||||
setTimeout(function(){
|
||||
TMS.css(elementId, {'transition': 'none'});
|
||||
}, (dTime + 1));
|
||||
} else {
|
||||
TMS.warn('TMS - Unable to fade in because DOM does not exist! (' + elementId + ')');
|
||||
};
|
||||
};
|
||||
/*
|
||||
fadeOut
|
||||
*/
|
||||
tmsTemp['fadeOut'] = function(elementId, animationTime){
|
||||
const elId = document.getElementById(elementId);
|
||||
if (elId !== null){
|
||||
var dTime = 1000;
|
||||
if (animationTime !== undefined && animationTime !== NaN){
|
||||
dTime = parseInt(animationTime);
|
||||
if (dTime < 0){
|
||||
dTime = 1;
|
||||
};
|
||||
};
|
||||
TMS.css(elementId, {'opacity': '0', 'transition': 'opacity ' + dTime + 'ms'});
|
||||
setTimeout(function(){
|
||||
TMS.css(elementId, {'transition': 'none', 'display': 'none'});
|
||||
}, (dTime + 1));
|
||||
} else {
|
||||
TMS.warn('TMS - Unable to fade out because DOM does not exist! (' + elementId + ')');
|
||||
};
|
||||
};
|
||||
/*
|
||||
scrollCenter
|
||||
*/
|
||||
tmsTemp['scrollCenter'] = function(elementId){
|
||||
const elId = document.getElementById(elementId);
|
||||
if (elId !== null){
|
||||
var parentDom = elId.parentElement,
|
||||
parentHeight = parentDom.offsetHeight;
|
||||
parentDom.scrollTo(0, (elId.offsetTop - (parentHeight / 2)))
|
||||
} else {
|
||||
TMS.warn('TMS - Unable to fade out because DOM does not exist! (' + elementId + ')');
|
||||
};
|
||||
};
|
||||
/*
|
||||
setInnerHtml
|
||||
*/
|
||||
tmsTemp['setInnerHtml'] = function(elementId, htmlData){
|
||||
const elId = document.getElementById(elementId);
|
||||
if (elId !== null){
|
||||
document.getElementById(elementId).innerHTML = htmlData;
|
||||
} else {
|
||||
TMS.warn('TMS - Unable to set innerHTML because DOM does not exist! (' + elementId + ')');
|
||||
};
|
||||
};
|
||||
/*
|
||||
END
|
||||
*/
|
||||
const TMS = tmsTemp;
|
||||
delete(tmsTemp);
|
123
App/js/design.js
Normal file
123
App/js/design.js
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
design.js
|
||||
*/
|
||||
|
||||
temp_DESIGN = {
|
||||
|
||||
/*
|
||||
Hack List
|
||||
*/
|
||||
hackList: [
|
||||
'DEPTH_DISABLE_HACK',
|
||||
'COMPUTE_DISABLE_HACK',
|
||||
'MEMORY_BOUND_HACK',
|
||||
'IMAGE_TEST_HACK',
|
||||
'IMAGE_LOAD_HACK',
|
||||
'DISABLE_SRGB_HACK'
|
||||
],
|
||||
|
||||
// Process checkbox status
|
||||
processCheckbox: function(domName){
|
||||
|
||||
var res = !1,
|
||||
domId = document.getElementById(domName).checked;
|
||||
|
||||
if (domId === !1){
|
||||
res = !0;
|
||||
}
|
||||
|
||||
document.getElementById(domName).checked = res;
|
||||
|
||||
},
|
||||
|
||||
// Render hack list
|
||||
renderHacklist: function(){
|
||||
|
||||
var htmlTemp = '';
|
||||
|
||||
this.hackList.forEach(function(hackName){
|
||||
htmlTemp = htmlTemp + '<input type="checkbox" id="CHECK_' + hackName + '"><label class="LABEL_checkbox" onclick="APP.design.processCheckbox(\'CHECK_' + hackName +
|
||||
'\');">Enable ' + hackName + '</label><br>';
|
||||
});
|
||||
|
||||
document.getElementById('DIV_HACK_LIST').innerHTML = htmlTemp;
|
||||
|
||||
},
|
||||
|
||||
// Render game list
|
||||
renderGameList: function(){
|
||||
|
||||
var gList = APP.gameList.list,
|
||||
tempHtml = '';
|
||||
|
||||
Object.keys(gList).forEach(function(cGame){
|
||||
tempHtml = tempHtml + '<div class="GAME_ENTRY" onclick="APP.design.selectGame(\'' + cGame + '\');"><img class="GAME_ICON" src="' +
|
||||
gList[cGame].icon + '"><div class="GAME_DETAILS"><label class="LABEL_gameTtitle">' + gList[cGame].name +
|
||||
'</label><br>' + 'Path: ' + gList[cGame].eboot + '</div></div>';
|
||||
});
|
||||
|
||||
// Insert HTML
|
||||
document.getElementById('DIV_LIST_INTERNAL').innerHTML = tempHtml;
|
||||
|
||||
// Clear BG image
|
||||
TMS.css('DIV_LIST_INTERNAL', {'background-image': 'none'});
|
||||
|
||||
},
|
||||
|
||||
// Select game
|
||||
selectGame: function(gameName){
|
||||
|
||||
if (APP.gameList.list[gameName] !== void 0){
|
||||
|
||||
const cGame = APP.gameList.list[gameName];
|
||||
TMS.css('DIV_LIST_INTERNAL', {
|
||||
'background-image': 'url("' + cGame.bg + '")'
|
||||
});
|
||||
|
||||
APP.gameList.selectedGame = gameName;
|
||||
APP.design.updateRunButtons();
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// Enable or Disable Run / Stop buttons
|
||||
updateRunButtons: function(){
|
||||
|
||||
// Check if emu is present before allowing to run
|
||||
if (APP.fs.existsSync(APP.settings.data.emuPath) === !0){
|
||||
|
||||
var btnRun = '',
|
||||
logHeight = '248px',
|
||||
btnKill = 'disabled',
|
||||
hackDisplay = 'inline',
|
||||
listHeight = 'calc(100% - 286px)',
|
||||
optionsHeight = 'calc(100% - 298px)';
|
||||
|
||||
// If emu is running
|
||||
if (APP.emuManager.emuRunning === !0){
|
||||
|
||||
btnKill = '';
|
||||
btnRun = 'disabled';
|
||||
listHeight = '172px';
|
||||
hackDisplay = 'none';
|
||||
optionsHeight = '160px';
|
||||
logHeight = 'calc(100% - 210px)';
|
||||
|
||||
}
|
||||
|
||||
// Update GUI
|
||||
TMS.css('DIV_LOG', {'height': logHeight});
|
||||
TMS.css('DIV_LIST', {'height': listHeight});
|
||||
TMS.css('DIV_OPTIONS', {'height': optionsHeight});
|
||||
TMS.css('DIV_HACK_LIST', {'display': hackDisplay});
|
||||
|
||||
// Update Buttons
|
||||
document.getElementById('BTN_RUN').disabled = btnRun;
|
||||
document.getElementById('BTN_KILL').disabled = btnKill;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
51
App/js/emumanager.js
Normal file
51
App/js/emumanager.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
emumanager.js
|
||||
*/
|
||||
|
||||
temp_EMUMANAGER = {
|
||||
|
||||
// Emulator is running
|
||||
emuRunning: !1,
|
||||
|
||||
// Run emu
|
||||
runGame: function(){
|
||||
|
||||
// If user selected a game
|
||||
if (APP.gameList.list[APP.gameList.selectedGame] !== void 0){
|
||||
|
||||
// Set main variables
|
||||
var ebootPath = APP.gameList.list[APP.gameList.selectedGame].eboot,
|
||||
emuArgs = ['-e', ebootPath],
|
||||
hList = APP.design.hackList;
|
||||
|
||||
// Get enabled hacks
|
||||
hList.forEach(function(hackName){
|
||||
if (document.getElementById('CHECK_' + hackName).checked === !0){
|
||||
emuArgs.push('-h');
|
||||
emuArgs.push(hackName);
|
||||
}
|
||||
});
|
||||
|
||||
// Log emu args
|
||||
APP.log('\nINFO - Running fpPS4 with args: ' + emuArgs.toString().replace(RegExp(',', 'gi'), ' ') + '\n\n');
|
||||
|
||||
// Run fpPS4
|
||||
APP.runExec(APP.settings.data.emuPath, emuArgs);
|
||||
this.emuRunning = !0;
|
||||
|
||||
// Update GUI
|
||||
APP.design.updateRunButtons();
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// Kill emu process
|
||||
killEmu: function(){
|
||||
|
||||
process.kill(APP.execProcess.pid);
|
||||
this.emuRunning = !1;
|
||||
|
||||
}
|
||||
|
||||
}
|
30
App/js/filemanager.js
Normal file
30
App/js/filemanager.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
filemanager.js
|
||||
*/
|
||||
|
||||
temp_FILEMANAGER = {
|
||||
|
||||
// Select path
|
||||
selectPath: function(postAction){
|
||||
|
||||
if (postAction !== void 0){
|
||||
|
||||
document.getElementById('APP_FOLDER_LOADER').onchange = function(){
|
||||
|
||||
const cFile = document.getElementById('APP_FOLDER_LOADER').files[0];
|
||||
|
||||
if (cFile.path !== null && cFile.path !== void 0 && cFile.path !== ''){
|
||||
postAction(cFile.path.replace(RegExp('\\\\', 'gi'), '/'));
|
||||
document.getElementById('APP_FOLDER_LOADER').value = '';
|
||||
document.getElementById('APP_FOLDER_LOADER').accept = '';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
document.getElementById('APP_FOLDER_LOADER').click();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
125
App/js/gamelist.js
Normal file
125
App/js/gamelist.js
Normal file
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
gamelist.js
|
||||
*/
|
||||
|
||||
temp_GAMELIST = {
|
||||
|
||||
// Game List
|
||||
list: {},
|
||||
|
||||
// Selected game
|
||||
selectedGame: '',
|
||||
|
||||
// Select game path
|
||||
selectPath: function(){
|
||||
|
||||
APP.fileManager.selectPath(function(newGamePath){
|
||||
APP.settings.data.gamePath = newGamePath;
|
||||
APP.settings.save();
|
||||
APP.gameList.load();
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
// Load list
|
||||
load: function(){
|
||||
|
||||
// Check if path exists
|
||||
if (APP.fs.existsSync(APP.settings.data.gamePath) === !0){
|
||||
|
||||
// Reset game list
|
||||
APP.gameList.list = {};
|
||||
|
||||
// Get game list
|
||||
const gList = APP.fs.readdirSync(APP.settings.data.gamePath);
|
||||
|
||||
if (gList.length > 0){
|
||||
|
||||
// Process game list
|
||||
gList.forEach(function(gPath){
|
||||
|
||||
var addGame = !0,
|
||||
elfName = '',
|
||||
ebootName = '',
|
||||
pathBase = APP.settings.data.gamePath + '/' + gPath,
|
||||
|
||||
appBg0 = pathBase + '/pic0.png',
|
||||
appBg1 = pathBase + '/pic1.png',
|
||||
appIcon = pathBase + '/icon.png',
|
||||
|
||||
finalBg = appBg0,
|
||||
finalIcon = appIcon,
|
||||
|
||||
ebootFile = pathBase + '/eboot.bin';
|
||||
|
||||
if (APP.fs.existsSync(ebootFile) === !0){
|
||||
ebootName = 'eboot.bin';
|
||||
}
|
||||
|
||||
// If eboot.bin doesn't exists, look for any .elf file
|
||||
if (APP.fs.existsSync(ebootFile) !== !0){
|
||||
|
||||
var fList = APP.fs.readdirSync(pathBase),
|
||||
execName = fList.filter(function(fName){
|
||||
if (fName.toLowerCase().indexOf('.elf') !== -1){
|
||||
return fName;
|
||||
}
|
||||
})[0];
|
||||
|
||||
ebootName = execName;
|
||||
|
||||
// If not found (undefined), skip
|
||||
if (execName === void 0){
|
||||
addGame = !1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Set icon
|
||||
if (APP.fs.existsSync(appIcon) === !1){
|
||||
finalIcon = APP.settings.data.nwPath + '/app/img/404.png';
|
||||
}
|
||||
|
||||
// Set BG image
|
||||
if (APP.fs.existsSync(appBg0) === !1){
|
||||
finalBg = appBg1;
|
||||
if (APP.fs.existsSync(appBg1) === !1){
|
||||
finalBg = APP.settings.data.nwPath + '/app/img/404_BG.png';
|
||||
}
|
||||
}
|
||||
|
||||
// If executable exists, set data
|
||||
if (addGame === !0){
|
||||
APP.gameList.list[gPath] = {
|
||||
bg: finalBg,
|
||||
name: gPath,
|
||||
icon: finalIcon,
|
||||
eboot: APP.settings.data.gamePath + '/' + gPath + '/' + ebootName
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
// No games / homebrew found
|
||||
APP.log('INFO - No games / homebrew were detected on current path (' + APP.settings.data.gamePath + ')');
|
||||
|
||||
}
|
||||
|
||||
// Render game list
|
||||
APP.design.renderGameList();
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// Open game folder
|
||||
openFolder: function(){
|
||||
|
||||
// Spawn explorer
|
||||
APP.childProcess.exec('start "" "' + APP.settings.data.gamePath + '"');
|
||||
|
||||
}
|
||||
|
||||
}
|
124
App/js/main.js
Normal file
124
App/js/main.js
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
main.js
|
||||
*/
|
||||
|
||||
var APP = {
|
||||
|
||||
// App version
|
||||
version: '1.0.0',
|
||||
|
||||
// Import nw modules
|
||||
fs: require('fs'),
|
||||
path: require('path'),
|
||||
childProcess: require('child_process'),
|
||||
|
||||
// Import app modules
|
||||
design: temp_DESIGN,
|
||||
gameList: temp_GAMELIST,
|
||||
settings: temp_SETTINGS,
|
||||
emuManager: temp_EMUMANAGER,
|
||||
fileManager: temp_FILEMANAGER,
|
||||
|
||||
// Log function and variables
|
||||
logData: '',
|
||||
log: function(text, skipLog){
|
||||
|
||||
if (text !== '' && text !== void 0){
|
||||
|
||||
var textarea = document.getElementById('APP_LOG'),
|
||||
previousLog = textarea.value,
|
||||
newLog = previousLog + '\n' + text;
|
||||
|
||||
if (previousLog == ''){
|
||||
newLog = text;
|
||||
}
|
||||
|
||||
if (previousLog.slice(previousLog.length - 1, previousLog.length) === '\n'){
|
||||
newLog = previousLog + text;
|
||||
}
|
||||
|
||||
textarea.value = newLog;
|
||||
APP.logData = newLog;
|
||||
|
||||
// If true, skip internal log
|
||||
if (skipLog !== !0){
|
||||
console.log(text);
|
||||
}
|
||||
|
||||
// Scroll log
|
||||
textarea.scrollTop = textarea.scrollHeight;
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// Run external software
|
||||
execProcess: void 0,
|
||||
runExec: function(exe, args){
|
||||
|
||||
if (exe !== void 0 && exe !== ''){
|
||||
|
||||
/*
|
||||
Spawn process
|
||||
It will change running dir to current exe location
|
||||
*/
|
||||
process.chdir(APP.path.parse(exe).dir);
|
||||
APP.execProcess = APP.childProcess.spawn(exe, args);
|
||||
|
||||
// Log on stdout and stderr
|
||||
APP.execProcess.stdout.on('data', function(data){
|
||||
APP.log(data.toString(), !0);
|
||||
});
|
||||
APP.execProcess.stderr.on('data', function(data){
|
||||
APP.log(data.toString(), !0);
|
||||
});
|
||||
|
||||
// Log on close
|
||||
APP.execProcess.on('close', function(code){
|
||||
process.chdir(APP.settings.data.nwPath);
|
||||
APP.emuManager.emuRunning = !1;
|
||||
APP.log('INFO - ' + APP.path.parse(exe).base + ' was closed returning code ' + code);
|
||||
APP.design.updateRunButtons();
|
||||
return code;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// About screen
|
||||
about: function(){
|
||||
window.alert('fpPS4 Temmie\'s Launcher - Version: ' + this.version + '\nCreated by TemmieHeartz\n(https://twitter.com/themitosan)\n\nfpPS4 main emulator is created by red-prig\n(https://github.com/red-prig/fpPS4)');
|
||||
},
|
||||
|
||||
// Reload app
|
||||
reload: function(){
|
||||
location.reload();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Delete modules
|
||||
delete temp_DESIGN;
|
||||
delete temp_SETTINGS;
|
||||
delete temp_GAMELIST;
|
||||
delete temp_EMUMANAGER;
|
||||
delete temp_FILEMANAGER;
|
||||
|
||||
// Start
|
||||
window.onload = function(){
|
||||
|
||||
// Main log
|
||||
APP.log('fpPS4 Temmie\'s Launcher - Version: ' + APP.version + '\nRunning on nw.js (node-webkit) version ' + process.versions.nw);
|
||||
|
||||
// Load settings
|
||||
APP.settings.load();
|
||||
APP.settings.checkPaths();
|
||||
|
||||
// Load game list
|
||||
APP.gameList.load();
|
||||
|
||||
// Rener hack list
|
||||
APP.design.renderHacklist();
|
||||
|
||||
}
|
69
App/js/settings.js
Normal file
69
App/js/settings.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
settings.js
|
||||
*/
|
||||
|
||||
temp_SETTINGS = {
|
||||
|
||||
// Settings list
|
||||
data: {
|
||||
nwPath: '',
|
||||
emuPath: '',
|
||||
gamePath: ''
|
||||
},
|
||||
|
||||
// Load settings
|
||||
load: function() {
|
||||
|
||||
// Create save
|
||||
if (localStorage.getItem('settings') === null){
|
||||
APP.settings.save();
|
||||
}
|
||||
|
||||
const settings = localStorage.getItem('settings');
|
||||
this.data = JSON.parse(settings);
|
||||
|
||||
},
|
||||
|
||||
// Save settings
|
||||
save: function() {
|
||||
localStorage.setItem('settings', JSON.stringify(this.data));
|
||||
},
|
||||
|
||||
// Check paths
|
||||
checkPaths: function(){
|
||||
|
||||
// Fix path
|
||||
this.data.nwPath = nw.__dirname.replace(RegExp('\\\\', 'gi'), '/');
|
||||
|
||||
const mainPath = this.data.nwPath,
|
||||
pathList = [
|
||||
'/Emu',
|
||||
'/Games'
|
||||
];
|
||||
|
||||
// Try create required paths
|
||||
pathList.forEach(function(cPath){
|
||||
if (APP.fs.existsSync(mainPath + cPath) !== !0){
|
||||
try {
|
||||
APP.fs.mkdirSync(mainPath + cPath);
|
||||
} catch (err) {
|
||||
APP.log('Unable to create path!\n(' + mainPath + cPath + ')\n' + err);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Set Games / Emu paths and check if fpPS4 exe is present
|
||||
this.data.gamePath = mainPath + '/Games';
|
||||
this.data.emuPath = mainPath + '/Emu/fpPS4.exe';
|
||||
|
||||
if (APP.fs.existsSync(this.data.emuPath) === !0){
|
||||
APP.log('INFO - Main fpPS4 was found!');
|
||||
} else {
|
||||
const errMsg = 'ERROR - Unable to locate main fpPS4 executable!\nMake sure to insert it on \"Emu\" folder and click on ok.';
|
||||
window.alert(errMsg);
|
||||
APP.log(errMsg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
25
package.json
Normal file
25
package.json
Normal file
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"version": "1.0.0",
|
||||
"license": "GPL-2",
|
||||
"main": "App/index.htm",
|
||||
"author": "TemmieHeartz",
|
||||
"name": "fpPS4 Temmie's Launcher",
|
||||
"description": "A simple launcher for fpPS4 project",
|
||||
"repository": "https://github.com/themitosan/fpPS4-Temmie-s-Launcher",
|
||||
"window": {
|
||||
"frame": true,
|
||||
"width": 1180,
|
||||
"height": 710,
|
||||
"toolbar": true,
|
||||
"min_width": 1180,
|
||||
"min_height": 710,
|
||||
"fullscreen": false,
|
||||
"position": "center",
|
||||
"theme-color": "#000",
|
||||
"icon": "App/img/logo.png",
|
||||
"title": "fpPS4 Temmie's Launcher"
|
||||
},
|
||||
"webkit": {
|
||||
"plugin": true
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue