Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions UIPlugin/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>me.egg82</groupId>
<artifactId>fetcharr-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>

<artifactId>fetcharr-ui</artifactId>
<version>${ui.version}</version>

<properties>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
<include>**/*.yaml</include>
<include>**/*.yml</include>
</includes>
</resource>

<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<includes>
<include>**/*.html</include>
<include>**/*.css</include>
<include>**/*.js</include>
</includes>
</resource>
</resources>

<sourceDirectory>src/main/java</sourceDirectory>

<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.21.0</version>
<configuration>
<rulesUri>file:///${project.basedir}/../versions.xml</rulesUri>
</configuration>
</plugin>

<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.15.0</version>
<configuration>
<source>21</source>
<target>21</target>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<dependencyReducedPomLocation>${project.build.directory}/dependency-reduced-pom.xml</dependencyReducedPomLocation>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
<exclude>LICENSE-2.0.txt</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

<repositories>
<repository>
<id>egg82-repo-releases</id>
<url>https://repo.egg82.me/releases/</url>
</repository>
<repository>
<id>egg82-repo-snapshots</id>
<url>https://repo.egg82.me/snapshots/</url>
</repository>
</repositories>

<dependencies>
<dependency>
<groupId>me.egg82</groupId>
<artifactId>fetcharr-api</artifactId>
<version>${api.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>me.egg82</groupId>
<artifactId>arr-lib</artifactId>
<version>${lib.version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>${jetbrains.version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>com.sasorio</groupId>
<artifactId>event-api</artifactId>
<version>${event.version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.spongepowered</groupId>
<artifactId>configurate-core</artifactId>
<version>${configurate.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.spongepowered</groupId>
<artifactId>configurate-yaml</artifactId>
<version>${configurate.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
170 changes: 170 additions & 0 deletions UIPlugin/src/main/java/me/egg82/fuiplugin/EventEntry.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package me.egg82.fuiplugin;

import me.egg82.arr.lidarr.v1.schema.ArtistResource;
import me.egg82.arr.radarr.v3.schema.MovieResource;
import me.egg82.arr.sonarr.v3.schema.SeriesResource;
import me.egg82.fetcharr.api.event.FetcharrEvent;
import me.egg82.fetcharr.api.event.update.AbstractUpdaterEvent;
import me.egg82.fetcharr.api.event.update.lidarr.*;
import me.egg82.fetcharr.api.event.update.radarr.*;
import me.egg82.fetcharr.api.event.update.sonarr.*;
import me.egg82.fetcharr.api.event.update.whisparr.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.time.Instant;

public record EventEntry(
@NotNull Instant time,
@NotNull String type,
@NotNull String service,
@NotNull String updaterUrl,
@NotNull String title,
boolean cancelled
) {
public static @NotNull EventEntry from(@NotNull FetcharrEvent event) {
Instant time = Instant.now();
String updaterUrl = "";

if (event instanceof AbstractUpdaterEvent ae) {
try {
updaterUrl = ae.updater().config().url();
} catch (Exception ignored) { }
}

// Radarr
if (event instanceof RadarrUpdateMovieEvent e) {
return new EventEntry(time, "RadarrUpdateMovie", "radarr", updaterUrl, radarrTitle(e.resource()), false);
}
if (event instanceof RadarrSelectMovieEvent e) {
return new EventEntry(time, "RadarrSelectMovie", "radarr", updaterUrl, radarrTitle(e.resource()), false);
}
if (event instanceof RadarrSkipMovieSelectionEvent e) {
return new EventEntry(time, "RadarrSkipMovie", "radarr", updaterUrl,
radarrTitle(e.resource()) + " [" + e.reason().name() + "]", true);
}
if (event instanceof RadarrFetchMovieEvent) {
return new EventEntry(time, "RadarrFetchMovie", "radarr", updaterUrl, "fetched from API", false);
}
if (event instanceof RadarrSearchEvent e) {
int count = e.resources().size();
return new EventEntry(time, "RadarrSearch", "radarr", updaterUrl, count + " movie" + (count != 1 ? "s" : ""), false);
}

// Sonarr
if (event instanceof SonarrUpdateSeriesEvent e) {
return new EventEntry(time, "SonarrUpdateSeries", "sonarr", updaterUrl, sonarrTitle(e.resource()), false);
}
if (event instanceof SonarrSelectSeriesEvent e) {
return new EventEntry(time, "SonarrSelectSeries", "sonarr", updaterUrl, sonarrTitle(e.resource()), false);
}
if (event instanceof SonarrSkipSeriesSelectionEvent e) {
return new EventEntry(time, "SonarrSkipSeries", "sonarr", updaterUrl,
sonarrTitle(e.resource()) + " [" + e.reason().name() + "]", true);
}
if (event instanceof SonarrFetchEpisodesEvent e) {
return new EventEntry(time, "SonarrFetchEpisodes", "sonarr", updaterUrl, sonarrTitle(e.series()), false);
}
if (event instanceof SonarrFetchSeriesEvent) {
return new EventEntry(time, "SonarrFetchSeries", "sonarr", updaterUrl, "fetched from API", false);
}
if (event instanceof SonarrSearchEvent e) {
int count = e.resources().size();
return new EventEntry(time, "SonarrSearch", "sonarr", updaterUrl, count + " series", false);
}

// Lidarr
if (event instanceof LidarrUpdateArtistEvent e) {
return new EventEntry(time, "LidarrUpdateArtist", "lidarr", updaterUrl, lidarrTitle(e.resource()), false);
}
if (event instanceof LidarrSelectArtistEvent e) {
return new EventEntry(time, "LidarrSelectArtist", "lidarr", updaterUrl, lidarrTitle(e.resource()), false);
}
if (event instanceof LidarrSkipArtistSelectionEvent e) {
return new EventEntry(time, "LidarrSkipArtist", "lidarr", updaterUrl,
lidarrTitle(e.resource()) + " [" + e.reason().name() + "]", true);
}
if (event instanceof LidarrFetchAlbumsEvent e) {
return new EventEntry(time, "LidarrFetchAlbums", "lidarr", updaterUrl, lidarrTitle(e.artist()), false);
}
if (event instanceof LidarrFetchTracksEvent e) {
return new EventEntry(time, "LidarrFetchTracks", "lidarr", updaterUrl, lidarrTitle(e.artist()), false);
}
if (event instanceof LidarrFetchArtistEvent) {
return new EventEntry(time, "LidarrFetchArtist", "lidarr", updaterUrl, "fetched from API", false);
}
if (event instanceof LidarrSearchEvent e) {
int count = e.resources().size();
return new EventEntry(time, "LidarrSearch", "lidarr", updaterUrl, count + " artist" + (count != 1 ? "s" : ""), false);
}

// Whisparr
if (event instanceof WhisparrUpdateMovieEvent e) {
return new EventEntry(time, "WhisparrUpdateMovie", "whisparr", updaterUrl, whisparrTitle(e.resource()), false);
}
if (event instanceof WhisparrSelectMovieEvent e) {
return new EventEntry(time, "WhisparrSelectMovie", "whisparr", updaterUrl, whisparrTitle(e.resource()), false);
}
if (event instanceof WhisparrSkipMovieSelectionEvent e) {
return new EventEntry(time, "WhisparrSkipMovie", "whisparr", updaterUrl,
whisparrTitle(e.resource()) + " [" + e.reason().name() + "]", true);
}
if (event instanceof WhisparrFetchMovieEvent) {
return new EventEntry(time, "WhisparrFetchMovie", "whisparr", updaterUrl, "fetched from API", false);
}
if (event instanceof WhisparrSearchEvent e) {
int count = e.resources().size();
return new EventEntry(time, "WhisparrSearch", "whisparr", updaterUrl, count + " movie" + (count != 1 ? "s" : ""), false);
}

return new EventEntry(time, event.eventType().getSimpleName(), "unknown", updaterUrl, "", false);
}

private static @NotNull String radarrTitle(@Nullable MovieResource r) {
if (r == null) return "Unknown";
String title = r.getTitle();
if (title == null || title.isBlank()) return "Unknown";
Integer year = r.getYear();
return (year != null && year > 0) ? title + " (" + year + ")" : title;
}

private static @NotNull String sonarrTitle(@Nullable SeriesResource r) {
if (r == null) return "Unknown";
String title = r.getTitle();
return (title != null && !title.isBlank()) ? title : "Unknown";
}

private static @NotNull String lidarrTitle(@Nullable ArtistResource r) {
if (r == null) return "Unknown";
String name = r.getArtistName();
return (name != null && !name.isBlank()) ? name : "Unknown";
}

private static @NotNull String whisparrTitle(@Nullable me.egg82.arr.whisparr.v3.schema.MovieResource r) {
if (r == null) return "Unknown";
String title = r.getTitle();
if (title == null || title.isBlank()) return "Unknown";
Integer year = r.getYear();
return (year != null && year > 0) ? title + " (" + year + ")" : title;
}

/** Serialize to a JSON object string (no external library needed). */
public @NotNull String toJson() {
return "{" +
"\"time\":\"" + jsonEscape(time.toString()) + "\"," +
"\"type\":\"" + jsonEscape(type) + "\"," +
"\"service\":\"" + jsonEscape(service) + "\"," +
"\"updaterUrl\":\"" + jsonEscape(updaterUrl) + "\"," +
"\"title\":\"" + jsonEscape(title) + "\"," +
"\"cancelled\":" + cancelled +
"}";
}

private static @NotNull String jsonEscape(@NotNull String s) {
return s.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t");
}
}
40 changes: 40 additions & 0 deletions UIPlugin/src/main/java/me/egg82/fuiplugin/EventLog.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package me.egg82.fuiplugin;

import org.jetbrains.annotations.NotNull;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;

public class EventLog {
private final int maxSize;
private final Deque<EventEntry> entries;

public EventLog(int maxSize) {
this.maxSize = maxSize;
this.entries = new ArrayDeque<>(maxSize);
}

public synchronized void add(@NotNull EventEntry entry) {
if (entries.size() >= maxSize) {
entries.pollFirst();
}
entries.addLast(entry);
}

public synchronized @NotNull List<EventEntry> snapshot() {
return new ArrayList<>(entries);
}

public @NotNull String toJson() {
List<EventEntry> snapshot = snapshot();
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < snapshot.size(); i++) {
if (i > 0) sb.append(",");
sb.append(snapshot.get(i).toJson());
}
sb.append("]");
return sb.toString();
}
}
Loading