Compare commits

..

No commits in common. "stable" and "perfectnogation" have entirely different histories.

23 changed files with 988 additions and 2621 deletions

View File

@ -5,7 +5,7 @@ process.on('message',data => {
switch(data.type)
{
case "CLIENT_CREATED":{
//slog("CLIENT_CREATED");
slog("CLIENT_CREATED");
let client = new Client();
client.isProxy = true;
client.proxyProcess = data.pid;
@ -22,7 +22,7 @@ process.on('message',data => {
data.value = transformDeserialization(data.value, data.typing);
//slog("CLIENT_UPDATE_PROP");
slog("CLIENT_UPDATE_PROP");
let client = Client.clients.get(data.uuid);
client[data.name] = data.value;
break;
@ -44,7 +44,7 @@ process.on('message',data => {
break;
}
case "CLIENT_DESTROY":{
//slog("CLIENT_DESTROY");
slog("CLIENT_DESTROY");
if(Client.clients.has(data.uuid))
{
Client.clients.delete(data.uuid);
@ -54,7 +54,7 @@ process.on('message',data => {
break;
}
case "ROOM_CREATED":{
//slog("ROOM_CREATED");
slog("ROOM_CREATED");
let room = Room.fromJSON(data.value);
Room.rooms.set(room.id, room);
break;
@ -64,13 +64,13 @@ process.on('message',data => {
data.value = transformDeserialization(data.value, data.typing);
//slog("ROOM_UPDATE_PROP");
slog("ROOM_UPDATE_PROP");
let room = Room.rooms.get(data.uuid);
room[data.name] = data.value;
break;
}
case "ROOM_JOIN_CLIENT":{
//slog("ROOM_JOIN_CLIENT");
slog("ROOM_JOIN_CLIENT");
let room = Room.rooms.get(data.uuid);
let client = Client.clients.get(data.client);
if(room && client)
@ -81,7 +81,7 @@ process.on('message',data => {
break;
}
case "ROOM_EJECT_CLIENT":{
//slog("ROOM_EJECT_CLIENT");
slog("ROOM_EJECT_CLIENT");
let room = Room.rooms.get(data.uuid);
let client = Client.clients.get(data.client);
if(room && client)
@ -92,7 +92,7 @@ process.on('message',data => {
break;
}
case "ROOM_DESTROY":{
//slog("ROOM_DESTROY");
slog("ROOM_DESTROY");
Room.rooms.delete(data.value);
break;
}

View File

@ -1,9 +1,8 @@
import WebRTC from "./WebRTC";
import Peer from "./Peer";
/**
* Deneyseldir kullanılması önerilmez
*/
export default class P2PFileSender
{
public rtc : RTCPeerConnection;

View File

@ -219,12 +219,7 @@ export default class Peer extends EventTarget
to: this.socketId
});
}else{
if(pack.type != ':rtcpack:')
{
this.rtc?.sendMessage(pack)
}else{
return console.warn("Socket is not writable");
}
this.rtc?.sendMessage(pack)
}
}
async forget(){

View File

@ -31,7 +31,7 @@ export default class WebRTC
rtcpMuxPolicy:"require",
};
private isPolite() : boolean
public isPolite() : boolean
{
let myId = this.peer?.mwse.peer('me').socketId as string;
let peerId = this.peer?.socketId as string;
@ -201,7 +201,6 @@ export default class WebRTC
};
sendingStream.senders = senders;
}
this.emit('stream:accepted', sendingStream);
break;
}
case "message":{
@ -238,10 +237,6 @@ export default class WebRTC
}
public sendMessage(data: any)
{
if(data.type == ':rtcpack:')
{
throw "WebRTC Kanalında Sızma";
}
this.send({
type: 'message',
payload: data
@ -296,7 +291,6 @@ export default class WebRTC
this.channel = undefined;
WebRTC.channels.delete(this.id);
WebRTC.requireGC = true;
this.active = false;
})
}else{
this.emit('datachannel', event.channel);

View File

@ -184,13 +184,13 @@ export default class MWSE extends EventTarget {
let peer = this.peer(from, true);
peer.info.info = info;
peer.emit("accepted/pair", peer);
this.peer('me').emit('accepted/pair', peer);
this.peer('me').emit('accepted/pairr', peer);
})
this.EventPooling.signal("end/pair", (payload : {from : string,info: any}) => {
let {from, info} = payload;
let peer = this.peer(from, true);
peer.emit("end/pair", info);
this.peer('me').emit('end/pair', from, info);
peer.emit("endPair", info);
this.peer('me').emit('endPair', from, info);
})
}
public room(options: IRoomOptions | string) : Room

View File

@ -1,25 +0,0 @@
import "./studio/window.js";
import { InputDevicesWindow } from "./studio/InputDevices.js";
import { Rooms } from "./studio/Rooms.js";
let mwse = new MWSE({
endpoint: "ws://localhost:7707"
});
mwse.scope(beginEngine);
async function beginEngine()
{
let me = await mwse.virtualPressure.allocAPIPAddress();
$(".network-id").text(me);
}
window.openInputDevicesWindow = () => {
InputDevicesWindow.toggle();
InputDevicesWindow.bringToFront();
};
window.openRoomsWindow = () => {
Rooms.toggle();
Rooms.bringToFront();
};

View File

@ -5,7 +5,6 @@ html,body{
body{
background-color: #141414;
overflow: hidden;
font-family: system-ui;
}
*{
box-sizing: border-box;
@ -16,7 +15,7 @@ body{
height: 100%;
display: flex;
flex-wrap: nowrap;
flex-direction: column;
flex-direction: row;
box-sizing: border-box;
overflow: hidden;
}
@ -74,7 +73,6 @@ video{
top: 0;
bottom: 0;
display: flex;
flex-direction: column;
}
.tool-container > .tools{
margin: auto;
@ -100,80 +98,3 @@ video{
line-height: 2;
}
.tool-container > .namer{
flex: 0 0 auto;
background-color: rgba(0, 0, 0, 0.5);
border-radius: 10px;
overflow: hidden;
color: white;
display: flex;
flex-direction: row;
gap: 10px;
line-height: 2;
margin: 10px;
width: max-content;
padding: 0 10px;
.avatar {
display: flex;
& > *{
margin: auto;
}
}
}
.tool-container > .progress{
margin-top: auto;
margin-bottom: 10px;
width: 250px;
margin-left: auto;
margin-right: auto;
height: 5px;
border-radius: 5px;
background-color: white;
overflow: auto;
& .progress-box {
height: 5px;
width: 50%;
background-color: red;
transition: width 0.05s linear;
}
}
.controllist{
display: flex;
flex-direction: row;
flex-wrap: nowrap;
gap: 12px;
flex: 1 1 auto;
}
.ctrl-btn {
width: 48px;
height: 48px;
border: 1px solid #ccc;
border-radius: 8px;
background: #fff;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.2s, border-color 0.2s;
}
.ctrl-btn:hover {
background: #f0f0f0;
border-color: #999;
}
.ctrl-btn .material-icons {
font-size: 26px;
}
.logo{
object-fit: contain;
max-height: 50px;
width: 100%;
background-color: white;
border-radius: 10px;
}

View File

@ -13,34 +13,6 @@
<div class="videolist">
</div>
<div style="display:flex;flex-direction: row;">
<div class="controllist">
<div style="flex:0 0 300px">
<img src="https://app.argist.com/img/argist-logo-yan.png" class="logo">
</div>
<div style="flex: 1 1 auto"></div>
<button class="ctrl-btn mic-on" title="Mikrofon Aç">
<span class="material-icons">mic</span>
</button>
<button class="ctrl-btn mic-off" title="Mikrofon Kapat" style="display:none">
<span class="material-icons">mic_off</span>
</button>
<button class="ctrl-btn cam-on" title="Kamera Aç" style="display:none">
<span class="material-icons">videocam</span>
</button>
<button class="ctrl-btn cam-off" title="Kamera Kapat">
<span class="material-icons">videocam_off</span>
</button>
<button class="ctrl-btn share-on" title="Ekran Paylaş">
<span class="material-icons">screen_share</span>
</button>
<button class="ctrl-btn share-off" title="Ekran Paylaşmayı Durdur" style="display:none">
<span class="material-icons">stop_screen_share</span>
</button>
<div style="flex: 1 1 auto"></div>
<div style="flex:0 0 300px"></div>
</div>
</div>
</div>
<script src="./index.js?v=42"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">

View File

@ -1,4 +1,3 @@
const url = new URL(window.location);
/**
* @type {import("./MWSE/index").default}
*/
@ -7,14 +6,6 @@ let mwse;
* @type {string}
*/
let mySocketId;
/**
* @type {string}
*/
let myIPAddress;
/**
* @type {string}
*/
let myNumber;
/**
* @type {string}
*/
@ -31,9 +22,7 @@ let outgoingStream;
* @type {HTMLDivElement}
*/
let videoContainer = document.querySelector(".videolist");
let amaxb;
let vmaxb;
let rate;
let maxbitrate;
let resulation;
let activePeers = {}
@ -44,11 +33,19 @@ function connect()
mwse = new MWSE({
endpoint: "wss://ws.saqut.com"
});
MWSE.rtc.defaultICEServers = [{
urls: "turn:20.166.82.187:3478",
username: "turnserver",
credential: "turnserver"
},{
urls: "stun:stun.l.google.com:19302"
}];
mwse.scope(beginEngine);
}
let peername = url.searchParams.get("user");
let interact = false;
@ -62,37 +59,28 @@ document.addEventListener("click",()=>{
})
/**
* @type {HTMLVideoElement}
*/
let activeVideo;
function templateVideo(name, stream,infinitedMute, peername)
function templateVideo(name, stream,infinitedMute)
{
let t = new DOMParser().parseFromString(`
<div class="frame" data-name="${name}">
<video autoplay playsinline muted>
<div class="frame">
<video autoplay playsinline muted data-name="${name}">
</video>
<div class="tool-container">
<div class="namer">
<div class="avatar">
<i class="material-icons">account_circle</i>
</div>
<div class="name">
${peername ?? "User"}
</div>
</div>
<!--div class="tool-container">
<div class="tools">
<button>
<i class="material-icons">home</i>
</button>
<button>
<i class="material-icons">close</i>
</button>
</div>
<div class="progress">
<div class="progress-box">
</div>
</div>
</div>
</div--->
</div>
`,"text/html");
@ -105,17 +93,14 @@ function templateVideo(name, stream,infinitedMute, peername)
i.muted = 1;
i.classList.add("soundon");
}
if(stream){
i.srcObject = stream;
bindAudioLevel(stream, t.querySelector(".progress-box"));
}
if(stream) i.srcObject = stream;
return t.querySelector("div");
}
function addVideoList(name, stream, peer, infinitedMute, name)
function addVideoList(name, stream, peer, infinitedMute)
{
if(!videoContainer.querySelector(`[name="${name}"]`))
{
let video = templateVideo(name, stream, infinitedMute, name);
let video = templateVideo(name, stream, infinitedMute);
video.dataset.user = peer.socketId;
videoContainer.appendChild(video);
}
@ -126,6 +111,10 @@ function removeVideoList(name)
if(videoContainer.querySelector(`[data-user="${name}"]`))
{
let k = videoContainer.querySelector(`[data-user="${name}"]`);
if(k.dataset.user == activeVideo?.dataset.user || !activeVideo)
{
activePeer = null;
}
k.remove();
}
}
@ -135,28 +124,36 @@ async function beginEngine()
let me = mwse.peer("me");
me.disablePairAuth();
mySocketId = me.socketId;
myIPAddress = await mwse.virtualPressure.allocAPIPAddress();
myNumber = await mwse.virtualPressure.allocAPNumber();
let url = new URL(window.location);
roomid = url.searchParams.get("room");
user = url.searchParams.get("user") ?? "User";
vmaxb = url.searchParams.get("vmaxb") ?? 32_0000
amaxb = url.searchParams.get("amaxb") ?? 2500000
resulation = url.searchParams.get("resulation") ?? 1
rate = url.searchParams.get("rate") ?? 10
if(!!roomid == 0)
{
let hash = window.crypto.randomUUID();
url.searchParams.set("room", hash);
url.searchParams.set("vmaxb", vmaxb);
url.searchParams.set("amaxb", amaxb);
url.searchParams.set("resulation", resulation);
url.searchParams.set("rate", rate);
url.searchParams.set("user", user);
window.location = url.href;
};
connectRoom(roomid);
if(url.searchParams.get("maxbitrate"))
{
let n = Number(url.searchParams.get("maxbitrate"));
if(Number.isFinite(n) && !Number.isNaN(n))
{
maxbitrate = n;
}else maxbitrate = 2500_000;
}else maxbitrate = 2500_000;
if(url.searchParams.get("resulation"))
{
let n = Number(url.searchParams.get("resulation"));
if(Number.isFinite(n) && !Number.isNaN(n))
{
resulation = n;
}else resulation = 1.2;
}else resulation = 1.2;
};
window.addEventListener("load", () => {
@ -181,8 +178,7 @@ async function startOutgoingWebcam()
{ width: { exact: 240 } }
],
facingMode: "user"
},
audio: true
}
});
outgoingStream = mediaStream;
}
@ -203,67 +199,50 @@ async function connectRoom()
notifyActionInvite: false,
notifyActionJoined: true
});
await mwse.peer('me').info.set("name", peername);
await room.createRoom();
room.on("join", peer => IncomingPeer(peer, true));
room.on("join", peer => IncomingPeer(peer,true));
room.on("eject", peer => OutgoingPeer(peer));
for (const peer of await room.fetchPeers()) {
IncomingPeer(peer)
if(peer.socketId != mwse.peer('me').socketId){
IncomingPeer(peer,false)
}
}
addVideoList("My Webcam",outgoingStream, mwse.peer("me"), true, peername);
addVideoList("My Webcam",outgoingStream, mwse.peer("me"), true)
};
/**
* @param {import("./MWSE/Peer").default} peer
*/
async function IncomingPeer(peer,activeConnect)
function IncomingPeer(peer,activeConnect)
{
await peer.info.fetch();
peer.createRTC({
iceCandidatePoolSize: 0
},[{
urls: "turn:20.166.82.187:3478",
username: "turnserver",
credential: "turnserver"
},{
urls: "stun:stun.l.google.com:19302"
}]);
if(peer.rtc.isPolite())
if(activeConnect)
{
peer.rtc.connect();
}
peer.rtc.rtc.turboBitrate = 0;
peer.rtc.on('connected',() => {
if(peer.rtc.isPolite())
console.log("Connected");
if(!activeConnect)
{
peer.rtc.sendStream(outgoingStream, "Webcam", {});
activePeers[peer.socketId] = peer;
activePeers[peer.socketId] = peer.rtc.rtc;
}
});
peer.rtc.on('disconnected',() => {
removeVideoList(peer.socketId, peer);
console.log("Disconnected");
removeVideoList(peer.streamY, peer);
delete activePeers[peer.socketId];
});
peer.rtc.on("stream:added", ({stream,name}) => {
addVideoList(
peer.socketId,
stream,
peer,
void 0,
peer.info.get("name")
);
if(peer.rtc.isPolite() == false)
peer.streamY = peer.socketId + " | " + name + " - " + stream.id;
addVideoList(peer.socketId + " | " + name + " - " + stream.id,stream, peer);
if(activeConnect)
{
peer.rtc.sendStream(outgoingStream, "Webcam", {});
activePeers[peer.socketId] = peer;
}
})
}
@ -273,80 +252,27 @@ async function IncomingPeer(peer,activeConnect)
function OutgoingPeer(peer)
{
removeVideoList(peer.socketId, peer);
delete activePeers[peer.socketId];
}
let relative;
setInterval(() => {
for(const [,peer] of Object.entries(activePeers))
for(const [,peerRtc] of Object.entries(activePeers))
{
let peerRtc = peer.rtc.rtc;
const senders = peerRtc.getSenders();
if(peerRtc.vturboBitrate !== 1)
if(peerRtc?.turboBitrate !== 1)
{
const senders = peerRtc.getSenders();
const videoSender = senders.find(sender => sender.track?.kind === 'video');
if(videoSender){
const parameters = videoSender.getParameters();
parameters.encodings[0].maxBitrate = vmaxb;
parameters.encodings[0].maxBitrate = maxbitrate;
parameters.encodings[0].scaleResolutionDownBy = resulation;
parameters.encodings[0].maxFramerate = rate;
videoSender.setParameters(parameters).then(() => {
peerRtc.vturboBitrate = 1;
});
}
}
if(peerRtc.aturboBitrate !== 1)
{
const audioSender = senders.find(sender => sender.track?.kind === 'audio');
if(audioSender){
const parameters = audioSender.getParameters();
parameters.encodings[0].maxBitrate = amaxb;
audioSender.setParameters(parameters).then(() => {
peerRtc.aturboBitrate = 1;
peerRtc.turboBitrate = 1;
});
}
}
}
},1000);
function bindAudioLevel(stream, element, options = {}) {
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const source = audioCtx.createMediaStreamSource(stream);
const analyser = audioCtx.createAnalyser();
analyser.fftSize = 512;
analyser.smoothingTimeConstant = 0.1;
const dataArray = new Uint8Array(analyser.frequencyBinCount);
source.connect(analyser);
const track = stream.getAudioTracks()[0];
const bufferLength = analyser.frequencyBinCount;
function update()
{
if (track.readyState === 'ended' || !track.enabled) {
source.disconnect();
analyser.disconnect();
audioCtx.close();
return;
}
analyser.getByteFrequencyData(dataArray);
// Ortalama ses seviyesi hesapla
let sum = 0;
for (let i = 0; i < bufferLength; i++) {
sum += dataArray[i];
}
const avg = sum / bufferLength;
// Ortalama değeri % olarak hesapla (0-255 arası değer)
const volumePercent = Math.min(100, (avg / 255) * 100);
element.style.width = `${volumePercent * 2}%`;
requestAnimationFrame(update);
}
requestAnimationFrame(update);
}
},1000);

View File

@ -1,175 +1,208 @@
/**
* =================================================================
* LİSANS BİLDİRİMİ -LGPL - LGPL-AU-EK
* =================================================================
* * Yazar (Original Author): Abdussamed ulutaş
* * İzinler (Permissions):
* ---------------------
* Bu kod, ticari veya kişisel amaçlarla serbestçe OKUNABILIR,
* KOPYALANABILIR, ÇOĞALTILABILIR, DEĞIŞTIRILEBILIR ve KULLANILABILIR.
* * * Koşul (Zorunlu Atıf Şartı - Attribution Requirement):
* ---------------------------------------------------
* Bu yazılımın temelindeki ANA ALGORITMA tamamen ve özgün bir şekilde değiştirilmediği sürece,
* "author by Abdussamed ulutaş" ifadesi kodun içerisinde MUTLAKA KORUNMALIDIR.
* * NOT: Algoritmanın temel mantığı korunarak yapılan küçük değişiklikler,
* optimizasyonlar veya arayüz entegrasyonları, bu atıf ifadesinin kaldırılması için yeterli sayılmaz.
* * * Sorumluluk Reddi (Disclaimer):
* ----------------------------
* Bu yazılım "olduğu gibi" (as-is) sağlanmıştır. Yazar, yazılımın kullanımından
* kaynaklanacak hiçbir zarardan sorumlu değildir.
* * =================================================================
*/
// Aşağıdaki satır, atıf şartını yerine getiren zorunlu ifadedir ve kodun içinde kalmalıdır:
//
// author by Abdussamed ulutaş
//
// =================================================================
/*
- Tüm dizinler herkese görünecek
- Dizinler ve dosyalar arayüzden tekrarlanamayacak
- Dosya ve klasör isimler aynı isimde olabilir
- Kimse bir başkasının dosyasını ve klasörünü silemez
- Yeni bir kişi bağlandığında dizin listesi eşitleniyor olacak
- Bağlanılan kişi ayrıldığında ona ait olan tüm dosya/dizin sistemi silinecek
*/
function é(rule)
function HostListItem()
{
if(é.element == null)
{
/** @type {HTMLStyleElement} */
é.element = document.createElement("style");
document.head.appendChild(é.element);
/** @type {CSSStyleSheet} */
é.sheet = é.element.sheet;
let item = $(`
<tr>
<td class="text-nowrap">
<button class="btn btn-outline-primary btn-sm action-download">
İndir
</button>
<button class="btn btn-outline-danger btn-sm action-remove">
Kaldır
</button>
</td>
<td class="text-nowrap">
<button class="btn btn-outline-secondary btn-sm action-sha1">
Hesapla
</button>
</td>
<td class="text-nowrap">
<span class="action-filename">DCIM_AMG_25TEM2025.png</span>
<br>
<span class="text-muted">
(Sizin cihazda)
</span>
</td>
<td class="text-nowrap">
<div class="progress" style="height:30px">
<div class="progress-bar" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</td>
</tr>
`);
return {
download: item.find(".action-download"),
hide: item.find(".action-hide"),
remove: item.find(".action-remove"),
sha1: item.find(".action-sha1"),
filename: item.find(".action-filename"),
progress: item.find(".progress"),
container: item
}
é.sheet.insertRule(rule);
}
é`html,body{
background-color: black;
height: 100%;
font-size: 14px;
> * {
box-sizing:border-box;
function RemoteListItem()
{
let item = $(`
<tr>
<td class="text-nowrap">
<button class="btn btn-outline-primary btn-sm action-download">
İndir
</button>
<button class="btn btn-outline-secondary btn-sm action-hide">
Gizle
</button>
</td>
<td class="text-nowrap">
<button class="btn btn-outline-secondary btn-sm action-sha1">
Hesapla
</button>
</td>
<td class="text-nowrap">
<span class="action-filename">DCIM.mp4</span>
<br>
<span class="text-muted">
(Karşı cihazda)
</span>
</td>
<td class="text-nowrap">
<div class="progress" style="height:30px">
<div class="progress-bar" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</td>
</tr>
`);
return {
download: item.find(".action-download"),
hide: item.find(".action-hide"),
remove: item.find(".action-remove"),
sha1: item.find(".action-sha1"),
filename: item.find(".action-filename"),
progress: item.find(".progress"),
container: item
}
}`;
é`body{
display: flex;
flex-direction: row;
flex-wrap: nowrap;
padding: 20px;
overflow: hidden;
}`;
}
é`@keyframes color-transition {
0% {
color: #c8c8c8;
}
50% {
color: #757575;
}
100% {
color: #c8c8c8;
}
}`;
function EmptyListItem()
{
return $(`
<tr>
<td class="text-center text-muted" colspan="4">
Gönderilecek veya alınacak dosya bulunmuyor
</td>
</tr>
`)
}
/// UI
function formatBytes(a,b=2){if(!+a)return"0 Bytes";const c=0>b?0:b,d=Math.floor(Math.log(a)/Math.log(1024));return`${parseFloat((a/Math.pow(1024,d)).toFixed(c))} ${["Bytes","KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"][d]}`}
// <span class="material-icons">
const UIM = new class UI {
constructor(){
this.setup();
}
setup(){
this.setupOutContainer();
this.setupDirentContainer();
}
/** @type {JQuery} */
container = null;
setupOutContainer(){
this.container = $("<div>");
this.container.addClass("dip-fev");
é`.dip-fev{
width: 100%;
height: 100%;
background-color: rgba(255,255,255,0.2);
position: relative;
border-radius: 5px;
border: solid 1px rgba(255,255,255,0.1);
display: flex;
overflow: auto;
flex-direction: column;
flex-wrap: nowrap;
}`;
document.body.append(this.container.get(0));
}
/** @type {JQuery} */
direntbezier = null;
setupDirentContainer(){
this.direntbezier = $("<div>");
this.direntbezier.addClass("dip-bezier");
é`.dip-bezier{
flex: 0 0 auto;
background-color: rgba(255,255,255,0.2);
display: flex;
flex-direction: row;
flex-wrap: nowrap;
padding: 5px;
& > .dip-bezier-icon{
padding: 3px;
animation: color-transition 1s ease-in-out infinite;
}
& > .dip-bezier-disk{
color: white;
padding: 3px;
}
& > .dip-bezier-object{
color: white;
padding: 3px 2px;
cursor: pointer;
border-radius: 3px;
&:hover{
background-color: rgba(255,255,255,0.05);
}
}
& > .dip-bezier-splitter{
margin: 5px 2px;
width: 1px;
background-color: rgba(0,0,0,0.1);
}
}`;
this.container.append(this.direntbezier);
const endpoint = `wss://ws.saqut.com/socket/webserver/${("000000"+(Math.random() * 512 | 0)).slice(-6)}.sock`;
this.setupBezier("Diskim",["Resimler","Yakalamalar","Benim yakalamalarım"]);
}
setupBezier(disk, folders){
let icon = $("<span>");
icon.addClass("dip-bezier-icon material-symbols-outlined");
icon.text("bigtop_updates");
this.direntbezier.append(icon);
let mwse = new MWSE({
endpoint,
autoReconnect: true,
autoReconnectTimeout: 60_000
});
let section = $("<div>");
section.addClass("dip-bezier-disk");
section.html(disk + " ://");
this.direntbezier.append(section);
mwse.scope(Connect);
folders.map((element, index, array) => {
let section = $("<div>");
section.addClass("dip-bezier-object");
section.text(element);
this.direntbezier.append(section);
if(index < array.length - 1)
{
let sectionPadding = $("<div>");
sectionPadding.addClass("dip-bezier-splitter");
this.direntbezier.append(sectionPadding);
}
let room;
let ip;
async function Connect()
{
await genRoom();
$(".network-id").text(ip);
}
async function genRoom()
{
do{
let vip = ip = [
(Math.random() * 16 | 0) + 10,
(Math.random() * 8 | 0),
(Math.random() * 4 | 0),
(Math.random() * 254 | 0) + 1
].join('.');
room = mwse.room({
name: `WEB3-Smash [${vip}] RO CONNECT:2`,
description: "Web3 Smash saQut Server Application",
joinType: "free",
notifyActionJoined: true,
notifyActionEjected: true,
ifexistsJoin: false
});
try{
await room.createRoom();
break;
}catch{
continue;
}
}while(1);
}
class FileDescriptor {
static hostfiles = new Map();
static remotefiles = new Map();
static hostindex = 0;
static remoteindex = 0;
file = null;
listItem = null;
constructor(isHost, item,file){
this.file = file;
this.listItem = item;
$("#thelist").append(item.container);
if(isHost)
{
FileDescriptor.hostfiles.set(
++FileDescriptor.hostindex,
this
);
}else{
FileDescriptor.remotefiles.set(
++FileDescriptor.remoteindex,
this
);
}
this.init();
}
}
init(){
this.listItem.filename.html(
this.file.name + " <span class='text-muted'>" + formatBytes(this.file.size) + "</span>"
);
}
};
$("#files").on('change',function(){
for (const file of this.files) {
$("#thelist .empty").remove();
new FileDescriptor(
true,
HostListItem(),
file
)
};
$("#files").val('');
});
$(".joinroom").on("chnage",function(){
let ip = $("#remoteadress").val();
if(!/^\d+\.\d+\.\d+$/.test(ip)){
return alert(" ")
}
$("#thelist .empty").remove();
room = mwse.room({
name: `WEB3-Smash [${vip}] RO CONNECT:2`,
description: "Web3 Smash saQut Server Application",
joinType: "free",
notifyActionJoined: true,
notifyActionEjected: true,
ifexistsJoin: false
});
})

View File

@ -1,27 +0,0 @@
/**
* =================================================================
* LİSANS BİLDİRİMİ - LGPL - LGPL-AU-EK
* =================================================================
* * Yazar (Original Author): Abdussamed ulutaş
* * İzinler (Permissions):
* ---------------------
* Bu kod, ticari veya kişisel amaçlarla serbestçe OKUNABILIR,
* KOPYALANABILIR, ÇOĞALTILABILIR, DEĞIŞTIRILEBILIR ve KULLANILABILIR.
* * * Koşul (Zorunlu Atıf Şartı - Attribution Requirement):
* ---------------------------------------------------
* Bu yazılımın temelindeki ANA ALGORITMA tamamen ve özgün bir şekilde değiştirilmediği sürece,
* "author by Abdussamed ulutaş" ifadesi kodun içerisinde MUTLAKA KORUNMALIDIR.
* * NOT: Algoritmanın temel mantığı korunarak yapılan küçük değişiklikler,
* optimizasyonlar veya arayüz entegrasyonları, bu atıf ifadesinin kaldırılması için yeterli sayılmaz.
* * * Sorumluluk Reddi (Disclaimer):
* ----------------------------
* Bu yazılım "olduğu gibi" (as-is) sağlanmıştır. Yazar, yazılımın kullanımından
* kaynaklanacak hiçbir zarardan sorumlu değildir.
* * =================================================================
*/
// Aşağıdaki satır, atıf şartını yerine getiren zorunlu ifadedir ve kodun içinde kalmalıdır:
//
// author by Abdussamed ulutaş
//
// =================================================================

View File

@ -1,86 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MWSE UI 24.3 Studio</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" />
</head>
<body>
<div class="container" style="max-width: 1200px;padding-top: 125px">
<h2 class="text-center">
MWSE UI 24.3
</h2>
<h1 class="text-center mb-5 mt-3 text-bold fw-bold">
<span>Ağ Adresiniz</span>
<span class="text-danger network-id">
#.#.#.#
</span>
</h1>
</div>
<div style="position:fixed;left:0;right:0;bottom:0;background-color: rgba(0,0,0,.1);display: flex;flex-direction: row;gap: 5px">
<span class="bg-white d-inline-block m-1">
<button class="btn btn-outline-primary" onclick="openInputDevicesWindow()">
Giriş Aygıtları
</button>
</span>
<!--span class="bg-white d-inline-block m-1">
<button class="btn btn-outline-primary" onclick="openOutputDevicesWindow()">
Çıkış Aygıtları
</button>
</span-->
<span class="bg-white d-inline-block m-1">
<button class="btn btn-outline-primary" onclick="openRoomsWindow()">
Odalar
</button>
</span>
<span class="bg-white d-inline-block m-1">
<button class="btn btn-outline-primary" onclick="openPeersWindow()">
Cihazlar
</button>
</span>
</div>
<script src="https://ws.saqut.com/script"></script>
<script src="./core.js" type="module"></script>
<style>
html,body{
margin: 0;
height: 100%;
background-image: url(./studio/background.jpg);
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
}
*{
box-sizing: border-box;
}
* {
scrollbar-width: thin;
scrollbar-color: #7a7a7a #1e1e1e;
}
*::-webkit-scrollbar {
width: 8px;
height: 8px;
}
*::-webkit-scrollbar-track {
background: #1e1e1e;
}
*::-webkit-scrollbar-thumb {
background-color: #7a7a7a;
border-radius: 8px;
}
*::-webkit-scrollbar-thumb:hover {
background-color: #aaaaaa;
}
</style>
</body>
</html>

View File

@ -1,398 +0,0 @@
import DWindow from "./window.js";
import { AddCell, FilterCell, memory, RemoveCell } from "./sdb.js";
export const InputDevicesWindow = new class InputDevicesWindow extends DWindow{
constructor(){
super();
this.initContent();
this.headtext.text("Giriş Aygıtları");
this.hide();
this.panel.css("min-width","640px");
this.panel.css("min-height","250px");
this.panel.css("width","max-content");
this.initEvent();
}
/**
* @type {JQuery<HTMLElement>}
*/
table = null;
initContent(){
this.table = $(`
<table class="table table-sm table-bordered table-striped text-nowrap">
<thead>
<tr>
<th>Cihaz Türü</th>
<th>Sağlanan Kanallar</th>
<th>Akış ID</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="4">
<button class="btn btn-success w-100 newdevice">
Yeni Giriş Cihazı Ekle
</button>
</td>
</tr>
</tfoot>
</table>
`);
this.updateDevices();
this.content.append(this.table);
}
initEvent(){
this.content.find(".newdevice").on('click', this.generateDevice.bind(this));
this.addEventListener("close",()=>{
this.hide();
})
}
updateDevices(){
let tbody = this.table.find("tbody");
tbody.text('');
for (const cell of FilterCell("rawstream", () => true))
{
let tr = $(`
<tr class="text-nowrap">
<td>${cell.source}</td>
<td>${cell.kind}</td>
<td>${cell.payload.id}</td>
<td>
<button class="btn btn-outline-primary action-view">Görüntüle</button>
<button class="btn btn-outline-danger action-close">Kapat</button>
</td>
</tr>
`);
tr.attr("data-declare", cell.payload.id);
cell.addEventListener("stop",() => tr.remove());
tbody.append(tr);
}
tbody.find(".action-view").on('click', e => this.viewSource($(e.target)));
tbody.find(".action-close").on('click', e => this.closeSource($(e.target)));
}
closeSource(btn){
let streamid = btn.closest("tr").attr("data-declare");
for (const brain of FilterCell("rawstream",e => e.payload.id == streamid)) {
brain.stop();
}
}
viewSource(btn){
let streamid = btn.closest("tr").attr("data-declare");
/**
* @type {MediaStream}
*/
let p = null;
for (const rawstream of FilterCell("rawstream",e => e.payload.id == streamid)) {
p = rawstream.payload;
}
let modal = new ViewSourceDialog(p.getTracks()[0]);
modal.enableDialog(this);
modal.bringToFront();
}
generateDevice(){
let modal = new AddDeviceDialog();
modal.enableDialog(this);
modal.bringToFront();
modal.addEventListener("stream:added",()=>{
this.updateDevices();
});
}
}
class StreamRecord extends EventTarget {
lockedby = 0;
stop(){
this.payload.getTracks().forEach(e => e.stop());
this.dispatchEvent(new Event("stop"));
}
isLocked(){
return this.lockedby != 0;
}
lock(){
this.lockedby++;
}
unlock(){
this.lockedby--;
}
}
class AddDeviceDialog extends DWindow {
constructor(){
super();
this.initContent();
this.headtext.text("Aygıt Ekleme Sihirbazı");
this.addEventListener('close',()=>{
this.disableDialog();
this.exit();
})
}
initContent(){
let table = $(`
<div style="display:flex;flex-direction:column;gap:5px">
<button class="btn btn-success w-100 action-sdcam">
SD Kamara Ekle
</button>
<button class="btn btn-success w-100 action-hdcam">
HD Kamara Ekle
</button>
<button class="btn btn-success w-100 action-mic">
Mikrofon Ekle
</button>
<button class="btn btn-success w-100 action-displaycam">
Ekran Görüntüsü Ekle
</button>
</div>
`);
table.find(".action-sdcam").on("click",this.sdcam.bind(this));
table.find(".action-hdcam").on("click",this.hdcam.bind(this));
table.find(".action-mic").on("click",this.mic.bind(this));
table.find(".action-displaycam").on("click",this.displaycam.bind(this));
this.content.append(table);
}
async sdcam(){
let stream = await navigator.mediaDevices.getUserMedia({
video: {
advanced: [
{ width: { exact: 640 } },
{ width: { exact: 320 } },
{ width: { exact: 240 } }
],
facingMode: "user"
}
});
AddCell("rawstream", new class extends StreamRecord {
source = "Kamera";
kind = "Görüntü";
payload = stream;
constructor(){
super();
this.onEnded(() => {
this.dispatchEvent(new Event("stop"));
})
this.addEventListener("stop",() => {
RemoveCell("rawstream",cell => {
return cell.payload.id == stream.id
})
})
}
onEnded(event){
/** @type {MediaStreamTrack} */
let track;
stream.getVideoTracks().forEach(e => track = e);
if(track)
{
track.addEventListener("ended",event);
}
}
});
this.dispatchEvent(new Event("stream:added"));
this.disableDialog();
this.exit();
}
async hdcam(){
let stream = await navigator.mediaDevices.getUserMedia({
video: {
advanced: [
{ width: { exact: 1920 } },
{ width: { exact: 1600 } },
{ width: { exact: 1366 } },
{ width: { exact: 1280 } },
{ width: { exact: 1024 } },
{ width: { exact: 900 } },
{ width: { exact: 800 } },
{ width: { exact: 640 } },
{ width: { exact: 320 } },
{ width: { exact: 240 } }
],
facingMode: "user"
}
});
AddCell("rawstream", new class extends StreamRecord {
source = "Kamera";
kind = "Görüntü";
payload = stream;
constructor(){
super();
this.onEnded(() => {
this.dispatchEvent(new Event("stop"));
})
this.addEventListener("stop",() => {
RemoveCell("rawstream",cell => {
return cell.payload.id == stream.id
})
})
}
onEnded(event){
/** @type {MediaStreamTrack} */
let track;
stream.getVideoTracks().forEach(e => track = e);
if(track)
{
track.addEventListener("ended",event);
}
}
});
this.dispatchEvent(new Event("stream:added"));
this.disableDialog();
this.exit();
}
async mic(){
let stream = await navigator.mediaDevices.getUserMedia({
audio: true
});
AddCell("rawstream", new class extends StreamRecord {
source = "Kamera";
kind = "Ses";
payload = stream;
constructor(){
super();
this.onEnded(() => {
this.dispatchEvent(new Event("stop"));
})
this.addEventListener("stop",() => {
RemoveCell("rawstream",cell => {
return cell.payload.id == stream.id
})
})
}
onEnded(event){
/** @type {MediaStreamTrack} */
let track;
stream.getAudioTracks().forEach(e => track = e);
if(track)
{
track.addEventListener("ended",event);
}
}
});
this.dispatchEvent(new Event("stream:added"));
this.disableDialog();
this.exit();
}
async displaycam(){
let stream = await navigator.mediaDevices.getDisplayMedia({
video: true
});
AddCell("rawstream", new class extends StreamRecord{
source = "Ekran";
kind = "Görüntü";
payload = stream;
constructor(){
super();
this.onEnded(() => {
this.dispatchEvent(new Event("stop"));
})
this.addEventListener("stop",() => {
RemoveCell("rawstream",cell => {
return cell.payload.id == stream.id
})
})
}
onEnded(event){
/** @type {MediaStreamTrack} */
let track;
stream.getTracks().forEach(e => track = e);
if(track)
{
track.addEventListener("ended",event);
}
}
});
this.dispatchEvent(new Event("stream:added"));
this.disableDialog();
this.exit();
}
}
class ViewSourceDialog extends DWindow {
/**
* @type {MediaStreamTrack}
*/
track = null;
extra = {};
constructor(track){
super();
this.headtext.text("Giriş Kaynağı Görüntüleme");
this.addEventListener('close',()=>{
this.disableDialog();
this.exit();
})
this.track = track;
this.initContent();
}
initContent(){
if(this.track.kind == "video")
{
this.initVideoContent();
}else{
this.initAudioContent();
}
this.table = $(`<table class="table">
<tbody>
<tr>
<td>Track ID</td>
<td>${this.track.id}</td>
</tr>
<tr>
<td>Data Type</td>
<td>${this.track.kind}</td>
</tr>
<tr>
<td>Status</td>
<td>${this.track.enabled ? "Active" : "Passive"}</td>
</tr>
<tr>
<td>Track Label</td>
<td>${this.track.label}</td>
</tr>
</tbody>
</table>`);
this.content.append(this.table);
}
initVideoContent(){
let player = $(`<video
style="height: 450px"
controls
/>`);
let stream = new MediaStream();
stream.addTrack(this.track);
player.on('canplay', e => e.target.play());
player.get(0).srcObject = stream;
this.content.append(player);
player.on('play', e => {
this.table.find("tbody").append(`
<tr>
<td>Video Width</td>
<td>${e.target.videoWidth}px</td>
</tr>
`);
this.table.find("tbody").append(`
<tr>
<td>Video Height</td>
<td>${e.target.videoHeight}px</td>
</tr>
`);
});
}
initAudioContent(){
let player = $(`<audio
style="width: 500px"
controls
/>`);
let stream = new MediaStream();
stream.addTrack(this.track);
player.get(0).srcObject = stream;
player.on('canplay', e => e.target.play());
this.content.append(player);
}
}

View File

@ -1,65 +0,0 @@
import DWindow from "./window.js";
import { AddCell, FilterCell, memory, RemoveCell } from "./sdb.js";
export const Rooms = new class Rooms extends DWindow{
constructor(){
super();
this.emptyConnect();
this.headtext.text("MWSE Ağları");
this.hide();
this.panel.css("min-width","640px");
this.addEventListener("close",()=>{
this.hide();
})
}
emptyConnect(){
this.content.append($(`
<h4 class="text-white text-center">MWSE Ağları</h4>
`),$(`
<h6 class="text-white text-center">Herhangi bir ağa bağlı değilsiniz</h6>
`));
this.content.append($(`
<h3 class="text-white text-center" style="margin-top: 50px">
Oluştur
</h3>
`));
let createinput = $(`
<input type="text" class="form-control" placeholder="Oluşturulacak Oda Adı" style="line-height:2;font-size: 2em">
`);
let createbutton = $(`
<button class="btn btn-lg btn-success d-block m-auto mt-3">Oluştur</button>
`);
this.content.append(createinput,createbutton);
this.content.append($(`
<h3 class="text-white text-center" style="margin-top: 50px">
Ağa Katıl
</h3>
`));
let joininput = $(`
<input type="text" class="form-control" placeholder="Katılacak Oda Adı" style="line-height:2;font-size: 2em">
`);
let joinbutton = $(`
<button class="btn btn-lg btn-success d-block m-auto mt-3">Katıl</button>
`);
this.content.append(joininput,joinbutton);
this.content.append($(`
<span class="text-white" style="margin-top: 50px;max-width:100%;font-size: 0.9em;line-height: 1;display: block;text-shadow: 0px 0px 4px black;">
Aynı ağdaki kullanıcılar birbirini görecek ve akışlarını paylaşabilecektir.
Verilerinizi, bilgilerinizi ve akışlarınızı paylaşmakta tamamen özgürsünüz.
Sistem tamamen deneysel teknoloji araştırma ve geliştirme üzerine kuruludur.
Sistem kullanılarak yapılan tüm iyi ve kötü amaçlı eylemlerden kullanıcı sorumludur.
</span>
`));
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 660 KiB

View File

@ -1,162 +0,0 @@
const style = document.createElement("style");
document.head.appendChild(style);
export default class CSSOM {
/** @type {Map<string, CSSOM>} */
static rules = new Map();
/** @type {Map<string, CSSRuleList>} */
static cRules = new Map();
/**
* @returns {CSSOM}
*/
static get(name){
return CSSOM.rules.get(name);
}
/** @returns {CSSRule} */
static findRule(selector){
for (let ruleIndex = 0; ruleIndex < style.sheet.cssRules.length; ruleIndex++)
{
let rule = style.sheet.cssRules.item(ruleIndex);
if(rule.selectorText == selector)
{
return rule;
}
}
}
/** @returns {CSSRule} */
static removeRule(selector){
for (let ruleIndex = 0; ruleIndex < style.sheet.cssRules.length; ruleIndex++)
{
let rule = style.sheet.cssRules.item(ruleIndex);
if(rule.selectorText == selector)
{
style.sheet.deleteRule(ruleIndex);
}
}
}
static css(selector, values){
let rule;
if(!(rule = CSSOM.findRule(selector)))
{
let no = style.sheet.insertRule(`${selector}{}`);
rule = style.sheet.cssRules[no];
}
for(let [stylename, stylevalue] of Object.entries(values))
{
let name = stylename;
let value = typeof stylevalue == "string" ? stylevalue.split('!')[0] : stylevalue;
let priority = typeof stylevalue == "string" ? (stylevalue.split('!')[1] == "important" ? "important" : void 0) : void 0;
name = name.replace(/([A-Z])/g,(_,$1) => '-' + $1.toLowerCase());
rule.style.setProperty(name, value, priority);
}
}
static generate(idd = null, css = null){
let id = idd || CSSOM.generateCode();
let t = new CSSOM(id);
CSSOM.rules.set(t.id,t);
css && t.css(css);
return t;
}
static generateCode(){
let mine;
do{
mine = Math.random().toString(36).slice(2,6);
}while(CSSOM.rules.has(mine));
return "i" + mine;
}
id = "";
/** @type {{[key:string]: CSSRuleList}} */
rule_t = {};
constructor(id){
this.id = id;
}
toString(){
return this.id;
}
css(name, value, prefix = 'owner'){
let rule;
if(!this.rule_t[prefix])
{
let rulename = `.${this.id}` + (prefix == "owner" ? "" : prefix);
let no = style.sheet.insertRule(`${rulename}{}`);
this.rule_t[prefix] = style.sheet.cssRules[no];
};
rule = this.rule_t[prefix];
if(value === undefined && typeof name == "string")
{
return rule.style.getPropertyValue(name);
}
if(value === null)
{
rule.style.removeProperty(name, value);
}else{
if(typeof name == "object")
{
for(let [stylename, stylevalue] of Object.entries(name))
{
let name = stylename;
let value = typeof stylevalue == "string" ? stylevalue.split('!')[0] : stylevalue;
let priority = typeof stylevalue == "string" ? (stylevalue.split('!')[1] == "important" ? "!important" : void 0) : stylevalue;
if(name.indexOf('-') == -1)
{
rule.style[name] = value + (priority || "");
}else{
rule.style.setProperty(name, value, priority);
}
}
}else{
rule.style.setProperty(name, value);
}
}
return this;
}
}
$.fn.cssom = function(obj, prefix){
if(prefix === void 0 || (typeof obj == "object" && typeof prefix == "string"))
{
let cssom;
if(this.attr("data-cssom"))
{
let name = this.attr("data-cssom");
cssom = CSSOM.get(name)
}else{
cssom = CSSOM.generate();
this.addClass(cssom.id);
this.attr("data-cssom", cssom.id);
}
cssom.css(obj,void 0,prefix);
}else{
if(obj.indexOf(":") == -1){
this.addClass(obj);
CSSOM.css("." + obj, prefix);
}else{
let [_class,_psudio] = obj.split(":");
this.addClass(_class);
CSSOM.css("." + _class + ":" + _psudio, prefix);
}
}
return this;
};
window.debugCssom = function(){
for (let ruleIndex = 0; ruleIndex < style.sheet.cssRules.length; ruleIndex++)
{
let rule = style.sheet.cssRules.item(ruleIndex);
console.log(rule.cssText)
}
};
window.cssom = CSSOM;
/*
*/

View File

@ -1,44 +0,0 @@
/**
* @ typedef {Object} BirthData
* @ property {Date} birthDate
*/
/**
* @typedef {Object} BrainCell
* @property {string} type
* @property {Object} data
*/
/**
* @type {BrainCell[]}
*/
export let memory = [];
export function AddCell(name, data)
{
memory.push({
type: name,
data
});
};
/**
* @param {string} type
* @param {(BrainCell) => boolean} filterQuery
*/
export function RemoveCell(type, filterQuery)
{
memory = memory.filter(e => !(
e.type == type && filterQuery(e.data)
));
};
/**
* @param {string} type
* @param {(BrainCell) => boolean} filterQuery
*/
export function FilterCell(type, filterQuery)
{
return memory.filter(e =>
e.type == type && filterQuery(e.data)
).map(e => e.data);
};
window.memoryDump = () => memory;

View File

@ -1,293 +0,0 @@
export default class DWindow extends EventTarget {
static allWindows = []; // açık pencereler
static zCounter = 1; // global sayaç
static normalizeThreshold = 9999; // yeniden sıfırlama eşiği
/** @type {JQuery<HTMLElement>} */ panel = null;
/** @type {JQuery<HTMLElement>} */ title = null;
/** @type {JQuery<HTMLElement>} */ content = null;
/** @type {JQuery<HTMLElement>} */ headtext = null;
constructor() {
super();
this.initpanel();
this.enableFocus();
DWindow.allWindows.push(this);
this.bringToFront();
requestAnimationFrame(()=>{
this.enableDragging();
this.enableResize();
})
}
activeDragging = true;
activeResizing = true;
initpanel() {
this.panel = $(`<div></div>`).css({
width: 450,
//height: 500,
position: "fixed",
left: (Math.random() * 300 | 0) + 100,
top: (Math.random() * 100 | 0) + 100,
boxShadow: "black 0px 0px 20px -10px",
borderRadius: "10px",
backgroundColor: "#3333335b",
backdropFilter: "blur(3px)",
border: "solid 1px #a2a2a2",
display: "flex",
flexDirection: "column",
outlineOffset: "-5px",
//overflow: "hidden",
userSelect: "none",
minWidth: "max-content",
minHeight: "max-content"
});
$("body").append(this.panel);
this.title = $(`<div></div>`).css({
display: "flex",
flex: "0 0 auto",
flexDirection: "row",
lineHeight: "2em",
backgroundColor: "#333333",
color: "white",
paddingLeft: "10px",
cursor: "move",
borderTopLeftRadius: "10px",
borderTopRightRadius: "10px",
});
this.content = $(`<div></div>`).css({
flex: "1 1 auto",
overflow: "auto",
borderBottomRightRadius: "10px",
borderBottomLeftRadius: "10px",
padding: "20px"
});
this.panel.append(this.title, this.content);
this.initTitle();
}
initTitle() {
this.headtext = $("<div>Başlıksız pencere</div>");
const divider = $("<div style='flex:1 1 auto'></div>");
this.exitbtn = $("<div><span class='btn btn-sm material-symbols-outlined text-white'>close</span></div>");
this.exitbtn.on('click',()=>{
this.dispatchEvent(new Event("close"));
})
this.title.append(
this.headtext,
divider,
this.exitbtn
);
}
enableDragging() {
let isDragging = false;
let startX, startY, startLeft, startTop;
this.title.on("mousedown", (e) => {
if(this.activeDragging == false){
return;
}
let isInput = $(e.target).closest("button, input, select, textarea,.btn");
if (isInput.length) return;
e.preventDefault();
isDragging = true;
startX = e.pageX;
startY = e.pageY;
startLeft = parseFloat(this.panel.css("left"));
startTop = parseFloat(this.panel.css("top"));
$("body").css("user-select", "none");
this.dispatchEvent(new Event("dragging"));
this.panel.css("box-shadow","black 0px 0px 40px -20px");
this.panel.css("backdrop-filter","blur(10px)");
});
$(document).on("mousemove", (e) => {
if (!isDragging) return;
const dx = e.pageX - startX;
const dy = e.pageY - startY;
this.panel.css({
left: startLeft + dx,
top: startTop + dy,
});
});
$(document).on("mouseup", () => {
if (isDragging) {
isDragging = false;
this.panel.css("box-shadow","black 0px 0px 20px -10px");
this.panel.css("backdrop-filter","blur(3px)");
$("body").css("user-select", "auto");
this.dispatchEvent(new Event("draggingend"));
}
});
}
enableResize() {
const offset = 5; // panelin dışından 5px alan
let resizing = false;
let resizeDir = "";
let startX, startY, startW, startH, startL, startT;
const minW = 200, minH = 150;
// overlay divleri oluştur
const handles = {};
const names = ["n","s","e","w","ne","nw","se","sw"];
names.forEach(n => {
handles[n] = $('<div></div>').css({
position: "absolute",
zIndex: 1000,
background: "transparent",
cursor: n + "-resize",
transition: "all 0.5s all",
outlineOffset: "3px"
}).appendTo(this.panel);
});
// boyut ve pozisyonlarını ayarla
const updateHandles = () => {
const w = this.panel.outerWidth();
const h = this.panel.outerHeight();
// kenarlar
handles.n.css({ top: -offset, left: 0, width: w, height: offset*2 });
handles.s.css({ bottom: -offset, left: 0, width: w, height: offset*2 });
handles.w.css({ top: 0, left: -offset, width: offset*2, height: h });
handles.e.css({ top: 0, right: -offset, width: offset*2, height: h });
// köşeler
handles.nw.css({ top: -offset, left: -offset, width: offset*2, height: offset*2 });
handles.ne.css({ top: -offset, right: -offset, width: offset*2, height: offset*2 });
handles.sw.css({ bottom: -offset, left: -offset, width: offset*2, height: offset*2 });
handles.se.css({ bottom: -offset, right: -offset, width: offset*2, height: offset*2 });
};
updateHandles();
$(window).on("resize", updateHandles);
let activeDir = null;
// resize eventleri
names.forEach(dir => {
handles[dir].on("mousedown", (e) => {
if(this.activeResizing == false){
return;
}
activeDir = e.target;
e.preventDefault();
e.stopPropagation();
resizing = true;
resizeDir = dir;
startX = e.pageX;
startY = e.pageY;
startW = this.panel.outerWidth();
startH = this.panel.outerHeight();
startL = parseFloat(this.panel.css("left"));
startT = parseFloat(this.panel.css("top"));
this.dispatchEvent(new Event("resizing"));
$("body").css("user-select","none");
});
});
$(document).on("mousemove", (e) => {
if (!resizing) return;
const dx = e.pageX - startX;
const dy = e.pageY - startY;
let newW = startW;
let newH = startH;
let newL = startL;
let newT = startT;
if (resizeDir.includes("e")) newW = Math.max(minW, startW + dx);
if (resizeDir.includes("w")) { newW = Math.max(minW, startW - dx); newL = startL + (startW - newW); }
if (resizeDir.includes("s")) newH = Math.max(minH, startH + dy);
if (resizeDir.includes("n")) { newH = Math.max(minH, startH - dy); newT = startT + (startH - newH); }
this.panel.css({ width: newW, height: newH, left: newL, top: newT });
updateHandles();
$(activeDir).css("outline", "solid 2px #00ff00");
});
$(document).on("mouseup", () => {
if (resizing) {
resizing = false;
$("body").css("user-select","auto");
$(activeDir).css("outline", "solid 0px #00ff00");
this.dispatchEvent(new Event("resizingend"));
}
});
}
enableFocus() {
this.panel.on("mousedown", () => {
this.bringToFront();
});
}
bringToFront() {
if (DWindow.zCounter > DWindow.normalizeThreshold) {
DWindow.normalizeZ();
}
DWindow.zCounter++;
this.panel.css("z-index", DWindow.zCounter);
}
showing = true;
show(){
this.dispatchEvent(new Event("show"));
this.panel.show();
this.showing = true;
}
hide(){
this.dispatchEvent(new Event("hide"));
this.panel.hide();
this.showing = false;
}
toggle(){
this.showing ? this.hide() : this.show();
}
exit(){
this.dispatchEvent(new Event("exit"));
this.panel.remove();
}
/** @type {DWindow} */
parent = null;
/** @param {DWindow} parent */
enableDialog(parent){
this.parent = parent;
this.parent.activeDragging = false;
this.parent.activeResizing = false;
this.parent.panel.css('pointer-events',"none");
this.parent.panel.css('filter',"grayscale(1)");
let [{
left: parentL,
top: parentT,
width: parentW,
height: parentH
}] = this.parent.panel[0].getClientRects();
let [{
width: childW,
height: childH
}] = this.panel[0].getClientRects();
let newLeft = parentL + (parentW - childW) / 2;
let newTop = parentT + (parentH - childH) / 2;
debugger;
newLeft = Math.max(newLeft, 20);
newTop = Math.max(newTop, 20);
newLeft = Math.min(newLeft, screen.availWidth - 100);
newTop = Math.min(newTop, screen.availHeight - 100);
Object.assign(this.panel[0].style, {
left: `${Math.round(newLeft)}px`,
top: `${Math.round(newTop)}px`
});
}
/** @param {DWindow} parent */
disableDialog(){
this.parent.activeDragging = true;
this.parent.activeResizing = true;
this.parent.panel.css('pointer-events',"all");
this.parent.panel.css('filter',"initial");
}
}

View File

@ -12,9 +12,9 @@ async function beginEngine()
accessType: "private",
description: "Private free joined room",
ifexistsJoin: false,
notifyActionEjected: false,
notifyActionEjected: true,
notifyActionInvite: false,
notifyActionJoined: false
notifyActionJoined: true
});
try{
await room.createRoom();

View File

@ -6,10 +6,58 @@
<title>Dosya Transfer Sistem</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.7/css/bootstrap.min.css">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" />
</head>
<body>
<div class="container" style="max-width: 1200px">
<h2 class="text-center mb-2 mt-5">Dosya Transfer Sistemi</h2>
<h1 class="text-center mb-5 mt-3 text-bold fw-bold">
<span>Ağ Adresiniz</span>
<span class="text-danger network-id">
#.#.#.#
</span>
</h1>
<div class="mx-auto d-flex flex-row mb-5" style="max-width: 800px;gap:20px">
<div class="flex-fill">
<input
type="file"
id="files"
multiple
class="form-control"
>
</div>
<div class="flex-fill d-flex" style="gap:5px">
<input
type="text"
class="form-control"
placeholder="Farklı bir ağa katıl"
id="remoteadress"
>
<button class="btn btn-outline-success joinroom">
Katıl
</button>
</div>
</div>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th class="text-nowrap" width="1%">İşlem</th>
<th class="text-nowrap" width="1%">SHA-1</th>
<th class="text-nowrap" width="49%">Dosya İsmi</th>
<th class="text-nowrap" width="50%">İşlem</th>
</tr>
</thead>
<tbody id="thelist">
<tr class="empty">
<td class="text-center text-muted" colspan="4">
Gönderilecek veya alınacak dosya bulunmuyor
</td>
</tr>
</tbody>
</table>
</div>
<script src="https://ws.saqut.com/script"></script>
<script src="m.h.2.8.8.js"></script>
</body>

View File

@ -1,166 +0,0 @@
<!doctype html>
<html lang="tr">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>jQuery ile Resizable Kutu</title>
<style>
body { font-family: Arial, Helvetica, sans-serif; height:100vh; margin:0; display:flex; align-items:center; justify-content:center; background:#f2f2f2; }
.stage { width:90vw; height:80vh; border:1px solid #ccc; position:relative; background:#fff; }
.box {
position:absolute;
left:50px; top:50px;
width:300px; height:200px;
background:#e8f0ff;
border:1px solid #5b8cff;
box-sizing:border-box;
user-select:none;
}
/* küçücük tutamaklar (handles) */
.handle {
position:absolute;
width:12px; height:12px;
background:#5b8cff;
border-radius:2px;
margin:-6px 0 0 -6px; /* merkezler */
cursor:default;
}
.handle.n { top:0; left:50%; cursor:n-resize; }
.handle.s { bottom:0; left:50%; cursor:s-resize; }
.handle.e { right:0; top:50%; cursor:e-resize; }
.handle.w { left:0; top:50%; cursor:w-resize; }
.handle.ne { right:0; top:0; cursor:ne-resize; }
.handle.nw { left:0; top:0; cursor:nw-resize; }
.handle.se { right:0; bottom:0; cursor:se-resize; }
.handle.sw { left:0; bottom:0; cursor:sw-resize; }
/* bilgi satırı (isteğe bağlı) */
.info { position:absolute; left:6px; bottom:6px; font-size:12px; color:#333; background:rgba(255,255,255,0.8); padding:4px 6px; border-radius:4px; }
</style>
</head>
<body>
<div class="stage">
<div class="box" id="resizable">
<div class="handle n" data-dir="n"></div>
<div class="handle s" data-dir="s"></div>
<div class="handle e" data-dir="e"></div>
<div class="handle w" data-dir="w"></div>
<div class="handle ne" data-dir="ne"></div>
<div class="handle nw" data-dir="nw"></div>
<div class="handle se" data-dir="se"></div>
<div class="handle sw" data-dir="sw"></div>
<div class="info" id="info"></div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script>
$(function(){
var $doc = $(document);
var $box = $('#resizable');
var dragging = false;
var dir = null;
var start = {}; // {mouseX, mouseY, left, top, width, height}
var minW = 60, minH = 40;
function updateInfo(){
var w = Math.round($box.width()), h = Math.round($box.height());
$('#info').text(w + ' x ' + h);
}
updateInfo();
$box.on('mousedown', '.handle', function(e){
e.preventDefault();
dragging = true;
dir = $(this).data('dir');
var offset = $box.position();
start = {
mouseX: e.pageX,
mouseY: e.pageY,
left: offset.left,
top: offset.top,
width: $box.outerWidth(),
height: $box.outerHeight()
};
// disable text selection while dragging
$('body').css('user-select','none');
});
$doc.on('mousemove', function(e){
if(!dragging) return;
e.preventDefault();
var dx = e.pageX - start.mouseX;
var dy = e.pageY - start.mouseY;
var newLeft = start.left;
var newTop = start.top;
var newW = start.width;
var newH = start.height;
// handle horizontal changes
if(dir.indexOf('e') !== -1){
newW = Math.max(minW, start.width + dx);
}
if(dir.indexOf('w') !== -1){
newW = Math.max(minW, start.width - dx);
newLeft = start.left + (start.width - newW);
}
// handle vertical changes
if(dir.indexOf('s') !== -1){
newH = Math.max(minH, start.height + dy);
}
if(dir.indexOf('n') !== -1){
newH = Math.max(minH, start.height - dy);
newTop = start.top + (start.height - newH);
}
// apply
$box.css({ left: newLeft + 'px', top: newTop + 'px', width: newW + 'px', height: newH + 'px' });
updateInfo();
});
$doc.on('mouseup mouseleave', function(){
if(dragging){
dragging = false;
dir = null;
$('body').css('user-select','auto');
}
});
// optional: allow dragging the whole box when clicking inside (but not on handles)
var draggingBox = false, dragBoxStart = {};
$box.on('mousedown', function(e){
if($(e.target).hasClass('handle')) return;
e.preventDefault();
draggingBox = true;
dragBoxStart = { mouseX: e.pageX, mouseY: e.pageY, left: $box.position().left, top: $box.position().top };
$('body').css('user-select','none');
});
$doc.on('mousemove', function(e){
if(!draggingBox) return;
var nx = dragBoxStart.left + (e.pageX - dragBoxStart.mouseX);
var ny = dragBoxStart.top + (e.pageY - dragBoxStart.mouseY);
$box.css({ left: nx + 'px', top: ny + 'px' });
});
$doc.on('mouseup', function(){
if(draggingBox){
draggingBox = false;
$('body').css('user-select','auto');
}
});
// keyboard nudges (isteğe bağlı)
$doc.on('keydown', function(e){
e.preventDefault();
if(!e.altKey) return; // alt ile etkinleştir
var pos = $box.position();
if(e.key === 'ArrowLeft') $box.css('left', pos.left - 1);
if(e.key === 'ArrowRight') $box.css('left', pos.left + 1);
if(e.key === 'ArrowUp') $box.css('top', pos.top - 1);
if(e.key === 'ArrowDown') $box.css('top', pos.top + 1);
});
});
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long