A lots of updates :)
parent
bbbd8f6365
commit
89a29a8717
|
@ -2,6 +2,15 @@
|
|||
* **03.11.18**
|
||||
- Reworked on the basic overlay sizes
|
||||
- Added hostbanner to the UI
|
||||
- Implemented sounds
|
||||
- Implemented poke notification
|
||||
- Added local volume change to music bots
|
||||
- Added move and channel kick to the music bot context menu options
|
||||
- Reworked private chat format
|
||||
- Added several server chat messages
|
||||
- Fixed client double click chat opening
|
||||
- Implemented client drag and drop
|
||||
- Fixed channel select within sub channels
|
||||
|
||||
* **28.10.18**
|
||||
- Restructured the project
|
||||
|
|
16
files.php
16
files.php
|
@ -35,6 +35,22 @@
|
|||
"path" => "css/",
|
||||
"local-path" => "./shared/css/"
|
||||
],
|
||||
[ /* shared sound files */
|
||||
"type" => "wav",
|
||||
"search-pattern" => "/.*\.wav$/",
|
||||
"build-target" => "dev|rel",
|
||||
|
||||
"path" => "audio/",
|
||||
"local-path" => "./shared/audio/"
|
||||
],
|
||||
[ /* shared data sound files */
|
||||
"type" => "json",
|
||||
"search-pattern" => "/.*\.json/",
|
||||
"build-target" => "dev|rel",
|
||||
|
||||
"path" => "audio/",
|
||||
"local-path" => "./shared/audio/"
|
||||
],
|
||||
[ /* shared image files */
|
||||
"type" => "img",
|
||||
"search-pattern" => "/.*\.(svg|png)/",
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
[{"file": "sound.test.wav", "key": "sound.test"}, {"file": "sound.egg.wav", "key": "sound.egg"}, {"file": "away_activated.wav", "key": "away_activated"}, {"file": "away_deactivated.wav", "key": "away_deactivated"}, {"file": "connection.connected.wav", "key": "connection.connected"}, {"file": "connection.disconnected.wav", "key": "connection.disconnected"}, {"file": "connection.disconnected.timeout.wav", "key": "connection.disconnected.timeout"}, {"file": "connection.refused.wav", "key": "connection.refused"}, {"file": "connection.banned.wav", "key": "connection.banned"}, {"file": "server.edited.wav", "key": "server.edited"}, {"file": "server.edited.self.wav", "key": "server.edited.self"}, {"file": "server.kicked.wav", "key": "server.kicked"}, {"file": "channel.kicked.wav", "key": "channel.kicked"}, {"file": "channel.moved.wav", "key": "channel.moved"}, {"file": "channel.joined.wav", "key": "channel.joined"}, {"file": "channel.created.wav", "key": "channel.created"}, {"file": "channel.edited.wav", "key": "channel.edited"}, {"file": "channel.edited.self.wav", "key": "channel.edited.self"}, {"file": "channel.deleted.wav", "key": "channel.deleted"}, {"file": "user.moved.wav", "key": "user.moved"}, {"file": "user.moved.self.wav", "key": "user.moved.self"}, {"file": "user.poked.self.wav", "key": "user.poked.self"}, {"file": "user.banned.wav", "key": "user.banned"}, {"file": "user.joined.wav", "key": "user.joined"}, {"file": "user.joined.moved.wav", "key": "user.joined.moved"}, {"file": "user.joined.kicked.wav", "key": "user.joined.kicked"}, {"file": "user.joined.connect.wav", "key": "user.joined.connect"}, {"file": "user.left.wav", "key": "user.left"}, {"file": "user.left.kicked.channel.wav", "key": "user.left.kicked.channel"}, {"file": "user.left.kicked.server.wav", "key": "user.left.kicked.server"}, {"file": "user.left.moved.wav", "key": "user.left.moved"}, {"file": "user.left.disconnect.wav", "key": "user.left.disconnect"}, {"file": "user.left.banned.wav", "key": "user.left.banned"}, {"file": "error.insufficient_permissions.wav", "key": "error.insufficient_permissions"}]
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,49 @@
|
|||
#Sound test
|
||||
sound.test;This is a test sound
|
||||
sound.egg;WolverinDEV is the best and I love TeaSpeak!
|
||||
|
||||
#Away
|
||||
away_activated;See you soon
|
||||
away_deactivated;Welcome back
|
||||
|
||||
#Connection
|
||||
connection.connected;Connected
|
||||
connection.disconnected;Disconnected
|
||||
connection.disconnected.timeout;Connection to server lost
|
||||
connection.refused;Connect failed
|
||||
connection.banned;You got banned from this server
|
||||
|
||||
#Server
|
||||
server.edited;Server edited
|
||||
server.edited.self;You edited the server
|
||||
server.kicked;You got kicked from the server
|
||||
|
||||
#Channel activity
|
||||
channel.kicked;You got kicked from the channel
|
||||
channel.moved;Channel moved
|
||||
channel.joined;Channel joined
|
||||
channel.created;Channel created
|
||||
channel.edited;Channel edited
|
||||
channel.edited.self;You edited the channel
|
||||
channel.deleted;Channel deleted
|
||||
|
||||
#User action
|
||||
user.moved;User moved
|
||||
user.moved.self;You have been moved
|
||||
user.poked.self;Hey wakeup!
|
||||
user.banned;User banned
|
||||
|
||||
user.joined;User joined your channel
|
||||
user.joined.moved;User got moved to your channel
|
||||
user.joined.kicked;User got kicked to your channel
|
||||
user.joined.connect;User connected to your channel
|
||||
|
||||
user.left;User left your channel
|
||||
user.left.kicked.channel;User in your channel got kicked from the channel
|
||||
user.left.kicked.server;User in your channel got kicked from the server
|
||||
user.left.moved;User was moved out of your channel
|
||||
user.left.disconnect;User disconnected from your channel
|
||||
user.left.banned;User in your channel was banned from the server
|
||||
|
||||
#Error
|
||||
error.insufficient_permissions;insufficient permissions
|
|
|
@ -13,6 +13,7 @@
|
|||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
flex-grow: 1;
|
||||
|
||||
.button-update {
|
||||
width: 100%;
|
||||
|
@ -80,13 +81,14 @@
|
|||
.container-select-info {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: stretch;
|
||||
|
||||
> div {
|
||||
flex-grow: 1;
|
||||
.select_server {
|
||||
> div {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -277,6 +277,7 @@ footer .container {
|
|||
}
|
||||
|
||||
min-width: 100px;
|
||||
max-width: 60%; /* tmp chat fix */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
|
@ -315,3 +316,24 @@ footer .container {
|
|||
border-radius: 0 0 2px 0;
|
||||
}
|
||||
}
|
||||
|
||||
#mouse-move {
|
||||
display: none;
|
||||
position: absolute;
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
display: block;
|
||||
|
||||
border: 2px solid gray;
|
||||
-webkit-border-radius: 2px;
|
||||
-moz-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
html, body {
|
||||
min-height: 500px;
|
||||
min-width: 500px;
|
||||
overflow: hidden;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
.container-poke {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.container-information {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.container-message {
|
||||
text-align: center;
|
||||
|
||||
.message {
|
||||
color: green;
|
||||
}
|
||||
}
|
||||
|
||||
.button-close {
|
||||
margin-top: 5px;
|
||||
width: 150px;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
<script class="jsrender-template" id="tmpl_poke_popup" type="text/html">
|
||||
<div class="container-poke">
|
||||
<div class="container-information">
|
||||
<a>You have been poked by </a><node key="invoker"></node><a>:</a>
|
||||
</div>
|
||||
<div class="container-message">
|
||||
<a class="message">{{>message}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
*/
|
|
@ -122,6 +122,10 @@
|
|||
flex-direction: row;
|
||||
top: 0px;
|
||||
left: 16px;
|
||||
|
||||
&.move-selected {
|
||||
border: 1px black solid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
"""
|
||||
This should be executed as python 2.7 (because of pydub)
|
||||
"""
|
||||
import os
|
||||
import requests
|
||||
import json
|
||||
import csv
|
||||
import shutil
|
||||
from pydub import AudioSegment
|
||||
|
||||
TARGET_DIRECTORY = "audio/speech"
|
||||
SOURCE_FILE = "audio/speech_sentences.csv"
|
||||
|
||||
|
||||
def tts(text, file):
|
||||
voice_id = 4
|
||||
language_id = 1
|
||||
req = requests.post(
|
||||
'https://kfiuqykx63.execute-api.us-east-1.amazonaws.com/Dev/tts?r={}&s={}&l=0&v=aca'.format(voice_id,
|
||||
language_id),
|
||||
stream=True,
|
||||
headers={
|
||||
'origin': 'https://www.naturalreaders.com',
|
||||
'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) '
|
||||
'Chrome/69.0.3497.100 Safari/537.36 OPR/56.0.3051.52',
|
||||
'content-type': 'application/x-www-form-urlencoded',
|
||||
'referer': 'https://www.naturalreaders.com/online/',
|
||||
'authority': 'kfiuqykx63.execute-api.us-east-1.amazonaws.com'
|
||||
},
|
||||
data=json.dumps({"t": text})
|
||||
)
|
||||
|
||||
if req.status_code != 200:
|
||||
raise ValueError("Invalid response code {}".format(req.status_code))
|
||||
|
||||
with open(file + ".mp3", "wb") as fstream:
|
||||
for chunk in req.iter_content(chunk_size=128):
|
||||
fstream.write(chunk)
|
||||
fstream.close()
|
||||
|
||||
sound = AudioSegment.from_mp3(file + ".mp3")
|
||||
sound.export(file, format="wav")
|
||||
|
||||
os.remove(file + ".mp3")
|
||||
|
||||
def main():
|
||||
if os.path.exists(TARGET_DIRECTORY):
|
||||
print("Deleting old speach directory (%s)!" % TARGET_DIRECTORY)
|
||||
try:
|
||||
shutil.rmtree(TARGET_DIRECTORY)
|
||||
except e:
|
||||
print("Cant delete old dir!")
|
||||
os.makedirs(TARGET_DIRECTORY)
|
||||
|
||||
mapping = []
|
||||
with open(SOURCE_FILE, 'r') as input:
|
||||
reader = csv.reader(filter(lambda row: len(row) != 0 and row[0] != '#', input), delimiter=';', quotechar='#')
|
||||
for row in reader:
|
||||
if len(row) != 2:
|
||||
continue
|
||||
print("Generating speech for {}: {}".format(row[0], row[1]))
|
||||
try:
|
||||
file = "{}.wav".format(row[0])
|
||||
tts(row[1], TARGET_DIRECTORY + "/" + file)
|
||||
|
||||
mapping.append({'key': row[0], 'file': file})
|
||||
except e:
|
||||
print(e)
|
||||
print("Failed to generate {}", row[0])
|
||||
|
||||
with open("audio/speech/mapping.json", "w") as fstream:
|
||||
fstream.write(json.dumps(mapping))
|
||||
fstream.close()
|
||||
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -53,6 +53,7 @@
|
|||
<link rel="stylesheet" href="css/modal-banlist.css" type="text/css">
|
||||
<link rel="stylesheet" href="css/modal-bancreate.css" type="text/css">
|
||||
<link rel="stylesheet" href="css/modal-settings.css" type="text/css">
|
||||
<link rel="stylesheet" href="css/modal-poke.css" type="text/css">
|
||||
<link rel="stylesheet" href="css/loader.css" type="text/css">
|
||||
<link rel="stylesheet" href="css/music/info_plate.css" type="text/css">
|
||||
<link rel="stylesheet" href="css/frame/SelectInfo.css" type="text/css">
|
||||
|
@ -145,6 +146,11 @@
|
|||
|
||||
<div id="music-test"></div>
|
||||
<div id="templates"></div>
|
||||
<div id="sounds"></div>
|
||||
<div id="mouse-move">
|
||||
<div class="container">
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<?php
|
||||
|
|
|
@ -431,7 +431,7 @@
|
|||
</x-entry>
|
||||
<x-entry>
|
||||
<x-tag>Transfers</x-tag>
|
||||
<x-content>TeaSpeak does not yet support these variables</x-content>
|
||||
<x-content>This needs to be implemented :)</x-content>
|
||||
</x-entry>
|
||||
<x-entry>
|
||||
<x-tag>Anti-Flood</x-tag>
|
||||
|
@ -1322,9 +1322,7 @@
|
|||
</script>
|
||||
<script class="jsrender-template" id="tmpl_selected_hostbanner" type="text/html">
|
||||
<div class="hostbanner">
|
||||
{{if property_virtualserver_hostbanner_url}}
|
||||
<a href="{{:property_virtualserver_hostbanner_url}}">
|
||||
{{/if}}
|
||||
<a href="{{:property_virtualserver_hostbanner_url}}" style="display: flex; flex-direction: row; justify-content: center;">
|
||||
|
||||
<img src="
|
||||
{{:property_virtualserver_hostbanner_gfx_url}}
|
||||
|
@ -1348,9 +1346,7 @@
|
|||
|
||||
alt="Host banner"
|
||||
>
|
||||
{{if property_virtualserver_hostbanner_url}}
|
||||
</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
</script>
|
||||
<script class="jsrender-template" id="tmpl_selected_server" type="text/html">
|
||||
|
@ -1463,5 +1459,16 @@
|
|||
<node key="bbcode_channel_description"></node>
|
||||
</div>
|
||||
</script>
|
||||
<script class="jsrender-template" id="tmpl_poke_popup" type="text/html">
|
||||
<div class="container-poke">
|
||||
<div class="container-information">
|
||||
<a>You have been poked by </a><node key="invoker"></node><a>:</a>
|
||||
</div>
|
||||
<div class="container-message">
|
||||
<a class="message">{{>message}}</a>
|
||||
</div>
|
||||
<button class="button-close">close</button>
|
||||
</div>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -65,7 +65,8 @@ namespace MessageHelper {
|
|||
console.warn("Message to format contains invalid index (" + number + ")");
|
||||
|
||||
result.push(...this.formatElement(objects[number]));
|
||||
begin = found = found + 2 + offset;
|
||||
found = found + 1 + offset;
|
||||
begin = found + 1;
|
||||
console.log("Offset: " + offset + " Number: " + number);
|
||||
} while(found++);
|
||||
|
||||
|
@ -237,6 +238,11 @@ class ChatEntry {
|
|||
return tag;
|
||||
}
|
||||
|
||||
focus() {
|
||||
this.handle.activeChat = this;
|
||||
this.handle.htmlTag.find(".input_box").focus();
|
||||
}
|
||||
|
||||
set name(newName : string) {
|
||||
console.log("Change name!");
|
||||
this._name = newName;
|
||||
|
|
|
@ -98,7 +98,7 @@ class TSClient {
|
|||
helpers.hashPassword(password.password).then(password => {
|
||||
this.serverConnection.startConnection({host, port}, new HandshakeHandler(identity, name, password));
|
||||
}).catch(error => {
|
||||
createErrorModal("Error while hasing password", "Faield to hash server password!").open();
|
||||
createErrorModal("Error while hashing password", "Failed to hash server password!<br>" + error).open();
|
||||
})
|
||||
} else
|
||||
this.serverConnection.startConnection({host, port}, new HandshakeHandler(identity, name, password ? password.password : undefined));
|
||||
|
@ -182,6 +182,7 @@ class TSClient {
|
|||
"Click <a href='" + this.certAcceptUrl() + "'>here</a> to accept the remote certificate"
|
||||
).open();
|
||||
}
|
||||
sound.play(Sound.CONNECTION_REFUSED);
|
||||
break;
|
||||
case DisconnectReason.CONNECTION_CLOSED:
|
||||
console.error("Lost connection to remote server!");
|
||||
|
@ -189,9 +190,11 @@ class TSClient {
|
|||
"Connection closed",
|
||||
"The connection was closed by remote host"
|
||||
).open();
|
||||
sound.play(Sound.CONNECTION_DISCONNECTED);
|
||||
break;
|
||||
case DisconnectReason.CONNECTION_PING_TIMEOUT:
|
||||
console.error("Connection ping timeout");
|
||||
sound.play(Sound.CONNECTION_DISCONNECTED_TIMEOUT);
|
||||
createErrorModal(
|
||||
"Connection lost",
|
||||
"Lost connection to remote host (Ping timeout)<br>Even possible?"
|
||||
|
@ -204,6 +207,7 @@ class TSClient {
|
|||
"The server is closed.<br>" +
|
||||
"Reason: " + data.reasonmsg
|
||||
).open();
|
||||
sound.play(Sound.CONNECTION_DISCONNECTED);
|
||||
break;
|
||||
case DisconnectReason.SERVER_REQUIRES_PASSWORD:
|
||||
chat.serverChat().appendError("Server requires password");
|
||||
|
@ -214,6 +218,19 @@ class TSClient {
|
|||
this.serverConnection._handshakeHandler.name,
|
||||
{password: password as string, hashed: false});
|
||||
}).open();
|
||||
break;
|
||||
case DisconnectReason.CLIENT_KICKED:
|
||||
chat.serverChat().appendError("You got kicked from the server by {0}{1}",
|
||||
ClientEntry.chatTag(data["invokerid"], data["invokername"], data["invokeruid"]),
|
||||
data["reasonmsg"] ? " (" + data["reasonmsg"] + ")" : "");
|
||||
sound.play(Sound.SERVER_KICKED);
|
||||
break;
|
||||
case DisconnectReason.CLIENT_BANNED:
|
||||
chat.serverChat().appendError("You got banned from the server by {0}{1}",
|
||||
ClientEntry.chatTag(data["invokerid"], data["invokername"], data["invokeruid"]),
|
||||
data["reasonmsg"] ? " (" + data["reasonmsg"] + ")" : "");
|
||||
sound.play(Sound.CONNECTION_BANNED); //TODO findout if it was a disconnect or a connect refuse
|
||||
break;
|
||||
default:
|
||||
console.error("Got uncaught disconnect!");
|
||||
console.error("Type: " + type + " Data:");
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
/// <reference path="ui/channel.ts" />
|
||||
/// <reference path="client.ts" />
|
||||
/// <reference path="sound/Sounds.ts" />
|
||||
/// <reference path="ui/modal/ModalPoke.ts" />
|
||||
|
||||
class CommandResult {
|
||||
success: boolean;
|
||||
|
@ -227,6 +229,7 @@ class ServerConnection {
|
|||
if(res.id == 2568) { //Permission error
|
||||
res.message = "Insufficient client permissions. Failed on permission " + this._client.permissions.resolveInfo(res.json["failed_permid"] as number).name;
|
||||
chat.serverChat().appendError("Insufficient client permissions. Failed on permission {}", this._client.permissions.resolveInfo(res.json["failed_permid"] as number).name);
|
||||
sound.play(Sound.ERROR_INSUFFICIENT_PERMISSIONS);
|
||||
} else {
|
||||
chat.serverChat().appendError(res.extra_message.length == 0 ? res.message : res.extra_message);
|
||||
}
|
||||
|
@ -473,6 +476,8 @@ class ConnectionCommandHandler {
|
|||
this["notifyserveredited"] = this.handleNotifyServerEdited;
|
||||
this["notifyserverupdated"] = this.handleNotifyServerUpdated;
|
||||
|
||||
this["notifyclientpoke"] = this.handleNotifyClientPoke;
|
||||
|
||||
this["notifymusicplayerinfo"] = this.handleNotifyMusicPlayerInfo;
|
||||
}
|
||||
|
||||
|
@ -524,6 +529,7 @@ class ConnectionCommandHandler {
|
|||
|
||||
chat.serverChat().name = this.connection._client.channelTree.server.properties["virtualserver_name"];
|
||||
chat.serverChat().appendMessage("Connected as {0}", true, this.connection._client.getClient().createChatTag(true));
|
||||
sound.play(Sound.CONNECTION_CONNECTED);
|
||||
globalClient.onConnected();
|
||||
}
|
||||
|
||||
|
@ -637,14 +643,42 @@ class ConnectionCommandHandler {
|
|||
chat.channelChat().name = channel.channelName();
|
||||
tree.moveClient(client, channel);
|
||||
}
|
||||
|
||||
const own_channel = this.connection._client.getClient().currentChannel();
|
||||
|
||||
if(json["reasonid"] == ViewReasonId.VREASON_USER_ACTION) {
|
||||
if(own_channel == channel)
|
||||
if(old_channel)
|
||||
sound.play(Sound.USER_ENTERED);
|
||||
else
|
||||
sound.play(Sound.USER_ENTERED_CONNECT);
|
||||
if(old_channel) {
|
||||
chat.serverChat().appendMessage("{0} appeared from {1} to {2}", true, client.createChatTag(true), old_channel.createChatTag(true), channel.createChatTag(true));
|
||||
} else {
|
||||
chat.serverChat().appendMessage("{0} connected to channel {1}", true, client.createChatTag(true), channel.createChatTag(true));
|
||||
}
|
||||
} else if(json["reasonid"] == ViewReasonId.VREASON_MOVED) {
|
||||
if(own_channel == channel)
|
||||
sound.play(Sound.USER_ENTERED_MOVED);
|
||||
|
||||
chat.serverChat().appendMessage("{0} appeared from {1} to {2}, moved by {3}", true,
|
||||
client.createChatTag(true),
|
||||
old_channel ? old_channel.createChatTag(true) : undefined,
|
||||
channel.createChatTag(true),
|
||||
ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]),
|
||||
);
|
||||
} else if(json["reasonid"] == ViewReasonId.VREASON_CHANNEL_KICK) {
|
||||
if(own_channel == channel)
|
||||
sound.play(Sound.USER_ENTERED_KICKED);
|
||||
|
||||
chat.serverChat().appendMessage("{0} appeared from {1} to {2}, kicked by {3}{4}", true,
|
||||
client.createChatTag(true),
|
||||
old_channel ? old_channel.createChatTag(true) : undefined,
|
||||
channel.createChatTag(true),
|
||||
ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]),
|
||||
json["reasonmsg"] > 0 ? " (" + json["msg"] + ")" : ""
|
||||
);
|
||||
} else {
|
||||
console.warn("Unknown reasonid for " + json["reasonid"]);
|
||||
}
|
||||
|
||||
let updates: {
|
||||
|
@ -678,44 +712,69 @@ class ConnectionCommandHandler {
|
|||
return 0;
|
||||
}
|
||||
if(client == this.connection._client.getClient()) {
|
||||
if(json["reasonid"] == ViewReasonId.VREASON_BAN)
|
||||
if(json["reasonid"] == ViewReasonId.VREASON_BAN) {
|
||||
this.connection._client.handleDisconnect(DisconnectReason.CLIENT_BANNED, json);
|
||||
else if(json["reasonid"] == ViewReasonId.VREASON_SERVER_KICK)
|
||||
} else if(json["reasonid"] == ViewReasonId.VREASON_SERVER_KICK) {
|
||||
this.connection._client.handleDisconnect(DisconnectReason.CLIENT_KICKED, json);
|
||||
else if(json["reasonid"] == ViewReasonId.VREASON_SERVER_SHUTDOWN)
|
||||
} else if(json["reasonid"] == ViewReasonId.VREASON_SERVER_SHUTDOWN) {
|
||||
this.connection._client.handleDisconnect(DisconnectReason.SERVER_CLOSED, json);
|
||||
else if(json["reasonid"] == ViewReasonId.VREASON_SERVER_STOPPED)
|
||||
} else if(json["reasonid"] == ViewReasonId.VREASON_SERVER_STOPPED) {
|
||||
this.connection._client.handleDisconnect(DisconnectReason.SERVER_CLOSED, json);
|
||||
else
|
||||
} else
|
||||
this.connection._client.handleDisconnect(DisconnectReason.UNKNOWN, json);
|
||||
return;
|
||||
}
|
||||
|
||||
const own_channel = this.connection._client.getClient().currentChannel();
|
||||
let channel_from = tree.findChannel(json["cfid"]);
|
||||
let channel_to = tree.findChannel(json["ctid"]);
|
||||
|
||||
|
||||
if(json["reasonid"] == ViewReasonId.VREASON_USER_ACTION) {
|
||||
chat.serverChat().appendMessage("{0} disappeared from {1} to {2}", true, client.createChatTag(true), channel_from.createChatTag(true), channel_to.createChatTag(true));
|
||||
|
||||
if(channel_from == own_channel)
|
||||
sound.play(Sound.USER_LEFT);
|
||||
} else if(json["reasonid"] == ViewReasonId.VREASON_SERVER_LEFT) {
|
||||
chat.serverChat().appendMessage("{0} left the server ({1})", true, client.createChatTag(true), json["reasonmsg"]);
|
||||
chat.serverChat().appendMessage("{0} left the server{1}", true,
|
||||
client.createChatTag(true),
|
||||
json["reasonmsg"] ? " (" + json["reasonmsg"] + ")" : ""
|
||||
);
|
||||
|
||||
if(channel_from == own_channel)
|
||||
sound.play(Sound.USER_LEFT_DISCONNECT);
|
||||
} else if(json["reasonid"] == ViewReasonId.VREASON_SERVER_KICK) {
|
||||
chat.serverChat().appendError("{0} was kicked from the server by {1}. ({2})",
|
||||
chat.serverChat().appendError("{0} was kicked from the server by {1}.{2}",
|
||||
client.createChatTag(true),
|
||||
ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]),
|
||||
json["reasonmsg"]
|
||||
json["reasonmsg"] ? " (" + json["reasonmsg"] + ")" : ""
|
||||
);
|
||||
if(channel_from == own_channel)
|
||||
sound.play(Sound.USER_LEFT_KICKED_SERVER);
|
||||
} else if(json["reasonid"] == ViewReasonId.VREASON_CHANNEL_KICK) {
|
||||
chat.serverChat().appendError("{0} was kicked from your channel by {1}.{2}",
|
||||
client.createChatTag(true),
|
||||
ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]),
|
||||
json["reasonmsg"] ? " (" + json["reasonmsg"] + ")" : ""
|
||||
);
|
||||
|
||||
if(channel_from == own_channel)
|
||||
sound.play(Sound.USER_LEFT_KICKED_CHANNEL);
|
||||
} else if(json["reasonid"] == ViewReasonId.VREASON_BAN) {
|
||||
//"Mulus" was banned for 1 second from the server by "WolverinDEV" (Sry brauchte kurz ein opfer :P <3 (Nohomo))
|
||||
let duration = "permanently";
|
||||
if(json["bantime"])
|
||||
duration = "for " + formatDate(Number.parseInt(json["bantime"]));
|
||||
chat.serverChat().appendError("{0} was banned {1} by {2}. ({3})",
|
||||
|
||||
chat.serverChat().appendError("{0} was banned {1} by {2}.{3}",
|
||||
client.createChatTag(true),
|
||||
duration,
|
||||
ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]),
|
||||
json["reasonmsg"]
|
||||
json["reasonmsg"] ? " (" + json["reasonmsg"] + ")" : ""
|
||||
);
|
||||
|
||||
if(channel_from == own_channel)
|
||||
sound.play(Sound.USER_LEFT_BANNED);
|
||||
} else {
|
||||
console.error("Unknown client left reason!");
|
||||
}
|
||||
|
@ -749,8 +808,10 @@ class ConnectionCommandHandler {
|
|||
if(entry !== client) entry.getAudioController().stopAudio(true);
|
||||
this.connection._client.controlBar.updateVoice(channel_to);
|
||||
}
|
||||
|
||||
tree.moveClient(client, channel_to);
|
||||
|
||||
const own_channel = this.connection._client.getClient().currentChannel();
|
||||
if(json["reasonid"] == ViewReasonId.VREASON_MOVED) {
|
||||
chat.serverChat().appendMessage(self ? "You was moved by {3} from channel {1} to {2}" : "{0} was moved from channel {1} to {2} by {3}", true,
|
||||
client.createChatTag(true),
|
||||
|
@ -758,12 +819,39 @@ class ConnectionCommandHandler {
|
|||
channel_to.createChatTag(true),
|
||||
ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"])
|
||||
);
|
||||
if(self)
|
||||
sound.play(Sound.USER_MOVED_SELF);
|
||||
else if(own_channel == channel_to)
|
||||
sound.play(Sound.USER_ENTERED_MOVED);
|
||||
else if(own_channel == channel_from)
|
||||
sound.play(Sound.USER_LEFT_MOVED);
|
||||
} else if(json["reasonid"] == ViewReasonId.VREASON_USER_ACTION) {
|
||||
chat.serverChat().appendMessage(self ? "You switched from channel {1} to {2}" : "{0} switched from channel {1} to {2}", true,
|
||||
client.createChatTag(true),
|
||||
channel_from ? channel_from.createChatTag(true) : undefined,
|
||||
channel_to.createChatTag(true)
|
||||
);
|
||||
if(self) {} //If we do an action we wait for the error response
|
||||
else if(own_channel == channel_to)
|
||||
sound.play(Sound.USER_ENTERED);
|
||||
else if(own_channel == channel_from)
|
||||
sound.play(Sound.USER_LEFT);
|
||||
} else if(json["reasonid"] == ViewReasonId.VREASON_CHANNEL_KICK) {
|
||||
chat.serverChat().appendMessage(self ? "You got kicked out of the channel {1} to channel {2} by {3}{4}" : "{0} got kicked from channel {1} to {2} by {3}{4}", true,
|
||||
client.createChatTag(true),
|
||||
channel_from ? channel_from.createChatTag(true) : undefined,
|
||||
channel_to.createChatTag(true),
|
||||
ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]),
|
||||
(json["reasonmsg"] || "").length > 0 ? " (" + json["msg"] + ")" : ""
|
||||
);
|
||||
if(self) {
|
||||
sound.play(Sound.CHANNEL_KICKED);
|
||||
} else if(own_channel == channel_to)
|
||||
sound.play(Sound.USER_ENTERED_KICKED);
|
||||
else if(own_channel == channel_from)
|
||||
sound.play(Sound.USER_LEFT_KICKED_CHANNEL);
|
||||
} else {
|
||||
console.warn("Unknown reason id " + json["reasonid"]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -836,14 +924,20 @@ class ConnectionCommandHandler {
|
|||
return;
|
||||
}
|
||||
if(invoker == this.connection._client.getClient()) {
|
||||
target.chat(true).appendMessage("<< " + json["msg"]);
|
||||
sound.play(Sound.MESSAGE_SEND, { background_notification: true });
|
||||
target.chat(true).appendMessage("{0}: {1}", true, this.connection._client.getClient().createChatTag(true), json["msg"]);
|
||||
} else {
|
||||
invoker.chat(true).appendMessage(">> " + json["msg"]);
|
||||
sound.play(Sound.MESSAGE_RECEIVED, { background_notification: true });
|
||||
invoker.chat(true).appendMessage("{0}: {1}", true, ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"], true), json["msg"]);
|
||||
}
|
||||
} else if(mode == 2) {
|
||||
chat.channelChat().appendMessage("{0} >> {1}", true, ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"], true), json["msg"])
|
||||
if(json["invokerid"] == this.connection._client.clientId)
|
||||
sound.play(Sound.MESSAGE_SEND, { background_notification: true });
|
||||
else
|
||||
sound.play(Sound.MESSAGE_RECEIVED, { background_notification: true });
|
||||
chat.channelChat().appendMessage("{0}: {1}", true, ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"], true), json["msg"])
|
||||
} else if(mode == 3) {
|
||||
chat.serverChat().appendMessage("{0} >> {1}", true, ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"], true), json["msg"]);
|
||||
chat.serverChat().appendMessage("{0}: {1}", true, ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"], true), json["msg"]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -921,4 +1015,15 @@ class ConnectionCommandHandler {
|
|||
|
||||
bot.handlePlayerInfo(json);
|
||||
}
|
||||
|
||||
handleNotifyClientPoke(json) {
|
||||
json = json[0];
|
||||
Modals.spawnPoke({
|
||||
id: parseInt(json["invokerid"]),
|
||||
name: json["invokername"],
|
||||
unique_id: json["invokeruid"]
|
||||
}, json["msg"]);
|
||||
|
||||
sound.play(Sound.USER_POKED_SELF);
|
||||
}
|
||||
}
|
|
@ -394,7 +394,7 @@ namespace sha {
|
|||
export function sha1(message: string | ArrayBuffer) : PromiseLike<ArrayBuffer> {
|
||||
let buffer = message instanceof ArrayBuffer ? message : encode_text(message as string);
|
||||
|
||||
if(/Edge/.test(navigator.userAgent))
|
||||
if(!crypto || !crypto.subtle || !crypto.subtle.digest || /Edge/.test(navigator.userAgent))
|
||||
return new Promise<ArrayBuffer>(resolve => {
|
||||
resolve(_sha1.arrayBuffer(buffer as ArrayBuffer));
|
||||
});
|
||||
|
|
|
@ -129,6 +129,8 @@ function loadDebug() {
|
|||
//Load general API's
|
||||
"js/log.js",
|
||||
|
||||
"js/sound/Sounds.js",
|
||||
|
||||
"js/utils/modal.js",
|
||||
"js/utils/tab.js",
|
||||
"js/utils/helpers.js",
|
||||
|
@ -147,6 +149,7 @@ function loadDebug() {
|
|||
"js/ui/modal/ModalBanCreate.js",
|
||||
"js/ui/modal/ModalBanList.js",
|
||||
"js/ui/modal/ModalYesNo.js",
|
||||
"js/ui/modal/ModalPoke.js",
|
||||
"js/ui/modal/ModalPermissionEdit.js",
|
||||
"js/ui/modal/ModalServerGroupDialog.js",
|
||||
|
||||
|
@ -154,6 +157,7 @@ function loadDebug() {
|
|||
"js/ui/client.js",
|
||||
"js/ui/server.js",
|
||||
"js/ui/view.js",
|
||||
"js/ui/client_move.js",
|
||||
|
||||
"js/ui/frames/SelectedItemInfo.js",
|
||||
"js/ui/frames/ControlBar.js",
|
||||
|
|
|
@ -152,8 +152,14 @@ function main() {
|
|||
*/
|
||||
|
||||
setup_close();
|
||||
|
||||
let _resize_timeout: NodeJS.Timer;
|
||||
$(window).on('resize', () => {
|
||||
globalClient.channelTree.handle_resized();
|
||||
if(_resize_timeout)
|
||||
clearTimeout(_resize_timeout);
|
||||
_resize_timeout = setTimeout(() => {
|
||||
globalClient.channelTree.handle_resized();
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -121,7 +121,7 @@ if(typeof ($) !== "undefined") {
|
|||
result = $(result);
|
||||
}
|
||||
result.find("node").each((index, element) => {
|
||||
$(element).replaceWith(values[$(element).attr("key")] || values[0][$(element).attr("key")]);
|
||||
$(element).replaceWith(values[$(element).attr("key")] || (values[0] || [])[$(element).attr("key")]);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
enum Sound {
|
||||
SOUND_TEST = "sound.test",
|
||||
SOUND_EGG = "sound.egg",
|
||||
|
||||
AWAY_ACTIVATED = "away_activated",
|
||||
AWAY_DEACTIVATED = "away_deactivated",
|
||||
|
||||
CONNECTION_CONNECTED = "connection.connected",
|
||||
CONNECTION_DISCONNECTED = "connection.disconnected",
|
||||
CONNECTION_BANNED = "connection.banned",
|
||||
CONNECTION_DISCONNECTED_TIMEOUT = "connection.disconnected.timeout",
|
||||
CONNECTION_REFUSED = "connection.refused",
|
||||
|
||||
SERVER_EDITED = "server.edited",
|
||||
SERVER_EDITED_SELF = "server.edited.self",
|
||||
SERVER_KICKED = "server.kicked",
|
||||
|
||||
CHANNEL_CREATED = "channel.created",
|
||||
CHANNEL_MOVED = "channel.moved",
|
||||
CHANNEL_EDITED = "channel.edited",
|
||||
CHANNEL_EDITED_SELF = "channel.edited.self",
|
||||
CHANNEL_DELETED = "channel.deleted",
|
||||
|
||||
CHANNEL_JOINED = "channel.joined",
|
||||
CHANNEL_KICKED = "channel.kicked", //You got kicked from the channel
|
||||
|
||||
USER_MOVED = "user.moved", //User moved
|
||||
USER_MOVED_SELF = "user.moved.self", //You were moved
|
||||
USER_POKED_SELF = "user.poked.self", //Hey wakeup
|
||||
USER_BANNED = "user.banned",
|
||||
|
||||
USER_ENTERED = "user.joined", //User joined your channel
|
||||
USER_ENTERED_MOVED = "user.joined.moved", //User was moved to your channel
|
||||
USER_ENTERED_KICKED = "user.joined.kicked", //User was kicked to your channel
|
||||
USER_ENTERED_CONNECT = "user.joined.connect",
|
||||
|
||||
USER_LEFT = "user.left", //User left your channel
|
||||
USER_LEFT_MOVED = "user.left.moved", //User was move out of your channel
|
||||
USER_LEFT_KICKED_CHANNEL = "user.left.kicked.server", //User was kicked out of your channel
|
||||
USER_LEFT_KICKED_SERVER = "user.left.kicked.channel", //User is your channel was kicked from the server
|
||||
USER_LEFT_DISCONNECT = "user.left.disconnect",
|
||||
USER_LEFT_BANNED = "user.left.banned",
|
||||
|
||||
ERROR_INSUFFICIENT_PERMISSIONS = "error.insufficient_permissions",
|
||||
|
||||
MESSAGE_SEND = "message.send",
|
||||
MESSAGE_RECEIVED = "message.received"
|
||||
}
|
||||
|
||||
namespace sound {
|
||||
interface SpeechFile {
|
||||
key: string;
|
||||
filename: string;
|
||||
|
||||
not_supported?: boolean;
|
||||
not_supported_timeout?: number;
|
||||
cached?: AudioBuffer;
|
||||
node?: HTMLAudioElement;
|
||||
|
||||
}
|
||||
let warned = false
|
||||
let speech_mapping: {[key: string]:SpeechFile} = {};
|
||||
|
||||
function register_sound(key: string, file: string) {
|
||||
speech_mapping[key] = {key: key, filename: file} as SpeechFile;
|
||||
}
|
||||
|
||||
export function initialize() : Promise<void> {
|
||||
$.ajaxSetup({
|
||||
beforeSend: function(jqXHR,settings){
|
||||
if (settings.dataType === 'binary'){
|
||||
console.log("Settins binary");
|
||||
settings.xhr().responseType = 'arraybuffer';
|
||||
settings.processData = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
register_sound("message.received", "effects/message_received.wav");
|
||||
register_sound("message.send", "effects/message_send.wav");
|
||||
|
||||
return new Promise<void>(resolve => {
|
||||
$.ajax({
|
||||
url: "audio/speech/mapping.json",
|
||||
success: response => {
|
||||
for(const entry of response)
|
||||
register_sound(entry.key, "speech/" + entry.file);
|
||||
resolve();
|
||||
},
|
||||
error: () => {
|
||||
console.log("error!");
|
||||
console.dir(...arguments);
|
||||
},
|
||||
timeout: 5000,
|
||||
async: true,
|
||||
type: 'GET'
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
function str2ab(str) {
|
||||
var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
|
||||
var bufView = new Uint16Array(buf);
|
||||
for (var i = 0, strLen=str.length; i<strLen; i++) {
|
||||
bufView[i] = str.charCodeAt(i);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
export function play(sound: Sound, options?: {
|
||||
background_notification?: boolean
|
||||
}) {
|
||||
console.log("playback sound " + sound);
|
||||
const file: SpeechFile = speech_mapping[sound];
|
||||
if(!file) {
|
||||
console.warn("Missing sound " + sound);
|
||||
return;
|
||||
}
|
||||
if(file.not_supported) {
|
||||
if(!file.not_supported_timeout || Date.now() < file.not_supported_timeout) //Test if the not supported isnt may timeouted
|
||||
return;
|
||||
file.not_supported = false;
|
||||
file.not_supported_timeout = undefined;
|
||||
}
|
||||
|
||||
const path = "audio/" + file.filename;
|
||||
const context = audio.player.context();
|
||||
const volume = options && options.background_notification ? .5 : 1;
|
||||
|
||||
if(context.decodeAudioData) {
|
||||
if(file.cached) {
|
||||
console.log("Using cached buffer: %o", file.cached);
|
||||
const player = context.createBufferSource();
|
||||
player.buffer = file.cached;
|
||||
player.start(0);
|
||||
|
||||
if(volume != 1 && context.createGain) {
|
||||
const gain = context.createGain();
|
||||
if(gain.gain.setValueAtTime)
|
||||
gain.gain.setValueAtTime(volume, 0);
|
||||
else
|
||||
gain.gain.value = volume;
|
||||
|
||||
player.connect(gain);
|
||||
gain.connect(audio.player.destination());
|
||||
} else
|
||||
player.connect(audio.player.destination());
|
||||
} else {
|
||||
const decode_data = buffer => {
|
||||
console.log(buffer);
|
||||
try {
|
||||
console.log("Decoding data");
|
||||
context.decodeAudioData(buffer, result => {
|
||||
console.log("Got decoded data");
|
||||
file.cached = result;
|
||||
play(sound, options);
|
||||
}, error => {
|
||||
console.error("Failed to decode audio data for " + sound);
|
||||
console.error(error);
|
||||
file.not_supported = true;
|
||||
file.not_supported_timeout = Date.now() + 1000 * 60 * 60; //Try in 2min again!
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
file.not_supported = true;
|
||||
file.not_supported_timeout = Date.now() + 1000 * 60 * 60; //Try in 2min again!
|
||||
}
|
||||
};
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', path, true);
|
||||
xhr.responseType = 'arraybuffer';
|
||||
|
||||
xhr.onload = function(e) {
|
||||
if (this.status == 200) {
|
||||
decode_data(this.response);
|
||||
} else {
|
||||
console.error("Failed to load audio file. (Response code " + this.status + ")");
|
||||
file.not_supported = true;
|
||||
file.not_supported_timeout = Date.now() + 1000 * 60 * 60; //Try in 2min again!
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = error => {
|
||||
console.error("Failed to load audio file " + sound);
|
||||
console.error(error);
|
||||
file.not_supported = true;
|
||||
file.not_supported_timeout = Date.now() + 1000 * 60 * 60; //Try in 2min again!
|
||||
};
|
||||
|
||||
xhr.send();
|
||||
}
|
||||
} else {
|
||||
console.log("Replaying " + path);
|
||||
if(file.node) {
|
||||
file.node.currentTime = 0;
|
||||
file.node.play();
|
||||
} else {
|
||||
if(!warned) {
|
||||
warned = true;
|
||||
console.warn("Your browser does not support decodeAudioData! Using a node to playback! This bypasses the audio output and volume regulation!");
|
||||
}
|
||||
const container = $("#sounds");
|
||||
const node = $.spawn("audio").attr("src", path);
|
||||
node.appendTo(container);
|
||||
|
||||
file.node = node[0];
|
||||
file.node.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -56,6 +56,7 @@ class ChannelEntry {
|
|||
|
||||
private _channelAlign: string;
|
||||
private _formatedChannelName: string;
|
||||
private _family_index: number = 0;
|
||||
|
||||
//HTML DOM elements
|
||||
private _tag_root: JQuery<HTMLElement>;
|
||||
|
@ -161,8 +162,10 @@ class ChannelEntry {
|
|||
|
||||
//Tag channel
|
||||
this._tag_channel = $.spawn("div");
|
||||
this._tag_channel.attr('channel-id', this.channelId);
|
||||
this._tag_channel.addClass("channelLine");
|
||||
this._tag_channel.addClass(this._channelAlign); //For left
|
||||
this._tag_channel.css('z-index', this._family_index);
|
||||
|
||||
let channelType = $.spawn("div");
|
||||
channelType.addClass("channel_only_normal channel_type icon client-channel_green_subscribed");
|
||||
|
@ -373,7 +376,9 @@ class ChannelEntry {
|
|||
}
|
||||
|
||||
perms[0]["cid"] = this.channelId;
|
||||
this.channelTree.client.serverConnection.sendCommand("channeladdperm", perms, ["continueonerror"]);
|
||||
this.channelTree.client.serverConnection.sendCommand("channeladdperm", perms, ["continueonerror"]).then(() => {
|
||||
sound.play(Sound.CHANNEL_EDITED_SELF);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -383,7 +388,11 @@ class ChannelEntry {
|
|||
icon: "client-channel_delete",
|
||||
name: "Delete channel",
|
||||
invalidPermission: !flagDelete,
|
||||
callback: () => this.channelTree.client.serverConnection.sendCommand("channeldelete", {cid: this.channelId})
|
||||
callback: () => {
|
||||
this.channelTree.client.serverConnection.sendCommand("channeldelete", {cid: this.channelId}).then(() => {
|
||||
sound.play(Sound.CHANNEL_DELETED);
|
||||
})
|
||||
}
|
||||
},
|
||||
MenuEntry.HR(),
|
||||
{
|
||||
|
@ -564,8 +573,10 @@ class ChannelEntry {
|
|||
this.updateChannelTypeIcon();
|
||||
});
|
||||
}).open();
|
||||
} else
|
||||
this.channelTree.client.getServerConnection().joinChannel(this, this._cachedPassword).catch(error => {
|
||||
} else if(this.channelTree.client.getClient().currentChannel() != this)
|
||||
this.channelTree.client.getServerConnection().joinChannel(this, this._cachedPassword).then(() => {
|
||||
sound.play(Sound.CHANNEL_JOINED);
|
||||
}).catch(error => {
|
||||
if(error instanceof CommandResult) {
|
||||
if(error.id == 781) { //Invalid password
|
||||
this._cachedPassword = undefined;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/// <reference path="channel.ts" />
|
||||
/// <reference path="modal/ModalChangeVolume.ts" />
|
||||
/// <reference path="modal/ModalServerGroupDialog.ts" />
|
||||
/// <reference path="client_move.ts" />
|
||||
|
||||
enum ClientType {
|
||||
CLIENT_VOICE,
|
||||
|
@ -80,7 +81,7 @@ class ClientEntry {
|
|||
return this._properties;
|
||||
}
|
||||
|
||||
currentChannel() { return this._channel; }
|
||||
currentChannel() : ChannelEntry { return this._channel; }
|
||||
clientNickName(){ return this.properties.client_nickname; }
|
||||
clientUid(){ return this.properties.client_unique_identifier; }
|
||||
clientId(){ return this._clientId; }
|
||||
|
@ -95,6 +96,11 @@ class ClientEntry {
|
|||
_this.channelTree.onSelect(_this);
|
||||
});
|
||||
|
||||
if(this.clientId() != this.channelTree.client.clientId && !(this instanceof MusicClientEntry))
|
||||
this.tag.dblclick(event => {
|
||||
this.chat(true).focus();
|
||||
});
|
||||
|
||||
if(!settings.static(Settings.KEY_DISABLE_CONTEXT_MENU, false)) {
|
||||
this.tag.on("contextmenu", function (event) {
|
||||
event.preventDefault();
|
||||
|
@ -105,6 +111,25 @@ class ClientEntry {
|
|||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
this.tag.mousedown(event => {
|
||||
this.channelTree.client_mover.activate(this, target => {
|
||||
if(!target) return;
|
||||
if(target == this._channel) return;
|
||||
|
||||
const source = this._channel;
|
||||
const self = this.channelTree.client.getClient();
|
||||
this.channelTree.client.serverConnection.sendCommand("clientmove", {
|
||||
clid: this.clientId(),
|
||||
cid: target.getChannelId()
|
||||
}).then(event => {
|
||||
if(this.clientId() == this.channelTree.client.clientId)
|
||||
sound.play(Sound.CHANNEL_JOINED);
|
||||
else if(target !== source && target != self.currentChannel())
|
||||
sound.play(Sound.USER_MOVED);
|
||||
});
|
||||
}, event);
|
||||
});
|
||||
}
|
||||
|
||||
protected assignment_context() : ContextMenuEntry[] {
|
||||
|
@ -312,7 +337,9 @@ class ClientEntry {
|
|||
uid: this.properties.client_unique_identifier,
|
||||
banreason: data.reason,
|
||||
time: data.length
|
||||
}, [data.no_ip ? "no-ip" : "", data.no_hwid ? "no-hardware-id" : "", data.no_name ? "no-nickname" : ""]);
|
||||
}, [data.no_ip ? "no-ip" : "", data.no_hwid ? "no-hardware-id" : "", data.no_name ? "no-nickname" : ""]).then(() => {
|
||||
sound.play(Sound.USER_BANNED);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -780,6 +807,48 @@ class MusicClientEntry extends ClientEntry {
|
|||
},
|
||||
MenuEntry.HR(),
|
||||
...super.assignment_context(),
|
||||
MenuEntry.HR(),{
|
||||
type: MenuEntryType.ENTRY,
|
||||
icon: "client-move_client_to_own_channel",
|
||||
name: "Move client to your channel",
|
||||
callback: () => {
|
||||
this.channelTree.client.serverConnection.sendCommand("clientmove", {
|
||||
clid: this.clientId(),
|
||||
cid: this.channelTree.client.getClient().currentChannel().getChannelId()
|
||||
});
|
||||
}
|
||||
}, {
|
||||
type: MenuEntryType.ENTRY,
|
||||
icon: "client-kick_channel",
|
||||
name: "Kick client from channel",
|
||||
callback: () => {
|
||||
createInputModal("Kick client from channel", "Kick reason:<br>", text => true, result => {
|
||||
if(result) {
|
||||
console.log("Kicking client " + this.clientNickName() + " from channel with reason " + result);
|
||||
this.channelTree.client.serverConnection.sendCommand("clientkick", {
|
||||
clid: this.clientId(),
|
||||
reasonid: ViewReasonId.VREASON_CHANNEL_KICK,
|
||||
reasonmsg: result
|
||||
});
|
||||
|
||||
}
|
||||
}, { width: 400, maxLength: 255 }).open();
|
||||
}
|
||||
},
|
||||
MenuEntry.HR(),
|
||||
{
|
||||
type: MenuEntryType.ENTRY,
|
||||
icon: "client-volume",
|
||||
name: "Change Volume",
|
||||
callback: () => {
|
||||
Modals.spawnChangeVolume(this.audioController.volume, volume => {
|
||||
settings.changeServer("volume_client_" + this.clientUid(), volume);
|
||||
this.audioController.volume = volume;
|
||||
if(globalClient.selectInfo.currentSelected == this)
|
||||
globalClient.selectInfo.update();
|
||||
});
|
||||
}
|
||||
},
|
||||
MenuEntry.HR(),
|
||||
{
|
||||
name: "Delete bot",
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
/// <reference path="client.ts" />
|
||||
|
||||
class ClientMover {
|
||||
static readonly listener_root = $(document);
|
||||
static readonly move_element = $("#mouse-move");
|
||||
readonly channel_tree: ChannelTree;
|
||||
|
||||
selected_client: ClientEntry;
|
||||
|
||||
hovered_channel: HTMLDivElement;
|
||||
callback: (channel?: ChannelEntry) => any;
|
||||
|
||||
private _bound_finish;
|
||||
private _bound_move;
|
||||
private _active: boolean = false;
|
||||
|
||||
private origin_point: {x: number, y: number} = undefined;
|
||||
|
||||
constructor(tree: ChannelTree) {
|
||||
this.channel_tree = tree;
|
||||
}
|
||||
|
||||
activate(client: ClientEntry, callback: (channel?: ChannelEntry) => any, event: any) {
|
||||
this.finish_listener(undefined);
|
||||
|
||||
this.selected_client = client;
|
||||
this.callback = callback;
|
||||
console.log("Starting mouse move");
|
||||
|
||||
ClientMover.listener_root.on('mouseup', this._bound_finish = this.finish_listener.bind(this)).on('mousemove', this._bound_move = this.move_listener.bind(this));
|
||||
|
||||
{
|
||||
const content = ClientMover.move_element.find(".container");
|
||||
content.empty();
|
||||
content.append($.spawn("a").text(client.clientNickName()));
|
||||
}
|
||||
this.move_listener(event);
|
||||
}
|
||||
|
||||
private move_listener(event) {
|
||||
//console.log("Mouse move: " + event.pageX + " - " + event.pageY);
|
||||
if(!event.pageX || !event.pageY) return;
|
||||
if(!this.origin_point)
|
||||
this.origin_point = {x: event.pageX, y: event.pageY};
|
||||
|
||||
ClientMover.move_element.css({
|
||||
"top": (event.pageY - 1) + "px",
|
||||
"left": (event.pageX + 10) + "px"
|
||||
});
|
||||
|
||||
if(!this._active) {
|
||||
const d_x = this.origin_point.x - event.pageX;
|
||||
const d_y = this.origin_point.y - event.pageY;
|
||||
this._active = Math.sqrt(d_x * d_x + d_y * d_y) > 5 * 5;
|
||||
|
||||
if(this._active)
|
||||
ClientMover.move_element.show();
|
||||
}
|
||||
|
||||
const elements = document.elementsFromPoint(event.pageX, event.pageY);
|
||||
while(elements.length > 0) {
|
||||
if(elements[0].classList.contains("channelLine")) break;
|
||||
elements.pop_front();
|
||||
}
|
||||
|
||||
if(this.hovered_channel) {
|
||||
this.hovered_channel.classList.remove("move-selected");
|
||||
this.hovered_channel = undefined;
|
||||
}
|
||||
if(elements.length > 0) {
|
||||
elements[0].classList.add("move-selected");
|
||||
this.hovered_channel = elements[0] as HTMLDivElement;
|
||||
}
|
||||
}
|
||||
|
||||
private finish_listener(event) {
|
||||
ClientMover.move_element.hide();
|
||||
|
||||
const channel_id = this.hovered_channel ? parseInt(this.hovered_channel.getAttribute("channel-id")) : 0;
|
||||
ClientMover.listener_root.unbind('mouseleave', this._bound_finish);
|
||||
ClientMover.listener_root.unbind('mouseup', this._bound_finish);
|
||||
ClientMover.listener_root.unbind('mousemove', this._bound_move);
|
||||
if(this.hovered_channel) {
|
||||
this.hovered_channel.classList.remove("move-selected");
|
||||
this.hovered_channel = undefined;
|
||||
}
|
||||
|
||||
this.origin_point = undefined;
|
||||
if(!this._active) {
|
||||
this.selected_client = undefined;
|
||||
this.callback = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
this._active = false;
|
||||
if(this.callback) {
|
||||
if(!channel_id)
|
||||
this.callback(undefined);
|
||||
else {
|
||||
this.callback(this.channel_tree.findChannel(channel_id));
|
||||
}
|
||||
this.callback = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
deactivate() {
|
||||
this.callback = undefined;
|
||||
this.finish_listener(undefined);
|
||||
}
|
||||
}
|
|
@ -232,6 +232,7 @@ class ControlBar {
|
|||
private onDisconnect() {
|
||||
this.handle.handleDisconnect(DisconnectReason.REQUESTED); //TODO message?
|
||||
this.update_connection_state();
|
||||
sound.play(Sound.CONNECTION_DISCONNECTED);
|
||||
}
|
||||
|
||||
private on_token_use() {
|
||||
|
|
|
@ -530,10 +530,64 @@ class MusicInfoManager extends ClientInfoManager {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
const player = properties["music_player"];
|
||||
const player_transformer = $.spawn("div").append(player);
|
||||
player_transformer.css({
|
||||
'display': 'block',
|
||||
//'width': "100%",
|
||||
'height': '100%'
|
||||
});
|
||||
properties["music_player"] = player_transformer;
|
||||
}
|
||||
|
||||
let rendered = $("#tmpl_selected_music").renderTag([properties]);
|
||||
html_tag.append(rendered);
|
||||
|
||||
{
|
||||
const player = properties["music_player"] as JQuery;
|
||||
const player_width = 400; //player.width();
|
||||
const player_height = 400; //player.height();
|
||||
|
||||
const parent = player.parent();
|
||||
parent.css({
|
||||
'flex-grow': 1,
|
||||
'display': 'flex',
|
||||
'flex-direction': 'row',
|
||||
'justify-content': 'space-around',
|
||||
});
|
||||
|
||||
const padding = 14;
|
||||
const scale_x = Math.min((parent.width() - padding) / player_width, 1.5);
|
||||
const scale_y = Math.min((parent.height() - padding) / player_height, 1.5);
|
||||
let scale = Math.min(scale_x, scale_y);
|
||||
|
||||
let translate_x = 50, translate_y = 50;
|
||||
if(scale_x == scale_y && scale_x == scale) {
|
||||
//Equal scale
|
||||
} else if(scale_x == scale) {
|
||||
//We scale on the x-Axis
|
||||
//We have to adjust the y-Axis
|
||||
} else {
|
||||
//We scale on the y-Axis
|
||||
//We have to adjust the x-Axis
|
||||
|
||||
}
|
||||
//1 => 0 | 0
|
||||
//1.5 => 0 | 25
|
||||
//0.5 => 0 | -25
|
||||
//const translate_x = scale_x != scale ? 0 : undefined || 50 - (50 * ((parent.width() - padding) / player_width));
|
||||
//const translate_y = scale_y != scale || scale_y > 1 ? 0 : undefined || 50 - (50 * ((parent.height() - padding) / player_height));
|
||||
const transform = ("translate(0%, " + (scale * 50 - 50) + "%) scale(" + scale.toPrecision(2) + ")");
|
||||
|
||||
console.log("Parents: %o | %o", parent.width(), parent.height());
|
||||
console.log("Player: %o | %o", player_width, player_height);
|
||||
console.log("Scale: %f => translate: %o | %o", scale, translate_x, translate_y);
|
||||
player.css({
|
||||
transform: transform
|
||||
});
|
||||
console.log("Transform: " + transform);
|
||||
}
|
||||
}
|
||||
|
||||
available<V>(object: V): boolean {
|
||||
|
|
|
@ -6,7 +6,10 @@ namespace Modals {
|
|||
const modal = createModal({
|
||||
header: channel ? "Edit channel" : "Create channel",
|
||||
body: () => {
|
||||
let template = $("#tmpl_channel_edit").renderTag(channel ? channel.properties : new ChannelProperties());
|
||||
let template = $("#tmpl_channel_edit").renderTag(channel ? channel.properties : {
|
||||
channel_flag_maxfamilyclients_unlimited: true,
|
||||
channel_flag_maxclients_unlimited: true
|
||||
} as ChannelProperties);
|
||||
template = $.spawn("div").append(template);
|
||||
return template.tabify();
|
||||
},
|
||||
|
@ -62,6 +65,8 @@ namespace Modals {
|
|||
});
|
||||
|
||||
modal.open();
|
||||
if(!channel)
|
||||
modal.htmlTag.find(".channel_name").focus();
|
||||
}
|
||||
|
||||
function applyGeneralListener(properties: ChannelProperties, tag: JQuery, button: JQuery, create: boolean) {
|
||||
|
@ -71,7 +76,7 @@ namespace Modals {
|
|||
else button.attr("disabled", "true");
|
||||
};
|
||||
|
||||
tag.find(".channel_name").change(function (this: HTMLInputElement) {
|
||||
tag.find(".channel_name").on('change keyup', function (this: HTMLInputElement) {
|
||||
properties.channel_name = this.value;
|
||||
|
||||
$(this).removeClass("input_error");
|
||||
|
@ -101,8 +106,10 @@ namespace Modals {
|
|||
}).prop("disabled", !globalClient.permissions.neededPermission(create ? PermissionType.B_CHANNEL_CREATE_WITH_DESCRIPTION : PermissionType.B_CHANNEL_MODIFY_DESCRIPTION).granted(1));
|
||||
|
||||
if(create) {
|
||||
tag.find(".channel_name").trigger("change");
|
||||
tag.find(".channel_password").trigger('change');
|
||||
setTimeout(() => {
|
||||
tag.find(".channel_name").trigger("change");
|
||||
tag.find(".channel_password").trigger('change');
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/// <reference path="../../utils/modal.ts" />
|
||||
/// <reference path="../../proto.ts" />
|
||||
/// <reference path="../../client.ts" />
|
||||
|
||||
namespace Modals {
|
||||
export function spawnPoke(invoker: {
|
||||
name: string,
|
||||
id: number,
|
||||
unique_id: string
|
||||
}, message) {
|
||||
let modal;
|
||||
modal = createModal({
|
||||
header: "You have been poked!",
|
||||
body: () => {
|
||||
let template = $("#tmpl_poke_popup").renderTag({
|
||||
"invoker": ClientEntry.chatTag(invoker.id, invoker.name, invoker.unique_id, true),
|
||||
"message": message
|
||||
});
|
||||
template = $.spawn("div").append(template);
|
||||
|
||||
template.find(".button-close").on('click', event => modal.close());
|
||||
|
||||
return template;
|
||||
},
|
||||
footer: undefined,
|
||||
width: 750
|
||||
});
|
||||
modal.open();
|
||||
}
|
||||
}
|
|
@ -130,7 +130,9 @@ class ServerEntry {
|
|||
log.info(LogCategory.SERVER, "Changing server properties %o", properties);
|
||||
console.log("Changed properties: %o", properties);
|
||||
if (properties)
|
||||
this.channelTree.client.serverConnection.sendCommand("serveredit", properties);
|
||||
this.channelTree.client.serverConnection.sendCommand("serveredit", properties).then(() => {
|
||||
sound.play(Sound.SERVER_EDITED_SELF);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
|
|
@ -13,9 +13,14 @@ class ChannelTree {
|
|||
channels: ChannelEntry[];
|
||||
clients: ClientEntry[];
|
||||
|
||||
readonly client_mover: ClientMover;
|
||||
|
||||
constructor(client, htmlTree) {
|
||||
document.addEventListener("touchstart", function(){}, true);
|
||||
|
||||
this.client = client;
|
||||
this.htmlTree = htmlTree;
|
||||
this.client_mover = new ClientMover(this);
|
||||
this.reset();
|
||||
|
||||
if(!settings.static(Settings.KEY_DISABLE_CONTEXT_MENU, false)) {
|
||||
|
@ -122,6 +127,7 @@ class ChannelTree {
|
|||
elm.after(entry);
|
||||
|
||||
channel.adjustSize(true);
|
||||
|
||||
channel.initializeListener();
|
||||
}
|
||||
|
||||
|
@ -164,8 +170,12 @@ class ChannelTree {
|
|||
}
|
||||
|
||||
|
||||
if(oldParent) oldParent.adjustSize();
|
||||
if(channel) channel.adjustSize();
|
||||
if(oldParent) {
|
||||
oldParent.adjustSize();
|
||||
}
|
||||
if(channel) {
|
||||
channel.adjustSize();
|
||||
}
|
||||
}
|
||||
|
||||
deleteClient(client: ClientEntry) {
|
||||
|
@ -306,6 +316,7 @@ class ChannelTree {
|
|||
return new Promise<ChannelEntry>(resolve => { resolve(channel); })
|
||||
}).then(channel => {
|
||||
chat.serverChat().appendMessage("Channel {} successfully created!", true, channel.createChatTag());
|
||||
sound.play(Sound.CHANNEL_CREATED);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -15,6 +15,9 @@ class AudioController {
|
|||
static initializeAudioController() {
|
||||
if(!audio.player.initialize())
|
||||
console.warn("Failed to initialize audio controller!");
|
||||
sound.initialize().then(() => {
|
||||
console.log("Sounds initialitzed");
|
||||
});
|
||||
//this._globalReplayScheduler = setInterval(() => { AudioController.invokeNextReplay(); }, 20); //Fix me
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue