From 685f462959e4e57e226b7fd902e7e0909d3d2a2c Mon Sep 17 00:00:00 2001 From: Bogdan Date: Sat, 11 May 2024 16:29:07 +0300 Subject: [PATCH] New: Include trending and popular options for Discover Movies --- frontend/src/DiscoverMovie/DiscoverMovie.js | 18 ++++- .../DiscoverMovie/DiscoverMovieConnector.js | 3 + ...iscoverMovieOverviewOptionsModalContent.js | 49 +++++++++++- .../DiscoverMoviePosterOptionsModalContent.js | 48 +++++++++++- .../Table/DiscoverMovieTableOptions.js | 74 +++++++++++++++---- .../src/Store/Actions/discoverMovieActions.js | 12 ++- src/NzbDrone.Core/Localization/Core/en.json | 4 + .../ImportLists/ImportListMoviesController.cs | 34 +++++---- 8 files changed, 198 insertions(+), 44 deletions(-) diff --git a/frontend/src/DiscoverMovie/DiscoverMovie.js b/frontend/src/DiscoverMovie/DiscoverMovie.js index 2d9152ec7..19fafe947 100644 --- a/frontend/src/DiscoverMovie/DiscoverMovie.js +++ b/frontend/src/DiscoverMovie/DiscoverMovie.js @@ -75,9 +75,19 @@ class DiscoverMovie extends Component { const { items, sortKey, - sortDirection + sortDirection, + includeRecommendations, + includeTrending, + includePopular } = this.props; + if (includeRecommendations !== prevProps.includeRecommendations || + includeTrending !== prevProps.includeTrending || + includePopular !== prevProps.includePopular + ) { + this.props.dispatchFetchListMovies(); + } + if (sortKey !== prevProps.sortKey || sortDirection !== prevProps.sortDirection || hasDifferentItemsOrOrder(prevProps.items, items) @@ -443,6 +453,9 @@ DiscoverMovie.propTypes = { sortKey: PropTypes.string, sortDirection: PropTypes.oneOf(sortDirections.all), view: PropTypes.string.isRequired, + includeRecommendations: PropTypes.bool.isRequired, + includeTrending: PropTypes.bool.isRequired, + includePopular: PropTypes.bool.isRequired, isSyncingLists: PropTypes.bool.isRequired, isSmallScreen: PropTypes.bool.isRequired, onSortSelect: PropTypes.func.isRequired, @@ -451,7 +464,8 @@ DiscoverMovie.propTypes = { onScroll: PropTypes.func.isRequired, onAddMoviesPress: PropTypes.func.isRequired, onExcludeMoviesPress: PropTypes.func.isRequired, - onImportListSyncPress: PropTypes.func.isRequired + onImportListSyncPress: PropTypes.func.isRequired, + dispatchFetchListMovies: PropTypes.func.isRequired }; export default DiscoverMovie; diff --git a/frontend/src/DiscoverMovie/DiscoverMovieConnector.js b/frontend/src/DiscoverMovie/DiscoverMovieConnector.js index 530a95b4a..90d0f6143 100644 --- a/frontend/src/DiscoverMovie/DiscoverMovieConnector.js +++ b/frontend/src/DiscoverMovie/DiscoverMovieConnector.js @@ -17,15 +17,18 @@ import DiscoverMovie from './DiscoverMovie'; function createMapStateToProps() { return createSelector( + (state) => state.discoverMovie, createDiscoverMovieClientSideCollectionItemsSelector('discoverMovie'), createCommandExecutingSelector(commandNames.IMPORT_LIST_SYNC), createDimensionsSelector(), ( + discoverMovie, movies, isSyncingLists, dimensionsState ) => { return { + ...discoverMovie.options, ...movies, isSyncingLists, isSmallScreen: dimensionsState.isSmallScreen diff --git a/frontend/src/DiscoverMovie/Overview/Options/DiscoverMovieOverviewOptionsModalContent.js b/frontend/src/DiscoverMovie/Overview/Options/DiscoverMovieOverviewOptionsModalContent.js index d2bedc734..bfe152bce 100644 --- a/frontend/src/DiscoverMovie/Overview/Options/DiscoverMovieOverviewOptionsModalContent.js +++ b/frontend/src/DiscoverMovie/Overview/Options/DiscoverMovieOverviewOptionsModalContent.js @@ -49,7 +49,9 @@ class DiscoverMovieOverviewOptionsModalContent extends Component { showRatings: props.showRatings, showYear: props.showYear, showGenres: props.showGenres, - includeRecommendations: props.includeRecommendations + includeRecommendations: props.includeRecommendations, + includeTrending: props.includeTrending, + includePopular: props.includePopular }; } @@ -61,7 +63,9 @@ class DiscoverMovieOverviewOptionsModalContent extends Component { showRatings, showCertification, showGenres, - includeRecommendations + includeRecommendations, + includeTrending, + includePopular } = this.props; const state = {}; @@ -94,6 +98,14 @@ class DiscoverMovieOverviewOptionsModalContent extends Component { state.includeRecommendations = includeRecommendations; } + if (includeTrending !== prevProps.includeTrending) { + state.includeTrending = includeTrending; + } + + if (includePopular !== prevProps.includePopular) { + state.includePopular = includePopular; + } + if (!_.isEmpty(state)) { this.setState(state); } @@ -135,19 +147,22 @@ class DiscoverMovieOverviewOptionsModalContent extends Component { showRatings, showYear, showGenres, - includeRecommendations + includeRecommendations, + includeTrending, + includePopular } = this.state; return ( - Overview Options + {translate('OverviewOptions')}
{translate('IncludeRadarrRecommendations')} + + + {translate('IncludeTrending')} + + + + + + {translate('IncludePopular')} + + + + {translate('PosterSize')} @@ -246,6 +285,8 @@ DiscoverMovieOverviewOptionsModalContent.propTypes = { showCertification: PropTypes.bool.isRequired, showGenres: PropTypes.bool.isRequired, includeRecommendations: PropTypes.bool.isRequired, + includeTrending: PropTypes.bool.isRequired, + includePopular: PropTypes.bool.isRequired, onChangeOverviewOption: PropTypes.func.isRequired, onChangeOption: PropTypes.func.isRequired, onModalClose: PropTypes.func.isRequired diff --git a/frontend/src/DiscoverMovie/Posters/Options/DiscoverMoviePosterOptionsModalContent.js b/frontend/src/DiscoverMovie/Posters/Options/DiscoverMoviePosterOptionsModalContent.js index 1409ca06f..4d2743215 100644 --- a/frontend/src/DiscoverMovie/Posters/Options/DiscoverMoviePosterOptionsModalContent.js +++ b/frontend/src/DiscoverMovie/Posters/Options/DiscoverMoviePosterOptionsModalContent.js @@ -45,7 +45,9 @@ class DiscoverMoviePosterOptionsModalContent extends Component { this.state = { size: props.size, showTitle: props.showTitle, - includeRecommendations: props.includeRecommendations + includeRecommendations: props.includeRecommendations, + includeTrending: props.includeTrending, + includePopular: props.includePopular }; } @@ -53,7 +55,9 @@ class DiscoverMoviePosterOptionsModalContent extends Component { const { size, showTitle, - includeRecommendations + includeRecommendations, + includeTrending, + includePopular } = this.props; const state = {}; @@ -70,6 +74,14 @@ class DiscoverMoviePosterOptionsModalContent extends Component { state.includeRecommendations = includeRecommendations; } + if (includeTrending !== prevProps.includeTrending) { + state.includeTrending = includeTrending; + } + + if (includePopular !== prevProps.includePopular) { + state.includePopular = includePopular; + } + if (!_.isEmpty(state)) { this.setState(state); } @@ -107,13 +119,15 @@ class DiscoverMoviePosterOptionsModalContent extends Component { const { size, showTitle, - includeRecommendations + includeRecommendations, + includeTrending, + includePopular } = this.state; return ( - Poster Options + {translate('PosterOptions')} @@ -130,6 +144,30 @@ class DiscoverMoviePosterOptionsModalContent extends Component { /> + + {translate('IncludeTrending')} + + + + + + {translate('IncludePopular')} + + + + {translate('PosterSize')} @@ -172,6 +210,8 @@ DiscoverMoviePosterOptionsModalContent.propTypes = { size: PropTypes.string.isRequired, showTitle: PropTypes.bool.isRequired, includeRecommendations: PropTypes.bool.isRequired, + includeTrending: PropTypes.bool.isRequired, + includePopular: PropTypes.bool.isRequired, onChangePosterOption: PropTypes.func.isRequired, onChangeOption: PropTypes.func.isRequired, onModalClose: PropTypes.func.isRequired diff --git a/frontend/src/DiscoverMovie/Table/DiscoverMovieTableOptions.js b/frontend/src/DiscoverMovie/Table/DiscoverMovieTableOptions.js index 65c7cce09..bc45bb03c 100644 --- a/frontend/src/DiscoverMovie/Table/DiscoverMovieTableOptions.js +++ b/frontend/src/DiscoverMovie/Table/DiscoverMovieTableOptions.js @@ -15,17 +15,29 @@ class DiscoverMovieTableOptions extends Component { super(props, context); this.state = { - includeRecommendations: props.includeRecommendations + includeRecommendations: props.includeRecommendations, + includeTrending: props.includeTrending, + includePopular: props.includePopular }; } componentDidUpdate(prevProps) { - const { includeRecommendations } = this.props; + const { + includeRecommendations, + includeTrending, + includePopular + } = this.props; if (includeRecommendations !== prevProps.includeRecommendations) { - this.setState({ - includeRecommendations - }); + this.setState({ includeRecommendations }); + } + + if (includeTrending !== prevProps.includeTrending) { + this.setState({ includeTrending }); + } + + if (includePopular !== prevProps.includePopular) { + this.setState({ includePopular }); } } @@ -47,27 +59,57 @@ class DiscoverMovieTableOptions extends Component { render() { const { - includeRecommendations + includeRecommendations, + includeTrending, + includePopular } = this.state; return ( - - {translate('IncludeRadarrRecommendations')} + <> + + {translate('IncludeRadarrRecommendations')} - - + + + + + {translate('IncludeTrending')} + + + + + + {translate('IncludePopular')} + + + + ); } } DiscoverMovieTableOptions.propTypes = { includeRecommendations: PropTypes.bool.isRequired, + includeTrending: PropTypes.bool.isRequired, + includePopular: PropTypes.bool.isRequired, onChangeOption: PropTypes.func.isRequired }; diff --git a/frontend/src/Store/Actions/discoverMovieActions.js b/frontend/src/Store/Actions/discoverMovieActions.js index 41221c85e..0dc53240c 100644 --- a/frontend/src/Store/Actions/discoverMovieActions.js +++ b/frontend/src/Store/Actions/discoverMovieActions.js @@ -42,7 +42,9 @@ export const defaultState = { view: 'overview', options: { - includeRecommendations: true + includeRecommendations: true, + includeTrending: true, + includePopular: true }, defaults: { @@ -583,10 +585,14 @@ export const actionHandlers = handleThunks({ ...otherPayload } = payload; - const includeRecommendations = getState().discoverMovie.options.includeRecommendations; + const { + includeRecommendations = false, + includeTrending = false, + includePopular = false + } = getState().discoverMovie.options; const promise = createAjaxRequest({ - url: `/importlist/movie?includeRecommendations=${includeRecommendations}`, + url: `/importlist/movie?includeRecommendations=${includeRecommendations}&includeTrending=${includeTrending}&includePopular=${includePopular}`, data: otherPayload, traditional: true }).request; diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json index 6efc2caf9..f5867caaa 100644 --- a/src/NzbDrone.Core/Localization/Core/en.json +++ b/src/NzbDrone.Core/Localization/Core/en.json @@ -731,8 +731,12 @@ "IncludeCustomFormatWhenRenaming": "Include Custom Format when Renaming", "IncludeCustomFormatWhenRenamingHelpText": "Include in {Custom Formats} renaming format", "IncludeHealthWarnings": "Include Health Warnings", + "IncludePopular": "Include Popular", + "IncludePopularMoviesHelpText": "Include popular movies on TMDb", "IncludeRadarrRecommendations": "Include {appName} Recommendations", "IncludeRecommendationsHelpText": "Include {appName} recommended movies in discovery view", + "IncludeTrending": "Include Trending", + "IncludeTrendingMoviesHelpText": "Include trending movies on TMDb", "IncludeUnmonitored": "Include Unmonitored", "Indexer": "Indexer", "IndexerDownloadClientHealthCheckMessage": "Indexers with invalid download clients: {0}.", diff --git a/src/Radarr.Api.V3/ImportLists/ImportListMoviesController.cs b/src/Radarr.Api.V3/ImportLists/ImportListMoviesController.cs index 678892d78..751febd20 100644 --- a/src/Radarr.Api.V3/ImportLists/ImportListMoviesController.cs +++ b/src/Radarr.Api.V3/ImportLists/ImportListMoviesController.cs @@ -64,28 +64,31 @@ public object GetDiscoverMovies(bool includeRecommendations = false, bool includ if (includeRecommendations) { - var mapped = new List(); + var recommendedResults = _movieService.GetRecommendedTmdbIds(); - var results = _movieService.GetRecommendedTmdbIds(); - - if (results.Count > 0) + if (recommendedResults.Count > 0) { - mapped = _movieInfo.GetBulkMovieInfo(results).Select(m => new Movie { MovieMetadata = m }).ToList(); - } + var mapped = _movieInfo.GetBulkMovieInfo(recommendedResults).Select(m => new Movie { MovieMetadata = m }).ToList(); - realResults.AddRange(MapToResource(mapped.Where(x => x != null), movieLanguage)); - realResults.ForEach(x => x.IsRecommendation = true); + realResults.AddRange(MapToResource(mapped.Where(x => x != null), movieLanguage, isRecommendation: true)); + } } - // Add TMDB Trending - var trendingResults = _movieInfo.GetTrendingMovies(); + if (includeTrending) + { + // Add TMDB Trending + var trendingResults = _movieInfo.GetTrendingMovies(); - realResults.AddRange(MapToResource(trendingResults.Select(m => new Movie { MovieMetadata = m }).Where(x => x != null), movieLanguage, true)); + realResults.AddRange(MapToResource(trendingResults.Select(m => new Movie { MovieMetadata = m }).Where(x => x != null), movieLanguage, isTrending: true)); + } - // Add TMDB Popular - var popularResults = _movieInfo.GetPopularMovies(); + if (includePopular) + { + // Add TMDB Popular + var popularResults = _movieInfo.GetPopularMovies(); - realResults.AddRange(MapToResource(popularResults.Select(m => new Movie { MovieMetadata = m }).Where(x => x != null), movieLanguage, false, true)); + realResults.AddRange(MapToResource(popularResults.Select(m => new Movie { MovieMetadata = m }).Where(x => x != null), movieLanguage, isPopular: true)); + } // Add List Movies var listMovies = MapToResource(_listMovieService.GetAllForLists(_importListFactory.Enabled().Select(x => x.Definition.Id).ToList()), movieLanguage).ToList(); @@ -120,7 +123,7 @@ public object AddMovies([FromBody] List resource) return _addMovieService.AddMovies(newMovies, true).ToResource(0); } - private IEnumerable MapToResource(IEnumerable movies, Language language, bool isTrending = false, bool isPopular = false) + private IEnumerable MapToResource(IEnumerable movies, Language language, bool isRecommendation = false, bool isTrending = false, bool isPopular = false) { // Avoid calling for naming spec on every movie in filenamebuilder var namingConfig = _namingService.GetConfig(); @@ -140,6 +143,7 @@ private IEnumerable MapToResource(IEnumerable m resource.Title = translation?.Title ?? resource.Title; resource.Overview = translation?.Overview ?? resource.Overview; resource.Folder = _fileNameBuilder.GetMovieFolder(currentMovie, namingConfig); + resource.IsRecommendation = isRecommendation; resource.IsTrending = isTrending; resource.IsPopular = isPopular;