Update config.json and workspace context as of 27. Dezember 2025

This commit is contained in:
Lukas 2025-12-27 21:10:53 +01:00
parent 4780f68a23
commit 803f35ef39
6 changed files with 209 additions and 79 deletions

BIN
data/aniworld.db-shm Normal file

Binary file not shown.

0
data/aniworld.db-wal Normal file
View File

View File

@ -17,7 +17,7 @@
"keep_days": 30 "keep_days": 30
}, },
"other": { "other": {
"master_password_hash": "$pbkdf2-sha256$29000$aq3VOsfY21sLwfgfQwghJA$d33KHoETVV5.zpCfR.BqM.ICe.DwjDcfATrsrsZ/3yM", "master_password_hash": "$pbkdf2-sha256$29000$LkUohZASQmgthdD6n9Nayw$6VmJzv/pYSdyW7..eU57P.YJpjK/6fXvXvef0L6PLDg",
"anime_directory": "/mnt/server/serien/Serien/" "anime_directory": "/mnt/server/serien/Serien/"
}, },
"version": "1.0.0" "version": "1.0.0"

View File

@ -1,7 +1,8 @@
/** /**
* AniWorld - WebSocket Client Module * AniWorld - WebSocket Client Module
* *
* WebSocket connection management and event handling. * Native WebSocket connection management with Socket.IO-style interface.
* Uses FastAPI native WebSocket backend with room-based messaging.
* *
* Dependencies: constants.js * Dependencies: constants.js
*/ */
@ -13,9 +14,24 @@ AniWorld.WebSocketClient = (function() {
const WS_EVENTS = AniWorld.Constants.WS_EVENTS; const WS_EVENTS = AniWorld.Constants.WS_EVENTS;
let socket = null; let ws = null;
let isConnected = false; let isConnected = false;
let eventHandlers = {}; let eventHandlers = {};
let rooms = new Set();
let messageQueue = [];
let reconnectAttempts = 0;
const maxReconnectAttempts = 5;
const reconnectDelay = 1000;
let autoReconnect = true;
/**
* Get WebSocket URL based on current page URL
*/
function getWebSocketUrl() {
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const host = window.location.host;
return protocol + '//' + host + '/ws/connect';
}
/** /**
* Initialize WebSocket connection * Initialize WebSocket connection
@ -25,62 +41,181 @@ AniWorld.WebSocketClient = (function() {
handlers = handlers || {}; handlers = handlers || {};
eventHandlers = handlers; eventHandlers = handlers;
// Check if Socket.IO is available connect();
if (typeof io === 'undefined') { }
console.error('Socket.IO not loaded');
/**
* Connect to WebSocket server
*/
function connect() {
if (ws && ws.readyState === WebSocket.OPEN) {
console.log('WebSocket already connected');
return; return;
} }
socket = io(); try {
const url = getWebSocketUrl();
console.log('Connecting to WebSocket:', url);
ws = new WebSocket(url);
// Handle connection events ws.onopen = function() {
socket.on('connected', function(data) { console.log('WebSocket connected');
console.log('WebSocket connection confirmed', data);
});
socket.on('connect', function() {
isConnected = true; isConnected = true;
console.log('Connected to server'); reconnectAttempts = 0;
// Subscribe to rooms // Emit connect event to handlers
if (socket.join) { emitToHandlers('connect');
socket.join('scan');
socket.join('downloads'); // Join default rooms for this application
socket.join('queue'); joinRoom('scan');
} joinRoom('downloads');
joinRoom('queue');
// Rejoin any previously joined rooms
rejoinRooms();
// Process queued messages
processMessageQueue();
// Call custom connect handler if provided // Call custom connect handler if provided
if (eventHandlers.onConnect) { if (eventHandlers.onConnect) {
eventHandlers.onConnect(); eventHandlers.onConnect();
} }
}); };
socket.on('disconnect', function() { ws.onmessage = function(event) {
handleMessage(event.data);
};
ws.onerror = function(error) {
console.error('WebSocket error:', error);
emitToHandlers('error', { error: 'WebSocket connection error' });
};
ws.onclose = function(event) {
console.log('WebSocket disconnected', event.code, event.reason);
isConnected = false; isConnected = false;
console.log('Disconnected from server'); emitToHandlers('disconnect', { code: event.code, reason: event.reason });
// Call custom disconnect handler if provided // Call custom disconnect handler if provided
if (eventHandlers.onDisconnect) { if (eventHandlers.onDisconnect) {
eventHandlers.onDisconnect(); eventHandlers.onDisconnect();
} }
});
// Set up event handlers for common events // Attempt reconnection
setupDefaultHandlers(); if (autoReconnect && reconnectAttempts < maxReconnectAttempts) {
reconnectAttempts++;
var delay = reconnectDelay * reconnectAttempts;
console.log('Attempting reconnection in ' + delay + 'ms (attempt ' + reconnectAttempts + ')');
setTimeout(connect, delay);
}
};
} catch (error) {
console.error('Failed to create WebSocket connection:', error);
emitToHandlers('error', { error: 'Failed to connect' });
}
} }
/** /**
* Set up default event handlers * Handle incoming WebSocket message
* @param {string} data - Raw message data
*/ */
function setupDefaultHandlers() { function handleMessage(data) {
if (!socket) return; try {
var message = JSON.parse(data);
var type = message.type;
var payload = message.data;
// Register any events that have handlers console.log('WebSocket message: type=' + type, payload);
Object.keys(eventHandlers).forEach(function(eventName) {
if (eventName !== 'onConnect' && eventName !== 'onDisconnect') { // Emit event to registered handlers
socket.on(eventName, eventHandlers[eventName]); if (type) {
emitToHandlers(type, payload || {});
} }
} catch (error) {
console.error('Failed to parse WebSocket message:', error, data);
}
}
/**
* Emit event to registered handlers (internal)
* @param {string} event - Event name
* @param {*} data - Event data
*/
function emitToHandlers(event, data) {
if (eventHandlers[event]) {
try {
if (data !== undefined) {
eventHandlers[event](data);
} else {
eventHandlers[event]();
}
} catch (error) {
console.error('Error in event handler for ' + event + ':', error);
}
}
}
/**
* Send message to server
* @param {string} action - Action type
* @param {Object} data - Data payload
*/
function send(action, data) {
var message = JSON.stringify({
action: action,
data: data || {}
}); });
if (isConnected && ws && ws.readyState === WebSocket.OPEN) {
ws.send(message);
} else {
console.warn('WebSocket not connected, queueing message');
messageQueue.push(message);
}
}
/**
* Join a room (subscribe to topic)
* @param {string} room - Room name
*/
function joinRoom(room) {
rooms.add(room);
if (isConnected) {
send('join', { room: room });
console.log('Joined room:', room);
}
}
/**
* Leave a room (unsubscribe from topic)
* @param {string} room - Room name
*/
function leaveRoom(room) {
rooms.delete(room);
if (isConnected) {
send('leave', { room: room });
console.log('Left room:', room);
}
}
/**
* Rejoin all rooms after reconnection
*/
function rejoinRooms() {
rooms.forEach(function(room) {
send('join', { room: room });
});
}
/**
* Process queued messages after connection
*/
function processMessageQueue() {
while (messageQueue.length > 0 && isConnected) {
var message = messageQueue.shift();
ws.send(message);
}
} }
/** /**
@ -89,14 +224,7 @@ AniWorld.WebSocketClient = (function() {
* @param {Function} handler - The handler function * @param {Function} handler - The handler function
*/ */
function on(eventName, handler) { function on(eventName, handler) {
if (!socket) {
console.warn('Socket not initialized');
return;
}
eventHandlers[eventName] = handler; eventHandlers[eventName] = handler;
socket.off(eventName); // Remove existing handler
socket.on(eventName, handler);
} }
/** /**
@ -104,24 +232,20 @@ AniWorld.WebSocketClient = (function() {
* @param {string} eventName - The event name * @param {string} eventName - The event name
*/ */
function off(eventName) { function off(eventName) {
if (!socket) return;
delete eventHandlers[eventName]; delete eventHandlers[eventName];
socket.off(eventName);
} }
/** /**
* Emit an event to the server * Emit an event to the server (Socket.IO compatibility)
* @param {string} eventName - The event name * @param {string} eventName - The event name
* @param {*} data - The data to send * @param {*} data - The data to send
*/ */
function emit(eventName, data) { function emit(eventName, data) {
if (!socket || !isConnected) { if (!isConnected) {
console.warn('Socket not connected'); console.warn('WebSocket not connected');
return; return;
} }
send(eventName, data);
socket.emit(eventName, data);
} }
/** /**
@ -133,20 +257,29 @@ AniWorld.WebSocketClient = (function() {
} }
/** /**
* Get the socket instance * Get the WebSocket instance (for compatibility)
* @returns {Object} The Socket.IO socket instance * @returns {Object} The WebSocket instance wrapped with event methods
*/ */
function getSocket() { function getSocket() {
return socket; // Return a wrapper object that provides Socket.IO-like interface
return {
on: on,
off: off,
emit: emit,
join: joinRoom,
leave: leaveRoom,
connected: isConnected
};
} }
/** /**
* Disconnect from server * Disconnect from server
*/ */
function disconnect() { function disconnect() {
if (socket) { autoReconnect = false;
socket.disconnect(); if (ws) {
socket = null; ws.close(1000, 'Client disconnected');
ws = null;
isConnected = false; isConnected = false;
} }
} }
@ -157,6 +290,9 @@ AniWorld.WebSocketClient = (function() {
on: on, on: on,
off: off, off: off,
emit: emit, emit: emit,
send: send,
join: joinRoom,
leave: leaveRoom,
isConnected: getConnectionStatus, isConnected: getConnectionStatus,
getSocket: getSocket, getSocket: getSocket,
disconnect: disconnect disconnect: disconnect

View File

@ -440,9 +440,6 @@
</div> </div>
</div> </div>
<!-- Socket.IO -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.7.2/socket.io.min.js"></script>
<!-- Shared Modules (load in dependency order) --> <!-- Shared Modules (load in dependency order) -->
<script src="/static/js/shared/constants.js"></script> <script src="/static/js/shared/constants.js"></script>
<script src="/static/js/shared/auth.js"></script> <script src="/static/js/shared/auth.js"></script>

View File

@ -233,9 +233,6 @@
</div> </div>
</div> </div>
<!-- Socket.IO -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.7.2/socket.io.min.js"></script>
<!-- Shared Modules (load in dependency order) --> <!-- Shared Modules (load in dependency order) -->
<script src="/static/js/shared/constants.js"></script> <script src="/static/js/shared/constants.js"></script>
<script src="/static/js/shared/auth.js"></script> <script src="/static/js/shared/auth.js"></script>