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));
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]
@ -72,7 +72,7 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeServiceTests
Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.MissingFromDisk));
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]
@ -87,7 +87,7 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeServiceTests
Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.MissingFromDisk));
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]
@ -102,7 +102,7 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeServiceTests
Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.Upgrade));
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]
@ -117,7 +117,7 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeServiceTests
Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.Upgrade));
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);
}
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));
}

View File

@ -3,12 +3,21 @@
namespace NzbDrone.Core.Datastore.Events
{
public class ModelEvent<TModel> : IEvent
where TModel : ModelBase
{
public int ModelId { get; set; }
public TModel Model { get; set; }
public ModelAction Action { get; set; }
public ModelEvent(int modelId, ModelAction action)
{
ModelId = modelId;
Action = action;
}
public ModelEvent(TModel model, ModelAction action)
{
ModelId = model.Id;
Model = model;
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.Mapping;
using NzbDrone.Common.Reflection;
@ -59,5 +62,10 @@ namespace NzbDrone.Core.Datastore.Extensions
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 SetMonitoredBySeason(int seriesId, int seasonNumber, 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
@ -163,6 +164,8 @@ namespace NzbDrone.Core.Tv
{
episode.Monitored = monitored;
SetFields(episode, p => p.Monitored);
ModelUpdated(episode, true);
}
public void SetMonitoredBySeason(int seriesId, int seasonNumber, bool monitored)
@ -173,30 +176,39 @@ namespace NzbDrone.Core.Tv
mapper.AddParameter("seasonNumber", seasonNumber);
mapper.AddParameter("monitored", monitored);
const string sql = "UPDATE Episodes " +
"SET Monitored = @monitored " +
"WHERE SeriesId = @seriesId " +
"AND SeasonNumber = @seasonNumber";
var sqlUpdate = $"UPDATE Episodes SET Monitored = @monitored WHERE SeriesId = @seriesId AND SeasonNumber = @seasonNumber AND Monitored != @monitored";
mapper.ExecuteNonQuery(sql);
mapper.ExecuteNonQuery(sqlUpdate);
}
public void SetMonitored(IEnumerable<int> ids, bool monitored)
{
var mapper = _database.GetDataMapper();
var mapper = DataMapper;
mapper.AddParameter("monitored", monitored);
var sql = "UPDATE Episodes " +
"SET Monitored = @monitored " +
$"WHERE Id IN ({string.Join(", ", ids)})";
var sqlUpdate = $"UPDATE Episodes SET Monitored = @monitored WHERE Id IN ({string.Join(", ", ids)}) AND Monitored != @monitored";
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)

View File

@ -220,14 +220,7 @@ namespace NzbDrone.Core.Tv
foreach (var episode in GetEpisodesByFileId(message.EpisodeFile.Id))
{
_logger.Debug("Detaching episode {0} from file.", episode.Id);
episode.EpisodeFileId = 0;
if (message.Reason != DeleteMediaFileReason.Upgrade && _configService.AutoUnmonitorPreviouslyDownloadedEpisodes)
{
episode.Monitored = false;
}
UpdateEpisode(episode);
_episodeRepository.ClearFileId(episode, message.Reason != DeleteMediaFileReason.Upgrade && _configService.AutoUnmonitorPreviouslyDownloadedEpisodes);
}
}
@ -235,7 +228,7 @@ namespace NzbDrone.Core.Tv
{
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);
}
}

View File

@ -69,7 +69,9 @@ namespace Sonarr.Api.V3.Episodes
var resource = Request.Body.FromJson<EpisodeResource>();
_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()
@ -77,10 +79,18 @@ namespace Sonarr.Api.V3.Episodes
var includeImages = Request.GetBooleanQueryParameter("includeImages", false);
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);
}
return ResponseWithCode(MapToResource(_episodeService.GetEpisodes(resource.EpisodeIds), false, false, includeImages)
, HttpStatusCode.Accepted);
var resources = MapToResource(_episodeService.GetEpisodes(resource.EpisodeIds), false, false, includeImages);
return ResponseWithCode(resources, HttpStatusCode.Accepted);
}
}
}

View File

@ -57,6 +57,13 @@ namespace Sonarr.Api.V3.Episodes
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)
{
var resource = episode.ToResource();

View File

@ -23,6 +23,11 @@ namespace Sonarr.Http
_signalRBroadcaster = signalRBroadcaster;
}
protected virtual TResource GetResourceByIdForBroadcast(int id)
{
return GetResourceById(id);
}
public void Handle(ModelEvent<TModel> message)
{
if (!_signalRBroadcaster.IsConnected) return;
@ -32,7 +37,7 @@ namespace Sonarr.Http
BroadcastResourceChange(message.Action);
}
BroadcastResourceChange(message.Action, message.Model.Id);
BroadcastResourceChange(message.Action, message.ModelId);
}
protected void BroadcastResourceChange(ModelAction action, int id)
@ -45,7 +50,7 @@ namespace Sonarr.Http
}
else
{
var resource = GetResourceById(id);
var resource = GetResourceByIdForBroadcast(id);
BroadcastResourceChange(action, resource);
}
}