private void FetchLyric()
        {
            if (cts != null)
            {
                cts.Cancel();
                return;
            }

            cts    = new CancellationTokenSource();
            status = "가사 받는 중...";
            Lyric.Clear();
            AudioChanged?.BeginInvoke(null, null, null, null);
            Task.Run(async() =>
            {
                Lyric ret = null;
                var a     = LyricSource.GetLyricsAsync(AudioInfo);
                foreach (var lyricTask in a)
                {
                    cts.Token.ThrowIfCancellationRequested();
                    try
                    {
                        ret = await lyricTask;
                        break;
                    }
                    catch { }
                }

                ret?.Insert(0, new LyricLine());

                cts.Token.ThrowIfCancellationRequested();
                Lyric = ret ?? throw new LyricNotFoundException();
            }, cts.Token).ContinueWith(result =>
            {
                cts = null;
                if (result.IsCanceled)
                {
                    FetchLyric();
                }
                else if (result.IsFaulted)
                {
                    status = "가사 없음";
                    lyric.Clear();
                }
            });
        }
        public async Task GetLyricsAsyncTest()
        {
            var au = new Audio.AudioInfo {
                CheckSum = "좋은 날", Beatmap = new Beatmap.BeatmapMetadata {
                    Artist = "아이유", Title = "좋은 날"
                }
            };
            var   a = LyricSource.GetLyricsAsync(au);
            Lyric ret;
            int   inc = 0;

            foreach (var lyricTask in a)
            {
                try
                {
                    ret = await lyricTask;
                    break;
                }
                catch { }
                inc++;
            }
            Assert.IsTrue(inc > 0);
        }