From a7fd486b03d837f8ab27c696f1521b26a8335ebd Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Mon, 3 Sep 2012 16:26:52 -0700 Subject: [PATCH] Change episode file quality New: Ability to change the quality of an episode in the database --- NzbDrone.Core/Providers/MediaFileProvider.cs | 10 +++ NzbDrone.Web/Content/Images/changequality.png | Bin 0 -> 5900 bytes NzbDrone.Web/Controllers/EpisodeController.cs | 20 ++++- NzbDrone.Web/Controllers/SeriesController.cs | 9 ++ NzbDrone.Web/Models/EpisodeModel.cs | 3 + NzbDrone.Web/Models/SeriesDetailsModel.cs | 2 + NzbDrone.Web/NzbDrone.Web.csproj | 1 + .../Scripts/NzbDrone/seriesDetails.js | 85 +++++++++++++++++- NzbDrone.Web/Views/Series/Details.cshtml | 7 ++ NzbDrone.Web/Views/Series/Episode.cshtml | 5 +- NzbDrone.Web/Views/Series/Season.cshtml | 5 +- NzbDrone/NzbDrone.csproj | 4 +- 12 files changed, 143 insertions(+), 8 deletions(-) create mode 100644 NzbDrone.Web/Content/Images/changequality.png diff --git a/NzbDrone.Core/Providers/MediaFileProvider.cs b/NzbDrone.Core/Providers/MediaFileProvider.cs index 831cb60f3..7cb7d59b9 100644 --- a/NzbDrone.Core/Providers/MediaFileProvider.cs +++ b/NzbDrone.Core/Providers/MediaFileProvider.cs @@ -221,6 +221,16 @@ namespace NzbDrone.Core.Providers return CleanFilename(result.Trim()); } + public virtual void ChangeQuality(int episodeFileId, QualityTypes quality) + { + _database.Execute("UPDATE EpisodeFiles SET Quality = @quality WHERE EpisodeFileId = @episodeFileId", new { episodeFileId, quality }); + } + + public virtual void ChangeQuality(int seriesId, int seasonNumber, QualityTypes quality) + { + _database.Execute("UPDATE EpisodeFiles SET Quality = @quality WHERE SeriesId = @seriesId AND SeasonNumber = @seasonNumber", new { seriesId, seasonNumber, quality }); + } + public static string CleanFilename(string name) { string result = name; diff --git a/NzbDrone.Web/Content/Images/changequality.png b/NzbDrone.Web/Content/Images/changequality.png new file mode 100644 index 0000000000000000000000000000000000000000..97cdc14cf524343fb7422c105b72cc5033a8153b GIT binary patch literal 5900 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 literal 0 HcmV?d00001 diff --git a/NzbDrone.Web/Controllers/EpisodeController.cs b/NzbDrone.Web/Controllers/EpisodeController.cs index 49b98f6f0..86a7c3771 100644 --- a/NzbDrone.Web/Controllers/EpisodeController.cs +++ b/NzbDrone.Web/Controllers/EpisodeController.cs @@ -1,6 +1,8 @@ using System; using System.Web.Mvc; using NzbDrone.Core.Jobs; +using NzbDrone.Core.Providers; +using NzbDrone.Core.Repository.Quality; using NzbDrone.Web.Models; namespace NzbDrone.Web.Controllers @@ -8,10 +10,12 @@ namespace NzbDrone.Web.Controllers public class EpisodeController : Controller { private readonly JobProvider _jobProvider; + private readonly MediaFileProvider _mediaFileProvider; - public EpisodeController(JobProvider jobProvider) + public EpisodeController(JobProvider jobProvider, MediaFileProvider mediaFileProvider) { _jobProvider = jobProvider; + _mediaFileProvider = mediaFileProvider; } public JsonResult Search(int episodeId) @@ -52,5 +56,19 @@ namespace NzbDrone.Web.Controllers _jobProvider.QueueJob(typeof(RenameSeriesJob)); return JsonNotificationResult.Queued("Series rename"); } + + [HttpPost] + public JsonResult ChangeEpisodeQuality(int episodeFileId, QualityTypes quality) + { + _mediaFileProvider.ChangeQuality(episodeFileId, quality); + return Json("ok"); + } + + [HttpPost] + public JsonResult ChangeSeasonQuality(int seriesId, int seasonNumber, QualityTypes quality) + { + _mediaFileProvider.ChangeQuality(seriesId, seasonNumber, quality); + return Json("ok"); + } } } \ No newline at end of file diff --git a/NzbDrone.Web/Controllers/SeriesController.cs b/NzbDrone.Web/Controllers/SeriesController.cs index a2ecd9437..ac7098962 100644 --- a/NzbDrone.Web/Controllers/SeriesController.cs +++ b/NzbDrone.Web/Controllers/SeriesController.cs @@ -128,6 +128,11 @@ namespace NzbDrone.Web.Controllers CommonStatus = GetCommonStatus(s.Episodes) }).ToList(); model.Seasons = seasons; + + var qualities = (from QualityTypes q in Enum.GetValues(typeof(QualityTypes)) + select new { Id = (int)q, Name = q.ToString() }).ToList(); + + model.QualitySelectList = new SelectList(qualities.Where(q => q.Id > 0), "Id", "Name"); return View(model); } @@ -216,12 +221,14 @@ namespace NzbDrone.Web.Controllers var episodeFileId = 0; var episodePath = String.Empty; var episodeQuality = "N/A"; + var episodeQualityId = 0; if (e.EpisodeFile != null) { episodePath = e.EpisodeFile.Path; episodeFileId = e.EpisodeFile.EpisodeFileId; episodeQuality = e.EpisodeFile.Quality.ToString(); + episodeQualityId = (int)e.EpisodeFile.Quality; } var airDate = String.Empty; @@ -232,6 +239,7 @@ namespace NzbDrone.Web.Controllers episodes.Add(new EpisodeModel { EpisodeId = e.EpisodeId, + EpisodeFileId = episodeFileId, EpisodeNumber = e.EpisodeNumber, SeasonNumber = e.SeasonNumber, Title = e.Title, @@ -240,6 +248,7 @@ namespace NzbDrone.Web.Controllers Path = episodePath, Status = e.Status.ToString(), Quality = episodeQuality, + QualityId = episodeQualityId, Ignored = e.Ignored }); } diff --git a/NzbDrone.Web/Models/EpisodeModel.cs b/NzbDrone.Web/Models/EpisodeModel.cs index b89f6c6ac..3857a9c3c 100644 --- a/NzbDrone.Web/Models/EpisodeModel.cs +++ b/NzbDrone.Web/Models/EpisodeModel.cs @@ -1,5 +1,6 @@ using System; using NzbDrone.Core.Model; +using NzbDrone.Core.Repository.Quality; namespace NzbDrone.Web.Models { @@ -7,6 +8,7 @@ namespace NzbDrone.Web.Models { public string Title { get; set; } public int EpisodeId { get; set; } + public int EpisodeFileId { get; set; } public int EpisodeNumber { get; set; } public int SeasonNumber { get; set; } public string Overview { get; set; } @@ -14,6 +16,7 @@ namespace NzbDrone.Web.Models public String Status { get; set; } public string AirDate { get; set; } public String Quality { get; set; } + public int QualityId { get; set; } public bool Ignored { get; set; } } } \ No newline at end of file diff --git a/NzbDrone.Web/Models/SeriesDetailsModel.cs b/NzbDrone.Web/Models/SeriesDetailsModel.cs index 329e213d5..9c3cb9054 100644 --- a/NzbDrone.Web/Models/SeriesDetailsModel.cs +++ b/NzbDrone.Web/Models/SeriesDetailsModel.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Web; +using System.Web.Mvc; using NzbDrone.Core.Model; using NzbDrone.Core.Repository; @@ -18,5 +19,6 @@ namespace NzbDrone.Web.Models public string Path { get; set; } public bool HasBanner { get; set; } public List Seasons { get; set; } + public SelectList QualitySelectList { get; set; } } } \ No newline at end of file diff --git a/NzbDrone.Web/NzbDrone.Web.csproj b/NzbDrone.Web/NzbDrone.Web.csproj index ca5469081..d5419bb9b 100644 --- a/NzbDrone.Web/NzbDrone.Web.csproj +++ b/NzbDrone.Web/NzbDrone.Web.csproj @@ -164,6 +164,7 @@ + diff --git a/NzbDrone.Web/Scripts/NzbDrone/seriesDetails.js b/NzbDrone.Web/Scripts/NzbDrone/seriesDetails.js index 276494086..495a654aa 100644 --- a/NzbDrone.Web/Scripts/NzbDrone/seriesDetails.js +++ b/NzbDrone.Web/Scripts/NzbDrone/seriesDetails.js @@ -8,6 +8,11 @@ var seriesId = 0; var saveSeasonIgnoreUrl = '../Command/SaveSeasonIgnore'; var saveEpisodeIgnoreUrl = '../Command/SaveEpisodeIgnore'; +var changeQualityType; +var changeQualityData; +var changeEpisodeQualityUrl = '../Episode/ChangeEpisodeQuality'; +var changeSeasonQualityUrl = '../Episode/ChangeSeasonQuality'; + //Episode Ignore Functions $(".ignoreEpisode").live("click", function () { var toggle = $(this); @@ -121,4 +126,82 @@ function saveEpisodeIgnore(episodeId, ignored) { alert("Sorry! We could save the ignore settings for Episode: " + episodeId + " at this time. " + error); } }); -} \ No newline at end of file +} + +//Change quality +$(document).on('click', '.changeQuality', function() { + changeQualityType = $(this).attr('data-changetype'); + + if (changeQualityType === "episode") { + var row = $(this).closest('tr'); + + changeQualityData = $(row).attr('data-episodefileid'); + + if (changeQualityData === "0") + return; + + var qualityId = $(row).find('.episodeQuality').attr('data-qualityid'); + $('#NewQuality').val(qualityId); + } + + else { + changeQualityData = $(this).closest('table').attr('data-season'); + } + + $('#qualityChanger').dialog('open'); +}); + +$("#qualityChanger").dialog({ + autoOpen: false, + height: 'auto', + width: 670, + resizable: false, + modal: true, + buttons: { + "Save": function () { + //Save the quality + var newQualityId = $('#NewQuality').val(); + var newQualityText = $('#NewQuality :selected').text(); + + if (changeQualityType === "episode") { + $.ajax({ + url: changeEpisodeQualityUrl, + data: { episodeFileId: changeQualityData, quality: newQualityId }, + type: 'POST', + success: function(data) { + var row = $('tr[data-episodefileid="' + changeQualityData + '"]'); + var qualityCell = $(row).find('.episodeQuality'); + $(qualityCell).attr('data-qualityid', newQualityId); + $(qualityCell).text(newQualityText); + } + }); + } + + else { + $.ajax({ + url: changeSeasonQualityUrl, + data: { seriesId: seriesId, seasonNumber: changeQualityData, quality: newQualityId }, + type: 'POST', + success: function (data) { + var table = $('table[data-season="' + changeQualityData + '"]'); + var rows = $(table).children('tr'); + + $(rows).each(function() { + if ($(this).attr('data-episodefileid') === 0) + return; + + var qualityCell = $(this).find('.episodeQuality'); + $(qualityCell).attr('data-qualityid', newQualityId); + $(qualityCell).text(newQualityText); + }); + } + }); + } + + $(this).dialog("close"); + }, + Cancel: function () { + $(this).dialog("close"); + } + } +}); \ No newline at end of file diff --git a/NzbDrone.Web/Views/Series/Details.cshtml b/NzbDrone.Web/Views/Series/Details.cshtml index 69c0f7569..60e692cc9 100644 --- a/NzbDrone.Web/Views/Series/Details.cshtml +++ b/NzbDrone.Web/Views/Series/Details.cshtml @@ -111,6 +111,13 @@ +
+
+ + @Html.DropDownList("NewQuality", Model.QualitySelectList) +
+
+ @section Scripts{ @Html.IncludeScript("NzbDrone/seriesDetails.js") @Html.IncludeScript("NzbDrone/series.js") diff --git a/NzbDrone.Web/Views/Series/Episode.cshtml b/NzbDrone.Web/Views/Series/Episode.cshtml index 56c4575ac..bd5d59fa4 100644 --- a/NzbDrone.Web/Views/Series/Episode.cshtml +++ b/NzbDrone.Web/Views/Series/Episode.cshtml @@ -2,11 +2,11 @@ @using NzbDrone.Web.Helpers @model NzbDrone.Web.Models.EpisodeModel - + @Model.EpisodeNumber @Model.Title @Model.AirDate - @Model.Quality + @Model.Quality @{ string cellColourClass = String.Empty; @@ -26,6 +26,7 @@ @Ajax.ImageActionLink("../../Content/Images/Search.png", new { Alt = "Search", Title = "Search for episode", @class = "gridAction" }, "Search", "Episode", new { episodeId = Model.EpisodeId }, null, null) + @Model.Status diff --git a/NzbDrone.Web/Views/Series/Season.cshtml b/NzbDrone.Web/Views/Series/Season.cshtml index 5764cffd8..8a24029c4 100644 --- a/NzbDrone.Web/Views/Series/Season.cshtml +++ b/NzbDrone.Web/Views/Series/Season.cshtml @@ -5,13 +5,13 @@ @(Model.SeasonNumber == 0 ? "Specials" : "Season " + Model.SeasonNumber) - +
- + @@ -24,6 +24,7 @@ diff --git a/NzbDrone/NzbDrone.csproj b/NzbDrone/NzbDrone.csproj index f6741ac32..f2dfdfdb7 100644 --- a/NzbDrone/NzbDrone.csproj +++ b/NzbDrone/NzbDrone.csproj @@ -42,7 +42,7 @@ 4trueBasicCorrectnessRules.ruleset - C:\Users\Markus\AppData\Local\Temp\vs73DE.tmp\x86\Debug\ + C:\Users\Mark\AppData\Local\Temp\vs32F1.tmp\x86\Debug\ x86 @@ -52,7 +52,7 @@ TRACE prompt 4 - C:\Users\Markus\AppData\Local\Temp\vs73DE.tmp\x86\Release\ + C:\Users\Mark\AppData\Local\Temp\vs32F1.tmp\x86\Release\ NzbDrone.ico
@Ajax.ImageActionLink("../../Content/Images/Search.png", new { Alt = "Search", Title = "Search for all episodes in this season", @class = "gridAction" }, "SearchSeason", "Episode", new { SeriesId = Model.SeriesId, SeasonNumber = Model.SeasonNumber }, null, null) + @Ajax.ImageActionLink("../../Content/Images/Rename.png", new { Alt = "Rename", Title = "Rename all episodes in this season", @class = "gridAction" }, "RenameSeason", "Episode", new { SeriesId = Model.SeriesId, SeasonNumber = Model.SeasonNumber }, null, null)