Implement history for uploading local tracks

This commit is contained in:
2026-01-03 18:49:45 +05:00
parent a3c43ce5a3
commit 5a68f652ed
8 changed files with 33 additions and 46 deletions

View File

@ -13,20 +13,24 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.bivashy.backend.composer.dto.importing.TrackProgressDTO;
import com.bivashy.backend.composer.dto.track.AddLocalTrackRequest; import com.bivashy.backend.composer.dto.track.AddLocalTrackRequest;
import com.bivashy.backend.composer.dto.track.PlaylistTrackResponse; import com.bivashy.backend.composer.dto.track.PlaylistTrackResponse;
import com.bivashy.backend.composer.dto.track.TrackBulkReorderRequest; import com.bivashy.backend.composer.dto.track.TrackBulkReorderRequest;
import com.bivashy.backend.composer.dto.track.TrackReorderAfterRequest;
import com.bivashy.backend.composer.dto.track.TrackResponse; import com.bivashy.backend.composer.dto.track.TrackResponse;
import com.bivashy.backend.composer.model.SourceTypes;
import com.bivashy.backend.composer.model.User; import com.bivashy.backend.composer.model.User;
import com.bivashy.backend.composer.service.TrackService; import com.bivashy.backend.composer.service.TrackService;
import com.bivashy.backend.composer.service.importing.RedisProgressService;
@RestController @RestController
public class TrackController { public class TrackController {
private final TrackService trackService; private final TrackService trackService;
private final RedisProgressService redisProgressService;
public TrackController(TrackService trackService) { public TrackController(TrackService trackService, RedisProgressService redisProgressService) {
this.trackService = trackService; this.trackService = trackService;
this.redisProgressService = redisProgressService;
} }
@PostMapping(path = "/playlist/{playlistId}/track/local", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @PostMapping(path = "/playlist/{playlistId}/track/local", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ -35,6 +39,15 @@ public class TrackController {
@PathVariable Long playlistId, @PathVariable Long playlistId,
@ModelAttribute AddLocalTrackRequest request) throws IOException { @ModelAttribute AddLocalTrackRequest request) throws IOException {
TrackResponse response = trackService.addLocalTrack(user, playlistId, request); TrackResponse response = trackService.addLocalTrack(user, playlistId, request);
redisProgressService.saveProgress(new TrackProgressDTO(playlistId,
response.trackId(),
response.title(),
response.fileFormat(),
SourceTypes.FILE,
100,
"",
null,
user.getId()));
return ResponseEntity.ok(response); return ResponseEntity.ok(response);
} }

View File

@ -33,15 +33,6 @@ public class ProgressSSEController {
this.redisSubscriber = redisSubscriber; this.redisSubscriber = redisSubscriber;
} }
@GetMapping("/importing/test/{playlistId}")
public void test(@PathVariable long playlistId, @AuthenticationPrincipal CustomUserDetails user) {
var userId = user.getId();
redisProgressService.saveProgress(new TrackProgressDTO(
playlistId,
"test",
userId));
}
@GetMapping(value = "/importing/stream/{playlistId}", produces = MediaType.TEXT_EVENT_STREAM_VALUE) @GetMapping(value = "/importing/stream/{playlistId}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<String>> streamProgress( public Flux<ServerSentEvent<String>> streamProgress(
@PathVariable long playlistId, @PathVariable long playlistId,

View File

@ -1,27 +0,0 @@
package com.bivashy.backend.composer.dto;
public enum SourceType {
AUDIO("AUDIO"),
PLAYLIST("PLAYLIST"),
FILE("FILE"),
URL("URL");
private final String value;
SourceType(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public static SourceType fromValue(String value) {
for (SourceType type : values()) {
if (type.value.equalsIgnoreCase(value)) {
return type;
}
}
throw new IllegalArgumentException("Unknown source type: " + value);
}
}

View File

@ -5,7 +5,7 @@ public class ImportTrackKey {
return String.format("progress:%d:%d", userId, playlistId); return String.format("progress:%d:%d", userId, playlistId);
} }
public static String trackKey(long playlistId, String trackId, long userId) { public static String trackKey(long playlistId, long trackId, long userId) {
return String.format("track:%d:%d:%s", userId, playlistId, trackId); return String.format("track:%d:%d:%s", userId, playlistId, trackId);
} }

View File

@ -2,7 +2,7 @@ package com.bivashy.backend.composer.dto.importing;
public class TrackProgressDTO { public class TrackProgressDTO {
private long playlistId; private long playlistId;
private String trackId; private long trackId;
private String trackTitle; private String trackTitle;
private String format; private String format;
private String sourceType; private String sourceType;
@ -14,7 +14,7 @@ public class TrackProgressDTO {
public TrackProgressDTO() { public TrackProgressDTO() {
} }
public TrackProgressDTO(long playlistId, String trackId, long userId) { public TrackProgressDTO(long playlistId, long trackId, long userId) {
this.playlistId = playlistId; this.playlistId = playlistId;
this.trackId = trackId; this.trackId = trackId;
this.userId = userId; this.userId = userId;
@ -22,7 +22,7 @@ public class TrackProgressDTO {
} }
public TrackProgressDTO(long playlistId, public TrackProgressDTO(long playlistId,
String trackId, long trackId,
String trackTitle, String trackTitle,
String format, String format,
String sourceType, String sourceType,
@ -49,11 +49,11 @@ public class TrackProgressDTO {
this.playlistId = playlistId; this.playlistId = playlistId;
} }
public String getTrackId() { public long getTrackId() {
return trackId; return trackId;
} }
public void setTrackId(String trackId) { public void setTrackId(long trackId) {
this.trackId = trackId; this.trackId = trackId;
} }

View File

@ -5,6 +5,7 @@ public record TrackResponse(
String title, String title,
String artist, String artist,
String audioPath, String audioPath,
String fileFormat,
Integer durationSeconds, Integer durationSeconds,
String fileName) { String fileName) {
} }

View File

@ -43,6 +43,7 @@ public class MetadataParseService {
var format = Optional.ofNullable(result.getFormat()); var format = Optional.ofNullable(result.getFormat());
var formatNameOpt = format.map(f -> f.getFormatName());
Optional<Float> formatDuration = format.map(f -> f.getDuration()); Optional<Float> formatDuration = format.map(f -> f.getDuration());
List<Optional<Float>> streamDuration = Optional.ofNullable(result.getStreams()) List<Optional<Float>> streamDuration = Optional.ofNullable(result.getStreams())
.map(streams -> streams.stream() .map(streams -> streams.stream()
@ -58,12 +59,14 @@ public class MetadataParseService {
var jsonResult = ffprobeObjectMapper.writeValueAsString(result); var jsonResult = ffprobeObjectMapper.writeValueAsString(result);
var formatName = formatNameOpt.orElse("unknown");
var title = format.map(f -> f.getTag("title")).orElse(null); var title = format.map(f -> f.getTag("title")).orElse(null);
var artist = format.map(f -> f.getTag("artist")).orElse(null); var artist = format.map(f -> f.getTag("artist")).orElse(null);
return Optional.of(new Metadata(title, artist, foundDuration.orElse(0f), jsonResult)); return Optional.of(new Metadata(title, artist, formatName, foundDuration.orElse(0f), jsonResult));
} }
public static record Metadata(String title, String artist, Float durationSeconds, String rawJson) { public static record Metadata(String title, String artist, String formatName, Float durationSeconds,
String rawJson) {
} }
} }

View File

@ -61,11 +61,17 @@ public class TrackService {
track, title, fileName, trackSource.getSourceUrl(), artist, null, durationSeconds); track, title, fileName, trackSource.getSourceUrl(), artist, null, durationSeconds);
trackPlaylistService.insertTrackAtEnd(playlistId, track.getId()); trackPlaylistService.insertTrackAtEnd(playlistId, track.getId());
String fileFormat = "unknown";
if (metadata.isPresent()) {
fileFormat = metadata.map(m -> m.formatName()).get();
}
return new TrackResponse( return new TrackResponse(
track.getId(), track.getId(),
title, title,
artist, artist,
trackSource.getSourceUrl(), trackSource.getSourceUrl(),
fileFormat,
durationSeconds, durationSeconds,
fileName); fileName);
} }