-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProgram.cs
More file actions
94 lines (82 loc) · 3.08 KB
/
Copy pathProgram.cs
File metadata and controls
94 lines (82 loc) · 3.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// Composition root for the terminal player. Everything is wired here and resolved through DI so the
// pieces (catalog, auth flows, audio backend, screens) stay decoupled and individually replaceable.
using System.Globalization;
using Microsoft.Extensions.DependencyInjection;
using Spectre.Console;
using YandexMusic;
using YandexMusic.Player;
using YandexMusic.Player.Auth;
using YandexMusic.Player.Catalog;
using YandexMusic.Player.Playback;
using YandexMusic.Player.Screens;
using YandexMusic.Player.Ui;
// The UI language follows the OS UI language by default; YM_PLAYER_LANG (e.g. "ru" or "en") overrides
// it. Localized strings are resolved from the .resx satellites via CurrentUICulture.
var forcedLanguage = Environment.GetEnvironmentVariable("YM_PLAYER_LANG");
if (!string.IsNullOrWhiteSpace(forcedLanguage))
{
var culture = CultureInfo.GetCultureInfo(forcedLanguage);
CultureInfo.CurrentUICulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
}
using var cts = new CancellationTokenSource();
Console.CancelKeyPress += (_, e) =>
{
e.Cancel = true;
cts.Cancel();
};
var services = new ServiceCollection();
// The library client and the app's services.
services.AddSingleton<IYandexMusicClient>(_ => new YandexMusicClient());
services.AddSingleton<ISessionStore, FileSessionStore>();
services.AddSingleton<IMusicCatalog, MusicCatalog>();
// Sign-in methods (order = menu order).
services.AddSingleton<IAuthFlow, TokenAuthFlow>();
services.AddSingleton<IAuthFlow, DeviceCodeAuthFlow>();
services.AddSingleton<IAuthFlow, QrAuthFlow>();
services.AddSingleton<IAuthFlow, PasswordAuthFlow>();
services.AddSingleton<AuthService>();
// Audio: a real backend on Windows, the simulated one everywhere (and as a fallback). Swapping in a
// cross-platform backend later means changing only this line.
services.AddSingleton<IAudioPlayer>(_ =>
{
IAudioPlayer? real = null;
#if WINDOWS
if (OperatingSystem.IsWindows())
{
real = new NAudioPlayer();
}
#endif
return new ResilientAudioPlayer(real, new SimulatedAudioPlayer());
});
services.AddSingleton<PlaybackController>();
services.AddSingleton<PlayReporter>();
// Screens.
services.AddSingleton<MainMenuScreen>();
services.AddSingleton<SearchScreen>();
services.AddSingleton<AlbumScreen>();
services.AddSingleton<AlbumsScreen>();
services.AddSingleton<PlaylistScreen>();
services.AddSingleton<PlaylistsScreen>();
services.AddSingleton<TrackListScreen>();
services.AddSingleton<NowPlayingScreen>();
services.AddSingleton<LyricsScreen>();
services.AddSingleton<RemoteScreen>();
services.AddSingleton<PlayerApp>();
await using var provider = services.BuildServiceProvider();
// The reporter only observes playback, so nothing injects it — pull it once to activate.
_ = provider.GetRequiredService<PlayReporter>();
if (!AnsiConsole.Profile.Capabilities.Interactive)
{
AnsiConsole.MarkupLine(Strings.NeedsInteractive);
return;
}
try
{
await provider.GetRequiredService<PlayerApp>().RunAsync(cts.Token);
}
catch (OperationCanceledException)
{
// Ctrl+C — exit quietly.
}
AnsiConsole.MarkupLine("[grey]Bye.[/]");