新增HTTP开放API服务

This commit is contained in:
lyswhut
2024-03-29 14:43:32 +08:00
parent 1e03791e82
commit 9c0ae12959
35 changed files with 681 additions and 340 deletions
+3
View File
@@ -136,6 +136,9 @@ const defaultSetting: LX.AppSetting = {
'sync.server.maxSsnapshotNum': 5,
'sync.client.host': '',
'openAPI.enable': false,
'openAPI.port': '23330',
// 'theme.id': 'blue_plus',
'theme.id': 'green',
'theme.lightId': 'green',
+2 -1
View File
@@ -59,7 +59,7 @@ const modules = {
open_dev_tools: 'open_dev_tools',
set_power_save_blocker: 'set_power_save_blocker',
progress: 'progress',
player_status: 'player_status',
change_tray: 'change_tray',
quit_update: 'quit_update',
update_check: 'update_check',
@@ -134,6 +134,7 @@ const modules = {
clear_music_url: 'clear_music_url',
get_music_url_count: 'get_music_url_count',
open_api_action: 'open_api_action',
sync_action: 'sync_action',
sync_get_server_devices: 'sync_get_server_devices',
sync_remove_server_device: 'sync_remove_server_device',
+11
View File
@@ -619,6 +619,17 @@ declare global {
*/
'sync.client.host': string
/**
* 是否启用开放API服务
*/
'openAPI.enable': boolean
/**
* 同步服务端口号
*/
'openAPI.port': '23333' | string
/**
* 是否在离开搜索界面时自动清空搜索框
*/
+25
View File
@@ -0,0 +1,25 @@
declare namespace LX {
namespace OpenAPI {
interface Status {
status: boolean
message: string
address: string
}
interface EnableServer {
enable: boolean
port: string
}
interface ActionBase <A> {
action: A
}
interface ActionData<A, D> extends ActionBase<A> {
data: D
}
type Action<A, D = undefined> = D extends undefined ? ActionBase<A> : ActionData<A, D>
type Actions = Action<'status'>
| Action<'enable', EnableServer>
}
}
+13
View File
@@ -15,5 +15,18 @@ declare namespace LX {
interface LyricInfo extends LX.Music.LyricInfo {
rawlrcInfo: LX.Music.LyricInfo
}
interface Status {
status: 'playing' | 'paused' | 'error' | 'stoped'
name: string
singer: string
albumName: string
picUrl: string
progress: number
duration: number
lyricLineText: string
lyric: string
collect: boolean
}
}
}
@@ -227,4 +227,8 @@ export default class Lyric {
this._handleLinePlayerOnPlay(num, '', this.linePlayer._currentTime())
} else this.playingLineNum = 0
}
setAutoPause(autoPause) {
this.linePlayer.setAutoPause(autoPause)
}
}
@@ -224,4 +224,16 @@ export default class LinePlayer {
this.extendedLyrics = extendedLyrics
this._init()
}
setAutoPause(autoPause) {
if (autoPause) {
timeoutTools.nextTick = window.requestAnimationFrame.bind(window)
timeoutTools.cancelNextTick = window.cancelAnimationFrame.bind(window)
} else {
timeoutTools.nextTick = (handler) => {
return setTimeout(handler, 80)
}
timeoutTools.cancelNextTick = clearTimeout.bind(global)
}
}
}
+4 -2
View File
@@ -3,6 +3,8 @@ export const getNow = typeof performance == 'object' && window.performance.now ?
export class TimeoutTools {
constructor(thresholdTime = 80) {
this.nextTick = window.requestAnimationFrame.bind(window)
this.cancelNextTick = window.cancelAnimationFrame.bind(window)
this.invokeTime = 0
this.animationFrameId = null
this.timeoutId = null
@@ -11,7 +13,7 @@ export class TimeoutTools {
}
run() {
this.animationFrameId = window.requestAnimationFrame(() => {
this.animationFrameId = this.nextTick(() => {
this.animationFrameId = null
let diff = this.invokeTime - getNow()
// console.log('diff', diff)
@@ -39,7 +41,7 @@ export class TimeoutTools {
clear() {
if (this.animationFrameId) {
window.cancelAnimationFrame(this.animationFrameId)
this.cancelNextTick(this.animationFrameId)
this.animationFrameId = null
}
if (this.timeoutId) {
+7
View File
@@ -460,6 +460,13 @@
"setting__odc": "Auto clear",
"setting__odc_clear_search_input": "Clear the search box when you are not searching",
"setting__odc_clear_search_list": "Clear the search list when you are not searching",
"setting__open_api": "Open API",
"setting__open_api_address": "Service address: {address}",
"setting__open_api_enable": "Enable open API service",
"setting__open_api_port": "Service port",
"setting__open_api_port_tip": "Please enter the open API service port",
"setting__open_api_tip": "This function is used to provide third-party software with the ability to call LX Music. You can see the currently available functions: ",
"setting__open_api_tip_link": "Access document",
"setting__other": "Extras",
"setting__other_dislike_list": "dislike song rule",
"setting__other_dislike_list_label": "Number of rules:",
+7
View File
@@ -460,6 +460,13 @@
"setting__odc": "强迫症设置",
"setting__odc_clear_search_input": "离开搜索界面时清空搜索框",
"setting__odc_clear_search_list": "离开搜索界面时清空搜索列表",
"setting__open_api": "开放API",
"setting__open_api_address": "服务地址:{address}",
"setting__open_api_enable": "启用开放API服务",
"setting__open_api_port": "服务端口",
"setting__open_api_port_tip": "请输入开放API服务端口",
"setting__open_api_tip": "该功能用于为第三方软件提供调用LX Music的能力,目前可用的功能可以看:",
"setting__open_api_tip_link": "接入文档",
"setting__other": "其他",
"setting__other_dislike_list": "不喜欢的歌曲规则",
"setting__other_dislike_list_label": "规则数量:",
+7
View File
@@ -460,6 +460,13 @@
"setting__odc": "強迫症設定",
"setting__odc_clear_search_input": "離開搜尋介面時清空搜尋框",
"setting__odc_clear_search_list": "離開搜尋介面時清空搜尋列表",
"setting__open_api": "開放API",
"setting__open_api_address": "服務地址:{address}",
"setting__open_api_enable": "啟用開放API服務",
"setting__open_api_port": "服務連接埠",
"setting__open_api_port_tip": "請輸入開放API服務端口",
"setting__open_api_tip": "此功能用於為第三方軟體提供呼叫LX Music的能力,目前可用的功能可以看:",
"setting__open_api_tip_link": "接上文件",
"setting__other": "其他",
"setting__other_dislike_list": "不喜歡的歌曲規則",
"setting__other_dislike_list_label": "規則數量:",
+12
View File
@@ -234,6 +234,18 @@ export const initAppSetting = async() => {
colors: {},
},
},
player_status: {
status: 'stoped',
name: '',
singer: '',
albumName: '',
picUrl: '',
progress: 0,
duration: 0,
lyricLineText: '',
lyric: '',
collect: false,
},
}
}
+8
View File
@@ -52,6 +52,14 @@ export class Event extends EventEmitter {
this.emit('deeplink', link)
}
player_status(status: Partial<LX.Player.Status>) {
for (const [key, value] of Object.entries(status)) {
// @ts-expect-error
global.lx.player_status[key] = value
}
this.emit('player_status', status)
}
hot_key_down(keyInfo: LX.HotKeyDownInfo) {
this.emit('hot_key_down', keyInfo)
}
+107
View File
@@ -0,0 +1,107 @@
import http from 'node:http'
let status: LX.OpenAPI.Status = {
status: false,
message: '',
address: '',
}
let httpServer: http.Server
const handleStartServer = async(port = 9000, ip = '127.0.0.1') => new Promise<void>((resolve, reject) => {
httpServer = http.createServer((req, res) => {
// console.log(req.url)
const endUrl = `/${req.url?.split('/').at(-1) ?? ''}`
let code
let msg
switch (endUrl) {
case '/status':
code = 200
res.setHeader('Content-Type', 'application/json; charset=utf-8')
msg = JSON.stringify({
status: global.lx.player_status.status,
name: global.lx.player_status.name,
singer: global.lx.player_status.singer,
albumName: global.lx.player_status.albumName,
duration: global.lx.player_status.duration,
progress: global.lx.player_status.progress,
picUrl: global.lx.player_status.picUrl,
lyricLineText: global.lx.player_status.lyricLineText,
})
break
case '/lyric':
code = 200
res.setHeader('Content-Type', 'text/plain; charset=utf-8')
msg = global.lx.player_status.lyric
break
default:
code = 401
msg = 'Forbidden'
break
}
if (!code) return
res.writeHead(code)
res.end(msg)
})
httpServer.on('error', error => {
console.log(error)
reject(error)
})
httpServer.on('listening', () => {
const addr = httpServer.address()
// console.log(addr)
if (!addr) {
reject(new Error('address is null'))
return
}
resolve()
})
httpServer.listen(port, ip)
})
const handleStopServer = async() => new Promise<void>((resolve, reject) => {
if (!httpServer) return
httpServer.close((err) => {
if (err) {
reject(err)
return
}
resolve()
})
})
export const stopServer = async() => {
if (!status.status) {
status.status = false
status.message = ''
status.address = ''
return status
}
await handleStopServer().then(() => {
status.status = false
status.message = ''
status.address = ''
}).catch(err => {
console.log(err)
status.message = err.message
})
return status
}
export const startServer = async(port: number) => {
if (status.status) await handleStopServer()
await handleStartServer(port).then(() => {
status.status = true
status.message = ''
status.address = `http://localhost${port == 80 ? '' : ':' + port}`
}).catch(err => {
console.log(err)
status.status = false
status.message = err.message
status.address = ''
})
return status
}
export const getStatus = (): LX.OpenAPI.Status => status
+73 -1
View File
@@ -1,7 +1,7 @@
import initRendererEvent, { handleKeyDown, hotKeyConfigUpdate } from './rendererEvent'
import { APP_EVENT_NAMES } from '@common/constants'
import { createWindow, minimize, toggleHide, toggleMinimize } from './main'
import { createWindow, minimize, setProgressBar, setThumbarButtons, toggleHide, toggleMinimize } from './main'
import initUpdate from './autoUpdate'
import { HOTKEY_COMMON } from '@common/hotKey'
import { quitApp } from '@main/app'
@@ -38,6 +38,78 @@ export default () => {
global.lx.event_app.on('app_inited', () => {
createWindow()
})
const keys = (['status', 'collect'] as const) satisfies Array<keyof LX.Player.Status>
const taskBarButtonFlags: LX.TaskBarButtonFlags = {
empty: true,
collect: false,
play: false,
next: true,
prev: true,
}
const progressStatus = {
progress: 0,
status: 'none' as Electron.ProgressBarOptions['mode'],
}
let showProgress = global.lx.appSetting['player.isShowTaskProgess']
global.lx.event_app.on('player_status', (status) => {
if (status.status) {
switch (status.status) {
case 'paused':
taskBarButtonFlags.play = false
taskBarButtonFlags.empty &&= false
progressStatus.status = 'paused'
break
case 'error':
taskBarButtonFlags.play = false
taskBarButtonFlags.empty &&= false
progressStatus.status = 'error'
break
case 'playing':
taskBarButtonFlags.play = true
taskBarButtonFlags.empty &&= false
progressStatus.status = 'normal'
break
case 'stoped':
taskBarButtonFlags.play &&= false
taskBarButtonFlags.empty = true
progressStatus.status = 'none'
progressStatus.progress = 0
break
}
if (showProgress) {
setProgressBar(progressStatus.progress, {
mode: progressStatus.status,
})
}
}
if (keys.some(k => status[k] != null)) {
if (status.collect != null) taskBarButtonFlags.collect = status.collect
setThumbarButtons(taskBarButtonFlags)
}
if (status.progress) {
const progress = status.progress / global.lx.player_status.duration
if (progress.toFixed(2) == progressStatus.progress.toFixed(2)) return
progressStatus.progress = progress
if (showProgress) {
setProgressBar(progress, {
mode: progressStatus.status,
})
}
}
})
global.lx.event_app.on('updated_config', (keys, setting) => {
if (keys.includes('player.isShowTaskProgess')) {
showProgress = setting['player.isShowTaskProgess']!
if (showProgress) {
setProgressBar(progressStatus.progress, {
mode: progressStatus.status,
})
} else {
setProgressBar(-1, { mode: 'none' })
}
}
})
}
export * from './main'
+3 -11
View File
@@ -14,10 +14,8 @@ import {
getCacheSize,
toggleDevTools,
setWindowBounds,
setProgressBar,
setIgnoreMouseEvents,
// setThumbnailClip,
setThumbarButtons,
toggleMinimize,
toggleHide,
showSelectDialog,
@@ -106,13 +104,6 @@ export default () => {
setWindowBounds(params)
})
mainOn<LX.Player.ProgressBarOptions>(WIN_MAIN_RENDERER_EVENT_NAME.progress, ({ params }) => {
// console.log(params)
setProgressBar(params.progress, {
mode: params.mode ?? 'normal',
})
})
mainOn<boolean>(WIN_MAIN_RENDERER_EVENT_NAME.set_ignore_mouse_events, ({ params: isIgnored }) => {
isIgnored
? setIgnoreMouseEvents(isIgnored, { forward: true })
@@ -123,8 +114,9 @@ export default () => {
// return setThumbnailClip(params)
// })
mainOn<LX.TaskBarButtonFlags>(WIN_MAIN_RENDERER_EVENT_NAME.player_action_set_buttons, ({ params }) => {
setThumbarButtons(params)
mainOn<LX.Player.Status>(WIN_MAIN_RENDERER_EVENT_NAME.player_status, ({ params }) => {
// setThumbarButtons(params)
global.lx.event_app.player_status(params)
})
mainOn(WIN_MAIN_RENDERER_EVENT_NAME.inited, () => {
@@ -11,6 +11,7 @@ import data from './data'
import music from './music'
import download from './download'
import soundEffect from './soundEffect'
import openAPI from './openAPI'
import { sendEvent } from '../main'
export * from './app'
@@ -37,6 +38,7 @@ export default () => {
music()
download()
soundEffect()
openAPI()
global.lx.event_app.on('updated_config', (keys, setting) => {
sendConfigChange(setting)
@@ -0,0 +1,18 @@
import { mainHandle } from '@common/mainIpc'
import { WIN_MAIN_RENDERER_EVENT_NAME } from '@common/ipcNames'
import {
startServer,
stopServer,
getStatus,
} from '@main/modules/openApi'
export default () => {
mainHandle<LX.OpenAPI.Actions, any>(WIN_MAIN_RENDERER_EVENT_NAME.open_api_action, async({ params: data }) => {
switch (data.action) {
case 'enable':
return data.data.enable ? await startServer(parseInt(data.data.port)) : await stopServer()
case 'status': return getStatus()
}
})
}
+1
View File
@@ -30,6 +30,7 @@ interface Lx {
dbService: DBSeriveTypes
}
theme: LX.ThemeSetting
player_status: LX.Player.Status
}
declare global {
+1
View File
@@ -14,3 +14,4 @@ import '@common/types/ipc_main'
import '@common/types/sound_effect'
import '@common/types/dislike_list'
import '@common/types/dislike_list_sync'
import '@common/types/open_api'
+5
View File
@@ -87,6 +87,7 @@ export const init = () => {
onPlay(line, text) {
setText(text, Math.max(line, 0))
setStatusText(text)
window.app_event.lyricLinePlay(text)
// console.log(line, text)
},
onSetLyric(lines, offset) { // listening lyrics seting event
@@ -185,6 +186,10 @@ export const setLyric = () => {
}
}
export const setAutoPause = (autoPause: boolean) => {
lrc.setAutoPause(autoPause)
}
export const play = () => {
// if (!musicInfo.lrc) return
+3
View File
@@ -4,6 +4,7 @@ import { proxy, isFullscreen, themeId } from '@renderer/store'
import { appSetting } from '@renderer/store/setting'
import useSync from './useSync'
import useOpenAPI from './useOpenAPI'
import useUpdate from './useUpdate'
import useDataInit from './useDataInit'
import useHandleEnvParams from './useHandleEnvParams'
@@ -25,6 +26,7 @@ export default () => {
const router = useRouter()
const initSyncService = useSync()
const initOpenAPI = useOpenAPI()
useEventListener()
const initPlayer = usePlayer()
const handleEnvParams = useHandleEnvParams()
@@ -62,6 +64,7 @@ export default () => {
handleEnvParams(envParams) // 处理传入的启动参数
void initDeeplink(envParams)
void initSyncService()
void initOpenAPI()
sendInited()
handleListAutoUpdate()
+42
View File
@@ -0,0 +1,42 @@
import { watch } from '@common/utils/vueTools'
import { appSetting } from '@renderer/store/setting'
import { sendOpenAPIAction } from '@renderer/utils/ipc'
import { openAPI } from '@renderer/store'
import { setAutoPause } from '@renderer/core/lyric'
export default () => {
const handleEnable = async(enable: boolean, port: string) => {
await sendOpenAPIAction({
action: 'enable',
data: {
enable,
port,
},
}).then((status) => {
openAPI.address = status.address
openAPI.message = status.message
}).catch((error) => {
openAPI.address = ''
openAPI.message = error.message
}).finally(() => {
if (openAPI.address) {
setAutoPause(false)
} else {
setAutoPause(true)
}
})
}
watch(() => appSetting['openAPI.enable'], enable => {
void handleEnable(enable, appSetting['openAPI.port'])
})
watch(() => appSetting['openAPI.port'], port => {
void handleEnable(appSetting['openAPI.enable'], port)
})
return async() => {
if (appSetting['openAPI.enable']) {
void handleEnable(true, appSetting['openAPI.port'])
}
}
}
@@ -1,7 +1,7 @@
import { onBeforeUnmount, watch } from '@common/utils/vueTools'
import { formatPlayTime2, getRandom } from '@common/utils/common'
import { throttle } from '@common/utils'
import { setTaskBarProgress, savePlayInfo } from '@renderer/utils/ipc'
import { savePlayInfo } from '@renderer/utils/ipc'
import { onTimeupdate, getCurrentTime, getDuration, setCurrentTime, onVisibilityChange } from '@renderer/plugins/player'
import { playProgress, setNowPlayTime, setMaxplayTime } from '@renderer/store/player/playProgress'
import { musicInfo, playMusicInfo, playInfo } from '@renderer/store/player/state'
@@ -14,7 +14,6 @@ const delaySavePlayInfo = throttle(savePlayInfo, 2000)
export default () => {
let restorePlayTime = 0
let prevProgressStatus: Electron.ProgressBarOptions['mode'] = 'none'
const mediaBuffer: {
timeout: NodeJS.Timeout | null
playTime: number
@@ -75,32 +74,18 @@ export default () => {
// if (!isPlay) audio.play()
}
const handleSetTaskBarState = (progress: number, status?: Electron.ProgressBarOptions['mode']) => {
if (appSetting['player.isShowTaskProgess']) setTaskBarProgress(progress, status)
}
const handlePlay = () => {
prevProgressStatus = 'normal'
handleSetTaskBarState(playProgress.progress, prevProgressStatus)
}
const handlePause = () => {
prevProgressStatus = 'paused'
handleSetTaskBarState(playProgress.progress, prevProgressStatus)
clearBufferTimeout()
}
const handleStop = () => {
setNowPlayTime(0)
setMaxplayTime(0)
prevProgressStatus = 'none'
handleSetTaskBarState(playProgress.progress, prevProgressStatus)
}
const handleError = () => {
restorePlayTime ||= getCurrentTime() // 记录出错的播放时间
console.log('handleError')
prevProgressStatus = 'error'
handleSetTaskBarState(playProgress.progress, prevProgressStatus)
}
const handleLoadeddata = () => {
@@ -157,10 +142,6 @@ export default () => {
}
}
watch(() => playProgress.progress, (newValue, oldValue) => {
if (newValue.toFixed(2) === oldValue.toFixed(2)) return
handleSetTaskBarState(newValue, prevProgressStatus)
})
watch(() => playProgress.nowPlayTime, (newValue, oldValue) => {
if (Math.abs(newValue - oldValue) > 2) window.app_event.activePlayProgressTransition()
if (appSetting['player.isSavePlayTime'] && !playMusicInfo.isTempPlay) {
@@ -183,7 +164,7 @@ export default () => {
}
})
window.app_event.on('play', handlePlay)
// window.app_event.on('play', handlePlay)
window.app_event.on('pause', handlePause)
window.app_event.on('stop', handleStop)
window.app_event.on('error', handleError)
@@ -213,7 +194,7 @@ export default () => {
onBeforeUnmount(() => {
rOnTimeupdate()
rVisibilityChange()
window.app_event.off('play', handlePlay)
// window.app_event.off('play', handlePlay)
window.app_event.off('pause', handlePause)
window.app_event.off('stop', handleStop)
window.app_event.off('error', handleError)
@@ -1,55 +1,65 @@
import { onBeforeUnmount } from '@common/utils/vueTools'
import { setPlayerAction, onPlayerAction } from '@renderer/utils/ipc'
import { onBeforeUnmount, watch } from '@common/utils/vueTools'
import { sendPlayerStatus, onPlayerAction } from '@renderer/utils/ipc'
// import store from '@renderer/store'
import { loveList } from '@renderer/store/list/state'
import { addListMusics, removeListMusics, checkListExistMusic } from '@renderer/store/list/action'
import { playMusicInfo } from '@renderer/store/player/state'
import { playMusicInfo, musicInfo } from '@renderer/store/player/state'
import { throttle } from '@common/utils'
import { pause, play, playNext, playPrev } from '@renderer/core/player'
import { playProgress } from '@renderer/store/player/playProgress'
export default () => {
// const setVisibleDesktopLyric = useCommit('setVisibleDesktopLyric')
// const setLockDesktopLyric = useCommit('setLockDesktopLyric')
let collect = false
const buttons = {
empty: true,
collect: false,
play: false,
prev: true,
next: true,
lrc: false,
lockLrc: false,
}
const setButtons = () => {
setPlayerAction(buttons)
}
const updateCollectStatus = async() => {
let status = !!playMusicInfo.musicInfo && await checkListExistMusic(loveList.id, playMusicInfo.musicInfo.id)
if (buttons.collect == status) return false
buttons.collect = status
if (collect == status) return false
collect = status
return true
}
const handlePlay = () => {
buttons.empty &&= false
buttons.play = true
setButtons()
sendPlayerStatus({ status: 'playing' })
}
const handlePause = () => {
buttons.empty &&= false
buttons.play = false
setButtons()
sendPlayerStatus({ status: 'paused' })
}
const handleStop = () => {
if (playMusicInfo.musicInfo != null) return
buttons.collect &&= false
buttons.empty = true
setButtons()
sendPlayerStatus({ status: 'stoped' })
}
const handleSetPlayInfo = () => {
void updateCollectStatus().then(isExist => {
if (isExist) setButtons()
const handleError = () => {
sendPlayerStatus({ status: 'error' })
}
const handleSetPlayInfo = async() => {
await updateCollectStatus()
sendPlayerStatus({
collect,
name: musicInfo.name,
singer: musicInfo.singer,
albumName: musicInfo.album,
picUrl: musicInfo.pic ?? '',
lyric: musicInfo.lrc ?? '',
lyricLineText: '',
})
}
const handleSetLyric = () => {
sendPlayerStatus({
lyric: musicInfo.lrc ?? '',
lyricLineText: '',
})
}
const handleSetPic = () => {
sendPlayerStatus({
picUrl: musicInfo.pic ?? '',
})
}
const handleSetLyricLine = (text: string) => {
sendPlayerStatus({
lyricLineText: text,
})
}
// const handleSetTaskbarThumbnailClip = (clip) => {
@@ -57,7 +67,7 @@ export default () => {
// }
const throttleListChange = throttle(async listIds => {
if (!listIds.includes(loveList.id)) return
if (await updateCollectStatus()) setButtons()
if (await updateCollectStatus()) sendPlayerStatus({ collect })
})
// const updateSetting = () => {
// const setting = store.getters.setting
@@ -82,12 +92,12 @@ export default () => {
case 'collect':
if (!playMusicInfo.musicInfo) return
void addListMusics(loveList.id, ['progress' in playMusicInfo.musicInfo ? playMusicInfo.musicInfo.metadata.musicInfo : playMusicInfo.musicInfo])
if (await updateCollectStatus()) setButtons()
if (await updateCollectStatus()) sendPlayerStatus({ collect })
break
case 'unCollect':
if (!playMusicInfo.musicInfo) return
void removeListMusics({ listId: loveList.id, ids: ['progress' in playMusicInfo.musicInfo ? playMusicInfo.musicInfo.metadata.musicInfo.id : playMusicInfo.musicInfo.id] })
if (await updateCollectStatus()) setButtons()
if (await updateCollectStatus()) sendPlayerStatus({ collect })
break
// case 'lrc':
// setVisibleDesktopLyric(true)
@@ -107,10 +117,24 @@ export default () => {
// break
}
})
watch(() => playProgress.nowPlayTime, (newValue, oldValue) => {
// console.log(playProgress.nowPlayTime, newValue, oldValue)
// if (newValue.toFixed(2) === oldValue.toFixed(2)) return
// console.log(playProgress.nowPlayTime)
sendPlayerStatus({ progress: newValue })
})
watch(() => playProgress.maxPlayTime, (newValue) => {
sendPlayerStatus({ duration: newValue })
})
window.app_event.on('play', handlePlay)
window.app_event.on('pause', handlePause)
window.app_event.on('stop', handleStop)
window.app_event.on('error', handleError)
window.app_event.on('musicToggled', handleSetPlayInfo)
window.app_event.on('lyricUpdated', handleSetLyric)
window.app_event.on('picUpdated', handleSetPic)
window.app_event.on('lyricLinePlay', handleSetLyricLine)
// window.app_event.on(eventTaskbarNames.setTaskbarThumbnailClip, handleSetTaskbarThumbnailClip)
window.app_event.on('myListUpdate', throttleListChange)
@@ -119,7 +143,11 @@ export default () => {
window.app_event.off('play', handlePlay)
window.app_event.off('pause', handlePause)
window.app_event.off('stop', handleStop)
window.app_event.off('error', handleError)
window.app_event.off('musicToggled', handleSetPlayInfo)
window.app_event.off('lyricUpdated', handleSetLyric)
window.app_event.off('picUpdated', handleSetPic)
window.app_event.off('lyricLinePlay', handleSetLyricLine)
// window.app_event.off(eventTaskbarNames.setTaskbarThumbnailClip, handleSetTaskbarThumbnailClip)
window.app_event.off('myListUpdate', throttleListChange)
})
@@ -129,7 +157,14 @@ export default () => {
// buttons.lrc = setting.desktopLyric.enable
// buttons.lockLrc = setting.desktopLyric.isLock
await updateCollectStatus()
if (playMusicInfo.musicInfo != null) buttons.empty = false
setButtons()
if (playMusicInfo.musicInfo == null) return
sendPlayerStatus({
collect,
name: musicInfo.name,
singer: musicInfo.singer,
albumName: musicInfo.album,
picUrl: musicInfo.pic ?? '',
lyric: musicInfo.lrc ?? '',
})
}
}
+1 -8
View File
@@ -1,7 +1,7 @@
import { watch } from '@common/utils/vueTools'
import { isFullscreen, proxy, sync, windowSizeList } from '@renderer/store'
import { appSetting } from '@renderer/store/setting'
import { sendSyncAction, setTaskBarProgress, setWindowSize } from '@renderer/utils/ipc'
import { sendSyncAction, setWindowSize } from '@renderer/utils/ipc'
import { setLanguage } from '@root/lang'
import { setUserApi } from '../apiSource'
// import { applyTheme, getThemes } from '@renderer/store/utils'
@@ -106,11 +106,4 @@ export default () => {
watch(() => appSetting['network.proxy.port'], port => {
proxy.port = port
})
watch(() => appSetting['player.isShowTaskProgess'], val => {
if (val) return
setTimeout(() => {
setTaskBarProgress(-1, 'normal')
})
})
}
+5
View File
@@ -144,6 +144,11 @@ export class AppEvent extends Event {
this.emit('lyricOffsetUpdate')
}
// 歌词行播放
lyricLinePlay(text: string) {
this.emit('lyricLinePlay', text)
}
// 我的列表改变事件
myListUpdate(ids: string[]) {
this.emit('myListUpdate', ids)
+5
View File
@@ -73,6 +73,11 @@ export const sync: {
},
})
export const openAPI = reactive({
address: '',
message: '',
})
export const windowSizeActive = computed(() => {
return windowSizeList.find(i => i.id === appSetting['common.windowSizeId']) ?? windowSizeList[0]
+1
View File
@@ -16,3 +16,4 @@ import '@common/types/config_files'
import '@common/types/music_metadata'
import '@common/types/sound_effect'
import '@common/types/dislike_list'
import '@common/types/open_api'
+7 -5
View File
@@ -172,11 +172,13 @@ export const userApiRequestCancel = (requestKey: LX.UserApi.UserApiRequestCancel
// }
// }
export const setTaskBarProgress = (progress: number, mode?: Electron.ProgressBarOptions['mode']) => {
rendererSend<LX.Player.ProgressBarOptions>(WIN_MAIN_RENDERER_EVENT_NAME.progress, {
progress: progress < 0 ? progress : Math.max(0.01, progress),
mode: mode ?? 'normal',
})
export const sendPlayerStatus = (status: Partial<LX.Player.Status>) => {
rendererSend<Partial<LX.Player.Status>>(WIN_MAIN_RENDERER_EVENT_NAME.player_status, status)
}
export const sendOpenAPIAction = async(action: LX.OpenAPI.Actions) => {
return rendererInvoke<LX.OpenAPI.Actions, LX.OpenAPI.Status>(WIN_MAIN_RENDERER_EVENT_NAME.open_api_action, action)
}
export const saveLastStartInfo = (version: string) => {
@@ -0,0 +1,50 @@
<template lang="pug">
dt#sync {{ $t('setting__open_api') }}
dd.gap-top
div
base-checkbox.gap-top(id="setting_open_api_enable" :model-value="appSetting['openAPI.enable']" :label="$t('setting__open_api_enable')" @update:model-value="updateSetting({ 'openAPI.enable': $event })")
.p.gap-top.small {{ $t('setting__open_api_address', { address: openAPI.address || '' }) }}
.p.small(v-if="openAPI.message") {{ openAPI.message }}
.p
.p.small {{ $t('setting__open_api_port') }}
div
base-input.gap-left(:class="$style.portInput" :model-value="appSetting['openAPI.port']" type="number" :placeholder="$t('setting__open_api_port_tip')" @update:model-value="setPort")
dd.gap-top
div
.p
| {{ $t('setting__open_api_tip') }}
strong.hover.underline(aria-label="https://lyswhut.github.io/lx-music-doc/desktop/faq/open-api" @click="openUrl('https://lyswhut.github.io/lx-music-doc/desktop/open-api')") {{ $t('setting__open_api_tip_link') }}
</template>
<script>
// import { computed } from '@common/utils/vueTools'
import { openAPI } from '@renderer/store'
import { openUrl } from '@common/utils/electron'
import { appSetting, updateSetting } from '@renderer/store/setting'
import { debounce } from '@common/utils'
export default {
name: 'SettingOpenAPI',
setup() {
const setPort = debounce(port => {
updateSetting({ 'openAPI.port': port.trim() })
}, 500)
return {
appSetting,
updateSetting,
openAPI,
openUrl,
setPort,
}
},
}
</script>
<style lang="less" module>
@import '@renderer/assets/styles/layout.less';
.portInput[disabled], .hostInput[disabled] {
opacity: .8 !important;
}
</style>
+4 -1
View File
@@ -60,6 +60,7 @@ import SettingSearch from './components/SettingSearch.vue'
import SettingList from './components/SettingList.vue'
import SettingDownload from './components/SettingDownload.vue'
import SettingSync from './components/SettingSync/index.vue'
import SettingOpenAPI from './components/SettingOpenAPI.vue'
import SettingHotKey from './components/SettingHotKey.vue'
import SettingNetwork from './components/SettingNetwork.vue'
import SettingOdc from './components/SettingOdc.vue'
@@ -79,6 +80,7 @@ export default {
SettingList,
SettingDownload,
SettingSync,
SettingOpenAPI,
SettingHotKey,
SettingNetwork,
SettingOdc,
@@ -102,8 +104,9 @@ export default {
{ id: 'SettingSearch', title: t('setting__search') },
{ id: 'SettingList', title: t('setting__list') },
{ id: 'SettingDownload', title: t('setting__download') },
{ id: 'SettingSync', title: t('setting__sync') },
{ id: 'SettingHotKey', title: t('setting__hot_key') },
{ id: 'SettingSync', title: t('setting__sync') },
{ id: 'SettingOpenAPI', title: t('setting__open_api') },
{ id: 'SettingNetwork', title: t('setting__network') },
{ id: 'SettingOdc', title: t('setting__odc') },
{ id: 'SettingBackup', title: t('setting__backup') },