mirror of
https://github.com/imgfloat/server.git
synced 2026-02-05 03:39:26 +00:00
Additional configuration from environment
This commit is contained in:
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2024 Imgfloat
|
Copyright (c) 2025 Andreas Krühlmann
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
12
Makefile
12
Makefile
@@ -6,11 +6,23 @@
|
|||||||
IMGFLOAT_DB_PATH ?= ./imgfloat.db
|
IMGFLOAT_DB_PATH ?= ./imgfloat.db
|
||||||
IMGFLOAT_ASSETS_PATH ?= ./assets
|
IMGFLOAT_ASSETS_PATH ?= ./assets
|
||||||
IMGFLOAT_PREVIEWS_PATH ?= ./previews
|
IMGFLOAT_PREVIEWS_PATH ?= ./previews
|
||||||
|
IMGFLOAT_MAX_SPEED ?= 4.0
|
||||||
|
IMGFLOAT_MIN_AUDIO_SPEED ?= 0.1
|
||||||
|
IMGFLOAT_MAX_AUDIO_SPEED ?= 4.0
|
||||||
|
IMGFLOAT_MIN_AUDIO_PITCH ?= 0.5
|
||||||
|
IMGFLOAT_MAX_AUDIO_PITCH ?= 2.0
|
||||||
|
IMGFLOAT_MAX_AUDIO_VOLUME ?= 2.0
|
||||||
SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE ?= 10MB
|
SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE ?= 10MB
|
||||||
SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE ?= 10MB
|
SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE ?= 10MB
|
||||||
RUNTIME_ENV = IMGFLOAT_ASSETS_PATH=$(IMGFLOAT_ASSETS_PATH) \
|
RUNTIME_ENV = IMGFLOAT_ASSETS_PATH=$(IMGFLOAT_ASSETS_PATH) \
|
||||||
IMGFLOAT_PREVIEWS_PATH=$(IMGFLOAT_PREVIEWS_PATH) \
|
IMGFLOAT_PREVIEWS_PATH=$(IMGFLOAT_PREVIEWS_PATH) \
|
||||||
IMGFLOAT_DB_PATH=$(IMGFLOAT_DB_PATH) \
|
IMGFLOAT_DB_PATH=$(IMGFLOAT_DB_PATH) \
|
||||||
|
IMGFLOAT_MAX_SPEED=$(IMGFLOAT_MAX_SPEED) \
|
||||||
|
IMGFLOAT_MIN_AUDIO_SPEED=$(IMGFLOAT_MIN_AUDIO_SPEED) \
|
||||||
|
IMGFLOAT_MAX_AUDIO_SPEED=$(IMGFLOAT_MAX_AUDIO_SPEED) \
|
||||||
|
IMGFLOAT_MIN_AUDIO_PITCH=$(IMGFLOAT_MIN_AUDIO_PITCH) \
|
||||||
|
IMGFLOAT_MAX_AUDIO_PITCH=$(IMGFLOAT_MAX_AUDIO_PITCH) \
|
||||||
|
IMGFLOAT_MAX_AUDIO_VOLUME=$(IMGFLOAT_MAX_AUDIO_VOLUME) \
|
||||||
SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE=$(SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE) \
|
SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE=$(SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE) \
|
||||||
SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE=$(SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE)
|
SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE=$(SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE)
|
||||||
WATCHDIR = ./src/main
|
WATCHDIR = ./src/main
|
||||||
|
|||||||
@@ -28,6 +28,18 @@ public class SystemEnvironmentValidator {
|
|||||||
private String previewsPath;
|
private String previewsPath;
|
||||||
@Value("${IMGFLOAT_DB_PATH}")
|
@Value("${IMGFLOAT_DB_PATH}")
|
||||||
private String dbPath;
|
private String dbPath;
|
||||||
|
@Value("${IMGFLOAT_MAX_SPEED}")
|
||||||
|
private double maxSpeed;
|
||||||
|
@Value("${IMGFLOAT_MIN_AUDIO_SPEED}")
|
||||||
|
private double minAudioSpeed;
|
||||||
|
@Value("${IMGFLOAT_MAX_AUDIO_SPEED}")
|
||||||
|
private double maxAudioSpeed;
|
||||||
|
@Value("${IMGFLOAT_MIN_AUDIO_PITCH}")
|
||||||
|
private double minAudioPitch;
|
||||||
|
@Value("${IMGFLOAT_MAX_AUDIO_PITCH}")
|
||||||
|
private double maxAudioPitch;
|
||||||
|
@Value("${IMGFLOAT_MAX_AUDIO_VOLUME}")
|
||||||
|
private double maxAudioVolume;
|
||||||
|
|
||||||
private long maxUploadBytes;
|
private long maxUploadBytes;
|
||||||
private long maxRequestBytes;
|
private long maxRequestBytes;
|
||||||
@@ -38,8 +50,14 @@ public class SystemEnvironmentValidator {
|
|||||||
|
|
||||||
maxUploadBytes = DataSize.parse(springMaxFileSize).toBytes();
|
maxUploadBytes = DataSize.parse(springMaxFileSize).toBytes();
|
||||||
maxRequestBytes = DataSize.parse(springMaxRequestSize).toBytes();
|
maxRequestBytes = DataSize.parse(springMaxRequestSize).toBytes();
|
||||||
checkLong(maxUploadBytes, "SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE", missing);
|
checkUnsignedNumeric(maxUploadBytes, "SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE", missing);
|
||||||
checkLong(maxRequestBytes, "SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE", missing);
|
checkUnsignedNumeric(maxRequestBytes, "SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE", missing);
|
||||||
|
checkUnsignedNumeric(maxSpeed, "IMGFLOAT_MAX_SPEED", missing);;
|
||||||
|
checkUnsignedNumeric(minAudioSpeed, "IMGFLOAT_MIN_AUDIO_SPEED", missing);;
|
||||||
|
checkUnsignedNumeric(maxAudioSpeed, "IMGFLOAT_MAX_AUDIO_SPEED", missing);;
|
||||||
|
checkUnsignedNumeric(minAudioPitch, "IMGFLOAT_MIN_AUDIO_PITCH", missing);;
|
||||||
|
checkUnsignedNumeric(maxAudioPitch, "IMGFLOAT_MAX_AUDIO_PITCH", missing);;
|
||||||
|
checkUnsignedNumeric(maxAudioVolume, "IMGFLOAT_MAX_AUDIO_VOLUME", missing);;
|
||||||
checkString(twitchClientId, "TWITCH_CLIENT_ID", missing);
|
checkString(twitchClientId, "TWITCH_CLIENT_ID", missing);
|
||||||
checkString(dbPath, "IMGFLOAT_DB_PATH", missing);
|
checkString(dbPath, "IMGFLOAT_DB_PATH", missing);
|
||||||
checkString(twitchClientSecret, "TWITCH_CLIENT_SECRET", missing);
|
checkString(twitchClientSecret, "TWITCH_CLIENT_SECRET", missing);
|
||||||
@@ -57,15 +75,18 @@ public class SystemEnvironmentValidator {
|
|||||||
log.info(" - TWITCH_CLIENT_ID: {}", redact(twitchClientId));
|
log.info(" - TWITCH_CLIENT_ID: {}", redact(twitchClientId));
|
||||||
log.info(" - TWITCH_CLIENT_SECRET: {}", redact(twitchClientSecret));
|
log.info(" - TWITCH_CLIENT_SECRET: {}", redact(twitchClientSecret));
|
||||||
log.info(" - SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE: {} ({} bytes)",
|
log.info(" - SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE: {} ({} bytes)",
|
||||||
springMaxFileSize,
|
springMaxFileSize, maxUploadBytes);
|
||||||
maxUploadBytes
|
|
||||||
);
|
|
||||||
log.info(" - SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE: {} ({} bytes)",
|
log.info(" - SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE: {} ({} bytes)",
|
||||||
springMaxRequestSize,
|
springMaxRequestSize, maxRequestBytes);
|
||||||
maxRequestBytes
|
|
||||||
);
|
|
||||||
log.info(" - IMGFLOAT_ASSETS_PATH: {}", assetsPath);
|
log.info(" - IMGFLOAT_ASSETS_PATH: {}", assetsPath);
|
||||||
log.info(" - IMGFLOAT_PREVIEWS_PATH: {}", previewsPath);
|
log.info(" - IMGFLOAT_PREVIEWS_PATH: {}", previewsPath);
|
||||||
|
log.info(" - IMGFLOAT_DB_PATH: {}", dbPath);
|
||||||
|
log.info(" - IMGFLOAT_MAX_SPEED: {}", maxSpeed);
|
||||||
|
log.info(" - IMGFLOAT_MIN_AUDIO_SPEED: {}", minAudioSpeed);
|
||||||
|
log.info(" - IMGFLOAT_MAX_AUDIO_SPEED: {}", maxAudioSpeed);
|
||||||
|
log.info(" - IMGFLOAT_MIN_AUDIO_PITCH: {}", minAudioPitch);
|
||||||
|
log.info(" - IMGFLOAT_MAX_AUDIO_PITCH: {}", maxAudioPitch);
|
||||||
|
log.info(" - IMGFLOAT_MAX_AUDIO_VOLUME: {}", maxAudioVolume);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkString(String value, String name, StringBuilder missing) {
|
private void checkString(String value, String name, StringBuilder missing) {
|
||||||
@@ -74,44 +95,15 @@ public class SystemEnvironmentValidator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkLong(Long value, String name, StringBuilder missing) {
|
private <T extends Number> void checkUnsignedNumeric(T value, String name, StringBuilder missing) {
|
||||||
if (value == null || value <= 0) {
|
if (value == null || value.doubleValue() <= 0) {
|
||||||
missing.append(" - ").append(name).append("\n");
|
missing.append(" - ").append(name).append('\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String formatBytes(long bytes) {
|
|
||||||
if (bytes < 1024) return bytes + " B";
|
|
||||||
|
|
||||||
double kb = bytes / 1024.0;
|
|
||||||
if (kb < 1024) return String.format("%.2f KB", kb);
|
|
||||||
|
|
||||||
double mb = kb / 1024.0;
|
|
||||||
if (mb < 1024) return String.format("%.2f MB", mb);
|
|
||||||
|
|
||||||
double gb = mb / 1024.0;
|
|
||||||
return String.format("%.2f GB", gb);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String redact(String value) {
|
private String redact(String value) {
|
||||||
if (!StringUtils.hasText(value)) return "(missing)";
|
if (!StringUtils.hasText(value)) return "(missing)";
|
||||||
if (value.length() <= 6) return "******";
|
if (value.length() <= 6) return "******";
|
||||||
return value.substring(0, 2) + "****" + value.substring(value.length() - 2);
|
return value.substring(0, 2) + "****" + value.substring(value.length() - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long parseSizeToBytes(String value) {
|
|
||||||
if (value == null) return -1;
|
|
||||||
|
|
||||||
String v = value.trim().toUpperCase(Locale.ROOT);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (v.endsWith("GB")) return Long.parseLong(v.replace("GB", "")) * 1024 * 1024 * 1024;
|
|
||||||
if (v.endsWith("MB")) return Long.parseLong(v.replace("MB", "")) * 1024 * 1024;
|
|
||||||
if (v.endsWith("KB")) return Long.parseLong(v.replace("KB", "")) * 1024;
|
|
||||||
if (v.endsWith("B")) return Long.parseLong(v.replace("B", ""));
|
|
||||||
return Long.parseLong(v);
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import dev.kruhlmann.imgfloat.service.VersionService;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
|
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
@@ -22,9 +23,31 @@ public class ViewController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private long uploadLimitBytes;
|
private long uploadLimitBytes;
|
||||||
|
|
||||||
public ViewController(ChannelDirectoryService channelDirectoryService, VersionService versionService) {
|
private double maxSpeed;
|
||||||
|
private double minAudioSpeed;
|
||||||
|
private double maxAudioSpeed;
|
||||||
|
private double minAudioPitch;
|
||||||
|
private double maxAudioPitch;
|
||||||
|
private double maxAudioVolume;
|
||||||
|
|
||||||
|
public ViewController(
|
||||||
|
ChannelDirectoryService channelDirectoryService,
|
||||||
|
VersionService versionService,
|
||||||
|
@Value("${IMGFLOAT_MAX_SPEED}") double maxSpeed,
|
||||||
|
@Value("${IMGFLOAT_MIN_AUDIO_SPEED}") double minAudioSpeed,
|
||||||
|
@Value("${IMGFLOAT_MAX_AUDIO_SPEED}") double maxAudioSpeed,
|
||||||
|
@Value("${IMGFLOAT_MIN_AUDIO_PITCH}") double minAudioPitch,
|
||||||
|
@Value("${IMGFLOAT_MAX_AUDIO_PITCH}") double maxAudioPitch,
|
||||||
|
@Value("${IMGFLOAT_MAX_AUDIO_VOLUME}") double maxAudioVolume
|
||||||
|
) {
|
||||||
this.channelDirectoryService = channelDirectoryService;
|
this.channelDirectoryService = channelDirectoryService;
|
||||||
this.versionService = versionService;
|
this.versionService = versionService;
|
||||||
|
this.maxSpeed = maxSpeed;
|
||||||
|
this.minAudioSpeed = minAudioSpeed;
|
||||||
|
this.maxAudioSpeed = maxAudioSpeed;
|
||||||
|
this.minAudioPitch = minAudioPitch;
|
||||||
|
this.maxAudioPitch = maxAudioPitch;
|
||||||
|
this.maxAudioVolume = maxAudioVolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
@org.springframework.web.bind.annotation.GetMapping("/")
|
@org.springframework.web.bind.annotation.GetMapping("/")
|
||||||
@@ -62,6 +85,13 @@ public class ViewController {
|
|||||||
model.addAttribute("username", login);
|
model.addAttribute("username", login);
|
||||||
model.addAttribute("uploadLimitBytes", uploadLimitBytes);
|
model.addAttribute("uploadLimitBytes", uploadLimitBytes);
|
||||||
|
|
||||||
|
model.addAttribute("maxSpeed", maxSpeed);
|
||||||
|
model.addAttribute("minAudioSpeed", minAudioSpeed);
|
||||||
|
model.addAttribute("maxAudioSpeed", maxAudioSpeed);
|
||||||
|
model.addAttribute("minAudioPitch", minAudioPitch);
|
||||||
|
model.addAttribute("maxAudioPitch", maxAudioPitch);
|
||||||
|
model.addAttribute("maxAudioVolume", maxAudioVolume);
|
||||||
|
|
||||||
return "admin";
|
return "admin";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,12 +35,6 @@ import static org.springframework.http.HttpStatus.PAYLOAD_TOO_LARGE;
|
|||||||
@Service
|
@Service
|
||||||
public class ChannelDirectoryService {
|
public class ChannelDirectoryService {
|
||||||
private static final Logger logger = LoggerFactory.getLogger(ChannelDirectoryService.class);
|
private static final Logger logger = LoggerFactory.getLogger(ChannelDirectoryService.class);
|
||||||
private static final double MAX_SPEED = 4.0;
|
|
||||||
private static final double MIN_AUDIO_SPEED = 0.1;
|
|
||||||
private static final double MAX_AUDIO_SPEED = 4.0;
|
|
||||||
private static final double MIN_AUDIO_PITCH = 0.5;
|
|
||||||
private static final double MAX_AUDIO_PITCH = 2.0;
|
|
||||||
private static final double MAX_AUDIO_VOLUME = 1.0;
|
|
||||||
private static final Pattern SAFE_FILENAME = Pattern.compile("[^a-zA-Z0-9._ -]");
|
private static final Pattern SAFE_FILENAME = Pattern.compile("[^a-zA-Z0-9._ -]");
|
||||||
|
|
||||||
private final ChannelRepository channelRepository;
|
private final ChannelRepository channelRepository;
|
||||||
@@ -53,13 +47,26 @@ public class ChannelDirectoryService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private long uploadLimitBytes;
|
private long uploadLimitBytes;
|
||||||
|
|
||||||
|
private double maxSpeed;
|
||||||
|
private double minAudioSpeed;
|
||||||
|
private double maxAudioSpeed;
|
||||||
|
private double minAudioPitch;
|
||||||
|
private double maxAudioPitch;
|
||||||
|
private double maxAudioVolume;
|
||||||
|
|
||||||
public ChannelDirectoryService(
|
public ChannelDirectoryService(
|
||||||
ChannelRepository channelRepository,
|
ChannelRepository channelRepository,
|
||||||
AssetRepository assetRepository,
|
AssetRepository assetRepository,
|
||||||
SimpMessagingTemplate messagingTemplate,
|
SimpMessagingTemplate messagingTemplate,
|
||||||
AssetStorageService assetStorageService,
|
AssetStorageService assetStorageService,
|
||||||
MediaDetectionService mediaDetectionService,
|
MediaDetectionService mediaDetectionService,
|
||||||
MediaOptimizationService mediaOptimizationService
|
MediaOptimizationService mediaOptimizationService,
|
||||||
|
@Value("${IMGFLOAT_MAX_SPEED}") double maxSpeed,
|
||||||
|
@Value("${IMGFLOAT_MIN_AUDIO_SPEED}") double minAudioSpeed,
|
||||||
|
@Value("${IMGFLOAT_MAX_AUDIO_SPEED}") double maxAudioSpeed,
|
||||||
|
@Value("${IMGFLOAT_MIN_AUDIO_PITCH}") double minAudioPitch,
|
||||||
|
@Value("${IMGFLOAT_MAX_AUDIO_PITCH}") double maxAudioPitch,
|
||||||
|
@Value("${IMGFLOAT_MAX_AUDIO_VOLUME}") double maxAudioVolume
|
||||||
) {
|
) {
|
||||||
this.channelRepository = channelRepository;
|
this.channelRepository = channelRepository;
|
||||||
this.assetRepository = assetRepository;
|
this.assetRepository = assetRepository;
|
||||||
@@ -67,6 +74,12 @@ public class ChannelDirectoryService {
|
|||||||
this.assetStorageService = assetStorageService;
|
this.assetStorageService = assetStorageService;
|
||||||
this.mediaDetectionService = mediaDetectionService;
|
this.mediaDetectionService = mediaDetectionService;
|
||||||
this.mediaOptimizationService = mediaOptimizationService;
|
this.mediaOptimizationService = mediaOptimizationService;
|
||||||
|
this.maxSpeed = maxSpeed;
|
||||||
|
this.minAudioSpeed = minAudioSpeed;
|
||||||
|
this.maxAudioSpeed = maxAudioSpeed;
|
||||||
|
this.minAudioPitch = minAudioPitch;
|
||||||
|
this.maxAudioPitch = maxAudioPitch;
|
||||||
|
this.maxAudioVolume = maxAudioVolume;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -244,17 +257,17 @@ public class ChannelDirectoryService {
|
|||||||
private void validateTransform(TransformRequest req) {
|
private void validateTransform(TransformRequest req) {
|
||||||
if (req.getWidth() <= 0) throw new ResponseStatusException(BAD_REQUEST, "Width must be > 0");
|
if (req.getWidth() <= 0) throw new ResponseStatusException(BAD_REQUEST, "Width must be > 0");
|
||||||
if (req.getHeight() <= 0) throw new ResponseStatusException(BAD_REQUEST, "Height must be > 0");
|
if (req.getHeight() <= 0) throw new ResponseStatusException(BAD_REQUEST, "Height must be > 0");
|
||||||
if (req.getSpeed() != null && (req.getSpeed() < 0 || req.getSpeed() > MAX_SPEED))
|
if (req.getSpeed() != null && (req.getSpeed() < 0 || req.getSpeed() > maxSpeed))
|
||||||
throw new ResponseStatusException(BAD_REQUEST, "Speed must be between 0 and " + MAX_SPEED);
|
throw new ResponseStatusException(BAD_REQUEST, "Speed must be between 0 and " + maxSpeed);
|
||||||
if (req.getZIndex() != null && req.getZIndex() < 1)
|
if (req.getZIndex() != null && req.getZIndex() < 1)
|
||||||
throw new ResponseStatusException(BAD_REQUEST, "zIndex must be >= 1");
|
throw new ResponseStatusException(BAD_REQUEST, "zIndex must be >= 1");
|
||||||
if (req.getAudioDelayMillis() != null && req.getAudioDelayMillis() < 0)
|
if (req.getAudioDelayMillis() != null && req.getAudioDelayMillis() < 0)
|
||||||
throw new ResponseStatusException(BAD_REQUEST, "Audio delay >= 0");
|
throw new ResponseStatusException(BAD_REQUEST, "Audio delay >= 0");
|
||||||
if (req.getAudioSpeed() != null && (req.getAudioSpeed() < MIN_AUDIO_SPEED || req.getAudioSpeed() > MAX_AUDIO_SPEED))
|
if (req.getAudioSpeed() != null && (req.getAudioSpeed() < minAudioSpeed || req.getAudioSpeed() > maxAudioSpeed))
|
||||||
throw new ResponseStatusException(BAD_REQUEST, "Audio speed out of range");
|
throw new ResponseStatusException(BAD_REQUEST, "Audio speed out of range");
|
||||||
if (req.getAudioPitch() != null && (req.getAudioPitch() < MIN_AUDIO_PITCH || req.getAudioPitch() > MAX_AUDIO_PITCH))
|
if (req.getAudioPitch() != null && (req.getAudioPitch() < minAudioPitch || req.getAudioPitch() > maxAudioPitch))
|
||||||
throw new ResponseStatusException(BAD_REQUEST, "Audio pitch out of range");
|
throw new ResponseStatusException(BAD_REQUEST, "Audio pitch out of range");
|
||||||
if (req.getAudioVolume() != null && (req.getAudioVolume() < 0 || req.getAudioVolume() > MAX_AUDIO_VOLUME))
|
if (req.getAudioVolume() != null && (req.getAudioVolume() < 0 || req.getAudioVolume() > maxAudioVolume))
|
||||||
throw new ResponseStatusException(BAD_REQUEST, "Audio volume out of range");
|
throw new ResponseStatusException(BAD_REQUEST, "Audio volume out of range");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ let interactionState = null;
|
|||||||
let lastSizeInputChanged = null;
|
let lastSizeInputChanged = null;
|
||||||
const HANDLE_SIZE = 10;
|
const HANDLE_SIZE = 10;
|
||||||
const ROTATE_HANDLE_OFFSET = 32;
|
const ROTATE_HANDLE_OFFSET = 32;
|
||||||
const MAX_VOLUME = 2;
|
const MAX_VOLUME = adminInputRestrictions.MAX_AUDIO_VOLUME;
|
||||||
const VOLUME_SLIDER_MAX = 200;
|
const VOLUME_SLIDER_MAX = adminInputRestrictions.MAX_AUDIO_VOLUME * 100;
|
||||||
const VOLUME_CURVE_STRENGTH = -0.6;
|
const VOLUME_CURVE_STRENGTH = -0.6;
|
||||||
const pendingTransformSaves = new Map();
|
const pendingTransformSaves = new Map();
|
||||||
const KEYBOARD_NUDGE_STEP = 5;
|
const KEYBOARD_NUDGE_STEP = 5;
|
||||||
@@ -2023,8 +2023,8 @@ function uploadAsset(file = null) {
|
|||||||
showToast('Choose an image, GIF, video, or audio file to upload.', 'info');
|
showToast('Choose an image, GIF, video, or audio file to upload.', 'info');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (selectedFile.size > upload_limit_bytes) {
|
if (selectedFile.size > adminInputRestrictions.UPLOAD_MAX_BYTES) {
|
||||||
showToast(`File is too large. Maximum upload size is ${upload_limit_bytes / 1024 / 1024} MB.`, 'error');
|
showToast(`File is too large. Maximum upload size is ${adminInputRestrictions.UPLOAD_MAX_BYTES / 1024 / 1024} MB.`, 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
<title>Imgfloat Admin</title>
|
<title>Imgfloat Admin</title>
|
||||||
<link rel="stylesheet" href="/css/styles.css" />
|
<link rel="stylesheet" href="/css/styles.css" />
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/stompjs@2.3.3/lib/stomp.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/stompjs@2.3.3/lib/stomp.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
@@ -14,7 +13,7 @@
|
|||||||
<header class="admin-topbar">
|
<header class="admin-topbar">
|
||||||
<div class="topbar-left">
|
<div class="topbar-left">
|
||||||
<div class="admin-identity">
|
<div class="admin-identity">
|
||||||
<p class="eyebrow subtle">Admin</p>
|
<p class="eyebrow subtle">CHANNEL ADMIN</p>
|
||||||
<h1 th:text="${broadcaster}"></h1>
|
<h1 th:text="${broadcaster}"></h1>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -208,7 +207,15 @@
|
|||||||
<script th:inline="javascript">
|
<script th:inline="javascript">
|
||||||
const broadcaster = /*[[${broadcaster}]]*/ '';
|
const broadcaster = /*[[${broadcaster}]]*/ '';
|
||||||
const username = /*[[${username}]]*/ '';
|
const username = /*[[${username}]]*/ '';
|
||||||
const upload_limit_bytes = /*[[${uploadLimitBytes}]]*/ + 0;
|
const adminInputRestrictions = {
|
||||||
|
UPLOAD_MAX_BYTES: /*[[${uploadLimitBytes}]]*/ + 0,
|
||||||
|
MAX_SPEED: /*[[${maxSpeed}]]*/ + 0.0,
|
||||||
|
MIN_AUDIO_SPEED: /*[[${minAudioSpeed}]]*/ + 0.0,
|
||||||
|
MAX_AUDIO_SPEED: /*[[${maxAudioSpeed}]]*/ + 0.0,
|
||||||
|
MIN_AUDIO_PITCH: /*[[${minAudioPitch}]]*/ + 0.0,
|
||||||
|
MAX_AUDIO_PITCH: /*[[${maxAudioPitch}]]*/ + 0.0,
|
||||||
|
MAX_AUDIO_VOLUME: /*[[${maxAudioVolume}]]*/ + 0.0,
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/toast.js"></script>
|
<script src="/js/toast.js"></script>
|
||||||
<script src="/js/admin.js"></script>
|
<script src="/js/admin.js"></script>
|
||||||
|
|||||||
@@ -69,7 +69,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-section">
|
<div class="card-section">
|
||||||
<div class="section-header">
|
<div class="section-header">
|
||||||
<h4 class="list-title">Admins</h4>
|
<h4 class="list-title">Channel Admins</h4>
|
||||||
<p class="muted">Users who can currently modify your overlay.</p>
|
<p class="muted">Users who can currently modify your overlay.</p>
|
||||||
</div>
|
</div>
|
||||||
<ul id="admin-list" class="stacked-list"></ul>
|
<ul id="admin-list" class="stacked-list"></ul>
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
<li th:each="channelName : ${adminChannels}" class="stacked-list-item">
|
<li th:each="channelName : ${adminChannels}" class="stacked-list-item">
|
||||||
<div>
|
<div>
|
||||||
<p class="list-title" th:text="${channelName}">channel</p>
|
<p class="list-title" th:text="${channelName}">channel</p>
|
||||||
<p class="muted">Admin access</p>
|
<p class="muted">Channel admin access</p>
|
||||||
</div>
|
</div>
|
||||||
<a class="button ghost" th:href="@{'/view/' + ${channelName} + '/admin'}">Open</a>
|
<a class="button ghost" th:href="@{'/view/' + ${channelName} + '/admin'}">Open</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
Reference in New Issue
Block a user