自定义源新增支持`local`源的`musicUrl`、`pic`、`lyric`的获取操作

pull/1773/head
lyswhut 2024-01-30 19:25:01 +08:00
parent 7893814da4
commit 1cd93344dd
7 changed files with 186 additions and 15 deletions

View File

@ -51,4 +51,4 @@
- 新增 `globalThis.lx.currentScriptInfo` 对象,可以从这里获取解析后的脚本头部注释信息及脚本原始内容,具体可用属性看文档说明 - 新增 `globalThis.lx.currentScriptInfo` 对象,可以从这里获取解析后的脚本头部注释信息及脚本原始内容,具体可用属性看文档说明
- `globalThis.lx.version` 属性更新到 `2.0.0` - `globalThis.lx.version` 属性更新到 `2.0.0`
- 自定义源不再使用`script`标签的形式执行,若要获取脚本原始代码字符串需从 `globalThis.lx.currentScriptInfo.rawScript` 属性获取 - 自定义源不再使用`script`标签的形式执行,若要获取脚本原始代码字符串需从 `globalThis.lx.currentScriptInfo.rawScript` 属性获取
- - 自定义源新增支持`local`源的`musicUrl`、`pic`、`lyric`的获取操作详情看自定义源文档说明

View File

@ -1,7 +1,7 @@
declare namespace LX { declare namespace LX {
namespace UserApi { namespace UserApi {
type UserApiSourceInfoType = 'music' type UserApiSourceInfoType = 'music'
type UserApiSourceInfoActions = 'musicUrl' type UserApiSourceInfoActions = 'musicUrl' | 'lyric' | 'pic'
interface UserApiSourceInfo { interface UserApiSourceInfo {
name: string name: string

View File

@ -23,13 +23,14 @@ const eventNames = Object.values(EVENT_NAMES)
const events = { const events = {
request: null, request: null,
} }
const allSources = ['kw', 'kg', 'tx', 'wy', 'mg'] const allSources = ['kw', 'kg', 'tx', 'wy', 'mg', 'local']
const supportQualitys = { const supportQualitys = {
kw: ['128k', '320k', 'flac', 'flac24bit'], kw: ['128k', '320k', 'flac', 'flac24bit'],
kg: ['128k', '320k', 'flac', 'flac24bit'], kg: ['128k', '320k', 'flac', 'flac24bit'],
tx: ['128k', '320k', 'flac', 'flac24bit'], tx: ['128k', '320k', 'flac', 'flac24bit'],
wy: ['128k', '320k', 'flac', 'flac24bit'], wy: ['128k', '320k', 'flac', 'flac24bit'],
mg: ['128k', '320k', 'flac', 'flac24bit'], mg: ['128k', '320k', 'flac', 'flac24bit'],
local: [],
} }
const supportActions = { const supportActions = {
kw: ['musicUrl'], kw: ['musicUrl'],
@ -38,6 +39,18 @@ const supportActions = {
wy: ['musicUrl'], wy: ['musicUrl'],
mg: ['musicUrl'], mg: ['musicUrl'],
xm: ['musicUrl'], xm: ['musicUrl'],
local: ['musicUrl', 'lyric', 'pic'],
}
const verifyLyricInfo = (info) => {
if (typeof info != 'object' || typeof info.lyric != 'string') throw new Error('failed')
if (info.lyric.length > 4096) throw new Error('failed')
return {
lyric: info.lyric,
tlyric: (typeof info.tlyric == 'string' && info.tlyric.length < 4096) ? info.tlyric : null,
mlyric: typeof info.mlyric == 'string' && info.mlyric.length < 4096 ? info.mlyric : null,
lxlyric: typeof info.lxlyric == 'string' && info.lxlyric.length < 4096 ? info.lxlyric : null,
}
} }
const handleRequest = (context, { requestKey, data }) => { const handleRequest = (context, { requestKey, data }) => {
@ -50,6 +63,7 @@ const handleRequest = (context, { requestKey, data }) => {
} }
switch (data.action) { switch (data.action) {
case 'musicUrl': case 'musicUrl':
if (typeof response != 'string' || response.length > 2048 || !/^https?:/.test(response)) throw new Error('failed')
sendData.result = { sendData.result = {
source: data.source, source: data.source,
action: data.action, action: data.action,
@ -59,6 +73,21 @@ const handleRequest = (context, { requestKey, data }) => {
}, },
} }
break break
case 'lyric':
sendData.result = {
source: data.source,
action: data.action,
data: verifyLyricInfo(response),
}
break
case 'pic':
if (typeof response != 'string' || response.length > 2048 || !/^https?:/.test(response)) throw new Error('failed')
sendData.result = {
source: data.source,
action: data.action,
data: response,
}
break
} }
sendMessage(USER_API_RENDERER_EVENT_NAME.response, sendData, true) sendMessage(USER_API_RENDERER_EVENT_NAME.response, sendData, true)
}).catch(err => { }).catch(err => {

View File

@ -79,16 +79,16 @@ export const createUserLists = (position: number, lists: LX.List.UserListInfo[])
* *
* @param lists * @param lists
*/ */
export const setUserLists = (lists: LX.List.UserListInfo[]) => { // const setUserLists = (lists: LX.List.UserListInfo[]) => {
const newUserLists: LX.DBService.UserListInfo[] = lists.map((list, index) => { // const newUserLists: LX.DBService.UserListInfo[] = lists.map((list, index) => {
return { // return {
...list, // ...list,
position: index, // position: index,
} // }
}) // })
inertUserLists(newUserLists, true) // inertUserLists(newUserLists, true)
userLists = newUserLists // userLists = newUserLists
} // }
/** /**
* *

View File

@ -6,8 +6,11 @@ import { getLocalFilePath } from '@renderer/utils/music'
import { import {
buildLyricInfo, buildLyricInfo,
getCachedLyricInfo, getCachedLyricInfo,
getOnlineOtherSourceLyricByLocal,
getOnlineOtherSourceLyricInfo, getOnlineOtherSourceLyricInfo,
getOnlineOtherSourceMusicUrl, getOnlineOtherSourceMusicUrl,
getOnlineOtherSourceMusicUrlByLocal,
getOnlineOtherSourcePicByLocal,
getOnlineOtherSourcePicUrl, getOnlineOtherSourcePicUrl,
getOtherSource, getOtherSource,
} from './utils' } from './utils'
@ -72,6 +75,14 @@ export const getMusicUrl = async({ musicInfo, isRefresh, onToggleSource = () =>
const path = await getLocalFilePath(musicInfo) const path = await getLocalFilePath(musicInfo)
if (path) return encodePath(path) if (path) return encodePath(path)
} }
try {
return await getOnlineOtherSourceMusicUrlByLocal(musicInfo, isRefresh).then(({ url, quality, isFromCache }) => {
if (!isFromCache) void saveMusicUrl(musicInfo, quality, url)
return url
})
} catch {}
onToggleSource() onToggleSource()
const otherSource = await getOtherSourceByLocal(musicInfo) const otherSource = await getOtherSourceByLocal(musicInfo)
if (!otherSource.length) throw new Error('source not found') if (!otherSource.length) throw new Error('source not found')
@ -97,6 +108,12 @@ export const getPicUrl = async({ musicInfo, listId, isRefresh, onToggleSource =
if (musicInfo.meta.picUrl) return musicInfo.meta.picUrl if (musicInfo.meta.picUrl) return musicInfo.meta.picUrl
} }
try {
return await getOnlineOtherSourcePicByLocal(musicInfo).then(({ url }) => {
return url
})
} catch {}
onToggleSource() onToggleSource()
const otherSource = await getOtherSourceByLocal(musicInfo) const otherSource = await getOtherSourceByLocal(musicInfo)
if (!otherSource.length) throw new Error('source not found') if (!otherSource.length) throw new Error('source not found')
@ -126,6 +143,14 @@ export const getLyricInfo = async({ musicInfo, isRefresh, onToggleSource = () =>
if (lyricInfo?.lyric) return buildLyricInfo(lyricInfo) if (lyricInfo?.lyric) return buildLyricInfo(lyricInfo)
} }
try {
// eslint-disable-next-line @typescript-eslint/promise-function-async
return await getOnlineOtherSourceLyricByLocal(musicInfo, isRefresh).then(({ lyricInfo, isFromCache }) => {
if (!isFromCache) void saveLyric(musicInfo, lyricInfo)
return buildLyricInfo(lyricInfo)
})
} catch {}
onToggleSource() onToggleSource()
const otherSource = await getOtherSourceByLocal(musicInfo) const otherSource = await getOtherSourceByLocal(musicInfo)
if (!otherSource.length) throw new Error('source not found') if (!otherSource.length) throw new Error('source not found')

View File

@ -10,6 +10,7 @@ import {
import { appSetting } from '@renderer/store/setting' import { appSetting } from '@renderer/store/setting'
import { langS2T, toNewMusicInfo, toOldMusicInfo } from '@renderer/utils' import { langS2T, toNewMusicInfo, toOldMusicInfo } from '@renderer/utils'
import { requestMsg } from '@renderer/utils/message' import { requestMsg } from '@renderer/utils/message'
import { apis } from '@renderer/utils/musicSdk/api-source'
const getOtherSourcePromises = new Map() const getOtherSourcePromises = new Map()
@ -147,6 +148,68 @@ export const getCachedLyricInfo = async(musicInfo: LX.Music.MusicInfo): Promise<
return null return null
} }
export const getOnlineOtherSourceMusicUrlByLocal = async(musicInfo: LX.Music.MusicInfoLocal, isRefresh: boolean): Promise<{
url: string
quality: LX.Quality
isFromCache: boolean
}> => {
if (!await window.lx.apiInitPromise[0]) throw new Error('source init failed')
const quality = '128k'
const cachedUrl = await getStoreMusicUrl(musicInfo, quality)
if (cachedUrl && !isRefresh) return { url: cachedUrl, quality, isFromCache: true }
let reqPromise
try {
reqPromise = apis('local').getMusicUrl(toOldMusicInfo(musicInfo), null).promise
} catch (err: any) {
reqPromise = Promise.reject(err)
}
return reqPromise.then(({ url }: { url: string }) => {
return { url, quality, isFromCache: false }
})
}
export const getOnlineOtherSourceLyricByLocal = async(musicInfo: LX.Music.MusicInfoLocal, isRefresh: boolean): Promise<{
lyricInfo: LX.Music.LyricInfo
isFromCache: boolean
}> => {
if (!await window.lx.apiInitPromise[0]) throw new Error('source init failed')
const lyricInfo = await getCachedLyricInfo(musicInfo)
if (lyricInfo && !isRefresh) return { lyricInfo, isFromCache: true }
let reqPromise
try {
reqPromise = apis('local').getLyric(toOldMusicInfo(musicInfo)).promise
} catch (err: any) {
reqPromise = Promise.reject(err)
}
return reqPromise.then((lyricInfo: LX.Music.LyricInfo) => {
return { lyricInfo, isFromCache: false }
})
}
export const getOnlineOtherSourcePicByLocal = async(musicInfo: LX.Music.MusicInfoLocal): Promise<{
url: string
}> => {
if (!await window.lx.apiInitPromise[0]) throw new Error('source init failed')
let reqPromise
try {
reqPromise = apis('local').getPic(toOldMusicInfo(musicInfo)).promise
} catch (err: any) {
reqPromise = Promise.reject(err)
}
return reqPromise.then((url: string) => {
return { url }
})
}
export const getPlayQuality = (highQuality: boolean, musicInfo: LX.Music.MusicInfoOnline): LX.Quality => { export const getPlayQuality = (highQuality: boolean, musicInfo: LX.Music.MusicInfoOnline): LX.Quality => {
let type: LX.Quality = '128k' let type: LX.Quality = '128k'
let list = qualityList.value[musicInfo.source] let list = qualityList.value[musicInfo.source]

View File

@ -57,7 +57,6 @@ export default () => {
// eslint-disable-next-line @typescript-eslint/promise-function-async // eslint-disable-next-line @typescript-eslint/promise-function-async
}).then(res => { }).then(res => {
// console.log(res) // console.log(res)
if (!/^https?:/.test(res.data.url)) return Promise.reject(new Error('Get url failed'))
return { type, url: res.data.url } return { type, url: res.data.url }
}).catch(async err => { }).catch(async err => {
console.log(err.message) console.log(err.message)
@ -66,7 +65,62 @@ export default () => {
} }
} }
break break
case 'lyric':
apis[source].getLyric = (songInfo: LX.Music.MusicInfo) => {
const requestKey = `request__${Math.random().toString().substring(2)}`
return {
canceleFn() {
userApiRequestCancel(requestKey)
},
promise: sendUserApiRequest({
requestKey,
data: {
source,
action: 'lyric',
info: {
type,
musicInfo: songInfo,
},
},
// eslint-disable-next-line @typescript-eslint/promise-function-async
}).then(res => {
// console.log(res)
return res.data
}).catch(async err => {
console.log(err.message)
return Promise.reject(err)
}),
}
}
break
case 'pic':
apis[source].getPic = (songInfo: LX.Music.MusicInfo) => {
const requestKey = `request__${Math.random().toString().substring(2)}`
return {
canceleFn() {
userApiRequestCancel(requestKey)
},
promise: sendUserApiRequest({
requestKey,
data: {
source,
action: 'pic',
info: {
type,
musicInfo: songInfo,
},
},
// eslint-disable-next-line @typescript-eslint/promise-function-async
}).then(res => {
// console.log(res)
return res.data
}).catch(async err => {
console.log(err.message)
return Promise.reject(err)
}),
}
}
break
default: default:
break break
} }