mirror of
https://github.com/lidarr/lidarr.git
synced 2025-07-30 03:38:26 -07:00
Add AlbumCutoffService and Refactor UI
This commit is contained in:
parent
8683c92de6
commit
eaba78ad4a
6 changed files with 192 additions and 61 deletions
|
@ -76,19 +76,19 @@ export const defaultState = {
|
||||||
isSortable: true,
|
isSortable: true,
|
||||||
isVisible: true
|
isVisible: true
|
||||||
},
|
},
|
||||||
|
// {
|
||||||
|
// name: 'episode',
|
||||||
|
// label: 'Episode',
|
||||||
|
// isVisible: true
|
||||||
|
// },
|
||||||
{
|
{
|
||||||
name: 'episode',
|
name: 'albumTitle',
|
||||||
label: 'Episode',
|
label: 'Album Title',
|
||||||
isVisible: true
|
isVisible: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'episodeTitle',
|
name: 'releaseDate',
|
||||||
label: 'Episode Title',
|
label: 'Release Date',
|
||||||
isVisible: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'airDateUtc',
|
|
||||||
label: 'Air Date',
|
|
||||||
isSortable: true,
|
isSortable: true,
|
||||||
isVisible: true
|
isVisible: true
|
||||||
},
|
},
|
||||||
|
@ -97,11 +97,11 @@ export const defaultState = {
|
||||||
label: 'Language',
|
label: 'Language',
|
||||||
isVisible: false
|
isVisible: false
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
name: 'status',
|
// name: 'status',
|
||||||
label: 'Status',
|
// label: 'Status',
|
||||||
isVisible: true
|
// isVisible: true
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
name: 'actions',
|
name: 'actions',
|
||||||
columnLabel: 'Actions',
|
columnLabel: 'Actions',
|
||||||
|
|
|
@ -3,7 +3,6 @@ import React from 'react';
|
||||||
import episodeEntities from 'Episode/episodeEntities';
|
import episodeEntities from 'Episode/episodeEntities';
|
||||||
import EpisodeTitleLink from 'Episode/EpisodeTitleLink';
|
import EpisodeTitleLink from 'Episode/EpisodeTitleLink';
|
||||||
import EpisodeStatusConnector from 'Episode/EpisodeStatusConnector';
|
import EpisodeStatusConnector from 'Episode/EpisodeStatusConnector';
|
||||||
import SeasonEpisodeNumber from 'Episode/SeasonEpisodeNumber';
|
|
||||||
import EpisodeSearchCellConnector from 'Episode/EpisodeSearchCellConnector';
|
import EpisodeSearchCellConnector from 'Episode/EpisodeSearchCellConnector';
|
||||||
import TrackFileLanguageConnector from 'TrackFile/TrackFileLanguageConnector';
|
import TrackFileLanguageConnector from 'TrackFile/TrackFileLanguageConnector';
|
||||||
import ArtistNameLink from 'Artist/ArtistNameLink';
|
import ArtistNameLink from 'Artist/ArtistNameLink';
|
||||||
|
@ -18,13 +17,7 @@ function CutoffUnmetRow(props) {
|
||||||
id,
|
id,
|
||||||
trackFileId,
|
trackFileId,
|
||||||
artist,
|
artist,
|
||||||
seasonNumber,
|
releaseDate,
|
||||||
episodeNumber,
|
|
||||||
absoluteEpisodeNumber,
|
|
||||||
sceneSeasonNumber,
|
|
||||||
sceneEpisodeNumber,
|
|
||||||
sceneAbsoluteEpisodeNumber,
|
|
||||||
airDateUtc,
|
|
||||||
title,
|
title,
|
||||||
isSelected,
|
isSelected,
|
||||||
columns,
|
columns,
|
||||||
|
@ -54,33 +47,14 @@ function CutoffUnmetRow(props) {
|
||||||
return (
|
return (
|
||||||
<TableRowCell key={name}>
|
<TableRowCell key={name}>
|
||||||
<ArtistNameLink
|
<ArtistNameLink
|
||||||
titleSlug={artist.titleSlug}
|
nameSlug={artist.nameSlug}
|
||||||
title={artist.title}
|
artistName={artist.artistName}
|
||||||
/>
|
/>
|
||||||
</TableRowCell>
|
</TableRowCell>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name === 'episode') {
|
if (name === 'albumTitle') {
|
||||||
return (
|
|
||||||
<TableRowCell
|
|
||||||
key={name}
|
|
||||||
className={styles.episode}
|
|
||||||
>
|
|
||||||
<SeasonEpisodeNumber
|
|
||||||
seasonNumber={seasonNumber}
|
|
||||||
episodeNumber={episodeNumber}
|
|
||||||
absoluteEpisodeNumber={absoluteEpisodeNumber}
|
|
||||||
artistType={artist.artistType}
|
|
||||||
sceneSeasonNumber={sceneSeasonNumber}
|
|
||||||
sceneEpisodeNumber={sceneEpisodeNumber}
|
|
||||||
sceneAbsoluteEpisodeNumber={sceneAbsoluteEpisodeNumber}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'episodeTitle') {
|
|
||||||
return (
|
return (
|
||||||
<TableRowCell key={name}>
|
<TableRowCell key={name}>
|
||||||
<EpisodeTitleLink
|
<EpisodeTitleLink
|
||||||
|
@ -94,11 +68,11 @@ function CutoffUnmetRow(props) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name === 'airDateUtc') {
|
if (name === 'releaseDate') {
|
||||||
return (
|
return (
|
||||||
<RelativeDateCellConnector
|
<RelativeDateCellConnector
|
||||||
key={name}
|
key={name}
|
||||||
date={airDateUtc}
|
date={releaseDate}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -155,13 +129,7 @@ CutoffUnmetRow.propTypes = {
|
||||||
id: PropTypes.number.isRequired,
|
id: PropTypes.number.isRequired,
|
||||||
trackFileId: PropTypes.number,
|
trackFileId: PropTypes.number,
|
||||||
artist: PropTypes.object.isRequired,
|
artist: PropTypes.object.isRequired,
|
||||||
seasonNumber: PropTypes.number.isRequired,
|
releaseDate: PropTypes.string.isRequired,
|
||||||
episodeNumber: PropTypes.number.isRequired,
|
|
||||||
absoluteEpisodeNumber: PropTypes.number,
|
|
||||||
sceneSeasonNumber: PropTypes.number,
|
|
||||||
sceneEpisodeNumber: PropTypes.number,
|
|
||||||
sceneAbsoluteEpisodeNumber: PropTypes.number,
|
|
||||||
airDateUtc: PropTypes.string.isRequired,
|
|
||||||
title: PropTypes.string.isRequired,
|
title: PropTypes.string.isRequired,
|
||||||
isSelected: PropTypes.bool,
|
isSelected: PropTypes.bool,
|
||||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.DecisionEngine;
|
using NzbDrone.Core.DecisionEngine;
|
||||||
using NzbDrone.Core.Music;
|
using NzbDrone.Core.Music;
|
||||||
using NzbDrone.Core.Tv; //TODO Remove after EpisodeCutoffService is Refactored
|
|
||||||
using NzbDrone.Core.ArtistStats;
|
using NzbDrone.Core.ArtistStats;
|
||||||
using NzbDrone.SignalR;
|
using NzbDrone.SignalR;
|
||||||
using Lidarr.Api.V3.Albums;
|
using Lidarr.Api.V3.Albums;
|
||||||
|
@ -12,9 +11,9 @@ namespace Lidarr.Api.V3.Wanted
|
||||||
{
|
{
|
||||||
public class CutoffModule : AlbumModuleWithSignalR
|
public class CutoffModule : AlbumModuleWithSignalR
|
||||||
{
|
{
|
||||||
private readonly IEpisodeCutoffService _episodeCutoffService;
|
private readonly IAlbumCutoffService _albumCutoffService;
|
||||||
|
|
||||||
public CutoffModule(IEpisodeCutoffService episodeCutoffService,
|
public CutoffModule(IAlbumCutoffService albumCutoffService,
|
||||||
IAlbumService albumService,
|
IAlbumService albumService,
|
||||||
IArtistStatisticsService artistStatisticsService,
|
IArtistStatisticsService artistStatisticsService,
|
||||||
IArtistService artistService,
|
IArtistService artistService,
|
||||||
|
@ -22,7 +21,7 @@ namespace Lidarr.Api.V3.Wanted
|
||||||
IBroadcastSignalRMessage signalRBroadcaster)
|
IBroadcastSignalRMessage signalRBroadcaster)
|
||||||
: base(albumService, artistStatisticsService, artistService, upgradableSpecification, signalRBroadcaster, "wanted/cutoff")
|
: base(albumService, artistStatisticsService, artistService, upgradableSpecification, signalRBroadcaster, "wanted/cutoff")
|
||||||
{
|
{
|
||||||
_episodeCutoffService = episodeCutoffService;
|
_albumCutoffService = albumCutoffService;
|
||||||
GetResourcePaged = GetCutoffUnmetAlbums;
|
GetResourcePaged = GetCutoffUnmetAlbums;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +36,6 @@ namespace Lidarr.Api.V3.Wanted
|
||||||
};
|
};
|
||||||
|
|
||||||
var includeArtist = Request.GetBooleanQueryParameter("includeArtist");
|
var includeArtist = Request.GetBooleanQueryParameter("includeArtist");
|
||||||
var includeTrackFile = Request.GetBooleanQueryParameter("includeTrackFile");
|
|
||||||
|
|
||||||
if (pagingResource.FilterKey == "monitored" && pagingResource.FilterValue == "false")
|
if (pagingResource.FilterKey == "monitored" && pagingResource.FilterValue == "false")
|
||||||
{
|
{
|
||||||
|
@ -48,9 +46,9 @@ namespace Lidarr.Api.V3.Wanted
|
||||||
pagingSpec.FilterExpression = v => v.Monitored == true && v.Artist.Monitored == true;
|
pagingSpec.FilterExpression = v => v.Monitored == true && v.Artist.Monitored == true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//var resource = ApplyToPage(_episodeCutoffService.EpisodesWhereCutoffUnmet, pagingSpec, v => MapToResource(v, includeSeries, includeEpisodeFile));
|
var resource = ApplyToPage(_albumCutoffService.AlbumsWhereCutoffUnmet, pagingSpec, v => MapToResource(v, includeArtist));
|
||||||
return null;
|
|
||||||
//return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
65
src/NzbDrone.Core/Music/AlbumCutoffService.cs
Normal file
65
src/NzbDrone.Core/Music/AlbumCutoffService.cs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
using NzbDrone.Core.Languages;
|
||||||
|
using NzbDrone.Core.Profiles.Qualities;
|
||||||
|
using NzbDrone.Core.Profiles.Languages;
|
||||||
|
using NzbDrone.Core.Qualities;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Music
|
||||||
|
{
|
||||||
|
public interface IAlbumCutoffService
|
||||||
|
{
|
||||||
|
PagingSpec<Album> AlbumsWhereCutoffUnmet(PagingSpec<Album> pagingSpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AlbumCutoffService : IAlbumCutoffService
|
||||||
|
{
|
||||||
|
private readonly IAlbumRepository _albumRepository;
|
||||||
|
private readonly IProfileService _profileService;
|
||||||
|
private readonly ILanguageProfileService _languageProfileService;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public AlbumCutoffService(IAlbumRepository albumRepository, IProfileService profileService, ILanguageProfileService languageProfileService, Logger logger)
|
||||||
|
{
|
||||||
|
_albumRepository = albumRepository;
|
||||||
|
_profileService = profileService;
|
||||||
|
_languageProfileService = languageProfileService;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PagingSpec<Album> AlbumsWhereCutoffUnmet(PagingSpec<Album> pagingSpec)
|
||||||
|
{
|
||||||
|
var qualitiesBelowCutoff = new List<QualitiesBelowCutoff>();
|
||||||
|
var languagesBelowCutoff = new List<LanguagesBelowCutoff>();
|
||||||
|
var profiles = _profileService.All();
|
||||||
|
var languageProfiles = _languageProfileService.All();
|
||||||
|
|
||||||
|
//Get all items less than the cutoff
|
||||||
|
foreach (var profile in profiles)
|
||||||
|
{
|
||||||
|
var cutoffIndex = profile.Items.FindIndex(v => v.Quality == profile.Cutoff);
|
||||||
|
var belowCutoff = profile.Items.Take(cutoffIndex).ToList();
|
||||||
|
|
||||||
|
if (belowCutoff.Any())
|
||||||
|
{
|
||||||
|
qualitiesBelowCutoff.Add(new QualitiesBelowCutoff(profile.Id, belowCutoff.Select(i => i.Quality.Id)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var profile in languageProfiles)
|
||||||
|
{
|
||||||
|
var languageCutoffIndex = profile.Languages.FindIndex(v => v.Language == profile.Cutoff);
|
||||||
|
var belowLanguageCutoff = profile.Languages.Take(languageCutoffIndex).ToList();
|
||||||
|
|
||||||
|
if (belowLanguageCutoff.Any())
|
||||||
|
{
|
||||||
|
languagesBelowCutoff.Add(new LanguagesBelowCutoff(profile.Id, belowLanguageCutoff.Select(l => l.Language.Id)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _albumRepository.AlbumsWhereCutoffUnmet(pagingSpec, qualitiesBelowCutoff, languagesBelowCutoff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,8 @@ using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.Datastore.Extensions;
|
using NzbDrone.Core.Datastore.Extensions;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
using NzbDrone.Core.Languages;
|
||||||
|
using NzbDrone.Core.Qualities;
|
||||||
using Marr.Data.QGen;
|
using Marr.Data.QGen;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Music
|
namespace NzbDrone.Core.Music
|
||||||
|
@ -18,6 +20,7 @@ namespace NzbDrone.Core.Music
|
||||||
Album FindByArtistAndName(string artistName, string cleanTitle);
|
Album FindByArtistAndName(string artistName, string cleanTitle);
|
||||||
Album FindById(string spotifyId);
|
Album FindById(string spotifyId);
|
||||||
PagingSpec<Album> AlbumsWithoutFiles(PagingSpec<Album> pagingSpec);
|
PagingSpec<Album> AlbumsWithoutFiles(PagingSpec<Album> pagingSpec);
|
||||||
|
PagingSpec<Album> AlbumsWhereCutoffUnmet(PagingSpec<Album> pagingSpec, List<QualitiesBelowCutoff> qualitiesBelowCutoff, List<LanguagesBelowCutoff> languagesBelowCutoff);
|
||||||
List<Album> AlbumsBetweenDates(DateTime startDate, DateTime endDate, bool includeUnmonitored);
|
List<Album> AlbumsBetweenDates(DateTime startDate, DateTime endDate, bool includeUnmonitored);
|
||||||
void SetMonitoredFlat(Album album, bool monitored);
|
void SetMonitoredFlat(Album album, bool monitored);
|
||||||
void SetMonitored(IEnumerable<int> ids, bool monitored);
|
void SetMonitored(IEnumerable<int> ids, bool monitored);
|
||||||
|
@ -61,6 +64,15 @@ namespace NzbDrone.Core.Music
|
||||||
return pagingSpec;
|
return pagingSpec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PagingSpec<Album> AlbumsWhereCutoffUnmet(PagingSpec<Album> pagingSpec, List<QualitiesBelowCutoff> qualitiesBelowCutoff, List<LanguagesBelowCutoff> languagesBelowCutoff)
|
||||||
|
{
|
||||||
|
|
||||||
|
pagingSpec.TotalRecords = GetCutOffAlbumsQueryCount(pagingSpec, qualitiesBelowCutoff, languagesBelowCutoff);
|
||||||
|
pagingSpec.Records = GetCutOffAlbumsQuery(pagingSpec, qualitiesBelowCutoff, languagesBelowCutoff).ToList();
|
||||||
|
|
||||||
|
return pagingSpec;
|
||||||
|
}
|
||||||
|
|
||||||
public List<Album> AlbumsBetweenDates(DateTime startDate, DateTime endDate, bool includeUnmonitored)
|
public List<Album> AlbumsBetweenDates(DateTime startDate, DateTime endDate, bool includeUnmonitored)
|
||||||
{
|
{
|
||||||
var query = Query.Join<Album, Artist>(JoinType.Inner, e => e.Artist, (e, s) => e.ArtistId == s.Id)
|
var query = Query.Join<Album, Artist>(JoinType.Inner, e => e.Artist, (e, s) => e.ArtistId == s.Id)
|
||||||
|
@ -148,6 +160,93 @@ namespace NzbDrone.Core.Music
|
||||||
currentTime.ToString("yyyy-MM-dd HH:mm:ss"));
|
currentTime.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private QueryBuilder<Album> GetCutOffAlbumsQuery(PagingSpec<Album> pagingSpec, List<QualitiesBelowCutoff> qualitiesBelowCutoff, List<LanguagesBelowCutoff> languagesBelowCutoff)
|
||||||
|
{
|
||||||
|
string sortKey;
|
||||||
|
string monitored = "(Albums.[Monitored] = 0) OR (Artists.[Monitored] = 0)";
|
||||||
|
|
||||||
|
if (pagingSpec.FilterExpression.ToString().Contains("True"))
|
||||||
|
{
|
||||||
|
monitored = "(Albums.[Monitored] = 1) AND (Artists.[Monitored] = 1)";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pagingSpec.SortKey == "releaseDate")
|
||||||
|
{
|
||||||
|
sortKey = "Albums." + pagingSpec.SortKey;
|
||||||
|
}
|
||||||
|
else if (pagingSpec.SortKey == "artist.sortName")
|
||||||
|
{
|
||||||
|
sortKey = "Artists." + pagingSpec.SortKey.Split('.').Last();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sortKey = "Albums.releaseDate";
|
||||||
|
}
|
||||||
|
|
||||||
|
string query = string.Format("SELECT Albums.* FROM(SELECT TrackFiles.AlbumId, TrackFiles.Language, COUNT(*) AS FileCount, " +
|
||||||
|
" MIN(Quality) AS MinQuality FROM TrackFiles GROUP BY TrackFiles.ArtistId, TrackFiles.AlbumId) as TrackFiles" +
|
||||||
|
" LEFT OUTER JOIN Albums ON TrackFiles.AlbumId == Albums.Id" +
|
||||||
|
" LEFT OUTER JOIN Artists ON Albums.ArtistId == Artists.Id" +
|
||||||
|
" WHERE ({0}) AND ({1} OR {2})" +
|
||||||
|
" GROUP BY TrackFiles.AlbumId" +
|
||||||
|
" ORDER BY {3} {4} LIMIT {5} OFFSET {6}",
|
||||||
|
monitored, BuildQualityCutoffWhereClause(qualitiesBelowCutoff), BuildLanguageCutoffWhereClause(languagesBelowCutoff), sortKey, pagingSpec.ToSortDirection(), pagingSpec.PageSize, pagingSpec.PagingOffset());
|
||||||
|
|
||||||
|
return Query.QueryText(query);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetCutOffAlbumsQueryCount(PagingSpec<Album> pagingSpec, List<QualitiesBelowCutoff> qualitiesBelowCutoff, List<LanguagesBelowCutoff> languagesBelowCutoff)
|
||||||
|
{
|
||||||
|
var monitored = 0;
|
||||||
|
|
||||||
|
if (pagingSpec.FilterExpression.ToString().Contains("True"))
|
||||||
|
{
|
||||||
|
monitored = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
string query = string.Format("SELECT Albums.* FROM (SELECT TrackFiles.AlbumId, TrackFiles.Language, COUNT(*) AS FileCount," +
|
||||||
|
" MIN(Quality) AS MinQuality FROM TrackFiles GROUP BY TrackFiles.ArtistId, TrackFiles.AlbumId) as TrackFiles" +
|
||||||
|
" LEFT OUTER JOIN Albums ON TrackFiles.AlbumId == Albums.Id" +
|
||||||
|
" LEFT OUTER JOIN Artists ON Albums.ArtistId == Artists.Id" +
|
||||||
|
" WHERE ({0}) AND ({1} OR {2})" +
|
||||||
|
" GROUP BY TrackFiles.AlbumId",
|
||||||
|
monitored, BuildQualityCutoffWhereClause(qualitiesBelowCutoff), BuildLanguageCutoffWhereClause(languagesBelowCutoff));
|
||||||
|
|
||||||
|
return Query.QueryText(query).Count();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string BuildLanguageCutoffWhereClause(List<LanguagesBelowCutoff> languagesBelowCutoff)
|
||||||
|
{
|
||||||
|
var clauses = new List<String>();
|
||||||
|
|
||||||
|
foreach (var language in languagesBelowCutoff)
|
||||||
|
{
|
||||||
|
foreach (var belowCutoff in language.LanguageIds)
|
||||||
|
{
|
||||||
|
clauses.Add(String.Format("(Artists.[LanguageProfileId] = {0} AND TrackFiles.[Language] = {1})", language.ProfileId, belowCutoff));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return String.Format("({0})", String.Join(" OR ", clauses));
|
||||||
|
}
|
||||||
|
|
||||||
|
private string BuildQualityCutoffWhereClause(List<QualitiesBelowCutoff> qualitiesBelowCutoff)
|
||||||
|
{
|
||||||
|
var clauses = new List<string>();
|
||||||
|
|
||||||
|
foreach (var profile in qualitiesBelowCutoff)
|
||||||
|
{
|
||||||
|
foreach (var belowCutoff in profile.QualityIds)
|
||||||
|
{
|
||||||
|
clauses.Add(string.Format("(Artists.[ProfileId] = {0} AND TrackFiles.MinQuality LIKE '%_quality_: {1},%')", profile.ProfileId, belowCutoff));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Format("({0})", string.Join(" OR ", clauses));
|
||||||
|
}
|
||||||
|
|
||||||
public void SetMonitoredFlat(Album album, bool monitored)
|
public void SetMonitoredFlat(Album album, bool monitored)
|
||||||
{
|
{
|
||||||
album.Monitored = monitored;
|
album.Monitored = monitored;
|
||||||
|
|
|
@ -866,6 +866,7 @@
|
||||||
<Compile Include="Extras\Metadata\MetadataService.cs" />
|
<Compile Include="Extras\Metadata\MetadataService.cs" />
|
||||||
<Compile Include="Extras\Metadata\MetadataType.cs" />
|
<Compile Include="Extras\Metadata\MetadataType.cs" />
|
||||||
<Compile Include="Music\ArtistStatusType.cs" />
|
<Compile Include="Music\ArtistStatusType.cs" />
|
||||||
|
<Compile Include="Music\AlbumCutoffService.cs" />
|
||||||
<Compile Include="Music\Links.cs" />
|
<Compile Include="Music\Links.cs" />
|
||||||
<Compile Include="Music\Commands\MoveArtistCommand.cs" />
|
<Compile Include="Music\Commands\MoveArtistCommand.cs" />
|
||||||
<Compile Include="Music\Events\ArtistMovedEvent.cs" />
|
<Compile Include="Music\Events\ArtistMovedEvent.cs" />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue