initial stage of indexer refactoring. things compile.

This commit is contained in:
kay.one 2011-05-19 20:47:07 -07:00
parent 7d7b37be5b
commit 9c1ff4af6b
21 changed files with 249 additions and 348 deletions

View File

@ -145,7 +145,7 @@
<virtualDirectory path="/" physicalPath="%NZBDRONE_PATH%\NZBDrone.Web" /> <virtualDirectory path="/" physicalPath="%NZBDRONE_PATH%\NZBDrone.Web" />
</application> </application>
<bindings> <bindings>
<binding protocol="http" bindingInformation="*:8989:" /> <binding protocol="http" bindingInformation="*:8980:" />
</bindings> </bindings>
</site> </site>
<siteDefaults> <siteDefaults>

View File

@ -58,6 +58,9 @@ namespace NzbDrone.Core.Test
var series = Builder<Series>.CreateNew().Build(); var series = Builder<Series>.CreateNew().Build();
series.QualityProfileId = profileId; series.QualityProfileId = profileId;
repo.Add(testProfile);
repo.Add(series);
var result = repo.All<Series>(); var result = repo.All<Series>();
Assert.Count(1, result); Assert.Count(1, result);

View File

@ -1,7 +1,10 @@
using System.Linq; using System;
using System.Linq;
using AutoMoq; using AutoMoq;
using MbUnit.Framework; using MbUnit.Framework;
using Moq;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using SubSonic.Repository; using SubSonic.Repository;
@ -113,5 +116,30 @@ namespace NzbDrone.Core.Test
Assert.AreEqual(1, rootDir.Id); Assert.AreEqual(1, rootDir.Id);
Assert.AreEqual(path, rootDir.Path); Assert.AreEqual(path, rootDir.Path);
} }
[Test]
public void None_existing_folder_returns_empty_list()
{
const string path = "d:\\bad folder";
var mocker = new AutoMoqer();
mocker.GetMock<DiskProvider>(MockBehavior.Strict)
.Setup(m => m.FolderExists(path)).Returns(false);
var result = mocker.Resolve<RootDirProvider>().GetUnmappedFolders(path);
Assert.IsNotNull(result);
Assert.IsEmpty(result);
mocker.VerifyAllMocks();
}
[Test]
[ExpectedException(typeof(ArgumentException))]
public void empty_folder_path_throws()
{
var mocker = new AutoMoqer();
mocker.Resolve<RootDirProvider>().GetUnmappedFolders("");
}
} }
} }

View File

@ -12,29 +12,6 @@ namespace NzbDrone.Core.Test
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
public class SyncProviderTest : TestBase public class SyncProviderTest : TestBase
{ {
[Test]
public void None_existing_folder_returns_empty_list()
{
const string path = "d:\\bad folder";
var mocker = new AutoMoqer();
mocker.GetMock<DiskProvider>(MockBehavior.Strict)
.Setup(m => m.FolderExists(path)).Returns(false);
var result = mocker.Resolve<SyncProvider>().GetUnmappedFolders(path);
Assert.IsNotNull(result);
Assert.IsEmpty(result);
mocker.VerifyAllMocks();
}
[Test]
[ExpectedException(typeof (ArgumentException))]
public void empty_folder_path_throws()
{
var mocker = new AutoMoqer();
mocker.Resolve<SyncProvider>().GetUnmappedFolders("");
}
} }
} }

View File

@ -7,11 +7,9 @@ namespace NzbDrone.Core.Model
public class EpisodeParseResult public class EpisodeParseResult
{ {
internal string CleanTitle { get; set; } internal string CleanTitle { get; set; }
public int SeriesId { get; set; }
public string FolderName { get; set; }
internal int SeasonNumber { get; set; } internal int SeasonNumber { get; set; }
internal List<int> Episodes { get; set; } internal List<int> Episodes { get; set; }
internal string EpisodeTitle { get; set; } internal string EpisodeTitle { get; set; }

View File

@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Core.Model
{
public enum IndexerType
{
Unknown = 0,
NzbsOrg = 1,
NzbMatrix = 2,
NzbsRus = 3,
Newzbin = 4
}
}

View File

@ -168,11 +168,11 @@
<Compile Include="Instrumentation\NlogWriter.cs" /> <Compile Include="Instrumentation\NlogWriter.cs" />
<Compile Include="Model\ConnectionInfoModel.cs" /> <Compile Include="Model\ConnectionInfoModel.cs" />
<Compile Include="Model\ExternalNotificationType.cs" /> <Compile Include="Model\ExternalNotificationType.cs" />
<Compile Include="Model\IndexerType.cs" />
<Compile Include="Model\LanguageType.cs" /> <Compile Include="Model\LanguageType.cs" />
<Compile Include="Model\SabnzbdInfoModel.cs" /> <Compile Include="Model\SabnzbdInfoModel.cs" />
<Compile Include="Providers\ExternalNotification\ExternalNotificationProviderBase.cs" /> <Compile Include="Providers\ExternalNotification\ExternalNotificationProviderBase.cs" />
<Compile Include="Providers\ExternalNotification\XbmcNotificationProvider.cs" /> <Compile Include="Providers\ExternalNotification\XbmcNotificationProvider.cs" />
<Compile Include="Providers\Indexer\IsNeededProvider.cs" />
<Compile Include="Providers\Indexer\SyndicationFeedXmlReader.cs" /> <Compile Include="Providers\Indexer\SyndicationFeedXmlReader.cs" />
<Compile Include="Providers\AutoConfigureProvider.cs" /> <Compile Include="Providers\AutoConfigureProvider.cs" />
<Compile Include="Providers\Indexer\NzbMatrixProvider.cs" /> <Compile Include="Providers\Indexer\NzbMatrixProvider.cs" />

View File

@ -27,6 +27,11 @@ namespace NzbDrone.Core.Providers
{ {
} }
public virtual int AddEpisode(Episode episode)
{
return (Int32)_repository.Add(episode);
}
public virtual Episode GetEpisode(long id) public virtual Episode GetEpisode(long id)
{ {
return _repository.Single<Episode>(id); return _repository.Single<Episode>(id);
@ -56,16 +61,6 @@ namespace NzbDrone.Core.Providers
return _repository.Find<Episode>(e => e.SeasonId == seasonId); return _repository.Find<Episode>(e => e.SeasonId == seasonId);
} }
public virtual IList<Episode> GetEpisodeByParseResult(EpisodeParseResult parseResult)
{
var seasonEpisodes = _repository.All<Episode>().Where(e =>
e.SeriesId == parseResult.SeriesId &&
e.SeasonNumber == parseResult.SeasonNumber).ToList();
//Has to be done separately since subsonic doesn't support contain method
return seasonEpisodes.Where(c => parseResult.Episodes.Contains(c.EpisodeNumber)).ToList();
}
public virtual IList<Episode> EpisodesWithoutFiles(bool includeSpecials) public virtual IList<Episode> EpisodesWithoutFiles(bool includeSpecials)
{ {
@ -80,73 +75,41 @@ namespace NzbDrone.Core.Providers
/// </summary> /// </summary>
/// <param name = "parsedReport">Episode that needs to be checked</param> /// <param name = "parsedReport">Episode that needs to be checked</param>
/// <returns></returns> /// <returns></returns>
public virtual bool IsNeeded(EpisodeParseResult parsedReport) public virtual bool IsNeeded(EpisodeParseResult parsedReport, Episode episodeInfo)
{ {
//Todo: Fix this so it properly handles multi-epsiode releases (Currently as long as the first episode is needed we download it) var file = episodeInfo.EpisodeFile;
//Todo: for small releases this is less of an issue, but for Full Season Releases this could be an issue if we only need the first episode (or first few)
foreach (var episode in parsedReport.Episodes) if (file != null)
{ {
var episodeInfo = GetEpisode(parsedReport.SeriesId, parsedReport.SeasonNumber, episode); Logger.Debug("Existing file is {0} proper:{1}", file.Quality, file.Proper);
if (episodeInfo == null) //There will never be a time when the episode quality is less than what we have and we want it... ever.... I think.
if (file.Quality > parsedReport.Quality)
{ {
Logger.Debug("Episode S{0:00}E{1:00} doesn't exist in db. adding it now.", parsedReport.SeasonNumber, episode); Logger.Trace("file has better quality. skipping");
//Todo: How do we want to handle this really? Episode could be released before information is on TheTvDB return false;
//(Parks and Rec did this a lot in the first season, from experience)
//Keivan: Should automatically add the episode to db with minimal information. then update the description/title when available.
//Mark: Perhaps we should only add the epsiode if its the latest season, sometimes people name things completely wrong (duh!)
episodeInfo = new Episode
{
SeriesId = parsedReport.SeriesId,
AirDate = DateTime.Now.Date,
EpisodeNumber = episode,
SeasonNumber = parsedReport.SeasonNumber,
Title = String.Empty,
Overview = String.Empty,
Language = "en"
};
_repository.Add(episodeInfo);
} }
var file = episodeInfo.EpisodeFile; //If not null we need to see if this episode has the quality as the download (or if it is better)
if (file.Quality == parsedReport.Quality && file.Proper == parsedReport.Proper)
if (file != null)
{ {
Logger.Debug("File is {0} Proper:{1}", file.Quality, file.Proper); Logger.Trace("Same quality/proper. existing proper. skipping");
return false;
//There will never be a time when the episode quality is less than what we have and we want it... ever.... I think.
if (file.Quality > parsedReport.Quality)
{
Logger.Trace("file has better quality. skipping");
continue;
}
//If not null we need to see if this episode has the quality as the download (or if it is better)
if (file.Quality == parsedReport.Quality && file.Proper == parsedReport.Proper)
{
Logger.Trace("Same quality/proper. existing proper. skipping");
continue;
}
//Now we need to handle upgrades and actually pay attention to the Cut-off Value
if (file.Quality < parsedReport.Quality)
{
if (episodeInfo.Series.QualityProfile.Cutoff <= file.Quality)
{
Logger.Trace("Quality is past cut-off skipping.");
continue;
}
}
} }
Logger.Debug("Episode {0} is needed", parsedReport); //Now we need to handle upgrades and actually pay attention to the Cut-off Value
return true; //If we get to this point and the file has not yet been rejected then accept it if (file.Quality < parsedReport.Quality)
{
if (episodeInfo.Series.QualityProfile.Cutoff <= file.Quality)
{
Logger.Trace("Quality is past cut-off skipping.");
return false;
}
}
} }
Logger.Debug("Episode {0} is not needed", parsedReport); Logger.Debug("Episode {0} is needed", parsedReport);
return false; return true; //If we get to this point and the file has not yet been rejected then accept it
} }
public virtual void RefreshEpisodeInfo(int seriesId) public virtual void RefreshEpisodeInfo(int seriesId)

View File

@ -50,8 +50,10 @@ namespace NzbDrone.Core.Providers
{ {
//Looks for the existence of this episode in History //Looks for the existence of this episode in History
if (_repository.Exists<History>(h => h.EpisodeId == episodeId && h.Quality == quality && h.IsProper == proper)) if (_repository.Exists<History>(h => h.EpisodeId == episodeId && h.Quality == quality && h.IsProper == proper))
{
Logger.Debug("Episode in History. ID:{0} Q:{1} Proper:{2}", episodeId, quality, proper);
return true; return true;
}
Logger.Debug("Episode not in History. ID:{0} Q:{1} Proper:{2}", episodeId, quality, proper); Logger.Debug("Episode not in History. ID:{0} Q:{1} Proper:{2}", episodeId, quality, proper);
return false; return false;
} }

View File

@ -1,14 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Net; using System.Net;
using System.ServiceModel.Syndication; using System.ServiceModel.Syndication;
using System.Linq;
using NLog; using NLog;
using NzbDrone.Core.Helpers;
using NzbDrone.Core.Model; using NzbDrone.Core.Model;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Providers.ExternalNotification;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Providers.Indexer namespace NzbDrone.Core.Providers.Indexer
@ -16,33 +12,16 @@ namespace NzbDrone.Core.Providers.Indexer
public abstract class IndexerProviderBase public abstract class IndexerProviderBase
{ {
protected readonly Logger _logger; protected readonly Logger _logger;
protected readonly ConfigProvider _configProvider;
protected readonly EpisodeProvider _episodeProvider;
private readonly HttpProvider _httpProvider; private readonly HttpProvider _httpProvider;
protected readonly ConfigProvider _configProvider;
private readonly IndexerProvider _indexerProvider; private readonly IndexerProvider _indexerProvider;
private readonly HistoryProvider _historyProvider;
protected readonly SeasonProvider _seasonProvider;
protected readonly SeriesProvider _seriesProvider;
protected readonly SabProvider _sabProvider;
protected readonly IEnumerable<ExternalNotificationProviderBase> _externalNotificationProvider;
protected IndexerProviderBase(SeriesProvider seriesProvider, SeasonProvider seasonProvider, protected IndexerProviderBase(HttpProvider httpProvider, ConfigProvider configProvider, IndexerProvider indexerProvider)
EpisodeProvider episodeProvider, ConfigProvider configProvider,
HttpProvider httpProvider, IndexerProvider indexerProvider,
HistoryProvider historyProvider, SabProvider sabProvider,
IEnumerable<ExternalNotificationProviderBase> externalNotificationProvider)
{ {
_seriesProvider = seriesProvider;
_seasonProvider = seasonProvider;
_episodeProvider = episodeProvider;
_configProvider = configProvider;
_httpProvider = httpProvider; _httpProvider = httpProvider;
_configProvider = configProvider;
_indexerProvider = indexerProvider; _indexerProvider = indexerProvider;
_historyProvider = historyProvider;
_sabProvider = sabProvider;
//Todo: IEnumerable yields no results for some reason, yet yields results in other classes
_externalNotificationProvider = externalNotificationProvider;
_logger = LogManager.GetLogger(GetType().ToString()); _logger = LogManager.GetLogger(GetType().ToString());
} }
@ -51,11 +30,6 @@ namespace NzbDrone.Core.Providers.Indexer
/// </summary> /// </summary>
public abstract string Name { get; } public abstract string Name { get; }
/// <summary>
/// Gets a bool to determine if Backlog Searching is Supported
/// </summary>
public abstract bool SupportsBacklog { get; }
/// <summary> /// <summary>
/// Gets the source URL for the feed /// Gets the source URL for the feed
/// </summary> /// </summary>
@ -80,10 +54,11 @@ namespace NzbDrone.Core.Providers.Indexer
/// <summary> /// <summary>
/// Fetches RSS feed and process each news item. /// Fetches RSS feed and process each news item.
/// </summary> /// </summary>
public List<Exception> Fetch() public List<EpisodeParseResult> Fetch()
{ {
_logger.Debug("Fetching feeds from " + Settings.Name); _logger.Debug("Fetching feeds from " + Settings.Name);
var exeptions = new List<Exception>();
var result = new List<EpisodeParseResult>();
foreach (var url in Urls) foreach (var url in Urls)
{ {
@ -98,11 +73,14 @@ namespace NzbDrone.Core.Providers.Indexer
{ {
try try
{ {
ProcessItem(item); var parsedEpisode = ParseFeed(item);
if (parsedEpisode != null)
{
result.Add(parsedEpisode);
}
} }
catch (Exception itemEx) catch (Exception itemEx)
{ {
exeptions.Add(itemEx);
_logger.ErrorException("An error occurred while processing feed item", itemEx); _logger.ErrorException("An error occurred while processing feed item", itemEx);
} }
@ -110,123 +88,24 @@ namespace NzbDrone.Core.Providers.Indexer
} }
catch (Exception feedEx) catch (Exception feedEx)
{ {
exeptions.Add(feedEx);
_logger.ErrorException("An error occurred while processing feed", feedEx); _logger.ErrorException("An error occurred while processing feed", feedEx);
} }
} }
_logger.Info("Finished processing feeds from " + Settings.Name); _logger.Info("Finished processing feeds from " + Settings.Name);
return exeptions; return result;
}
internal void ProcessItem(SyndicationItem feedItem)
{
_logger.Debug("Processing RSS feed item " + feedItem.Title.Text);
var parseResult = ParseFeed(feedItem);
if (parseResult != null && parseResult.SeriesId != 0)
{
if (!_seriesProvider.IsMonitored(parseResult.SeriesId))
{
_logger.Debug("{0} is present in the DB but not tracked. skipping.", parseResult.CleanTitle);
return;
}
if (!_seriesProvider.QualityWanted(parseResult.SeriesId, parseResult.Quality))
{
_logger.Debug("Post doesn't meet the quality requirements [{0}]. skipping.", parseResult.Quality);
return;
}
if (_seasonProvider.IsIgnored(parseResult.SeriesId, parseResult.SeasonNumber))
{
_logger.Debug("Season {0} is currently set to ignore. skipping.", parseResult.SeasonNumber);
return;
}
//Todo: How to handle full season files? Currently the episode list is completely empty for these releases
//Todo: Should we assume that the release contains all the episodes that belong to this season and add them from the DB?
if (!_episodeProvider.IsNeeded(parseResult))
{
_logger.Debug("Episode {0} is not needed. skipping.", parseResult);
return;
}
var episodes = _episodeProvider.GetEpisodeByParseResult(parseResult);
if (InHistory(episodes, parseResult, feedItem))
{
return;
}
parseResult.EpisodeTitle = episodes[0].Title;
var sabTitle = _sabProvider.GetSabTitle(parseResult);
if (_sabProvider.IsInQueue(sabTitle))
{
return;
}
if (!_sabProvider.AddByUrl(NzbDownloadUrl(feedItem), sabTitle))
{
_logger.Warn("Unable to add item to SAB queue. {0} {1}", NzbDownloadUrl(feedItem), sabTitle);
return;
}
foreach (var episode in episodes)
{
_historyProvider.Add(new History
{
Date = DateTime.Now,
EpisodeId = episode.EpisodeId,
IsProper = parseResult.Proper,
NzbTitle = feedItem.Title.Text,
Quality = parseResult.Quality,
Indexer = Name
});
}
//Notify!
foreach (var notification in _externalNotificationProvider.Where(n => n.Settings.Enabled))
{
notification.OnGrab(sabTitle);
}
}
} }
/// <summary> /// <summary>
/// Parses the RSS feed item and. /// Parses the RSS feed item
/// </summary> /// </summary>
/// <param name = "item">RSS feed item to parse</param> /// <param name = "item">RSS feed item to parse</param>
/// <returns>Detailed episode info</returns> /// <returns>Detailed episode info</returns>
public EpisodeParseResult ParseFeed(SyndicationItem item) public EpisodeParseResult ParseFeed(SyndicationItem item)
{ {
var episodeParseResult = Parser.ParseEpisodeInfo(item.Title.Text); var episodeParseResult = Parser.ParseEpisodeInfo(item.Title.Text);
if (episodeParseResult == null) return null;
var seriesInfo = _seriesProvider.FindSeries(episodeParseResult.CleanTitle); return CustomParser(item, episodeParseResult);
if (seriesInfo == null)
{
var seriesId = SceneNameHelper.FindByName(episodeParseResult.CleanTitle);
if (seriesId != 0)
seriesInfo = _seriesProvider.GetSeries(seriesId);
}
if (seriesInfo != null)
{
episodeParseResult.SeriesId = seriesInfo.SeriesId;
episodeParseResult.FolderName = new DirectoryInfo(seriesInfo.Path).Name; ;
episodeParseResult.CleanTitle = seriesInfo.Title;
return CustomParser(item, episodeParseResult);
}
_logger.Debug("Unable to map {0} to any of series in database", episodeParseResult.CleanTitle);
return null;
} }
/// <summary> /// <summary>
@ -246,18 +125,5 @@ namespace NzbDrone.Core.Providers.Indexer
/// <param name = "item">RSS Feed item to generate the link for</param> /// <param name = "item">RSS Feed item to generate the link for</param>
/// <returns>Download link URL</returns> /// <returns>Download link URL</returns>
protected abstract string NzbDownloadUrl(SyndicationItem item); protected abstract string NzbDownloadUrl(SyndicationItem item);
private bool InHistory(IList<Episode> episodes, EpisodeParseResult parseResult, SyndicationItem feedItem)
{
foreach (var episode in episodes)
{
if (_historyProvider.Exists(episode.EpisodeId, parseResult.Quality, parseResult.Proper))
{
_logger.Debug("Episode in history: {0}", feedItem.Title.Text);
return true;
}
}
return false;
}
} }
} }

View File

@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using NLog;
using NzbDrone.Core.Helpers;
using NzbDrone.Core.Model;
using NzbDrone.Core.Repository;
using System.ServiceModel.Syndication;
namespace NzbDrone.Core.Providers.Indexer
{
public class IsNeededProvider
{
private readonly SeriesProvider _seriesProvider;
private readonly SeasonProvider _seasonProvider;
private readonly EpisodeProvider _episodeProvider;
private readonly HistoryProvider _historyProvider;
private readonly SabProvider _sabProvider;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public IsNeededProvider(SeriesProvider seriesProvider, SeasonProvider seasonProvider, EpisodeProvider episodeProvider, HistoryProvider historyProvider, SabProvider sabProvider)
{
_seriesProvider = seriesProvider;
_seasonProvider = seasonProvider;
_episodeProvider = episodeProvider;
_historyProvider = historyProvider;
_sabProvider = sabProvider;
}
internal bool IsNeeded(EpisodeParseResult parseResult, Series series)
{
foreach (var episodeNumber in parseResult.Episodes)
{
//Todo: How to handle full season files? Currently the episode list is completely empty for these releases
//Todo: Should we assume that the release contains all the episodes that belong to this season and add them from the DB?
//Todo: Fix this so it properly handles multi-epsiode releases (Currently as long as the first episode is needed we download it)
//Todo: for small releases this is less of an issue, but for Full Season Releases this could be an issue if we only need the first episode (or first few)
if (!series.Monitored)
{
Logger.Debug("{0} is present in the DB but not tracked. skipping.", parseResult.CleanTitle);
return false;
}
if (!_seriesProvider.QualityWanted(series.SeriesId, parseResult.Quality))
{
Logger.Debug("Post doesn't meet the quality requirements [{0}]. skipping.", parseResult.Quality);
return false;
}
if (_seasonProvider.IsIgnored(series.SeriesId, parseResult.SeasonNumber))
{
Logger.Debug("Season {0} is currently set to ignore. skipping.", parseResult.SeasonNumber);
return false;
}
var episodeInfo = _episodeProvider.GetEpisode(series.SeriesId, parseResult.SeasonNumber, episodeNumber);
if (episodeInfo == null)
{
episodeInfo = _episodeProvider.GetEpisode(series.SeriesId, parseResult.AirDate);
}
//if still null we should add the temp episode
if (episodeInfo == null)
{
Logger.Debug("Episode {0} doesn't exist in db. adding it now.", parseResult);
episodeInfo = new Episode
{
SeriesId = series.SeriesId,
AirDate = DateTime.Now.Date,
EpisodeNumber = episodeNumber,
SeasonNumber = parseResult.SeasonNumber,
Title = parseResult.EpisodeTitle,
Overview = String.Empty,
Language = "en"
};
_episodeProvider.AddEpisode(episodeInfo);
}
if (!_episodeProvider.IsNeeded(parseResult, episodeInfo))
{
Logger.Debug("Episode {0} is not needed. skipping.", parseResult);
return false;
}
if (_historyProvider.Exists(episodeInfo.EpisodeId, parseResult.Quality, parseResult.Proper))
{
Logger.Debug("Episode {0} is in history. skipping.", parseResult);
return false;
}
parseResult.EpisodeTitle = episodeInfo.Title;
var sabTitle = _sabProvider.GetSabTitle(parseResult, new DirectoryInfo(series.Path).Name);
if (_sabProvider.IsInQueue(sabTitle))
{
Logger.Debug("Episode {0} is already in sab's queue. skipping.", parseResult);
return false;
}
//Congragulations younge feed item! you have made it this far. you are truly special!!!
return true;
}
return false;
}
}
}

View File

@ -9,13 +9,7 @@ namespace NzbDrone.Core.Providers.Indexer
{ {
public class NewzbinProvider : IndexerProviderBase public class NewzbinProvider : IndexerProviderBase
{ {
public NewzbinProvider(SeriesProvider seriesProvider, SeasonProvider seasonProvider, public NewzbinProvider(HttpProvider httpProvider, ConfigProvider configProvider, IndexerProvider indexerProvider) : base(httpProvider, configProvider, indexerProvider)
EpisodeProvider episodeProvider, ConfigProvider configProvider,
HttpProvider httpProvider, IndexerProvider indexerProvider,
HistoryProvider historyProvider, SabProvider sabProvider, IEnumerable<ExternalNotificationProviderBase> externalNotificationProvider)
: base(seriesProvider, seasonProvider, episodeProvider,
configProvider, httpProvider, indexerProvider, historyProvider,
sabProvider, externalNotificationProvider)
{ {
} }
@ -40,11 +34,6 @@ namespace NzbDrone.Core.Providers.Indexer
get { return "Newzbin"; } get { return "Newzbin"; }
} }
public override bool SupportsBacklog
{
get { return false; }
}
protected override string NzbDownloadUrl(SyndicationItem item) protected override string NzbDownloadUrl(SyndicationItem item)
{ {
return item.Id + "/nzb"; return item.Id + "/nzb";

View File

@ -11,13 +11,7 @@ namespace NzbDrone.Core.Providers.Indexer
{ {
public class NzbMatrixProvider : IndexerProviderBase public class NzbMatrixProvider : IndexerProviderBase
{ {
public NzbMatrixProvider(SeriesProvider seriesProvider, SeasonProvider seasonProvider, public NzbMatrixProvider(HttpProvider httpProvider, ConfigProvider configProvider, IndexerProvider indexerProvider) : base(httpProvider, configProvider, indexerProvider)
EpisodeProvider episodeProvider, ConfigProvider configProvider,
HttpProvider httpProvider, IndexerProvider indexerProvider,
HistoryProvider historyProvider, SabProvider sabProvider, IEnumerable<ExternalNotificationProviderBase> externalNotificationProvider)
: base(seriesProvider, seasonProvider, episodeProvider,
configProvider, httpProvider, indexerProvider, historyProvider,
sabProvider, externalNotificationProvider)
{ {
} }
@ -40,10 +34,6 @@ namespace NzbDrone.Core.Providers.Indexer
get { return "NzbMatrix"; } get { return "NzbMatrix"; }
} }
public override bool SupportsBacklog
{
get { return true; }
}
protected override string NzbDownloadUrl(SyndicationItem item) protected override string NzbDownloadUrl(SyndicationItem item)
{ {

View File

@ -10,13 +10,7 @@ namespace NzbDrone.Core.Providers.Indexer
{ {
public class NzbsOrgProvider : IndexerProviderBase public class NzbsOrgProvider : IndexerProviderBase
{ {
public NzbsOrgProvider(SeriesProvider seriesProvider, SeasonProvider seasonProvider, public NzbsOrgProvider(HttpProvider httpProvider, ConfigProvider configProvider, IndexerProvider indexerProvider) : base(httpProvider, configProvider, indexerProvider)
EpisodeProvider episodeProvider, ConfigProvider configProvider,
HttpProvider httpProvider, IndexerProvider indexerProvider,
HistoryProvider historyProvider, SabProvider sabProvider, IEnumerable<ExternalNotificationProviderBase> externalNotificationProvider)
: base(seriesProvider, seasonProvider, episodeProvider,
configProvider, httpProvider, indexerProvider, historyProvider,
sabProvider, externalNotificationProvider)
{ {
} }
@ -36,10 +30,6 @@ namespace NzbDrone.Core.Providers.Indexer
get { return "Nzbs.org"; } get { return "Nzbs.org"; }
} }
public override bool SupportsBacklog
{
get { return false; }
}
protected override string NzbDownloadUrl(SyndicationItem item) protected override string NzbDownloadUrl(SyndicationItem item)
{ {

View File

@ -10,13 +10,7 @@ namespace NzbDrone.Core.Providers.Indexer
{ {
public class NzbsRUsProvider : IndexerProviderBase public class NzbsRUsProvider : IndexerProviderBase
{ {
public NzbsRUsProvider(SeriesProvider seriesProvider, SeasonProvider seasonProvider, public NzbsRUsProvider(HttpProvider httpProvider, ConfigProvider configProvider, IndexerProvider indexerProvider) : base(httpProvider, configProvider, indexerProvider)
EpisodeProvider episodeProvider, ConfigProvider configProvider,
HttpProvider httpProvider, IndexerProvider indexerProvider,
HistoryProvider historyProvider, SabProvider sabProvider, IEnumerable<ExternalNotificationProviderBase> externalNotificationProvider)
: base(seriesProvider, seasonProvider, episodeProvider,
configProvider, httpProvider, indexerProvider, historyProvider,
sabProvider, externalNotificationProvider)
{ {
} }
@ -39,12 +33,7 @@ namespace NzbDrone.Core.Providers.Indexer
get { return "NzbsRUs"; } get { return "NzbsRUs"; }
} }
public override bool SupportsBacklog protected override string NzbDownloadUrl(SyndicationItem item)
{
get { return false; }
}
protected override string NzbDownloadUrl(SyndicationItem item)
{ {
return item.Links[0].Uri.ToString(); return item.Links[0].Uri.ToString();
} }

View File

@ -1,6 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using NLog;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
using SubSonic.Repository; using SubSonic.Repository;
@ -9,10 +12,16 @@ namespace NzbDrone.Core.Providers
public class RootDirProvider public class RootDirProvider
{ {
private readonly IRepository _sonioRepo; private readonly IRepository _sonioRepo;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly DiskProvider _diskProvider;
private readonly SeriesProvider _seriesProvider;
public RootDirProvider(IRepository sonicRepo)
public RootDirProvider(IRepository sonicRepo, SeriesProvider seriesProvider, DiskProvider diskProvider)
{ {
_sonioRepo = sonicRepo; _sonioRepo = sonicRepo;
_diskProvider = diskProvider;
_seriesProvider = seriesProvider;
} }
#region IRootDirProvider #region IRootDirProvider
@ -42,6 +51,33 @@ namespace NzbDrone.Core.Providers
return _sonioRepo.Single<RootDir>(rootDirId); return _sonioRepo.Single<RootDir>(rootDirId);
} }
public List<String> GetUnmappedFolders(string path)
{
Logger.Debug("Generating list of unmapped folders");
if (String.IsNullOrEmpty(path))
throw new ArgumentException("Invalid path provided", "path");
var results = new List<String>();
if (!_diskProvider.FolderExists(path))
{
Logger.Debug("Path supplied does not exist: {0}", path);
return results;
}
foreach (string seriesFolder in _diskProvider.GetDirectories(path))
{
var cleanPath = Parser.NormalizePath(new DirectoryInfo(seriesFolder).FullName);
if (!_seriesProvider.SeriesPathExists(cleanPath))
results.Add(cleanPath);
}
Logger.Debug("{0} unmapped folders detected.", results.Count);
return results;
}
#endregion #endregion
} }
} }

View File

@ -92,7 +92,7 @@ namespace NzbDrone.Core.Providers
_configProvider.SabPassword); _configProvider.SabPassword);
} }
public String GetSabTitle(EpisodeParseResult parseResult) public String GetSabTitle(EpisodeParseResult parseResult, String folderName)
{ {
//Show Name - 1x01-1x02 - Episode Name //Show Name - 1x01-1x02 - Episode Name
//Show Name - 1x01 - Episode Name //Show Name - 1x01 - Episode Name
@ -105,7 +105,7 @@ namespace NzbDrone.Core.Providers
var epNumberString = String.Join("-", episodeString); var epNumberString = String.Join("-", episodeString);
var result = String.Format("{0} - {1} - {2} [{3}]", parseResult.FolderName, epNumberString, parseResult.EpisodeTitle, parseResult.Quality); var result = String.Format("{0} - {1} - {2} [{3}]", folderName, epNumberString, parseResult.EpisodeTitle, parseResult.Quality);
if (parseResult.Proper) if (parseResult.Proper)
{ {

View File

@ -3,6 +3,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using NLog; using NLog;
using NzbDrone.Core.Helpers;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Quality; using NzbDrone.Core.Repository.Quality;
@ -108,8 +109,14 @@ namespace NzbDrone.Core.Providers
public virtual Series FindSeries(string title) public virtual Series FindSeries(string title)
{ {
//TODO:Add series alias support here. if a series is not found in the repo should be tried using its aliases
var normalizeTitle = Parser.NormalizeTitle(title); var normalizeTitle = Parser.NormalizeTitle(title);
var seriesId = SceneNameHelper.FindByName(normalizeTitle);
if (seriesId != 0)
{
return GetSeries(seriesId);
}
return _repository.Single<Series>(s => s.CleanTitle == normalizeTitle); return _repository.Single<Series>(s => s.CleanTitle == normalizeTitle);
} }

View File

@ -11,41 +11,7 @@ namespace NzbDrone.Core.Providers
{ {
public class SyncProvider public class SyncProvider
{ {
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly DiskProvider _diskProvider;
private readonly SeriesProvider _seriesProvider;
public SyncProvider(SeriesProvider seriesProvider, DiskProvider diskProvider)
{
_seriesProvider = seriesProvider;
_diskProvider = diskProvider;
}
public List<String> GetUnmappedFolders(string path)
{
Logger.Debug("Generating list of unmapped folders");
if (String.IsNullOrEmpty(path))
throw new ArgumentException("Invalid path provided", "path");
var results = new List<String>();
if (!_diskProvider.FolderExists(path))
{
Logger.Debug("Path supplied does not exist: {0}", path);
return results;
}
foreach (string seriesFolder in _diskProvider.GetDirectories(path))
{
var cleanPath = Parser.NormalizePath(new DirectoryInfo(seriesFolder).FullName);
if (!_seriesProvider.SeriesPathExists(cleanPath))
results.Add(cleanPath);
}
Logger.Debug("{0} unmapped folders detected.", results.Count);
return results;
}
} }
} }

View File

@ -72,7 +72,7 @@ namespace NzbDrone.Web.Controllers
foreach (var folder in _rootFolderProvider.GetAll()) foreach (var folder in _rootFolderProvider.GetAll())
{ {
unmappedList.AddRange(_syncProvider.GetUnmappedFolders(folder.Path)); unmappedList.AddRange(_rootFolderProvider.GetUnmappedFolders(folder.Path));
} }
return View(unmappedList); return View(unmappedList);

View File

@ -4,6 +4,6 @@
<supportedRuntime version="v4.0" /> <supportedRuntime version="v4.0" />
</startup> </startup>
<appSettings> <appSettings>
<add key="port" value="8989" /> <add key="port" value="8980" />
</appSettings> </appSettings>
</configuration> </configuration>