274 lines
7.1 KiB
TypeScript
274 lines
7.1 KiB
TypeScript
import { invoke } from '@tauri-apps/api/core'
|
||
import { listen, type UnlistenFn } from '@tauri-apps/api/event'
|
||
|
||
// 类型定义,对应 Rust 端的结构
|
||
export interface ConnectionConfig {
|
||
host: string
|
||
port: number
|
||
timeout: number
|
||
autoReconnect: boolean
|
||
reconnectInterval: number
|
||
}
|
||
|
||
export interface VideoInfo {
|
||
path: string
|
||
title: string
|
||
duration?: number
|
||
size?: number
|
||
format?: string
|
||
}
|
||
|
||
export interface PlayerState {
|
||
connectionStatus: 'connected' | 'connecting' | 'disconnected' | { error: string }
|
||
playbackStatus: 'playing' | 'paused' | 'stopped' | 'loading'
|
||
currentVideo?: VideoInfo
|
||
position: number
|
||
duration: number
|
||
volume: number
|
||
isLooping: boolean
|
||
isFullscreen: boolean
|
||
playlist: VideoInfo[]
|
||
currentPlaylistIndex?: number
|
||
}
|
||
|
||
export interface ApiResponse<T> {
|
||
success: boolean
|
||
data?: T
|
||
message?: string
|
||
error?: string
|
||
}
|
||
|
||
export type PlaybackCommand =
|
||
| 'play'
|
||
| 'pause'
|
||
| 'stop'
|
||
| { seek: { position: number } }
|
||
| { setVolume: { volume: number } }
|
||
| { setLoop: { enabled: boolean } }
|
||
| 'toggleFullscreen'
|
||
| { loadVideo: { path: string } }
|
||
| { setPlaylist: { videos: string[] } }
|
||
| { playFromPlaylist: { index: number } }
|
||
|
||
export interface AppSettings {
|
||
connection: ConnectionConfig
|
||
defaultVolume: number
|
||
defaultLoop: boolean
|
||
autoFullscreen: boolean
|
||
playbackEndBehavior: 'stop' | 'next' | 'repeat'
|
||
theme: string
|
||
language: string
|
||
showNotifications: boolean
|
||
debugMode: boolean
|
||
cacheSize: number
|
||
proxy?: string
|
||
}
|
||
|
||
/**
|
||
* Tauri API composable
|
||
* 提供与 Tauri 后端通信的方法
|
||
*/
|
||
export function useTauri() {
|
||
const toast = useToast()
|
||
|
||
/**
|
||
* 安全地调用 Tauri API
|
||
*/
|
||
async function safeInvoke<T>(command: string, args?: any): Promise<T | null> {
|
||
try {
|
||
const result = await invoke<T>(command, args)
|
||
return result
|
||
} catch (error) {
|
||
console.error(`Tauri invoke error (${command}):`, error)
|
||
toast.add({
|
||
title: '操作失败',
|
||
description: `调用 ${command} 失败: ${error}`,
|
||
color: 'error'
|
||
})
|
||
return null
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 连接到视频播放器
|
||
*/
|
||
async function connectToPlayer(config: ConnectionConfig): Promise<PlayerState | null> {
|
||
const response = await safeInvoke<ApiResponse<PlayerState>>('connect_to_player', { config })
|
||
if (response?.success && response.data) {
|
||
toast.add({
|
||
title: '连接成功',
|
||
description: response.message || '已成功连接到视频播放器',
|
||
color: 'success'
|
||
})
|
||
return response.data
|
||
}
|
||
const host = config?.host || '127.0.0.1'
|
||
const port = config?.port || 6666
|
||
const reason = response?.error || '无法连接到视频播放器,请检查地址与端口是否正确,以及播放器是否已启动'
|
||
toast.add({
|
||
title: '连接失败',
|
||
description: `${reason}(目标:${host}:${port})`,
|
||
color: 'error'
|
||
})
|
||
return null
|
||
}
|
||
|
||
/**
|
||
* 断开与视频播放器的连接
|
||
*/
|
||
async function disconnectFromPlayer(): Promise<boolean> {
|
||
const response = await safeInvoke<ApiResponse<void>>('disconnect_from_player')
|
||
if (response?.success) {
|
||
toast.add({
|
||
title: '已断开连接',
|
||
description: response.message || '已断开与视频播放器的连接',
|
||
color: 'warning'
|
||
})
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
|
||
/**
|
||
* 获取连接状态
|
||
*/
|
||
async function getConnectionStatus(): Promise<PlayerState | null> {
|
||
const response = await safeInvoke<ApiResponse<PlayerState>>('get_connection_status')
|
||
return response?.success && response.data ? response.data : null
|
||
}
|
||
|
||
/**
|
||
* 发送播放控制命令
|
||
*/
|
||
async function sendPlaybackCommand(command: PlaybackCommand): Promise<boolean> {
|
||
const response = await safeInvoke<ApiResponse<void>>('send_playback_command', { command })
|
||
if (response?.success) {
|
||
// 不显示成功消息,避免过多通知
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
|
||
/**
|
||
* 更新连接配置
|
||
*/
|
||
async function updateConnectionConfig(config: ConnectionConfig): Promise<boolean> {
|
||
const response = await safeInvoke<ApiResponse<void>>('update_connection_config', { config })
|
||
if (response?.success) {
|
||
toast.add({
|
||
title: '配置更新成功',
|
||
description: response.message || '连接配置已更新',
|
||
color: 'success'
|
||
})
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
|
||
/**
|
||
* 获取应用设置
|
||
*/
|
||
async function getSettings(): Promise<AppSettings | null> {
|
||
const response = await safeInvoke<ApiResponse<AppSettings>>('get_settings')
|
||
return response?.success && response.data ? response.data : null
|
||
}
|
||
|
||
/**
|
||
* 保存应用设置
|
||
*/
|
||
async function saveSettings(settings: AppSettings): Promise<boolean> {
|
||
const response = await safeInvoke<ApiResponse<void>>('save_settings', { settings })
|
||
if (response?.success) {
|
||
toast.add({
|
||
title: '设置保存成功',
|
||
description: response.message || '应用设置已保存',
|
||
color: 'success'
|
||
})
|
||
return true
|
||
}
|
||
return false
|
||
}
|
||
|
||
/**
|
||
* 选择文件
|
||
*/
|
||
async function selectFile(): Promise<string | null> {
|
||
const response = await safeInvoke<ApiResponse<string>>('select_file')
|
||
return response?.success && response.data ? response.data : null
|
||
}
|
||
|
||
/**
|
||
* 选择多个文件
|
||
*/
|
||
async function selectFiles(): Promise<string[] | null> {
|
||
const response = await safeInvoke<ApiResponse<string[]>>('select_files')
|
||
return response?.success && response.data ? response.data : null
|
||
}
|
||
|
||
/**
|
||
* 监听播放器状态更新事件
|
||
*/
|
||
async function listenPlayerStateUpdate(callback: (state: PlayerState) => void): Promise<UnlistenFn | null> {
|
||
try {
|
||
return await listen<PlayerState>('player-state-update', (event) => {
|
||
callback(event.payload)
|
||
})
|
||
} catch (error) {
|
||
console.error('监听播放器状态更新失败:', error)
|
||
return null
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 监听播放命令发送事件
|
||
*/
|
||
async function listenPlaybackCommandSent(callback: (command: PlaybackCommand) => void): Promise<UnlistenFn | null> {
|
||
try {
|
||
return await listen<PlaybackCommand>('playback-command-sent', (event) => {
|
||
callback(event.payload)
|
||
})
|
||
} catch (error) {
|
||
console.error('监听播放命令发送失败:', error)
|
||
return null
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 监听连接状态变化事件
|
||
*/
|
||
async function listenConnectionStatusChange(callback: (status: string) => void): Promise<UnlistenFn | null> {
|
||
try {
|
||
return await listen<string>('connection-status-change', (event) => {
|
||
callback(event.payload)
|
||
})
|
||
} catch (error) {
|
||
console.error('监听连接状态变化失败:', error)
|
||
return null
|
||
}
|
||
}
|
||
|
||
return {
|
||
// 连接管理
|
||
connectToPlayer,
|
||
disconnectFromPlayer,
|
||
getConnectionStatus,
|
||
updateConnectionConfig,
|
||
|
||
// 播放控制
|
||
sendPlaybackCommand,
|
||
|
||
// 设置管理
|
||
getSettings,
|
||
saveSettings,
|
||
|
||
// 文件操作
|
||
selectFile,
|
||
selectFiles,
|
||
|
||
// 事件监听
|
||
listenPlayerStateUpdate,
|
||
listenPlaybackCommandSent,
|
||
listenConnectionStatusChange,
|
||
}
|
||
}
|