Skip to content

Commit d554ccb

Browse files
ComputerEliteComputerElite
authored andcommitted
add mod installation in headset
1 parent e98a61e commit d554ccb

14 files changed

Lines changed: 226 additions & 25 deletions

Assets/html/index.html

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
<title>Quest App Version Switcher - Main</title>
44
<link rel="stylesheet" type="text/css" href="style.css">
55
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,400italic,700,700italic' rel='stylesheet' type='text/css'>
6+
<script async src="https://cse.google.com/cse.js?cx=256b790fca48449ad"></script>
67
</head>
78
<body>
9+
810
<div class="menuContainer">
911
<div class="sidebar">
1012
<div class="header">
@@ -17,7 +19,8 @@
1719
<div class="menuItem" section="downgrade">Downgrade</div>
1820
<div class="menuItem" section="download">Download progress</div>
1921
<div class="menuItem" section="patching">Mod my game</div>
20-
<div class="menuItem" section="mods" id="modsButton">Mods</div>
22+
<div class="menuItem" section="mods" id="modsButton">Installed Mods</div>
23+
<div class="menuItem" section="getMods" id="getModsButton">Get Mods</div>
2124
<div class="menuItem" section="tools">Tools & Options</div>
2225
</div>
2326
<div class="content">
@@ -74,7 +77,7 @@ <h2>Patching options</h2>
7477
</div>
7578
<div class="contentItem hidden" id="mods">
7679
<b>Please note that mod installation is in early access, there may be issues. Feel free to give feedback on the OculusDB Discord Server at <code>discord.gg/zwRfHQN2UY</code></b>
77-
<div class="button" onclick="UploadMod()">Install a Mod</div>
80+
<div class="button" id="installModButton" onclick="UploadMod()">Install a Mod from Disk</div>
7881
<div id="operations">
7982
<h2 id="ongoingCount">Ongoing operations:</h2>
8083
<div class="loaderContainer" style="margin-bottom: 10px;">
@@ -91,15 +94,24 @@ <h2 id="ongoingCount">Ongoing operations:</h2>
9194
${operations}
9295
</div>
9396
</div>
94-
<h2>Mods</h2>
97+
<h2>Installed Mods</h2>
9598
<div class="infiniteList" id="modsList">
9699

97100
</div>
98-
<h2>Libraries</h2>
101+
<h2>Installed Libraries</h2>
99102
<div class="infiniteList" id="libsList">
100103

101104
</div>
102105
</div>
106+
<div class="contentItem hidden" style="padding: 0px;" id="getMods">
107+
<h2>To download mods simply download any mod from one of the following sites</h2>
108+
<div style="display: flex; flex-direction: column;" class="buttonsContainer">
109+
<div class="button labelMargin" onclick="OpenSite(`https://computerelite.github.io/tools/Oculus/QAVSHome.html`)">Open website hub</div>
110+
<div class="button labelMargin" onclick="OpenSite(`https://computerelite.github.io/tools/Beat_Saber/questmods.html`)">Open Beat Saber Mods page</div>
111+
<div class="button labelMargin" onclick="OpenSite(`https://www.google.com/search?q=computerelite`)">Open Google</div>
112+
</div>
113+
114+
</div>
103115

104116
<div class="contentItem" id="backup">
105117
<div class="contentHeader">
@@ -147,9 +159,9 @@ <h2>Libraries</h2>
147159
<div id="backupTextBox" class="textBox"></div>
148160
</div>
149161
</div>
150-
<div class="contentItem hidden" id="downgrade" style="padding: 0px;">
162+
<div class="contentItem hidden" style="padding: 0px;" id="downgrade" style="padding: 0px;">
151163
<b style="font-size: 4em;" id="downgradeLoginMsg">To downgrade you must first log in in the tools & options tab!</b>
152-
<iframe id="downgradeframe" src="" style="width: 100%; height: 100%; border: none; overflow-y: visible;"></iframe>
164+
<iframe id="downgradeframe" src=""></iframe>
153165
</div>
154166
<div class="contentItem hidden" id="download">
155167
<div id="progressBarContainers" style="width: 95%;">
@@ -400,6 +412,8 @@ <h2>Libraries</h2>
400412
</div>
401413
</div>
402414
</div>
415+
416+
<div id="toasts"></div>
403417
<script src="script.js"></script>
404418
</body>
405419
</html>

Assets/html/script.js

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,49 @@ const squareLoader = `
1111
<div class="loaderSquare"></div>
1212
</div>`
1313

14+
const browser = document.getElementById("browser")
15+
const toastsE = document.getElementById("toasts")
1416
document.getElementById("downgradeframe").src = `https://oculusdb.rui2015.me/search?query=Beat+Saber&headsets=MONTEREY%2CHOLLYWOOD${IsOnQuest() ? `&isqavs=true` : ``}`
1517

1618
function IsOnQuest() {
1719
return location.host.startsWith("127.0.0.1")
1820
}
1921

22+
function BrowserGo(direction) {
23+
browser.contentWindow.history.go(direction);
24+
}
25+
26+
function OpenSite(url) {
27+
location = url
28+
}
29+
30+
let toasts = 0;
31+
let currentToasts = 0;
32+
function ShowToast(msg, color, bgc) {
33+
toasts++;
34+
currentToasts++;
35+
let toastId = toasts;
36+
toastsE.innerHTML += `
37+
<div id="toast${toastId}" style="background-color: ${bgc}; color: ${color}; padding: 5px; height: 100px; width: 250px; position: fixed; bottom: ${(currentToasts - 1) * 120 + 20}px; right: 30px; border-radius: 10px">
38+
${msg}
39+
</div>
40+
`;
41+
setTimeout(() => {
42+
document.getElementById(`toast${toastId}`).remove();
43+
currentToasts--;
44+
}, 5000)
45+
}
46+
2047
if(!IsOnQuest()) {
2148
// Is not on quest
2249
document.getElementById("restoreBackup").classList.add("notActive")
2350
document.getElementById("onPcInfo").classList.remove("hidden")
2451
document.getElementById("uninstall").classList.add("notActive")
52+
//document.getElementById("getModsButton").style.display = "none"
53+
54+
} else {
55+
document.getElementById("installModButton").classList.add("notActive")
56+
document.getElementById("installModButton").style.display = "none"
2557
}
2658

2759
document.getElementById("logintoken").onclick = () => {
@@ -429,17 +461,19 @@ document.getElementById("confirmPort").onclick = () => {
429461
document.getElementById("appListContainer").onclick = (event) => {
430462
if (event.target.id == 'appListContainer') UpdateUI(true)
431463
}
464+
setInterval(() => {
465+
Array.prototype.forEach.call(document.getElementsByClassName("menuItem"), i => {
466+
i.onclick = function () {
467+
Array.prototype.forEach.call(document.getElementsByClassName("menuItem"), e => {
468+
e.className = "menuItem" + (e.getAttribute("section") == this.getAttribute("section") ? " selected" : "")
469+
})
470+
Array.prototype.forEach.call(document.getElementsByClassName("contentItem"), e => {
471+
e.className = "contentItem" + (e.id == this.getAttribute("section") ? "" : " hidden")
472+
})
473+
}
474+
})
475+
}, 500)
432476

433-
Array.prototype.forEach.call(document.getElementsByClassName("menuItem"), i => {
434-
i.onclick = function () {
435-
Array.prototype.forEach.call(document.getElementsByClassName("menuItem"), e => {
436-
e.className = "menuItem" + (e.getAttribute("section") == this.getAttribute("section") ? " selected" : "")
437-
})
438-
Array.prototype.forEach.call(document.getElementsByClassName("contentItem"), e => {
439-
e.className = "contentItem" + (e.id == this.getAttribute("section") ? "" : " hidden")
440-
})
441-
}
442-
})
443477

444478
var backupInProgress = false
445479

Assets/html/style.css

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,10 @@ body {
315315
padding: 20px;
316316
}
317317

318+
.noPadding {
319+
padding: 0px !important;
320+
}
321+
318322
.contentHeader {
319323
font-size: 130%;
320324
margin-bottom: 30px;
@@ -425,6 +429,17 @@ body {
425429
margin-left: 20px;
426430
}
427431

432+
iframe {
433+
width: 100%;
434+
height: 100%;
435+
border: none;
436+
overflow-y: visible;
437+
}
438+
439+
.buttonsContainer > div {
440+
margin: 5px;
441+
}
442+
428443
.leftRightSplit {
429444
display: flex;
430445
flex-direction: row;
@@ -437,6 +452,10 @@ body {
437452
flex-direction: column;
438453
}
439454

455+
.navigationMargin {
456+
margin: 5px;
457+
}
458+
440459
.spaceBetween {
441460
justify-content: space-between;
442461
}
@@ -610,6 +629,8 @@ code {
610629
display: flex;
611630
}
612631

632+
633+
613634
.buttonMargin {
614635
margin-left: 20px;
615636
}

CoreService.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public class CoreService
2222
public static QAVSWebserver qAVSWebserver = new QAVSWebserver();
2323
public static CoreVars coreVars = new CoreVars();
2424
public static Version version = Assembly.GetExecutingAssembly().GetName().Version;
25+
public static string ua = "Mozilla/5.0 (X11; Linux x86_64; Quest) AppleWebKit/537.36 (KHTML, like Gecko) OculusBrowser/23.2.0.4.49.401374055 SamsungBrowser/4.0 Chrome/104.0.5112.111 VR Safari/537.36";
2526
public async void Start()
2627
{
2728

@@ -43,11 +44,12 @@ public async void Start()
4344
browser.Focusable = true;
4445
browser.Settings.MediaPlaybackRequiresUserGesture = false;
4546
browser.Settings.DomStorageEnabled = true;
46-
browser.Settings.UserAgentString = "Mozilla/5.0 (X11; Linux x86_64; Quest) AppleWebKit/537.36 (KHTML, like Gecko) OculusBrowser/23.2.0.4.49.401374055 SamsungBrowser/4.0 Chrome/104.0.5112.111 VR Safari/537.36";
47+
browser.Settings.UserAgentString = ua;
4748
browser.Settings.DatabaseEnabled = true;
4849
browser.Settings.DatabasePath = "/data/data/" + browser.Context.PackageName + "/databases/";
4950
browser.Settings.LoadWithOverviewMode = true;
5051
browser.Settings.UseWideViewPort = true;
52+
browser.SetDownloadListener(new DownloadListener());
5153
CookieManager.Instance.SetAcceptThirdPartyCookies(browser, true);
5254

5355
// Create all directories and files

CoreVars.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public class CoreVars // aka config
2424
public readonly string QAVSConfigLocation = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/QuestAppVersionSwitcher/config.json";
2525
public readonly string AndroidAppLocation = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/Android/data/";
2626
public readonly string AndroidObbLocation = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath + "/Android/obb/";
27+
public static string fileDir = "";
2728
public static string oculusLoginUrl = "https://auth.oculus.com/login/?redirect_uri=https%3A%2F%2Fsecure.oculus.com%2F";
2829
public void Save()
2930
{

DownloadListener.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using Android.Webkit;
2+
using Java.Interop;
3+
using Java.Lang;
4+
using QuestAppVersionSwitcher.Core;
5+
using QuestAppVersionSwitcher.Mods;
6+
using System;
7+
using System.IO;
8+
using System.Net;
9+
10+
namespace QuestAppVersionSwitcher
11+
{
12+
public class DownloadListener : Java.Lang.Object, IDownloadListener
13+
{
14+
public void OnDownloadStart(string url, string userAgent, string contentDisposition, string mimetype, long contentLength)
15+
{
16+
CoreService.browser.EvaluateJavascript("ShowToast('Downloading mod', '#FFFFFF', '#222222')", null);
17+
string modPath = CoreService.coreVars.QAVSTmpModsDir + "downloadedmod" + DateTime.Now.Ticks + ".qmod";
18+
DownloadManager m = new DownloadManager();
19+
m.DownloadFinishedEvent += (manager) =>
20+
{
21+
CoreService.browser.EvaluateJavascript("ShowToast('Downloaded, now installing', '#FFFFFF', '#222222')", null);
22+
Thread t = new Thread(() =>
23+
{
24+
QAVSModManager.InstallMod(File.ReadAllBytes(modPath), Path.GetFileName(modPath));
25+
File.Delete(modPath);
26+
});
27+
t.Start();
28+
};
29+
m.StartDownload(url, modPath);
30+
QAVSWebserver.managers.Add(m);
31+
}
32+
}
33+
}

DownloadManager.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,65 @@ public void StartDownload(string binaryid, string password, string version, stri
9393
downloader.DownloadFileAsync(new Uri("https://securecdn.oculus.com/binaries/download/?id=" + binaryid + "&access_token=" + decodedToken), tmpPath);
9494
}
9595

96+
public void StartDownload(string url, string path)
97+
{
98+
WebClient downloader = new WebClient();
99+
downloader.Headers.Add("User-Agent", "QuestAppVersionSwitcher/" + CoreService.version.ToString());
100+
string p = CoreVars.fileDir + DateTime.Now.Ticks;
101+
tmpPath = p;
102+
List<long> lastBytesPerSec = new List<long>();
103+
DateTime lastUpdate = DateTime.Now;
104+
bool locked = false;
105+
long BytesToRecieve = 0;
106+
long lastBytes = 0;
107+
this.name = Path.GetFileName(url);
108+
this.backupName = "";
109+
downloader.DownloadProgressChanged += (o, e) =>
110+
{
111+
if (locked) return;
112+
113+
locked = true;
114+
double secondsPassed = (DateTime.Now - lastUpdate).TotalSeconds;
115+
if (secondsPassed >= 0.5)
116+
{
117+
BytesToRecieve = e.TotalBytesToReceive;
118+
string current = SizeConverter.ByteSizeToString(e.BytesReceived);
119+
string total = SizeConverter.ByteSizeToString(BytesToRecieve);
120+
long bytesPerSec = (long)Math.Round((e.BytesReceived - lastBytes) / secondsPassed);
121+
lastBytesPerSec.Add(bytesPerSec);
122+
if (lastBytesPerSec.Count > 5) lastBytesPerSec.RemoveAt(0);
123+
lastBytes = e.BytesReceived;
124+
long avg = 0;
125+
foreach (long l in lastBytesPerSec) avg += l;
126+
avg = avg / lastBytesPerSec.Count;
127+
this.done = e.BytesReceived;
128+
this.total = BytesToRecieve;
129+
this.speed = bytesPerSec;
130+
this.eTASeconds = (e.TotalBytesToReceive - e.BytesReceived) / avg;
131+
this.doneString = SizeConverter.ByteSizeToString(this.done);
132+
this.totalString = SizeConverter.ByteSizeToString(this.total);
133+
this.speedString = SizeConverter.ByteSizeToString(this.speed, 0) + "/s";
134+
this.eTAString = SizeConverter.SecondsToBetterString(this.eTASeconds);
135+
this.percentage = this.done / (double)this.total;
136+
this.percentageString = String.Format("{0:0.#}", this.percentage * 100) + "%";
137+
lastUpdate = DateTime.Now;
138+
}
139+
locked = false;
140+
};
141+
downloader.DownloadFileCompleted += (o, e) =>
142+
{
143+
if(e.Error != null)
144+
{
145+
Logger.Log(e.Error.ToString(), LoggingType.Warning);
146+
}
147+
File.Move(tmpPath, path);
148+
QAVSWebserver.managers.Remove(this);
149+
DownloadFinishedEvent(this);
150+
};
151+
Logger.Log(tmpPath);
152+
downloader.DownloadFileAsync(new Uri(url), tmpPath);
153+
}
154+
96155
public void SetEmpty(bool alsoSize = true)
97156
{
98157

MainActivity.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
using AndroidX.Core.App;
99
using AndroidX.Core.Content;
1010
using ComputerUtils.Android;
11+
using ComputerUtils.Android.FileManaging;
1112
using ComputerUtils.Android.Logging;
1213
using Google.Android.Material.Snackbar;
1314
using QuestAppVersionSwitcher.Core;
15+
using System.IO;
1416

1517
namespace QuestAppVersionSwitcher
1618
{
@@ -27,6 +29,8 @@ protected override void OnCreate(Bundle savedInstanceState)
2729
SetContentView(Resource.Layout.activity_main);
2830
//Get webView WebView from Main Layout
2931
webView = FindViewById<WebView>(Resource.Id.webView);
32+
CoreVars.fileDir = "/sdcard/Android/data/com.ComputerElite.questappversionswitcher/files/";
33+
FileManager.CreateDirectoryIfNotExisting(CoreVars.fileDir);
3034
CoreService.browser = webView;
3135
AndroidCore.context = this;
3236
AndroidCore.assetManager = this.Assets;

Properties/AndroidManifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.6.6" package="com.ComputerElite.questappversionswitcher" android:installLocation="preferExternal" android:versionCode="26">
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.7.0" package="com.ComputerElite.questappversionswitcher" android:installLocation="preferExternal" android:versionCode="27">
33
<uses-sdk android:minSdkVersion="28" android:targetSdkVersion="29" />
44
<uses-permission android:name="oculus.permission.handtracking" />
55
<uses-permission android:name="com.oculus.permission.HAND_TRACKING" />

Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@
2222
// Minor Version
2323
// Build Number
2424
// Revision
25-
[assembly: AssemblyVersion("1.6.6.0")]
26-
[assembly: AssemblyFileVersion("1.6.6.0")]
25+
[assembly: AssemblyVersion("1.7.0.0")]
26+
[assembly: AssemblyFileVersion("1.7.0.0")]

0 commit comments

Comments
 (0)