diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index 0eb47a119..6507a24a8 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -138,9 +138,9 @@ False ..\Libraries\Migrator.NET\Migrator.Providers.dll - + False - ..\packages\MiniProfiler.1.4\lib\MvcMiniProfiler.dll + ..\packages\MiniProfiler.1.6\lib\MvcMiniProfiler.dll ..\packages\Ninject.2.2.1.4\lib\net40-Full\Ninject.dll diff --git a/NzbDrone.Core/Parser.cs b/NzbDrone.Core/Parser.cs index 0d983fd6b..dc4a7e441 100644 --- a/NzbDrone.Core/Parser.cs +++ b/NzbDrone.Core/Parser.cs @@ -398,5 +398,16 @@ public static string NormalizePath(string path) return info.FullName.Trim('/', '\\', ' '); } + + public static string UppercaseFirst(string s) + { + // Check for empty string. + if (string.IsNullOrEmpty(s)) + { + return string.Empty; + } + // Return char and concat substring. + return char.ToUpper(s[0]) + s.Substring(1); + } } } diff --git a/NzbDrone.Core/Providers/EpisodeProvider.cs b/NzbDrone.Core/Providers/EpisodeProvider.cs index a3284ed86..416def223 100644 --- a/NzbDrone.Core/Providers/EpisodeProvider.cs +++ b/NzbDrone.Core/Providers/EpisodeProvider.cs @@ -197,12 +197,12 @@ public virtual void RefreshEpisodeInfo(Series series) Logger.Trace("Updating info for [{0}] - S{1}E{2}", tvDbSeriesInfo.SeriesName, episode.SeasonNumber, episode.EpisodeNumber); //first check using tvdbId, this should cover cases when and episode number in a season is changed - var episodeToUpdate = seriesEpisodes.Where(e => e.TvDbEpisodeId == episode.Id).FirstOrDefault(); + var episodeToUpdate = seriesEpisodes.Where(e => e.TvDbEpisodeId == episode.Id).SingleOrDefault(); //not found, try using season/episode number if (episodeToUpdate == null) { - episodeToUpdate = seriesEpisodes.Where(e => e.SeasonNumber == episode.SeasonNumber && e.EpisodeNumber == episode.EpisodeNumber).FirstOrDefault(); + episodeToUpdate = seriesEpisodes.Where(e => e.SeasonNumber == episode.SeasonNumber && e.EpisodeNumber == episode.EpisodeNumber).SingleOrDefault(); } //Episode doesn't exist locally diff --git a/NzbDrone.Core/Providers/Jobs/JobProvider.cs b/NzbDrone.Core/Providers/Jobs/JobProvider.cs index 4c15457b1..549fbd6fa 100644 --- a/NzbDrone.Core/Providers/Jobs/JobProvider.cs +++ b/NzbDrone.Core/Providers/Jobs/JobProvider.cs @@ -171,31 +171,34 @@ private void ProcessQueue() { Tuple job = null; - try + using (NestedDiagnosticsContext.Push(Guid.NewGuid().ToString())) { - lock (Queue) + try { - if (Queue.Count != 0) + lock (Queue) { - job = Queue.First(); + if (Queue.Count != 0) + { + job = Queue.First(); + } } - } - if (job != null) - { - Execute(job.Item1, job.Item2); - } + if (job != null) + { + Execute(job.Item1, job.Item2); + } - } - catch (Exception e) - { - Logger.FatalException("An error has occurred while processing queued job.", e); - } - finally - { - if (job != null) + } + catch (Exception e) { - Queue.Remove(job); + Logger.FatalException("An error has occurred while processing queued job.", e); + } + finally + { + if (job != null) + { + Queue.Remove(job); + } } } @@ -214,14 +217,14 @@ private void ProcessQueue() /// to allow it to filter it's target of execution private void Execute(Type jobType, int targetId = 0) { - var jobImplementation = _jobs.Where(t => t.GetType() == jobType).FirstOrDefault(); + var jobImplementation = _jobs.Where(t => t.GetType() == jobType).Single(); if (jobImplementation == null) { Logger.Error("Unable to locate implementation for '{0}'. Make sure it is properly registered.", jobType); return; } - var settings = All().Where(j => j.TypeName == jobType.ToString()).FirstOrDefault(); + var settings = All().Where(j => j.TypeName == jobType.ToString()).Single(); using (_notification = new ProgressNotification(jobImplementation.Name)) { @@ -294,11 +297,7 @@ public virtual void Initialize() /// DateTime of next scheduled job execution public virtual DateTime NextScheduledRun(Type jobType) { - var job = All().Where(t => t.TypeName == jobType.ToString()).FirstOrDefault(); - - if (job == null) - return DateTime.Now; - + var job = All().Where(t => t.TypeName == jobType.ToString()).Single(); return job.LastExecution.AddMinutes(job.Interval); } } diff --git a/NzbDrone.Core/Providers/RootDirProvider.cs b/NzbDrone.Core/Providers/RootDirProvider.cs index fcd574f05..a7111e353 100644 --- a/NzbDrone.Core/Providers/RootDirProvider.cs +++ b/NzbDrone.Core/Providers/RootDirProvider.cs @@ -74,7 +74,9 @@ public List GetUnmappedFolders(string path) var cleanPath = Parser.NormalizePath(new DirectoryInfo(seriesFolder).FullName); if (!_seriesProvider.SeriesPathExists(cleanPath)) + { results.Add(cleanPath); + } } Logger.Debug("{0} unmapped folders detected.", results.Count); diff --git a/NzbDrone.Core/Providers/SeriesProvider.cs b/NzbDrone.Core/Providers/SeriesProvider.cs index ac908c260..8daeb1c89 100644 --- a/NzbDrone.Core/Providers/SeriesProvider.cs +++ b/NzbDrone.Core/Providers/SeriesProvider.cs @@ -130,7 +130,7 @@ public virtual Series FindSeries(string title) var series = _database.Fetch(@"SELECT * FROM Series INNER JOIN QualityProfiles ON Series.QualityProfileId = QualityProfiles.QualityProfileId - WHERE CleanTitle = @0", normalizeTitle).FirstOrDefault(); + WHERE CleanTitle = @0", normalizeTitle).SingleOrDefault(); return series; } diff --git a/NzbDrone.Core/packages.config b/NzbDrone.Core/packages.config index 399a6aebb..462426294 100644 --- a/NzbDrone.Core/packages.config +++ b/NzbDrone.Core/packages.config @@ -2,5 +2,5 @@ - + \ No newline at end of file diff --git a/NzbDrone.Web/Content/ActionButton.css b/NzbDrone.Web/Content/ActionButton.css index 83b4fd123..4727720a2 100644 --- a/NzbDrone.Web/Content/ActionButton.css +++ b/NzbDrone.Web/Content/ActionButton.css @@ -1,7 +1,7 @@ .actionButton { - margin: 5px 5px 5px 5px; - padding: 5px 10px 5px 10px; + margin: 5px; + padding: 2px 5px; background-repeat: no-repeat; background-position: 5px center; background-color: #cccccc; @@ -14,7 +14,7 @@ cursor: pointer; vertical-align: middle; position: relative; - bottom: 1px; + bottom: 3px; } .delete diff --git a/NzbDrone.Web/Content/Blueprint/screen.css b/NzbDrone.Web/Content/Blueprint/screen.css index a66a8f804..69f2d5ec0 100644 --- a/NzbDrone.Web/Content/Blueprint/screen.css +++ b/NzbDrone.Web/Content/Blueprint/screen.css @@ -46,7 +46,6 @@ table caption, th, td { text-align: left; - font-weight: normal; float: none !important; } table, th, td @@ -80,11 +79,9 @@ body font-size: 75%; color: #222; background: #fff; - font-family: "Helvetica Neue" , Arial, Helvetica, sans-serif; } h1, h2, h3, h4, h5, h6 { - font-weight: normal; color: #111; } h1 @@ -100,21 +97,19 @@ h2 } h3 { + margin-top: 0.75em; font-size: 1.5em; line-height: 1; - margin-bottom: 1em; } h4 { font-size: 1.2em; line-height: 1.25; - margin-bottom: 1.25em; } h5 { font-size: 1em; font-weight: bold; - margin-bottom: 1.5em; } h6 { @@ -162,10 +157,7 @@ blockquote color: #666; font-style: italic; } -strong, dfn -{ - font-weight: bold; -} + em, dfn { font-style: italic; @@ -192,11 +184,7 @@ pre margin: 1.5em 0; white-space: pre; } -pre, code, tt -{ - font: 1em 'andale mono' , 'lucida console' , monospace; - line-height: 1.5; -} + li ul, li ol { margin: 0; @@ -218,10 +206,7 @@ dl { margin: 0 0 1.5em 0; } -dl dt -{ - font-weight: bold; -} + dd { margin-left: 1.5em; @@ -231,10 +216,7 @@ table margin-bottom: 1.4em; width: 100%; } -th -{ - font-weight: bold; -} + thead th { background: #c3d9ff; @@ -323,7 +305,6 @@ fieldset } legend { - font-weight: bold; font-size: 1.2em; margin-top: -0.2em; margin-bottom: 1em; diff --git a/NzbDrone.Web/Content/NzbDrone.css b/NzbDrone.Web/Content/NzbDrone.css index 0d8a5822e..a24bb934a 100644 --- a/NzbDrone.Web/Content/NzbDrone.css +++ b/NzbDrone.Web/Content/NzbDrone.css @@ -1,17 +1,25 @@ -h1, h2, h3 + +* { - color: #000000; + font-family: "Segoe UI" , "Segoe UI Light" , Tahoma, Geneva, sans-serif; } body { background: #191919 url(images/img07.jpg) no-repeat right top; - font-family: "Segoe UI" , "Segoe UI Light" , Tahoma, Geneva, sans-serif !important; font-size: 13px; color: #3C3C3C; background-attachment: fixed; } +h1, h2, h3, h4, h5, h6 +{ + font-family: "Segoe UI Light" , "Segoe UI" , Tahoma, Geneva, sans-serif; + color: #3C3C3C; + font-weight: 300; +} + + fieldset { border-style: solid; @@ -60,7 +68,6 @@ hr text-align: center; text-transform: lowercase; font-size: 17px; - font-weight: normal; vertical-align: middle; height: 28px; } @@ -160,8 +167,6 @@ button, input[type="button"], input[type="submit"], input[type="reset"] background-color: #065EFE; border-style: solid; border-color: #065EFE; - padding: 5px 10px 5px 10px; - margin: 10px; } button:active, input[type="button"]:active, input[type="submit"]:active, input[type="reset"]:active @@ -171,17 +176,20 @@ button:active, input[type="button"]:active, input[type="submit"]:active, input[t input[type=text], select { - font-size: larger; - padding: 4px 2px; + font-size: small; + padding: 2px 2px; border: solid 1px #aacfe4; width: 200px; - margin: 2px 0 10px 10px; + margin: 2px 0 10px 0px; height: 20px; } -select + +select, button, input[type="button"], input[type="submit"], input[type="reset"] { - height: 30px; + height: 26px; + min-width: 50px; + margin-left: 10px; } .listButton @@ -229,4 +237,11 @@ select { margin-left: auto; margin-right: auto; +} + + +.qualitySelector +{ + min-width: 60px; + width: auto; } \ No newline at end of file diff --git a/NzbDrone.Web/Content/Overrides.css b/NzbDrone.Web/Content/Overrides.css index 36c187f82..39d6bc0bc 100644 --- a/NzbDrone.Web/Content/Overrides.css +++ b/NzbDrone.Web/Content/Overrides.css @@ -16,3 +16,8 @@ { font-weight: normal; } + +.t-combobox .t-input +{ + line-height: 25px; +} diff --git a/NzbDrone.Web/Controllers/AddSeriesController.cs b/NzbDrone.Web/Controllers/AddSeriesController.cs index 4caf1d731..61ad6a275 100644 --- a/NzbDrone.Web/Controllers/AddSeriesController.cs +++ b/NzbDrone.Web/Controllers/AddSeriesController.cs @@ -67,70 +67,61 @@ public ActionResult AddNew() public ActionResult Index() { - var rootDirs = _rootFolderProvider.GetAll(); - - var profiles = _qualityProvider.All(); - var defaultQuality = Convert.ToInt32(_configProvider.DefaultQualityProfile); - var selectList = new SelectList(profiles, "QualityProfileId", "Name", defaultQuality); - ViewData["qualities"] = selectList; - ViewData["ShowRootDirs"] = false; - - //There are no RootDirs Show the RootDirs Panel - if (rootDirs.Count == 0) - ViewData["ShowRootDirs"] = true; - - return View(rootDirs); + return View(); } - public ActionResult AddExisting() + public ActionResult ExistingSeries() { - var rootDirs = _rootFolderProvider.GetAll(); + var result = new ExistingSeriesModel(); var unmappedList = new List(); - foreach (var folder in rootDirs) + foreach (var folder in _rootFolderProvider.GetAll()) { unmappedList.AddRange(_rootFolderProvider.GetUnmappedFolders(folder.Path)); } - return View(unmappedList); - } + result.ExistingSeries = new List>(); - public ActionResult RenderPartial(string path) - { - var suggestions = GetSuggestionList(new DirectoryInfo(path).Name); + foreach (var folder in unmappedList) + { + var foldername = new DirectoryInfo(folder).Name; + var tvdbResult = _tvDbProvider.SearchSeries(foldername).FirstOrDefault(); - ViewData["guid"] = Guid.NewGuid(); - ViewData["path"] = path; - ViewData["javaPath"] = path.Replace(Path.DirectorySeparatorChar, '|').Replace(Path.VolumeSeparatorChar, '^').Replace('\'', '`'); + var title = String.Empty; + if (tvdbResult != null) + { + title = tvdbResult.SeriesName; + } - var defaultQuality = _configProvider.DefaultQualityProfile; - var qualityProfiles = _qualityProvider.All(); + result.ExistingSeries.Add(new Tuple(folder, title)); + } - ViewData["quality"] = new SelectList( - qualityProfiles, - "QualityProfileId", - "Name", - defaultQuality); + var defaultQuality = Convert.ToInt32(_configProvider.DefaultQualityProfile); + result.Quality = new SelectList(_qualityProvider.All(), "QualityProfileId", "Name", defaultQuality); - return PartialView("AddSeriesItem", suggestions); + return View(result); } [HttpPost] - public JsonResult AddNewSeries(string rootPath, string seriesName, int seriesId, int qualityProfileId) + public JsonResult AddNewSeries(string path, string seriesName, int qualityProfileId) + { + path = Path.Combine(path, MediaFileProvider.CleanFilename(seriesName)); + return AddExistingSeries(path, seriesName, qualityProfileId); + } + + [HttpPost] + public JsonResult AddExistingSeries(string path, string seriesName, int qualityProfileId) { try { - var path = Path.Combine(rootPath.Replace('|', Path.DirectorySeparatorChar) - .Replace('^', Path.VolumeSeparatorChar) - .Replace('`', '\''), - MediaFileProvider.CleanFilename(seriesName)); - //Create the folder for the new series and then Add it _diskProvider.CreateDirectory(path); - _seriesProvider.AddSeries(path, seriesId, qualityProfileId); + var series = _tvDbProvider.SearchSeries(seriesName).Where(s => s.SeriesName == seriesName).Single(); + + _seriesProvider.AddSeries(path, series.Id, qualityProfileId); ScanNewSeries(); return new JsonResult { Data = "ok" }; } @@ -154,30 +145,6 @@ public JsonResult AddSeries(string path, int seriesId, int qualityProfileId) return new JsonResult { Data = "ok" }; } - [HttpPost] - public ActionResult _textLookUp(string text, int? filterMode) - { - var suggestions = GetSuggestionList(text); - - return new JsonResult - { - JsonRequestBehavior = JsonRequestBehavior.AllowGet, - Data = suggestions - }; - } - - public SelectList GetSuggestionList(string searchString) - { - var dataVal = _tvDbProvider.SearchSeries(searchString); - - int selectId = 0; - if (dataVal.Count != 0) - { - selectId = dataVal[0].Id; - } - - return new SelectList(dataVal, "Id", "SeriesName", selectId); - } //Root Directory [HttpPost] @@ -202,36 +169,15 @@ public JsonResult SaveRootDir(string path) return new JsonResult { }; } - public PartialViewResult AddRootDir() + [HttpGet] + public JsonResult LookupSeries(string q) { - var model = new RootDirModel - { - Id = 0, - Path = "", - CleanPath = "", - SelectList = new SelectList(new List { "" }, "") - }; - ViewData["guid"] = Guid.NewGuid(); + var dataVal = _tvDbProvider.SearchSeries(q); - return PartialView("RootDir", model); + return Json(dataVal.Select(c => new KeyValuePair(c.Id, c.SeriesName)), JsonRequestBehavior.AllowGet); } - public ActionResult GetRootDirView(RootDir rootDir) - { - var model = new RootDirModel - { - Id = rootDir.Id, - Path = rootDir.Path, - SelectList = new SelectList(new List { rootDir.Path }, rootDir.Path) - }; - - ViewData["guid"] = Guid.NewGuid(); - - return PartialView("RootDir", model); - } - - public ActionResult RootList() { IEnumerable rootDir = _rootFolderProvider.GetAll().Select(c => c.Path).OrderBy(e => e); diff --git a/NzbDrone.Web/Controllers/HealthController.cs b/NzbDrone.Web/Controllers/HealthController.cs index 7d29862e4..9ae802294 100644 --- a/NzbDrone.Web/Controllers/HealthController.cs +++ b/NzbDrone.Web/Controllers/HealthController.cs @@ -14,6 +14,7 @@ public class HealthController : Controller [HttpGet] public JsonResult Index() { + MvcMiniProfiler.MiniProfiler.Stop(true); return Json("OK", JsonRequestBehavior.AllowGet); } diff --git a/NzbDrone.Web/Controllers/SeriesController.cs b/NzbDrone.Web/Controllers/SeriesController.cs index 61c1a53f9..c1d0835be 100644 --- a/NzbDrone.Web/Controllers/SeriesController.cs +++ b/NzbDrone.Web/Controllers/SeriesController.cs @@ -90,7 +90,6 @@ public ActionResult _AjaxSeriesGrid() public ActionResult _SaveAjaxSeriesEditing(int id, string path, bool monitored, bool seasonFolder, int qualityProfileId, List seasonEditor) { var oldSeries = _seriesProvider.GetSeries(id); - oldSeries.Path = path; oldSeries.Monitored = monitored; oldSeries.SeasonFolder = seasonFolder; oldSeries.QualityProfileId = qualityProfileId; diff --git a/NzbDrone.Web/Models/AddExistingManualModel.cs b/NzbDrone.Web/Models/AddExistingManualModel.cs deleted file mode 100644 index 5a529e219..000000000 --- a/NzbDrone.Web/Models/AddExistingManualModel.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.ComponentModel; -using System.Web.Mvc; - -namespace NzbDrone.Web.Models -{ - public class AddExistingManualModel - { - public string Path { get; set; } - public string FolderName { get; set; } - - [DisplayName("Quality Profile")] - public int QualityProfileId { get; set; } - - public SelectList QualitySelectList { get; set; } - } -} \ No newline at end of file diff --git a/NzbDrone.Web/Models/AddExistingSeriesModel.cs b/NzbDrone.Web/Models/AddExistingSeriesModel.cs deleted file mode 100644 index ef9fb98de..000000000 --- a/NzbDrone.Web/Models/AddExistingSeriesModel.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace NzbDrone.Web.Models -{ - public class AddExistingSeriesModel - { - public bool IsWanted { get; set; } - public string Path { get; set; } - public string PathEncoded { get; set; } - public int TvDbId { get; set; } - public string TvDbName { get; set; } - } -} \ No newline at end of file diff --git a/NzbDrone.Web/Models/ExistingSeriesModel.cs b/NzbDrone.Web/Models/ExistingSeriesModel.cs new file mode 100644 index 000000000..b6a391e42 --- /dev/null +++ b/NzbDrone.Web/Models/ExistingSeriesModel.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Web.Mvc; + +namespace NzbDrone.Web.Models +{ + public class ExistingSeriesModel + { + public SelectList Quality { get; set; } + + public List> ExistingSeries { get; set; } + } +} \ No newline at end of file diff --git a/NzbDrone.Web/NzbDrone.Web.csproj b/NzbDrone.Web/NzbDrone.Web.csproj index 2874ee488..e158a9177 100644 --- a/NzbDrone.Web/NzbDrone.Web.csproj +++ b/NzbDrone.Web/NzbDrone.Web.csproj @@ -51,9 +51,9 @@ ..\Libraries\MVC3\Microsoft.Web.Infrastructure.dll True - + False - ..\packages\MiniProfiler.1.4\lib\MvcMiniProfiler.dll + ..\packages\MiniProfiler.1.6\lib\MvcMiniProfiler.dll ..\packages\Ninject.2.2.1.4\lib\net40-Full\Ninject.dll @@ -156,8 +156,7 @@ - - + @@ -251,6 +250,7 @@ + @@ -261,7 +261,6 @@ - Designer @@ -325,7 +324,7 @@ - + diff --git a/NzbDrone.Web/Scripts/AutoComplete.js b/NzbDrone.Web/Scripts/AutoComplete.js index fe6ba6d7c..01e689753 100644 --- a/NzbDrone.Web/Scripts/AutoComplete.js +++ b/NzbDrone.Web/Scripts/AutoComplete.js @@ -1,13 +1,48 @@ -function bindFolderAutoComplete(selector) { - YUI().use("autocomplete", "autocomplete-highlighters", 'autocomplete-filters', function (Y) { - Y.one('body').addClass('yui3-skin-sam'); - Y.one(selector).plug(Y.Plugin.AutoComplete, { +jQuery(document).ready(function () { + $.ajaxSetup({ + cache: false + }); + + $('.folderLookup').livequery(function () { + bindFolderAutoComplete(".folderLookup"); + }); + + $('.seriesLookup').livequery(function () { + bindSeriesAutoComplete(".seriesLookup"); + }); - resultHighlighter: 'startsWith', - resultFilters: 'phraseMatch', - source: '/Directory/GetDirectories/?q={query}' +}); + +function bindFolderAutoComplete(selector) { + + $(selector).each(function (index, element) { + + YUI().use("autocomplete", "autocomplete-highlighters", 'autocomplete-filters', function (Y) { + Y.one('body').addClass('yui3-skin-sam'); + Y.one(element).plug(Y.Plugin.AutoComplete, { + resultHighlighter: 'startsWith', + resultFilters: 'phraseMatch', + source: '/Directory/GetDirectories/?q={query}' + }); }); - }) + }); +} + +function bindSeriesAutoComplete(selector) { + + $(selector).each(function (index, element) { + YUI().use("autocomplete", "autocomplete-highlighters", 'autocomplete-filters', function (Y) { + Y.one('body').addClass('yui3-skin-sam'); + Y.one(element).plug(Y.Plugin.AutoComplete, { + resultHighlighter: 'startsWith', + resultFilters: 'phraseMatch', + resultTextLocator: 'Value', + minQueryLength: 3, + queryDelay: 500, + source: '/AddSeries/LookupSeries/?q={query}' + }); + }); + }); } \ No newline at end of file diff --git a/NzbDrone.Web/Scripts/Plugins/jquery.livequery.js b/NzbDrone.Web/Scripts/Plugins/jquery.livequery.js new file mode 100644 index 000000000..dde8ad8e3 --- /dev/null +++ b/NzbDrone.Web/Scripts/Plugins/jquery.livequery.js @@ -0,0 +1,250 @@ +/*! Copyright (c) 2008 Brandon Aaron (http://brandonaaron.net) + * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) + * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. + * + * Version: 1.0.3 + * Requires jQuery 1.1.3+ + * Docs: http://docs.jquery.com/Plugins/livequery + */ + +(function($) { + +$.extend($.fn, { + livequery: function(type, fn, fn2) { + var self = this, q; + + // Handle different call patterns + if ($.isFunction(type)) + fn2 = fn, fn = type, type = undefined; + + // See if Live Query already exists + $.each( $.livequery.queries, function(i, query) { + if ( self.selector == query.selector && self.context == query.context && + type == query.type && (!fn || fn.$lqguid == query.fn.$lqguid) && (!fn2 || fn2.$lqguid == query.fn2.$lqguid) ) + // Found the query, exit the each loop + return (q = query) && false; + }); + + // Create new Live Query if it wasn't found + q = q || new $.livequery(this.selector, this.context, type, fn, fn2); + + // Make sure it is running + q.stopped = false; + + // Run it immediately for the first time + q.run(); + + // Contnue the chain + return this; + }, + + expire: function(type, fn, fn2) { + var self = this; + + // Handle different call patterns + if ($.isFunction(type)) + fn2 = fn, fn = type, type = undefined; + + // Find the Live Query based on arguments and stop it + $.each( $.livequery.queries, function(i, query) { + if ( self.selector == query.selector && self.context == query.context && + (!type || type == query.type) && (!fn || fn.$lqguid == query.fn.$lqguid) && (!fn2 || fn2.$lqguid == query.fn2.$lqguid) && !this.stopped ) + $.livequery.stop(query.id); + }); + + // Continue the chain + return this; + } +}); + +$.livequery = function(selector, context, type, fn, fn2) { + this.selector = selector; + this.context = context || document; + this.type = type; + this.fn = fn; + this.fn2 = fn2; + this.elements = []; + this.stopped = false; + + // The id is the index of the Live Query in $.livequery.queries + this.id = $.livequery.queries.push(this)-1; + + // Mark the functions for matching later on + fn.$lqguid = fn.$lqguid || $.livequery.guid++; + if (fn2) fn2.$lqguid = fn2.$lqguid || $.livequery.guid++; + + // Return the Live Query + return this; +}; + +$.livequery.prototype = { + stop: function() { + var query = this; + + if ( this.type ) + // Unbind all bound events + this.elements.unbind(this.type, this.fn); + else if (this.fn2) + // Call the second function for all matched elements + this.elements.each(function(i, el) { + query.fn2.apply(el); + }); + + // Clear out matched elements + this.elements = []; + + // Stop the Live Query from running until restarted + this.stopped = true; + }, + + run: function() { + // Short-circuit if stopped + if ( this.stopped ) return; + var query = this; + + var oEls = this.elements, + els = $(this.selector, this.context), + nEls = els.not(oEls); + + // Set elements to the latest set of matched elements + this.elements = els; + + if (this.type) { + // Bind events to newly matched elements + nEls.bind(this.type, this.fn); + + // Unbind events to elements no longer matched + if (oEls.length > 0) + $.each(oEls, function(i, el) { + if ( $.inArray(el, els) < 0 ) + $.event.remove(el, query.type, query.fn); + }); + } + else { + // Call the first function for newly matched elements + nEls.each(function() { + query.fn.apply(this); + }); + + // Call the second function for elements no longer matched + if ( this.fn2 && oEls.length > 0 ) + $.each(oEls, function(i, el) { + if ( $.inArray(el, els) < 0 ) + query.fn2.apply(el); + }); + } + } +}; + +$.extend($.livequery, { + guid: 0, + queries: [], + queue: [], + running: false, + timeout: null, + + checkQueue: function() { + if ( $.livequery.running && $.livequery.queue.length ) { + var length = $.livequery.queue.length; + // Run each Live Query currently in the queue + while ( length-- ) + $.livequery.queries[ $.livequery.queue.shift() ].run(); + } + }, + + pause: function() { + // Don't run anymore Live Queries until restarted + $.livequery.running = false; + }, + + play: function() { + // Restart Live Queries + $.livequery.running = true; + // Request a run of the Live Queries + $.livequery.run(); + }, + + registerPlugin: function() { + $.each( arguments, function(i,n) { + // Short-circuit if the method doesn't exist + if (!$.fn[n]) return; + + // Save a reference to the original method + var old = $.fn[n]; + + // Create a new method + $.fn[n] = function() { + // Call the original method + var r = old.apply(this, arguments); + + // Request a run of the Live Queries + $.livequery.run(); + + // Return the original methods result + return r; + } + }); + }, + + run: function(id) { + if (id != undefined) { + // Put the particular Live Query in the queue if it doesn't already exist + if ( $.inArray(id, $.livequery.queue) < 0 ) + $.livequery.queue.push( id ); + } + else + // Put each Live Query in the queue if it doesn't already exist + $.each( $.livequery.queries, function(id) { + if ( $.inArray(id, $.livequery.queue) < 0 ) + $.livequery.queue.push( id ); + }); + + // Clear timeout if it already exists + if ($.livequery.timeout) clearTimeout($.livequery.timeout); + // Create a timeout to check the queue and actually run the Live Queries + $.livequery.timeout = setTimeout($.livequery.checkQueue, 20); + }, + + stop: function(id) { + if (id != undefined) + // Stop are particular Live Query + $.livequery.queries[ id ].stop(); + else + // Stop all Live Queries + $.each( $.livequery.queries, function(id) { + $.livequery.queries[ id ].stop(); + }); + } +}); + +// Register core DOM manipulation methods +$.livequery.registerPlugin('append', 'prepend', 'after', 'before', 'wrap', 'attr', 'removeAttr', 'addClass', 'removeClass', 'toggleClass', 'empty', 'remove'); + +// Run Live Queries when the Document is ready +$(function() { $.livequery.play(); }); + + +// Save a reference to the original init method +var init = $.prototype.init; + +// Create a new init method that exposes two new properties: selector and context +$.prototype.init = function(a,c) { + // Call the original init and save the result + var r = init.apply(this, arguments); + + // Copy over properties if they exist already + if (a && a.selector) + r.context = a.context, r.selector = a.selector; + + // Set properties + if ( typeof a == 'string' ) + r.context = c || document, r.selector = a; + + // Return the result + return r; +}; + +// Give the init function the jQuery prototype for later instantiation (needed after Rev 4091) +$.prototype.init.prototype = $.prototype; + +})(jQuery); \ No newline at end of file diff --git a/NzbDrone.Web/Views/AddSeries/AddExisting.cshtml b/NzbDrone.Web/Views/AddSeries/AddExisting.cshtml deleted file mode 100644 index 09f26f195..000000000 --- a/NzbDrone.Web/Views/AddSeries/AddExisting.cshtml +++ /dev/null @@ -1,15 +0,0 @@ -@model IEnumerable - -@{ - Layout = null; -} - -@if (Model.Count() == 0) -{ - @Html.DisplayText("No Series to Add"); -} - -@foreach (var path in Model) -{ - Html.RenderAction("RenderPartial", "AddSeries", new {path}); -} \ No newline at end of file diff --git a/NzbDrone.Web/Views/AddSeries/AddNew.cshtml b/NzbDrone.Web/Views/AddSeries/AddNew.cshtml index 124afee72..cdb834363 100644 --- a/NzbDrone.Web/Views/AddSeries/AddNew.cshtml +++ b/NzbDrone.Web/Views/AddSeries/AddNew.cshtml @@ -2,56 +2,44 @@ @using NzbDrone.Web.Models @{ Layout = null; }
- @Html.Label("Root Directory") - @Html.DropDownList("rootDirList", new SelectList((IList)ViewData["RootDirs"])) - @Html.Label("Quality") - @Html.DropDownList("qualityList", new SelectList((IList)ViewData["QualityList"], "QualityProfileId", "Name")) -
-
-
- @{Html.Telerik().ComboBox() - .Name("seriesList_new") - .DataBinding(binding => binding.Ajax().Select("_textLookUp", "AddSeries").Delay(400)) - .Filterable(f => f.FilterMode(AutoCompleteFilterMode.Contains)) - .HighlightFirstMatch(true) - .HtmlAttributes(new { style = "width: 300px;" }) - .Render();} - @Html.Telerik().DropDownList().Name("qualityList_new").BindTo((SelectList)ViewData["quality"]).HtmlAttributes(new { style = "width: 100px", @class = "qualityDropbox" }) -
-@section Scripts{ - -} + + + }); + }); + + + diff --git a/NzbDrone.Web/Views/AddSeries/AddSeriesItem.cshtml b/NzbDrone.Web/Views/AddSeries/AddSeriesItem.cshtml deleted file mode 100644 index 32f84c960..000000000 --- a/NzbDrone.Web/Views/AddSeries/AddSeriesItem.cshtml +++ /dev/null @@ -1,20 +0,0 @@ -@using NzbDrone.Core.Repository.Quality -@model SelectList -
-
- @ViewData["path"].ToString() -
- @{Html.Telerik().ComboBox() - .Name("seriesList_" + ViewData["guid"]) - .BindTo(Model) - .DataBinding(binding => binding.Ajax().Select("_textLookUp", "AddSeries").Delay(400)) - .Filterable(f => f.FilterMode(AutoCompleteFilterMode.Contains)) - .HighlightFirstMatch(true) - .HtmlAttributes(new { style = "width: 300px;" }) - .Render();} - @Html.Telerik().DropDownList().Name("qualityList_" + ViewData["guid"]).BindTo((SelectList)ViewData["quality"]).HtmlAttributes(new { style = "width: 100px", @class = "qualityDropbox" }) - -
-
-
\ No newline at end of file diff --git a/NzbDrone.Web/Views/AddSeries/ExistingSeries.cshtml b/NzbDrone.Web/Views/AddSeries/ExistingSeries.cshtml new file mode 100644 index 000000000..eaa88eea6 --- /dev/null +++ b/NzbDrone.Web/Views/AddSeries/ExistingSeries.cshtml @@ -0,0 +1,96 @@ +@using System.Collections +@using NzbDrone.Web.Models +@using System.Web.Mvc.Html +@model ExistingSeriesModel +@{ + Layout = null; +} +@if (Model.ExistingSeries.Count == 0) +{ +

+ No series available. Try adding a new Root Folder. +

+} +else +{ +

+ Series Ready to be added. + @Html.DropDownList(Guid.NewGuid().ToString(), Model.Quality, new { @class = "qualitySelector masterQualitySelector" }) +

+
+ +
+ +} +@foreach (var series in Model.ExistingSeries) +{ + +
+ + @Html.Label(series.Item1) + +
+
+ + @Html.DropDownList(Guid.NewGuid().ToString(), Model.Quality, new { @class = "qualitySelector" }) + +
+
+} + + + diff --git a/NzbDrone.Web/Views/AddSeries/Index.cshtml b/NzbDrone.Web/Views/AddSeries/Index.cshtml index 7d4022af2..4912142ff 100644 --- a/NzbDrone.Web/Views/AddSeries/Index.cshtml +++ b/NzbDrone.Web/Views/AddSeries/Index.cshtml @@ -1,90 +1,18 @@ -@model List -@using NzbDrone.Core.Repository -@section HeaderContent -{ - -} +@using NzbDrone.Core.Repository @section TitleContent{ Add Series } @section MainContent{ -
- @{ Html.RenderAction("AddNew", "AddSeries"); } -
+

+ Add New Series

+ @{ Html.RenderAction("AddNew", "AddSeries"); } +

+ Add Series Already on Disk

+

+ Manage Root Folders +

@{Html.RenderAction("RootDir");}
-
- - @Html.Telerik().DropDownList().Name("masterDropbox").BindTo((SelectList)ViewData["qualities"]).HtmlAttributes( - new { style = "width: 100px; margin-left:224px;" }).ClientEvents(events => events.OnChange("masterChanged")) -
- @{ Html.RenderAction("AddExisting", "AddSeries"); } + @{ Html.RenderAction("ExistingSeries", "AddSeries"); }
} -@section Scripts -{ - -} diff --git a/NzbDrone.Web/Views/AddSeries/RootDir.cshtml b/NzbDrone.Web/Views/AddSeries/RootDir.cshtml index 0907941a5..2e566ab00 100644 --- a/NzbDrone.Web/Views/AddSeries/RootDir.cshtml +++ b/NzbDrone.Web/Views/AddSeries/RootDir.cshtml @@ -1,26 +1,18 @@  - + - - + @{Html.RenderAction("RootList");} + + diff --git a/NzbDrone.Web/packages.config b/NzbDrone.Web/packages.config index 00619dcd0..9dd660df6 100644 --- a/NzbDrone.Web/packages.config +++ b/NzbDrone.Web/packages.config @@ -8,5 +8,5 @@ - + \ No newline at end of file diff --git a/NzbDrone/Program.cs b/NzbDrone/Program.cs index deb6c13ab..697065fb7 100644 --- a/NzbDrone/Program.cs +++ b/NzbDrone/Program.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using System.Net; using System.Threading; using System.Timers; using Exceptioneer.WindowsFormsClient; @@ -38,7 +39,18 @@ private static void Main() Attach(); #endif - if (Environment.UserInteractive) + if (!Environment.UserInteractive) + { + try + { + new WebClient().DownloadString(IISController.AppUrl); + } + catch (Exception e) + { + Logger.ErrorException("Failed to load home page.", e); + } + } + else { try { diff --git a/packages/MiniProfiler.1.4/MiniProfiler.1.4.nupkg b/packages/MiniProfiler.1.4/MiniProfiler.1.4.nupkg deleted file mode 100644 index dcbc7f48e..000000000 Binary files a/packages/MiniProfiler.1.4/MiniProfiler.1.4.nupkg and /dev/null differ diff --git a/packages/MiniProfiler.1.4/lib/MvcMiniProfiler.pdb b/packages/MiniProfiler.1.4/lib/MvcMiniProfiler.pdb deleted file mode 100644 index 2c55ac7d7..000000000 Binary files a/packages/MiniProfiler.1.4/lib/MvcMiniProfiler.pdb and /dev/null differ diff --git a/packages/MiniProfiler.1.6/MiniProfiler.1.6.nupkg b/packages/MiniProfiler.1.6/MiniProfiler.1.6.nupkg new file mode 100644 index 000000000..145e209e4 Binary files /dev/null and b/packages/MiniProfiler.1.6/MiniProfiler.1.6.nupkg differ diff --git a/packages/MiniProfiler.1.4/lib/MvcMiniProfiler.dll b/packages/MiniProfiler.1.6/lib/MvcMiniProfiler.dll similarity index 51% rename from packages/MiniProfiler.1.4/lib/MvcMiniProfiler.dll rename to packages/MiniProfiler.1.6/lib/MvcMiniProfiler.dll index e35747310..db133f6a3 100644 Binary files a/packages/MiniProfiler.1.4/lib/MvcMiniProfiler.dll and b/packages/MiniProfiler.1.6/lib/MvcMiniProfiler.dll differ diff --git a/packages/MiniProfiler.1.6/lib/MvcMiniProfiler.pdb b/packages/MiniProfiler.1.6/lib/MvcMiniProfiler.pdb new file mode 100644 index 000000000..80f61f512 Binary files /dev/null and b/packages/MiniProfiler.1.6/lib/MvcMiniProfiler.pdb differ diff --git a/packages/MiniProfiler.1.4/lib/MvcMiniProfiler.xml b/packages/MiniProfiler.1.6/lib/MvcMiniProfiler.xml similarity index 76% rename from packages/MiniProfiler.1.4/lib/MvcMiniProfiler.xml rename to packages/MiniProfiler.1.6/lib/MvcMiniProfiler.xml index 3cf07f964..30cd1ae7d 100644 --- a/packages/MiniProfiler.1.4/lib/MvcMiniProfiler.xml +++ b/packages/MiniProfiler.1.6/lib/MvcMiniProfiler.xml @@ -4,11 +4,6 @@ MvcMiniProfiler - - - Formats any SQL query with inline parameters, optionally including the value type - - Takes a SqlTiming and returns a formatted SQL string, for parameter replacement, etc. @@ -21,32 +16,55 @@ Formatted SQL - - - Creates a new Inline SQL Formatter, optionally including the parameter type info in comments beside the replaced value - - whether to include a comment after the value, indicating the type, e.g. /* @myParam DbType.Int32 */ - - - - Formats the SQL in a generic frieldly format, including the parameter type information in a comment if it was specified in the InlineFormatter constructor - - The SqlTiming to format - A formatted SQL string - - - - Returns a string representation of the parameter's value, including the type - - The parameter to get a value for - - A single MiniProfiler can be used to represent any number of steps/levels in a call-graph, via Step() Totally baller. + + + A callback for ProfiledDbConnection and family + + + + + Called when a command starts executing + + + + + + + Called when a reader finishes executing + + + + + + + + Called when a command finishes executing + + + + + + + Called when a reader is done iterating through the data + + + + + + True if the profiler instance is active + + + + + Returns all currently open commands on this connection + + Starts when this profiler is instantiated. Each step will use this Stopwatch's current ticks as @@ -98,6 +116,11 @@ be prematurely stopped and discarded. Useful for when a specific route does not need to be profiled. + + + Makes sure 'profiler' has a Name, pulling it from route data or url. + + Returns an that will time the code between its creation and disposal. Use this method when you @@ -169,6 +192,25 @@ All other s will be children of this one. + + + A string identifying the user/client that is profiling this request. Set + with an -implementing class to provide a custom value. + + + If this is not set manually at some point, the implementation will be used; + by default, this will be the current request's ip address. + + + + + Returns true when this MiniProfiler has been viewed by the that recorded it. + + + Allows POSTs that result in a redirect to be profiled. implementation + will keep a list of all profilers that haven't been fetched down. + + Contains information about queries executed during this profiling session. @@ -229,15 +271,47 @@ Various configuration properties. - + - Ensures that and objects are initialized. Null values will - be initialized to use the default strategy. + Excludes the specified assembly from the stack trace output. + + The short name of the assembly. AssemblyName.Name + + + + Excludes the specified type from the stack trace output. + + The System.Type name to exclude + + + + Excludes the specified method name from the stack trace output. + + The name of the method + + + + Make sure we can at least store profiler results to the http runtime cache. - + - When true, link and script tags will be written to the response stream when MiniProfiler.Stop is called. + Assemblies to exclude from the stack trace report. + + + + + Types to exclude from the stack trace report. + + + + + Methods to exclude from the stack trace report. + + + + + The max length of the stack string to report back; defaults to 120 chars. @@ -269,11 +343,17 @@ For a per-page override you can use .RenderIncludes(position: RenderPosition.Left/Right) - + - When is called, if the current request url starts with this property, - no profiler will be instantiated and no results will be displayed. - Default value is { "/mini-profiler-includes.js", "/mini-profiler-includes.less", "/mini-profiler-results", "/content/", "/scripts/" }. + By default, SqlTimings will grab a stack trace to help locate where queries are being executed. + When this setting is true, no stack trace will be collected, possibly improving profiler performance. + + + + + When is called, if the current request url contains any items in this property, + no profiler will be instantiated and no results will be displayed. + Default value is { "/mini-profiler-", "/content/", "/scripts/", "/favicon.ico" }. @@ -283,10 +363,10 @@ Any setting here should be in APP RELATIVE FORM, e.g. "~/myDirectory/" - + - Understands how to save and load MiniProfilers for a very limited time. Used for caching between when - a profiling session ends and results can be fetched to the client. + Understands how to save and load MiniProfilers. Used for caching between when + a profiling session ends and results can be fetched to the client, and for showing shared, full-page results. The normal profiling session life-cycle is as follows: @@ -294,23 +374,22 @@ 2) profiler is started 3) normal page/controller/request execution 4) profiler is stopped - 5) profiler is cached with 's implementation of + 5) profiler is cached with 's implementation of 6) request ends 7) page is displayed and profiling results are ajax-fetched down, pulling cached results from - 's implementation of + 's implementation of - - - Understands how to save and load MiniProfilers for an extended (even indefinite) time, allowing results to be - shared with other developers or even tracked over time. - - The formatter applied to the SQL being rendered (used only for UI) + + + Provides user identification for a given profiling request. + + Assembly version of this dank MiniProfiler. @@ -326,6 +405,269 @@ Both the HttpRequest and MiniProfiler parameters that will be passed into this function should never be null. + + + Execute parameterized SQL + + Number of rows affected + + + + Return a list of dynamic objects, reader is closed after the call + + + + + Execute a command that returns multiple result sets, and access each in turn + + + + + Return a typed list of objects, reader is closed after the call + + + + + Maps a query to objects + + The return type + + + + + + + + The Field we should split and read the second object from (default: id) + Number of seconds before command execution timeout + + + + + This is a micro-cache; suitable when the number of terms is controllable (a few hundred, for example), + and strictly append-only; you cannot change existing values. All key matches are on **REFERENCE** + equality. The type is fully thread-safe. + + + + + Read the next grid of results + + + + + Wraps a database connection, allowing sql execution timings to be collected when a session is started. + + + + + Returns a new that wraps , + providing query execution profiling. + + Your provider-specific flavor of connection, e.g. SqlConnection, OracleConnection + + + + Returns a new that wraps , + providing query execution profiling. + + Your provider-specific flavor of connection, e.g. SqlConnection, OracleConnection + The currently started or null. + + + + Returns a new that wraps , + providing query execution profiling. If profiler is null, no profiling will occur. + + Your provider-specific flavor of connection, e.g. SqlConnection, OracleConnection + The currently started or null. + + + + Connection factory used for EF Code First DbContext API + + + + + Create a profiled connection factory + + The underlying connection that needs to be profiled + + + + Create a wrapped connection for profiling purposes + + + + + + + Understands how to save MiniProfiler results to a MSSQL database, allowing more permanent storage and + querying of slow results. + + + + + Provides saving and loading s to a storage medium. + + + + + Stores under its . + + The results of a profiling session. + + Should also ensure the profiler is stored as being unviewed by its profiling . + + + + + Returns a from storage based on , which should map to . + + + Should also update that the resulting profiler has been marked as viewed by its profiling . + + + + + Returns a list of s that haven't been seen by . + + User identified by the current . + + + + Returns a new SqlServerDatabaseStorage object that will insert into the database identified by connectionString. + + + + + Saves 'profiler' to a database under its . + + + + + Returns the MiniProfiler identified by 'id' from the database or null when no MiniProfiler exists under that 'id'. + + + + + Returns a list of s that haven't been seen by . + + User identified by the current . + + + + Returns a DbConnection for your specific provider. + + + + + Returns a DbConnection already opened for execution. + + + + + Giving freshly selected collections, this method puts them in the correct + hierarchy under the 'result' MiniProfiler. + + + + + How we connect to the database used to save/load MiniProfiler results. + + + + + Formats SQL server queries with a DECLARE up top for parameter values + + + + + Formats the SQL in a SQL-Server friendly way, with DECLARE statements for the parameters up top. + + The SqlTiming to format + A formatted SQL string + + + + Wrapper for a db provider factory to enable profiling + + + + + Every provider factory must have an Instance public field + + + + + Used for db provider apis internally + + + + + Allow to re-init the provider factory. + + + + + + + proxy + + + + + + + proxy + + + + + proxy + + + + + proxy + + + + + proxy + + + + + proxy + + + + + proxy + + + + + proxy + + + + + proxy + + + + + Extension mechanism for additional services; + + requested service provider or null. + + + + proxy + + Categorizes individual steps to allow filtering. @@ -390,186 +732,69 @@ The current profiling session or null. - + - Execute parameterized SQL - - Number of rows affected - - - - Return a list of dynamic objects, reader is closed after the call + Gets part of a stack trace containing only methods we care about. - + - Execute a command that returns multiple result sets, and access each in turn + Gets the current formatted and filted stack trace. + + Space separated list of methods + + + + Understands how to store a to the with absolute expiration. - + - Return a typed list of objects, reader is closed after the call + The string that prefixes all keys that MiniProfilers are saved under, e.g. + "mini-profiler-ecfb0050-7ce8-4bf1-bf82-2cb38e90e31e". - + - Maps a query to objects + Returns a new HttpRuntimeCacheStorage class that will cache MiniProfilers for the specified duration. - The return type - - - - - - - - The Field we should split and read the second object from (default: id) - Number of seconds before command execution timeout + + + + Saves to the HttpRuntime.Cache under a key concated with + and the parameter's . + + + + + Returns the saved identified by . Also marks the resulting + profiler to true. + + + + + Returns a list of s that haven't been seen by . + + User identified by the current . + + + + Syncs access to runtime cache when adding a new list of ids for a user. + + + + + How long to cache each for (i.e. the absolute expiration parameter of + ) + + + + + Get DB command definition + + - - - This is a micro-cache; suitable when the number of terms is controllable (a few hundred, for example), - and strictly append-only; you cannot change existing values. All key matches are on **REFERENCE** - equality. The type is fully thread-safe. - - - - - Read the next grid of results - - - - - This is a micro-cache; suitable when the number of terms is controllable (a few hundred, for example), - and strictly append-only; you cannot change existing values. All key matches are on **REFERENCE** - equality. The type is fully thread-safe. - - - - - Provides saving and loading s to a storage medium. - - - - - Stores under , which is also its . - - - The Guid that identifies the MiniProfiler; subsequent calls to - will pass this Guid. - - The results of a profiling session. - - Should be able to be called multiple times on the same profiler. - - - - - Returns a from storage based on . - - - - - NOT IMPLEMENTED - will format statements with paramters in an Oracle friendly way - - - - - Does NOTHING, implement me! - - - - - Understands how to store a to a MSSQL database. - - - - - Understands how to save MiniProfiler results to a MSSQL database, allowing more permanent storage and - querying of slow results. - - - - - Returns a new SqlServerDatabaseStorage object that will insert into the database identified by connectionString. - - - - - Saves 'profiler' to a database under 'id'. - - - - - Returns the MiniProfiler identified by 'id' from the database or null when no MiniProfiler exists under that 'id'. - - - - - Returns a DbConnection for your specific provider. - - - - - Returns a DbConnection already opened for execution. - - - - - Giving freshly selected collections, this method puts them in the correct - hierarchy under the 'result' MiniProfiler. - - - - - How we connect to the database used to save/load MiniProfiler results. - - - - - Creates needed tables. Run this once on your database. - - - Works in sql server and sqlite (with documented removals). - TODO: add indexes - - - - - Returns a new . - - - - - Stores 'profiler' to dbo.MiniProfilers under 'id'; stores all child Timings and SqlTimings to their respective tables. - - - - - Saves parameter Timing to the dbo.MiniProfilerTimings table. - - - - - Saves parameter SqlTiming to the dbo.MiniProfilerSqlTimings table. - - - - - Saves any SqlTimingParameters used in the profiled SqlTiming to the dbo.MiniProfilerSqlTimingParameters table. - - - - - Loads the MiniProfiler identifed by 'id' from the database. - - - - - Returns a connection to Sql Server. - - An individual profiling step that can contain child steps. @@ -734,233 +959,37 @@ How many sql non-query statements were executed in this Timing step. - + Categories of sql statements. - + Unknown - + DML statements that alter database state, e.g. INSERT, UPDATE - + Statements that return a single record - + Statements that iterate over a result set - - - Contains helper code to time sql statements. - - - - - Returns a new SqlProfiler to be used in the 'profiler' session. - - - - - Tracks when 'command' is started. - - - - - Finishes profiling for 'command', recording durations. - - - - - Called when 'reader' finishes its iterations and is closed. - - - - - The profiling session this SqlProfiler is part of. - - - - - Helper methods that allow operation on SqlProfilers, regardless of their instantiation. - - - - - Tracks when 'command' is started. - - - - - Finishes profiling for 'command', recording durations. - - - - - Called when 'reader' finishes its iterations and is closed. - - - - - Understands how to route and respond to MiniProfiler UI urls. - - - - - Returns this to handle . - - - - - Returns either includes' css/javascript or results' html. - - - - - Handles rendering static content files. - - - - - Handles rendering a previous MiniProfiler session, identified by its "?id=GUID" on the query. - - - - - Embedded resource contents keyed by filename. - - - - - Helper method that sets a proper 404 response code. - - - - - Try to keep everything static so we can easily be reused. - - - - - Formats SQL server queries with a DECLARE up top for parameter values - - - - - Formats the SQL in a SQL-Server friendly way, with DECLARE statements for the parameters up top. - - The SqlTiming to format - A formatted SQL string - - - - Common extension methods to use only in this project - - - - - Answers true if this String is either null or empty. - - - - - Answers true if this String is neither null or empty. - - - - - Removes trailing / characters from a path and leaves just one - - - - - Removes any leading / characters from a path - - - - - Removes any leading / characters from a path - - - - - Extension mechanism for additional services; - - requested service provider or null. - - - - Wraps a database connection, allowing sql execution timings to be collected when a session is started. - - - - - Returns a new that wraps , - providing query execution profiling. - - Your provider-specific flavor of connection, e.g. SqlConnection, OracleConnection - - - - Returns a new that wraps , - providing query execution profiling. - - Your provider-specific flavor of connection, e.g. SqlConnection, OracleConnection - The currently started or null. - - - - Returns a new that wraps , - providing query execution profiling. If profiler is null, no profiling will occur. - - Your provider-specific flavor of connection, e.g. SqlConnection, OracleConnection - The currently started or null. - - - - Information about a DbParameter used in the sql statement profiled by SqlTiming. - - - - - Which SqlTiming this Parameter was executed with. - - - - - Parameter name, e.g. "@routeName" - - - - - The value submitted to the database. - - - - - System.Data.DbType, e.g. "String", "Bit" - - - - - How large the type is, e.g. for string, size could be 4000 - - Profiles a single sql execution. - + Creates a new SqlTiming to profile 'command'. @@ -977,7 +1006,7 @@ - Called when database reader is closed, ending profiling for SqlTimings. + Called when database reader is closed, ending profiling for SqlTimings. @@ -1054,56 +1083,290 @@ True when other identical sql statements have been executed during this MiniProfiler session. - - - Gets part of a stack trace containing only methods we care about. - - - - - Contains the default list of full type names we don't want in any stack trace snippets. - - - - - Understands how to store a to the with absolute expiration. - - - - - The string that prefixes all keys that MiniProfilers are saved under, e.g. - "mini-profiler-ecfb0050-7ce8-4bf1-bf82-2cb38e90e31e". - - - - - Returns a new HttpRuntimeCacheStorage class that will cache MiniProfilers for the specified duration. - - - - - Saves to the HttpRuntime.Cache under a key concated with - and . - - - - - Returns the originally-stored - - - - - - - How long to cache each for (i.e. the absolute expiration parameter of - ) - - If the underlying command supports BindByName, this sets/clears the underlying implementation accordingly. This is required to support OracleCommand from dapper-dot-net + + + Formats any SQL query with inline parameters, optionally including the value type + + + + + Creates a new Inline SQL Formatter, optionally including the parameter type info in comments beside the replaced value + + whether to include a comment after the value, indicating the type, e.g. /* @myParam DbType.Int32 */ + + + + Formats the SQL in a generic frieldly format, including the parameter type information in a comment if it was specified in the InlineFormatter constructor + + The SqlTiming to format + A formatted SQL string + + + + Returns a string representation of the parameter's value, including the type + + The parameter to get a value for + + + + + Identifies users based on ip address. + + + + + Provides functionality to identify which user is profiling a request. + + + + + Returns a string to identify the user profiling the current 'request'. + + The current HttpRequest being profiled. + + + + Returns the paramter HttpRequest's client ip address. + + + + + This is a micro-cache; suitable when the number of terms is controllable (a few hundred, for example), + and strictly append-only; you cannot change existing values. All key matches are on **REFERENCE** + equality. The type is fully thread-safe. + + + + + NOT IMPLEMENTED - will format statements with paramters in an Oracle friendly way + + + + + Does NOTHING, implement me! + + + + + Understands how to store a to a MSSQL database. + + + + + Creates needed tables. Run this once on your database. + + + Works in sql server and sqlite (with documented removals). + TODO: add indexes + + + + + Returns a new . + + + + + Stores to dbo.MiniProfilers under its ; + stores all child Timings and SqlTimings to their respective tables. + + + + + Saves parameter Timing to the dbo.MiniProfilerTimings table. + + + + + Saves parameter SqlTiming to the dbo.MiniProfilerSqlTimings table. + + + + + Saves any SqlTimingParameters used in the profiled SqlTiming to the dbo.MiniProfilerSqlTimingParameters table. + + + + + Loads the MiniProfiler identifed by 'id' from the database. + + + + + Returns a list of s that haven't been seen by . + + User identified by the current . + + + + Returns a connection to Sql Server. + + + + + Contains helper code to time sql statements. + + + + + Returns a new SqlProfiler to be used in the 'profiler' session. + + + + + Tracks when 'command' is started. + + + + + Returns all currently open commands on this connection + + + + + Finishes profiling for 'command', recording durations. + + + + + Called when 'reader' finishes its iterations and is closed. + + + + + The profiling session this SqlProfiler is part of. + + + + + Helper methods that allow operation on SqlProfilers, regardless of their instantiation. + + + + + Tracks when 'command' is started. + + + + + Finishes profiling for 'command', recording durations. + + + + + Called when 'reader' finishes its iterations and is closed. + + + + + Information about a DbParameter used in the sql statement profiled by SqlTiming. + + + + + Which SqlTiming this Parameter was executed with. + + + + + Parameter name, e.g. "@routeName" + + + + + The value submitted to the database. + + + + + System.Data.DbType, e.g. "String", "Bit" + + + + + How large the type is, e.g. for string, size could be 4000 + + + + + Understands how to route and respond to MiniProfiler UI urls. + + + + + Returns this to handle . + + + + + Returns either includes' css/javascript or results' html. + + + + + Handles rendering static content files. + + + + + Handles rendering a previous MiniProfiler session, identified by its "?id=GUID" on the query. + + + + + Embedded resource contents keyed by filename. + + + + + Helper method that sets a proper 404 response code. + + + + + Try to keep everything static so we can easily be reused. + + + + + Common extension methods to use only in this project + + + + + Answers true if this String is either null or empty. + + + + + Answers true if this String is neither null or empty. + + + + + Removes trailing / characters from a path and leaves just one + + + + + Removes any leading / characters from a path + + + + + Removes any leading / characters from a path + + + + + Serializes to a json string. + +