mirror of
https://github.com/GiriNeko/YesPlayMusic.git
synced 2025-12-17 13:48:02 +00:00
feat: updates
This commit is contained in:
parent
196a974a64
commit
8f4c3d8e5b
24 changed files with 572 additions and 93 deletions
|
|
@ -1,10 +1,134 @@
|
|||
import { formatDate, formatDuration, resizeImage } from '@/web/utils/common'
|
||||
import {
|
||||
formatDate,
|
||||
formatDuration,
|
||||
isIOS,
|
||||
isSafari,
|
||||
resizeImage,
|
||||
} from '@/web/utils/common'
|
||||
import { css, cx } from '@emotion/css'
|
||||
import Icon from '@/web/components/Icon'
|
||||
import dayjs from 'dayjs'
|
||||
import { useMemo } from 'react'
|
||||
import Image from './Image'
|
||||
import useIsMobile from '@/web/hooks/useIsMobile'
|
||||
import { memo, useEffect, useMemo, useRef } from 'react'
|
||||
import Hls from 'hls.js'
|
||||
import Plyr, { APITypes, PlyrProps, PlyrInstance } from 'plyr-react'
|
||||
import useVideoCover from '@/web/hooks/useVideoCover'
|
||||
import { motion } from 'framer-motion'
|
||||
import { ease } from '@/web/utils/const'
|
||||
import { injectGlobal } from '@emotion/css'
|
||||
|
||||
injectGlobal`
|
||||
.plyr__video-wrapper,
|
||||
.plyr--video {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
`
|
||||
|
||||
const VideoCover = ({ source }: { source?: string }) => {
|
||||
const ref = useRef<APITypes>(null)
|
||||
useEffect(() => {
|
||||
const loadVideo = async () => {
|
||||
if (!source || !Hls.isSupported()) return
|
||||
const video = document.getElementById('plyr') as HTMLVideoElement
|
||||
const hls = new Hls()
|
||||
hls.loadSource(source)
|
||||
hls.attachMedia(video)
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
ref.current!.plyr.media = video
|
||||
|
||||
hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-extra-semi
|
||||
;(ref.current!.plyr as PlyrInstance).play()
|
||||
})
|
||||
}
|
||||
loadVideo()
|
||||
})
|
||||
|
||||
return (
|
||||
<div className='z-10 aspect-square overflow-hidden rounded-24'>
|
||||
<Plyr
|
||||
id='plyr'
|
||||
options={{
|
||||
volume: 0,
|
||||
controls: [],
|
||||
autoplay: true,
|
||||
clickToPlay: false,
|
||||
loop: {
|
||||
active: true,
|
||||
},
|
||||
}}
|
||||
source={{} as PlyrProps['source']}
|
||||
ref={ref}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Cover = memo(
|
||||
({ album, playlist }: { album?: Album; playlist?: Playlist }) => {
|
||||
const isMobile = useIsMobile()
|
||||
const { data: videoCover } = useVideoCover({
|
||||
id: album?.id,
|
||||
name: album?.name,
|
||||
artist: album?.artist.name,
|
||||
})
|
||||
const cover = album?.picUrl || playlist?.coverImgUrl || ''
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='relative z-10 aspect-square w-full overflow-auto rounded-24 '>
|
||||
<Image
|
||||
className='absolute inset-0 h-full w-full'
|
||||
src={resizeImage(cover, 'lg')}
|
||||
alt='Cover'
|
||||
/>
|
||||
|
||||
{videoCover && (
|
||||
<motion.div
|
||||
initial={{ opacity: isIOS ? 1 : 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.6, ease }}
|
||||
className='absolute inset-0 h-full w-full'
|
||||
>
|
||||
{isSafari ? (
|
||||
<video
|
||||
src={videoCover}
|
||||
className='h-full w-full'
|
||||
autoPlay
|
||||
loop
|
||||
muted
|
||||
playsInline
|
||||
></video>
|
||||
) : (
|
||||
<VideoCover source={videoCover} />
|
||||
)}
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Blur bg */}
|
||||
{!isMobile && (
|
||||
<img
|
||||
className={cx(
|
||||
'absolute z-0 object-cover opacity-70',
|
||||
css`
|
||||
top: -400px;
|
||||
left: -370px;
|
||||
width: 1572px;
|
||||
height: 528px;
|
||||
filter: blur(256px) saturate(1.2);
|
||||
`
|
||||
)}
|
||||
src={resizeImage(cover, 'sm')}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
)
|
||||
Cover.displayName = 'Cover'
|
||||
|
||||
const TrackListHeader = ({
|
||||
album,
|
||||
|
|
@ -15,18 +139,16 @@ const TrackListHeader = ({
|
|||
playlist?: Playlist
|
||||
onPlay: () => void
|
||||
}) => {
|
||||
const isMobile = useIsMobile()
|
||||
const albumDuration = useMemo(() => {
|
||||
const duration = album?.songs?.reduce((acc, cur) => acc + cur.dt, 0) || 0
|
||||
return formatDuration(duration, 'en', 'hh[hr] mm[min]')
|
||||
}, [album?.songs])
|
||||
const isMobile = useIsMobile()
|
||||
|
||||
const cover = album?.picUrl || playlist?.coverImgUrl || ''
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx(
|
||||
'mx-2.5 rounded-48 p-8 dark:bg-white/10',
|
||||
'z-10 mx-2.5 rounded-48 p-8 dark:bg-white/10',
|
||||
'lg:mx-0 lg:grid lg:grid-rows-1 lg:gap-10 lg:rounded-none lg:p-0 lg:dark:bg-transparent',
|
||||
!isMobile &&
|
||||
css`
|
||||
|
|
@ -34,29 +156,7 @@ const TrackListHeader = ({
|
|||
`
|
||||
)}
|
||||
>
|
||||
{/* Cover */}
|
||||
<Image
|
||||
className='z-10 aspect-square w-full rounded-24'
|
||||
src={resizeImage(cover, 'lg')}
|
||||
alt='Cover'
|
||||
/>
|
||||
|
||||
{/* Blur bg */}
|
||||
{!isMobile && (
|
||||
<img
|
||||
className={cx(
|
||||
'absolute z-0 object-cover opacity-70',
|
||||
css`
|
||||
top: -400px;
|
||||
left: -370px;
|
||||
width: 1572px;
|
||||
height: 528px;
|
||||
filter: blur(256px) saturate(1.2);
|
||||
`
|
||||
)}
|
||||
src={resizeImage(cover, 'sm')}
|
||||
/>
|
||||
)}
|
||||
<Cover {...{ album, playlist }} />
|
||||
|
||||
<div className='flex flex-col justify-between'>
|
||||
<div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue