diff --git a/NzbDrone.Core.Test/SeriesProviderTest.cs b/NzbDrone.Core.Test/SeriesProviderTest.cs index 12c7ae557..f0a338062 100644 --- a/NzbDrone.Core.Test/SeriesProviderTest.cs +++ b/NzbDrone.Core.Test/SeriesProviderTest.cs @@ -54,6 +54,36 @@ namespace NzbDrone.Core.Test Assert.AreEqual(fakeSeries, mappedSeries); } + [Test] + public void Add_new_series() + { + var repo = MockLib.GetEmptyRepository(); + + var kernel = new MockingKernel(); + kernel.Bind().To(); + kernel.Bind().ToConstant(repo); + + string path = "C:\\Test\\"; + int tvDbId = 1234; + int qualityProfileId = 2; + + //Act + var seriesProvider = kernel.Get(); + seriesProvider.AddSeries(path, tvDbId, qualityProfileId); + + + //Assert + var series = seriesProvider.GetAllSeries(); + Assert.IsNotEmpty(series); + Assert.Count(1, series); + Assert.AreEqual(path, series.First().Path); + Assert.AreEqual(tvDbId, series.First().SeriesId); + Assert.AreEqual(qualityProfileId, series.First().QualityProfileId); + + } + + + [Test] [Row(new object[] { "That's Life - 2x03 -The Devil and Miss DeLucca", "That's Life" })] [Row(new object[] { "Van.Duin.Op.Zn.Best.S02E05.DUTCH.WS.PDTV.XViD-DiFFERENT", "Van Duin Op Zn Best" })] diff --git a/NzbDrone.Core/Providers/ConfigProvider.cs b/NzbDrone.Core/Providers/ConfigProvider.cs index 9851eaab2..044e165ce 100644 --- a/NzbDrone.Core/Providers/ConfigProvider.cs +++ b/NzbDrone.Core/Providers/ConfigProvider.cs @@ -163,11 +163,36 @@ namespace NzbDrone.Core.Providers set { SetValue("BlackholeDirectory", value); } } + public bool UseSeasonFolder + { + get { return GetValueBoolean("Sorting_SeasonFolder", true); } + + set { SetValue("Sorting_SeasonFolder", value); } + } + + public int DefaultQualityProfile + { + get { return GetValueInt("DefaultQualityProfile", 1); } + + set { SetValue("DefaultQualityProfile", value); } + } + + private string GetValue(string key) { return GetValue(key, String.Empty, false); } + private bool GetValueBoolean(string key, bool defaultValue = false) + { + return Convert.ToBoolean(GetValue(key, defaultValue, false)); + } + + private int GetValueInt(string key, int defaultValue = 0) + { + return Convert.ToInt16(GetValue(key, defaultValue, false)); + } + public string GetValue(string key, object defaultValue, bool makePermanent) { string value; @@ -185,6 +210,16 @@ namespace NzbDrone.Core.Providers return value; } + public void SetValue(string key, Boolean value) + { + SetValue(key, value.ToString()); + } + + public void SetValue(string key, int value) + { + SetValue(key, value.ToString()); + } + public void SetValue(string key, string value) { if (String.IsNullOrEmpty(key)) diff --git a/NzbDrone.Core/Providers/DiskProvider.cs b/NzbDrone.Core/Providers/DiskProvider.cs index 529440563..e87263262 100644 --- a/NzbDrone.Core/Providers/DiskProvider.cs +++ b/NzbDrone.Core/Providers/DiskProvider.cs @@ -49,12 +49,6 @@ namespace NzbDrone.Core.Providers File.Move(sourcePath, destinationPath); } - public string GetFolderName(string path) - { - var di = new DirectoryInfo(path); - return di.Name; - } - #endregion } } \ No newline at end of file diff --git a/NzbDrone.Core/Providers/IConfigProvider.cs b/NzbDrone.Core/Providers/IConfigProvider.cs index 8c8c223c6..67979c576 100644 --- a/NzbDrone.Core/Providers/IConfigProvider.cs +++ b/NzbDrone.Core/Providers/IConfigProvider.cs @@ -25,6 +25,8 @@ namespace NzbDrone.Core.Providers String SyncFrequency { get; set; } String SabTvPriority { get; set; } String ApiKey { get; set; } + bool UseSeasonFolder { get; set; } + int DefaultQualityProfile { get; set; } string GetValue(string key, object defaultValue, bool makePermanent); void SetValue(string key, string value); diff --git a/NzbDrone.Core/Providers/IDiskProvider.cs b/NzbDrone.Core/Providers/IDiskProvider.cs index 242721f27..bf17cf1d1 100644 --- a/NzbDrone.Core/Providers/IDiskProvider.cs +++ b/NzbDrone.Core/Providers/IDiskProvider.cs @@ -13,6 +13,5 @@ namespace NzbDrone.Core.Providers long GetSize(string path); void DeleteFile(string path); void RenameFile(string sourcePath, string destinationPath); - string GetFolderName(string path); } } \ No newline at end of file diff --git a/NzbDrone.Core/Providers/ISeriesProvider.cs b/NzbDrone.Core/Providers/ISeriesProvider.cs index 84763b350..1d09f77f2 100644 --- a/NzbDrone.Core/Providers/ISeriesProvider.cs +++ b/NzbDrone.Core/Providers/ISeriesProvider.cs @@ -19,12 +19,12 @@ namespace NzbDrone.Core.Providers /// Whether or not the show is monitored bool IsMonitored(long id); TvdbSeries MapPathToSeries(string path); - TvdbSeries MapPathToSeries(int tvDbId); - void AddSeries(string path, TvdbSeries series, int qualityProfileId); + void AddSeries(string path, int tvDbSeriesId, int qualityProfileId); Series FindSeries(string cleanTitle); bool QualityWanted(int seriesId, QualityTypes quality); void UpdateSeries(Series series); void DeleteSeries(int seriesId); bool SeriesPathExists(string cleanPath); + Series UpdateSeriesInfo(int seriesId); } } \ No newline at end of file diff --git a/NzbDrone.Core/Providers/ISyncProvider.cs b/NzbDrone.Core/Providers/ISyncProvider.cs index 0aa902b8c..dbbdb3a64 100644 --- a/NzbDrone.Core/Providers/ISyncProvider.cs +++ b/NzbDrone.Core/Providers/ISyncProvider.cs @@ -6,9 +6,8 @@ namespace NzbDrone.Core.Providers { public interface ISyncProvider { - bool BeginSyncUnmappedFolders(List unmapped); - bool BeginAddNewSeries(string dir, int seriesId, string seriesName, int qualityProfileId); - bool BeginAddExistingSeries(string path, int seriesId, int qualityProfileId); + List GetUnmappedFolders(string path); + bool BeginUpdateNewSeries(); } } \ No newline at end of file diff --git a/NzbDrone.Core/Providers/SeriesProvider.cs b/NzbDrone.Core/Providers/SeriesProvider.cs index 92bbcd4d2..2e94a0430 100644 --- a/NzbDrone.Core/Providers/SeriesProvider.cs +++ b/NzbDrone.Core/Providers/SeriesProvider.cs @@ -18,17 +18,15 @@ namespace NzbDrone.Core.Providers //Trims all white spaces and separators from the end of the title. private readonly IConfigProvider _config; - private readonly IDiskProvider _diskProvider; private readonly IRepository _sonioRepo; private readonly ITvDbProvider _tvDb; private readonly IQualityProvider _quality; private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - public SeriesProvider(IDiskProvider diskProvider, IConfigProvider configProvider, + public SeriesProvider(IConfigProvider configProvider, IRepository dataRepository, ITvDbProvider tvDbProvider, IQualityProvider quality) { - _diskProvider = diskProvider; _config = configProvider; _sonioRepo = dataRepository; _tvDb = tvDbProvider; @@ -76,33 +74,38 @@ namespace NzbDrone.Core.Providers return _tvDb.GetSeries(searchResults.Id, false); } - public TvdbSeries MapPathToSeries(int tvDbId) + public Series UpdateSeriesInfo(int seriesId) { - return _tvDb.GetSeries(tvDbId, false); + var tvDbSeries = _tvDb.GetSeries(seriesId, true); + var series = GetSeries(seriesId); + + series.SeriesId = tvDbSeries.Id; + series.Title = tvDbSeries.SeriesName; + series.AirTimes = tvDbSeries.AirsTime; + series.AirsDayOfWeek = tvDbSeries.AirsDayOfWeek; + series.Overview = tvDbSeries.Overview; + series.Status = tvDbSeries.Status; + series.Language = tvDbSeries.Language != null ? tvDbSeries.Language.Abbriviation : string.Empty; + series.CleanTitle = Parser.NormalizeTitle(tvDbSeries.SeriesName); + series.LastInfoSync = DateTime.Now; + + UpdateSeries(series); + return series; } - public void AddSeries(string path, TvdbSeries series, int qualityProfileId) + public void AddSeries(string path, int tvDbSeriesId, int qualityProfileId) { - Logger.Info("Adding Series [{0}]:{1} Path: {2}", series.Id, series.SeriesName, path); + Logger.Info("Adding Series [{0}] Path: [{1}]", tvDbSeriesId, path); + var repoSeries = new Series(); - repoSeries.SeriesId = series.Id; - repoSeries.Title = series.SeriesName; - repoSeries.AirTimes = series.AirsTime; - repoSeries.AirsDayOfWeek = series.AirsDayOfWeek; - repoSeries.Overview = series.Overview; - repoSeries.Status = series.Status; - repoSeries.Language = series.Language != null ? series.Language.Abbriviation : string.Empty; + repoSeries.SeriesId = tvDbSeriesId; repoSeries.Path = path; - repoSeries.CleanTitle = Parser.NormalizeTitle(series.SeriesName); repoSeries.Monitored = true; //New shows should be monitored repoSeries.QualityProfileId = qualityProfileId; if (qualityProfileId == 0) repoSeries.QualityProfileId = Convert.ToInt32(_config.GetValue("DefaultQualityProfile", "1", true)); - - repoSeries.SeasonFolder = true; - if (!Convert.ToBoolean(_config.GetValue("Sorting_SeasonFolder", true, true))) - repoSeries.SeasonFolder = false; + repoSeries.SeasonFolder = _config.UseSeasonFolder; _sonioRepo.Add(repoSeries); } @@ -119,22 +122,35 @@ namespace NzbDrone.Core.Providers public void DeleteSeries(int seriesId) { - var series = _sonioRepo.Single(seriesId); + Logger.Warn("Deleting Series [{0}]", seriesId); + + try + { + var series = _sonioRepo.Single(seriesId); + + //Delete Files, Episdes, Seasons then the Series + //Can't use providers because episode provider needs series provider - Cyclic Dependency Injection, this will work + + Logger.Debug("Deleting EpisodeFiles from DB for Series: {0}", series.SeriesId); + _sonioRepo.DeleteMany(series.EpisodeFiles); - //Delete Files, Episdes, Seasons then the Series - //Can't use providers because episode provider needs series provider - Cyclic Dependency Injection, this will work + Logger.Debug("Deleting Episodes from DB for Series: {0}", series.SeriesId); + _sonioRepo.DeleteMany(series.Episodes); - Logger.Debug("Deleting EpisodeFiles from DB for Series: {0}", series.SeriesId); - _sonioRepo.DeleteMany(series.EpisodeFiles); + Logger.Debug("Deleting Seasons from DB for Series: {0}", series.SeriesId); + _sonioRepo.DeleteMany(series.Seasons); - Logger.Debug("Deleting Episodes from DB for Series: {0}", series.SeriesId); - _sonioRepo.DeleteMany(series.Episodes); + Logger.Debug("Deleting Series from DB {0}", series.Title); + _sonioRepo.Delete(seriesId); - Logger.Debug("Deleting Seasons from DB for Series: {0}", series.SeriesId); - _sonioRepo.DeleteMany(series.Seasons); + Logger.Info("Successfully deleted Series [{0}]", seriesId); - Logger.Debug("Deleting Series from DB {0}", series.Title); - _sonioRepo.Delete(seriesId); + } + catch (Exception e) + { + Logger.Error("An error has occurred while deleting series.", e); + throw; + } } public bool SeriesPathExists(string cleanPath) @@ -147,10 +163,5 @@ namespace NzbDrone.Core.Providers #endregion - #region Static Helpers - - - - #endregion } } \ No newline at end of file diff --git a/NzbDrone.Core/Providers/SyncProvider.cs b/NzbDrone.Core/Providers/SyncProvider.cs index b0bb106c5..2a9d44203 100644 --- a/NzbDrone.Core/Providers/SyncProvider.cs +++ b/NzbDrone.Core/Providers/SyncProvider.cs @@ -20,7 +20,6 @@ namespace NzbDrone.Core.Providers private ProgressNotification _seriesSyncNotification; private Thread _seriesSyncThread; - private List _syncList; private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); @@ -46,6 +45,7 @@ namespace NzbDrone.Core.Providers if (!_diskProvider.FolderExists(path)) { Logger.Debug("Path supplied does not exist: {0}", path); + return null; } var results = new List(); @@ -63,19 +63,18 @@ namespace NzbDrone.Core.Providers #endregion - public bool BeginSyncUnmappedFolders(List unmapped) + public bool BeginUpdateNewSeries() { - Logger.Debug("User has requested series folder scan"); + Logger.Debug("User has requested a scan of new series"); if (_seriesSyncThread == null || !_seriesSyncThread.IsAlive) { - Logger.Debug("Initializing background scan of series folder."); - _seriesSyncThread = new Thread(SyncUnmappedFolders) + Logger.Debug("Initializing background scan thread"); + _seriesSyncThread = new Thread(SyncNewSeries) { - Name = "SyncUnmappedFolders", + Name = "SyncNewSeries", Priority = ThreadPriority.Lowest }; - _syncList = unmapped; _seriesSyncThread.Start(); } else @@ -90,139 +89,66 @@ namespace NzbDrone.Core.Providers return true; } - public bool BeginAddNewSeries(string dir, int seriesId, string seriesName, int qualityProfileId) + + private void SyncNewSeries() { - Logger.Debug("User has requested adding of new series"); - if (_seriesSyncThread == null || !_seriesSyncThread.IsAlive) + Logger.Info("Syncing new series"); + + try { - Logger.Debug("Initializing background add of of series folder."); - _seriesSyncThread = new Thread(SyncUnmappedFolders) + using (_seriesSyncNotification = new ProgressNotification("Series Scan")) { - Name = "SyncUnmappedFolders", - Priority = ThreadPriority.Lowest - }; - - _syncList = new List(); - - var path = dir + Path.DirectorySeparatorChar + seriesName; - - //Create a directory for this new series - _diskProvider.CreateDirectory(path); + _notificationProvider.Register(_seriesSyncNotification); - //Add it to the list so it will be processed - _syncList.Add(new SeriesMappingModel { Path = path, TvDbId = seriesId, QualityProfileId = qualityProfileId }); + _seriesSyncNotification.CurrentStatus = "Finding New Series"; + ScanSeries(); - _seriesSyncThread.Start(); + _seriesSyncNotification.CurrentStatus = "Series Scan Completed"; + Logger.Info("Series folders scan has successfully completed."); + Thread.Sleep(3000); + _seriesSyncNotification.Status = ProgressNotificationStatus.Completed; + } } - else + catch (Exception e) { - 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; + Logger.ErrorException(e.Message, e); } - - //return true if sync has started - return true; } - public bool BeginAddExistingSeries(string path, int seriesId, int qualityProfileId) + private void ScanSeries() { - 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(); - //Add it to the list so it will be processed - _syncList.Add(new SeriesMappingModel { Path = path, TvDbId = seriesId, QualityProfileId = qualityProfileId }); + var syncList = _seriesProvider.GetAllSeries().Where(s => s.LastInfoSync == null).ToList(); + if (syncList.Count == 0) return; - _seriesSyncThread.Start(); - } - else + _seriesSyncNotification.ProgressMax = syncList.Count; + + foreach (var currentSeries in syncList) { - Logger.Warn("Series folder scan already in progress. Ignoring request."); + try + { + _seriesSyncNotification.CurrentStatus = String.Format("Searching For: {0}", new DirectoryInfo(currentSeries.Path).Name); + var updatedSeries = _seriesProvider.UpdateSeriesInfo(currentSeries.SeriesId); - //return false if sync was already running, then we can tell the user to try again later - return false; - } + _seriesSyncNotification.CurrentStatus = String.Format("Downloading episode info For: {0}", updatedSeries.Title); + _episodeProvider.RefreshEpisodeInfo(updatedSeries.SeriesId); - //return true if sync has started - return true; - } + _seriesSyncNotification.CurrentStatus = String.Format("Scanning series folder {0}", updatedSeries.Path); + _mediaFileProvider.Scan(_seriesProvider.GetSeries(updatedSeries.SeriesId)); - private void SyncUnmappedFolders() - { - Logger.Info("Starting Series folder scan"); + //Todo: Launch Backlog search for this series _backlogProvider.StartSearch(mappedSeries.Id); + } - try - { - using (_seriesSyncNotification = new ProgressNotification("Series Scan")) + catch (Exception e) { - _notificationProvider.Register(_seriesSyncNotification); - _seriesSyncNotification.CurrentStatus = "Analysing Folder"; - _seriesSyncNotification.ProgressMax = _syncList.Count; - - foreach (var seriesFolder in _syncList) - { - try - { - _seriesSyncNotification.CurrentStatus = String.Format("Searching For: {0}", new DirectoryInfo(seriesFolder.Path).Name); - - if (_seriesProvider.SeriesPathExists(Parser.NormalizePath(seriesFolder.Path))) - { - Logger.Debug("Folder '{0}' is mapped in the database. Skipping.'", seriesFolder); - continue; - } - - Logger.Debug("Folder '{0}' isn't mapped in the database. Trying to map it.'", seriesFolder); - var mappedSeries = _seriesProvider.MapPathToSeries(seriesFolder.TvDbId); - - if (mappedSeries == null) - { - Logger.Warn("Invalid TVDB ID '{0}' Unable to map: '{1}'", seriesFolder.TvDbId, seriesFolder.Path); - } - else - { - //Check if series is mapped to another folder - if (_seriesProvider.GetSeries(mappedSeries.Id) == null) - { - _seriesSyncNotification.CurrentStatus = String.Format("{0}: downloading series info...", mappedSeries.SeriesName); - _seriesProvider.AddSeries(seriesFolder.Path, mappedSeries, seriesFolder.QualityProfileId); - _episodeProvider.RefreshEpisodeInfo(mappedSeries.Id); - _seriesSyncNotification.CurrentStatus = String.Format("{0}: finding episodes on disk...", mappedSeries.SeriesName); - _mediaFileProvider.Scan(_seriesProvider.GetSeries(mappedSeries.Id)); - //Todo: Launch Backlog search for this series _backlogProvider.StartSearch(mappedSeries.Id); - } - else - { - Logger.Warn("Folder '{0}' mapped to '{1}' which is already another folder assigned to it.'", seriesFolder, mappedSeries.SeriesName); - } - } - } - catch (Exception e) - { - Logger.ErrorException(e.Message, e); - } - _seriesSyncNotification.ProgressValue++; - } - - _seriesSyncNotification.CurrentStatus = "Series Scan Completed"; - Logger.Info("Series folders scan has successfully completed."); - Thread.Sleep(3000); - _seriesSyncNotification.Status = ProgressNotificationStatus.Completed; + Logger.ErrorException(e.Message, e); } + _seriesSyncNotification.ProgressValue++; } - catch (Exception e) - { - Logger.ErrorException(e.Message, e); - } + + //Keep scanning until there no more shows left. + ScanSeries(); } } } diff --git a/NzbDrone.Core/Repository/Episode.cs b/NzbDrone.Core/Repository/Episode.cs index 5748cbf96..f7197bc02 100644 --- a/NzbDrone.Core/Repository/Episode.cs +++ b/NzbDrone.Core/Repository/Episode.cs @@ -21,6 +21,10 @@ namespace NzbDrone.Core.Repository public string Language { get; set; } public EpisodeStatusType Status { get; set; } + public DayOfWeek? LastInfoSync { get; set; } + + public DayOfWeek? LastDiskSync { get; set; } + [SubSonicToOneRelation(ThisClassContainsJoinKey = true)] public virtual Season Season { get; set; } diff --git a/NzbDrone.Core/Repository/Season.cs b/NzbDrone.Core/Repository/Season.cs index 26d952710..d8fadd580 100644 --- a/NzbDrone.Core/Repository/Season.cs +++ b/NzbDrone.Core/Repository/Season.cs @@ -11,6 +11,10 @@ namespace NzbDrone.Core.Repository public virtual int SeriesId { get; set; } public virtual int SeasonNumber { get; set; } public bool Monitored { get; set; } + + public DayOfWeek? LastInfoSync { get; set; } + + public DayOfWeek? LastDiskSync { get; set; } [SubSonicToManyRelation] public virtual List Episodes { get; private set; } diff --git a/NzbDrone.Core/Repository/Series.cs b/NzbDrone.Core/Repository/Series.cs index adbd7b214..011de2d11 100644 --- a/NzbDrone.Core/Repository/Series.cs +++ b/NzbDrone.Core/Repository/Series.cs @@ -11,21 +11,25 @@ namespace NzbDrone.Core.Repository [SubSonicPrimaryKey(false)] public virtual int SeriesId { get; set; } + [SubSonicNullString] public string Title { get; set; } + [SubSonicNullString] public string CleanTitle { get; set; } [SubSonicNullString] public string Status { get; set; } - [SubSonicLongString] + [SubSonicNullString] public string Overview { get; set; } [DisplayName("Air on")] public DayOfWeek? AirsDayOfWeek { get; set; } + [SubSonicNullString] public String AirTimes { get; set; } + [SubSonicNullString] public string Language { get; set; } public string Path { get; set; } @@ -36,6 +40,10 @@ namespace NzbDrone.Core.Repository public bool SeasonFolder { get; set; } + public DateTime? LastInfoSync { get; set; } + + public DateTime? LastDiskSync { get; set; } + [SubSonicToOneRelation(ThisClassContainsJoinKey = true, JoinKeyName = "QualityProfileId")] public virtual QualityProfile QualityProfile { get; private set; } diff --git a/NzbDrone.Web/Content/style.css b/NzbDrone.Web/Content/style.css index 762d498b9..b02e2c9e8 100644 --- a/NzbDrone.Web/Content/style.css +++ b/NzbDrone.Web/Content/style.css @@ -214,17 +214,7 @@ hr margin-bottom: 10px; } -input[type="text"] -{ - border: 1px solid #006; - background: #CBE8FF; -} -input[type="text"]:hover -{ - border: 1px solid #065EFE; - background: #C0D6FF; -} input[type="button"], input[type="submit"], input[type="reset"], input[type="file"]::-webkit-file-upload-button, button { @@ -236,6 +226,12 @@ input[type="button"], input[type="submit"], input[type="reset"], input[type="fil margin: 10px; } +.listButton +{ + padding: 1px 10px 2px 10px; + margin: 0px; +} + #save_button { } diff --git a/NzbDrone.Web/Controllers/AddSeriesController.cs b/NzbDrone.Web/Controllers/AddSeriesController.cs new file mode 100644 index 000000000..01495d232 --- /dev/null +++ b/NzbDrone.Web/Controllers/AddSeriesController.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using NzbDrone.Core.Providers; +using NzbDrone.Web.Models; + +namespace NzbDrone.Web.Controllers +{ + public class AddSeriesController : Controller + { + public IConfigProvider ConfigProvider { get; set; } + private readonly ISyncProvider _syncProvider; + private readonly IRootDirProvider _rootFolderProvider; + private readonly IConfigProvider _configProvider; + private readonly IQualityProvider _qualityProvider; + private readonly ITvDbProvider _tvDbProvider; + private readonly ISeriesProvider _seriesProvider; + + public AddSeriesController(ISyncProvider syncProvider, IRootDirProvider rootFolderProvider, IConfigProvider configProvider, + IQualityProvider qualityProvider, ITvDbProvider tvDbProvider, ISeriesProvider seriesProvider) + { + ConfigProvider = configProvider; + _syncProvider = syncProvider; + _rootFolderProvider = rootFolderProvider; + _configProvider = configProvider; + _qualityProvider = qualityProvider; + _tvDbProvider = tvDbProvider; + _seriesProvider = seriesProvider; + } + + [HttpPost] + public JsonResult ScanNewSeries() + { + _syncProvider.BeginUpdateNewSeries(); + return new JsonResult(); + } + + public ActionResult AddNew() + { + ViewData["RootDirs"] = _rootFolderProvider.GetAll(); + ViewData["DirSep"] = Path.DirectorySeparatorChar; + + var profiles = _qualityProvider.GetAllProfiles(); + var selectList = new SelectList(profiles, "QualityProfileId", "Name"); + var defaultQuality = Convert.ToInt32(_configProvider.DefaultQualityProfile); + + var model = new AddNewSeriesModel + { + DirectorySeparatorChar = Path.DirectorySeparatorChar.ToString(), + RootDirectories = _rootFolderProvider.GetAll(), + QualityProfileId = defaultQuality, + QualitySelectList = selectList + }; + + return View(model); + } + + public ActionResult AddExisting() + { + var defaultQuality = _configProvider.DefaultQualityProfile; + var profiles = _qualityProvider.GetAllProfiles(); + var selectList = new SelectList(profiles, "QualityProfileId", "Name"); + + ViewData["QualityProfileId"] = defaultQuality; + ViewData["QualitySelectList"] = selectList; + + var unmappedList = new List(); + + foreach (var folder in _rootFolderProvider.GetAll()) + { + unmappedList.AddRange(_syncProvider.GetUnmappedFolders(folder.Path)); + } + + return View(unmappedList); + } + + public ActionResult AddExistingManual(string path) + { + var profiles = _qualityProvider.GetAllProfiles(); + var selectList = new SelectList(profiles, "QualityProfileId", "Name"); + var defaultQuality = _configProvider.DefaultQualityProfile; + + var model = new AddExistingManualModel(); + model.Path = path; + model.FolderName = new DirectoryInfo(path).Name; + model.QualityProfileId = defaultQuality; + model.QualitySelectList = selectList; + + return View(model); + } + + + public ActionResult RenderPartial(string path) + { + var dataVal = _tvDbProvider.SearchSeries(new DirectoryInfo(path).Name); + var names = dataVal.Select(tvdb => tvdb.SeriesName).ToList(); + + if (dataVal.Count == 0) return null; + var ids = dataVal.Select(tvdb => tvdb.Id).ToList(); + var list = new SelectList(dataVal, "Id", "SeriesName"); + + ViewData["guid"] = Guid.NewGuid(); + ViewData["path"] = path; + ViewData["javaPath"] = path.Replace(Path.DirectorySeparatorChar, '|').Replace(Path.VolumeSeparatorChar, '^'); + return PartialView("AddSeriesItem", list); + + } + + + public JsonResult AddSeries(string path, int seriesId, int qualityProfileId) + { + //Get TVDB Series Name + //Create new folder for series + //Add the new series to the Database + + _seriesProvider.AddSeries(path.Replace('|', Path.DirectorySeparatorChar).Replace('^', Path.VolumeSeparatorChar), seriesId, qualityProfileId); + ScanNewSeries(); + return new JsonResult() { Data = "ok" }; + } + + } +} diff --git a/NzbDrone.Web/Controllers/SeriesController.cs b/NzbDrone.Web/Controllers/SeriesController.cs index 56c84544f..49f910f84 100644 --- a/NzbDrone.Web/Controllers/SeriesController.cs +++ b/NzbDrone.Web/Controllers/SeriesController.cs @@ -61,52 +61,9 @@ namespace NzbDrone.Web.Controllers return View(); } - public ActionResult AddExisting() - { - var defaultQuality = Convert.ToInt32(_configProvider.GetValue("DefaultQualityProfile", "1", true)); - var profiles = _qualityProvider.GetAllProfiles(); - var selectList = new SelectList(profiles, "QualityProfileId", "Name"); - - ViewData["QualityProfileId"] = defaultQuality; - ViewData["QualitySelectList"] = selectList; - - return View(); - } + - public ActionResult AddNew() - { - ViewData["RootDirs"] = _rootDirProvider.GetAll(); - ViewData["DirSep"] = Path.DirectorySeparatorChar; - var profiles = _qualityProvider.GetAllProfiles(); - var selectList = new SelectList(profiles, "QualityProfileId", "Name"); - var defaultQuality = Convert.ToInt32(_configProvider.GetValue("DefaultQualityProfile", "1", true)); - - var model = new AddNewSeriesModel - { - DirectorySeparatorChar = Path.DirectorySeparatorChar.ToString(), - RootDirectories = _rootDirProvider.GetAll(), - QualityProfileId = defaultQuality, - QualitySelectList = selectList - }; - - return View(model); - } - - public ActionResult AddExistingManual(string path) - { - var profiles = _qualityProvider.GetAllProfiles(); - var selectList = new SelectList(profiles, "QualityProfileId", "Name"); - var defaultQuality = Convert.ToInt32(_configProvider.GetValue("DefaultQualityProfile", "1", true)); - - var model = new AddExistingManualModel(); - model.Path = path; - model.FolderName = _diskProvider.GetFolderName(path); - model.QualityProfileId = defaultQuality; - model.QualitySelectList = selectList; - - return View(model); - } public ActionResult RssSync() { @@ -187,41 +144,6 @@ namespace NzbDrone.Web.Controllers return View(new GridModel(unmappedList)); } - public ActionResult SyncSelectedSeries(string path, int tvdbId, int qualityProfileId) - { - var unmappedList = new List(); - - //If the TvDbId for this show is 0 then skip it... User made a mistake... They will have to manually map it - if (tvdbId < 1) throw new ArgumentException("Invalid tvdb id", "tvdbId"); - - unmappedList.Add(new SeriesMappingModel { Path = path, TvDbId = tvdbId, QualityProfileId = qualityProfileId }); - - return Content("Ok"); - } - - public ActionResult AddNewSeries(string dir, int seriesId, string seriesName, int qualityProfileId) - { - //Get TVDB Series Name - //Create new folder for series - //Add the new series to the Database - - if (_syncProvider.BeginAddNewSeries(dir, seriesId, seriesName, qualityProfileId)) - return Content("Adding new series has started."); - - return Content("Unable to add new series, please wait for previous scans to complete first."); - } - - public ActionResult AddExistingSeries(string path, int seriesId, int qualityProfileId) - { - //Get TVDB Series Name - //Create new folder for series - //Add the new series to the Database - - if (_syncProvider.BeginAddExistingSeries(path, seriesId, qualityProfileId)) - 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) { diff --git a/NzbDrone.Web/Controllers/SettingsController.cs b/NzbDrone.Web/Controllers/SettingsController.cs index 5412434e7..7e9a95add 100644 --- a/NzbDrone.Web/Controllers/SettingsController.cs +++ b/NzbDrone.Web/Controllers/SettingsController.cs @@ -162,7 +162,7 @@ namespace NzbDrone.Web.Controllers model.ReplaceSpaces = Convert.ToBoolean(_configProvider.GetValue("Sorting_ReplaceSpaces", false, true)); model.AppendQuality = Convert.ToBoolean(_configProvider.GetValue("Sorting_AppendQuality", false, true)); model.UseAirByDate = Convert.ToBoolean(_configProvider.GetValue("Sorting_UseAirByDate", true, true)); - model.SeasonFolders = Convert.ToBoolean(_configProvider.GetValue("Sorting_SeasonFolder", true, true)); + model.SeasonFolders = _configProvider.UseSeasonFolder; model.SeasonFolderFormat = _configProvider.GetValue("Sorting_SeasonFolderFormat", "Season %s", true); model.SeparatorStyle = Convert.ToInt32(_configProvider.GetValue("Sorting_SeparatorStyle", 0, true)); model.NumberStyle = Convert.ToInt32(_configProvider.GetValue("Sorting_NumberStyle", 2, true)); diff --git a/NzbDrone.Web/NzbDrone.Web.csproj b/NzbDrone.Web/NzbDrone.Web.csproj index f1ed7e26f..0af7be141 100644 --- a/NzbDrone.Web/NzbDrone.Web.csproj +++ b/NzbDrone.Web/NzbDrone.Web.csproj @@ -14,6 +14,7 @@ NzbDrone.Web v4.0 true + false false @@ -27,6 +28,8 @@ 4 x86 false + true + false pdbonly @@ -35,6 +38,8 @@ TRACE prompt 4 + true + false @@ -186,6 +191,7 @@ + @@ -600,19 +606,17 @@ + - - - - + + + - - @@ -642,14 +646,11 @@ - - - diff --git a/NzbDrone.Web/Views/AddSeries/AddExisting.aspx b/NzbDrone.Web/Views/AddSeries/AddExisting.aspx new file mode 100644 index 000000000..cdd4c5754 --- /dev/null +++ b/NzbDrone.Web/Views/AddSeries/AddExisting.aspx @@ -0,0 +1,17 @@ +<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage>" %> + +<%@ Import Namespace="Telerik.Web.Mvc.UI" %> +<%@ Import Namespace="NzbDrone.Web.Models" %> + + Add Existing Series + + + <%: Html.DropDownList("qualityProfileId", (SelectList)ViewData["QualitySelectList"], ViewData["QualityProfileId"])%> + <% + foreach (var path in Model) + { + Html.RenderAction("RenderPartial", "AddSeries", new { path }); + } + + %> + diff --git a/NzbDrone.Web/Views/Series/AddExistingManual.aspx b/NzbDrone.Web/Views/AddSeries/AddExistingManual.aspx similarity index 93% rename from NzbDrone.Web/Views/Series/AddExistingManual.aspx rename to NzbDrone.Web/Views/AddSeries/AddExistingManual.aspx index 1e792bb7f..ab73b84ad 100644 --- a/NzbDrone.Web/Views/Series/AddExistingManual.aspx +++ b/NzbDrone.Web/Views/AddSeries/AddExistingManual.aspx @@ -11,11 +11,6 @@ - - <% - Html.RenderPartial("SubMenu"); - %> -
@@ -86,7 +81,7 @@ var pathTest = $('#series_path').val(); $('#tester').text(pathTest); - $("#addResult").load('<%=Url.Action("AddExistingSeries", "Series") %>', { + $("#addResult").load('<%=Url.Action("AddExistingManual", "AddSeries") %>', { path: pathTest, seriesId: checkedSeries, qualityProfileId: qualityProfileId diff --git a/NzbDrone.Web/Views/Series/AddNew.aspx b/NzbDrone.Web/Views/AddSeries/AddNew.aspx similarity index 94% rename from NzbDrone.Web/Views/Series/AddNew.aspx rename to NzbDrone.Web/Views/AddSeries/AddNew.aspx index 82ca63d0c..c2f72eaef 100644 --- a/NzbDrone.Web/Views/Series/AddNew.aspx +++ b/NzbDrone.Web/Views/AddSeries/AddNew.aspx @@ -11,11 +11,6 @@ }); - - <% - Html.RenderPartial("SubMenu"); - %> -
@@ -83,7 +78,7 @@ var seriesName = $(id).val(); var qualityProfileId = $("#QualityProfileId").val(); - $("#addResult").load('<%=Url.Action("AddNewSeries", "Series") %>', { + $("#addResult").load('<%=Url.Action("AddSeries", "Series") %>', { dir: checkedDir, seriesId: checkedSeries, seriesName: seriesName, diff --git a/NzbDrone.Web/Views/AddSeries/AddSeriesItem.ascx b/NzbDrone.Web/Views/AddSeries/AddSeriesItem.ascx new file mode 100644 index 000000000..08f1f7caa --- /dev/null +++ b/NzbDrone.Web/Views/AddSeries/AddSeriesItem.ascx @@ -0,0 +1,47 @@ +<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> +
"> +
+ <%=ViewData["path"].ToString() %> +
+
+ <% + Html.Telerik().ComboBox() + .Name(ViewData["guid"].ToString()) + // .AutoFill(true) + .BindTo(Model) + // .DataBinding(b => b.Ajax().Select("TvDbLookup", "AddSeries")) + .Filterable(f => f.FilterMode(AutoCompleteFilterMode.Contains)) + .HighlightFirstMatch(true) + .HtmlAttributes(new { style = "width:70%; align:right" }) + .SelectedIndex(0) + .Render(); + %> + +
+
+ diff --git a/NzbDrone.Web/Views/Home/About.aspx b/NzbDrone.Web/Views/Home/About.aspx deleted file mode 100644 index 335c141b7..000000000 --- a/NzbDrone.Web/Views/Home/About.aspx +++ /dev/null @@ -1,12 +0,0 @@ -<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %> - - - About Us - - - -

About

-

- Put content here. -

-
diff --git a/NzbDrone.Web/Views/Home/Index.aspx b/NzbDrone.Web/Views/Home/Index.aspx deleted file mode 100644 index 495767f1e..000000000 --- a/NzbDrone.Web/Views/Home/Index.aspx +++ /dev/null @@ -1,19 +0,0 @@ -<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %> - -<%@ Import Namespace="Telerik.Web.Mvc.UI" %> - - Logs - - - <% - Html.Telerik().Menu().Name("logMenu").Items(items => items.Add().Text("Clear Logs").Action("Clear", "Log")).Render(); - %> - - -

- <%: ViewData["Message"] %>

-

- To learn more about ASP.NET MVC visit - http://asp.net/mvc. -

-
diff --git a/NzbDrone.Web/Views/Home/Test.aspx b/NzbDrone.Web/Views/Home/Test.aspx deleted file mode 100644 index 608b60db6..000000000 --- a/NzbDrone.Web/Views/Home/Test.aspx +++ /dev/null @@ -1,31 +0,0 @@ -<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %> - - - Test - - - - -

Test

- - <% using (Html.BeginForm("Test", "Home", FormMethod.Post, new { id = "form", name = "form" })) - {%> - -
One: <%=Html.RadioButtonFor(t => t.Number, 1)%>
-
Two: <%=Html.RadioButtonFor(t => t.Number, 2)%>
-
Three: <%=Html.RadioButtonFor(t => t.Number, 3)%>
-
Four: <%=Html.RadioButtonFor(t => t.Number, 4)%>
- - - <% } %> - -
- - - - - - - - - diff --git a/NzbDrone.Web/Views/Series/AddExisting.aspx b/NzbDrone.Web/Views/Series/AddExisting.aspx deleted file mode 100644 index 4852f8c75..000000000 --- a/NzbDrone.Web/Views/Series/AddExisting.aspx +++ /dev/null @@ -1,133 +0,0 @@ -<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %> - -<%@ Import Namespace="Telerik.Web.Mvc.UI" %> -<%@ Import Namespace="NzbDrone.Web.Models" %> - - Add Existing Series - - - <% - Html.RenderPartial("SubMenu"); - %> - - - - <%= Html.Label("Quality Profile")%> - <%: Html.DropDownList("qualityProfileId", (SelectList)ViewData["QualitySelectList"], ViewData["QualityProfileId"])%> - -
-
- -
diff --git a/NzbDrone.Web/Views/Series/EpisodeDetail.ascx b/NzbDrone.Web/Views/Series/EpisodeDetail.ascx deleted file mode 100644 index 67d7fc94a..000000000 --- a/NzbDrone.Web/Views/Series/EpisodeDetail.ascx +++ /dev/null @@ -1,14 +0,0 @@ -<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> -<%@ Import Namespace="Telerik.Web.Mvc.UI" %> -<%: Model.Overview %> -<%--<%: - Html.Telerik().Grid(Model.Files) - .Name("files_" + Model.EpisodeId) - .Columns(columns => - { - columns.Bound(c => c.Path); - columns.Bound(c => c.Quality); - columns.Bound(c => c.DateAdded); - }) - .Footer(false) -%>--%> \ No newline at end of file diff --git a/NzbDrone.Web/Views/Series/SubMenu.ascx b/NzbDrone.Web/Views/Series/SubMenu.ascx index a0cb233a9..d7ddd8ebb 100644 --- a/NzbDrone.Web/Views/Series/SubMenu.ascx +++ b/NzbDrone.Web/Views/Series/SubMenu.ascx @@ -1,12 +1,12 @@ <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> -<%@ Import Namespace="Telerik.Web.Mvc.UI" %> +<%@ Import Namespace="NzbDrone.Web.Controllers" %> <% Html.Telerik().Menu().Name("telerikGrid").Items(items => { items.Add().Text("Add Series") - .Items(subItem => subItem.Add().Text("New Series").Action("AddNew", "Series")) - .Items(subItem => subItem.Add().Text("Existing Series").Action("AddExisting", "Series")); + .Items(subItem => subItem.Add().Text("New Series").Action(c => c.AddNew())) + .Items(subItem => subItem.Add().Text("Existing Series").Action(c => c.AddExisting())); - items.Add().Text("Start RSS Sync").Action("RssSync", "Series"); - items.Add().Text("Rename All").Action("RenameAll", "Series"); + items.Add().Text("Start RSS Sync").Action(c => c.RssSync()); + items.Add().Text("Rename All").Action(c => c.RenameAll()); }).Render(); %> \ No newline at end of file diff --git a/NzbDrone.Web/Views/Series/Unmapped.aspx b/NzbDrone.Web/Views/Series/Unmapped.aspx deleted file mode 100644 index 8255d7470..000000000 --- a/NzbDrone.Web/Views/Series/Unmapped.aspx +++ /dev/null @@ -1,28 +0,0 @@ -<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage>" %> - -<%@ Import Namespace="Telerik.Web.Mvc.UI" %> - - Unmapped - - -

- The following folders aren't currently mapped to any Series.

-

- Please Re-sync your folders. If the problem persists try renaming your folders to - something more similar to the name of series they contain.

- <%= Html.Telerik().Grid(Model) - .Name("Grid") - .DataKeys(dataKeys => dataKeys.Add(c => c.Id)) - .DataBinding(dataBinding => dataBinding - //Server binding - .Ajax() - .Select("UnMapped", "Series") - .Update("Update", "Home") - ) - .Columns(columns => - { - columns.Bound(c => c.Path); - columns.Command(commands => commands.Edit()); - }) - %> -
diff --git a/NzbDrone.Web/Views/Series/index.aspx b/NzbDrone.Web/Views/Series/index.aspx index f10b8df90..d103bd73c 100644 --- a/NzbDrone.Web/Views/Series/index.aspx +++ b/NzbDrone.Web/Views/Series/index.aspx @@ -19,14 +19,14 @@ columns.Template(c => { %> - <%:Html.ActionLink(c.Title, "Details", new {seriesId =c.SeriesId}) %> + <%:Html.ActionLink(c.Title??"New Series", "Details", new {seriesId =c.SeriesId}) %> <% - }).Title("Title"); - columns.Bound(o => o.Seasons.Count).Title("Seasons"); - columns.Bound(o => o.QualityProfile.Name).Title("Quality"); - columns.Bound(o => o.Status); - columns.Bound(o => o.AirsDayOfWeek); - columns.Bound(o => o.Path); + }).Title("Title"); + columns.Bound(o => o.Seasons.Count).Title("Seasons"); + columns.Bound(o => o.QualityProfile.Name).Title("Quality"); + columns.Bound(o => o.Status); + columns.Bound(o => o.AirsDayOfWeek); + columns.Bound(o => o.Path); }) .Sortable(sort => sort.OrderBy(order => order.Add(o => o.Title).Ascending()).Enabled(false))