Initial commit
This commit is contained in:
150
remote/public/index.html
Normal file
150
remote/public/index.html
Normal file
@@ -0,0 +1,150 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>xc-remote</title>
|
||||
<link rel="stylesheet" href="css/main.css">
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="video-canvas"></canvas>
|
||||
<button id="file-transfer-btn">📁 文件传输</button>
|
||||
|
||||
<script src="js/jsmpeg.min.js"></script>
|
||||
<script src="js/utils.js"></script>
|
||||
<script src="js/player.js"></script>
|
||||
<script src="js/input.js"></script>
|
||||
<script src="js/file-panel.js"></script>
|
||||
<script src="js/app.js"></script>
|
||||
<script>
|
||||
(function() {
|
||||
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
const wsHost = window.location.hostname;
|
||||
const wsPort = window.location.port;
|
||||
const wsUrlBase = wsPort ? `${wsProtocol}//${wsHost}:${wsPort}/ws` : `${wsProtocol}//${wsHost}/ws`;
|
||||
const password = getCookie('auth') || '';
|
||||
const WS_URL = password ? `${wsUrlBase}?password=${encodeURIComponent(password)}` : wsUrlBase;
|
||||
|
||||
let clipboardWs = null;
|
||||
let isClipboardSyncing = false;
|
||||
|
||||
function connectClipboardWs() {
|
||||
if (clipboardWs && clipboardWs.readyState === WebSocket.OPEN) {
|
||||
return clipboardWs;
|
||||
}
|
||||
|
||||
clipboardWs = new WebSocket(WS_URL);
|
||||
|
||||
clipboardWs.onmessage = async (e) => {
|
||||
if (e.data instanceof Blob) return;
|
||||
|
||||
try {
|
||||
const msg = JSON.parse(e.data);
|
||||
|
||||
if (msg.type === 'clipboardData') {
|
||||
if (msg.contentType === 'text' && msg.data) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(msg.data);
|
||||
console.log('Clipboard synced from remote');
|
||||
} catch (err) {
|
||||
console.error('Failed to write local clipboard:', err);
|
||||
}
|
||||
}
|
||||
} else if (msg.type === 'clipboardTooLarge') {
|
||||
console.warn('Remote clipboard content too large:', msg.size);
|
||||
}
|
||||
} catch (err) {}
|
||||
};
|
||||
|
||||
clipboardWs.onopen = () => console.log('Clipboard sync ready');
|
||||
clipboardWs.onclose = () => { clipboardWs = null; };
|
||||
clipboardWs.onerror = () => { clipboardWs = null; };
|
||||
|
||||
return clipboardWs;
|
||||
}
|
||||
|
||||
async function syncFromRemote() {
|
||||
if (isClipboardSyncing) return;
|
||||
isClipboardSyncing = true;
|
||||
|
||||
try {
|
||||
const ws = connectClipboardWs();
|
||||
const sendRequest = () => {
|
||||
ws.send(JSON.stringify({ type: 'clipboardGet' }));
|
||||
};
|
||||
|
||||
if (ws.readyState === WebSocket.OPEN) {
|
||||
sendRequest();
|
||||
} else {
|
||||
ws.onopen = sendRequest;
|
||||
}
|
||||
} finally {
|
||||
setTimeout(() => { isClipboardSyncing = false; }, 500);
|
||||
}
|
||||
}
|
||||
|
||||
async function syncToRemote() {
|
||||
if (isClipboardSyncing) return;
|
||||
isClipboardSyncing = true;
|
||||
|
||||
try {
|
||||
let text = '';
|
||||
try {
|
||||
text = await navigator.clipboard.readText();
|
||||
} catch (err) {
|
||||
console.warn('Cannot read local clipboard');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!text) return;
|
||||
|
||||
const ws = connectClipboardWs();
|
||||
const sendRequest = () => {
|
||||
ws.send(JSON.stringify({
|
||||
type: 'clipboardSet',
|
||||
contentType: 'text',
|
||||
data: text
|
||||
}));
|
||||
console.log('Clipboard synced to remote');
|
||||
};
|
||||
|
||||
if (ws.readyState === WebSocket.OPEN) {
|
||||
sendRequest();
|
||||
} else {
|
||||
ws.onopen = sendRequest;
|
||||
}
|
||||
} finally {
|
||||
setTimeout(() => { isClipboardSyncing = false; }, 500);
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', async (e) => {
|
||||
if (e.ctrlKey && e.key === 'c' && !e.shiftKey && !e.altKey) {
|
||||
if (document.activeElement.tagName === 'INPUT' ||
|
||||
document.activeElement.tagName === 'TEXTAREA') {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
await syncFromRemote();
|
||||
}
|
||||
|
||||
if (e.ctrlKey && e.key === 'v' && !e.shiftKey && !e.altKey) {
|
||||
if (document.activeElement.tagName === 'INPUT' ||
|
||||
document.activeElement.tagName === 'TEXTAREA') {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
await syncToRemote();
|
||||
}
|
||||
});
|
||||
|
||||
connectClipboardWs();
|
||||
|
||||
const filePanel = new FilePanel();
|
||||
document.getElementById('file-transfer-btn').addEventListener('click', () => {
|
||||
filePanel.toggle();
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user