新增 Scheme URL 支持
parent
20518cbe2b
commit
a393bb02dd
16
README.md
16
README.md
|
@ -93,6 +93,22 @@ npm run pack:linux
|
|||
- `name`:要播放的本地列表歌单名字,source为`myList`时必传,举例:`./lx-music-desktop -play="type=songList&source=myList&name=默认列表"`
|
||||
- `index`:从列表的哪个位置开始播放,选传,若不传默认播放第一首歌曲,举例:`./lx-music-desktop -play="type=songList&source=myList&name=默认列表&index=2"`
|
||||
|
||||
### Scheme URL支持
|
||||
|
||||
从v1.17.0起支持 Scheme URL,可以使用此功能从浏览器等场景下调用LX Music,我们开发了一个[油猴脚本](https://github.com/lyswhut/lx-music-script#readme)<br>
|
||||
以下是目前可用的Scheme URL调用方式:
|
||||
|
||||
- URL统一以`lxmusic://`开头
|
||||
- 此技术目前只支持 Windows、Mac系统
|
||||
- URL传参以经过URL编码的JSON数据传参,例:`lxmusic://music/play?data=xxxx`,其中`xxxx`为经过URL编码后的JSON数据
|
||||
- 若无特别说明,源的可用值为:`kw/kg/tx/wy/mg`
|
||||
- 若无特别说明,音质的可用值为:`128k/320k/flac/flac32bit`
|
||||
|
||||
| 描述 | URL | 参数
|
||||
| --- | --- | ---
|
||||
| 打开歌单 | `songlist/open` | `source<String>`(源,必须)<br>`id<String|Number>`(歌单ID,可选)<br>`url<String>`(歌单URL,可选)其中ID与URL必需传一个
|
||||
| 播放歌单 | `songlist/play` | `source<String>`(源,必须)<br>`id<String|Number>`(歌单ID,可选)<br>`url<String>`(歌单URL,可选)其中`id`与`url`必需传一个<br>`index<Number>`(播放第几首歌,可选,从0开始)
|
||||
| 播放歌曲 | `music/play` | `name<String>`(歌曲名,必传)<br>`singer<String>`(艺术家名,必传)<br>`source<String>`(源,必传)<br>`songmid<String|Number>`(歌曲ID,必传)<br>`img<String>`(歌曲图片链接,选传)<br>`albumId<String|Number>`(歌曲专辑ID,选传)<br>`interval<String>`(格式化后的歌曲时长,选传,例:`03:55`)<br>`albumName<String>`(歌曲专辑名称,选传)<br>`types<Sbject>`(歌曲可用音质数组,必传,数组格式:`[{"type": "<音质>", size: "<格式化后的文件大小,选传>", hash: "<kg源必传>"}]`,例:`[{"type": "128k", size: "3.56M"}, {"type": "320k", size: null}]`)<br><br>以下为平台特定参数:<br>`hash<String>`(歌曲hash,kg源必传)<br>`strMediaMid<String>`(歌曲strMediaMid,tx源必传)<br>`albumMid<String>`(歌曲albumMid,tx源专用,选传)<br>`copyrightId<String>`(歌曲copyrightId,mg源必传)<br>`lrcUrl<String>`(歌曲lrcUrl,mg源专用,选传)
|
||||
|
||||
### 常见问题
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "lx-music-desktop",
|
||||
"version": "1.17.0-beta",
|
||||
"version": "1.17.0-beta2",
|
||||
"description": "一个免费的音乐查找助手",
|
||||
"main": "./dist/electron/main.js",
|
||||
"productName": "lx-music-desktop",
|
||||
|
@ -77,6 +77,12 @@
|
|||
},
|
||||
"build": {
|
||||
"appId": "cn.toside.music.desktop",
|
||||
"protocols": {
|
||||
"name": "lx-music-protocol",
|
||||
"schemes": [
|
||||
"lxmusic"
|
||||
]
|
||||
},
|
||||
"directories": {
|
||||
"buildResources": "./resources",
|
||||
"output": "./build"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
### 新增
|
||||
|
||||
- 新增 Scheme URL 支持,同时发布lx-music-script项目配合使用(一个油猴脚本,可以在浏览器中的官方平台网页直接调用LX Music),Scheme URL的调用说明看Readme.md文档的Scheme URL支持部分
|
||||
- 新增启动参数`-proxy-server`与`-proxy-bypass-list`,详细介绍看Readme.md文档的启动参数部分
|
||||
|
||||
### 优化
|
||||
|
|
|
@ -8,6 +8,7 @@ const names = {
|
|||
clear_cache: 'clear_cache',
|
||||
get_cache_size: 'get_cache_size',
|
||||
get_env_params: 'get_env_params',
|
||||
clear_env_params_deeplink: 'clear_env_params_deeplink',
|
||||
wait: 'wait',
|
||||
wait_cancel: 'wait_cancel',
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"date_format_hour": "{num} hours ago",
|
||||
"date_format_minute": "{num} minutes ago",
|
||||
"date_format_second": "{num} seconds ago",
|
||||
"deep_link__handle_error_tip": "Call failed: {message}",
|
||||
"default": "Default",
|
||||
"default_list": "Recently Played",
|
||||
"desktop_lyric__back": "Back",
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"date_format_hour": "{num}小时前",
|
||||
"date_format_minute": "{num}分钟前",
|
||||
"date_format_second": "{num}秒前",
|
||||
"deep_link__handle_error_tip": "调用失败:{message}",
|
||||
"default": "默认",
|
||||
"default_list": "试听列表",
|
||||
"desktop_lyric__back": "返回",
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"date_format_hour": "{num}小時前",
|
||||
"date_format_minute": "{num}分鐘前",
|
||||
"date_format_second": "{num}秒前",
|
||||
"deep_link__handle_error_tip": "調用失敗:{message}",
|
||||
"default": "默認",
|
||||
"default_list": "試聽列表",
|
||||
"desktop_lyric__back": "返回",
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
const urlSchemeRxp = /^lxmusic:\/\//
|
||||
|
||||
const parseEnv = () => {
|
||||
const params = {}
|
||||
const rx = /^-\w+/
|
||||
for (let param of process.argv) {
|
||||
if (urlSchemeRxp.test(param)) {
|
||||
global.envParams.deeplink = param
|
||||
}
|
||||
|
||||
if (!rx.test(param)) continue
|
||||
param = param.substring(1)
|
||||
let index = param.indexOf('=')
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
const { app, BrowserWindow, shell } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
const urlSchemeRxp = /^lxmusic:\/\//
|
||||
|
||||
// 单例应用程序
|
||||
if (!app.requestSingleInstanceLock()) {
|
||||
app.quit()
|
||||
|
@ -8,6 +10,13 @@ if (!app.requestSingleInstanceLock()) {
|
|||
}
|
||||
if (!global.modules) global.modules = {}
|
||||
app.on('second-instance', (event, argv, cwd) => {
|
||||
for (const param of argv) {
|
||||
if (urlSchemeRxp.test(param)) {
|
||||
global.envParams.deeplink = param
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (global.modules.mainWindow) {
|
||||
if (global.modules.mainWindow.isMinimized()) {
|
||||
global.modules.mainWindow.restore()
|
||||
|
@ -44,6 +53,33 @@ if (global.envParams.cmdParams['proxy-server']) {
|
|||
}
|
||||
// if (global.envParams.cmdParams['proxy-pac-url']) app.commandLine.appendSwitch('proxy-pac-url', global.envParams.cmdParams['proxy-pac-url'])
|
||||
|
||||
// deep link
|
||||
app.on('open-url', (event, url) => {
|
||||
if (!urlSchemeRxp.test(url)) return
|
||||
event.preventDefault()
|
||||
global.envParams.deeplink = url
|
||||
if (global.modules.mainWindow) {
|
||||
if (global.modules.mainWindow.isMinimized()) {
|
||||
global.modules.mainWindow.restore()
|
||||
}
|
||||
if (global.modules.mainWindow.isVisible()) {
|
||||
global.modules.mainWindow.focus()
|
||||
} else {
|
||||
global.modules.mainWindow.show()
|
||||
}
|
||||
} else if (global.modules.mainWindow === null) {
|
||||
init()
|
||||
}
|
||||
})
|
||||
if (isDev && process.platform === 'win32') {
|
||||
// Set the path of electron.exe and your app.
|
||||
// These two additional parameters are only available on windows.
|
||||
// console.log(process.execPath, process.argv)
|
||||
app.setAsDefaultProtocolClient('lxmusic', process.execPath, process.argv.slice(1))
|
||||
} else {
|
||||
app.setAsDefaultProtocolClient('lxmusic')
|
||||
}
|
||||
|
||||
const { navigationUrlWhiteList, themes } = require('../common/config')
|
||||
const { getWindowSizeInfo, initSetting, updateSetting } = require('./utils')
|
||||
const { isMac, isLinux, initHotKey } = require('../common/utils')
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
const { mainHandle, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
const { mainHandle, mainOn, NAMES: { mainWindow: ipcMainWindowNames } } = require('../../common/ipc')
|
||||
|
||||
mainHandle(ipcMainWindowNames.get_env_params, async(event, options) => {
|
||||
return global.envParams.cmdParams
|
||||
return global.envParams
|
||||
})
|
||||
|
||||
mainOn(ipcMainWindowNames.clear_env_params_deeplink, () => {
|
||||
global.envParams.deeplink = null
|
||||
})
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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 })}`)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,13 +83,16 @@ const actions = {
|
|||
},
|
||||
getListDetail({ state, commit }, { id, source, page }) {
|
||||
let key = `sdetail__${source}__${id}__${page}`
|
||||
if (state.listDetail.list.length && state.listDetail.key == key) return Promise.resolve()
|
||||
if (state.listDetail.list.length && state.listDetail.key == key) return Promise.resolve(state.listDetail.list)
|
||||
commit('clearListDetail')
|
||||
return (
|
||||
cache.has(key)
|
||||
? Promise.resolve(cache.get(key))
|
||||
: music[source].songList.getListDetail(id, page).then(result => ({ ...result, list: filterList(result.list) }))
|
||||
).then(result => commit('setListDetail', { result, key, source, id, page }))
|
||||
).then(result => {
|
||||
commit('setListDetail', { result, key, source, id, page })
|
||||
return result.list
|
||||
})
|
||||
},
|
||||
getListDetailAll({ state, rootState }, { source, id }) {
|
||||
// console.log(source, id)
|
||||
|
|
|
@ -48,6 +48,10 @@ export const getEnvParams = () => {
|
|||
return rendererInvoke(NAMES.mainWindow.get_env_params)
|
||||
}
|
||||
|
||||
export const clearEnvParamsDeeplink = () => {
|
||||
return rendererSend(NAMES.mainWindow.clear_env_params_deeplink)
|
||||
}
|
||||
|
||||
export const onUpdateAvailable = callback => {
|
||||
rendererOn(NAMES.mainWindow.update_available, callback)
|
||||
return () => {
|
||||
|
|
|
@ -170,10 +170,25 @@ export default {
|
|||
this.sortId = this.setting.songList.sortId
|
||||
if (!this.isVisibleListDetail) this.setTagListWidth()
|
||||
this.listenEvent()
|
||||
|
||||
if (this.$route.query.source && (this.$route.query.id || this.$route.query.url)) {
|
||||
this.handleRouteParams(this.$route.query.id, this.$route.query.url, this.$route.query.source)
|
||||
this.$router.replace({
|
||||
path: '/songList',
|
||||
})
|
||||
}
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.unlistenEvent()
|
||||
},
|
||||
beforeRouteUpdate(to) {
|
||||
if (to.query.source && (to.query.id || to.query.url)) {
|
||||
this.handleRouteParams(to.query.id, to.query.url, to.query.source)
|
||||
return {
|
||||
path: '/songList',
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['setSongList']),
|
||||
...mapActions('songList', ['getTags', 'getList', 'getListDetail', 'getListDetailAll']),
|
||||
|
@ -201,6 +216,10 @@ export default {
|
|||
event.target.classList.contains('key-bind')) return
|
||||
this.hideListDetail()
|
||||
},
|
||||
handleRouteParams(id, url, source) {
|
||||
if (!id) id = decodeURIComponent(url)
|
||||
this.handleGetSongListDetail(id, source)
|
||||
},
|
||||
handleToggleListPage(page) {
|
||||
this.getList(page).then(() => {
|
||||
this.$nextTick(() => {
|
||||
|
|
Loading…
Reference in New Issue