private IEnumerable <AudioRecognitionItem> BuildPhraseList(AudioFeedResponse feeds, ILookup <string, string> feedAliasLookup)
        {
            foreach (var item in feeds.Items)
            {
                if (string.IsNullOrEmpty(item.Name?.Trim()))
                {
                    continue;
                }

                _log.LogDebug("Adding phrases for {Feed}", item.Name);
                _log.LogTrace("Adding {Feed} -> {Alias}", item.Name, item.Name);

                yield return(new AudioRecognitionItem()
                {
                    FeedName = item.Name, Alias = item.Name
                });

                if (feedAliasLookup.Contains(item.Name))
                {
                    _log.LogDebug("Found aliases for {Feed}", item.Name);

                    foreach (var alias in feedAliasLookup[item.Name])
                    {
                        _log.LogTrace("Adding {Feed} -> {Alias}", item.Name, alias);
                        yield return(new AudioRecognitionItem()
                        {
                            FeedName = item.Name, Alias = alias
                        });
                    }
                }
            }
        }
        private async Task <bool> UpdateAudioFeedTableAsync(ApplicationDbContext dbContext, AudioFeedResponse feeds)
        {
            if (!feeds.Success)
            {
                return(false);
            }

            var feedNames = feeds.Items.Select(d => d.Name?.Trim()).Where(d => !string.IsNullOrEmpty(d));
            var dbFeeds   = await dbContext.AudioFeeds.ToListAsync();

            var  existingNames = new HashSet <string>(dbFeeds.Select(d => d.Name));
            bool anyChange     = false;

            foreach (var feedName in feedNames)
            {
                if (!existingNames.Contains(feedName))
                {
                    anyChange = true;
                    _log.LogDebug("Adding {Name} to provide alias functionality", feedName);
                    dbContext.AudioFeeds.Add(new AudioFeed()
                    {
                        Name = feedName
                    });
                }
            }

            return(!anyChange || await dbContext.SaveChangesAsync() > 0);
        }
        private async Task <UpdateVoiceRecognitionRequest> BuildUpdateRequest(CancellationToken cancellationToken,
                                                                              ApplicationDbContext dbContext, AudioFeedResponse audioFeedResponse)
        {
            var request  = new UpdateVoiceRecognitionRequest();
            var settings = (await dbContext.KeyValueSettings.ToListAsync(cancellationToken)).ToDictionary(d => d.Key, d => d.Value);

            request.AudioPhrase =
                settings.TryGetValue(KeyValueKind.VoiceRecognitionTriggerWordAudio, out var audioPhrase)
                                        ? audioPhrase
                                        : "Audio";

            request.TriggerPhrase =
                settings.TryGetValue(KeyValueKind.VoiceRecognitionTriggerWord, out var triggerWord)
                                        ? triggerWord
                                        : "Computer";

            var offAliasList =
                settings.TryGetValue(KeyValueKind.VoiceRecognitionTriggerWordOffAliases, out var offAliases)
                                        ? offAliases
                                        : "off";

            var onAliasList =
                settings.TryGetValue(KeyValueKind.VoiceRecognitionTriggerWordOnAliases, out var onAliases)
                                        ? onAliases
                                        : "on";

            var confirmMessageText =
                settings.TryGetValue(KeyValueKind.VoiceRecognitionConfirmMessage, out var confirmMessage)
                                        ? confirmMessage
                                        : "OK";

            var errorMessageText =
                settings.TryGetValue(KeyValueKind.VoiceRecognitionErrorMessage, out var errorMessage)
                                        ? errorMessage
                                        : "Error";

            var thresholdText =
                settings.TryGetValue(KeyValueKind.VoiceRecognitionThreshold, out var threshold)
                                        ? threshold
                                        : "25";

            var masterText =
                settings.TryGetValue(KeyValueKind.VoiceRecognitionTriggerWordAudioMaster, out var master)
                                        ? master
                                        : "master";

            var feedAliases = await dbContext.AudioFeedAliases
                              .Select(d => new ValueTuple <string, string>(d.Feed.Name, d.Alias)).ToListAsync(cancellationToken);

            var feedAliasDictionary = feedAliases.ToLookup(d => d.Item1, d => d.Item2);

            request.SynthesizerConfirmMessage = confirmMessageText;
            request.SynthesizerErrorMessage   = errorMessageText;
            request.OffAliases.AddRange(offAliasList.Split('|'));
            request.OnAliases.AddRange(onAliasList.Split('|'));
            request.AudioRecognitionItems.AddRange(BuildPhraseList(audioFeedResponse, feedAliasDictionary));
            request.RecognitionThreshold = int.TryParse(thresholdText, out var parsedThreshold) ? parsedThreshold : 25;
            request.MasterPhrase         = masterText;

            return(request);
        }