1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-03-25 17:35:35 -04:00

Compare commits

...

17 Commits

Author SHA1 Message Date
Mark McDowall
9367a07db4 New: Return static response to requests while app is starting
(cherry picked from commit 303fc5d786ccf2ad14c8523fc239696c5d37ea53)
2023-02-08 01:35:52 +00:00
Qstick
9c86598b54 Fixup language specification tests 2023-02-06 19:38:44 -06:00
Qstick
0fe2262162 Fixed: Releases incorrectly rejected due to language 2023-02-06 19:06:03 -06:00
Qstick
47353aea75 Fixed: Avoid failure on null SceneName 2023-02-05 23:31:00 -06:00
Giulia Petenazzi
af43cb2aca New: Added release year to queue ( issue #6330) (#8019) 2023-02-05 19:09:20 -06:00
Fuochi
bc838b74c7 Fixed: Remove initial dot in filename (#4509) 2023-02-05 17:22:07 -06:00
Qstick
cbcf3d1058 New: Custom Format Updates (#8067) 2023-02-05 17:09:37 -06:00
Qstick
c72e64f081 Bump version to 4.4.2 2023-02-04 21:15:36 -06:00
Qstick
e09607edb0 Remove old, broken test
Fixes #7186
2023-02-04 21:12:22 -06:00
Winter
d91578aee3 Fixed: Releases from PTP showing skewed publish date
PTP returns UTC timestamps, without a timezone specifier. Previously, users
would see skewed publish dates, as the UTC timestamps were being parsed
as if they were in the system's timezone. To fix this, we just assume the
publish date is in UTC.
2023-02-04 17:46:23 -06:00
Mark McDowall
affedd7f9d Fixed: Ping endpoint no longer requires authentication
(cherry picked from commit ad42d4a14c814d5911dafb5e78e97ec09b4b13a5)
2023-02-04 17:44:37 -06:00
Qstick
c3665e9fea New: Spanish (Latino) languages
Closes #7914
Closes #3467
Closes #6415
2023-02-04 17:42:39 -06:00
Mark McDowall
364d8bd7c5 Fixed: Don't try to remove the same item from queue multiple times
Closes #7932

(cherry picked from commit 2491da067815e129df3a3a79c0cc7221a9d87094)
2023-02-04 17:32:18 -06:00
Mark McDowall
7142d1f224 Improve usage of Original Title renaming token
Closes #7168

Fixed: Don't recursively add the current file name to new file name when '{Original Title}' is used in addition to other naming tokens
(cherry picked from commit ebb48a19cc792c71bfbd57d5f106067190d95339)
2023-02-04 17:26:07 -06:00
Stevie Robinson
86777e021b Fixed: Mass Editor Footer on Smaller Screens
Closes #6968

(cherry picked from commit 9afcec8b1ffc11da93ae50b73f77f5ebe6e12391)
2023-02-04 17:26:07 -06:00
bakerboy448
9d2dacea97 New: Improve Manual Import logging when not parsing files
Closes #8059

(cherry picked from commit 83f63590630ae0728fd9f9f03567a294934eebcc)
2023-02-04 17:26:07 -06:00
Mark McDowall
d98c86c3d9 Fixed: Parse year in title from square brackets
(cherry picked from commit 99e60196a4e513d6340a090de4a5517f205e7a29)
2023-02-04 17:22:26 -06:00
113 changed files with 1035 additions and 1120 deletions

View File

@@ -9,7 +9,7 @@ variables:
testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '4.4.1'
majorVersion: '4.4.2'
minorVersion: $[counter('minorVersion', 2000)]
radarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(radarrVersion)'

View File

@@ -56,6 +56,7 @@ class HistoryRow extends Component {
movie,
quality,
customFormats,
customFormatScore,
languages,
qualityCutoffNotMet,
eventType,
@@ -175,7 +176,7 @@ class HistoryRow extends Component {
key={name}
className={styles.customFormatScore}
>
{formatCustomFormatScore(data.customFormatScore)}
{formatCustomFormatScore(customFormatScore)}
</TableRowCell>
);
}
@@ -241,8 +242,9 @@ HistoryRow.propTypes = {
movie: PropTypes.object.isRequired,
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
quality: PropTypes.object.isRequired,
customFormats: PropTypes.arrayOf(PropTypes.object),
customFormatScore: PropTypes.number.isRequired,
qualityCutoffNotMet: PropTypes.bool.isRequired,
customFormats: PropTypes.arrayOf(PropTypes.object).isRequired,
eventType: PropTypes.string.isRequired,
sourceTitle: PropTypes.string.isRequired,
date: PropTypes.string.isRequired,

View File

@@ -128,6 +128,7 @@ class QueueRow extends Component {
{
columns.map((column) => {
const {
name,
isVisible
@@ -234,6 +235,16 @@ class QueueRow extends Component {
);
}
if (name === 'year') {
return (
<TableRowCell key={name}>
{
movie ? movie.year : ''
}
</TableRowCell>
);
}
if (name === 'title') {
return (
<TableRowCell key={name}>
@@ -362,6 +373,7 @@ QueueRow.propTypes = {
estimatedCompletionTime: PropTypes.string,
timeleft: PropTypes.string,
size: PropTypes.number,
year: PropTypes.number,
sizeleft: PropTypes.number,
showRelativeDates: PropTypes.bool.isRequired,
shortDateFormat: PropTypes.string.isRequired,

View File

@@ -19,7 +19,7 @@
}
}
@media only screen and (max-width: $breakpointLarge) {
@media only screen and (max-width: $breakpointExtraLarge) {
.contentFooter {
flex-wrap: wrap;
}

View File

@@ -64,6 +64,15 @@ const columns = [
isSortable: true,
isVisible: true
},
{
name: 'customFormats',
label: React.createElement(Icon, {
name: icons.INTERACTIVE,
title: translate('CustomFormat')
}),
isSortable: true,
isVisible: true
},
{
name: 'rejections',
label: React.createElement(Icon, {

View File

@@ -5,8 +5,10 @@
}
.quality,
.language {
.languages {
composes: cell from '~Components/Table/Cells/TableRowCell.css';
text-align: center;
}
.label {
@@ -21,3 +23,7 @@
margin-top: 0;
text-align: start;
}
.customFormatTooltip {
max-width: 250px;
}

View File

@@ -12,6 +12,7 @@ import SelectLanguageModal from 'InteractiveImport/Language/SelectLanguageModal'
import SelectMovieModal from 'InteractiveImport/Movie/SelectMovieModal';
import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal';
import SelectReleaseGroupModal from 'InteractiveImport/ReleaseGroup/SelectReleaseGroupModal';
import MovieFormats from 'Movie/MovieFormats';
import MovieLanguage from 'Movie/MovieLanguage';
import MovieQuality from 'Movie/MovieQuality';
import formatBytes from 'Utilities/Number/formatBytes';
@@ -150,6 +151,7 @@ class InteractiveImportRow extends Component {
languages,
releaseGroup,
size,
customFormats,
rejections,
isReprocessing,
isSelected,
@@ -226,7 +228,7 @@ class InteractiveImportRow extends Component {
</TableRowCellButton>
<TableRowCellButton
className={styles.language}
className={styles.languages}
title={translate('ClickToChangeLanguage')}
onPress={this.onSelectLanguagePress}
>
@@ -259,7 +261,26 @@ class InteractiveImportRow extends Component {
<TableRowCell>
{
!!rejections.length &&
customFormats?.length ?
<Popover
anchor={
<Icon name={icons.INTERACTIVE} />
}
title="Formats"
body={
<div className={styles.customFormatTooltip}>
<MovieFormats formats={customFormats} />
</div>
}
position={tooltipPositions.LEFT}
/> :
null
}
</TableRowCell>
<TableRowCell>
{
rejections.length ?
<Popover
anchor={
<Icon
@@ -282,7 +303,9 @@ class InteractiveImportRow extends Component {
</ul>
}
position={tooltipPositions.LEFT}
/>
canFlip={false}
/> :
null
}
</TableRowCell>
@@ -330,6 +353,7 @@ InteractiveImportRow.propTypes = {
languages: PropTypes.arrayOf(PropTypes.object),
releaseGroup: PropTypes.string,
size: PropTypes.number.isRequired,
customFormats: PropTypes.arrayOf(PropTypes.object),
rejections: PropTypes.arrayOf(PropTypes.object).isRequired,
isReprocessing: PropTypes.bool,
isSelected: PropTypes.bool,

View File

@@ -62,6 +62,7 @@ class MovieHistoryRow extends Component {
sourceTitle,
quality,
customFormats,
customFormatScore,
languages,
qualityCutoffNotMet,
date,
@@ -106,7 +107,7 @@ class MovieHistoryRow extends Component {
</TableRowCell>
<TableRowCell key={name}>
{formatCustomFormatScore(data.customFormatScore)}
{formatCustomFormatScore(customFormatScore)}
</TableRowCell>
<RelativeDateCellConnector
@@ -161,7 +162,8 @@ MovieHistoryRow.propTypes = {
sourceTitle: PropTypes.string.isRequired,
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
quality: PropTypes.object.isRequired,
customFormats: PropTypes.arrayOf(PropTypes.object).isRequired,
customFormats: PropTypes.arrayOf(PropTypes.object),
customFormatScore: PropTypes.number.isRequired,
qualityCutoffNotMet: PropTypes.bool.isRequired,
date: PropTypes.string.isRequired,
data: PropTypes.object.isRequired,

View File

@@ -118,6 +118,12 @@ export const defaultState = {
isSortable: true,
isVisible: false
},
{
name: 'year',
label: translate('Year'),
isSortable: true,
isVisible: true
},
{
name: 'outputPath',
label: translate('OutputPath'),

View File

@@ -1,5 +1,4 @@
function formatCustomFormatScore(input) {
function formatCustomFormatScore(input, customFormatsLength = 0) {
const score = Number(input);
if (score > 0) {
@@ -10,7 +9,7 @@ function formatCustomFormatScore(input) {
return score;
}
return '';
return customFormatsLength > 0 ? '+0' : '';
}
export default formatCustomFormatScore;

View File

@@ -9,6 +9,7 @@ namespace NzbDrone.Common.EnvironmentInfo
bool IsAdmin { get; }
bool IsWindowsService { get; }
bool IsWindowsTray { get; }
bool IsStarting { get; set; }
bool IsExiting { get; set; }
bool IsTray { get; }
RuntimeMode Mode { get; }

View File

@@ -19,6 +19,7 @@ namespace NzbDrone.Common.EnvironmentInfo
_logger = logger;
IsWindowsService = hostLifetime is WindowsServiceLifetime;
IsStarting = true;
// net6.0 will return Radarr.dll for entry assembly, we need the actual
// executable name (Radarr on linux). On mono this will return the location of
@@ -82,6 +83,7 @@ namespace NzbDrone.Common.EnvironmentInfo
public bool IsWindowsService { get; private set; }
public bool IsStarting { get; set; }
public bool IsExiting { get; set; }
public bool IsTray
{

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
@@ -9,7 +9,7 @@ using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.CustomFormats
{
[TestFixture]
public class CustomFormatsFixture : CoreTest
public class CustomFormatsTestHelpers : CoreTest
{
private static List<CustomFormat> _customFormats { get; set; }

View File

@@ -46,14 +46,14 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
ParsedMovieInfo = new ParsedMovieInfo { Quality = new QualityModel(Quality.DVD, new Revision(version: 2)) },
};
CustomFormatsFixture.GivenCustomFormats(_format1, _format2);
CustomFormatsTestHelpers.GivenCustomFormats(_format1, _format2);
}
[Test]
public void should_allow_if_format_score_greater_than_min()
{
_remoteMovie.CustomFormats = new List<CustomFormat> { _format1 };
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name);
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_format1.Name);
_remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats);
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue();
@@ -63,7 +63,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void should_deny_if_format_score_not_greater_than_min()
{
_remoteMovie.CustomFormats = new List<CustomFormat> { _format2 };
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name);
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_format1.Name);
_remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats);
Console.WriteLine(_remoteMovie.CustomFormatScore);
@@ -76,7 +76,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void should_deny_if_format_score_not_greater_than_min_2()
{
_remoteMovie.CustomFormats = new List<CustomFormat> { _format2, _format1 };
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name);
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_format1.Name);
_remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats);
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeFalse();
@@ -86,7 +86,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void should_allow_if_all_format_is_defined_in_profile()
{
_remoteMovie.CustomFormats = new List<CustomFormat> { _format2, _format1 };
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name, _format2.Name);
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_format1.Name, _format2.Name);
_remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats);
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeTrue();
@@ -96,7 +96,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void should_deny_if_no_format_was_parsed_and_min_score_positive()
{
_remoteMovie.CustomFormats = new List<CustomFormat> { };
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name, _format2.Name);
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_format1.Name, _format2.Name);
_remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats);
Subject.IsSatisfiedBy(_remoteMovie, null).Accepted.Should().BeFalse();
@@ -106,7 +106,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void should_allow_if_no_format_was_parsed_min_score_is_zero()
{
_remoteMovie.CustomFormats = new List<CustomFormat> { };
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(_format1.Name, _format2.Name);
_remoteMovie.Movie.Profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_format1.Name, _format2.Name);
_remoteMovie.Movie.Profile.MinFormatScore = 0;
_remoteMovie.CustomFormatScore = _remoteMovie.Movie.Profile.CalculateCustomFormatScore(_remoteMovie.CustomFormats);

View File

@@ -40,8 +40,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
private void GivenProfile(Profile profile)
{
CustomFormatsFixture.GivenCustomFormats();
profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems();
CustomFormatsTestHelpers.GivenCustomFormats();
profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems();
profile.MinFormatScore = 0;
_remoteMovie.Movie.Profile = profile;
@@ -74,7 +74,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{
_customFormat = new CustomFormat("My Format", new ResolutionSpecification { Value = (int)Resolution.R1080p }) { Id = 1 };
CustomFormatsFixture.GivenCustomFormats(_customFormat);
CustomFormatsTestHelpers.GivenCustomFormats(_customFormat);
}
[Test]
@@ -157,7 +157,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
Cutoff = Quality.HDTV720p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(),
MinFormatScore = 0,
FormatItems = CustomFormatsFixture.GetSampleFormatItems("My Format"),
FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems("My Format"),
UpgradeAllowed = true
});

View File

@@ -38,14 +38,14 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
Mocker.Resolve<UpgradableSpecification>();
_upgradeHistory = Mocker.Resolve<HistorySpecification>();
CustomFormatsFixture.GivenCustomFormats();
CustomFormatsTestHelpers.GivenCustomFormats();
_fakeMovie = Builder<Movie>.CreateNew()
.With(c => c.Profile = new Profile
{
Items = Qualities.QualityFixture.GetDefaultQualities(),
Cutoff = Quality.Bluray1080p.Id,
FormatItems = CustomFormatsFixture.GetSampleFormatItems("None"),
FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems("None"),
MinFormatScore = 0,
UpgradeAllowed = true
})
@@ -66,7 +66,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
.Returns(true);
Mocker.GetMock<ICustomFormatCalculationService>()
.Setup(x => x.ParseCustomFormat(It.IsAny<MovieHistory>()))
.Setup(x => x.ParseCustomFormat(It.IsAny<MovieHistory>(), It.IsAny<Movie>()))
.Returns(new List<CustomFormat>());
}
@@ -163,7 +163,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{
Items = Qualities.QualityFixture.GetDefaultQualities(),
Cutoff = Quality.Bluray1080p.Id,
FormatItems = CustomFormatsFixture.GetSampleFormatItems(),
FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(),
MinFormatScore = 0
};
@@ -171,7 +171,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
_upgradableQuality = new QualityModel(Quality.WEBDL1080p, new Revision(version: 1));
Mocker.GetMock<ICustomFormatCalculationService>()
.Setup(x => x.ParseCustomFormat(It.IsAny<MovieHistory>()))
.Setup(x => x.ParseCustomFormat(It.IsAny<MovieHistory>(), It.IsAny<Movie>()))
.Returns(new List<CustomFormat>());
GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, MovieHistoryEventType.Grabbed);
@@ -186,7 +186,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{
Items = Qualities.QualityFixture.GetDefaultQualities(),
Cutoff = Quality.WEBDL1080p.Id,
FormatItems = CustomFormatsFixture.GetSampleFormatItems(),
FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(),
MinFormatScore = 0
};
@@ -221,7 +221,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{
Items = Qualities.QualityFixture.GetDefaultQualities(),
Cutoff = Quality.WEBDL1080p.Id,
FormatItems = CustomFormatsFixture.GetSampleFormatItems(),
FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(),
MinFormatScore = 0
};

View File

@@ -41,17 +41,17 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
private void WithEnglishRelease()
{
_remoteMovie.ParsedMovieInfo.Languages = new List<Language> { Language.English };
_remoteMovie.Languages = new List<Language> { Language.English };
}
private void WithGermanRelease()
{
_remoteMovie.ParsedMovieInfo.Languages = new List<Language> { Language.German };
_remoteMovie.Languages = new List<Language> { Language.German };
}
private void WithFrenchRelease()
{
_remoteMovie.ParsedMovieInfo.Languages = new List<Language> { Language.French };
_remoteMovie.Languages = new List<Language> { Language.French };
}
[Test]

View File

@@ -37,7 +37,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
_customFormat1 = new CustomFormat("My Format 1", new LanguageSpecification { Value = (int)Language.English }) { Id = 1 };
_customFormat2 = new CustomFormat("My Format 2", new LanguageSpecification { Value = (int)Language.French }) { Id = 2 };
CustomFormatsFixture.GivenCustomFormats(_customFormat1, _customFormat2);
CustomFormatsTestHelpers.GivenCustomFormats(_customFormat1, _customFormat2);
Mocker.GetMock<IQualityDefinitionService>()
.Setup(s => s.Get(It.IsAny<Quality>()))
@@ -62,7 +62,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
remoteMovie.Movie = Builder<Movie>.CreateNew().With(m => m.Profile = new Profile
{
Items = Qualities.QualityFixture.GetDefaultQualities(),
FormatItems = CustomFormatsFixture.GetSampleFormatItems(_customFormat1.Name, _customFormat2.Name),
FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_customFormat1.Name, _customFormat2.Name),
MinFormatScore = 0
})
.With(m => m.Title = "A Movie")

View File

@@ -48,7 +48,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[SetUp]
public void Setup()
{
CustomFormatsFixture.GivenCustomFormats(_customFormat1, _customFormat2);
CustomFormatsTestHelpers.GivenCustomFormats(_customFormat1, _customFormat2);
}
private void GivenAutoDownloadPropers(ProperDownloadTypes type)
@@ -73,7 +73,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
var profile = new Profile
{
Items = Qualities.QualityFixture.GetDefaultQualities(),
FormatItems = CustomFormatsFixture.GetSampleFormatItems(_customFormat1.Name, _customFormat2.Name),
FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(_customFormat1.Name, _customFormat2.Name),
MinFormatScore = 0
};

View File

@@ -32,13 +32,13 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{
Mocker.Resolve<UpgradableSpecification>();
CustomFormatsFixture.GivenCustomFormats();
CustomFormatsTestHelpers.GivenCustomFormats();
_movie = Builder<Movie>.CreateNew()
.With(e => e.Profile = new Profile
{
Items = Qualities.QualityFixture.GetDefaultQualities(),
FormatItems = CustomFormatsFixture.GetSampleFormatItems(),
FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(),
MinFormatScore = 0,
UpgradeAllowed = true
})
@@ -58,7 +58,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
.Build();
Mocker.GetMock<ICustomFormatCalculationService>()
.Setup(x => x.ParseCustomFormat(It.IsAny<ParsedMovieInfo>(), _movie))
.Setup(x => x.ParseCustomFormat(It.IsAny<RemoteMovie>(), It.IsAny<long>()))
.Returns(new List<CustomFormat>());
}

View File

@@ -31,7 +31,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
Mocker.Resolve<UpgradableSpecification>();
_upgradeDisk = Mocker.Resolve<UpgradeDiskSpecification>();
CustomFormatsFixture.GivenCustomFormats();
CustomFormatsTestHelpers.GivenCustomFormats();
_firstFile = new MovieFile { Quality = new QualityModel(Quality.Bluray1080p, new Revision(version: 2)), DateAdded = DateTime.Now };
@@ -39,7 +39,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
.With(c => c.Profile = new Profile
{
Cutoff = Quality.Bluray1080p.Id, Items = Qualities.QualityFixture.GetDefaultQualities(),
FormatItems = CustomFormatsFixture.GetSampleFormatItems(),
FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(),
MinFormatScore = 0
})
.With(e => e.MovieFile = _firstFile)

View File

@@ -0,0 +1,112 @@
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Download.Aggregation.Aggregators;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Download.Aggregation.Aggregators
{
[TestFixture]
public class AggregateLanguagesFixture : CoreTest<AggregateLanguages>
{
private RemoteMovie _remoteMovie;
private Movie _movie;
private string _simpleReleaseTitle = "Series.Title.S01E01.xyz-RlsGroup";
[SetUp]
public void Setup()
{
_movie = Builder<Movie>.CreateNew()
.With(m => m.MovieMetadata = new MovieMetadata
{
Title = "Some Movie",
OriginalLanguage = Language.English
})
.Build();
_remoteMovie = Builder<RemoteMovie>.CreateNew()
.With(l => l.ParsedMovieInfo = null)
.With(l => l.Movie = _movie)
.Build();
}
private ParsedMovieInfo GetParsedMovieInfo(List<Language> languages, string releaseTitle, string releaseTokens = "")
{
return new ParsedMovieInfo
{
Languages = languages,
ReleaseTitle = releaseTitle,
SimpleReleaseTitle = releaseTokens
};
}
[Test]
public void should_return_existing_language_if_episode_title_does_not_have_language()
{
_remoteMovie.ParsedMovieInfo = GetParsedMovieInfo(new List<Language> { Language.Original }, _simpleReleaseTitle);
Subject.Aggregate(_remoteMovie).Languages.Should().Contain(_movie.MovieMetadata.Value.OriginalLanguage);
}
[Test]
public void should_return_parsed_language()
{
_remoteMovie.ParsedMovieInfo = GetParsedMovieInfo(new List<Language> { Language.French }, _simpleReleaseTitle);
Subject.Aggregate(_remoteMovie).Languages.Should().Equal(_remoteMovie.ParsedMovieInfo.Languages);
}
[Test]
public void should_exclude_language_that_is_part_of_episode_title_when_release_tokens_contains_episode_title()
{
var releaseTitle = "Series.Title.S01E01.Jimmy.The.Greek.xyz-RlsGroup";
var releaseTokens = ".Jimmy.The.Greek.xyz-RlsGroup";
_remoteMovie.Movie.Title = "Jimmy The Greek";
_remoteMovie.ParsedMovieInfo = GetParsedMovieInfo(new List<Language> { Language.Greek }, releaseTitle, releaseTokens);
Subject.Aggregate(_remoteMovie).Languages.Should().Equal(_movie.MovieMetadata.Value.OriginalLanguage);
}
[Test]
public void should_remove_parsed_language_that_is_part_of_episode_title_when_release_tokens_contains_episode_title()
{
var releaseTitle = "Series.Title.S01E01.Jimmy.The.Greek.French.xyz-RlsGroup";
var releaseTokens = ".Jimmy.The.Greek.French.xyz-RlsGroup";
_remoteMovie.Movie.Title = "Jimmy The Greek";
_remoteMovie.ParsedMovieInfo = GetParsedMovieInfo(new List<Language> { Language.Greek, Language.French }, releaseTitle, releaseTokens);
Subject.Aggregate(_remoteMovie).Languages.Should().Equal(Language.French);
}
[Test]
public void should_not_exclude_language_that_is_part_of_episode_title_when_release_tokens_does_not_contain_episode_title()
{
var releaseTitle = "Series.Title.S01E01.xyz-RlsGroup";
var releaseTokens = ".xyz-RlsGroup";
_remoteMovie.Movie.Title = "Jimmy The Greek";
_remoteMovie.ParsedMovieInfo = GetParsedMovieInfo(new List<Language> { Language.Greek }, releaseTitle, releaseTokens);
Subject.Aggregate(_remoteMovie).Languages.Should().Equal(Language.Greek);
}
[Test]
public void should_use_reparse_language_after_determining_languages_that_are_in_episode_titles()
{
var releaseTitle = "Series.Title.S01E01.Jimmy.The.Greek.Greek.xyz-RlsGroup";
var releaseTokens = ".Jimmy.The.Greek.Greek.xyz-RlsGroup";
_remoteMovie.Movie.Title = "Jimmy The Greek";
_remoteMovie.ParsedMovieInfo = GetParsedMovieInfo(new List<Language> { Language.Greek }, releaseTitle, releaseTokens);
Subject.Aggregate(_remoteMovie).Languages.Should().Equal(Language.Greek);
}
}
}

View File

@@ -54,6 +54,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
Id = id,
Title = "Movie.Title.2020.720p-Radarr",
ParsedMovieInfo = new ParsedMovieInfo { MovieTitles = new List<string> { title }, Year = year },
Release = Builder<ReleaseInfo>.CreateNew().Build(),
MovieId = _movie.Id
});
}

View File

@@ -1,3 +1,4 @@
using System;
using System.Linq;
using System.Net.Http;
using FluentAssertions;
@@ -55,7 +56,7 @@ namespace NzbDrone.Core.Test.IndexerTests.PTPTests
first.DownloadUrl.Should().Be("https://passthepopcorn.me/torrents.php?action=download&id=452135&authkey=00000000000000000000000000000000&torrent_pass=00000000000000000000000000000000");
first.InfoUrl.Should().Be("https://passthepopcorn.me/torrents.php?id=148131&torrentid=452135");
// first.PublishDate.Should().Be(DateTime.Parse("2017-04-17T12:13:42+0000").ToUniversalTime()); stupid timezones
first.PublishDate.Should().Be(DateTime.Parse("2016-10-18T23:40:59+0000").ToUniversalTime());
first.Size.Should().Be(2466170624L);
first.InfoHash.Should().BeNullOrEmpty();
first.MagnetUrl.Should().BeNullOrEmpty();

View File

@@ -49,6 +49,7 @@ namespace NzbDrone.Core.Test.Languages
new object[] { 34, Language.Bengali },
new object[] { 35, Language.Slovak },
new object[] { 36, Language.Latvian },
new object[] { 37, Language.SpanishLatino }
};
public static object[] ToIntCases =
@@ -92,6 +93,7 @@ namespace NzbDrone.Core.Test.Languages
new object[] { Language.Bengali, 34 },
new object[] { Language.Slovak, 35 },
new object[] { Language.Latvian, 36 },
new object[] { Language.SpanishLatino, 37 }
};
[Test]

View File

@@ -35,7 +35,7 @@ namespace NzbDrone.Core.Test.MovieTests.MovieRepositoryTests
var profile = new Profile
{
Items = Qualities.QualityFixture.GetDefaultQualities(Quality.Bluray1080p, Quality.DVD, Quality.HDTV720p),
FormatItems = CustomFormatsFixture.GetDefaultFormatItems(),
FormatItems = CustomFormatsTestHelpers.GetDefaultFormatItems(),
MinFormatScore = 0,
Cutoff = Quality.Bluray1080p.Id,
Name = "TestProfile"

View File

@@ -10,6 +10,8 @@ namespace NzbDrone.Core.Test.OrganizerTests
{
[TestCase("Mission: Impossible - no [HDTV-720p]",
"Mission Impossible - no [HDTV-720p]")]
[TestCase(".45 (2006)", "45 (2006)")]
[TestCase(" The Movie Title ", "The Movie Title")]
public void CleanFileName(string name, string expectedName)
{
FileNameBuilder.CleanFileName(name).Should().Be(expectedName);

View File

@@ -562,19 +562,6 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
.Should().Be(string.Format("HDTV-720p{0}South{0}Park", separator));
}
[Test]
public void should_be_able_to_use_original_filename()
{
_movie.Title = "30 Rock";
_namingConfig.StandardMovieFormat = "{Movie Title} - {Original Filename}";
_movieFile.SceneName = "30.Rock.S01E01.xvid-LOL";
_movieFile.RelativePath = "30 Rock - S01E01 - Test";
Subject.BuildFileName(_movie, _movieFile)
.Should().Be("30 Rock - 30 Rock - S01E01 - Test");
}
[TestCase("en-US")]
[TestCase("fr-FR")]
[TestCase("az")]

View File

@@ -0,0 +1,88 @@
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
{
[TestFixture]
public class OriginalTitleFixture : CoreTest<FileNameBuilder>
{
private Movie _movie;
private MovieFile _movieFile;
private NamingConfig _namingConfig;
[SetUp]
public void Setup()
{
_movie = Builder<Movie>
.CreateNew()
.With(s => s.Title = "My Movie")
.Build();
_movieFile = new MovieFile { Quality = new QualityModel(Quality.HDTV720p), ReleaseGroup = "RadarrTest" };
_namingConfig = NamingConfig.Default;
_namingConfig.RenameMovies = true;
Mocker.GetMock<INamingConfigService>()
.Setup(c => c.GetConfig()).Returns(_namingConfig);
Mocker.GetMock<IQualityDefinitionService>()
.Setup(v => v.Get(Moq.It.IsAny<Quality>()))
.Returns<Quality>(v => Quality.DefaultQualityDefinitions.First(c => c.Quality == v));
Mocker.GetMock<ICustomFormatService>()
.Setup(v => v.All())
.Returns(new List<CustomFormat>());
}
[Test]
public void should_not_recursively_include_current_filename()
{
_movieFile.RelativePath = "My Movie";
_namingConfig.StandardMovieFormat = "{Movie Title} {[Original Title]}";
Subject.BuildFileName(_movie, _movieFile)
.Should().Be("My Movie");
}
[Test]
public void should_include_original_title_if_not_current_file_name()
{
_movieFile.SceneName = "my.movie.2008";
_movieFile.RelativePath = "My Movie";
_namingConfig.StandardMovieFormat = "{Movie Title} {[Original Title]}";
Subject.BuildFileName(_movie, _movieFile)
.Should().Be("My Movie [my.movie.2008]");
}
[Test]
public void should_include_current_filename_if_not_renaming_files()
{
_movieFile.SceneName = "my.movie.2008";
_namingConfig.RenameMovies = false;
Subject.BuildFileName(_movie, _movieFile)
.Should().Be("my.movie.2008");
}
[Test]
public void should_include_current_filename_if_not_including_multiple_naming_tokens()
{
_movieFile.RelativePath = "My Movie";
_namingConfig.StandardMovieFormat = "{Original Title}";
Subject.BuildFileName(_movie, _movieFile)
.Should().Be("My Movie");
}
}
}

View File

@@ -1,3 +1,4 @@
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Languages;
@@ -380,6 +381,18 @@ namespace NzbDrone.Core.Test.ParserTests
result.Languages.Should().BeEquivalentTo(Language.Latvian);
}
[TestCase("Movie.Title.2019.720p_Eng-Spa(Latino)_MovieClubMx")]
[TestCase("Movie.Title.1.WEB-DL.720p.Complete.Latino.YG")]
[TestCase("Movie.Title.1080p.WEB.H264.Latino.YG")]
[TestCase("Movie Title latino")]
[TestCase("Movie Title (Temporada 11 Completa) Audio Dual Ingles/Latino 1920x1080")]
[TestCase("Movie title 7x4 audio latino")]
public void should_parse_language_spanish_latino(string postTitle)
{
var result = LanguageParser.ParseLanguages(postTitle);
result.First().Id.Should().Be(Language.SpanishLatino.Id);
}
[TestCase("Movie.Title.en.sub")]
[TestCase("Movie Title.eng.sub")]
[TestCase("Movie.Title.eng.forced.sub")]

View File

@@ -215,6 +215,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Movie Name FRENCH BluRay 720p 2016 kjhlj", 2016)]
[TestCase("Der.Movie.German.Bluray.FuckYou.Pso.Why.cant.you.follow.scene.rules.1998", 1998)]
[TestCase("Movie Name (1897) [DVD].mp4", 1897)]
[TestCase("World Movie Z Movie [2023]", 2023)]
public void should_parse_movie_year(string postTitle, int year)
{
Parser.Parser.ParseMovieTitle(postTitle).Year.Should().Be(year);
@@ -254,6 +255,18 @@ namespace NzbDrone.Core.Test.ParserTests
parsed.Languages.Should().Contain(Language.German);
}
[TestCase("Movie.Title.2016.1080p.KORSUB.WEBRip.x264.AAC2.0-RADARR", "KORSUB")]
[TestCase("Movie.Title.2016.1080p.KORSUBS.WEBRip.x264.AAC2.0-RADARR", "KORSUBS")]
[TestCase("Movie Title 2017 HC 720p HDRiP DD5 1 x264-LEGi0N", "Generic Hardcoded Subs")]
[TestCase("Movie.Title.2017.720p.SUBBED.HDRip.V2.XViD-26k.avi", "Generic Hardcoded Subs")]
[TestCase("Movie.Title.2000.1080p.BlueRay.x264.DTS.RoSubbed-playHD", null)]
[TestCase("Movie Title! 2018 [Web][MKV][h264][480p][AAC 2.0][Softsubs]", null)]
[TestCase("Movie Title! 2019 [HorribleSubs][Web][MKV][h264][848x480][AAC 2.0][Softsubs(HorribleSubs)]", null)]
public void should_parse_hardcoded_subs(string postTitle, string sub)
{
Parser.Parser.ParseMovieTitle(postTitle).HardcodedSubs.Should().Be(sub);
}
[TestCase("That Italian Movie 2008 [tt1234567] 720p BluRay X264", "tt1234567")]
[TestCase("That Italian Movie 2008 [tt12345678] 720p BluRay X264", "tt12345678")]
public void should_parse_imdb_in_title(string postTitle, string imdb)

View File

@@ -1,28 +0,0 @@
using System.Collections.Generic;
using NUnit.Framework;
using NzbDrone.Core.Parser.Augmenters;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests.AugmentersTests
{
[TestFixture]
public abstract class AugmentMovieInfoFixture<TAugmenter> : CoreTest<TAugmenter>
where TAugmenter : class, IAugmentParsedMovieInfo
{
protected ParsedMovieInfo MovieInfo;
[SetUp]
public virtual void Setup()
{
MovieInfo = new ParsedMovieInfo
{
MovieTitles = new List<string> { "A Movie" },
Year = 1998,
SimpleReleaseTitle = "A Movie Title 1998 Bluray 1080p",
Quality = new QualityModel(Quality.Bluray1080p)
};
}
}
}

View File

@@ -1,23 +0,0 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Parser.Augmenters;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests.AugmentersTests
{
[TestFixture]
public class AugmentWithFileSizeFixture : AugmentMovieInfoFixture<AugmentWithFileSize>
{
[Test]
public void should_add_file_size()
{
var localMovie = new LocalMovie
{
Size = 1500
};
var movieInfo = Subject.AugmentMovieInfo(MovieInfo, localMovie);
movieInfo.ExtraInfo["Size"].Should().BeEquivalentTo(1500);
}
}
}

View File

@@ -1,109 +0,0 @@
using System;
using System.Collections.Generic;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.History;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.Rarbg;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Parser.Augmenters;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests.AugmentersTests
{
[TestFixture]
public class AugmentWithHistoryFixture : AugmentMovieInfoFixture<AugmentWithHistory>
{
private AugmentWithHistory _customSubject { get; set; }
[SetUp]
public override void Setup()
{
base.Setup();
// Add multi indexer
GivenIndexerSettings(new RarbgSettings
{
MultiLanguages = new List<int>
{
(int)Language.English,
(int)Language.French,
}
});
}
protected new AugmentWithHistory Subject
{
get
{
if (_customSubject == null)
{
_customSubject = new AugmentWithHistory(new List<Lazy<IAugmentParsedMovieInfo>> { new (Mocker.Resolve<AugmentWithReleaseInfo>()) });
}
return _customSubject;
}
}
private void GivenIndexerSettings(IIndexerSettings indexerSettings)
{
Mocker.GetMock<IIndexerFactory>().Setup(f => f.Get(It.IsAny<int>())).Returns(new IndexerDefinition
{
Settings = indexerSettings
});
}
private MovieHistory HistoryWithData(params string[] data)
{
var dict = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
for (var i = 0; i < data.Length; i += 2)
{
dict.Add(data[i], data[i + 1]);
}
return new MovieHistory
{
Data = dict,
EventType = MovieHistoryEventType.Grabbed
};
}
[Test]
public void should_add_indexer_flags()
{
var history = HistoryWithData("IndexerFlags", (IndexerFlags.PTP_Approved | IndexerFlags.PTP_Golden).ToString());
var movieInfo = Subject.AugmentMovieInfo(MovieInfo, history);
movieInfo.ExtraInfo["IndexerFlags"].Should().BeEquivalentTo(IndexerFlags.PTP_Golden | IndexerFlags.PTP_Approved);
}
[Test]
public void should_add_size()
{
var history = HistoryWithData("Size", 9663676416.ToString());
var movieInfo = Subject.AugmentMovieInfo(MovieInfo, history);
movieInfo.ExtraInfo["Size"].Should().BeEquivalentTo(9663676416);
}
[Test]
public void should_use_settings_languages_when_necessary()
{
var history = HistoryWithData("IndexerId", 1.ToString());
var movieInfo = Subject.AugmentMovieInfo(MovieInfo, history);
movieInfo.Languages.Should().BeEquivalentTo();
MovieInfo.SimpleReleaseTitle = "A Movie 1998 Bluray 1080p MULTI";
var multiInfo = Subject.AugmentMovieInfo(MovieInfo, history);
multiInfo.Languages.Should().BeEquivalentTo(Language.English, Language.French);
}
[Test]
public void should_not_use_settings_languages()
{
var unknownIndexer = HistoryWithData();
var unknownIndexerInfo = Subject.AugmentMovieInfo(MovieInfo, unknownIndexer);
unknownIndexerInfo.Languages.Should().BeEquivalentTo();
}
}
}

View File

@@ -1,90 +0,0 @@
// using FluentAssertions;
// using NUnit.Framework;
// using NzbDrone.Core.CustomFormats;
// using NzbDrone.Core.MediaFiles.MediaInfo;
// using NzbDrone.Core.Parser;
// using NzbDrone.Core.Parser.Augmenters;
// using NzbDrone.Core.Qualities;
// namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests.AugmentersTests
// {
// [TestFixture]
// public class AugmentWithMediaInfoFixture : AugmentMovieInfoFixture<AugmentWithMediaInfo>
// {
// [TestCase(Resolution.R720p, Source.BLURAY, Resolution.R1080p)]
// [TestCase(Resolution.R1080p, Source.TV, Resolution.R720p)]
// public void should_correct_resolution(Resolution resolution, Source source, Resolution realResolution)
// {
// var quality = new QualityModel
// {
// Source = source,
// Resolution = resolution,
// };
// MovieInfo.Quality = quality;
// var realWidth = 480;
// switch (realResolution)
// {
// case Resolution.R720p:
// realWidth = 1280;
// break;
// case Resolution.R1080p:
// realWidth = 1920;
// break;
// case Resolution.R2160p:
// realWidth = 2160;
// break;
// }
// var mediaInfo = new MediaInfoModel
// {
// Width = realWidth
// };
// var movieInfo = Subject.AugmentMovieInfo(MovieInfo, mediaInfo);
// movieInfo.Quality.Resolution.Should().BeEquivalentTo(realResolution);
// movieInfo.Quality.QualityDetectionSource.Should().BeEquivalentTo(QualityDetectionSource.MediaInfo);
// }
// [TestCase(Resolution.R720P, Source.BLURAY, Resolution.R1080P, Modifier.BRDISK)]
// [TestCase(Resolution.R1080P, Source.BLURAY, Resolution.R720P, Modifier.REMUX)]
// [TestCase(Resolution.R480P, Source.BLURAY, Resolution.R720P)]
// [TestCase(Resolution.R720P, Source.DVD, Resolution.R480P)]
// public void should_not_correct_resolution(Resolution resolution, Source source, Resolution realResolution, Modifier modifier = Modifier.NONE)
// {
// var quality = new QualityModel
// {
// Source = source,
// Resolution = resolution,
// Modifier = modifier,
// };
// MovieInfo.Quality = quality;
// var realWidth = 480;
// switch (realResolution)
// {
// case Resolution.R720P:
// realWidth = 1280;
// break;
// case Resolution.R1080P:
// realWidth = 1920;
// break;
// case Resolution.R2160P:
// realWidth = 2160;
// break;
// }
// var mediaInfo = new MediaInfoModel
// {
// Width = realWidth
// };
// var movieInfo = Subject.AugmentMovieInfo(MovieInfo, mediaInfo);
// movieInfo.Quality.Resolution.Should().BeEquivalentTo(resolution);
// movieInfo.Quality.QualityDetectionSource.Should().BeEquivalentTo(QualityDetectionSource.Name);
// }
// }
// }

View File

@@ -1,29 +0,0 @@
using System;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Parser.Augmenters;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests.AugmentersTests
{
[TestFixture]
public class AugmentWithOriginalLanguageFixture : AugmentMovieInfoFixture<AugmentWithOriginalLanguage>
{
[Test]
public void should_add_movie_original_language()
{
var releaseInfo = new ParsedMovieInfo();
var movie = new Movies.Movie
{
MovieMetadata = new Movies.MovieMetadata
{
OriginalLanguage = Language.English
}
};
var result = Subject.AugmentMovieInfo(releaseInfo, movie);
result.ExtraInfo.Should().ContainKey("OriginalLanguage");
result.ExtraInfo["OriginalLanguage"].Should().Be(Language.English);
}
}
}

View File

@@ -1,77 +0,0 @@
using System.Collections.Generic;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Parser.Augmenters;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests.AugmentersTests
{
[TestFixture]
public class AugmentWithParsedMovieInfoFixture : AugmentMovieInfoFixture<AugmentWithParsedMovieInfo>
{
[Test]
public void should_add_edition_if_null()
{
var folderInfo = new ParsedMovieInfo
{
Edition = "Directors Cut"
};
var result = Subject.AugmentMovieInfo(MovieInfo, folderInfo);
result.Edition.Should().Be(folderInfo.Edition);
}
[Test]
public void should_preferr_longer_edition()
{
var folderInfo = new ParsedMovieInfo
{
Edition = "Super duper cut"
};
MovieInfo.Edition = "Rogue";
var result = Subject.AugmentMovieInfo(MovieInfo, folderInfo);
result.Edition.Should().Be(folderInfo.Edition);
MovieInfo.Edition = "Super duper awesome cut";
result = Subject.AugmentMovieInfo(MovieInfo, folderInfo);
result.Edition.Should().Be(MovieInfo.Edition);
}
[Test]
public void should_combine_languages()
{
var folderInfo = new ParsedMovieInfo
{
Languages = new List<Language> { Language.French }
};
MovieInfo.Languages = new List<Language> { Language.English };
var result = Subject.AugmentMovieInfo(MovieInfo, folderInfo);
result.Languages.Should().BeEquivalentTo(Language.English, Language.French);
}
[Test]
public void should_use_folder_release_group()
{
var folderInfo = new ParsedMovieInfo
{
ReleaseGroup = "AwesomeGroup"
};
MovieInfo.ReleaseGroup = "";
var result = Subject.AugmentMovieInfo(MovieInfo, folderInfo);
result.ReleaseGroup.Should().BeEquivalentTo(folderInfo.ReleaseGroup);
}
}
}

View File

@@ -1,82 +0,0 @@
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Indexers.Rarbg;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Parser.Augmenters;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests.AugmentersTests
{
[TestFixture]
public class AugmentWithReleaseInfoFixture : AugmentMovieInfoFixture<AugmentWithReleaseInfo>
{
private IndexerDefinition _indexerDefinition;
private ReleaseInfo ReleaseInfoWithLanguages(params Language[] languages)
{
_indexerDefinition = new IndexerDefinition
{
Settings = new RarbgSettings { MultiLanguages = languages.ToList().Select(l => (int)l) }
};
Mocker.GetMock<IIndexerFactory>()
.Setup(v => v.Get(1))
.Returns(_indexerDefinition);
return new ReleaseInfo
{
IndexerId = 1
};
}
[Test]
public void should_add_language_from_indexer()
{
var releaseInfo = ReleaseInfoWithLanguages(Language.English, Language.French);
MovieInfo.SimpleReleaseTitle = "A Movie Title 1998 Bluray 1080p MULTI";
var movieInfo = Subject.AugmentMovieInfo(MovieInfo, releaseInfo);
movieInfo.Languages.Count.Should().Be(2);
movieInfo.Languages.Should().BeEquivalentTo(Language.English, Language.French);
}
[Test]
public void should_add_size_info()
{
var releaseInfo = new ReleaseInfo
{
Size = 1500
};
var movieInfo = Subject.AugmentMovieInfo(MovieInfo, releaseInfo);
movieInfo.ExtraInfo["Size"].Should().BeEquivalentTo(1500);
}
[Test]
public void should_not_add_size_when_already_present()
{
var releaseInfo = new ReleaseInfo
{
Size = 1500
};
MovieInfo.ExtraInfo["Size"] = 1600;
var movieInfo = Subject.AugmentMovieInfo(MovieInfo, releaseInfo);
movieInfo.ExtraInfo["Size"].Should().BeEquivalentTo(1600);
}
[Test]
public void should_add_indexer_flags()
{
var releaseInfo = new ReleaseInfo
{
IndexerFlags = IndexerFlags.PTP_Approved | IndexerFlags.PTP_Golden
};
var movieInfo = Subject.AugmentMovieInfo(MovieInfo, releaseInfo);
movieInfo.ExtraInfo["IndexerFlags"].Should().BeEquivalentTo(IndexerFlags.PTP_Approved | IndexerFlags.PTP_Golden);
}
}
}

View File

@@ -194,20 +194,5 @@ namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests
Subject.Map(_umlautInfo, "", _movieSearchCriteria).Movie.Should().Be(_movieSearchCriteria.Movie);
Subject.Map(_umlautAltInfo, "", _movieSearchCriteria).Movie.Should().Be(_movieSearchCriteria.Movie);
}
[Test]
public void should_convert_original()
{
Subject.Map(_multiLanguageInfo, "", _movieSearchCriteria).RemoteMovie.ParsedMovieInfo.Languages.Should().Contain(Language.English);
Subject.Map(_multiLanguageInfo, "", _movieSearchCriteria).RemoteMovie.ParsedMovieInfo.Languages.Should().Contain(Language.French);
}
[Test]
public void should_remove_original_as_already_exists()
{
Subject.Map(_multiLanguageWithOriginalInfo, "", _movieSearchCriteria).RemoteMovie.ParsedMovieInfo.Languages.Should().Contain(Language.English);
Subject.Map(_multiLanguageWithOriginalInfo, "", _movieSearchCriteria).RemoteMovie.ParsedMovieInfo.Languages.Should().Contain(Language.French);
Subject.Map(_multiLanguageWithOriginalInfo, "", _movieSearchCriteria).RemoteMovie.ParsedMovieInfo.Languages.Should().NotContain(Language.Original);
}
}
}

View File

@@ -452,18 +452,6 @@ namespace NzbDrone.Core.Test.ParserTests
result.ResolutionDetectionSource.Should().Be(QualityDetectionSource.Name);
}
[TestCase("Movie.Title.2016.1080p.KORSUB.WEBRip.x264.AAC2.0-RADARR", "KORSUB")]
[TestCase("Movie.Title.2016.1080p.KORSUBS.WEBRip.x264.AAC2.0-RADARR", "KORSUBS")]
[TestCase("Movie Title 2017 HC 720p HDRiP DD5 1 x264-LEGi0N", "Generic Hardcoded Subs")]
[TestCase("Movie.Title.2017.720p.SUBBED.HDRip.V2.XViD-26k.avi", "Generic Hardcoded Subs")]
[TestCase("Movie.Title.2000.1080p.BlueRay.x264.DTS.RoSubbed-playHD", null)]
[TestCase("Movie Title! 2018 [Web][MKV][h264][480p][AAC 2.0][Softsubs]", null)]
[TestCase("Movie Title! 2019 [HorribleSubs][Web][MKV][h264][848x480][AAC 2.0][Softsubs(HorribleSubs)]", null)]
public void should_parse_hardcoded_subs(string postTitle, string sub)
{
QualityParser.ParseQuality(postTitle).HardcodedSubs.Should().Be(sub);
}
[TestCase("Movie Title 2018 REPACK 720p x264 aAF", true)]
[TestCase("Movie.Title.2018.REPACK.720p.x264-aAF", true)]
[TestCase("Movie.Title.2018.PROPER.720p.x264-aAF", false)]

View File

@@ -22,7 +22,7 @@ namespace NzbDrone.Core.Test.Profiles
{
Items = Qualities.QualityFixture.GetDefaultQualities(Quality.Bluray1080p, Quality.DVD, Quality.HDTV720p),
MinFormatScore = 0,
FormatItems = CustomFormatsFixture.GetDefaultFormatItems(),
FormatItems = CustomFormatsTestHelpers.GetDefaultFormatItems(),
Cutoff = Quality.Bluray1080p.Id,
Name = "TestProfile"
};

View File

@@ -170,9 +170,9 @@ namespace NzbDrone.Core.Test.Profiles
var customFormat1 = new CustomFormat("My Format 1", new LanguageSpecification { Value = (int)Language.English }) { Id = 1 };
var customFormat2 = new CustomFormat("My Format 2", new LanguageSpecification { Value = (int)Language.French }) { Id = 2 };
CustomFormatsFixture.GivenCustomFormats(customFormat1, customFormat2);
CustomFormatsTestHelpers.GivenCustomFormats(customFormat1, customFormat2);
profile.FormatItems = CustomFormatsFixture.GetSampleFormatItems(customFormat2.Name);
profile.FormatItems = CustomFormatsTestHelpers.GetSampleFormatItems(customFormat2.Name);
Mocker.GetMock<IProfileRepository>()
.Setup(s => s.Get(It.IsAny<int>()))

View File

@@ -14,28 +14,133 @@ namespace NzbDrone.Core.CustomFormats
{
public interface ICustomFormatCalculationService
{
List<CustomFormat> ParseCustomFormat(ParsedMovieInfo movieInfo, Movie movie);
List<CustomFormat> ParseCustomFormat(RemoteMovie remoteMovie, long size);
List<CustomFormat> ParseCustomFormat(MovieFile movieFile, Movie movie);
List<CustomFormat> ParseCustomFormat(MovieFile movieFile);
List<CustomFormat> ParseCustomFormat(Blocklist blocklist);
List<CustomFormat> ParseCustomFormat(MovieHistory history);
List<CustomFormat> ParseCustomFormat(Blocklist blocklist, Movie movie);
List<CustomFormat> ParseCustomFormat(MovieHistory history, Movie movie);
List<CustomFormat> ParseCustomFormat(LocalMovie localMovie);
}
public class CustomFormatCalculationService : ICustomFormatCalculationService
{
private readonly ICustomFormatService _formatService;
private readonly IParsingService _parsingService;
private readonly IMovieService _movieService;
public CustomFormatCalculationService(ICustomFormatService formatService,
IParsingService parsingService,
IMovieService movieService)
public CustomFormatCalculationService(ICustomFormatService formatService)
{
_formatService = formatService;
_parsingService = parsingService;
_movieService = movieService;
}
public static List<CustomFormat> ParseCustomFormat(ParsedMovieInfo movieInfo, List<CustomFormat> allCustomFormats)
public List<CustomFormat> ParseCustomFormat(RemoteMovie remoteMovie, long size)
{
var input = new CustomFormatInput
{
MovieInfo = remoteMovie.ParsedMovieInfo,
Movie = remoteMovie.Movie,
Size = size,
Languages = remoteMovie.Languages
};
return ParseCustomFormat(input);
}
public List<CustomFormat> ParseCustomFormat(MovieFile movieFile, Movie movie)
{
return ParseCustomFormat(movieFile, movie, _formatService.All());
}
public List<CustomFormat> ParseCustomFormat(MovieFile movieFile)
{
return ParseCustomFormat(movieFile, movieFile.Movie, _formatService.All());
}
public List<CustomFormat> ParseCustomFormat(Blocklist blocklist, Movie movie)
{
var parsed = Parser.Parser.ParseMovieTitle(blocklist.SourceTitle);
var movieInfo = new ParsedMovieInfo
{
MovieTitles = new List<string>() { movie.Title },
SimpleReleaseTitle = parsed?.SimpleReleaseTitle ?? blocklist.SourceTitle.SimplifyReleaseTitle(),
ReleaseTitle = parsed?.ReleaseTitle ?? blocklist.SourceTitle,
Edition = parsed?.Edition,
Quality = blocklist.Quality,
Languages = blocklist.Languages,
ReleaseGroup = parsed?.ReleaseGroup
};
var input = new CustomFormatInput
{
MovieInfo = movieInfo,
Movie = movie,
Size = blocklist.Size ?? 0,
IndexerFlags = blocklist.IndexerFlags,
Languages = blocklist.Languages
};
return ParseCustomFormat(input);
}
public List<CustomFormat> ParseCustomFormat(MovieHistory history, Movie movie)
{
var parsed = Parser.Parser.ParseMovieTitle(history.SourceTitle);
long.TryParse(history.Data.GetValueOrDefault("size"), out var size);
Enum.TryParse(history.Data.GetValueOrDefault("indexerFlags"), true, out IndexerFlags flags);
var movieInfo = new ParsedMovieInfo
{
MovieTitles = new List<string>() { movie.Title },
SimpleReleaseTitle = parsed?.SimpleReleaseTitle ?? history.SourceTitle.SimplifyReleaseTitle(),
ReleaseTitle = parsed?.ReleaseTitle ?? history.SourceTitle,
Edition = parsed?.Edition,
Quality = history.Quality,
Languages = history.Languages,
ReleaseGroup = parsed?.ReleaseGroup,
};
var input = new CustomFormatInput
{
MovieInfo = movieInfo,
Movie = movie,
Size = size,
IndexerFlags = flags,
Languages = history.Languages
};
return ParseCustomFormat(input);
}
public List<CustomFormat> ParseCustomFormat(LocalMovie localMovie)
{
var episodeInfo = new ParsedMovieInfo
{
MovieTitles = new List<string>() { localMovie.Movie.Title },
SimpleReleaseTitle = localMovie.SceneName?.SimplifyReleaseTitle(),
ReleaseTitle = localMovie.SceneName,
Quality = localMovie.Quality,
Edition = localMovie.Edition,
Languages = localMovie.Languages,
ReleaseGroup = localMovie.ReleaseGroup
};
var input = new CustomFormatInput
{
MovieInfo = episodeInfo,
Movie = localMovie.Movie,
Size = localMovie.Size,
Languages = localMovie.Languages
};
return ParseCustomFormat(input);
}
private List<CustomFormat> ParseCustomFormat(CustomFormatInput input)
{
return ParseCustomFormat(input, _formatService.All());
}
private static List<CustomFormat> ParseCustomFormat(CustomFormatInput input, List<CustomFormat> allCustomFormats)
{
var matches = new List<CustomFormat>();
@@ -45,7 +150,7 @@ namespace NzbDrone.Core.CustomFormats
.GroupBy(t => t.GetType())
.Select(g => new SpecificationMatchesGroup
{
Matches = g.ToDictionary(t => t, t => t.IsSatisfiedBy(movieInfo))
Matches = g.ToDictionary(t => t, t => t.IsSatisfiedBy(input))
})
.ToList();
@@ -58,7 +163,7 @@ namespace NzbDrone.Core.CustomFormats
return matches;
}
public static List<CustomFormat> ParseCustomFormat(MovieFile movieFile, List<CustomFormat> allCustomFormats)
private static List<CustomFormat> ParseCustomFormat(MovieFile movieFile, Movie movie, List<CustomFormat> allCustomFormats)
{
var sceneName = string.Empty;
if (movieFile.SceneName.IsNotNullOrWhiteSpace())
@@ -74,90 +179,29 @@ namespace NzbDrone.Core.CustomFormats
sceneName = Path.GetFileName(movieFile.RelativePath);
}
var info = new ParsedMovieInfo
var movieInfo = new ParsedMovieInfo
{
MovieTitles = new List<string>() { movieFile.Movie.MovieMetadata.Value.Title },
MovieTitles = new List<string>() { movie.Title },
SimpleReleaseTitle = sceneName.SimplifyReleaseTitle(),
Quality = movieFile.Quality,
Languages = movieFile.Languages,
ReleaseGroup = movieFile.ReleaseGroup,
Edition = movieFile.Edition,
Year = movieFile.Movie.MovieMetadata.Value.Year,
ImdbId = movieFile.Movie.MovieMetadata.Value.ImdbId,
ExtraInfo = new Dictionary<string, object>
{
{ "IndexerFlags", movieFile.IndexerFlags },
{ "Size", movieFile.Size },
{ "Filename", Path.GetFileName(movieFile.RelativePath) },
{ "OriginalLanguage", movieFile.Movie.MovieMetadata.Value.OriginalLanguage }
}
ImdbId = movieFile.Movie.MovieMetadata.Value.ImdbId
};
return ParseCustomFormat(info, allCustomFormats);
}
public List<CustomFormat> ParseCustomFormat(ParsedMovieInfo movieInfo, Movie movie)
{
movieInfo = _parsingService.EnhanceMovieInfo(movieInfo, new List<object> { movie }) ?? movieInfo;
return ParseCustomFormat(movieInfo, _formatService.All());
}
public List<CustomFormat> ParseCustomFormat(MovieFile movieFile)
{
return ParseCustomFormat(movieFile, _formatService.All());
}
public List<CustomFormat> ParseCustomFormat(Blocklist blocklist)
{
var movie = _movieService.GetMovie(blocklist.MovieId);
var parsed = _parsingService.ParseMovieInfo(blocklist.SourceTitle, null);
var info = new ParsedMovieInfo
var input = new CustomFormatInput
{
MovieTitles = new List<string>() { movie.MovieMetadata.Value.Title },
SimpleReleaseTitle = parsed?.SimpleReleaseTitle ?? blocklist.SourceTitle.SimplifyReleaseTitle(),
Quality = blocklist.Quality,
Languages = blocklist.Languages,
ReleaseGroup = parsed?.ReleaseGroup,
Edition = parsed?.Edition,
Year = movie.MovieMetadata.Value.Year,
ImdbId = movie.MovieMetadata.Value.ImdbId,
ExtraInfo = new Dictionary<string, object>
{
{ "IndexerFlags", blocklist.IndexerFlags },
{ "Size", blocklist.Size }
}
MovieInfo = movieInfo,
Movie = movie,
Size = movieFile.Size,
IndexerFlags = movieFile.IndexerFlags,
Languages = movieFile.Languages,
Filename = Path.GetFileName(movieFile.RelativePath)
};
return ParseCustomFormat(info, movie);
}
public List<CustomFormat> ParseCustomFormat(MovieHistory history)
{
var movie = _movieService.GetMovie(history.MovieId);
var parsed = _parsingService.ParseMovieInfo(history.SourceTitle, null);
Enum.TryParse(history.Data.GetValueOrDefault("indexerFlags"), true, out IndexerFlags flags);
long.TryParse(history.Data.GetValueOrDefault("size"), out var size);
var info = new ParsedMovieInfo
{
MovieTitles = new List<string>() { movie.MovieMetadata.Value.Title },
SimpleReleaseTitle = parsed?.SimpleReleaseTitle ?? history.SourceTitle.SimplifyReleaseTitle(),
Quality = history.Quality,
Languages = history.Languages,
ReleaseGroup = parsed?.ReleaseGroup,
Edition = parsed?.Edition,
Year = movie.MovieMetadata.Value.Year,
ImdbId = movie.MovieMetadata.Value.ImdbId,
ExtraInfo = new Dictionary<string, object>
{
{ "IndexerFlags", flags },
{ "Size", size }
}
};
return ParseCustomFormat(info, movie);
return ParseCustomFormat(input, allCustomFormats);
}
}
}

View File

@@ -0,0 +1,22 @@
using System.Collections.Generic;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.CustomFormats
{
public class CustomFormatInput
{
public ParsedMovieInfo MovieInfo { get; set; }
public Movie Movie { get; set; }
public long Size { get; set; }
public IndexerFlags IndexerFlags { get; set; }
public List<Language> Languages { get; set; }
public string Filename { get; set; }
public CustomFormatInput()
{
Languages = new List<Language>();
}
}
}

View File

@@ -21,9 +21,9 @@ namespace NzbDrone.Core.CustomFormats
public abstract NzbDroneValidationResult Validate();
public bool IsSatisfiedBy(ParsedMovieInfo movieInfo)
public bool IsSatisfiedBy(CustomFormatInput input)
{
var match = IsSatisfiedByWithoutNegate(movieInfo);
var match = IsSatisfiedByWithoutNegate(input);
if (Negate)
{
match = !match;
@@ -32,6 +32,6 @@ namespace NzbDrone.Core.CustomFormats
return match;
}
protected abstract bool IsSatisfiedByWithoutNegate(ParsedMovieInfo movieInfo);
protected abstract bool IsSatisfiedByWithoutNegate(CustomFormatInput input);
}
}

View File

@@ -1,5 +1,3 @@
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.CustomFormats
{
public class EditionSpecification : RegexSpecificationBase
@@ -8,9 +6,9 @@ namespace NzbDrone.Core.CustomFormats
public override string ImplementationName => "Edition";
public override string InfoLink => "https://wiki.servarr.com/radarr/settings#custom-formats-2";
protected override bool IsSatisfiedByWithoutNegate(ParsedMovieInfo movieInfo)
protected override bool IsSatisfiedByWithoutNegate(CustomFormatInput input)
{
return MatchString(movieInfo.Edition);
return MatchString(input.MovieInfo.Edition);
}
}
}

View File

@@ -15,6 +15,6 @@ namespace NzbDrone.Core.CustomFormats
NzbDroneValidationResult Validate();
ICustomFormatSpecification Clone();
bool IsSatisfiedBy(ParsedMovieInfo movieInfo);
bool IsSatisfiedBy(CustomFormatInput input);
}
}

View File

@@ -32,10 +32,9 @@ namespace NzbDrone.Core.CustomFormats
[FieldDefinition(1, Label = "Flag", Type = FieldType.Select, SelectOptions = typeof(IndexerFlags))]
public int Value { get; set; }
protected override bool IsSatisfiedByWithoutNegate(ParsedMovieInfo movieInfo)
protected override bool IsSatisfiedByWithoutNegate(CustomFormatInput input)
{
var flags = movieInfo?.ExtraInfo?.GetValueOrDefault("IndexerFlags") as IndexerFlags?;
return flags?.HasFlag((IndexerFlags)Value) == true;
return input.IndexerFlags.HasFlag((IndexerFlags)Value) == true;
}
public override NzbDroneValidationResult Validate()

View File

@@ -32,12 +32,12 @@ namespace NzbDrone.Core.CustomFormats
[FieldDefinition(1, Label = "Language", Type = FieldType.Select, SelectOptions = typeof(LanguageFieldConverter))]
public int Value { get; set; }
protected override bool IsSatisfiedByWithoutNegate(ParsedMovieInfo movieInfo)
protected override bool IsSatisfiedByWithoutNegate(CustomFormatInput input)
{
var comparedLanguage = movieInfo != null && Value == Language.Original.Id && movieInfo.ExtraInfo.ContainsKey("OriginalLanguage")
? (Language)movieInfo.ExtraInfo["OriginalLanguage"]
var comparedLanguage = input.MovieInfo != null && Value == Language.Original.Id && input.Movie.MovieMetadata.Value.OriginalLanguage != Language.Unknown
? input.Movie.MovieMetadata.Value.OriginalLanguage
: (Language)Value;
return movieInfo?.Languages?.Contains(comparedLanguage) ?? false;
return input?.Languages?.Contains(comparedLanguage) ?? false;
}
public override NzbDroneValidationResult Validate()

View File

@@ -32,9 +32,9 @@ namespace NzbDrone.Core.CustomFormats
[FieldDefinition(1, Label = "Quality Modifier", Type = FieldType.Select, SelectOptions = typeof(Modifier))]
public int Value { get; set; }
protected override bool IsSatisfiedByWithoutNegate(ParsedMovieInfo movieInfo)
protected override bool IsSatisfiedByWithoutNegate(CustomFormatInput input)
{
return (movieInfo?.Quality?.Quality?.Modifier ?? (int)Modifier.NONE) == (Modifier)Value;
return (input.MovieInfo?.Quality?.Quality?.Modifier ?? (int)Modifier.NONE) == (Modifier)Value;
}
public override NzbDroneValidationResult Validate()

View File

@@ -8,9 +8,9 @@ namespace NzbDrone.Core.CustomFormats
public override string ImplementationName => "Release Group";
public override string InfoLink => "https://wiki.servarr.com/radarr/settings#custom-formats-2";
protected override bool IsSatisfiedByWithoutNegate(ParsedMovieInfo movieInfo)
protected override bool IsSatisfiedByWithoutNegate(CustomFormatInput input)
{
return MatchString(movieInfo?.ReleaseGroup);
return MatchString(input.MovieInfo?.ReleaseGroup);
}
}
}

View File

@@ -9,11 +9,9 @@ namespace NzbDrone.Core.CustomFormats
public override string ImplementationName => "Release Title";
public override string InfoLink => "https://wiki.servarr.com/radarr/settings#custom-formats-2";
protected override bool IsSatisfiedByWithoutNegate(ParsedMovieInfo movieInfo)
protected override bool IsSatisfiedByWithoutNegate(CustomFormatInput input)
{
var filename = (string)movieInfo?.ExtraInfo?.GetValueOrDefault("Filename");
return MatchString(movieInfo?.SimpleReleaseTitle) || MatchString(filename);
return MatchString(input.MovieInfo?.SimpleReleaseTitle) || MatchString(input.Filename);
}
}
}

View File

@@ -24,9 +24,9 @@ namespace NzbDrone.Core.CustomFormats
[FieldDefinition(1, Label = "Resolution", Type = FieldType.Select, SelectOptions = typeof(Resolution))]
public int Value { get; set; }
protected override bool IsSatisfiedByWithoutNegate(ParsedMovieInfo movieInfo)
protected override bool IsSatisfiedByWithoutNegate(CustomFormatInput input)
{
return (movieInfo?.Quality?.Quality?.Resolution ?? (int)Resolution.Unknown) == Value;
return (input.MovieInfo?.Quality?.Quality?.Resolution ?? (int)Resolution.Unknown) == Value;
}
public override NzbDroneValidationResult Validate()

View File

@@ -28,9 +28,9 @@ namespace NzbDrone.Core.CustomFormats
[FieldDefinition(1, Label = "Maximum Size", HelpText = "Release must be less than or equal to this size", Unit = "GB", Type = FieldType.Number)]
public double Max { get; set; }
protected override bool IsSatisfiedByWithoutNegate(ParsedMovieInfo movieInfo)
protected override bool IsSatisfiedByWithoutNegate(CustomFormatInput input)
{
var size = (movieInfo?.ExtraInfo?.GetValueOrDefault("Size", 0.0) as long?) ?? 0;
var size = input.Size;
return size > Min.Gigabytes() && size <= Max.Gigabytes();
}

View File

@@ -24,9 +24,9 @@ namespace NzbDrone.Core.CustomFormats
[FieldDefinition(1, Label = "Source", Type = FieldType.Select, SelectOptions = typeof(Source))]
public int Value { get; set; }
protected override bool IsSatisfiedByWithoutNegate(ParsedMovieInfo movieInfo)
protected override bool IsSatisfiedByWithoutNegate(CustomFormatInput input)
{
return (movieInfo?.Quality?.Quality?.Source ?? (int)Source.UNKNOWN) == (Source)Value;
return (input.MovieInfo?.Quality?.Quality?.Source ?? (int)Source.UNKNOWN) == (Source)Value;
}
public override NzbDroneValidationResult Validate()

View File

@@ -8,6 +8,7 @@ using NzbDrone.Common.Serializer;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.Download.Aggregation;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Parser;
@@ -28,18 +29,21 @@ namespace NzbDrone.Core.DecisionEngine
private readonly IParsingService _parsingService;
private readonly IConfigService _configService;
private readonly ICustomFormatCalculationService _formatCalculator;
private readonly IRemoteMovieAggregationService _aggregationService;
private readonly Logger _logger;
public DownloadDecisionMaker(IEnumerable<IDecisionEngineSpecification> specifications,
IParsingService parsingService,
IConfigService configService,
ICustomFormatCalculationService formatCalculator,
IRemoteMovieAggregationService aggregationService,
Logger logger)
{
_specifications = specifications;
_parsingService = parsingService;
_configService = configService;
_formatCalculator = formatCalculator;
_aggregationService = aggregationService;
_logger = logger;
}
@@ -104,11 +108,11 @@ namespace NzbDrone.Core.DecisionEngine
result.ReleaseName = report.Title;
var remoteMovie = result.RemoteMovie;
remoteMovie.CustomFormats = _formatCalculator.ParseCustomFormat(parsedMovieInfo, result?.Movie);
remoteMovie.CustomFormatScore = remoteMovie?.Movie?.Profile?.CalculateCustomFormatScore(remoteMovie.CustomFormats) ?? 0;
remoteMovie.Release = report;
remoteMovie.MappingResult = result.MappingResultType;
_aggregationService.Augment(remoteMovie);
if (result.MappingResultType != MappingResultType.Success)
{
var rejection = result.ToRejection();
@@ -116,33 +120,11 @@ namespace NzbDrone.Core.DecisionEngine
}
else
{
if (parsedMovieInfo.Quality.HardcodedSubs.IsNotNullOrWhiteSpace())
{
// remoteMovie.DownloadAllowed = true;
if (_configService.AllowHardcodedSubs)
{
decision = GetDecisionForReport(remoteMovie, searchCriteria);
}
else
{
var whitelisted = _configService.WhitelistedHardcodedSubs.Split(',');
_logger.Debug("Testing: {0}", whitelisted);
if (whitelisted != null && whitelisted.Any(t => (parsedMovieInfo.Quality.HardcodedSubs.ToLower().Contains(t.ToLower()) && t.IsNotNullOrWhiteSpace())))
{
decision = GetDecisionForReport(remoteMovie, searchCriteria);
}
else
{
decision = new DownloadDecision(remoteMovie, new Rejection("Hardcoded subs found: " + parsedMovieInfo.Quality.HardcodedSubs));
}
}
}
else
{
// _aggregationService.Augment(remoteMovie);
remoteMovie.DownloadAllowed = remoteMovie.Movie != null;
decision = GetDecisionForReport(remoteMovie, searchCriteria);
}
remoteMovie.CustomFormats = _formatCalculator.ParseCustomFormat(remoteMovie, remoteMovie.Release.Size);
remoteMovie.CustomFormatScore = remoteMovie?.Movie?.Profile?.CalculateCustomFormatScore(remoteMovie.CustomFormats) ?? 0;
remoteMovie.DownloadAllowed = remoteMovie.Movie != null;
decision = GetDecisionForReport(remoteMovie, searchCriteria);
}
}
catch (Exception e)

View File

@@ -0,0 +1,47 @@
using System.Linq;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.DecisionEngine.Specifications
{
public class HardcodeSubsSpecification : IDecisionEngineSpecification
{
private readonly IConfigService _configService;
private readonly Logger _logger;
public HardcodeSubsSpecification(IConfigService configService, Logger logger)
{
_configService = configService;
_logger = logger;
}
public SpecificationPriority Priority => SpecificationPriority.Default;
public RejectionType Type => RejectionType.Permanent;
public Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase searchCriteria)
{
var hardcodeSubs = subject.ParsedMovieInfo.HardcodedSubs;
if (_configService.AllowHardcodedSubs || hardcodeSubs.IsNullOrWhiteSpace())
{
return Decision.Accept();
}
var whitelisted = _configService.WhitelistedHardcodedSubs.Split(',');
if (whitelisted != null && whitelisted.Any(t => (hardcodeSubs.ToLower().Contains(t.ToLower()) && t.IsNotNullOrWhiteSpace())))
{
_logger.Debug("Release hardcode subs ({0}) are in allowed values ({1})", hardcodeSubs, whitelisted);
return Decision.Accept();
}
else
{
_logger.Debug("Hardcode subs found: {0}", hardcodeSubs);
return Decision.Reject("Hardcode subs found: {0}", hardcodeSubs);
}
}
}
}

View File

@@ -31,10 +31,10 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
if (wantedLanguage == Language.Original)
{
if (!subject.ParsedMovieInfo.Languages.Contains(originalLanguage))
if (!subject.Languages.Contains(originalLanguage))
{
_logger.Debug("Original Language({0}) is wanted, but found {1}", originalLanguage, subject.ParsedMovieInfo.Languages.ToExtendedString());
return Decision.Reject("Original Language ({0}) is wanted, but found {1}", originalLanguage, subject.ParsedMovieInfo.Languages.ToExtendedString());
_logger.Debug("Original Language({0}) is wanted, but found {1}", originalLanguage, subject.Languages.ToExtendedString());
return Decision.Reject("Original Language ({0}) is wanted, but found {1}", originalLanguage, subject.Languages.ToExtendedString());
}
return Decision.Accept();
@@ -42,10 +42,10 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
_logger.Debug("Checking if report meets language requirements. {0}", subject.ParsedMovieInfo.Languages.ToExtendedString());
if (!subject.ParsedMovieInfo.Languages.Contains(wantedLanguage))
if (!subject.Languages.Contains(wantedLanguage))
{
_logger.Debug("Report Language: {0} rejected because it is not wanted, wanted {1}", subject.ParsedMovieInfo.Languages.ToExtendedString(), wantedLanguage);
return Decision.Reject("{0} is wanted, but found {1}", wantedLanguage, subject.ParsedMovieInfo.Languages.ToExtendedString());
_logger.Debug("Report Language: {0} rejected because it is not wanted, wanted {1}", subject.Languages.ToExtendedString(), wantedLanguage);
return Decision.Reject("{0} is wanted, but found {1}", wantedLanguage, subject.Languages.ToExtendedString());
}
return Decision.Accept();

View File

@@ -50,7 +50,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
continue;
}
var customFormats = _formatService.ParseCustomFormat(remoteMovie.ParsedMovieInfo, subject.Movie);
var customFormats = _formatService.ParseCustomFormat(remoteMovie, (long)queueItem.Size);
_logger.Debug("Checking if existing release in queue meets cutoff. Queued quality is: {0} - {1}",
remoteMovie.ParsedMovieInfo.Quality,

View File

@@ -49,7 +49,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
if (mostRecent != null && mostRecent.EventType == MovieHistoryEventType.Grabbed)
{
var customFormats = _formatService.ParseCustomFormat(mostRecent);
var customFormats = _formatService.ParseCustomFormat(mostRecent, subject.Movie);
var cutoffUnmet = _upgradableSpecification.CutoffNotMet(subject.Movie.Profile,
mostRecent.Quality,

View File

@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NLog;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Download.Aggregation.Aggregators
{
public class AggregateLanguages : IAggregateRemoteMovie
{
private readonly Logger _logger;
public AggregateLanguages(Logger logger)
{
_logger = logger;
}
public RemoteMovie Aggregate(RemoteMovie remoteMovie)
{
var parsedMovieInfo = remoteMovie.ParsedMovieInfo;
var languages = parsedMovieInfo.Languages;
var movie = remoteMovie.Movie;
var releaseTokens = parsedMovieInfo.SimpleReleaseTitle ?? parsedMovieInfo.ReleaseTitle;
var normalizedReleaseTokens = Parser.Parser.NormalizeEpisodeTitle(releaseTokens);
var languagesToRemove = new List<Language>();
if (movie == null)
{
_logger.Debug("Unable to aggregate languages, using parsed values: {0}", string.Join(", ", languages.ToList()));
remoteMovie.Languages = languages;
return remoteMovie;
}
var movieTitleLanguage = LanguageParser.ParseLanguages(movie.Title);
if (!movieTitleLanguage.Contains(Language.Unknown))
{
var normalizedEpisodeTitle = Parser.Parser.NormalizeEpisodeTitle(movie.Title);
var movieTitleIndex = normalizedReleaseTokens.IndexOf(normalizedEpisodeTitle, StringComparison.CurrentCultureIgnoreCase);
if (movieTitleIndex >= 0)
{
releaseTokens = releaseTokens.Remove(movieTitleIndex, normalizedEpisodeTitle.Length);
languagesToRemove.AddRange(movieTitleLanguage);
}
}
// Remove any languages still in the title that would normally be removed
languagesToRemove = languagesToRemove.Except(LanguageParser.ParseLanguages(releaseTokens)).ToList();
// Remove all languages that aren't part of the updated releaseTokens
languages = languages.Except(languagesToRemove).ToList();
// Use movie language as fallback if we couldn't parse a language
if (languages.Count == 0 || (languages.Count == 1 && languages.First() == Language.Unknown))
{
languages = new List<Language> { movie.MovieMetadata.Value.OriginalLanguage };
_logger.Debug("Language couldn't be parsed from release, fallback to movie original language: {0}", movie.MovieMetadata.Value.OriginalLanguage.Name);
}
if (languages.Contains(Language.Original))
{
languages.Remove(Language.Original);
if (!languages.Contains(movie.MovieMetadata.Value.OriginalLanguage))
{
languages.Add(movie.MovieMetadata.Value.OriginalLanguage);
}
else
{
languages.Add(Language.Unknown);
}
}
_logger.Debug("Selected languages: {0}", string.Join(", ", languages.ToList()));
remoteMovie.Languages = languages;
return remoteMovie;
}
}
}

View File

@@ -0,0 +1,9 @@
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Download.Aggregation.Aggregators
{
public interface IAggregateRemoteMovie
{
RemoteMovie Aggregate(RemoteMovie remoteMovie);
}
}

View File

@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using NLog;
using NzbDrone.Core.Download.Aggregation.Aggregators;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Download.Aggregation
{
public interface IRemoteMovieAggregationService
{
RemoteMovie Augment(RemoteMovie remoteMovie);
}
public class RemoteMovieAggregationService : IRemoteMovieAggregationService
{
private readonly IEnumerable<IAggregateRemoteMovie> _augmenters;
private readonly Logger _logger;
public RemoteMovieAggregationService(IEnumerable<IAggregateRemoteMovie> augmenters,
Logger logger)
{
_augmenters = augmenters;
_logger = logger;
}
public RemoteMovie Augment(RemoteMovie remoteMovie)
{
foreach (var augmenter in _augmenters)
{
try
{
augmenter.Aggregate(remoteMovie);
}
catch (Exception ex)
{
_logger.Warn(ex, ex.Message);
}
}
return remoteMovie;
}
}
}

View File

@@ -58,7 +58,7 @@ namespace NzbDrone.Core.Download.Clients.Flood
result.Add(remoteMovie.ParsedMovieInfo.Quality.Quality.ToString());
break;
case (int)AdditionalTags.Languages:
result.UnionWith(remoteMovie.ParsedMovieInfo.Languages.ConvertAll(language => language.ToString()));
result.UnionWith(remoteMovie.Languages.ConvertAll(language => language.ToString()));
break;
case (int)AdditionalTags.ReleaseGroup:
result.Add(remoteMovie.ParsedMovieInfo.ReleaseGroup);

View File

@@ -34,7 +34,7 @@ namespace NzbDrone.Core.Download
var downloadIgnoredEvent = new DownloadIgnoredEvent
{
MovieId = movie.Id,
Languages = trackedDownload.RemoteMovie.ParsedMovieInfo.Languages,
Languages = trackedDownload.RemoteMovie.Languages,
Quality = trackedDownload.RemoteMovie.ParsedMovieInfo.Quality,
SourceTitle = trackedDownload.DownloadItem.Title,
DownloadClientInfo = trackedDownload.DownloadItem.DownloadClientInfo,

View File

@@ -7,6 +7,7 @@ using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download.Aggregation;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Jobs;
using NzbDrone.Core.Languages;
@@ -44,6 +45,7 @@ namespace NzbDrone.Core.Download.Pending
private readonly IDelayProfileService _delayProfileService;
private readonly ITaskManager _taskManager;
private readonly IConfigService _configService;
private readonly IRemoteMovieAggregationService _aggregationService;
private readonly ICustomFormatCalculationService _formatCalculator;
private readonly IEventAggregator _eventAggregator;
private readonly Logger _logger;
@@ -55,6 +57,7 @@ namespace NzbDrone.Core.Download.Pending
IDelayProfileService delayProfileService,
ITaskManager taskManager,
IConfigService configService,
IRemoteMovieAggregationService aggregationService,
ICustomFormatCalculationService formatCalculator,
IEventAggregator eventAggregator,
Logger logger)
@@ -66,6 +69,7 @@ namespace NzbDrone.Core.Download.Pending
_delayProfileService = delayProfileService;
_taskManager = taskManager;
_configService = configService;
_aggregationService = aggregationService;
_formatCalculator = formatCalculator;
_eventAggregator = eventAggregator;
_logger = logger;
@@ -163,8 +167,6 @@ namespace NzbDrone.Core.Download.Pending
{
if (pendingRelease.RemoteMovie != null)
{
pendingRelease.RemoteMovie.CustomFormats = _formatCalculator.ParseCustomFormat(pendingRelease.ParsedMovieInfo, pendingRelease.RemoteMovie.Movie);
var ect = pendingRelease.Release.PublishDate.AddMinutes(GetDelay(pendingRelease.RemoteMovie));
if (ect < nextRssSync.Value)
@@ -188,7 +190,7 @@ namespace NzbDrone.Core.Download.Pending
Id = GetQueueId(pendingRelease, pendingRelease.RemoteMovie.Movie),
Movie = pendingRelease.RemoteMovie.Movie,
Quality = pendingRelease.RemoteMovie.ParsedMovieInfo?.Quality ?? new QualityModel(),
Languages = pendingRelease.RemoteMovie.ParsedMovieInfo?.Languages ?? new List<Language>(),
Languages = pendingRelease.RemoteMovie.Languages,
Title = pendingRelease.Title,
Size = pendingRelease.RemoteMovie.Release.Size,
Sizeleft = pendingRelease.RemoteMovie.Release.Size,
@@ -296,6 +298,9 @@ namespace NzbDrone.Core.Download.Pending
Release = release.Release
};
_aggregationService.Augment(release.RemoteMovie);
release.RemoteMovie.CustomFormats = _formatCalculator.ParseCustomFormat(release.RemoteMovie, release.Release.Size);
result.Add(release);
}

View File

@@ -6,6 +6,7 @@ using NzbDrone.Common.Cache;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.Download.Aggregation;
using NzbDrone.Core.Download.History;
using NzbDrone.Core.History;
using NzbDrone.Core.Messaging.Events;
@@ -32,6 +33,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
private readonly IEventAggregator _eventAggregator;
private readonly IDownloadHistoryService _downloadHistoryService;
private readonly IConfigService _config;
private readonly IRemoteMovieAggregationService _aggregationService;
private readonly ICustomFormatCalculationService _formatCalculator;
private readonly Logger _logger;
private readonly ICached<TrackedDownload> _cache;
@@ -40,6 +42,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
ICacheManager cacheManager,
IHistoryService historyService,
IConfigService config,
IRemoteMovieAggregationService aggregationService,
ICustomFormatCalculationService formatCalculator,
IEventAggregator eventAggregator,
IDownloadHistoryService downloadHistoryService,
@@ -49,6 +52,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
_historyService = historyService;
_cache = cacheManager.GetCache<TrackedDownload>(GetType());
_config = config;
_aggregationService = aggregationService;
_formatCalculator = formatCalculator;
_eventAggregator = eventAggregator;
_downloadHistoryService = downloadHistoryService;
@@ -118,6 +122,8 @@ namespace NzbDrone.Core.Download.TrackedDownloads
if (parsedMovieInfo != null)
{
trackedDownload.RemoteMovie = _parsingService.Map(parsedMovieInfo, "", null).RemoteMovie;
_aggregationService.Augment(trackedDownload.RemoteMovie);
}
var downloadHistory = _downloadHistoryService.GetLatestDownloadHistoryItem(downloadItem.DownloadId);
@@ -151,7 +157,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
// Calculate custom formats
if (trackedDownload.RemoteMovie != null)
{
trackedDownload.RemoteMovie.CustomFormats = _formatCalculator.ParseCustomFormat(parsedMovieInfo, trackedDownload.RemoteMovie.Movie);
trackedDownload.RemoteMovie.CustomFormats = _formatCalculator.ParseCustomFormat(trackedDownload.RemoteMovie, downloadItem.TotalSize);
}
// Track it so it can be displayed in the queue even though we can't determine which movie it is for
@@ -192,6 +198,8 @@ namespace NzbDrone.Core.Download.TrackedDownloads
var parsedMovieInfo = Parser.Parser.ParseMovieTitle(trackedDownload.DownloadItem.Title);
trackedDownload.RemoteMovie = parsedMovieInfo == null ? null : _parsingService.Map(parsedMovieInfo, "", null).RemoteMovie;
_aggregationService.Augment(trackedDownload.RemoteMovie);
}
private static TrackedDownloadState GetStateFromHistory(DownloadHistoryEventType eventType)

View File

@@ -132,7 +132,7 @@ namespace NzbDrone.Core.History
EventType = MovieHistoryEventType.Grabbed,
Date = DateTime.UtcNow,
Quality = message.Movie.ParsedMovieInfo.Quality,
Languages = message.Movie.ParsedMovieInfo.Languages,
Languages = message.Movie.Languages,
SourceTitle = message.Movie.Release.Title,
DownloadId = message.DownloadId,
MovieId = message.Movie.Movie.Id
@@ -203,6 +203,7 @@ namespace NzbDrone.Core.History
history.Data.Add("DownloadClient", message.DownloadClientInfo?.Type);
history.Data.Add("DownloadClientName", message.DownloadClientInfo?.Name);
history.Data.Add("ReleaseGroup", message.MovieInfo.ReleaseGroup);
history.Data.Add("CustomFormatScore", message.MovieInfo.CustomFormatScore.ToString());
_historyRepository.Insert(history);
}

View File

@@ -97,7 +97,7 @@ namespace NzbDrone.Core.Indexers.PassThePopcorn
InfoUrl = GetInfoUrl(result.GroupId, id),
Seeders = int.Parse(torrent.Seeders),
Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders),
PublishDate = torrent.UploadTime.ToUniversalTime(),
PublishDate = TimeZoneInfo.ConvertTimeToUtc(torrent.UploadTime, TimeZoneInfo.Utc), // PTP returns UTC timestamps, without a timezone specifier.
Golden = torrent.GoldenPopcorn,
Scene = torrent.Scene,
Approved = torrent.Checked,

View File

@@ -107,6 +107,7 @@ namespace NzbDrone.Core.Languages
public static Language Bengali => new Language(34, "Bengali");
public static Language Slovak => new Language(35, "Slovak");
public static Language Latvian => new Language(36, "Latvian");
public static Language SpanishLatino => new Language(37, "Spanish (Latino)");
public static Language Any => new Language(-1, "Any");
public static Language Original => new Language(-2, "Original");
@@ -153,6 +154,7 @@ namespace NzbDrone.Core.Languages
Bengali,
Slovak,
Latvian,
SpanishLatino,
Any,
Original
};

View File

@@ -4,6 +4,7 @@ using System.Linq;
using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
using NzbDrone.Core.MediaFiles.MovieImport.Aggregation;
@@ -30,6 +31,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport
private readonly IDiskProvider _diskProvider;
private readonly IDetectSample _detectSample;
private readonly IParsingService _parsingService;
private readonly ICustomFormatCalculationService _formatCalculator;
private readonly Logger _logger;
public ImportDecisionMaker(IEnumerable<IImportDecisionEngineSpecification> specifications,
@@ -38,6 +40,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport
IDiskProvider diskProvider,
IDetectSample detectSample,
IParsingService parsingService,
ICustomFormatCalculationService formatCalculator,
Logger logger)
{
_specifications = specifications;
@@ -46,6 +49,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport
_diskProvider = diskProvider;
_detectSample = detectSample;
_parsingService = parsingService;
_formatCalculator = formatCalculator;
_logger = logger;
}
@@ -75,7 +79,6 @@ namespace NzbDrone.Core.MediaFiles.MovieImport
if (downloadClientItem != null)
{
downloadClientItemInfo = Parser.Parser.ParseMovieTitle(downloadClientItem.Title);
downloadClientItemInfo = _parsingService.EnhanceMovieInfo(downloadClientItemInfo);
}
var nonSampleVideoFileCount = GetNonSampleVideoFileCount(newFiles, movie.MovieMetadata);
@@ -115,11 +118,6 @@ namespace NzbDrone.Core.MediaFiles.MovieImport
var fileMovieInfo = Parser.Parser.ParseMoviePath(localMovie.Path);
if (fileMovieInfo != null)
{
fileMovieInfo = _parsingService.EnhanceMovieInfo(fileMovieInfo);
}
localMovie.FileMovieInfo = fileMovieInfo;
localMovie.Size = _diskProvider.GetFileSize(localMovie.Path);
@@ -133,6 +131,9 @@ namespace NzbDrone.Core.MediaFiles.MovieImport
}
else
{
localMovie.CustomFormats = _formatCalculator.ParseCustomFormat(localMovie);
localMovie.CustomFormatScore = localMovie.Movie.Profile?.CalculateCustomFormatScore(localMovie.CustomFormats) ?? 0;
decision = GetDecision(localMovie, downloadClientItem);
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Movies;
@@ -17,7 +18,13 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual
public List<Language> Languages { get; set; }
public string ReleaseGroup { get; set; }
public string DownloadId { get; set; }
public List<CustomFormat> CustomFormats { get; set; }
public IEnumerable<Rejection> Rejections { get; set; }
public Movie Movie { get; set; }
public ManualImportItem()
{
CustomFormats = new List<CustomFormat>();
}
}
}

View File

@@ -6,6 +6,7 @@ using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
using NzbDrone.Core.Download.TrackedDownloads;
@@ -37,6 +38,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual
private readonly IAggregationService _aggregationService;
private readonly ITrackedDownloadService _trackedDownloadService;
private readonly IDownloadedMovieImportService _downloadedMovieImportService;
private readonly ICustomFormatCalculationService _formatCalculator;
private readonly IEventAggregator _eventAggregator;
private readonly Logger _logger;
@@ -49,6 +51,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual
IImportApprovedMovie importApprovedMovie,
ITrackedDownloadService trackedDownloadService,
IDownloadedMovieImportService downloadedMovieImportService,
ICustomFormatCalculationService formatCalculator,
IEventAggregator eventAggregator,
Logger logger)
{
@@ -61,6 +64,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual
_importApprovedMovie = importApprovedMovie;
_trackedDownloadService = trackedDownloadService;
_downloadedMovieImportService = downloadedMovieImportService;
_formatCalculator = formatCalculator;
_eventAggregator = eventAggregator;
_logger = logger;
}
@@ -156,6 +160,8 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual
if (files.Count() > 100)
{
_logger.Warn("Unable to determine movie from folder name and found more than 100 files. Skipping parsing");
return ProcessDownloadDirectory(rootFolder, files);
}
@@ -289,6 +295,8 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual
if (decision.LocalMovie.Movie != null)
{
item.Movie = decision.LocalMovie.Movie;
item.CustomFormats = _formatCalculator.ParseCustomFormat(decision.LocalMovie);
}
item.Quality = decision.LocalMovie.Quality;
@@ -341,7 +349,10 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual
localMovie.SceneSource = !existingFile;
}
// Augment movie file so imported files have all additional information an automatic import would
localMovie = _aggregationService.Augment(localMovie, trackedDownload?.DownloadItem);
localMovie.CustomFormats = _formatCalculator.ParseCustomFormat(localMovie);
localMovie.CustomFormatScore = localMovie.Movie.Profile?.CalculateCustomFormatScore(localMovie.CustomFormats) ?? 0;
// Apply the user-chosen values.
localMovie.Movie = movie;

View File

@@ -118,6 +118,8 @@ namespace NzbDrone.Core.Notifications.CustomScript
environmentVariables.Add("Radarr_MovieFile_MediaInfo_Subtitles", movieFile.MediaInfo.Subtitles.ConcatToString(" / "));
environmentVariables.Add("Radarr_MovieFile_MediaInfo_VideoCodec", MediaInfoFormatter.FormatVideoCodec(movieFile.MediaInfo, null));
environmentVariables.Add("Radarr_MovieFile_MediaInfo_VideoDynamicRangeType", MediaInfoFormatter.FormatVideoDynamicRangeType(movieFile.MediaInfo));
environmentVariables.Add("Radarr_MovieFile_CustomFormat", string.Join("|", message.MovieInfo.CustomFormats));
environmentVariables.Add("Radarr_MovieFile_CustomFormatScore", message.MovieInfo.CustomFormatScore.ToString());
if (message.OldMovieFiles.Any())
{

View File

@@ -2,6 +2,7 @@ using System.Collections.Generic;
using NzbDrone.Core.Download;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Notifications
{
@@ -9,6 +10,7 @@ namespace NzbDrone.Core.Notifications
{
public string Message { get; set; }
public Movie Movie { get; set; }
public LocalMovie MovieInfo { get; set; }
public MovieFile MovieFile { get; set; }
public List<MovieFile> OldMovieFiles { get; set; }
public string SourcePath { get; set; }

View File

@@ -130,6 +130,7 @@ namespace NzbDrone.Core.Notifications
var downloadMessage = new DownloadMessage
{
Message = GetMessage(message.MovieInfo.Movie, message.MovieInfo.Quality),
MovieInfo = message.MovieInfo,
MovieFile = message.ImportedMovie,
Movie = message.MovieInfo.Movie,
OldMovieFiles = message.OldFiles,

View File

@@ -36,7 +36,8 @@ namespace NzbDrone.Core.Notifications.Webhook
Release = new WebhookRelease(quality, remoteMovie),
DownloadClient = message.DownloadClientName,
DownloadClientType = message.DownloadClientType,
DownloadId = message.DownloadId
DownloadId = message.DownloadId,
CustomFormatInfo = new WebhookCustomFormatInfo(remoteMovie.CustomFormats, remoteMovie.CustomFormatScore)
};
}
@@ -55,7 +56,8 @@ namespace NzbDrone.Core.Notifications.Webhook
IsUpgrade = message.OldMovieFiles.Any(),
DownloadClient = message.DownloadClientInfo?.Name,
DownloadClientType = message.DownloadClientInfo?.Type,
DownloadId = message.DownloadId
DownloadId = message.DownloadId,
CustomFormatInfo = new WebhookCustomFormatInfo(message.MovieInfo.CustomFormats, message.MovieInfo.CustomFormatScore)
};
if (message.OldMovieFiles.Any())

View File

@@ -0,0 +1,18 @@
using System.Text.Json.Serialization;
using NzbDrone.Core.CustomFormats;
namespace NzbDrone.Core.Notifications.Webhook
{
public class WebhookCustomFormat
{
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
public int Id { get; set; }
public string Name { get; set; }
public WebhookCustomFormat(CustomFormat customFormat)
{
Id = customFormat.Id;
Name = customFormat.Name;
}
}
}

View File

@@ -0,0 +1,18 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.CustomFormats;
namespace NzbDrone.Core.Notifications.Webhook
{
public class WebhookCustomFormatInfo
{
public List<WebhookCustomFormat> CustomFormats { get; set; }
public int CustomFormatScore { get; set; }
public WebhookCustomFormatInfo(List<CustomFormat> customFormats, int customFormatScore)
{
CustomFormats = customFormats.Select(c => new WebhookCustomFormat(c)).ToList();
CustomFormatScore = customFormatScore;
}
}
}

View File

@@ -8,5 +8,6 @@ namespace NzbDrone.Core.Notifications.Webhook
public string DownloadClient { get; set; }
public string DownloadClientType { get; set; }
public string DownloadId { get; set; }
public WebhookCustomFormatInfo CustomFormatInfo { get; set; }
}
}

View File

@@ -12,5 +12,6 @@ namespace NzbDrone.Core.Notifications.Webhook
public string DownloadClientType { get; set; }
public string DownloadId { get; set; }
public List<WebhookMovieFile> DeletedFiles { get; set; }
public WebhookCustomFormatInfo CustomFormatInfo { get; set; }
}
}

View File

@@ -35,7 +35,7 @@ namespace NzbDrone.Core.Organizer
private readonly IQualityDefinitionService _qualityDefinitionService;
private readonly IUpdateMediaInfo _mediaInfoUpdater;
private readonly IMovieTranslationService _movieTranslationService;
private readonly ICustomFormatService _formatService;
private readonly ICustomFormatCalculationService _formatCalculator;
private readonly Logger _logger;
private static readonly Regex TitleRegex = new Regex(@"(?<tag>\{(?:imdb-|edition-))?\{(?<prefix>[- ._\[(]*)(?<token>(?:[a-z0-9]+)(?:(?<separator>[- ._]+)(?:[a-z0-9]+))?)(?::(?<customFormat>[a-z0-9|+-]+(?<!-)))?(?<suffix>[-} ._)\]]*)\}",
@@ -83,14 +83,14 @@ namespace NzbDrone.Core.Organizer
IQualityDefinitionService qualityDefinitionService,
IUpdateMediaInfo mediaInfoUpdater,
IMovieTranslationService movieTranslationService,
ICustomFormatService formatService,
ICustomFormatCalculationService formatCalculator,
Logger logger)
{
_namingConfigService = namingConfigService;
_qualityDefinitionService = qualityDefinitionService;
_mediaInfoUpdater = mediaInfoUpdater;
_movieTranslationService = movieTranslationService;
_formatService = formatService;
_formatCalculator = formatCalculator;
_logger = logger;
}
@@ -103,11 +103,12 @@ namespace NzbDrone.Core.Organizer
if (!namingConfig.RenameMovies)
{
return GetOriginalTitle(movieFile);
return GetOriginalTitle(movieFile, false);
}
var pattern = namingConfig.StandardMovieFormat;
var tokenHandlers = new Dictionary<string, Func<TokenMatch, string>>(FileNameBuilderTokenEqualityComparer.Instance);
var multipleTokens = TitleRegex.Matches(pattern).Count > 1;
UpdateMediaInfoIfNeeded(pattern, movieFile, movie);
@@ -116,7 +117,7 @@ namespace NzbDrone.Core.Organizer
AddIdTokens(tokenHandlers, movie);
AddQualityTokens(tokenHandlers, movie, movieFile);
AddMediaInfoTokens(tokenHandlers, movieFile);
AddMovieFileTokens(tokenHandlers, movieFile);
AddMovieFileTokens(tokenHandlers, movieFile, multipleTokens);
AddEditionTagsTokens(tokenHandlers, movieFile);
AddCustomFormats(tokenHandlers, movie, movieFile, customFormats);
@@ -167,6 +168,7 @@ namespace NzbDrone.Core.Organizer
var pattern = namingConfig.MovieFolderFormat;
var tokenHandlers = new Dictionary<string, Func<TokenMatch, string>>(FileNameBuilderTokenEqualityComparer.Instance);
var multipleTokens = TitleRegex.Matches(pattern).Count > 1;
AddMovieTokens(tokenHandlers, movie);
AddReleaseDateTokens(tokenHandlers, movie.Year);
@@ -176,12 +178,12 @@ namespace NzbDrone.Core.Organizer
{
AddQualityTokens(tokenHandlers, movie, movieFile);
AddMediaInfoTokens(tokenHandlers, movieFile);
AddMovieFileTokens(tokenHandlers, movieFile);
AddMovieFileTokens(tokenHandlers, movieFile, multipleTokens);
AddEditionTagsTokens(tokenHandlers, movieFile);
}
else
{
AddMovieFileTokens(tokenHandlers, new MovieFile { SceneName = $"{movie.Title} {movie.Year}", RelativePath = $"{movie.Title} {movie.Year}" });
AddMovieFileTokens(tokenHandlers, new MovieFile { SceneName = $"{movie.Title} {movie.Year}", RelativePath = $"{movie.Title} {movie.Year}" }, multipleTokens);
}
var splitPatterns = pattern.Split(new char[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);
@@ -231,7 +233,7 @@ namespace NzbDrone.Core.Organizer
result = result.Replace(badCharacters[i], replace ? goodCharacters[i] : string.Empty);
}
return result.Trim();
return result.TrimStart(' ', '.').TrimEnd(' ');
}
public static string CleanFolderName(string name)
@@ -306,10 +308,10 @@ namespace NzbDrone.Core.Organizer
tokenHandlers["{TmdbId}"] = m => movie.MovieMetadata.Value.TmdbId.ToString();
}
private void AddMovieFileTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, MovieFile movieFile)
private void AddMovieFileTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, MovieFile movieFile, bool multipleTokens)
{
tokenHandlers["{Original Title}"] = m => GetOriginalTitle(movieFile);
tokenHandlers["{Original Filename}"] = m => GetOriginalFileName(movieFile);
tokenHandlers["{Original Title}"] = m => GetOriginalTitle(movieFile, multipleTokens);
tokenHandlers["{Original Filename}"] = m => GetOriginalFileName(movieFile, multipleTokens);
tokenHandlers["{Release Group}"] = m => movieFile.ReleaseGroup ?? m.DefaultValue("Radarr");
}
@@ -395,7 +397,7 @@ namespace NzbDrone.Core.Organizer
if (customFormats == null)
{
movieFile.Movie = movie;
customFormats = CustomFormatCalculationService.ParseCustomFormat(movieFile, _formatService.All());
customFormats = _formatCalculator.ParseCustomFormat(movieFile, movie);
}
tokenHandlers["{Custom Formats}"] = m => string.Join(" ", customFormats.Where(x => x.IncludeCustomFormatWhenRenaming));
@@ -572,18 +574,23 @@ namespace NzbDrone.Core.Organizer
return string.Empty;
}
private string GetOriginalTitle(MovieFile movieFile)
private string GetOriginalTitle(MovieFile movieFile, bool multipleTokens)
{
if (movieFile.SceneName.IsNullOrWhiteSpace())
{
return GetOriginalFileName(movieFile);
return GetOriginalFileName(movieFile, multipleTokens);
}
return movieFile.SceneName;
}
private string GetOriginalFileName(MovieFile movieFile)
private string GetOriginalFileName(MovieFile movieFile, bool multipleTokens)
{
if (multipleTokens)
{
return string.Empty;
}
if (movieFile.RelativePath.IsNullOrWhiteSpace())
{
return Path.GetFileNameWithoutExtension(movieFile.Path);

View File

@@ -1,26 +0,0 @@
using System;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Parser.Augmenters
{
public class AugmentWithFileSize : IAugmentParsedMovieInfo
{
public Type HelperType
{
get
{
return typeof(LocalMovie);
}
}
public ParsedMovieInfo AugmentMovieInfo(ParsedMovieInfo movieInfo, object helper)
{
if (helper is LocalMovie localMovie && localMovie.Size != 0)
{
movieInfo.ExtraInfo["Size"] = localMovie.Size;
}
return movieInfo;
}
}
}

View File

@@ -1,59 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.History;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Parser.Augmenters
{
public class AugmentWithHistory : IAugmentParsedMovieInfo
{
private readonly IEnumerable<Lazy<IAugmentParsedMovieInfo>> _augmenters;
public AugmentWithHistory(IEnumerable<Lazy<IAugmentParsedMovieInfo>> augmenters)
{
_augmenters = augmenters;
}
public Type HelperType
{
get
{
return typeof(MovieHistory);
}
}
public ParsedMovieInfo AugmentMovieInfo(ParsedMovieInfo movieInfo, object helper)
{
if (helper is MovieHistory history && history.EventType == MovieHistoryEventType.Grabbed)
{
// First we create a release info from history data.
var releaseInfo = new ReleaseInfo();
if (int.TryParse(history.Data.GetValueOrDefault("indexerId"), out var indexerId))
{
releaseInfo.IndexerId = indexerId;
}
if (long.TryParse(history.Data.GetValueOrDefault("size"), out var size))
{
releaseInfo.Size = size;
}
if (Enum.TryParse(history.Data.GetValueOrDefault("indexerFlags"), true, out IndexerFlags indexerFlags))
{
releaseInfo.IndexerFlags = indexerFlags;
}
// Now we run the release info augmenters from the history release info. TODO: Add setting to only do that if you trust your indexer!
var releaseInfoAugmenters = _augmenters.Where(a => a.Value.HelperType.IsInstanceOfType(releaseInfo));
foreach (var augmenter in releaseInfoAugmenters)
{
movieInfo = augmenter.Value.AugmentMovieInfo(movieInfo, releaseInfo);
}
}
return movieInfo;
}
}
}

View File

@@ -1,58 +0,0 @@
using System;
using NzbDrone.Core.MediaFiles.MediaInfo;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities;
namespace NzbDrone.Core.Parser.Augmenters
{
public class AugmentWithMediaInfo : IAugmentParsedMovieInfo
{
public Type HelperType
{
get
{
return typeof(MediaInfoModel);
}
}
public ParsedMovieInfo AugmentMovieInfo(ParsedMovieInfo movieInfo, object helper)
{
if (helper is MediaInfoModel mediaInfo)
{
var quality = movieInfo.Quality;
if (!(quality.Quality.Modifier == Modifier.BRDISK || quality.Quality.Modifier == Modifier.REMUX) &&
(quality.Quality.Source == Source.BLURAY || quality.Quality.Source == Source.TV ||
quality.Quality.Source == Source.WEBDL) &&
!(quality.Quality.Resolution == (int)Resolution.R480p || quality.Quality.Resolution == (int)Resolution.R576p))
{
var width = mediaInfo.Width;
var existing = quality.Quality.Resolution;
if (width > 854)
{
quality.Quality.Resolution = (int)Resolution.R720p;
}
if (width > 1280)
{
quality.Quality.Resolution = (int)Resolution.R1080p;
}
if (width > 1920)
{
quality.Quality.Resolution = (int)Resolution.R2160p;
}
if (existing != quality.Quality.Resolution)
{
// _logger.Debug("Overwriting resolution info {0} with info from media info {1}", existing, quality.Resolution);
quality.ResolutionDetectionSource = QualityDetectionSource.MediaInfo;
movieInfo.Quality = quality;
}
}
}
return movieInfo;
}
}
}

View File

@@ -1,27 +0,0 @@
using System;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Parser.Augmenters
{
public class AugmentWithOriginalLanguage : IAugmentParsedMovieInfo
{
public Type HelperType
{
get
{
return typeof(Movie);
}
}
public ParsedMovieInfo AugmentMovieInfo(ParsedMovieInfo movieInfo, object helper)
{
if (helper is Movie movie && movie?.MovieMetadata.Value.OriginalLanguage != null && movieInfo != null)
{
movieInfo.ExtraInfo["OriginalLanguage"] = movie.MovieMetadata.Value.OriginalLanguage;
}
return movieInfo;
}
}
}

View File

@@ -1,42 +0,0 @@
using System;
using System.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Parser.Augmenters
{
public class AugmentWithParsedMovieInfo : IAugmentParsedMovieInfo
{
public Type HelperType
{
get
{
return typeof(ParsedMovieInfo);
}
}
public ParsedMovieInfo AugmentMovieInfo(ParsedMovieInfo movieInfo, object helper)
{
if (helper is ParsedMovieInfo otherInfo)
{
// Create union of all languages
if (otherInfo.Languages != null)
{
movieInfo.Languages = movieInfo.Languages.Union(otherInfo.Languages).Distinct().ToList();
}
if ((otherInfo.Edition?.Length ?? 0) > (movieInfo.Edition?.Length ?? 0))
{
movieInfo.Edition = otherInfo.Edition;
}
if (otherInfo.ReleaseGroup.IsNotNullOrWhiteSpace() && movieInfo.ReleaseGroup.IsNullOrWhiteSpace())
{
movieInfo.ReleaseGroup = otherInfo.ReleaseGroup;
}
}
return movieInfo;
}
}
}

View File

@@ -1,69 +0,0 @@
using System;
using System.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Parser.Augmenters
{
public class AugmentWithReleaseInfo : IAugmentParsedMovieInfo
{
private readonly Lazy<IIndexerFactory> _indexerFactory;
public AugmentWithReleaseInfo(Lazy<IIndexerFactory> indexerFactory)
{
_indexerFactory = indexerFactory;
}
public Type HelperType
{
get
{
return typeof(ReleaseInfo);
}
}
public ParsedMovieInfo AugmentMovieInfo(ParsedMovieInfo movieInfo, object helper)
{
if (helper is ReleaseInfo releaseInfo)
{
IIndexerSettings indexerSettings = null;
try
{
indexerSettings = _indexerFactory.Value.Get(releaseInfo.IndexerId)?.Settings as IIndexerSettings;
}
catch (Exception)
{
// _logger.Debug("Indexer with id {0} does not exist, skipping minimum seeder checks.", subject.Release.IndexerId);
} // First, let's augment the language!
var languageTitle = movieInfo.SimpleReleaseTitle;
if (movieInfo.PrimaryMovieTitle.IsNotNullOrWhiteSpace())
{
if (languageTitle.ToLower().Contains("multi") && indexerSettings?.MultiLanguages?.Any() == true)
{
foreach (var i in indexerSettings.MultiLanguages)
{
var language = (Language)i;
if (!movieInfo.Languages.Contains(language))
{
movieInfo.Languages.Add(language);
}
}
}
}
// Next, let's add other useful info to the extra info dict
if (!movieInfo.ExtraInfo.ContainsKey("Size"))
{
movieInfo.ExtraInfo["Size"] = releaseInfo.Size;
}
movieInfo.ExtraInfo["IndexerFlags"] = releaseInfo.IndexerFlags;
}
return movieInfo;
}
}
}

View File

@@ -1,12 +0,0 @@
using System;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Parser.Augmenters
{
public interface IAugmentParsedMovieInfo
{
Type HelperType { get; }
ParsedMovieInfo AugmentMovieInfo(ParsedMovieInfo movieInfo, object helper);
}
}

View File

@@ -44,7 +44,8 @@ namespace NzbDrone.Core.Parser
new IsoLanguage("be", "", "ben", "Bengali", Language.Bengali),
new IsoLanguage("lt", "", "lit", "Lithuanian", Language.Lithuanian),
new IsoLanguage("sk", "", "slk", "Slovak", Language.Slovak),
new IsoLanguage("lv", "", "lav", "Latvian", Language.Latvian)
new IsoLanguage("lv", "", "lav", "Latvian", Language.Latvian),
new IsoLanguage("es", "mx", "spa", "Spanish (Latino)", Language.SpanishLatino)
};
public static IsoLanguage Find(string isoCode)

View File

@@ -197,6 +197,11 @@ namespace NzbDrone.Core.Parser
languages.Add(Language.Latvian);
}
if (lowerTitle.Contains("latino"))
{
languages.Add(Language.SpanishLatino);
}
// Case sensitive
var caseSensitiveMatchs = CaseSensitiveLanguageRegex.Matches(title);

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.Languages;
using NzbDrone.Core.MediaFiles.MediaInfo;
using NzbDrone.Core.Movies;
@@ -10,6 +11,7 @@ namespace NzbDrone.Core.Parser.Model
{
public LocalMovie()
{
CustomFormats = new List<CustomFormat>();
}
public string Path { get; set; }
@@ -27,6 +29,8 @@ namespace NzbDrone.Core.Parser.Model
public string Edition { get; set; }
public string SceneName { get; set; }
public bool OtherVideoFiles { get; set; }
public List<CustomFormat> CustomFormats { get; set; }
public int CustomFormatScore { get; set; }
public override string ToString()
{

View File

@@ -25,8 +25,7 @@ namespace NzbDrone.Core.Parser.Model
public int Year { get; set; }
public string ImdbId { get; set; }
public int TmdbId { get; set; }
[JsonIgnore]
public Dictionary<string, object> ExtraInfo { get; set; } = new Dictionary<string, object>();
public string HardcodedSubs { get; set; }
public string MovieTitle => PrimaryMovieTitle;

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.Download.Clients;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Movies;
namespace NzbDrone.Core.Parser.Model
@@ -15,6 +16,13 @@ namespace NzbDrone.Core.Parser.Model
public MappingResultType MappingResult { get; set; }
public bool DownloadAllowed { get; set; }
public TorrentSeedConfiguration SeedConfiguration { get; set; }
public List<Language> Languages { get; set; }
public RemoteMovie()
{
CustomFormats = new List<CustomFormat>();
Languages = new List<Language>();
}
public override string ToString()
{

View File

@@ -18,6 +18,9 @@ namespace NzbDrone.Core.Parser
private static readonly Regex ReportEditionRegex = new Regex(@"^.+?" + EditionRegex, RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex HardcodedSubsRegex = new Regex(@"\b((?<hcsub>(\w+(?<!SOFT|HORRIBLE)SUBS?))|(?<hc>(HC|SUBBED)))\b",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
private static readonly RegexReplace[] PreSubstitutionRegex = Array.Empty<RegexReplace>();
private static readonly Regex[] ReportMovieTitleRegex = new[]
@@ -144,7 +147,7 @@ namespace NzbDrone.Core.Parser
private static readonly Regex AnimeReleaseGroupRegex = new Regex(@"^(?:\[(?<subgroup>(?!\s).+?(?<!\s))\](?:_|-|\s|\.)?)",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex YearInTitleRegex = new Regex(@"^(?<title>.+?)(?:\W|_)?(?<year>\d{4})",
private static readonly Regex YearInTitleRegex = new Regex(@"^(?<title>.+?)(?:\W|_.)?[\(\[]?(?<year>\d{4})[\]\)]?",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
// Handle Exception Release Groups that don't follow -RlsGrp; Manual List
@@ -295,6 +298,8 @@ namespace NzbDrone.Core.Parser
result.ReleaseGroup = subGroup;
}
result.HardcodedSubs = ParseHardcodeSubs(title);
Logger.Debug("Release Group parsed: {0}", result.ReleaseGroup);
result.Languages = LanguageParser.ParseLanguages(result.ReleaseGroup.IsNotNullOrWhiteSpace() ? simpleReleaseTitle.Replace(result.ReleaseGroup, "RlsGrp") : simpleReleaseTitle);
@@ -491,6 +496,25 @@ namespace NzbDrone.Core.Parser
return SimpleReleaseTitleRegex.Replace(title, string.Empty);
}
public static string ParseHardcodeSubs(string title)
{
var subMatch = HardcodedSubsRegex.Matches(title).OfType<Match>().LastOrDefault();
if (subMatch != null && subMatch.Success)
{
if (subMatch.Groups["hcsub"].Success)
{
return subMatch.Groups["hcsub"].Value;
}
else if (subMatch.Groups["hc"].Success)
{
return "Generic Hardcoded Subs";
}
}
return null;
}
public static string ParseReleaseGroup(string title)
{
title = title.Trim();

View File

@@ -6,7 +6,6 @@ using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Parser.Augmenters;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Parser.RomanNumerals;
@@ -17,7 +16,6 @@ namespace NzbDrone.Core.Parser
Movie GetMovie(string title);
MappingResult Map(ParsedMovieInfo parsedMovieInfo, string imdbId, SearchCriteriaBase searchCriteria = null);
ParsedMovieInfo ParseMovieInfo(string title, List<object> helpers);
ParsedMovieInfo EnhanceMovieInfo(ParsedMovieInfo parsedMovieInfo, List<object> helpers = null);
ParsedMovieInfo ParseMinimalMovieInfo(string path, bool isDir = false);
ParsedMovieInfo ParseMinimalPathMovieInfo(string path);
}
@@ -27,15 +25,12 @@ namespace NzbDrone.Core.Parser
private static HashSet<ArabicRomanNumeral> _arabicRomanNumeralMappings;
private readonly IMovieService _movieService;
private readonly IEnumerable<IAugmentParsedMovieInfo> _augmenters;
private readonly Logger _logger;
public ParsingService(IMovieService movieService,
IEnumerable<IAugmentParsedMovieInfo> augmenters,
Logger logger)
{
_movieService = movieService;
_augmenters = augmenters;
_logger = logger;
if (_arabicRomanNumeralMappings == null)
@@ -53,27 +48,9 @@ namespace NzbDrone.Core.Parser
return null;
}
result = EnhanceMovieInfo(result, helpers);
return result;
}
public ParsedMovieInfo EnhanceMovieInfo(ParsedMovieInfo minimalInfo, List<object> helpers = null)
{
if (helpers != null)
{
var augmenters = _augmenters.Where(a => helpers.Any(t => a.HelperType.IsInstanceOfType(t)) || a.HelperType == null);
foreach (var augmenter in augmenters)
{
minimalInfo = augmenter.AugmentMovieInfo(minimalInfo,
helpers.FirstOrDefault(h => augmenter.HelperType.IsInstanceOfType(h)));
}
}
return minimalInfo;
}
public ParsedMovieInfo ParseMinimalMovieInfo(string file, bool isDir = false)
{
return Parser.ParseMovieTitle(file, isDir);
@@ -127,27 +104,6 @@ namespace NzbDrone.Core.Parser
result.Movie = null;
}
// Use movie language as fallback if we could't parse a language (more accurate than just using English)
if (parsedMovieInfo.Languages.Count <= 1 && parsedMovieInfo.Languages.First() == Language.Unknown && result.Movie != null)
{
parsedMovieInfo.Languages = new List<Language> { result.Movie.MovieMetadata.Value.OriginalLanguage };
_logger.Debug("Language couldn't be parsed from release, fallback to movie original language: {0}", result.Movie.MovieMetadata.Value.OriginalLanguage.Name);
}
if (parsedMovieInfo.Languages.Contains(Language.Original))
{
parsedMovieInfo.Languages.Remove(Language.Original);
if (result.Movie != null && !parsedMovieInfo.Languages.Contains(result.Movie.MovieMetadata.Value.OriginalLanguage))
{
parsedMovieInfo.Languages.Add(result.Movie.MovieMetadata.Value.OriginalLanguage);
}
else
{
parsedMovieInfo.Languages.Add(Language.Unknown);
}
}
result.RemoteMovie.ParsedMovieInfo = parsedMovieInfo;
return result;

View File

@@ -75,9 +75,6 @@ namespace NzbDrone.Core.Parser
private static readonly Regex RemuxRegex = new Regex(@"(?:[_. \[]|\d{4}p-)(?<remux>(?:(BD|UHD)[-_. ]?)?Remux)\b|(?<remux>(?:(BD|UHD)[-_. ]?)?Remux[_. ]\d{4}p)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex HardcodedSubsRegex = new Regex(@"\b((?<hcsub>(\w+(?<!SOFT|HORRIBLE)SUBS?))|(?<hc>(HC|SUBBED)))\b",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
public static QualityModel ParseQuality(string name)
{
Logger.Debug("Trying to parse quality for {0}", name);
@@ -110,19 +107,6 @@ namespace NzbDrone.Core.Parser
{
var normalizedName = name.Replace('_', ' ').Trim();
var result = ParseQualityModifiers(name, normalizedName);
var subMatch = HardcodedSubsRegex.Matches(normalizedName).OfType<Match>().LastOrDefault();
if (subMatch != null && subMatch.Success)
{
if (subMatch.Groups["hcsub"].Success)
{
result.HardcodedSubs = subMatch.Groups["hcsub"].Value;
}
else if (subMatch.Groups["hc"].Success)
{
result.HardcodedSubs = "Generic Hardcoded Subs";
}
}
var sourceMatches = SourceRegex.Matches(normalizedName);
var sourceMatch = sourceMatches.OfType<Match>().LastOrDefault();

View File

@@ -10,8 +10,6 @@ namespace NzbDrone.Core.Qualities
public Revision Revision { get; set; }
public string HardcodedSubs { get; set; }
[JsonIgnore]
public QualityDetectionSource SourceDetectionSource { get; set; }

View File

@@ -56,6 +56,7 @@ namespace NzbDrone.Host
private void OnAppStarted()
{
_runtimeInfo.IsStarting = false;
_runtimeInfo.IsExiting = false;
if (!_startupContext.Flags.Contains(StartupContext.NO_BROWSER)

View File

@@ -264,6 +264,7 @@ namespace NzbDrone.Host
app.UseMiddleware<VersionMiddleware>();
app.UseMiddleware<UrlBaseMiddleware>(configFileProvider.UrlBase);
app.UseMiddleware<StartingUpMiddleware>();
app.UseMiddleware<CacheHeaderMiddleware>();
app.UseMiddleware<IfModifiedMiddleware>();
app.UseMiddleware<BufferingMiddleware>(new List<string> { "/api/v3/command" });

Some files were not shown because too many files have changed in this diff Show More