mirror of
https://github.com/BluemediaGER/muse.git
synced 2024-11-23 09:15:29 +01:00
Reorg third party services & config
This commit is contained in:
parent
79e7e88fab
commit
efcdeb78c8
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
25
src/index.ts
25
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({});
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
36
src/services/config.ts
Normal file
36
src/services/config.ts
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.');
|
||||
|
|
36
src/services/third-party.ts
Normal file
36
src/services/third-party.ts
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
12
src/types.ts
12
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')
|
||||
},
|
||||
|
|
|
@ -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');
|
|
@ -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({
|
||||
|
|
Loading…
Reference in a new issue