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 = {
|
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;
|
@ -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');
|
||||||
|
@ -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');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user