79 lines
2.4 KiB
TypeScript
79 lines
2.4 KiB
TypeScript
|
import { Command } from 'commander';
|
||
|
import { checkbox } from '@inquirer/prompts';
|
||
|
import { getAllPlaylists, getSonglistForPlaylist } from './lib/services/jellyfin.ts';
|
||
|
import type { Playlist, SongMeta } from './lib/services/jellyfin.ts';
|
||
|
import { downloadSongs } from './lib/fileDownloader.ts';
|
||
|
import { writeM3UFile } from './lib/m3uWriter.ts';
|
||
|
import 'dotenv/config';
|
||
|
|
||
|
const program = new Command();
|
||
|
|
||
|
const { JF_SERVER, JF_USERNAME, JF_PASSWORD, DEST_FOLDER, PLAYLISTS } = process.env;
|
||
|
|
||
|
program
|
||
|
.name('')
|
||
|
.description('CLI to download Jellyfin Playlists to mp3 player m3u format.')
|
||
|
.version('0.0.1');
|
||
|
|
||
|
program
|
||
|
.command('wizard')
|
||
|
.description('Start the CLI wizzard to select playlists and start the downloads')
|
||
|
.action(async (str, options) => {
|
||
|
console.log('Fetching playlist information...');
|
||
|
if (!JF_SERVER) {
|
||
|
console.error('Missing required env var JF_SERVER. Exiting...');
|
||
|
process.exit();
|
||
|
}
|
||
|
if (!JF_USERNAME) {
|
||
|
console.error('Missing required env var JF_USERNAME. Exiting...');
|
||
|
process.exit();
|
||
|
}
|
||
|
if (!JF_PASSWORD) {
|
||
|
console.error('Missing required env var JF_PASSWORD. Exiting...');
|
||
|
process.exit();
|
||
|
}
|
||
|
if (!DEST_FOLDER) {
|
||
|
console.error('Missing required env var DEST_FOLDER. Exiting...');
|
||
|
process.exit();
|
||
|
}
|
||
|
const creds = {
|
||
|
server: JF_SERVER,
|
||
|
user: JF_USERNAME,
|
||
|
password: JF_PASSWORD,
|
||
|
};
|
||
|
const playlistMetas = await getAllPlaylists(creds);
|
||
|
const answer = await checkbox({
|
||
|
message: 'Which playlists would you like to download?',
|
||
|
choices: playlistMetas.map((pl: Playlist) => ({ name: pl.Name, value: pl.Id })),
|
||
|
});
|
||
|
const playlists = await Promise.all(
|
||
|
answer.map(async id => {
|
||
|
const pl = {
|
||
|
...playlistMetas.find(p => p.Id === id),
|
||
|
};
|
||
|
pl.songlist = await getSonglistForPlaylist(creds, id);
|
||
|
return pl;
|
||
|
}),
|
||
|
);
|
||
|
|
||
|
const allSongs = playlists.reduce(
|
||
|
(songs, pl) => {
|
||
|
console.log('PLAYLIST: ', pl);
|
||
|
pl.songlist?.forEach(song => {
|
||
|
songs[song.Id] = song;
|
||
|
});
|
||
|
return songs;
|
||
|
},
|
||
|
{} as Record<string, SongMeta>,
|
||
|
);
|
||
|
await downloadSongs(creds, Object.values(allSongs), DEST_FOLDER);
|
||
|
|
||
|
await Promise.all(
|
||
|
playlists.map((pl, i) =>
|
||
|
writeM3UFile(DEST_FOLDER, pl.Name || `playlist${i}`, pl.songlist as SongMeta[]),
|
||
|
),
|
||
|
);
|
||
|
});
|
||
|
|
||
|
await program.parseAsync(process.argv);
|