From efcdeb78c8b690bc544dac1ed0be96a6693bcff6 Mon Sep 17 00:00:00 2001 From: Max Isom Date: Sun, 19 Sep 2021 19:50:25 -0400 Subject: Reorg third party services & config --- src/services/config.ts | 36 ++++++++++++++++++++++++++++++++++++ src/services/get-songs.ts | 12 +++++++----- src/services/third-party.ts | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 src/services/config.ts create mode 100644 src/services/third-party.ts (limited to 'src/services') diff --git a/src/services/config.ts b/src/services/config.ts new file mode 100644 index 0000000..80b4a81 --- /dev/null +++ b/src/services/config.ts @@ -0,0 +1,36 @@ +import dotenv from 'dotenv'; +import {injectable} from 'inversify'; +import path from 'path'; +dotenv.config(); + +export const DATA_DIR = path.resolve(process.env.DATA_DIR ? process.env.DATA_DIR : './data'); + +const CONFIG_MAP = { + DISCORD_TOKEN: process.env.DISCORD_TOKEN, + YOUTUBE_API_KEY: process.env.YOUTUBE_API_KEY, + SPOTIFY_CLIENT_ID: process.env.SPOTIFY_CLIENT_ID, + SPOTIFY_CLIENT_SECRET: process.env.SPOTIFY_CLIENT_SECRET, + DATA_DIR, + CACHE_DIR: path.join(DATA_DIR, 'cache') +} as const; + +@injectable() +export default class Config { + readonly DISCORD_TOKEN!: string; + readonly YOUTUBE_API_KEY!: string; + readonly SPOTIFY_CLIENT_ID!: string; + readonly SPOTIFY_CLIENT_SECRET!: string; + readonly DATA_DIR!: string; + readonly CACHE_DIR!: string; + + constructor() { + for (const [key, value] of Object.entries(CONFIG_MAP)) { + if (typeof value === 'undefined') { + console.error(`Missing environment variable for ${key}`); + process.exit(1); + } + + this[key as keyof typeof CONFIG_MAP] = value; + } + } +} diff --git a/src/services/get-songs.ts b/src/services/get-songs.ts index d5ccdef..0a6524f 100644 --- a/src/services/get-songs.ts +++ b/src/services/get-songs.ts @@ -11,6 +11,8 @@ import {Except} from 'type-fest'; import {QueuedSong, QueuedPlaylist} from '../services/player'; import {TYPES} from '../types'; import {cleanUrl} from '../utils/url'; +import ThirdParty from './third-party'; +import Config from './config'; type QueuedSongWithoutChannel = Except; @@ -20,10 +22,10 @@ export default class { private readonly youtubeKey: string; private readonly spotify: Spotify; - constructor(@inject(TYPES.Lib.YouTube) youtube: YouTube, @inject(TYPES.Config.YOUTUBE_API_KEY) youtubeKey: string, @inject(TYPES.Lib.Spotify) spotify: Spotify) { - this.youtube = youtube; - this.youtubeKey = youtubeKey; - this.spotify = spotify; + constructor(@inject(TYPES.ThirdParty) thirdParty: ThirdParty, @inject(TYPES.Config) config: Config) { + this.youtube = thirdParty.youtube; + this.youtubeKey = config.YOUTUBE_API_KEY; + this.spotify = thirdParty.spotify; } async youtubeVideoSearch(query: string): Promise { @@ -214,7 +216,7 @@ export default class { private async spotifyToYouTube(track: SpotifyApi.TrackObjectSimplified, _: QueuedPlaylist | null): Promise { try { const {items} = await this.youtube.videos.search({q: `"${track.name}" "${track.artists[0].name}"`, maxResults: 10}); - const videoResult = items[0]; // Items.find(item => item.type === 'video'); + const videoResult = items[0]; if (!videoResult) { throw new Error('No video found for query.'); diff --git a/src/services/third-party.ts b/src/services/third-party.ts new file mode 100644 index 0000000..00b9269 --- /dev/null +++ b/src/services/third-party.ts @@ -0,0 +1,36 @@ +import {inject, injectable} from 'inversify'; +import SpotifyWebApi from 'spotify-web-api-node'; +import Youtube from 'youtube.ts'; +import {TYPES} from '../types'; +import Config from './config'; + +@injectable() +export default class ThirdParty { + readonly youtube: Youtube; + readonly spotify: SpotifyWebApi; + + private spotifyTokenTimerId?: NodeJS.Timeout; + + constructor(@inject(TYPES.Config) config: Config) { + this.youtube = new Youtube(config.YOUTUBE_API_KEY); + this.spotify = new SpotifyWebApi({ + clientId: config.SPOTIFY_CLIENT_ID, + clientSecret: config.SPOTIFY_CLIENT_SECRET + }); + + void this.refreshSpotifyToken(); + } + + cleanup() { + if (this.spotifyTokenTimerId) { + clearTimeout(this.spotifyTokenTimerId); + } + } + + private async refreshSpotifyToken() { + const auth = await this.spotify.clientCredentialsGrant(); + this.spotify.setAccessToken(auth.body.access_token); + + this.spotifyTokenTimerId = setTimeout(this.refreshSpotifyToken, (auth.body.expires_in / 2) * 1000); + } +} -- cgit v1.2.3