aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Isom <[email protected]>2021-09-19 19:50:25 -0400
committerMax Isom <[email protected]>2021-09-19 19:50:25 -0400
commitefcdeb78c8b690bc544dac1ed0be96a6693bcff6 (patch)
treed4a453f92d928613c2f4209af7475190a093321d
parent79e7e88fab1ce05cf84abeba2e05300a93b4759c (diff)
downloadmuse-efcdeb78c8b690bc544dac1ed0be96a6693bcff6.tar.xz
muse-efcdeb78c8b690bc544dac1ed0be96a6693bcff6.zip
Reorg third party services & config
-rw-r--r--src/bot.ts5
-rw-r--r--src/index.ts25
-rw-r--r--src/inversify.config.ts20
-rw-r--r--src/managers/player.ts5
-rw-r--r--src/services/config.ts36
-rw-r--r--src/services/get-songs.ts12
-rw-r--r--src/services/third-party.ts36
-rw-r--r--src/types.ts12
-rw-r--r--src/utils/config.ts10
-rw-r--r--src/utils/db.ts2
10 files changed, 99 insertions, 64 deletions
diff --git a/src/bot.ts b/src/bot.ts
index 16bdba0..00deb17 100644
--- a/src/bot.ts
+++ b/src/bot.ts
@@ -10,6 +10,7 @@ import handleGuildCreate from './events/guild-create';
import handleVoiceStateUpdate from './events/voice-state-update';
import errorMsg from './utils/error-msg';
import {isUserInVoice} from './utils/channels';
+import Config from './services/config';
@injectable()
export default class {
@@ -18,10 +19,10 @@ export default class {
private readonly token: string;
private readonly commands!: Collection<string, Command>;
- constructor(@inject(TYPES.Client) client: Client, @inject(TYPES.Services.NaturalLanguage) naturalLanguage: NaturalLanguage, @inject(TYPES.Config.DISCORD_TOKEN) token: string) {
+ constructor(@inject(TYPES.Client) client: Client, @inject(TYPES.Services.NaturalLanguage) naturalLanguage: NaturalLanguage, @inject(TYPES.Config) config: Config) {
this.client = client;
this.naturalLanguage = naturalLanguage;
- this.token = token;
+ this.token = config.DISCORD_TOKEN;
this.commands = new Collection();
}
diff --git a/src/index.ts b/src/index.ts
index 2cdd6f1..7b1aac4 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,31 +1,20 @@
-import Spotify from 'spotify-web-api-node';
import makeDir from 'make-dir';
import path from 'path';
import container from './inversify.config';
import {TYPES} from './types';
import Bot from './bot';
import {sequelize} from './utils/db';
+import Config from './services/config';
-let bot = container.get<Bot>(TYPES.Bot);
-const spotify = container.get<Spotify>(TYPES.Lib.Spotify);
-
-const refreshSpotifyToken = async () => {
- const auth = await spotify.clientCredentialsGrant();
-
- spotify.setAccessToken(auth.body.access_token);
-
- return auth.body.expires_in;
-};
+const bot = container.get<Bot>(TYPES.Bot);
(async () => {
- const spotifyRefreshIntervalSeconds = await refreshSpotifyToken();
-
- setInterval(async () => refreshSpotifyToken(), (spotifyRefreshIntervalSeconds / 2) * 1000);
-
// Create data directories if necessary
- await makeDir(container.get(TYPES.Config.DATA_DIR));
- await makeDir(container.get(TYPES.Config.CACHE_DIR));
- await makeDir(path.join(container.get(TYPES.Config.CACHE_DIR), 'tmp'));
+ const config = container.get<Config>(TYPES.Config);
+
+ await makeDir(config.DATA_DIR);
+ await makeDir(config.CACHE_DIR);
+ await makeDir(path.join(config.CACHE_DIR, 'tmp'));
await sequelize.sync({});
diff --git a/src/inversify.config.ts b/src/inversify.config.ts
index f211083..0b60f6f 100644
--- a/src/inversify.config.ts
+++ b/src/inversify.config.ts
@@ -3,16 +3,7 @@ import {Container} from 'inversify';
import {TYPES} from './types';
import Bot from './bot';
import {Client} from 'discord.js';
-import YouTube from 'youtube.ts';
-import Spotify from 'spotify-web-api-node';
-import {
- DISCORD_TOKEN,
- YOUTUBE_API_KEY,
- SPOTIFY_CLIENT_ID,
- SPOTIFY_CLIENT_SECRET,
- DATA_DIR,
- CACHE_DIR
-} from './utils/config';
+import ConfigProvider from './services/config';
// Managers
import PlayerManager from './managers/player';
@@ -36,6 +27,7 @@ import Shortcuts from './commands/shortcuts';
import Shuffle from './commands/shuffle';
import Skip from './commands/skip';
import Unskip from './commands/unskip';
+import ThirdParty from './services/third-party';
let container = new Container();
@@ -70,13 +62,9 @@ container.bind<NaturalLanguage>(TYPES.Services.NaturalLanguage).to(NaturalLangua
});
// Config values
-container.bind<string>(TYPES.Config.DISCORD_TOKEN).toConstantValue(DISCORD_TOKEN);
-container.bind<string>(TYPES.Config.YOUTUBE_API_KEY).toConstantValue(YOUTUBE_API_KEY);
-container.bind<string>(TYPES.Config.DATA_DIR).toConstantValue(DATA_DIR);
-container.bind<string>(TYPES.Config.CACHE_DIR).toConstantValue(CACHE_DIR);
+container.bind(TYPES.Config).toConstantValue(new ConfigProvider());
// Static libraries
-container.bind<YouTube>(TYPES.Lib.YouTube).toConstantValue(new YouTube(YOUTUBE_API_KEY));
-container.bind<Spotify>(TYPES.Lib.Spotify).toConstantValue(new Spotify({clientId: SPOTIFY_CLIENT_ID, clientSecret: SPOTIFY_CLIENT_SECRET}));
+container.bind(TYPES.ThirdParty).to(ThirdParty);
export default container;
diff --git a/src/managers/player.ts b/src/managers/player.ts
index 0afcc71..71fbd55 100644
--- a/src/managers/player.ts
+++ b/src/managers/player.ts
@@ -2,6 +2,7 @@ import {inject, injectable} from 'inversify';
import {TYPES} from '../types';
import Player from '../services/player';
import {Client} from 'discord.js';
+import Config from '../services/config';
@injectable()
export default class {
@@ -9,9 +10,9 @@ export default class {
private readonly cacheDir: string;
private readonly discordClient: Client;
- constructor(@inject(TYPES.Config.CACHE_DIR) cacheDir: string, @inject(TYPES.Client) client: Client) {
+ constructor(@inject(TYPES.Config) config: Config, @inject(TYPES.Client) client: Client) {
this.guildPlayers = new Map();
- this.cacheDir = cacheDir;
+ this.cacheDir = config.CACHE_DIR;
this.discordClient = client;
}
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<QueuedSong, 'addedInChannelId'>;
@@ -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<QueuedSongWithoutChannel|null> {
@@ -214,7 +216,7 @@ export default class {
private async spotifyToYouTube(track: SpotifyApi.TrackObjectSimplified, _: QueuedPlaylist | null): Promise<QueuedSongWithoutChannel | null> {
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);
+ }
+}
diff --git a/src/types.ts b/src/types.ts
index 8202b2f..a64ec49 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -1,17 +1,9 @@
export const TYPES = {
Bot: Symbol('Bot'),
Client: Symbol('Client'),
- Config: {
- DISCORD_TOKEN: Symbol('DISCORD_TOKEN'),
- YOUTUBE_API_KEY: Symbol('YOUTUBE_API_KEY'),
- DATA_DIR: Symbol('DATA_DIR'),
- CACHE_DIR: Symbol('CACHE_DIR')
- },
+ Config: Symbol('Config'),
Command: Symbol('Command'),
- Lib: {
- YouTube: Symbol('YouTube'),
- Spotify: Symbol('Spotify')
- },
+ ThirdParty: Symbol('ThirdParty'),
Managers: {
Player: Symbol('PlayerManager')
},
diff --git a/src/utils/config.ts b/src/utils/config.ts
deleted file mode 100644
index 2e72677..0000000
--- a/src/utils/config.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import dotenv from 'dotenv';
-import path from 'path';
-dotenv.config();
-
-export const DISCORD_TOKEN: string = process.env.DISCORD_TOKEN ? process.env.DISCORD_TOKEN : '';
-export const YOUTUBE_API_KEY: string = process.env.YOUTUBE_API_KEY ? process.env.YOUTUBE_API_KEY : '';
-export const SPOTIFY_CLIENT_ID: string = process.env.SPOTIFY_CLIENT_ID ? process.env.SPOTIFY_CLIENT_ID : '';
-export const SPOTIFY_CLIENT_SECRET: string = process.env.SPOTIFY_CLIENT_SECRET ? process.env.SPOTIFY_CLIENT_SECRET : '';
-export const DATA_DIR = path.resolve(process.env.DATA_DIR ? process.env.DATA_DIR : './data');
-export const CACHE_DIR = path.join(DATA_DIR, 'cache');
diff --git a/src/utils/db.ts b/src/utils/db.ts
index 965de89..01d5e01 100644
--- a/src/utils/db.ts
+++ b/src/utils/db.ts
@@ -1,6 +1,6 @@
import {Sequelize} from 'sequelize-typescript';
import path from 'path';
-import {DATA_DIR} from '../utils/config';
+import {DATA_DIR} from '../services/config';
import {Settings, Shortcut} from '../models';
export const sequelize = new Sequelize({