test
All checks were successful
/ upload (release) Successful in 25s

This commit is contained in:
pavel 2026-02-24 21:37:18 +01:00
commit d703501b78
12 changed files with 4062 additions and 72 deletions

View file

@ -31,6 +31,8 @@ const state = {
onlineUsers: new Set(),
};
const el = {
authScreen: document.getElementById("auth-screen"),
loginBtn: document.getElementById("login-btn"),
@ -724,22 +726,35 @@ function ensurePeerConnection(peerId) {
const pc = new RTCPeerConnection({ iceServers: state.voice.iceServers });
// Add transceivers in a fixed order to ensure stable SDP m-lines: [Audio, Camera, Screen]
// 1. Audio
if (state.voice.localStream) {
for (const track of state.voice.localStream.getTracks()) {
pc.addTrack(track, state.voice.localStream);
}
pc.addTransceiver(state.voice.localStream.getAudioTracks()[0], {
direction: 'sendrecv',
streams: [state.voice.localStream]
});
} else {
pc.addTransceiver('audio', { direction: 'sendrecv' });
}
// 2. Camera Video
if (state.voice.videoStream) {
for (const track of state.voice.videoStream.getTracks()) {
pc.addTrack(track, state.voice.videoStream);
}
pc.addTransceiver(state.voice.videoStream.getVideoTracks()[0], {
direction: 'sendrecv',
streams: [state.voice.videoStream]
});
} else {
pc.addTransceiver('video', { direction: 'sendrecv' });
}
// 3. Screen Video
if (state.voice.screenStream) {
for (const track of state.voice.screenStream.getTracks()) {
pc.addTrack(track, state.voice.screenStream);
}
pc.addTransceiver(state.voice.screenStream.getVideoTracks()[0], {
direction: 'sendrecv',
streams: [state.voice.screenStream]
});
} else {
pc.addTransceiver('video', { direction: 'sendrecv' });
}
pc.onicecandidate = (event) => {
@ -945,11 +960,12 @@ async function toggleVideo() {
if (state.voice.ws) {
state.voice.ws.send(JSON.stringify({ type: "set_video_status", is_sharing_video: false }));
}
const trackId = `video-${state.me.id}-camera`;
for (const pc of state.voice.peerConnections.values()) {
const senders = pc.getSenders();
const videoSender = senders.find(s => s.track && s.track.kind === "video" && !s.track.label.toLowerCase().includes('screen'));
if (videoSender) pc.removeTrack(videoSender);
const transceivers = pc.getTransceivers();
const cameraTransceiver = transceivers.find(t => t.receiver.track.kind === 'video' && t.mid === transceivers[1].mid);
if (cameraTransceiver) {
cameraTransceiver.sender.replaceTrack(null);
}
}
} else {
try {
@ -963,8 +979,9 @@ async function toggleVideo() {
}
for (const pc of state.voice.peerConnections.values()) {
for (const track of stream.getTracks()) {
pc.addTrack(track, stream);
const transceivers = pc.getTransceivers();
if (transceivers[1]) {
transceivers[1].sender.replaceTrack(stream.getVideoTracks()[0]);
}
}
} catch (err) {
@ -986,9 +1003,10 @@ async function toggleScreenShare() {
state.voice.ws.send(JSON.stringify({ type: "set_screen_status", is_sharing_screen: false }));
}
for (const pc of state.voice.peerConnections.values()) {
const senders = pc.getSenders();
const screenSender = senders.find(s => s.track && s.track.kind === "video" && (s.track.label.toLowerCase().includes('screen') || s.track.label.toLowerCase().includes('monitor')));
if (screenSender) pc.removeTrack(screenSender);
const transceivers = pc.getTransceivers();
if (transceivers[2]) {
transceivers[2].sender.replaceTrack(null);
}
}
} else {
try {
@ -1007,8 +1025,9 @@ async function toggleScreenShare() {
}
for (const pc of state.voice.peerConnections.values()) {
for (const track of stream.getTracks()) {
pc.addTrack(track, stream);
const transceivers = pc.getTransceivers();
if (transceivers[2]) {
transceivers[2].sender.replaceTrack(stream.getVideoTracks()[0]);
}
}
} catch (err) {
@ -1137,11 +1156,26 @@ function closeMobileMenus() {
async function init() {
lucide.createIcons();
try {
const searchParams = new URLSearchParams(location.search);
const jwtToken = searchParams.get("token");
if (jwtToken) {
localStorage.setItem("chattz_token", jwtToken);
searchParams.delete("token");
const nextQuery = searchParams.toString();
const nextUrl = `${location.pathname}${nextQuery ? `?${nextQuery}` : ""}`;
history.replaceState(null, "", nextUrl);
}
} catch (e) {
console.error("Failed to parse token from URL:", e);
}
el.loginBtn.onclick = () => { location.href = "/auth/login"; };
el.logoutBtn.onclick = async () => {
await leaveVoice();
await api("/auth/logout", { method: "POST" });
localStorage.removeItem("chattz_token");
try { await api("/auth/logout", { method: "POST" }); } catch (e) { }
location.reload();
};

View file

@ -8,7 +8,7 @@
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/static/styles.css" />
<link rel="stylesheet" href="styles.css" />
<!-- Lucide Icons -->
<script src="https://unpkg.com/lucide@latest"></script>
</head>
@ -238,7 +238,7 @@
</div>
</div>
<script src="/static/app.js" defer></script>
<script src="app.js" defer></script>
</body>
</html>