Browse Source

Add playlist download (#266)

master
jeffvli 3 years ago
parent
commit
d240b6d5d3
  1. 30
      src/components/playlist/PlaylistView.tsx
  2. 91
      src/hooks/useBrowserDownload.ts

30
src/components/playlist/PlaylistView.tsx

@ -10,6 +10,7 @@ import { useParams, useHistory } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import {
DeleteButton,
DownloadButton,
EditButton,
PlayAppendButton,
PlayAppendNextButton,
@ -26,6 +27,7 @@ import {
formatDate,
formatDateTime,
formatDuration,
getAlbumSize,
getCurrentEntryList,
getRecoveryPath,
getUniqueRandomNumberArr,
@ -52,6 +54,7 @@ import Popup from '../shared/Popup';
import usePlayQueueHandler from '../../hooks/usePlayQueueHandler';
import useFavorite from '../../hooks/useFavorite';
import { useRating } from '../../hooks/useRating';
import { useBrowserDownload } from '../../hooks/useBrowserDownload';
interface PlaylistParams {
id: string;
@ -148,6 +151,7 @@ const PlaylistView = ({ ...rest }) => {
});
const { handlePlayQueueAdd } = usePlayQueueHandler();
const { handleDownload } = useBrowserDownload();
const handleSave = async (recovery: boolean) => {
dispatch(clearSelected());
@ -554,7 +558,31 @@ const PlaylistView = ({ ...rest }) => {
disabled={misc.isProcessingPlaylist.includes(data?.id)}
/>
</Whisper>
<Whisper
trigger="hover"
placement="bottom"
delay={250}
enterable
preventOverflow
speaker={
<Popup>
<ButtonToolbar>
<StyledButton onClick={() => handleDownload(data, 'download', true)}>
{t('Download')}
</StyledButton>
<StyledButton onClick={() => handleDownload(data, 'copy', true)}>
{t('Copy to clipboard')}
</StyledButton>
</ButtonToolbar>
</Popup>
}
>
<DownloadButton
size="lg"
appearance="subtle"
downloadSize={getAlbumSize(data.song)}
/>
</Whisper>
<Whisper
enterable
placement="auto"

91
src/hooks/useBrowserDownload.ts

@ -0,0 +1,91 @@
/* eslint-disable no-await-in-loop */
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { clipboard, shell } from 'electron';
import { apiController } from '../api/controller';
import { notifyToast } from '../components/shared/toast';
import { useAppSelector } from '../redux/hooks';
import { Server } from '../types';
export const useBrowserDownload = () => {
const { t } = useTranslation();
const config = useAppSelector((state) => state.config);
const handleDownload = useCallback(
async (data, type: 'copy' | 'download', playlist?: boolean) => {
const downloadUrls = [];
if (config.serverType === Server.Jellyfin) {
for (let i = 0; i < data.song.length; i += 1) {
downloadUrls.push(
await apiController({
serverType: Server.Jellyfin,
endpoint: 'getDownloadUrl',
args: { id: data.song[i].id },
})
);
}
}
if (config.serverType === Server.Subsonic) {
if (playlist) {
// This matches Navidrome's playlist GUID Id format
if (data.id.includes('-')) {
downloadUrls.push(
await apiController({
serverType: Server.Subsonic,
endpoint: 'getDownloadUrl',
args: { id: data.id },
})
);
} else {
for (let i = 0; i < data.song.length; i += 1) {
downloadUrls.push(
await apiController({
serverType: Server.Subsonic,
endpoint: 'getDownloadUrl',
args: { id: data.song[i].id },
})
);
}
}
}
// If not Navidrome (this assumes Airsonic), then we need to use a song's parent
// to download. This is because Airsonic does not support downloading via album ids
// that are provided by /getAlbum or /getAlbumList2
else if (data.song[0]?.parent) {
downloadUrls.push(
await apiController({
serverType: Server.Subsonic,
endpoint: 'getDownloadUrl',
args: { id: data.song[0].parent },
})
);
} else {
downloadUrls.push(
await apiController({
serverType: Server.Subsonic,
endpoint: 'getDownloadUrl',
args: { id: data.song[0].parent },
})
);
notifyToast('info', t('Download links copied!'));
}
}
if (downloadUrls.length === 0) {
return notifyToast('warning', t('No parent album found'));
}
if (type === 'download') {
return downloadUrls.forEach((url) => shell.openExternal(url));
}
clipboard.writeText(downloadUrls.join('\n'));
return notifyToast('info', t('Download links copied!'));
},
[config.serverType, t]
);
return { handleDownload };
};
Loading…
Cancel
Save