mirror of
https://github.com/Readarr/Readarr
synced 2026-05-08 12:42:51 +02:00
New: Detect audio vs text from newznab categories
This commit is contained in:
parent
065f03a01a
commit
3abda061ba
9 changed files with 72 additions and 10 deletions
|
|
@ -11,6 +11,7 @@
|
||||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
using NzbDrone.Core.Parser;
|
using NzbDrone.Core.Parser;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
using NzbDrone.Core.Qualities;
|
||||||
using NzbDrone.Core.Test.Framework;
|
using NzbDrone.Core.Test.Framework;
|
||||||
using NzbDrone.Test.Common;
|
using NzbDrone.Test.Common;
|
||||||
|
|
||||||
|
|
@ -60,7 +61,8 @@ public void Setup()
|
||||||
_remoteBook = new RemoteBook
|
_remoteBook = new RemoteBook
|
||||||
{
|
{
|
||||||
Author = new Author(),
|
Author = new Author(),
|
||||||
Books = new List<Book> { new Book() }
|
Books = new List<Book> { new Book() },
|
||||||
|
ParsedBookInfo = Builder<ParsedBookInfo>.CreateNew().With(x => x.Quality = new QualityModel(Quality.FLAC)).Build()
|
||||||
};
|
};
|
||||||
|
|
||||||
Mocker.GetMock<IParsingService>()
|
Mocker.GetMock<IParsingService>()
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ public void init_should_add_default_profiles()
|
||||||
Subject.Handle(new ApplicationStartedEvent());
|
Subject.Handle(new ApplicationStartedEvent());
|
||||||
|
|
||||||
Mocker.GetMock<IProfileRepository>()
|
Mocker.GetMock<IProfileRepository>()
|
||||||
.Verify(v => v.Insert(It.IsAny<QualityProfile>()), Times.Exactly(4));
|
.Verify(v => v.Insert(It.IsAny<QualityProfile>()), Times.Exactly(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
using NzbDrone.Core.Parser;
|
using NzbDrone.Core.Parser;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
using NzbDrone.Core.Qualities;
|
||||||
|
|
||||||
namespace NzbDrone.Core.DecisionEngine
|
namespace NzbDrone.Core.DecisionEngine
|
||||||
{
|
{
|
||||||
|
|
@ -105,6 +106,12 @@ private IEnumerable<DownloadDecision> GetBookDecisions(List<ReleaseInfo> reports
|
||||||
|
|
||||||
remoteBook.Release = report;
|
remoteBook.Release = report;
|
||||||
|
|
||||||
|
// parse quality again with title and category if unknown
|
||||||
|
if (remoteBook.ParsedBookInfo.Quality.Quality == Quality.Unknown)
|
||||||
|
{
|
||||||
|
remoteBook.ParsedBookInfo.Quality = QualityParser.ParseQuality(report.Title, null, report.Categories);
|
||||||
|
}
|
||||||
|
|
||||||
if (remoteBook.Author == null)
|
if (remoteBook.Author == null)
|
||||||
{
|
{
|
||||||
decision = new DownloadDecision(remoteBook, new Rejection("Unknown Author"));
|
decision = new DownloadDecision(remoteBook, new Rejection("Unknown Author"));
|
||||||
|
|
@ -138,7 +145,7 @@ private IEnumerable<DownloadDecision> GetBookDecisions(List<ReleaseInfo> reports
|
||||||
{
|
{
|
||||||
parsedBookInfo = new ParsedBookInfo
|
parsedBookInfo = new ParsedBookInfo
|
||||||
{
|
{
|
||||||
Quality = QualityParser.ParseQuality(report.Title)
|
Quality = QualityParser.ParseQuality(report.Title, null, report.Categories)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,7 +167,7 @@ private IEnumerable<DownloadDecision> GetBookDecisions(List<ReleaseInfo> reports
|
||||||
{
|
{
|
||||||
parsedBookInfo = new ParsedBookInfo
|
parsedBookInfo = new ParsedBookInfo
|
||||||
{
|
{
|
||||||
Quality = QualityParser.ParseQuality(report.Title, null)
|
Quality = QualityParser.ParseQuality(report.Title, null, report.Categories)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,25 @@ protected override DateTime GetPublishDate(XElement item)
|
||||||
return base.GetPublishDate(item);
|
return base.GetPublishDate(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override List<int> GetCategories(XElement item)
|
||||||
|
{
|
||||||
|
var values = item.Elements(ns + "attr")
|
||||||
|
.Where(e => e.Attribute("name").Value.Equals("category", StringComparison.OrdinalIgnoreCase) &&
|
||||||
|
e.Attribute("value")?.Value != null)
|
||||||
|
.Select(e => e.Attribute("value").Value);
|
||||||
|
|
||||||
|
var cats = new List<int>();
|
||||||
|
foreach (var value in values)
|
||||||
|
{
|
||||||
|
if (int.TryParse(value, out var cat))
|
||||||
|
{
|
||||||
|
cats.Add(cat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cats;
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual string GetAuthor(XElement item)
|
protected virtual string GetAuthor(XElement item)
|
||||||
{
|
{
|
||||||
var authorString = TryGetNewznabAttribute(item, "author");
|
var authorString = TryGetNewznabAttribute(item, "author");
|
||||||
|
|
|
||||||
|
|
@ -159,6 +159,7 @@ protected virtual ReleaseInfo ProcessItem(XElement item, ReleaseInfo releaseInfo
|
||||||
releaseInfo.BasicAuthString = GetBasicAuth();
|
releaseInfo.BasicAuthString = GetBasicAuth();
|
||||||
releaseInfo.InfoUrl = GetInfoUrl(item);
|
releaseInfo.InfoUrl = GetInfoUrl(item);
|
||||||
releaseInfo.CommentUrl = GetCommentUrl(item);
|
releaseInfo.CommentUrl = GetCommentUrl(item);
|
||||||
|
releaseInfo.Categories = GetCategories(item);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -230,6 +231,11 @@ protected virtual string GetCommentUrl(XElement item)
|
||||||
return ParseUrl((string)item.Element("comments"));
|
return ParseUrl((string)item.Element("comments"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual List<int> GetCategories(XElement item)
|
||||||
|
{
|
||||||
|
return new List<int>();
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual long GetSize(XElement item)
|
protected virtual long GetSize(XElement item)
|
||||||
{
|
{
|
||||||
if (UseEnclosureLength)
|
if (UseEnclosureLength)
|
||||||
|
|
|
||||||
|
|
@ -91,9 +91,23 @@ protected override long GetSize(XElement item)
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DateTime GetPublishDate(XElement item)
|
protected override List<int> GetCategories(XElement item)
|
||||||
{
|
{
|
||||||
return base.GetPublishDate(item);
|
var values = item.Elements(ns + "attr")
|
||||||
|
.Where(e => e.Attribute("name").Value.Equals("category", StringComparison.OrdinalIgnoreCase) &&
|
||||||
|
e.Attribute("value")?.Value != null)
|
||||||
|
.Select(e => e.Attribute("value").Value);
|
||||||
|
|
||||||
|
var cats = new List<int>();
|
||||||
|
foreach (var value in values)
|
||||||
|
{
|
||||||
|
if (int.TryParse(value, out var cat))
|
||||||
|
{
|
||||||
|
cats.Add(cat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cats;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string GetDownloadUrl(XElement item)
|
protected override string GetDownloadUrl(XElement item)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
|
|
||||||
|
|
@ -25,7 +26,7 @@ public class ReleaseInfo
|
||||||
public string Source { get; set; }
|
public string Source { get; set; }
|
||||||
public string Container { get; set; }
|
public string Container { get; set; }
|
||||||
public string Codec { get; set; }
|
public string Codec { get; set; }
|
||||||
public string Resolution { get; set; }
|
public List<int> Categories { get; set; }
|
||||||
|
|
||||||
public int Age
|
public int Age
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
|
|
@ -29,7 +31,7 @@ public class QualityParser
|
||||||
private static readonly Regex CodecRegex = new Regex(@"\b(?:(?<PDF>PDF)|(?<MOBI>MOBI)|(?<EPUB>EPUB)|(?<AZW3>AZW3?)|(?<MP1>MPEG Version \d(.5)? Audio, Layer 1|MP1)|(?<MP2>MPEG Version \d(.5)? Audio, Layer 2|MP2)|(?<MP3VBR>MP3.*VBR|MPEG Version \d(.5)? Audio, Layer 3 vbr)|(?<MP3CBR>MP3|MPEG Version \d(.5)? Audio, Layer 3)|(?<FLAC>flac)|(?<WAVPACK>wavpack|wv)|(?<ALAC>alac)|(?<WMA>WMA\d?)|(?<WAV>WAV|PCM)|(?<AAC>M4A|M4P|M4B|AAC|mp4a|MPEG-4 Audio(?!.*alac))|(?<OGG>OGG|OGA|Vorbis))\b|(?<APE>monkey's audio|[\[|\(].*\bape\b.*[\]|\)])|(?<OPUS>Opus Version \d(.5)? Audio|[\[|\(].*\bopus\b.*[\]|\)])",
|
private static readonly Regex CodecRegex = new Regex(@"\b(?:(?<PDF>PDF)|(?<MOBI>MOBI)|(?<EPUB>EPUB)|(?<AZW3>AZW3?)|(?<MP1>MPEG Version \d(.5)? Audio, Layer 1|MP1)|(?<MP2>MPEG Version \d(.5)? Audio, Layer 2|MP2)|(?<MP3VBR>MP3.*VBR|MPEG Version \d(.5)? Audio, Layer 3 vbr)|(?<MP3CBR>MP3|MPEG Version \d(.5)? Audio, Layer 3)|(?<FLAC>flac)|(?<WAVPACK>wavpack|wv)|(?<ALAC>alac)|(?<WMA>WMA\d?)|(?<WAV>WAV|PCM)|(?<AAC>M4A|M4P|M4B|AAC|mp4a|MPEG-4 Audio(?!.*alac))|(?<OGG>OGG|OGA|Vorbis))\b|(?<APE>monkey's audio|[\[|\(].*\bape\b.*[\]|\)])|(?<OPUS>Opus Version \d(.5)? Audio|[\[|\(].*\bopus\b.*[\]|\)])",
|
||||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
public static QualityModel ParseQuality(string name, string desc = null)
|
public static QualityModel ParseQuality(string name, string desc = null, List<int> categories = null)
|
||||||
{
|
{
|
||||||
Logger.Debug("Trying to parse quality for {0}", name);
|
Logger.Debug("Trying to parse quality for {0}", name);
|
||||||
|
|
||||||
|
|
@ -107,6 +109,16 @@ public static QualityModel ParseQuality(string name, string desc = null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Based on category
|
||||||
|
if (result.Quality == Quality.Unknown && categories != null)
|
||||||
|
{
|
||||||
|
if (categories.Any(x => x >= 3000 && x < 4000))
|
||||||
|
{
|
||||||
|
result.Quality = Quality.UnknownAudio;
|
||||||
|
result.QualityDetectionSource = QualityDetectionSource.Category;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
namespace NzbDrone.Core.Qualities
|
namespace NzbDrone.Core.Qualities
|
||||||
{
|
{
|
||||||
public enum QualityDetectionSource
|
public enum QualityDetectionSource
|
||||||
{
|
{
|
||||||
Name,
|
Name,
|
||||||
Extension,
|
Extension,
|
||||||
TagLib
|
TagLib,
|
||||||
|
Category
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue