Fixed: Size on disk calculation including multi-episode files multiple times
Closes #5296
This commit is contained in:
parent
f15f08e51a
commit
6c53bf30d5
|
@ -4,6 +4,7 @@ using System.Linq;
|
||||||
using FizzWare.NBuilder;
|
using FizzWare.NBuilder;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Languages;
|
using NzbDrone.Core.Languages;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
using NzbDrone.Core.Qualities;
|
using NzbDrone.Core.Qualities;
|
||||||
|
@ -180,5 +181,25 @@ namespace NzbDrone.Core.Test.SeriesStatsTests
|
||||||
stats.Should().HaveCount(1);
|
stats.Should().HaveCount(1);
|
||||||
stats.First().SizeOnDisk.Should().Be(_episodeFile.Size);
|
stats.First().SizeOnDisk.Should().Be(_episodeFile.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_duplicate_size_for_multi_episode_files()
|
||||||
|
{
|
||||||
|
GivenEpisodeWithFile();
|
||||||
|
GivenEpisode();
|
||||||
|
GivenEpisodeFile();
|
||||||
|
|
||||||
|
var episode2 = _episode.JsonClone();
|
||||||
|
|
||||||
|
episode2.Id = 0;
|
||||||
|
episode2.EpisodeNumber += 1;
|
||||||
|
|
||||||
|
Db.Insert(episode2);
|
||||||
|
|
||||||
|
var stats = Subject.SeriesStatistics();
|
||||||
|
|
||||||
|
stats.Should().HaveCount(1);
|
||||||
|
stats.First().SizeOnDisk.Should().Be(_episodeFile.Size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using Dapper;
|
using Dapper;
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
@ -17,7 +16,8 @@ namespace NzbDrone.Core.SeriesStats
|
||||||
|
|
||||||
public class SeriesStatisticsRepository : ISeriesStatisticsRepository
|
public class SeriesStatisticsRepository : ISeriesStatisticsRepository
|
||||||
{
|
{
|
||||||
private const string _selectTemplate = "SELECT /**select**/ FROM Episodes /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/ /**groupby**/ /**having**/ /**orderby**/";
|
private const string _selectEpisodesTemplate = "SELECT /**select**/ FROM Episodes /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/ /**groupby**/ /**having**/ /**orderby**/";
|
||||||
|
private const string _selectEpisodeFilesTemplate = "SELECT /**select**/ FROM EpisodeFiles /**join**/ /**innerjoin**/ /**leftjoin**/ /**where**/ /**groupby**/ /**having**/ /**orderby**/";
|
||||||
|
|
||||||
private readonly IMainDatabase _database;
|
private readonly IMainDatabase _database;
|
||||||
|
|
||||||
|
@ -29,18 +29,34 @@ namespace NzbDrone.Core.SeriesStats
|
||||||
public List<SeasonStatistics> SeriesStatistics()
|
public List<SeasonStatistics> SeriesStatistics()
|
||||||
{
|
{
|
||||||
var time = DateTime.UtcNow;
|
var time = DateTime.UtcNow;
|
||||||
return Query(Builder(time));
|
return MapResults(Query(EpisodesBuilder(time), _selectEpisodesTemplate),
|
||||||
|
Query(EpisodeFilesBuilder(), _selectEpisodeFilesTemplate));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SeasonStatistics> SeriesStatistics(int seriesId)
|
public List<SeasonStatistics> SeriesStatistics(int seriesId)
|
||||||
{
|
{
|
||||||
var time = DateTime.UtcNow;
|
var time = DateTime.UtcNow;
|
||||||
return Query(Builder(time).Where<Episode>(x => x.SeriesId == seriesId));
|
|
||||||
|
return MapResults(Query(EpisodesBuilder(time).Where<Episode>(x => x.SeriesId == seriesId), _selectEpisodesTemplate),
|
||||||
|
Query(EpisodeFilesBuilder().Where<EpisodeFile>(x => x.SeriesId == seriesId), _selectEpisodeFilesTemplate));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<SeasonStatistics> Query(SqlBuilder builder)
|
private List<SeasonStatistics> MapResults(List<SeasonStatistics> episodesResult, List<SeasonStatistics> filesResult)
|
||||||
{
|
{
|
||||||
var sql = builder.AddTemplate(_selectTemplate).LogQuery();
|
episodesResult.ForEach(e =>
|
||||||
|
{
|
||||||
|
var file = filesResult.SingleOrDefault(f => f.SeriesId == e.SeriesId & f.SeasonNumber == e.SeasonNumber);
|
||||||
|
|
||||||
|
e.SizeOnDisk = file?.SizeOnDisk ?? 0;
|
||||||
|
e.ReleaseGroupsString = file?.ReleaseGroupsString;
|
||||||
|
});
|
||||||
|
|
||||||
|
return episodesResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<SeasonStatistics> Query(SqlBuilder builder, string template)
|
||||||
|
{
|
||||||
|
var sql = builder.AddTemplate(template).LogQuery();
|
||||||
|
|
||||||
using (var conn = _database.OpenConnection())
|
using (var conn = _database.OpenConnection())
|
||||||
{
|
{
|
||||||
|
@ -48,24 +64,33 @@ namespace NzbDrone.Core.SeriesStats
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private SqlBuilder Builder(DateTime currentDate)
|
private SqlBuilder EpisodesBuilder(DateTime currentDate)
|
||||||
{
|
{
|
||||||
var parameters = new DynamicParameters();
|
var parameters = new DynamicParameters();
|
||||||
parameters.Add("currentDate", currentDate, null);
|
parameters.Add("currentDate", currentDate, null);
|
||||||
|
|
||||||
return new SqlBuilder()
|
return new SqlBuilder()
|
||||||
.Select(@"Episodes.SeriesId AS SeriesId,
|
.Select(@"Episodes.SeriesId AS SeriesId,
|
||||||
Episodes.SeasonNumber,
|
Episodes.SeasonNumber,
|
||||||
SUM(COALESCE(EpisodeFiles.Size, 0)) AS SizeOnDisk,
|
|
||||||
GROUP_CONCAT(EpisodeFiles.ReleaseGroup, '|') AS ReleaseGroupsString,
|
|
||||||
COUNT(*) AS TotalEpisodeCount,
|
COUNT(*) AS TotalEpisodeCount,
|
||||||
SUM(CASE WHEN AirdateUtc <= @currentDate OR EpisodeFileId > 0 THEN 1 ELSE 0 END) AS AvailableEpisodeCount,
|
SUM(CASE WHEN AirdateUtc <= @currentDate OR EpisodeFileId > 0 THEN 1 ELSE 0 END) AS AvailableEpisodeCount,
|
||||||
SUM(CASE WHEN (Monitored = 1 AND AirdateUtc <= @currentDate) OR EpisodeFileId > 0 THEN 1 ELSE 0 END) AS EpisodeCount,
|
SUM(CASE WHEN (Monitored = 1 AND AirdateUtc <= @currentDate) OR EpisodeFileId > 0 THEN 1 ELSE 0 END) AS EpisodeCount,
|
||||||
SUM(CASE WHEN EpisodeFileId > 0 THEN 1 ELSE 0 END) AS EpisodeFileCount,
|
SUM(CASE WHEN EpisodeFileId > 0 THEN 1 ELSE 0 END) AS EpisodeFileCount,
|
||||||
MIN(CASE WHEN AirDateUtc < @currentDate OR EpisodeFileId > 0 OR Monitored = 0 THEN NULL ELSE AirDateUtc END) AS NextAiringString,
|
MIN(CASE WHEN AirDateUtc < @currentDate OR EpisodeFileId > 0 OR Monitored = 0 THEN NULL ELSE AirDateUtc END) AS NextAiringString,
|
||||||
MAX(CASE WHEN AirDateUtc >= @currentDate OR EpisodeFileId = 0 AND Monitored = 0 THEN NULL ELSE AirDateUtc END) AS PreviousAiringString", parameters)
|
MAX(CASE WHEN AirDateUtc >= @currentDate OR EpisodeFileId = 0 AND Monitored = 0 THEN NULL ELSE AirDateUtc END) AS PreviousAiringString", parameters)
|
||||||
.LeftJoin<Episode, EpisodeFile>((t, f) => t.EpisodeFileId == f.Id)
|
|
||||||
.GroupBy<Episode>(x => x.SeriesId)
|
.GroupBy<Episode>(x => x.SeriesId)
|
||||||
.GroupBy<Episode>(x => x.SeasonNumber);
|
.GroupBy<Episode>(x => x.SeasonNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private SqlBuilder EpisodeFilesBuilder()
|
||||||
|
{
|
||||||
|
return new SqlBuilder()
|
||||||
|
.Select(@"SeriesId,
|
||||||
|
SeasonNumber,
|
||||||
|
SUM(COALESCE(Size, 0)) AS SizeOnDisk,
|
||||||
|
GROUP_CONCAT(ReleaseGroup, '|') AS ReleaseGroupsString")
|
||||||
|
.GroupBy<EpisodeFile>(x => x.SeriesId)
|
||||||
|
.GroupBy<EpisodeFile>(x => x.SeasonNumber);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue