mirror of
https://github.com/imgfloat/server.git
synced 2026-02-05 03:39:26 +00:00
Add audio
This commit is contained in:
@@ -61,6 +61,11 @@ public class SchemaMigration implements ApplicationRunner {
|
||||
addColumnIfMissing("assets", columns, "speed", "REAL", "1.0");
|
||||
addColumnIfMissing("assets", columns, "muted", "BOOLEAN", "0");
|
||||
addColumnIfMissing("assets", columns, "media_type", "TEXT", "'application/octet-stream'");
|
||||
addColumnIfMissing("assets", columns, "audio_loop", "BOOLEAN", "0");
|
||||
addColumnIfMissing("assets", columns, "audio_delay_millis", "INTEGER", "0");
|
||||
addColumnIfMissing("assets", columns, "audio_speed", "REAL", "1.0");
|
||||
addColumnIfMissing("assets", columns, "audio_pitch", "REAL", "1.0");
|
||||
addColumnIfMissing("assets", columns, "audio_volume", "REAL", "1.0");
|
||||
}
|
||||
|
||||
private void addColumnIfMissing(String tableName, List<String> existingColumns, String columnName, String dataType, String defaultValue) {
|
||||
|
||||
@@ -35,6 +35,11 @@ public class Asset {
|
||||
private String mediaType;
|
||||
private String originalMediaType;
|
||||
private Integer zIndex;
|
||||
private Boolean audioLoop;
|
||||
private Integer audioDelayMillis;
|
||||
private Double audioSpeed;
|
||||
private Double audioPitch;
|
||||
private Double audioVolume;
|
||||
private boolean hidden;
|
||||
private Instant createdAt;
|
||||
|
||||
@@ -80,6 +85,21 @@ public class Asset {
|
||||
if (this.zIndex == null || this.zIndex < 1) {
|
||||
this.zIndex = 1;
|
||||
}
|
||||
if (this.audioLoop == null) {
|
||||
this.audioLoop = Boolean.FALSE;
|
||||
}
|
||||
if (this.audioDelayMillis == null) {
|
||||
this.audioDelayMillis = 0;
|
||||
}
|
||||
if (this.audioSpeed == null) {
|
||||
this.audioSpeed = 1.0;
|
||||
}
|
||||
if (this.audioPitch == null) {
|
||||
this.audioPitch = 1.0;
|
||||
}
|
||||
if (this.audioVolume == null) {
|
||||
this.audioVolume = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
@@ -210,6 +230,46 @@ public class Asset {
|
||||
this.zIndex = zIndex == null ? null : Math.max(1, zIndex);
|
||||
}
|
||||
|
||||
public boolean isAudioLoop() {
|
||||
return audioLoop != null && audioLoop;
|
||||
}
|
||||
|
||||
public void setAudioLoop(Boolean audioLoop) {
|
||||
this.audioLoop = audioLoop;
|
||||
}
|
||||
|
||||
public Integer getAudioDelayMillis() {
|
||||
return audioDelayMillis == null ? 0 : Math.max(0, audioDelayMillis);
|
||||
}
|
||||
|
||||
public void setAudioDelayMillis(Integer audioDelayMillis) {
|
||||
this.audioDelayMillis = audioDelayMillis;
|
||||
}
|
||||
|
||||
public double getAudioSpeed() {
|
||||
return audioSpeed == null ? 1.0 : Math.max(0.1, audioSpeed);
|
||||
}
|
||||
|
||||
public void setAudioSpeed(Double audioSpeed) {
|
||||
this.audioSpeed = audioSpeed;
|
||||
}
|
||||
|
||||
public double getAudioPitch() {
|
||||
return audioPitch == null ? 1.0 : Math.max(0.5, audioPitch);
|
||||
}
|
||||
|
||||
public void setAudioPitch(Double audioPitch) {
|
||||
this.audioPitch = audioPitch;
|
||||
}
|
||||
|
||||
public double getAudioVolume() {
|
||||
return audioVolume == null ? 1.0 : Math.max(0.0, Math.min(1.0, audioVolume));
|
||||
}
|
||||
|
||||
public void setAudioVolume(Double audioVolume) {
|
||||
this.audioVolume = audioVolume;
|
||||
}
|
||||
|
||||
private static String normalize(String value) {
|
||||
return value == null ? null : value.toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,11 @@ public record AssetView(
|
||||
String mediaType,
|
||||
String originalMediaType,
|
||||
Integer zIndex,
|
||||
Boolean audioLoop,
|
||||
Integer audioDelayMillis,
|
||||
Double audioSpeed,
|
||||
Double audioPitch,
|
||||
Double audioVolume,
|
||||
boolean hidden,
|
||||
Instant createdAt
|
||||
) {
|
||||
@@ -36,6 +41,11 @@ public record AssetView(
|
||||
asset.getMediaType(),
|
||||
asset.getOriginalMediaType(),
|
||||
asset.getZIndex(),
|
||||
asset.isAudioLoop(),
|
||||
asset.getAudioDelayMillis(),
|
||||
asset.getAudioSpeed(),
|
||||
asset.getAudioPitch(),
|
||||
asset.getAudioVolume(),
|
||||
asset.isHidden(),
|
||||
asset.getCreatedAt()
|
||||
);
|
||||
|
||||
@@ -9,6 +9,11 @@ public class TransformRequest {
|
||||
private Double speed;
|
||||
private Boolean muted;
|
||||
private Integer zIndex;
|
||||
private Boolean audioLoop;
|
||||
private Integer audioDelayMillis;
|
||||
private Double audioSpeed;
|
||||
private Double audioPitch;
|
||||
private Double audioVolume;
|
||||
|
||||
public double getX() {
|
||||
return x;
|
||||
@@ -73,4 +78,44 @@ public class TransformRequest {
|
||||
public void setZIndex(Integer zIndex) {
|
||||
this.zIndex = zIndex;
|
||||
}
|
||||
|
||||
public Boolean getAudioLoop() {
|
||||
return audioLoop;
|
||||
}
|
||||
|
||||
public void setAudioLoop(Boolean audioLoop) {
|
||||
this.audioLoop = audioLoop;
|
||||
}
|
||||
|
||||
public Integer getAudioDelayMillis() {
|
||||
return audioDelayMillis;
|
||||
}
|
||||
|
||||
public void setAudioDelayMillis(Integer audioDelayMillis) {
|
||||
this.audioDelayMillis = audioDelayMillis;
|
||||
}
|
||||
|
||||
public Double getAudioSpeed() {
|
||||
return audioSpeed;
|
||||
}
|
||||
|
||||
public void setAudioSpeed(Double audioSpeed) {
|
||||
this.audioSpeed = audioSpeed;
|
||||
}
|
||||
|
||||
public Double getAudioPitch() {
|
||||
return audioPitch;
|
||||
}
|
||||
|
||||
public void setAudioPitch(Double audioPitch) {
|
||||
this.audioPitch = audioPitch;
|
||||
}
|
||||
|
||||
public Double getAudioVolume() {
|
||||
return audioVolume;
|
||||
}
|
||||
|
||||
public void setAudioVolume(Double audioVolume) {
|
||||
this.audioVolume = audioVolume;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,13 +125,18 @@ public class ChannelDirectoryService {
|
||||
.orElse("Asset " + System.currentTimeMillis());
|
||||
|
||||
String dataUrl = "data:" + optimized.mediaType() + ";base64," + Base64.getEncoder().encodeToString(optimized.bytes());
|
||||
double width = optimized.width() > 0 ? optimized.width() : 640;
|
||||
double height = optimized.height() > 0 ? optimized.height() : 360;
|
||||
double width = optimized.width() > 0 ? optimized.width() : (optimized.mediaType().startsWith("audio/") ? 400 : 640);
|
||||
double height = optimized.height() > 0 ? optimized.height() : (optimized.mediaType().startsWith("audio/") ? 80 : 360);
|
||||
Asset asset = new Asset(channel.getBroadcaster(), name, dataUrl, width, height);
|
||||
asset.setOriginalMediaType(mediaType);
|
||||
asset.setMediaType(optimized.mediaType());
|
||||
asset.setSpeed(1.0);
|
||||
asset.setMuted(optimized.mediaType().startsWith("video/"));
|
||||
asset.setAudioLoop(false);
|
||||
asset.setAudioDelayMillis(0);
|
||||
asset.setAudioSpeed(1.0);
|
||||
asset.setAudioPitch(1.0);
|
||||
asset.setAudioVolume(1.0);
|
||||
asset.setZIndex(nextZIndex(channel.getBroadcaster()));
|
||||
|
||||
assetRepository.save(asset);
|
||||
@@ -159,6 +164,22 @@ public class ChannelDirectoryService {
|
||||
if (request.getMuted() != null && asset.isVideo()) {
|
||||
asset.setMuted(request.getMuted());
|
||||
}
|
||||
if (request.getAudioLoop() != null) {
|
||||
asset.setAudioLoop(request.getAudioLoop());
|
||||
}
|
||||
if (request.getAudioDelayMillis() != null && request.getAudioDelayMillis() >= 0) {
|
||||
asset.setAudioDelayMillis(request.getAudioDelayMillis());
|
||||
}
|
||||
if (request.getAudioSpeed() != null && request.getAudioSpeed() >= 0) {
|
||||
asset.setAudioSpeed(request.getAudioSpeed());
|
||||
}
|
||||
if (request.getAudioPitch() != null && request.getAudioPitch() > 0) {
|
||||
asset.setAudioPitch(request.getAudioPitch());
|
||||
}
|
||||
if (request.getAudioVolume() != null && request.getAudioVolume() >= 0) {
|
||||
double clamped = Math.max(0.0, Math.min(1.0, request.getAudioVolume()));
|
||||
asset.setAudioVolume(clamped);
|
||||
}
|
||||
assetRepository.save(asset);
|
||||
AssetView view = AssetView.from(normalized, asset);
|
||||
messagingTemplate.convertAndSend(topicFor(broadcaster), AssetEvent.updated(broadcaster, view));
|
||||
@@ -289,6 +310,9 @@ public class ChannelDirectoryService {
|
||||
case "mp4" -> "video/mp4";
|
||||
case "webm" -> "video/webm";
|
||||
case "mov" -> "video/quicktime";
|
||||
case "mp3" -> "audio/mpeg";
|
||||
case "wav" -> "audio/wav";
|
||||
case "ogg" -> "audio/ogg";
|
||||
default -> "application/octet-stream";
|
||||
})
|
||||
.orElse("application/octet-stream");
|
||||
@@ -324,6 +348,10 @@ public class ChannelDirectoryService {
|
||||
return new OptimizedAsset(bytes, mediaType, dimensions.width(), dimensions.height());
|
||||
}
|
||||
|
||||
if (mediaType.startsWith("audio/")) {
|
||||
return new OptimizedAsset(bytes, mediaType, 0, 0);
|
||||
}
|
||||
|
||||
BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes));
|
||||
if (image != null) {
|
||||
return new OptimizedAsset(bytes, mediaType, image.getWidth(), image.getHeight());
|
||||
|
||||
Reference in New Issue
Block a user