mirror of
https://github.com/lidarr/lidarr.git
synced 2025-08-20 05:23:31 -07:00
New: Custom Filtering for UI (#234)
This commit is contained in:
parent
c6873014c7
commit
7354e02bff
154 changed files with 3498 additions and 1370 deletions
|
@ -203,12 +203,7 @@ namespace Lidarr.Api.V1.Artist
|
|||
|
||||
private void LinkArtistStatistics(ArtistResource resource, ArtistStatistics artistStatistics)
|
||||
{
|
||||
resource.TotalTrackCount = artistStatistics.TotalTrackCount;
|
||||
resource.TrackCount = artistStatistics.TrackCount;
|
||||
resource.TrackFileCount = artistStatistics.TrackFileCount;
|
||||
resource.SizeOnDisk = artistStatistics.SizeOnDisk;
|
||||
resource.AlbumCount = artistStatistics.AlbumCount;
|
||||
|
||||
resource.Statistics = artistStatistics.ToResource();
|
||||
}
|
||||
|
||||
//private void PopulateAlternateTitles(List<ArtistResource> resources)
|
||||
|
|
|
@ -30,12 +30,7 @@ namespace Lidarr.Api.V1.Artist
|
|||
public string ArtistType { get; set; }
|
||||
public string Disambiguation { get; set; }
|
||||
public List<Links> Links { get; set; }
|
||||
|
||||
public int? AlbumCount { get; set; }
|
||||
public int? TotalTrackCount { get; set; }
|
||||
public int? TrackCount { get; set; }
|
||||
public int? TrackFileCount { get; set; }
|
||||
public long? SizeOnDisk { get; set; }
|
||||
|
||||
public Album NextAlbum { get; set; }
|
||||
public Album LastAlbum { get; set; }
|
||||
|
||||
|
@ -64,7 +59,7 @@ namespace Lidarr.Api.V1.Artist
|
|||
public AddArtistOptions AddOptions { get; set; }
|
||||
public Ratings Ratings { get; set; }
|
||||
|
||||
//TODO: Add series statistics as a property of the series (instead of individual properties)
|
||||
public ArtistStatisticsResource Statistics { get; set; }
|
||||
}
|
||||
|
||||
public static class ArtistResourceMapper
|
||||
|
|
41
src/Lidarr.Api.V1/Artist/ArtistStatisticsResource.cs
Normal file
41
src/Lidarr.Api.V1/Artist/ArtistStatisticsResource.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
using NzbDrone.Core.ArtistStats;
|
||||
|
||||
namespace Lidarr.Api.V1.Artist
|
||||
{
|
||||
public class ArtistStatisticsResource
|
||||
{
|
||||
public int AlbumCount { get; set; }
|
||||
public int TrackFileCount { get; set; }
|
||||
public int TrackCount { get; set; }
|
||||
public int TotalTrackCount { get; set; }
|
||||
public long SizeOnDisk { get; set; }
|
||||
|
||||
public decimal PercentOfTracks
|
||||
{
|
||||
get
|
||||
{
|
||||
if (TrackCount == 0) return 0;
|
||||
|
||||
return (decimal)TrackFileCount / (decimal)TrackCount * 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ArtistStatisticsResourceMapper
|
||||
{
|
||||
public static ArtistStatisticsResource ToResource(this ArtistStatistics model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
|
||||
return new ArtistStatisticsResource
|
||||
{
|
||||
AlbumCount = model.AlbumCount,
|
||||
TrackFileCount = model.TrackFileCount,
|
||||
TrackCount = model.TrackCount,
|
||||
TotalTrackCount = model.TotalTrackCount,
|
||||
SizeOnDisk = model.SizeOnDisk
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ namespace Lidarr.Api.V1.Config
|
|||
public string RecycleBin { get; set; }
|
||||
public bool AutoDownloadPropers { get; set; }
|
||||
public bool CreateEmptyArtistFolders { get; set; }
|
||||
public bool DeleteEmptyFolders { get; set; }
|
||||
public FileDateType FileDate { get; set; }
|
||||
|
||||
public bool SetPermissionsLinux { get; set; }
|
||||
|
@ -35,6 +36,7 @@ namespace Lidarr.Api.V1.Config
|
|||
RecycleBin = model.RecycleBin,
|
||||
AutoDownloadPropers = model.AutoDownloadPropers,
|
||||
CreateEmptyArtistFolders = model.CreateEmptyArtistFolders,
|
||||
DeleteEmptyFolders = model.DeleteEmptyFolders,
|
||||
FileDate = model.FileDate,
|
||||
|
||||
SetPermissionsLinux = model.SetPermissionsLinux,
|
||||
|
|
|
@ -69,18 +69,22 @@ namespace Lidarr.Api.V1.History
|
|||
var includeAlbum = Request.GetBooleanQueryParameter("includeAlbum");
|
||||
var includeTrack = Request.GetBooleanQueryParameter("includeTrack");
|
||||
|
||||
if (pagingResource.FilterKey == "eventType")
|
||||
var eventTypeFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "eventType");
|
||||
var albumIdFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "albumId");
|
||||
|
||||
if (eventTypeFilter != null)
|
||||
{
|
||||
var filterValue = (HistoryEventType)Convert.ToInt32(pagingResource.FilterValue);
|
||||
pagingSpec.FilterExpression = v => v.EventType == filterValue;
|
||||
var filterValue = (HistoryEventType)Convert.ToInt32(eventTypeFilter.Value);
|
||||
pagingSpec.FilterExpressions.Add(v => v.EventType == filterValue);
|
||||
}
|
||||
|
||||
if (pagingResource.FilterKey == "albumId")
|
||||
if (albumIdFilter != null)
|
||||
{
|
||||
int albumId = Convert.ToInt32(pagingResource.FilterValue);
|
||||
pagingSpec.FilterExpression = h => h.AlbumId == albumId;
|
||||
var albumId = Convert.ToInt32(albumIdFilter.Value);
|
||||
pagingSpec.FilterExpressions.Add(h => h.AlbumId == albumId);
|
||||
}
|
||||
|
||||
|
||||
return ApplyToPage(_historyService.Paged, pagingSpec, h => MapToResource(h, includeArtist, includeAlbum, includeTrack));
|
||||
}
|
||||
|
||||
|
|
|
@ -88,6 +88,7 @@
|
|||
<Compile Include="Albums\AlbumStatisticsResource.cs" />
|
||||
<Compile Include="Albums\AlbumLookupModule.cs" />
|
||||
<Compile Include="Albums\MediumResource.cs" />
|
||||
<Compile Include="Artist\ArtistStatisticsResource.cs" />
|
||||
<Compile Include="Blacklist\BlacklistModule.cs" />
|
||||
<Compile Include="Blacklist\BlacklistResource.cs" />
|
||||
<Compile Include="Calendar\CalendarFeedModule.cs" />
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using NzbDrone.Core.Instrumentation;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Instrumentation;
|
||||
using Lidarr.Http;
|
||||
|
||||
namespace Lidarr.Api.V1.Logs
|
||||
|
@ -22,27 +23,29 @@ namespace Lidarr.Api.V1.Logs
|
|||
pageSpec.SortKey = "id";
|
||||
}
|
||||
|
||||
if (pagingResource.FilterKey == "level")
|
||||
var levelFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "level");
|
||||
|
||||
if (levelFilter != null)
|
||||
{
|
||||
switch (pagingResource.FilterValue)
|
||||
switch (levelFilter.Value)
|
||||
{
|
||||
case "Fatal":
|
||||
pageSpec.FilterExpression = h => h.Level == "Fatal";
|
||||
case "fatal":
|
||||
pageSpec.FilterExpressions.Add(h => h.Level == "Fatal");
|
||||
break;
|
||||
case "Error":
|
||||
pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error";
|
||||
case "error":
|
||||
pageSpec.FilterExpressions.Add(h => h.Level == "Fatal" || h.Level == "Error");
|
||||
break;
|
||||
case "Warn":
|
||||
pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn";
|
||||
case "warn":
|
||||
pageSpec.FilterExpressions.Add(h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn");
|
||||
break;
|
||||
case "Info":
|
||||
pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn" || h.Level == "Info";
|
||||
case "info":
|
||||
pageSpec.FilterExpressions.Add(h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn" || h.Level == "Info");
|
||||
break;
|
||||
case "Debug":
|
||||
pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn" || h.Level == "Info" || h.Level == "Debug";
|
||||
case "debug":
|
||||
pageSpec.FilterExpressions.Add(h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn" || h.Level == "Info" || h.Level == "Debug");
|
||||
break;
|
||||
case "Trace":
|
||||
pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn" || h.Level == "Info" || h.Level == "Debug" || h.Level == "Trace";
|
||||
case "trace":
|
||||
pageSpec.FilterExpressions.Add(h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn" || h.Level == "Info" || h.Level == "Debug" || h.Level == "Trace");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -57,4 +60,4 @@ namespace Lidarr.Api.V1.Logs
|
|||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using NzbDrone.Core.Instrumentation;
|
||||
using Lidarr.Http.REST;
|
||||
|
||||
|
@ -24,11 +24,10 @@ namespace Lidarr.Api.V1.Logs
|
|||
return new LogResource
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
Time = model.Time,
|
||||
Exception = model.Exception,
|
||||
ExceptionType = model.ExceptionType,
|
||||
Level = model.Level,
|
||||
Level = model.Level.ToLowerInvariant(),
|
||||
Logger = model.Logger,
|
||||
Message = model.Message
|
||||
};
|
||||
|
|
|
@ -69,7 +69,6 @@ namespace Lidarr.Api.V1.TrackFiles
|
|||
Language = model.Language,
|
||||
Quality = model.Quality,
|
||||
MediaInfo = model.MediaInfo.ToResource(),
|
||||
|
||||
QualityCutoffNotMet = upgradableSpecification.QualityCutoffNotMet(artist.Profile.Value, model.Quality),
|
||||
LanguageCutoffNotMet = upgradableSpecification.LanguageCutoffNotMet(artist.LanguageProfile.Value, model.Language)
|
||||
};
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System.Linq;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Music;
|
||||
|
@ -36,14 +37,15 @@ namespace Lidarr.Api.V1.Wanted
|
|||
};
|
||||
|
||||
var includeArtist = Request.GetBooleanQueryParameter("includeArtist");
|
||||
var filter = pagingResource.Filters.FirstOrDefault(f => f.Key == "monitored");
|
||||
|
||||
if (pagingResource.FilterKey == "monitored" && pagingResource.FilterValue == "false")
|
||||
if (filter != null && filter.Value == "false")
|
||||
{
|
||||
pagingSpec.FilterExpression = v => v.Monitored == false || v.Artist.Monitored == false;
|
||||
pagingSpec.FilterExpressions.Add(v => v.Monitored == false || v.Artist.Monitored == false);
|
||||
}
|
||||
else
|
||||
{
|
||||
pagingSpec.FilterExpression = v => v.Monitored == true && v.Artist.Monitored == true;
|
||||
pagingSpec.FilterExpressions.Add(v => v.Monitored == true && v.Artist.Monitored == true);
|
||||
}
|
||||
|
||||
var resource = ApplyToPage(_albumCutoffService.AlbumsWhereCutoffUnmet, pagingSpec, v => MapToResource(v, includeArtist));
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System.Linq;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Music;
|
||||
|
@ -32,14 +33,15 @@ namespace Lidarr.Api.V1.Wanted
|
|||
};
|
||||
|
||||
var includeArtist = Request.GetBooleanQueryParameter("includeArtist");
|
||||
var monitoredFilter = pagingResource.Filters.FirstOrDefault(f => f.Key == "monitored");
|
||||
|
||||
if (pagingResource.FilterKey == "monitored" && pagingResource.FilterValue == "false")
|
||||
if (monitoredFilter != null && monitoredFilter.Value == "false")
|
||||
{
|
||||
pagingSpec.FilterExpression = v => v.Monitored == false || v.Artist.Monitored == false;
|
||||
pagingSpec.FilterExpressions.Add(v => v.Monitored == false || v.Artist.Monitored == false);
|
||||
}
|
||||
else
|
||||
{
|
||||
pagingSpec.FilterExpression = v => v.Monitored == true && v.Artist.Monitored == true;
|
||||
pagingSpec.FilterExpressions.Add(v => v.Monitored == true && v.Artist.Monitored == true);
|
||||
}
|
||||
|
||||
var resource = ApplyToPage(_albumService.AlbumsWithoutFiles, pagingSpec, v => MapToResource(v, includeArtist));
|
||||
|
|
|
@ -108,6 +108,7 @@
|
|||
<Compile Include="Mapping\MappingValidation.cs" />
|
||||
<Compile Include="Mapping\ResourceMappingException.cs" />
|
||||
<Compile Include="PagingResource.cs" />
|
||||
<Compile Include="PagingResourceFilter.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ResourceChangeMessage.cs" />
|
||||
<Compile Include="REST\BadRequestException.cs" />
|
||||
|
|
|
@ -9,8 +9,7 @@ namespace Lidarr.Http
|
|||
public int PageSize { get; set; }
|
||||
public string SortKey { get; set; }
|
||||
public SortDirection SortDirection { get; set; }
|
||||
public string FilterKey { get; set; }
|
||||
public string FilterValue { get; set; }
|
||||
public List<PagingResourceFilter> Filters { get; set; }
|
||||
public int TotalRecords { get; set; }
|
||||
public List<TResource> Records { get; set; }
|
||||
}
|
||||
|
|
8
src/Lidarr.Http/PagingResourceFilter.cs
Normal file
8
src/Lidarr.Http/PagingResourceFilter.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Lidarr.Http
|
||||
{
|
||||
public class PagingResourceFilter
|
||||
{
|
||||
public string Key { get; set; }
|
||||
public string Value { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentValidation;
|
||||
|
@ -14,6 +14,16 @@ namespace Lidarr.Http.REST
|
|||
private const string ROOT_ROUTE = "/";
|
||||
private const string ID_ROUTE = @"/(?<id>[\d]{1,10})";
|
||||
|
||||
private HashSet<string> EXCLUDED_KEYS = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase)
|
||||
{
|
||||
"page",
|
||||
"pageSize",
|
||||
"sortKey",
|
||||
"sortDirection",
|
||||
"filterKey",
|
||||
"filterValue",
|
||||
};
|
||||
|
||||
private Action<int> _deleteResource;
|
||||
private Func<int, TResource> _getResourceById;
|
||||
private Func<List<TResource>> _getResourceAll;
|
||||
|
@ -226,6 +236,7 @@ namespace Lidarr.Http.REST
|
|||
{
|
||||
PageSize = pageSize,
|
||||
Page = page,
|
||||
Filters = new List<PagingResourceFilter>()
|
||||
};
|
||||
|
||||
if (Request.Query.SortKey != null)
|
||||
|
@ -251,17 +262,39 @@ namespace Lidarr.Http.REST
|
|||
}
|
||||
}
|
||||
|
||||
// For backwards compatibility with v2
|
||||
if (Request.Query.FilterKey != null)
|
||||
{
|
||||
pagingResource.FilterKey = Request.Query.FilterKey.ToString();
|
||||
var filter = new PagingResourceFilter
|
||||
{
|
||||
Key = Request.Query.FilterKey.ToString()
|
||||
};
|
||||
|
||||
if (Request.Query.FilterValue != null)
|
||||
{
|
||||
pagingResource.FilterValue = Request.Query.FilterValue.ToString();
|
||||
filter.Value = Request.Query.FilterValue?.ToString();
|
||||
}
|
||||
|
||||
pagingResource.Filters.Add(filter);
|
||||
}
|
||||
|
||||
// v3 uses filters in key=value format
|
||||
|
||||
foreach (var key in Request.Query)
|
||||
{
|
||||
if (EXCLUDED_KEYS.Contains(key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
pagingResource.Filters.Add(new PagingResourceFilter
|
||||
{
|
||||
Key = key,
|
||||
Value = Request.Query[key]
|
||||
});
|
||||
}
|
||||
|
||||
return pagingResource;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -154,6 +154,13 @@ namespace NzbDrone.Core.Configuration
|
|||
set { SetValue("CreateEmptyArtistFolders", value); }
|
||||
}
|
||||
|
||||
public bool DeleteEmptyFolders
|
||||
{
|
||||
get { return GetValueBoolean("DeleteEmptyFolders", false); }
|
||||
|
||||
set { SetValue("DeleteEmptyFolders", value); }
|
||||
}
|
||||
|
||||
public FileDateType FileDate
|
||||
{
|
||||
get { return GetValueEnum("FileDate", FileDateType.None); }
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace NzbDrone.Core.Configuration
|
|||
string RecycleBin { get; set; }
|
||||
bool AutoDownloadPropers { get; set; }
|
||||
bool CreateEmptyArtistFolders { get; set; }
|
||||
bool DeleteEmptyFolders { get; set; }
|
||||
FileDateType FileDate { get; set; }
|
||||
bool SkipFreeSpaceCheckWhenImporting { get; set; }
|
||||
bool CopyUsingHardlinks { get; set; }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
|
@ -254,10 +254,21 @@ namespace NzbDrone.Core.Datastore
|
|||
|
||||
protected virtual SortBuilder<TModel> GetPagedQuery(QueryBuilder<TModel> query, PagingSpec<TModel> pagingSpec)
|
||||
{
|
||||
return query.Where(pagingSpec.FilterExpression)
|
||||
.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection())
|
||||
.Skip(pagingSpec.PagingOffset())
|
||||
.Take(pagingSpec.PageSize);
|
||||
var filterExpressions = pagingSpec.FilterExpressions;
|
||||
var sortQuery = query.Where(filterExpressions.FirstOrDefault());
|
||||
|
||||
if (filterExpressions.Count > 1)
|
||||
{
|
||||
// Start at the second item for the AndWhere clauses
|
||||
for (var i = 1; i < filterExpressions.Count; i++)
|
||||
{
|
||||
sortQuery.AndWhere(filterExpressions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return sortQuery.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection())
|
||||
.Skip(pagingSpec.PagingOffset())
|
||||
.Take(pagingSpec.PageSize);
|
||||
}
|
||||
|
||||
protected void ModelCreated(TModel model)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
|
@ -12,7 +12,12 @@ namespace NzbDrone.Core.Datastore
|
|||
public string SortKey { get; set; }
|
||||
public SortDirection SortDirection { get; set; }
|
||||
public List<TModel> Records { get; set; }
|
||||
public Expression<Func<TModel, bool>> FilterExpression { get; set; }
|
||||
public List<Expression<Func<TModel, bool>>> FilterExpressions { get; set; }
|
||||
|
||||
public PagingSpec()
|
||||
{
|
||||
FilterExpressions = new List<Expression<Func<TModel, bool>>>();
|
||||
}
|
||||
}
|
||||
|
||||
public enum SortDirection
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace NzbDrone.Core.Extras.Files
|
|||
|
||||
public abstract class ExtraFileService<TExtraFile> : IExtraFileService<TExtraFile>,
|
||||
IHandleAsync<ArtistDeletedEvent>,
|
||||
IHandleAsync<TrackFileDeletedEvent>
|
||||
IHandle<TrackFileDeletedEvent>
|
||||
where TExtraFile : ExtraFile, new()
|
||||
{
|
||||
private readonly IExtraFileRepository<TExtraFile> _repository;
|
||||
|
@ -103,7 +103,7 @@ namespace NzbDrone.Core.Extras.Files
|
|||
_repository.DeleteForArtist(message.Artist.Id);
|
||||
}
|
||||
|
||||
public void HandleAsync(TrackFileDeletedEvent message)
|
||||
public void Handle(TrackFileDeletedEvent message)
|
||||
{
|
||||
var trackFile = message.TrackFile;
|
||||
|
||||
|
|
|
@ -78,32 +78,34 @@ namespace NzbDrone.Core.IndexerSearch
|
|||
{
|
||||
int artistId = message.ArtistId.Value;
|
||||
|
||||
albums = _albumService.AlbumsWithoutFiles(new PagingSpec<Album>
|
||||
var pagingSpec = new PagingSpec<Album>
|
||||
{
|
||||
Page = 1,
|
||||
PageSize = 100000,
|
||||
SortDirection = SortDirection.Ascending,
|
||||
SortKey = "Id",
|
||||
FilterExpression =
|
||||
v =>
|
||||
v.Monitored == true &&
|
||||
v.Artist.Monitored == true
|
||||
}).Records.Where(e => e.ArtistId.Equals(artistId)).ToList();
|
||||
SortKey = "Id"
|
||||
};
|
||||
|
||||
pagingSpec.FilterExpressions.Add(v => v.Monitored == true && v.Artist.Monitored == true);
|
||||
|
||||
albums = _albumService.AlbumsWithoutFiles(pagingSpec).Records.Where(e => e.ArtistId.Equals(artistId)).ToList();
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
albums = _albumService.AlbumsWithoutFiles(new PagingSpec<Album>
|
||||
var pagingSpec = new PagingSpec<Album>
|
||||
{
|
||||
Page = 1,
|
||||
PageSize = 100000,
|
||||
SortDirection = SortDirection.Ascending,
|
||||
SortKey = "Id",
|
||||
FilterExpression =
|
||||
v =>
|
||||
v.Monitored == true &&
|
||||
v.Artist.Monitored == true
|
||||
}).Records.ToList();
|
||||
SortKey = "Id"
|
||||
};
|
||||
|
||||
pagingSpec.FilterExpressions.Add(v => v.Monitored == true && v.Artist.Monitored == true);
|
||||
|
||||
albums = _albumService.AlbumsWithoutFiles(pagingSpec).Records.ToList();
|
||||
|
||||
}
|
||||
|
||||
var queue = _queueService.GetQueue().Select(q => q.Album.Id);
|
||||
|
@ -131,14 +133,17 @@ namespace NzbDrone.Core.IndexerSearch
|
|||
v.Artist.Monitored == true;
|
||||
}
|
||||
|
||||
var albums = _albumCutoffService.AlbumsWhereCutoffUnmet(new PagingSpec<Album>
|
||||
var pagingSpec = new PagingSpec<Album>
|
||||
{
|
||||
Page = 1,
|
||||
PageSize = 100000,
|
||||
SortDirection = SortDirection.Ascending,
|
||||
SortKey = "Id",
|
||||
FilterExpression = filterExpression
|
||||
}).Records.ToList();
|
||||
SortKey = "Id"
|
||||
};
|
||||
|
||||
pagingSpec.FilterExpressions.Add(filterExpression);
|
||||
|
||||
var albums = _albumCutoffService.AlbumsWhereCutoffUnmet(pagingSpec).Records.ToList();
|
||||
|
||||
var queue = _queueService.GetQueue().Select(q => q.Album.Id);
|
||||
var missing = albums.Where(e => !queue.Contains(e.Id)).ToList();
|
||||
|
|
|
@ -94,8 +94,10 @@ namespace NzbDrone.Core.MediaFiles
|
|||
{
|
||||
_logger.Debug("Artist folder doesn't exist: {0}", artist.Path);
|
||||
}
|
||||
|
||||
CleanMediaFiles(artist, new List<string>());
|
||||
CompletedScanning(artist);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -112,6 +114,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
_logger.Trace("Import decisions complete for: {0} [{1}]", artist, decisionsStopwatch.Elapsed);
|
||||
_importApprovedTracks.Import(decisions, false);
|
||||
|
||||
RemoveEmptyArtistFolder(artist.Path);
|
||||
CompletedScanning(artist);
|
||||
}
|
||||
|
||||
|
@ -183,7 +186,22 @@ namespace NzbDrone.Core.MediaFiles
|
|||
_logger.Warn(ex, "Unable to apply permissions to: " + path);
|
||||
_logger.Debug(ex, ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveEmptyArtistFolder(string path)
|
||||
{
|
||||
if (_configService.DeleteEmptyFolders)
|
||||
{
|
||||
if (_diskProvider.GetFiles(path, SearchOption.AllDirectories).Empty())
|
||||
{
|
||||
_diskProvider.DeleteFolder(path, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
_diskProvider.RemoveEmptySubfolders(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(ArtistUpdatedEvent message)
|
||||
{
|
||||
|
|
|
@ -4,7 +4,10 @@ using System.Net;
|
|||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Exceptions;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Core.Music.Events;
|
||||
|
@ -16,24 +19,29 @@ namespace NzbDrone.Core.MediaFiles
|
|||
void DeleteTrackFile(Artist artist, TrackFile trackFile);
|
||||
}
|
||||
|
||||
public class MediaFileDeletionService : IDeleteMediaFiles, IHandleAsync<ArtistDeletedEvent>
|
||||
public class MediaFileDeletionService : IDeleteMediaFiles,
|
||||
IHandleAsync<ArtistDeletedEvent>,
|
||||
IHandle<TrackFileDeletedEvent>
|
||||
{
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IRecycleBinProvider _recycleBinProvider;
|
||||
private readonly IMediaFileService _mediaFileService;
|
||||
private readonly IArtistService _artistService;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public MediaFileDeletionService(IDiskProvider diskProvider,
|
||||
IRecycleBinProvider recycleBinProvider,
|
||||
IMediaFileService mediaFileService,
|
||||
IArtistService artistService,
|
||||
IConfigService configService,
|
||||
Logger logger)
|
||||
{
|
||||
_diskProvider = diskProvider;
|
||||
_recycleBinProvider = recycleBinProvider;
|
||||
_mediaFileService = mediaFileService;
|
||||
_artistService = artistService;
|
||||
_configService = configService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
@ -104,5 +112,29 @@ namespace NzbDrone.Core.MediaFiles
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
[EventHandleOrder(EventHandleOrder.Last)]
|
||||
public void Handle(TrackFileDeletedEvent message)
|
||||
{
|
||||
if (message.Reason == DeleteMediaFileReason.Upgrade)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_configService.DeleteEmptyFolders)
|
||||
{
|
||||
var artist = message.TrackFile.Artist.Value;
|
||||
var albumFolder = message.TrackFile.Path.GetParentPath();
|
||||
|
||||
if (_diskProvider.GetFiles(artist.Path, SearchOption.AllDirectories).Empty())
|
||||
{
|
||||
_diskProvider.DeleteFolder(artist.Path, true);
|
||||
}
|
||||
else if (_diskProvider.GetFiles(albumFolder, SearchOption.AllDirectories).Empty())
|
||||
{
|
||||
_diskProvider.RemoveEmptySubfolders(albumFolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
22
src/NzbDrone.Core/Messaging/EventHandleOrderAttribute.cs
Normal file
22
src/NzbDrone.Core/Messaging/EventHandleOrderAttribute.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
|
||||
namespace NzbDrone.Core.Messaging
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class EventHandleOrderAttribute : Attribute
|
||||
{
|
||||
public EventHandleOrder EventHandleOrder { get; set; }
|
||||
|
||||
public EventHandleOrderAttribute(EventHandleOrder eventHandleOrder)
|
||||
{
|
||||
EventHandleOrder = eventHandleOrder;
|
||||
}
|
||||
}
|
||||
|
||||
public enum EventHandleOrder
|
||||
{
|
||||
First,
|
||||
Any,
|
||||
Last
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
|
@ -48,7 +49,11 @@ namespace NzbDrone.Core.Messaging.Events
|
|||
|
||||
|
||||
//call synchronous handlers first.
|
||||
foreach (var handler in _serviceFactory.BuildAll<IHandle<TEvent>>())
|
||||
var handlers = _serviceFactory.BuildAll<IHandle<TEvent>>()
|
||||
.OrderBy(GetEventHandleOrder)
|
||||
.ToList();
|
||||
|
||||
foreach (var handler in handlers)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -96,5 +101,25 @@ namespace NzbDrone.Core.Messaging.Events
|
|||
|
||||
return string.Format("{0}<{1}>", eventType.Name.Remove(eventType.Name.IndexOf('`')), eventType.GetGenericArguments()[0].Name);
|
||||
}
|
||||
|
||||
private int GetEventHandleOrder<TEvent>(IHandle<TEvent> eventHandler) where TEvent : class, IEvent
|
||||
{
|
||||
// TODO: Convert "Handle" to nameof(eventHandler.Handle) after .net 4.5
|
||||
var method = eventHandler.GetType().GetMethod("Handle", new Type[] { typeof(TEvent) });
|
||||
|
||||
if (method == null)
|
||||
{
|
||||
return (int)EventHandleOrder.Any;
|
||||
}
|
||||
|
||||
var attribute = method.GetCustomAttributes(typeof(EventHandleOrderAttribute), true).FirstOrDefault() as EventHandleOrderAttribute;
|
||||
|
||||
if (attribute == null)
|
||||
{
|
||||
return (int)EventHandleOrder.Any;
|
||||
}
|
||||
|
||||
return (int)attribute.EventHandleOrder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ namespace NzbDrone.Core.Music
|
|||
string sortKey;
|
||||
string monitored = "(Albums.[Monitored] = 0) OR (Artists.[Monitored] = 0)";
|
||||
|
||||
if (pagingSpec.FilterExpression.ToString().Contains("True"))
|
||||
if (pagingSpec.FilterExpressions.FirstOrDefault().ToString().Contains("True"))
|
||||
{
|
||||
monitored = "(Albums.[Monitored] = 1) AND (Artists.[Monitored] = 1)";
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ namespace NzbDrone.Core.Music
|
|||
{
|
||||
var monitored = 0;
|
||||
|
||||
if (pagingSpec.FilterExpression.ToString().Contains("True"))
|
||||
if (pagingSpec.FilterExpressions.FirstOrDefault().ToString().Contains("True"))
|
||||
{
|
||||
monitored = 1;
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ namespace NzbDrone.Core.Music
|
|||
string sortKey;
|
||||
string monitored = "(Albums.[Monitored] = 0) OR (Artists.[Monitored] = 0)";
|
||||
|
||||
if (pagingSpec.FilterExpression.ToString().Contains("True"))
|
||||
if (pagingSpec.FilterExpressions.FirstOrDefault().ToString().Contains("True"))
|
||||
{
|
||||
monitored = "(Albums.[Monitored] = 1) AND (Artists.[Monitored] = 1)";
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ namespace NzbDrone.Core.Music
|
|||
{
|
||||
var monitored = 0;
|
||||
|
||||
if (pagingSpec.FilterExpression.ToString().Contains("True"))
|
||||
if (pagingSpec.FilterExpressions.FirstOrDefault().ToString().Contains("True"))
|
||||
{
|
||||
monitored = 1;
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ namespace NzbDrone.Core.Music
|
|||
private SortBuilder<Track> GetMissingTracksQuery(PagingSpec<Track> pagingSpec, DateTime currentTime)
|
||||
{
|
||||
return Query.Join<Track, Artist>(JoinType.Inner, e => e.Artist, (e, s) => e.ArtistId == s.Id)
|
||||
.Where(pagingSpec.FilterExpression)
|
||||
.Where(pagingSpec.FilterExpressions.FirstOrDefault())
|
||||
.AndWhere(e => e.TrackFileId == 0)
|
||||
.AndWhere(BuildAirDateUtcCutoffWhereClause(currentTime))
|
||||
.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection())
|
||||
|
@ -138,7 +138,7 @@ namespace NzbDrone.Core.Music
|
|||
{
|
||||
return Query.Join<Track, Artist>(JoinType.Inner, e => e.Artist, (e, s) => e.ArtistId == s.Id)
|
||||
.Join<Track, TrackFile>(JoinType.Left, e => e.TrackFile, (e, s) => e.TrackFileId == s.Id)
|
||||
.Where(pagingSpec.FilterExpression)
|
||||
.Where(pagingSpec.FilterExpressions.FirstOrDefault())
|
||||
.AndWhere(e => e.TrackFileId != 0)
|
||||
.AndWhere(BuildQualityCutoffWhereClause(qualitiesBelowCutoff))
|
||||
.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection())
|
||||
|
|
|
@ -757,6 +757,7 @@
|
|||
<Compile Include="Messaging\Commands\IExecute.cs" />
|
||||
<Compile Include="Messaging\Commands\TestCommand.cs" />
|
||||
<Compile Include="Messaging\Commands\TestCommandExecutor.cs" />
|
||||
<Compile Include="Messaging\EventHandleOrderAttribute.cs" />
|
||||
<Compile Include="Messaging\Events\CommandExecutedEvent.cs" />
|
||||
<Compile Include="Messaging\Events\EventAggregator.cs" />
|
||||
<Compile Include="Messaging\Events\IEventAggregator.cs" />
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue