New: Trending and Popular Movies in Discovery

This commit is contained in:
Qstick 2024-01-27 20:24:56 -06:00
parent 3b1d4460ad
commit 0be449033f
15 changed files with 221 additions and 5 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -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 (
<VirtualTableHeaderCell
key={name}

View File

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

View File

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

View File

@ -82,6 +82,8 @@ class DiscoverMovieRow extends Component {
isExisting,
isExcluded,
isRecommendation,
isTrending,
isPopular,
isSelected,
lists,
onSelectedChange
@ -305,6 +307,7 @@ class DiscoverMovieRow extends Component {
{
isRecommendation ?
<Icon
className={styles.statusIcon}
name={icons.RECOMMENDED}
size={12}
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') {
return (
<VirtualTableRowCell
@ -404,6 +447,8 @@ DiscoverMovieRow.propTypes = {
isExcluded: PropTypes.bool.isRequired,
isSelected: PropTypes.bool,
isRecommendation: PropTypes.bool.isRequired,
isPopular: PropTypes.bool.isRequired,
isTrending: PropTypes.bool.isRequired,
lists: PropTypes.arrayOf(PropTypes.number).isRequired,
onSelectedChange: PropTypes.func.isRequired
};

View File

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

View File

@ -88,6 +88,20 @@ export const defaultState = {
isVisible: true,
isModifiable: false
},
{
name: 'isTrending',
columnLabel: 'Trending',
isSortable: true,
isVisible: true,
isModifiable: false
},
{
name: 'isPopular',
columnLabel: 'Popular',
isSortable: true,
isVisible: true,
isModifiable: false
},
{
name: 'sortTitle',
label: () => translate('MovieTitle'),
@ -267,6 +281,28 @@ export const defaultState = {
label: () => translate('All'),
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',
label: 'New Non-Excluded',
@ -456,6 +492,18 @@ export const defaultState = {
label: 'Recommended',
type: filterBuilderTypes.EXACT,
valueType: filterBuilderValueTypes.BOOL
},
{
name: 'isTrending',
label: 'Trending',
type: filterBuilderTypes.EXACT,
valueType: filterBuilderValueTypes.BOOL
},
{
name: 'isPopular',
label: 'Popular',
type: filterBuilderTypes.EXACT,
valueType: filterBuilderValueTypes.BOOL
}
]
};

View File

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

View File

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

View File

@ -70,6 +70,34 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
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)
{
var httpRequest = _radarrMetadata.Create()

View File

@ -54,7 +54,7 @@ namespace Radarr.Api.V3.ImportLists
}
[HttpGet]
public object GetDiscoverMovies(bool includeRecommendations = false)
public object GetDiscoverMovies(bool includeRecommendations = false, bool includeTrending = false, bool includePopular = false)
{
var movieLanguage = (Language)_configService.MovieInfoLanguage;
@ -77,6 +77,17 @@ namespace Radarr.Api.V3.ImportLists
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();
realResults.AddRange(listMovies);
@ -92,6 +103,8 @@ namespace Radarr.Api.V3.ImportLists
movie.IsExcluded = listExclusions.Any(e => e.TmdbId == movie.TmdbId);
movie.IsExisting = existingTmdbIds.Any(e => e == movie.TmdbId);
movie.IsRecommendation = x.Any(m => m.IsRecommendation);
movie.IsPopular = x.Any(m => m.IsPopular);
movie.IsTrending = x.Any(m => m.IsTrending);
return movie;
}).ToList();
@ -107,7 +120,7 @@ namespace Radarr.Api.V3.ImportLists
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
var namingConfig = _namingService.GetConfig();
@ -127,6 +140,8 @@ namespace Radarr.Api.V3.ImportLists
resource.Title = translation?.Title ?? resource.Title;
resource.Overview = translation?.Overview ?? resource.Overview;
resource.Folder = _fileNameBuilder.GetMovieFolder(currentMovie, namingConfig);
resource.IsTrending = isTrending;
resource.IsPopular = isPopular;
yield return resource;
}

View File

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