feat(api): fetch listens from spotify

This commit is contained in:
Julian Tölle 2020-02-02 19:21:58 +01:00
parent f253a66f86
commit f2065d3f1f
54 changed files with 1180 additions and 256 deletions

View file

@ -0,0 +1,67 @@
import { PagingObject } from "./paging-object";
import { SimplifiedTrackObject } from "./simplified-track-object";
import { SimplifiedArtistObject } from "./simplified-artist-object";
// tslint:disable: variable-name
export class AlbumObject {
/**
* A list of the genres used to classify the album.
* For example: "Prog Rock" , "Post-Grunge".
* (If not yet classified, the array is empty.)
*/
genres: string[];
/**
* The artists of the album.
* Each artist object includes a link in href to more detailed information about the artist.
*/
artists: SimplifiedArtistObject[];
/**
* A link to the Web API endpoint providing full details of the album.
*/
href: string;
/**
* The Spotify ID for the album.
*/
id: string;
/**
* The label for the album.
*/
label: string;
/**
* The name of the album.
* In case of an album takedown, the value may be an empty string.
*/
name: string;
/**
* The object type: "album".
*/
type: "album";
/**
* The Spotify URI for the album.
*/
uri: string;
/**
* The date the album was first released, for example `1981`.
* Depending on the precision, it might be shown as `1981-12` or `1981-12-15`.
*/
release_date: string;
/**
* The precision with which `release_date` value is known: `year` , `month` , or `day`.
*/
release_date_precision: "year" | "month" | "day";
/**
* The tracks of the album.
*/
tracks: PagingObject<SimplifiedTrackObject>;
}

View file

@ -0,0 +1,32 @@
export class ArtistObject {
/**
* A list of the genres the artist is associated with.
* For example: "Prog Rock" , "Post-Grunge".
* (If not yet classified, the array is empty.)
*/
genres: string[];
/**
* A link to the Web API endpoint providing full details of the artist.
*/
href: string;
/**
* The Spotify ID for the artist.
*/
id: string;
/**
* The name of the artist.
*/
name: string;
/**
* The object type: "artist".
*/
type: "artist";
/**
* The Spotify URI for the artist.
*/
uri: string;
}

View file

@ -0,0 +1,25 @@
import { ExternalUrlObject } from "./external-url-object";
// tslint:disable variable-name
export class ContextObject {
/**
* External URLs for this context.
*/
external_urls: ExternalUrlObject;
/**
* A link to the Web API endpoint providing full details of the track.
*/
href: string;
/**
* The object type, e.g. "artist", "playlist", "album".
*/
type: string;
/**
* The Spotify URI for the context.
*/
uri: string;
}

View file

@ -0,0 +1,3 @@
export class ExternalUrlObject {
// No documentation for this exists
}

View file

@ -0,0 +1,36 @@
export class PagingObject<T = any> {
/**
* A link to the Web API endpoint returning the full result of the request
*/
href: string;
/**
* The requested data
*/
items: T[];
/**
* The maximum number of items in the response (as set in the query or by default).
*/
limit: number;
/**
* URL to the next page of items. ( null if none)
*/
next: string;
/**
* The offset of the items returned (as set in the query or by default)
*/
offset: number;
/**
* URL to the previous page of items. ( null if none)
*/
previous: string;
/**
* The total number of items available to return.
*/
total: number;
}

View file

@ -0,0 +1,21 @@
import { ContextObject } from "./context-object";
import { SimplifiedTrackObject } from "./simplified-track-object";
// tslint:disable variable-name
export class PlayHistoryObject {
/**
* The context the track was played from.
*/
context: ContextObject;
/**
* The date and time the track was played.
*/
played_at: string;
/**
* The track the user listened to.
*/
track: SimplifiedTrackObject;
}

View file

@ -0,0 +1,41 @@
// tslint:disable: variable-name
export class SimplifiedAlbumObject {
album_type: "album" | "single" | "compilation";
/**
* A link to the Web API endpoint providing full details of the album.
*/
href: string;
/**
* The Spotify ID for the album.
*/
id: string;
/**
* The name of the album. In case of an album takedown, the value may be an empty string.
*/
name: string;
/**
* The object type: "album".
*/
type: "album";
/**
* The Spotify URI for the album.
*/
uri: string;
/**
* The date the album was first released, for example `1981`.
* Depending on the precision, it might be shown as `1981-12` or `1981-12-15`.
*/
release_date: string;
/**
* The precision with which `release_date` value is known: `year` , `month` , or `day`.
*/
release_date_precision: "year" | "month" | "day";
}

View file

@ -0,0 +1,26 @@
export class SimplifiedArtistObject {
/**
* A link to the Web API endpoint providing full details of the artist.
*/
href: string;
/**
* The Spotify ID for the artist.
*/
id: string;
/**
* The name of the artist.
*/
name: string;
/**
* The object type: "artist".
*/
type: "artist";
/**
* The Spotify URI for the artist.
*/
uri: string;
}

View file

@ -0,0 +1,16 @@
export class SimplifiedTrackObject {
/**
* The Spotify ID for the track.
*/
id: string;
/**
* The name of the track.
*/
name: string;
/**
* The Spotify URI for the track.
*/
uri: string;
}

View file

@ -0,0 +1,46 @@
import { SimplifiedAlbumObject } from "./simplified-album-object";
import { SimplifiedArtistObject } from "./simplified-artist-object";
// tslint:disable: variable-name
export class TrackObject {
/**
* The album on which the track appears. The album object includes a link in href to full information about the album.
*/
album: SimplifiedAlbumObject;
/**
* The album on which the track appears. The album object includes a link in href to full information about the album.
*/
artists: SimplifiedArtistObject[];
/**
* The track length in milliseconds.
*/
duration_ms: number;
/**
* A link to the Web API endpoint providing full details of the track.
*/
href: string;
/**
* The Spotify ID for the track.
*/
id: string;
/**
* The name of the track.
*/
name: string;
/**
* The object type: "track".
*/
type: "track";
/**
* The Spotify URI for the track.
*/
uri: string;
}

View file

@ -0,0 +1,16 @@
import { HttpModule, Module } from "@nestjs/common";
import { SpotifyApiService } from "./spotify-api.service";
@Module({
imports: [
HttpModule.registerAsync({
useFactory: () => ({
timeout: 5000,
baseURL: "https://api.spotify.com/"
})
})
],
providers: [SpotifyApiService],
exports: [SpotifyApiService]
})
export class SpotifyApiModule {}

View file

@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { SpotifyApiService } from './spotify-api.service';
describe('SpotifyApiService', () => {
let service: SpotifyApiService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [SpotifyApiService],
}).compile();
service = module.get<SpotifyApiService>(SpotifyApiService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View file

@ -0,0 +1,81 @@
import { HttpService, Injectable } from "@nestjs/common";
import { SpotifyConnection } from "../spotify-connection.entity";
import { AlbumObject } from "./entities/album-object";
import { ArtistObject } from "./entities/artist-object";
import { PagingObject } from "./entities/paging-object";
import { PlayHistoryObject } from "./entities/play-history-object";
import { TrackObject } from "./entities/track-object";
@Injectable()
export class SpotifyApiService {
constructor(private readonly httpService: HttpService) {}
async getRecentlyPlayedTracks({
accessToken,
lastRefreshTime
}: SpotifyConnection): Promise<PlayHistoryObject[]> {
console.log("SpotifyApiService#getRecentlyPlayedTracks");
const parameters: { limit: number; after?: number } = {
limit: 50
};
if (lastRefreshTime) {
parameters.after = lastRefreshTime.getTime();
}
console.log(
"getRecentlyPlayedTracks parameters",
parameters,
lastRefreshTime
);
const history = await this.httpService
.get<PagingObject<PlayHistoryObject>>(`v1/me/player/recently-played`, {
headers: { Authorization: `Bearer ${accessToken}` },
params: parameters
})
.toPromise();
return history.data.items;
}
async getArtist(
accessToken: string,
spotifyID: string
): Promise<ArtistObject> {
console.log("SpotifyApiService#getArtist");
const artist = await this.httpService
.get<ArtistObject>(`v1/artists/${spotifyID}`, {
headers: { Authorization: `Bearer ${accessToken}` }
})
.toPromise();
return artist.data;
}
async getAlbum(accessToken: string, spotifyID: string): Promise<AlbumObject> {
console.log("SpotifyApiService#getAlbum");
const album = await this.httpService
.get<AlbumObject>(`v1/albums/${spotifyID}`, {
headers: { Authorization: `Bearer ${accessToken}` }
})
.toPromise();
console.log("getAlbum", { data: album.data });
return album.data;
}
async getTrack(accessToken: string, spotifyID: string): Promise<TrackObject> {
console.log("SpotifyApiService#getTrack");
const track = await this.httpService
.get<TrackObject>(`v1/tracks/${spotifyID}`, {
headers: { Authorization: `Bearer ${accessToken}` }
})
.toPromise();
return track.data;
}
}