From f9613c7c2f30012a17c63abfdcbf7e0c9defcf85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Kr=C3=BChlmann?= Date: Thu, 29 Jan 2026 16:56:20 +0100 Subject: [PATCH] Add emote sync --- .../imgfloat/model/db/imgfloat/Settings.java | 12 ++++++ .../imgfloat/service/EmoteSyncScheduler.java | 41 ++++++++++++------- .../imgfloat/service/SettingsService.java | 7 ++++ .../V10__settings_emote_sync_last_run.sql | 1 + 4 files changed, 47 insertions(+), 14 deletions(-) create mode 100644 src/main/resources/db/migration/V10__settings_emote_sync_last_run.sql diff --git a/src/main/java/dev/kruhlmann/imgfloat/model/db/imgfloat/Settings.java b/src/main/java/dev/kruhlmann/imgfloat/model/db/imgfloat/Settings.java index ef772a1..55ed1a0 100644 --- a/src/main/java/dev/kruhlmann/imgfloat/model/db/imgfloat/Settings.java +++ b/src/main/java/dev/kruhlmann/imgfloat/model/db/imgfloat/Settings.java @@ -43,6 +43,9 @@ public class Settings { @Column(nullable = false) private int emoteSyncIntervalMinutes; + @Column(name = "last_emote_sync_at") + private Instant lastEmoteSyncAt; + @Column(name = "created_at", nullable = false, updatable = false) private Instant createdAt; @@ -62,6 +65,7 @@ public class Settings { s.setMaxCanvasSideLengthPixels(7680); s.setCanvasFramesPerSecond(60); s.setEmoteSyncIntervalMinutes(60); + s.setLastEmoteSyncAt(null); return s; } @@ -145,6 +149,14 @@ public class Settings { this.emoteSyncIntervalMinutes = emoteSyncIntervalMinutes; } + public Instant getLastEmoteSyncAt() { + return lastEmoteSyncAt; + } + + public void setLastEmoteSyncAt(Instant lastEmoteSyncAt) { + this.lastEmoteSyncAt = lastEmoteSyncAt; + } + @PrePersist public void initializeTimestamps() { Instant now = Instant.now(); diff --git a/src/main/java/dev/kruhlmann/imgfloat/service/EmoteSyncScheduler.java b/src/main/java/dev/kruhlmann/imgfloat/service/EmoteSyncScheduler.java index 1287ada..b143975 100644 --- a/src/main/java/dev/kruhlmann/imgfloat/service/EmoteSyncScheduler.java +++ b/src/main/java/dev/kruhlmann/imgfloat/service/EmoteSyncScheduler.java @@ -50,14 +50,22 @@ public class EmoteSyncScheduler implements SchedulingConfigurer { private Trigger buildTrigger() { return (TriggerContext triggerContext) -> { - Instant lastCompletion = triggerContext.lastCompletion() == null - ? Instant.now() - : triggerContext.lastCompletion(); - assert lastCompletion != null; - return lastCompletion.plus(Duration.ofMinutes(resolveIntervalMinutes())); + int interval = resolveIntervalMinutes(); + Instant lastCompletion = resolveLastCompletion(triggerContext, interval); + return lastCompletion.plus(Duration.ofMinutes(interval)); }; } + private Instant resolveLastCompletion(TriggerContext triggerContext, int intervalMinutes) { + Instant lastCompletion = triggerContext.lastCompletion(); + if (lastCompletion != null) { + return lastCompletion; + } + Settings settings = settingsService.get(); + Instant persisted = settings.getLastEmoteSyncAt(); + return persisted != null ? persisted : Instant.now().minus(Duration.ofMinutes(intervalMinutes)); + } + private int resolveIntervalMinutes() { Settings settings = settingsService.get(); int interval = settings.getEmoteSyncIntervalMinutes(); @@ -67,15 +75,20 @@ public class EmoteSyncScheduler implements SchedulingConfigurer { private void syncEmotes() { int interval = resolveIntervalMinutes(); LOG.info("Synchronizing emotes (interval {} minutes)", interval); - - twitchEmoteService.refreshGlobalEmotes(); - List channels = channelRepository.findAll(); - for (Channel channel : channels) { - String broadcaster = channel.getBroadcaster(); - twitchEmoteService.refreshChannelEmotes(broadcaster); - sevenTvEmoteService.refreshChannelEmotes(broadcaster); + List channels = List.of(); + try { + channels = channelRepository.findAll(); + twitchEmoteService.refreshGlobalEmotes(); + for (Channel channel : channels) { + String broadcaster = channel.getBroadcaster(); + twitchEmoteService.refreshChannelEmotes(broadcaster); + sevenTvEmoteService.refreshChannelEmotes(broadcaster); + } + LOG.info("Completed emote sync for {} channels", channels.size()); + } catch (Exception ex) { + LOG.error("Emote sync failed", ex); + } finally { + settingsService.updateLastEmoteSyncAt(Instant.now()); } - - LOG.info("Completed emote sync for {} channels", channels.size()); } } diff --git a/src/main/java/dev/kruhlmann/imgfloat/service/SettingsService.java b/src/main/java/dev/kruhlmann/imgfloat/service/SettingsService.java index b0cb96b..eb8da4e 100644 --- a/src/main/java/dev/kruhlmann/imgfloat/service/SettingsService.java +++ b/src/main/java/dev/kruhlmann/imgfloat/service/SettingsService.java @@ -9,6 +9,7 @@ import dev.kruhlmann.imgfloat.repository.AudioAssetRepository; import dev.kruhlmann.imgfloat.repository.SettingsRepository; import dev.kruhlmann.imgfloat.repository.VisualAssetRepository; import jakarta.annotation.PostConstruct; +import java.time.Instant; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; @@ -59,6 +60,12 @@ public class SettingsService { return savedSettings; } + public void updateLastEmoteSyncAt(Instant timestamp) { + Settings settings = get(); + settings.setLastEmoteSyncAt(timestamp); + repo.save(settings); + } + public void logSettings(String msg, Settings settings) { try { logger.info("{}:\n{}", msg, objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(settings)); diff --git a/src/main/resources/db/migration/V10__settings_emote_sync_last_run.sql b/src/main/resources/db/migration/V10__settings_emote_sync_last_run.sql new file mode 100644 index 0000000..e794950 --- /dev/null +++ b/src/main/resources/db/migration/V10__settings_emote_sync_last_run.sql @@ -0,0 +1 @@ +ALTER TABLE settings ADD COLUMN last_emote_sync_at TIMESTAMP;