新增 Scheme URL 支持

This commit is contained in:
lyswhut
2022-01-07 17:23:48 +08:00
parent 20518cbe2b
commit a393bb02dd
18 changed files with 448 additions and 28 deletions
+10 -1
View File
@@ -162,7 +162,16 @@ export const clearPlayedList = () => {
export const tempPlayList = reactive([])
export const addTempPlayList = (list) => {
tempPlayList.push(...list.map(({ musicInfo, listId }) => ({ musicInfo, listId, isTempPlay: true })))
const topList = []
const bottomList = list.filter(({ isTop, ...musicInfo }) => {
if (isTop) {
topList.push(musicInfo)
return false
}
return true
})
if (topList.length) tempPlayList.unshift(...topList.map(({ musicInfo, listId }) => ({ musicInfo, listId, isTempPlay: true })))
if (bottomList.length) tempPlayList.push(...bottomList.map(({ musicInfo, listId }) => ({ musicInfo, listId, isTempPlay: true })))
}
export const removeTempPlayList = (index) => {
tempPlayList.splice(index, 1)
@@ -0,0 +1,66 @@
import { useAction, useCommit } from '@renderer/utils/vueTools'
import { tempList } from '@renderer/core/share/list'
const getListPlayIndex = (list, index) => {
if (index == null) {
index = 1
} else {
index = parseInt(index)
if (Number.isNaN(index)) {
index = 1
} else {
if (index < 1) index = 1
else if (index > list.length) index = list.length
}
}
return index - 1
}
export default () => {
const getListDetail = useAction('songList', 'getListDetail')
const getListDetailAll = useAction('songList', 'getListDetailAll')
const setTempList = useCommit('player', 'setTempList')
const updateTempList = useCommit('player', 'updateTempList')
const playSongListDetail = async(source, link, playIndex) => {
console.log(source, link, playIndex)
if (link == null) return
let isPlayingList = false
const id = decodeURIComponent(link)
const playListId = `${source}__${decodeURIComponent(link)}`
let list
try {
list = await getListDetail({ source, id, page: 1 })
} catch (err) {
console.log(err)
}
if (list.length > playIndex) {
isPlayingList = true
setTempList({
list,
index: getListPlayIndex(list, playIndex),
id: playListId,
})
}
getListDetailAll({ source, id }).then(list => {
if (isPlayingList) {
if (tempList.meta.id == id) {
updateTempList({
list,
id: playListId,
})
}
} else {
setTempList({
list,
index: getListPlayIndex(list, playIndex),
id: playListId,
})
}
})
}
return (source, link, playIndex) => {
playSongListDetail(source, link, playIndex)
}
}
+4 -1
View File
@@ -9,6 +9,7 @@ import useUpdate from './useUpdate'
import useDataInit from './useDataInit'
import useHandleEnvParams from './useHandleEnvParams'
import useEventListener from './useEventListener'
import useDeepLink from './useDeepLink'
import usePlayer from './usePlayer'
@@ -44,10 +45,11 @@ export default () => {
const initData = useDataInit({
setting,
})
const initDeepLink = useDeepLink()
getEnvParams().then(envParams => {
const envProxy = envParams['proxy-server']
const envProxy = envParams.cmdParams['proxy-server']
if (envProxy && typeof envProxy == 'string') {
const [host, port = ''] = envProxy.split(':')
proxy.envProxy = {
@@ -59,6 +61,7 @@ export default () => {
// 初始化我的列表、下载列表等数据
initData().then(() => {
handleEnvParams(envParams) // 处理传入的启动参数
initDeepLink(envParams)
})
})
}
+260
View File
@@ -0,0 +1,260 @@
import { useCommit, useAction, onBeforeUnmount, useRouter, useI18n } from '@renderer/utils/vueTools'
import { base as eventBaseName } from '@renderer/event/names'
import { getEnvParams, clearEnvParamsDeeplink } from '@renderer/utils/tools'
import { decodeName } from '@renderer/utils'
// import { allList, defaultList, loveList, userLists } from '@renderer/core/share/list'
import { isShowPlayerDetail, setShowPlayerDetail, playMusicInfo } from '@renderer/core/share/player'
import usePlaySonglist from './compositions/usePlaySonglist'
import { dialog } from '@renderer/plugins/Dialog'
const sources = ['kw', 'kg', 'tx', 'wy', 'mg']
const sourceVerify = source => {
if (!sources.includes(source)) throw new Error('Source no match')
}
const qualitys = ['128k', '320k', 'flac', 'flac32bit']
const qualityFilter = (source, types) => {
types = types.filter(({ type }) => qualitys.includes(type)).map(({ type, size, hash }) => {
if (size != null && typeof size != 'string') throw new Error(type + ' size type no match')
if (source == 'kg' && typeof hash != 'string') throw new Error(type + ' hash type no match')
return hash == null ? { type, size } : { type, size, hash }
})
if (!types.length) throw new Error('quality no match')
return types
}
const dataVerify = (rules, data) => {
const newData = {}
for (const rule of rules) {
const val = data[rule.key]
if (rule.required && val == null) throw new Error(rule.key + ' missing')
if (val == null ? false : rule.types && !rule.types.includes(typeof val)) throw new Error(rule.key + ' type no match')
if (val == null ? false : rule.max && String(val).length > rule.max) throw new Error(rule.key + ' max length no match')
if (val == null ? false : rule.min && String(val).length > rule.min) throw new Error(rule.key + ' min length no match')
newData[rule.key] = val
}
return newData
}
export default () => {
// const setList = useCommit('list', 'setList')
// const listAdd = useCommit('list', 'listAdd')
// const listMove = useCommit('list', 'listMove')
// const listAddMultiple = useCommit('list', 'listAddMultiple')
// const listMoveMultiple = useCommit('list', 'listMoveMultiple')
// const listRemove = useCommit('list', 'listRemove')
// const listRemoveMultiple = useCommit('list', 'listRemoveMultiple')
// const listClear = useCommit('list', 'listClear')
// const updateMusicInfo = useCommit('list', 'updateMusicInfo')
// const createUserList = useCommit('list', 'createUserList')
// const removeUserList = useCommit('list', 'removeUserList')
// const setUserListName = useCommit('list', 'setUserListName')
// const setMusicPosition = useCommit('list', 'setMusicPosition')
// // const setSyncListData = useCommit('list', 'setSyncListData')
// const setUserListPosition = useCommit('list', 'setUserListPosition')
const router = useRouter()
const setTempPlayList = useCommit('player', 'setTempPlayList')
const playNext = useAction('player', 'playNext')
const playSongListDetail = usePlaySonglist()
const { t } = useI18n()
const handleOpenSonglist = params => {
if (params.id) {
router.replace({
path: '/songList',
query: {
source: params.source,
id: params.id,
},
})
} else if (params.url) {
router.replace({
path: '/songList',
query: {
source: params.source,
url: params.url,
},
})
}
}
const handleOpenMusic = _musicInfo => {
const musicInfo = {
..._musicInfo,
singer: decodeName(_musicInfo.singer),
name: decodeName(_musicInfo.name),
albumName: decodeName(_musicInfo.albumName),
otherSource: null,
_types: {},
typeUrl: {},
}
for (const type of musicInfo.types) {
musicInfo._types[type.type] = { size: type.size }
}
const isPlaying = !!playMusicInfo.musicInfo
setTempPlayList([{ listId: '__temp__', musicInfo, isTop: true }])
if (isPlaying) playNext()
}
const handleSonglist = (action, songlistInfo) => {
sourceVerify(songlistInfo.source)
switch (action) {
case 'open':
songlistInfo = dataVerify([
{ key: 'source', types: ['string'] },
{ key: 'id', types: ['string', 'number'], max: 64 },
{ key: 'url', types: ['string'], max: 500 },
], songlistInfo)
if (isShowPlayerDetail.value) setShowPlayerDetail(false)
handleOpenSonglist(songlistInfo)
break
case 'play':
songlistInfo = dataVerify([
{ key: 'source', types: ['string'] },
{ key: 'id', types: ['string', 'number'], max: 64 },
{ key: 'url', types: ['string'], max: 500 },
{ key: 'index', types: ['number'], max: 1000000 },
], songlistInfo)
playSongListDetail(songlistInfo.source, songlistInfo.id ?? songlistInfo.url, songlistInfo.index ?? 0)
break
default: throw new Error('Unknown action: ' + action)
}
}
const handleMusic = (action, musicInfo) => {
switch (musicInfo.source) {
case 'kw':
musicInfo = dataVerify([
{ key: 'name', types: ['string'], required: true, max: 200 },
{ key: 'singer', types: ['string'], required: true, max: 200 },
{ key: 'source', types: ['string'], required: true },
{ key: 'songmid', types: ['string', 'number'], max: 64, required: true },
{ key: 'img', types: ['string'], max: 1024 },
{ key: 'albumId', types: ['string', 'number'], max: 64 },
{ key: 'interval', types: ['string'], max: 64 },
{ key: 'albumName', types: ['string'], max: 64 },
{ key: 'types', types: ['object'], required: true },
], musicInfo)
break
case 'kg':
musicInfo = dataVerify([
{ key: 'name', types: ['string'], required: true, max: 200 },
{ key: 'singer', types: ['string'], required: true, max: 200 },
{ key: 'source', types: ['string'], required: true },
{ key: 'songmid', types: ['string', 'number'], max: 64, required: true },
{ key: 'img', types: ['string'], max: 1024 },
{ key: 'albumId', types: ['string', 'number'], max: 64 },
{ key: 'interval', types: ['string'], max: 64 },
{ key: '_interval', types: ['number'], max: 64 },
{ key: 'albumName', types: ['string'], max: 64 },
{ key: 'types', types: ['object'], required: true },
{ key: 'hash', types: ['string'], required: true, max: 64 },
], musicInfo)
break
case 'tx':
musicInfo = dataVerify([
{ key: 'name', types: ['string'], required: true, max: 200 },
{ key: 'singer', types: ['string'], required: true, max: 200 },
{ key: 'source', types: ['string'], required: true },
{ key: 'songmid', types: ['string', 'number'], max: 64, required: true },
{ key: 'img', types: ['string'], max: 1024 },
{ key: 'albumId', types: ['string', 'number'], max: 64 },
{ key: 'interval', types: ['string'], max: 64 },
{ key: 'albumName', types: ['string'], max: 64 },
{ key: 'types', types: ['object'], required: true },
{ key: 'strMediaMid', types: ['string'], required: true, max: 64 },
{ key: 'albumMid', types: ['string'], max: 64 },
], musicInfo)
break
case 'wy':
musicInfo = dataVerify([
{ key: 'name', types: ['string'], required: true, max: 200 },
{ key: 'singer', types: ['string'], required: true, max: 200 },
{ key: 'source', types: ['string'], required: true },
{ key: 'songmid', types: ['string', 'number'], max: 64, required: true },
{ key: 'img', types: ['string'], max: 1024 },
{ key: 'albumId', types: ['string', 'number'], max: 64 },
{ key: 'interval', types: ['string'], max: 64 },
{ key: 'albumName', types: ['string'], max: 64 },
{ key: 'types', types: ['object'], required: true },
], musicInfo)
break
case 'mg':
musicInfo = dataVerify([
{ key: 'name', types: ['string'], required: true, max: 200 },
{ key: 'singer', types: ['string'], required: true, max: 200 },
{ key: 'source', types: ['string'], required: true },
{ key: 'songmid', types: ['string', 'number'], max: 64, required: true },
{ key: 'img', types: ['string'], max: 1024 },
{ key: 'albumId', types: ['string', 'number'], max: 64 },
{ key: 'interval', types: ['string'], max: 64 },
{ key: 'albumName', types: ['string'], max: 64 },
{ key: 'types', types: ['object'], required: true },
{ key: 'copyrightId', types: ['string', 'number'], required: true, max: 64 },
{ key: 'lrcUrl', types: ['string'], max: 64 },
], musicInfo)
break
default: throw new Error('Unknown action: ' + action)
}
musicInfo.types = qualityFilter(musicInfo.source, musicInfo.types)
switch (action) {
case 'play':
handleOpenMusic(musicInfo)
break
default: throw new Error('Unknown action: ' + action)
}
}
const handleLinkAction = link => {
// console.log(link)
const [url, search] = link.split('?')
const [type, action] = url.replace('lxmusic://', '').split('/')
const params = {}
for (const param of search.split('&')) {
const [key, value] = param.split('=')
params[key] = value
}
if (params.data) params.data = JSON.parse(decodeURIComponent(params.data))
console.log(params.data)
switch (type) {
case 'music':
handleMusic(action, params.data)
break
case 'songlist':
handleSonglist(action, params.data)
break
default: throw new Error('Unknown type: ' + type)
}
}
const handleFocus = () => {
getEnvParams().then(envParams => {
if (!envParams.deeplink) return
clearEnvParamsDeeplink()
try {
handleLinkAction(envParams.deeplink)
} catch (err) {
dialog(`${t('deep_link__handle_error_tip', { message: err.message })}`)
}
})
}
window.eventHub.on(eventBaseName.focus, handleFocus)
onBeforeUnmount(() => {
window.eventHub.off(eventBaseName.focus, handleFocus)
})
return envParams => {
if (!envParams.deeplink) return
clearEnvParamsDeeplink()
try {
handleLinkAction(envParams.deeplink)
} catch (err) {
dialog(`${t('deep_link__handle_error_tip', { message: err.message })}`)
}
}
}
+5 -21
View File
@@ -1,7 +1,8 @@
import { useAction, useCommit, useRouter } from '@renderer/utils/vueTools'
import { useCommit, useRouter } from '@renderer/utils/vueTools'
import { parseUrlParams } from '@renderer/utils'
import { defaultList, loveList, userLists } from '@renderer/core/share/list'
import { getList } from '@renderer/core/share/utils'
import usePlaySonglist from './compositions/usePlaySonglist'
const getListPlayIndex = (list, index) => {
if (index == null) {
@@ -32,26 +33,9 @@ const useInitEnvParamSearch = () => {
}
}
const useInitEnvParamPlay = () => {
const getListDetailAll = useAction('songList', 'getListDetailAll')
const setPlayList = useCommit('player', 'setList')
const setTempList = useCommit('player', 'setTempList')
const playSongListDetail = async(source, link, playIndex) => {
if (link == null) return
let list
let id
try {
id = decodeURIComponent(link)
list = await getListDetailAll({ source, id })
} catch (err) {
console.log(err)
}
setTempList({
list,
index: getListPlayIndex(list, playIndex),
id: `${source}__${id}`,
})
}
const playSongListDetail = usePlaySonglist()
return (playStr) => {
if (playStr == null || typeof playStr != 'string') return
@@ -98,7 +82,7 @@ export default () => {
const initEnvParamPlay = useInitEnvParamPlay()
return envParams => {
initEnvParamSearch(envParams.search)
initEnvParamPlay(envParams.play)
initEnvParamSearch(envParams.cmdParams.search)
initEnvParamPlay(envParams.cmdParams.play)
}
}