feat: add top-artists report

This commit is contained in:
Julian Tölle 2020-05-31 23:26:06 +02:00
parent 6a6ba493f6
commit 6fc10c40ca
18 changed files with 345 additions and 30 deletions

View file

@ -17,7 +17,10 @@ import {
} from "date-fns";
import { ListensService } from "../listens/listens.service";
import { GetListenReportDto } from "./dto/get-listen-report.dto";
import { GetTopArtistsReportDto } from "./dto/get-top-artists-report.dto";
import { ListenReportDto } from "./dto/listen-report.dto";
import { TopArtistsReportDto } from "./dto/top-artists-report.dto";
import { Interval } from "./interval";
import { Timeframe } from "./timeframe.enum";
import { TimePreset } from "./timePreset.enum";
@ -55,6 +58,8 @@ const timePresetToDays: { [x in TimePreset]: number } = {
[TimePreset.CUSTOM]: 0, // Not used for this
};
const PAGINATION_LIMIT_UNLIMITED = 10000000;
@Injectable()
export class ReportsService {
constructor(private readonly listensService: ListensService) {}
@ -73,7 +78,7 @@ export class ReportsService {
user,
filter: { time: interval },
page: 1,
limit: 10000000,
limit: PAGINATION_LIMIT_UNLIMITED,
});
const reportInterval: Interval = {
@ -91,6 +96,54 @@ export class ReportsService {
return { items: reportItems, timeStart, timeEnd, timeFrame };
}
async getTopArtists(
options: GetTopArtistsReportDto
): Promise<TopArtistsReportDto> {
const { user, timePreset, customTimeStart, customTimeEnd } = options;
const interval = this.getIntervalFromPreset({
timePreset,
customTimeStart,
customTimeEnd,
});
const { items: listens } = await this.listensService.getListens({
user,
filter: { time: interval },
page: 1,
limit: PAGINATION_LIMIT_UNLIMITED,
});
// Declare types for metrics calculation
type Item = TopArtistsReportDto["items"][0];
type Accumulator = {
[x: string]: Item;
};
const items: TopArtistsReportDto["items"] = Object.values<Item>(
listens
.flatMap((listen) => listen.track.artists)
.reduce<Accumulator>((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: {
timePreset: TimePreset;
customTimeStart?: string;