restyle the rest of the pages
All checks were successful
CI / Maven unit tests (push) Successful in 14s
CI / Build and push images (push) Has been skipped
CI / Deploy to server (push) Has been skipped

This commit is contained in:
2026-08-02 16:32:00 +01:00
parent 11809a7da8
commit eab3f8be20
46 changed files with 2022 additions and 857 deletions

View File

@@ -116,7 +116,11 @@ public class ClipController {
clip.getTitle(),
clip.getDescription(),
clip.getDuration(),
clip.getCreatedAt()
clip.getCreatedAt(),
clip.getWidth(),
clip.getHeight(),
clip.getFps(),
clip.getFileSize()
);
}
}

View File

@@ -1,14 +1,17 @@
package com.ddf.vodsystem.controllers;
import com.ddf.vodsystem.controllers.dto.IngestResponse;
import com.ddf.vodsystem.controllers.dto.StreamResponse;
import com.ddf.vodsystem.dto.APIResponse;
import com.ddf.vodsystem.entities.Stream;
import com.ddf.vodsystem.services.StreamService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.net.URI;
import java.util.List;
import java.util.Optional;
@@ -18,8 +21,18 @@ public class StreamController {
private static final Logger logger = LoggerFactory.getLogger(StreamController.class);
private static final String SUCCESS = "success";
/** Matches the port and application name in nginx/default.conf.template. */
private static final int RTMP_PORT = 1935;
private static final String RTMP_APPLICATION = "live";
private final StreamService streamService;
@Value("${stream.ingest.url:}")
private String configuredIngestUrl;
@Value("${frontend.url:}")
private String frontendUrl;
public StreamController(StreamService streamService) {
this.streamService = streamService;
}
@@ -53,6 +66,49 @@ public class StreamController {
return ResponseEntity.ok(new APIResponse<>(SUCCESS, "Stream history retrieved", history));
}
@GetMapping("/ingest")
public ResponseEntity<APIResponse<IngestResponse>> getIngestEndpoint() {
return ResponseEntity.ok(new APIResponse<>(SUCCESS,
"Ingest endpoint retrieved",
new IngestResponse(resolveIngestUrl())));
}
/**
* The RTMP endpoint to publish to. Set {@code STREAM_INGEST_URL} to state it outright —
* needed when the RTMP port is reached through a different host or a non-default port.
* Otherwise it is derived from the frontend's host, which is where docker-compose
* publishes the nginx-rtmp container.
*/
private String resolveIngestUrl() {
if (configuredIngestUrl != null && !configuredIngestUrl.isBlank()) {
return configuredIngestUrl.trim();
}
String host = hostOf(frontendUrl);
return "rtmp://" + (host == null ? "localhost" : host) + ":" + RTMP_PORT + "/" + RTMP_APPLICATION;
}
private static String hostOf(String url) {
if (url == null || url.isBlank()) {
return null;
}
String trimmed = url.trim();
try {
String host = URI.create(trimmed).getHost();
if (host != null && !host.isBlank()) {
return host;
}
} catch (IllegalArgumentException e) {
logger.warn("Could not parse frontend.url ({})", trimmed);
}
// A bare "example.net" or "example.net:8080" parses as a path, not a host.
String bare = trimmed.split("/", 2)[0].split(":", 2)[0];
return bare.isBlank() ? null : bare;
}
@GetMapping("/current")
public ResponseEntity<APIResponse<StreamResponse>> getCurrentStream() {
Optional<Stream> stream = streamService.getActiveStream();

View File

@@ -93,7 +93,11 @@ public class VodController {
vod.getTitle(),
vod.getDescription(),
vod.getDuration(),
vod.getCreatedAt()
vod.getCreatedAt(),
vod.getWidth(),
vod.getHeight(),
vod.getFps(),
vod.getFileSize()
);
}
}

View File

@@ -8,5 +8,9 @@ public record ClipResponse(
String title,
String description,
Float duration,
Instant createdAt
Instant createdAt,
Integer width,
Integer height,
Float fps,
Long fileSize
) {}

View File

@@ -0,0 +1,4 @@
package com.ddf.vodsystem.controllers.dto;
/** Where OBS (or anything else speaking RTMP) should publish to. */
public record IngestResponse(String url) {}

View File

@@ -8,5 +8,9 @@ public record VodResponse(
String title,
String description,
Float duration,
Instant createdAt
Instant createdAt,
Integer width,
Integer height,
Float fps,
Long fileSize
) {}