Files
t5de/patches/0025-Sign-in-to-T5DE-s-hub-from-Settings.patch
T
dhkatzandClaude Opus 5.5 1a2c85126e Sign in to T5DE's hub from Settings
Settings > T5DE gets a T5DE Hub section to sign in (showing the code and opening the hub's page) or out,
through T5DE's proxy, which keeps the sign-in.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 19:25:49 -07:00

162 lines
6.9 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: dhkatz <[email protected]>
Date: Thu, 29 Oct 2026 19:20:16 -0700
Subject: [PATCH] Sign in to T5DE's hub from Settings
Settings > T5DE gets a T5DE Hub section: sign in (it shows a code and opens the hub's page for it in the
browser) or out, and who's signed in. T5DE's proxy keeps the sign-in and answers the page at
http://t5de-proxy.local/; signing in or out takes effect at once.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
T5de-Id: t5de-hub
T5de-Name: T5DE Hub
T5de-Group: general
T5de-Depends: t5de-proxy, t5de-renderer
---
imvuContent/settings/index.html | 12 ++++++++
imvuContent/settings/style.css | 9 ++++++
imvuContent/settings/t5de-hub.js | 47 +++++++++++++++++++++++++++++++
library/imvu/mode/SettingsMode.py | 20 +++++++++++++
4 files changed, 88 insertions(+)
create mode 100644 imvuContent/settings/t5de-hub.js
diff --git a/imvuContent/settings/index.html b/imvuContent/settings/index.html
index 72afd50a1c2ac86ced5d3df19db690df0e82bad4..045ac3e815fcc62e987b119003f7009d7c680ed0 100644
--- a/imvuContent/settings/index.html
+++ b/imvuContent/settings/index.html
@@ -29,6 +29,7 @@
<script src="BlockActionSettings.js"></script>
<script src="t5de.js"></script>
<script src="t5de-graphics.js"></script>
+ <script src="t5de-hub.js"></script>
<script src="../widgets/button/imvuButton.js"></script>
</head><body class="yui-skin-sam">
@@ -121,6 +122,16 @@
</div>
</div>
<div class="page" imvu:page="t5de" id="t5de-page">
+ <div class="subsection" id="t5de-hub">
+ <h1>T5DE Hub</h1>
+ <div id="t5de-hub-status">&nbsp;</div>
+ <div id="t5de-hub-code" class="hidden"></div>
+ <div class="t5de-hub-buttons">
+ <button id="t5de-hub-signin">Sign In</button>
+ <button id="t5de-hub-signout" class="hidden">Sign Out</button>
+ </div>
+ <div class="info t5de-info">Your T5DE account: community products, your library, and who's online.</div>
+ </div>
<div class="subsection" id="t5de-graphics">
<h1>Graphics</h1>
<div><span class="choice_desc">Frame Rate</span>
@@ -249,6 +260,7 @@
var tb = new ToolBar(imvu.call);
t5deSettings(imvu);
t5deGraphicsSettings(imvu);
+ t5deHubSettings(imvu);
}
</script>
</body></html>
\ No newline at end of file
diff --git a/imvuContent/settings/style.css b/imvuContent/settings/style.css
index 76187e882716ca5bcccf71952ba8657a739495c0..c846b5ef0772ff8b8fb5e1643bc45b55285bb984 100644
--- a/imvuContent/settings/style.css
+++ b/imvuContent/settings/style.css
@@ -480,3 +480,12 @@ ul li {
.t5de-info {
margin-top: 10px;
}
+#t5de-hub-code {
+ margin-top: 6px;
+ font-size: 16px;
+ font-weight: bold;
+ letter-spacing: 2px;
+}
+.t5de-hub-buttons {
+ margin-top: 8px;
+}
diff --git a/imvuContent/settings/t5de-hub.js b/imvuContent/settings/t5de-hub.js
new file mode 100644
index 0000000000000000000000000000000000000000..2cb97c2d76e8429a3cd36372a34e28324a731137
--- /dev/null
+++ b/imvuContent/settings/t5de-hub.js
@@ -0,0 +1,47 @@
+// Signing in to T5DE's hub (the T5DE Hub patch), through T5DE's proxy, which keeps the sign-in
+// (SettingsMode.py: handle_t5deHub). Signing in opens the hub's page in the browser for the code shown here.
+function t5deHubSettings(imvu) {
+ var status = document.getElementById('t5de-hub-status');
+ var code = document.getElementById('t5de-hub-code');
+ var signin = document.getElementById('t5de-hub-signin');
+ var signout = document.getElementById('t5de-hub-signout');
+ var timer = null;
+
+ function call(action) {
+ try {
+ return JSON.parse(imvu.call('t5deHub', action));
+ } catch (e) {
+ return {error: 'proxy'};
+ }
+ }
+
+ function show(s) {
+ $(code).addClass('hidden');
+ $(signin).toggleClass('hidden', !!s.signedIn);
+ $(signout).toggleClass('hidden', !s.signedIn);
+ if (s.error === 'proxy') {
+ status.textContent = "T5DE's proxy isn't running.";
+ $(signin).addClass('hidden');
+ } else if (s.signedIn) {
+ status.textContent = s.username ? 'Signed in as ' + s.username + '.' : 'Signed in.';
+ } else if (s.signingIn) {
+ status.textContent = s.code ? 'Enter this code on the page that opened:' : 'Getting a code...';
+ if (s.code) {
+ code.textContent = s.code.slice(0, 4) + '-' + s.code.slice(4);
+ $(code).removeClass('hidden');
+ }
+ } else if (s.error) {
+ status.textContent = "Couldn't sign in: " + s.error;
+ } else {
+ status.textContent = 'Not signed in.';
+ }
+ clearTimeout(timer);
+ if (s.signingIn || (s.signedIn && !s.username)) {
+ timer = setTimeout(function () { show(call('status')); }, 1500);
+ }
+ }
+
+ signin.addEventListener('click', function () { show(call('signin')); }, false);
+ signout.addEventListener('click', function () { show(call('signout')); }, false);
+ show(call('status'));
+}
diff --git a/library/imvu/mode/SettingsMode.py b/library/imvu/mode/SettingsMode.py
index 69a1ca1d6ca6ca2818c3d96cdd11c63939243c9f..27ef0499f542c9f7e558d94fcc82b34fdb98f185 100644
--- a/library/imvu/mode/SettingsMode.py
+++ b/library/imvu/mode/SettingsMode.py
@@ -65,6 +65,26 @@ class SettingsGeckoListener(object):
_winreg.SetValueEx(key, 'FrameRate', 0, _winreg.REG_DWORD, int(rate))
finally:
key.Close()
+
+ def handle_t5deHub(self, context, action):
+ """T5DE's hub sign-in, kept by T5DE's proxy, which answers at http://t5de-proxy.local/: action 'status',
+ 'signin' or 'signout'. The proxy's answer as JSON text, or {"error": "proxy"} if it isn't running."""
+ import httplib, json
+ from main.client import t5deProxy, t5deProxyAuthorization
+ proxy = t5deProxy()
+ if proxy is None:
+ return json.dumps({'error': 'proxy'})
+ host, port, token = proxy
+ method, path = {'status': ('GET', '/hub'), 'signin': ('POST', '/hub/signin'), 'signout': ('POST', '/hub/signout')}[action]
+ conn = httplib.HTTPConnection(host, port, timeout=10)
+ try:
+ conn.request(method, 'http://t5de-proxy.local' + path, '', {'Proxy-Authorization': t5deProxyAuthorization(token)})
+ response = conn.getresponse()
+ return response.read() if response.status == 200 else json.dumps({'error': 'proxy'})
+ except Exception:
+ return json.dumps({'error': 'proxy'})
+ finally:
+ conn.close()
def handle_registerSettingsListeners(self, context, prefList):
for pref in prefList:
self.__serviceProvider.eventBus.register(self.__serviceProvider.prefService, 'PrefChanged-%s' % (pref,), self.__prefListener)