Implement download button
This commit is contained in:
parent
62b01f0d94
commit
6cf89b0d20
3 changed files with 61 additions and 12 deletions
|
|
@ -1,9 +1,10 @@
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
import { getCors, getDownloadUrl, getTracks } from 'utils/search'
|
import { getDownloadUrl, getTracks, triggerDownload } from 'utils/search'
|
||||||
import type { AlbumRow, TrackRow } from 'utils/types'
|
import type { AlbumRow, TrackRow } from 'utils/types'
|
||||||
import Loader from './Loader'
|
import Loader from './Loader'
|
||||||
import ClipboardBtn from './ClipboardBtn'
|
import ClipboardBtn from './ClipboardBtn'
|
||||||
|
import { AlbumDLBtn } from './AlbumDLBtn'
|
||||||
|
|
||||||
export default function Album(props: { album: AlbumRow; lastReqRef: React.RefObject<number> }) {
|
export default function Album(props: { album: AlbumRow; lastReqRef: React.RefObject<number> }) {
|
||||||
const { album, lastReqRef } = props
|
const { album, lastReqRef } = props
|
||||||
|
|
@ -15,7 +16,7 @@ export default function Album(props: { album: AlbumRow; lastReqRef: React.RefObj
|
||||||
<h3>{album.name}</h3>
|
<h3>{album.name}</h3>
|
||||||
<div className='btn-container'>
|
<div className='btn-container'>
|
||||||
<ClipboardBtn albumUrl={album.url} lastReqRef={lastReqRef} />
|
<ClipboardBtn albumUrl={album.url} lastReqRef={lastReqRef} />
|
||||||
<button className='download-btn'>Download album</button>
|
<AlbumDLBtn album={album} lastReqRef={lastReqRef} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<TrackList url={album.url} open={open} lastReqRef={lastReqRef} />
|
<TrackList url={album.url} open={open} lastReqRef={lastReqRef} />
|
||||||
|
|
@ -77,10 +78,10 @@ function TrackDownload(props: { track: TrackRow; lastReqRef: React.RefObject<num
|
||||||
async function fetchUrl() {
|
async function fetchUrl() {
|
||||||
try {
|
try {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
const dlUrl = getCors(await getDownloadUrl(track.url, lastReqRef))
|
const dlUrl = await getDownloadUrl(track.url, lastReqRef)
|
||||||
|
|
||||||
setDownloadUrl(dlUrl)
|
setDownloadUrl(dlUrl)
|
||||||
downloadTrack(dlUrl)
|
await downloadTrack(dlUrl)
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
|
|
@ -92,12 +93,7 @@ function TrackDownload(props: { track: TrackRow; lastReqRef: React.RefObject<num
|
||||||
const dlBlob = await (await fetch(dlUrl)).blob()
|
const dlBlob = await (await fetch(dlUrl)).blob()
|
||||||
const fileURL = window.URL.createObjectURL(dlBlob)
|
const fileURL = window.URL.createObjectURL(dlBlob)
|
||||||
|
|
||||||
const fileLink = document.createElement('a')
|
triggerDownload(fileURL, track.fileName)
|
||||||
fileLink.href = fileURL
|
|
||||||
fileLink.setAttribute('download', track.fileName)
|
|
||||||
document.body.appendChild(fileLink)
|
|
||||||
fileLink.click()
|
|
||||||
fileLink.remove()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
29
src/components/AlbumDLBtn.tsx
Normal file
29
src/components/AlbumDLBtn.tsx
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { useState } from 'react'
|
||||||
|
|
||||||
|
import { downloadAlbum } from 'utils/search'
|
||||||
|
import type { AlbumRow } from 'utils/types'
|
||||||
|
|
||||||
|
import Loader from './Loader'
|
||||||
|
|
||||||
|
export function AlbumDLBtn(props: { album: AlbumRow; lastReqRef: React.RefObject<number> }) {
|
||||||
|
const { album, lastReqRef } = props
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
|
||||||
|
function handleClick(ev: React.MouseEvent<HTMLButtonElement>) {
|
||||||
|
ev.stopPropagation()
|
||||||
|
setLoading(true)
|
||||||
|
downloadAlbum(album, lastReqRef).finally(() => setLoading(false))
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button className='download-btn' onClick={handleClick} disabled={loading}>
|
||||||
|
{loading ? (
|
||||||
|
<div className='loader-container'>
|
||||||
|
<Loader show />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<span> Download album</span>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -102,12 +102,12 @@ export async function getDownloadUrl(trackPageUrl: string, lastReqRef: React.Ref
|
||||||
|
|
||||||
const flacLinks = audioLinks.filter((link) => link.endsWith('.flac'))
|
const flacLinks = audioLinks.filter((link) => link.endsWith('.flac'))
|
||||||
if (flacLinks.length > 0) {
|
if (flacLinks.length > 0) {
|
||||||
return flacLinks[0]
|
return getCors(flacLinks[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
const mp3Links = audioLinks.filter((link) => link.endsWith('.mp3'))
|
const mp3Links = audioLinks.filter((link) => link.endsWith('.mp3'))
|
||||||
if (mp3Links.length > 0) {
|
if (mp3Links.length > 0) {
|
||||||
return mp3Links[0]
|
return getCors(mp3Links[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error('Failed to fetch download url')
|
throw new Error('Failed to fetch download url')
|
||||||
|
|
@ -121,3 +121,27 @@ export async function copyDownloadUrls(albumUrl: string, lastReqRef: React.RefOb
|
||||||
await navigator.clipboard.writeText(filterUrl.join('\n'))
|
await navigator.clipboard.writeText(filterUrl.join('\n'))
|
||||||
toast.success('Copied links to the clipboard!')
|
toast.success('Copied links to the clipboard!')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function triggerDownload(url: string, fileName: string) {
|
||||||
|
const fileLink = document.createElement('a')
|
||||||
|
fileLink.href = url
|
||||||
|
fileLink.setAttribute('download', fileName)
|
||||||
|
document.body.appendChild(fileLink)
|
||||||
|
fileLink.click()
|
||||||
|
fileLink.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function downloadAlbum(album: AlbumRow, lastReqRef: React.RefObject<number>) {
|
||||||
|
const trackList = await getTracks(album.url, lastReqRef)
|
||||||
|
const newZip = new JSZip()
|
||||||
|
|
||||||
|
const downloadList = await Promise.all(
|
||||||
|
trackList.map(async (t) => ({ ...t, blob: await (await fetch(await getDownloadUrl(t.url, lastReqRef))).blob() }))
|
||||||
|
)
|
||||||
|
|
||||||
|
downloadList.forEach((d) => {
|
||||||
|
newZip.file(d.fileName, d.blob)
|
||||||
|
})
|
||||||
|
const zipBlob = window.URL.createObjectURL(await newZip.generateAsync({ type: 'blob' }))
|
||||||
|
triggerDownload(zipBlob, `${album.name}.zip`)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue