Exemple #1
0
        public IDictionary <List <BaseItem>, List <BaseItem> > GetItemsByActor(User user, List <string> actorNames)
        {
            var actors = new List <BaseItem>();

            foreach (var actor in actorNames)
            {
                var actorName  = StringNormalization.ValidateSpeechQueryString(actor);
                var actorQuery = LibraryManager.GetItemsResult(new InternalItemsQuery()
                {
                    IncludeItemTypes = new[] { "Person" },
                    SearchTerm       = actorName,
                    Recursive        = true
                });

                if (actorQuery.TotalRecordCount <= 0)
                {
                    continue;
                }

                actors.Add(actorQuery.Items[0]);
            }

            var query = LibraryManager.GetItemsResult(new InternalItemsQuery(user)
            {
                IncludeItemTypes = new[] { "Series", "Movie" },
                Recursive        = true,
                PersonIds        = actors.Select(a => a.InternalId).ToArray()
            });

            return(new Dictionary <List <BaseItem>, List <BaseItem> >()
            {
                { actors, query.Items.ToList() }
            });
        }
        protected static void UpComingEpisodes(StringBuilder speech, List <BaseItem> items, DateTime date)
        {
            speech.Append("There ");
            speech.Append(items?.Count > 1 ? "are" : "is");
            speech.Append(SayAsCardinal(items?.Count.ToString()));
            speech.Append(" upcoming episode");
            speech.Append(items?.Count > 1 ? "s" : "");

            speech.Append($" scheduled to air over the next {(date - DateTime.Now).Days} days.");
            speech.Append(InsertStrengthBreak(StrengthBreak.weak));

            var schedule = items.DistinctBy(item => item.Parent.ParentId).ToList();

            var dateGroup = schedule.GroupBy(s => s?.PremiereDate);

            foreach (var d in dateGroup)
            {
                // ReSharper disable once PossibleNullReferenceException
                // ReSharper disable once PossibleInvalidOperationException
                speech.Append($"On {d.Key.Value.DayOfWeek}'s:");
                speech.Append(InsertStrengthBreak(StrengthBreak.strong));
                var i = 1;
                foreach (var item in d)
                {
                    speech.Append(StringNormalization.ValidateSpeechQueryString(item.Parent.Parent.Name));
                    if (item.IndexNumber == 1)
                    {
                        speech.Append($" which will premiere season {SayAsCardinal(item.Parent.IndexNumber.ToString())} ");
                        speech.Append(SayAsDate(Date.md, d.Key.Value.ToString("M/d")));
                        speech.Append(InsertStrengthBreak(StrengthBreak.weak));
                    }

                    speech.Append(", ");
                    if (d.Count() > 1 && i == d.Count() - 1)
                    {
                        speech.Append(" and ");
                    }

                    i++;
                }
            }

            speech.Append(
                $"This completes the list of episodes scheduled for the next {(date - DateTime.Now).Days} days. ");
        }
        protected static void NewLibraryItems(StringBuilder speech, List <BaseItem> items, DateTime date, IAlexaSession session)
        {
            speech.Append("There ");
            speech.Append(items?.Count > 1 ? "are" : "is");
            speech.Append(SayAsCardinal(items?.Count.ToString()));
            speech.Append(" new ");
            speech.Append(items?.Count > 1 ? items[0].GetType().Name + "s" : items?[0].GetType().Name);

            //var date = DateTime.Parse(query.args[0]);
            speech.Append($" added in the past {(date - DateTime.Now).Days * -1} days. ");

            if (!session.supportsApl)
            {
                speech.Append(string.Join($", {InsertStrengthBreak(StrengthBreak.weak)}",
                                          // ReSharper disable once AssignNullToNotNullAttribute
                                          items?.ToArray().Select(item => StringNormalization.ValidateSpeechQueryString(item.Name))));
            }
        }
        protected static void ItemBrowse(StringBuilder speech, BaseItem item, IAlexaSession session, bool deviceAvailable = true)
        {
            if (deviceAvailable == false)
            {
                speech.Append(GetSpeechPrefix(SpeechPrefix.DYSFLUENCY_NEGATIVE));
                speech.Append(InsertStrengthBreak(StrengthBreak.weak));
                speech.Append(GetSpeechPrefix(SpeechPrefix.APOLOGETIC));
                speech.Append(InsertStrengthBreak(StrengthBreak.weak));
                speech.Append("That device is currently unavailable.");
                return;
            }

            //speech.Append(GetSpeechPrefix(SpeechPrefix.COMPLIANCE));
            speech.Append(InsertStrengthBreak(StrengthBreak.weak));
            if (RandomIndex.NextDouble() > 0.5 && !item.IsFolder) //Randomly incorporate "Here is.." into phrasing
            {
                speech.Append("Here is ");
            }

            var name = StringNormalization.ValidateSpeechQueryString(item.Name);

            speech.Append(name);

            if (!item.IsFolder) //Don't describe a rating of a library or collection folder.
            {
                var rating = item.OfficialRating;
                speech.Append(", ");
                speech.Append(string.IsNullOrEmpty(rating) ? "unrated" : $"Rated {rating}");
            }

            if (!session.hasRoom)
            {
                return;
            }
            speech.Append(InsertStrengthBreak(StrengthBreak.weak));
            speech.Append("Showing in the ");
            speech.Append(session.room.Name);
        }
        public async Task <string> Response()
        {
            await AlexaResponseClient.Instance.PostProgressiveResponse("OK.",
                                                                       AlexaRequest.context.System.apiAccessToken, AlexaRequest.request.requestId);

            //TODO: Why does validating a room throw an object exception in this class? No other Intent class throws an object exception here.
            try
            {
                Session.room = await RoomContextManager.Instance.ValidateRoom(AlexaRequest, Session);
            }
            catch { } //catch the exception and throw it away. If there is a room requested at this point there will be no exception.
            Session.hasRoom = !(Session.room is null);
            if (!Session.hasRoom && !Session.supportsApl)
            {
                Session.PersistedRequestData = AlexaRequest;
                AlexaSessionManager.Instance.UpdateSession(Session, null);
                return(await RoomContextManager.Instance.RequestRoom(AlexaRequest, Session));
            }

            var request           = AlexaRequest.request;
            var intent            = request.intent;
            var slots             = intent.slots;
            var collectionRequest = slots.MovieCollection.value ?? slots.Movie.value;

            collectionRequest = StringNormalization.ValidateSpeechQueryString(collectionRequest);

            ServerController.Instance.Log.Info($"Collection Request: {collectionRequest}");

            var collection         = ServerDataQuery.Instance.GetCollectionItems(Session.User, collectionRequest);
            var collectionItems    = collection.Values.FirstOrDefault();
            var collectionBaseItem = collection.Keys.FirstOrDefault();

            //Parental Control check for baseItem
            if (!(collectionBaseItem is null))
            {
                if (!collectionBaseItem.IsParentalAllowed(Session.User))
                {
                    if (Plugin.Instance.Configuration.EnableServerActivityLogNotifications)
                    {
                        await ServerController.Instance.CreateActivityEntry(LogSeverity.Warn,
                                                                            $"{Session.User} attempted to view a restricted item.", $"{Session.User} attempted to view {collectionBaseItem.Name}.").ConfigureAwait(false);
                    }

                    var genericLayoutProperties = await DataSourcePropertiesManager.Instance.GetGenericViewPropertiesAsync($"Stop! Rated {collectionBaseItem.OfficialRating}", "/particles");

                    var aplaDataSource = await DataSourcePropertiesManager.Instance.GetAudioResponsePropertiesAsync(new InternalAudioResponseQuery()
                    {
                        SpeechResponseType = SpeechResponseType.ParentalControlNotAllowed,
                        item    = collectionBaseItem,
                        session = Session
                    });

                    return(await AlexaResponseClient.Instance.BuildAlexaResponseAsync(new Response()
                    {
                        shouldEndSession = true,

                        directives = new List <IDirective>()
                        {
                            await RenderDocumentDirectiveManager.Instance.RenderVisualDocumentDirectiveAsync(genericLayoutProperties, Session),
                            await RenderDocumentDirectiveManager.Instance.RenderAudioDocumentDirectiveAsync(aplaDataSource)
                        }
                    }, Session));
                }
            }

            if (Session.hasRoom)
            {
                try
                {
                    await ServerController.Instance.BrowseItemAsync(Session, collectionBaseItem);
                }
                catch (Exception exception)
                {
                    ServerController.Instance.Log.Error(exception.Message);
                }
            }

            var sequenceLayoutProperties = await DataSourcePropertiesManager.Instance.GetBaseItemCollectionSequenceViewPropertiesAsync(collectionItems, collectionBaseItem);

            //Update Session
            Session.NowViewingBaseItem = collectionBaseItem;
            AlexaSessionManager.Instance.UpdateSession(Session, sequenceLayoutProperties);

            var renderDocumentDirective = await RenderDocumentDirectiveManager.Instance.RenderVisualDocumentDirectiveAsync(sequenceLayoutProperties, Session);

            return(await AlexaResponseClient.Instance.BuildAlexaResponseAsync(new Response()
            {
                outputSpeech = new OutputSpeech()
                {
                    phrase = $"{collectionBaseItem?.Name}",
                },
                shouldEndSession = null,
                directives = new List <IDirective>()
                {
                    renderDocumentDirective
                },
            }, Session));
        }
        public async Task <string> Response()
        {
            await AlexaResponseClient.Instance.PostProgressiveResponse($"OK. { SpeechBuilderService.GetSpeechPrefix(SpeechPrefix.REPOSE)}.",
                                                                       AlexaRequest.context.System.apiAccessToken, AlexaRequest.request.requestId);

            Session.room = await RoomContextManager.Instance.ValidateRoom(AlexaRequest, Session);

            Session.hasRoom = !(Session.room is null);
            if (!Session.hasRoom && !Session.supportsApl)
            {
                Session.PersistedRequestData = AlexaRequest;
                AlexaSessionManager.Instance.UpdateSession(Session, null);
                return(await RoomContextManager.Instance.RequestRoom(AlexaRequest, Session));
            }

            var request = AlexaRequest.request;
            var intent  = request.intent;
            var slots   = intent.slots;

            var searchName = (slots.Movie.value ?? slots.Series.value) ?? slots.MovieCollection.value;

            searchName = StringNormalization.ValidateSpeechQueryString(searchName);

            if (string.IsNullOrEmpty(searchName))
            {
                return(await new NotUnderstood(AlexaRequest, Session).Response());
            }

            var result = ServerDataQuery.Instance.QuerySpeechResultItem(searchName, new[] { "Movie", "Series", "Collection" });

            if (result is null)
            {
                var aplaDataSourceProperties = await DataSourcePropertiesManager.Instance.GetAudioResponsePropertiesAsync(new InternalAudioResponseQuery()
                {
                    SpeechResponseType = SpeechResponseType.NoItemExists
                });

                return(await AlexaResponseClient.Instance.BuildAlexaResponseAsync(new Response()
                {
                    shouldEndSession = true,
                    directives = new List <IDirective>()
                    {
                        await RenderDocumentDirectiveManager.Instance.RenderAudioDocumentDirectiveAsync(aplaDataSourceProperties)
                    }
                }, Session));
            }

            //User should not access this item. Warn the user, and place a notification in the Emby Activity Label
            if (!result.IsParentalAllowed(Session.User))
            {
                try
                {
                    var config = Plugin.Instance.Configuration;
                    if (config.EnableServerActivityLogNotifications)
                    {
                        await ServerController.Instance.CreateActivityEntry(LogSeverity.Warn,
                                                                            $"{Session.User} attempted to view a restricted item.",
                                                                            $"{Session.User} attempted to view {result.Name}.");
                    }
                }
                catch { }

                var genericLayoutProperties = await DataSourcePropertiesManager.Instance.GetGenericViewPropertiesAsync($"Stop! Rated {result.OfficialRating}", "/particles");

                var parentalControlNotAllowedAudioProperties = await DataSourcePropertiesManager.Instance.GetAudioResponsePropertiesAsync(new InternalAudioResponseQuery()
                {
                    SpeechResponseType = SpeechResponseType.ParentalControlNotAllowed,
                    item    = result,
                    session = Session
                });

                return(await AlexaResponseClient.Instance.BuildAlexaResponseAsync(new Response()
                {
                    shouldEndSession = null,
                    directives = new List <IDirective>()
                    {
                        await RenderDocumentDirectiveManager.Instance.RenderVisualDocumentDirectiveAsync(genericLayoutProperties, Session),
                        await RenderDocumentDirectiveManager.Instance.RenderAudioDocumentDirectiveAsync(parentalControlNotAllowedAudioProperties)
                    }
                }, Session));
            }

            if (Session.hasRoom)
            {
                try
                {
                    await ServerController.Instance.BrowseItemAsync(Session, result);
                }
                catch (Exception exception)
                {
                    ServerController.Instance.Log.Error(exception.Message);
                }
            }

            var sequenceLayoutProperties = await DataSourcePropertiesManager.Instance.GetBaseItemDetailViewPropertiesAsync(result, Session);

            var aplaDataSource1 = await DataSourcePropertiesManager.Instance.GetAudioResponsePropertiesAsync(new InternalAudioResponseQuery()
            {
                SpeechResponseType = SpeechResponseType.ItemBrowse,
                item    = result,
                session = Session
            }
                                                                                                             );

            //Update Session
            Session.NowViewingBaseItem = result;
            AlexaSessionManager.Instance.UpdateSession(Session, sequenceLayoutProperties);

            var renderDocumentDirective = await RenderDocumentDirectiveManager.Instance.RenderVisualDocumentDirectiveAsync(sequenceLayoutProperties, Session);

            var renderAudioDirective = await RenderDocumentDirectiveManager.Instance.RenderAudioDocumentDirectiveAsync(aplaDataSource1);

            try
            {
                return(await AlexaResponseClient.Instance.BuildAlexaResponseAsync(new Response()
                {
                    shouldEndSession = null,
                    directives = new List <IDirective>()
                    {
                        renderDocumentDirective,
                        renderAudioDirective
                    }
                }, Session));
            }
            catch (Exception exception)
            {
                throw new Exception("I was unable to build the render document. " + exception.Message);
            }
        }