mirror of
https://github.com/lidarr/lidarr.git
synced 2025-07-16 10:03:51 -07:00
AlbumStudio and ArtistEditor Fixes
This commit is contained in:
parent
49309125b6
commit
70cc2ed8a5
15 changed files with 96 additions and 47 deletions
|
@ -4,6 +4,7 @@ import { createSelector } from 'reselect';
|
||||||
import connectSection from 'Store/connectSection';
|
import connectSection from 'Store/connectSection';
|
||||||
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
|
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
|
||||||
import { setAlbumStudioSort, setAlbumStudioFilter, saveAlbumStudio } from 'Store/Actions/albumStudioActions';
|
import { setAlbumStudioSort, setAlbumStudioFilter, saveAlbumStudio } from 'Store/Actions/albumStudioActions';
|
||||||
|
import { fetchEpisodes, clearEpisodes } from 'Store/Actions/episodeActions';
|
||||||
import AlbumStudio from './AlbumStudio';
|
import AlbumStudio from './AlbumStudio';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
|
@ -18,6 +19,8 @@ function createMapStateToProps() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
|
fetchEpisodes,
|
||||||
|
clearEpisodes,
|
||||||
setAlbumStudioSort,
|
setAlbumStudioSort,
|
||||||
setAlbumStudioFilter,
|
setAlbumStudioFilter,
|
||||||
saveAlbumStudio
|
saveAlbumStudio
|
||||||
|
@ -25,6 +28,28 @@ const mapDispatchToProps = {
|
||||||
|
|
||||||
class AlbumStudioConnector extends Component {
|
class AlbumStudioConnector extends Component {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Lifecycle
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.populate();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.unpopulate();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Control
|
||||||
|
|
||||||
|
populate = () => {
|
||||||
|
this.props.fetchEpisodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
unpopulate = () => {
|
||||||
|
this.props.clearEpisodes();
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
|
@ -58,6 +83,8 @@ class AlbumStudioConnector extends Component {
|
||||||
AlbumStudioConnector.propTypes = {
|
AlbumStudioConnector.propTypes = {
|
||||||
setAlbumStudioSort: PropTypes.func.isRequired,
|
setAlbumStudioSort: PropTypes.func.isRequired,
|
||||||
setAlbumStudioFilter: PropTypes.func.isRequired,
|
setAlbumStudioFilter: PropTypes.func.isRequired,
|
||||||
|
fetchEpisodes: PropTypes.func.isRequired,
|
||||||
|
clearEpisodes: PropTypes.func.isRequired,
|
||||||
saveAlbumStudio: PropTypes.func.isRequired
|
saveAlbumStudio: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,16 +10,22 @@ import AlbumStudioRow from './AlbumStudioRow';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
|
(state) => state.episodes,
|
||||||
createArtistSelector(),
|
createArtistSelector(),
|
||||||
(artist) => {
|
(episodes, artist) => {
|
||||||
return _.pick(artist, [
|
const albumsInArtist = _.filter(episodes.items, { artistId: artist.id });
|
||||||
'status',
|
const sortedAlbums = _.orderBy(albumsInArtist, 'releaseDate', 'desc');
|
||||||
'nameSlug',
|
|
||||||
'artistName',
|
return {
|
||||||
'monitored',
|
...artist,
|
||||||
'albums',
|
artistId: artist.id,
|
||||||
'isSaving'
|
artistName: artist.artistName,
|
||||||
]);
|
nameSlug: artist.nameSlug,
|
||||||
|
monitored: artist.monitored,
|
||||||
|
status: artist.status,
|
||||||
|
isSaving: artist.isSaving,
|
||||||
|
albums: sortedAlbums
|
||||||
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -50,7 +56,7 @@ class AlbumStudioRowConnector extends Component {
|
||||||
onAlbumMonitoredPress = (albumId, monitored) => {
|
onAlbumMonitoredPress = (albumId, monitored) => {
|
||||||
this.props.toggleEpisodeMonitored({
|
this.props.toggleEpisodeMonitored({
|
||||||
albumId,
|
albumId,
|
||||||
monitored: !monitored
|
monitored
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -135,7 +135,7 @@ class AlbumRow extends Component {
|
||||||
return (
|
return (
|
||||||
<TableRowCell key={name}>
|
<TableRowCell key={name}>
|
||||||
{
|
{
|
||||||
statistics.trackCount
|
statistics.totalTrackCount
|
||||||
}
|
}
|
||||||
</TableRowCell>
|
</TableRowCell>
|
||||||
);
|
);
|
||||||
|
|
|
@ -66,7 +66,7 @@ class ArtistEditorFooter extends Component {
|
||||||
case 'monitored':
|
case 'monitored':
|
||||||
this.props.onSaveSelected({ [name]: value === 'monitored' });
|
this.props.onSaveSelected({ [name]: value === 'monitored' });
|
||||||
break;
|
break;
|
||||||
case 'seasonFolder':
|
case 'albumFolder':
|
||||||
this.props.onSaveSelected({ [name]: value === 'yes' });
|
this.props.onSaveSelected({ [name]: value === 'yes' });
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -16,7 +16,7 @@ class ArtistEditorRow extends Component {
|
||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onSeasonFolderChange = () => {
|
onAlbumFolderChange = () => {
|
||||||
// Mock handler to satisfy `onChange` being required for `CheckInput`.
|
// Mock handler to satisfy `onChange` being required for `CheckInput`.
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ class ArtistEditorRow extends Component {
|
||||||
name="albumFolder"
|
name="albumFolder"
|
||||||
value={albumFolder}
|
value={albumFolder}
|
||||||
isDisabled={true}
|
isDisabled={true}
|
||||||
onChange={this.onSeasonFolderChange}
|
onChange={this.onAlbumFolderChange}
|
||||||
/>
|
/>
|
||||||
</TableRowCell>
|
</TableRowCell>
|
||||||
|
|
||||||
|
|
|
@ -71,9 +71,9 @@ export const BULK_DELETE_ARTIST = 'BULK_DELETE_ARTIST';
|
||||||
//
|
//
|
||||||
// Season Pass
|
// Season Pass
|
||||||
|
|
||||||
export const SET_SEASON_PASS_SORT = 'SET_SEASON_PASS_SORT';
|
export const SET_ALBUM_STUDIO_SORT = 'SET_ALBUM_STUDIO_SORT';
|
||||||
export const SET_SEASON_PASS_FILTER = 'SET_SEASON_PASS_FILTER';
|
export const SET_ALBUM_STUDIO_FILTER = 'SET_ALBUM_STUDIO_FILTER';
|
||||||
export const SAVE_SEASON_PASS = 'SAVE_SEASON_PASS';
|
export const SAVE_ALBUM_STUDIO = 'SAVE_ALBUM_STUDIO';
|
||||||
|
|
||||||
//
|
//
|
||||||
// Episodes
|
// Episodes
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { fetchArtist } from './artistActions';
|
||||||
const section = 'albumStudio';
|
const section = 'albumStudio';
|
||||||
|
|
||||||
const albumStudioActionHandlers = {
|
const albumStudioActionHandlers = {
|
||||||
[types.SAVE_SEASON_PASS]: function(payload) {
|
[types.SAVE_ALBUM_STUDIO]: function(payload) {
|
||||||
return function(dispatch, getState) {
|
return function(dispatch, getState) {
|
||||||
const {
|
const {
|
||||||
artistIds,
|
artistIds,
|
||||||
|
@ -30,15 +30,15 @@ const albumStudioActionHandlers = {
|
||||||
|
|
||||||
if (monitor) {
|
if (monitor) {
|
||||||
const {
|
const {
|
||||||
seasons,
|
albums,
|
||||||
options: artistMonitoringOptions
|
options: artistMonitoringOptions
|
||||||
} = getMonitoringOptions(_.cloneDeep(s.seasons), monitor);
|
} = getMonitoringOptions(_.cloneDeep(s.albums), monitor);
|
||||||
|
|
||||||
if (!monitoringOptions) {
|
if (!monitoringOptions) {
|
||||||
monitoringOptions = artistMonitoringOptions;
|
monitoringOptions = artistMonitoringOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
artistToUpdate.seasons = seasons;
|
artistToUpdate.albums = albums;
|
||||||
}
|
}
|
||||||
|
|
||||||
artist.push(artistToUpdate);
|
artist.push(artistToUpdate);
|
||||||
|
|
|
@ -2,6 +2,6 @@ import { createAction } from 'redux-actions';
|
||||||
import * as types from './actionTypes';
|
import * as types from './actionTypes';
|
||||||
import albumStudioActionHandlers from './albumStudioActionHandlers';
|
import albumStudioActionHandlers from './albumStudioActionHandlers';
|
||||||
|
|
||||||
export const setAlbumStudioSort = createAction(types.SET_SEASON_PASS_SORT);
|
export const setAlbumStudioSort = createAction(types.SET_ALBUM_STUDIO_SORT);
|
||||||
export const setAlbumStudioFilter = createAction(types.SET_SEASON_PASS_FILTER);
|
export const setAlbumStudioFilter = createAction(types.SET_ALBUM_STUDIO_FILTER);
|
||||||
export const saveAlbumStudio = albumStudioActionHandlers[types.SAVE_SEASON_PASS];
|
export const saveAlbumStudio = albumStudioActionHandlers[types.SAVE_ALBUM_STUDIO];
|
||||||
|
|
|
@ -14,7 +14,7 @@ const episodeActionHandlers = {
|
||||||
[types.TOGGLE_EPISODE_MONITORED]: function(payload) {
|
[types.TOGGLE_EPISODE_MONITORED]: function(payload) {
|
||||||
return function(dispatch, getState) {
|
return function(dispatch, getState) {
|
||||||
const {
|
const {
|
||||||
albumId: id,
|
albumId,
|
||||||
episodeEntity = episodeEntities.EPISODES,
|
episodeEntity = episodeEntities.EPISODES,
|
||||||
monitored
|
monitored
|
||||||
} = payload;
|
} = payload;
|
||||||
|
@ -22,13 +22,13 @@ const episodeActionHandlers = {
|
||||||
const episodeSection = _.last(episodeEntity.split('.'));
|
const episodeSection = _.last(episodeEntity.split('.'));
|
||||||
|
|
||||||
dispatch(updateItem({
|
dispatch(updateItem({
|
||||||
id,
|
id: albumId,
|
||||||
section: episodeSection,
|
section: episodeSection,
|
||||||
isSaving: true
|
isSaving: true
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const promise = $.ajax({
|
const promise = $.ajax({
|
||||||
url: `/album/${id}`,
|
url: `/album/${albumId}`,
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
data: JSON.stringify({ monitored }),
|
data: JSON.stringify({ monitored }),
|
||||||
dataType: 'json'
|
dataType: 'json'
|
||||||
|
@ -36,7 +36,7 @@ const episodeActionHandlers = {
|
||||||
|
|
||||||
promise.done((data) => {
|
promise.done((data) => {
|
||||||
dispatch(updateItem({
|
dispatch(updateItem({
|
||||||
id,
|
id: albumId,
|
||||||
section: episodeSection,
|
section: episodeSection,
|
||||||
isSaving: false,
|
isSaving: false,
|
||||||
monitored
|
monitored
|
||||||
|
@ -45,7 +45,7 @@ const episodeActionHandlers = {
|
||||||
|
|
||||||
promise.fail((xhr) => {
|
promise.fail((xhr) => {
|
||||||
dispatch(updateItem({
|
dispatch(updateItem({
|
||||||
id,
|
id: albumId,
|
||||||
section: episodeSection,
|
section: episodeSection,
|
||||||
isSaving: false
|
isSaving: false
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -31,8 +31,8 @@ const albumStudioReducers = handleActions({
|
||||||
|
|
||||||
[types.SET]: createSetReducer(reducerSection),
|
[types.SET]: createSetReducer(reducerSection),
|
||||||
|
|
||||||
[types.SET_SEASON_PASS_SORT]: createSetClientSideCollectionSortReducer(reducerSection),
|
[types.SET_ALBUM_STUDIO_SORT]: createSetClientSideCollectionSortReducer(reducerSection),
|
||||||
[types.SET_SEASON_PASS_FILTER]: createSetClientSideCollectionFilterReducer(reducerSection)
|
[types.SET_ALBUM_STUDIO_FILTER]: createSetClientSideCollectionFilterReducer(reducerSection)
|
||||||
|
|
||||||
}, defaultState);
|
}, defaultState);
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,10 @@ function monitorSeasons(seasons, startingSeason) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMonitoringOptions(seasons, monitor) {
|
function getMonitoringOptions(albums, monitor) {
|
||||||
if (!seasons.length) {
|
if (!albums.length) {
|
||||||
return {
|
return {
|
||||||
seasons: [],
|
albums: [],
|
||||||
options: {
|
options: {
|
||||||
ignoreEpisodesWithFiles: false,
|
ignoreEpisodesWithFiles: false,
|
||||||
ignoreEpisodesWithoutFiles: false
|
ignoreEpisodesWithoutFiles: false
|
||||||
|
@ -21,10 +21,10 @@ function getMonitoringOptions(seasons, monitor) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const firstSeason = _.minBy(_.reject(seasons, { seasonNumber: 0 }), 'seasonNumber').seasonNumber;
|
const firstSeason = _.minBy(_.reject(albums, { seasonNumber: 0 }), 'seasonNumber').seasonNumber;
|
||||||
const lastSeason = _.maxBy(seasons, 'seasonNumber').seasonNumber;
|
const lastSeason = _.maxBy(albums, 'seasonNumber').seasonNumber;
|
||||||
|
|
||||||
monitorSeasons(seasons, firstSeason);
|
monitorSeasons(albums, firstSeason);
|
||||||
|
|
||||||
const monitoringOptions = {
|
const monitoringOptions = {
|
||||||
ignoreEpisodesWithFiles: false,
|
ignoreEpisodesWithFiles: false,
|
||||||
|
@ -37,11 +37,11 @@ function getMonitoringOptions(seasons, monitor) {
|
||||||
monitoringOptions.ignoreEpisodesWithoutFiles = true;
|
monitoringOptions.ignoreEpisodesWithoutFiles = true;
|
||||||
break;
|
break;
|
||||||
case 'latest':
|
case 'latest':
|
||||||
monitorSeasons(seasons, lastSeason);
|
monitorSeasons(albums, lastSeason);
|
||||||
break;
|
break;
|
||||||
case 'first':
|
case 'first':
|
||||||
monitorSeasons(seasons, lastSeason + 1);
|
monitorSeasons(albums, lastSeason + 1);
|
||||||
_.find(seasons, { seasonNumber: firstSeason }).monitored = true;
|
_.find(albums, { seasonNumber: firstSeason }).monitored = true;
|
||||||
break;
|
break;
|
||||||
case 'missing':
|
case 'missing':
|
||||||
monitoringOptions.ignoreEpisodesWithFiles = true;
|
monitoringOptions.ignoreEpisodesWithFiles = true;
|
||||||
|
@ -50,14 +50,14 @@ function getMonitoringOptions(seasons, monitor) {
|
||||||
monitoringOptions.ignoreEpisodesWithoutFiles = true;
|
monitoringOptions.ignoreEpisodesWithoutFiles = true;
|
||||||
break;
|
break;
|
||||||
case 'none':
|
case 'none':
|
||||||
monitorSeasons(seasons, lastSeason + 1);
|
monitorSeasons(albums, lastSeason + 1);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
seasons: _.map(seasons, (season) => {
|
seasons: _.map(albums, (season) => {
|
||||||
return _.pick(season, [
|
return _.pick(season, [
|
||||||
'seasonNumber',
|
'seasonNumber',
|
||||||
'monitored'
|
'monitored'
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace Lidarr.Api.V3.Albums
|
||||||
|
|
||||||
if (!Request.Query.ArtistId.HasValue && !albumIdsQuery.HasValue)
|
if (!Request.Query.ArtistId.HasValue && !albumIdsQuery.HasValue)
|
||||||
{
|
{
|
||||||
throw new BadRequestException("artistId or albumIds must be provided");
|
return MapToResource(_albumService.GetAllAlbums(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (artistIdQuery.HasValue)
|
if (artistIdQuery.HasValue)
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace Lidarr.Api.V3.Artist
|
||||||
{
|
{
|
||||||
_artistService = artistService;
|
_artistService = artistService;
|
||||||
Put["/"] = artist => SaveAll();
|
Put["/"] = artist => SaveAll();
|
||||||
Delete["/"] = artist => DeleteSeries();
|
Delete["/"] = artist => DeleteArtist();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Response SaveAll()
|
private Response SaveAll()
|
||||||
|
@ -70,7 +70,7 @@ namespace Lidarr.Api.V3.Artist
|
||||||
.AsResponse(HttpStatusCode.Accepted);
|
.AsResponse(HttpStatusCode.Accepted);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Response DeleteSeries()
|
private Response DeleteArtist()
|
||||||
{
|
{
|
||||||
var resource = Request.Body.FromJson<ArtistEditorResource>();
|
var resource = Request.Body.FromJson<ArtistEditorResource>();
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,7 @@ namespace Lidarr.Api.V3.Artist
|
||||||
|
|
||||||
var resource = artist.ToResource();
|
var resource = artist.ToResource();
|
||||||
MapCoversToLocal(resource);
|
MapCoversToLocal(resource);
|
||||||
MapAlbums(resource);
|
//MapAlbums(resource);
|
||||||
FetchAndLinkArtistStatistics(resource);
|
FetchAndLinkArtistStatistics(resource);
|
||||||
//PopulateAlternateTitles(resource);
|
//PopulateAlternateTitles(resource);
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ namespace Lidarr.Api.V3.Artist
|
||||||
var artistsResources = _artistService.GetAllArtists().ToResource();
|
var artistsResources = _artistService.GetAllArtists().ToResource();
|
||||||
|
|
||||||
MapCoversToLocal(artistsResources.ToArray());
|
MapCoversToLocal(artistsResources.ToArray());
|
||||||
MapAlbums(artistsResources.ToArray());
|
//MapAlbums(artistsResources.ToArray());
|
||||||
LinkArtistStatistics(artistsResources, artistStats);
|
LinkArtistStatistics(artistsResources, artistStats);
|
||||||
//PopulateAlternateTitles(seriesResources);
|
//PopulateAlternateTitles(seriesResources);
|
||||||
|
|
||||||
|
|
|
@ -164,12 +164,28 @@ namespace NzbDrone.Core.Music
|
||||||
var album = _albumRepository.Get(albumId);
|
var album = _albumRepository.Get(albumId);
|
||||||
_albumRepository.SetMonitoredFlat(album, monitored);
|
_albumRepository.SetMonitoredFlat(album, monitored);
|
||||||
|
|
||||||
|
var tracks = _trackService.GetTracksByAlbum(albumId);
|
||||||
|
foreach (var track in tracks)
|
||||||
|
{
|
||||||
|
track.Monitored = monitored;
|
||||||
|
}
|
||||||
|
_trackService.UpdateTracks(tracks);
|
||||||
|
|
||||||
_logger.Debug("Monitored flag for Album:{0} was set to {1}", albumId, monitored);
|
_logger.Debug("Monitored flag for Album:{0} was set to {1}", albumId, monitored);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetMonitored(IEnumerable<int> ids, bool monitored)
|
public void SetMonitored(IEnumerable<int> ids, bool monitored)
|
||||||
{
|
{
|
||||||
_albumRepository.SetMonitored(ids, monitored);
|
_albumRepository.SetMonitored(ids, monitored);
|
||||||
|
foreach (var id in ids)
|
||||||
|
{
|
||||||
|
var tracks = _trackService.GetTracksByAlbum(id);
|
||||||
|
foreach (var track in tracks)
|
||||||
|
{
|
||||||
|
track.Monitored = monitored;
|
||||||
|
}
|
||||||
|
_trackService.UpdateTracks(tracks);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Album> UpdateAlbums(List<Album> album)
|
public List<Album> UpdateAlbums(List<Album> album)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue