New: Trending and Popular Movies in Discovery

pull/9704/head
Qstick 4 months ago
parent 3b1d4460ad
commit 0be449033f

@ -19,7 +19,7 @@ function ImportListList({ lists, importListList }) {
return ( return (
<Label <Label
key={list.id} key={list.id}
kind={kinds.INFO} kind={kinds.SUCCESS}
size={sizes.MEDIUM} size={sizes.MEDIUM}
> >
{list.name} {list.name}

@ -97,6 +97,8 @@ class DiscoverMovieOverview extends Component {
isExisting, isExisting,
isExcluded, isExcluded,
isRecommendation, isRecommendation,
isPopular,
isTrending,
isSelected, isSelected,
overviewOptions, overviewOptions,
...otherProps ...otherProps
@ -214,6 +216,26 @@ class DiscoverMovieOverview extends Component {
null null
} }
{
isPopular ?
<Label
kind={kinds.INFO}
>
{translate('Popular')}
</Label> :
null
}
{
isTrending ?
<Label
kind={kinds.INFO}
>
{translate('Trending')}
</Label> :
null
}
<ImportListListConnector <ImportListListConnector
lists={lists} lists={lists}
/> />
@ -283,6 +305,8 @@ DiscoverMovieOverview.propTypes = {
isExisting: PropTypes.bool.isRequired, isExisting: PropTypes.bool.isRequired,
isExcluded: PropTypes.bool.isRequired, isExcluded: PropTypes.bool.isRequired,
isRecommendation: PropTypes.bool.isRequired, isRecommendation: PropTypes.bool.isRequired,
isPopular: PropTypes.bool.isRequired,
isTrending: PropTypes.bool.isRequired,
isSelected: PropTypes.bool, isSelected: PropTypes.bool,
lists: PropTypes.arrayOf(PropTypes.number).isRequired, lists: PropTypes.arrayOf(PropTypes.number).isRequired,
onSelectedChange: PropTypes.func.isRequired onSelectedChange: PropTypes.func.isRequired

@ -57,10 +57,12 @@
flex: 0 0 115px; flex: 0 0 115px;
} }
.isTrending,
.isPopular,
.isRecommendation { .isRecommendation {
composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css'; composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css';
flex: 0 0 50px; flex: 0 0 30px;
} }
.actions { .actions {

@ -7,7 +7,9 @@ interface CssExports {
'digitalRelease': string; 'digitalRelease': string;
'genres': string; 'genres': string;
'inCinemas': string; 'inCinemas': string;
'isPopular': string;
'isRecommendation': string; 'isRecommendation': string;
'isTrending': string;
'lists': string; 'lists': string;
'originalLanguage': string; 'originalLanguage': string;
'physicalRelease': string; 'physicalRelease': string;

@ -103,6 +103,40 @@ class DiscoverMovieHeader extends Component {
); );
} }
if (name === 'isTrending') {
return (
<VirtualTableHeaderCell
key={name}
className={styles[name]}
name={name}
isSortable={true}
{...otherProps}
>
<Icon
name={icons.TRENDING}
size={12}
/>
</VirtualTableHeaderCell>
);
}
if (name === 'isPopular') {
return (
<VirtualTableHeaderCell
key={name}
className={styles[name]}
name={name}
isSortable={true}
{...otherProps}
>
<Icon
name={icons.POPULAR}
size={12}
/>
</VirtualTableHeaderCell>
);
}
return ( return (
<VirtualTableHeaderCell <VirtualTableHeaderCell
key={name} key={name}

@ -76,10 +76,12 @@
flex: 1 0 110px; flex: 1 0 110px;
} }
.isTrending,
.isPopular,
.isRecommendation { .isRecommendation {
composes: cell; composes: cell;
flex: 0 0 50px; flex: 0 0 30px;
} }
.actions { .actions {
@ -95,6 +97,11 @@
margin-top: 0; margin-top: 0;
} }
.statusIcon {
width: 20px !important;
text-align: center;
}
.externalLinks { .externalLinks {
margin-right: 0.5em; margin-right: 0.5em;
} }

@ -12,7 +12,9 @@ interface CssExports {
'externalLinks': string; 'externalLinks': string;
'genres': string; 'genres': string;
'inCinemas': string; 'inCinemas': string;
'isPopular': string;
'isRecommendation': string; 'isRecommendation': string;
'isTrending': string;
'lists': string; 'lists': string;
'originalLanguage': string; 'originalLanguage': string;
'physicalRelease': string; 'physicalRelease': string;
@ -21,6 +23,7 @@ interface CssExports {
'runtime': string; 'runtime': string;
'sortTitle': string; 'sortTitle': string;
'status': string; 'status': string;
'statusIcon': string;
'studio': string; 'studio': string;
} }
export const cssExports: CssExports; export const cssExports: CssExports;

@ -82,6 +82,8 @@ class DiscoverMovieRow extends Component {
isExisting, isExisting,
isExcluded, isExcluded,
isRecommendation, isRecommendation,
isTrending,
isPopular,
isSelected, isSelected,
lists, lists,
onSelectedChange onSelectedChange
@ -305,6 +307,7 @@ class DiscoverMovieRow extends Component {
{ {
isRecommendation ? isRecommendation ?
<Icon <Icon
className={styles.statusIcon}
name={icons.RECOMMENDED} name={icons.RECOMMENDED}
size={12} size={12}
title={translate('MovieIsRecommend')} title={translate('MovieIsRecommend')}
@ -315,6 +318,46 @@ class DiscoverMovieRow extends Component {
); );
} }
if (name === 'isTrending') {
return (
<VirtualTableRowCell
key={name}
className={styles[name]}
>
{
isTrending ?
<Icon
className={styles.statusIcon}
name={icons.TRENDING}
size={12}
title={translate('MovieIsTrending')}
/> :
null
}
</VirtualTableRowCell>
);
}
if (name === 'isPopular') {
return (
<VirtualTableRowCell
key={name}
className={styles[name]}
>
{
isPopular ?
<Icon
className={styles.statusIcon}
name={icons.POPULAR}
size={12}
title={translate('MovieIsPopular')}
/> :
null
}
</VirtualTableRowCell>
);
}
if (name === 'actions') { if (name === 'actions') {
return ( return (
<VirtualTableRowCell <VirtualTableRowCell
@ -404,6 +447,8 @@ DiscoverMovieRow.propTypes = {
isExcluded: PropTypes.bool.isRequired, isExcluded: PropTypes.bool.isRequired,
isSelected: PropTypes.bool, isSelected: PropTypes.bool,
isRecommendation: PropTypes.bool.isRequired, isRecommendation: PropTypes.bool.isRequired,
isPopular: PropTypes.bool.isRequired,
isTrending: PropTypes.bool.isRequired,
lists: PropTypes.arrayOf(PropTypes.number).isRequired, lists: PropTypes.arrayOf(PropTypes.number).isRequired,
onSelectedChange: PropTypes.func.isRequired onSelectedChange: PropTypes.func.isRequired
}; };

@ -23,6 +23,7 @@ import {
import { import {
faArrowCircleLeft as fasArrowCircleLeft, faArrowCircleLeft as fasArrowCircleLeft,
faArrowCircleRight as fasArrowCircleRight, faArrowCircleRight as fasArrowCircleRight,
faArrowTrendUp as fasArrowTrendUp,
faAsterisk as fasAsterisk, faAsterisk as fasAsterisk,
faBackward as fasBackward, faBackward as fasBackward,
faBan as fasBan, faBan as fasBan,
@ -233,6 +234,7 @@ export const TAGS = fasTags;
export const TBA = fasQuestionCircle; export const TBA = fasQuestionCircle;
export const TEST = fasVial; export const TEST = fasVial;
export const TRANSLATE = fasLanguage; export const TRANSLATE = fasLanguage;
export const TRENDING = fasArrowTrendUp;
export const UNGROUP = farObjectUngroup; export const UNGROUP = farObjectUngroup;
export const UNKNOWN = fasQuestion; export const UNKNOWN = fasQuestion;
export const UNMONITORED = farBookmark; export const UNMONITORED = farBookmark;

@ -88,6 +88,20 @@ export const defaultState = {
isVisible: true, isVisible: true,
isModifiable: false isModifiable: false
}, },
{
name: 'isTrending',
columnLabel: 'Trending',
isSortable: true,
isVisible: true,
isModifiable: false
},
{
name: 'isPopular',
columnLabel: 'Popular',
isSortable: true,
isVisible: true,
isModifiable: false
},
{ {
name: 'sortTitle', name: 'sortTitle',
label: () => translate('MovieTitle'), label: () => translate('MovieTitle'),
@ -267,6 +281,28 @@ export const defaultState = {
label: () => translate('All'), label: () => translate('All'),
filters: [] filters: []
}, },
{
key: 'popular',
label: 'Popular',
filters: [
{
key: 'isPopular',
value: true,
type: filterTypes.EQUAL
}
]
},
{
key: 'trending',
label: 'Trending',
filters: [
{
key: 'isTrending',
value: true,
type: filterTypes.EQUAL
}
]
},
{ {
key: 'newNotExcluded', key: 'newNotExcluded',
label: 'New Non-Excluded', label: 'New Non-Excluded',
@ -456,6 +492,18 @@ export const defaultState = {
label: 'Recommended', label: 'Recommended',
type: filterBuilderTypes.EXACT, type: filterBuilderTypes.EXACT,
valueType: filterBuilderValueTypes.BOOL valueType: filterBuilderValueTypes.BOOL
},
{
name: 'isTrending',
label: 'Trending',
type: filterBuilderTypes.EXACT,
valueType: filterBuilderValueTypes.BOOL
},
{
name: 'isPopular',
label: 'Popular',
type: filterBuilderTypes.EXACT,
valueType: filterBuilderValueTypes.BOOL
} }
] ]
}; };

@ -877,7 +877,9 @@
"MovieIsDownloading": "Movie is downloading", "MovieIsDownloading": "Movie is downloading",
"MovieIsMonitored": "Movie is monitored", "MovieIsMonitored": "Movie is monitored",
"MovieIsOnImportExclusionList": "Movie is on Import Exclusion List", "MovieIsOnImportExclusionList": "Movie is on Import Exclusion List",
"MovieIsPopular": "Movie is Popular on TMDb",
"MovieIsRecommend": "Movie is recommended based on recent addition", "MovieIsRecommend": "Movie is recommended based on recent addition",
"MovieIsTrending": "Movie is Trending on TMDb",
"MovieIsUnmonitored": "Movie is unmonitored", "MovieIsUnmonitored": "Movie is unmonitored",
"MovieMatchType": "Movie Match Type", "MovieMatchType": "Movie Match Type",
"MovieNaming": "Movie Naming", "MovieNaming": "Movie Naming",

@ -12,6 +12,8 @@ namespace NzbDrone.Core.MetadataSource
Tuple<MovieMetadata, List<Credit>> GetMovieInfo(int tmdbId); Tuple<MovieMetadata, List<Credit>> GetMovieInfo(int tmdbId);
MovieCollection GetCollectionInfo(int tmdbId); MovieCollection GetCollectionInfo(int tmdbId);
List<MovieMetadata> GetBulkMovieInfo(List<int> tmdbIds); List<MovieMetadata> GetBulkMovieInfo(List<int> tmdbIds);
List<MovieMetadata> GetTrendingMovies();
List<MovieMetadata> GetPopularMovies();
HashSet<int> GetChangedMovies(DateTime startTime); HashSet<int> GetChangedMovies(DateTime startTime);
} }

@ -70,6 +70,34 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
return new HashSet<int>(response.Resource); return new HashSet<int>(response.Resource);
} }
public List<MovieMetadata> GetTrendingMovies()
{
var request = _radarrMetadata.Create()
.SetSegment("route", "list/tmdb/trending")
.Build();
request.AllowAutoRedirect = true;
request.SuppressHttpError = true;
var response = _httpClient.Get<List<MovieResource>>(request);
return response.Resource.DistinctBy(x => x.TmdbId).Select(MapMovie).ToList();
}
public List<MovieMetadata> GetPopularMovies()
{
var request = _radarrMetadata.Create()
.SetSegment("route", "list/tmdb/popular")
.Build();
request.AllowAutoRedirect = true;
request.SuppressHttpError = true;
var response = _httpClient.Get<List<MovieResource>>(request);
return response.Resource.DistinctBy(x => x.TmdbId).Select(MapMovie).ToList();
}
public Tuple<MovieMetadata, List<Credit>> GetMovieInfo(int tmdbId) public Tuple<MovieMetadata, List<Credit>> GetMovieInfo(int tmdbId)
{ {
var httpRequest = _radarrMetadata.Create() var httpRequest = _radarrMetadata.Create()

@ -54,7 +54,7 @@ namespace Radarr.Api.V3.ImportLists
} }
[HttpGet] [HttpGet]
public object GetDiscoverMovies(bool includeRecommendations = false) public object GetDiscoverMovies(bool includeRecommendations = false, bool includeTrending = false, bool includePopular = false)
{ {
var movieLanguage = (Language)_configService.MovieInfoLanguage; var movieLanguage = (Language)_configService.MovieInfoLanguage;
@ -77,6 +77,17 @@ namespace Radarr.Api.V3.ImportLists
realResults.ForEach(x => x.IsRecommendation = true); realResults.ForEach(x => x.IsRecommendation = true);
} }
// Add TMDB Trending
var trendingResults = _movieInfo.GetTrendingMovies();
realResults.AddRange(MapToResource(trendingResults.Select(m => new Movie { MovieMetadata = m }).Where(x => x != null), movieLanguage, true));
// Add TMDB Popular
var popularResults = _movieInfo.GetPopularMovies();
realResults.AddRange(MapToResource(popularResults.Select(m => new Movie { MovieMetadata = m }).Where(x => x != null), movieLanguage, false, true));
// Add List Movies
var listMovies = MapToResource(_listMovieService.GetAllForLists(_importListFactory.Enabled().Select(x => x.Definition.Id).ToList()), movieLanguage).ToList(); var listMovies = MapToResource(_listMovieService.GetAllForLists(_importListFactory.Enabled().Select(x => x.Definition.Id).ToList()), movieLanguage).ToList();
realResults.AddRange(listMovies); realResults.AddRange(listMovies);
@ -92,6 +103,8 @@ namespace Radarr.Api.V3.ImportLists
movie.IsExcluded = listExclusions.Any(e => e.TmdbId == movie.TmdbId); movie.IsExcluded = listExclusions.Any(e => e.TmdbId == movie.TmdbId);
movie.IsExisting = existingTmdbIds.Any(e => e == movie.TmdbId); movie.IsExisting = existingTmdbIds.Any(e => e == movie.TmdbId);
movie.IsRecommendation = x.Any(m => m.IsRecommendation); movie.IsRecommendation = x.Any(m => m.IsRecommendation);
movie.IsPopular = x.Any(m => m.IsPopular);
movie.IsTrending = x.Any(m => m.IsTrending);
return movie; return movie;
}).ToList(); }).ToList();
@ -107,7 +120,7 @@ namespace Radarr.Api.V3.ImportLists
return _addMovieService.AddMovies(newMovies, true).ToResource(0); return _addMovieService.AddMovies(newMovies, true).ToResource(0);
} }
private IEnumerable<ImportListMoviesResource> MapToResource(IEnumerable<Movie> movies, Language language) private IEnumerable<ImportListMoviesResource> MapToResource(IEnumerable<Movie> movies, Language language, bool isTrending = false, bool isPopular = false)
{ {
// Avoid calling for naming spec on every movie in filenamebuilder // Avoid calling for naming spec on every movie in filenamebuilder
var namingConfig = _namingService.GetConfig(); var namingConfig = _namingService.GetConfig();
@ -127,6 +140,8 @@ namespace Radarr.Api.V3.ImportLists
resource.Title = translation?.Title ?? resource.Title; resource.Title = translation?.Title ?? resource.Title;
resource.Overview = translation?.Overview ?? resource.Overview; resource.Overview = translation?.Overview ?? resource.Overview;
resource.Folder = _fileNameBuilder.GetMovieFolder(currentMovie, namingConfig); resource.Folder = _fileNameBuilder.GetMovieFolder(currentMovie, namingConfig);
resource.IsTrending = isTrending;
resource.IsPopular = isPopular;
yield return resource; yield return resource;
} }

@ -42,6 +42,8 @@ namespace Radarr.Api.V3.ImportLists
public MovieCollection Collection { get; set; } public MovieCollection Collection { get; set; }
public bool IsExcluded { get; set; } public bool IsExcluded { get; set; }
public bool IsExisting { get; set; } public bool IsExisting { get; set; }
public bool IsTrending { get; set; }
public bool IsPopular { get; set; }
public bool IsRecommendation { get; set; } public bool IsRecommendation { get; set; }
public HashSet<int> Lists { get; set; } public HashSet<int> Lists { get; set; }

Loading…
Cancel
Save