1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2024-12-14 11:23:42 +02:00

added release results to episode detail tab

This commit is contained in:
kay.one 2013-06-06 17:17:57 -07:00
parent a5be71fd8c
commit 890d1f2398
14 changed files with 191 additions and 48 deletions

View File

@ -1,10 +1,8 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using NzbDrone.Api.Mapping; using NzbDrone.Api.Mapping;
using NzbDrone.Api.REST;
using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.IndexerSearch;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Parser;
using Omu.ValueInjecter; using Omu.ValueInjecter;
using System.Linq; using System.Linq;
@ -13,13 +11,32 @@ namespace NzbDrone.Api.Indexers
public class ReleaseModule : NzbDroneRestModule<ReleaseResource> public class ReleaseModule : NzbDroneRestModule<ReleaseResource>
{ {
private readonly IFetchAndParseRss _rssFetcherAndParser; private readonly IFetchAndParseRss _rssFetcherAndParser;
private readonly ISearchForNzb _nzbSearchService;
private readonly IMakeDownloadDecision _downloadDecisionMaker; private readonly IMakeDownloadDecision _downloadDecisionMaker;
public ReleaseModule(IFetchAndParseRss rssFetcherAndParser, IMakeDownloadDecision downloadDecisionMaker) public ReleaseModule(IFetchAndParseRss rssFetcherAndParser, ISearchForNzb nzbSearchService, IMakeDownloadDecision downloadDecisionMaker)
{ {
_rssFetcherAndParser = rssFetcherAndParser; _rssFetcherAndParser = rssFetcherAndParser;
_nzbSearchService = nzbSearchService;
_downloadDecisionMaker = downloadDecisionMaker; _downloadDecisionMaker = downloadDecisionMaker;
GetResourceAll = GetRss; GetResourceAll = GetReleases;
}
private List<ReleaseResource> GetReleases()
{
if (Request.Query.episodeId != null)
{
return GetEpisodeReleases(Request.Query.episodeId);
}
return GetRss();
}
private List<ReleaseResource> GetEpisodeReleases(int episodeId)
{
var decisions = _nzbSearchService.EpisodeSearch(episodeId);
return MapDecisions(decisions);
} }
private List<ReleaseResource> GetRss() private List<ReleaseResource> GetRss()
@ -27,6 +44,11 @@ private List<ReleaseResource> GetRss()
var reports = _rssFetcherAndParser.Fetch(); var reports = _rssFetcherAndParser.Fetch();
var decisions = _downloadDecisionMaker.GetRssDecision(reports); var decisions = _downloadDecisionMaker.GetRssDecision(reports);
return MapDecisions(decisions);
}
private static List<ReleaseResource> MapDecisions(IEnumerable<DownloadDecision> decisions)
{
var result = new List<ReleaseResource>(); var result = new List<ReleaseResource>();
foreach (var downloadDecision in decisions) foreach (var downloadDecision in decisions)
@ -44,24 +66,4 @@ private List<ReleaseResource> GetRss()
return result; return result;
} }
} }
public class ReleaseResource : RestResource
{
public Int32 Age { get; set; }
public Int64 Size { get; set; }
public String Indexer { get; set; }
public String NzbInfoUrl { get; set; }
public String NzbUrl { get; set; }
public String ReleaseGroup { get; set; }
public String Title { get; set; }
public Boolean FullSeason { get; set; }
public Boolean SceneSource { get; set; }
public Int32 SeasonNumber { get; set; }
public Language Language { get; set; }
public DateTime? AirDate { get; set; }
public String SeriesTitle { get; set; }
public int[] EpisodeNumbers { get; set; }
public Boolean Approved { get; set; }
public List<string> Rejections { get; set; }
}
} }

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using NzbDrone.Api.REST;
using NzbDrone.Core.Parser;
namespace NzbDrone.Api.Indexers
{
public class ReleaseResource : RestResource
{
public Int32 Age { get; set; }
public Int64 Size { get; set; }
public String Indexer { get; set; }
public String NzbInfoUrl { get; set; }
public String NzbUrl { get; set; }
public String ReleaseGroup { get; set; }
public String Title { get; set; }
public Boolean FullSeason { get; set; }
public Boolean SceneSource { get; set; }
public Int32 SeasonNumber { get; set; }
public Language Language { get; set; }
public DateTime? AirDate { get; set; }
public String SeriesTitle { get; set; }
public int[] EpisodeNumbers { get; set; }
public Boolean Approved { get; set; }
public List<string> Rejections { get; set; }
}
}

View File

@ -115,6 +115,7 @@
<Compile Include="Indexers\IndexerResource.cs" /> <Compile Include="Indexers\IndexerResource.cs" />
<Compile Include="Indexers\ReleaseModule.cs" /> <Compile Include="Indexers\ReleaseModule.cs" />
<Compile Include="Extensions\LazyExtensions.cs" /> <Compile Include="Extensions\LazyExtensions.cs" />
<Compile Include="Indexers\ReleaseResource.cs" />
<Compile Include="Logs\LogModule.cs" /> <Compile Include="Logs\LogModule.cs" />
<Compile Include="Logs\LogResource.cs" /> <Compile Include="Logs\LogResource.cs" />
<Compile Include="Mapping\CloneInjection.cs" /> <Compile Include="Mapping\CloneInjection.cs" />

View File

@ -26,5 +26,11 @@
<RegexTestSelector> <RegexTestSelector>
<RegularExpression>NzbDrone\.Common\.Test\.EventingTests\.ServiceNameFixture\..*</RegularExpression> <RegularExpression>NzbDrone\.Common\.Test\.EventingTests\.ServiceNameFixture\..*</RegularExpression>
</RegexTestSelector> </RegexTestSelector>
<RegexTestSelector>
<RegularExpression>NzbDrone\.Common\.Test\.ProcessProviderTests\..*</RegularExpression>
</RegexTestSelector>
<RegexTestSelector>
<RegularExpression>NzbDrone\.Common\.Test\.ServiceFactoryFixture\..*</RegularExpression>
</RegexTestSelector>
</IgnoredTests> </IgnoredTests>
</ProjectConfiguration> </ProjectConfiguration>

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using NzbDrone.Common.EnsureThat;
namespace NzbDrone.Core.IndexerSearch.Definitions namespace NzbDrone.Core.IndexerSearch.Definitions
{ {
@ -21,6 +22,8 @@ public string QueryTitle
private static string GetQueryTitle(string title) private static string GetQueryTitle(string title)
{ {
Ensure.That(() => title).IsNotNullOrWhiteSpace();
var cleanTitle = BeginningThe.Replace(title, String.Empty); var cleanTitle = BeginningThe.Replace(title, String.Empty);
cleanTitle = cleanTitle cleanTitle = cleanTitle

View File

@ -14,9 +14,8 @@ namespace NzbDrone.Core.IndexerSearch
{ {
public interface ISearchForNzb public interface ISearchForNzb
{ {
List<DownloadDecision> SearchSingle(int seriesId, int seasonNumber, int episodeNumber); List<DownloadDecision> EpisodeSearch(int episodeId);
List<DownloadDecision> SearchDaily(int seriesId, DateTime airDate); List<DownloadDecision> SeasonSearch(int seriesId, int seasonNumber);
List<DownloadDecision> SearchSeason(int seriesId, int seasonNumber);
} }
public class NzbSearchService : ISearchForNzb public class NzbSearchService : ISearchForNzb
@ -40,7 +39,23 @@ public NzbSearchService(IIndexerService indexerService, IFetchFeedFromIndexers f
_logger = logger; _logger = logger;
} }
public List<DownloadDecision> SearchSingle(int seriesId, int seasonNumber, int episodeNumber)
public List<DownloadDecision> EpisodeSearch(int episodeId)
{
var episode = _episodeService.GetEpisode(episodeId);
var series = _seriesService.GetSeries(episode.SeriesId);
if (series.SeriesType == SeriesTypes.Daily)
{
return SearchDaily(episode.SeriesId, episode.AirDate.Value.Date);
}
return SearchSingle(episode.SeriesId, episode.SeasonNumber, episode.EpisodeNumber);
}
private List<DownloadDecision> SearchSingle(int seriesId, int seasonNumber, int episodeNumber)
{ {
var searchSpec = Get<SingleEpisodeSearchCriteria>(seriesId, seasonNumber); var searchSpec = Get<SingleEpisodeSearchCriteria>(seriesId, seasonNumber);
@ -59,7 +74,7 @@ public List<DownloadDecision> SearchSingle(int seriesId, int seasonNumber, int e
return Dispatch(indexer => _feedFetcher.Fetch(indexer, searchSpec), searchSpec); return Dispatch(indexer => _feedFetcher.Fetch(indexer, searchSpec), searchSpec);
} }
public List<DownloadDecision> SearchDaily(int seriesId, DateTime airDate) private List<DownloadDecision> SearchDaily(int seriesId, DateTime airDate)
{ {
var searchSpec = Get<DailyEpisodeSearchCriteria>(seriesId); var searchSpec = Get<DailyEpisodeSearchCriteria>(seriesId);
searchSpec.Airtime = airDate; searchSpec.Airtime = airDate;
@ -67,7 +82,7 @@ public List<DownloadDecision> SearchDaily(int seriesId, DateTime airDate)
return Dispatch(indexer => _feedFetcher.Fetch(indexer, searchSpec), searchSpec); return Dispatch(indexer => _feedFetcher.Fetch(indexer, searchSpec), searchSpec);
} }
public List<DownloadDecision> SearchSeason(int seriesId, int seasonNumber) public List<DownloadDecision> SeasonSearch(int seriesId, int seasonNumber)
{ {
var searchSpec = Get<SeasonSearchCriteria>(seriesId, seasonNumber); var searchSpec = Get<SeasonSearchCriteria>(seriesId, seasonNumber);
searchSpec.SeasonNumber = seasonNumber; searchSpec.SeasonNumber = seasonNumber;
@ -99,10 +114,15 @@ private List<DownloadDecision> PartialSeasonSearch(SeasonSearchCriteria search)
{ {
var spec = new TSpec(); var spec = new TSpec();
var tvdbId = _seriesService.GetSeries(seriesId).TvdbId; var series = _seriesService.GetSeries(seriesId);
spec.SeriesId = seriesId; spec.SeriesId = seriesId;
spec.SceneTitle = _sceneMapping.GetSceneName(tvdbId, seasonNumber); spec.SceneTitle = _sceneMapping.GetSceneName(series.TvdbId, seasonNumber);
if (string.IsNullOrWhiteSpace(spec.SceneTitle))
{
spec.SceneTitle = series.Title;
}
return spec; return spec;
} }

View File

@ -12,7 +12,7 @@ interface ISearchAndDownload
void SearchSeason(int seriesId, int seasonNumber); void SearchSeason(int seriesId, int seasonNumber);
} }
public class SearchAndDownloadService : ISearchAndDownload /* public class SearchAndDownloadService : ISearchAndDownload
{ {
private readonly ISearchForNzb _searchService; private readonly ISearchForNzb _searchService;
private readonly IMakeDownloadDecision _downloadDecisionMaker; private readonly IMakeDownloadDecision _downloadDecisionMaker;
@ -23,7 +23,7 @@ public SearchAndDownloadService(ISearchForNzb searchService, IMakeDownloadDecisi
_downloadDecisionMaker = downloadDecisionMaker; _downloadDecisionMaker = downloadDecisionMaker;
} }
public void SearchSingle(int seriesId, int seasonNumber, int episodeNumber) public void FetchSearchSingle(int seriesId, int seasonNumber, int episodeNumber)
{ {
var result = _searchService.SearchSingle(seriesId, seasonNumber, episodeNumber); var result = _searchService.SearchSingle(seriesId, seasonNumber, episodeNumber);
} }
@ -37,5 +37,5 @@ public void SearchSeason(int seriesId, int seasonNumber)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
} }*/
} }

View File

@ -48,7 +48,7 @@ public IList<ReportInfo> Fetch(IIndexer indexer, SeasonSearchCriteria searchCrit
{ {
_logger.Debug("Searching for {0}", searchCriteria); _logger.Debug("Searching for {0}", searchCriteria);
var searchUrls = indexer.GetSeasonSearchUrls(searchCriteria.SceneTitle, searchCriteria.SeasonNumber); var searchUrls = indexer.GetSeasonSearchUrls(searchCriteria.QueryTitle, searchCriteria.SeasonNumber);
var result = Fetch(indexer, searchUrls); var result = Fetch(indexer, searchUrls);
@ -60,7 +60,7 @@ public IList<ReportInfo> Fetch(IIndexer indexer, SingleEpisodeSearchCriteria sea
{ {
_logger.Debug("Searching for {0}", searchCriteria); _logger.Debug("Searching for {0}", searchCriteria);
var searchUrls = indexer.GetEpisodeSearchUrls(searchCriteria.SceneTitle, searchCriteria.SeasonNumber, searchCriteria.EpisodeNumber); var searchUrls = indexer.GetEpisodeSearchUrls(searchCriteria.QueryTitle, searchCriteria.SeasonNumber, searchCriteria.EpisodeNumber);
var result = Fetch(indexer, searchUrls); var result = Fetch(indexer, searchUrls);
@ -73,7 +73,7 @@ public IList<ReportInfo> Fetch(IIndexer indexer, PartialSeasonSearchCriteria sea
{ {
_logger.Debug("Searching for {0}", searchCriteria); _logger.Debug("Searching for {0}", searchCriteria);
var searchUrls = indexer.GetSeasonSearchUrls(searchCriteria.SceneTitle, searchCriteria.SeasonNumber); var searchUrls = indexer.GetSeasonSearchUrls(searchCriteria.QueryTitle, searchCriteria.SeasonNumber);
var result = Fetch(indexer, searchUrls); var result = Fetch(indexer, searchUrls);
@ -85,7 +85,7 @@ public IList<ReportInfo> Fetch(IIndexer indexer, DailyEpisodeSearchCriteria sear
{ {
_logger.Debug("Searching for {0}", searchCriteria); _logger.Debug("Searching for {0}", searchCriteria);
var searchUrls = indexer.GetDailyEpisodeSearchUrls(searchCriteria.SceneTitle, searchCriteria.Airtime); var searchUrls = indexer.GetDailyEpisodeSearchUrls(searchCriteria.QueryTitle, searchCriteria.Airtime);
var result = Fetch(indexer, searchUrls); var result = Fetch(indexer, searchUrls);
_logger.Info("Finished searching {0} on {1}. Found {2}", indexer.Name, searchCriteria, result.Count); _logger.Info("Finished searching {0} on {1}. Found {2}", indexer.Name, searchCriteria, result.Count);

View File

@ -1,6 +1,6 @@
<SolutionConfiguration> <SolutionConfiguration>
<FileVersion>1</FileVersion> <FileVersion>1</FileVersion>
<AutoEnableOnStartup>False</AutoEnableOnStartup> <AutoEnableOnStartup>True</AutoEnableOnStartup>
<AllowParallelTestExecution>true</AllowParallelTestExecution> <AllowParallelTestExecution>true</AllowParallelTestExecution>
<AllowTestsToRunInParallelWithThemselves>true</AllowTestsToRunInParallelWithThemselves> <AllowTestsToRunInParallelWithThemselves>true</AllowTestsToRunInParallelWithThemselves>
<FrameworkUtilisationTypeForNUnit>UseDynamicAnalysis</FrameworkUtilisationTypeForNUnit> <FrameworkUtilisationTypeForNUnit>UseDynamicAnalysis</FrameworkUtilisationTypeForNUnit>

View File

@ -1,5 +1,5 @@
"use strict"; "use strict";
define(['app', 'Episode/Summary/View'], function () { define(['app', 'Shared/SpinnerView', 'Episode/Summary/View', 'Episode/Search/Layout', 'Release/Collection'], function () {
NzbDrone.Episode.Layout = Backbone.Marionette.Layout.extend({ NzbDrone.Episode.Layout = Backbone.Marionette.Layout.extend({
template: 'Episode/LayoutTemplate', template: 'Episode/LayoutTemplate',
@ -27,6 +27,7 @@ define(['app', 'Episode/Summary/View'], function () {
onShow: function () { onShow: function () {
this.showSummary(); this.showSummary();
this._releaseSearchActivated = false;
}, },
@ -53,9 +54,23 @@ define(['app', 'Episode/Summary/View'], function () {
e.preventDefault(); e.preventDefault();
} }
if (this._releaseSearchActivated) {
return;
}
var self = this;
this.ui.search.tab('show'); this.ui.search.tab('show');
this.search.show(new NzbDrone.Shared.SpinnerView());
var releases = new NzbDrone.Release.Collection();
var promise = releases.fetchEpisodeReleases(this.model.id);
promise.done(function () {
self.search.show(new NzbDrone.Episode.Search.Layout({collection: releases}));
});
} }
}); });
}); });

View File

@ -2,9 +2,65 @@
define(['app'], function () { define(['app'], function () {
NzbDrone.Episode.Search.Layout = Backbone.Marionette.Layout.extend({ NzbDrone.Episode.Search.Layout = Backbone.Marionette.Layout.extend({
template: 'Episode/Search/LayoutTemplate' template: 'Episode/Search/LayoutTemplate',
regions: {
grid: '#episode-release-grid'
},
columns: [
{
name : 'age',
label : 'Age',
sortable: true,
cell : Backgrid.IntegerCell
},
{
name : 'size',
label : 'Size',
sortable: true,
cell : Backgrid.IntegerCell
},
{
name : 'title',
label : 'Title',
sortable: true,
cell : Backgrid.StringCell
},
{
name : 'seasonNumber',
label: 'season',
cell : Backgrid.IntegerCell
},
{
name : 'episodeNumber',
label: 'episode',
cell : Backgrid.StringCell
},
{
name : 'approved',
label: 'Approved',
cell : Backgrid.BooleanCell
}
],
initialize: function () {
},
onShow :function(){
if (!this.isClosed) {
this.grid.show(new Backgrid.Grid(
{
row : Backgrid.Row,
columns : this.columns,
collection: this.collection,
className : 'table table-hover'
}));
}
}
}); });
}); });

View File

@ -1 +1 @@
 <div id="episode-release-grid"/>

View File

@ -4,6 +4,10 @@ define(['app', 'Release/Model'], function () {
url : NzbDrone.Constants.ApiRoot + '/release', url : NzbDrone.Constants.ApiRoot + '/release',
model: NzbDrone.Release.Model, model: NzbDrone.Release.Model,
mode : 'client' mode: 'client',
fetchEpisodeReleases: function (episodeId) {
return this.fetch({ data: { episodeId: episodeId }});
}
}); });
}); });

View File

@ -10,9 +10,18 @@ define(['app'], function () {
$(document).on('click', 'a[href]', this._handleClick); $(document).on('click', 'a[href]', this._handleClick);
}, },
_isInTab: function (element) {
return;
},
_handleClick: function (event) { _handleClick: function (event) {
var $target = $(event.target); var $target = $(event.target);
//check if tab nav
if ($target.parents('.nav-tabs').length) {
return;
}
if ($target.hasClass('no-router')) { if ($target.hasClass('no-router')) {
return; return;
} }