mirror of
https://github.com/imgfloat/server.git
synced 2026-02-05 03:39:26 +00:00
Add default custom asset
This commit is contained in:
@@ -41,9 +41,11 @@ import java.util.regex.Pattern;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.springframework.web.server.ResponseStatusException;
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
@@ -424,7 +426,20 @@ public class ChannelDirectoryService {
|
|||||||
public List<ScriptMarketplaceEntry> listMarketplaceScripts(String query) {
|
public List<ScriptMarketplaceEntry> listMarketplaceScripts(String query) {
|
||||||
String q = normalizeDescription(query);
|
String q = normalizeDescription(query);
|
||||||
String normalizedQuery = q == null ? null : q.toLowerCase(Locale.ROOT);
|
String normalizedQuery = q == null ? null : q.toLowerCase(Locale.ROOT);
|
||||||
List<ScriptAsset> scripts = scriptAssetRepository.findByIsPublicTrue();
|
List<ScriptMarketplaceEntry> entries = new ArrayList<>();
|
||||||
|
DefaultMarketplaceScript.entryForQuery(normalizedQuery).ifPresent(entries::add);
|
||||||
|
List<ScriptAsset> scripts;
|
||||||
|
try {
|
||||||
|
scripts = scriptAssetRepository.findByIsPublicTrue();
|
||||||
|
} catch (DataAccessException ex) {
|
||||||
|
logger.warn("Unable to load marketplace scripts", ex);
|
||||||
|
return entries
|
||||||
|
.stream()
|
||||||
|
.sorted(
|
||||||
|
Comparator.comparing(ScriptMarketplaceEntry::name, Comparator.nullsLast(String::compareToIgnoreCase))
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
if (normalizedQuery != null && !normalizedQuery.isBlank()) {
|
if (normalizedQuery != null && !normalizedQuery.isBlank()) {
|
||||||
scripts =
|
scripts =
|
||||||
scripts
|
scripts
|
||||||
@@ -442,7 +457,8 @@ public class ChannelDirectoryService {
|
|||||||
.stream()
|
.stream()
|
||||||
.collect(Collectors.toMap(Asset::getId, (asset) -> asset));
|
.collect(Collectors.toMap(Asset::getId, (asset) -> asset));
|
||||||
|
|
||||||
return scripts
|
entries.addAll(
|
||||||
|
scripts
|
||||||
.stream()
|
.stream()
|
||||||
.map((script) -> {
|
.map((script) -> {
|
||||||
Asset asset = assets.get(script.getId());
|
Asset asset = assets.get(script.getId());
|
||||||
@@ -458,11 +474,20 @@ public class ChannelDirectoryService {
|
|||||||
broadcaster
|
broadcaster
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
.toList()
|
||||||
|
);
|
||||||
|
|
||||||
|
return entries
|
||||||
|
.stream()
|
||||||
.sorted(Comparator.comparing(ScriptMarketplaceEntry::name, Comparator.nullsLast(String::compareToIgnoreCase)))
|
.sorted(Comparator.comparing(ScriptMarketplaceEntry::name, Comparator.nullsLast(String::compareToIgnoreCase)))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<AssetContent> getMarketplaceLogo(String scriptId) {
|
public Optional<AssetContent> getMarketplaceLogo(String scriptId) {
|
||||||
|
if (DefaultMarketplaceScript.matches(scriptId)) {
|
||||||
|
return DefaultMarketplaceScript.logoContent();
|
||||||
|
}
|
||||||
|
try {
|
||||||
return scriptAssetRepository
|
return scriptAssetRepository
|
||||||
.findById(scriptId)
|
.findById(scriptId)
|
||||||
.filter(ScriptAsset::isPublic)
|
.filter(ScriptAsset::isPublic)
|
||||||
@@ -471,13 +496,23 @@ public class ChannelDirectoryService {
|
|||||||
.flatMap((file) ->
|
.flatMap((file) ->
|
||||||
assetStorageService.loadAssetFileSafely(file.getBroadcaster(), file.getId(), file.getMediaType())
|
assetStorageService.loadAssetFileSafely(file.getBroadcaster(), file.getId(), file.getMediaType())
|
||||||
);
|
);
|
||||||
|
} catch (DataAccessException ex) {
|
||||||
|
logger.warn("Unable to load marketplace logo", ex);
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<AssetView> importMarketplaceScript(String targetBroadcaster, String scriptId) {
|
public Optional<AssetView> importMarketplaceScript(String targetBroadcaster, String scriptId) {
|
||||||
ScriptAsset sourceScript = scriptAssetRepository
|
if (DefaultMarketplaceScript.matches(scriptId)) {
|
||||||
.findById(scriptId)
|
return importDefaultMarketplaceScript(targetBroadcaster);
|
||||||
.filter(ScriptAsset::isPublic)
|
}
|
||||||
.orElse(null);
|
ScriptAsset sourceScript;
|
||||||
|
try {
|
||||||
|
sourceScript = scriptAssetRepository.findById(scriptId).filter(ScriptAsset::isPublic).orElse(null);
|
||||||
|
} catch (DataAccessException ex) {
|
||||||
|
logger.warn("Unable to import marketplace script {}", scriptId, ex);
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
Asset sourceAsset = sourceScript == null ? null : assetRepository.findById(scriptId).orElse(null);
|
Asset sourceAsset = sourceScript == null ? null : assetRepository.findById(scriptId).orElse(null);
|
||||||
if (sourceScript == null || sourceAsset == null) {
|
if (sourceScript == null || sourceAsset == null) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
@@ -538,6 +573,69 @@ public class ChannelDirectoryService {
|
|||||||
return Optional.of(view);
|
return Optional.of(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Optional<AssetView> importDefaultMarketplaceScript(String targetBroadcaster) {
|
||||||
|
AssetContent sourceContent = DefaultMarketplaceScript.sourceContent().orElse(null);
|
||||||
|
AssetContent attachmentContent = DefaultMarketplaceScript.attachmentContent().orElse(null);
|
||||||
|
if (sourceContent == null || attachmentContent == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
Asset asset = new Asset(targetBroadcaster, AssetType.SCRIPT);
|
||||||
|
ScriptAssetFile sourceFile = new ScriptAssetFile(asset.getBroadcaster(), AssetType.SCRIPT);
|
||||||
|
sourceFile.setId(asset.getId());
|
||||||
|
sourceFile.setMediaType(sourceContent.mediaType());
|
||||||
|
sourceFile.setOriginalMediaType(sourceContent.mediaType());
|
||||||
|
try {
|
||||||
|
assetStorageService.storeAsset(
|
||||||
|
sourceFile.getBroadcaster(),
|
||||||
|
sourceFile.getId(),
|
||||||
|
sourceContent.bytes(),
|
||||||
|
sourceContent.mediaType()
|
||||||
|
);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ResponseStatusException(BAD_REQUEST, "Unable to store custom script", e);
|
||||||
|
}
|
||||||
|
assetRepository.save(asset);
|
||||||
|
scriptAssetFileRepository.save(sourceFile);
|
||||||
|
|
||||||
|
ScriptAssetFile attachmentFile = new ScriptAssetFile(asset.getBroadcaster(), AssetType.IMAGE);
|
||||||
|
attachmentFile.setMediaType(attachmentContent.mediaType());
|
||||||
|
attachmentFile.setOriginalMediaType(attachmentContent.mediaType());
|
||||||
|
try {
|
||||||
|
assetStorageService.storeAsset(
|
||||||
|
attachmentFile.getBroadcaster(),
|
||||||
|
attachmentFile.getId(),
|
||||||
|
attachmentContent.bytes(),
|
||||||
|
attachmentContent.mediaType()
|
||||||
|
);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ResponseStatusException(BAD_REQUEST, "Unable to store script attachment", e);
|
||||||
|
}
|
||||||
|
scriptAssetFileRepository.save(attachmentFile);
|
||||||
|
|
||||||
|
ScriptAsset script = new ScriptAsset(asset.getId(), DefaultMarketplaceScript.SCRIPT_NAME);
|
||||||
|
script.setDescription(DefaultMarketplaceScript.SCRIPT_DESCRIPTION);
|
||||||
|
script.setPublic(false);
|
||||||
|
script.setMediaType(sourceContent.mediaType());
|
||||||
|
script.setOriginalMediaType(sourceContent.mediaType());
|
||||||
|
script.setSourceFileId(sourceFile.getId());
|
||||||
|
script.setLogoFileId(attachmentFile.getId());
|
||||||
|
script.setAttachments(List.of());
|
||||||
|
scriptAssetRepository.save(script);
|
||||||
|
|
||||||
|
ScriptAssetAttachment attachment = new ScriptAssetAttachment(asset.getId(), DefaultMarketplaceScript.ATTACHMENT_NAME);
|
||||||
|
attachment.setFileId(attachmentFile.getId());
|
||||||
|
attachment.setMediaType(attachmentContent.mediaType());
|
||||||
|
attachment.setOriginalMediaType(attachmentContent.mediaType());
|
||||||
|
attachment.setAssetType(AssetType.IMAGE);
|
||||||
|
scriptAssetAttachmentRepository.save(attachment);
|
||||||
|
|
||||||
|
script.setAttachments(loadScriptAttachments(asset.getBroadcaster(), asset.getId(), null));
|
||||||
|
AssetView view = AssetView.fromScript(asset.getBroadcaster(), asset, script);
|
||||||
|
messagingTemplate.convertAndSend(topicFor(targetBroadcaster), AssetEvent.created(targetBroadcaster, view));
|
||||||
|
return Optional.of(view);
|
||||||
|
}
|
||||||
|
|
||||||
private String sanitizeFilename(String original) {
|
private String sanitizeFilename(String original) {
|
||||||
String stripped = original.replaceAll("^.*[/\\\\]", "");
|
String stripped = original.replaceAll("^.*[/\\\\]", "");
|
||||||
return SAFE_FILENAME.matcher(stripped).replaceAll("_");
|
return SAFE_FILENAME.matcher(stripped).replaceAll("_");
|
||||||
@@ -750,6 +848,7 @@ public class ChannelDirectoryService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
public boolean deleteAsset(String assetId) {
|
public boolean deleteAsset(String assetId) {
|
||||||
return assetRepository
|
return assetRepository
|
||||||
.findById(assetId)
|
.findById(assetId)
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package dev.kruhlmann.imgfloat.service;
|
||||||
|
|
||||||
|
import dev.kruhlmann.imgfloat.model.ScriptMarketplaceEntry;
|
||||||
|
import dev.kruhlmann.imgfloat.service.media.AssetContent;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
|
||||||
|
public final class DefaultMarketplaceScript {
|
||||||
|
|
||||||
|
public static final String SCRIPT_ID = "imgfloat-default-rotating-logo";
|
||||||
|
public static final String SCRIPT_NAME = "Rotating Imgfloat logo";
|
||||||
|
public static final String SCRIPT_DESCRIPTION =
|
||||||
|
"Renders the Imgfloat logo and rotates it every tick.";
|
||||||
|
public static final String SCRIPT_BROADCASTER = "Imgfloat";
|
||||||
|
public static final String ATTACHMENT_NAME = "Imgfloat logo";
|
||||||
|
public static final String LOGO_URL = "/api/marketplace/scripts/" + SCRIPT_ID + "/logo";
|
||||||
|
public static final String SOURCE_MEDIA_TYPE = "application/javascript";
|
||||||
|
public static final String LOGO_MEDIA_TYPE = "image/png";
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(DefaultMarketplaceScript.class);
|
||||||
|
private static final String LOGO_RESOURCE = "static/img/brand.png";
|
||||||
|
private static final String SOURCE_RESOURCE = "assets/default-marketplace-script.js";
|
||||||
|
private static final AtomicReference<byte[]> LOGO_BYTES = new AtomicReference<>();
|
||||||
|
private static final AtomicReference<byte[]> SOURCE_BYTES = new AtomicReference<>();
|
||||||
|
|
||||||
|
private DefaultMarketplaceScript() {}
|
||||||
|
|
||||||
|
public static boolean matches(String scriptId) {
|
||||||
|
return SCRIPT_ID.equals(scriptId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<ScriptMarketplaceEntry> entryForQuery(String query) {
|
||||||
|
if (query == null || query.isBlank()) {
|
||||||
|
return Optional.of(entry());
|
||||||
|
}
|
||||||
|
String normalized = query.toLowerCase(Locale.ROOT);
|
||||||
|
if (
|
||||||
|
SCRIPT_NAME.toLowerCase(Locale.ROOT).contains(normalized) ||
|
||||||
|
SCRIPT_DESCRIPTION.toLowerCase(Locale.ROOT).contains(normalized)
|
||||||
|
) {
|
||||||
|
return Optional.of(entry());
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ScriptMarketplaceEntry entry() {
|
||||||
|
return new ScriptMarketplaceEntry(
|
||||||
|
SCRIPT_ID,
|
||||||
|
SCRIPT_NAME,
|
||||||
|
SCRIPT_DESCRIPTION,
|
||||||
|
LOGO_URL,
|
||||||
|
SCRIPT_BROADCASTER
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<AssetContent> logoContent() {
|
||||||
|
return loadContent(LOGO_BYTES, LOGO_RESOURCE, LOGO_MEDIA_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<AssetContent> sourceContent() {
|
||||||
|
return loadContent(SOURCE_BYTES, SOURCE_RESOURCE, SOURCE_MEDIA_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<AssetContent> attachmentContent() {
|
||||||
|
return logoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Optional<AssetContent> loadContent(
|
||||||
|
AtomicReference<byte[]> cache,
|
||||||
|
String resourcePath,
|
||||||
|
String mediaType
|
||||||
|
) {
|
||||||
|
byte[] bytes = cache.get();
|
||||||
|
if (bytes == null) {
|
||||||
|
bytes = readBytes(resourcePath).orElse(null);
|
||||||
|
if (bytes != null) {
|
||||||
|
cache.set(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bytes == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
return Optional.of(new AssetContent(bytes, mediaType));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Optional<byte[]> readBytes(String resourcePath) {
|
||||||
|
ClassPathResource resource = new ClassPathResource(resourcePath);
|
||||||
|
if (!resource.exists()) {
|
||||||
|
logger.warn("Default marketplace resource {} is missing", resourcePath);
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
try (InputStream input = resource.getInputStream()) {
|
||||||
|
return Optional.of(input.readAllBytes());
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.warn("Failed to read default marketplace resource {}", resourcePath, ex);
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/main/resources/assets/default-marketplace-script.js
Normal file
33
src/main/resources/assets/default-marketplace-script.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
async function init(context, state) {
|
||||||
|
const asset = Array.isArray(context.assets) ? context.assets[0] : null;
|
||||||
|
if (!asset?.blob) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.rotation = 0;
|
||||||
|
state.imageReady = false;
|
||||||
|
try {
|
||||||
|
state.image = await createImageBitmap(asset.blob);
|
||||||
|
state.imageReady = true;
|
||||||
|
} catch (error) {
|
||||||
|
state.imageError = error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function tick(context, state) {
|
||||||
|
const { ctx, width, height, deltaMs } = context;
|
||||||
|
if (!ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx.clearRect(0, 0, width, height);
|
||||||
|
const image = state?.image;
|
||||||
|
if (!image || !state.imageReady) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const size = Math.min(width, height) * 0.35;
|
||||||
|
state.rotation = (state.rotation + (deltaMs || 0) * 0.002) % (Math.PI * 2);
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(width / 2, height / 2);
|
||||||
|
ctx.rotate(state.rotation);
|
||||||
|
ctx.drawImage(image, -size / 2, -size / 2, size, size);
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ export class BroadcastRenderer {
|
|||||||
this.scriptWorker = null;
|
this.scriptWorker = null;
|
||||||
this.scriptWorkerReady = false;
|
this.scriptWorkerReady = false;
|
||||||
this.scriptErrorKeys = new Set();
|
this.scriptErrorKeys = new Set();
|
||||||
|
this.scriptAttachmentCache = new Map();
|
||||||
|
|
||||||
this.obsBrowser = !!globalThis.obsstudio;
|
this.obsBrowser = !!globalThis.obsstudio;
|
||||||
this.supportsAnimatedDecode =
|
this.supportsAnimatedDecode =
|
||||||
@@ -487,12 +488,12 @@ export class BroadcastRenderer {
|
|||||||
payload: {
|
payload: {
|
||||||
id: asset.id,
|
id: asset.id,
|
||||||
source: assetSource,
|
source: assetSource,
|
||||||
attachments: asset.scriptAttachments || [],
|
attachments: await this.resolveScriptAttachments(asset.scriptAttachments),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateScriptWorkerAttachments(asset) {
|
async updateScriptWorkerAttachments(asset) {
|
||||||
if (!this.scriptWorker || !this.scriptWorkerReady || !asset?.id) {
|
if (!this.scriptWorker || !this.scriptWorkerReady || !asset?.id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -500,7 +501,7 @@ export class BroadcastRenderer {
|
|||||||
type: "updateAttachments",
|
type: "updateAttachments",
|
||||||
payload: {
|
payload: {
|
||||||
id: asset.id,
|
id: asset.id,
|
||||||
attachments: asset.scriptAttachments || [],
|
attachments: await this.resolveScriptAttachments(asset.scriptAttachments),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -514,4 +515,35 @@ export class BroadcastRenderer {
|
|||||||
payload: { id: assetId },
|
payload: { id: assetId },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async resolveScriptAttachments(attachments) {
|
||||||
|
if (!Array.isArray(attachments) || attachments.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const resolved = await Promise.all(
|
||||||
|
attachments.map(async (attachment) => {
|
||||||
|
if (!attachment?.url || !attachment.mediaType?.startsWith("image/")) {
|
||||||
|
return attachment;
|
||||||
|
}
|
||||||
|
const cacheKey = attachment.id || attachment.url;
|
||||||
|
const cached = this.scriptAttachmentCache.get(cacheKey);
|
||||||
|
if (cached?.blob) {
|
||||||
|
return { ...attachment, blob: cached.blob };
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const response = await fetch(attachment.url);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Failed to fetch script attachment");
|
||||||
|
}
|
||||||
|
const blob = await response.blob();
|
||||||
|
this.scriptAttachmentCache.set(cacheKey, { blob });
|
||||||
|
return { ...attachment, blob };
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Unable to load script attachment", error);
|
||||||
|
return attachment;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,9 +22,11 @@ import dev.kruhlmann.imgfloat.repository.AudioAssetRepository;
|
|||||||
import dev.kruhlmann.imgfloat.repository.ChannelRepository;
|
import dev.kruhlmann.imgfloat.repository.ChannelRepository;
|
||||||
import dev.kruhlmann.imgfloat.repository.ScriptAssetRepository;
|
import dev.kruhlmann.imgfloat.repository.ScriptAssetRepository;
|
||||||
import dev.kruhlmann.imgfloat.repository.ScriptAssetAttachmentRepository;
|
import dev.kruhlmann.imgfloat.repository.ScriptAssetAttachmentRepository;
|
||||||
|
import dev.kruhlmann.imgfloat.repository.ScriptAssetFileRepository;
|
||||||
import dev.kruhlmann.imgfloat.repository.VisualAssetRepository;
|
import dev.kruhlmann.imgfloat.repository.VisualAssetRepository;
|
||||||
import dev.kruhlmann.imgfloat.service.AssetStorageService;
|
import dev.kruhlmann.imgfloat.service.AssetStorageService;
|
||||||
import dev.kruhlmann.imgfloat.service.ChannelDirectoryService;
|
import dev.kruhlmann.imgfloat.service.ChannelDirectoryService;
|
||||||
|
import dev.kruhlmann.imgfloat.service.DefaultMarketplaceScript;
|
||||||
import dev.kruhlmann.imgfloat.service.SettingsService;
|
import dev.kruhlmann.imgfloat.service.SettingsService;
|
||||||
import dev.kruhlmann.imgfloat.service.media.MediaDetectionService;
|
import dev.kruhlmann.imgfloat.service.media.MediaDetectionService;
|
||||||
import dev.kruhlmann.imgfloat.service.media.MediaOptimizationService;
|
import dev.kruhlmann.imgfloat.service.media.MediaOptimizationService;
|
||||||
@@ -58,6 +60,7 @@ class ChannelDirectoryServiceTest {
|
|||||||
private AudioAssetRepository audioAssetRepository;
|
private AudioAssetRepository audioAssetRepository;
|
||||||
private ScriptAssetRepository scriptAssetRepository;
|
private ScriptAssetRepository scriptAssetRepository;
|
||||||
private ScriptAssetAttachmentRepository scriptAssetAttachmentRepository;
|
private ScriptAssetAttachmentRepository scriptAssetAttachmentRepository;
|
||||||
|
private ScriptAssetFileRepository scriptAssetFileRepository;
|
||||||
private SettingsService settingsService;
|
private SettingsService settingsService;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
@@ -69,6 +72,7 @@ class ChannelDirectoryServiceTest {
|
|||||||
audioAssetRepository = mock(AudioAssetRepository.class);
|
audioAssetRepository = mock(AudioAssetRepository.class);
|
||||||
scriptAssetRepository = mock(ScriptAssetRepository.class);
|
scriptAssetRepository = mock(ScriptAssetRepository.class);
|
||||||
scriptAssetAttachmentRepository = mock(ScriptAssetAttachmentRepository.class);
|
scriptAssetAttachmentRepository = mock(ScriptAssetAttachmentRepository.class);
|
||||||
|
scriptAssetFileRepository = mock(ScriptAssetFileRepository.class);
|
||||||
settingsService = mock(SettingsService.class);
|
settingsService = mock(SettingsService.class);
|
||||||
when(settingsService.get()).thenReturn(Settings.defaults());
|
when(settingsService.get()).thenReturn(Settings.defaults());
|
||||||
setupInMemoryPersistence();
|
setupInMemoryPersistence();
|
||||||
@@ -86,6 +90,7 @@ class ChannelDirectoryServiceTest {
|
|||||||
audioAssetRepository,
|
audioAssetRepository,
|
||||||
scriptAssetRepository,
|
scriptAssetRepository,
|
||||||
scriptAssetAttachmentRepository,
|
scriptAssetAttachmentRepository,
|
||||||
|
scriptAssetFileRepository,
|
||||||
messagingTemplate,
|
messagingTemplate,
|
||||||
assetStorageService,
|
assetStorageService,
|
||||||
mediaDetectionService,
|
mediaDetectionService,
|
||||||
@@ -173,6 +178,16 @@ class ChannelDirectoryServiceTest {
|
|||||||
assertThat(view.zIndex()).isEqualTo(1);
|
assertThat(view.zIndex()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void includesDefaultMarketplaceScript() {
|
||||||
|
when(scriptAssetRepository.findByIsPublicTrue()).thenReturn(List.of());
|
||||||
|
|
||||||
|
List<dev.kruhlmann.imgfloat.model.ScriptMarketplaceEntry> entries = service.listMarketplaceScripts(null);
|
||||||
|
|
||||||
|
assertThat(entries)
|
||||||
|
.anyMatch((entry) -> DefaultMarketplaceScript.SCRIPT_ID.equals(entry.id()));
|
||||||
|
}
|
||||||
|
|
||||||
private byte[] samplePng() throws IOException {
|
private byte[] samplePng() throws IOException {
|
||||||
BufferedImage image = new BufferedImage(2, 2, BufferedImage.TYPE_INT_ARGB);
|
BufferedImage image = new BufferedImage(2, 2, BufferedImage.TYPE_INT_ARGB);
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
|||||||
Reference in New Issue
Block a user