diff --git a/frontend/src/Album/Details/TrackRow.css b/frontend/src/Album/Details/TrackRow.css index b31babbef..3162ac9cc 100644 --- a/frontend/src/Album/Details/TrackRow.css +++ b/frontend/src/Album/Details/TrackRow.css @@ -28,3 +28,9 @@ width: 100px; } + +.customFormatScore { + composes: cell from '~Components/Table/Cells/TableRowCell.css'; + + width: 55px; +} diff --git a/frontend/src/Album/Details/TrackRow.css.d.ts b/frontend/src/Album/Details/TrackRow.css.d.ts index 97eedb160..7b473fe05 100644 --- a/frontend/src/Album/Details/TrackRow.css.d.ts +++ b/frontend/src/Album/Details/TrackRow.css.d.ts @@ -2,6 +2,7 @@ // Please do not change this file! interface CssExports { 'audio': string; + 'customFormatScore': string; 'duration': string; 'monitored': string; 'status': string; diff --git a/frontend/src/Album/Details/TrackRow.js b/frontend/src/Album/Details/TrackRow.js index 67c33c36d..f8a09e4e5 100644 --- a/frontend/src/Album/Details/TrackRow.js +++ b/frontend/src/Album/Details/TrackRow.js @@ -1,11 +1,15 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; +import AlbumFormats from 'Album/AlbumFormats'; import EpisodeStatusConnector from 'Album/EpisodeStatusConnector'; import TableRowCell from 'Components/Table/Cells/TableRowCell'; import TableRow from 'Components/Table/TableRow'; +import Tooltip from 'Components/Tooltip/Tooltip'; +import { tooltipPositions } from 'Helpers/Props'; import MediaInfoConnector from 'TrackFile/MediaInfoConnector'; import * as mediaInfoTypes from 'TrackFile/mediaInfoTypes'; import formatTimeSpan from 'Utilities/Date/formatTimeSpan'; +import formatPreferredWordScore from 'Utilities/Number/formatPreferredWordScore'; import TrackActionsCell from './TrackActionsCell'; import styles from './TrackRow.css'; @@ -24,6 +28,8 @@ class TrackRow extends Component { title, duration, trackFilePath, + customFormats, + customFormatScore, columns, deleteTrackFile } = this.props; @@ -111,6 +117,34 @@ class TrackRow extends Component { ); } + if (name === 'customFormats') { + return ( + + + + ); + } + + if (name === 'customFormatScore') { + return ( + + } + position={tooltipPositions.BOTTOM} + /> + + ); + } + if (name === 'status') { return ( { return { - trackFilePath: trackFile ? trackFile.path : null + trackFilePath: trackFile ? trackFile.path : null, + customFormats: trackFile ? trackFile.customFormats : [], + customFormatScore: trackFile ? trackFile.customFormatScore : 0 }; } ); diff --git a/frontend/src/Store/Actions/trackActions.js b/frontend/src/Store/Actions/trackActions.js index d40e2860d..03a03e7cb 100644 --- a/frontend/src/Store/Actions/trackActions.js +++ b/frontend/src/Store/Actions/trackActions.js @@ -1,5 +1,7 @@ +import React from 'react'; import { createAction } from 'redux-actions'; -import { sortDirections } from 'Helpers/Props'; +import Icon from 'Components/Icon'; +import { icons, sortDirections } from 'Helpers/Props'; import { createThunk, handleThunks } from 'Store/thunks'; import translate from 'Utilities/String/translate'; import createFetchHandler from './Creators/createFetchHandler'; @@ -56,6 +58,20 @@ export const defaultState = { label: translate('AudioInfo'), isVisible: true }, + { + name: 'customFormats', + label: 'Formats', + isVisible: false + }, + { + name: 'customFormatScore', + columnLabel: translate('CustomFormatScore'), + label: React.createElement(Icon, { + name: icons.SCORE, + title: translate('CustomFormatScore') + }), + isVisible: false + }, { name: 'status', label: translate('Status'), diff --git a/src/Lidarr.Api.V1/TrackFiles/TrackFileController.cs b/src/Lidarr.Api.V1/TrackFiles/TrackFileController.cs index 3df6d6d91..227ec2240 100644 --- a/src/Lidarr.Api.V1/TrackFiles/TrackFileController.cs +++ b/src/Lidarr.Api.V1/TrackFiles/TrackFileController.cs @@ -4,6 +4,7 @@ using Lidarr.Http; using Lidarr.Http.REST; using Lidarr.Http.REST.Attributes; using Microsoft.AspNetCore.Mvc; +using NzbDrone.Core.CustomFormats; using NzbDrone.Core.Datastore.Events; using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.Exceptions; @@ -28,6 +29,7 @@ namespace Lidarr.Api.V1.TrackFiles private readonly IAudioTagService _audioTagService; private readonly IArtistService _artistService; private readonly IAlbumService _albumService; + private readonly ICustomFormatCalculationService _formatCalculator; private readonly IUpgradableSpecification _upgradableSpecification; public TrackFileController(IBroadcastSignalRMessage signalRBroadcaster, @@ -36,6 +38,7 @@ namespace Lidarr.Api.V1.TrackFiles IAudioTagService audioTagService, IArtistService artistService, IAlbumService albumService, + ICustomFormatCalculationService formatCalculator, IUpgradableSpecification upgradableSpecification) : base(signalRBroadcaster) { @@ -44,6 +47,7 @@ namespace Lidarr.Api.V1.TrackFiles _audioTagService = audioTagService; _artistService = artistService; _albumService = albumService; + _formatCalculator = formatCalculator; _upgradableSpecification = upgradableSpecification; } @@ -51,7 +55,7 @@ namespace Lidarr.Api.V1.TrackFiles { if (trackFile.AlbumId > 0 && trackFile.Artist != null && trackFile.Artist.Value != null) { - return trackFile.ToResource(trackFile.Artist.Value, _upgradableSpecification); + return trackFile.ToResource(trackFile.Artist.Value, _upgradableSpecification, _formatCalculator); } else { @@ -84,7 +88,7 @@ namespace Lidarr.Api.V1.TrackFiles { var artist = _artistService.GetArtist(artistId.Value); - return _mediaFileService.GetFilesByArtist(artistId.Value).ConvertAll(f => f.ToResource(artist, _upgradableSpecification)); + return _mediaFileService.GetFilesByArtist(artistId.Value).ConvertAll(f => f.ToResource(artist, _upgradableSpecification, _formatCalculator)); } if (albumIds.Any()) @@ -94,7 +98,7 @@ namespace Lidarr.Api.V1.TrackFiles { var album = _albumService.GetAlbum(albumId); var albumArtist = _artistService.GetArtist(album.ArtistId); - result.AddRange(_mediaFileService.GetFilesByAlbum(album.Id).ConvertAll(f => f.ToResource(albumArtist, _upgradableSpecification))); + result.AddRange(_mediaFileService.GetFilesByAlbum(album.Id).ConvertAll(f => f.ToResource(albumArtist, _upgradableSpecification, _formatCalculator))); } return result; @@ -152,7 +156,7 @@ namespace Lidarr.Api.V1.TrackFiles _mediaFileService.Update(trackFiles); - return Accepted(trackFiles.ConvertAll(f => f.ToResource(trackFiles.First().Artist.Value, _upgradableSpecification))); + return Accepted(trackFiles.ConvertAll(f => f.ToResource(trackFiles.First().Artist.Value, _upgradableSpecification, _formatCalculator))); } [RestDeleteById] diff --git a/src/Lidarr.Api.V1/TrackFiles/TrackFileResource.cs b/src/Lidarr.Api.V1/TrackFiles/TrackFileResource.cs index 7ae99aa28..5c6695875 100644 --- a/src/Lidarr.Api.V1/TrackFiles/TrackFileResource.cs +++ b/src/Lidarr.Api.V1/TrackFiles/TrackFileResource.cs @@ -1,6 +1,9 @@ using System; +using System.Collections.Generic; using System.Linq; +using Lidarr.Api.V1.CustomFormats; using Lidarr.Http.REST; +using NzbDrone.Core.CustomFormats; using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.MediaFiles; using NzbDrone.Core.Parser.Model; @@ -19,6 +22,8 @@ namespace Lidarr.Api.V1.TrackFiles public string ReleaseGroup { get; set; } public QualityModel Quality { get; set; } public int QualityWeight { get; set; } + public List CustomFormats { get; set; } + public int CustomFormatScore { get; set; } public MediaInfoResource MediaInfo { get; set; } public bool QualityCutoffNotMet { get; set; } @@ -62,13 +67,17 @@ namespace Lidarr.Api.V1.TrackFiles }; } - public static TrackFileResource ToResource(this TrackFile model, NzbDrone.Core.Music.Artist artist, IUpgradableSpecification upgradableSpecification) + public static TrackFileResource ToResource(this TrackFile model, NzbDrone.Core.Music.Artist artist, IUpgradableSpecification upgradableSpecification, ICustomFormatCalculationService formatCalculationService) { if (model == null) { return null; } + model.Artist = artist; + var customFormats = formatCalculationService?.ParseCustomFormat(model, model.Artist); + var customFormatScore = artist?.QualityProfile?.Value?.CalculateCustomFormatScore(customFormats) ?? 0; + return new TrackFileResource { Id = model.Id, @@ -83,7 +92,9 @@ namespace Lidarr.Api.V1.TrackFiles Quality = model.Quality, QualityWeight = QualityWeight(model.Quality), MediaInfo = model.MediaInfo.ToResource(), - QualityCutoffNotMet = upgradableSpecification.QualityCutoffNotMet(artist.QualityProfile.Value, model.Quality) + QualityCutoffNotMet = upgradableSpecification.QualityCutoffNotMet(artist.QualityProfile.Value, model.Quality), + CustomFormats = customFormats.ToResource(false), + CustomFormatScore = customFormatScore }; } } diff --git a/src/Lidarr.Api.V1/Tracks/TrackController.cs b/src/Lidarr.Api.V1/Tracks/TrackController.cs index b9766a98b..38628d0f2 100644 --- a/src/Lidarr.Api.V1/Tracks/TrackController.cs +++ b/src/Lidarr.Api.V1/Tracks/TrackController.cs @@ -3,6 +3,7 @@ using System.Linq; using Lidarr.Http; using Lidarr.Http.REST; using Microsoft.AspNetCore.Mvc; +using NzbDrone.Core.CustomFormats; using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.Music; using NzbDrone.SignalR; @@ -15,8 +16,9 @@ namespace Lidarr.Api.V1.Tracks public TrackController(IArtistService artistService, ITrackService trackService, IUpgradableSpecification upgradableSpecification, + ICustomFormatCalculationService formatCalculator, IBroadcastSignalRMessage signalRBroadcaster) - : base(trackService, artistService, upgradableSpecification, signalRBroadcaster) + : base(trackService, artistService, upgradableSpecification, formatCalculator, signalRBroadcaster) { } diff --git a/src/Lidarr.Api.V1/Tracks/TrackControllerWithSignalR.cs b/src/Lidarr.Api.V1/Tracks/TrackControllerWithSignalR.cs index 066f01cbf..0f8ef254e 100644 --- a/src/Lidarr.Api.V1/Tracks/TrackControllerWithSignalR.cs +++ b/src/Lidarr.Api.V1/Tracks/TrackControllerWithSignalR.cs @@ -3,6 +3,7 @@ using Lidarr.Api.V1.Artist; using Lidarr.Api.V1.TrackFiles; using Lidarr.Http.REST; using Microsoft.AspNetCore.Mvc; +using NzbDrone.Core.CustomFormats; using NzbDrone.Core.Datastore.Events; using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.MediaFiles.Events; @@ -19,16 +20,19 @@ namespace Lidarr.Api.V1.Tracks protected readonly ITrackService _trackService; protected readonly IArtistService _artistService; protected readonly IUpgradableSpecification _upgradableSpecification; + private readonly ICustomFormatCalculationService _formatCalculator; protected TrackControllerWithSignalR(ITrackService trackService, IArtistService artistService, IUpgradableSpecification upgradableSpecification, + ICustomFormatCalculationService formatCalculator, IBroadcastSignalRMessage signalRBroadcaster) : base(signalRBroadcaster) { _trackService = trackService; _artistService = artistService; _upgradableSpecification = upgradableSpecification; + _formatCalculator = formatCalculator; } public override TrackResource GetResourceById(int id) @@ -53,7 +57,7 @@ namespace Lidarr.Api.V1.Tracks if (includeTrackFile && track.TrackFileId != 0) { - resource.TrackFile = track.TrackFile.Value.ToResource(artist, _upgradableSpecification); + resource.TrackFile = track.TrackFile.Value.ToResource(artist, _upgradableSpecification, _formatCalculator); } } @@ -80,7 +84,7 @@ namespace Lidarr.Api.V1.Tracks if (includeTrackFile && tracks[i].TrackFileId != 0) { - resource.TrackFile = tracks[i].TrackFile.Value.ToResource(artist, _upgradableSpecification); + resource.TrackFile = tracks[i].TrackFile.Value.ToResource(artist, _upgradableSpecification, _formatCalculator); } } }