diff --git a/build.ps1 b/build.ps1 index a84a1de8e..b7ce1cfac 100644 --- a/build.ps1 +++ b/build.ps1 @@ -74,6 +74,12 @@ Function PackageMono() Write-Host Removing Update Client Remove-Item -Recurse -Force "$outputFolderMono\NzbDrone.Update" + Write-Host Creating MDBs + get-childitem $outputFolderMono -File -Include @("*.exe", "*.dll") -Exclude @("MediaInfo.dll", "sqlite3.dll") -Recurse | foreach ($_) { + Write-Host "Creating .mdb for $_" + & "tools\pdb2mdb\pdb2mdb.exe" $_.fullname + } + Write-Host Removing PDBs get-childitem $outputFolderMono -File -Filter *.pdb -Recurse | foreach ($_) {remove-item $_.fullname} @@ -89,8 +95,15 @@ Function PackageMono() Copy-Item "$sourceFolder\MediaInfoDotNet.dll.config" $outputFolderMono Write-Host Renaming NzbDrone.Console.exe to NzbDrone.exe - get-childitem $outputFolderMono -File -Filter NzbDrone.exe -Recurse | foreach ($_) {remove-item $_.fullname} - Rename-Item "$outputFolderMono\NzbDrone.Console.exe" "NzbDrone.exe" + Get-ChildItem $outputFolderMono -File -Filter "NzbDrone.exe*" -Recurse | foreach ($_) {remove-item $_.fullname} + + Get-ChildItem $outputFolderMono -File -Filter "NzbDrone.Console.exe*" -Recurse | foreach ($_) { + $newName = $_.fullname -Replace ".Console","" + + Rename-Item $_.fullname $newName + } + + Remove-Item "$outputFolderMono\NzbDrone.Console.vshost.exe" Write-Host "##teamcity[progressFinish 'Creating Mono Package']" } diff --git a/src/NzbDrone.Api/Authentication/AuthenticationService.cs b/src/NzbDrone.Api/Authentication/AuthenticationService.cs index af9194c8d..b71b7a07e 100644 --- a/src/NzbDrone.Api/Authentication/AuthenticationService.cs +++ b/src/NzbDrone.Api/Authentication/AuthenticationService.cs @@ -16,13 +16,11 @@ namespace NzbDrone.Api.Authentication private readonly IConfigFileProvider _configFileProvider; private static readonly NzbDroneUser AnonymousUser = new NzbDroneUser { UserName = "Anonymous" }; - public AuthenticationService(IConfigFileProvider configFileProvider) { _configFileProvider = configFileProvider; } - public IUserIdentity Validate(string username, string password) { if (!Enabled) diff --git a/src/NzbDrone.Api/Extensions/RequestExtensions.cs b/src/NzbDrone.Api/Extensions/RequestExtensions.cs index 02686deb6..672cdb7d5 100644 --- a/src/NzbDrone.Api/Extensions/RequestExtensions.cs +++ b/src/NzbDrone.Api/Extensions/RequestExtensions.cs @@ -7,7 +7,7 @@ namespace NzbDrone.Api.Extensions { public static bool IsApiRequest(this Request request) { - return request.Path.StartsWith("/api/", StringComparison.InvariantCultureIgnoreCase); + return request.Path.StartsWith("/api/", StringComparison.InvariantCultureIgnoreCase) || request.IsLogFileRequest(); } public static bool IsSignalRRequest(this Request request) @@ -21,5 +21,11 @@ namespace NzbDrone.Api.Extensions request.UserHostAddress.Equals("127.0.0.1") || request.UserHostAddress.Equals("::1")); } + + private static bool IsLogFileRequest(this Request request) + { + return request.Path.StartsWith("/log/", StringComparison.InvariantCultureIgnoreCase) && + request.Path.EndsWith(".txt", StringComparison.InvariantCultureIgnoreCase); + } } } diff --git a/src/NzbDrone.Api/Frontend/Mappers/LogFileMapper.cs b/src/NzbDrone.Api/Frontend/Mappers/LogFileMapper.cs index e41a9b711..f251fff97 100644 --- a/src/NzbDrone.Api/Frontend/Mappers/LogFileMapper.cs +++ b/src/NzbDrone.Api/Frontend/Mappers/LogFileMapper.cs @@ -25,7 +25,7 @@ namespace NzbDrone.Api.Frontend.Mappers public override bool CanHandle(string resourceUrl) { - return resourceUrl.StartsWith("/log") && resourceUrl.EndsWith(".txt"); + return resourceUrl.StartsWith("/log/") && resourceUrl.EndsWith(".txt"); } } } \ No newline at end of file diff --git a/src/NzbDrone.Common/Security/IgnoreCertErrorPolicy.cs b/src/NzbDrone.Common/Security/IgnoreCertErrorPolicy.cs index 809b0fe74..8e09b8024 100644 --- a/src/NzbDrone.Common/Security/IgnoreCertErrorPolicy.cs +++ b/src/NzbDrone.Common/Security/IgnoreCertErrorPolicy.cs @@ -1,27 +1,18 @@ using System.Net; using System.Net.Security; using System.Security.Cryptography.X509Certificates; -using NLog; -using NzbDrone.Common.EnvironmentInfo; -using NzbDrone.Common.Instrumentation; namespace NzbDrone.Common.Security { public static class IgnoreCertErrorPolicy { - private static readonly Logger Logger = NzbDroneLogger.GetLogger(); - public static void Register() { - if (OsInfo.IsLinux) - { - ServicePointManager.ServerCertificateValidationCallback = ValidationCallback; - } + ServicePointManager.ServerCertificateValidationCallback = ValidationCallback; } private static bool ValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyerrors) { - Logger.Warn("[{0}] {1}", sender.GetType(), sslpolicyerrors); return true; } } diff --git a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/FullSeasonSpecificationFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/FullSeasonSpecificationFixture.cs new file mode 100644 index 000000000..a62e8ba9e --- /dev/null +++ b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/FullSeasonSpecificationFixture.cs @@ -0,0 +1,48 @@ +using FizzWare.NBuilder; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Common; +using NzbDrone.Core.MediaFiles.EpisodeImport.Specifications; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.Tv; +using NzbDrone.Test.Common; + +namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications +{ + [TestFixture] + public class FullSeasonSpecificationFixture : CoreTest<FullSeasonSpecification> + { + private LocalEpisode _localEpisode; + + [SetUp] + public void Setup() + { + _localEpisode = new LocalEpisode + { + Path = @"C:\Test\30 Rock\30.rock.s01e01.avi".AsOsAgnostic(), + Size = 100, + Series = Builder<Series>.CreateNew().Build(), + ParsedEpisodeInfo = new ParsedEpisodeInfo + { + FullSeason = false + } + }; + } + + [Test] + public void should_return_false_when_file_contains_the_full_season() + { + _localEpisode.ParsedEpisodeInfo.FullSeason = true; + + Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse(); + } + + [Test] + public void should_return_true_when_file_does_not_contain_the_full_season() + { + Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue(); + } + } +} diff --git a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index 42a514e8c..8e4f7cf7c 100644 --- a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -146,6 +146,7 @@ <Compile Include="MediaCoverTests\CoverExistsSpecificationFixture.cs" /> <Compile Include="MediaCoverTests\MediaCoverServiceFixture.cs" /> <Compile Include="MediaFiles\EpisodeFileMovingServiceTests\MoveEpisodeFileFixture.cs" /> + <Compile Include="MediaFiles\EpisodeImport\Specifications\FullSeasonSpecificationFixture.cs" /> <Compile Include="MediaFiles\EpisodeImport\Specifications\FreeSpaceSpecificationFixture.cs" /> <Compile Include="MediaFiles\EpisodeImport\ImportDecisionMakerFixture.cs" /> <Compile Include="MediaFiles\EpisodeImport\Specifications\NotInUseSpecificationFixture.cs" /> diff --git a/src/NzbDrone.Core.Test/ParserTests/ParserFixture.cs b/src/NzbDrone.Core.Test/ParserTests/ParserFixture.cs index f797c9f27..ea35b5445 100644 --- a/src/NzbDrone.Core.Test/ParserTests/ParserFixture.cs +++ b/src/NzbDrone.Core.Test/ParserTests/ParserFixture.cs @@ -106,6 +106,7 @@ namespace NzbDrone.Core.Test.ParserTests result.EpisodeNumbers.First().Should().Be(episodeNumber); result.SeriesTitle.Should().Be(title.CleanSeriesTitle()); result.AbsoluteEpisodeNumbers.Should().BeEmpty(); + result.FullSeason.Should().BeFalse(); } [TestCase(@"z:\tv shows\battlestar galactica (2003)\Season 3\S03E05 - Collaborators.mkv", 3, 5)] @@ -129,6 +130,8 @@ namespace NzbDrone.Core.Test.ParserTests result.EpisodeNumbers.Should().HaveCount(1); result.SeasonNumber.Should().Be(season); result.EpisodeNumbers[0].Should().Be(episode); + result.AbsoluteEpisodeNumbers.Should().BeEmpty(); + result.FullSeason.Should().BeFalse(); ExceptionVerification.IgnoreWarns(); } @@ -169,6 +172,8 @@ namespace NzbDrone.Core.Test.ParserTests result.SeasonNumber.Should().Be(season); result.EpisodeNumbers.Should().BeEquivalentTo(episodes); result.SeriesTitle.Should().Be(title.CleanSeriesTitle()); + result.AbsoluteEpisodeNumbers.Should().BeEmpty(); + result.FullSeason.Should().BeFalse(); } @@ -190,6 +195,8 @@ namespace NzbDrone.Core.Test.ParserTests result.SeriesTitle.Should().Be(title.CleanSeriesTitle()); result.AirDate.Should().Be(airDate.ToString(Episode.AIR_DATE_FORMAT)); result.EpisodeNumbers.Should().BeEmpty(); + result.AbsoluteEpisodeNumbers.Should().BeEmpty(); + result.FullSeason.Should().BeFalse(); } [TestCase("[SubDESU]_High_School_DxD_07_(1280x720_x264-AAC)_[6B7FD717]", "High School DxD", 7, 0, 0)] @@ -222,9 +229,9 @@ namespace NzbDrone.Core.Test.ParserTests result.SeasonNumber.Should().Be(seasonNumber); result.EpisodeNumbers.FirstOrDefault().Should().Be(episodeNumber); result.SeriesTitle.Should().Be(title.CleanSeriesTitle()); + result.FullSeason.Should().BeFalse(); } - [TestCase("Conan {year} {month} {day} Emma Roberts HDTV XviD BFF")] [TestCase("The Tonight Show With Jay Leno {year} {month} {day} 1080i HDTV DD5 1 MPEG2 TrollHD")] [TestCase("The.Daily.Show.{year}.{month}.{day}.Johnny.Knoxville.iTouch-MW")] @@ -238,7 +245,6 @@ namespace NzbDrone.Core.Test.ParserTests Parser.Parser.ParseTitle(yearTooLow).Should().BeNull(); } - [TestCase("Conan {year} {month} {day} Emma Roberts HDTV XviD BFF")] [TestCase("The Tonight Show With Jay Leno {year} {month} {day} 1080i HDTV DD5 1 MPEG2 TrollHD")] [TestCase("The.Daily.Show.{year}.{month}.{day}.Johnny.Knoxville.iTouch-MW")] @@ -268,12 +274,14 @@ namespace NzbDrone.Core.Test.ParserTests [TestCase("The.Office.US.S03.720p.x264-DIMENSION", "The.Office.US", 3)] [TestCase(@"Sons.of.Anarchy.S03.720p.BluRay-CLUE\REWARD", "Sons.of.Anarchy", 3)] [TestCase("Adventure Time S02 720p HDTV x264 CRON", "Adventure Time", 2)] + [TestCase("Sealab.2021.S04.iNTERNAL.DVDRip.XviD-VCDVaULT", "Sealab 2021", 4)] public void full_season_release_parse(string postTitle, string title, int season) { var result = Parser.Parser.ParseTitle(postTitle); result.SeasonNumber.Should().Be(season); result.SeriesTitle.Should().Be(title.CleanSeriesTitle()); - result.EpisodeNumbers.Length.Should().Be(0); + result.EpisodeNumbers.Should().BeEmpty(); + result.AbsoluteEpisodeNumbers.Should().BeEmpty(); result.FullSeason.Should().BeTrue(); } @@ -466,5 +474,13 @@ namespace NzbDrone.Core.Test.ParserTests { Parser.Parser.ParseReleaseGroup(title).Should().Be(expected); } + + [Test] + public void should_not_include_extension_in_releaseGroup() + { + const string path = @"C:\Test\Doctor.Who.2005.s01e01.internal.bdrip.x264-archivist.mkv"; + + Parser.Parser.ParsePath(path).ReleaseGroup.Should().Be("archivist"); + } } } diff --git a/src/NzbDrone.Core/Indexers/Newznab/Newznab.cs b/src/NzbDrone.Core/Indexers/Newznab/Newznab.cs index 7e7df8e54..8a1be6f66 100644 --- a/src/NzbDrone.Core/Indexers/Newznab/Newznab.cs +++ b/src/NzbDrone.Core/Indexers/Newznab/Newznab.cs @@ -46,6 +46,14 @@ namespace NzbDrone.Core.Indexers.Newznab Settings = GetSettings("https://dognzb.cr", new List<Int32>()) }); + list.Add(new IndexerDefinition + { + Enable = false, + Name = "OZnzb.com", + Implementation = GetType().Name, + Settings = GetSettings("https://www.oznzb.com", new List<Int32>()) + }); + return list; } diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/FullSeasonSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/FullSeasonSpecification.cs new file mode 100644 index 000000000..0bd8418f4 --- /dev/null +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/FullSeasonSpecification.cs @@ -0,0 +1,31 @@ +using System; +using System.IO; +using NLog; +using NzbDrone.Common; +using NzbDrone.Core.Parser.Model; + +namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications +{ + public class FullSeasonSpecification : IImportDecisionEngineSpecification + { + private readonly Logger _logger; + + public FullSeasonSpecification(Logger logger) + { + _logger = logger; + } + + public string RejectionReason { get { return "Full season file"; } } + + public bool IsSatisfiedBy(LocalEpisode localEpisode) + { + if (localEpisode.ParsedEpisodeInfo.FullSeason) + { + _logger.Trace("Single episode file detected as containing all episodes in the season"); + return false; + } + + return true; + } + } +} diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index a18250e84..af8e20cee 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -284,6 +284,7 @@ <Compile Include="Instrumentation\DeleteLogFilesService.cs" /> <Compile Include="MediaFiles\Commands\RenameFilesCommand.cs" /> <Compile Include="MediaFiles\EpisodeFileMoveResult.cs" /> + <Compile Include="MediaFiles\EpisodeImport\Specifications\FullSeasonSpecification.cs" /> <Compile Include="MediaFiles\MediaFileExtensions.cs" /> <Compile Include="MediaFiles\MediaInfo\VideoFileInfoReader.cs" /> <Compile Include="MediaFiles\RenameEpisodeFilePreview.cs" /> diff --git a/src/NzbDrone.Core/Parser/Parser.cs b/src/NzbDrone.Core/Parser/Parser.cs index de2b06ca7..7797a61cd 100644 --- a/src/NzbDrone.Core/Parser/Parser.cs +++ b/src/NzbDrone.Core/Parser/Parser.cs @@ -74,10 +74,6 @@ namespace NzbDrone.Core.Parser new Regex(@"^(?<title>.+?)(?:\W+(?:(?:Part\W?|(?<!\d+\W+)e)(?<episode>\d{1,2}(?!\d+)))+)", RegexOptions.IgnoreCase | RegexOptions.Compiled), - //Supports 1103/1113 naming - new Regex(@"^(?<title>.+?)?(?:\W?(?<season>(?<!\d+|\(|\[|e|x)\d{2})(?<episode>(?<!e|x)\d{2}(?!p|i|\d+|\)|\]|\W\d+)))+(\W+|_|$)(?!\\)", - RegexOptions.IgnoreCase | RegexOptions.Compiled), - //Supports Season 01 Episode 03 new Regex(@"(?:.*(?:\""|^))(?<title>.*?)(?:\W?Season\W?)(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:\W|_)(?:Episode\W)(?<episode>(?<!\d+)\d{1,2}(?!\d+))", RegexOptions.IgnoreCase | RegexOptions.Compiled), @@ -86,6 +82,10 @@ namespace NzbDrone.Core.Parser new Regex(@"^(?<title>.+?)\W(?:S|Season)\W?(?<season>\d{1,2}(?!\d+))(\W+|_|$)(?<extras>EXTRAS|SUBPACK)?(?!\\)", RegexOptions.IgnoreCase | RegexOptions.Compiled), + //Supports 1103/1113 naming + new Regex(@"^(?<title>.+?)?(?:\W?(?<season>(?<!\d+|\(|\[|e|x)\d{2})(?<episode>(?<!e|x)\d{2}(?!p|i|\d+|\)|\]|\W\d+)))+(\W+|_|$)(?!\\)", + RegexOptions.IgnoreCase | RegexOptions.Compiled), + //4-digit episode number //Episodes without a title, Single (S01E05, 1x05) AND Multi (S01E04E05, 1x04x05, etc) new Regex(@"^(?:S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]|\W[ex]|_){1,2}(?<episode>\d{4}(?!\d+|i|p)))+)(\W+|_|$)(?!\\)", @@ -129,8 +129,11 @@ namespace NzbDrone.Core.Parser if (result == null) { Logger.Warn("Unable to parse episode info from path {0}", path); + return null; } + result.ReleaseGroup = ParseReleaseGroup(fileInfo.Name.Replace(fileInfo.Extension, "")); + return result; } @@ -336,7 +339,8 @@ namespace NzbDrone.Core.Parser var count = last - first + 1; result.AbsoluteEpisodeNumbers = Enumerable.Range(first, count).ToArray(); } - else + + if (!episodeCaptures.Any() && !absoluteEpisodeCaptures.Any()) { //Check to see if this is an "Extras" or "SUBPACK" release, if it is, return NULL //Todo: Set a "Extras" flag in EpisodeParseResult if we want to download them ever diff --git a/src/NzbDrone.Core/Parser/ParsingService.cs b/src/NzbDrone.Core/Parser/ParsingService.cs index a274684fa..0134bbe4a 100644 --- a/src/NzbDrone.Core/Parser/ParsingService.cs +++ b/src/NzbDrone.Core/Parser/ParsingService.cs @@ -112,6 +112,11 @@ namespace NzbDrone.Core.Parser { var result = new List<Episode>(); + if (parsedEpisodeInfo.FullSeason) + { + return _episodeService.GetEpisodesBySeason(series.Id, parsedEpisodeInfo.SeasonNumber); + } + if (parsedEpisodeInfo.IsDaily()) { if (series.SeriesType == SeriesTypes.Standard) diff --git a/src/NzbDrone.Host/Bootstrap.cs b/src/NzbDrone.Host/Bootstrap.cs index 952e9c17e..c42a7cbf1 100644 --- a/src/NzbDrone.Host/Bootstrap.cs +++ b/src/NzbDrone.Host/Bootstrap.cs @@ -15,18 +15,15 @@ namespace NzbDrone.Host private static IContainer _container; private static readonly Logger Logger = NzbDroneLogger.GetLogger(); - public static void Start(StartupContext startupContext, IUserAlert userAlert, Action<IContainer> startCallback = null) { try { - GlobalExceptionHandlers.Register(); IgnoreCertErrorPolicy.Register(); Logger.Info("Starting NzbDrone Console. Version {0}", Assembly.GetExecutingAssembly().GetName().Version); - if (!PlatformValidation.IsValidate(userAlert)) { throw new TerminateApplicationException("Missing system requirements"); @@ -92,8 +89,6 @@ namespace NzbDrone.Host } } - - private static ApplicationModes GetApplicationMode(StartupContext startupContext) { if (startupContext.Flags.Contains(StartupContext.HELP)) @@ -119,8 +114,6 @@ namespace NzbDrone.Host return ApplicationModes.Interactive; } - - private static bool IsInUtilityMode(ApplicationModes applicationMode) { switch (applicationMode) @@ -137,6 +130,5 @@ namespace NzbDrone.Host } } } - } } \ No newline at end of file diff --git a/src/NzbDrone.Host/BrowserService.cs b/src/NzbDrone.Host/BrowserService.cs index eebb361bc..dc21c011d 100644 --- a/src/NzbDrone.Host/BrowserService.cs +++ b/src/NzbDrone.Host/BrowserService.cs @@ -38,7 +38,7 @@ namespace NzbDrone.Host } else { - _logger.Debug("none-interactive runtime. Won't attempt to open browser."); + _logger.Debug("non-interactive runtime. Won't attempt to open browser."); } } catch (Exception e) diff --git a/src/NzbDrone.Host/PriorityMonitor.cs b/src/NzbDrone.Host/PriorityMonitor.cs index 47e9c7d69..72eda2ac1 100644 --- a/src/NzbDrone.Host/PriorityMonitor.cs +++ b/src/NzbDrone.Host/PriorityMonitor.cs @@ -23,7 +23,6 @@ namespace NzbDrone.Host { _processPriorityCheckTimer = new Timer(EnsurePriority); _processPriorityCheckTimer.Change(TimeSpan.FromSeconds(15), TimeSpan.FromMinutes(30)); - } public virtual void EnsurePriority(object sender) diff --git a/src/NzbDrone/SysTray/SysTrayApp.cs b/src/NzbDrone/SysTray/SysTrayApp.cs index 62e73a650..1c410d895 100644 --- a/src/NzbDrone/SysTray/SysTrayApp.cs +++ b/src/NzbDrone/SysTray/SysTrayApp.cs @@ -38,7 +38,7 @@ namespace NzbDrone.SysTray _trayIcon.ContextMenu = _trayMenu; _trayIcon.Visible = true; - + _trayIcon.DoubleClick += LaunchBrowser; Application.Run(this); } diff --git a/src/UI/AddSeries/SearchResultView.js b/src/UI/AddSeries/SearchResultView.js index e8b24435c..eced403ec 100644 --- a/src/UI/AddSeries/SearchResultView.js +++ b/src/UI/AddSeries/SearchResultView.js @@ -147,12 +147,11 @@ define( this.model.set('seasonFolder', seasonFolder); var self = this; - - SeriesCollection.add(this.model); - var promise = this.model.save(); promise.done(function () { + SeriesCollection.add(self.model); + self.close(); icon.removeClass('icon-spin icon-spinner disabled').addClass('icon-search'); diff --git a/src/UI/Cells/EpisodeStatusCell.js b/src/UI/Cells/EpisodeStatusCell.js index c0d8bb705..8a7fc89ac 100644 --- a/src/UI/Cells/EpisodeStatusCell.js +++ b/src/UI/Cells/EpisodeStatusCell.js @@ -31,7 +31,7 @@ define( var hasAired = Moment(this.model.get('airDateUtc')).isBefore(Moment()); var hasFile = this.model.get('hasFile'); - if (hasFile) { + if (hasFile && reqres.hasHandler(reqres.Requests.GetEpisodeFileById)) { var episodeFile = reqres.request(reqres.Requests.GetEpisodeFileById, this.model.get('episodeFileId')); this.listenTo(episodeFile, 'change', this._refresh); diff --git a/src/UI/Navbar/NavbarTemplate.html b/src/UI/Navbar/NavbarTemplate.html index 57b62d37c..34d3b7631 100644 --- a/src/UI/Navbar/NavbarTemplate.html +++ b/src/UI/Navbar/NavbarTemplate.html @@ -22,28 +22,28 @@ </a> </li> <li> - <a href="history"> + <a href="/history"> <i class="icon-time"></i> <br> History </a> </li> <li> - <a href="missing"> + <a href="/missing"> <i class="icon-warning-sign"></i> <br> Missing </a> </li> <li> - <a href="settings"> + <a href="/settings"> <i class="icon-cogs"></i> <br> Settings </a> </li> <li> - <a href="system"> + <a href="/system"> <i class="icon-laptop"></i> <br> System diff --git a/src/UI/Series/Details/SeriesDetailsLayout.js b/src/UI/Series/Details/SeriesDetailsLayout.js index bc2d77b58..c54e777fb 100644 --- a/src/UI/Series/Details/SeriesDetailsLayout.js +++ b/src/UI/Series/Details/SeriesDetailsLayout.js @@ -186,6 +186,10 @@ define( this.episodeCollection = new EpisodeCollection({ seriesId: this.model.id }).bindSignalR(); this.episodeFileCollection = new EpisodeFileCollection({ seriesId: this.model.id }).bindSignalR(); + reqres.setHandler(reqres.Requests.GetEpisodeFileById, function (episodeFileId) { + return self.episodeFileCollection.get(episodeFileId); + }); + $.when(this.episodeCollection.fetch(), this.episodeFileCollection.fetch()).done(function () { var seasonCollectionView = new SeasonCollectionView({ collection : self.seasonCollection, @@ -193,10 +197,6 @@ define( series : self.model }); - reqres.setHandler(reqres.Requests.GetEpisodeFileById, function (episodeFileId) { - return self.episodeFileCollection.get(episodeFileId); - }); - self.seasons.show(seasonCollectionView); }); }, diff --git a/src/UI/Series/series.less b/src/UI/Series/series.less index 098c2c091..474c61d99 100644 --- a/src/UI/Series/series.less +++ b/src/UI/Series/series.less @@ -224,6 +224,10 @@ } } +.season-actions { + width: 70px; +} + .season-actions, .series-actions { div { diff --git a/src/UI/Settings/SettingsLayout.js b/src/UI/Settings/SettingsLayout.js index a8b281cf8..88d10205c 100644 --- a/src/UI/Settings/SettingsLayout.js +++ b/src/UI/Settings/SettingsLayout.js @@ -184,7 +184,7 @@ define( }, _navigate:function(route){ - Backbone.history.navigate(route, {trigger:true}); + Backbone.history.navigate(route, { trigger: true, replace: true }); }, _save: function () { diff --git a/src/UI/System/SystemLayout.js b/src/UI/System/SystemLayout.js index 29c06d43b..d4a34ae12 100644 --- a/src/UI/System/SystemLayout.js +++ b/src/UI/System/SystemLayout.js @@ -52,7 +52,7 @@ define( }, _navigate:function(route){ - Backbone.history.navigate(route); + Backbone.history.navigate(route, { trigger: true, replace: true }); }, _showInfo: function (e) { diff --git a/src/UI/System/Update/UpdateLayout.js b/src/UI/System/Update/UpdateLayout.js index 026170265..eea1a7098 100644 --- a/src/UI/System/Update/UpdateLayout.js +++ b/src/UI/System/Update/UpdateLayout.js @@ -16,17 +16,18 @@ define( initialize: function () { this.updateCollection = new UpdateCollection(); + + this.listenTo(this.updateCollection, 'sync', this._showUpdates); }, onRender: function () { this.updates.show(new LoadingView()); - var self = this; - var promise = this.updateCollection.fetch(); + this.updateCollection.fetch(); + }, - promise.done(function (){ - self.updates.show(new UpdateCollectionView({ collection: self.updateCollection })); - }); + _showUpdates: function () { + this.updates.show(new UpdateCollectionView({ collection: this.updateCollection })); } }); }); diff --git a/tools/pdb2mdb/Mono.Cecil.Mdb.dll b/tools/pdb2mdb/Mono.Cecil.Mdb.dll new file mode 100644 index 000000000..5b119cb49 Binary files /dev/null and b/tools/pdb2mdb/Mono.Cecil.Mdb.dll differ diff --git a/tools/pdb2mdb/Mono.Cecil.dll b/tools/pdb2mdb/Mono.Cecil.dll new file mode 100644 index 000000000..4b5646655 Binary files /dev/null and b/tools/pdb2mdb/Mono.Cecil.dll differ diff --git a/tools/pdb2mdb/Mono.CompilerServices.SymbolWriter.dll b/tools/pdb2mdb/Mono.CompilerServices.SymbolWriter.dll new file mode 100644 index 000000000..e14192d54 Binary files /dev/null and b/tools/pdb2mdb/Mono.CompilerServices.SymbolWriter.dll differ diff --git a/tools/pdb2mdb/pdb2mdb.exe b/tools/pdb2mdb/pdb2mdb.exe new file mode 100644 index 000000000..31a1f9e34 Binary files /dev/null and b/tools/pdb2mdb/pdb2mdb.exe differ