T1-4/T1-7: search engine resolver + site zoom store (TDD RED->GREEN, 32 tests)

This commit is contained in:
Yun Chan 2026-08-15 12:04:23 +09:00
parent 21b7c4d8bd
commit 470c9267f2
9 changed files with 522 additions and 0 deletions

View file

@ -0,0 +1,34 @@
namespace VideoDownloader.App.Browser;
/// <summary>검색엔진 정의. QueryTemplate 의 {0} 이 URL 인코딩된 검색어로 치환된다.</summary>
public sealed record SearchEngine(string Name, string Keyword, string QueryTemplate);
/// <summary>기본 프리셋 엔진. Keyword 는 주소창에서 `&lt;키워드&gt; &lt;검색어&gt;` 형태로 즉시 전환에 쓰인다.</summary>
public static class SearchEngines
{
public static readonly IReadOnlyList<SearchEngine> Presets = new[]
{
new SearchEngine("Google", "g", "https://www.google.com/search?q={0}"),
new SearchEngine("Bing", "b", "https://www.bing.com/search?q={0}"),
new SearchEngine("DuckDuckGo", "d", "https://duckduckgo.com/?q={0}"),
new SearchEngine("Naver", "n", "https://search.naver.com/search.naver?query={0}"),
new SearchEngine("YouTube", "yt", "https://www.youtube.com/results?search_query={0}"),
};
public static SearchEngine? FindByName(string? name, IEnumerable<SearchEngine>? extra = null)
{
var pool = extra != null ? Presets.Concat(extra) : Presets;
return pool.FirstOrDefault(e =>
string.Equals(e.Name, name, StringComparison.OrdinalIgnoreCase));
}
public static SearchEngine? FindByKeyword(string? keyword, IEnumerable<SearchEngine>? extra = null)
{
var pool = extra != null ? Presets.Concat(extra) : Presets;
return pool.FirstOrDefault(e =>
string.Equals(e.Keyword, keyword, StringComparison.OrdinalIgnoreCase));
}
}
/// <summary>주소창 입력에 대한 네비게이션 의도. IsUrl=false 면 Target 은 검색 결과 URL.</summary>
public sealed record NavigationIntent(bool IsUrl, string Target, string? EngineName = null);