parent
7be5732a3a
commit
69f99373e5
@ -0,0 +1,100 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using Dapper;
|
||||||
|
using FluentAssertions;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common.Serializer;
|
||||||
|
using NzbDrone.Core.Datastore.Migration;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.Datastore.Migration
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class parse_title_from_existing_subtitle_filesFixture : MigrationTest<parse_title_from_existing_subtitle_files>
|
||||||
|
{
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].testtitle.default.eng.forced.ass", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", "testtitle", 0)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].eng.default.testtitle.forced.ass", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", "testtitle", 0)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].default.eng.testtitle.forced.ass", "Name (2020)/Season 1/Name (2020).mkv", "testtitle", 0)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].testtitle.forced.eng.ass", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", "testtitle", 0)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].eng.forced.testtitle.ass", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", "testtitle", 0)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].forced.eng.testtitle.ass", "Name (2020)/Season 1/Name (2020).mkv", "testtitle", 0)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].testtitle.default.fra.forced.ass", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", "testtitle", 0)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].fra.default.testtitle.forced.ass", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", "testtitle", 0)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].default.fra.testtitle.forced.ass", "Name (2020)/Season 1/Name (2020).mkv", "testtitle", 0)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].testtitle.forced.fra.ass", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", "testtitle", 0)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].fra.forced.testtitle.ass", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", "testtitle", 0)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].forced.fra.testtitle.ass", "Name (2020)/Season 1/Name (2020).mkv", "testtitle", 0)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].default.forced.ass", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", null, 0)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].default.ass", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", null, 0)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].ass", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", null, 0)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].testtitle.ass", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", null, 0)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].testtitle - 3.default.eng.forced.ass", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", "testtitle", 3)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].testtitle - 3.forced.eng.ass", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", "testtitle", 3)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].eng.forced.testtitle - 3.ass", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", "testtitle", 3)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].fra.default.testtitle - 3.forced.ass", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", "testtitle", 3)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].3.default.eng.forced.ass", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", null, 3)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].3.forced.eng.ass", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", null, 3)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].eng.forced.3.ass", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", null, 3)]
|
||||||
|
[TestCase("Name (2020) - S01E20 - [AAC 2.0].fra.default.3.forced.ass", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", null, 3)]
|
||||||
|
public void should_process_file_with_missing_title(string subtitlePath, string episodePath, string title, int copy)
|
||||||
|
{
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
|
||||||
|
var db = WithDapperMigrationTestDb(c =>
|
||||||
|
{
|
||||||
|
c.Insert.IntoTable("SubtitleFiles").Row(new
|
||||||
|
{
|
||||||
|
SeriesId = 1,
|
||||||
|
SeasonNumber = 1,
|
||||||
|
EpisodeFileId = 1,
|
||||||
|
RelativePath = subtitlePath,
|
||||||
|
Added = now,
|
||||||
|
LastUpdated = now,
|
||||||
|
Extension = Path.GetExtension(subtitlePath),
|
||||||
|
Language = 10,
|
||||||
|
LanguageTags = new List<string> { "sdh" }.ToJson()
|
||||||
|
});
|
||||||
|
|
||||||
|
c.Insert.IntoTable("EpisodeFiles").Row(new
|
||||||
|
{
|
||||||
|
Id = 1,
|
||||||
|
SeriesId = 1,
|
||||||
|
RelativePath = episodePath,
|
||||||
|
OriginalFilePath = string.Empty,
|
||||||
|
Quality = new { }.ToJson(),
|
||||||
|
Size = 0,
|
||||||
|
DateAdded = now,
|
||||||
|
SeasonNumber = 1,
|
||||||
|
Languages = new List<int> { 1 }.ToJson()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var files = db.Query<SubtitleFile198>("SELECT * FROM \"SubtitleFiles\"").ToList();
|
||||||
|
|
||||||
|
files.Should().HaveCount(1);
|
||||||
|
|
||||||
|
files.First().Title.Should().Be(title);
|
||||||
|
files.First().Copy.Should().Be(copy);
|
||||||
|
files.First().LanguageTags.Should().NotContain("sdh");
|
||||||
|
files.First().Language.Should().NotBe(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SubtitleFile198
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public int SeriesId { get; set; }
|
||||||
|
public int? EpisodeFileId { get; set; }
|
||||||
|
public int? SeasonNumber { get; set; }
|
||||||
|
public string RelativePath { get; set; }
|
||||||
|
public DateTime Added { get; set; }
|
||||||
|
public DateTime LastUpdated { get; set; }
|
||||||
|
public string Extension { get; set; }
|
||||||
|
public int Language { get; set; }
|
||||||
|
public int Copy { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public List<string> LanguageTags { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
using FluentAssertions;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Aggregation.Aggregators
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class AggregateSubtitleInfoFixture : CoreTest<AggregateSubtitleInfo>
|
||||||
|
{
|
||||||
|
[TestCase("Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", "", "Name (2020) - S01E20 - [AAC 2.0].default.eng.forced.ass")]
|
||||||
|
[TestCase("Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", "", "Name (2020) - S01E20 - [AAC 2.0].eng.default.ass")]
|
||||||
|
[TestCase("Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", "", "Name (2020) - S01E20 - [AAC 2.0].fra.ass")]
|
||||||
|
[TestCase("", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", "Name (2020) - S01E20 - [AAC 2.0].default.eng.forced.ass")]
|
||||||
|
[TestCase("", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", "Name (2020) - S01E20 - [AAC 2.0].eng.default.ass")]
|
||||||
|
[TestCase("", "Name (2020)/Season 1/Name (2020) - S01E20 - [AAC 2.0].mkv", "Name (2020) - S01E20 - [AAC 2.0].fra.ass")]
|
||||||
|
public void should_do_basic_parse(string relativePath, string originalFilePath, string path)
|
||||||
|
{
|
||||||
|
var episodeFile = new EpisodeFile
|
||||||
|
{
|
||||||
|
RelativePath = relativePath,
|
||||||
|
OriginalFilePath = originalFilePath
|
||||||
|
};
|
||||||
|
|
||||||
|
var subtitleTitleInfo = Subject.CleanSubtitleTitleInfo(episodeFile, path);
|
||||||
|
|
||||||
|
subtitleTitleInfo.Title.Should().BeNull();
|
||||||
|
subtitleTitleInfo.Copy.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase("Default (2020)/Season 1/Default (2020) - S01E20 - [AAC 2.0].mkv", "Default (2020) - S01E20 - [AAC 2.0].default.eng.forced.ass")]
|
||||||
|
[TestCase("Default (2020)/Season 1/Default (2020) - S01E20 - [AAC 2.0].mkv", "Default (2020) - S01E20 - [AAC 2.0].eng.default.ass")]
|
||||||
|
[TestCase("Default (2020)/Season 1/Default (2020) - S01E20 - [AAC 2.0].mkv", "Default (2020) - S01E20 - [AAC 2.0].default.eng.testtitle.forced.ass")]
|
||||||
|
[TestCase("Default (2020)/Season 1/Default (2020) - S01E20 - [AAC 2.0].mkv", "Default (2020) - S01E20 - [AAC 2.0].testtitle.eng.default.ass")]
|
||||||
|
public void should_not_parse_default(string relativePath, string path)
|
||||||
|
{
|
||||||
|
var episodeFile = new EpisodeFile
|
||||||
|
{
|
||||||
|
RelativePath = relativePath
|
||||||
|
};
|
||||||
|
|
||||||
|
var subtitleTitleInfo = Subject.CleanSubtitleTitleInfo(episodeFile, path);
|
||||||
|
|
||||||
|
subtitleTitleInfo.LanguageTags.Should().NotContain("default");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using Dapper;
|
||||||
|
using FluentMigrator;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common.Instrumentation;
|
||||||
|
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||||
|
using NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators;
|
||||||
|
using NzbDrone.Core.Parser;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Datastore.Migration
|
||||||
|
{
|
||||||
|
[Migration(198)]
|
||||||
|
public class parse_title_from_existing_subtitle_files : NzbDroneMigrationBase
|
||||||
|
{
|
||||||
|
private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(AggregateSubtitleInfo));
|
||||||
|
|
||||||
|
protected override void MainDbUpgrade()
|
||||||
|
{
|
||||||
|
Alter.Table("SubtitleFiles").AddColumn("Title").AsString().Nullable();
|
||||||
|
Alter.Table("SubtitleFiles").AddColumn("Copy").AsInt32().WithDefaultValue(0);
|
||||||
|
Execute.WithConnection(UpdateTitles);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateTitles(IDbConnection conn, IDbTransaction tran)
|
||||||
|
{
|
||||||
|
var updates = new List<object>();
|
||||||
|
|
||||||
|
using (var cmd = conn.CreateCommand())
|
||||||
|
{
|
||||||
|
cmd.Transaction = tran;
|
||||||
|
cmd.CommandText = "SELECT \"SubtitleFiles\".\"Id\", \"SubtitleFiles\".\"RelativePath\", \"EpisodeFiles\".\"RelativePath\", \"EpisodeFiles\".\"OriginalFilePath\" FROM \"SubtitleFiles\" JOIN \"EpisodeFiles\" ON \"SubtitleFiles\".\"EpisodeFileId\" = \"EpisodeFiles\".\"Id\"";
|
||||||
|
|
||||||
|
using var reader = cmd.ExecuteReader();
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
var id = reader.GetInt32(0);
|
||||||
|
var relativePath = reader.GetString(1);
|
||||||
|
var episodeFileRelativePath = reader.GetString(2);
|
||||||
|
var episodeFileOriginalFilePath = reader.GetString(3);
|
||||||
|
|
||||||
|
var subtitleTitleInfo = CleanSubtitleTitleInfo(episodeFileRelativePath, episodeFileOriginalFilePath, relativePath);
|
||||||
|
|
||||||
|
updates.Add(new
|
||||||
|
{
|
||||||
|
Id = id,
|
||||||
|
Title = subtitleTitleInfo.Title,
|
||||||
|
Language = subtitleTitleInfo.Language,
|
||||||
|
LanguageTags = subtitleTitleInfo.LanguageTags,
|
||||||
|
Copy = subtitleTitleInfo.Copy
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var updateSubtitleFilesSql = "UPDATE \"SubtitleFiles\" SET \"Title\" = @Title, \"Copy\" = @Copy, \"Language\" = @Language, \"LanguageTags\" = @LanguageTags, \"LastUpdated\" = CURRENT_TIMESTAMP WHERE \"Id\" = @Id";
|
||||||
|
conn.Execute(updateSubtitleFilesSql, updates, transaction: tran);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SubtitleTitleInfo CleanSubtitleTitleInfo(string relativePath, string originalFilePath, string path)
|
||||||
|
{
|
||||||
|
var subtitleTitleInfo = LanguageParser.ParseSubtitleLanguageInformation(path);
|
||||||
|
|
||||||
|
var episodeFileTitle = Path.GetFileNameWithoutExtension(relativePath);
|
||||||
|
var originalEpisodeFileTitle = Path.GetFileNameWithoutExtension(originalFilePath) ?? string.Empty;
|
||||||
|
|
||||||
|
if (subtitleTitleInfo.TitleFirst && (episodeFileTitle.Contains(subtitleTitleInfo.RawTitle, StringComparison.OrdinalIgnoreCase) || originalEpisodeFileTitle.Contains(subtitleTitleInfo.RawTitle, StringComparison.OrdinalIgnoreCase)))
|
||||||
|
{
|
||||||
|
Logger.Debug("Subtitle title '{0}' is in episode file title '{1}'. Removing from subtitle title.", subtitleTitleInfo.RawTitle, episodeFileTitle);
|
||||||
|
|
||||||
|
subtitleTitleInfo = LanguageParser.ParseBasicSubtitle(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
var cleanedTags = subtitleTitleInfo.LanguageTags.Where(t => !episodeFileTitle.Contains(t, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||||
|
|
||||||
|
if (cleanedTags.Count != subtitleTitleInfo.LanguageTags.Count)
|
||||||
|
{
|
||||||
|
Logger.Debug("Removed language tags '{0}' from subtitle title '{1}'.", string.Join(", ", subtitleTitleInfo.LanguageTags.Except(cleanedTags)), subtitleTitleInfo.RawTitle);
|
||||||
|
subtitleTitleInfo.LanguageTags = cleanedTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
return subtitleTitleInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Core.Download;
|
||||||
|
using NzbDrone.Core.Extras.Subtitles;
|
||||||
|
using NzbDrone.Core.Parser;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators
|
||||||
|
{
|
||||||
|
public class AggregateSubtitleInfo : IAggregateLocalEpisode
|
||||||
|
{
|
||||||
|
public int Order => 2;
|
||||||
|
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public AggregateSubtitleInfo(Logger logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalEpisode Aggregate(LocalEpisode localEpisode, DownloadClientItem downloadClientItem)
|
||||||
|
{
|
||||||
|
var path = localEpisode.Path;
|
||||||
|
var isSubtitleFile = SubtitleFileExtensions.Extensions.Contains(Path.GetExtension(path));
|
||||||
|
|
||||||
|
if (!isSubtitleFile)
|
||||||
|
{
|
||||||
|
return localEpisode;
|
||||||
|
}
|
||||||
|
|
||||||
|
var firstEpisode = localEpisode.Episodes.First();
|
||||||
|
var episodeFile = firstEpisode.EpisodeFile.Value;
|
||||||
|
localEpisode.SubtitleInfo = CleanSubtitleTitleInfo(episodeFile, path);
|
||||||
|
|
||||||
|
return localEpisode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubtitleTitleInfo CleanSubtitleTitleInfo(EpisodeFile episodeFile, string path)
|
||||||
|
{
|
||||||
|
var subtitleTitleInfo = LanguageParser.ParseSubtitleLanguageInformation(path);
|
||||||
|
|
||||||
|
var episodeFileTitle = Path.GetFileNameWithoutExtension(episodeFile.RelativePath);
|
||||||
|
var originalEpisodeFileTitle = Path.GetFileNameWithoutExtension(episodeFile.OriginalFilePath) ?? string.Empty;
|
||||||
|
|
||||||
|
if (subtitleTitleInfo.TitleFirst && (episodeFileTitle.Contains(subtitleTitleInfo.RawTitle, StringComparison.OrdinalIgnoreCase) || originalEpisodeFileTitle.Contains(subtitleTitleInfo.RawTitle, StringComparison.OrdinalIgnoreCase)))
|
||||||
|
{
|
||||||
|
_logger.Debug("Subtitle title '{0}' is in episode file title '{1}'. Removing from subtitle title.", subtitleTitleInfo.RawTitle, episodeFileTitle);
|
||||||
|
|
||||||
|
subtitleTitleInfo = LanguageParser.ParseBasicSubtitle(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
var cleanedTags = subtitleTitleInfo.LanguageTags.Where(t => !episodeFileTitle.Contains(t, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||||
|
|
||||||
|
if (cleanedTags.Count != subtitleTitleInfo.LanguageTags.Count)
|
||||||
|
{
|
||||||
|
_logger.Debug("Removed language tags '{0}' from subtitle title '{1}'.", string.Join(", ", subtitleTitleInfo.LanguageTags.Except(cleanedTags)), subtitleTitleInfo.RawTitle);
|
||||||
|
subtitleTitleInfo.LanguageTags = cleanedTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
return subtitleTitleInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Core.Languages;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Parser.Model
|
||||||
|
{
|
||||||
|
public class SubtitleTitleInfo
|
||||||
|
{
|
||||||
|
public List<string> LanguageTags { get; set; }
|
||||||
|
public Language Language { get; set; }
|
||||||
|
public string RawTitle { get; set; }
|
||||||
|
public string Title { get; set; }
|
||||||
|
public int Copy { get; set; }
|
||||||
|
public bool TitleFirst { get; set; }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue