feat: use bulk Spotify API calls & inserts to make spotify crawling more efficient (#271)

* feat(spotify-api): bulk endpoints
* feat(music-library): allow bulk operations
* feat(spotify): bulk track+album+artist+genre import
* feat(spotify): use bulk import api for user crawl
* feat(spotify): bulk listen insert

For the benchmark case of a new user where Listory imports 50 new listens along with all now tracks, artists, albums & genres we significantly reduced the number of things happening:

    Spotify API Requests: 208 => 8
    DB Insert: 96 => 8
    Tracing Spans: 1953 => 66
This commit is contained in:
Julian Tölle 2023-05-07 02:20:43 +02:00 committed by GitHub
parent 24b7308343
commit 8721fd101d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 427 additions and 23 deletions

View file

@ -33,6 +33,12 @@ export class MusicLibraryService {
});
}
async findArtists(query: FindArtistDto[]): Promise<Artist[]> {
return this.artistRepository.find({
where: query,
});
}
async getArtistWithOldestUpdate(): Promise<Artist | undefined> {
const [oldestArtist] = await this.artistRepository.find({
take: 1,
@ -69,6 +75,12 @@ export class MusicLibraryService {
return artist;
}
async createArtists(data: CreateArtistDto[]): Promise<Artist[]> {
return this.artistRepository.save(
data.map((entry) => this.artistRepository.create(entry))
);
}
async updateArtist({
artist,
updatedFields,
@ -86,6 +98,10 @@ export class MusicLibraryService {
});
}
async findAlbums(query: FindAlbumDto[]): Promise<Album[]> {
return this.albumRepository.find({ where: query });
}
async createAlbum(data: CreateAlbumDto): Promise<Album> {
const album = this.albumRepository.create();
@ -111,12 +127,24 @@ export class MusicLibraryService {
return album;
}
async createAlbums(data: CreateAlbumDto[]): Promise<Album[]> {
return this.albumRepository.save(
data.map((entry) => this.albumRepository.create(entry))
);
}
async findGenre(query: FindGenreDto): Promise<Genre | undefined> {
return this.genreRepository.findOneBy({
name: query.name,
});
}
async findGenres(query: FindGenreDto[]): Promise<Genre[]> {
return this.genreRepository.find({
where: query,
});
}
async createGenre(data: CreateGenreDto): Promise<Genre> {
const genre = this.genreRepository.create();
@ -140,12 +168,22 @@ export class MusicLibraryService {
return genre;
}
async createGenres(data: CreateGenreDto[]): Promise<Genre[]> {
return this.genreRepository.save(
data.map((entry) => this.genreRepository.create(entry))
);
}
async findTrack(query: FindTrackDto): Promise<Track | undefined> {
return this.trackRepository.findOneBy({
spotify: { id: query.spotify.id },
});
}
async findTracks(query: FindTrackDto[]): Promise<Track[]> {
return this.trackRepository.find({ where: query });
}
async createTrack(data: CreateTrackDto): Promise<Track> {
const track = this.trackRepository.create();
@ -171,4 +209,10 @@ export class MusicLibraryService {
return track;
}
async createTracks(data: CreateTrackDto[]): Promise<Track[]> {
return this.trackRepository.save(
data.map((entry) => this.trackRepository.create(entry))
);
}
}