1
0
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:
Taloth Saldono 2021-05-16 17:08:08 +02:00
parent dab1834960
commit 9e81d41f26
9 changed files with 88 additions and 44 deletions

View File

@ -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());
} }
} }
} }

View File

@ -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));
} }

View File

@ -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;
} }

View File

@ -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();
}
} }
} }

View File

@ -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)

View File

@ -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);
} }
} }

View File

@ -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);
} }
} }
} }

View File

@ -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();

View File

@ -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);
} }
} }