Misc fixes

This commit is contained in:
Erik 2024-03-27 21:44:03 +02:00
parent 729466a031
commit a8b52e9192
4 changed files with 80 additions and 25 deletions

View File

@ -1,7 +1,17 @@
export type DownloaderResult = { type BaseResult = {
filePath: string, existing?: boolean,
artist: string, artist: string,
song: string, song: string,
album: string, album: string,
ext: string ext: string,
}; }
type ExistingResult = {
existing: true
} & BaseResult
type DownloadedResult = {
filePath: string
} & BaseResult
export type DownloaderResult = ExistingResult | DownloadedResult;

View File

@ -11,6 +11,7 @@ import { MusicIndexEntry, MusicQuery } from '../../../@types/MusicPlayer.js';
import similarity from 'similarity'; import similarity from 'similarity';
import MusicDownloader from './MusicDownloader.js'; import MusicDownloader from './MusicDownloader.js';
import MusicPlayerError from '../../errors/MusicPlayerError.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; 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 class MusicLibrary implements Initialisable
@ -55,7 +56,7 @@ class MusicLibrary implements Initialisable
stop (): void | Promise<void> stop (): void | Promise<void>
{ {
this.saveIndex(); this.#saveIndex();
} }
async download (keyword: string) async download (keyword: string)
@ -69,7 +70,7 @@ class MusicLibrary implements Initialisable
if (!domain) if (!domain)
throw new MusicPlayerError('Invalid link'); throw new MusicPlayerError('Invalid link');
let result = null; let result: DownloaderResult | null = null;
if (domain.includes('spotify.com')) if (domain.includes('spotify.com'))
result = await this.#downloader.download('spotify', keyword); result = await this.#downloader.download('spotify', keyword);
else else
@ -78,6 +79,12 @@ class MusicLibrary implements Initialisable
if (!result) if (!result)
return null; 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); const targetDir = path.join(this.#path, result.artist);
if (!fs.existsSync(targetDir)) if (!fs.existsSync(targetDir))
fs.mkdirSync(targetDir); fs.mkdirSync(targetDir);
@ -173,7 +180,7 @@ class MusicLibrary implements Initialisable
const end = Date.now(); const end = Date.now();
const newFiles = this.#index.size - initialSize; const newFiles = this.#index.size - initialSize;
this.#logger.info(`Library scan took ${end - start} ms, ${this.#index.size} (${newFiles} new) files indexed`); this.#logger.info(`Library scan took ${end - start} ms, ${this.#index.size} (${newFiles} new) files indexed`);
this.saveIndex(); this.#saveIndex();
return newFiles; return newFiles;
} }
@ -183,6 +190,12 @@ class MusicLibrary implements Initialisable
if (this.#index.has(fp) && !force) if (this.#index.has(fp) && !force)
return; return;
if (force)
{
this.#currentId = 0;
this.#index.clear();
}
// Expensive call // Expensive call
const metadata = await parseFile(fp, { skipCovers: true }); const metadata = await parseFile(fp, { skipCovers: true });
const { common } = metadata; const { common } = metadata;
@ -225,7 +238,7 @@ class MusicLibrary implements Initialisable
this.#logger.info(`Index loaded with ${this.#index.size} entries`); this.#logger.info(`Index loaded with ${this.#index.size} entries`);
} }
saveIndex () #saveIndex ()
{ {
this.#logger.info('Saving index to file'); this.#logger.info('Saving index to file');
const cachePath = path.join(process.cwd(), 'cache'); const cachePath = path.join(process.cwd(), 'cache');

View File

@ -38,7 +38,7 @@ class RequestCommand extends Command
if (err instanceof MusicPlayerError) if (err instanceof MusicPlayerError)
return response.edit(`**Error while requesting song:**\n${err.message}`); return response.edit(`**Error while requesting song:**\n${err.message}`);
this.logger.error(err as Error); this.logger.error(err as Error);
return 'Internal error, this has been logged'; return response.edit('Internal error, this has been logged');
} }
} }
} }

View File

@ -5,6 +5,7 @@ import { DownloaderResult } from '../../../../@types/Downloader.js';
import Downloader from '../../../interfaces/Downloader.js'; import Downloader from '../../../interfaces/Downloader.js';
import DiscordClient from '../../DiscordClient.js'; import DiscordClient from '../../DiscordClient.js';
import path from 'node:path'; import path from 'node:path';
import MusicPlayerError from '../../../errors/MusicPlayerError.js';
class SpotifyDownloader extends Downloader class SpotifyDownloader extends Downloader
{ {
@ -25,7 +26,7 @@ class SpotifyDownloader extends Downloader
'--download-real-time true', '--download-real-time true',
'--md-allgenres true', '--md-allgenres true',
'--skip-previously-downloaded true', '--skip-previously-downloaded true',
'--output "{artist} - {song_name} - {album}.{ext}"', '--output "{artist} --- {song_name} --- {album}.{ext}"',
'--print-downloads true', '--print-downloads true',
]; ];
if (process.env.CREDENTIAL_PATH) if (process.env.CREDENTIAL_PATH)
@ -48,6 +49,7 @@ class SpotifyDownloader extends Downloader
}); });
}); });
} }
override download (url: string): Promise<DownloaderResult> override download (url: string): Promise<DownloaderResult>
{ {
if (!this.#available) if (!this.#available)
@ -57,37 +59,39 @@ class SpotifyDownloader extends Downloader
const match = url.match(/spotify\.com\/track\/(\w+)/u); const match = url.match(/spotify\.com\/track\/(\w+)/u);
if (!match) if (!match)
throw new Error('Bad URL'); throw new MusicPlayerError('The bot will only process track URLs');
const [ , id ] = match; const [ , id ] = match;
if (!id) if (!id)
throw new Error('Could not parse ID from url'); throw new Error('Could not parse ID from url');
this.logger.debug('Song ID', id); 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) => return new Promise((resolve, reject) =>
{ {
childProcess.exec(`"${this.#executable}" --root-path "${this.downloadDir}" ${this.#options.join(' ')} ${url}`, (error, stdout, stderr) => childProcess.exec(`"${this.#executable}" --root-path "${this.downloadDir}" ${this.#options.join(' ')} ${url}`, (error, stdout, stderr) =>
{ {
if (error) if (error)
return reject(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' }); const data = this.#getSongData(id);
// console.log(file); if (!data)
const lines = file.split('\n');
const line = lines.find(ln => ln.startsWith(id))?.replace('\r', '');
this.logger.debug('Song entry', line ?? 'undefined');
if (!line)
throw new Error('Failed to find file reference'); throw new Error('Failed to find file reference');
const elements = line.split('\t'); const { fileName, artist, song, album, ext } = data;
const fileName = elements[elements.length - 1];
const filePath = path.join(this.downloadDir!, fileName); const filePath = path.join(this.downloadDir!, fileName);
const [ name, ext ] = fileName.split('.');
const [ artist, song, album ] = name.split('-');
if (stderr && !stderr.includes('charmap')) if (stderr && !stderr.includes('charmap'))
this.logger.debug('stderr', stderr); 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 override get available (): boolean
{ {
return this.#available; return this.#available;