Skip to content
Merged
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
16 changes: 10 additions & 6 deletions frontend/src/components/SongTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ interface SortableRowProps {
isDraggable: boolean;
}

function format2(n?: number) {
return typeof n === "number" ? n.toFixed(2) : "";
}

const SortableRow = ({ track, id, index, isDraggable }: SortableRowProps) => {
const {
attributes,
Expand Down Expand Up @@ -114,7 +118,7 @@ const SortableRow = ({ track, id, index, isDraggable }: SortableRowProps) => {

<Box sx={{ width: 60, textAlign: "center" }}>
<Typography variant="body2" sx={{ color: "#aaa" }}>
{track.tempo}
{format2(track.tempo)}
</Typography>
</Box>

Expand All @@ -126,13 +130,13 @@ const SortableRow = ({ track, id, index, isDraggable }: SortableRowProps) => {

<Box sx={{ width: 90, textAlign: "center" }}>
<Typography variant="body2" sx={{ color: "#aaa" }}>
{track.loudness}
{format2(track.loudness)}
</Typography>
</Box>

<Box sx={{ width: 60, textAlign: "center" }}>
<Typography variant="body2" sx={{ color: "#aaa" }}>
{track.energy}
{format2(track.energy)}
</Typography>
</Box>

Expand Down Expand Up @@ -197,7 +201,7 @@ const StaticRow = ({ track, index }: { track: NextTrack; index: number }) => {

<Box sx={{ width: 60, textAlign: "center" }}>
<Typography variant="body2" sx={{ color: "#aaa" }}>
{track.tempo}
{format2(track.tempo)}
</Typography>
</Box>

Expand All @@ -209,13 +213,13 @@ const StaticRow = ({ track, index }: { track: NextTrack; index: number }) => {

<Box sx={{ width: 90, textAlign: "center" }}>
<Typography variant="body2" sx={{ color: "#aaa" }}>
{track.loudness}
{format2(track.loudness)}
</Typography>
</Box>

<Box sx={{ width: 60, textAlign: "center" }}>
<Typography variant="body2" sx={{ color: "#aaa" }}>
{track.energy}
{format2(track.energy)}
</Typography>
</Box>

Expand Down
4 changes: 2 additions & 2 deletions frontend/src/models/next-track.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ export interface NextTrack {
trackUri: string;
trackIndex?: number;
tempo?: number;
key?: string;
loudness?: string;
key?: number;
loudness?: number;
energy?: number;
danceability?: number;
mode?: string;
Expand Down
4 changes: 1 addition & 3 deletions spring-boot-app/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,4 @@ build/
!**/src/test/**/build/

### VS Code ###
.vscode/
/src/main/resources/application.properties
**/application.properties
.vscode/
21 changes: 21 additions & 0 deletions spring-boot-app/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Stage 1: Build
FROM maven:3.8.4-openjdk-17 AS build

WORKDIR /app

COPY pom.xml .
RUN mvn dependency:go-offline

COPY src ./src
RUN mvn clean package -DskipTests

# Stage 2: Runtime
FROM openjdk:17-jdk-slim

WORKDIR /app

COPY --from=build /app/target/*-SNAPSHOT.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]
34 changes: 4 additions & 30 deletions spring-boot-app/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<url/>
</scm>
<properties>
<java.version>23</java.version>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
Expand All @@ -52,11 +52,6 @@
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
Expand All @@ -66,12 +61,7 @@
<groupId>se.michaelthelin.spotify</groupId>
<artifactId>spotify-web-api-java</artifactId>
<version>9.1.1</version>
</dependency>
<dependency>
<groupId>io.github.cdimascio</groupId>
<artifactId>dotenv-java</artifactId>
<version>2.3.2</version>
</dependency>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
Expand All @@ -82,27 +72,11 @@
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</path>
</annotationProcessorPaths>
</configuration>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

import com.nexttrack.spring_boot_app.model.NextTrackAudioFeatures;
import com.nexttrack.spring_boot_app.repository.NextTrackAudioFeaturesRepo;

import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;

import java.util.Map;
import java.util.Optional;
Expand All @@ -11,17 +15,160 @@
public class NextTrackAudioFeaturesService {

private final NextTrackAudioFeaturesRepo nextTrackAudioFeaturesRepo;
private final WebClient webClient;

public NextTrackAudioFeaturesService(NextTrackAudioFeaturesRepo nextTrackAudioFeaturesRepo) {
this.nextTrackAudioFeaturesRepo = nextTrackAudioFeaturesRepo;
this.webClient = WebClient.builder()
.baseUrl("https://feature-extraction-service-production.up.railway.app/extract_features")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
}

public NextTrackAudioFeatures findOrCreateTrack(String name, String artist) {
return nextTrackAudioFeaturesRepo.findByNameAndArtist(name, artist)
.orElseGet(() -> {
var requestBody = Map.of(
"artist", artist,
"track_name", name);

var track = nextTrackAudioFeaturesRepo.findByNameAndArtist(name, artist);
AudioFeaturesResponse resp = webClient.post()
.bodyValue(requestBody)
.retrieve()
.bodyToMono(AudioFeaturesResponse.class)
.block();

// TODO: Make call to audio feature extraction
return track.orElse(new NextTrackAudioFeatures());
AudioFeaturesResponse.Features f = resp.getFeatures();

NextTrackAudioFeatures entity = new NextTrackAudioFeatures();
entity.setName(name);
entity.setArtist(artist);
entity.setAcousticness(f.getAcousticness());
entity.setDanceability(f.getDanceability());
entity.setEnergy(f.getEnergy());
entity.setInstrumentalness(f.getInstrumentalness());
entity.setKey(f.getKey());
entity.setLiveness(f.getLiveness());
entity.setLoudness(f.getLoudness());
entity.setSpeechiness(f.getSpeechiness());
entity.setTempo(f.getTempo());
entity.setValence(f.getValence());
return nextTrackAudioFeaturesRepo.save(entity);
});
}

public static class AudioFeaturesResponse {
private Features features;
private String track;

public static class Features {
private double acousticness;
private double danceability;
private double energy;
private double instrumentalness;
private int key;
private double liveness;
private double loudness;
private double speechiness;
private double tempo;
private double valence;

public double getAcousticness() {
return acousticness;
}

public void setAcousticness(double acousticness) {
this.acousticness = acousticness;
}

public double getDanceability() {
return danceability;
}

public void setDanceability(double danceability) {
this.danceability = danceability;
}

public double getEnergy() {
return energy;
}

public void setEnergy(double energy) {
this.energy = energy;
}

public double getInstrumentalness() {
return instrumentalness;
}

public void setInstrumentalness(double instrumentalness) {
this.instrumentalness = instrumentalness;
}

public int getKey() {
return key;
}

public void setKey(int key) {
this.key = key;
}

public double getLiveness() {
return liveness;
}

public void setLiveness(double liveness) {
this.liveness = liveness;
}

public double getLoudness() {
return loudness;
}

public void setLoudness(double loudness) {
this.loudness = loudness;
}

public double getSpeechiness() {
return speechiness;
}

public void setSpeechiness(double speechiness) {
this.speechiness = speechiness;
}

public double getTempo() {
return tempo;
}

public void setTempo(double tempo) {
this.tempo = tempo;
}

public double getValence() {
return valence;
}

public void setValence(double valence) {
this.valence = valence;
}
}

public Features getFeatures() {
return features;
}

public void setFeatures(Features features) {
this.features = features;
}

public String getTrack() {
return track;
}

public void setTrack(String track) {
this.track = track;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import java.util.Arrays;
import java.util.List;

import com.nexttrack.spring_boot_app.Keys;
import com.nexttrack.spring_boot_app.configurations.SpotifyConfig;
import com.nexttrack.spring_boot_app.responses.CreatePlaylistReponse;

import se.michaelthelin.spotify.SpotifyApi;
Expand All @@ -29,22 +29,21 @@
import se.michaelthelin.spotify.requests.data.users_profile.GetUsersProfileRequest;

import org.apache.hc.core5.http.ParseException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class SpotifyService {

private String clientId = Keys.getKey("SPOTIFY_CLIENT_ID");
private String clientSecret = Keys.getKey("SPOTIFY_CLIENT_SECRET");

private static final URI redirectUri = URI.create("http://localhost:8080/api/get-user-code");
private URI redirectUri;

private final SpotifyApi spotifyApi;

public SpotifyService() {
public SpotifyService(SpotifyConfig config) {
this.redirectUri = URI.create(config.getApiUrl() + "/api/get-user-code");
this.spotifyApi = new SpotifyApi.Builder()
.setClientId(clientId)
.setClientSecret(clientSecret)
.setClientId(config.getClientId())
.setClientSecret(config.getClientSecret())
.setRedirectUri(redirectUri)
.build();
}
Expand Down
Loading