mirror of
https://github.com/BluemediaGER/muse.git
synced 2024-11-23 01:05:30 +01:00
Fix caching (#941)
This commit is contained in:
parent
f54d7caa72
commit
dd140b50fb
|
@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
### Added
|
### Added
|
||||||
- Muse now normalizes playback volume across tracks. Thanks to @UniversalSuperBox for sponsoring this feature!
|
- Muse now normalizes playback volume across tracks. Thanks to @UniversalSuperBox for sponsoring this feature!
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed a bug where tracks wouldn't be cached
|
||||||
|
|
||||||
## [2.2.4] - 2023-04-17
|
## [2.2.4] - 2023-04-17
|
||||||
### Fixed
|
### Fixed
|
||||||
- Bumped ytdl-core
|
- Bumped ytdl-core
|
||||||
|
|
|
@ -18,11 +18,11 @@ export default class FileCacheProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns path to cached file if it exists, otherwise throws an error.
|
* Returns path to cached file if it exists, otherwise returns null.
|
||||||
* Updates the `accessedAt` property of the cached file.
|
* Updates the `accessedAt` property of the cached file.
|
||||||
* @param hash lookup key
|
* @param hash lookup key
|
||||||
*/
|
*/
|
||||||
async getPathFor(hash: string): Promise<string> {
|
async getPathFor(hash: string): Promise<string | null> {
|
||||||
const model = await prisma.fileCache.findUnique({
|
const model = await prisma.fileCache.findUnique({
|
||||||
where: {
|
where: {
|
||||||
hash,
|
hash,
|
||||||
|
@ -30,7 +30,7 @@ export default class FileCacheProvider {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!model) {
|
if (!model) {
|
||||||
throw new Error('File is not cached');
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolvedPath = path.join(this.config.CACHE_DIR, hash);
|
const resolvedPath = path.join(this.config.CACHE_DIR, hash);
|
||||||
|
@ -44,7 +44,7 @@ export default class FileCacheProvider {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
throw new Error('File is not cached');
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
await prisma.fileCache.update({
|
await prisma.fileCache.update({
|
||||||
|
@ -76,19 +76,15 @@ export default class FileCacheProvider {
|
||||||
const stats = await fs.stat(tmpPath);
|
const stats = await fs.stat(tmpPath);
|
||||||
|
|
||||||
if (stats.size !== 0) {
|
if (stats.size !== 0) {
|
||||||
try {
|
await fs.rename(tmpPath, finalPath);
|
||||||
await fs.rename(tmpPath, finalPath);
|
|
||||||
|
|
||||||
await prisma.fileCache.create({
|
await prisma.fileCache.create({
|
||||||
data: {
|
data: {
|
||||||
hash,
|
hash,
|
||||||
accessedAt: new Date(),
|
accessedAt: new Date(),
|
||||||
bytes: stats.size,
|
bytes: stats.size,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (error) {
|
|
||||||
debug('Errored when moving a finished cache file:', error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.evictOldestIfNecessary();
|
await this.evictOldestIfNecessary();
|
||||||
|
|
|
@ -410,26 +410,18 @@ export default class {
|
||||||
|
|
||||||
private async getStream(song: QueuedSong, options: {seek?: number; to?: number} = {}): Promise<Readable> {
|
private async getStream(song: QueuedSong, options: {seek?: number; to?: number} = {}): Promise<Readable> {
|
||||||
if (song.source === MediaSource.HLS) {
|
if (song.source === MediaSource.HLS) {
|
||||||
return this.createReadStream(song.url);
|
return this.createReadStream({url: song.url, cacheKey: song.url});
|
||||||
}
|
}
|
||||||
|
|
||||||
let ffmpegInput = '';
|
let ffmpegInput: string | null;
|
||||||
const ffmpegInputOptions: string[] = [];
|
const ffmpegInputOptions: string[] = [];
|
||||||
let shouldCacheVideo = false;
|
let shouldCacheVideo = false;
|
||||||
|
|
||||||
let format: YTDLVideoFormat | undefined;
|
let format: YTDLVideoFormat | undefined;
|
||||||
|
|
||||||
try {
|
ffmpegInput = await this.fileCache.getPathFor(this.getHashForCache(song.url));
|
||||||
ffmpegInput = await this.fileCache.getPathFor(this.getHashForCache(song.url));
|
|
||||||
|
|
||||||
if (options.seek) {
|
if (!ffmpegInput) {
|
||||||
ffmpegInputOptions.push('-ss', options.seek.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.to) {
|
|
||||||
ffmpegInputOptions.push('-to', options.to.toString());
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// Not yet cached, must download
|
// Not yet cached, must download
|
||||||
const info = await ytdl.getInfo(song.url);
|
const info = await ytdl.getInfo(song.url);
|
||||||
|
|
||||||
|
@ -485,17 +477,19 @@ export default class {
|
||||||
'-reconnect_delay_max',
|
'-reconnect_delay_max',
|
||||||
'5',
|
'5',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (options.seek) {
|
|
||||||
ffmpegInputOptions.push('-ss', options.seek.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.to) {
|
|
||||||
ffmpegInputOptions.push('-to', options.to.toString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.createReadStream(ffmpegInput, {
|
if (options.seek) {
|
||||||
|
ffmpegInputOptions.push('-ss', options.seek.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.to) {
|
||||||
|
ffmpegInputOptions.push('-to', options.to.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.createReadStream({
|
||||||
|
url: ffmpegInput,
|
||||||
|
cacheKey: song.url,
|
||||||
ffmpegInputOptions,
|
ffmpegInputOptions,
|
||||||
cache: shouldCacheVideo,
|
cache: shouldCacheVideo,
|
||||||
volumeAdjustment: format?.loudnessDb ? `${-format.loudnessDb}dB` : undefined,
|
volumeAdjustment: format?.loudnessDb ? `${-format.loudnessDb}dB` : undefined,
|
||||||
|
@ -556,19 +550,19 @@ export default class {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createReadStream(url: string, options: {ffmpegInputOptions?: string[]; cache?: boolean; volumeAdjustment?: string} = {}): Promise<Readable> {
|
private async createReadStream(options: {url: string; cacheKey: string; ffmpegInputOptions?: string[]; cache?: boolean; volumeAdjustment?: string}): Promise<Readable> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const capacitor = new WriteStream();
|
const capacitor = new WriteStream();
|
||||||
|
|
||||||
if (options?.cache) {
|
if (options?.cache) {
|
||||||
const cacheStream = this.fileCache.createWriteStream(this.getHashForCache(url));
|
const cacheStream = this.fileCache.createWriteStream(this.getHashForCache(options.cacheKey));
|
||||||
capacitor.createReadStream().pipe(cacheStream);
|
capacitor.createReadStream().pipe(cacheStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
const returnedStream = capacitor.createReadStream();
|
const returnedStream = capacitor.createReadStream();
|
||||||
let hasReturnedStreamClosed = false;
|
let hasReturnedStreamClosed = false;
|
||||||
|
|
||||||
const stream = ffmpeg(url)
|
const stream = ffmpeg(options.url)
|
||||||
.inputOptions(options?.ffmpegInputOptions ?? ['-re'])
|
.inputOptions(options?.ffmpegInputOptions ?? ['-re'])
|
||||||
.noVideo()
|
.noVideo()
|
||||||
.audioCodec('libopus')
|
.audioCodec('libopus')
|
||||||
|
|
Loading…
Reference in a new issue