54 lines
1.4 KiB
TypeScript
54 lines
1.4 KiB
TypeScript
|
import fs from 'fs';
|
||
|
import nodePath from 'node:path';
|
||
|
import { finished } from 'stream/promises';
|
||
|
|
||
|
import type { SongMeta, ServerCreds } from './services/jellyfin.ts';
|
||
|
import { getSongFileBuffer } from './services/jellyfin.ts';
|
||
|
|
||
|
const QUEUE: (() => Promise<void>)[] = [];
|
||
|
let downloadCount = 0;
|
||
|
const DOWNLOAD_LIMIT = 10;
|
||
|
|
||
|
export const downloadSongs = async (
|
||
|
creds: ServerCreds,
|
||
|
songs: SongMeta[],
|
||
|
path: string,
|
||
|
) => {
|
||
|
const promises = songs.map(s => getSongDownloader(creds, s, path));
|
||
|
QUEUE.push(...promises);
|
||
|
processQueue();
|
||
|
await Promise.all(promises);
|
||
|
};
|
||
|
|
||
|
const getSongDownloader =
|
||
|
(creds: ServerCreds, song: SongMeta, path: string) => async () => {
|
||
|
const extension = song.Path.split('.').pop();
|
||
|
const filePath = nodePath.join(path, `${song.Id}.${extension}`);
|
||
|
try {
|
||
|
const write = fs.createWriteStream(filePath, {
|
||
|
flags: 'wx',
|
||
|
});
|
||
|
console.log('Downloading: ', filePath);
|
||
|
const download = await getSongFileBuffer(creds, song.Id);
|
||
|
await finished(download.pipe(write));
|
||
|
} catch (err: any) {
|
||
|
if (err?.code !== 'EEXIST') {
|
||
|
throw err;
|
||
|
}
|
||
|
console.log('File already exists, skipping: ', filePath);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const processQueue = () => {
|
||
|
if (downloadCount < DOWNLOAD_LIMIT && QUEUE.length) {
|
||
|
downloadCount++;
|
||
|
const next = QUEUE.shift();
|
||
|
next &&
|
||
|
next().then(() => {
|
||
|
downloadCount--;
|
||
|
processQueue();
|
||
|
});
|
||
|
processQueue();
|
||
|
}
|
||
|
};
|