nukeop/nuclear

View on GitHub
packages/core/src/rest/Bandcamp.ts

Summary

Maintainability
A
0 mins
Test Coverage
/* eslint-disable @typescript-eslint/no-explicit-any */
import cheerio from 'cheerio';
import * as bandcamp from 'bandcamp-scraper';
import _ from 'lodash';

type BandcampAlbumInfo = {
  artist: string;
  title: string;
  imageUrl: string;
  url: string;
  tracks: Array<BandcampTrack>;
}

type BandcampArtistInfo = {
  name: string;
  location: string;
  coverImage: string;
  description: string;
  albums: {
    url: string;
    coverImage?: string;
    title: string;
  }[];
  shows: {
    date: string;
    venue: string;
    venueUrl: string;
    location: string;
  }[];
  bandLinks: {
    name: string;
    url: string;
  }[];
}

type BandcampTrack = {
  name: string;
  url: string;
  duration: string;
}

export type BandcampSearchResult = {
  type: 'artist' | 'album' | 'track';
  name: string;
  url: string;
  imageUrl: string;
  tags: string[];

  genre?: string;
  location?: string;
  releaseDate?: string;
  artist?: string;
}

/* eslint-disable @typescript-eslint/ban-types */
const promisify = <T>(func: Function, arg: any): Promise<T> => new Promise((resolve, reject) => {
  func.apply(null, [arg, (err, result) => {
    if (err) {
      reject(err);
    } else {
      resolve(result);
    }
  }]);
});

export const search = (query: string, page = 1): Promise<BandcampSearchResult[]> => promisify(bandcamp.search, { query, page });
export const getAlbumInfo = (albumUrl: string): Promise<BandcampAlbumInfo> => promisify(bandcamp.getAlbumInfo, albumUrl);
export const getArtistInfo = (artistUrl: string): Promise<BandcampArtistInfo> => promisify(bandcamp.getArtistInfo, artistUrl);

export const getTrackData = async (trackUrl: string) => {
  const page = await fetch(trackUrl);
  const html = await page.text();

  const $ = cheerio.load(html);
  const scriptWithRaw = $('script[data-tralbum]');

  let meta;
  if (scriptWithRaw.length > 0) {
    meta = scriptWithRaw.data('tralbum');
  }

  const imageUrl = $('#tralbumArt').first().find('a').first().attr('href');
  const duration = _.get(meta, 'trackinfo[0].duration', 0);
  const stream = _.get(meta, 'trackinfo[0].file[\'mp3-128\']');
  const name = _.get(meta, 'trackinfo[0].title');

  return {
    url: trackUrl,
    imageUrl,
    name,
    stream,
    duration,
    tags: [],
    type: 'track' as const
  };
};