Misc fixes
This commit is contained in:
parent
729466a031
commit
a8b52e9192
18
@types/Downloader.d.ts
vendored
18
@types/Downloader.d.ts
vendored
@ -1,7 +1,17 @@
|
||||
export type DownloaderResult = {
|
||||
filePath: string,
|
||||
type BaseResult = {
|
||||
existing?: boolean,
|
||||
artist: string,
|
||||
song: string,
|
||||
album: string,
|
||||
ext: string
|
||||
};
|
||||
ext: string,
|
||||
}
|
||||
|
||||
type ExistingResult = {
|
||||
existing: true
|
||||
} & BaseResult
|
||||
|
||||
type DownloadedResult = {
|
||||
filePath: string
|
||||
} & BaseResult
|
||||
|
||||
export type DownloaderResult = ExistingResult | DownloadedResult;
|
@ -11,6 +11,7 @@ import { MusicIndexEntry, MusicQuery } from '../../../@types/MusicPlayer.js';
|
||||
import similarity from 'similarity';
|
||||
import MusicDownloader from './MusicDownloader.js';
|
||||
import MusicPlayerError from '../../errors/MusicPlayerError.js';
|
||||
import { DownloaderResult } from '../../../@types/Downloader.js';
|
||||
|
||||
const linkReg = /(https?:\/\/(www\.)?)?(?<domain>([a-z0-9-]{1,63}\.)?([a-z0-9-]{1,63})(\.[a-z0-9-]{2,63})(\.[a-z0-9-]{2,63})?)(\/[^()\s]*)?/iu;
|
||||
class MusicLibrary implements Initialisable
|
||||
@ -55,7 +56,7 @@ class MusicLibrary implements Initialisable
|
||||
|
||||
stop (): void | Promise<void>
|
||||
{
|
||||
this.saveIndex();
|
||||
this.#saveIndex();
|
||||
}
|
||||
|
||||
async download (keyword: string)
|
||||
@ -69,7 +70,7 @@ class MusicLibrary implements Initialisable
|
||||
if (!domain)
|
||||
throw new MusicPlayerError('Invalid link');
|
||||
|
||||
let result = null;
|
||||
let result: DownloaderResult | null = null;
|
||||
if (domain.includes('spotify.com'))
|
||||
result = await this.#downloader.download('spotify', keyword);
|
||||
else
|
||||
@ -78,6 +79,12 @@ class MusicLibrary implements Initialisable
|
||||
if (!result)
|
||||
return null;
|
||||
|
||||
if (result.existing)
|
||||
{
|
||||
const entry = this.#index.find((e) => e.title === result!.song);
|
||||
return entry;
|
||||
}
|
||||
|
||||
const targetDir = path.join(this.#path, result.artist);
|
||||
if (!fs.existsSync(targetDir))
|
||||
fs.mkdirSync(targetDir);
|
||||
@ -173,7 +180,7 @@ class MusicLibrary implements Initialisable
|
||||
const end = Date.now();
|
||||
const newFiles = this.#index.size - initialSize;
|
||||
this.#logger.info(`Library scan took ${end - start} ms, ${this.#index.size} (${newFiles} new) files indexed`);
|
||||
this.saveIndex();
|
||||
this.#saveIndex();
|
||||
return newFiles;
|
||||
}
|
||||
|
||||
@ -183,6 +190,12 @@ class MusicLibrary implements Initialisable
|
||||
if (this.#index.has(fp) && !force)
|
||||
return;
|
||||
|
||||
if (force)
|
||||
{
|
||||
this.#currentId = 0;
|
||||
this.#index.clear();
|
||||
}
|
||||
|
||||
// Expensive call
|
||||
const metadata = await parseFile(fp, { skipCovers: true });
|
||||
const { common } = metadata;
|
||||
@ -225,7 +238,7 @@ class MusicLibrary implements Initialisable
|
||||
this.#logger.info(`Index loaded with ${this.#index.size} entries`);
|
||||
}
|
||||
|
||||
saveIndex ()
|
||||
#saveIndex ()
|
||||
{
|
||||
this.#logger.info('Saving index to file');
|
||||
const cachePath = path.join(process.cwd(), 'cache');
|
||||
|
@ -38,7 +38,7 @@ class RequestCommand extends Command
|
||||
if (err instanceof MusicPlayerError)
|
||||
return response.edit(`**Error while requesting song:**\n${err.message}`);
|
||||
this.logger.error(err as Error);
|
||||
return 'Internal error, this has been logged';
|
||||
return response.edit('Internal error, this has been logged');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import { DownloaderResult } from '../../../../@types/Downloader.js';
|
||||
import Downloader from '../../../interfaces/Downloader.js';
|
||||
import DiscordClient from '../../DiscordClient.js';
|
||||
import path from 'node:path';
|
||||
import MusicPlayerError from '../../../errors/MusicPlayerError.js';
|
||||
|
||||
class SpotifyDownloader extends Downloader
|
||||
{
|
||||
@ -25,7 +26,7 @@ class SpotifyDownloader extends Downloader
|
||||
'--download-real-time true',
|
||||
'--md-allgenres true',
|
||||
'--skip-previously-downloaded true',
|
||||
'--output "{artist} - {song_name} - {album}.{ext}"',
|
||||
'--output "{artist} --- {song_name} --- {album}.{ext}"',
|
||||
'--print-downloads true',
|
||||
];
|
||||
if (process.env.CREDENTIAL_PATH)
|
||||
@ -48,6 +49,7 @@ class SpotifyDownloader extends Downloader
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
override download (url: string): Promise<DownloaderResult>
|
||||
{
|
||||
if (!this.#available)
|
||||
@ -57,37 +59,39 @@ class SpotifyDownloader extends Downloader
|
||||
|
||||
const match = url.match(/spotify\.com\/track\/(\w+)/u);
|
||||
if (!match)
|
||||
throw new Error('Bad URL');
|
||||
throw new MusicPlayerError('The bot will only process track URLs');
|
||||
|
||||
const [ , id ] = match;
|
||||
if (!id)
|
||||
throw new Error('Could not parse ID from url');
|
||||
this.logger.debug('Song ID', id);
|
||||
|
||||
const existing = this.#getSongData(id);
|
||||
if (existing)
|
||||
{
|
||||
const { artist, song, ext, album } = existing;
|
||||
return Promise.resolve({
|
||||
existing: true,
|
||||
artist,
|
||||
song,
|
||||
ext,
|
||||
album
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
{
|
||||
childProcess.exec(`"${this.#executable}" --root-path "${this.downloadDir}" ${this.#options.join(' ')} ${url}`, (error, stdout, stderr) =>
|
||||
{
|
||||
if (error)
|
||||
return reject(error);
|
||||
const songIdsPath = path.join(this.downloadDir!, '.song_ids');
|
||||
this.logger.debug('.song_ids path', songIdsPath);
|
||||
if (!fs.existsSync(songIdsPath))
|
||||
return reject(new Error('Something went wrong with the download'));
|
||||
|
||||
const file = fs.readFileSync(songIdsPath, { encoding: 'utf-8' });
|
||||
// console.log(file);
|
||||
const lines = file.split('\n');
|
||||
const line = lines.find(ln => ln.startsWith(id))?.replace('\r', '');
|
||||
this.logger.debug('Song entry', line ?? 'undefined');
|
||||
if (!line)
|
||||
const data = this.#getSongData(id);
|
||||
if (!data)
|
||||
throw new Error('Failed to find file reference');
|
||||
|
||||
const elements = line.split('\t');
|
||||
const fileName = elements[elements.length - 1];
|
||||
const { fileName, artist, song, album, ext } = data;
|
||||
const filePath = path.join(this.downloadDir!, fileName);
|
||||
const [ name, ext ] = fileName.split('.');
|
||||
const [ artist, song, album ] = name.split('-');
|
||||
|
||||
if (stderr && !stderr.includes('charmap'))
|
||||
this.logger.debug('stderr', stderr);
|
||||
@ -105,6 +109,34 @@ class SpotifyDownloader extends Downloader
|
||||
});
|
||||
}
|
||||
|
||||
#getSongData (id: string)
|
||||
{
|
||||
const songIdsPath = path.join(this.downloadDir!, '.song_ids');
|
||||
if (!fs.existsSync(songIdsPath))
|
||||
throw new Error('Something went wrong with the download');
|
||||
|
||||
const file = fs.readFileSync(songIdsPath, { encoding: 'utf-8' });
|
||||
const lines = file.split('\n');
|
||||
const line = lines.find(ln => ln.startsWith(id))?.replace('\r', '');
|
||||
|
||||
this.logger.debug('Song entry', line ?? 'undefined');
|
||||
if (!line)
|
||||
return null;
|
||||
|
||||
const elements = line.split('\t');
|
||||
const fileName = elements[elements.length - 1];
|
||||
const [ name, ext ] = fileName.split('.');
|
||||
const [ artist, song, album ] = name.split('---');
|
||||
|
||||
return {
|
||||
fileName,
|
||||
artist,
|
||||
song,
|
||||
album,
|
||||
ext
|
||||
};
|
||||
}
|
||||
|
||||
override get available (): boolean
|
||||
{
|
||||
return this.#available;
|
||||
|
Loading…
Reference in New Issue
Block a user