nukeop/nuclear

View on GitHub
packages/core/src/plugins/meta/bandcamp.ts

Summary

Maintainability
B
4 hrs
Test Coverage
import _ from 'lodash';
import MetaProvider from '../metaProvider';
import {
  SearchResultsArtist,
  SearchResultsAlbum,
  SearchResultsTrack,
  ArtistDetails,
  AlbumDetails,
  AlbumType,
  SearchResultsSource
} from '../plugins.types';
import { Bandcamp, LastFmApi } from '../../rest';
import { Track } from '../..';
import { LastFmArtistInfo, LastfmTopTracks } from '../../rest/Lastfm.types';

class BandcampMetaProvider extends MetaProvider {
  lastfm: LastFmApi;
  constructor() {
    super();
    this.name = 'Bandcamp Meta Provider';
    this.sourceName = 'Bandcamp Meta Provider';
    this.description = 'Metadata provider that uses Bandcamp as a source.';
    this.searchName = 'Bandcamp';
    this.image = null;
    this.lastfm = new LastFmApi(process.env.LAST_FM_API_KEY, process.env.LASTFM_API_SECRET);
  }

  searchForArtists(query: string): Promise<Array<SearchResultsArtist>> {
    return Bandcamp.search(query)
      .then(results => _(results).filter({ type: 'artist' }).map(artist => ({
        id: btoa(artist.url),
        coverImage: artist.imageUrl,
        thumb: artist.imageUrl,
        name: artist.name,
        resourceUrl: artist.url,
        source: SearchResultsSource.Bandcamp
      }))
        .value());
  }

  searchForReleases(query: string): Promise<Array<SearchResultsAlbum>> {
    return Bandcamp.search(query)
      .then(results => _(results).filter({ type: 'album' }).map(album => ({
        id: btoa(album.url),
        coverImage: album.imageUrl,
        thumb: album.imageUrl,
        title: album.name,
        artist: album.artist,
        resourceUrl: album.url,
        source: SearchResultsSource.Bandcamp
      }))
        .value());
  }

  async searchForTracks(query: string): Promise<SearchResultsTrack[]> {
    const results = await Bandcamp.search(query);
    return results
      .filter(result => result.type === 'track')
      .map(result => ({
        id: btoa(result.url),
        title: result.name,
        artist: result.artist,
        source: SearchResultsSource.Bandcamp
      }));
  }

  searchAll(): Promise<{
    artists: Array<SearchResultsArtist>;
    releases: Array<SearchResultsAlbum>;
    tracks: Array<SearchResultsTrack>;
  }> {
    throw new Error('Method not implemented.');
  }

  async fetchArtistAlbums(artistId: string): Promise<SearchResultsAlbum[]> {
    const artistInfo = await Bandcamp.getArtistInfo(atob(artistId));

    return artistInfo.albums.map(album => ({
      id: btoa(album.url),
      coverImage: album.coverImage,
      thumb: album.coverImage,
      title: album.title,
      artist: artistInfo.name,
      resourceUrl: album.url,
      type: 'master',
      source: SearchResultsSource.Bandcamp
    }));
  }

  async fetchArtistDetailsByName(artistName: string): Promise<ArtistDetails> {
    const artists = await this.searchForArtists(artistName);
    return this.fetchArtistDetails(artists[0]?.id); 
  }

  async fetchAlbumDetailsByName(albumName: string): Promise<AlbumDetails> {
    const albums = await this.searchForReleases(albumName);
    return this.fetchAlbumDetails(albums[0]?.id, 'master', albums[0]?.resourceUrl);
  }

  async fetchArtistDetails(artistId: string): Promise<ArtistDetails> {
    const bandcampArtistDetails = await Bandcamp.getArtistInfo(atob(artistId));
    const lastFmInfo: LastFmArtistInfo = (await (await this.lastfm.getArtistInfo(bandcampArtistDetails.name)).json()).artist;
    const lastFmTopTracks: LastfmTopTracks = (await (await this.lastfm.getArtistTopTracks(bandcampArtistDetails.name)).json()).toptracks;

    return ({
      id: artistId,
      name: bandcampArtistDetails.name,
      description: bandcampArtistDetails.description,
      coverImage: bandcampArtistDetails.coverImage,
      onTour: bandcampArtistDetails.shows.length > 0,
      similar: _.map(lastFmInfo?.similar.artist, artist => ({
        name: artist.name,
        thumbnail: _.get(_.find(artist.image, { size: 'large' }), '#text')
      })),
      topTracks: _.map(lastFmTopTracks?.track, (track) => ({
        name: track.name,
        title: track.name,
        thumb: bandcampArtistDetails.coverImage,
        playcount: track.playcount,
        listeners: track.listeners,
        artist: track.artist
      })),
      source: SearchResultsSource.Bandcamp
    });
  }

  fetchAlbumDetails(
    albumId: string,
    albumType: 'master' | 'release',
    resourceUrl: string
  ): Promise<AlbumDetails> {
    return Bandcamp.getAlbumInfo(resourceUrl).then(album => ({
      id: albumId,
      artist: album.artist,
      title: album.title,
      thumb: album.imageUrl,
      coverImage: album.imageUrl,
      type: albumType as AlbumType,
      tracklist: album.tracks.map((track, index) => new Track({
        artist: album.artist,
        title: track.name,
        duration: track.duration,
        thumbnail: album.imageUrl,
        position: index + 1
      }))
    }));
  }
}

export default BandcampMetaProvider;