* fix: 让从本地缓存获取的音乐可以拖动进度条

* fix: 登陆二维码使用SVG & 二维码支持强调色

* fix: 搜索页面在没有取得结果不再白屏

* fix: 避免私人FM出现相同的歌曲连着出现

* fix: 给部分api添加时间戳参数

因为发现无法获取个性化推荐歌单,添加时间戳后成功获取

* 改用`Date.now()`

* 将个性化推荐放在推荐歌单的前面
This commit is contained in:
memorydream 2022-04-30 02:08:25 +08:00 committed by GitHub
parent 07d7564b1e
commit 4d59401549
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 41 additions and 14 deletions

View file

@ -275,7 +275,12 @@ class Cache {
fs.unlinkSync(path) fs.unlinkSync(path)
return res.status(404).send({ error: 'Audio not found' }) return res.status(404).send({ error: 'Audio not found' })
} }
res.send(audio) res
.status(206)
.setHeader('Accept-Ranges', 'bytes')
.setHeader('Connection', 'keep-alive')
.setHeader('Content-Range', `bytes 0-${audio.byteLength - 1}/${audio.byteLength}`)
.send(audio)
} catch (error) { } catch (error) {
res.status(500).send({ error }) res.status(500).send({ error })
} }

View file

@ -95,6 +95,9 @@ export function fetchPersonalFM(): Promise<FetchPersonalFMResponse> {
return request({ return request({
url: '/personal/fm', url: '/personal/fm',
method: 'get', method: 'get',
params: {
timestamp: Date.now(),
},
}) })
} }
@ -110,6 +113,7 @@ export function fmTrash(id: number): Promise<FMTrashResponse> {
method: 'post', method: 'post',
params: { params: {
id, id,
timestamp: Date.now(),
}, },
}) })
} }

View file

@ -44,6 +44,9 @@ export function fetchDailyRecommendPlaylists(): Promise<FetchDailyRecommendPlayl
return request({ return request({
url: '/recommend/resource', url: '/recommend/resource',
method: 'get', method: 'get',
params: {
timestamp: Date.now(),
},
}) })
} }

View file

@ -46,7 +46,6 @@ export default function Home() {
...(recommendedPlaylists?.result ?? []), ...(recommendedPlaylists?.result ?? []),
] ]
.slice(0, 10) .slice(0, 10)
.reverse()
return ( return (
<div> <div>

View file

@ -17,6 +17,8 @@ enum Method {
Phone = 'phone', Phone = 'phone',
} }
const domParser = new DOMParser()
// Shared components and methods // Shared components and methods
const EmailInput = ({ const EmailInput = ({
email, email,
@ -367,23 +369,34 @@ const LoginWithQRCode = () => {
useEffect(() => { useEffect(() => {
const updateImage = async () => { const updateImage = async () => {
const image = await QRCode.toDataURL(qrCodeUrl, { const svg = await QRCode.toString(qrCodeUrl, {
width: 1024,
margin: 0, margin: 0,
color: { color: {
dark: '#335eea', // TODO: change brand color
light: '#ffffff00', light: '#ffffff00',
}, },
type: 'svg',
}) })
setQrCodeImage(image) const path = domParser
.parseFromString(svg, 'text/xml')
.getElementsByTagName('path')[0]
setQrCodeImage(path?.getAttribute('d') ?? '')
} }
updateImage() updateImage()
}, [qrCodeUrl]) }, [qrCodeUrl])
return ( return (
<div className='flex flex-col items-center justify-center'> <div className='flex flex-col items-center justify-center'>
<div className='rounded-3xl border p-6 dark:border-gray-700'> <div className='rounded-3xl border p-6 text-brand-500 dark:border-gray-700'>
<img src={qrCodeImage} alt='QR Code' className='no-drag' /> <svg
xmlns='http://www.w3.org/2000/svg'
width='270'
height='270'
viewBox='0 0 37 37'
shapeRendering='crispEdges'
>
<path stroke='currentColor' d={qrCodeImage} />
</svg>
</div> </div>
<div className='mt-4 text-sm text-gray-500 dark:text-gray-200'> <div className='mt-4 text-sm text-gray-500 dark:text-gray-200'>
{qrCodeMessage} {qrCodeMessage}

View file

@ -98,7 +98,7 @@ const Search = () => {
const handlePlayTracks = useCallback( const handlePlayTracks = useCallback(
(trackID: number | null = null) => { (trackID: number | null = null) => {
const tracks = searchResult?.result.song.songs const tracks = searchResult?.result?.song?.songs
if (!tracks?.length) { if (!tracks?.length) {
toast('无法播放歌单') toast('无法播放歌单')
return return
@ -108,7 +108,7 @@ const Search = () => {
trackID trackID
) )
}, },
[searchResult?.result.song.songs] [searchResult?.result?.song?.songs]
) )
const navigate = useNavigate() const navigate = useNavigate()
@ -163,21 +163,21 @@ const Search = () => {
{/* Search result */} {/* Search result */}
<div className='grid grid-cols-2 gap-6'> <div className='grid grid-cols-2 gap-6'>
{searchResult?.result.artist.artists && ( {searchResult?.result?.artist?.artists && (
<div> <div>
<div className='mb-2 text-sm font-medium text-gray-400'></div> <div className='mb-2 text-sm font-medium text-gray-400'></div>
<Artists artists={searchResult.result.artist.artists} /> <Artists artists={searchResult.result.artist.artists} />
</div> </div>
)} )}
{searchResult?.result.album.albums && ( {searchResult?.result?.album?.albums && (
<div> <div>
<div className='mb-2 text-sm font-medium text-gray-400'></div> <div className='mb-2 text-sm font-medium text-gray-400'></div>
<Albums albums={searchResult.result.album.albums} /> <Albums albums={searchResult.result.album.albums} />
</div> </div>
)} )}
{searchResult?.result.song.songs && ( {searchResult?.result?.song?.songs && (
<div className='col-span-2'> <div className='col-span-2'>
<div className='mb-2 text-sm font-medium text-gray-400'></div> <div className='mb-2 text-sm font-medium text-gray-400'></div>
<TrackGrid <TrackGrid

View file

@ -285,7 +285,10 @@ export class Player {
private async _loadMoreFMTracks() { private async _loadMoreFMTracks() {
if (this.fmTrackList.length <= 5) { if (this.fmTrackList.length <= 5) {
const response = await fetchPersonalFMWithReactQuery() const response = await fetchPersonalFMWithReactQuery()
this.fmTrackList.push(...(response?.data?.map(r => r.id) ?? [])) const ids = (response?.data?.map(r => r.id) ?? []).filter(
r => !this.fmTrackList.includes(r)
)
this.fmTrackList.push(...ids)
} }
} }