diff --git a/README.md b/README.md
index 57cfe344..f3ad6d32 100644
--- a/README.md
+++ b/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)
+以下是目前可用的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`(源,必须)
`id`(歌单ID,可选)
`url`(歌单URL,可选)其中ID与URL必需传一个
+| 播放歌单 | `songlist/play` | `source`(源,必须)
`id`(歌单ID,可选)
`url`(歌单URL,可选)其中`id`与`url`必需传一个
`index`(播放第几首歌,可选,从0开始)
+| 播放歌曲 | `music/play` | `name`(歌曲名,必传)
`singer`(艺术家名,必传)
`source`(源,必传)
`songmid`(歌曲ID,必传)
`img`(歌曲图片链接,选传)
`albumId`(歌曲专辑ID,选传)
`interval`(格式化后的歌曲时长,选传,例:`03:55`)
`albumName`(歌曲专辑名称,选传)
`types`(歌曲可用音质数组,必传,数组格式:`[{"type": "<音质>", size: "<格式化后的文件大小,选传>", hash: ""}]`,例:`[{"type": "128k", size: "3.56M"}, {"type": "320k", size: null}]`)
以下为平台特定参数:
`hash`(歌曲hash,kg源必传)
`strMediaMid`(歌曲strMediaMid,tx源必传)
`albumMid`(歌曲albumMid,tx源专用,选传)
`copyrightId`(歌曲copyrightId,mg源必传)
`lrcUrl`(歌曲lrcUrl,mg源专用,选传)
### 常见问题
diff --git a/package.json b/package.json
index 16130c76..31db91b3 100644
--- a/package.json
+++ b/package.json
@@ -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"
diff --git a/publish/changeLog.md b/publish/changeLog.md
index 0142f0f8..b05e06c7 100644
--- a/publish/changeLog.md
+++ b/publish/changeLog.md
@@ -1,5 +1,6 @@
### 新增
+- 新增 Scheme URL 支持,同时发布lx-music-script项目配合使用(一个油猴脚本,可以在浏览器中的官方平台网页直接调用LX Music),Scheme URL的调用说明看Readme.md文档的Scheme URL支持部分
- 新增启动参数`-proxy-server`与`-proxy-bypass-list`,详细介绍看Readme.md文档的启动参数部分
### 优化
diff --git a/src/common/ipcNames.js b/src/common/ipcNames.js
index 113c290c..2d951b9d 100644
--- a/src/common/ipcNames.js
+++ b/src/common/ipcNames.js
@@ -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',
diff --git a/src/lang/en-us.json b/src/lang/en-us.json
index 2bb1f837..2bffc144 100644
--- a/src/lang/en-us.json
+++ b/src/lang/en-us.json
@@ -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",
diff --git a/src/lang/zh-cn.json b/src/lang/zh-cn.json
index e5118802..7910355a 100644
--- a/src/lang/zh-cn.json
+++ b/src/lang/zh-cn.json
@@ -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": "返回",
diff --git a/src/lang/zh-tw.json b/src/lang/zh-tw.json
index 63e35cfa..fbdbd86b 100644
--- a/src/lang/zh-tw.json
+++ b/src/lang/zh-tw.json
@@ -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": "返回",
diff --git a/src/main/env/cmdParams.js b/src/main/env/cmdParams.js
index e5da711f..d8fd814f 100644
--- a/src/main/env/cmdParams.js
+++ b/src/main/env/cmdParams.js
@@ -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('=')
diff --git a/src/main/index.js b/src/main/index.js
index 67678277..60fc4056 100644
--- a/src/main/index.js
+++ b/src/main/index.js
@@ -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')
diff --git a/src/main/rendererEvents/getEnvParams.js b/src/main/rendererEvents/getEnvParams.js
index 060f48cf..b6278769 100644
--- a/src/main/rendererEvents/getEnvParams.js
+++ b/src/main/rendererEvents/getEnvParams.js
@@ -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
+})
diff --git a/src/renderer/core/share/player.js b/src/renderer/core/share/player.js
index 005bf11f..a97bae0d 100644
--- a/src/renderer/core/share/player.js
+++ b/src/renderer/core/share/player.js
@@ -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)
diff --git a/src/renderer/core/useApp/compositions/usePlaySonglist.js b/src/renderer/core/useApp/compositions/usePlaySonglist.js
new file mode 100644
index 00000000..cb968d96
--- /dev/null
+++ b/src/renderer/core/useApp/compositions/usePlaySonglist.js
@@ -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)
+ }
+}
diff --git a/src/renderer/core/useApp/index.js b/src/renderer/core/useApp/index.js
index 7a51f5c0..59f2f431 100644
--- a/src/renderer/core/useApp/index.js
+++ b/src/renderer/core/useApp/index.js
@@ -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)
})
})
}
diff --git a/src/renderer/core/useApp/useDeepLink.js b/src/renderer/core/useApp/useDeepLink.js
new file mode 100644
index 00000000..359767f7
--- /dev/null
+++ b/src/renderer/core/useApp/useDeepLink.js
@@ -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 })}`)
+ }
+ }
+}
diff --git a/src/renderer/core/useApp/useHandleEnvParams.js b/src/renderer/core/useApp/useHandleEnvParams.js
index c03a88be..4f096d5b 100644
--- a/src/renderer/core/useApp/useHandleEnvParams.js
+++ b/src/renderer/core/useApp/useHandleEnvParams.js
@@ -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)
}
}
diff --git a/src/renderer/store/modules/songList.js b/src/renderer/store/modules/songList.js
index 1618de75..57058f9c 100644
--- a/src/renderer/store/modules/songList.js
+++ b/src/renderer/store/modules/songList.js
@@ -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)
diff --git a/src/renderer/utils/tools.js b/src/renderer/utils/tools.js
index f36492f7..39902415 100644
--- a/src/renderer/utils/tools.js
+++ b/src/renderer/utils/tools.js
@@ -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 () => {
diff --git a/src/renderer/views/songList/SongList.vue b/src/renderer/views/songList/SongList.vue
index 2cfea448..77ca7caa 100644
--- a/src/renderer/views/songList/SongList.vue
+++ b/src/renderer/views/songList/SongList.vue
@@ -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(() => {