From a393bb02ddf09a478e0231e9254bbe353ba87ec9 Mon Sep 17 00:00:00 2001 From: lyswhut Date: Fri, 7 Jan 2022 17:23:48 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20Scheme=20URL=20=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 16 ++ package.json | 8 +- publish/changeLog.md | 1 + src/common/ipcNames.js | 1 + src/lang/en-us.json | 1 + src/lang/zh-cn.json | 1 + src/lang/zh-tw.json | 1 + src/main/env/cmdParams.js | 6 + src/main/index.js | 36 +++ src/main/rendererEvents/getEnvParams.js | 7 +- src/renderer/core/share/player.js | 11 +- .../useApp/compositions/usePlaySonglist.js | 66 +++++ src/renderer/core/useApp/index.js | 5 +- src/renderer/core/useApp/useDeepLink.js | 260 ++++++++++++++++++ .../core/useApp/useHandleEnvParams.js | 26 +- src/renderer/store/modules/songList.js | 7 +- src/renderer/utils/tools.js | 4 + src/renderer/views/songList/SongList.vue | 19 ++ 18 files changed, 448 insertions(+), 28 deletions(-) create mode 100644 src/renderer/core/useApp/compositions/usePlaySonglist.js create mode 100644 src/renderer/core/useApp/useDeepLink.js 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(() => {