Fixed: Size on disk calculation including multi-episode files multiple times

Closes #5296
This commit is contained in:
Mark McDowall 2022-12-14 17:45:43 -08:00
parent f15f08e51a
commit 6c53bf30d5
2 changed files with 56 additions and 10 deletions

View File

@ -4,6 +4,7 @@ using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Languages;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Qualities;
@ -180,5 +181,25 @@ namespace NzbDrone.Core.Test.SeriesStatsTests
stats.Should().HaveCount(1);
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);
}
}
}

View File

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Dapper;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.MediaFiles;
@ -17,7 +16,8 @@ namespace NzbDrone.Core.SeriesStats
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;
@ -29,18 +29,34 @@ namespace NzbDrone.Core.SeriesStats
public List<SeasonStatistics> SeriesStatistics()
{
var time = DateTime.UtcNow;
return Query(Builder(time));
return MapResults(Query(EpisodesBuilder(time), _selectEpisodesTemplate),
Query(EpisodeFilesBuilder(), _selectEpisodeFilesTemplate));
}
public List<SeasonStatistics> SeriesStatistics(int seriesId)
{
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())
{
@ -48,24 +64,33 @@ namespace NzbDrone.Core.SeriesStats
}
}
private SqlBuilder Builder(DateTime currentDate)
private SqlBuilder EpisodesBuilder(DateTime currentDate)
{
var parameters = new DynamicParameters();
parameters.Add("currentDate", currentDate, null);
return new SqlBuilder()
.Select(@"Episodes.SeriesId AS SeriesId,
Episodes.SeasonNumber,
SUM(COALESCE(EpisodeFiles.Size, 0)) AS SizeOnDisk,
GROUP_CONCAT(EpisodeFiles.ReleaseGroup, '|') AS ReleaseGroupsString,
COUNT(*) AS TotalEpisodeCount,
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 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,
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.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);
}
}
}