Phase D (T2-10): media playlist - auto-collect detected media, flyout management, player window (native+hls.js+dash.js bundles), persistence, auto-next (101 tests GREEN)
This commit is contained in:
parent
406957088f
commit
40c1b39b70
8 changed files with 491 additions and 0 deletions
|
|
@ -40,6 +40,10 @@ public partial class MainWindow : Window
|
|||
private readonly ObservableCollection<HistoryEntry> _history = new();
|
||||
private bool _suggesting; // 주소창 인라인 자동완성 도중 (TextChanged 재귀 방지)
|
||||
|
||||
// Phase D: 미디어 재생목록 (T2-10)
|
||||
private readonly MediaPlaylist _playlist = new();
|
||||
private PlayerWindow? _player;
|
||||
|
||||
// Phase C: 팔레트/부스트/워크스페이스/레이아웃
|
||||
private readonly CommandPalette _palette = new();
|
||||
private BoostStore _boostStore = null!;
|
||||
|
|
@ -101,6 +105,7 @@ public partial class MainWindow : Window
|
|||
_workspaces = System.Text.Json.JsonSerializer.Deserialize<List<WorkspaceSnapshot>>(File.ReadAllText(wsPath)) ?? new();
|
||||
}
|
||||
catch { }
|
||||
_playlist.Load(Path.Combine(AppDataDir, "playlist.json"));
|
||||
BuildPalette();
|
||||
|
||||
Loaded += async (_, _) => await InitializeBrowserAsync();
|
||||
|
|
@ -227,6 +232,8 @@ public partial class MainWindow : Window
|
|||
|
||||
// T1-5 다운로드 속도 갱신 타이머
|
||||
DownloadsList.ItemsSource = _pageDownloads.Items;
|
||||
PlaylistList.ItemsSource = _playlist.Tracks;
|
||||
PlaylistEmptyHint.Visibility = _playlist.Tracks.Count == 0 ? Visibility.Visible : Visibility.Collapsed;
|
||||
_speedTimer = new System.Windows.Threading.DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
|
||||
_speedTimer.Tick += (_, _) =>
|
||||
{
|
||||
|
|
@ -451,6 +458,7 @@ public partial class MainWindow : Window
|
|||
else
|
||||
{
|
||||
_manager.LogPanel($"★ 미디어 감지 [{ct}] {FmtLen(len)}: {uri}");
|
||||
AddToPlaylist(uri, GuessTitle(uri), MediaKind.Direct.ToString(), referer);
|
||||
_manager.OnDetected(new DetectionContext(uri, referer, MediaKind.Direct, ct));
|
||||
}
|
||||
}
|
||||
|
|
@ -870,6 +878,7 @@ public partial class MainWindow : Window
|
|||
ConfigStore.Save(_config);
|
||||
// T1-10 세션 저장: 탭 URL/활성/핀 보존
|
||||
try { if (_tabs != null) TabSessionStore.Save(SessionPath, _tabs.CaptureSession()); } catch { }
|
||||
try { _playlist.Save(Path.Combine(AppDataDir, "playlist.json")); } catch { } // T2-10
|
||||
}
|
||||
|
||||
// ---- 개인정보 보호 모드 + 브라우저 데이터 관리 ----
|
||||
|
|
@ -1141,6 +1150,8 @@ public partial class MainWindow : Window
|
|||
_palette.Register("인쇄", "print pdf", () => { try { Cv?.ShowPrintUI(); } catch { } });
|
||||
_palette.Register("저장 폴더 열기", "folder open output", () => OpenInExplorer(null));
|
||||
_palette.Register("이 페이지 즐겨찾기", "bookmark add star", () => AddBookmark_Click(this, new RoutedEventArgs()));
|
||||
_palette.Register("미디어 재생목록", "playlist play media 음악 영상", () => { PlaylistPopup.IsOpen = true; });
|
||||
_palette.Register("재생목록 재생", "playlist play start", OpenPlayer);
|
||||
_palette.RegisterSeparator();
|
||||
_palette.RegisterDynamic(() => _tabs.Tabs
|
||||
.Select(t => new PaletteCommand($"탭 전환: {Trunc(t.Title, 40)}", "tab go switch", () => _tabs.Activate(t)))
|
||||
|
|
@ -1475,6 +1486,58 @@ public partial class MainWindow : Window
|
|||
Log($"워크스페이스 '{ws.Name}' 전환 ({ws.Urls.Count} 탭)");
|
||||
}
|
||||
|
||||
// ---- T2-10 미디어 재생목록 ----
|
||||
private void AddToPlaylist(string url, string title, string kind, string? referer)
|
||||
{
|
||||
_playlist.Add(new MediaTrack(url, Trunc(title, 70), kind, DateTime.UtcNow, Referer: referer));
|
||||
try { _playlist.Save(Path.Combine(AppDataDir, "playlist.json")); } catch { }
|
||||
PlaylistEmptyHint.Visibility = _playlist.Tracks.Count == 0 ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private static string GuessTitle(string url)
|
||||
{
|
||||
try
|
||||
{
|
||||
var name = Path.GetFileName(new Uri(url).AbsolutePath);
|
||||
return string.IsNullOrWhiteSpace(name) ? url : Uri.UnescapeDataString(name);
|
||||
}
|
||||
catch { return url; }
|
||||
}
|
||||
|
||||
private void TogglePlaylistPanel(object sender, RoutedEventArgs e)
|
||||
{
|
||||
PlaylistPopup.IsOpen = !PlaylistPopup.IsOpen;
|
||||
}
|
||||
|
||||
private void PlaylistPlay_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if ((sender as FrameworkElement)?.DataContext is MediaTrack t)
|
||||
{
|
||||
_playlist.CurrentIndex = _playlist.Tracks.IndexOf(t);
|
||||
OpenPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
private void PlaylistRemove_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if ((sender as FrameworkElement)?.DataContext is MediaTrack t) _playlist.Remove(t);
|
||||
}
|
||||
|
||||
private void PlaylistClear_Click(object sender, RoutedEventArgs e) => _playlist.Clear();
|
||||
|
||||
private void PlaylistPlayAll_Click(object sender, RoutedEventArgs e) => OpenPlayer();
|
||||
|
||||
private void OpenPlayer()
|
||||
{
|
||||
if (_player == null || _player.IsLoaded == false)
|
||||
{
|
||||
_player = new PlayerWindow(_env!, _config, _playlist) { Owner = this };
|
||||
_player.Closed += (_, _) => _player = null;
|
||||
_player.Show();
|
||||
}
|
||||
else { _player.Activate(); _player.PlayCurrent(); }
|
||||
}
|
||||
|
||||
// ---- 카드 액션 ----
|
||||
private void CardDownload_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue