AnkiIO 1.0.2
Build, validate, import, and export Anki-compatible decks from .NET
Loading...
Searching...
No Matches
AnkiInstallationDetector.cs
1using Microsoft.Win32;
2
3namespace AnkiIO;
4
22public static class AnkiInstallationDetector
23{
34 public static AnkiInstallation? Detect()
35 {
36 var candidates = new List<(string Path, string? Version)>();
37 var overridden = Environment.GetEnvironmentVariable("ANKI_EXECUTABLE");
38 if (!string.IsNullOrWhiteSpace(overridden))
39 {
40 candidates.Add((overridden, Environment.GetEnvironmentVariable("ANKI_VERSION")));
41 }
42
43 if (OperatingSystem.IsWindows())
44 {
45 AddWindowsRegistryCandidates(candidates);
46 candidates.Add((Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Programs", "Anki", "anki.exe"), null));
47 candidates.Add((Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Anki", "anki.exe"), null));
48 }
49 else if (OperatingSystem.IsMacOS())
50 {
51 candidates.Add(("/Applications/Anki.app/Contents/MacOS/anki", null));
52 }
53 else
54 {
55 candidates.Add(("/usr/bin/anki", null));
56 candidates.Add(("/usr/local/bin/anki", null));
57 }
58
59 var candidate = candidates.FirstOrDefault(item => File.Exists(item.Path));
60 if (candidate == default)
61 {
62 return null;
63 }
64
65 var text = candidate.Version;
66 if (string.IsNullOrWhiteSpace(text) && OperatingSystem.IsWindows())
67 {
68 text = System.Diagnostics.FileVersionInfo.GetVersionInfo(candidate.Path).ProductVersion;
69 }
70
71 text = string.IsNullOrWhiteSpace(text) ? "0.0" : text.Split([' ', '+'], StringSplitOptions.RemoveEmptyEntries)[0];
72 _ = Version.TryParse(text, out var version);
73 var data = GetDataDirectory();
74 var profileDirectories = data is null || !Directory.Exists(data) ? [] : Directory.GetDirectories(data);
75 return new AnkiInstallation(
76 Path.GetFullPath(candidate.Path),
77 Path.GetDirectoryName(Path.GetFullPath(candidate.Path))!,
78 version ?? new Version(0, 0),
79 text,
80 data,
81 profileDirectories.Length > 0,
82 profileDirectories.Any(directory => File.Exists(Path.Combine(directory, "collection.anki2")) || File.Exists(Path.Combine(directory, "collection.anki21"))),
83 profileDirectories.Any(directory => Directory.Exists(Path.Combine(directory, "collection.media"))),
84 data is not null && Directory.Exists(Path.Combine(data, "addons21")));
85 }
86
87 private static string? GetDataDirectory()
88 {
89 var overridden = Environment.GetEnvironmentVariable("ANKI_DATA_DIRECTORY");
90 if (!string.IsNullOrWhiteSpace(overridden))
91 {
92 return Path.GetFullPath(overridden);
93 }
94
95 if (OperatingSystem.IsWindows()) return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Anki2");
96 if (OperatingSystem.IsMacOS()) return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Library", "Application Support", "Anki2");
97 return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), ".local", "share", "Anki2");
98 }
99
100 [System.Runtime.Versioning.SupportedOSPlatform("windows")]
101 private static void AddWindowsRegistryCandidates(List<(string Path, string? Version)> candidates)
102 {
103 foreach (var hive in new[] { Registry.CurrentUser, Registry.LocalMachine })
104 {
105 using var uninstall = hive.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Uninstall");
106 if (uninstall is null) continue;
107 foreach (var name in uninstall.GetSubKeyNames())
108 {
109 using var key = uninstall.OpenSubKey(name);
110 if (key is null || !string.Equals(key.GetValue("DisplayName") as string, "Anki", StringComparison.OrdinalIgnoreCase)) continue;
111 var location = key.GetValue("InstallLocation") as string;
112 var icon = (key.GetValue("DisplayIcon") as string)?.Split(',')[0].Trim('"');
113 var path = !string.IsNullOrWhiteSpace(location) ? Path.Combine(location, "anki.exe") : icon;
114 if (!string.IsNullOrWhiteSpace(path)) candidates.Add((path, key.GetValue("DisplayVersion") as string));
115 }
116 }
117 }
118}
Discovers a local Anki executable and reports conservative profile-presence metadata.
static ? AnkiInstallation Detect()
Locates the first existing Anki executable using overrides and platform conventions.
Provides an immutable snapshot of an Anki application discovered on the local computer.