138 Commits

Author SHA1 Message Date
d0cecebe69 fix(iOS): add User-Agent header to all HLS segment + playlist requests
CBS streams require iPhone UA to serve actual TS data. Without it, segments
download as empty/small placeholder responses. Also added per-segment size
logging for diagnostics.
2026-07-17 21:36:53 +08:00
1f8ecb9bcb fix(iOS): replace FileHandle(forWritingTo:) with Data concatenation for TS merge
FileHandle(forWritingTo:) throws when file doesn't exist — it opens, not creates.
Changed to Data.append + Data.write which creates the file automatically.
2026-07-17 21:31:51 +08:00
f73bc4532e fix(iOS): show recorder errors as full-screen overlay instead of fleeting toast
- Added recorderErrorMessage @Published var for persistent error display
- Recording errors now shown as overlay with error details + Dismiss button
- presentShareSheet now logs errors and sets recorderErrorMessage on failure
- Errors like 'No window scene' or 'No view controller' visible on screen
2026-07-17 21:28:15 +08:00
04fb3acecc fix(iOS): use UIKit UIActivityViewController directly instead of SwiftUI .sheet
SwiftUI multiple .sheet modifiers can conflict — replaced the pendingExportURL
sheet binding with a direct UIKit UIActivityViewController presentation from
the key window's root VC. This bypasses any SwiftUI sheet stack issues.

Also added copyLocalFile() for local file recording (FileManager.copyItem
instead of URLSession.download which fails on file:// URLs).
2026-07-17 21:21:16 +08:00
4aec892151 fix(iOS): add copyLocalFile for local file recording on iOS
HLSRecorder.recordStream() now checks url.isFileURL first and copies
locally instead of using URLSession.download() which only works for
http/https URLs. Fixes recording local mp4 files on iOS.
2026-07-17 21:14:36 +08:00
96d617617f chore: remove accidentally committed xcodeproj.bak 2026-07-17 20:58:47 +08:00
da4495ab3e fix: Xcode ViewBuilder compile error — wrap NSLog in closure for iOS sheet
NSLog returns Void which doesn't conform to View in SwiftUI ViewBuilder.
Wrapped in inline closure  to avoid compilation error.
2026-07-17 20:58:22 +08:00
04990674cc fix: save dialog not appearing after recording on macOS/iOS
macOS:
- Replace deprecated NSSavePanel.begin(completionHandler:) with async begin() API
- The old API has been deprecated since macOS 12 and may silently fail on macOS 26
- Added diagnostic logging throughout recording completion flow

iOS:
- Added diagnostic logging to track onRecordingSaved → pendingExportURL → sheet chain
- Logs file existence, size after recording completes

Diagnostic logging added to help verify the save dialog flow:
- macOS: file size check, showSaveDialog entry, NSSavePanel response
- iOS: recordStream output verification, onRecordingSaved call, sheet binding activation
2026-07-17 20:27:49 +08:00
01bf7d6f4a fix(iOS): Connect+Browse buttons — Connect opens Files for auth, Browse opens file picker. Add auto-opens Files. 2026-07-04 20:06:30 +08:00
6c7a6e567f fix(iOS): simplified — server list + system file picker. FileManager can't browse SMB directly on iOS, use .fileImporter instead. 2026-07-04 20:02:16 +08:00
3cb5b1d8a4 fix(iOS): connect flow — new SMB opens Files for auth, saved servers use FileManager directly. Both flows save to history. 2026-07-04 19:57:33 +08:00
6a605451e4 fix: use browseURL scheme to detect SMB context — iOS maps SMB files to file:// URLs 2026-07-04 19:55:07 +08:00
80e332bda0 feat: iOS — saved server list, built-in file browser, HTTP stream server
- LocalStreamServer: NWListener-based HTTP proxy, streams SMB via localhost
- Saved server list with delete, one-tap reconnect
- Removed file importer — all browsing in MiniPlayer
- Removed SMBStreamingLoader (custom scheme approach didn't work)
2026-07-04 19:51:42 +08:00
b1a04526a2 feat: SMB streaming via AVAssetResourceLoaderDelegate — no file copy, reads on-demand.
- SMBStreamingLoader: wraps smb:// as miniplayer-smb:// custom scheme
- PlayerBridge.playSMBSource(): creates AVURLAsset with resource loader
- iOS NetworkFileBrowser: tap SMB media → stream directly
- Removed old FileManager.copyItem approach
2026-07-04 18:24:10 +08:00
b9e65f306a fix(iOS): copy SMB files to local Documents before playing — AVPlayer can't handle smb:// URLs 2026-07-04 18:10:31 +08:00
bf734454f8 fix(iOS): SMB connect flow — use FileManager first, fallback to Files app. Extract shared buildFileItems helper. 2026-07-04 18:06:50 +08:00
592a23b02e fix(iOS): SMB URL detection — show alert guiding to Files app instead of trying to play. Add import UIKit. 2026-07-04 18:00:44 +08:00
d01baed1c9 test: SMB network share verified — mount /Volumes/sambashare, browse media dirs. Fix NSWorkspace API + MediaLibraryView platform guard 2026-07-04 17:39:13 +08:00
0a9ed6e746 feat: network file browser — browse SMB/NFS shares, auto-pair ASS subtitles
- macOS: browse /Volumes (mounted shares), manual SMB/NFS connect
- iOS: system file picker (Files app SMB) + manual URL entry
- Auto-detect matching .ass files when selecting media
- Network button in control toolbar
- loadExternalSubtitle() skeleton for future ASS parsing
2026-07-04 17:33:58 +08:00
1412c234f8 fix(iOS): move pendingExportURL to PlayerBridge — SwiftUI can now observe it and trigger save sheet 2026-07-03 08:29:02 +08:00
3ed5696ae0 fix(iOS): read file data into memory BEFORE revoking security-scoped access, prevents exists=false 2026-07-03 08:22:14 +08:00
6503712be9 fix: show file diagnostics (exists, size, magic bytes) directly on error screen 2026-07-03 08:19:53 +08:00
0e172e015e fix: add file magic number verification to diagnose corruption 2026-07-03 08:18:33 +08:00
beaeb3b4c6 fix: ensure AVAudioSession is active right before player.play(), add diagnostic logging 2026-07-03 08:17:32 +08:00
15b26ce416 fix: show full error details (code+domain+filename) on playback failure 2026-07-03 08:14:10 +08:00
e81af97437 fix: add device diagnostic log (miniplayer_diag.log in Documents) to trace playback issues 2026-07-02 22:58:57 +08:00
37d7338823 fix: change audio mode back to .default — .moviePlayback breaks all playback on iOS 26 2026-07-02 22:41:07 +08:00
6f786cd1a8 fix: revert to .moviePlayback audio mode for proper video A/V sync 2026-07-02 22:36:01 +08:00
0388ae2a45 fix: add diagnostics for local file playback — file existence, audio route, player rate 2026-07-02 22:31:16 +08:00
58c34250c5 fix(iOS): replace lock overlay with allowsHitTesting — icon now reliably unlocks 2026-07-02 22:24:51 +08:00
d519e9aa17 fix(iOS): fix lock overlay ZStack order — icon now above overlay, unlock shows toolbar 2026-07-02 22:20:26 +08:00
01116180d1 fix: compile errors — frame API + sheet binding for let hlsRecorder 2026-07-02 22:13:26 +08:00
4c38b06860 修复四个问题: 录制后弹保存窗/本地文件播放/左上角锁定/音轨循环切换
1. HLSRecorder: 添加 pendingExportURL,录制完成后通过 SwiftUI sheet 弹出分享面板
2. PlayerBridge: AVAudioSession mode 改为 .default 兼容视频+音频,本地文件加载失败增强日志
3. PlayerContentView: iOS 锁屏功能,30秒无操作自动锁定,左上角图标切换锁状态
4. ControlToolbar: 音轨按钮改为直接循环切换(仅多音轨时可用),添加 cycleTrack() 方法
2026-07-02 22:10:55 +08:00
a74a021518 fix(iOS): add CFBundleIcons to Info.plist so app icon loads from Assets.car 2026-07-02 21:57:33 +08:00
75a319d7fb fix(iOS): fix presentActivitySheet keyWindow deprecation, use windowScene.keyWindow + fallback 2026-07-02 21:54:21 +08:00
bfb7631714 fix(iOS): improve PiP KVO observation, fix recording stop flow and export sheet
- PiPController: add KVO on isPictureInPicturePossible, avoid duplicate setup, better logging
- HLSRecorder: add stopRequested check after Task.sleep to ensure recording exits cleanly
- HLSRecorder: add 120s timeout to remuxToMP4 via TaskGroup to prevent hanging
- HLSRecorder: improve presentActivitySheet VC lookup (key window, foregroundActive scene)
- Add detailed logging throughout recording/export flow for debugging
2026-07-02 21:13:24 +08:00
bf7d3de9ba iOS: PiP画中画、AirPlay投屏、录制保存弹窗、播放记录持久化恢复 2026-07-02 08:16:33 +08:00
ce5878957e fix(iOS): fix recording, playback compatibility, and media library UI
Recording:
- stopRecording() now only sets stopRequested=true, no longer cancels task
- Task exits polling loop naturally → merges TS segments → exports MP4
- System share sheet + Photos save shown on completion
- Added HEAD request to detect HLS Content-Type for non-.m3u8 URLs
- Faster exit when stopRequested && segments exist

Playback:
- Copy imported files to app Documents sandbox (security-scoped URLs expire after defer)
- Remove Referer header that blocks some streams; use iPhone UA only
- AVURLAsset options only for http/https schemes

Media Library UI (iOS):
- Replace NavigationSplitView with VStack + horizontal category chips
- Search bar at top, swipe actions for queue/delete
- scrollDismissesKeyboard(.interactively) on list
- Tap gesture sends resignFirstResponder to dismiss keyboard
- Compact rows with context menu, inline play button
- Close button in navigation bar
- presentationDetents(.medium) for tag/playlist sheets
2026-07-02 07:44:09 +08:00
88f1ecbe9c fix(iOS): rewrite HLSRecorder for continuous recording until user stops
- Poll m3u8 every 2s to download new segments (supports live HLS)
- For non-HLS URLs, download entire file
- Accumulate TS segments incrementally, merge on stop
- Remux TS→MP4 via AVAssetExportSession
- Show system share sheet + save to Photos on completion
- Proper cancellation support via Task.cancel()
2026-07-01 23:18:39 +08:00
44708f39ef feat(iOS): add recording, media library, and local file import
- Wire up HLSRecorder for iOS stream recording (toggleRecording)
- Add MediaLibraryView sheet for iOS (toggleLibraryWindow)
- Add .fileImporter for iOS local file playback (openFileDialog)
- Add Assets.xcassets with app icons
- Add UniformTypeIdentifiers import for iOS
- Add handleFileImport() with security-scoped resource access
2026-07-01 22:55:35 +08:00
4bfd4e5565 fix: .ipa 复制到项目根目录,Xcode Add App 弹窗可见 2026-07-01 22:05:33 +08:00
6c21bdbef7 fix: iOS .ipa 打包成功 - 修复 Team ID、Bundle.module、@main 入口点
- build-ios.sh: 设置正确 Team ID (LR8YT5M53U), 添加 GENERATE_INFOPLIST_FILE
- MiniPlayerApp.swift: Bundle.module → Bundle.main (非SPM), @main 条件编译
- 签名: Apple Development + Personal Team provisioning profile
- 产物: MiniPlayer.ipa (584K)
2026-07-01 21:38:52 +08:00
d22a5037b8 feat: iOS/macOS 双平台打包支持
- Package.swift: 重构为 MiniPlayerCore(共享库) + MiniPlayer(macOS) + MiniPlayeriOS(iOS) 三 target
- 所有源文件添加 #if os(macOS) / #if os(iOS) 条件编译
- HLSRecorder.swift: iOS 纯 Swift HLS 录制器(下载TS+合并+AVAssetExportSession转MP4)
- scripts/build-macos.sh: macOS 打包脚本 (.app + .dmg)
- scripts/build-ios.sh: iOS 打包脚本 (xcodegen + xcodebuild archive → .ipa)
- .gitignore: 排除构建产物
2026-07-01 08:29:16 +08:00
103b994c60 debug: 添加录制流程日志 2026-07-01 08:01:45 +08:00
16fdd72271 fix: 用 NSEvent.addLocalMonitorForEvents 替代 .onHover/tracking area
之前的方案(.onHover 和 .background tracking area)都不可靠:
- .onHover 在 macOS 上行为不稳定
- .background() 里的 NSView 被 AVPlayerLayer 挡住收不到鼠标事件

新方案:用 NSEvent.addLocalMonitorForEvents 在应用层监听 mouseMoved 事件,
直接检测鼠标是否在窗口 frame 内,完全绕过 SwiftUI 的 hover 机制。
加上双层防抖(lastState + currentlyVisible 检查)避免重复设置。
2026-07-01 07:48:16 +08:00
fde83a87bc fix: 用 NSTrackingArea 替代 .onHover 解决标题栏闪烁和红绿灯丢失问题
.onHover 在 macOS 上不可靠,鼠标离开后会误触发 true 导致标题栏短暂回来但没有红绿灯按钮。
改用 NSTrackingArea 的 mouseEntered/mouseExited 做可靠的鼠标追踪。
2026-07-01 07:42:16 +08:00
ec8c3bd51c fix: title bar shows/hides based on window hover, not just top strip
- Remove 28pt overlay hover detection
- Add .onHover to entire window content (ZStack)
- Extract setWindowTitleBarVisible() helper function
- Mouse enters window → show title bar, mouse leaves → hide
2026-06-30 23:54:36 +08:00
5a031a57ea fix: fully hide title bar including traffic lights
- Hide close/minimize/zoom buttons on startup
- Show all buttons + title on hover, hide on exit
- Use asyncAfter to ensure window is ready
- Find visible window instead of first window
- Enable window drag by background when title bar hidden
2026-06-30 23:49:32 +08:00
03b8ef8d40 feat: URL deduplication for media library and queue
- On load: merge duplicate URLs (keep first, merge tags/liked/position)
- addItem: check queue for existing URL, show toast if duplicate
- addItemNoPlay: skip if URL already in queue
- Add hasItem(url:) helper
- Playlist references updated when merging duplicates
2026-06-30 23:45:02 +08:00
7c1a84c413 feat: title bar hover to show/hide
- Title bar hidden by default (titleVisibility + titlebarAppearsTransparent)
- Mouse enter top 28pt area: show title bar
- Mouse exit: hide title bar
- Decouple title visibility from toolbar state
2026-06-30 23:27:14 +08:00