Ability to manually add a show has been added.
UI cleanup for adding series (new, existing and manual).
This commit is contained in:
parent
3d81bc8770
commit
636f352599
|
@ -30,9 +30,10 @@ namespace NzbDrone.Core.Test
|
||||||
list.Add(new Indexer { IndexerName = "Test4", RssUrl = "http://www.test4.com/rss.php", Enabled = false, Order = 2 });
|
list.Add(new Indexer { IndexerName = "Test4", RssUrl = "http://www.test4.com/rss.php", Enabled = false, Order = 2 });
|
||||||
|
|
||||||
var repo = new Mock<IRepository>();
|
var repo = new Mock<IRepository>();
|
||||||
|
var config = new Mock<IConfigProvider>();
|
||||||
repo.Setup(r => r.All<Indexer>()).Returns(list.AsQueryable());
|
repo.Setup(r => r.All<Indexer>()).Returns(list.AsQueryable());
|
||||||
|
|
||||||
var target = new IndexerProvider(repo.Object);
|
var target = new IndexerProvider(repo.Object, config.Object);
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var result = target.AllIndexers();
|
var result = target.AllIndexers();
|
||||||
|
@ -57,9 +58,10 @@ namespace NzbDrone.Core.Test
|
||||||
list.Add(new Indexer { IndexerName = "Test4", RssUrl = "http://www.test4.com/rss.php", Enabled = false, Order = 2 });
|
list.Add(new Indexer { IndexerName = "Test4", RssUrl = "http://www.test4.com/rss.php", Enabled = false, Order = 2 });
|
||||||
|
|
||||||
var repo = new Mock<IRepository>();
|
var repo = new Mock<IRepository>();
|
||||||
|
var config = new Mock<IConfigProvider>();
|
||||||
repo.Setup(r => r.All<Indexer>()).Returns(list.AsQueryable());
|
repo.Setup(r => r.All<Indexer>()).Returns(list.AsQueryable());
|
||||||
|
|
||||||
var target = new IndexerProvider(repo.Object);
|
var target = new IndexerProvider(repo.Object, config.Object);
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
var result = target.EnabledIndexers();
|
var result = target.EnabledIndexers();
|
||||||
|
|
|
@ -57,9 +57,9 @@ namespace NzbDrone.Core.Test
|
||||||
[Test]
|
[Test]
|
||||||
[Row(@"c:\test\", @"c:\test")]
|
[Row(@"c:\test\", @"c:\test")]
|
||||||
[Row(@"c:\\test\\", @"c:\test")]
|
[Row(@"c:\\test\\", @"c:\test")]
|
||||||
[Row(@"C:\\Test\\", @"c:\test")]
|
[Row(@"C:\\Test\\", @"C:\Test")]
|
||||||
[Row(@"C:\\Test\\Test\", @"c:\test\test")]
|
[Row(@"C:\\Test\\Test\", @"C:\Test\Test")]
|
||||||
[Row(@"\\Testserver\Test\", @"\\testserver\test")]
|
[Row(@"\\Testserver\Test\", @"\\Testserver\Test")]
|
||||||
public void Normalize_Path(string dirty, string clean)
|
public void Normalize_Path(string dirty, string clean)
|
||||||
{
|
{
|
||||||
var result = Parser.NormalizePath(dirty);
|
var result = Parser.NormalizePath(dirty);
|
||||||
|
|
|
@ -171,15 +171,18 @@ namespace NzbDrone.Core
|
||||||
{
|
{
|
||||||
//Setup the default providers in the Providers table
|
//Setup the default providers in the Providers table
|
||||||
|
|
||||||
string nzbMatrixRss = "http://rss.nzbmatrix.com/rss.php?page=download&username={USERNAME}&apikey={APIKEY}&subcat=6&english=1";
|
string nzbMatrixRss = "http://rss.nzbmatrix.com/rss.php?page=download&username={USERNAME}&apikey={APIKEY}&subcat=6,41&english=1";
|
||||||
|
string nzbMatrixApi = "http://rss.nzbmatrix.com/rss.php?page=download&username={USERNAME}&apikey={APIKEY}&subcat=6,41&english=1&age={AGE}&term={TERM}";
|
||||||
string nzbsOrgRss = "http://nzbs.org/rss.php?type=1&dl=1&num=100&i={UID}&h={HASH}";
|
string nzbsOrgRss = "http://nzbs.org/rss.php?type=1&dl=1&num=100&i={UID}&h={HASH}";
|
||||||
|
string nzbsOrgApi = String.Empty;
|
||||||
string nzbsrusRss = "http://www.nzbsrus.com/rssfeed.php?cat=91,75&i={UID}&h={HASH}";
|
string nzbsrusRss = "http://www.nzbsrus.com/rssfeed.php?cat=91,75&i={UID}&h={HASH}";
|
||||||
|
string nzbsrusApi = String.Empty;
|
||||||
|
|
||||||
var nzbMatrixIndexer = new Indexer
|
var nzbMatrixIndexer = new Indexer
|
||||||
{
|
{
|
||||||
IndexerName = "NzbMatrix",
|
IndexerName = "NzbMatrix",
|
||||||
RssUrl = nzbMatrixRss,
|
RssUrl = nzbMatrixRss,
|
||||||
ApiUrl = String.Empty,
|
ApiUrl = nzbMatrixApi,
|
||||||
Order = 1
|
Order = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -187,7 +190,7 @@ namespace NzbDrone.Core
|
||||||
{
|
{
|
||||||
IndexerName = "NzbsOrg",
|
IndexerName = "NzbsOrg",
|
||||||
RssUrl = nzbsOrgRss,
|
RssUrl = nzbsOrgRss,
|
||||||
ApiUrl = String.Empty,
|
ApiUrl = nzbsOrgApi,
|
||||||
Order = 2
|
Order = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -195,7 +198,7 @@ namespace NzbDrone.Core
|
||||||
{
|
{
|
||||||
IndexerName = "Nzbsrus",
|
IndexerName = "Nzbsrus",
|
||||||
RssUrl = nzbsrusRss,
|
RssUrl = nzbsrusRss,
|
||||||
ApiUrl = String.Empty,
|
ApiUrl = nzbsrusApi,
|
||||||
Order = 3
|
Order = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using NzbDrone.Core.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Helpers
|
||||||
|
{
|
||||||
|
public static class SceneNameHelper
|
||||||
|
{
|
||||||
|
private static List<SceneNameModel> _sceneNameMappings = new List<SceneNameModel>
|
||||||
|
{
|
||||||
|
new SceneNameModel { SeriesId = 72546, Name = "CSI" },
|
||||||
|
new SceneNameModel { SeriesId = 73696, Name = "CSI New York" },
|
||||||
|
new SceneNameModel { SeriesId = 73696, Name = "CSI NY" },
|
||||||
|
new SceneNameModel { SeriesId = 110381, Name = "Archer" },
|
||||||
|
new SceneNameModel { SeriesId = 83897, Name = "Life After People The Series" },
|
||||||
|
new SceneNameModel { SeriesId = 83897, Name = "Life After People" },
|
||||||
|
new SceneNameModel { SeriesId = 80552, Name = "Kitchen Nightmares US" },
|
||||||
|
new SceneNameModel { SeriesId = 71256, Name = "The Daily Show" },
|
||||||
|
new SceneNameModel { SeriesId = 71256, Name = "The Daily Show with Jon Stewart" },
|
||||||
|
new SceneNameModel { SeriesId = 75692, Name = "Law and Order SVU" },
|
||||||
|
new SceneNameModel { SeriesId = 75692, Name = "Law and Order Special Victims Unit" },
|
||||||
|
new SceneNameModel { SeriesId = 71489, Name = "Law and Order Criminal Intent" },
|
||||||
|
new SceneNameModel { SeriesId = 71489, Name = "Law and Order CI" },
|
||||||
|
new SceneNameModel { SeriesId = 79590, Name = "Dancing With The Stars US" },
|
||||||
|
new SceneNameModel { SeriesId = 73387, Name = "Craig Ferguson" },
|
||||||
|
new SceneNameModel { SeriesId = 85355, Name = "Jimmy Fallon" },
|
||||||
|
new SceneNameModel { SeriesId = 75088, Name = "David Letterman" },
|
||||||
|
new SceneNameModel { SeriesId = 76706, Name = "Big Brother US" },
|
||||||
|
new SceneNameModel { SeriesId = 105521, Name = "The Colony" },
|
||||||
|
new SceneNameModel { SeriesId = 105521, Name = "The Colony US" },
|
||||||
|
new SceneNameModel { SeriesId = 76235, Name = "Americas Funniest Home Videos" },
|
||||||
|
new SceneNameModel { SeriesId = 76235, Name = "AFHV" },
|
||||||
|
new SceneNameModel { SeriesId = 139941, Name = "Childrens Hospital US" },
|
||||||
|
new SceneNameModel { SeriesId = 139941, Name = "Childrens Hospital" },
|
||||||
|
new SceneNameModel { SeriesId = 83123, Name = "Merlin" },
|
||||||
|
new SceneNameModel { SeriesId = 83123, Name = "Merlin 2008" },
|
||||||
|
new SceneNameModel { SeriesId = 76779, Name = "WWE Monday Night RAW" },
|
||||||
|
new SceneNameModel { SeriesId = 164951, Name = "Shit My Dad Says" },
|
||||||
|
new SceneNameModel { SeriesId = 83714, Name = "Genius with Dave Gorman" },
|
||||||
|
new SceneNameModel { SeriesId = 168161, Name = "Law and Order Los Angeles" },
|
||||||
|
new SceneNameModel { SeriesId = 168161, Name = "Law and Order LA" },
|
||||||
|
new SceneNameModel { SeriesId = 77526, Name = "Star Trek TOS" },
|
||||||
|
new SceneNameModel { SeriesId = 72073, Name = "Star Trek DS9" },
|
||||||
|
new SceneNameModel { SeriesId = 72194, Name = "Ellen Degeneres" },
|
||||||
|
new SceneNameModel { SeriesId = 72194, Name = "Ellen Degeneres" },
|
||||||
|
new SceneNameModel { SeriesId = 195831, Name = "Drinking Made Easy" },
|
||||||
|
new SceneNameModel { SeriesId = 195831, Name = "Zane Lampreys Drinking Made Easy" },
|
||||||
|
new SceneNameModel { SeriesId = 76133, Name = "Poirot" },
|
||||||
|
new SceneNameModel { SeriesId = 76133, Name = "Agatha Christies Poirot" },
|
||||||
|
new SceneNameModel { SeriesId = 70870, Name = "The Real World Road Rules Challenge" },
|
||||||
|
new SceneNameModel { SeriesId = 70870, Name = "The Challenge Cutthroat" },
|
||||||
|
new SceneNameModel { SeriesId = 77444, Name = "This Old House Program" },
|
||||||
|
new SceneNameModel { SeriesId = 73290, Name = "60 Minutes US" },
|
||||||
|
new SceneNameModel { SeriesId = 194751, Name = "Conan" },
|
||||||
|
new SceneNameModel { SeriesId = 194751, Name = "Conan 2010" },
|
||||||
|
new SceneNameModel { SeriesId = 164451, Name = "Carlos 2010" },
|
||||||
|
new SceneNameModel { SeriesId = 70726, Name = "Babalon 5" },
|
||||||
|
new SceneNameModel { SeriesId = 70726, Name = "Babalon5" },
|
||||||
|
new SceneNameModel { SeriesId = 83714, Name = "Genius" },
|
||||||
|
new SceneNameModel { SeriesId = 83714, Name = "Genius With Dave Gormand" },
|
||||||
|
new SceneNameModel { SeriesId = 212571, Name = "Come Fly With Me 2010" },
|
||||||
|
new SceneNameModel { SeriesId = 81563, Name = "Border Security" },
|
||||||
|
new SceneNameModel { SeriesId = 81563, Name = "Border Security Australias Frontline" },
|
||||||
|
new SceneNameModel { SeriesId = 172381, Name = "Silent Library US" },
|
||||||
|
new SceneNameModel { SeriesId = 131791, Name = "Sci-Fi Science" },
|
||||||
|
new SceneNameModel { SeriesId = 80646, Name = "Frontline" },
|
||||||
|
new SceneNameModel { SeriesId = 80646, Name = "Frontline US" },
|
||||||
|
new SceneNameModel { SeriesId = 189931, Name = "RBT AU" },
|
||||||
|
new SceneNameModel { SeriesId = 73255, Name = "House" },
|
||||||
|
new SceneNameModel { SeriesId = 73255, Name = "House MD" },
|
||||||
|
new SceneNameModel { SeriesId = 73244, Name = "The Office" },
|
||||||
|
new SceneNameModel { SeriesId = 73244, Name = "The Office US" },
|
||||||
|
};
|
||||||
|
|
||||||
|
public static int FindByName(string seriesName)
|
||||||
|
{
|
||||||
|
var map = _sceneNameMappings.Single(s => s.Name == seriesName);
|
||||||
|
|
||||||
|
if (map == null)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return map.SeriesId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> FindById(int seriesId)
|
||||||
|
{
|
||||||
|
List<String> results = new List<string>();
|
||||||
|
|
||||||
|
var maps = _sceneNameMappings.Where(s => s.SeriesId == seriesId);
|
||||||
|
|
||||||
|
foreach (var map in maps)
|
||||||
|
results.Add(map.Name);
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Model
|
||||||
|
{
|
||||||
|
public class SceneNameModel
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public int SeriesId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -158,6 +158,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Helpers\EpisodeRenameHelper.cs" />
|
<Compile Include="Helpers\EpisodeRenameHelper.cs" />
|
||||||
<Compile Include="Helpers\EpisodeSortingHelper.cs" />
|
<Compile Include="Helpers\EpisodeSortingHelper.cs" />
|
||||||
|
<Compile Include="Helpers\SceneNameHelper.cs" />
|
||||||
<Compile Include="Helpers\ServerHelper.cs" />
|
<Compile Include="Helpers\ServerHelper.cs" />
|
||||||
<Compile Include="Instrumentation\ILogProvider.cs" />
|
<Compile Include="Instrumentation\ILogProvider.cs" />
|
||||||
<Compile Include="Instrumentation\LogLevel.cs" />
|
<Compile Include="Instrumentation\LogLevel.cs" />
|
||||||
|
@ -174,9 +175,12 @@
|
||||||
<Compile Include="Model\NzbInfoModel.cs" />
|
<Compile Include="Model\NzbInfoModel.cs" />
|
||||||
<Compile Include="Model\NzbSiteModel.cs" />
|
<Compile Include="Model\NzbSiteModel.cs" />
|
||||||
<Compile Include="Model\SabnzbdPriorityType.cs" />
|
<Compile Include="Model\SabnzbdPriorityType.cs" />
|
||||||
|
<Compile Include="Model\SceneNameModel.cs" />
|
||||||
<Compile Include="Model\SeriesMappingModel.cs" />
|
<Compile Include="Model\SeriesMappingModel.cs" />
|
||||||
|
<Compile Include="Providers\BacklogProvider.cs" />
|
||||||
<Compile Include="Providers\ExternalNotificationProvider.cs" />
|
<Compile Include="Providers\ExternalNotificationProvider.cs" />
|
||||||
<Compile Include="Providers\HistoryProvider.cs" />
|
<Compile Include="Providers\HistoryProvider.cs" />
|
||||||
|
<Compile Include="Providers\IBacklogProvider.cs" />
|
||||||
<Compile Include="Providers\IExtenalNotificationProvider.cs" />
|
<Compile Include="Providers\IExtenalNotificationProvider.cs" />
|
||||||
<Compile Include="Providers\IHistoryProvider.cs" />
|
<Compile Include="Providers\IHistoryProvider.cs" />
|
||||||
<Compile Include="Providers\IIndexerProvider.cs" />
|
<Compile Include="Providers\IIndexerProvider.cs" />
|
||||||
|
|
|
@ -0,0 +1,277 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Core.Helpers;
|
||||||
|
using NzbDrone.Core.Model;
|
||||||
|
using NzbDrone.Core.Model.Notification;
|
||||||
|
using NzbDrone.Core.Repository;
|
||||||
|
using Rss;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Providers
|
||||||
|
{
|
||||||
|
public class BacklogProvider : IBacklogProvider
|
||||||
|
{
|
||||||
|
private readonly ISeriesProvider _seriesProvider;
|
||||||
|
private readonly INotificationProvider _notificationProvider;
|
||||||
|
private readonly IConfigProvider _configProvider;
|
||||||
|
private readonly IIndexerProvider _indexerProvider;
|
||||||
|
private readonly IRssProvider _rssProvider;
|
||||||
|
|
||||||
|
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||||
|
private List<Series> _seriesList;
|
||||||
|
private Thread _backlogThread;
|
||||||
|
private ProgressNotification _backlogSearchNotification;
|
||||||
|
|
||||||
|
public BacklogProvider(ISeriesProvider seriesProvider, INotificationProvider notificationProvider,
|
||||||
|
IConfigProvider configProvider, IIndexerProvider indexerProvider,
|
||||||
|
IRssProvider rssProvider)
|
||||||
|
{
|
||||||
|
_seriesProvider = seriesProvider;
|
||||||
|
_notificationProvider = notificationProvider;
|
||||||
|
_configProvider = configProvider;
|
||||||
|
_indexerProvider = indexerProvider;
|
||||||
|
_rssProvider = rssProvider;
|
||||||
|
|
||||||
|
_seriesList = new List<Series>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IBacklogProvider Members
|
||||||
|
|
||||||
|
public bool StartSearch()
|
||||||
|
{
|
||||||
|
Logger.Debug("Backlog Search Requested");
|
||||||
|
if (_backlogThread == null || !_backlogThread.IsAlive)
|
||||||
|
{
|
||||||
|
Logger.Debug("Initializing Backlog Search");
|
||||||
|
_backlogThread = new Thread(PerformSearch)
|
||||||
|
{
|
||||||
|
Name = "BacklogSearch",
|
||||||
|
Priority = ThreadPriority.Lowest
|
||||||
|
};
|
||||||
|
|
||||||
|
_seriesList.AddRange(_seriesProvider.GetAllSeries());
|
||||||
|
_backlogThread.Start();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.Warn("Backlog Search already in progress. Ignoring request.");
|
||||||
|
|
||||||
|
//return false if backlog search was already running
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//return true if backlog search has started
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool StartSearch(int seriesId)
|
||||||
|
{
|
||||||
|
//Get the series
|
||||||
|
//Start new Thread if one isn't already started
|
||||||
|
|
||||||
|
Logger.Debug("Backlog Search Requested");
|
||||||
|
if (_backlogThread == null || !_backlogThread.IsAlive)
|
||||||
|
{
|
||||||
|
Logger.Debug("Initializing Backlog Search");
|
||||||
|
_backlogThread = new Thread(PerformSearch)
|
||||||
|
{
|
||||||
|
Name = "BacklogSearch",
|
||||||
|
Priority = ThreadPriority.Lowest
|
||||||
|
};
|
||||||
|
|
||||||
|
var series = _seriesProvider.GetSeries(seriesId);
|
||||||
|
|
||||||
|
if (series == null)
|
||||||
|
{
|
||||||
|
Logger.Debug("Invalid Series - Not starting Backlog Search");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_seriesList.Add(series);
|
||||||
|
_backlogThread.Start();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.Warn("Backlog Search already in progress. Ignoring request.");
|
||||||
|
|
||||||
|
//return false if backlog search was already running
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//return true if backlog search has started
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private void PerformSearch()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (_backlogSearchNotification = new ProgressNotification("Series Scan"))
|
||||||
|
{
|
||||||
|
_notificationProvider.Register(_backlogSearchNotification);
|
||||||
|
_backlogSearchNotification.CurrentStatus = "Starting Backlog Search";
|
||||||
|
_backlogSearchNotification.ProgressMax = _seriesList.Count;
|
||||||
|
|
||||||
|
foreach (var series in _seriesList)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//Do the searching here
|
||||||
|
_backlogSearchNotification.CurrentStatus = String.Format("Backlog Searching For: {0}", series.Title);
|
||||||
|
|
||||||
|
var sceneNames = SceneNameHelper.FindById(series.SeriesId);
|
||||||
|
|
||||||
|
if (sceneNames.Count < 1)
|
||||||
|
sceneNames.Add(series.Title);
|
||||||
|
|
||||||
|
foreach (var season in series.Seasons)
|
||||||
|
{
|
||||||
|
var episodesWithoutFiles = season.Episodes.Where(e => e.EpisodeFileId == 0);
|
||||||
|
|
||||||
|
if (season.Episodes.Count() == episodesWithoutFiles.Count())
|
||||||
|
{
|
||||||
|
//Whole season needs to be grabbed, look for the whole season first
|
||||||
|
//Lookup scene name using seriesId
|
||||||
|
|
||||||
|
foreach (var sceneName in sceneNames)
|
||||||
|
{
|
||||||
|
var searchString = String.Format("{0} Season {1}", sceneName,
|
||||||
|
season.SeasonNumber);
|
||||||
|
|
||||||
|
foreach (var i in _indexerProvider.EnabledIndexers())
|
||||||
|
{
|
||||||
|
//Get the users URL
|
||||||
|
GetUsersUrl(i, searchString);
|
||||||
|
|
||||||
|
//If the url still contains '{' & '}' the user probably hasn't configured the indexer settings
|
||||||
|
if (i.ApiUrl.Contains("{") && i.ApiUrl.Contains("}"))
|
||||||
|
{
|
||||||
|
Logger.Debug("Unable to Sync {0}. User Information has not been configured.", i.IndexerName);
|
||||||
|
continue; //Skip this indexer
|
||||||
|
}
|
||||||
|
|
||||||
|
var indexer = new FeedInfoModel(i.IndexerName, i.ApiUrl);
|
||||||
|
|
||||||
|
var feedItems = _rssProvider.GetFeed(indexer);
|
||||||
|
|
||||||
|
if (feedItems.Count() == 0)
|
||||||
|
{
|
||||||
|
Logger.Debug("Failed to download Backlog Search URL: {0}", indexer.Name);
|
||||||
|
continue; //No need to process anything else
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (RssItem item in feedItems)
|
||||||
|
{
|
||||||
|
NzbInfoModel nzb = Parser.ParseNzbInfo(indexer, item);
|
||||||
|
QueueSeasonIfWanted(nzb, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Grab the episodes 1-by-1 (or in smaller chunks)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
//Done searching for each episode
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.WarnException(ex.Message, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
_backlogSearchNotification.ProgressValue++;
|
||||||
|
}
|
||||||
|
|
||||||
|
_backlogSearchNotification.CurrentStatus = "Backlog Search Completed";
|
||||||
|
Logger.Info("Backlog Search has successfully completed.");
|
||||||
|
Thread.Sleep(3000);
|
||||||
|
_backlogSearchNotification.Status = ProgressNotificationStatus.Completed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.WarnException(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetUsersUrl(Indexer indexer, string searchString)
|
||||||
|
{
|
||||||
|
if (indexer.IndexerName == "NzbMatrix")
|
||||||
|
{
|
||||||
|
var nzbMatrixUsername = _configProvider.GetValue("NzbMatrixUsername", String.Empty, false);
|
||||||
|
var nzbMatrixApiKey = _configProvider.GetValue("NzbMatrixApiKey", String.Empty, false);
|
||||||
|
var retention = Convert.ToInt32(_configProvider.GetValue("Retention", String.Empty, false));
|
||||||
|
|
||||||
|
if (!String.IsNullOrEmpty(nzbMatrixUsername) && !String.IsNullOrEmpty(nzbMatrixApiKey))
|
||||||
|
indexer.ApiUrl = indexer.ApiUrl.Replace("{USERNAME}", nzbMatrixUsername).Replace("{APIKEY}", nzbMatrixApiKey).Replace("{AGE}", retention.ToString()).Replace("{TERM}", searchString);
|
||||||
|
|
||||||
|
//Todo: Perform validation at the config level so a user is unable to enable a provider until user details are provided
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indexer.IndexerName == "NzbsOrg")
|
||||||
|
{
|
||||||
|
var nzbsOrgUId = _configProvider.GetValue("NzbsOrgUId", String.Empty, false);
|
||||||
|
var nzbsOrgHash = _configProvider.GetValue("NzbsOrgHash", String.Empty, false);
|
||||||
|
|
||||||
|
if (!String.IsNullOrEmpty(nzbsOrgUId) && !String.IsNullOrEmpty(nzbsOrgHash))
|
||||||
|
indexer.RssUrl = indexer.RssUrl.Replace("{UID}", nzbsOrgUId).Replace("{HASH}", nzbsOrgHash);
|
||||||
|
|
||||||
|
//Todo: Perform validation at the config level so a user is unable to enable a provider until user details are provided
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indexer.IndexerName == "NzbsOrg")
|
||||||
|
{
|
||||||
|
var nzbsrusUId = _configProvider.GetValue("NzbsrusUId", String.Empty, false);
|
||||||
|
var nzbsrusHash = _configProvider.GetValue("NzbsrusHash", String.Empty, false);
|
||||||
|
|
||||||
|
if (!String.IsNullOrEmpty(nzbsrusUId) && !String.IsNullOrEmpty(nzbsrusHash))
|
||||||
|
indexer.RssUrl = indexer.RssUrl.Replace("{UID}", nzbsrusUId).Replace("{HASH}", nzbsrusHash);
|
||||||
|
|
||||||
|
//Todo: Perform validation at the config level so a user is unable to enable a provider until user details are provided
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return; //Currently other providers do not require user information to be substituted, simply return
|
||||||
|
}
|
||||||
|
|
||||||
|
private void QueueSeasonIfWanted(NzbInfoModel nzb, Indexer indexer)
|
||||||
|
{
|
||||||
|
//Do we want this item?
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (nzb.IsPassworded())
|
||||||
|
{
|
||||||
|
Logger.Debug("Skipping Passworded Report {0}", nzb.Title);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Need to get REGEX that will handle "Show Name Season 1 quality"
|
||||||
|
nzb.TitleFix = String.Empty;
|
||||||
|
nzb.TitleFix = String.Format("{0} [{1}]", nzb.TitleFix, nzb.Quality); //Add Quality to the titleFix
|
||||||
|
|
||||||
|
//Check that we want this quality
|
||||||
|
var quality = Parser.ParseQuality(nzb.Title);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.DebugException(ex.Message, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -49,6 +49,12 @@ namespace NzbDrone.Core.Providers
|
||||||
File.Move(sourcePath, destinationPath);
|
File.Move(sourcePath, destinationPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string GetFolderName(string path)
|
||||||
|
{
|
||||||
|
var di = new DirectoryInfo(path);
|
||||||
|
return di.Name;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Providers
|
||||||
|
{
|
||||||
|
public interface IBacklogProvider
|
||||||
|
{
|
||||||
|
//Will provide Backlog Search functionality
|
||||||
|
|
||||||
|
bool StartSearch();
|
||||||
|
bool StartSearch(int seriesId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,5 +13,6 @@ namespace NzbDrone.Core.Providers
|
||||||
long GetSize(string path);
|
long GetSize(string path);
|
||||||
void DeleteFile(string path);
|
void DeleteFile(string path);
|
||||||
void RenameFile(string sourcePath, string destinationPath);
|
void RenameFile(string sourcePath, string destinationPath);
|
||||||
|
string GetFolderName(string path);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,6 +8,7 @@ namespace NzbDrone.Core.Providers
|
||||||
{
|
{
|
||||||
bool BeginSyncUnmappedFolders(List<SeriesMappingModel> unmapped);
|
bool BeginSyncUnmappedFolders(List<SeriesMappingModel> unmapped);
|
||||||
bool BeginAddNewSeries(string dir, int seriesId, string seriesName);
|
bool BeginAddNewSeries(string dir, int seriesId, string seriesName);
|
||||||
|
bool BeginAddExistingSeries(string path, int seriesId);
|
||||||
List<String> GetUnmappedFolders(string path);
|
List<String> GetUnmappedFolders(string path);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,13 +14,15 @@ namespace NzbDrone.Core.Providers
|
||||||
{
|
{
|
||||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||||
private readonly IRepository _sonicRepo;
|
private readonly IRepository _sonicRepo;
|
||||||
|
private readonly IConfigProvider _configProvider;
|
||||||
|
|
||||||
public IndexerProvider(IRepository sonicRepo)
|
public IndexerProvider(IRepository sonicRepo, IConfigProvider configProvider)
|
||||||
{
|
{
|
||||||
_sonicRepo = sonicRepo;
|
_sonicRepo = sonicRepo;
|
||||||
|
_configProvider = configProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region IIndexerProvider
|
#region IIndexerProvider Members
|
||||||
|
|
||||||
public List<Indexer> AllIndexers()
|
public List<Indexer> AllIndexers()
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using NzbDrone.Core.Helpers;
|
||||||
using NzbDrone.Core.Model;
|
using NzbDrone.Core.Model;
|
||||||
using NzbDrone.Core.Model.Notification;
|
using NzbDrone.Core.Model.Notification;
|
||||||
using NzbDrone.Core.Repository;
|
using NzbDrone.Core.Repository;
|
||||||
|
@ -146,8 +147,14 @@ namespace NzbDrone.Core.Providers
|
||||||
|
|
||||||
if (series == null)
|
if (series == null)
|
||||||
{
|
{
|
||||||
Logger.Debug("Show is not being watched: {0}", episodeParseResults[0].SeriesTitle);
|
//If we weren't able to find a title using the clean name, lets try again looking for a scene name
|
||||||
return;
|
series = _series.GetSeries(SceneNameHelper.FindByName(episodeParseResults[0].SeriesTitle));
|
||||||
|
|
||||||
|
if (series == null)
|
||||||
|
{
|
||||||
|
Logger.Debug("Show is not being watched: {0}", episodeParseResults[0].SeriesTitle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Debug("Show is being watched: {0}", series.Title);
|
Logger.Debug("Show is being watched: {0}", series.Title);
|
||||||
|
|
|
@ -126,6 +126,37 @@ namespace NzbDrone.Core.Providers
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool BeginAddExistingSeries(string path, int seriesId)
|
||||||
|
{
|
||||||
|
Logger.Debug("User has requested adding of new series");
|
||||||
|
if (_seriesSyncThread == null || !_seriesSyncThread.IsAlive)
|
||||||
|
{
|
||||||
|
Logger.Debug("Initializing background add of of series folder.");
|
||||||
|
_seriesSyncThread = new Thread(SyncUnmappedFolders)
|
||||||
|
{
|
||||||
|
Name = "SyncUnmappedFolders",
|
||||||
|
Priority = ThreadPriority.Lowest
|
||||||
|
};
|
||||||
|
|
||||||
|
_syncList = new List<SeriesMappingModel>();
|
||||||
|
|
||||||
|
//Add it to the list so it will be processed
|
||||||
|
_syncList.Add(new SeriesMappingModel { Path = path, TvDbId = seriesId });
|
||||||
|
|
||||||
|
_seriesSyncThread.Start();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.Warn("Series folder scan already in progress. Ignoring request.");
|
||||||
|
|
||||||
|
//return false if sync was already running, then we can tell the user to try again later
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//return true if sync has started
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private void SyncUnmappedFolders()
|
private void SyncUnmappedFolders()
|
||||||
{
|
{
|
||||||
Logger.Info("Starting Series folder scan");
|
Logger.Info("Starting Series folder scan");
|
||||||
|
@ -167,6 +198,7 @@ namespace NzbDrone.Core.Providers
|
||||||
_episodeProvider.RefreshEpisodeInfo(mappedSeries.Id);
|
_episodeProvider.RefreshEpisodeInfo(mappedSeries.Id);
|
||||||
_seriesSyncNotification.CurrentStatus = String.Format("{0}: finding episodes on disk...", mappedSeries.SeriesName);
|
_seriesSyncNotification.CurrentStatus = String.Format("{0}: finding episodes on disk...", mappedSeries.SeriesName);
|
||||||
_mediaFileProvider.Scan(_seriesProvider.GetSeries(mappedSeries.Id));
|
_mediaFileProvider.Scan(_seriesProvider.GetSeries(mappedSeries.Id));
|
||||||
|
//Todo: Launch Backlog search for this series _backlogProvider.StartSearch(mappedSeries.Id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -235,3 +235,10 @@ input[type="text"]:hover
|
||||||
border: 1px solid #f00;
|
border: 1px solid #f00;
|
||||||
background: #eef;
|
background: #eef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add Series */
|
||||||
|
|
||||||
|
.tvDbSearchResults
|
||||||
|
{
|
||||||
|
width: 400px;
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ namespace NzbDrone.Web.Controllers
|
||||||
private readonly IRenameProvider _renameProvider;
|
private readonly IRenameProvider _renameProvider;
|
||||||
private readonly IRootDirProvider _rootDirProvider;
|
private readonly IRootDirProvider _rootDirProvider;
|
||||||
private readonly ITvDbProvider _tvDbProvider;
|
private readonly ITvDbProvider _tvDbProvider;
|
||||||
|
private readonly IDiskProvider _diskProvider;
|
||||||
|
|
||||||
//
|
//
|
||||||
// GET: /Series/
|
// GET: /Series/
|
||||||
|
@ -36,7 +37,7 @@ namespace NzbDrone.Web.Controllers
|
||||||
IEpisodeProvider episodeProvider, IRssSyncProvider rssSyncProvider,
|
IEpisodeProvider episodeProvider, IRssSyncProvider rssSyncProvider,
|
||||||
IQualityProvider qualityProvider, IMediaFileProvider mediaFileProvider,
|
IQualityProvider qualityProvider, IMediaFileProvider mediaFileProvider,
|
||||||
IRenameProvider renameProvider, IRootDirProvider rootDirProvider,
|
IRenameProvider renameProvider, IRootDirProvider rootDirProvider,
|
||||||
ITvDbProvider tvDbProvider)
|
ITvDbProvider tvDbProvider, IDiskProvider diskProvider)
|
||||||
{
|
{
|
||||||
_seriesProvider = seriesProvider;
|
_seriesProvider = seriesProvider;
|
||||||
_episodeProvider = episodeProvider;
|
_episodeProvider = episodeProvider;
|
||||||
|
@ -47,6 +48,7 @@ namespace NzbDrone.Web.Controllers
|
||||||
_renameProvider = renameProvider;
|
_renameProvider = renameProvider;
|
||||||
_rootDirProvider = rootDirProvider;
|
_rootDirProvider = rootDirProvider;
|
||||||
_tvDbProvider = tvDbProvider;
|
_tvDbProvider = tvDbProvider;
|
||||||
|
_diskProvider = diskProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionResult Index()
|
public ActionResult Index()
|
||||||
|
@ -67,7 +69,25 @@ namespace NzbDrone.Web.Controllers
|
||||||
|
|
||||||
public ActionResult AddNew()
|
public ActionResult AddNew()
|
||||||
{
|
{
|
||||||
return View();
|
ViewData["RootDirs"] = _rootDirProvider.GetAll();
|
||||||
|
ViewData["DirSep"] = Path.DirectorySeparatorChar;
|
||||||
|
|
||||||
|
var model = new AddNewSeriesModel
|
||||||
|
{
|
||||||
|
DirectorySeparatorChar = Path.DirectorySeparatorChar.ToString(),
|
||||||
|
RootDirectories = _rootDirProvider.GetAll()
|
||||||
|
};
|
||||||
|
|
||||||
|
return View(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActionResult AddExistingManual(string path)
|
||||||
|
{
|
||||||
|
var model = new AddExistingManualModel();
|
||||||
|
model.Path = path;
|
||||||
|
model.FolderName = _diskProvider.GetFolderName(path);
|
||||||
|
|
||||||
|
return View(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionResult RssSync()
|
public ActionResult RssSync()
|
||||||
|
@ -137,6 +157,7 @@ namespace NzbDrone.Web.Controllers
|
||||||
{
|
{
|
||||||
IsWanted = true,
|
IsWanted = true,
|
||||||
Path = unmappedFolder,
|
Path = unmappedFolder,
|
||||||
|
PathEncoded = Url.Encode(unmappedFolder),
|
||||||
TvDbId = tvDbSeries.Id,
|
TvDbId = tvDbSeries.Id,
|
||||||
TvDbName = tvDbSeries.SeriesName
|
TvDbName = tvDbSeries.SeriesName
|
||||||
});
|
});
|
||||||
|
@ -181,26 +202,35 @@ namespace NzbDrone.Web.Controllers
|
||||||
return Content("Unable to add new series, please wait for previous scans to complete first.");
|
return Content("Unable to add new series, please wait for previous scans to complete first.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ActionResult AddExistingSeries(string path, int seriesId)
|
||||||
|
{
|
||||||
|
//Get TVDB Series Name
|
||||||
|
//Create new folder for series
|
||||||
|
//Add the new series to the Database
|
||||||
|
|
||||||
|
if (_syncProvider.BeginAddExistingSeries(path, seriesId))
|
||||||
|
return Content("Manual adding of existing series has started");
|
||||||
|
|
||||||
|
return Content("Unable to add existing series, please wait for previous scans to complete first.");
|
||||||
|
}
|
||||||
|
|
||||||
public ActionResult SearchForSeries(string seriesName)
|
public ActionResult SearchForSeries(string seriesName)
|
||||||
{
|
{
|
||||||
var model = new List<SeriesSearchResultModel>();
|
var model = new List<SeriesSearchResultModel>();
|
||||||
|
|
||||||
//Get Results from TvDb and convert them to something we can use.
|
//Get Results from TvDb and convert them to something we can use.
|
||||||
//foreach (var tvdbSearchResult in _tvDbProvider.SearchSeries(seriesName))
|
foreach (var tvdbSearchResult in _tvDbProvider.SearchSeries(seriesName))
|
||||||
//{
|
{
|
||||||
// model.Add(new SeriesSearchResultModel
|
model.Add(new SeriesSearchResultModel
|
||||||
// {
|
{
|
||||||
// TvDbId = tvdbSearchResult.Id,
|
TvDbId = tvdbSearchResult.Id,
|
||||||
// TvDbName = tvdbSearchResult.SeriesName,
|
TvDbName = tvdbSearchResult.SeriesName,
|
||||||
// FirstAired = tvdbSearchResult.FirstAired
|
FirstAired = tvdbSearchResult.FirstAired
|
||||||
// });
|
});
|
||||||
//}
|
}
|
||||||
|
|
||||||
ViewData["RootDirs"] = _rootDirProvider.GetAll();
|
//model.Add(new SeriesSearchResultModel{ TvDbId = 12345, TvDbName = "30 Rock", FirstAired = DateTime.Today });
|
||||||
ViewData["DirSep"] = Path.DirectorySeparatorChar;
|
//model.Add(new SeriesSearchResultModel { TvDbId = 65432, TvDbName = "The Office (US)", FirstAired = DateTime.Today.AddDays(-100) });
|
||||||
|
|
||||||
model.Add(new SeriesSearchResultModel{ TvDbId = 12345, TvDbName = "30 Rock", FirstAired = DateTime.Today });
|
|
||||||
model.Add(new SeriesSearchResultModel { TvDbId = 65432, TvDbName = "The Office (US)", FirstAired = DateTime.Today.AddDays(-100) });
|
|
||||||
|
|
||||||
return PartialView("SeriesSearchResults", model);
|
return PartialView("SeriesSearchResults", model);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Web;
|
||||||
|
|
||||||
|
namespace NzbDrone.Web.Models
|
||||||
|
{
|
||||||
|
public class AddExistingManualModel
|
||||||
|
{
|
||||||
|
public string Path { get; set; }
|
||||||
|
public string FolderName { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ namespace NzbDrone.Web.Models
|
||||||
{
|
{
|
||||||
public bool IsWanted { get; set; }
|
public bool IsWanted { get; set; }
|
||||||
public string Path { get; set; }
|
public string Path { get; set; }
|
||||||
|
public string PathEncoded { get; set; }
|
||||||
public int TvDbId { get; set; }
|
public int TvDbId { get; set; }
|
||||||
public string TvDbName { get; set; }
|
public string TvDbName { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.ComponentModel;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
|
using NzbDrone.Core.Repository;
|
||||||
|
|
||||||
namespace NzbDrone.Web.Models
|
namespace NzbDrone.Web.Models
|
||||||
{
|
{
|
||||||
|
@ -14,5 +15,9 @@ namespace NzbDrone.Web.Models
|
||||||
[DisplayName("Single Series Path")]
|
[DisplayName("Single Series Path")]
|
||||||
[DisplayFormat(ConvertEmptyStringToNull = false)]
|
[DisplayFormat(ConvertEmptyStringToNull = false)]
|
||||||
public string SeriesName { get; set; }
|
public string SeriesName { get; set; }
|
||||||
|
|
||||||
|
public string DirectorySeparatorChar { get; set; }
|
||||||
|
|
||||||
|
public List<RootDir> RootDirectories { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -90,6 +90,7 @@
|
||||||
<Compile Include="Helpers\HtmlPrefixScopeExtensions.cs" />
|
<Compile Include="Helpers\HtmlPrefixScopeExtensions.cs" />
|
||||||
<Compile Include="Helpers\IsCurrentActionHelper.cs" />
|
<Compile Include="Helpers\IsCurrentActionHelper.cs" />
|
||||||
<Compile Include="Models\AccountModels.cs" />
|
<Compile Include="Models\AccountModels.cs" />
|
||||||
|
<Compile Include="Models\AddExistingManualModel.cs" />
|
||||||
<Compile Include="Models\AddExistingSeriesModel.cs" />
|
<Compile Include="Models\AddExistingSeriesModel.cs" />
|
||||||
<Compile Include="Models\AddNewSeriesModel.cs" />
|
<Compile Include="Models\AddNewSeriesModel.cs" />
|
||||||
<Compile Include="Models\DownloadSettingsModel.cs" />
|
<Compile Include="Models\DownloadSettingsModel.cs" />
|
||||||
|
@ -278,6 +279,7 @@
|
||||||
<Content Include="Views\Home\Test.aspx" />
|
<Content Include="Views\Home\Test.aspx" />
|
||||||
<Content Include="Views\Log\Index.aspx" />
|
<Content Include="Views\Log\Index.aspx" />
|
||||||
<Content Include="Views\Series\AddExisting.aspx" />
|
<Content Include="Views\Series\AddExisting.aspx" />
|
||||||
|
<Content Include="Views\Series\AddExistingManual.aspx" />
|
||||||
<Content Include="Views\Series\AddNew.aspx" />
|
<Content Include="Views\Series\AddNew.aspx" />
|
||||||
<Content Include="Views\Series\Details.aspx" />
|
<Content Include="Views\Series\Details.aspx" />
|
||||||
<Content Include="Views\Series\Edit.aspx" />
|
<Content Include="Views\Series\Edit.aspx" />
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<%@ Import Namespace="NzbDrone.Web.Models" %>
|
<%@ Import Namespace="NzbDrone.Web.Models" %>
|
||||||
|
|
||||||
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
|
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
|
||||||
Add Existing
|
Add Existing Series
|
||||||
</asp:Content>
|
</asp:Content>
|
||||||
<asp:Content ID="Menu" ContentPlaceHolderID="ActionMenu" runat="server">
|
<asp:Content ID="Menu" ContentPlaceHolderID="ActionMenu" runat="server">
|
||||||
<%
|
<%
|
||||||
|
@ -16,6 +16,7 @@
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$('#mastercheckbox').attr("checked", "checked");
|
$('#mastercheckbox').attr("checked", "checked");
|
||||||
|
document.getElementById('unmappedGrid').style.display = 'block';
|
||||||
});
|
});
|
||||||
|
|
||||||
function Grid_onRowDataBound(e) {
|
function Grid_onRowDataBound(e) {
|
||||||
|
@ -31,32 +32,43 @@
|
||||||
//You can use the OnRowDataBound event to customize the way data is presented on the client-side
|
//You can use the OnRowDataBound event to customize the way data is presented on the client-side
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function Grid_onLoad(e) {
|
||||||
|
$('.t-no-data').text("Loading...");
|
||||||
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<%
|
<div id="unmappedGrid" style="display:none">
|
||||||
Html.Telerik().Grid<AddExistingSeriesModel>().Name("Unmapped_Series_Folders")
|
<%
|
||||||
.TableHtmlAttributes(new { id = "UnmappedSeriesGrid" })
|
Html.Telerik().Grid<AddExistingSeriesModel>().Name("Unmapped_Series_Folders")
|
||||||
.Columns(columns =>
|
.TableHtmlAttributes(new { id = "UnmappedSeriesGrid" })
|
||||||
{
|
.Columns(columns =>
|
||||||
columns.Bound(c => c.IsWanted).ClientTemplate("<input type='checkbox' name='<#= Path #>' class='checkedSeries' value='<#= TvDbId #>' checked='true'/>")
|
{
|
||||||
.Width(20).Title("<input id='mastercheckbox' type='checkbox' />")
|
columns.Bound(c => c.IsWanted).ClientTemplate("<input type='checkbox' name='<#= Path #>' class='checkedSeries' value='<#= TvDbId #>' checked='true'/>")
|
||||||
.HtmlAttributes(new { style = "text-align:center" });
|
.Width(20).Title("<input id='mastercheckbox' type='checkbox' style='margin-left:5px'/>")
|
||||||
|
.HtmlAttributes(new { style = "text-align:center" });
|
||||||
|
|
||||||
columns.Bound(c => c.Path);
|
columns.Bound(c => c.Path).ClientTemplate("<a href=" + Url.Action("AddExistingManual", "Series", new { path = "<#= PathEncoded #>" }) + "><#= Path #></a>")
|
||||||
columns.Bound(c => c.TvDbName);
|
.Template(c =>
|
||||||
})
|
{ %>
|
||||||
.DataBinding(d => d.Ajax().Select("_AjaxUnmappedFoldersGrid", "Series"))
|
<%:Html.ActionLink(c.Path, "AddExistingManual", new { path = c.Path })%>
|
||||||
.ClientEvents(events => events.OnRowDataBound("Grid_onRowDataBound"))
|
<% }).Title("Path");
|
||||||
.Footer(false)
|
columns.Bound(c => c.TvDbName);
|
||||||
.Render();
|
})
|
||||||
%>
|
.DataBinding(d => d.Ajax().Select("_AjaxUnmappedFoldersGrid", "Series"))
|
||||||
|
.ClientEvents(events => events.OnRowDataBound("Grid_onRowDataBound"))
|
||||||
|
.ClientEvents(events => events.OnLoad("Grid_onLoad"))
|
||||||
|
.Footer(false)
|
||||||
|
.Render();
|
||||||
|
%>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<button class="t.button" onclick="syncSelected ()">Sync Selected Series</button>
|
<button class="t.button" onclick="syncSelected ()">Sync Selected Series</button>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="result"></div>
|
<div id="result"></div>
|
||||||
<div id="tester"></div>
|
|
||||||
|
|
||||||
<script type="text/javascript" language="javascript">
|
<script type="text/javascript" language="javascript">
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<NzbDrone.Web.Models.AddExistingManualModel>" %>
|
||||||
|
|
||||||
|
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
|
||||||
|
Add Series Manually
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
jQuery(document).ready(function () {
|
||||||
|
$('#searchButton').click();
|
||||||
|
$('#searchButton').attr('disabled', '');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</asp:Content>
|
||||||
|
<asp:Content ID="Menu" ContentPlaceHolderID="ActionMenu" runat="server">
|
||||||
|
<%
|
||||||
|
Html.RenderPartial("SubMenu");
|
||||||
|
%>
|
||||||
|
</asp:Content>
|
||||||
|
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h4><%= Html.Label(Model.Path) %></h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%= Html.Label("Enter a Series Name") %>
|
||||||
|
<%= Html.TextBoxFor(m => m.FolderName, new { id="existing_series_id" }) %>
|
||||||
|
<%= Html.TextBoxFor(m => m.Path, new { id ="series_path", style="display:none" }) %>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<button class="t.button" id="searchButton" disabled="disabled" onclick="searchSeries ()">Search</button>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div id="result"></div>
|
||||||
|
|
||||||
|
<div id="addSeriesControls" style="display:none">
|
||||||
|
<button class="t.button" onclick="addSeries ()">Add Series</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="addResult"></div>
|
||||||
|
|
||||||
|
<script type="text/javascript" language="javascript">
|
||||||
|
|
||||||
|
$('#existing_series_id').bind('keydown', function (e) {
|
||||||
|
if (e.keyCode == 13) {
|
||||||
|
$('#searchButton').click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function searchSeries() {
|
||||||
|
var seriesSearch = $('#existing_series_id');
|
||||||
|
|
||||||
|
$("#result").text("Searching..."); //Tell the user that we're performing the search
|
||||||
|
document.getElementById('addSeriesControls').style.display = 'none'; //Hide the add button
|
||||||
|
$("#result").load('<%=Url.Action("SearchForSeries", "Series") %>', {
|
||||||
|
seriesName: seriesSearch.val()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(".searchRadio").live("change", function () {
|
||||||
|
var checked = $(this).attr('checked');
|
||||||
|
|
||||||
|
if (checked) {
|
||||||
|
document.getElementById('addSeriesControls').style.display = 'inline';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function addSeries() {
|
||||||
|
//Get the selected tvdbid + selected root folder
|
||||||
|
//jquery bit below doesn't want to work...
|
||||||
|
|
||||||
|
var checkedSeries = $("input[name='selectedSeries']:checked").val();
|
||||||
|
|
||||||
|
var id = "#" + checkedSeries + "_text";
|
||||||
|
var seriesName = $(id).val();
|
||||||
|
|
||||||
|
var pathTest = $('#series_path').val();
|
||||||
|
$('#tester').text(pathTest);
|
||||||
|
|
||||||
|
$("#addResult").load('<%=Url.Action("AddExistingSeries", "Series") %>', {
|
||||||
|
path: pathTest,
|
||||||
|
seriesId: checkedSeries
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<div id="tester"></div>
|
||||||
|
|
||||||
|
</asp:Content>
|
|
@ -1,9 +1,17 @@
|
||||||
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<AddNewSeriesModel>" %>
|
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<AddNewSeriesModel>" %>
|
||||||
<%@ Import Namespace="NzbDrone.Web.Models" %>
|
<%@ Import Namespace="NzbDrone.Web.Models" %>
|
||||||
<%@ Import Namespace="Telerik.Web.Mvc.UI" %>
|
<%@ Import Namespace="Telerik.Web.Mvc.UI" %>
|
||||||
|
<%@ Import Namespace="NzbDrone.Core.Repository" %>
|
||||||
|
|
||||||
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
|
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
|
||||||
Add New Series
|
Add New Series
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
jQuery(document).ready(function () {
|
||||||
|
$('#searchButton').attr('disabled', '');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
</asp:Content>
|
</asp:Content>
|
||||||
<asp:Content ID="Menu" ContentPlaceHolderID="ActionMenu" runat="server">
|
<asp:Content ID="Menu" ContentPlaceHolderID="ActionMenu" runat="server">
|
||||||
<%
|
<%
|
||||||
|
@ -16,30 +24,95 @@
|
||||||
<%= Html.TextBox("new_series_name", String.Empty, new { id="new_series_id" }) %>
|
<%= Html.TextBox("new_series_name", String.Empty, new { id="new_series_id" }) %>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<button class="t.button" onclick="searchSeries ()">Search</button>
|
<button class="t.button" id="searchButton" disabled="disabled" onclick="searchSeries ()">Search</button>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div id="result"></div>
|
<div id="result"></div>
|
||||||
|
|
||||||
|
<div id="RootDirectories" style="display:none">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Root TV Folders</legend>
|
||||||
|
|
||||||
|
<% int d = 0; %>
|
||||||
|
<% foreach (var dir in Model.RootDirectories)
|
||||||
|
{ %>
|
||||||
|
<%: Html.RadioButton("selectedRootDir", dir.Path, dir.Default, new { @class="dirList examplePart", id="dirRadio_" + d }) %>
|
||||||
|
<%: Html.Label(dir.Path) %>
|
||||||
|
<% if (dir.Default) { %> * <% } %>
|
||||||
|
<% d++;%>
|
||||||
|
<br />
|
||||||
|
<% } %>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<div id="example"></div>
|
||||||
|
|
||||||
|
<button class="t.button" onclick="addSeries ()">Add New Series</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="addResult"></div>
|
||||||
|
|
||||||
<script type="text/javascript" language="javascript">
|
<script type="text/javascript" language="javascript">
|
||||||
|
|
||||||
|
$('#new_series_id').bind('keydown', function (e) {
|
||||||
|
if (e.keyCode == 13) {
|
||||||
|
$('#searchButton').click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function searchSeries() {
|
function searchSeries() {
|
||||||
var seriesSearch = $('#new_series_id');
|
var seriesSearch = $('#new_series_id');
|
||||||
|
|
||||||
// if ($seriesSearch.length < 1) {
|
$("#result").text("Searching...");
|
||||||
// alert("Enter a valid name to search for");
|
document.getElementById('RootDirectories').style.display = 'none';
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
//Setup a function to handle the results... Or return a partial...
|
|
||||||
$("#result").load('<%=Url.Action("SearchForSeries", "Series") %>', {
|
$("#result").load('<%=Url.Action("SearchForSeries", "Series") %>', {
|
||||||
seriesName: seriesSearch.val()
|
seriesName: seriesSearch.val()
|
||||||
}
|
});
|
||||||
|
|
||||||
//this.window.location = '<%= Url.Action("Index", "Series") %>';
|
|
||||||
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$(".searchRadio").live("change", function () {
|
||||||
|
var checked = $(this).attr('checked');
|
||||||
|
|
||||||
|
if (checked) {
|
||||||
|
document.getElementById('RootDirectories').style.display = 'inline';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function addSeries() {
|
||||||
|
//Get the selected tvdbid + selected root folder
|
||||||
|
//jquery bit below doesn't want to work...
|
||||||
|
|
||||||
|
var checkedSeries = $("input[name='selectedSeries']:checked").val();
|
||||||
|
//var checkedSeries = $('input.searchRadio:checked').val();
|
||||||
|
//var checkedSeries = $('input:radio[name=selectedSeries]:checked').val();
|
||||||
|
//var checkedSeries = $('input:radio[class=searchRadio]:checked').val();
|
||||||
|
|
||||||
|
var checkedDir = $("input[name='selectedRootDir']:checked").val();
|
||||||
|
|
||||||
|
var id = "#" + checkedSeries + "_text";
|
||||||
|
var seriesName = $(id).val();
|
||||||
|
|
||||||
|
$("#addResult").load('<%=Url.Action("AddNewSeries", "Series") %>', {
|
||||||
|
dir: checkedDir,
|
||||||
|
seriesId: checkedSeries,
|
||||||
|
seriesName: seriesName
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//Need to figure out how to use 'ViewData["DirSep"]' instead of hardcoding '\'
|
||||||
|
$(".examplePart").live("change", function () {
|
||||||
|
var dir = $("input[name='selectedRootDir']:checked").val();
|
||||||
|
var series = $("input[name='selectedSeries']:checked").val();
|
||||||
|
|
||||||
|
var id = "#" + series + "_text";
|
||||||
|
var seriesName = $(id).val();
|
||||||
|
|
||||||
|
var sep = "\\";
|
||||||
|
|
||||||
|
var str = "Example: " + dir + sep + seriesName;
|
||||||
|
|
||||||
|
$('#example').text(str);
|
||||||
|
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<div id="tester"></div>
|
<div id="tester"></div>
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,16 @@
|
||||||
<%@ Import Namespace="NzbDrone.Core.Repository" %>
|
<%@ Import Namespace="NzbDrone.Core.Repository" %>
|
||||||
|
|
||||||
<div id="searchResults">
|
<div id="searchResults">
|
||||||
<fieldset>
|
<fieldset class="tvDbSearchResults">
|
||||||
<legend>Search Results</legend>
|
<legend>Search Results</legend>
|
||||||
|
|
||||||
|
<% if (Model.Count == 0)
|
||||||
|
{ %>
|
||||||
|
<b>No results found for the series name</b>
|
||||||
|
<% }
|
||||||
|
%>
|
||||||
|
|
||||||
|
|
||||||
<% int r = 0; %>
|
<% int r = 0; %>
|
||||||
<% foreach (var result in Model)
|
<% foreach (var result in Model)
|
||||||
{ %>
|
{ %>
|
||||||
|
@ -18,74 +25,3 @@
|
||||||
} %>
|
} %>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="RootDirectories" style="display:none">
|
|
||||||
<fieldset>
|
|
||||||
<legend>Root TV Folders</legend>
|
|
||||||
|
|
||||||
<% int d = 0; %>
|
|
||||||
<% foreach (var dir in (List<RootDir>)ViewData["RootDirs"])
|
|
||||||
{ %>
|
|
||||||
<%: Html.RadioButton("selectedRootDir", dir.Path, dir.Default, new { @class="dirList examplePart", id="dirRadio_" + d }) %>
|
|
||||||
<%: Html.Label(dir.Path) %>
|
|
||||||
<% if (dir.Default) { %> * <% } %>
|
|
||||||
<% d++;%>
|
|
||||||
<br />
|
|
||||||
<% } %>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<div id="example"></div>
|
|
||||||
|
|
||||||
<button class="t.button" onclick="addSeries ()">Add New Series</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="addResult"></div>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
$(".searchRadio").live("change", function () {
|
|
||||||
var checked = $(this).attr('checked');
|
|
||||||
|
|
||||||
if (checked) {
|
|
||||||
document.getElementById('RootDirectories').style.display = 'inline';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function addSeries() {
|
|
||||||
//Get the selected tvdbid + selected root folder
|
|
||||||
//jquery bit below doesn't want to work...
|
|
||||||
|
|
||||||
var checkedSeries = $("input[name='selectedSeries']:checked").val();
|
|
||||||
//var checkedSeries = $('input.searchRadio:checked').val();
|
|
||||||
//var checkedSeries = $('input:radio[name=selectedSeries]:checked').val();
|
|
||||||
//var checkedSeries = $('input:radio[class=searchRadio]:checked').val();
|
|
||||||
|
|
||||||
var checkedDir = $("input[name='selectedRootDir']:checked").val();
|
|
||||||
|
|
||||||
var id = "#" + checkedSeries + "_text";
|
|
||||||
var seriesName = $(id).val();
|
|
||||||
|
|
||||||
$("#addResult").load('<%=Url.Action("AddNewSeries", "Series") %>', {
|
|
||||||
dir: checkedDir,
|
|
||||||
seriesId: checkedSeries,
|
|
||||||
seriesName: seriesName
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//Need to figure out how to use 'ViewData["DirSep"]' instead of hardcoding '\'
|
|
||||||
$(".examplePart").live("change", function () {
|
|
||||||
var dir = $("input[name='selectedRootDir']:checked").val();
|
|
||||||
var series = $("input[name='selectedSeries']:checked").val();
|
|
||||||
|
|
||||||
var id = "#" + series + "_text";
|
|
||||||
var seriesName = $(id).val();
|
|
||||||
|
|
||||||
//var sep = '<%= ViewData["DirSep"] %>';
|
|
||||||
var sep = "\\";
|
|
||||||
|
|
||||||
var str = "Example: " + dir + sep + seriesName;
|
|
||||||
|
|
||||||
$('#example').text(str);
|
|
||||||
|
|
||||||
});
|
|
||||||
</script>
|
|
Loading…
Reference in New Issue