diff --git a/src/main/java/dev/kruhlmann/imgfloat/ImgfloatApplication.java b/src/main/java/dev/kruhlmann/imgfloat/ImgfloatApplication.java
index 97b9fd2..a5dae60 100644
--- a/src/main/java/dev/kruhlmann/imgfloat/ImgfloatApplication.java
+++ b/src/main/java/dev/kruhlmann/imgfloat/ImgfloatApplication.java
@@ -3,8 +3,10 @@ package dev.kruhlmann.imgfloat;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
@EnableAsync
+@EnableScheduling
@SpringBootApplication
public class ImgfloatApplication {
diff --git a/src/main/java/dev/kruhlmann/imgfloat/config/SchedulingConfig.java b/src/main/java/dev/kruhlmann/imgfloat/config/SchedulingConfig.java
new file mode 100644
index 0000000..358ba4b
--- /dev/null
+++ b/src/main/java/dev/kruhlmann/imgfloat/config/SchedulingConfig.java
@@ -0,0 +1,19 @@
+package dev.kruhlmann.imgfloat.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.TaskScheduler;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
+
+@Configuration
+public class SchedulingConfig {
+
+ @Bean
+ public TaskScheduler emoteSyncTaskScheduler() {
+ ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
+ scheduler.setPoolSize(1);
+ scheduler.setThreadNamePrefix("emote-sync-");
+ scheduler.initialize();
+ return scheduler;
+ }
+}
diff --git a/src/main/java/dev/kruhlmann/imgfloat/model/Settings.java b/src/main/java/dev/kruhlmann/imgfloat/model/Settings.java
index b50bd58..e99bb9f 100644
--- a/src/main/java/dev/kruhlmann/imgfloat/model/Settings.java
+++ b/src/main/java/dev/kruhlmann/imgfloat/model/Settings.java
@@ -40,6 +40,9 @@ public class Settings {
@Column(nullable = false)
private int canvasFramesPerSecond;
+ @Column(nullable = false)
+ private int emoteSyncIntervalMinutes;
+
@Column(name = "created_at", nullable = false, updatable = false)
private Instant createdAt;
@@ -58,6 +61,7 @@ public class Settings {
s.setMaxAssetVolumeFraction(5.0);
s.setMaxCanvasSideLengthPixels(7680);
s.setCanvasFramesPerSecond(60);
+ s.setEmoteSyncIntervalMinutes(60);
return s;
}
@@ -133,6 +137,14 @@ public class Settings {
this.canvasFramesPerSecond = canvasFramesPerSecond;
}
+ public int getEmoteSyncIntervalMinutes() {
+ return emoteSyncIntervalMinutes;
+ }
+
+ public void setEmoteSyncIntervalMinutes(int emoteSyncIntervalMinutes) {
+ this.emoteSyncIntervalMinutes = emoteSyncIntervalMinutes;
+ }
+
@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
new file mode 100644
index 0000000..dfc0316
--- /dev/null
+++ b/src/main/java/dev/kruhlmann/imgfloat/service/EmoteSyncScheduler.java
@@ -0,0 +1,81 @@
+package dev.kruhlmann.imgfloat.service;
+
+import dev.kruhlmann.imgfloat.model.Channel;
+import dev.kruhlmann.imgfloat.model.Settings;
+import dev.kruhlmann.imgfloat.repository.ChannelRepository;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.scheduling.TaskScheduler;
+import org.springframework.scheduling.Trigger;
+import org.springframework.scheduling.TriggerContext;
+import org.springframework.scheduling.annotation.SchedulingConfigurer;
+import org.springframework.scheduling.config.ScheduledTaskRegistrar;
+import org.springframework.stereotype.Service;
+
+@Service
+public class EmoteSyncScheduler implements SchedulingConfigurer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(EmoteSyncScheduler.class);
+ private static final int DEFAULT_INTERVAL_MINUTES = 60;
+
+ private final SettingsService settingsService;
+ private final ChannelRepository channelRepository;
+ private final TwitchEmoteService twitchEmoteService;
+ private final SevenTvEmoteService sevenTvEmoteService;
+ private final TaskScheduler taskScheduler;
+
+ public EmoteSyncScheduler(
+ SettingsService settingsService,
+ ChannelRepository channelRepository,
+ TwitchEmoteService twitchEmoteService,
+ SevenTvEmoteService sevenTvEmoteService,
+ @Qualifier("emoteSyncTaskScheduler") TaskScheduler taskScheduler
+ ) {
+ this.settingsService = settingsService;
+ this.channelRepository = channelRepository;
+ this.twitchEmoteService = twitchEmoteService;
+ this.sevenTvEmoteService = sevenTvEmoteService;
+ this.taskScheduler = taskScheduler;
+ }
+
+ @Override
+ public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
+ taskRegistrar.setScheduler(taskScheduler);
+ taskRegistrar.addTriggerTask(this::syncEmotes, buildTrigger());
+ }
+
+ private Trigger buildTrigger() {
+ return (TriggerContext triggerContext) -> {
+ Instant lastCompletion = triggerContext.lastCompletionTime() == null
+ ? Instant.now()
+ : triggerContext.lastCompletionTime().toInstant();
+ return Date.from(lastCompletion.plus(Duration.ofMinutes(resolveIntervalMinutes())));
+ };
+ }
+
+ private int resolveIntervalMinutes() {
+ Settings settings = settingsService.get();
+ int interval = settings.getEmoteSyncIntervalMinutes();
+ return interval > 0 ? interval : DEFAULT_INTERVAL_MINUTES;
+ }
+
+ private void syncEmotes() {
+ int interval = resolveIntervalMinutes();
+ LOG.info("Synchronizing emotes (interval {} minutes)", interval);
+
+ twitchEmoteService.refreshGlobalEmotes();
+ List -- Keeps alerts comfortable Emote sync -- Minutes between refreshes
Emotes
++ Choose how often Imgfloat refreshes Twitch and 7TV emote catalogs. +
+Set to 60 for hourly refreshes.
+