Added forum account UI and fixed firefox not working issue
parent
aa2ab6fbd6
commit
8080d426e7
|
@ -3,6 +3,10 @@
|
|||
- Made sounds configurable
|
||||
- Added option to mute sounds when output is muted
|
||||
- Added push to talk delay option
|
||||
- Have improvements related to identity management
|
||||
- First load of the app generates identity
|
||||
- Default VAD is not longer PPT, changed to Voice activity detection via threshold
|
||||
- Added identity improve gui
|
||||
|
||||
* **26.01.19**
|
||||
- Improved TeaSpeak identities (now generates automatic and are saveable)
|
||||
|
|
|
@ -243,10 +243,11 @@
|
|||
}
|
||||
|
||||
if(!$_INCLIDE_ONLY) {
|
||||
$app = getXF();
|
||||
if(!$app) return;
|
||||
|
||||
if (isset($_GET["type"])) {
|
||||
error_log("Got authX request!");
|
||||
var_dump($_GET);
|
||||
var_dump($_POST);
|
||||
if ($_GET["type"] == "login") {
|
||||
die(json_encode(checkLogin($_POST["user"], $_POST["pass"])));
|
||||
} else if ($_GET["type"] == "logout") {
|
||||
|
@ -256,8 +257,12 @@
|
|||
header("Location: login.php");
|
||||
else
|
||||
header("Location: https://web.teaspeak.de/");
|
||||
|
||||
$session = $app->session();
|
||||
setcookie($session->getCookieName(), '', time() - 3600, '/');
|
||||
setcookie("session", '', time() - 3600, '/');
|
||||
setcookie("user_data", '', time() - 3600, '/');
|
||||
setcookie("user_sign", '', time() - 3600, '/');
|
||||
} else die("unknown type!");
|
||||
} else if(isset($_POST["action"])) {
|
||||
error_log("Got auth post request!");
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
.help-tip-container {
|
||||
/* position: relative; */
|
||||
display: inline;
|
||||
|
||||
.help-tip {
|
||||
position: absolute;
|
||||
|
|
|
@ -24,5 +24,7 @@
|
|||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
color: red;
|
||||
}
|
||||
}
|
|
@ -430,6 +430,82 @@
|
|||
}
|
||||
}
|
||||
|
||||
.modal .settings-general {
|
||||
padding: 5px;
|
||||
|
||||
.not-connected {
|
||||
/* display: none; */
|
||||
}
|
||||
|
||||
.connected {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: stretch;
|
||||
|
||||
.connected-info {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.property {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: stretch;
|
||||
|
||||
.key {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
&.premium {
|
||||
.premium {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.non-premium {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.container-info-action {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: stretch;
|
||||
|
||||
.divider {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
width: 2px;
|
||||
|
||||
background: lightgray;
|
||||
}
|
||||
|
||||
.container-info, .container-actions {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
width: 50%;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: stretch;
|
||||
}
|
||||
|
||||
.container-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
||||
button {
|
||||
width: 150px;
|
||||
|
||||
align-self: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal .settings-profiles {
|
||||
margin: 5px;
|
||||
> div:not(:first-of-type) {
|
||||
|
@ -565,5 +641,158 @@
|
|||
}
|
||||
*/
|
||||
}
|
||||
|
||||
&.identity-settings-teamspeak {
|
||||
.property {
|
||||
&:not(:first-of-type) {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: stretch;
|
||||
|
||||
.key {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.value {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&.level {
|
||||
.value {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: stretch;
|
||||
|
||||
button {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.identity-undefined {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.manage {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.container-teamspeak-import {
|
||||
.error {
|
||||
color: red;
|
||||
/* margin-bottom: 5px; */
|
||||
}
|
||||
|
||||
.success {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.input-file {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.load-data {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: stretch;
|
||||
|
||||
.buttons {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: end;
|
||||
|
||||
button:not(:first-of-type) {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 5px;
|
||||
text-align: right;
|
||||
margin-bottom: 5px;
|
||||
|
||||
.button-import {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.container-teamspeak-improve {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.property {
|
||||
&:not(:first-of-type) {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: stretch;
|
||||
|
||||
.key {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
width: 120px;
|
||||
|
||||
.help-tagged {
|
||||
width: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
.value {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 2;
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
.property {
|
||||
margin-top: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.buttons {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
button {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
.help-tip-container {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
|
@ -159,11 +159,14 @@
|
|||
</div>
|
||||
<div class="profile-select-container">
|
||||
<div style="text-align: right;">{{tr "Connection profile:" /}}</div>
|
||||
<select class="profile-select"> </select>
|
||||
<div class="profile-container">
|
||||
<select class="profile-select"> </select>
|
||||
<button class="button-manage-profiles">{{tr "Manage profiles" /}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="profile-invalid">
|
||||
<hr>
|
||||
<div>The selected connect profile is invalid</div>
|
||||
<div>{{tr "The selected connect profile is invalid" /}}</div>
|
||||
<div><div>Click </div><a href="#" class="button-manage-profiles">here</a><div> to manage your connect profiles</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -608,7 +611,44 @@
|
|||
<x-tab>
|
||||
<x-entry>
|
||||
<x-tag>{{tr "General"/}}</x-tag>
|
||||
<x-content>{{tr "Didnt setuped yet!"/}}</x-content>
|
||||
<x-content>
|
||||
<div class="settings-general">
|
||||
<div class="group_box">
|
||||
<div class="header">{{tr "TeaSpeak Forum Connection" /}}</div>
|
||||
<div class="content settings-teaspeak-forum">
|
||||
<div class="not-connected">
|
||||
<div>{{tr "You're currently not connected with your TeaSpeak Forum account" /}}</div>
|
||||
<button class="button-login">{{tr "login" /}}</button>
|
||||
</div>
|
||||
<div class="connected">
|
||||
<div class="connected-info">{{tr "You're connected via TeaSpeak forum" /}}</div>
|
||||
<div class="container-info-action">
|
||||
<div class="container-info">
|
||||
<div class="property username">
|
||||
<div class="key">{{tr "Username:" /}}</div>
|
||||
<div class="value">WolverinDEV</div>
|
||||
</div>
|
||||
<div class="property premium">
|
||||
<div class="key">{{tr "Premium:" /}}</div>
|
||||
<div class="value">YES</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
<div class="container-actions">
|
||||
<button class="button-logout">logout</button>
|
||||
</div>
|
||||
</div>
|
||||
<!--
|
||||
<div class="property synchronized">
|
||||
<div class="key">{{tr "Synchronized:" /}}</div>
|
||||
<div class="value">NO <button class="button-enable-disable-sync">{{tr "enable synchronization" /}}</button></div>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-content>
|
||||
</x-entry>
|
||||
<x-entry>
|
||||
<x-tag>{{tr "Audio" /}}</x-tag>
|
||||
|
@ -845,10 +885,38 @@
|
|||
</div>
|
||||
<hr>
|
||||
<div class="identity-settings identity-settings-teamspeak">
|
||||
{{tr "Please enter your exported TS3 Identity string bellow or select your exported Identity"/}}<br>
|
||||
<div style="width: 100%; display: flex; justify-content: stretch; flex-direction: row">
|
||||
<input placeholder="Identity string" style="min-width: 60%; flex-shrink: 1; flex-grow: 2; margin: 5px;" class="identity_string">
|
||||
<div style="max-width: 200px; flex-grow: 1; flex-shrink: 4; margin: 5px"><input style="display: flex; width: 100%;" class="identity_file" type="file"></div>
|
||||
<!--
|
||||
<div class="import">
|
||||
{{tr "Please enter your exported TS3 Identity string bellow or select your exported Identity"/}}<br>
|
||||
<div style="width: 100%; display: flex; justify-content: stretch; flex-direction: row">
|
||||
<input placeholder="Identity string" style="min-width: 60%; flex-shrink: 1; flex-grow: 2; margin: 5px;" class="identity_string">
|
||||
<div style="max-width: 200px; flex-grow: 1; flex-shrink: 4; margin: 5px"><input style="display: flex; width: 100%;" class="identity_file" type="file"></div>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
<div class="identity-info" style="display: none">
|
||||
<div class="property unique-id">
|
||||
<div class="key">{{tr "UniqueID:" /}}</div>
|
||||
<div class="value">
|
||||
<input type="text" value="xxjnc14LmvTk+Lyrm8OOeo4tOqw=" readonly/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="property level">
|
||||
<div class="key">{{tr "Level:" /}}</div>
|
||||
<div class="value">
|
||||
<input type="text" value="39" readonly/> <button class="button-improve">{{tr "Improve" /}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="identity-undefined">
|
||||
<div>{{tr "You have'nt generated/imported an identity.<br>Generate a new one or import one." /}}</div>
|
||||
</div>
|
||||
<div class="manage">
|
||||
<button class="button-generate">{{tr "Generate new" /}}</button>
|
||||
<div class="export-import">
|
||||
<button class="button-import">{{tr "Import identity" /}}</button>
|
||||
<button class="button-export">{{tr "Export identity" /}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="identity-settings identity-settings-teaforo">
|
||||
|
@ -857,8 +925,9 @@
|
|||
</div>
|
||||
<div class="disconnected">
|
||||
<!-- TODO tr -->
|
||||
You cant use your TeaSpeak forum account. You're not connected!<br>
|
||||
Click {{if !client}}<a href="{{:forum_path}}login.php">here</a>{{else}}<a href="#" class="native-teaforo-login">here</a>{{/if}} to login via the TeaSpeak forum.
|
||||
<!-- <a href="#" class="native-teaforo-login">here</a> -->
|
||||
You cant use your TeaSpeak forum account. You're not connected with your forum Account!<br>
|
||||
Setup your connection <a class="forum-setup" href="#">here</a>.
|
||||
</div>
|
||||
</div>
|
||||
<div class="identity-settings identity-settings-nickname">
|
||||
|
@ -889,6 +958,80 @@
|
|||
</div>
|
||||
</script>
|
||||
|
||||
<script class="jsrender-template" id="tmpl_settings-teamspeak_import" type="text/html">
|
||||
<div class="container-teamspeak-import">
|
||||
<div class="error">{{tr "Failed to import identity (my little error)" /}}</div>
|
||||
<div class="load-data">
|
||||
<div>{{tr "Import an identity from TeamSpeak or an exported identity" /}}</div>
|
||||
<div class="buttons">
|
||||
<button class="button-load-text">{{tr "Load from text" /}}</button>
|
||||
<button class="button-load-file">{{tr "Load from file" /}}</button>
|
||||
<input class="input-file" type="file">
|
||||
</div>
|
||||
</div>
|
||||
<div class="success">
|
||||
{{tr "Identity successfully loaded. Ready to import" /}}
|
||||
</div>
|
||||
<div class="footer">
|
||||
<button class="button-import">{{tr "Import" /}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script class="jsrender-template" id="tmpl_settings-teamspeak_improve" type="text/html">
|
||||
<div class="container-teamspeak-improve">
|
||||
<div class="property identity-unique-id">
|
||||
<div class="key">{{tr "Identity:" /}}</div>
|
||||
<div class="value"><input value="" readonly></div>
|
||||
</div>
|
||||
<div class="property identity-level">
|
||||
<div class="key">{{tr "Current level: " /}}</div>
|
||||
<div class="value"><input value="loading" readonly></div>
|
||||
</div>
|
||||
<div class="property identity-target-level">
|
||||
<div class="key">
|
||||
<div class="help-tagged">{{tr "Target level: " /}}</div>
|
||||
<div class="help-tip-container"> <!-- lets be absolute -->
|
||||
<div class="help-tip tip-right tip-small">
|
||||
<p>
|
||||
{{tr "A value of zero means unlimited. Improve until you abort"/}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="value"><input value="0" type="number" min="0" max="160"></div>
|
||||
</div>
|
||||
<div class="property threads">
|
||||
<div class="key">
|
||||
<div class="help-tagged">{{tr "Threads: " /}}</div>
|
||||
<div class="help-tip-container"> <!-- lets be absolute -->
|
||||
<div class="help-tip tip-right tip-small">
|
||||
<p>
|
||||
{{tr "The number of threads used to improve your identity<br>The optimal value is equal to the amount of kernal threads."/}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="value"><input value="2" type="number" min="1" max="32"></div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="property hash-rate">
|
||||
<div class="key">{{tr "Hashes/second:" /}}</div>
|
||||
<div class="value"><input value="0" readonly></div>
|
||||
</div>
|
||||
<div class="property time-elapsed">
|
||||
<div class="key">{{tr "Elapsed time:" /}}</div>
|
||||
<div class="value"><input value="00:00" readonly></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<button class="button-close">{{tr "Close" /}}</button>
|
||||
<button class="button-start-stop">{{tr "Start" /}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script class="jsrender-template" id="settings-profile-list-entry" type="text/html">
|
||||
<div class="entry profile {{if id == 'default'}}default{{/if}}">
|
||||
<div class="name">{{>profile_name}}</div>
|
||||
|
|
|
@ -216,7 +216,7 @@ function base64ArrayBuffer(arrayBuffer) {
|
|||
return base64
|
||||
}
|
||||
|
||||
function Base64EncodeUrl(str) {
|
||||
function Base64EncodeUrl(str){
|
||||
return str.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '');
|
||||
}
|
||||
|
||||
|
|
|
@ -126,11 +126,29 @@ namespace profiles {
|
|||
}
|
||||
}
|
||||
|
||||
if(!find_profile("default")) { //Create a default profile
|
||||
const profile = create_new_profile("default","default");
|
||||
profile.default_password = "";
|
||||
profile.default_username = "Another TeaSpeak user";
|
||||
profile.profile_name = "Default Profile";
|
||||
if(!find_profile("default")) { //Create a default profile and teaforo profile
|
||||
{
|
||||
const profile = create_new_profile("default","default");
|
||||
profile.default_password = "";
|
||||
profile.default_username = "Another TeaSpeak user";
|
||||
profile.profile_name = "Default Profile";
|
||||
|
||||
/* generate default identity */
|
||||
try {
|
||||
const identity = await identities.TeaSpeakIdentity.generate_new();
|
||||
profile.set_identity(identities.IdentitifyType.TEAMSPEAK, identity);
|
||||
profile.selected_identity_type = identities.IdentitifyType[identities.IdentitifyType.TEAMSPEAK];
|
||||
} catch(error) {
|
||||
createErrorModal(tr("Failed to generate default identity"), tr("Failed to generate default identity!<br>Please manually generate the identity within your settings => profiles")).open();
|
||||
}
|
||||
}
|
||||
|
||||
{ /* forum identity (works only when connected to the forum) */
|
||||
const profile = create_new_profile("TeaSpeak Forum","teaforo");
|
||||
profile.default_password = "";
|
||||
profile.default_username = "Another TeaSpeak user";
|
||||
profile.profile_name = "TeaSpeak Forum profile";
|
||||
}
|
||||
|
||||
save();
|
||||
}
|
||||
|
|
|
@ -40,43 +40,67 @@ namespace profiles.identities {
|
|||
}
|
||||
|
||||
export class TeaForumIdentity implements Identity {
|
||||
private identityData: string;
|
||||
private identityDataJson: string;
|
||||
private identitySign: string;
|
||||
private identity_data: string;
|
||||
private identity_data_raw: string;
|
||||
private identity_data_sign: string;
|
||||
|
||||
valid() : boolean {
|
||||
return this.identityDataJson.length > 0 && this.identityDataJson.length > 0 && this.identitySign.length > 0;
|
||||
return this.identity_data_raw.length > 0 && this.identity_data_raw.length > 0 && this.identity_data_sign.length > 0;
|
||||
}
|
||||
|
||||
constructor(data: string, sign: string) {
|
||||
this.identityDataJson = data;
|
||||
this.identityData = data ? JSON.parse(this.identityDataJson) : undefined;
|
||||
this.identitySign = sign;
|
||||
this.identity_data_raw = data;
|
||||
this.identity_data_sign = sign;
|
||||
try {
|
||||
this.identity_data = data ? JSON.parse(this.identity_data_raw) : undefined;
|
||||
} catch(error) { }
|
||||
}
|
||||
|
||||
data_json() : string { return this.identityDataJson; }
|
||||
data_sign() : string { return this.identitySign; }
|
||||
data_json() : string { return this.identity_data_raw; }
|
||||
data_sign() : string { return this.identity_data_sign; }
|
||||
|
||||
name() : string { return this.identityData["user_name"]; }
|
||||
uid() : string { return "TeaForo#" + this.identityData["user_id"]; }
|
||||
name() : string { return this.identity_data["user_name"]; }
|
||||
uid() : string { return "TeaForo#" + this.identity_data["user_id"]; }
|
||||
type() : IdentitifyType { return IdentitifyType.TEAFORO; }
|
||||
|
||||
forum_user_id() { return this.identity_data["user_id"]; }
|
||||
forum_user_group() { return this.identity_data["user_group_id"]; }
|
||||
is_stuff() : boolean { return this.identity_data["is_staff"]; }
|
||||
is_premium() : boolean { return (<number[]>this.identity_data["user_groups"]).indexOf(5) != -1; }
|
||||
data_age() : Date { return new Date(this.identity_data["data_age"]); }
|
||||
|
||||
/*
|
||||
$user_data["user_id"] = $user->user_id;
|
||||
$user_data["user_name"] = $user->username;
|
||||
$user_data["user_group"] = $user->user_group_id;
|
||||
$user_data["user_groups"] = $user->secondary_group_ids;
|
||||
|
||||
$user_data["trophy_points"] = $user->trophy_points;
|
||||
$user_data["register_date"] = $user->register_date;
|
||||
$user_data["is_staff"] = $user->is_staff;
|
||||
$user_data["is_admin"] = $user->is_admin;
|
||||
$user_data["is_super_admin"] = $user->is_super_admin;
|
||||
$user_data["is_banned"] = $user->is_banned;
|
||||
|
||||
$user_data["data_age"] = milliseconds();
|
||||
*/
|
||||
|
||||
decode(data) : Promise<void> {
|
||||
data = JSON.parse(data);
|
||||
if(data.version !== 1)
|
||||
throw "invalid version";
|
||||
|
||||
this.identityDataJson = data["identity_data"];
|
||||
this.identitySign = data["identity_sign"];
|
||||
this.identityData = JSON.parse(this.identityData);
|
||||
this.identity_data_raw = data["identity_data"];
|
||||
this.identity_data_sign = data["identity_sign"];
|
||||
this.identity_data = JSON.parse(this.identity_data);
|
||||
return;
|
||||
}
|
||||
|
||||
encode?() : string {
|
||||
return JSON.stringify({
|
||||
version: 1,
|
||||
identity_data: this.identityDataJson,
|
||||
identity_sign: this.identitySign
|
||||
identity_data: this.identity_data_raw,
|
||||
identity_sign: this.identity_data_sign
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -580,7 +580,7 @@ namespace profiles.identities {
|
|||
return await this.improve_level(-1, threads, () => active);
|
||||
}
|
||||
|
||||
async improve_level(target: number, threads: number, active_callback: () => boolean) : Promise<Boolean> {
|
||||
async improve_level(target: number, threads: number, active_callback: () => boolean, callback_level?: (current: number) => any) : Promise<Boolean> {
|
||||
if(!this._initialized || !this.public_key)
|
||||
throw "not initialized";
|
||||
if(target == -1) /* get the highest level possible */
|
||||
|
@ -652,6 +652,8 @@ namespace profiles.identities {
|
|||
|
||||
console.log("Found new best at %s (%d). Old was %d", this.hash_number, worker.current_level(), best_level);
|
||||
best_level = worker.current_level();
|
||||
if(callback_level)
|
||||
callback_level(best_level);
|
||||
}
|
||||
|
||||
if(active) {
|
||||
|
|
|
@ -192,7 +192,7 @@ namespace sound {
|
|||
register_sound("message.received", "effects/message_received.wav");
|
||||
register_sound("message.send", "effects/message_send.wav");
|
||||
|
||||
reinitialisize_audio();
|
||||
audio.player.on_ready(reinitialisize_audio);
|
||||
return new Promise<void>(resolve => {
|
||||
$.ajax({
|
||||
url: "audio/speech/mapping.json",
|
||||
|
|
|
@ -89,7 +89,8 @@ if(!$.fn.dividerfy) {
|
|||
apply_view(config.property, config.previous, config.next);
|
||||
}
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
if(!(e instanceof SyntaxError))
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -500,6 +500,17 @@ class MusicInfoManager extends ClientInfoManager {
|
|||
});
|
||||
});
|
||||
_frame.find(".btn-settings").click(() => {
|
||||
this.handle.handle.serverConnection.helper.request_playlist_list().then(lists => {
|
||||
for(const entry of lists) {
|
||||
if(entry.playlist_id == bot.properties.client_playlist_id) {
|
||||
Modals.spawnPlaylistEdit(bot.channelTree.client, entry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
createErrorModal(tr("Invalid permissions"), tr("You don't have to see the bots playlist.")).open();
|
||||
}).catch(error => {
|
||||
createErrorModal(tr("Failed to query playlist."), tr("Failed to query playlist info.")).open();
|
||||
});
|
||||
createErrorModal(tr("Not implemented"), tr("This function is not implemented yet!")).open();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -9,8 +9,196 @@ namespace Modals {
|
|||
import ConnectionProfile = profiles.ConnectionProfile;
|
||||
import IdentitifyType = profiles.identities.IdentitifyType;
|
||||
|
||||
export function spawnSettingsModal() : Modal{
|
||||
let modal;
|
||||
function spawnTeamSpeakIdentityImprove(identity: profiles.identities.TeaSpeakIdentity) : Modal {
|
||||
let modal: Modal;
|
||||
let elapsed_timer: NodeJS.Timer;
|
||||
|
||||
modal = createModal({
|
||||
header: tr("Improve identity"),
|
||||
body: () => {
|
||||
let template = $("#tmpl_settings-teamspeak_improve").renderTag();
|
||||
template = $.spawn("div").append(template);
|
||||
|
||||
let active;
|
||||
const button_start_stop = template.find(".button-start-stop");
|
||||
const button_close = template.find(".button-close");
|
||||
const input_current_level = template.find(".property.identity-level input");
|
||||
const input_target_level = template.find(".property.identity-target-level input");
|
||||
const input_threads = template.find(".property.threads input");
|
||||
const input_hash_rate = template.find(".property.hash-rate input");
|
||||
const input_elapsed = template.find(".property.time-elapsed input");
|
||||
|
||||
button_close.on('click', event => {
|
||||
if(active)
|
||||
button_start_stop.trigger('click');
|
||||
|
||||
if(modal.shown)
|
||||
modal.close();
|
||||
});
|
||||
|
||||
button_start_stop.on('click', event => {
|
||||
if(active)
|
||||
button_start_stop.text(tr("Start"));
|
||||
else
|
||||
button_start_stop.text(tr("Stop"));
|
||||
|
||||
input_threads.prop("disabled", !active);
|
||||
input_target_level.prop("disabled", !active);
|
||||
if(active) {
|
||||
input_hash_rate.val(0);
|
||||
clearInterval(elapsed_timer);
|
||||
active = false;
|
||||
return;
|
||||
}
|
||||
active = true;
|
||||
input_hash_rate.val("nan");
|
||||
|
||||
const threads = parseInt(input_threads.val() as string);
|
||||
const target_level = parseInt(input_target_level.val() as string);
|
||||
if(target_level == 0) {
|
||||
identity.improve_level(-1, threads, () => active, current_level => {
|
||||
input_current_level.val(current_level);
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
createErrorModal(tr("Failed to improve identity"), tr("Failed to improve identity.<br>Error:") + error).open();
|
||||
if(active)
|
||||
button_start_stop.trigger('click');
|
||||
});
|
||||
} else {
|
||||
identity.improve_level(target_level, threads, () => active, current_level => {
|
||||
input_current_level.val(current_level);
|
||||
}).then(success => {
|
||||
if(success) {
|
||||
identity.level().then(level => {
|
||||
input_current_level.val(level);
|
||||
createInfoModal(tr("Identity successfully improved"), MessageHelper.formatMessage(tr("Identity successfully improved to level {}"), level)).open();
|
||||
}).catch(error => {
|
||||
input_current_level.val("error: " + error);
|
||||
});
|
||||
}
|
||||
if(active)
|
||||
button_start_stop.trigger('click');
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
createErrorModal(tr("Failed to improve identity"), tr("Failed to improve identity.<br>Error:") + error).open();
|
||||
if(active)
|
||||
button_start_stop.trigger('click');
|
||||
});
|
||||
}
|
||||
|
||||
const begin = Date.now();
|
||||
elapsed_timer = setInterval(() => {
|
||||
const time = (Date.now() - begin) / 1000;
|
||||
let seconds = Math.floor(time % 60).toString();
|
||||
let minutes = Math.floor(time / 60).toString();
|
||||
|
||||
if(seconds.length < 2)
|
||||
seconds = "0" + seconds;
|
||||
|
||||
if(minutes.length < 2)
|
||||
minutes = "0" + minutes;
|
||||
|
||||
input_elapsed.val(minutes + ":" + seconds);
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
|
||||
template.find(".property.identity-unique-id input").val(identity.uid());
|
||||
identity.level().then(level => {
|
||||
input_current_level.val(level);
|
||||
}).catch(error => {
|
||||
input_current_level.val("error: " + error);
|
||||
});
|
||||
return template;
|
||||
},
|
||||
footer: undefined,
|
||||
width: 750
|
||||
});
|
||||
modal.close_listener.push(() => modal.htmlTag.find(".button-close").trigger('click'));
|
||||
modal.open();
|
||||
return modal;
|
||||
}
|
||||
|
||||
function spawnTeamSpeakIdentityImport(callback: (identity: profiles.identities.TeaSpeakIdentity) => any) : Modal {
|
||||
let modal: Modal;
|
||||
let loaded_identity: profiles.identities.TeaSpeakIdentity;
|
||||
|
||||
modal = createModal({
|
||||
header: tr("Import identity"),
|
||||
body: () => {
|
||||
let template = $("#tmpl_settings-teamspeak_import").renderTag();
|
||||
template = $.spawn("div").append(template);
|
||||
|
||||
template.find(".button-load-file").on('click', event => template.find(".input-file").trigger('click'));
|
||||
|
||||
const button_import = template.find(".button-import");
|
||||
const set_error = message => {
|
||||
template.find(".success").hide();
|
||||
if(message) {
|
||||
template.find(".error").text(message).show();
|
||||
button_import.prop("disabled", true);
|
||||
} else
|
||||
template.find(".error").hide();
|
||||
};
|
||||
|
||||
const import_identity = (data: string, ini: boolean) => {
|
||||
profiles.identities.TeaSpeakIdentity.import_ts(data, ini).then(identity => {
|
||||
loaded_identity = identity;
|
||||
set_error("");
|
||||
button_import.prop("disabled", false);
|
||||
template.find(".success").show();
|
||||
}).catch(error => {
|
||||
set_error("Failed to load identity: " + error);
|
||||
});
|
||||
};
|
||||
|
||||
{ /* file select button */
|
||||
template.find(".input-file").on('change', event => {
|
||||
const element = event.target as HTMLInputElement;
|
||||
const file_reader = new FileReader();
|
||||
|
||||
file_reader.onload = function() {
|
||||
import_identity(file_reader.result as string, true);
|
||||
};
|
||||
|
||||
file_reader.onerror = ev => {
|
||||
console.error(tr("Failed to read give identity file: %o"), ev);
|
||||
set_error(tr("Failed to read file!"));
|
||||
return;
|
||||
};
|
||||
|
||||
if(element.files && element.files.length > 0)
|
||||
file_reader.readAsText(element.files[0]);
|
||||
});
|
||||
}
|
||||
|
||||
{ /* text input */
|
||||
template.find(".button-load-text").on('click', event => {
|
||||
createInputModal("Import identity from text", "Please paste your idenity bellow<br>", text => text.length > 0 && text.indexOf('V') != -1, result => {
|
||||
if(result)
|
||||
import_identity(result as string, false);
|
||||
}).open();
|
||||
});
|
||||
}
|
||||
|
||||
button_import.on('click', event => {
|
||||
modal.close();
|
||||
callback(loaded_identity);
|
||||
});
|
||||
|
||||
set_error("");
|
||||
button_import.prop("disabled", true);
|
||||
return template;
|
||||
},
|
||||
footer: undefined,
|
||||
width: 750
|
||||
});
|
||||
modal.open();
|
||||
return modal;
|
||||
}
|
||||
|
||||
export function spawnSettingsModal() : Modal {
|
||||
let modal: Modal;
|
||||
modal = createModal({
|
||||
header: tr("Settings"),
|
||||
body: () => {
|
||||
|
@ -21,9 +209,10 @@ namespace Modals {
|
|||
});
|
||||
|
||||
template = $.spawn("div").append(template);
|
||||
initialiseSettingListeners(modal,template = template.tabify());
|
||||
initialiseVoiceListeners(modal, (template = template.tabify()).find(".settings_audio"));
|
||||
initialise_translations(template.find(".settings-translations"));
|
||||
initialise_profiles(modal, template.find(".settings-profiles"));
|
||||
initialise_global(modal, template.find(".settings-general"));
|
||||
|
||||
return template;
|
||||
},
|
||||
|
@ -47,13 +236,33 @@ namespace Modals {
|
|||
return modal;
|
||||
}
|
||||
|
||||
function initialiseSettingListeners(modal: Modal, tag: JQuery) {
|
||||
//Voice
|
||||
initialiseVoiceListeners(modal, tag.find(".settings_audio"));
|
||||
function initialise_global(modal: Modal, tag: JQuery) {
|
||||
console.log(tag);
|
||||
{/* setup the forum */
|
||||
const identity = profiles.identities.static_forum_identity();
|
||||
if(identity && identity.valid()) {
|
||||
tag.find(".not-connected").hide();
|
||||
|
||||
tag.find(".property.username .value").text(identity.name());
|
||||
const premium_tag = tag.find(".property.premium .value").text("");
|
||||
if(identity.is_stuff() || identity.is_premium())
|
||||
premium_tag.append($.spawn("div").addClass("premium").text(tr("yes")));
|
||||
else
|
||||
premium_tag.append($.spawn("div").addClass("non-premium").text(tr("no")));
|
||||
} else {
|
||||
tag.find(".connected").hide();
|
||||
}
|
||||
tag.find(".button-logout").on('click', event => {
|
||||
window.location.href = settings.static("forum_path") + "auth.php?type=logout";
|
||||
});
|
||||
tag.find(".button-login").on('click', event => {
|
||||
window.location.href = settings.static("forum_path") + "login.php";
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function initialiseVoiceListeners(modal: Modal, tag: JQuery) {
|
||||
let currentVAD = settings.global("vad_type", "ppt");
|
||||
let currentVAD = settings.global("vad_type", "vad");
|
||||
|
||||
{ //Initialized voice activation detection
|
||||
const vad_tag = tag.find(".settings-vad-container");
|
||||
|
@ -658,64 +867,98 @@ namespace Modals {
|
|||
{
|
||||
{ //TeamSpeak change listener
|
||||
const teamspeak_tag = settings_tag.find(".identity-settings-teamspeak");
|
||||
teamspeak_tag.find(".identity_file").on('change', event => {
|
||||
if(!selected_profile) return;
|
||||
const identity_info_tag = teamspeak_tag.find(".identity-info");
|
||||
const button_export = teamspeak_tag.find(".button-export");
|
||||
const button_import = teamspeak_tag.find(".button-import");
|
||||
const button_generate = teamspeak_tag.find(".button-generate");
|
||||
const button_improve = teamspeak_tag.find(".button-improve");
|
||||
|
||||
const element = event.target as HTMLInputElement;
|
||||
const file_reader = new FileReader();
|
||||
file_reader.onload = function() {
|
||||
const identity_promise = profiles.identities.TeaSpeakIdentity.import_ts(file_reader.result as string, true);
|
||||
identity_promise.then(identity => {
|
||||
(identity as profiles.identities.TeaSpeakIdentity).export_ts().then(e => teamspeak_tag.find(".identity_string").val(e));
|
||||
selected_profile.set_identity(IdentitifyType.TEAMSPEAK, identity as any);
|
||||
profiles.mark_need_save();
|
||||
display_error(undefined);
|
||||
button_import.on('click', event => {
|
||||
const profile = selected_profile.selected_identity(IdentitifyType.TEAMSPEAK) as profiles.identities.TeaSpeakIdentity;
|
||||
|
||||
const set_identity = (identity: profiles.identities.TeaSpeakIdentity) => {
|
||||
selected_profile.set_identity(IdentitifyType.TEAMSPEAK, identity);
|
||||
teamspeak_tag.trigger('show');
|
||||
createInfoModal(tr("Identity imported"), tr("Your identity has been successfully imported!")).open();
|
||||
};
|
||||
|
||||
if(profile && profile.valid()) {
|
||||
spawnYesNo(tr("Are you sure"), tr("Do you really want to import a new identity and override the old identity?"), result => {
|
||||
if(result)
|
||||
spawnTeamSpeakIdentityImport(set_identity);
|
||||
});
|
||||
} else
|
||||
spawnTeamSpeakIdentityImport(set_identity);
|
||||
});
|
||||
button_export.on('click', event => {
|
||||
const profile = selected_profile.selected_identity(IdentitifyType.TEAMSPEAK) as profiles.identities.TeaSpeakIdentity;
|
||||
if(!profile) return;
|
||||
|
||||
createInputModal(tr("File name"), tr("Please enter the file name"), text => !!text, name => {
|
||||
if(name) {
|
||||
profile.export_ts(true).then(data => {
|
||||
const element = $.spawn("a")
|
||||
.text("donwload")
|
||||
.attr("href", "data:test/plain;charset=utf-8," + encodeURIComponent(data))
|
||||
.attr("download", name + ".ini")
|
||||
.css("display", "none")
|
||||
.appendTo($("body"));
|
||||
element[0].click();
|
||||
element.detach();
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
createErrorModal(tr("Failed to export identity"), tr("Failed to export and save identity.<br>Error: ") + error).open();
|
||||
});
|
||||
}
|
||||
}).open();
|
||||
});
|
||||
|
||||
button_generate.on('click', event => {
|
||||
const profile = selected_profile.selected_identity(IdentitifyType.TEAMSPEAK) as profiles.identities.TeaSpeakIdentity;
|
||||
const generate_identity = () => {
|
||||
profiles.identities.TeaSpeakIdentity.generate_new().then(identity => {
|
||||
selected_profile.set_identity(IdentitifyType.TEAMSPEAK, identity);
|
||||
teamspeak_tag.trigger('show');
|
||||
createInfoModal(tr("Identity generate"), tr("A new identity had been successfully generated")).open();
|
||||
}).catch(error => {
|
||||
display_error(tr("Failed to parse identity.<br>Reason: ") + error);
|
||||
return;
|
||||
createErrorModal(tr("Failed to generate identity"), tr("Failed to generate a new identity.<br>Error:") + error).open();
|
||||
});
|
||||
};
|
||||
|
||||
file_reader.onerror = ev => {
|
||||
console.error(tr("Failed to read give identity file: %o"), ev);
|
||||
display_error(tr("Failed to read file!"));
|
||||
return;
|
||||
};
|
||||
|
||||
if(element.files && element.files.length > 0)
|
||||
file_reader.readAsText(element.files[0]);
|
||||
});
|
||||
|
||||
teamspeak_tag.find(".identity_string").on('change', event => {
|
||||
if(!selected_profile) return;
|
||||
|
||||
const element = event.target as HTMLInputElement;
|
||||
if(element.value.length == 0) {
|
||||
display_error("Please provide an identity");
|
||||
selected_profile.set_identity(IdentitifyType.TEAMSPEAK, undefined as any);
|
||||
profiles.mark_need_save();
|
||||
} else {
|
||||
const identity_promise = profiles.identities.TeaSpeakIdentity.import_ts(element.value, false);
|
||||
identity_promise.then(identity => {
|
||||
(identity as profiles.identities.TeaSpeakIdentity).export_ts().then(e => teamspeak_tag.find(".identity_string").val(e));
|
||||
selected_profile.set_identity(IdentitifyType.TEAMSPEAK, identity as any);
|
||||
profiles.mark_need_save();
|
||||
display_error(undefined);
|
||||
}).catch(error => {
|
||||
display_error(tr("Failed to parse identity.<br>Reason: ") + error);
|
||||
return;
|
||||
if(profile && profile.valid()) {
|
||||
spawnYesNo(tr("Are you sure"), tr("Do you really want to generate a new identity and override the old identity?"), result => {
|
||||
if(result)
|
||||
generate_identity();
|
||||
});
|
||||
}
|
||||
} else
|
||||
generate_identity();
|
||||
});
|
||||
|
||||
button_improve.on('click', event => {
|
||||
const profile = selected_profile.selected_identity(IdentitifyType.TEAMSPEAK) as profiles.identities.TeaSpeakIdentity;
|
||||
if(!profile) return;
|
||||
|
||||
spawnTeamSpeakIdentityImprove(profile).close_listener.push(() => teamspeak_tag.trigger('show'));
|
||||
});
|
||||
|
||||
/* updates the data */
|
||||
teamspeak_tag.on('show', event => {
|
||||
const profile = selected_profile.selected_identity(IdentitifyType.TEAMSPEAK);
|
||||
if(!profile)
|
||||
display_error("invalid profile");
|
||||
else if(!profile.valid())
|
||||
display_error("profile isn't valid");
|
||||
else
|
||||
display_error();
|
||||
const profile = selected_profile.selected_identity(IdentitifyType.TEAMSPEAK) as profiles.identities.TeaSpeakIdentity;
|
||||
|
||||
if(!profile || !profile.valid()) {
|
||||
identity_info_tag.hide();
|
||||
teamspeak_tag.find(".identity-undefined").show();
|
||||
button_export.prop("disabled", true);
|
||||
} else {
|
||||
identity_info_tag.show();
|
||||
teamspeak_tag.find(".identity-undefined").hide();
|
||||
button_export.prop("disabled", false);
|
||||
|
||||
identity_info_tag.find(".property.unique-id input").val(profile.uid());
|
||||
const input_level = identity_info_tag.find(".property.level input").val("loading...");
|
||||
profile.level().then(level => input_level.val(level.toString())).catch(error => input_level.val("error: " + error));
|
||||
}
|
||||
display_error();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 7fe6a479984b77160a9135f9d2182fb79ca56023
|
||||
Subproject commit 0c9d48b2e1d37ddefa6bafb3e2d0c7d04ad4dac6
|
|
@ -54,7 +54,10 @@ namespace audio.player {
|
|||
}
|
||||
|
||||
export function destination() : AudioNode {
|
||||
return context().destination;
|
||||
const ctx = context();
|
||||
if(!ctx) throw tr("Audio player isn't initialized yet!");
|
||||
|
||||
return ctx.destination;
|
||||
}
|
||||
|
||||
export function on_ready(cb: () => any) {
|
||||
|
|
Loading…
Reference in New Issue