mirror of
https://github.com/Radarr/Radarr.git
synced 2024-09-11 20:12:41 +02:00
Fixed: Cutoff Status and Filter on MovieIndex
This commit is contained in:
parent
f83ccb6ca4
commit
89fec7841c
@ -4,7 +4,7 @@ import formatBytes from 'Utilities/Number/formatBytes';
|
|||||||
import { kinds } from 'Helpers/Props';
|
import { kinds } from 'Helpers/Props';
|
||||||
import Label from 'Components/Label';
|
import Label from 'Components/Label';
|
||||||
|
|
||||||
function getTooltip(title, quality, size) {
|
function getTooltip(title, quality, size, isMonitored, isCutoffNotMet) {
|
||||||
const revision = quality.revision;
|
const revision = quality.revision;
|
||||||
|
|
||||||
if (revision.real && revision.real > 0) {
|
if (revision.real && revision.real > 0) {
|
||||||
@ -19,6 +19,12 @@ function getTooltip(title, quality, size) {
|
|||||||
title += ` - ${formatBytes(size)}`;
|
title += ` - ${formatBytes(size)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isMonitored) {
|
||||||
|
title += ' [Not Monitored]';
|
||||||
|
} else if (isCutoffNotMet) {
|
||||||
|
title += ' [Cutoff Not Met]';
|
||||||
|
}
|
||||||
|
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,14 +34,22 @@ function MovieQuality(props) {
|
|||||||
title,
|
title,
|
||||||
quality,
|
quality,
|
||||||
size,
|
size,
|
||||||
|
isMonitored,
|
||||||
isCutoffNotMet
|
isCutoffNotMet
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
let kind = kinds.DEFAULT;
|
||||||
|
if (!isMonitored) {
|
||||||
|
kind = kinds.DISABLED;
|
||||||
|
} else if (isCutoffNotMet) {
|
||||||
|
kind = kinds.INVERSE;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Label
|
<Label
|
||||||
className={className}
|
className={className}
|
||||||
kind={isCutoffNotMet ? kinds.INVERSE : kinds.DEFAULT}
|
kind={kind}
|
||||||
title={getTooltip(title, quality, size)}
|
title={getTooltip(title, quality, size, isMonitored, isCutoffNotMet)}
|
||||||
>
|
>
|
||||||
{quality.quality.name}
|
{quality.quality.name}
|
||||||
</Label>
|
</Label>
|
||||||
@ -47,11 +61,13 @@ MovieQuality.propTypes = {
|
|||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
quality: PropTypes.object.isRequired,
|
quality: PropTypes.object.isRequired,
|
||||||
size: PropTypes.number,
|
size: PropTypes.number,
|
||||||
|
isMonitored: PropTypes.bool,
|
||||||
isCutoffNotMet: PropTypes.bool
|
isCutoffNotMet: PropTypes.bool
|
||||||
};
|
};
|
||||||
|
|
||||||
MovieQuality.defaultProps = {
|
MovieQuality.defaultProps = {
|
||||||
title: ''
|
title: '',
|
||||||
|
isMonitored: true
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MovieQuality;
|
export default MovieQuality;
|
||||||
|
@ -4,28 +4,10 @@ import { icons, kinds, sizes } from 'Helpers/Props';
|
|||||||
import Icon from 'Components/Icon';
|
import Icon from 'Components/Icon';
|
||||||
import ProgressBar from 'Components/ProgressBar';
|
import ProgressBar from 'Components/ProgressBar';
|
||||||
import QueueDetails from 'Activity/Queue/QueueDetails';
|
import QueueDetails from 'Activity/Queue/QueueDetails';
|
||||||
import formatBytes from 'Utilities/Number/formatBytes';
|
import MovieQuality from 'Movie/MovieQuality';
|
||||||
import Label from 'Components/Label';
|
import Label from 'Components/Label';
|
||||||
import styles from './MovieStatus.css';
|
import styles from './MovieStatus.css';
|
||||||
|
|
||||||
function getTooltip(title, quality, size) {
|
|
||||||
const revision = quality.revision;
|
|
||||||
|
|
||||||
if (revision.real && revision.real > 0) {
|
|
||||||
title += ' [REAL]';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (revision.version && revision.version > 1) {
|
|
||||||
title += ' [PROPER]';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size) {
|
|
||||||
title += ` - ${formatBytes(size)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return title;
|
|
||||||
}
|
|
||||||
|
|
||||||
function MovieStatus(props) {
|
function MovieStatus(props) {
|
||||||
const {
|
const {
|
||||||
inCinemas,
|
inCinemas,
|
||||||
@ -76,32 +58,18 @@ function MovieStatus(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasMovieFile && monitored) {
|
if (hasMovieFile) {
|
||||||
const quality = movieFile.quality;
|
|
||||||
// TODO: Fix on Backend
|
|
||||||
// const isCutoffNotMet = movieFile.qualityCutoffNotMet;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.center}>
|
|
||||||
<Label
|
|
||||||
kind={kinds.SUCCESS}
|
|
||||||
title={getTooltip('Movie Downloaded', quality, movieFile.size)}
|
|
||||||
>
|
|
||||||
{quality.quality.name}
|
|
||||||
</Label>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else if (hasMovieFile && !monitored) {
|
|
||||||
const quality = movieFile.quality;
|
const quality = movieFile.quality;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.center}>
|
<div className={styles.center}>
|
||||||
<Label
|
<MovieQuality
|
||||||
kind={kinds.DISABLED}
|
title={quality.quality.name}
|
||||||
title={getTooltip('Movie Downloaded', quality, movieFile.size)}
|
size={movieFile.size}
|
||||||
>
|
quality={quality}
|
||||||
{quality.quality.name}
|
isMonitored={monitored}
|
||||||
</Label>
|
isCutoffNotMet={movieFile.qualityCutoffNotMet}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ export const filters = [
|
|||||||
type: filterTypes.EQUAL
|
type: filterTypes.EQUAL
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'movieFile.qualityCutoffNotMet',
|
key: 'qualityCutoffNotMet',
|
||||||
value: true,
|
value: true,
|
||||||
type: filterTypes.EQUAL
|
type: filterTypes.EQUAL
|
||||||
}
|
}
|
||||||
@ -106,12 +106,6 @@ export const filters = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const filterPredicates = {
|
export const filterPredicates = {
|
||||||
missing: function(item) {
|
|
||||||
const { statistics = {} } = item;
|
|
||||||
|
|
||||||
return statistics.episodeCount - statistics.episodeFileCount > 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
added: function(item, filterValue, type) {
|
added: function(item, filterValue, type) {
|
||||||
return dateFilterPredicate(item.added, filterValue, type);
|
return dateFilterPredicate(item.added, filterValue, type);
|
||||||
},
|
},
|
||||||
@ -128,6 +122,12 @@ export const filterPredicates = {
|
|||||||
const predicate = filterTypePredicates[type];
|
const predicate = filterTypePredicates[type];
|
||||||
|
|
||||||
return predicate(item.ratings.value * 10, filterValue);
|
return predicate(item.ratings.value * 10, filterValue);
|
||||||
|
},
|
||||||
|
|
||||||
|
qualityCutoffNotMet: function(item) {
|
||||||
|
const { movieFile = {} } = item;
|
||||||
|
|
||||||
|
return movieFile.qualityCutoffNotMet;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
using Nancy;
|
using Nancy;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Datastore.Events;
|
using NzbDrone.Core.Datastore.Events;
|
||||||
|
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||||
using NzbDrone.Core.MediaCover;
|
using NzbDrone.Core.MediaCover;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
using NzbDrone.Core.MediaFiles.Events;
|
using NzbDrone.Core.MediaFiles.Events;
|
||||||
@ -28,20 +29,22 @@ public class MovieModule : RadarrRestModuleWithSignalR<MovieResource, Movie>,
|
|||||||
{
|
{
|
||||||
protected readonly IMovieService _moviesService;
|
protected readonly IMovieService _moviesService;
|
||||||
private readonly IMapCoversToLocal _coverMapper;
|
private readonly IMapCoversToLocal _coverMapper;
|
||||||
|
private readonly IUpgradableSpecification _qualityUpgradableSpecification;
|
||||||
|
|
||||||
public MovieModule(IBroadcastSignalRMessage signalRBroadcaster,
|
public MovieModule(IBroadcastSignalRMessage signalRBroadcaster,
|
||||||
IMovieService moviesService,
|
IMovieService moviesService,
|
||||||
IMapCoversToLocal coverMapper,
|
IMapCoversToLocal coverMapper,
|
||||||
RootFolderValidator rootFolderValidator,
|
IUpgradableSpecification qualityUpgradableSpecification,
|
||||||
MoviePathValidator moviesPathValidator,
|
RootFolderValidator rootFolderValidator,
|
||||||
MovieExistsValidator moviesExistsValidator,
|
MoviePathValidator moviesPathValidator,
|
||||||
MovieAncestorValidator moviesAncestorValidator,
|
MovieExistsValidator moviesExistsValidator,
|
||||||
ProfileExistsValidator profileExistsValidator,
|
MovieAncestorValidator moviesAncestorValidator,
|
||||||
MovieFolderAsRootFolderValidator movieFolderAsRootFolderValidator)
|
ProfileExistsValidator profileExistsValidator,
|
||||||
|
MovieFolderAsRootFolderValidator movieFolderAsRootFolderValidator)
|
||||||
: base(signalRBroadcaster)
|
: base(signalRBroadcaster)
|
||||||
{
|
{
|
||||||
_moviesService = moviesService;
|
_moviesService = moviesService;
|
||||||
|
_qualityUpgradableSpecification = qualityUpgradableSpecification;
|
||||||
_coverMapper = coverMapper;
|
_coverMapper = coverMapper;
|
||||||
|
|
||||||
GetResourceAll = AllMovie;
|
GetResourceAll = AllMovie;
|
||||||
@ -75,7 +78,7 @@ public MovieModule(IBroadcastSignalRMessage signalRBroadcaster,
|
|||||||
|
|
||||||
private List<MovieResource> AllMovie()
|
private List<MovieResource> AllMovie()
|
||||||
{
|
{
|
||||||
var moviesResources = _moviesService.GetAllMovies().ToResource();
|
var moviesResources = _moviesService.GetAllMovies().ToResource(_qualityUpgradableSpecification);
|
||||||
|
|
||||||
MapCoversToLocal(moviesResources.ToArray());
|
MapCoversToLocal(moviesResources.ToArray());
|
||||||
PopulateAlternateTitles(moviesResources);
|
PopulateAlternateTitles(moviesResources);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||||
using NzbDrone.Core.MediaCover;
|
using NzbDrone.Core.MediaCover;
|
||||||
using NzbDrone.Core.Movies;
|
using NzbDrone.Core.Movies;
|
||||||
using Radarr.Api.V3.MovieFiles;
|
using Radarr.Api.V3.MovieFiles;
|
||||||
@ -132,6 +133,67 @@ public static MovieResource ToResource(this Movie model)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MovieResource ToResource(this Movie model, IUpgradableSpecification upgradableSpecification)
|
||||||
|
{
|
||||||
|
if (model == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
long size = model.MovieFile?.Size ?? 0;
|
||||||
|
MovieFileResource movieFile = model.MovieFile?.ToResource(model, upgradableSpecification);
|
||||||
|
|
||||||
|
return new MovieResource
|
||||||
|
{
|
||||||
|
Id = model.Id,
|
||||||
|
TmdbId = model.TmdbId,
|
||||||
|
Title = model.Title,
|
||||||
|
SortTitle = model.SortTitle,
|
||||||
|
InCinemas = model.InCinemas,
|
||||||
|
PhysicalRelease = model.PhysicalRelease,
|
||||||
|
PhysicalReleaseNote = model.PhysicalReleaseNote,
|
||||||
|
HasFile = model.HasFile,
|
||||||
|
|
||||||
|
SizeOnDisk = size,
|
||||||
|
Status = model.Status,
|
||||||
|
Overview = model.Overview,
|
||||||
|
|
||||||
|
Images = model.Images,
|
||||||
|
|
||||||
|
Year = model.Year,
|
||||||
|
SecondaryYear = model.SecondaryYear,
|
||||||
|
SecondaryYearSourceId = model.SecondaryYearSourceId,
|
||||||
|
|
||||||
|
Path = model.Path,
|
||||||
|
QualityProfileId = model.ProfileId,
|
||||||
|
PathState = model.PathState,
|
||||||
|
|
||||||
|
Monitored = model.Monitored,
|
||||||
|
MinimumAvailability = model.MinimumAvailability,
|
||||||
|
|
||||||
|
IsAvailable = model.IsAvailable(),
|
||||||
|
FolderName = model.FolderName(),
|
||||||
|
|
||||||
|
Runtime = model.Runtime,
|
||||||
|
LastInfoSync = model.LastInfoSync,
|
||||||
|
CleanTitle = model.CleanTitle,
|
||||||
|
ImdbId = model.ImdbId,
|
||||||
|
TitleSlug = model.TitleSlug,
|
||||||
|
RootFolderPath = model.RootFolderPath,
|
||||||
|
Certification = model.Certification,
|
||||||
|
Website = model.Website,
|
||||||
|
Genres = model.Genres,
|
||||||
|
Tags = model.Tags,
|
||||||
|
Added = model.Added,
|
||||||
|
AddOptions = model.AddOptions,
|
||||||
|
AlternateTitles = model.AlternativeTitles.ToResource(),
|
||||||
|
Ratings = model.Ratings,
|
||||||
|
MovieFile = movieFile,
|
||||||
|
YouTubeTrailerId = model.YouTubeTrailerId,
|
||||||
|
Studio = model.Studio
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public static Movie ToModel(this MovieResource resource)
|
public static Movie ToModel(this MovieResource resource)
|
||||||
{
|
{
|
||||||
if (resource == null)
|
if (resource == null)
|
||||||
@ -197,6 +259,11 @@ public static List<MovieResource> ToResource(this IEnumerable<Movie> movies)
|
|||||||
return movies.Select(ToResource).ToList();
|
return movies.Select(ToResource).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<MovieResource> ToResource(this IEnumerable<Movie> movies, IUpgradableSpecification upgradableSpecification)
|
||||||
|
{
|
||||||
|
return movies.ToList().ConvertAll(f => f.ToResource(upgradableSpecification));
|
||||||
|
}
|
||||||
|
|
||||||
public static List<Movie> ToModel(this IEnumerable<MovieResource> resources)
|
public static List<Movie> ToModel(this IEnumerable<MovieResource> resources)
|
||||||
{
|
{
|
||||||
return resources.Select(ToModel).ToList();
|
return resources.Select(ToModel).ToList();
|
||||||
|
Loading…
Reference in New Issue
Block a user