Skip to content

Commit

Permalink
Merge pull request #57 from nini22P/dev
Browse files Browse the repository at this point in the history
Improve metadata persistence
  • Loading branch information
nini22P authored Nov 27, 2023
2 parents 92c7415 + 8451db3 commit 3badf08
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 98 deletions.
1 change: 1 addition & 0 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"remove": "Remove",
"delete": "Delete",
"clear": "Clear",
"calculate": "Calculate",
"more": "More",
"about": "About",
"openSourceDependencies": "Open source dependencies"
Expand Down
1 change: 1 addition & 0 deletions src/locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"remove": "移除",
"delete": "删除",
"clear": "清除",
"calculate": "计算",
"more": "更多",
"about": "关于",
"openSourceDependencies": "开源库"
Expand Down
134 changes: 67 additions & 67 deletions src/pages/Player/Player.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Grid from '@mui/material/Unstable_Grid2'
import KeyboardArrowDownOutlinedIcon from '@mui/icons-material/KeyboardArrowDownOutlined'
import useHistoryStore from '../../store/useHistoryStore'
import useUiStore from '../../store/useUiStore'
import useMetaDataListStore from '../../store/useMetaDataListStore'
import useLocalMetaDataStore from '../../store/useLocalMetaDataStore'
import usePlayQueueStore from '../../store/usePlayQueueStore'
import usePlayerStore from '../../store/usePlayerStore'
import { useControlHide } from '../../hooks/useControlHide'
Expand All @@ -21,14 +21,14 @@ import { MetaData } from '../../types/MetaData'
const Player = () => {

const { styles } = useTheme()
const [metaData, setMetaData] = useState<MetaData | null>(null)
const [currentMetaData, setCurrentMetaData] = useState<MetaData | null>(null)

const { getFileData } = useFilesData()

const [type, playQueue, currentIndex, updateCurrentIndex, updatePlayQueue] = usePlayQueueStore(
(state) => [state.type, state.playQueue, state.currentIndex, state.updateCurrentIndex, state.updatePlayQueue])

const [metaDataList, insertMetaDataList] = useMetaDataListStore((state) => [state.metaDataList, state.insertMetaDataList])
const { getLocalMetaData, setLocalMetaData } = useLocalMetaDataStore()

const [playStatu, cover, shuffle, repeat, updatePlayStatu, updateCover, updateCurrentTime, updateDuration, updateRepeat] = usePlayerStore(
(state) => [state.playStatu, state.cover, state.shuffle, state.repeat, state.updatePlayStatu, state.updateCover, state.updateCurrentTime, state.updateDuration, state.updateRepeat])
Expand Down Expand Up @@ -249,82 +249,82 @@ const Player = () => {
// 获取 metadata
useEffect(
() => {
if (type === 'audio' && playQueue !== null) {
const path = playQueue.filter(item => item.index === currentIndex)[0].filePath
console.log('开始获取 metadata', path)
if (metaDataList.some(item => filePathConvert(item.path) === filePathConvert(path))) {
console.log('跳过获取 metadata')
} else {
try {
mm.fetchFromUrl(url).then(metadata => {
if (metadata) {
if (metadata.common.title !== undefined) {
console.log('获取 metadata')
const metaData = {
path: path,
title: metadata.common.title,
artist: metadata.common.artist,
albumArtist: metadata.common.albumartist,
album: metadata.common.album,
year: metadata.common.year,
genre: metadata.common.genre,
cover: metadata.common.picture,
}
insertMetaDataList(metaData)
}
}
})
} catch (error) {
console.log('未能获取 metadata', error)
const getNetMetaData = async (path: string[]) => {
try {
const metadata = await mm.fetchFromUrl(url)
if (metadata && metadata.common.title !== undefined) {
const metaData = {
path: path,
title: metadata.common.title,
artist: metadata.common.artist,
albumArtist: metadata.common.albumartist,
album: metadata.common.album,
year: metadata.common.year,
genre: metadata.common.genre,
cover: metadata.common.picture,
}
return metaData
}
} catch (error) {
console.log('Failed to get net metadata', error)
return null
}
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[url]
)

// 更新当前 metadata
useEffect(
() => {
if (playQueue && playQueue.length !== 0) {
const test = metaDataList
.filter(metaData =>
filePathConvert(metaData.path) === filePathConvert(playQueue.filter(item => item.index === currentIndex)[0].filePath))
console.log('设定当前 metadata', test)
if (test.length !== 0) {
setMetaData({
...test[0],
size: playQueue.filter(item => item.index === currentIndex)[0].fileSize
})
if (test[0].cover?.length) {
const cover = test[0].cover[0].data
if (cover && 'data' in cover && Array.isArray(cover.data)) {
updateCover(URL.createObjectURL(new Blob([new Uint8Array(cover.data as unknown as ArrayBufferLike)], { type: 'image/png' })))
} else if (cover) {
updateCover(URL.createObjectURL(new Blob([new Uint8Array(cover as ArrayBufferLike)], { type: 'image/png' })))
} else {
updateCover('./cover.png')
}
const updateCurrentMetaData = (metaData: MetaData) => {
setCurrentMetaData(metaData)

if (metaData.cover?.length) {
const cover = metaData.cover[0].data
if (cover && 'data' in cover && Array.isArray(cover.data)) {
updateCover(URL.createObjectURL(new Blob([new Uint8Array(cover.data as unknown as ArrayBufferLike)], { type: 'image/png' })))
}
else if (cover) {
updateCover(URL.createObjectURL(new Blob([new Uint8Array(cover as ArrayBufferLike)], { type: 'image/png' })))
}
else
updateCover('./cover.png')
} else {
setMetaData({
title: playQueue.filter(item => item.index === currentIndex)[0].fileName,
artist: '',
path: playQueue.filter(item => item.index === currentIndex)[0].filePath,
})
updateCover('./cover.png')
}
}

const run = async () => {

if (playQueue) {
updateCurrentMetaData(
{
title: playQueue.filter(item => item.index === currentIndex)[0].fileName,
artist: '',
path: playQueue.filter(item => item.index === currentIndex)[0].filePath,
}
)
}

if (playQueue && type === 'audio') {
const path = playQueue.filter(item => item.index === currentIndex)[0].filePath
const localMetaData = await getLocalMetaData(path)

if (localMetaData) {
console.log('Get local metadata')
updateCurrentMetaData(localMetaData)
} else {
const netMetaData = await getNetMetaData(path)
console.log('Get net metadata')
if (netMetaData) {
setLocalMetaData(netMetaData)
updateCurrentMetaData(netMetaData)
}
}
}
}

run()
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[playQueue?.find(item => item.index === currentIndex)?.filePath, metaDataList]
[url]
)

// 向 mediaSession 发送当前播放进度
useMediaSession(player, cover, metaData?.album, metaData?.artist, metaData?.title,
useMediaSession(player, cover, currentMetaData?.album, currentMetaData?.artist, currentMetaData?.title,
handleClickPlay, handleClickPause, handleClickNext, handleClickPrev, handleClickSeekbackward, handleClickSeekforward, SeekTo)

// 检测全屏
Expand Down Expand Up @@ -405,7 +405,7 @@ const Player = () => {
<Container maxWidth={false} disableGutters={true}>
<Box sx={(controlIsShow) ? {} : { display: 'none' }}>
<PlayerControl
metaData={metaData}
metaData={currentMetaData}
handleClickPlay={handleClickPlay}
handleClickPause={handleClickPause}
handleClickNext={handleClickNext}
Expand All @@ -418,7 +418,7 @@ const Player = () => {
/>
</Box>
<Audio
metaData={metaData}
metaData={currentMetaData}
handleClickPlay={handleClickPlay}
handleClickPause={handleClickPause}
handleClickNext={handleClickNext}
Expand Down
40 changes: 29 additions & 11 deletions src/pages/Setting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,40 @@ import useUser from '../hooks/useUser'
import { useTranslation } from 'react-i18next'
import useTheme from '../hooks/useTheme'
import { licenses } from '../data/licenses'
import useMetaDataListStore from '../store/useMetaDataListStore'
import { useEffect, useState } from 'react'
import { useState } from 'react'
import useLocalMetaDataStore from '../store/useLocalMetaDataStore'

const Setting = () => {
const { accounts, logout } = useUser()
const { t } = useTranslation()
const { styles } = useTheme()

const [metaDataList, clearMetaDataList] = useMetaDataListStore((state) => [state.metaDataList, state.clearMetaDataList])
const { getAllLocalMetaData, clearLocalMetaData } = useLocalMetaDataStore()

const [metaDataCachesize, setMetaDataCachesize] = useState<string | null>(null)
const [localMetaDataSize, setLocalMetaDataSize] = useState<string | null>(null)
const [localMetaDataButton, setLocalMetaDataButton] = useState<'calculate' | 'clear'>('calculate')

useEffect(() => {
const size = metaDataList.length ? (Buffer.byteLength(JSON.stringify(metaDataList)) / 1024 / 1024).toFixed(2) : null
setMetaDataCachesize(size)
},[metaDataList])
const getLocalMetaDataSize = async () => {
const allLocalMetaData = await getAllLocalMetaData()
if (allLocalMetaData) {
const blob = new Blob([JSON.stringify(allLocalMetaData)], { type: 'application/json' })
return (blob.size / 1024 / 1024).toFixed(2)
}
}

const handleLocalMetaDataButton = async () => {
if (localMetaDataButton === 'calculate') {
const size = await getLocalMetaDataSize()
setLocalMetaDataSize(size || null)
setLocalMetaDataButton('clear')
}
if (localMetaDataButton === 'clear') {
clearLocalMetaData()
setLocalMetaDataSize(null)
setLocalMetaDataButton('calculate')
}

}

return (
<List>
Expand Down Expand Up @@ -47,13 +65,13 @@ const Setting = () => {
</ListItem>
<ListItem
secondaryAction={
<Button onClick={() => clearMetaDataList()}>
{t('common.clear')}
<Button onClick={() => handleLocalMetaDataButton()}>
{localMetaDataButton === 'calculate' ? t('common.calculate') : t('common.clear')}
</Button>
}
>
<ListItemAvatar></ListItemAvatar>
<ListItemText primary={t('data.localMetaDataCache')} secondary={metaDataCachesize ? `${metaDataCachesize} MB` : null} />
<ListItemText primary={t('data.localMetaDataCache')} secondary={localMetaDataSize ? `${localMetaDataSize} MB` : ' '} />
</ListItem>

<Divider sx={{ mt: 1, mb: 1 }} />
Expand Down
24 changes: 24 additions & 0 deletions src/store/useLocalMetaDataStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { MetaData } from '../types/MetaData'
import { filePathConvert } from '../utils'
import { get, set, clear, entries, createStore } from 'idb-keyval'

const useLocalMetaDataStore = () => {

const metaDataStore = createStore('metadata', 'metadata-store')

const getLocalMetaData = async (filePath: MetaData['path']) => {
const metaData = await get(filePathConvert(filePath), metaDataStore)
return metaData ? JSON.parse(metaData) : null
}

const setLocalMetaData = async (metaData: MetaData) => await set(filePathConvert(metaData.path), JSON.stringify(metaData), metaDataStore)

const getAllLocalMetaData = async () => await entries(metaDataStore)

const clearLocalMetaData = async () => await clear(metaDataStore)

return { getLocalMetaData, setLocalMetaData, getAllLocalMetaData, clearLocalMetaData }

}

export default useLocalMetaDataStore
20 changes: 0 additions & 20 deletions src/store/useMetaDataListStore.ts

This file was deleted.

0 comments on commit 3badf08

Please sign in to comment.