yumoqing cae63c6588 fix: persistent fullscreen window — never destroy AVPlayerView
Root cause: every fullscreen exit destroyed the AVPlayerView, triggering
CoreMedia's FigNotificationCenterRemoveWeakListeners which races with
the main thread's autorelease pool drain. No amount of nil-ing the
player reference or delaying the close could prevent this race.

Solution: the fullscreen NSWindow + AVPlayerView are created ONCE on
first use and never destroyed. Toggle uses orderFront/orderOut instead
of makeKeyAndOrderFront/close. The AVPlayerView stays alive for the
entire app lifetime, so CoreMedia teardown never happens during toggle.

Also:
- Removed onDisappear { bridge.cleanup() } — cleanup during app
  termination races with autorelease pool drain. Process exit handles
  all teardown correctly.
- Double-click exit uses DispatchQueue.main.async to avoid calling
  toggleFullscreen from inside the event monitor callback.
- isReleasedWhenClosed = false on fullscreen window
2026-06-22 09:01:04 +08:00

MiniPlayer

简洁多平台视频/音频播放器,支持 macOS、iPhone、iPad。

功能

  • 播放大多数视频/音频格式 (MP4, MKV, AVI, MOV, MP3, FLAC, WAV, OGG, AAC 等)
  • 支持 M3U8 流媒体播放
  • 音轨切换
  • 全屏播放
  • 播放列表管理(拖拽排序、删除)
  • 自动播放下一首
  • 单曲循环 / 列表循环 / 不循环
  • 快进快退 10 秒
  • 本地文件 + URL 流媒体双入口

系统要求

  • macOS 14+ (Sonoma)
  • iOS / iPadOS 17+
  • Xcode 15+

构建

# 安装 XcodeGen如未安装
brew install xcodegen

# 生成项目并打开
bash setup.sh

或在 Xcode 中File → New → Project → Multiplatform → App将 Sources/ 目录的文件添加进去。

快捷键

快捷键 功能
Space 播放/暂停
→ / ← 快进/快退 10 秒
⌘→ / ⌘← 下一个/上一个
⌘F 全屏切换
ESC 退出全屏

架构

Sources/
├── MiniPlayerApp.swift       # App 入口
├── ContentView.swift         # 主布局 (NavigationSplitView)
├── PlayerView.swift          # 视频显示 + 控制层
├── PlaylistView.swift        # 播放列表侧边栏
├── PlayerEngine.swift        # AVPlayer 播放引擎
├── PlayerLayerView.swift     # 跨平台视频渲染层
└── Models.swift              # 数据模型
  • SwiftUI + AVFoundation
  • 单一代码库,#if os(iOS) / #if os(macOS) 处理平台差异
  • AVPlayerLayer 自定义渲染(比 VideoPlayer 更可控)
Description
No description provided
Readme 168 MiB