From e42ac25657e33c3a381e4224150688a7edbba8f1 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Tue, 26 Nov 2013 00:06:28 -0800 Subject: [PATCH] Rename preview for full series and season New: Preview before renaming files --- .../Episodes/RenameEpisodeModule.cs | 42 ++++++++ .../Episodes/RenameEpisodeResource.cs | 18 ++++ src/NzbDrone.Api/NzbDrone.Api.csproj | 2 + .../RenameEpisodeFileServiceFixture.cs | 46 +++------ ...SeriesCommand.cs => RenameFilesCommand.cs} | 9 +- .../Commands/RenameSeasonCommand.cs | 24 ----- .../MediaFiles/MediaFileService.cs | 7 ++ .../MediaFiles/RenameEpisodeFilePreview.cs | 17 ++++ .../MediaFiles/RenameEpisodeFileService.cs | 81 ++++++++++++--- src/NzbDrone.Core/NzbDrone.Core.csproj | 4 +- ...ServiceInstall.csproj.FileListAbsolute.txt | 6 ++ .../obj/x86/Debug/ServiceInstall.exe | Bin 0 -> 14336 bytes ...rviceUninstall.csproj.FileListAbsolute.txt | 5 + .../obj/x86/Debug/ServiceUninstall.exe | Bin 0 -> 14336 bytes src/UI/Content/bootstrap.toggle-switch.css | 1 - src/UI/Content/theme.less | 14 +++ src/UI/Rename/RenamePreviewCollection.js | 38 +++++++ src/UI/Rename/RenamePreviewCollectionView.js | 11 +++ .../RenamePreviewEmptyCollectionView.js | 10 ++ ...amePreviewEmptyCollectionViewTemplate.html | 3 + src/UI/Rename/RenamePreviewItemView.js | 13 +++ .../Rename/RenamePreviewItemViewTemplate.html | 25 +++++ src/UI/Rename/RenamePreviewLayout.js | 93 ++++++++++++++++++ .../Rename/RenamePreviewLayoutTemplate.html | 19 ++++ src/UI/Rename/RenamePreviewModel.js | 9 ++ src/UI/Series/Details/SeasonLayout.js | 16 +-- src/UI/Series/Details/SeriesDetailsLayout.js | 35 ++++--- src/UI/Shared/Modal/Controller.js | 9 +- src/UI/vent.js | 3 +- 29 files changed, 449 insertions(+), 111 deletions(-) create mode 100644 src/NzbDrone.Api/Episodes/RenameEpisodeModule.cs create mode 100644 src/NzbDrone.Api/Episodes/RenameEpisodeResource.cs rename src/NzbDrone.Core/MediaFiles/Commands/{RenameSeriesCommand.cs => RenameFilesCommand.cs} (58%) delete mode 100644 src/NzbDrone.Core/MediaFiles/Commands/RenameSeasonCommand.cs create mode 100644 src/NzbDrone.Core/MediaFiles/RenameEpisodeFilePreview.cs create mode 100644 src/ServiceHelpers/ServiceInstall/obj/x86/Debug/ServiceInstall.csproj.FileListAbsolute.txt create mode 100644 src/ServiceHelpers/ServiceInstall/obj/x86/Debug/ServiceInstall.exe create mode 100644 src/ServiceHelpers/ServiceUninstall/obj/x86/Debug/ServiceUninstall.csproj.FileListAbsolute.txt create mode 100644 src/ServiceHelpers/ServiceUninstall/obj/x86/Debug/ServiceUninstall.exe create mode 100644 src/UI/Rename/RenamePreviewCollection.js create mode 100644 src/UI/Rename/RenamePreviewCollectionView.js create mode 100644 src/UI/Rename/RenamePreviewEmptyCollectionView.js create mode 100644 src/UI/Rename/RenamePreviewEmptyCollectionViewTemplate.html create mode 100644 src/UI/Rename/RenamePreviewItemView.js create mode 100644 src/UI/Rename/RenamePreviewItemViewTemplate.html create mode 100644 src/UI/Rename/RenamePreviewLayout.js create mode 100644 src/UI/Rename/RenamePreviewLayoutTemplate.html create mode 100644 src/UI/Rename/RenamePreviewModel.js diff --git a/src/NzbDrone.Api/Episodes/RenameEpisodeModule.cs b/src/NzbDrone.Api/Episodes/RenameEpisodeModule.cs new file mode 100644 index 000000000..ffe9a37e0 --- /dev/null +++ b/src/NzbDrone.Api/Episodes/RenameEpisodeModule.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using NzbDrone.Api.REST; +using NzbDrone.Core.MediaFiles; + +namespace NzbDrone.Api.Episodes +{ + public class RenameEpisodeModule : NzbDroneRestModule + { + private readonly IRenameEpisodeFileService _renameEpisodeFileService; + + public RenameEpisodeModule(IRenameEpisodeFileService renameEpisodeFileService) + : base("rename") + { + _renameEpisodeFileService = renameEpisodeFileService; + + GetResourceAll = GetEpisodes; + } + + private List GetEpisodes() + { + int seriesId; + + if (Request.Query.SeriesId.HasValue) + { + seriesId = (int)Request.Query.SeriesId; + } + + else + { + throw new BadRequestException("seriesId is missing"); + } + + if (Request.Query.SeasonNumber.HasValue) + { + var seasonNumber = (int)Request.Query.SeasonNumber; + return ToListResource(() => _renameEpisodeFileService.GetRenamePreviews(seriesId, seasonNumber)); + } + + return ToListResource(() => _renameEpisodeFileService.GetRenamePreviews(seriesId)); + } + } +} diff --git a/src/NzbDrone.Api/Episodes/RenameEpisodeResource.cs b/src/NzbDrone.Api/Episodes/RenameEpisodeResource.cs new file mode 100644 index 000000000..9598de0ce --- /dev/null +++ b/src/NzbDrone.Api/Episodes/RenameEpisodeResource.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NzbDrone.Api.REST; + +namespace NzbDrone.Api.Episodes +{ + public class RenameEpisodeResource : RestResource + { + public Int32 SeriesId { get; set; } + public Int32 SeasonNumber { get; set; } + public List EpisodeNumbers { get; set; } + public Int32 EpisodeFileId { get; set; } + public String ExistingPath { get; set; } + public String NewPath { get; set; } + } +} diff --git a/src/NzbDrone.Api/NzbDrone.Api.csproj b/src/NzbDrone.Api/NzbDrone.Api.csproj index f5bf73cf7..939dcd9ef 100644 --- a/src/NzbDrone.Api/NzbDrone.Api.csproj +++ b/src/NzbDrone.Api/NzbDrone.Api.csproj @@ -95,6 +95,8 @@ + + diff --git a/src/NzbDrone.Core.Test/MediaFiles/RenameEpisodeFileServiceFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/RenameEpisodeFileServiceFixture.cs index 662727575..5757641dc 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/RenameEpisodeFileServiceFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/RenameEpisodeFileServiceFixture.cs @@ -38,22 +38,14 @@ namespace NzbDrone.Core.Test.MediaFiles private void GivenNoEpisodeFiles() { Mocker.GetMock() - .Setup(s => s.GetFilesBySeries(_series.Id)) - .Returns(new List()); - - Mocker.GetMock() - .Setup(s => s.GetFilesBySeason(_series.Id, _episodeFiles.First().SeasonNumber)) + .Setup(s => s.Get(It.IsAny>())) .Returns(new List()); } private void GivenEpisodeFiles() { Mocker.GetMock() - .Setup(s => s.GetFilesBySeries(_series.Id)) - .Returns(_episodeFiles); - - Mocker.GetMock() - .Setup(s => s.GetFilesBySeason(_series.Id, _episodeFiles.First().SeasonNumber)) + .Setup(s => s.Get(It.IsAny>())) .Returns(_episodeFiles); } @@ -68,7 +60,7 @@ namespace NzbDrone.Core.Test.MediaFiles { GivenNoEpisodeFiles(); - Subject.Execute(new RenameSeriesCommand(_series.Id)); + Subject.Execute(new RenameFilesCommand(_series.Id, new List{1})); Mocker.GetMock() .Verify(v => v.PublishEvent(It.IsAny()), Times.Never()); @@ -83,7 +75,7 @@ namespace NzbDrone.Core.Test.MediaFiles .Setup(s => s.MoveEpisodeFile(It.IsAny(), It.IsAny())) .Throws(new SameFilenameException("Same file name", "Filename")); - Subject.Execute(new RenameSeriesCommand(_series.Id)); + Subject.Execute(new RenameFilesCommand(_series.Id, new List { 1 })); Mocker.GetMock() .Verify(v => v.PublishEvent(It.IsAny()), Times.Never()); @@ -95,7 +87,7 @@ namespace NzbDrone.Core.Test.MediaFiles GivenEpisodeFiles(); GivenMovedFiles(); - Subject.Execute(new RenameSeriesCommand(_series.Id)); + Subject.Execute(new RenameFilesCommand(_series.Id, new List { 1 })); Mocker.GetMock() .Verify(v => v.PublishEvent(It.IsAny()), Times.Once()); @@ -107,40 +99,24 @@ namespace NzbDrone.Core.Test.MediaFiles GivenEpisodeFiles(); GivenMovedFiles(); - Subject.Execute(new RenameSeriesCommand(_series.Id)); + Subject.Execute(new RenameFilesCommand(_series.Id, new List { 1 })); Mocker.GetMock() .Verify(v => v.Update(It.IsAny()), Times.Exactly(2)); } [Test] - public void rename_season_should_get_episodefiles_for_season() + public void should_get_episodefiles_by_ids_only() { GivenEpisodeFiles(); GivenMovedFiles(); - Subject.Execute(new RenameSeasonCommand(_series.Id, _episodeFiles.First().SeasonNumber)); + var files = new List { 1 }; + + Subject.Execute(new RenameFilesCommand(_series.Id, files)); Mocker.GetMock() - .Verify(v => v.GetFilesBySeries(_series.Id), Times.Never()); - - Mocker.GetMock() - .Verify(v => v.GetFilesBySeason(_series.Id, _episodeFiles.First().SeasonNumber), Times.Once()); - } - - [Test] - public void rename_series_should_get_episodefiles_for_series() - { - GivenEpisodeFiles(); - GivenMovedFiles(); - - Subject.Execute(new RenameSeriesCommand(_series.Id)); - - Mocker.GetMock() - .Verify(v => v.GetFilesBySeries(_series.Id), Times.Once()); - - Mocker.GetMock() - .Verify(v => v.GetFilesBySeason(_series.Id, _episodeFiles.First().SeasonNumber), Times.Never()); + .Verify(v => v.Get(files), Times.Once()); } } } diff --git a/src/NzbDrone.Core/MediaFiles/Commands/RenameSeriesCommand.cs b/src/NzbDrone.Core/MediaFiles/Commands/RenameFilesCommand.cs similarity index 58% rename from src/NzbDrone.Core/MediaFiles/Commands/RenameSeriesCommand.cs rename to src/NzbDrone.Core/MediaFiles/Commands/RenameFilesCommand.cs index eb7e578d4..2003a3e9f 100644 --- a/src/NzbDrone.Core/MediaFiles/Commands/RenameSeriesCommand.cs +++ b/src/NzbDrone.Core/MediaFiles/Commands/RenameFilesCommand.cs @@ -1,10 +1,12 @@ +using System.Collections.Generic; using NzbDrone.Core.Messaging.Commands; namespace NzbDrone.Core.MediaFiles.Commands { - public class RenameSeriesCommand : Command + public class RenameFilesCommand : Command { public int SeriesId { get; set; } + public List Files { get; set; } public override bool SendUpdatesToClient { @@ -14,13 +16,14 @@ namespace NzbDrone.Core.MediaFiles.Commands } } - public RenameSeriesCommand() + public RenameFilesCommand() { } - public RenameSeriesCommand(int seriesId) + public RenameFilesCommand(int seriesId, List files) { SeriesId = seriesId; + Files = files; } } } \ No newline at end of file diff --git a/src/NzbDrone.Core/MediaFiles/Commands/RenameSeasonCommand.cs b/src/NzbDrone.Core/MediaFiles/Commands/RenameSeasonCommand.cs deleted file mode 100644 index b9a917ca3..000000000 --- a/src/NzbDrone.Core/MediaFiles/Commands/RenameSeasonCommand.cs +++ /dev/null @@ -1,24 +0,0 @@ -using NzbDrone.Core.Messaging.Commands; - -namespace NzbDrone.Core.MediaFiles.Commands -{ - public class RenameSeasonCommand : Command - { - public int SeriesId { get; set; } - public int SeasonNumber { get; set; } - - public override bool SendUpdatesToClient - { - get - { - return true; - } - } - - public RenameSeasonCommand(int seriesId, int seasonNumber) - { - SeriesId = seriesId; - SeasonNumber = seasonNumber; - } - } -} \ No newline at end of file diff --git a/src/NzbDrone.Core/MediaFiles/MediaFileService.cs b/src/NzbDrone.Core/MediaFiles/MediaFileService.cs index 44f67174c..a49d667df 100644 --- a/src/NzbDrone.Core/MediaFiles/MediaFileService.cs +++ b/src/NzbDrone.Core/MediaFiles/MediaFileService.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using NLog; @@ -17,6 +18,7 @@ namespace NzbDrone.Core.MediaFiles List GetFilesBySeason(int seriesId, int seasonNumber); List FilterExistingFiles(List files, int seriesId); EpisodeFile Get(int id); + List Get(IEnumerable ids); } public class MediaFileService : IMediaFileService, IHandleAsync @@ -75,6 +77,11 @@ namespace NzbDrone.Core.MediaFiles return _mediaFileRepository.Get(id); } + public List Get(IEnumerable ids) + { + return _mediaFileRepository.Get(ids).ToList(); + } + public void HandleAsync(SeriesDeletedEvent message) { var files = GetFilesBySeries(message.Series.Id); diff --git a/src/NzbDrone.Core/MediaFiles/RenameEpisodeFilePreview.cs b/src/NzbDrone.Core/MediaFiles/RenameEpisodeFilePreview.cs new file mode 100644 index 000000000..a3c68fd5b --- /dev/null +++ b/src/NzbDrone.Core/MediaFiles/RenameEpisodeFilePreview.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NzbDrone.Core.MediaFiles +{ + public class RenameEpisodeFilePreview + { + public Int32 SeriesId { get; set; } + public Int32 SeasonNumber { get; set; } + public List EpisodeNumbers { get; set; } + public Int32 EpisodeFileId { get; set; } + public String ExistingPath { get; set; } + public String NewPath { get; set; } + } +} diff --git a/src/NzbDrone.Core/MediaFiles/RenameEpisodeFileService.cs b/src/NzbDrone.Core/MediaFiles/RenameEpisodeFileService.cs index 8cbfc51a2..7441dd3dd 100644 --- a/src/NzbDrone.Core/MediaFiles/RenameEpisodeFileService.cs +++ b/src/NzbDrone.Core/MediaFiles/RenameEpisodeFileService.cs @@ -1,37 +1,100 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using NLog; +using NzbDrone.Common; using NzbDrone.Core.Instrumentation; using NzbDrone.Core.MediaFiles.Commands; using NzbDrone.Core.MediaFiles.Events; using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Organizer; using NzbDrone.Core.Tv; namespace NzbDrone.Core.MediaFiles { - public class RenameEpisodeFileService : IExecute, IExecute + public interface IRenameEpisodeFileService + { + List GetRenamePreviews(int seriesId); + List GetRenamePreviews(int seriesId, int seasonNumber); + } + + public class RenameEpisodeFileService : IRenameEpisodeFileService, + IExecute { private readonly ISeriesService _seriesService; private readonly IMediaFileService _mediaFileService; private readonly IMoveEpisodeFiles _episodeFileMover; private readonly IEventAggregator _eventAggregator; + private readonly IEpisodeService _episodeService; + private readonly IBuildFileNames _filenameBuilder; private readonly Logger _logger; public RenameEpisodeFileService(ISeriesService seriesService, IMediaFileService mediaFileService, IMoveEpisodeFiles episodeFileMover, IEventAggregator eventAggregator, + IEpisodeService episodeService, + IBuildFileNames filenameBuilder, Logger logger) { _seriesService = seriesService; _mediaFileService = mediaFileService; _episodeFileMover = episodeFileMover; _eventAggregator = eventAggregator; + _episodeService = episodeService; + _filenameBuilder = filenameBuilder; _logger = logger; } + public List GetRenamePreviews(int seriesId) + { + var series = _seriesService.GetSeries(seriesId); + var episodes = _episodeService.GetEpisodeBySeries(seriesId); + var files = _mediaFileService.GetFilesBySeries(seriesId); + + return GetPreviews(series, episodes, files).ToList(); + } + + public List GetRenamePreviews(int seriesId, int seasonNumber) + { + var series = _seriesService.GetSeries(seriesId); + var episodes = _episodeService.GetEpisodesBySeason(seriesId, seasonNumber); + var files = _mediaFileService.GetFilesBySeason(seriesId, seasonNumber); + + return GetPreviews(series, episodes, files).ToList(); + } + + private IEnumerable GetPreviews(Series series, List episodes, List files) + { + foreach (var file in files) + { + var episodesInFile = episodes.Where(e => e.EpisodeFileId == file.Id).ToList(); + var seasonNumber = episodesInFile.First().SeasonNumber; + var newName = _filenameBuilder.BuildFilename(episodesInFile, series, file); + var newPath = _filenameBuilder.BuildFilePath(series, seasonNumber, newName, Path.GetExtension(file.Path)); + + if (!file.Path.PathEquals(newPath)) + { + yield return new RenameEpisodeFilePreview + { + SeriesId = series.Id, + SeasonNumber = seasonNumber, + EpisodeNumbers = episodesInFile.Select(e => e.EpisodeNumber).ToList(), + EpisodeFileId = file.Id, + ExistingPath = GetRelativePath(series.Path, file.Path), + NewPath = GetRelativePath(series.Path, newPath) + }; + } + } + } + + private string GetRelativePath(string seriesPath, string path) + { + return path.Substring(seriesPath.Length + 1); + } + private void RenameFiles(List episodeFiles, Series series) { var renamed = new List(); @@ -64,24 +127,14 @@ namespace NzbDrone.Core.MediaFiles } } - public void Execute(RenameSeasonCommand message) + public void Execute(RenameFilesCommand message) { var series = _seriesService.GetSeries(message.SeriesId); - var episodeFiles = _mediaFileService.GetFilesBySeason(message.SeriesId, message.SeasonNumber); - - _logger.ProgressInfo("Renaming {0} files for {1} season {2}", episodeFiles.Count, series.Title, message.SeasonNumber); - RenameFiles(episodeFiles, series); - _logger.ProgressInfo("Episode Fies renamed for {0} season {1}", series.Title, message.SeasonNumber); - } - - public void Execute(RenameSeriesCommand message) - { - var series = _seriesService.GetSeries(message.SeriesId); - var episodeFiles = _mediaFileService.GetFilesBySeries(message.SeriesId); + var episodeFiles = _mediaFileService.Get(message.Files); _logger.ProgressInfo("Renaming {0} files for {1}", episodeFiles.Count, series.Title); RenameFiles(episodeFiles, series); - _logger.ProgressInfo("Episode Fies renamed for {0}", series.Title); + _logger.ProgressInfo("Selected Episode Files renamed for {0}", series.Title); } } } diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index 142c9d9e8..ae95fbd39 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -278,9 +278,11 @@ + + @@ -343,8 +345,6 @@ - - diff --git a/src/ServiceHelpers/ServiceInstall/obj/x86/Debug/ServiceInstall.csproj.FileListAbsolute.txt b/src/ServiceHelpers/ServiceInstall/obj/x86/Debug/ServiceInstall.csproj.FileListAbsolute.txt new file mode 100644 index 000000000..f07066f35 --- /dev/null +++ b/src/ServiceHelpers/ServiceInstall/obj/x86/Debug/ServiceInstall.csproj.FileListAbsolute.txt @@ -0,0 +1,6 @@ +C:\Dropbox\Dev\NzbDrone\_output\ServiceInstall.exe.config +C:\Dropbox\Dev\NzbDrone\_output\ServiceInstall.exe +C:\Dropbox\Dev\NzbDrone\_output\ServiceInstall.pdb +C:\Dropbox\Dev\NzbDrone\src\ServiceHelpers\ServiceInstall\obj\x86\Debug\ServiceInstall.csprojResolveAssemblyReference.cache +C:\Dropbox\Dev\NzbDrone\src\ServiceHelpers\ServiceInstall\obj\x86\Debug\ServiceInstall.exe +C:\Dropbox\Dev\NzbDrone\src\ServiceHelpers\ServiceInstall\obj\x86\Debug\ServiceInstall.pdb diff --git a/src/ServiceHelpers/ServiceInstall/obj/x86/Debug/ServiceInstall.exe b/src/ServiceHelpers/ServiceInstall/obj/x86/Debug/ServiceInstall.exe new file mode 100644 index 0000000000000000000000000000000000000000..1c443d08ea7f53dbfb5c1f5c700bccd165189ef3 GIT binary patch literal 14336 zcmeHOdw3K@wy#M-c(_D?#a);6ZWGi+*-R1$2ns?-cti++Jb45{&rHvxNl*8ryC=yI zAd#nlyx*b-C<}`CRzyKSiSiWR_*fU&{q~Rj_U`BPpX<8&xqW}9dU`UG1U9;NzrFX{ zE$CBKr>ah!I_FfK)6*W?TR zORHr=2s;3{b^|cC+1N#HR z{ULzfmB#c%smCCeieY>l$s5bSxEs-8{D_)U1pz4S$0%Pnh;_ZAPgXL!fPUZ?{m_&; z@FukNN$Hi6(TnNXME55^u;EXj*Fbbjb=n?oZCi^rqaV8cpc|*5Vd@^NTatD&&u`TJ zgXcfeeiqGzXbx$iUk@W4dC%^t+5oC|zpm>K|C-tbQyI`!5A9Y$CZb@~Kxscmc3W3% zpk0HU2#MwQV0YZblC?o7+1%eTw&dQiE|MY=>9{V(o#h^qH6(ikVY)B{a5z>sU=d@F zA^#H;FrdWLWi?<>kB4B4e?mT>tb}duZkyYH31tQOz&(cgZjc@@R?$4v83~efP3XJV zg(k-SeCrSf70~Pu0JjaSj^|*J^^BIOJ^ld=q#jYOQ&};agxWT?6sGYd`w&oYrMXgB zx$90qA1^QD@IelbaQGgFf8a1RiTd~F@UA2pH6>{&8_hhJDwSLLNEkKiPlBX#qM+6z;0%@Lgr2_ zCt6ElQw8d^fz7~37n^I>y3Ju}sBMq7so1_Qc7oTovStX@#dh?^FpN9I`jO;;InCjD zz$ErQyNPvk-NyQJcsqyL9FE{Hm%{=Mr*SxgLy<$7!&<;WECQItRss&gY~5UUvmNZ? zq|tzXOv-0_fVmB@U-CruEUYP?9bxw-7qXLVL2?B(~~+KJ0VAe(2$5gIGV8n+;*N1K!Ot0rS{6z)7qGu!Q5i9M&)u z7=zUVHnL_{39E(_k|AftjzI)B_$;3ENFN&U6DPkBx0CSkQI66NnVo` zin7WAl36unz9(PTRB0Rt78to|t}iI7vSI3?sp+gZtVRdA^JOuhYKAF$4VEvOVzK0v zC`l-%W#ZpfO7V}+HXpJa}QtC#9E zy(ZVhY2yi-5_5Zr8+!@vV#%*y4H(064MPfglt`&;DpG5Ar(<-60@ajsEff`@!6t-d zUu$QFMwE~C4dZ1+x@u#druyYT7~%py?Z@V6!H}p%+BZOXzOdJ9-;k$;BDx%??x3ku z7kyGtj2DcL34`;7O-$@8ft%xG&C5wTj1&|x5`Tf}*I2%+ zL+zR#;WaYe7>0MUwH|96A6Aqpup~BBG^-gn^2ln;_)0Lj4&K~T;m^EsNK{ybtopQi zqreAyMho$n7uI#uoThet$A)FaEKrLzg*H#LK>V_C4cJ2lW>pPptiW8-WSSp(_ezFQ zVv0IOVpRs#K|?sJRKZ>f2QjO`o5~ESq*_uGTU-*y6-z!Y3J_6!qV6jSo1w7TVbeHW z$HpPDdAcN;(iF{Jro#tsYGo#V1M`hN5i>ylO!WDx>}le=a5SGH0n6#Ju~I-*d1J98 z`uO5G$|e)TRfw`VUeh5klUo2$Limx%WX5iv!sas%%V#>%n2Mu=&SNSWfC{fmtN}Tz zDFaqSU&0E^M7zNJprJA!O6}>`;{@J=`d9ODUKYk&bV#Yd2^cH$nwL}5;q556&t+cx zgD&uo`cQ8f(1%umP31g@Xd_N^P*jmqouH2e`J6K9CR)WPWjkozxTvzP=fB^bykcM9 zI^&)-e_`DY&#x@MDd&ro2*B`8!_x31r7)K(EfudcKkeN;xf@GM5l|Mar7q%@8WcM(AS$Gp4{1d^`n z+NF26cZ8m#2`=^%_mpv^v2*$t(bI7hg^(^*n)bt3Q@(736fr`^eFKdVVl6^W9~VoD z`m^Zy0*$-aE!jgx+&Ro6iW$;SkC>4&*fTg|xahkxW4LeVu;HFz!^NRPJO~k8tXp;# zLe?xd!rLw`a+rNx?1uXKdbc{?<0Gf$_G&@9r{jzm`-zM7oiL?Lm>{W=E-J#*ut$-- zLfsI&UAb6SP6q`9w@Cj%0a`RYv7t`){iKoh}Q%Af$nvsmSRklWOF6;l{fP{f|!+H#4>!c${?X znRe~iK~0R_Wt!thQ5;Qs>x--4@t)eQKaIbE1|=jLAzTHI)2&Ui5o4}`p9=i;e5^Mm zZdd_+dm$l2(}5Wb?+dMIZZ2avwD@Rx2kn>a!k<87o0a2(!&OIQIbf{&|0 zK81}(nbNV8FaJt%ao#|jd^B&h-$L554OTIt99~HW9hrNw0{AaK{3)ed7%ilf`z`Xq z3in?!_sP5idnRQw6zBp^>m1^ZvyC+F#$QnA2b`yMe#?N$3e6b0V{%I1CIDAijF6(P+vzz zRI?@AS^jL8>n@AWuf8(-x%;oo*tOtDX<2DkYM*9`eGB*1U%L14`YYr28&~dK=9iptPF^`* z=^uQ1k2UZ7!B0YTbLR*_ymDSR3C))Nh`>UF2~o{7AF&%ZyKli#j> z`^B%;es;`S{pqXL{hu7MmVNw^wHS1oK6=(#06LKmp0uiWuV^QKxv8Q5j>~UZTYr7Z z+VuJB*7{!^x7L8ps!w0BR($fZwe;f`t@|!LZ_%2RJ*(S|pV!pTcjNh&_pLko(!Mok zUf8$t)YC^c{_3Q)4s=$2aQK^ruRZqc!c+VAHNL)YU(Jr?z%vGqbI$Of2leT@YL4PxK8V*VxE{$wPWG2IolVs%--JEGHcuX zmYLfkEi<+@v`pVx-%`FRbO>kXO>N~fE$k^Q+Mu4CvLV<~xL#?Qw7#b0-gWa@3f9Rj zlN-f{!C$YoV>+tOiqz!MnMCIRowdF*+bz$Tt^7QggY&6e_ZgVK-TI4zRo#o8T5xId zYm0FX-)Buc+GLG?b)l92N~1M#Tks;}(zm1e+Tw85=h1mqbKwzwrUlOJ-7Ay=LhpbI8)V&dvUJrPT)g)X4UU7 z|EcX(wcU1g;jK7nN@gvi8bl9`>etpwVj?HzABH-WAYE=ugFJ`&zg5( zmlb$@>(`}aWfR)YOZ926+w!&gCh{HR%gBFBgDi@UFSCkv8l9fMs!_`$KNp6NGQdYI z_|Pss%6$y!q;g3u`GlXf<)L);^o&`ruKwf9mUY(jQ){g9H&$Dv;G>xMcqrWI`QdBx z$e%>sf0FxK@^R#I$P}# z@g?goZ9i$-#=$r~9NVD%+Vaj@+G`&X=0aOI9vMoJDaT@j{%JjXP^8%#d;KbQoKieEc)mf&PQXE z50XWzjoP*mcxugO(!o_H<9&+frL~`x&zn20w7e`~9)F`Tx_0x5XUi(e3&F<#dMc}Z z6-}@0`-EaviZ>~4B|a#2wfV4hay8qi{^hERrPIrQG^%Ey zlo2cEZT|cXYwdeSzFz#wzROEbKJmLXpC0}8fzOWexOpXFUgBfl5E=Bo>>ZGl0 zkSyjMc%akgZ*^0B-d4n<6x&j)z47yt)`nl5K&5Xn-9{-)oepK zu(s3lBi7HOSfAo+iudFBptzs-pxFO`Pml8We`QoB#K+ZaLw$UGr{~AJLf%7PoUtDK z;*Bz?*}_M zAGR#$Jz)#vu{l8}#7CS?I3LhS)HaqxZ9_k}=?v_czl%9`cC}nyP}fUa(KJa}(pac0 zZY-=>JfA=FkXJ9PD>ApO+PMYx>Db2lsBPSLeE%Ojb!x=7KrfP-!-YP2n#@8ko+`6u zMA`I;gnf3k`LBhqm^tJ6^%o9b*%q~pm`-4$q!X#p*noBNckXM^`Mz!b27Ppgw!!6b z(whJH_H&rOQ*rM1;Q{(6xRz}+Kezkcf8_j=r8-hXMI5FeZ0JNCz!bLR~GK63poW8}uVuFDSXS-0o% z`LFjx`B-=A`S(Q?XL`loZ{wZi1@G^DwdGBt0`+<(-r@gYHs4u({x|x?{}%AiDZB8k zWoUyc4wsvlIqobxV|weJ#6|j zhNq9dr)Q6mq7kgizDtbW$`OL1D*GkFbiNPUBSA|wFicnPGQ8Ee&|+i+Wv{Lon%~U8 z7h8-Ey6dvj1>TWrb=lvo`{2LXeXv8l!H`F#SDR+&uFOpObX-5gt?7Zx!C6_^nbQj= zmv9C%WV&{xdZlzMQV_6A``VFnS0q6+^hr8hQ1QikRC-|~Hx$C>Wqzl{ErvqrnKlJe z4;%dchrP&7@XNrja*5ZHkmQy95l8}}jaosQ#YY9GD1uKmh_K*?jR?5cgCPOB=@${| zWZevliag)8)5JO2C>(dT&`}cT&Jw3m>`*CBpd$D+UGRwBntI$&5)w&blZP;seLajc zstP_ykxbh#uC)><+%d(BjMx^4-vn)z&+Tqh`ghjY$jlfUt=r1kgP94NaAam|H}ej} z;>g4${>>vVp*tOZ&Qv%vobw~LT)tCt1qI5Z9fA9xvAq{PqYVgE#Qvl|o`|C$po&|5 zazK@Qw0Y^0CEr}`7=d~j)Woo<1)(4>NJj(%s__yr34d#WDIH#+e@TVuXewP-b8~$- z>ftQfmZNuygBSyM{z3@DwFHSKpEI`E1tS~^X*v!%{M84Ub({r^jBhLOjY@AEGBkV0 zaL))aW2kS$u#6nP$Coi&8tlsu2j}Eu4IVtyKVpcuFnS!5N!gr_%#0Hk7x>6bXTAI~ zW2=Vy=$(YI?5jt;TgnFI`9-m3~KJCw|*%k`yV$IjoLKA2xKv zP|vWO?3^60*Pre4Cv;ZeTEb$W4H4(09+}y(L|XBXUDPO{)`Z9eqWkBBT>lEQB8H^D RCuzRtUtzKTUSnGc{14NLU1k6P literal 0 HcmV?d00001 diff --git a/src/ServiceHelpers/ServiceUninstall/obj/x86/Debug/ServiceUninstall.csproj.FileListAbsolute.txt b/src/ServiceHelpers/ServiceUninstall/obj/x86/Debug/ServiceUninstall.csproj.FileListAbsolute.txt new file mode 100644 index 000000000..a2704133c --- /dev/null +++ b/src/ServiceHelpers/ServiceUninstall/obj/x86/Debug/ServiceUninstall.csproj.FileListAbsolute.txt @@ -0,0 +1,5 @@ +C:\Dropbox\Dev\NzbDrone\_output\ServiceUninstall.exe.config +C:\Dropbox\Dev\NzbDrone\_output\ServiceUninstall.exe +C:\Dropbox\Dev\NzbDrone\_output\ServiceUninstall.pdb +C:\Dropbox\Dev\NzbDrone\src\ServiceHelpers\ServiceUninstall\obj\x86\Debug\ServiceUninstall.exe +C:\Dropbox\Dev\NzbDrone\src\ServiceHelpers\ServiceUninstall\obj\x86\Debug\ServiceUninstall.pdb diff --git a/src/ServiceHelpers/ServiceUninstall/obj/x86/Debug/ServiceUninstall.exe b/src/ServiceHelpers/ServiceUninstall/obj/x86/Debug/ServiceUninstall.exe new file mode 100644 index 0000000000000000000000000000000000000000..388d95519fe5773c7d6c2e325efc234ff3d25466 GIT binary patch literal 14336 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 literal 0 HcmV?d00001 diff --git a/src/UI/Content/bootstrap.toggle-switch.css b/src/UI/Content/bootstrap.toggle-switch.css index 5604b2415..ce924d3ce 100644 --- a/src/UI/Content/bootstrap.toggle-switch.css +++ b/src/UI/Content/bootstrap.toggle-switch.css @@ -49,7 +49,6 @@ https://github.com/ghinda/css-toggle-switch left: -100px; width: 100%; margin: 0; - padding-right: 100px; text-align: left; } diff --git a/src/UI/Content/theme.less b/src/UI/Content/theme.less index 7c1decd1f..f3a77ecbe 100644 --- a/src/UI/Content/theme.less +++ b/src/UI/Content/theme.less @@ -183,4 +183,18 @@ footer { #errors{ display : none; +} + +.rename-preview-item { + margin-bottom: 5px; + padding: 5px; + border-bottom: 1px solid #e5e5e5; + + .checkbox { + width: 80px; + margin-left: 0px; + display: inline-block; + padding-top: 0px; + margin-bottom: 0px; + } } \ No newline at end of file diff --git a/src/UI/Rename/RenamePreviewCollection.js b/src/UI/Rename/RenamePreviewCollection.js new file mode 100644 index 000000000..0f55f9634 --- /dev/null +++ b/src/UI/Rename/RenamePreviewCollection.js @@ -0,0 +1,38 @@ +'use strict'; +define( + [ + 'backbone', + 'Rename/RenamePreviewModel' + ], function (Backbone, RenamePreviewModel) { + return Backbone.Collection.extend({ + url : window.NzbDrone.ApiRoot + '/rename', + model: RenamePreviewModel, + + originalFetch: Backbone.Collection.prototype.fetch, + + initialize: function (options) { + if (!options.seriesId) { + throw 'seriesId is required'; + } + + this.seriesId = options.seriesId; + this.seasonNumber = options.seasonNumber; + }, + + fetch: function (options) { + if (!this.seriesId) { + throw 'seriesId is required'; + } + + options = options || {}; + options.data = {}; + options.data.seriesId = this.seriesId; + + if (this.seasonNumber) { + options.data.seasonNumber = this.seasonNumber; + } + + return this.originalFetch.call(this, options); + } + }); + }); diff --git a/src/UI/Rename/RenamePreviewCollectionView.js b/src/UI/Rename/RenamePreviewCollectionView.js new file mode 100644 index 000000000..7906b81e0 --- /dev/null +++ b/src/UI/Rename/RenamePreviewCollectionView.js @@ -0,0 +1,11 @@ +'use strict'; +define( + [ + 'marionette', + 'Rename/RenamePreviewItemView' + ], function (Marionette, RenamePreviewItemView) { + return Marionette.CollectionView.extend({ + + itemView : RenamePreviewItemView + }); + }); diff --git a/src/UI/Rename/RenamePreviewEmptyCollectionView.js b/src/UI/Rename/RenamePreviewEmptyCollectionView.js new file mode 100644 index 000000000..8101ddc05 --- /dev/null +++ b/src/UI/Rename/RenamePreviewEmptyCollectionView.js @@ -0,0 +1,10 @@ +'use strict'; +define( + [ + 'vent', + 'marionette' + ], function (vent, Marionette) { + return Marionette.ItemView.extend({ + template: 'Rename/RenamePreviewEmptyCollectionViewTemplate' + }); + }); diff --git a/src/UI/Rename/RenamePreviewEmptyCollectionViewTemplate.html b/src/UI/Rename/RenamePreviewEmptyCollectionViewTemplate.html new file mode 100644 index 000000000..1975f8a6a --- /dev/null +++ b/src/UI/Rename/RenamePreviewEmptyCollectionViewTemplate.html @@ -0,0 +1,3 @@ +
+ Success! My work is done, no files to rename. +
\ No newline at end of file diff --git a/src/UI/Rename/RenamePreviewItemView.js b/src/UI/Rename/RenamePreviewItemView.js new file mode 100644 index 000000000..71994e208 --- /dev/null +++ b/src/UI/Rename/RenamePreviewItemView.js @@ -0,0 +1,13 @@ +'use strict'; +define( + [ + 'vent', + 'marionette', + 'Mixins/AsModelBoundView' + ], function (vent, Marionette, AsModelBoundView) { + var view = Marionette.ItemView.extend({ + template: 'Rename/RenamePreviewItemViewTemplate' + }); + + return AsModelBoundView.apply(view); + }); diff --git a/src/UI/Rename/RenamePreviewItemViewTemplate.html b/src/UI/Rename/RenamePreviewItemViewTemplate.html new file mode 100644 index 000000000..cb6dc2288 --- /dev/null +++ b/src/UI/Rename/RenamePreviewItemViewTemplate.html @@ -0,0 +1,25 @@ +
+
+
+
+
\ No newline at end of file diff --git a/src/UI/Rename/RenamePreviewLayout.js b/src/UI/Rename/RenamePreviewLayout.js new file mode 100644 index 000000000..469f75a7d --- /dev/null +++ b/src/UI/Rename/RenamePreviewLayout.js @@ -0,0 +1,93 @@ +'use strict'; +define( + [ + 'underscore', + 'vent', + 'marionette', + 'Rename/RenamePreviewCollection', + 'Rename/RenamePreviewCollectionView', + 'Rename/RenamePreviewEmptyCollectionView', + 'Shared/LoadingView', + 'Commands/CommandController' + ], function (_, vent, Marionette, RenamePreviewCollection, RenamePreviewCollectionView, EmptyCollectionView, LoadingView, CommandController) { + + return Marionette.Layout.extend({ + template: 'Rename/RenamePreviewLayoutTemplate', + + regions: { + renamePreviews : '#rename-previews' + }, + + ui: { + pathInfo: '.x-path-info' + }, + + events: { + 'click .x-organize': '_organizeFiles' + }, + + initialize: function (options) { + this.model = options.series; + this.seasonNumber = options.seasonNumber; + + var viewOptions = {}; + viewOptions.seriesId = this.model.id; + viewOptions.seasonNumber = this.seasonNumber; + + this.collection = new RenamePreviewCollection(viewOptions); + this.listenTo(this.collection, 'sync', this._showPreviews); + + this.collection.fetch(); + }, + + onRender: function() { + this.renamePreviews.show(new LoadingView()); + }, + + _showPreviews: function () { + if (this.collection.length === 0) { + this.ui.pathInfo.hide(); + this.renamePreviews.show(new EmptyCollectionView()); + return; + } + + this.collection.invoke('set', { rename: true }); + this.renamePreviews.show(new RenamePreviewCollectionView({ collection: this.collection })); + }, + + _organizeFiles: function () { + if (this.collection.length === 0) { + vent.trigger(vent.Commands.CloseModalCommand); + } + + var files = _.map(this.collection.where({ rename: true }), function (model) { + return model.get('episodeFileId'); + }); + + if (files.length === 0) { + vent.trigger(vent.Commands.CloseModalCommand); + return; + } + + if (this.seasonNumber) { + CommandController.Execute('renameFiles', { + name : 'renameFiles', + seriesId : this.model.id, + seasonNumber: this.seasonNumber, + files : files + }); + } + + else { + CommandController.Execute('renameFiles', { + name : 'renameFiles', + seriesId : this.model.id, + seasonNumber: -1, + files : files + }); + } + + vent.trigger(vent.Commands.CloseModalCommand); + } + }); + }); diff --git a/src/UI/Rename/RenamePreviewLayoutTemplate.html b/src/UI/Rename/RenamePreviewLayoutTemplate.html new file mode 100644 index 000000000..5151e6257 --- /dev/null +++ b/src/UI/Rename/RenamePreviewLayoutTemplate.html @@ -0,0 +1,19 @@ +
+ + + +
+ diff --git a/src/UI/Rename/RenamePreviewModel.js b/src/UI/Rename/RenamePreviewModel.js new file mode 100644 index 000000000..19de2d6e1 --- /dev/null +++ b/src/UI/Rename/RenamePreviewModel.js @@ -0,0 +1,9 @@ +'use strict'; +define( + [ + 'backbone' + ], function (Backbone) { + return Backbone.Model.extend({ + }); + }); + diff --git a/src/UI/Series/Details/SeasonLayout.js b/src/UI/Series/Details/SeasonLayout.js index 8015ce0e1..0492f1768 100644 --- a/src/UI/Series/Details/SeasonLayout.js +++ b/src/UI/Series/Details/SeasonLayout.js @@ -12,7 +12,7 @@ define( 'Commands/CommandController', 'moment', 'underscore' - ], function (vent, Marionette, Backgrid, ToggleCell, EpisodeTitleCell, RelativeDateCell, EpisodeStatusCell, EpisodeActionsCell, CommandController, Moment,_) { + ], function (vent, Marionette, Backgrid, ToggleCell, EpisodeTitleCell, RelativeDateCell, EpisodeStatusCell, EpisodeActionsCell, CommandController, Moment, _) { return Marionette.Layout.extend({ template: 'Series/Details/SeasonLayoutTemplate', @@ -114,7 +114,7 @@ define( CommandController.bindToCommand({ element: this.ui.seasonRename, command: { - name : 'renameSeason', + name : 'renameFiles', seriesId : this.series.id, seasonNumber: this.model.get('seasonNumber') } @@ -131,12 +131,7 @@ define( }, _seasonRename: function () { - - CommandController.Execute('renameSeason', { - name : 'renameSeason', - seriesId : this.series.id, - seasonNumber: this.model.get('seasonNumber') - }); + vent.trigger(vent.Commands.ShowRenamePreview, { series: this.series, seasonNumber: this.model.get('seasonNumber') }); }, _seasonMonitored: function () { @@ -172,11 +167,6 @@ define( } }, - - _afterRename: function () { - vent.trigger(vent.Events.SeasonRenamed, { series: this.series, seasonNumber: this.model.get('seasonNumber') }); - }, - _showEpisodes: function () { this.episodeGrid.show(new Backgrid.Grid({ columns : this.columns, diff --git a/src/UI/Series/Details/SeriesDetailsLayout.js b/src/UI/Series/Details/SeriesDetailsLayout.js index b04aa0aa9..bc2d77b58 100644 --- a/src/UI/Series/Details/SeriesDetailsLayout.js +++ b/src/UI/Series/Details/SeriesDetailsLayout.js @@ -2,6 +2,7 @@ define( [ 'jquery', + 'underscore', 'vent', 'reqres', 'marionette', @@ -13,10 +14,21 @@ define( 'Series/Details/InfoView', 'Commands/CommandController', 'Shared/LoadingView', - 'underscore', 'backstrech', 'Mixins/backbone.signalr.mixin' - ], function ($,vent,reqres, Marionette, Backbone, EpisodeCollection, EpisodeFileCollection, SeasonCollection, SeasonCollectionView, InfoView, CommandController, LoadingView, _) { + ], function ($, + _, + vent, + reqres, + Marionette, + Backbone, + EpisodeCollection, + EpisodeFileCollection, + SeasonCollection, + SeasonCollectionView, + InfoView, + CommandController, + LoadingView) { return Marionette.Layout.extend({ itemViewContainer: '.x-series-seasons', @@ -47,7 +59,6 @@ define( initialize: function () { this.listenTo(this.model, 'change:monitored', this._setMonitoredState); this.listenTo(vent, vent.Events.SeriesDeleted, this._onSeriesDeleted); - this.listenTo(vent, vent.Events.SeasonRenamed, this._onSeasonRenamed); vent.on(vent.Events.CommandComplete, this._commandComplete, this); }, @@ -86,7 +97,9 @@ define( CommandController.bindToCommand({ element: this.ui.rename, command: { - name: 'renameSeries' + name : 'renameFiles', + seriesId : this.model.id, + seasonNumber: -1 } }); }, @@ -154,11 +167,7 @@ define( }, _renameSeries: function () { - CommandController.Execute('renameSeries', { - name : 'renameSeries', - seriesId: this.model.id - }); - + vent.trigger(vent.Commands.ShowRenamePreview, { series: this.model }); }, _seriesSearch: function () { @@ -196,14 +205,8 @@ define( this.info.show(new InfoView({ model: this.model })); }, - _onSeasonRenamed: function (event) { - if (this.model.get('id') === event.series.get('id')) { - this.episodeFileCollection.fetch(); - } - }, - _commandComplete: function (options) { - if (options.command.get('name') === 'refreshseries' || options.command.get('name') === 'renameseries') { + if (options.command.get('name') === 'refreshseries' || options.command.get('name') === 'renamefiles') { if (options.command.get('seriesId') === this.model.get('id')) { this._showSeasons(); this._setMonitoredState(); diff --git a/src/UI/Shared/Modal/Controller.js b/src/UI/Shared/Modal/Controller.js index 199aed4e6..177092de3 100644 --- a/src/UI/Shared/Modal/Controller.js +++ b/src/UI/Shared/Modal/Controller.js @@ -9,7 +9,8 @@ define( 'Episode/EpisodeDetailsLayout', 'History/Details/HistoryDetailsView', 'System/Logs/Table/Details/LogDetailsView', - ], function (vent, AppLayout, Marionette, EditSeriesView, DeleteSeriesView, EpisodeDetailsLayout, HistoryDetailsView, LogDetailsView) { + 'Rename/RenamePreviewLayout' + ], function (vent, AppLayout, Marionette, EditSeriesView, DeleteSeriesView, EpisodeDetailsLayout, HistoryDetailsView, LogDetailsView, RenamePreviewLayout) { return Marionette.AppRouter.extend({ @@ -21,6 +22,7 @@ define( vent.on(vent.Commands.ShowEpisodeDetails, this._showEpisode, this); vent.on(vent.Commands.ShowHistoryDetails, this._showHistory, this); vent.on(vent.Commands.ShowLogDetails, this._showLogDetails, this); + vent.on(vent.Commands.ShowRenamePreview, this._showRenamePreview, this); }, _openModal: function (view) { @@ -54,6 +56,11 @@ define( _showLogDetails: function (options) { var view = new LogDetailsView({ model: options.model }); AppLayout.modalRegion.show(view); + }, + + _showRenamePreview: function (options) { + var view = new RenamePreviewLayout(options); + AppLayout.modalRegion.show(view); } }); }); diff --git a/src/UI/vent.js b/src/UI/vent.js index 348e9c461..fdd869153 100644 --- a/src/UI/vent.js +++ b/src/UI/vent.js @@ -10,7 +10,6 @@ define( vent.Events = { SeriesAdded : 'series:added', SeriesDeleted : 'series:deleted', - SeasonRenamed : 'season:renamed', CommandComplete: 'command:complete', ServerUpdated : 'server:updated' }; @@ -25,7 +24,7 @@ define( ShowLogDetails : 'ShowLogDetails', SaveSettings : 'saveSettings', ShowLogFile : 'showLogFile', - ShowNamingWizard : 'showNamingWizard' + ShowRenamePreview : 'showRenamePreview' }; return vent;