Updated Add Series

pull/4/head
kay.one 14 years ago
parent 68321c98d0
commit b4fb3002a4

@ -138,9 +138,9 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Libraries\Migrator.NET\Migrator.Providers.dll</HintPath>
</Reference>
<Reference Include="MvcMiniProfiler, Version=1.4.4195.37960, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="MvcMiniProfiler, Version=1.6.0.0, Culture=neutral, PublicKeyToken=b44f9351044011a3, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\MiniProfiler.1.4\lib\MvcMiniProfiler.dll</HintPath>
<HintPath>..\packages\MiniProfiler.1.6\lib\MvcMiniProfiler.dll</HintPath>
</Reference>
<Reference Include="Ninject, Version=2.2.0.0, Culture=neutral, PublicKeyToken=c7192dc5380945e7, processorArchitecture=MSIL">
<HintPath>..\packages\Ninject.2.2.1.4\lib\net40-Full\Ninject.dll</HintPath>

File diff suppressed because one or more lines are too long

@ -195,12 +195,12 @@ namespace NzbDrone.Core.Providers
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

@ -171,31 +171,34 @@ namespace NzbDrone.Core.Providers.Jobs
{
Tuple<Type, int> 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)
}
catch (Exception e)
{
Execute(job.Item1, job.Item2);
Logger.FatalException("An error has occurred while processing queued job.", e);
}
}
catch (Exception e)
{
Logger.FatalException("An error has occurred while processing queued job.", e);
}
finally
{
if (job != null)
finally
{
Queue.Remove(job);
if (job != null)
{
Queue.Remove(job);
}
}
}
@ -214,14 +217,14 @@ namespace NzbDrone.Core.Providers.Jobs
/// to allow it to filter it's target of execution</param>
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 @@ namespace NzbDrone.Core.Providers.Jobs
/// <returns>DateTime of next scheduled job execution</returns>
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);
}
}

@ -74,7 +74,9 @@ namespace NzbDrone.Core.Providers
var cleanPath = Parser.NormalizePath(new DirectoryInfo(seriesFolder).FullName);
if (!_seriesProvider.SeriesPathExists(cleanPath))
{
results.Add(cleanPath);
}
}
Logger.Debug("{0} unmapped folders detected.", results.Count);

@ -130,7 +130,7 @@ namespace NzbDrone.Core.Providers
var series = _database.Fetch<Series, QualityProfile>(@"SELECT * FROM Series
INNER JOIN QualityProfiles ON Series.QualityProfileId = QualityProfiles.QualityProfileId
WHERE CleanTitle = @0", normalizeTitle).FirstOrDefault();
WHERE CleanTitle = @0", normalizeTitle).SingleOrDefault();
return series;
}

@ -2,5 +2,5 @@
<packages>
<package id="Ninject" version="2.2.1.4" />
<package id="SqlServerCompact" version="4.0.8482.1" />
<package id="MiniProfiler" version="1.4" />
<package id="MiniProfiler" version="1.6" />
</packages>

@ -1,7 +1,7 @@
.actionButton
{
margin: 5px 5px 5px 5px;
padding: 5px 10px 5px 10px;
padding: 3px 10px;
background-repeat: no-repeat;
background-position: 5px center;
background-color: #cccccc;

@ -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;

@ -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;
}

@ -16,3 +16,8 @@
{
font-weight: normal;
}
.t-combobox .t-input
{
line-height: 25px;
}

@ -67,70 +67,61 @@ namespace NzbDrone.Web.Controllers
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<String>();
foreach (var folder in rootDirs)
foreach (var folder in _rootFolderProvider.GetAll())
{
unmappedList.AddRange(_rootFolderProvider.GetUnmappedFolders(folder.Path));
}
return View(unmappedList);
}
result.ExistingSeries = new List<Tuple<string, string>>();
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<string, string>(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 path, string seriesName, int qualityProfileId)
{
path = Path.Combine(path, MediaFileProvider.CleanFilename(seriesName));
return AddExistingSeries(path, seriesName, qualityProfileId);
}
[HttpPost]
public JsonResult AddNewSeries(string rootPath, string seriesName, int seriesId, int qualityProfileId)
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 @@ namespace NzbDrone.Web.Controllers
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 @@ namespace NzbDrone.Web.Controllers
return new JsonResult { };
}
public PartialViewResult AddRootDir()
{
var model = new RootDirModel
{
Id = 0,
Path = "",
CleanPath = "",
SelectList = new SelectList(new List<string> { "" }, "")
};
ViewData["guid"] = Guid.NewGuid();
return PartialView("RootDir", model);
}
public ActionResult GetRootDirView(RootDir rootDir)
[HttpGet]
public JsonResult LookupSeries(string q)
{
var model = new RootDirModel
{
Id = rootDir.Id,
Path = rootDir.Path,
SelectList = new SelectList(new List<string> { rootDir.Path }, rootDir.Path)
};
ViewData["guid"] = Guid.NewGuid();
var dataVal = _tvDbProvider.SearchSeries(q);
return PartialView("RootDir", model);
return Json(dataVal.Select(c => new KeyValuePair<int, string>(c.Id, c.SeriesName)), JsonRequestBehavior.AllowGet);
}
public ActionResult RootList()
{
IEnumerable<String> rootDir = _rootFolderProvider.GetAll().Select(c => c.Path).OrderBy(e => e);

@ -14,6 +14,7 @@ namespace NzbDrone.Web.Controllers
[HttpGet]
public JsonResult Index()
{
MvcMiniProfiler.MiniProfiler.Stop(true);
return Json("OK", JsonRequestBehavior.AllowGet);
}

@ -90,7 +90,6 @@ namespace NzbDrone.Web.Controllers
public ActionResult _SaveAjaxSeriesEditing(int id, string path, bool monitored, bool seasonFolder, int qualityProfileId, List<SeasonEditModel> seasonEditor)
{
var oldSeries = _seriesProvider.GetSeries(id);
oldSeries.Path = path;
oldSeries.Monitored = monitored;
oldSeries.SeasonFolder = seasonFolder;
oldSeries.QualityProfileId = qualityProfileId;

@ -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; }
}
}

@ -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; }
}
}

@ -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<Tuple<string, string>> ExistingSeries { get; set; }
}
}

@ -51,9 +51,9 @@
<HintPath>..\Libraries\MVC3\Microsoft.Web.Infrastructure.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="MvcMiniProfiler, Version=1.4.4195.37960, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="MvcMiniProfiler, Version=1.6.0.0, Culture=neutral, PublicKeyToken=b44f9351044011a3, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\MiniProfiler.1.4\lib\MvcMiniProfiler.dll</HintPath>
<HintPath>..\packages\MiniProfiler.1.6\lib\MvcMiniProfiler.dll</HintPath>
</Reference>
<Reference Include="Ninject, Version=2.2.0.0, Culture=neutral, PublicKeyToken=c7192dc5380945e7, processorArchitecture=MSIL">
<HintPath>..\packages\Ninject.2.2.1.4\lib\net40-Full\Ninject.dll</HintPath>
@ -156,8 +156,7 @@
<Compile Include="Helpers\DescriptionExtension.cs" />
<Compile Include="Helpers\HtmlPrefixScopeExtensions.cs" />
<Compile Include="Helpers\IsCurrentActionHelper.cs" />
<Compile Include="Models\AddExistingManualModel.cs" />
<Compile Include="Models\AddExistingSeriesModel.cs" />
<Compile Include="Models\ExistingSeriesModel.cs" />
<Compile Include="Models\AddNewSeriesModel.cs" />
<Compile Include="Models\PendingProcessingModel.cs" />
<Compile Include="Models\QualityTypeModel.cs" />
@ -251,6 +250,7 @@
<Content Include="favicon.ico" />
<Content Include="Global.asax" />
<Content Include="Scripts\AutoComplete.js" />
<Content Include="Scripts\Plugins\jquery.livequery.js" />
<Content Include="Scripts\settingsForm.js" />
<Content Include="Scripts\Plugins\doTimeout.js" />
<Content Include="Scripts\episodeSearch.js" />
@ -261,7 +261,6 @@
<Content Include="Scripts\Notification.js" />
<Content Include="Views\AddSeries\Index.cshtml" />
<Content Include="Views\AddSeries\AddNew.cshtml" />
<Content Include="Views\AddSeries\AddSeriesItem.cshtml" />
<Content Include="Web.config">
<SubType>Designer</SubType>
</Content>
@ -325,7 +324,7 @@
<Content Include="Views\Series\SingleSeason.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\AddSeries\AddExisting.cshtml" />
<Content Include="Views\AddSeries\ExistingSeries.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Views\System\PendingProcessing.cshtml" />

@ -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}'
});
});
});
}

@ -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);

@ -1,15 +0,0 @@
@model IEnumerable<String>
@{
Layout = null;
}
@if (Model.Count() == 0)
{
@Html.DisplayText("No Series to Add");
}
@foreach (var path in Model)
{
Html.RenderAction("RenderPartial", "AddSeries", new {path});
}

@ -2,56 +2,44 @@
@using NzbDrone.Web.Models
@{ Layout = null; }
<div>
@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"))
</div>
<br />
<div>
@{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" })
<button class="listButton" onclick="addNewSeries()">
<div>
<input id="newSeriesLookup" class="seriesLookup" type="text" style="width: 400px" />
</div>
<input id="newSeriesPath" class="folderLookup" type="text" style="width: 400px" />
@Html.DropDownList("qualityList", new SelectList((IList)ViewData["QualityList"], "QualityProfileId", "Name"), new { @class = "qualitySelector" })
<button id="saveNewSeries">
Add</button>
</div>
@section Scripts{
<script type="text/javascript" language="javascript">
var addNewSeriesUrl = '@Url.Action("AddNewSeries", "AddSeries")';
<br />
<script type="text/javascript" language="javascript">
jQuery(document).ready(function () {
$('#newSeriesPath').watermark('Path for the new series...');
$('#newSeriesLookup').watermark('Title of the series you want to add...');
function addNewSeries() {
var seriesComboBox = $("#seriesList_new").data("tDropDownList");
var qualityComboBox = $("#qualityList_new").data("tDropDownList");
var path = $("input[name='selectedRootDir']:checked").val();
$('#saveNewSeries').click(function () {
sendToServerNew(seriesComboBox.value(), path, seriesComboBox.text(), qualityComboBox.value());
}
var addSeriesUrl = '@Url.Action("AddNewSeries", "AddSeries")';
var seriesTitle = $("#newSeriesLookup").val();
var qualityId = $("#qualityList").val();
var path = $('#newSeriesPath').val();
function sendToServerNew(id, rootPath, seriesName, quality) {
$.ajax({
type: "POST",
url: addNewSeriesUrl,
data: jQuery.param({ rootPath: rootPath, seriesName: seriesName, seriesId: id, qualityProfileId: quality }),
url: addSeriesUrl,
data: jQuery.param({ path: path, seriesName: seriesTitle, qualityProfileId: qualityId }),
error: function (req, status, error) {
alert("Sorry! We could not add " + seriesName + " at this time. " + error);
alert("Sorry! We could not add " + path + " at this time. " + error);
},
success: function (data, textStatus, jqXHR) {
//Clear the search box
$("#seriesList_new").data("tComboBox").text('');
//Through up an alert if we failed to add the series
if (data != 'ok')
alert("Sorry! We could not add " + seriesName + ", does it already exist?");
else
closeAddNewSeries(); //Close the Window!
success: function () {
$("#newSeriesLookup").val("");
$('#newSeriesPath').val("");
}
});
}
</script>
}
});
});
</script>

@ -1,20 +0,0 @@
@using NzbDrone.Core.Repository.Quality
@model SelectList
<div style="padding:3px" id="div_@(ViewData["guid"])">
<fieldset>
<legend>@ViewData["path"].ToString()</legend>
<div>
@{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" })
<button class="listButton" onclick="addSeries('@ViewData["guid"]','@ViewData["javaPath"].ToString()' )">
Add</button>
</div>
</fieldset>
</div>

@ -0,0 +1,98 @@
@using System.Collections
@using NzbDrone.Web.Models
@using System.Web.Mvc.Html
@model ExistingSeriesModel
@{
Layout = null;
}
@if (Model.ExistingSeries.Count == 0)
{
<h3 style="color: tomato">
No series available. Try adding a new Root Folder.
</h3>
}
else
{
<h3>
Series Ready to be added.
@Html.DropDownList(Guid.NewGuid().ToString(), Model.Quality, new { @class = "qualitySelector masterQualitySelector" })
</h3>
<div>
</div>
}
@foreach (var series in Model.ExistingSeries)
{
<span class="existingSeries">
<div>
<span class="seriesPathValue">
@Html.Label(series.Item1)
</span>
</div>
<div>
<input class="seriesLookup" type="text" style="width: 400px" value="@series.Item2" />
@Html.DropDownList(Guid.NewGuid().ToString(), Model.Quality, new { @class = "qualitySelector" })
<button class="addExistingButton">
Add</button>
</div>
</span>
}
<style>
.existingSeries
{
border-color: #f2f2f2;
border-width: 1px;
border-style: solid;
background-color: #f2f2f2;
margin: 0px 10px 20px 0px;
padding-left: 10px;
padding-right: 10px;
display: inline-block;
}
.masterQualitySelector
{
left: 202px;
position: relative;
background-color: #f2f2f2;
}
</style>
<script type="text/javascript">
jQuery(document).ready(function () {
$(".masterQualitySelector").change(function () {
var profileId = $(this).val();
$("#existingSeries").find(".qualitySelector").each(function () {
$(this).val(profileId);
});
});
$(".addExistingButton").click(function () {
var root = $(this).parents(".existingSeries");
var addSeriesUrl = '@Url.Action("AddExistingSeries", "AddSeries")';
var title = $(this).siblings(".seriesLookup").val();
var qualityId = $(this).siblings(".qualitySelector").val();
var path = root.find(".seriesPathValue Label").text();
$.ajax({
type: "POST",
url: addSeriesUrl,
data: jQuery.param({ path: path, seriesName: title, qualityProfileId: qualityId }),
error: function (req, status, error) {
alert("Sorry! We could not add " + path + " at this time. " + error);
},
success: function () {
root.hide('highlight', 'fast');
}
});
});
});
</script>

@ -1,90 +1,18 @@
@model List<RootDir>
@using NzbDrone.Core.Repository
@section HeaderContent
{
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/yui/3.3.0/build/yui/yui-min.js"></script>
}
@using NzbDrone.Core.Repository
@section TitleContent{
Add Series
}
@section MainContent{
<div id="addNewWindow" class="dialog">
@{ Html.RenderAction("AddNew", "AddSeries"); }
</div>
<h2>
Add New Series</h2>
@{ Html.RenderAction("AddNew", "AddSeries"); }
<h2>
Add Series Already on Disk</h2>
<h3>
Manage Root Folders
</h3>
@{Html.RenderAction("RootDir");}
<div id="existingSeries">
<div style="padding-bottom: 10px; padding-top: 15px;">
<button onclick="openAddNewSeries(); return false;" class="listButton" style="margin-left: 5px">
Add New</button>
@Html.Telerik().DropDownList().Name("masterDropbox").BindTo((SelectList)ViewData["qualities"]).HtmlAttributes(
new { style = "width: 100px; margin-left:224px;" }).ClientEvents(events => events.OnChange("masterChanged"))
</div>
@{ Html.RenderAction("AddExisting", "AddSeries"); }
@{ Html.RenderAction("ExistingSeries", "AddSeries"); }
</div>
}
@section Scripts
{
<script type="text/javascript">
$(document).ready(function () {
$("#addNewWindow").dialog({
title: 'add new series',
height: '500',
width: '700',
modal: true
});
});
function openAddNewSeries() {
var window = $('#Window').data('tWindow');
window.center().open();
window.refresh();
}
function closeAddNewSeries() {
var window = $('#Window').data("tWindow");
window.close();
}
function masterChanged() {
var masterQuality = $('#masterDropbox').data("tDropDownList").value();
var qualityDropbox = $(".qualityDropbox");
qualityDropbox.each(function () {
var child = $(this).children("[id^='qualityList']");
var comboBox = child.data("tDropDownList");
comboBox.value(masterQuality);
});
}
var addSeriesUrl = '@Url.Action("AddSeries", "AddSeries")';
function addSeries(guid, path) {
var seriesComboBox = $("#seriesList_" + guid).data("tComboBox");
var qualityComboBox = $("#qualityList_" + guid).data("tDropDownList");
sendToServer(seriesComboBox.value(), path, qualityComboBox.value());
$("#div_" + guid).hide();
}
function sendToServer(id, path, quality) {
$.ajax({
type: "POST",
url: addSeriesUrl,
data: jQuery.param({ path: path, seriesId: id, qualityProfileId: quality }),
error: function (req, status, error) {
alert("Sorry! We could not add " + path + " at this time. " + error);
}
});
}
function reloadExistingSeries() {
$('#reloadAjax').show();
$('#existingSeries').load('@Url.Action("AddExisting", "AddSeries")',
function (responseText, textStatus, XMLHttpRequest) {
$('#reloadAjax').hide();
});
}
</script>
}

@ -1,26 +1,18 @@
<span>
<input id="rootDirInput" type="text" style="width: 400px" />
<input id="rootDirInput" class="folderLookup" type="text" style="width: 400px" />
<button id="saveDir">
Add</button>
</span>
<span id="rootDirs">
</span><span id="rootDirs">
@{Html.RenderAction("RootList");}
</span>
<script type="text/javascript">
jQuery(document).ready(function() {
$.ajaxSetup({
cache: false
});
bindFolderAutoComplete('#rootDirInput');
jQuery(document).ready(function () {
$('#rootDirInput').watermark('Start typing to add new root folder...');
$('#rootDirs .actionButton img').live('click',
function(image) {
function (image) {
var path = $(image.target).attr('id');
$.post('@Url.Action("DeleteRootDir", "AddSeries")', { Path: path }, function() {
$.post('@Url.Action("DeleteRootDir", "AddSeries")', { Path: path }, function () {
refreshRoot();
});
});
@ -29,18 +21,20 @@
function saveRootDir() {
var path = $("#rootDirInput").val();
$.post('@Url.Action("SaveRootDir", "AddSeries")', { Path: path }, function() {
refreshRoot();
$("#rootDirInput").val('');
});
if (path) {
$.post('@Url.Action("SaveRootDir", "AddSeries")', { Path: path }, function () {
refreshRoot();
$("#rootDirInput").val('');
});
}
}
function refreshRoot() {
$.get('@Url.Action("RootList", "AddSeries")', function(data) {
$.get('@Url.Action("RootList", "AddSeries")', function (data) {
$('#rootDirs').html(data);
});
reloadExistingSeries();
}
});

@ -1,42 +1,35 @@
@using NzbDrone.Web.Helpers;
@using NzbDrone.Web.Models;
@model NzbDrone.Web.Models.SeriesModel
@{
Layout = null;
}
<div style="width: 435px; margin: 10px;">
<div class=".settingsForm">
@Html.HiddenFor(m => m.SeriesId)
<div class="edit-group">
<div class="config-title">@Html.LabelFor(m => m.Path)</div>
<div class="config-value">@Html.TextBoxFor(m => m.Path, new { style = "width: 300" })</div>
</div>
<div class="edit-group">
<div class="config-title">@Html.LabelFor(m => m.Monitored)</div>
<div class="config-value">@Html.CheckBoxFor(m => m.Monitored, new { style = "margin-right:287px" })</div>
</div>
<div class="edit-group">
<div class="config-title">@Html.LabelFor(m => m.SeasonFolder)</div>
<div class="config-value">@Html.CheckBoxFor(m => m.SeasonFolder, new { style = "margin-right:287px" })</div>
</div>
<div class="edit-group">
<b>@Html.LabelFor(m => m.QualityProfileId)</b>
@Html.DropDownListFor(model => model.QualityProfileId, (SelectList)ViewData["SelectList"], new { style = "margin-left:40px" })
</div>
<label class="labelClass">@Html.LabelFor(m => m.Monitored)
<span class="small">@Html.DescriptionFor(m => m.Monitored)</span>
</label>
@Html.CheckBoxFor(m => m.Monitored, new { @class = "inputClass checkClass" })
<label class="labelClass">@Html.LabelFor(m => m.SeasonFolder)
<span class="small">@Html.DescriptionFor(m => m.SeasonFolder)</span>
</label>
@Html.CheckBoxFor(m => m.SeasonFolder, new { @class = "inputClass checkClass" })
<label class="labelClass">@Html.LabelFor(m => m.QualityProfileId)
<span class="small">@Html.DescriptionFor(m => m.QualityProfileId)</span>
</label>
@Html.DropDownListFor(m => m.QualityProfileId, (SelectList)ViewData["SelectList"], new { @class = "inputClass" })
<div id="seasonEditorSection">
<div style="font-weight: bold; padding-right: 15px; padding-bottom: 5px;">
@Html.LabelFor(m => m.SeasonEditor)
<span id="seasonEditorLoader"><img src="../../../Content/Images/ajax-loader.gif" width="14px" height="14px" style="margin-bottom: -2px;"/></span>
<span id="seasonEditorLoader">
<img src="../../../Content/Images/ajax-loader.gif" width="14px" height="14px" style="margin-bottom: -2px;" /></span>
</div>
<div id="season-editor">
</div>
<div id="season-editor"></div>
</div>
</div>
<span id="ajaxSaveWheel" style="display: none; float: right; padding-right: 368px; padding-top: 1.5px;"><img src="../../../Content/Images/ajax-loader.gif" width="20px" height="20px"/></span>
<span id="ajaxSaveWheel" style="display: none; float: right; padding-right: 368px;
padding-top: 1.5px;">
<img src="../../../Content/Images/ajax-loader.gif" width="20px" height="20px" /></span>

@ -2,7 +2,7 @@
@model NzbDrone.Web.Models.NotificationSettingsModel
@section HeaderContent{
<link rel="stylesheet" type="text/css" href="../../Content/Settings.css" />
<link rel="stylesheet" type="text/css" href="/Content/Settings.css" />
<style>
.notifier

@ -64,7 +64,7 @@
<label class="labelClass">@Html.LabelFor(m => m.SabDropDirectory)
<span class="small">@Html.DescriptionFor(m => m.SabDropDirectory)</span>
</label>
@Html.TextBoxFor(m => m.SabDropDirectory, new { @class = "inputClass" })
@Html.TextBoxFor(m => m.SabDropDirectory, new { @class = "inputClass folderLookup" })
<button type="submit" id="save_button" >Save</button><img src="../../Content/Images/ajax-loader.gif" alt="Loader" id="saveAjax"/>
}

@ -15,8 +15,10 @@
<link type="text/css" rel="stylesheet" href="/Content/overrides.css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/yui/3.3.0/build/yui/yui-min.js"></script>
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/4.0/1/MicrosoftAjax.js"></script>
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/mvc/3.0/MicrosoftMvcAjax.js"></script>
<script type="text/javascript" src="/Scripts/Plugins/jquery.livequery.js"></script>
<script type="text/javascript" src="/Scripts/Plugins/jquery.form.js"></script>
<script type="text/javascript" src="/Scripts/Plugins/jquery.jgrowl.js"></script>
<script type="text/javascript" src="/Scripts/Plugins/jquery-tgc-countdown-1.0.js"></script>

@ -8,5 +8,5 @@
<package id="jQuery.Validation" version="1.8.0.1" />
<package id="jQuery" version="1.6.1" />
<package id="SqlServerCompact" version="4.0.8482.1" />
<package id="MiniProfiler" version="1.4" />
<package id="MiniProfiler" version="1.6" />
</packages>

@ -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 @@ namespace NzbDrone
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
{

Loading…
Cancel
Save