feat: updates

This commit is contained in:
qier222 2022-03-27 15:21:48 +08:00
parent 74dcb36e67
commit b5f681631e
No known key found for this signature in database
GPG key ID: 9C85007ED905F14D
15 changed files with 320 additions and 99 deletions

View file

@ -99,7 +99,6 @@ export function getCache(
if (!isIDsValid) return
const idsQuery = ids.map(id => `id = ${id}`).join(' OR ')
console.log(idsQuery)
const tracksRaw = realm
.objects(ModelNames.TRACK)
.filtered(`(${idsQuery})`)

View file

@ -1,4 +1,5 @@
import './preload' // must be first
import './sentry'
import {
BrowserWindow,
BrowserWindowConstructorOptions,

14
packages/main/sentry.ts Normal file
View file

@ -0,0 +1,14 @@
import * as Sentry from '@sentry/node'
import * as Tracing from '@sentry/tracing'
import pkg from '../../package.json'
Sentry.init({
dsn: 'https://2aaaa67f1c3d4d6baefafa5d58fcf340@o436528.ingest.sentry.io/6274637',
release: `yesplaymusic@${pkg.version}`,
environment: import.meta.env.MODE,
// Set tracesSampleRate to 1.0 to capture 100%
// of transactions for performance monitoring.
// We recommend adjusting this value in production
tracesSampleRate: 1.0,
})

View file

@ -1,2 +1,4 @@
<svg viewBox="0 0 576 512" xmlns="http://www.w3.org/2000/svg"><path d="M301.2 34.85c-11.5-5.19-25.02-3.122-34.44 5.253L131.8 160H48c-26.51 0-48 21.49-48 47.1v95.1c0 26.51 21.49 47.1 48 47.1h83.84l134.9 119.9c5.98 5.31 13.58 8.09 21.26 8.09 4.43 0 8.97-.94 13.17-2.85 11.5-5.16 18.82-16.56 18.82-29.16V63.99c-.89-12.59-7.29-24-18.79-29.15ZM513.9 255.1l47.03-47.03c9.375-9.375 9.375-24.56 0-33.94 -9.375-9.38-24.56-9.375-33.94 0L480 222.1 432.1 175c-9.375-9.375-24.56-9.375-33.94 0 -9.38 9.375-9.375 24.56 0 33.94l47.03 47.03L398.16 303c-9.375 9.375-9.375 24.56 0 33.94 9.37 9.37 24.56 9.38 33.94 0L480 289.9l47.03 47.03c9.37 9.37 24.56 9.38 33.94 0 9.375-9.375 9.375-24.56 0-33.94L513.9 255.1Z"/></svg>
<svg viewBox="0 0 448 512" xmlns="http://www.w3.org/2000/svg"><path d="M412.6 181.9c-10.28-8.35-25.41-6.875-33.75 3.4 -8.41 10.25-6.91 25.37 3.375 33.78 11.27 9.31 17.77 22.714 17.77 36.91 0 14.19-6.5 27.62-17.81 36.87 -10.28 8.4-11.78 23.53-3.375 33.78 4.71 5.81 11.62 8.81 18.56 8.81 5.34 0 10.75-1.79 15.19-5.41 22.53-18.46 35.435-45.36 35.435-74.06 0-28.7-12.9-55.6-35.4-74.1ZM301.2 34.84c-11.5-5.19-25.01-3.12-34.43 5.25L131.8 159.99H48c-26.51 0-48 21.49-48 47.1v95.1c0 26.51 21.49 47.1 48 47.1h83.84l134.9 119.9c5.96 8 13.56 10.8 21.26 10.8 4.43 0 8.95-.94 13.16-2.84 11.54-5.17 18.84-16.57 18.84-29.17v-384c0-12.59-7.3-24.9-18.8-29.16Z"/></svg>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.4966 5.50774L10.4966 5.50774L6.61626 9H4.5C3.67157 9 3 9.67157 3 10.5V13.5C3 14.3284 3.67157 15 4.5 15H6.61626L10.4966 18.4923C11.4618 19.361 13 18.676 13 17.3773V6.62268C13 5.32402 11.4618 4.63899 10.4966 5.50774Z" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<path d="M16.5 9C16.5 9 17.5 10 17.5 12C17.5 14 16.5 15 16.5 15" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 525 B

Before After
Before After

View file

@ -1,4 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 10.5V13.5C3 14.3284 3.67157 15 4.5 15H6.61626L10.4966 18.4923C11.4618 19.361 13 18.676 13 17.3773V6.62268C13 5.32402 11.4618 4.63899 10.4966 5.50774L10.4966 5.50774L6.61626 9L4.5 9C3.67157 9 3 9.67157 3 10.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<path d="M16.5 9.5C16.5 9.5 17.5 10.5 17.5 12C17.5 13.5 16.5 14.5 16.5 14.5M19 7C19 7 21 9 21 12C21 15 19 17 19 17" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<path d="M10.4966 5.50774L10.4966 5.50774L6.61626 9H4.5C3.67157 9 3 9.67157 3 10.5V13.5C3 14.3284 3.67157 15 4.5 15H6.61626L10.4966 18.4923C11.4618 19.361 13 18.676 13 17.3773V6.62268C13 5.32402 11.4618 4.63899 10.4966 5.50774Z" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
<path d="M16.5 9C16.5 9 17.5 10 17.5 12C17.5 14 16.5 15 16.5 15M19 6.5C19 6.5 21 9 21 12C21 15 19 17.5 19 17.5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 569 B

After

Width:  |  Height:  |  Size: 572 B

Before After
Before After

View file

@ -1,3 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 6L18 18M18 6L6 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 354 B

After

Width:  |  Height:  |  Size: 222 B

Before After
Before After

View file

@ -29,17 +29,38 @@ const NavigationButtons = () => {
}
const SearchBox = () => {
const [keyword, setKeyword] = useState('')
const navigate = useNavigate()
const toSearch = (e: React.KeyboardEvent) => {
if (!keyword) return
if (e.key === 'Enter') {
navigate(`/search/${keyword}`)
}
}
return (
<div className='app-region-no-drag group flex w-[16rem] cursor-text items-center rounded-full bg-gray-500 bg-opacity-5 px-3 transition duration-300 hover:bg-opacity-10 dark:bg-gray-300 dark:bg-opacity-5'>
<div className='app-region-no-drag group flex w-[16rem] cursor-text items-center rounded-full bg-gray-500 bg-opacity-5 pl-2.5 pr-2 transition duration-300 hover:bg-opacity-10 dark:bg-gray-300 dark:bg-opacity-5'>
<SvgIcon
className='mr-2 h-5 w-5 text-gray-500 transition duration-300 group-hover:text-gray-600 dark:text-gray-400 dark:group-hover:text-gray-200'
className='mr-2 h-4 w-4 text-gray-500 transition duration-300 group-hover:text-gray-600 dark:text-gray-400 dark:group-hover:text-gray-200'
name='search'
/>
<input
value={keyword}
onChange={e => setKeyword(e.target.value)}
onKeyDown={toSearch}
type='text'
className='w-full bg-transparent placeholder:text-gray-500 dark:text-white dark:placeholder:text-gray-400'
className='flex-grow bg-transparent placeholder:text-gray-500 dark:text-white dark:placeholder:text-gray-400'
placeholder='搜索'
/>
<div
onClick={() => setKeyword('')}
className={classNames(
'cursor-default rounded-full p-1 transition after:bg-gray-300 hover:bg-white/20 dark:text-white/50',
!keyword && 'hidden'
)}
>
<SvgIcon className='h-4 w-4' name='x' />
</div>
</div>
)
}
@ -55,9 +76,12 @@ const Settings = () => {
const Avatar = () => {
const navigate = useNavigate()
const { data: user } = useUser()
const avatarUrl = resizeImage(user?.profile?.avatarUrl ?? '', 'sm')
return (
<img
src={user?.profile?.avatarUrl}
src={avatarUrl}
onClick={() => navigate('/login')}
className='app-region-no-drag h-9 w-9 rounded-full bg-gray-100 dark:bg-gray-700'
/>

View file

@ -1,9 +1,24 @@
import { StrictMode } from 'react'
import { render } from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import * as Sentry from '@sentry/react'
import { BrowserTracing } from '@sentry/tracing'
import 'virtual:svg-icons-register'
import '@/styles/global.scss'
import App from './App'
import pkg from '../../../package.json'
Sentry.init({
dsn: 'https://7cc7879b42ba4bed9f66fb6752558475@o436528.ingest.sentry.io/6274630',
integrations: [new BrowserTracing()],
release: `yesplaymusic@${pkg.version}`,
environment: import.meta.env.MODE,
// Set tracesSampleRate to 1.0 to capture 100%
// of transactions for performance monitoring.
// We recommend adjusting this value in production
tracesSampleRate: 1.0,
})
render(
<StrictMode>

View file

@ -96,7 +96,7 @@ const Header = ({
/>
</Fragment>
)}
<div className='absolute top-0 h-full w-full bg-gradient-to-b from-white/75 to-white dark:from-black/50 dark:to-[#1d1d1d]'></div>
<div className='absolute top-0 h-full w-full bg-gradient-to-b from-white/80 to-white dark:from-black/50 dark:to-[#1d1d1d]'></div>
</div>
<div className='grid grid-cols-[17rem_auto] items-center gap-9'>
@ -145,7 +145,7 @@ const Header = ({
<Skeleton className='mt-5 w-64 text-lg'>PLACEHOLDER</Skeleton>
) : (
<div className='mt-5 text-lg font-medium text-gray-800 dark:text-gray-300'>
Album by{' '}
Album ·{' '}
<NavLink
to={`/artist/${album?.artist.id}`}
className='cursor-default font-semibold hover:underline'
@ -161,8 +161,14 @@ const Header = ({
PLACEHOLDER
</Skeleton>
) : (
<div className='text-sm text-gray-500 dark:text-gray-400'>
{dayjs(album?.publishTime || 0).year()} · {album?.size} ,{' '}
<div className='flex items-center text-sm text-gray-500 dark:text-gray-400'>
{album?.mark === 1056768 && (
<SvgIcon
name='explicit'
className='mt-px mr-1 h-4 w-4 text-gray-400 dark:text-gray-500'
/>
)}
{dayjs(album?.publishTime || 0).year()} · {album?.size} ·{' '}
{albumDuration}
</div>
)}

View file

@ -11,22 +11,113 @@ import Skeleton from '@/components/Skeleton'
import { Fragment } from 'react'
import useTracks from '@/hooks/useTracks'
const Header = ({ artist }: { artist: Artist | undefined }) => {
const coverImage = resizeImage(artist?.img1v1Url || '', 'md')
return (
<Fragment>
<div className='absolute top-0 left-0 z-0 h-[24rem] w-full overflow-hidden'>
{coverImage && (
<Fragment>
<img
src={coverImage}
className='absolute -top-full w-full blur-[100px]'
/>
<img
src={coverImage}
className='absolute -top-full w-full blur-[100px]'
/>
</Fragment>
)}
<div className='absolute top-0 h-full w-full bg-gradient-to-b from-white/80 to-white dark:from-black/50 dark:to-[#1d1d1d]'></div>
</div>
<div className='relative mt-6 overflow-hidden rounded-2xl bg-gray-500/10 dark:bg-gray-800/20'>
<div className='flex h-[26rem] justify-center overflow-hidden'>
<img src={coverImage} className='aspect-square brightness-[.5]' />
<img src={coverImage} className='aspect-square brightness-[.5]' />
<img src={coverImage} />
<img src={coverImage} className='aspect-square brightness-[.5]' />
<img src={coverImage} className='aspect-square brightness-[.5]' />
</div>
<div className='absolute right-0 left-0 top-[18rem] h-32 bg-gradient-to-t from-[#222]/60 to-transparent'></div>
<div className='absolute top-0 right-0 left-0 flex h-[26rem] items-end justify-between p-8 pb-6'>
<div className='text-7xl font-bold text-white'>{artist?.name}</div>
</div>
</div>
</Fragment>
)
}
const LatestRelease = ({
album,
isLoading,
}: {
album: Album | undefined
isLoading: boolean
}) => {
return (
<div>
<div className='mb-6 text-2xl font-semibold text-gray-800 dark:text-white'>
</div>
<div className='flex-grow rounded-xl '>
{isLoading ? (
<Skeleton className='aspect-square w-full rounded-xl'></Skeleton>
) : (
<Cover imageUrl={album?.picUrl ?? ''} />
)}
<div className='line-clamp-2 line-clamp-1 mt-2 font-semibold leading-tight decoration-gray-600 decoration-2 hover:underline dark:text-white dark:decoration-gray-200'>
{album?.name}
</div>
<div className='text-[12px] text-gray-500 dark:text-gray-400'>
{album?.type} · {dayjs(album?.publishTime || 0).year()}
</div>
</div>
</div>
)
}
const PopularTracks = ({
tracks,
isLoadingArtist,
}: {
tracks: Track[] | undefined
isLoadingArtist: boolean
}) => {
const { data: tracksWithExtraInfo } = useTracks({
ids: tracks?.slice(0, 10)?.map(t => t.id) ?? [],
})
return (
<div>
<div className='mb-6 text-2xl font-semibold text-gray-800 dark:text-white'>
</div>
<div className='rounded-xl'>
<TracksGrid
tracks={tracksWithExtraInfo?.songs ?? tracks?.slice(0, 10) ?? []}
isSkeleton={isLoadingArtist}
/>
</div>
</div>
)
}
const Artist = () => {
const params = useParams()
const { data: artist, isLoading } = useArtist({
const { data: artist, isLoading: isLoadingArtist } = useArtist({
id: Number(params.id) || 0,
})
const { data: albumsRaw, isLoading: isLoadingAlbum } = useArtistAlbums({
const { data: albumsRaw, isLoading: isLoadingAlbums } = useArtistAlbums({
id: Number(params.id) || 0,
limit: 1000,
})
const { data: tracks, isLoading: isLoadingTracks } = useTracks({
ids: artist?.hotSongs?.slice(0, 10)?.map(t => t.id) ?? [],
})
const albums = useMemo(() => {
if (!albumsRaw?.hotAlbums) return []
const albums: Album[] = []
@ -66,84 +157,20 @@ const Artist = () => {
)
}, [albums, albumsRaw?.hotAlbums])
const latestAlbum = useMemo(() => {
if (!albumsRaw || !albumsRaw.hotAlbums) return
return albumsRaw.hotAlbums[0]
}, [albumsRaw])
const coverImage = resizeImage(artist?.artist?.img1v1Url || '', 'md')
return (
<div>
<div className='absolute top-0 left-0 z-0 h-[24rem] w-full overflow-hidden'>
{coverImage && (
<Fragment>
<img
src={coverImage}
className='absolute -top-full w-full blur-[100px]'
/>
<img
src={coverImage}
className='absolute -top-full w-full blur-[100px]'
/>
</Fragment>
)}
<div className='absolute top-0 h-full w-full bg-gradient-to-b from-white/[.84] to-white dark:from-black/[.6] dark:to-[#1d1d1d]'></div>
</div>
{/* Header */}
<div className='relative mt-6 overflow-hidden rounded-2xl'>
<div className='flex h-[26rem] justify-center overflow-hidden'>
<img src={coverImage} className='aspect-square brightness-[.5]' />
<img src={coverImage} className='aspect-square brightness-[.5]' />
<img src={coverImage} />
<img src={coverImage} className='aspect-square brightness-[.5]' />
<img src={coverImage} className='aspect-square brightness-[.5]' />
</div>
<div className='absolute right-0 left-0 top-[18rem] h-32 bg-gradient-to-t from-[#222]/60 to-transparent'></div>
<div className='absolute top-0 right-0 left-0 flex h-[26rem] items-end justify-between p-8 pb-6'>
<div className='text-7xl font-bold text-white'>
{artist?.artist.name}
</div>
</div>
</div>
<Header artist={artist?.artist} />
<div className='mt-12 grid h-[20rem] grid-cols-[14rem,_auto] grid-rows-1 gap-16 px-2'>
{/* Latest release */}
<div>
<div className='mb-6 text-2xl font-semibold text-gray-800 dark:text-white'>
</div>
<div className='flex-grow rounded-xl '>
{isLoadingAlbum ? (
<Skeleton className='aspect-square w-full rounded-xl'></Skeleton>
) : (
<Cover imageUrl={latestAlbum?.picUrl ?? ''} />
)}
<div className='line-clamp-2 line-clamp-1 mt-2 font-semibold leading-tight decoration-gray-600 decoration-2 hover:underline dark:text-white dark:decoration-gray-200'>
{latestAlbum?.name}
</div>
<div className='text-[12px] text-gray-500 dark:text-gray-400'>
{latestAlbum?.type} ·{' '}
{dayjs(latestAlbum?.publishTime || 0).year()}
</div>
</div>
</div>
<LatestRelease
album={albumsRaw?.hotAlbums[0]}
isLoading={isLoadingAlbums}
/>
{/* Popular tracks */}
<div>
<div className='mb-6 text-2xl font-semibold text-gray-800 dark:text-white'>
</div>
<div className='rounded-xl'>
<TracksGrid
tracks={tracks?.songs ?? artist?.hotSongs.slice(0, 10) ?? []}
isSkeleton={isLoading}
/>
</div>
</div>
<PopularTracks
tracks={artist?.hotSongs}
isLoadingArtist={isLoadingArtist}
/>
</div>
{/* Albums */}

View file

@ -30,7 +30,7 @@ const Header = memo(
<div className='absolute top-0 left-0 z-0 h-[24rem] w-full overflow-hidden'>
<img src={coverUrl} className='absolute top-0 w-full blur-[100px]' />
<img src={coverUrl} className='absolute top-0 w-full blur-[100px]' />
<div className='absolute top-0 h-full w-full bg-gradient-to-b from-white/[.84] to-white dark:from-black/[.5] dark:to-[#1d1d1d]'></div>
<div className='absolute top-0 h-full w-full bg-gradient-to-b from-white/80 to-white dark:from-black/50 dark:to-[#1d1d1d]'></div>
</div>
<div className='grid grid-cols-[17rem_auto] items-center gap-9'>
@ -73,7 +73,7 @@ const Header = memo(
{/* <!-- Playlist creator --> */}
{!isLoading && (
<div className='mt-5 text-lg font-medium text-gray-800 dark:text-gray-300'>
Playlist by <span>{playlist?.creator?.nickname}</span>
· <span>{playlist?.creator?.nickname}</span>
</div>
)}
{isLoading && (

View file

@ -0,0 +1,5 @@
const Search = () => {
return <div></div>
}
export default Search

View file

@ -0,0 +1,3 @@
import Search from './Search'
export default Search