mirror of
https://github.com/Sonarr/Sonarr.git
synced 2024-11-25 04:02:48 +01:00
Send signalr message for episode monitored flag changes
This commit is contained in:
parent
dab1834960
commit
9e81d41f26
@ -61,7 +61,7 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeServiceTests
|
|||||||
Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.MissingFromDisk));
|
Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.MissingFromDisk));
|
||||||
|
|
||||||
Mocker.GetMock<IEpisodeRepository>()
|
Mocker.GetMock<IEpisodeRepository>()
|
||||||
.Verify(v => v.Update(It.Is<Episode>(e => e.EpisodeFileId == 0)), Times.Once());
|
.Verify(v => v.ClearFileId(It.IsAny<Episode>(), It.IsAny<bool>()), Times.Once());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -72,7 +72,7 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeServiceTests
|
|||||||
Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.MissingFromDisk));
|
Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.MissingFromDisk));
|
||||||
|
|
||||||
Mocker.GetMock<IEpisodeRepository>()
|
Mocker.GetMock<IEpisodeRepository>()
|
||||||
.Verify(v => v.Update(It.Is<Episode>(e => e.EpisodeFileId == 0)), Times.Exactly(2));
|
.Verify(v => v.ClearFileId(It.IsAny<Episode>(), It.IsAny<bool>()), Times.Exactly(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -87,7 +87,7 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeServiceTests
|
|||||||
Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.MissingFromDisk));
|
Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.MissingFromDisk));
|
||||||
|
|
||||||
Mocker.GetMock<IEpisodeRepository>()
|
Mocker.GetMock<IEpisodeRepository>()
|
||||||
.Verify(v => v.Update(It.Is<Episode>(e => e.Monitored == false)), Times.Once());
|
.Verify(v => v.ClearFileId(It.IsAny<Episode>(), true), Times.Once());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -102,7 +102,7 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeServiceTests
|
|||||||
Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.Upgrade));
|
Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.Upgrade));
|
||||||
|
|
||||||
Mocker.GetMock<IEpisodeRepository>()
|
Mocker.GetMock<IEpisodeRepository>()
|
||||||
.Verify(v => v.Update(It.Is<Episode>(e => e.Monitored == true)), Times.Once());
|
.Verify(v => v.ClearFileId(It.IsAny<Episode>(), false), Times.Once());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -117,7 +117,7 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeServiceTests
|
|||||||
Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.Upgrade));
|
Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.Upgrade));
|
||||||
|
|
||||||
Mocker.GetMock<IEpisodeRepository>()
|
Mocker.GetMock<IEpisodeRepository>()
|
||||||
.Verify(v => v.Update(It.Is<Episode>(e => e.Monitored == true)), Times.Once());
|
.Verify(v => v.ClearFileId(It.IsAny<Episode>(), false), Times.Once());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,24 +279,24 @@ namespace NzbDrone.Core.Datastore
|
|||||||
.Take(pagingSpec.PageSize);
|
.Take(pagingSpec.PageSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ModelCreated(TModel model)
|
protected void ModelCreated(TModel model, bool forcePublish = false)
|
||||||
{
|
{
|
||||||
PublishModelEvent(model, ModelAction.Created);
|
PublishModelEvent(model, ModelAction.Created, forcePublish);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ModelUpdated(TModel model)
|
protected void ModelUpdated(TModel model, bool forcePublish = false)
|
||||||
{
|
{
|
||||||
PublishModelEvent(model, ModelAction.Updated);
|
PublishModelEvent(model, ModelAction.Updated, forcePublish);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ModelDeleted(TModel model)
|
protected void ModelDeleted(TModel model, bool forcePublish = false)
|
||||||
{
|
{
|
||||||
PublishModelEvent(model, ModelAction.Deleted);
|
PublishModelEvent(model, ModelAction.Deleted, forcePublish);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PublishModelEvent(TModel model, ModelAction action)
|
private void PublishModelEvent(TModel model, ModelAction action, bool forcePublish)
|
||||||
{
|
{
|
||||||
if (PublishModelEvents)
|
if (PublishModelEvents || forcePublish)
|
||||||
{
|
{
|
||||||
_eventAggregator.PublishEvent(new ModelEvent<TModel>(model, action));
|
_eventAggregator.PublishEvent(new ModelEvent<TModel>(model, action));
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,22 @@
|
|||||||
|
|
||||||
namespace NzbDrone.Core.Datastore.Events
|
namespace NzbDrone.Core.Datastore.Events
|
||||||
{
|
{
|
||||||
public class ModelEvent <TModel> : IEvent
|
public class ModelEvent<TModel> : IEvent
|
||||||
|
where TModel : ModelBase
|
||||||
{
|
{
|
||||||
|
public int ModelId { get; set; }
|
||||||
public TModel Model { get; set; }
|
public TModel Model { get; set; }
|
||||||
public ModelAction Action { get; set; }
|
public ModelAction Action { get; set; }
|
||||||
|
|
||||||
|
public ModelEvent(int modelId, ModelAction action)
|
||||||
|
{
|
||||||
|
ModelId = modelId;
|
||||||
|
Action = action;
|
||||||
|
}
|
||||||
|
|
||||||
public ModelEvent(TModel model, ModelAction action)
|
public ModelEvent(TModel model, ModelAction action)
|
||||||
{
|
{
|
||||||
|
ModelId = model.Id;
|
||||||
Model = model;
|
Model = model;
|
||||||
Action = action;
|
Action = action;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
using System.Reflection;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using Marr.Data;
|
using Marr.Data;
|
||||||
using Marr.Data.Mapping;
|
using Marr.Data.Mapping;
|
||||||
using NzbDrone.Common.Reflection;
|
using NzbDrone.Common.Reflection;
|
||||||
@ -59,5 +62,10 @@ namespace NzbDrone.Core.Datastore.Extensions
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<TModel> QueryScalar<TModel>(this IDataMapper dataMapper, string sql)
|
||||||
|
{
|
||||||
|
return dataMapper.ExecuteReader(sql, reader => (TModel)Convert.ChangeType(reader.GetValue(0), typeof(TModel))).ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -30,7 +30,8 @@ namespace NzbDrone.Core.Tv
|
|||||||
void SetMonitoredFlat(Episode episode, bool monitored);
|
void SetMonitoredFlat(Episode episode, bool monitored);
|
||||||
void SetMonitoredBySeason(int seriesId, int seasonNumber, bool monitored);
|
void SetMonitoredBySeason(int seriesId, int seasonNumber, bool monitored);
|
||||||
void SetMonitored(IEnumerable<int> ids, bool monitored);
|
void SetMonitored(IEnumerable<int> ids, bool monitored);
|
||||||
void SetFileId(int episodeId, int fileId);
|
void SetFileId(Episode episode, int fileId);
|
||||||
|
void ClearFileId(Episode episode, bool unmonitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EpisodeRepository : BasicRepository<Episode>, IEpisodeRepository
|
public class EpisodeRepository : BasicRepository<Episode>, IEpisodeRepository
|
||||||
@ -163,6 +164,8 @@ namespace NzbDrone.Core.Tv
|
|||||||
{
|
{
|
||||||
episode.Monitored = monitored;
|
episode.Monitored = monitored;
|
||||||
SetFields(episode, p => p.Monitored);
|
SetFields(episode, p => p.Monitored);
|
||||||
|
|
||||||
|
ModelUpdated(episode, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetMonitoredBySeason(int seriesId, int seasonNumber, bool monitored)
|
public void SetMonitoredBySeason(int seriesId, int seasonNumber, bool monitored)
|
||||||
@ -173,30 +176,39 @@ namespace NzbDrone.Core.Tv
|
|||||||
mapper.AddParameter("seasonNumber", seasonNumber);
|
mapper.AddParameter("seasonNumber", seasonNumber);
|
||||||
mapper.AddParameter("monitored", monitored);
|
mapper.AddParameter("monitored", monitored);
|
||||||
|
|
||||||
const string sql = "UPDATE Episodes " +
|
var sqlUpdate = $"UPDATE Episodes SET Monitored = @monitored WHERE SeriesId = @seriesId AND SeasonNumber = @seasonNumber AND Monitored != @monitored";
|
||||||
"SET Monitored = @monitored " +
|
|
||||||
"WHERE SeriesId = @seriesId " +
|
|
||||||
"AND SeasonNumber = @seasonNumber";
|
|
||||||
|
|
||||||
mapper.ExecuteNonQuery(sql);
|
mapper.ExecuteNonQuery(sqlUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetMonitored(IEnumerable<int> ids, bool monitored)
|
public void SetMonitored(IEnumerable<int> ids, bool monitored)
|
||||||
{
|
{
|
||||||
var mapper = _database.GetDataMapper();
|
var mapper = DataMapper;
|
||||||
|
|
||||||
mapper.AddParameter("monitored", monitored);
|
mapper.AddParameter("monitored", monitored);
|
||||||
|
|
||||||
var sql = "UPDATE Episodes " +
|
var sqlUpdate = $"UPDATE Episodes SET Monitored = @monitored WHERE Id IN ({string.Join(", ", ids)}) AND Monitored != @monitored";
|
||||||
"SET Monitored = @monitored " +
|
|
||||||
$"WHERE Id IN ({string.Join(", ", ids)})";
|
|
||||||
|
|
||||||
mapper.ExecuteNonQuery(sql);
|
mapper.ExecuteNonQuery(sqlUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetFileId(int episodeId, int fileId)
|
public void SetFileId(Episode episode, int fileId)
|
||||||
{
|
{
|
||||||
SetFields(new Episode { Id = episodeId, EpisodeFileId = fileId }, episode => episode.EpisodeFileId);
|
episode.EpisodeFileId = fileId;
|
||||||
|
|
||||||
|
SetFields(episode, ep => ep.EpisodeFileId);
|
||||||
|
|
||||||
|
ModelUpdated(episode, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearFileId(Episode episode, bool unmonitor)
|
||||||
|
{
|
||||||
|
episode.EpisodeFileId = 0;
|
||||||
|
episode.Monitored &= !unmonitor;
|
||||||
|
|
||||||
|
SetFields(episode, ep => ep.EpisodeFileId, ep => ep.Monitored);
|
||||||
|
|
||||||
|
ModelUpdated(episode, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SortBuilder<Episode> GetMissingEpisodesQuery(PagingSpec<Episode> pagingSpec, DateTime currentTime, int startingSeasonNumber)
|
private SortBuilder<Episode> GetMissingEpisodesQuery(PagingSpec<Episode> pagingSpec, DateTime currentTime, int startingSeasonNumber)
|
||||||
|
@ -220,14 +220,7 @@ namespace NzbDrone.Core.Tv
|
|||||||
foreach (var episode in GetEpisodesByFileId(message.EpisodeFile.Id))
|
foreach (var episode in GetEpisodesByFileId(message.EpisodeFile.Id))
|
||||||
{
|
{
|
||||||
_logger.Debug("Detaching episode {0} from file.", episode.Id);
|
_logger.Debug("Detaching episode {0} from file.", episode.Id);
|
||||||
episode.EpisodeFileId = 0;
|
_episodeRepository.ClearFileId(episode, message.Reason != DeleteMediaFileReason.Upgrade && _configService.AutoUnmonitorPreviouslyDownloadedEpisodes);
|
||||||
|
|
||||||
if (message.Reason != DeleteMediaFileReason.Upgrade && _configService.AutoUnmonitorPreviouslyDownloadedEpisodes)
|
|
||||||
{
|
|
||||||
episode.Monitored = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateEpisode(episode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,7 +228,7 @@ namespace NzbDrone.Core.Tv
|
|||||||
{
|
{
|
||||||
foreach (var episode in message.EpisodeFile.Episodes.Value)
|
foreach (var episode in message.EpisodeFile.Episodes.Value)
|
||||||
{
|
{
|
||||||
_episodeRepository.SetFileId(episode.Id, message.EpisodeFile.Id);
|
_episodeRepository.SetFileId(episode, message.EpisodeFile.Id);
|
||||||
_logger.Debug("Linking [{0}] > [{1}]", message.EpisodeFile.RelativePath, episode);
|
_logger.Debug("Linking [{0}] > [{1}]", message.EpisodeFile.RelativePath, episode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,9 @@ namespace Sonarr.Api.V3.Episodes
|
|||||||
var resource = Request.Body.FromJson<EpisodeResource>();
|
var resource = Request.Body.FromJson<EpisodeResource>();
|
||||||
_episodeService.SetEpisodeMonitored(id, resource.Monitored);
|
_episodeService.SetEpisodeMonitored(id, resource.Monitored);
|
||||||
|
|
||||||
return ResponseWithCode(MapToResource(_episodeService.GetEpisode(id), false, false, false), HttpStatusCode.Accepted);
|
resource = MapToResource(_episodeService.GetEpisode(id), false, false, false);
|
||||||
|
|
||||||
|
return ResponseWithCode(resource, HttpStatusCode.Accepted);
|
||||||
}
|
}
|
||||||
|
|
||||||
private object SetEpisodesMonitored()
|
private object SetEpisodesMonitored()
|
||||||
@ -77,10 +79,18 @@ namespace Sonarr.Api.V3.Episodes
|
|||||||
var includeImages = Request.GetBooleanQueryParameter("includeImages", false);
|
var includeImages = Request.GetBooleanQueryParameter("includeImages", false);
|
||||||
var resource = Request.Body.FromJson<EpisodesMonitoredResource>();
|
var resource = Request.Body.FromJson<EpisodesMonitoredResource>();
|
||||||
|
|
||||||
|
if (resource.EpisodeIds.Count == 1)
|
||||||
|
{
|
||||||
|
_episodeService.SetEpisodeMonitored(resource.EpisodeIds.First(), resource.Monitored);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
_episodeService.SetMonitored(resource.EpisodeIds, resource.Monitored);
|
_episodeService.SetMonitored(resource.EpisodeIds, resource.Monitored);
|
||||||
|
}
|
||||||
|
|
||||||
return ResponseWithCode(MapToResource(_episodeService.GetEpisodes(resource.EpisodeIds), false, false, includeImages)
|
var resources = MapToResource(_episodeService.GetEpisodes(resource.EpisodeIds), false, false, includeImages);
|
||||||
, HttpStatusCode.Accepted);
|
|
||||||
|
return ResponseWithCode(resources, HttpStatusCode.Accepted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,13 @@ namespace Sonarr.Api.V3.Episodes
|
|||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override EpisodeResource GetResourceByIdForBroadcast(int id)
|
||||||
|
{
|
||||||
|
var episode = _episodeService.GetEpisode(id);
|
||||||
|
var resource = MapToResource(episode, false, false, false);
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
protected EpisodeResource MapToResource(Episode episode, bool includeSeries, bool includeEpisodeFile, bool includeImages)
|
protected EpisodeResource MapToResource(Episode episode, bool includeSeries, bool includeEpisodeFile, bool includeImages)
|
||||||
{
|
{
|
||||||
var resource = episode.ToResource();
|
var resource = episode.ToResource();
|
||||||
|
@ -23,6 +23,11 @@ namespace Sonarr.Http
|
|||||||
_signalRBroadcaster = signalRBroadcaster;
|
_signalRBroadcaster = signalRBroadcaster;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual TResource GetResourceByIdForBroadcast(int id)
|
||||||
|
{
|
||||||
|
return GetResourceById(id);
|
||||||
|
}
|
||||||
|
|
||||||
public void Handle(ModelEvent<TModel> message)
|
public void Handle(ModelEvent<TModel> message)
|
||||||
{
|
{
|
||||||
if (!_signalRBroadcaster.IsConnected) return;
|
if (!_signalRBroadcaster.IsConnected) return;
|
||||||
@ -32,7 +37,7 @@ namespace Sonarr.Http
|
|||||||
BroadcastResourceChange(message.Action);
|
BroadcastResourceChange(message.Action);
|
||||||
}
|
}
|
||||||
|
|
||||||
BroadcastResourceChange(message.Action, message.Model.Id);
|
BroadcastResourceChange(message.Action, message.ModelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void BroadcastResourceChange(ModelAction action, int id)
|
protected void BroadcastResourceChange(ModelAction action, int id)
|
||||||
@ -45,7 +50,7 @@ namespace Sonarr.Http
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var resource = GetResourceById(id);
|
var resource = GetResourceByIdForBroadcast(id);
|
||||||
BroadcastResourceChange(action, resource);
|
BroadcastResourceChange(action, resource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user