My objective is to create an application that should allow to stream audio from S3 buckets. My backend is actually returning a list of titles to stream. In my controller I have a basic call:
@GetMapping(
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Flux<AudioResponseDto>> getPlaylist() {
return new ResponseEntity<>(this.audioService.getPlaylist(), HttpStatus.OK);
}
In my service:
@Override
public Flux<AudioResponseDto> getPlaylist() {
return audioRepository.findAll().map(AudioUtils::audioEntityToAudioResponseDto);
}
As a matter of fact my code is working and i'm returning AudioResponseDto but it's rather dirty: anyone can download the file because the URL link is visible Here is my model response object:
public class AudioResponseDto {
private String id;
private String title;
private String artist;
private String album;
private int year;
private byte[] albumImage;
private int length;
private String streamUrl;
}
My streamUrl is a link to a file from S3 bucket and looks like this:
https://custom-storage-audio.s3.eu-west-3.amazonaws.com/{folderId]/my+file.mp3
My front app is running on angular. My work is highly inspired from Shibaji Debnath tutorial that allowed me to have a first approach on audio streaming. I call my springboot app and retrieve a playlist. I implemented a service to call my API:
getFiles(): Observable<AudioStream[]> {
return this.http.get<AudioStream[]>("http://localhost:8080/audio/tracks")
}
My AudioStream model is based on the AudioResponseDto object:
export interface AudioStream {
id: string;
title: string;
artist: string;
album: string;
year: number;
albumImage: any[];
length: number;
streamUrl: string;
}
To play a title, a method is called:
openFile(file: AudioStream, index: number) {
this.currentFile = { index, file };
this.audioService.stop();
this.playStream(file.streamUrl);
}
playStream(url: string) {
this.audioService.playStream(url).subscribe( (events: any) => {
if(events.type == 'ended'){
if(!this.isLastPlaying()){
this.next();
}else{
this.openFile(this.files[0], 0);
}
}
});
}
From my service:
playStream(url: string) {
return this.streamObservable(url).pipe(takeUntil(this.stop$));
}
I do have security concerns:
- I would like to make the file readable but not available for download for guests
- Make the title available for download in specific conditions
- I would like to have an url each time a title is listened
Ideally, my AudioResponse should not contain web url that make the track available for download, I would like to stream from S3 without sharing URL by passing bytes array, without downloading possibility, and without giving the link to the bucket.
I do think I should create a route that retrieve the file from S3 in springboot and return a content to stream. I will also have the same issue concerning videos :)
I hope that I make myself clear enough. Thanks