diff --git a/src/listens/listens.module.ts b/src/listens/listens.module.ts index 7d5b837..6571bed 100644 --- a/src/listens/listens.module.ts +++ b/src/listens/listens.module.ts @@ -1,13 +1,13 @@ import { Module } from "@nestjs/common"; -import { ListensService } from "./listens.service"; import { TypeOrmModule } from "@nestjs/typeorm"; import { ListenRepository } from "./listen.repository"; import { ListensController } from "./listens.controller"; +import { ListensService } from "./listens.service"; @Module({ imports: [TypeOrmModule.forFeature([ListenRepository])], providers: [ListensService], - exports: [ListensService], + exports: [ListensService, TypeOrmModule], controllers: [ListensController], }) export class ListensModule {} diff --git a/src/music-library/artist.entity.ts b/src/music-library/artist.entity.ts index 3a5ebbf..8e56c9b 100644 --- a/src/music-library/artist.entity.ts +++ b/src/music-library/artist.entity.ts @@ -1,5 +1,5 @@ -import { Entity, PrimaryGeneratedColumn, Column, ManyToMany } from "typeorm"; import { SpotifyLibraryDetails } from "src/sources/spotify/spotify-library-details.entity"; +import { Column, Entity, ManyToMany, PrimaryGeneratedColumn } from "typeorm"; import { Album } from "./album.entity"; @Entity() @@ -11,7 +11,7 @@ export class Artist { name: string; @ManyToMany((type) => Album, (album) => album.artists) - albums: Album[]; + albums?: Album[]; @Column((type) => SpotifyLibraryDetails) spotify: SpotifyLibraryDetails; diff --git a/src/reports/reports.module.ts b/src/reports/reports.module.ts index 3d11814..48dbbd2 100644 --- a/src/reports/reports.module.ts +++ b/src/reports/reports.module.ts @@ -1,7 +1,7 @@ import { Module } from "@nestjs/common"; -import { ReportsService } from "./reports.service"; -import { ReportsController } from "./reports.controller"; import { ListensModule } from "src/listens/listens.module"; +import { ReportsController } from "./reports.controller"; +import { ReportsService } from "./reports.service"; @Module({ imports: [ListensModule], diff --git a/src/reports/reports.service.ts b/src/reports/reports.service.ts index e816f4a..c67a2aa 100644 --- a/src/reports/reports.service.ts +++ b/src/reports/reports.service.ts @@ -15,6 +15,7 @@ import { startOfDay, sub, } from "date-fns"; +import { ListenRepository } from "../listens/listen.repository"; import { ListensService } from "../listens/listens.service"; import { GetListenReportDto } from "./dto/get-listen-report.dto"; import { GetTopArtistsReportDto } from "./dto/get-top-artists-report.dto"; @@ -62,7 +63,10 @@ const PAGINATION_LIMIT_UNLIMITED = 10000000; @Injectable() export class ReportsService { - constructor(private readonly listensService: ListensService) {} + constructor( + private readonly listensService: ListensService, + private readonly listenRepository: ListenRepository + ) {} async getListens(options: GetListenReportDto): Promise { const { user, timeFrame, timeStart, timeEnd } = options; @@ -108,40 +112,41 @@ export class ReportsService { customTimeEnd, }); - const { items: listens } = await this.listensService.getListens({ - user, - filter: { time: interval }, - page: 1, - limit: PAGINATION_LIMIT_UNLIMITED, - }); + const getArtistsWithCountQB = this.listenRepository + .createQueryBuilder("l") + .andWhere('l."userId" = :userID', { userID: user.id }) + .andWhere("l.playedAt BETWEEN :timeStart AND :timeEnd", { + timeStart: interval.start, + timeEnd: interval.end, + }) + .leftJoin("l.track", "track") + .leftJoinAndSelect("track.artists", "artists") + .groupBy("artists.id") + .select("artists.*") + .addSelect("count(*) as listens") + .orderBy("listens", "DESC"); - // Declare types for metrics calculation - type Item = TopArtistsReportDto["items"][0]; - type Accumulator = { - [x: string]: Item; + const rawArtistsWithCount = await getArtistsWithCountQB.getRawMany(); + + const items: TopArtistsReportDto["items"] = rawArtistsWithCount.map( + (data) => ({ + count: Number.parseInt(data.listens, 10), + artist: { + id: data.id, + name: data.name, + spotify: { + id: data.spotifyId, + uri: data.spotifyUri, + type: data.spotifyType, + href: data.spotifyHref, + }, + }, + }) + ); + + return { + items, }; - - const items: TopArtistsReportDto["items"] = Object.values( - listens - .flatMap((listen) => listen.track.artists) - .reduce((counters, artist) => { - if (!counters[artist.id]) { - counters[artist.id] = { - artist, - count: 0, - }; - } - - counters[artist.id].count += 1; - - return counters; - }, {}) - ) - .sort((a, b) => a.count - b.count) - .reverse() // sort descending - .slice(0, 20); // TODO: Make configurable - - return { items }; } private getIntervalFromPreset(options: {