diff --git a/allstarr/Controllers/AdminController.cs b/allstarr/Controllers/AdminController.cs
index 8cd8ba8..465cfd5 100644
--- a/allstarr/Controllers/AdminController.cs
+++ b/allstarr/Controllers/AdminController.cs
@@ -502,6 +502,92 @@ public class AdminController : ControllerBase
return Ok(new { message = "Cache cleared", filesDeleted = clearedFiles });
}
+ ///
+ /// Restart the allstarr container to apply configuration changes
+ ///
+ [HttpPost("restart")]
+ public async Task RestartContainer()
+ {
+ _logger.LogInformation("Container restart requested from admin UI");
+
+ try
+ {
+ // Use Docker socket to restart the container
+ var socketPath = "/var/run/docker.sock";
+
+ if (!System.IO.File.Exists(socketPath))
+ {
+ _logger.LogWarning("Docker socket not available at {Path}", socketPath);
+ return StatusCode(503, new {
+ error = "Docker socket not available",
+ message = "Please restart manually: docker-compose restart allstarr"
+ });
+ }
+
+ // Get container ID from hostname (Docker sets hostname to container ID by default)
+ // Or use the well-known container name
+ var containerId = Environment.MachineName;
+ var containerName = "allstarr";
+
+ _logger.LogInformation("Attempting to restart container {ContainerId} / {ContainerName}", containerId, containerName);
+
+ // Create Unix socket HTTP client
+ var handler = new SocketsHttpHandler
+ {
+ ConnectCallback = async (context, cancellationToken) =>
+ {
+ var socket = new System.Net.Sockets.Socket(
+ System.Net.Sockets.AddressFamily.Unix,
+ System.Net.Sockets.SocketType.Stream,
+ System.Net.Sockets.ProtocolType.Unspecified);
+
+ var endpoint = new System.Net.Sockets.UnixDomainSocketEndPoint(socketPath);
+ await socket.ConnectAsync(endpoint, cancellationToken);
+
+ return new System.Net.Sockets.NetworkStream(socket, ownsSocket: true);
+ }
+ };
+
+ using var dockerClient = new HttpClient(handler)
+ {
+ BaseAddress = new Uri("http://localhost")
+ };
+
+ // Try to restart by container name first, then by ID
+ var response = await dockerClient.PostAsync($"/containers/{containerName}/restart?t=5", null);
+
+ if (!response.IsSuccessStatusCode)
+ {
+ // Try by container ID
+ response = await dockerClient.PostAsync($"/containers/{containerId}/restart?t=5", null);
+ }
+
+ if (response.IsSuccessStatusCode)
+ {
+ _logger.LogInformation("Container restart initiated successfully");
+ return Ok(new { message = "Restarting container...", success = true });
+ }
+ else
+ {
+ var errorBody = await response.Content.ReadAsStringAsync();
+ _logger.LogError("Failed to restart container: {StatusCode} - {Body}", response.StatusCode, errorBody);
+ return StatusCode((int)response.StatusCode, new {
+ error = "Failed to restart container",
+ message = "Please restart manually: docker-compose restart allstarr"
+ });
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error restarting container");
+ return StatusCode(500, new {
+ error = "Failed to restart container",
+ details = ex.Message,
+ message = "Please restart manually: docker-compose restart allstarr"
+ });
+ }
+ }
+
///
/// Initialize cookie date to current date if cookie exists but date is not set
///
diff --git a/allstarr/wwwroot/index.html b/allstarr/wwwroot/index.html
index 2238004..3fc764a 100644
--- a/allstarr/wwwroot/index.html
+++ b/allstarr/wwwroot/index.html
@@ -1146,8 +1146,57 @@
}
}
- function restartContainer() {
- alert('To apply configuration changes, please restart the container manually via Dockge or docker-compose:\n\ndocker-compose restart allstarr\n\nor use Dockge UI to restart the stack.');
+ async function restartContainer() {
+ if (!confirm('Restart the container to apply configuration changes?\n\nThe dashboard will be temporarily unavailable.')) {
+ return;
+ }
+
+ try {
+ showToast('Restarting container...', 'success');
+ const res = await fetch('/api/admin/restart', { method: 'POST' });
+ const data = await res.json();
+
+ if (res.ok) {
+ showToast('Container restarting... Page will reload shortly.', 'success');
+ // Wait a bit then start checking if the server is back
+ setTimeout(() => {
+ checkServerAndReload();
+ }, 3000);
+ } else {
+ showToast(data.message || data.error || 'Failed to restart', 'error');
+ }
+ } catch (error) {
+ showToast('Failed to restart container', 'error');
+ }
+ }
+
+ async function checkServerAndReload() {
+ let attempts = 0;
+ const maxAttempts = 30; // Try for 30 seconds
+
+ const checkHealth = async () => {
+ try {
+ const res = await fetch('/api/admin/status', {
+ method: 'GET',
+ cache: 'no-store'
+ });
+ if (res.ok) {
+ window.location.reload();
+ return;
+ }
+ } catch (e) {
+ // Server still restarting
+ }
+
+ attempts++;
+ if (attempts < maxAttempts) {
+ setTimeout(checkHealth, 1000);
+ } else {
+ showToast('Server may still be restarting. Please refresh manually.', 'warning');
+ }
+ };
+
+ checkHealth();
}
function openAddPlaylist() {
diff --git a/docker-compose.yml b/docker-compose.yml
index a8e09a5..2a8d61f 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -111,6 +111,8 @@ services:
- ${DOWNLOAD_PATH:-./downloads}:/app/downloads
- ${KEPT_PATH:-./kept}:/app/kept
- ${CACHE_PATH:-./cache}:/app/cache
+ # Docker socket for self-restart capability (admin UI only)
+ - /var/run/docker.sock:/var/run/docker.sock:ro
networks:
allstarr-network: