1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2026-03-18 16:24:13 -04:00

Compare commits

...

8 Commits

Author SHA1 Message Date
Mark McDowall
67e2fe551a Bumped package version to 3.0.10 2023-03-06 10:28:17 -08:00
Mark McDowall
5db5b1dace Fixed: Migrations on SQLite 3.41.0 2023-03-06 07:27:50 -08:00
bakerboy448
c7919f80de Fixed: Improve WebDL and WebRip Parsing 2022-08-07 13:43:04 -07:00
David Newhall
1a1d427c42 Fixed: Logging when series folder is moved successfully 2022-08-07 12:03:27 -07:00
bakerboy448
9263fc1564 New: Improve messaging for rejected quality upgrades 2022-08-07 11:54:15 -07:00
Kevin Richter
8ab040f612 Fixed: Improve moving file to location where another one exists 2022-08-07 11:52:54 -07:00
Dominik Krivohlavek
d6dff451e0 New: Preserve language tags when importing subtitle files
Closes #2570
Closes #3278
2022-08-07 11:47:14 -07:00
C.J. Manca
ac7afc351c New: Add maximum single episode age option (per indexer) 2022-08-07 11:43:18 -07:00
23 changed files with 324 additions and 23 deletions

View File

@@ -45,6 +45,7 @@ function EditIndexerModalContent(props) {
tags,
fields,
priority,
seasonSearchMaximumSingleEpisodeAge,
protocol,
downloadClientId
} = item;
@@ -153,6 +154,23 @@ function EditIndexerModalContent(props) {
/>
</FormGroup>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>Maximum Single Episode Age</FormLabel>
<FormInputGroup
type={inputTypes.NUMBER}
name="seasonSearchMaximumSingleEpisodeAge"
helpText="During a full season search only season packs will be allowed when the season's last episode is older than this setting. Standard series only. Use 0 to disable."
min={0}
unit="days"
{...seasonSearchMaximumSingleEpisodeAge}
onChange={onInputChange}
/>
</FormGroup>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}

View File

@@ -265,6 +265,11 @@ namespace NzbDrone.Common.Disk
protected virtual void MoveFileInternal(string source, string destination)
{
if (File.Exists(destination))
{
throw new FileAlreadyExistsException("File already exists", destination);
}
File.Move(source, destination);
}

View File

@@ -0,0 +1,14 @@
using System;
namespace NzbDrone.Common.Disk
{
public class FileAlreadyExistsException : Exception
{
public string Filename { get; set; }
public FileAlreadyExistsException(string message, string filename) : base(message)
{
Filename = filename;
}
}
}

View File

@@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Parser.Model;
using NUnit.Framework;
using FluentAssertions;
using FizzWare.NBuilder;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.IndexerSearch.Definitions;
namespace NzbDrone.Core.Test.DecisionEngineTests
{
[TestFixture]
public class SingleEpisodeAgeDownloadDecisionFixture : CoreTest<SeasonPackOnlySpecification>
{
private RemoteEpisode parseResultMulti;
private RemoteEpisode parseResultSingle;
private Series series;
private List<Episode> episodes;
private SeasonSearchCriteria multiSearch;
[SetUp]
public void Setup()
{
series = Builder<Series>.CreateNew()
.With(s => s.Seasons = Builder<Season>.CreateListOfSize(1).Build().ToList())
.With(s => s.SeriesType = SeriesTypes.Standard)
.Build();
episodes = new List<Episode>();
episodes.Add(CreateEpisodeStub(1, 400));
episodes.Add(CreateEpisodeStub(2, 370));
episodes.Add(CreateEpisodeStub(3, 340));
episodes.Add(CreateEpisodeStub(4, 310));
multiSearch = new SeasonSearchCriteria();
multiSearch.Episodes = episodes.ToList();
multiSearch.SeasonNumber = 1;
parseResultMulti = new RemoteEpisode
{
Series = series,
Release = new ReleaseInfo(),
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.SDTV, new Revision(version: 2)), FullSeason = true },
Episodes = episodes.ToList()
};
parseResultSingle = new RemoteEpisode
{
Series = series,
Release = new ReleaseInfo(),
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.SDTV, new Revision(version: 2)) },
Episodes = new List<Episode>()
};
}
Episode CreateEpisodeStub(int number, int age)
{
return new Episode() {
SeasonNumber = 1,
EpisodeNumber = number,
AirDateUtc = DateTime.UtcNow.AddDays(-age)
};
}
[TestCase(1, 200, false)]
[TestCase(4, 200, false)]
[TestCase(1, 600, true)]
[TestCase(1, 365, true)]
[TestCase(4, 365, true)]
[TestCase(1, 0, true)]
public void single_episode_release(int episode, int SeasonSearchMaximumSingleEpisodeAge, bool expectedResult)
{
parseResultSingle.Release.SeasonSearchMaximumSingleEpisodeAge = SeasonSearchMaximumSingleEpisodeAge;
parseResultSingle.Episodes.Clear();
parseResultSingle.Episodes.Add(episodes.Find(e => e.EpisodeNumber == episode));
Subject.IsSatisfiedBy(parseResultSingle, multiSearch).Accepted.Should().Be(expectedResult);
}
// should always accept all season packs
[TestCase(200, true)]
[TestCase(600, true)]
[TestCase(365, true)]
[TestCase(0, true)]
public void multi_episode_release(int SeasonSearchMaximumSingleEpisodeAge, bool expectedResult)
{
parseResultMulti.Release.SeasonSearchMaximumSingleEpisodeAge = SeasonSearchMaximumSingleEpisodeAge;
Subject.IsSatisfiedBy(parseResultMulti, multiSearch).Accepted.Should().BeTrue();
}
}
}

View File

@@ -82,8 +82,8 @@ namespace NzbDrone.Core.Test.Extras.Subtitles
[TestCase("Series Title - S01E01.srt", "Series Title - S01E01.srt")]
[TestCase("Series.Title.S01E01.en.srt", "Series Title - S01E01.en.srt")]
[TestCase("Series.Title.S01E01.english.srt", "Series Title - S01E01.en.srt")]
[TestCase("Series-Title-S01E01-fr-cc.srt", "Series Title - S01E01.fr.srt")]
[TestCase("Series Title S01E01_en_sdh_forced.srt", "Series Title - S01E01.en.srt")]
[TestCase("Series-Title-S01E01-fr-cc.srt", "Series Title - S01E01.fr.cc.srt")]
[TestCase("Series Title S01E01_en_sdh_forced.srt", "Series Title - S01E01.en.sdh.forced.srt")]
[TestCase("Series_Title_S01E01 en.srt", "Series Title - S01E01.en.srt")]
[TestCase(@"Subs\S01E01.en.srt", "Series Title - S01E01.en.srt")]
[TestCase(@"Subs\Series.Title.S01E01\2_en.srt", "Series Title - S01E01.en.srt")]
@@ -104,7 +104,7 @@ namespace NzbDrone.Core.Test.Extras.Subtitles
var files = new List<string>
{
Path.Combine(_episodeFolder, "Series.Title.S01E01.en.srt").AsOsAgnostic(),
Path.Combine(_episodeFolder, "Series.Title.S01E01.english.srt").AsOsAgnostic(),
Path.Combine(_episodeFolder, "Series.Title.S01E01.eng.srt").AsOsAgnostic(),
Path.Combine(_episodeFolder, "Subs", "Series_Title_S01E01_en_forced.srt").AsOsAgnostic(),
Path.Combine(_episodeFolder, "Subs", "Series.Title.S01E01", "2_fr.srt").AsOsAgnostic()
};
@@ -113,7 +113,7 @@ namespace NzbDrone.Core.Test.Extras.Subtitles
{
"Series Title - S01E01.1.en.srt",
"Series Title - S01E01.2.en.srt",
"Series Title - S01E01.3.en.srt",
"Series Title - S01E01.en.forced.srt",
"Series Title - S01E01.fr.srt",
};
@@ -126,6 +126,35 @@ namespace NzbDrone.Core.Test.Extras.Subtitles
results[i].RelativePath.AsOsAgnostic().PathEquals(Path.Combine("Season 1", expectedOutputs[i]).AsOsAgnostic()).Should().Be(true);
}
}
[Test]
public void should_import_multiple_subtitle_files_per_language_with_tags()
{
var files = new List<string>
{
Path.Combine(_episodeFolder, "Series.Title.S01E01.en.forced.cc.srt").AsOsAgnostic(),
Path.Combine(_episodeFolder, "Series.Title.S01E01.other.en.forced.cc.srt").AsOsAgnostic(),
Path.Combine(_episodeFolder, "Series.Title.S01E01.en.forced.sdh.srt").AsOsAgnostic(),
Path.Combine(_episodeFolder, "Series.Title.S01E01.en.forced.default.srt").AsOsAgnostic(),
};
var expectedOutputs = new[]
{
"Series Title - S01E01.1.en.forced.cc.srt",
"Series Title - S01E01.2.en.forced.cc.srt",
"Series Title - S01E01.en.forced.sdh.srt",
"Series Title - S01E01.en.forced.default.srt"
};
var results = Subject.ImportFiles(_localEpisode, _episodeFile, files, true).ToList();
results.Count().Should().Be(expectedOutputs.Length);
for (int i = 0; i < expectedOutputs.Length; i++)
{
results[i].RelativePath.AsOsAgnostic().PathEquals(Path.Combine("Season 1", expectedOutputs[i]).AsOsAgnostic()).Should().Be(true);
}
}
[Test]
[TestCase("sub.srt", "Series Title - S01E01.srt")]

View File

@@ -256,6 +256,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("The Series 42 S09E13 1.54 GB WEB-RIP 1080p Dual-Audio 2019 MKV", false)]
[TestCase("Series.Title.1x04.ITA.1080p.WEBMux.x264-NovaRip", false)]
[TestCase("Series.Title.2019.S02E07.Chapter.15.The.Believer.4Kto1080p.DSNYP.Webrip.x265.10bit.EAC3.5.1.Atmos.GokiTAoE", false)]
[TestCase("Series.Title.S01.1080p.AMZN.WEB-Rip.DDP5.1.H.264-Telly", false)]
public void should_parse_webrip1080p_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Quality.WEBRip1080p, proper);

View File

@@ -36,7 +36,7 @@ namespace NzbDrone.Core.Datastore.Migration
removeFailedDownloads = false;
}
using (var updateClientCmd = conn.CreateCommand(tran, $"UPDATE DownloadClients SET RemoveCompletedDownloads = (CASE WHEN Implementation IN (\"RTorrent\", \"Flood\") THEN 0 ELSE ? END), RemoveFailedDownloads = ?"))
using (var updateClientCmd = conn.CreateCommand(tran, $"UPDATE DownloadClients SET RemoveCompletedDownloads = (CASE WHEN Implementation IN ('RTorrent', 'Flood') THEN 0 ELSE ? END), RemoveFailedDownloads = ?"))
{
updateClientCmd.AddParameter(removeCompletedDownloads ? 1 : 0);
updateClientCmd.AddParameter(removeFailedDownloads ? 1 : 0);

View File

@@ -0,0 +1,14 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(170)]
public class add_language_tags_to_subtitle_files : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Alter.Table("SubtitleFiles").AddColumn("LanguageTags").AsString().Nullable();
}
}
}

View File

@@ -0,0 +1,14 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(172)]
public class add_SeasonSearchMaximumSingleEpisodeAge_to_indexers : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Alter.Table("Indexers").AddColumn("SeasonSearchMaximumSingleEpisodeAge").AsInt32().NotNullable().WithDefaultValue(0);
}
}
}

View File

@@ -23,6 +23,11 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
public override bool SupportsTransactions => true;
public override bool TableExists(string schemaName, string tableName)
{
return Exists("select count(*) from sqlite_master where name='{0}' and type='table'", tableName);
}
public override void Process(AlterColumnExpression expression)
{
var tableDefinition = GetTableSchema(expression.TableName);

View File

@@ -0,0 +1,51 @@
using System;
using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Common.Extensions;
using System.Linq;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.DecisionEngine.Specifications
{
public class SeasonPackOnlySpecification : IDecisionEngineSpecification
{
private readonly IConfigService _configService;
private readonly Logger _logger;
public SeasonPackOnlySpecification(IConfigService configService, Logger logger)
{
_configService = configService;
_logger = logger;
}
public SpecificationPriority Priority => SpecificationPriority.Default;
public RejectionType Type => RejectionType.Permanent;
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
{
if (searchCriteria == null || searchCriteria.Episodes.Count == 1)
{
return Decision.Accept();
}
if (subject.Release.SeasonSearchMaximumSingleEpisodeAge > 0)
{
if (subject.Series.SeriesType == SeriesTypes.Standard && !subject.ParsedEpisodeInfo.FullSeason && subject.Episodes.Count >= 1)
{
// test against episodes of the same season in the current search, and make sure they have an air date
var subset = searchCriteria.Episodes.Where(e => e.AirDateUtc.HasValue && e.SeasonNumber == subject.Episodes.First().SeasonNumber).ToList();
if (subset.Count() > 0 && subset.Max(e => e.AirDateUtc).Value.Before(DateTime.UtcNow - TimeSpan.FromDays(subject.Release.SeasonSearchMaximumSingleEpisodeAge)))
{
_logger.Debug("Release {0}: last episode in this season aired more than {1} days ago, season pack required.", subject.Release.Title, subject.Release.SeasonSearchMaximumSingleEpisodeAge);
return Decision.Reject("Last episode in this season aired more than {0} days ago, season pack required.", subject.Release.SeasonSearchMaximumSingleEpisodeAge);
}
}
}
return Decision.Accept();
}
}
}

View File

@@ -1,4 +1,5 @@
using NzbDrone.Core.Extras.Files;
using System.Collections.Generic;
using NzbDrone.Core.Extras.Files;
using NzbDrone.Core.Languages;
namespace NzbDrone.Core.Extras.Subtitles
@@ -6,5 +7,11 @@ namespace NzbDrone.Core.Extras.Subtitles
public class SubtitleFile : ExtraFile
{
public Language Language { get; set; }
public string AggregateString => Language + LanguageTagsAsString + Extension;
public List<string> LanguageTags { get; set; }
private string LanguageTagsAsString => string.Join(".", LanguageTags);
}
}

View File

@@ -72,7 +72,7 @@ namespace NzbDrone.Core.Extras.Subtitles
foreach (var episodeFile in episodeFiles)
{
var groupedExtraFilesForEpisodeFile = subtitleFiles.Where(m => m.EpisodeFileId == episodeFile.Id)
.GroupBy(s => s.Language + s.Extension).ToList();
.GroupBy(s => s.AggregateString).ToList();
foreach (var group in groupedExtraFilesForEpisodeFile)
{
@@ -81,7 +81,7 @@ namespace NzbDrone.Core.Extras.Subtitles
foreach (var subtitleFile in group)
{
var suffix = GetSuffix(subtitleFile.Language, copy, groupCount > 1);
var suffix = GetSuffix(subtitleFile.Language, copy, subtitleFile.LanguageTags, groupCount > 1);
movedFiles.AddIfNotNull(MoveFile(series, episodeFile, subtitleFile, suffix));
copy++;
@@ -116,7 +116,7 @@ namespace NzbDrone.Core.Extras.Subtitles
try
{
// Filename match
if (Path.GetFileNameWithoutExtension(file).StartsWith(sourceFileName, StringComparison.InvariantCultureIgnoreCase))
if (Path.GetFileNameWithoutExtension(file).StartsWithIgnoreCase(sourceFileName))
{
matchingFiles.Add(file);
continue;
@@ -175,16 +175,24 @@ namespace NzbDrone.Core.Extras.Subtitles
}
}
var subtitleFiles = new List<Tuple<string, Language, string>>();
var subtitleFiles = new List<SubtitleFile>();
foreach (string file in matchingFiles)
{
var language = LanguageParser.ParseSubtitleLanguage(file);
var extension = Path.GetExtension(file);
subtitleFiles.Add(new Tuple<string, Language, string>(file, language, extension));
var languageTags = LanguageParser.ParseLanguageTags(file);
var subFile = new SubtitleFile
{
Language = language,
Extension = extension
};
subFile.LanguageTags = languageTags.ToList();
subFile.RelativePath = PathExtensions.GetRelativePath(sourceFolder, file);
subtitleFiles.Add(subFile);
}
var groupedSubtitleFiles = subtitleFiles.GroupBy(s => s.Item2 + s.Item3).ToList();
var groupedSubtitleFiles = subtitleFiles.GroupBy(s => s.AggregateString).ToList();
foreach (var group in groupedSubtitleFiles)
{
@@ -193,14 +201,15 @@ namespace NzbDrone.Core.Extras.Subtitles
foreach (var file in group)
{
var path = Path.Combine(sourceFolder, file.RelativePath);
var language = file.Language;
var extension = file.Extension;
var suffix = GetSuffix(language, copy, file.LanguageTags, groupCount > 1);
try
{
var path = file.Item1;
var language = file.Item2;
var extension = file.Item3;
var suffix = GetSuffix(language, copy, groupCount > 1);
var subtitleFile = ImportFile(localEpisode.Series, episodeFile, path, isReadOnly, extension, suffix);
subtitleFile.Language = language;
subtitleFile.LanguageTags = file.LanguageTags;
_mediaFileAttributeService.SetFilePermissions(path);
_subtitleFileService.Upsert(subtitleFile);
@@ -211,7 +220,7 @@ namespace NzbDrone.Core.Extras.Subtitles
}
catch (Exception ex)
{
_logger.Warn(ex, "Failed to import subtitle file: {0}", file.Item1);
_logger.Warn(ex, "Failed to import subtitle file: {0}", path);
}
}
}
@@ -219,7 +228,7 @@ namespace NzbDrone.Core.Extras.Subtitles
return importedFiles;
}
private string GetSuffix(Language language, int copy, bool multipleCopies = false)
private string GetSuffix(Language language, int copy, List<string> languageTags, bool multipleCopies = false)
{
var suffixBuilder = new StringBuilder();
@@ -235,6 +244,12 @@ namespace NzbDrone.Core.Extras.Subtitles
suffixBuilder.Append(IsoLanguages.Get(language).TwoLetterCode);
}
if (languageTags.Any())
{
suffixBuilder.Append(".");
suffixBuilder.Append(string.Join(".", languageTags));
}
return suffixBuilder.ToString();
}
}

View File

@@ -23,6 +23,7 @@ namespace NzbDrone.Core.Indexers
public abstract string Name { get; }
public abstract DownloadProtocol Protocol { get; }
public int Priority { get; set; }
public int SeasonSearchMaximumSingleEpisodeAge { get; set; }
public abstract bool SupportsRss { get; }
public abstract bool SupportsSearch { get; }
@@ -81,6 +82,7 @@ namespace NzbDrone.Core.Indexers
c.Indexer = Definition.Name;
c.DownloadProtocol = Protocol;
c.IndexerPriority = ((IndexerDefinition)Definition).Priority;
c.SeasonSearchMaximumSingleEpisodeAge = ((IndexerDefinition)Definition).SeasonSearchMaximumSingleEpisodeAge;
});
return result;

View File

@@ -12,6 +12,7 @@ namespace NzbDrone.Core.Indexers
public bool SupportsRss { get; set; }
public bool SupportsSearch { get; set; }
public int Priority { get; set; } = 25;
public int SeasonSearchMaximumSingleEpisodeAge { get; set; } = 0;
public override bool Enable => EnableRss || EnableAutomaticSearch || EnableInteractiveSearch;

View File

@@ -48,8 +48,8 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
if (qualityCompare < 0)
{
_logger.Debug("This file isn't a quality upgrade for all episodes. Skipping {0}", localEpisode.Path);
return Decision.Reject("Not an upgrade for existing episode file(s)");
_logger.Debug("This file isn't a quality upgrade for all episodes. New Quality is {0}. Skipping {1}", localEpisode.Quality.Quality, localEpisode.Path);
return Decision.Reject("Not an upgrade for existing episode file(s). New Quality is {0}", localEpisode.Quality.Quality);
}
// Same quality, is not a language upgrade, propers/repacks are preferred and it is not a revision update

View File

@@ -134,6 +134,10 @@ namespace NzbDrone.Core.MediaFiles
_eventAggregator.PublishEvent(new EpisodeFileRenamedEvent(series, episodeFile, previousPath));
}
catch (FileAlreadyExistsException ex)
{
_logger.Warn("File not renamed, there is already a file at the destination: {0}", ex.Filename);
}
catch (SameFilenameException ex)
{
_logger.Debug("File not renamed, source and destination are the same: {0}", ex.Filename);

View File

@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Instrumentation;
using NzbDrone.Core.Languages;
@@ -152,6 +154,25 @@ namespace NzbDrone.Core.Parser
return Language.Unknown;
}
public static IEnumerable<string> ParseLanguageTags(string fileName)
{
try
{
var simpleFilename = Path.GetFileNameWithoutExtension(fileName);
var match = SubtitleLanguageRegex.Match(simpleFilename);
var languageTags = match.Groups["tags"].Captures.Cast<Capture>()
.Where(tag => !tag.Value.Empty())
.Select(tag => tag.Value.ToLower());
return languageTags;
}
catch (Exception ex)
{
Logger.Debug(ex, "Failed parsing language tags from subtitle file: {0}", fileName);
}
return Enumerable.Empty<string>();
}
private static Language RegexLanguage(string title)
{

View File

@@ -15,6 +15,7 @@ namespace NzbDrone.Core.Parser.Model
public int IndexerId { get; set; }
public string Indexer { get; set; }
public int IndexerPriority { get; set; }
public int SeasonSearchMaximumSingleEpisodeAge { get; set; }
public DownloadProtocol DownloadProtocol { get; set; }
public int TvdbId { get; set; }
public int TvRageId { get; set; }

View File

@@ -16,7 +16,7 @@ namespace NzbDrone.Core.Parser
private static readonly Regex SourceRegex = new Regex(@"\b(?:
(?<bluray>BluRay|Blu-Ray|HD-?DVD|BDMux|BD(?!$))|
(?<webdl>WEB[-_. ]DL|WEBDL|AmazonHD|iTunesHD|MaxdomeHD|NetflixU?HD|WebHD|[. ]WEB[. ](?:[xh][ .]?26[45]|DDP?5[. ]1)|[. ](?-i:WEB)$|\d+0p(?:[-. ]AMZN)?[-. ]WEB[-. ]|WEB-DLMux|\b\s\/\sWEB\s\/\s\b|(?:AMZN|NF|DP)[. ]WEB[. ])|
(?<webdl>WEB[-_. ]DL(?:mux)?|WEBDL|AmazonHD|iTunesHD|MaxdomeHD|NetflixU?HD|WebHD|[. ]WEB[. ](?:[xh][ .]?26[45]|DDP?5[. ]1)|[. ](?-i:WEB)$|(?:720|1080|2160)p[-. ]WEB[-. ]|[-. ]WEB[-. ](?:720|1080|2160)p|\b\s\/\sWEB\s\/\s\b|(?:AMZN|NF|DP)[. -]WEB[. -](?!Rip))|
(?<webrip>WebRip|Web-Rip|WEBMux)|
(?<hdtv>HDTV)|
(?<bdrip>BDRip|BDLight)|

View File

@@ -58,7 +58,7 @@ namespace NzbDrone.Core.Tv
_diskProvider.CreateFolder(new DirectoryInfo(destinationPath).Parent.FullName);
_diskTransferService.TransferFolder(sourcePath, destinationPath, TransferMode.Move);
_logger.ProgressInfo("{0} moved successfully to {1}", series.Title, series.Path);
_logger.ProgressInfo("{0} moved successfully to {1}", series.Title, destinationPath);
_eventAggregator.PublishEvent(new SeriesMovedEvent(series, sourcePath, destinationPath));
}

View File

@@ -11,6 +11,7 @@ namespace Sonarr.Api.V3.Indexers
public bool SupportsSearch { get; set; }
public DownloadProtocol Protocol { get; set; }
public int Priority { get; set; }
public int SeasonSearchMaximumSingleEpisodeAge { get; set; }
public int DownloadClientId { get; set; }
}
@@ -29,6 +30,7 @@ namespace Sonarr.Api.V3.Indexers
resource.SupportsSearch = definition.SupportsSearch;
resource.Protocol = definition.Protocol;
resource.Priority = definition.Priority;
resource.SeasonSearchMaximumSingleEpisodeAge = definition.SeasonSearchMaximumSingleEpisodeAge;
resource.DownloadClientId = definition.DownloadClientId;
return resource;
@@ -44,6 +46,7 @@ namespace Sonarr.Api.V3.Indexers
definition.EnableAutomaticSearch = resource.EnableAutomaticSearch;
definition.EnableInteractiveSearch = resource.EnableInteractiveSearch;
definition.Priority = resource.Priority;
definition.SeasonSearchMaximumSingleEpisodeAge = resource.SeasonSearchMaximumSingleEpisodeAge;
definition.DownloadClientId = resource.DownloadClientId;
return definition;

View File

@@ -1,7 +1,7 @@
#! /bin/bash
# Increment packageVersion when package scripts change
packageVersion='3.0.9'
packageVersion='3.0.10'
# For now we keep the build version and package version the same
buildVersion=$packageVersion