Updating project

canary
WolverinDEV 2019-04-15 15:33:51 +02:00
parent a10e794e3b
commit 27fcdcbd29
118 changed files with 3673 additions and 104460 deletions

1
.gitignore vendored
View File

@ -10,3 +10,4 @@ package-lock.json
.package-lock.json
TeaSpeakUI.tar.gz
TeaWeb-*.zip

View File

@ -1,19 +0,0 @@
sudo: true
dist: trusty
services:
- docker
before_install:
- echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
- docker pull $DOCKER_USERNAME/teaweb:build_new
jobs:
include:
- stage: "build"
name: TeaWeb build master branch
script:
- "mkdir -p /tmp/build"
- "docker run --rm -v /tmp/build/logs/:/build/logs/ -v /tmp/build/packages/:/build/packages/ -v `pwd`:/build/TeaWeb $DOCKER_USERNAME/teaweb:build_new --enable-release --enable-debug || travis_terminate 1;"
- "./scripts/travis_deploy.sh || travis_terminate 1;"
if: branch = master

View File

@ -1,4 +1,8 @@
# Changelog:
* **XX.XX.XX**
TODO:
- Save renamed name to use it the next time we try to connect to a server
* **04.04.19**
- Fixed issue with client icons not updating correctly (Showing invalid microphone state)
- Added multi server mode

View File

@ -1 +0,0 @@
/var/www/html/xforo/

3245
client/declarations/imports_shared.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -13,6 +13,11 @@
}
}
}
.reserved-slots {
display: inline;
color: red;
}
}
.select_server {

View File

@ -2385,10 +2385,12 @@
<td>{{tr "Address:" /}}</td>
<td>{{>server_address}}</td>
</tr>
<!--
<tr>
<td>{{tr "Type:"/}}</td>
<td>TeaSpeak</td>
</tr>
-->
<tr>
<td>{{tr "Version:"/}}</td>
<td><a title="{{>property_virtualserver_version}}">{{*: data.property_virtualserver_version.split(" ")[0]; }}</a> on {{>property_virtualserver_platform}}</td>
@ -2403,7 +2405,15 @@
</tr>
<tr>
<td>{{tr "Current Clients:"/}}</td>
<td>{{:property_virtualserver_clientsonline}}</td>
<td>
{{:property_virtualserver_clientsonline}}/{{:property_virtualserver_maxclients}}
{{if property_virtualserver_reserved_slots > 0}}
(<div class="reserved-slots">-{{:property_virtualserver_reserved_slots}} {{tr "Slots reserved" /}}</div>)
{{/if}}
{{if hidden_clients > 0}}
({{:hidden_clients}} {{tr "clients hidden" /}})
{{/if}}
</td>
</tr>
<tr>
<td>{{tr "Current Queries:"/}}</td>

View File

@ -10,9 +10,12 @@
/// <reference path="ui/frames/ControlBar.ts" />
/// <reference path="connection/ConnectionBase.ts" />
import spawnConnectModal = Modals.spawnConnectModal;
enum DisconnectReason {
HANDLER_DESTROYED,
REQUESTED,
DNS_FAILED,
CONNECT_FAILURE,
CONNECTION_CLOSED,
CONNECTION_FATAL_ERROR,
@ -22,6 +25,7 @@ enum DisconnectReason {
HANDSHAKE_FAILED,
SERVER_CLOSED,
SERVER_REQUIRES_PASSWORD,
IDENTITY_TOO_LOW,
UNKNOWN
}
@ -68,7 +72,7 @@ interface VoiceStatus {
class ConnectionHandler {
channelTree: ChannelTree;
serverConnection: connection.ServerConnection;
serverConnection: connection.AbstractServerConnection;
fileManager: FileManager;
@ -87,6 +91,7 @@ class ConnectionHandler {
private _local_client: LocalClientEntry;
private _reconnect_timer: NodeJS.Timer;
private _reconnect_attempt: boolean = false;
private _connect_initialize_id: number = 1;
client_status: VoiceStatus = {
input_hardware: false,
@ -112,7 +117,7 @@ class ConnectionHandler {
this.chat = new ChatBox(this);
this.sound = new sound.SoundManager(this);
this.serverConnection = new connection.ServerConnection(this);
this.serverConnection = connection.spawn_server_connection(this);
this.serverConnection.onconnectionstatechanged = this.on_connection_state_changed.bind(this);
this.fileManager = new FileManager(this);
@ -162,16 +167,48 @@ class ConnectionHandler {
console.log(tr("Start connection to %s:%d"), host, port);
this.channelTree.initialiseHead(addr, {host, port});
if(password && !password.hashed) {
helpers.hashPassword(password.password).then(password => {
this.chat.serverChat().appendMessage(tr("Initializing connection to {0}:{1}"), true, host, port);
const do_connect = (address: string, port: number) => {
const remote_address = {
host: address,
port: port
};
this.chat.serverChat().appendMessage(tr("Connecting to {0}:{1}"), true, address, port);
if(password && !password.hashed) {
helpers.hashPassword(password.password).then(password => {
/* errors will be already handled via the handle disconnect thing */
this.serverConnection.connect(remote_address, new connection.HandshakeHandler(profile, name, password));
}).catch(error => {
createErrorModal(tr("Error while hashing password"), tr("Failed to hash server password!<br>") + error).open();
})
} else {
/* errors will be already handled via the handle disconnect thing */
this.serverConnection.connect({host, port}, new connection.HandshakeHandler(profile, name, password));
this.serverConnection.connect(remote_address, new connection.HandshakeHandler(profile, name, password ? password.password : undefined));
}
};
if(dns.supported() && !host.match(Modals.Regex.IP_V4) && !host.match(Modals.Regex.IP_V6)) {
const id = ++this._connect_initialize_id;
this.chat.serverChat().appendMessage(tr("Resolving hostname..."));
dns.resolve_address(host, { timeout: 5000 }).then(result => {
if(id != this._connect_initialize_id)
return; /* we're old */
const _result = result || { target_ip: undefined, target_port: undefined };
//if(!result)
// throw "empty result";
this.chat.serverChat().appendMessage(tr("Hostname successfully resolved to {0}"), true, _result.target_ip || host);
do_connect(_result.target_ip || host, _result.target_port || port);
}).catch(error => {
createErrorModal(tr("Error while hashing password"), tr("Failed to hash server password!<br>") + error).open();
})
if(id != this._connect_initialize_id)
return; /* we're old */
this.handleDisconnect(DisconnectReason.DNS_FAILED, error);
});
} else {
/* errors will be already handled via the handle disconnect thing */
this.serverConnection.connect({host, port}, new connection.HandshakeHandler(profile, name, password ? password.password : undefined));
do_connect(host, port);
}
}
@ -188,7 +225,7 @@ class ConnectionHandler {
return this._clientId;
}
getServerConnection() : connection.ServerConnection { return this.serverConnection; }
getServerConnection() : connection.AbstractServerConnection { return this.serverConnection; }
/**
@ -250,8 +287,8 @@ class ConnectionHandler {
private generate_ssl_certificate_accept() : JQuery {
const properties = {
connect_default: true,
connect_profile: this.serverConnection._handshakeHandler.profile.id,
connect_address: this.serverConnection._remote_address.host + (this.serverConnection._remote_address.port !== 9987 ? ":" + this.serverConnection._remote_address.port : "")
connect_profile: this.serverConnection.handshake_handler().profile.id,
connect_address: this.serverConnection.remote_address().host + (this.serverConnection.remote_address().port !== 9987 ? ":" + this.serverConnection.remote_address().port : "")
};
const build_url = props => {
@ -265,7 +302,7 @@ class ConnectionHandler {
else
callback += "&" + parameters.join("&");
return "https://" + this.serverConnection._remote_address.host + ":" + this.serverConnection._remote_address.port + "/?forward_url=" + encodeURIComponent(callback);
return "https://" + this.serverConnection.remote_address().host + ":" + this.serverConnection.remote_address().port + "/?forward_url=" + encodeURIComponent(callback);
};
/* generate the tag */
@ -318,6 +355,8 @@ class ConnectionHandler {
private _certificate_modal: Modal;
handleDisconnect(type: DisconnectReason, data: any = {}) {
this._connect_initialize_id++;
this.tag_connection_handler.find(".server-name").text(tr("Not connected"));
let auto_reconnect = false;
switch (type) {
@ -327,13 +366,18 @@ class ConnectionHandler {
if(data)
this.sound.play(Sound.CONNECTION_DISCONNECTED);
break;
case DisconnectReason.DNS_FAILED:
console.error(tr("Failed to resolve hostname: %o"), data);
this.chat.serverChat().appendError(tr("Failed to resolve hostname: {0}"), data);
this.sound.play(Sound.CONNECTION_REFUSED);
break;
case DisconnectReason.CONNECT_FAILURE:
if(this._reconnect_attempt) {
auto_reconnect = true;
this.chat.serverChat().appendError(tr("Connect failed"));
break;
}
console.error(tr("Could not connect to remote host! Exception: %o"), data);
console.error(tr("Could not connect to remote host! Error: %o"), data);
if(native_client) {
createErrorModal(
@ -363,6 +407,15 @@ class ConnectionHandler {
tr("Failed to process handshake: ") + data as string
).open();
break;
case DisconnectReason.IDENTITY_TOO_LOW:
createErrorModal(
tr("Identity level is too low"),
MessageHelper.formatMessage(tr("You've been disconnected, because your Identity level is too low.{:br:}You need at least a level of {0}"), data["extra_message"])
).open();
this.sound.play(Sound.CONNECTION_DISCONNECTED);
auto_reconnect = false;
break;
case DisconnectReason.CONNECTION_CLOSED:
console.error(tr("Lost connection to remote server!"));
createErrorModal(
@ -397,9 +450,9 @@ class ConnectionHandler {
this.chat.serverChat().appendError(tr("Server requires password"));
createInputModal(tr("Server password"), tr("Enter server password:"), password => password.length != 0, password => {
if(!(typeof password === "string")) return;
this.startConnection(this.serverConnection._remote_address.host + ":" + this.serverConnection._remote_address.port,
this.serverConnection._handshakeHandler.profile,
this.serverConnection._handshakeHandler.name,
this.startConnection(this.serverConnection.remote_address().host + ":" + this.serverConnection.remote_address().port,
this.serverConnection.handshake_handler().profile,
this.serverConnection.handshake_handler().name,
{password: password as string, hashed: false});
}).open();
break;
@ -440,10 +493,10 @@ class ConnectionHandler {
this.chat.serverChat().appendMessage(tr("Reconnecting in 5 seconds"));
console.log(tr("Allowed to auto reconnect. Reconnecting in 5000ms"));
const server_address = this.serverConnection._remote_address;
const profile = this.serverConnection._handshakeHandler.profile;
const name = this.serverConnection._handshakeHandler.name;
const password = this.serverConnection._handshakeHandler.server_password;
const server_address = this.serverConnection.remote_address();
const profile = this.serverConnection.handshake_handler().profile;
const name = this.serverConnection.handshake_handler().name;
const password = this.serverConnection.handshake_handler().server_password;
this._reconnect_timer = setTimeout(() => {
this._reconnect_timer = undefined;
@ -518,8 +571,8 @@ class ConnectionHandler {
if(targetChannel && (!vconnection || vconnection.connected())) {
const encoding_supported = vconnection.encoding_supported(targetChannel.properties.channel_codec);
const decoding_supported = vconnection.decoding_supported(targetChannel.properties.channel_codec);
const encoding_supported = vconnection && vconnection.encoding_supported(targetChannel.properties.channel_codec);
const decoding_supported = vconnection && vconnection.decoding_supported(targetChannel.properties.channel_codec);
if(this.client_status.channel_codec_decoding_supported !== decoding_supported || this.client_status.channel_codec_encoding_supported !== encoding_supported) {
this.client_status.channel_codec_decoding_supported = decoding_supported;

View File

@ -44,97 +44,24 @@ namespace transfer {
overwrite: boolean;
}
export interface DownloadTransfer {
get_key() : DownloadKey;
request_file() : Promise<Response>;
}
export type DownloadKey = TransferKey;
export type UploadKey = TransferKey;
}
class StreamedFileDownload {
readonly transfer_key: transfer.DownloadKey;
currentSize: number = 0;
on_start: () => void = () => {};
on_complete: () => void = () => {};
on_fail: (reason: string) => void = (_) => {};
on_data: (data: Uint8Array) => void = (_) => {};
private _handle: FileManager;
private _promiseCallback: (value: StreamedFileDownload) => void;
private _socket: WebSocket;
private _active: boolean;
private _succeed: boolean;
private _parseActive: boolean;
constructor(key: transfer.DownloadKey) {
this.transfer_key = key;
export function spawn_download_transfer(key: DownloadKey) : DownloadTransfer {
return new RequestFileDownload(key);
}
start() {
if(!this.transfer_key) {
this.on_fail("Missing data!");
return;
}
console.debug(tr("Create new file download to %s:%s (Key: %s, Expect %d bytes)"), this.transfer_key.peer.hosts[0], this.transfer_key.peer.port, this.transfer_key.key, this.transfer_key.total_size);
this._active = true;
this._socket = new WebSocket("wss://" + this.transfer_key.peer.hosts[0] + ":" + this.transfer_key.peer.port);
this._socket.onopen = this.onOpen.bind(this);
this._socket.onclose = this.onClose.bind(this);
this._socket.onmessage = this.onMessage.bind(this);
this._socket.onerror = this.onError.bind(this);
}
private onOpen() {
if(!this._active) return;
this._socket.send(this.transfer_key.key);
this.on_start();
}
private onMessage(data: MessageEvent) {
if(!this._active) {
console.error(tr("Got data, but socket closed?"));
return;
}
this._parseActive = true;
let fileReader = new FileReader();
fileReader.onload = (event: any) => {
this.onBinaryData(new Uint8Array(event.target.result));
//if(this._socket.readyState != WebSocket.OPEN && !this._succeed) this.on_fail("unexpected close");
this._parseActive = false;
};
fileReader.readAsArrayBuffer(data.data);
}
private onBinaryData(data: Uint8Array) {
this.currentSize += data.length;
this.on_data(data);
if(this.currentSize == this.transfer_key.total_size) {
this._succeed = true;
this.on_complete();
this.disconnect();
}
}
private onError() {
if(!this._active) return;
this.on_fail(tr("an error occurent"));
this.disconnect();
}
private onClose() {
if(!this._active) return;
if(!this._parseActive) this.on_fail(tr("unexpected close (remote closed)"));
this.disconnect();
}
private disconnect(){
this._active = false;
//this._socket.close();
export function spawn_upload_transfer(key: DownloadKey) : DownloadTransfer {
return new RequestFileDownload(key);
}
}
class RequestFileDownload {
class RequestFileDownload implements transfer.DownloadTransfer {
readonly transfer_key: transfer.DownloadKey;
constructor(key: transfer.DownloadKey) {
@ -145,13 +72,6 @@ class RequestFileDownload {
return await this.try_fetch("https://" + this.transfer_key.peer.hosts[0] + ":" + this.transfer_key.peer.port);
}
/*
response.setHeader("Access-Control-Allow-Methods", {"GET, POST"});
response.setHeader("Access-Control-Allow-Origin", {"*"});
response.setHeader("Access-Control-Allow-Headers", {"*"});
response.setHeader("Access-Control-Max-Age", {"86400"});
response.setHeader("Access-Control-Expose-Headers", {"X-media-bytes"});
*/
private async try_fetch(url: string) : Promise<Response> {
const response = await fetch(url, {
method: 'GET',
@ -168,6 +88,10 @@ class RequestFileDownload {
throw (response.type == 'opaque' || response.type == 'opaqueredirect' ? "invalid cross origin flag! May target isn't a TeaSpeak server?" : response.statusText || "response is not ok");
return response;
}
get_key(): transfer.DownloadKey {
return this.transfer_key;
}
}
class RequestFileUpload {
@ -333,7 +257,8 @@ class FileManager extends connection.AbstractCommandHandler {
"name": file,
"cid": (channel ? channel.channelId : "0"),
"cpw": (password ? password : ""),
"clientftfid": transfer_data.client_transfer_id
"clientftfid": transfer_data.client_transfer_id,
"seekpos": 0
}).catch(reason => {
this.pending_download_requests.remove(transfer_data);
reject(reason);
@ -371,27 +296,28 @@ class FileManager extends connection.AbstractCommandHandler {
private notifyStartDownload(json) {
json = json[0];
let clientftfid = parseInt(json["clientftfid"]);
let transfer: transfer.DownloadKey;
for(let e of this.pending_download_requests)
if(e.client_transfer_id == json["clientftfid"]) {
if(e.client_transfer_id == clientftfid) {
transfer = e;
break;
}
transfer.server_transfer_id = json["serverftfid"];
transfer.server_transfer_id = parseInt(json["serverftfid"]);
transfer.key = json["ftkey"];
transfer.total_size = json["size"];
transfer.peer = {
hosts: (json["ip"] || "").split(","),
port: json["port"]
port: parseInt(json["port"])
};
if(transfer.peer.hosts.length == 0)
transfer.peer.hosts.push("0.0.0.0");
if(transfer.peer.hosts[0].length == 0 || transfer.peer.hosts[0] == '0.0.0.0')
transfer.peer.hosts[0] = this.handle.serverConnection._remote_address.host;
transfer.peer.hosts[0] = this.handle.serverConnection.remote_address().host;
(transfer["_callback"] as (val: transfer.DownloadKey) => void)(transfer);
this.pending_download_requests.remove(transfer);
@ -401,25 +327,26 @@ class FileManager extends connection.AbstractCommandHandler {
json = json[0];
let transfer: transfer.UploadKey;
let clientftfid = parseInt(json["clientftfid"]);
for(let e of this.pending_upload_requests)
if(e.client_transfer_id == json["clientftfid"]) {
if(e.client_transfer_id == clientftfid) {
transfer = e;
break;
}
transfer.server_transfer_id = json["serverftfid"];
transfer.server_transfer_id = parseInt(json["serverftfid"]);
transfer.key = json["ftkey"];
transfer.peer = {
hosts: (json["ip"] || "").split(","),
port: json["port"]
port: parseInt(json["port"])
};
if(transfer.peer.hosts.length == 0)
transfer.peer.hosts.push("0.0.0.0");
if(transfer.peer.hosts[0].length == 0 || transfer.peer.hosts[0] == '0.0.0.0')
transfer.peer.hosts[0] = this.handle.serverConnection._remote_address.host;
transfer.peer.hosts[0] = this.handle.serverConnection.remote_address().host;
(transfer["_callback"] as (val: transfer.UploadKey) => void)(transfer);
this.pending_upload_requests.remove(transfer);
@ -592,7 +519,7 @@ class IconManager {
throw "Failed to request icon";
}
const downloader = new RequestFileDownload(download_key);
const downloader = transfer.spawn_download_transfer(download_key);
let response: Response;
try {
response = await downloader.request_file();
@ -757,7 +684,7 @@ class AvatarManager {
throw "Failed to request icon";
}
const downloader = new RequestFileDownload(download_key);
const downloader = transfer.spawn_download_transfer(download_key);
let response: Response;
try {
response = await downloader.request_file();

View File

@ -7,10 +7,10 @@ namespace connection {
}
export class ConnectionCommandHandler extends AbstractCommandHandler {
readonly connection: ServerConnection;
readonly connection: AbstractServerConnection;
readonly connection_handler: ConnectionHandler;
constructor(connection: ServerConnection) {
constructor(connection: AbstractServerConnection) {
super(connection);
this.connection_handler = connection.client;
@ -68,7 +68,7 @@ namespace connection {
json = json[0]; //Only one bulk
let code : string = json["return_code"];
if(code.length == 0) {
if(!code || code.length == 0) {
console.log(tr("Invalid return code! (%o)"), json);
return;
}
@ -94,8 +94,6 @@ namespace connection {
const connection = this.connection.voice_connection();
if(connection instanceof audio.js.VoiceConnection)
connection.createSession();
else
throw "unknown voice connection";
} else {
console.log(tr("Skipping voice setup (No voice bridge available)"));
}
@ -220,205 +218,223 @@ namespace connection {
}
handleCommandClientEnterView(json) {
json = json[0]; //Only one bulk
let tree = this.connection.client.channelTree;
let client: ClientEntry;
let channel = tree.findChannel(json["ctid"]);
let old_channel = tree.findChannel(json["cfid"]);
let channel = undefined;
let old_channel = undefined;
let reason_id, reason_msg;
client = tree.findClient(json["clid"]);
let invokerid, invokername, invokeruid;
if(!client) {
if(parseInt(json["client_type_exact"]) == ClientType.CLIENT_MUSIC) {
client = new MusicClientEntry(parseInt(json["clid"]), json["client_nickname"]);
} else {
client = new ClientEntry(parseInt(json["clid"]), json["client_nickname"]);
}
for(const entry of json) {
/* attempt to update properties if given */
channel = typeof(entry["ctid"]) !== "undefined" ? tree.findChannel(parseInt(entry["ctid"])) : channel;
old_channel = typeof(entry["cfid"]) !== "undefined" ? tree.findChannel(parseInt(entry["cfid"])) : old_channel;
reason_id = typeof(entry["reasonid"]) !== "undefined" ? entry["reasonid"] : reason_id;
reason_msg = typeof(entry["reason_msg"]) !== "undefined" ? entry["reason_msg"] : reason_msg;
client.properties.client_type = parseInt(json["client_type"]);
client = tree.insertClient(client, channel);
} else {
if(client == this.connection.client.getClient())
this.connection_handler.chat.channelChat().name = channel.channelName();
tree.moveClient(client, channel);
}
invokerid = typeof(entry["invokerid"]) !== "undefined" ? parseInt(entry["invokerid"]) : invokerid;
invokername = typeof(entry["invokername"]) !== "undefined" ? entry["invokername"] : invokername;
invokeruid = typeof(entry["invokeruid"]) !== "undefined" ? entry["invokeruid"] : invokeruid;
if(this.connection_handler.client_status.queries_visible || client.properties.client_type != ClientType.CLIENT_QUERY) {
const own_channel = this.connection.client.getClient().currentChannel();
if(json["reasonid"] == ViewReasonId.VREASON_USER_ACTION) {
if(own_channel == channel)
if(old_channel)
this.connection_handler.sound.play(Sound.USER_ENTERED);
else
this.connection_handler.sound.play(Sound.USER_ENTERED_CONNECT);
if(old_channel) {
this.connection_handler.chat.serverChat().appendMessage(tr("{0} appeared from {1} to {2}"), true, client.createChatTag(true), old_channel.generate_tag(true), channel.generate_tag(true));
client = tree.findClient(parseInt(entry["clid"]));
if(!client) {
if(parseInt(entry["client_type_exact"]) == ClientType.CLIENT_MUSIC) {
client = new MusicClientEntry(parseInt(entry["clid"]), entry["client_nickname"]);
} else {
this.connection_handler.chat.serverChat().appendMessage(tr("{0} connected to channel {1}"), true, client.createChatTag(true), channel.generate_tag(true));
client = new ClientEntry(parseInt(entry["clid"]), entry["client_nickname"]);
}
} else if(json["reasonid"] == ViewReasonId.VREASON_MOVED) {
if(own_channel == channel)
this.connection_handler.sound.play(Sound.USER_ENTERED_MOVED);
this.connection_handler.chat.serverChat().appendMessage(tr("{0} appeared from {1} to {2}, moved by {3}"), true,
client.createChatTag(true),
old_channel ? old_channel.generate_tag(true) : undefined,
channel.generate_tag(true),
ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]),
);
} else if(json["reasonid"] == ViewReasonId.VREASON_CHANNEL_KICK) {
if(own_channel == channel)
this.connection_handler.sound.play(Sound.USER_ENTERED_KICKED);
this.connection_handler.chat.serverChat().appendMessage(tr("{0} appeared from {1} to {2}, kicked by {3}{4}"), true,
client.createChatTag(true),
old_channel ? old_channel.generate_tag(true) : undefined,
channel.generate_tag(true),
ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]),
json["reasonmsg"] > 0 ? " (" + json["msg"] + ")" : ""
);
client.properties.client_type = parseInt(entry["client_type"]);
client = tree.insertClient(client, channel);
} else {
console.warn(tr("Unknown reasonid for %o"), json["reasonid"]);
if(client == this.connection.client.getClient())
this.connection_handler.chat.channelChat().name = channel.channelName();
tree.moveClient(client, channel);
}
}
let updates: {
key: string,
value: string
}[] = [];
if(this.connection_handler.client_status.queries_visible || client.properties.client_type != ClientType.CLIENT_QUERY) {
const own_channel = this.connection.client.getClient().currentChannel();
if(reason_id == ViewReasonId.VREASON_USER_ACTION) {
if(own_channel == channel)
if(old_channel)
this.connection_handler.sound.play(Sound.USER_ENTERED);
else
this.connection_handler.sound.play(Sound.USER_ENTERED_CONNECT);
if(old_channel) {
this.connection_handler.chat.serverChat().appendMessage(tr("{0} appeared from {1} to {2}"), true, client.createChatTag(true), old_channel.generate_tag(true), channel.generate_tag(true));
} else {
this.connection_handler.chat.serverChat().appendMessage(tr("{0} connected to channel {1}"), true, client.createChatTag(true), channel.generate_tag(true));
}
} else if(reason_id == ViewReasonId.VREASON_MOVED) {
if(own_channel == channel)
this.connection_handler.sound.play(Sound.USER_ENTERED_MOVED);
for(let key in json) {
if(key == "cfid") continue;
if(key == "ctid") continue;
if(key === "invokerid") continue;
if(key === "invokername") continue;
if(key === "invokeruid") continue;
if(key === "reasonid") continue;
this.connection_handler.chat.serverChat().appendMessage(tr("{0} appeared from {1} to {2}, moved by {3}"), true,
client.createChatTag(true),
old_channel ? old_channel.generate_tag(true) : undefined,
channel.generate_tag(true),
ClientEntry.chatTag(invokerid, invokername, invokeruid),
);
} else if(reason_id == ViewReasonId.VREASON_CHANNEL_KICK) {
if(own_channel == channel)
this.connection_handler.sound.play(Sound.USER_ENTERED_KICKED);
updates.push({key: key, value: json[key]});
}
this.connection_handler.chat.serverChat().appendMessage(tr("{0} appeared from {1} to {2}, kicked by {3}{4}"), true,
client.createChatTag(true),
old_channel ? old_channel.generate_tag(true) : undefined,
channel.generate_tag(true),
ClientEntry.chatTag(invokerid, invokername, invokeruid),
reason_msg.length > 0 ? " (" + entry["msg"] + ")" : ""
);
} else {
console.warn(tr("Unknown reasonid for %o"), reason_id);
}
}
client.updateVariables(...updates);
let updates: {
key: string,
value: string
}[] = [];
{
let client_chat = client.chat(false);
if(!client_chat) {
for(const c of this.connection_handler.chat.open_chats()) {
if(c.owner_unique_id == client.properties.client_unique_identifier && c.flag_offline) {
client_chat = c;
break;
for(let key in entry) {
if(key == "cfid") continue;
if(key == "ctid") continue;
if(key === "invokerid") continue;
if(key === "invokername") continue;
if(key === "invokeruid") continue;
if(key === "reasonid") continue;
updates.push({key: key, value: entry[key]});
}
client.updateVariables(...updates);
{
let client_chat = client.chat(false);
if(!client_chat) {
for(const c of this.connection_handler.chat.open_chats()) {
if(c.owner_unique_id == client.properties.client_unique_identifier && c.flag_offline) {
client_chat = c;
break;
}
}
}
}
if(client_chat) {
client_chat.appendMessage(
"{0}", true,
if(client_chat) {
client_chat.appendMessage(
"{0}", true,
$.spawn("div")
.addClass("event-message event-partner-connect")
.text(tr("Your chat partner has reconnected"))
);
client_chat.flag_offline = false;
);
client_chat.flag_offline = false;
}
}
}
if(client instanceof LocalClientEntry) {
this.connection_handler.update_voice_status();
if(client instanceof LocalClientEntry) {
this.connection_handler.update_voice_status();
}
}
}
handleCommandClientLeftView(json) {
json = json[0]; //Only one bulk
let tree = this.connection.client.channelTree;
let client = tree.findClient(json["clid"]);
if(!client) {
console.error(tr("Unknown client left!"));
return 0;
}
if(client == this.connection.client.getClient()) {
if(json["reasonid"] == ViewReasonId.VREASON_BAN) {
this.connection.client.handleDisconnect(DisconnectReason.CLIENT_BANNED, json);
} else if(json["reasonid"] == ViewReasonId.VREASON_SERVER_KICK) {
this.connection.client.handleDisconnect(DisconnectReason.CLIENT_KICKED, json);
} else if(json["reasonid"] == ViewReasonId.VREASON_SERVER_SHUTDOWN) {
this.connection.client.handleDisconnect(DisconnectReason.SERVER_CLOSED, json);
} else if(json["reasonid"] == ViewReasonId.VREASON_SERVER_STOPPED) {
this.connection.client.handleDisconnect(DisconnectReason.SERVER_CLOSED, json);
} else
this.connection.client.handleDisconnect(DisconnectReason.UNKNOWN, json);
return;
}
let reason_id;
if(this.connection_handler.client_status.queries_visible || client.properties.client_type != ClientType.CLIENT_QUERY) {
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) {
this.connection_handler.chat.serverChat().appendMessage(tr("{0} disappeared from {1} to {2}"), true, client.createChatTag(true), channel_from.generate_tag(true), channel_to.generate_tag(true));
if(channel_from == own_channel)
this.connection_handler.sound.play(Sound.USER_LEFT);
} else if(json["reasonid"] == ViewReasonId.VREASON_SERVER_LEFT) {
this.connection_handler.chat.serverChat().appendMessage(tr("{0} left the server{1}"), true,
client.createChatTag(true),
json["reasonmsg"] ? " (" + json["reasonmsg"] + ")" : ""
);
if(channel_from == own_channel)
this.connection_handler.sound.play(Sound.USER_LEFT_DISCONNECT);
} else if(json["reasonid"] == ViewReasonId.VREASON_SERVER_KICK) {
this.connection_handler.chat.serverChat().appendError(tr("{0} was kicked from the server by {1}.{2}"),
client.createChatTag(true),
ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]),
json["reasonmsg"] ? " (" + json["reasonmsg"] + ")" : ""
);
if(channel_from == own_channel)
this.connection_handler.sound.play(Sound.USER_LEFT_KICKED_SERVER);
} else if(json["reasonid"] == ViewReasonId.VREASON_CHANNEL_KICK) {
this.connection_handler.chat.serverChat().appendError(tr("{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)
this.connection_handler.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"]));
this.connection_handler.chat.serverChat().appendError(tr("{0} was banned {1} by {2}.{3}"),
client.createChatTag(true),
duration,
ClientEntry.chatTag(json["invokerid"], json["invokername"], json["invokeruid"]),
json["reasonmsg"] ? " (" + json["reasonmsg"] + ")" : ""
);
if(channel_from == own_channel)
this.connection_handler.sound.play(Sound.USER_LEFT_BANNED);
} else {
console.error(tr("Unknown client left reason!"));
for(const entry of json) {
reason_id = entry["reasonid"] || reason_id;
let tree = this.connection.client.channelTree;
let client = tree.findClient(entry["clid"]);
if(!client) {
console.error(tr("Unknown client left!"));
return 0;
}
if(client == this.connection.client.getClient()) {
if(reason_id == ViewReasonId.VREASON_BAN) {
this.connection.client.handleDisconnect(DisconnectReason.CLIENT_BANNED, entry);
} else if(reason_id == ViewReasonId.VREASON_SERVER_KICK) {
this.connection.client.handleDisconnect(DisconnectReason.CLIENT_KICKED, entry);
} else if(reason_id == ViewReasonId.VREASON_SERVER_SHUTDOWN) {
this.connection.client.handleDisconnect(DisconnectReason.SERVER_CLOSED, entry);
} else if(reason_id == ViewReasonId.VREASON_SERVER_STOPPED) {
this.connection.client.handleDisconnect(DisconnectReason.SERVER_CLOSED, entry);
} else
this.connection.client.handleDisconnect(DisconnectReason.UNKNOWN, entry);
return;
}
{
const chat = client.chat(false);
if(chat) {
chat.flag_offline = true;
chat.appendMessage(
"{0}", true,
$.spawn("div")
.addClass("event-message event-partner-disconnect")
.text(tr("Your chat partner has disconnected"))
if(this.connection_handler.client_status.queries_visible || client.properties.client_type != ClientType.CLIENT_QUERY) {
const own_channel = this.connection.client.getClient().currentChannel();
let channel_from = tree.findChannel(entry["cfid"]);
let channel_to = tree.findChannel(entry["ctid"]);
if(reason_id == ViewReasonId.VREASON_USER_ACTION) {
this.connection_handler.chat.serverChat().appendMessage(tr("{0} disappeared from {1} to {2}"), true, client.createChatTag(true), channel_from.generate_tag(true), channel_to.generate_tag(true));
if(channel_from == own_channel)
this.connection_handler.sound.play(Sound.USER_LEFT);
} else if(reason_id == ViewReasonId.VREASON_SERVER_LEFT) {
this.connection_handler.chat.serverChat().appendMessage(tr("{0} left the server{1}"), true,
client.createChatTag(true),
entry["reasonmsg"] ? " (" + entry["reasonmsg"] + ")" : ""
);
if(channel_from == own_channel)
this.connection_handler.sound.play(Sound.USER_LEFT_DISCONNECT);
} else if(json["reasonid"] == ViewReasonId.VREASON_SERVER_KICK) {
this.connection_handler.chat.serverChat().appendError(tr("{0} was kicked from the server by {1}.{2}"),
client.createChatTag(true),
ClientEntry.chatTag(entry["invokerid"], entry["invokername"], entry["invokeruid"]),
entry["reasonmsg"] ? " (" + entry["reasonmsg"] + ")" : ""
);
if(channel_from == own_channel)
this.connection_handler.sound.play(Sound.USER_LEFT_KICKED_SERVER);
} else if(reason_id == ViewReasonId.VREASON_CHANNEL_KICK) {
this.connection_handler.chat.serverChat().appendError(tr("{0} was kicked from your channel by {1}.{2}"),
client.createChatTag(true),
ClientEntry.chatTag(entry["invokerid"], entry["invokername"], entry["invokeruid"]),
entry["reasonmsg"] ? " (" + entry["reasonmsg"] + ")" : ""
);
if(channel_from == own_channel)
this.connection_handler.sound.play(Sound.USER_LEFT_KICKED_CHANNEL);
} else if(reason_id == 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(entry["bantime"])
duration = "for " + formatDate(Number.parseInt(entry["bantime"]));
this.connection_handler.chat.serverChat().appendError(tr("{0} was banned {1} by {2}.{3}"),
client.createChatTag(true),
duration,
ClientEntry.chatTag(entry["invokerid"], entry["invokername"], entry["invokeruid"]),
entry["reasonmsg"] ? " (" + entry["reasonmsg"] + ")" : ""
);
if(channel_from == own_channel)
this.connection_handler.sound.play(Sound.USER_LEFT_BANNED);
} else {
console.error(tr("Unknown client left reason!"));
}
{
const chat = client.chat(false);
if(chat) {
chat.flag_offline = true;
chat.appendMessage(
"{0}", true,
$.spawn("div")
.addClass("event-message event-partner-disconnect")
.text(tr("Your chat partner has disconnected"))
);
}
}
}
}
tree.deleteClient(client);
tree.deleteClient(client);
}
}
handleNotifyClientMoved(json) {
@ -450,7 +466,7 @@ namespace connection {
tree.moveClient(client, channel_to);
for(const entry of current_clients || [])
if(entry !== client)
if(entry !== client && entry.get_audio_handle())
entry.get_audio_handle().abort_replay();
const own_channel = this.connection.client.getClient().currentChannel();

View File

@ -36,6 +36,9 @@ namespace connection {
abstract get onconnectionstatechanged() : ConnectionStateListener;
abstract set onconnectionstatechanged(listener: ConnectionStateListener);
abstract remote_address() : ServerAddress; /* only valid when connected */
abstract handshake_handler() : HandshakeHandler; /* only valid when connected */
}
export namespace voice {

View File

@ -8,7 +8,7 @@ namespace connection {
}
export class HandshakeHandler {
private connection: ServerConnection;
private connection: AbstractServerConnection;
private handshake_handler: HandshakeIdentityHandler;
private failed = false;
@ -22,11 +22,11 @@ namespace connection {
this.name = name;
}
setConnection(con: ServerConnection) {
setConnection(con: AbstractServerConnection) {
this.connection = con;
}
startHandshake() {
initialize() {
this.handshake_handler = this.profile.spawn_identity_handshake_handler(this.connection);
if(!this.handshake_handler) {
this.handshake_failed("failed to create identity handler");
@ -39,7 +39,13 @@ namespace connection {
else
this.handshake_failed(message);
});
}
get_identity_handler() : HandshakeIdentityHandler {
return this.handshake_handler;
}
startHandshake() {
this.handshake_handler.start_handshake();
}
@ -69,6 +75,7 @@ namespace connection {
client_nickname: this.name,
client_platform: (browser_name ? browser_name + " " : "") + navigator.platform,
client_version: "TeaWeb " + git_version + " (" + navigator.userAgent + ")",
client_version_sign: undefined,
client_server_password: this.server_password,
client_browser_engine: navigator.product,
@ -79,6 +86,8 @@ namespace connection {
client_output_muted: this.connection.client.client_status.output_muted,
};
//0.0.1 [Build: 1549713549] Linux 7XvKmrk7uid2ixHFeERGqcC8vupeQqDypLtw2lY9slDNPojEv//F47UaDLG+TmVk4r6S0TseIKefzBpiRtLDAQ==
if(version) {
data.client_version = "TeaClient ";
data.client_version += " " + version;
@ -98,16 +107,23 @@ namespace connection {
data.client_platform = (os_mapping[os.platform()] || os.platform());
}
/* required to keep compatibility */
if(this.profile.selected_type() === profiles.identities.IdentitifyType.TEAMSPEAK) {
data["client_key_offset"] = (this.profile.selected_identity() as profiles.identities.TeaSpeakIdentity).hash_number;
}
this.connection.send_command("clientinit", data).catch(error => {
this.connection.disconnect();
if(error instanceof CommandResult) {
if(error.id == 1028) {
this.connection.client.handleDisconnect(DisconnectReason.SERVER_REQUIRES_PASSWORD);
} else if(error.id == 783 || error.id == 519) {
error.extra_message = parseInt(error.extra_message) == NaN ? "8" : error.extra_message;
this.connection.client.handleDisconnect(DisconnectReason.IDENTITY_TOO_LOW, error);
} else {
this.connection.client.handleDisconnect(DisconnectReason.CLIENT_KICKED, error);
}
}
} else
this.connection.disconnect();
});
}
}

View File

@ -14,7 +14,7 @@ class CommandResult {
constructor(json) {
this.json = json;
this.id = json["id"];
this.id = parseInt(json["id"]);
this.message = json["msg"];
this.extra_message = "";
@ -34,10 +34,11 @@ class ReturnListener<T> {
namespace connection {
export class ServerConnection extends AbstractServerConnection {
_remote_address: ServerAddress;
_socket: WebSocket;
_connectionState: ConnectionState = ConnectionState.UNCONNECTED;
_handshakeHandler: HandshakeHandler;
private _remote_address: ServerAddress;
private _handshakeHandler: HandshakeHandler;
private _command_boss: ServerConnectionCommandBoss;
private _command_handler_default: ConnectionCommandHandler;
@ -71,6 +72,7 @@ namespace connection {
on_connect: () => void = () => {
console.log(tr("Socket connected"));
this.client.chat.serverChat().appendMessage(tr("Logging in..."));
this._handshakeHandler.initialize();
this._handshakeHandler.startHandshake();
};
@ -96,7 +98,6 @@ namespace connection {
this._handshakeHandler = handshake;
this._handshakeHandler.setConnection(this);
this._connected = false;
this.client.chat.serverChat().appendMessage(tr("Connecting to {0}:{1}"), true, address.host, address.port);
const self = this;
let local_socket: WebSocket;
@ -333,6 +334,18 @@ namespace connection {
set onconnectionstatechanged(listener: connection.ConnectionStateListener) {
this._connection_state_listener = listener;
}
handshake_handler(): connection.HandshakeHandler {
return this._handshakeHandler;
}
remote_address(): ServerAddress {
return this._remote_address;
}
}
export function spawn_server_connection(handle: ConnectionHandler) : AbstractServerConnection {
return new ServerConnection(handle); /* will be overridden by the client */
}
}

35
shared/js/dns.ts Normal file
View File

@ -0,0 +1,35 @@
namespace dns {
export interface AddressTarget {
target_ip: string;
target_port?: number;
}
export interface ResolveOptions {
timeout?: number;
allow_cache?: boolean;
max_depth?: number;
allow_srv?: boolean;
allow_cname?: boolean;
allow_any?: boolean;
allow_a?: boolean;
allow_aaaa?: boolean;
}
export const default_options: ResolveOptions = {
timeout: 5000,
allow_cache: true,
max_depth: 5,
allow_a: true,
allow_aaaa: true,
allow_any: true,
allow_cname: true,
allow_srv: true
};
export function supported() { return false; }
export function resolve_address(address: string, options?: ResolveOptions) : Promise<AddressTarget> {
return Promise.reject("not supported");
}
//TODO: Implement a remote server DNS request API
}

View File

@ -416,7 +416,7 @@ const loader_javascript = {
let file_path = request.url;
if(!file_path.startsWith("file://"))
throw "Invalid file path (" + file_path + ")";
file_path = file_path.substring(7);
file_path = file_path.substring(process.platform === "win32" ? 8 : 7);
const fs = require('fs');
if(fs.existsSync(file_path)) {
@ -591,6 +591,7 @@ const loader_javascript = {
"js/FileManager.js",
"js/ConnectionHandler.js",
"js/BrowserIPC.js",
"js/dns.js",
//Connection
"js/connection/CommandHandler.js",

View File

@ -551,6 +551,7 @@ class PermissionManager extends connection.AbstractCommandHandler {
let group = log.group(log.LogType.TRACE, LogCategory.PERMISSIONS, tr("Permission mapping"));
const table_entries = [];
let permission_id = 0;
for(let e of json) {
if(e["group_id_end"]) {
let group = new PermissionGroup();
@ -569,8 +570,10 @@ class PermissionManager extends connection.AbstractCommandHandler {
}
let perm = new PermissionInfo();
permission_id++;
perm.name = e["permname"];
perm.id = parseInt(e["permid"]);
perm.id = parseInt(e["permid"]) || permission_id; /* using permission_id as fallback if we dont have permid */
perm.description = e["permdesc"];
this.permissionList.push(perm);

View File

@ -136,6 +136,11 @@ namespace profiles {
/* generate default identity */
try {
const identity = await identities.TeaSpeakIdentity.generate_new();
let active = true;
setTimeout(() => {
active = false;
}, 1000);
await identity.improve_level(8, 1, () => active);
profile.set_identity(identities.IdentitifyType.TEAMSPEAK, identity);
profile.selected_identity_type = identities.IdentitifyType[identities.IdentitifyType.TEAMSPEAK];
} catch(error) {

View File

@ -222,6 +222,10 @@ namespace profiles.identities {
});
}
skip_and_initialize() {
this.trigger_success();
}
private handle_proof(json) {
if(!json[0]["digest"]) {
this.trigger_fail("server too old");

View File

@ -257,6 +257,8 @@ class Settings extends StaticSettings {
this.updated = false;
let global = JSON.stringify(this.cacheGlobal);
localStorage.setItem("settings.global", global);
if(localStorage.save)
localStorage.save();
}
}
@ -313,6 +315,8 @@ class ServerSettings extends SettingsBase {
let serverId = this.currentServer.properties.virtualserver_unique_identifier;
let server = JSON.stringify(this.cacheServer);
localStorage.setItem("settings.server_" + serverId, server);
if(localStorage.save)
localStorage.save();
}
}
}

View File

@ -816,6 +816,9 @@ class ChannelEntry {
});
else
this.flag_subscribed = false;
for(const client of this.clients(false))
this.channelTree.deleteClient(client, false);
}
}

View File

@ -97,7 +97,7 @@ function generate_tag(entry: ContextMenuEntry) : JQuery {
if(entry.disabled || entry.invalidPermission) tag.addClass("disabled");
else {
let menu = $.spawn("div").addClass("sub-menu").addClass("context-menu");
let menu = $.spawn("div").addClass("sub-menu").addClass("context-menu-container");
for(const e of entry.sub_menu) {
if(typeof(entry.visible) === 'boolean' && !entry.visible)
continue;

View File

@ -387,7 +387,15 @@ class ControlBar {
}
update_connection_state() {
switch (this.connection_handler.serverConnection ? this.connection_handler.serverConnection._connectionState : ConnectionState.UNCONNECTED) {
if(this.connection_handler.serverConnection && this.connection_handler.serverConnection.connected()) {
this.htmlTag.find(".container-disconnect").show();
this.htmlTag.find(".container-connect").hide();
} else {
this.htmlTag.find(".container-disconnect").hide();
this.htmlTag.find(".container-connect").show();
}
/*
switch (this.connection_handler.serverConnection ? this.connection_handler.serverConnection.connected() : ConnectionState.UNCONNECTED) {
case ConnectionState.CONNECTED:
case ConnectionState.CONNECTING:
case ConnectionState.INITIALISING:
@ -398,6 +406,7 @@ class ControlBar {
this.htmlTag.find(".container-disconnect").hide();
this.htmlTag.find(".container-connect").show();
}
*/
}
private on_execute_disconnect() {
@ -454,8 +463,8 @@ class ControlBar {
createInputModal(tr("Enter bookmarks name"), tr("Please enter the bookmarks name:<br>"), text => true, result => {
if(result) {
const bookmark = bookmarks.create_bookmark(result as string, bookmarks.bookmarks(), {
server_port: this.connection_handler.serverConnection._remote_address.port,
server_address: this.connection_handler.serverConnection._remote_address.host,
server_port: this.connection_handler.serverConnection.remote_address().port,
server_address: this.connection_handler.serverConnection.remote_address().host,
server_password: "",
server_password_hash: ""

View File

@ -398,6 +398,7 @@ class ServerInfoManager extends InfoManager<ServerEntry> {
properties["server_name"] = $.spawn("a").text(server.properties.virtualserver_name);
properties["server_onlinetime"] = formatDate(server.calculateUptime());
properties["server_address"] = server.remote_address.host + ":" + server.remote_address.port;
properties["hidden_clients"] = Math.max(0, server.properties.virtualserver_clientsonline - server.channelTree.clients.length);
for(let key in server.properties)
properties["property_" + key] = server.properties[key];

View File

@ -121,7 +121,7 @@ namespace Modals {
return;
}
let Regex = {
export const Regex = {
//DOMAIN<:port>
DOMAIN: /^(localhost|((([a-zA-Z0-9_-]{0,63}\.){0,253})?[a-zA-Z0-9_-]{0,63}\.[a-zA-Z]{2,64}))(|:(6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[0-5]?[0-9]{1,46}))$/,
//IP<:port>

View File

@ -178,7 +178,7 @@ class ServerEntry {
icon: "client-invite_buddy",
name: tr("Invite buddy"),
callback: () => {
const address = this.channelTree.client.serverConnection._remote_address.host + ":" + this.channelTree.client.serverConnection._remote_address.port;
const address = this.channelTree.client.serverConnection.remote_address().host + ":" + this.channelTree.client.serverConnection.remote_address().port;
const parameter = "connect_default=1&connect_address=" + encodeURIComponent(address);
const url = document.location.origin + document.location.pathname + "?" + parameter;

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.

View File

@ -1 +0,0 @@
[{"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"}, {"file": "group.server.assigned.wav", "key": "group.server.assigned"}, {"file": "group.server.revoked.wav", "key": "group.server.revoked"}, {"file": "group.channel.changed.wav", "key": "group.channel.changed"}, {"file": "group.server.assigned.self.wav", "key": "group.server.assigned.self"}, {"file": "group.server.revoked.self.wav", "key": "group.server.revoked.self"}, {"file": "group.channel.changed.self.wav", "key": "group.channel.changed.self"}]

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.

View File

@ -1,198 +0,0 @@
.loader {
margin: 0;
display: block;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 900;
text-align: center; }
.loader .half {
position: fixed;
background: #222222;
top: 0;
bottom: 0;
width: 50%;
height: 100%; }
.loader .half.right {
right: 0; }
.loader .half.left {
left: 0; }
.bookshelf_wrapper {
position: relative;
top: 40%;
left: 50%;
transform: translate(-50%, -50%); }
.books_list {
margin: 0 auto;
width: 300px;
padding: 0; }
.book_item {
position: absolute;
top: -120px;
box-sizing: border-box;
list-style: none;
width: 40px;
height: 120px;
opacity: 0;
background-color: #1e6cc7;
border: 5px solid white;
transform-origin: bottom left;
transform: translateX(300px);
animation: travel 2500ms linear infinite; }
.book_item.first {
top: -140px;
height: 140px; }
.book_item.first:before, .book_item.first:after {
content: '';
position: absolute;
top: 10px;
left: 0;
width: 100%;
height: 5px;
background-color: white; }
.book_item.first:after {
top: initial;
bottom: 10px; }
.book_item.second:before, .book_item.second:after, .book_item.fifth:before, .book_item.fifth:after {
box-sizing: border-box;
content: '';
position: absolute;
top: 10px;
left: 0;
width: 100%;
height: 17.5px;
border-top: 5px solid white;
border-bottom: 5px solid white; }
.book_item.second:after, .book_item.fifth:after {
top: initial;
bottom: 10px; }
.book_item.third:before, .book_item.third:after {
box-sizing: border-box;
content: '';
position: absolute;
top: 10px;
left: 9px;
width: 12px;
height: 12px;
border-radius: 50%;
border: 5px solid white; }
.book_item.third:after {
top: initial;
bottom: 10px; }
.book_item.fourth {
top: -130px;
height: 130px; }
.book_item.fourth:before {
box-sizing: border-box;
content: '';
position: absolute;
top: 46px;
left: 0;
width: 100%;
height: 17.5px;
border-top: 5px solid white;
border-bottom: 5px solid white; }
.book_item.fifth {
top: -100px;
height: 100px; }
.book_item.sixth {
top: -140px;
height: 140px; }
.book_item.sixth:before {
box-sizing: border-box;
content: '';
position: absolute;
bottom: 31px;
left: 0px;
width: 100%;
height: 5px;
background-color: white; }
.book_item.sixth:after {
box-sizing: border-box;
content: '';
position: absolute;
bottom: 10px;
left: 9px;
width: 12px;
height: 12px;
border-radius: 50%;
border: 5px solid white; }
.book_item:nth-child(2) {
animation-delay: 416.66667ms; }
.book_item:nth-child(3) {
animation-delay: 833.33333ms; }
.book_item:nth-child(4) {
animation-delay: 1250ms; }
.book_item:nth-child(5) {
animation-delay: 1666.66667ms; }
.book_item:nth-child(6) {
animation-delay: 2083.33333ms; }
.shelf {
width: 300px;
height: 5px;
margin: 0 auto;
background-color: white;
position: relative; }
.shelf:before, .shelf:after {
content: '';
position: absolute;
width: 100%;
height: 100%;
background: #222222;
background-image: radial-gradient(rgba(255, 255, 255, 0.5) 30%, transparent 0);
background-size: 10px 10px;
background-position: 0 -2.5px;
top: 200%;
left: 5%;
animation: move 250ms linear infinite; }
.shelf:after {
top: 400%;
left: 7.5%; }
@keyframes move {
from {
background-position-x: 0; }
to {
background-position-x: 10px; } }
@keyframes travel {
0% {
opacity: 0;
transform: translateX(300px) rotateZ(0deg) scaleY(1); }
6.5% {
transform: translateX(279.5px) rotateZ(0deg) scaleY(1.1); }
8.8% {
transform: translateX(273.6px) rotateZ(0deg) scaleY(1); }
10% {
opacity: 1;
transform: translateX(270px) rotateZ(0deg); }
17.6% {
transform: translateX(247.2px) rotateZ(-30deg); }
45% {
transform: translateX(165px) rotateZ(-30deg); }
49.5% {
transform: translateX(151.5px) rotateZ(-45deg); }
61.5% {
transform: translateX(115.5px) rotateZ(-45deg); }
67% {
transform: translateX(99px) rotateZ(-60deg); }
76% {
transform: translateX(72px) rotateZ(-60deg); }
83.5% {
opacity: 1;
transform: translateX(49.5px) rotateZ(-90deg); }
90% {
opacity: 0; }
100% {
opacity: 0;
transform: translateX(0px) rotateZ(-90deg); } }
/*# sourceMappingURL=loader.css.map */

File diff suppressed because one or more lines are too long

View File

@ -1,18 +0,0 @@
html, body {
height: 100%;
overflow-y: hidden; }
.app-container {
width: 100%;
height: 100%;
display: flex;
justify-content: center; }
.app-container .app {
width: 100%;
height: calc(100% - 50px);
margin: 0;
display: flex;
flex-direction: column;
resize: both; }
/*# sourceMappingURL=main.css.map */

File diff suppressed because one or more lines are too long

View File

@ -1,32 +0,0 @@
{
"info": {
"contributors": [
{
"name": "Markus Hadenfeldt",
"email": "i18n.client@teaspeak.de"
}
],
"name": "German translations"
},
"translations": [
{
"key": {
"message": "Show permission description",
"line": 374,
"character": 30,
"filename": "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts"
},
"translated": "Berechtigungsbeschreibung anzeigen",
"flags": [
"google-translate"
]
},
{
"key": {
"message": "Create a new connection"
},
"translated": "Verbinden",
"flags": [ ]
}
]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +0,0 @@
{
"translations": [
{
"key": "de_gt",
"path": "de_google_translate.translation"
},
{
"key": "pl_gt",
"path": "pl_google_translate.translation"
},
{
"key": "tr_gt",
"path": "tr_google_translate.translation"
},
{
"key": "fr_gt",
"path": "fr_google_translate.translation"
}
],
"name": "Default TeaSpeak repository",
"contact": "i18n@teaspeak.de"
}

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +0,0 @@
{
"info": {
"contributors": [
/* add yourself if you have done anything :) */
{
"name": "Markus Hadenfeldt", /* this field is required */
"email": "i18n.client@teaspeak.de" /* this field is required */
}
],
"name": "A template translation file" /* this field is required */
},
"translations": [ /* Array with all translation objects */
{ /* translation object */
"key": { /* the key */
"message": "Show permission description", /* necessary to identify the message */
"line": 374, /* optional, only for specify the translation for a specific case (Not supported yet!) */
"character": 30, /* optional, only for specify the translation for a specific case (Not supported yet!) */
"filename": "/home/wolverindev/TeaSpeak/TeaSpeak/Web-Client/shared/js/ui/modal/ModalPermissionEdit.ts" /* optional, only for specify the translation for a specific case (Not supported yet!) */
},
"translated": "Berechtigungsbeschreibung anzeigen", /* The actual translation */
"flags": [ /* some flags for this translation */
"google-translate", /* this translation has been made with google translator */
"verified" /* this translation has been verified by a native speaker */
]
}
]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 334 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,107 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100%"
height="100%"
viewBox="0 0 128 128"
version="1.1"
xml:space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"
id="svg13635"
inkscape:version="0.91 r13725"
sodipodi:docname="loading_image.svg"><metadata
id="metadata13682"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs13680" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview13678"
showgrid="false"
inkscape:zoom="1.84375"
inkscape:cx="64"
inkscape:cy="64"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg13635" /><g
transform="matrix(1,0,0,1,-2688,-480)"
id="g13637"><g
id="loading_image"
transform="matrix(1,0,0,1.37634,2688,294.194)"><rect
x="0"
y="135"
width="128"
height="93"
style="fill:none;"
id="rect13640" /><g
transform="matrix(1,0,0,0.726562,0,134.273)"
id="g13642"><path
d="M9.041,88.646C9.041,84.78 12.175,81.646 16.041,81.646L112.041,81.646C115.907,81.646 119.041,84.78 119.041,88.646L119.041,97.646C119.041,101.512 115.907,104.646 112.041,104.646L16.041,104.646C12.175,104.646 9.041,101.512 9.041,97.646L9.041,88.646L9.041,88.646Z"
style="fill:#a9aaac;fill-rule:nonzero;fill-opacity:1"
id="path13644" /></g><g
transform="matrix(1,0,0,0.726562,0,134.273)"
id="g13646"><path
d="M9.041,88.646C9.041,84.78 12.175,81.646 16.041,81.646L78.041,81.646C81.907,81.646 85.041,84.78 85.041,88.646L85.041,97.646C85.041,101.512 81.907,104.646 78.041,104.646L16.041,104.646C12.175,104.646 9.041,101.512 9.041,97.646L9.041,88.646L9.041,88.646Z"
style="fill:#7289da;fill-rule:nonzero;fill-opacity:1"
id="path13648" /></g><g
transform="matrix(1,0,0,0.726562,0,134.273)"
id="g13650"><path
d="M8.95,25.658L12.516,25.658L12.516,40.274L19.369,40.274L19.369,43.308L8.95,43.308L8.95,25.658Z"
style="fill:#a9aaac;fill-rule:nonzero;fill-opacity:1"
id="path13652" /><path
d="M29.13,25.354C30.429,25.354 31.6,25.565 32.645,25.986C33.69,26.408 34.579,27.011 35.313,27.795C36.046,28.578 36.611,29.527 37.008,30.639C37.403,31.752 37.602,33.009 37.602,34.407C37.602,35.824 37.395,37.096 36.982,38.225C36.568,39.355 35.987,40.32 35.237,41.121C34.487,41.923 33.576,42.537 32.506,42.967C31.436,43.397 30.243,43.612 28.928,43.612C27.63,43.612 26.449,43.401 25.387,42.98C24.325,42.558 23.423,41.951 22.681,41.159C21.939,40.367 21.366,39.41 20.962,38.289C20.557,37.167 20.355,35.908 20.355,34.509C20.355,31.575 21.123,29.316 22.657,27.731C24.19,26.147 26.349,25.354 29.13,25.354ZM28.915,28.111C28.205,28.111 27.559,28.262 26.976,28.566C26.393,28.87 25.89,29.299 25.467,29.856C25.044,30.412 24.719,31.087 24.49,31.879C24.262,32.671 24.149,33.548 24.149,34.509C24.149,35.469 24.262,36.342 24.49,37.125C24.719,37.909 25.049,38.575 25.479,39.124C25.91,39.671 26.421,40.097 27.013,40.401C27.604,40.705 28.272,40.856 29.016,40.856C29.725,40.856 30.372,40.701 30.956,40.388C31.538,40.076 32.041,39.642 32.464,39.086C32.886,38.529 33.216,37.859 33.453,37.075C33.69,36.291 33.808,35.428 33.808,34.483C33.808,33.505 33.694,32.621 33.465,31.827C33.237,31.035 32.907,30.365 32.476,29.817C32.045,29.269 31.53,28.848 30.93,28.553C30.331,28.258 29.659,28.111 28.915,28.111Z"
style="fill:#a9aaac;fill-rule:nonzero;fill-opacity:1"
id="path13654" /><path
d="M56.77,43.309L52.901,43.309L51.359,39.238L44,39.238L42.458,43.309L38.79,43.309L45.719,25.659L49.74,25.659L56.77,43.309ZM48.93,32.435C48.829,32.165 48.719,31.85 48.602,31.487C48.483,31.125 48.37,30.754 48.26,30.374C48.15,29.996 48.045,29.638 47.944,29.3C47.843,28.963 47.767,28.676 47.716,28.44L47.666,28.44C47.598,28.676 47.514,28.962 47.413,29.3C47.312,29.638 47.198,29.996 47.071,30.374C46.945,30.754 46.822,31.125 46.705,31.487C46.587,31.849 46.477,32.165 46.376,32.435L44.91,36.557L50.397,36.557L48.93,32.435Z"
style="fill:#a9aaac;fill-rule:nonzero;fill-opacity:1"
id="path13656" /><path
d="M63.976,25.658C65.459,25.658 66.837,25.814 68.111,26.126C69.383,26.438 70.488,26.947 71.424,27.655C72.36,28.364 73.089,29.283 73.612,30.411C74.134,31.541 74.396,32.924 74.396,34.559C74.396,36.11 74.125,37.438 73.586,38.541C73.047,39.646 72.309,40.552 71.373,41.26C70.438,41.968 69.338,42.486 68.073,42.816C66.808,43.144 65.443,43.309 63.976,43.309L59.146,43.309L59.146,25.659L63.976,25.659L63.976,25.658ZM62.712,40.603L63.647,40.603C64.625,40.603 65.544,40.498 66.403,40.287C67.262,40.076 68.008,39.736 68.641,39.263C69.273,38.791 69.774,38.167 70.146,37.391C70.516,36.616 70.703,35.663 70.703,34.534C70.703,33.355 70.516,32.372 70.146,31.588C69.774,30.804 69.273,30.176 68.641,29.704C68.008,29.232 67.262,28.903 66.403,28.718C65.544,28.532 64.624,28.439 63.647,28.439L62.712,28.439L62.712,40.603Z"
style="fill:#a9aaac;fill-rule:nonzero;fill-opacity:1"
id="path13658" /><rect
x="77.731"
y="25.658"
width="3.566"
height="17.65"
style="fill:#a9aaac;fill-rule:nonzero;fill-opacity:1"
id="rect13660" /><path
d="M97.051,25.658L100.264,25.658L100.264,43.308L95.762,43.308L91.236,34.66C91,34.222 90.759,33.745 90.515,33.231C90.271,32.718 90.03,32.211 89.794,31.714C89.558,31.217 89.343,30.749 89.148,30.311C88.955,29.873 88.798,29.51 88.681,29.223L88.63,29.223C88.647,29.493 88.663,29.877 88.681,30.373C88.698,30.871 88.709,31.406 88.719,31.979C88.727,32.552 88.736,33.117 88.743,33.674C88.752,34.229 88.757,34.694 88.757,35.064L88.757,43.308L85.544,43.308L85.544,25.658L90.3,25.658L94.75,34.382C94.919,34.702 95.112,35.09 95.332,35.545C95.551,36.001 95.774,36.472 96.003,36.961C96.23,37.451 96.445,37.927 96.647,38.39C96.85,38.854 97.017,39.237 97.154,39.54L97.204,39.54C97.186,39.22 97.17,38.786 97.154,38.239C97.136,37.69 97.12,37.105 97.103,36.48C97.085,35.857 97.073,35.241 97.065,34.634C97.055,34.028 97.051,33.505 97.051,33.067L97.051,25.658L97.051,25.658Z"
style="fill:#a9aaac;fill-rule:nonzero;fill-opacity:1"
id="path13662" /><path
d="M118.242,29.324C117.701,29.038 117.013,28.803 116.176,28.616C115.34,28.431 114.465,28.338 113.554,28.338C112.607,28.338 111.754,28.481 110.993,28.767C110.233,29.053 109.587,29.456 109.055,29.978C108.522,30.5 108.109,31.139 107.812,31.896C107.517,32.653 107.369,33.494 107.369,34.42C107.369,35.329 107.505,36.161 107.775,36.919C108.045,37.675 108.439,38.319 108.955,38.849C109.471,39.379 110.109,39.791 110.87,40.086C111.631,40.381 112.502,40.527 113.483,40.527C113.854,40.527 114.222,40.506 114.586,40.464C114.949,40.422 115.275,40.359 115.563,40.275L115.563,35.899L111.795,35.899L111.795,33.067L118.951,33.067L118.951,42.55C117.99,42.887 117.013,43.127 116.017,43.27C115.023,43.413 114.02,43.485 113.008,43.485C111.659,43.485 110.407,43.279 109.252,42.865C108.098,42.452 107.099,41.854 106.256,41.07C105.413,40.286 104.756,39.334 104.283,38.213C103.811,37.092 103.575,35.824 103.575,34.407C103.575,33.042 103.811,31.807 104.283,30.703C104.756,29.599 105.426,28.659 106.294,27.884C107.162,27.108 108.212,26.514 109.442,26.101C110.671,25.688 112.055,25.481 113.588,25.481C114.465,25.481 115.321,25.531 116.155,25.632C116.99,25.734 117.768,25.911 118.494,26.163L118.242,29.324Z"
style="fill:#a9aaac;fill-rule:nonzero;fill-opacity:1"
id="path13664" /><g
id="g13666"><rect
x="9.05"
y="50.073"
width="4.968"
height="24.584"
style="fill:#a9aaac;fill-rule:nonzero;fill-opacity:1"
id="rect13668" /><path
d="M31.734,61.802C32.064,62.835 32.422,64.02 32.809,65.359C33.196,66.698 33.532,67.941 33.812,69.092L33.882,69.092C34.212,67.941 34.576,66.697 34.974,65.359C35.374,64.02 35.738,62.835 36.066,61.802L40.012,50.073L47.725,50.073L47.725,74.657L42.97,74.657L42.97,62.647C42.97,62.06 42.97,61.39 42.97,60.639C42.97,59.888 42.976,59.107 42.988,58.295C42.999,57.486 43.012,56.682 43.023,55.883C43.035,55.085 43.052,54.334 43.076,53.629L43.006,53.629C42.817,54.216 42.618,54.861 42.407,55.567C42.195,56.271 41.978,56.976 41.755,57.679C41.532,58.385 41.321,59.054 41.122,59.688C40.921,60.322 40.752,60.863 40.611,61.309L35.857,74.657L31.418,74.657L26.839,61.449C26.746,61.167 26.592,60.698 26.382,60.04C26.17,59.382 25.942,58.654 25.695,57.855C25.449,57.057 25.214,56.277 24.99,55.513C24.767,54.751 24.585,54.121 24.444,53.629L24.374,53.629C24.397,54.334 24.414,55.085 24.427,55.883C24.439,56.681 24.45,57.486 24.462,58.295C24.474,59.107 24.481,59.888 24.481,60.639L24.481,74.657L19.937,74.657L19.937,50.073L27.898,50.073L31.734,61.802Z"
style="fill:#a9aaac;fill-rule:nonzero;fill-opacity:1"
id="path13670" /><path
d="M75.939,74.657L70.549,74.657L68.402,68.987L58.151,68.987L56.003,74.657L50.895,74.657L60.546,50.073L66.147,50.073L75.939,74.657ZM65.02,59.511C64.879,59.136 64.726,58.696 64.563,58.192C64.397,57.688 64.241,57.17 64.087,56.641C63.934,56.113 63.788,55.615 63.647,55.144C63.507,54.674 63.4,54.275 63.33,53.946L63.26,53.946C63.165,54.275 63.048,54.674 62.908,55.144C62.767,55.614 62.608,56.113 62.431,56.641C62.255,57.17 62.084,57.687 61.921,58.192C61.756,58.696 61.604,59.136 61.463,59.511L59.421,65.253L67.064,65.253L65.02,59.511Z"
style="fill:#a9aaac;fill-rule:nonzero;fill-opacity:1"
id="path13672" /><path
d="M98.023,55.179C97.269,54.78 96.31,54.452 95.146,54.193C93.98,53.935 92.761,53.806 91.493,53.806C90.175,53.806 88.986,54.005 87.926,54.404C86.868,54.802 85.968,55.364 85.227,56.091C84.485,56.818 83.909,57.708 83.497,58.762C83.085,59.817 82.878,60.988 82.878,62.278C82.878,63.544 83.067,64.703 83.445,65.758C83.82,66.812 84.369,67.708 85.087,68.446C85.806,69.184 86.694,69.759 87.755,70.169C88.816,70.579 90.027,70.784 91.395,70.784C91.914,70.784 92.426,70.754 92.932,70.696C93.438,70.637 93.892,70.55 94.292,70.432L94.292,64.337L89.043,64.337L89.043,60.393L99.011,60.393L99.011,73.601C97.672,74.071 96.311,74.405 94.925,74.604C93.54,74.803 92.143,74.905 90.734,74.905C88.855,74.905 87.112,74.618 85.504,74.042C83.895,73.467 82.504,72.634 81.329,71.541C80.155,70.448 79.24,69.123 78.583,67.561C77.925,66 77.597,64.233 77.597,62.26C77.597,60.358 77.925,58.638 78.583,57.1C79.24,55.562 80.174,54.252 81.383,53.173C82.593,52.092 84.054,51.265 85.77,50.69C87.483,50.115 89.409,49.827 91.545,49.827C92.766,49.827 93.958,49.898 95.121,50.038C96.283,50.18 97.368,50.426 98.379,50.777L98.023,55.179Z"
style="fill:#a9aaac;fill-rule:nonzero;fill-opacity:1"
id="path13674" /><path
d="M104.397,50.073L118.944,50.073L118.944,54.193L109.293,54.193L109.293,60.077L118.17,60.077L118.17,64.057L109.293,64.057L109.293,70.538L119.05,70.538L119.05,74.657L104.398,74.657L104.398,50.073L104.397,50.073Z"
style="fill:#a9aaac;fill-rule:nonzero;fill-opacity:1"
id="path13676" /></g></g></g></g>
</svg>

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45 45" style="enable-background:new 0 0 45 45;" xml:space="preserve" version="1.1" id="svg2"><metadata id="metadata8"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata><defs id="defs6"><clipPath id="clipPath16" clipPathUnits="userSpaceOnUse"><path id="path18" d="M 0,36 36,36 36,0 0,0 0,36 Z"/></clipPath><clipPath id="clipPath28" clipPathUnits="userSpaceOnUse"><path id="path30" d="M 2,18 C 2,9.164 9.164,2 18,2 l 0,0 c 8.836,0 16,7.164 16,16 l 0,0 c 0,8.836 -7.164,16 -16,16 l 0,0 C 9.164,34 2,26.836 2,18 m 11.235,0 c 0,2.632 2.133,4.765 4.765,4.765 l 0,0 c 2.631,0 4.766,-2.133 4.766,-4.765 l 0,0 c 0,-2.631 -2.135,-4.766 -4.766,-4.766 l 0,0 c -2.632,0 -4.765,2.135 -4.765,4.766"/></clipPath></defs><g transform="matrix(1.25,0,0,-1.25,0,45)" id="g10"><g id="g12"><g clip-path="url(#clipPath16)" id="g14"><g transform="translate(18,21)" id="g20"><path id="path22" style="fill:#8899a6;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 0,0 c -1.657,0 -3,-1.343 -3,-3 0,-1.657 1.343,-3 3,-3 1.657,0 3,1.343 3,3 0,1.657 -1.343,3 -3,3 m 18,-3 c 0,-9.941 -8.059,-18 -18,-18 -9.941,0 -18,8.059 -18,18 0,9.941 8.059,18 18,18 9.941,0 18,-8.059 18,-18"/></g></g></g><g id="g24"><g clip-path="url(#clipPath28)" id="g26"><g transform="translate(18,18)" id="g32"><path id="path34" style="fill:#ccd6dd;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 0,0 -18,2 0,16 16,0 2,-18 z"/></g><g transform="translate(18,18)" id="g36"><path id="path38" style="fill:#ccd6dd;fill-opacity:1;fill-rule:nonzero;stroke:none" d="M 0,0 18,-2 18,-18 2,-18 0,0 Z"/></g><g transform="translate(18.0005,17.9995)" id="g40"><path id="path42" style="fill:#f5f8fa;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 0,0 2.124,-18.999 15.875,1 L 0,0 Z"/></g><g transform="translate(18.0005,17.9995)" id="g44"><path id="path46" style="fill:#f5f8fa;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 0,0 -18.001,18.001 16,1 L 0,0 Z"/></g></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<g id="forward_2_">
<path d="M35.518,24.306l-10.971,8.592C24.329,33.065,24,32.978,24,32.703v-7.971v-0.022l-10.453,8.187
C13.329,33.065,13,32.978,13,32.703V15.28c0-0.275,0.329-0.362,0.547-0.194L24,23.242V23.22V15.28c0-0.275,0.329-0.362,0.547-0.194
l11.033,8.608C35.798,23.862,35.734,24.138,35.518,24.306z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 669 B

View File

@ -1,8 +0,0 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" height="300px" width="300px" version="1.0" viewBox="-300 -300 600 600" xml:space="preserve">
<circle stroke="#AAA" stroke-width="10" r="280" fill="#FFF"/>
<text style="letter-spacing:1;text-anchor:middle;text-align:center;stroke-opacity:.5;stroke:#000;stroke-width:2;fill:#444;font-size:360px;font-family:Bitstream Vera Sans,Liberation Sans, Arial, sans-serif;line-height:125%;writing-mode:lr-tb;" transform="scale(.2)">
<tspan y="-40" x="8">NO IMAGE</tspan>
<tspan y="400" x="8">AVAILABLE</tspan>
</text>
</svg>

Before

Width:  |  Height:  |  Size: 574 B

View File

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<g id="playlist_1_">
<path d="M37.192,23.032c-0.847,0.339-0.179-0.339-0.179-0.339s1.422-2.092,0.406-3.786c-0.793-1.321-3.338-1.075-4.42-1.669v14.154
c0,0.037-0.016,0.07-0.022,0.106c-0.154,1.504-1.607,3.034-3.696,3.712c-2.559,0.829-5.102,0.063-5.678-1.711
c-0.574-1.774,1.034-3.887,3.595-4.717c0.66-0.189,2.207-0.439,2.801-0.193V12.607C30,12.273,30.271,12,30.607,12h1.785
C32.728,12,33,12.273,33,12.607v0.549c1.542,1.004,6.18,1.455,6.851,4.139C40.656,20.52,38.038,22.693,37.192,23.032z M12.5,20H28
v-3H12.5c-0.275,0-0.5,0.225-0.5,0.5v2C12,19.775,12.225,20,12.5,20z M12.5,26H28v-3H12.5c-0.275,0-0.5,0.225-0.5,0.5v2
C12,25.775,12.225,26,12.5,26z M22.625,29H12.5c-0.275,0-0.5,0.225-0.5,0.5v2c0,0.275,0.225,0.5,0.5,0.5h8.551
C21.227,30.925,21.779,29.887,22.625,29z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 48 48" style="enable-background:new 0 0 48 48;" xml:space="preserve">
<g id="rewind_2_">
<path d="M35,15.28v17.423c0,0.274-0.329,0.362-0.547,0.194L24,24.711v0.022v7.971c0,0.274-0.329,0.362-0.547,0.194l-10.971-8.592
c-0.217-0.168-0.28-0.443-0.062-0.611l11.033-8.608C23.671,14.918,24,15.005,24,15.28v7.939v0.023l10.453-8.156
C34.671,14.918,35,15.005,35,15.28z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 653 B

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 231.2 231.2" style="enable-background:new 0 0 231.2 231.2;" xml:space="preserve">
<style type="text/css">
.st0{fill:#333333;}
</style>
<path class="st0" d="M230.5,102.8c-0.4-3.2-4.2-5.7-7.4-5.7c-10.6,0-20-6.2-23.9-15.8c-4-9.9-1.4-21.3,6.5-28.6
c2.5-2.3,2.8-6.1,0.7-8.7c-5.4-6.9-11.6-13.1-18.3-18.5c-2.6-2.1-6.5-1.8-8.8,0.7c-6.9,7.6-19.3,10.5-28.8,6.5
c-10-4.2-16.2-14.3-15.6-25.1c0.2-3.4-2.3-6.4-5.7-6.8c-8.6-1-17.3-1-26-0.1c-3.3,0.4-5.8,3.3-5.7,6.6c0.4,10.7-6,20.6-15.8,24.7
c-9.5,3.9-21.7,1-28.6-6.5c-2.3-2.5-6.1-2.8-8.7-0.7c-6.9,5.4-13.2,11.7-18.7,18.5c-2.1,2.7-1.8,6.5,0.7,8.8
c8,7.3,10.6,18.9,6.5,28.8c-4,9.5-13.9,15.6-25.2,15.6c-3.7-0.1-6.3,2.3-6.7,5.7c-1,8.7-1,17.5,0,26.3c0.4,3.3,4.3,5.7,7.6,5.7
c10.1-0.3,19.7,6,23.8,15.8c4,9.9,1.4,21.3-6.5,28.6c-2.5,2.3-2.8,6.1-0.7,8.7c5.4,6.8,11.5,13.1,18.3,18.5c2.7,2.1,6.5,1.8,8.8-0.7
c6.9-7.6,19.3-10.5,28.8-6.5c10,4.2,16.3,14.3,15.6,25.1c-0.2,3.4,2.3,6.4,5.7,6.8c4.4,0.5,8.9,0.8,13.3,0.8c4.2,0,8.5-0.2,12.7-0.7
c3.4-0.4,5.8-3.3,5.7-6.6c-0.4-10.7,6-20.6,15.8-24.7c9.5-3.9,21.8-1,28.6,6.5c2.3,2.5,6.1,2.8,8.7,0.7c6.9-5.4,13.2-11.6,18.7-18.5
c2.1-2.6,1.8-6.5-0.7-8.8c-8-7.3-10.7-18.9-6.5-28.8c3.9-9.4,13.4-15.7,23.6-15.7l1.4,0c3.3,0.3,6.4-2.3,6.8-5.7
C231.5,120.4,231.5,111.5,230.5,102.8z M115.6,182.3c-36.8,0-66.7-29.8-66.7-66.7S78.8,49,115.6,49s66.7,29.8,66.7,66.7
c0,12.5-3.4,24.2-9.4,34.2l-29.2-29.2c2.1-5,3.2-10.4,3.2-16c0-10.9-4.3-21.2-12-28.9c-7.7-7.7-18-12-28.9-12
c-3.6,0-7.3,0.5-10.8,1.4c-1.5,0.4-2.8,1.7-3.2,3.2c-0.4,1.6,0.1,3.2,1.3,4.4c0,0,14.4,14.5,19.2,19.3c0.5,0.5,0.5,1.7,0.4,2.1
l0,0.3c-0.5,5.3-1.4,11.7-2.2,14.1c-0.1,0.1-0.2,0.2-0.3,0.3c-0.1,0.1-0.2,0.2-0.3,0.3c-2.5,0.8-8.9,1.7-14.3,2.2l0,0l-0.2,0.1
c0,0-0.1,0-0.2,0c-0.6,0-1.4-0.2-2.2-0.9c-5-5-18.9-18.8-18.9-18.8c-1.2-1.2-2.5-1.5-3.4-1.5c-2,0-3.8,1.4-4.3,3.5
c-3.8,14.1,0.2,29.3,10.5,39.6c7.7,7.7,18,12,28.9,12c5.6,0,11-1.1,16-3.2l29.5,29.5C141.1,178.4,128.8,182.3,115.6,182.3z"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View File

@ -1,66 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 58 58" style="enable-background:new 0 0 58 58;" xml:space="preserve">
<g>
<path d="M6.5,41v15c0,1.009,1.22,2,2.463,2h40.074c1.243,0,2.463-0.991,2.463-2V41H6.5z M27.021,51.566
c0,0.474-0.087,0.873-0.26,1.196c-0.174,0.323-0.406,0.583-0.697,0.779c-0.292,0.196-0.627,0.333-1.005,0.41
s-0.769,0.116-1.169,0.116c-0.201,0-0.436-0.021-0.704-0.062s-0.547-0.104-0.834-0.191s-0.563-0.185-0.827-0.294
c-0.265-0.109-0.488-0.232-0.67-0.369l0.697-1.107c0.091,0.063,0.221,0.13,0.39,0.198s0.353,0.132,0.554,0.191
c0.2,0.06,0.41,0.111,0.629,0.157s0.424,0.068,0.615,0.068c0.482,0,0.868-0.094,1.155-0.28s0.439-0.504,0.458-0.95v-7.711h1.668
V51.566z M34.958,52.298c-0.15,0.342-0.362,0.643-0.636,0.902s-0.611,0.467-1.012,0.622c-0.401,0.155-0.857,0.232-1.367,0.232
c-0.219,0-0.444-0.012-0.677-0.034s-0.468-0.062-0.704-0.116c-0.237-0.055-0.463-0.13-0.677-0.226s-0.399-0.212-0.554-0.349
l0.287-1.176c0.127,0.073,0.289,0.144,0.485,0.212s0.398,0.132,0.608,0.191c0.209,0.06,0.419,0.107,0.629,0.144
c0.209,0.036,0.405,0.055,0.588,0.055c0.556,0,0.982-0.13,1.278-0.39s0.444-0.645,0.444-1.155c0-0.31-0.105-0.574-0.314-0.793
c-0.21-0.219-0.472-0.417-0.786-0.595s-0.654-0.355-1.019-0.533c-0.365-0.178-0.707-0.388-1.025-0.629
c-0.319-0.241-0.584-0.526-0.793-0.854c-0.21-0.328-0.314-0.738-0.314-1.23c0-0.446,0.082-0.843,0.246-1.189
s0.385-0.641,0.663-0.882s0.602-0.426,0.971-0.554s0.759-0.191,1.169-0.191c0.419,0,0.843,0.039,1.271,0.116
c0.428,0.077,0.774,0.203,1.039,0.376c-0.055,0.118-0.119,0.248-0.191,0.39c-0.073,0.142-0.142,0.273-0.205,0.396
c-0.064,0.123-0.119,0.226-0.164,0.308c-0.046,0.082-0.073,0.128-0.082,0.137c-0.055-0.027-0.116-0.063-0.185-0.109
s-0.167-0.091-0.294-0.137c-0.128-0.046-0.297-0.077-0.506-0.096c-0.21-0.019-0.479-0.014-0.807,0.014
c-0.183,0.019-0.355,0.07-0.52,0.157s-0.311,0.193-0.438,0.321c-0.128,0.128-0.229,0.271-0.301,0.431
c-0.073,0.159-0.109,0.313-0.109,0.458c0,0.364,0.104,0.658,0.314,0.882c0.209,0.224,0.469,0.419,0.779,0.588
c0.31,0.169,0.646,0.333,1.012,0.492c0.364,0.159,0.704,0.354,1.019,0.581s0.576,0.513,0.786,0.854
c0.209,0.342,0.314,0.781,0.314,1.319C35.184,51.603,35.108,51.956,34.958,52.298z"/>
<path d="M51.5,39V13.978c0-0.766-0.092-1.333-0.55-1.792L39.313,0.55C38.964,0.201,38.48,0,37.985,0H8.963
C7.777,0,6.5,0.916,6.5,2.926V39H51.5z M29.5,32c0,0.552-0.447,1-1,1s-1-0.448-1-1v-3c0-0.552,0.447-1,1-1s1,0.448,1,1V32z
M37.5,3.391c0-0.458,0.553-0.687,0.877-0.363l10.095,10.095C48.796,13.447,48.567,14,48.109,14H37.5V3.391z M36.5,23v-4
c0-0.551-0.448-1-1-1c-0.553,0-1-0.448-1-1s0.447-1,1-1c1.654,0,3,1.346,3,3v4c0,1.103,0.897,2,2,2c0.553,0,1,0.448,1,1
s-0.447,1-1,1c-1.103,0-2,0.897-2,2v4c0,1.654-1.346,3-3,3c-0.553,0-1-0.448-1-1s0.447-1,1-1c0.552,0,1-0.449,1-1v-4
c0-1.2,0.542-2.266,1.382-3C37.042,25.266,36.5,24.2,36.5,23z M28.5,21c0.828,0,1.5,0.672,1.5,1.5S29.328,24,28.5,24
S27,23.328,27,22.5S27.672,21,28.5,21z M16.5,25c1.103,0,2-0.897,2-2v-4c0-1.654,1.346-3,3-3c0.553,0,1,0.448,1,1s-0.447,1-1,1
c-0.552,0-1,0.449-1,1v4c0,1.2-0.542,2.266-1.382,3c0.84,0.734,1.382,1.8,1.382,3v4c0,0.551,0.448,1,1,1c0.553,0,1,0.448,1,1
s-0.447,1-1,1c-1.654,0-3-1.346-3-3v-4c0-1.103-0.897-2-2-2c-0.553,0-1-0.448-1-1S15.947,25,16.5,25z"/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

View File

@ -1,197 +0,0 @@
<?php
$testXF = false;
$localhost = false;
$_INCLIDE_ONLY = true;
if (file_exists('auth.php'))
include_once('auth.php');
else if (file_exists('auth/auth.php'))
include_once('auth/auth.php');
else {
function authPath() {
return "";
}
function redirectOnInvalidSession()
{
}
function logged_in() {
return false;
}
}
if(function_exists("setup_forum_auth"))
setup_forum_auth();
$localhost |= gethostname() == "WolverinDEV";
if(!$localhost || $testXF) {
//redirectOnInvalidSession();
}
$WEB_CLIENT = http_response_code() !== false;
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="TeaSpeak Web Client, connect to any TeaSpeak server without installing anything." />
<?php
if(!$WEB_CLIENT) {
echo "<title>TeaClient</title>";
} else {
echo "<title>TeaSpeak-Web</title>";
}
?>
<!-- PHP generated properties -->
<x-properties id="properties">
<?php
function spawn_property($name, $value, $element_id = null)
{
if(isset($value))
echo "\t\t\t<x-property key=\"" . $name . "\" " . (isset($element_id) ? "id=\"" . $element_id . "\" " : "") . "value=\"" . urlencode($value) . "\"></x-property>\r\n";
}
spawn_property('connect_default_host', $localhost ? "localhost" : "ts.TeaSpeak.de");
spawn_property('localhost_debug', $localhost ? "true" : "false");
if(isset($_COOKIE)) {
if(array_key_exists("COOKIE_NAME_USER_DATA", $GLOBALS) && array_key_exists($GLOBALS["COOKIE_NAME_USER_DATA"], $_COOKIE))
spawn_property('forum_user_data', $_COOKIE[$GLOBALS["COOKIE_NAME_USER_DATA"]]);
if(array_key_exists("COOKIE_NAME_USER_SIGN", $GLOBALS) && array_key_exists($GLOBALS["COOKIE_NAME_USER_SIGN"], $_COOKIE))
spawn_property('forum_user_sign', $_COOKIE[$GLOBALS["COOKIE_NAME_USER_SIGN"]]);
}
spawn_property('forum_path', authPath());
$version = file_get_contents("./version");
if ($version === false)
$version = "unknown";
spawn_property("version", $version, "app_version");
?>
</x-properties>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-113151733-4"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'UA-113151733-4');
</script>
<!-- required static style for the critical page and the enable javascript page -->
<style>
.fulloverlay {
z-index: 10000;
display: none;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: gray;
text-align: center;
}
.fulloverlay .container {
position: relative;
display: inline-block;
top: 30%;
max-width: unset!important; /* override bootstrap */
}
.no-js {
display: block;
}
</style>
<div id="style">
<link rel="stylesheet" href="css/loader/loader.css">
</div>
<div id="scripts">
<script type="application/javascript" src="js/load.js" defer></script>
</div>
</head>
<body>
<!-- No javascript error -->
<div class="fulloverlay no-js">
<div class="container">
<img src="img/script.svg" height="128px">
<h1>Please enable JavaScript</h1>
<h3>TeaSpeak web could not run without it!</h3>
<h3>Its like you, without coffee</h3>
</div>
</div>
<script type="text/javascript" class="no-js">
let elements = document.getElementsByClassName("no-js");
while (elements.length > 0) //Removing these elements (even self)
elements.item(0).remove();
</script>
<!-- Loading screen -->
<div class="loader">
<div class="half right"></div>
<div class="half left"></div>
<div class="bookshelf_wrapper">
<ul class="books_list">
<li class="book_item first"></li>
<li class="book_item second"></li>
<li class="book_item third"></li>
<li class="book_item fourth"></li>
<li class="book_item fifth"></li>
<li class="book_item sixth"></li>
</ul>
<div class="shelf"></div>
</div>
</div>
<!-- Critical load error -->
<div class="fulloverlay" id="critical-load">
<div class="container">
<img src="img/loading_error_right.svg" height="192px">
<h1 style="color: red">Ooops, we encountered some trouble while loading important files!</h1>
<h3 class="detail"></h3>
</div>
</div>
<div id="music-test"></div>
<div id="templates"></div>
<div id="sounds"></div>
<div id="mouse-move">
<div class="container">
</div>
</div>
</body>
<?php
$footer_style = "display: none;";
$footer_forum = '';
if($WEB_CLIENT) {
$footer_style = "display: block;";
if (logged_in()) {
$footer_forum = "<a href=\"" . authPath() . "auth.php?type=logout\">logout</a>";
} else {
$footer_forum = "<a href=\"" . authPath() . "login.php\">Login</a> via the TeaSpeak forum.";
}
}
?>
<footer style="<?php echo $footer_style; ?>">
<div class="container" style="display: flex; flex-direction: row; align-content: space-between;">
<div style="align-self: center; position: fixed; left: 5px;">Open source on <a href="https://github.com/TeaSpeak/TeaSpeak-Web" style="display: inline-block; position: relative">github.com</a></div>
<div style="align-self: center;">TeaSpeak Web client (<?php echo $version; ?>) by WolverinDEV</div>
<div style="align-self: center; position: fixed; right: 5px;"><?php echo $footer_forum; ?></div>
</div>
</footer>
</html>

File diff suppressed because one or more lines are too long

View File

@ -1,797 +0,0 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var app;
(function (app) {
let Type;
(function (Type) {
Type[Type["UNKNOWN"] = 0] = "UNKNOWN";
Type[Type["CLIENT_RELEASE"] = 1] = "CLIENT_RELEASE";
Type[Type["CLIENT_DEBUG"] = 2] = "CLIENT_DEBUG";
Type[Type["WEB_DEBUG"] = 3] = "WEB_DEBUG";
Type[Type["WEB_RELEASE"] = 4] = "WEB_RELEASE";
})(Type = app.Type || (app.Type = {}));
app.type = Type.UNKNOWN;
})(app || (app = {}));
var loader;
(function (loader) {
let Stage;
(function (Stage) {
/*
loading loader required files (incl this)
*/
Stage[Stage["INITIALIZING"] = 0] = "INITIALIZING";
/*
setting up the loading process
*/
Stage[Stage["SETUP"] = 1] = "SETUP";
/*
loading all style sheet files
*/
Stage[Stage["STYLE"] = 2] = "STYLE";
/*
loading all javascript files
*/
Stage[Stage["JAVASCRIPT"] = 3] = "JAVASCRIPT";
/*
loading all template files
*/
Stage[Stage["TEMPLATES"] = 4] = "TEMPLATES";
/*
initializing static/global stuff
*/
Stage[Stage["JAVASCRIPT_INITIALIZING"] = 5] = "JAVASCRIPT_INITIALIZING";
/*
finalizing load process
*/
Stage[Stage["FINALIZING"] = 6] = "FINALIZING";
/*
invoking main task
*/
Stage[Stage["LOADED"] = 7] = "LOADED";
Stage[Stage["DONE"] = 8] = "DONE";
})(Stage = loader.Stage || (loader.Stage = {}));
loader.allow_cached_files = false;
let current_stage = Stage.INITIALIZING;
const tasks = {};
function finished() {
return current_stage == Stage.DONE;
}
loader.finished = finished;
function register_task(stage, task) {
if (current_stage > stage) {
console.warn("Register loading task, but it had already been finished. Executing task anyways!");
task.function().catch(error => {
console.error("Failed to execute delayed loader task!");
console.log(" - %s: %o", task.name, error);
displayCriticalError(error);
});
return;
}
const task_array = tasks[stage] || [];
task_array.push(task);
tasks[stage] = task_array.sort((a, b) => a.priority > b.priority ? 1 : 0);
}
loader.register_task = register_task;
function execute() {
return __awaiter(this, void 0, void 0, function* () {
const load_begin = Date.now();
let begin = Date.now();
let end;
while (current_stage <= Stage.LOADED) {
let current_tasks = [];
while ((tasks[current_stage] || []).length > 0) {
if (current_tasks.length == 0 || current_tasks[0].priority == tasks[current_stage][0].priority) {
current_tasks.push(tasks[current_stage].pop());
}
else
break;
}
const errors = [];
const promises = [];
for (const task of current_tasks) {
try {
console.debug("Executing loader %s (%d)", task.name, task.priority);
promises.push(task.function().catch(error => {
errors.push({
task: task,
error: error
});
return Promise.resolve();
}));
}
catch (error) {
errors.push({
task: task,
error: error
});
}
}
yield Promise.all([...promises]);
if (errors.length > 0) {
console.error("Failed to execute loader. The following tasks failed (%d):", errors.length);
for (const error of errors)
console.error(" - %s: %o", error.task.name, error.error);
throw "failed to process step " + Stage[current_stage];
}
if (current_tasks.length == 0) {
if (current_stage < Stage.LOADED)
console.debug("[loader] entering next state (%s). Last state took %dms", Stage[current_stage + 1], (end = Date.now()) - begin);
else
console.debug("[loader] Finish invoke took %dms", (end = Date.now()) - begin);
begin = end;
current_stage += 1;
}
}
console.debug("[loader] finished loader. (Total time: %dms)", Date.now() - load_begin);
});
}
loader.execute = execute;
function script_name(path) {
if (Array.isArray(path)) {
let buffer = "";
let _or = " or ";
for (let entry of path)
buffer += _or + script_name(entry);
return buffer.slice(_or.length);
}
else
return "<code>" + path + "</code>";
}
class SyntaxError {
constructor(source) {
this.source = source;
}
}
function load_script(path) {
return __awaiter(this, void 0, void 0, function* () {
if (Array.isArray(path)) { //We have some fallback
return load_script(path[0]).catch(error => {
if (error instanceof SyntaxError)
return Promise.reject(error.source);
if (path.length > 1)
return load_script(path.slice(1));
return Promise.reject(error);
});
}
else {
return new Promise((resolve, reject) => {
const tag = document.createElement("script");
let error = false;
const error_handler = (event) => {
if (event.filename == tag.src && event.message.indexOf("Illegal constructor") == -1) { //Our tag throw an uncaught error
console.log("msg: %o, url: %o, line: %o, col: %o, error: %o", event.message, event.filename, event.lineno, event.colno, event.error);
window.removeEventListener('error', error_handler);
reject(new SyntaxError(event.error));
event.preventDefault();
error = true;
}
};
window.addEventListener('error', error_handler);
const timeout_handle = setTimeout(() => {
reject("timeout");
}, 5000);
tag.type = "application/javascript";
tag.async = true;
tag.defer = true;
tag.onerror = error => {
clearTimeout(timeout_handle);
window.removeEventListener('error', error_handler);
tag.remove();
reject(error);
};
tag.onload = () => {
clearTimeout(timeout_handle);
window.removeEventListener('error', error_handler);
console.debug("Script %o loaded", path);
setTimeout(resolve, 100);
};
document.getElementById("scripts").appendChild(tag);
tag.src = path + (loader.allow_cached_files ? "" : "?_ts=" + Date.now());
});
}
});
}
loader.load_script = load_script;
function load_scripts(paths) {
return __awaiter(this, void 0, void 0, function* () {
const promises = [];
const errors = [];
for (const script of paths)
promises.push(load_script(script).catch(error => {
errors.push({
script: script,
error: error
});
return Promise.resolve();
}));
yield Promise.all([...promises]);
if (errors.length > 0) {
console.error("Failed to load the following scripts:");
for (const script of errors)
console.log(" - %o: %o", script.script, script.error);
displayCriticalError("Failed to load script " + script_name(errors[0].script) + " <br>" + "View the browser console for more information!");
throw "failed to load script " + script_name(errors[0].script);
}
});
}
loader.load_scripts = load_scripts;
function load_style(path) {
return __awaiter(this, void 0, void 0, function* () {
if (Array.isArray(path)) { //We have some fallback
return load_script(path[0]).catch(error => {
if (error instanceof SyntaxError)
return Promise.reject(error.source);
if (path.length > 1)
return load_script(path.slice(1));
return Promise.reject(error);
});
}
else {
return new Promise((resolve, reject) => {
const tag = document.createElement("link");
let error = false;
const error_handler = (event) => {
console.log("msg: %o, url: %o, line: %o, col: %o, error: %o", event.message, event.filename, event.lineno, event.colno, event.error);
if (event.filename == tag.href) { //FIXME!
window.removeEventListener('error', error_handler);
reject(new SyntaxError(event.error));
event.preventDefault();
error = true;
}
};
window.addEventListener('error', error_handler);
const timeout_handle = setTimeout(() => {
reject("timeout");
}, 5000);
tag.type = "text/css";
tag.rel = "stylesheet";
tag.onerror = error => {
clearTimeout(timeout_handle);
window.removeEventListener('error', error_handler);
tag.remove();
console.error("File load error for file %s: %o", path, error);
reject("failed to load file " + path);
};
tag.onload = () => {
{
const css = tag.sheet;
const rules = css.cssRules;
const rules_remove = [];
const rules_add = [];
for (let index = 0; index < rules.length; index++) {
const rule = rules.item(index);
let rule_text = rule.cssText;
if (rule.cssText.indexOf("%%base_path%%") != -1) {
rules_remove.push(index);
rules_add.push(rule_text.replace("%%base_path%%", document.location.origin + document.location.pathname));
}
}
for (const index of rules_remove.sort((a, b) => b > a ? 1 : 0)) {
if (css.removeRule)
css.removeRule(index);
else
css.deleteRule(index);
}
for (const rule of rules_add)
css.insertRule(rule, rules_remove[0]);
}
clearTimeout(timeout_handle);
window.removeEventListener('error', error_handler);
console.debug("Style sheet %o loaded", path);
setTimeout(resolve, 100);
};
document.getElementById("style").appendChild(tag);
tag.href = path + (loader.allow_cached_files ? "" : "?_ts=" + Date.now());
});
}
});
}
loader.load_style = load_style;
function load_styles(paths) {
return __awaiter(this, void 0, void 0, function* () {
const promises = [];
const errors = [];
for (const sheet of paths)
promises.push(load_style(sheet).catch(error => {
errors.push({
sheet: sheet,
error: error
});
return Promise.resolve();
}));
yield Promise.all([...promises]);
if (errors.length > 0) {
console.error("Failed to load the following style sheet:");
for (const sheet of errors)
console.log(" - %o: %o", sheet.sheet, sheet.error);
displayCriticalError("Failed to load style sheet " + script_name(errors[0].sheet) + " <br>" + "View the browser console for more information!");
throw "failed to load style sheet " + script_name(errors[0].sheet);
}
});
}
loader.load_styles = load_styles;
})(loader || (loader = {}));
/* define that here */
let _critical_triggered = false;
const display_critical_load = message => {
if (_critical_triggered)
return; /* only show the first error */
_critical_triggered = true;
let tag = document.getElementById("critical-load");
let detail = tag.getElementsByClassName("detail")[0];
detail.innerHTML = message;
tag.style.display = "block";
fadeoutLoader();
};
const loader_impl_display_critical_error = message => {
if (typeof (createErrorModal) !== 'undefined' && typeof (window.ModalFunctions) !== 'undefined') {
createErrorModal("A critical error occurred while loading the page!", message, { closeable: false }).open();
}
else {
display_critical_load(message);
}
fadeoutLoader();
};
if (!window.impl_display_critical_error) { /* default impl */
window.impl_display_critical_error = loader_impl_display_critical_error;
}
function displayCriticalError(message) {
if (window.impl_display_critical_error)
window.impl_display_critical_error(message);
else
loader_impl_display_critical_error(message);
}
/* all javascript loaders */
const loader_javascript = {
detect_type: () => __awaiter(this, void 0, void 0, function* () {
/* test if js/proto.js is available. If so we're in debug mode */
const request = new XMLHttpRequest();
request.open('GET', 'js/proto.js', true);
yield new Promise((resolve, reject) => {
request.onreadystatechange = () => {
if (request.readyState === 4) {
if (request.status === 404) {
app.type = app.Type.WEB_RELEASE;
}
else {
app.type = app.Type.WEB_DEBUG;
}
resolve();
}
};
request.onerror = () => {
reject("Failed to detect app type");
};
request.send();
});
}),
load_scripts: () => __awaiter(this, void 0, void 0, function* () {
/*
if(window.require !== undefined) {
console.log("Loading node specific things");
const remote = require('electron').remote;
module.paths.push(remote.app.getAppPath() + "/node_modules");
module.paths.push(remote.app.getAppPath() + "/app");
module.paths.push(remote.getGlobal("browser-root") + "js/");
window.$ = require("assets/jquery.min.js");
require("native/loader_adapter.js");
}
*/
if (!window.require) {
yield loader.load_script(["vendor/jquery/jquery.min.js"]);
}
/* bootstrap material design and libs */
yield loader.load_script(["vendor/popper/popper.js"]);
//depends on popper
yield loader.load_script(["vendor/bootstrap-material/bootstrap-material-design.js"]);
loader.register_task(loader.Stage.JAVASCRIPT_INITIALIZING, {
name: "materialize body",
priority: 10,
function: () => __awaiter(this, void 0, void 0, function* () { $(document).ready(function () { $('body').bootstrapMaterialDesign(); }); })
});
yield loader.load_script("vendor/jsrender/jsrender.min.js");
yield loader.load_scripts([
["vendor/bbcode/xbbcode.js"],
["vendor/moment/moment.js"],
["https://webrtc.github.io/adapter/adapter-latest.js"]
]);
if (app.type == app.Type.WEB_RELEASE || app.type == app.Type.CLIENT_RELEASE) {
loader.register_task(loader.Stage.JAVASCRIPT, {
name: "scripts release",
priority: 20,
function: loader_javascript.loadRelease
});
}
else {
loader.register_task(loader.Stage.JAVASCRIPT, {
name: "scripts debug",
priority: 20,
function: loader_javascript.load_scripts_debug
});
}
}),
load_scripts_debug: () => __awaiter(this, void 0, void 0, function* () {
/* test if we're loading as TeaClient or WebClient */
if (!window.require) {
loader.register_task(loader.Stage.JAVASCRIPT, {
name: "javascript web",
priority: 10,
function: loader_javascript.load_scripts_debug_web
});
}
/* load some extends classes */
yield loader.load_scripts([
["js/connection/ConnectionBase.js"]
]);
/* load the main app */
yield loader.load_scripts([
//Load general API's
"js/proto.js",
"js/i18n/localize.js",
"js/log.js",
"js/sound/Sounds.js",
"js/utils/modal.js",
"js/utils/tab.js",
"js/utils/helpers.js",
"js/crypto/sha.js",
"js/crypto/hex.js",
"js/crypto/asn1.js",
//load the profiles
"js/profiles/ConnectionProfile.js",
"js/profiles/Identity.js",
//Load UI
"js/ui/modal/ModalQuery.js",
"js/ui/modal/ModalQueryManage.js",
"js/ui/modal/ModalPlaylistList.js",
"js/ui/modal/ModalPlaylistEdit.js",
"js/ui/modal/ModalBookmarks.js",
"js/ui/modal/ModalConnect.js",
"js/ui/modal/ModalSettings.js",
"js/ui/modal/ModalCreateChannel.js",
"js/ui/modal/ModalServerEdit.js",
"js/ui/modal/ModalChangeVolume.js",
"js/ui/modal/ModalBanClient.js",
"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",
"js/ui/channel.js",
"js/ui/client.js",
"js/ui/server.js",
"js/ui/view.js",
"js/ui/client_move.js",
"js/ui/context_divider.js",
"js/ui/htmltags.js",
"js/ui/frames/SelectedItemInfo.js",
"js/ui/frames/ControlBar.js",
//Load permissions
"js/permission/PermissionManager.js",
"js/permission/GroupManager.js",
//Load audio
"js/voice/VoiceHandler.js",
"js/voice/VoiceRecorder.js",
"js/voice/AudioResampler.js",
"js/voice/AudioController.js",
//Load codec
"js/codec/Codec.js",
"js/codec/BasicCodec.js",
//Load general stuff
"js/settings.js",
"js/bookmarks.js",
"js/contextMenu.js",
"js/FileManager.js",
"js/client.js",
"js/chat.js",
//Connection
"js/connection/CommandHandler.js",
"js/connection/CommandHelper.js",
"js/connection/HandshakeHandler.js",
"js/connection/ServerConnection.js",
"js/stats.js",
"js/PPTListener.js",
"js/codec/CodecWrapperWorker.js",
"js/profiles/identities/NameIdentity.js",
"js/profiles/identities/TeaForumIdentity.js",
"js/profiles/identities/TeamSpeakIdentity.js",
]);
yield loader.load_script("js/main.js");
}),
load_scripts_debug_web: () => __awaiter(this, void 0, void 0, function* () {
yield loader.load_scripts([
["js/audio/AudioPlayer.js"],
["js/audio/WebCodec.js"],
["js/WebPPTListener.js"]
]);
}),
load_release: () => __awaiter(this, void 0, void 0, function* () {
console.log("Load for release!");
yield loader.load_scripts([
//Load general API's
["js/client.min.js", "js/client.js"]
]);
})
};
const loader_webassembly = {
test_webassembly: () => __awaiter(this, void 0, void 0, function* () {
/* We dont required WebAssembly anymore for fundamental functions, only for auto decoding
if(typeof (WebAssembly) === "undefined" || typeof (WebAssembly.compile) === "undefined") {
console.log(navigator.browserSpecs);
if (navigator.browserSpecs.name == 'Safari') {
if (parseInt(navigator.browserSpecs.version) < 11) {
displayCriticalError("You require Safari 11 or higher to use the web client!<br>Safari " + navigator.browserSpecs.version + " does not support WebAssambly!");
return;
}
}
else {
// Do something for all other browsers.
}
displayCriticalError("You require WebAssembly for TeaSpeak-Web!");
throw "Missing web assembly";
}
*/
})
};
const loader_style = {
load_style: () => __awaiter(this, void 0, void 0, function* () {
yield loader.load_styles([
"vendor/bbcode/xbbcode.css"
]);
if (app.type == app.Type.WEB_DEBUG || app.type == app.Type.CLIENT_DEBUG) {
yield loader_style.load_style_debug();
}
else {
yield loader_style.load_style_release();
}
/* the material design */
yield loader.load_style("css/theme/bootstrap-material-design.css");
}),
load_style_debug: () => __awaiter(this, void 0, void 0, function* () {
yield loader.load_styles([
"css/static/main.css",
"css/static/helptag.css",
"css/static/scroll.css",
"css/static/channel-tree.css",
"css/static/ts/tab.css",
"css/static/ts/chat.css",
"css/static/ts/icons.css",
"css/static/general.css",
"css/static/modals.css",
"css/static/modal-bookmarks.css",
"css/static/modal-connect.css",
"css/static/modal-channel.css",
"css/static/modal-query.css",
"css/static/modal-playlist.css",
"css/static/modal-banlist.css",
"css/static/modal-bancreate.css",
"css/static/modal-settings.css",
"css/static/modal-poke.css",
"css/static/modal-server.css",
"css/static/modal-permissions.css",
"css/static/music/info_plate.css",
"css/static/frame/SelectInfo.css",
"css/static/control_bar.css",
"css/static/context_menu.css",
"css/static/htmltags.css"
]);
}),
load_style_release: () => __awaiter(this, void 0, void 0, function* () {
yield loader.load_styles([
"css/static/base.css",
"css/static/main.css",
]);
})
};
function load_templates() {
return __awaiter(this, void 0, void 0, function* () {
try {
const response = yield $.ajax("templates.html" + (loader.allow_cached_files ? "" : "?_ts" + Date.now()));
let node = document.createElement("html");
node.innerHTML = response;
let tags;
if (node.getElementsByTagName("body").length > 0)
tags = node.getElementsByTagName("body")[0].children;
else
tags = node.children;
let root = document.getElementById("templates");
if (!root) {
displayCriticalError("Failed to find template tag!");
return;
}
while (tags.length > 0) {
let tag = tags.item(0);
root.appendChild(tag);
}
}
catch (error) {
displayCriticalError("Failed to find template tag!");
throw "template error";
}
});
}
/* test if all files shall be load from cache or fetch again */
function check_updates() {
return __awaiter(this, void 0, void 0, function* () {
const app_version = (() => {
const version_node = document.getElementById("app_version");
if (!version_node)
return undefined;
const version = version_node.hasAttribute("value") ? version_node.getAttribute("value") : undefined;
if (!version)
return undefined;
if (version == "unknown" || version.replace(/0+/, "").length == 0)
return undefined;
return version;
})();
console.log("Found current app version: %o", app_version);
if (!app_version) {
/* TODO add warning */
loader.allow_cached_files = false;
return;
}
const cached_version = localStorage.getItem("cached_version");
if (!cached_version || cached_version != app_version) {
loader.allow_cached_files = false;
loader.register_task(loader.Stage.LOADED, {
priority: 0,
name: "cached version updater",
function: () => __awaiter(this, void 0, void 0, function* () {
localStorage.setItem("cached_version", app_version);
})
});
/* loading screen */
return;
}
loader.allow_cached_files = true;
});
}
//FUN: loader_ignore_age=0&loader_default_duration=1500&loader_default_age=5000
let _fadeout_warned = false;
function fadeoutLoader(duration = undefined, minAge = undefined, ignoreAge = undefined) {
if (typeof ($) === "undefined") {
if (!_fadeout_warned)
console.warn("Could not fadeout loader screen. Missing jquery functions.");
_fadeout_warned = true;
return;
}
let settingsDefined = typeof (StaticSettings) !== "undefined";
if (!duration) {
if (settingsDefined)
duration = StaticSettings.instance.static("loader_default_duration", 750);
else
duration = 750;
}
if (!minAge) {
if (settingsDefined)
minAge = StaticSettings.instance.static("loader_default_age", 1750);
else
minAge = 750;
}
if (!ignoreAge) {
if (settingsDefined)
ignoreAge = StaticSettings.instance.static("loader_ignore_age", false);
else
ignoreAge = false;
}
/*
let age = Date.now() - app.appLoaded;
if(age < minAge && !ignoreAge) {
setTimeout(() => fadeoutLoader(duration, 0, true), minAge - age);
return;
}
*/
$(".loader .bookshelf_wrapper").animate({ top: 0, opacity: 0 }, duration);
$(".loader .half").animate({ width: 0 }, duration, () => {
$(".loader").detach();
});
}
window["Module"] = window["Module"] || {};
navigator.browserSpecs = (function () {
let ua = navigator.userAgent, tem, M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if (/trident/i.test(M[1])) {
tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
return { name: 'IE', version: (tem[1] || '') };
}
if (M[1] === 'Chrome') {
tem = ua.match(/\b(OPR|Edge)\/(\d+)/);
if (tem != null)
return { name: tem[1].replace('OPR', 'Opera'), version: tem[2] };
}
M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?'];
if ((tem = ua.match(/version\/(\d+)/i)) != null)
M.splice(1, 1, tem[1]);
return { name: M[0], version: M[1] };
})();
console.log(navigator.browserSpecs); //Object { name: "Firefox", version: "42" }
/* register tasks */
loader.register_task(loader.Stage.INITIALIZING, {
name: "safari fix",
function: () => __awaiter(this, void 0, void 0, function* () {
/* safari remove "fix" */
if (Element.prototype.remove === undefined)
Object.defineProperty(Element.prototype, "remove", {
enumerable: false,
configurable: false,
writable: false,
value: function () {
this.parentElement.removeChild(this);
}
});
}),
priority: 50
});
/* TeaClient */
if (window.require) {
const path = require("path");
const remote = require('electron').remote;
module.paths.push(path.join(remote.app.getAppPath(), "/modules"));
module.paths.push(path.join(path.dirname(remote.getGlobal("browser-root")), "js"));
const connector = require("renderer");
console.log(connector);
loader.register_task(loader.Stage.INITIALIZING, {
name: "teaclient initialize",
function: connector.initialize,
priority: 40
});
}
loader.register_task(loader.Stage.INITIALIZING, {
name: "webassembly tester",
function: loader_webassembly.test_webassembly,
priority: 20
});
loader.register_task(loader.Stage.INITIALIZING, {
name: "app type test",
function: loader_javascript.detect_type,
priority: 20
});
loader.register_task(loader.Stage.INITIALIZING, {
name: "update tester",
priority: 60,
function: check_updates
});
loader.register_task(loader.Stage.JAVASCRIPT, {
name: "javascript",
function: loader_javascript.load_scripts,
priority: 10
});
loader.register_task(loader.Stage.STYLE, {
name: "style",
function: loader_style.load_style,
priority: 10
});
loader.register_task(loader.Stage.TEMPLATES, {
name: "templates",
function: load_templates,
priority: 10
});
loader.register_task(loader.Stage.LOADED, {
name: "loaded handler",
function: () => __awaiter(this, void 0, void 0, function* () {
fadeoutLoader();
}),
priority: 10
});
loader.register_task(loader.Stage.LOADED, {
name: "error task",
function: () => __awaiter(this, void 0, void 0, function* () {
if (Settings.instance.static("dummy_load_error", false)) {
displayCriticalError("The tea is cold!");
throw "The tea is cold!";
}
}),
priority: 20
});
loader.execute().then(() => {
console.log("app successfully loaded!");
}).catch(error => {
displayCriticalError("failed to load app!<br>Please lookup the browser console for more details");
console.error("Failed to load app!\nError: %o", error);
});
//# sourceMappingURL=load.js.map

View File

@ -1,234 +0,0 @@
const prefix = "[CodecWorker] ";
const workerCallbackToken = "callback_token";
let codecInstance;
onmessage = function (e) {
let data = e.data;
let res = {};
res.token = data.token;
res.success = false;
//console.log(prefix + " Got from main: %o", data);
switch (data.command) {
case "initialise":
let error;
console.log(prefix + "Got initialize for type " + CodecType[data.type]);
switch (data.type) {
case CodecType.OPUS_MUSIC:
codecInstance = new OpusWorker(2, OpusType.AUDIO);
break;
case CodecType.OPUS_VOICE:
codecInstance = new OpusWorker(1, OpusType.VOIP);
break;
default:
error = "Could not find worker type!";
console.error("Could not resolve opus type!");
break;
}
error = error || codecInstance.initialise();
if (error)
res["message"] = error;
else
res["success"] = true;
break;
case "encodeSamples":
let encodeArray = new Float32Array(data.dataLength);
for (let index = 0; index < encodeArray.length; index++)
encodeArray[index] = data.data[index];
let encodeResult = codecInstance.encode(encodeArray);
if (typeof encodeResult === "string") {
res.message = encodeResult;
}
else {
res.success = true;
res.data = encodeResult;
res.dataLength = encodeResult.length;
}
break;
case "decodeSamples":
let decodeArray = new Uint8Array(data.dataLength);
for (let index = 0; index < decodeArray.length; index++)
decodeArray[index] = data.data[index];
let decodeResult = codecInstance.decode(decodeArray);
if (typeof decodeResult === "string") {
res.message = decodeResult;
}
else {
res.success = true;
res.data = decodeResult;
res.dataLength = decodeResult.length;
}
break;
case "reset":
codecInstance.reset();
break;
default:
console.error(prefix + "Unknown type " + data.command);
}
if (res.token && res.token.length > 0)
sendMessage(res, e.origin);
};
function printMessageToServerTab(message) {
/*
sendMessage({
token: workerCallbackToken,
type: "chatmessage_server",
message: message
});
*/
}
function sendMessage(message, origin) {
message["timestamp"] = Date.now();
postMessage(message);
}
/// <reference path="CodecWorker.ts" />
const WASM_ERROR_MESSAGES = [
'no native wasm support detected'
];
this["Module"] = this["Module"] || {};
let initialized = false;
Module['onRuntimeInitialized'] = function () {
initialized = true;
console.log(prefix + "Initialized!");
sendMessage({
token: workerCallbackToken,
type: "loaded",
success: true
});
};
let abort_message = undefined;
let last_error_message;
Module['print'] = function () {
if (arguments.length == 1 && arguments[0] == abort_message)
return; /* we don't need to reprint the abort message! */
console.log(...arguments);
};
Module['printErr'] = function () {
if (arguments.length == 1 && arguments[0] == abort_message)
return; /* we don't need to reprint the abort message! */
last_error_message = arguments[0];
for (const suppress of WASM_ERROR_MESSAGES)
if (arguments[0].indexOf(suppress) != -1)
return;
console.error(...arguments);
};
Module['onAbort'] = (message) => {
/* no native wasm support detected */
Module['onAbort'] = undefined;
if (message instanceof DOMException)
message = "DOMException (" + message.name + "): " + message.code + " => " + message.message;
else {
abort_message = message;
if (message.indexOf("no binaryen method succeeded") != -1)
for (const error of WASM_ERROR_MESSAGES)
if (last_error_message.indexOf(error) != -1) {
message = "no native wasm support detected, but its required";
break;
}
}
sendMessage({
token: workerCallbackToken,
type: "loaded",
success: false,
message: message
});
};
try {
console.log("Node init!");
Module['locateFile'] = file => "../../wasm/" + file;
importScripts("../../wasm/TeaWeb-Worker-Codec-Opus.js");
}
catch (e) {
if (typeof (Module['onAbort']) === "function") {
console.log(e);
Module['onAbort']("Failed to load native scripts");
} /* else the error had been already handled because its a WASM error */
}
var OpusType;
(function (OpusType) {
OpusType[OpusType["VOIP"] = 2048] = "VOIP";
OpusType[OpusType["AUDIO"] = 2049] = "AUDIO";
OpusType[OpusType["RESTRICTED_LOWDELAY"] = 2051] = "RESTRICTED_LOWDELAY";
})(OpusType || (OpusType = {}));
class OpusWorker {
constructor(channelCount, type) {
this.bufferSize = 4096 * 2;
this.channelCount = channelCount;
this.type = type;
}
name() {
return "Opus (Type: " + OpusWorker[this.type] + " Channels: " + this.channelCount + ")";
}
initialise() {
this.fn_newHandle = Module.cwrap("codec_opus_createNativeHandle", "pointer", ["number", "number"]);
this.fn_decode = Module.cwrap("codec_opus_decode", "number", ["pointer", "pointer", "number", "number"]);
/* codec_opus_decode(handle, buffer, length, maxlength) */
this.fn_encode = Module.cwrap("codec_opus_encode", "number", ["pointer", "pointer", "number", "number"]);
this.fn_reset = Module.cwrap("codec_opus_reset", "number", ["pointer"]);
this.nativeHandle = this.fn_newHandle(this.channelCount, this.type);
this.encodeBufferRaw = Module._malloc(this.bufferSize);
this.encodeBuffer = new Float32Array(Module.HEAPF32.buffer, this.encodeBufferRaw, this.bufferSize / 4);
this.decodeBufferRaw = Module._malloc(this.bufferSize);
this.decodeBuffer = new Uint8Array(Module.HEAPU8.buffer, this.decodeBufferRaw, this.bufferSize);
return undefined;
}
deinitialise() { } //TODO
decode(data) {
if (data.byteLength > this.decodeBuffer.byteLength)
return "Data to long!";
this.decodeBuffer.set(data);
//console.log("decode(" + data.length + ")");
//console.log(data);
let result = this.fn_decode(this.nativeHandle, this.decodeBuffer.byteOffset, data.byteLength, this.decodeBuffer.byteLength);
if (result < 0) {
return "invalid result on decode (" + result + ")";
}
return Module.HEAPF32.slice(this.decodeBuffer.byteOffset / 4, (this.decodeBuffer.byteOffset / 4) + (result * this.channelCount));
}
encode(data) {
this.encodeBuffer.set(data);
let result = this.fn_encode(this.nativeHandle, this.encodeBuffer.byteOffset, data.length, this.encodeBuffer.byteLength);
if (result < 0) {
return "invalid result on encode (" + result + ")";
}
let buf = Module.HEAP8.slice(this.encodeBuffer.byteOffset, this.encodeBuffer.byteOffset + result);
return Uint8Array.from(buf);
}
reset() {
console.log(prefix + " Reseting opus codec!");
this.fn_reset(this.nativeHandle);
}
}
var CodecType;
(function (CodecType) {
CodecType[CodecType["OPUS_VOICE"] = 0] = "OPUS_VOICE";
CodecType[CodecType["OPUS_MUSIC"] = 1] = "OPUS_MUSIC";
CodecType[CodecType["SPEEX_NARROWBAND"] = 2] = "SPEEX_NARROWBAND";
CodecType[CodecType["SPEEX_WIDEBAND"] = 3] = "SPEEX_WIDEBAND";
CodecType[CodecType["SPEEX_ULTRA_WIDEBAND"] = 4] = "SPEEX_ULTRA_WIDEBAND";
CodecType[CodecType["CELT_MONO"] = 5] = "CELT_MONO";
})(CodecType || (CodecType = {}));
class BufferChunk {
constructor(buffer) {
this.buffer = buffer;
this.index = 0;
}
copyRangeTo(target, maxLength, offset) {
let copy = Math.min(this.buffer.length - this.index, maxLength);
//TODO may warning if channel counts are not queal?
for (let channel = 0; channel < Math.min(target.numberOfChannels, this.buffer.numberOfChannels); channel++) {
target.getChannelData(channel).set(this.buffer.getChannelData(channel).subarray(this.index, this.index + copy), offset);
}
return copy;
}
}
class CodecClientCache {
constructor() {
this._chunks = [];
}
bufferedSamples(max = 0) {
let value = 0;
for (let i = 0; i < this._chunks.length && value < max; i++)
value += this._chunks[i].buffer.length - this._chunks[i].index;
return value;
}
}
//# sourceMappingURL=WorkerCodec.js.map

View File

@ -1,90 +0,0 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
const prefix = "[POWWorker] ";
let initialized = false;
let memory;
let memory_u8;
let wasm_object;
function post_status(code, result) {
let data = {};
data.code = code;
if (typeof (result) === "string") {
data.success = false;
data.message = result;
}
else if (typeof (result) === "boolean") {
data.success = result;
}
else {
data.success = true;
Object.assign(data, result);
}
postMessage(data);
}
{
memory = new WebAssembly.Memory({ initial: 1 });
memory_u8 = new Uint8Array(memory.buffer);
if (typeof (WebAssembly.instantiateStreaming) === "undefined") {
WebAssembly.instantiateStreaming = (stream, imports) => __awaiter(this, void 0, void 0, function* () {
const response = yield stream;
const buffer = yield response.arrayBuffer();
return WebAssembly.instantiate(buffer, imports);
});
}
WebAssembly.instantiateStreaming(fetch('../../wat/pow/sha1.wasm'), {
env: {
memory: memory
}
}).then(object => {
wasm_object = object;
post_status("initialize", true);
}).catch(error => {
post_status("initialize", "failed to initialize WASM handle (" + error + ")");
});
}
let key_offset = 0;
let hash_offset = 0;
onmessage = function (e) {
let data = e.data;
//console.log(prefix + "Got data: %o", data);
if (data.type == "set_data") {
const key = data.private_key;
key_offset = 0;
for (const char of key)
memory_u8[0x0A0 + key_offset++] = char.charCodeAt(0);
post_status(data.code, true);
}
else if (data.type == "mine") {
let hash = data.hash;
const iterations = data.iterations;
const target = data.target;
hash_offset = 0;
for (const char of hash) {
memory_u8[0x0A0 + key_offset + hash_offset++] = char.charCodeAt(0);
}
let level = wasm_object.instance.exports.mine(key_offset, hash_offset, iterations, target > 1 ? target - 1 : target);
hash = "";
hash_offset = 0;
while (memory_u8[0x0A0 + key_offset + hash_offset] != 0)
hash = hash + String.fromCharCode(memory_u8[0x0A0 + key_offset + hash_offset++]);
console.log(prefix + "New hash: %s, level %o", hash, level);
post_status(data.code, {
result: level >= target,
hash: hash,
level: level
});
}
else if (data.type == "finalize") {
wasm_object = undefined;
memory = undefined;
memory_u8 = undefined;
post_status(data.code, true);
}
};
//# sourceMappingURL=WorkerPOW.js.map

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More