mirror of
https://github.com/lidarr/lidarr.git
synced 2025-07-15 01:23:53 -07:00
Fixed: Faster artist endpoint (#874)
* Fixed: Speed up AllArtist API endpoint * New: Display UI before artists have loaded * Add test of new repository methods
This commit is contained in:
parent
698d5e1cf5
commit
0352f8d3ff
18 changed files with 158 additions and 31 deletions
|
@ -50,6 +50,10 @@ class BlacklistRow extends Component {
|
||||||
onRemovePress
|
onRemovePress
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
if (!artist) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
{
|
{
|
||||||
|
|
|
@ -67,7 +67,7 @@ class HistoryRow extends Component {
|
||||||
onMarkAsFailedPress
|
onMarkAsFailedPress
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (!album) {
|
if (!artist || !album) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
||||||
import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
||||||
import selectAll from 'Utilities/Table/selectAll';
|
import selectAll from 'Utilities/Table/selectAll';
|
||||||
import toggleSelected from 'Utilities/Table/toggleSelected';
|
import toggleSelected from 'Utilities/Table/toggleSelected';
|
||||||
|
@ -145,7 +146,7 @@ class AlbumStudio extends Component {
|
||||||
|
|
||||||
{
|
{
|
||||||
!isFetching && !!error &&
|
!isFetching && !!error &&
|
||||||
<div>Unable to load the Album Studio</div>
|
<div>{getErrorMessage(error, 'Failed to load artist from API')}</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
||||||
import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
||||||
import selectAll from 'Utilities/Table/selectAll';
|
import selectAll from 'Utilities/Table/selectAll';
|
||||||
import toggleSelected from 'Utilities/Table/toggleSelected';
|
import toggleSelected from 'Utilities/Table/toggleSelected';
|
||||||
|
@ -209,7 +210,7 @@ class ArtistEditor extends Component {
|
||||||
|
|
||||||
{
|
{
|
||||||
!isFetching && !!error &&
|
!isFetching && !!error &&
|
||||||
<div>Unable to load the calendar</div>
|
<div>{getErrorMessage(error, 'Failed to load artist from API')}</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,6 +4,12 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.errorMessage {
|
||||||
|
margin-top: 20px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.contentBody {
|
.contentBody {
|
||||||
composes: contentBody from '~Components/Page/PageContentBody.css';
|
composes: contentBody from '~Components/Page/PageContentBody.css';
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import _ from 'lodash';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
|
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
|
||||||
|
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
||||||
import { align, icons, sortDirections } from 'Helpers/Props';
|
import { align, icons, sortDirections } from 'Helpers/Props';
|
||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
import PageContent from 'Components/Page/PageContent';
|
import PageContent from 'Components/Page/PageContent';
|
||||||
|
@ -340,7 +341,9 @@ class ArtistIndex extends Component {
|
||||||
|
|
||||||
{
|
{
|
||||||
!isFetching && !!error &&
|
!isFetching && !!error &&
|
||||||
<div>Unable to load artist</div>
|
<div className={styles.errorMessage}>
|
||||||
|
{getErrorMessage(error, 'Failed to load artist from API')}
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,3 +12,9 @@
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.errorMessage {
|
||||||
|
margin-top: 20px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
||||||
import { align, icons } from 'Helpers/Props';
|
import { align, icons } from 'Helpers/Props';
|
||||||
import PageContent from 'Components/Page/PageContent';
|
import PageContent from 'Components/Page/PageContent';
|
||||||
import Measure from 'Components/Measure';
|
import Measure from 'Components/Measure';
|
||||||
|
@ -75,6 +76,7 @@ class CalendarPage extends Component {
|
||||||
selectedFilterKey,
|
selectedFilterKey,
|
||||||
filters,
|
filters,
|
||||||
hasArtist,
|
hasArtist,
|
||||||
|
artistError,
|
||||||
missingAlbumIds,
|
missingAlbumIds,
|
||||||
isSearchingForMissing,
|
isSearchingForMissing,
|
||||||
useCurrentPage,
|
useCurrentPage,
|
||||||
|
@ -131,21 +133,31 @@ class CalendarPage extends Component {
|
||||||
className={styles.calendarPageBody}
|
className={styles.calendarPageBody}
|
||||||
innerClassName={styles.calendarInnerPageBody}
|
innerClassName={styles.calendarInnerPageBody}
|
||||||
>
|
>
|
||||||
<Measure
|
{
|
||||||
whitelist={['width']}
|
artistError &&
|
||||||
onMeasure={this.onMeasure}
|
<div className={styles.errorMessage}>
|
||||||
>
|
{getErrorMessage(artistError, 'Failed to load artist from API')}
|
||||||
{
|
</div>
|
||||||
isMeasured ?
|
}
|
||||||
<PageComponent
|
|
||||||
useCurrentPage={useCurrentPage}
|
|
||||||
/> :
|
|
||||||
<div />
|
|
||||||
}
|
|
||||||
</Measure>
|
|
||||||
|
|
||||||
{
|
{
|
||||||
hasArtist &&
|
!artistError &&
|
||||||
|
<Measure
|
||||||
|
whitelist={['width']}
|
||||||
|
onMeasure={this.onMeasure}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
isMeasured ?
|
||||||
|
<PageComponent
|
||||||
|
useCurrentPage={useCurrentPage}
|
||||||
|
/> :
|
||||||
|
<div />
|
||||||
|
}
|
||||||
|
</Measure>
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
hasArtist && !!artistError &&
|
||||||
<LegendConnector />
|
<LegendConnector />
|
||||||
}
|
}
|
||||||
</PageContentBodyConnector>
|
</PageContentBodyConnector>
|
||||||
|
@ -169,6 +181,7 @@ CalendarPage.propTypes = {
|
||||||
selectedFilterKey: PropTypes.string.isRequired,
|
selectedFilterKey: PropTypes.string.isRequired,
|
||||||
filters: PropTypes.arrayOf(PropTypes.object).isRequired,
|
filters: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
hasArtist: PropTypes.bool.isRequired,
|
hasArtist: PropTypes.bool.isRequired,
|
||||||
|
artistError: PropTypes.object,
|
||||||
missingAlbumIds: PropTypes.arrayOf(PropTypes.number).isRequired,
|
missingAlbumIds: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||||
isSearchingForMissing: PropTypes.bool.isRequired,
|
isSearchingForMissing: PropTypes.bool.isRequired,
|
||||||
useCurrentPage: PropTypes.bool.isRequired,
|
useCurrentPage: PropTypes.bool.isRequired,
|
||||||
|
|
|
@ -72,7 +72,8 @@ function createMapStateToProps() {
|
||||||
selectedFilterKey,
|
selectedFilterKey,
|
||||||
filters,
|
filters,
|
||||||
colorImpairedMode: uiSettings.enableColorImpairedMode,
|
colorImpairedMode: uiSettings.enableColorImpairedMode,
|
||||||
hasArtist: !!artistCount,
|
hasArtist: !!artistCount.count,
|
||||||
|
artistError: artistCount.error,
|
||||||
missingAlbumIds,
|
missingAlbumIds,
|
||||||
isSearchingForMissing
|
isSearchingForMissing
|
||||||
};
|
};
|
||||||
|
|
|
@ -43,7 +43,6 @@ const selectAppProps = createSelector(
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectIsPopulated = createSelector(
|
const selectIsPopulated = createSelector(
|
||||||
(state) => state.artist.isPopulated,
|
|
||||||
(state) => state.customFilters.isPopulated,
|
(state) => state.customFilters.isPopulated,
|
||||||
(state) => state.tags.isPopulated,
|
(state) => state.tags.isPopulated,
|
||||||
(state) => state.settings.ui.isPopulated,
|
(state) => state.settings.ui.isPopulated,
|
||||||
|
@ -52,7 +51,6 @@ const selectIsPopulated = createSelector(
|
||||||
(state) => state.settings.importLists.isPopulated,
|
(state) => state.settings.importLists.isPopulated,
|
||||||
(state) => state.system.status.isPopulated,
|
(state) => state.system.status.isPopulated,
|
||||||
(
|
(
|
||||||
artistIsPopulated,
|
|
||||||
customFiltersIsPopulated,
|
customFiltersIsPopulated,
|
||||||
tagsIsPopulated,
|
tagsIsPopulated,
|
||||||
uiSettingsIsPopulated,
|
uiSettingsIsPopulated,
|
||||||
|
@ -62,7 +60,6 @@ const selectIsPopulated = createSelector(
|
||||||
systemStatusIsPopulated
|
systemStatusIsPopulated
|
||||||
) => {
|
) => {
|
||||||
return (
|
return (
|
||||||
artistIsPopulated &&
|
|
||||||
customFiltersIsPopulated &&
|
customFiltersIsPopulated &&
|
||||||
tagsIsPopulated &&
|
tagsIsPopulated &&
|
||||||
uiSettingsIsPopulated &&
|
uiSettingsIsPopulated &&
|
||||||
|
@ -75,7 +72,6 @@ const selectIsPopulated = createSelector(
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectErrors = createSelector(
|
const selectErrors = createSelector(
|
||||||
(state) => state.artist.error,
|
|
||||||
(state) => state.customFilters.error,
|
(state) => state.customFilters.error,
|
||||||
(state) => state.tags.error,
|
(state) => state.tags.error,
|
||||||
(state) => state.settings.ui.error,
|
(state) => state.settings.ui.error,
|
||||||
|
@ -84,7 +80,6 @@ const selectErrors = createSelector(
|
||||||
(state) => state.settings.importLists.error,
|
(state) => state.settings.importLists.error,
|
||||||
(state) => state.system.status.error,
|
(state) => state.system.status.error,
|
||||||
(
|
(
|
||||||
artistError,
|
|
||||||
customFiltersError,
|
customFiltersError,
|
||||||
tagsError,
|
tagsError,
|
||||||
uiSettingsError,
|
uiSettingsError,
|
||||||
|
@ -94,7 +89,6 @@ const selectErrors = createSelector(
|
||||||
systemStatusError
|
systemStatusError
|
||||||
) => {
|
) => {
|
||||||
const hasError = !!(
|
const hasError = !!(
|
||||||
artistError ||
|
|
||||||
customFiltersError ||
|
customFiltersError ||
|
||||||
tagsError ||
|
tagsError ||
|
||||||
uiSettingsError ||
|
uiSettingsError ||
|
||||||
|
@ -106,7 +100,6 @@ const selectErrors = createSelector(
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hasError,
|
hasError,
|
||||||
artistError,
|
|
||||||
customFiltersError,
|
customFiltersError,
|
||||||
tagsError,
|
tagsError,
|
||||||
uiSettingsError,
|
uiSettingsError,
|
||||||
|
|
|
@ -4,8 +4,12 @@ import createAllArtistSelector from './createAllArtistSelector';
|
||||||
function createArtistCountSelector() {
|
function createArtistCountSelector() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
createAllArtistSelector(),
|
createAllArtistSelector(),
|
||||||
(artists) => {
|
(state) => state.artist.error,
|
||||||
return artists.length;
|
(artists, error) => {
|
||||||
|
return {
|
||||||
|
count: artists.length,
|
||||||
|
error
|
||||||
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,10 @@ function CutoffUnmetRow(props) {
|
||||||
onSelectedChange
|
onSelectedChange
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
if (!artist) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableSelectCell
|
<TableSelectCell
|
||||||
|
|
|
@ -184,11 +184,13 @@ namespace Lidarr.Api.V1.Artist
|
||||||
|
|
||||||
private void LinkNextPreviousAlbums(params ArtistResource[] artists)
|
private void LinkNextPreviousAlbums(params ArtistResource[] artists)
|
||||||
{
|
{
|
||||||
|
var nextAlbums = _albumService.GetNextAlbumsByArtistMetadataId(artists.Select(x => x.ArtistMetadataId));
|
||||||
|
var lastAlbums = _albumService.GetLastAlbumsByArtistMetadataId(artists.Select(x => x.ArtistMetadataId));
|
||||||
|
|
||||||
foreach (var artistResource in artists)
|
foreach (var artistResource in artists)
|
||||||
{
|
{
|
||||||
var artistAlbums = _albumService.GetAlbumsByArtist(artistResource.Id).OrderBy(s=>s.ReleaseDate);
|
artistResource.NextAlbum = nextAlbums.FirstOrDefault(x => x.ArtistMetadataId == artistResource.ArtistMetadataId);
|
||||||
artistResource.NextAlbum = artistAlbums.Where(s => s.ReleaseDate >= DateTime.UtcNow && s.Monitored).FirstOrDefault();
|
artistResource.LastAlbum = lastAlbums.FirstOrDefault(x => x.ArtistMetadataId == artistResource.ArtistMetadataId);
|
||||||
artistResource.LastAlbum = artistAlbums.Where(s => s.ReleaseDate <= DateTime.UtcNow && s.Monitored).LastOrDefault();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.MediaCover;
|
using NzbDrone.Core.MediaCover;
|
||||||
using NzbDrone.Core.Music;
|
using NzbDrone.Core.Music;
|
||||||
using Lidarr.Http.REST;
|
using Lidarr.Http.REST;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Lidarr.Api.V1.Artist
|
namespace Lidarr.Api.V1.Artist
|
||||||
{
|
{
|
||||||
|
@ -14,6 +15,8 @@ namespace Lidarr.Api.V1.Artist
|
||||||
//Todo: Is there an easy way to keep IgnoreArticlesWhenSorting in sync between, Series, History, Missing?
|
//Todo: Is there an easy way to keep IgnoreArticlesWhenSorting in sync between, Series, History, Missing?
|
||||||
//Todo: We should get the entire Profile instead of ID and Name separately
|
//Todo: We should get the entire Profile instead of ID and Name separately
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public int ArtistMetadataId { get; set; }
|
||||||
public ArtistStatusType Status { get; set; }
|
public ArtistStatusType Status { get; set; }
|
||||||
|
|
||||||
public bool Ended => Status == ArtistStatusType.Ended;
|
public bool Ended => Status == ArtistStatusType.Ended;
|
||||||
|
@ -70,6 +73,7 @@ namespace Lidarr.Api.V1.Artist
|
||||||
return new ArtistResource
|
return new ArtistResource
|
||||||
{
|
{
|
||||||
Id = model.Id,
|
Id = model.Id,
|
||||||
|
ArtistMetadataId = model.ArtistMetadataId,
|
||||||
|
|
||||||
ArtistName = model.Name,
|
ArtistName = model.Name,
|
||||||
//AlternateTitles
|
//AlternateTitles
|
||||||
|
|
|
@ -3,7 +3,9 @@ using FluentAssertions;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using NzbDrone.Core.Music;
|
using NzbDrone.Core.Music;
|
||||||
using NzbDrone.Core.Test.Framework;
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Test.MusicTests.AlbumRepositoryTests
|
namespace NzbDrone.Core.Test.MusicTests.AlbumRepositoryTests
|
||||||
{
|
{
|
||||||
|
@ -13,6 +15,7 @@ namespace NzbDrone.Core.Test.MusicTests.AlbumRepositoryTests
|
||||||
private Artist _artist;
|
private Artist _artist;
|
||||||
private Album _album;
|
private Album _album;
|
||||||
private Album _albumSpecial;
|
private Album _albumSpecial;
|
||||||
|
private List<Album> _albums;
|
||||||
private AlbumRelease _release;
|
private AlbumRelease _release;
|
||||||
private AlbumRepository _albumRepo;
|
private AlbumRepository _albumRepo;
|
||||||
private ReleaseRepository _releaseRepo;
|
private ReleaseRepository _releaseRepo;
|
||||||
|
@ -150,5 +153,47 @@ namespace NzbDrone.Core.Test.MusicTests.AlbumRepositoryTests
|
||||||
|
|
||||||
album.Should().BeNull();
|
album.Should().BeNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void GivenMultipleAlbums()
|
||||||
|
{
|
||||||
|
_albums = Builder<Album>.CreateListOfSize(4)
|
||||||
|
.All()
|
||||||
|
.With(x => x.Id = 0)
|
||||||
|
.With(x => x.Artist = _artist)
|
||||||
|
.With(x => x.ArtistMetadataId = _artist.ArtistMetadataId)
|
||||||
|
.TheFirst(1)
|
||||||
|
// next
|
||||||
|
.With(x => x.ReleaseDate = DateTime.UtcNow.AddDays(1))
|
||||||
|
.TheNext(1)
|
||||||
|
// another future one
|
||||||
|
.With(x => x.ReleaseDate = DateTime.UtcNow.AddDays(2))
|
||||||
|
.TheNext(1)
|
||||||
|
// most recent
|
||||||
|
.With(x => x.ReleaseDate = DateTime.UtcNow.AddDays(-1))
|
||||||
|
.TheNext(1)
|
||||||
|
// an older one
|
||||||
|
.With(x => x.ReleaseDate = DateTime.UtcNow.AddDays(-2))
|
||||||
|
.BuildList();
|
||||||
|
|
||||||
|
_albumRepo.InsertMany(_albums);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void get_next_albums_should_return_next_album()
|
||||||
|
{
|
||||||
|
GivenMultipleAlbums();
|
||||||
|
|
||||||
|
var result = _albumRepo.GetNextAlbums(new [] { _artist.ArtistMetadataId });
|
||||||
|
result.Should().BeEquivalentTo(_albums.Take(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void get_last_albums_should_return_next_album()
|
||||||
|
{
|
||||||
|
GivenMultipleAlbums();
|
||||||
|
|
||||||
|
var result = _albumRepo.GetLastAlbums(new [] { _artist.ArtistMetadataId });
|
||||||
|
result.Should().BeEquivalentTo(_albums.Skip(2).Take(1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ namespace NzbDrone.Core.Datastore
|
||||||
|
|
||||||
public IEnumerable<TModel> All()
|
public IEnumerable<TModel> All()
|
||||||
{
|
{
|
||||||
return DataMapper.Query<TModel>().ToList();
|
return Query.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Count()
|
public int Count()
|
||||||
|
|
|
@ -14,6 +14,8 @@ namespace NzbDrone.Core.Music
|
||||||
public interface IAlbumRepository : IBasicRepository<Album>
|
public interface IAlbumRepository : IBasicRepository<Album>
|
||||||
{
|
{
|
||||||
List<Album> GetAlbums(int artistId);
|
List<Album> GetAlbums(int artistId);
|
||||||
|
List<Album> GetLastAlbums(IEnumerable<int> artistMetadataIds);
|
||||||
|
List<Album> GetNextAlbums(IEnumerable<int> artistMetadataIds);
|
||||||
List<Album> GetAlbumsByArtistMetadataId(int artistMetadataId);
|
List<Album> GetAlbumsByArtistMetadataId(int artistMetadataId);
|
||||||
List<Album> GetAlbumsForRefresh(int artistId, IEnumerable<string> foreignIds);
|
List<Album> GetAlbumsForRefresh(int artistId, IEnumerable<string> foreignIds);
|
||||||
Album FindByTitle(int artistMetadataId, string title);
|
Album FindByTitle(int artistMetadataId, string title);
|
||||||
|
@ -47,6 +49,32 @@ namespace NzbDrone.Core.Music
|
||||||
.Where<Artist>(a => a.Id == artistId).ToList();
|
.Where<Artist>(a => a.Id == artistId).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Album> GetLastAlbums(IEnumerable<int> artistMetadataIds)
|
||||||
|
{
|
||||||
|
string query = string.Format("SELECT Albums.* " +
|
||||||
|
"FROM Albums " +
|
||||||
|
"WHERE Albums.ArtistMetadataId IN ({0}) " +
|
||||||
|
"AND Albums.ReleaseDate < datetime('now') " +
|
||||||
|
"GROUP BY Albums.ArtistMetadataId " +
|
||||||
|
"HAVING Albums.ReleaseDate = MAX(Albums.ReleaseDate)",
|
||||||
|
string.Join(", ", artistMetadataIds));
|
||||||
|
|
||||||
|
return Query.QueryText(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Album> GetNextAlbums(IEnumerable<int> artistMetadataIds)
|
||||||
|
{
|
||||||
|
string query = string.Format("SELECT Albums.* " +
|
||||||
|
"FROM Albums " +
|
||||||
|
"WHERE Albums.ArtistMetadataId IN ({0}) " +
|
||||||
|
"AND Albums.ReleaseDate > datetime('now') " +
|
||||||
|
"GROUP BY Albums.ArtistMetadataId " +
|
||||||
|
"HAVING Albums.ReleaseDate = MIN(Albums.ReleaseDate)",
|
||||||
|
string.Join(", ", artistMetadataIds));
|
||||||
|
|
||||||
|
return Query.QueryText(query);
|
||||||
|
}
|
||||||
|
|
||||||
public List<Album> GetAlbumsByArtistMetadataId(int artistMetadataId)
|
public List<Album> GetAlbumsByArtistMetadataId(int artistMetadataId)
|
||||||
{
|
{
|
||||||
return Query.Where(s => s.ArtistMetadataId == artistMetadataId);
|
return Query.Where(s => s.ArtistMetadataId == artistMetadataId);
|
||||||
|
|
|
@ -15,6 +15,8 @@ namespace NzbDrone.Core.Music
|
||||||
Album GetAlbum(int albumId);
|
Album GetAlbum(int albumId);
|
||||||
List<Album> GetAlbums(IEnumerable<int> albumIds);
|
List<Album> GetAlbums(IEnumerable<int> albumIds);
|
||||||
List<Album> GetAlbumsByArtist(int artistId);
|
List<Album> GetAlbumsByArtist(int artistId);
|
||||||
|
List<Album> GetNextAlbumsByArtistMetadataId(IEnumerable<int> artistMetadataIds);
|
||||||
|
List<Album> GetLastAlbumsByArtistMetadataId(IEnumerable<int> artistMetadataIds);
|
||||||
List<Album> GetAlbumsByArtistMetadataId(int artistMetadataId);
|
List<Album> GetAlbumsByArtistMetadataId(int artistMetadataId);
|
||||||
List<Album> GetAlbumsForRefresh(int artistMetadataId, IEnumerable<string> foreignIds);
|
List<Album> GetAlbumsForRefresh(int artistMetadataId, IEnumerable<string> foreignIds);
|
||||||
Album AddAlbum(Album newAlbum);
|
Album AddAlbum(Album newAlbum);
|
||||||
|
@ -170,6 +172,16 @@ namespace NzbDrone.Core.Music
|
||||||
return _albumRepository.GetAlbums(artistId).ToList();
|
return _albumRepository.GetAlbums(artistId).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Album> GetNextAlbumsByArtistMetadataId(IEnumerable<int> artistMetadataIds)
|
||||||
|
{
|
||||||
|
return _albumRepository.GetNextAlbums(artistMetadataIds).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Album> GetLastAlbumsByArtistMetadataId(IEnumerable<int> artistMetadataIds)
|
||||||
|
{
|
||||||
|
return _albumRepository.GetLastAlbums(artistMetadataIds).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
public List<Album> GetAlbumsByArtistMetadataId(int artistMetadataId)
|
public List<Album> GetAlbumsByArtistMetadataId(int artistMetadataId)
|
||||||
{
|
{
|
||||||
return _albumRepository.GetAlbumsByArtistMetadataId(artistMetadataId).ToList();
|
return _albumRepository.GetAlbumsByArtistMetadataId(artistMetadataId).ToList();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue