New: The Manual Search result table is now sorted by the internal prioritization logic and sorting by quality now works as well.

Tnx to mspec and betrayed for averting catastrophe.
pull/2/head
Taloth Saldono 11 years ago
parent d8543ad533
commit 8f192e635f

@ -15,6 +15,7 @@ using Omu.ValueInjecter;
using System.Linq; using System.Linq;
using Nancy.ModelBinding; using Nancy.ModelBinding;
using NzbDrone.Api.Extensions; using NzbDrone.Api.Extensions;
using NzbDrone.Core.Qualities;
namespace NzbDrone.Api.Indexers namespace NzbDrone.Api.Indexers
{ {
@ -23,6 +24,7 @@ namespace NzbDrone.Api.Indexers
private readonly IFetchAndParseRss _rssFetcherAndParser; private readonly IFetchAndParseRss _rssFetcherAndParser;
private readonly ISearchForNzb _nzbSearchService; private readonly ISearchForNzb _nzbSearchService;
private readonly IMakeDownloadDecision _downloadDecisionMaker; private readonly IMakeDownloadDecision _downloadDecisionMaker;
private readonly IPrioritizeDownloadDecision _prioritizeDownloadDecision;
private readonly IDownloadService _downloadService; private readonly IDownloadService _downloadService;
private readonly IParsingService _parsingService; private readonly IParsingService _parsingService;
private readonly Logger _logger; private readonly Logger _logger;
@ -30,6 +32,7 @@ namespace NzbDrone.Api.Indexers
public ReleaseModule(IFetchAndParseRss rssFetcherAndParser, public ReleaseModule(IFetchAndParseRss rssFetcherAndParser,
ISearchForNzb nzbSearchService, ISearchForNzb nzbSearchService,
IMakeDownloadDecision downloadDecisionMaker, IMakeDownloadDecision downloadDecisionMaker,
IPrioritizeDownloadDecision prioritizeDownloadDecision,
IDownloadService downloadService, IDownloadService downloadService,
IParsingService parsingService, IParsingService parsingService,
Logger logger) Logger logger)
@ -37,6 +40,7 @@ namespace NzbDrone.Api.Indexers
_rssFetcherAndParser = rssFetcherAndParser; _rssFetcherAndParser = rssFetcherAndParser;
_nzbSearchService = nzbSearchService; _nzbSearchService = nzbSearchService;
_downloadDecisionMaker = downloadDecisionMaker; _downloadDecisionMaker = downloadDecisionMaker;
_prioritizeDownloadDecision = prioritizeDownloadDecision;
_downloadService = downloadService; _downloadService = downloadService;
_parsingService = parsingService; _parsingService = parsingService;
_logger = logger; _logger = logger;
@ -70,7 +74,9 @@ namespace NzbDrone.Api.Indexers
try try
{ {
var decisions = _nzbSearchService.EpisodeSearch(episodeId); var decisions = _nzbSearchService.EpisodeSearch(episodeId);
return MapDecisions(decisions); var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisions(decisions);
return MapDecisions(prioritizedDecisions);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -84,8 +90,9 @@ namespace NzbDrone.Api.Indexers
{ {
var reports = _rssFetcherAndParser.Fetch(); var reports = _rssFetcherAndParser.Fetch();
var decisions = _downloadDecisionMaker.GetRssDecision(reports); var decisions = _downloadDecisionMaker.GetRssDecision(reports);
var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisions(decisions);
return MapDecisions(decisions); return MapDecisions(prioritizedDecisions);
} }
private static List<ReleaseResource> MapDecisions(IEnumerable<DownloadDecision> decisions) private static List<ReleaseResource> MapDecisions(IEnumerable<DownloadDecision> decisions)
@ -102,6 +109,18 @@ namespace NzbDrone.Api.Indexers
release.Rejections = downloadDecision.Rejections.ToList(); release.Rejections = downloadDecision.Rejections.ToList();
release.DownloadAllowed = downloadDecision.RemoteEpisode.DownloadAllowed; release.DownloadAllowed = downloadDecision.RemoteEpisode.DownloadAllowed;
release.ReleaseWeight = result.Count;
if (downloadDecision.RemoteEpisode.Series != null)
{
release.QualityWeight = downloadDecision.RemoteEpisode.Series.QualityProfile.Value.Items.FindIndex(v => v.Quality == release.Quality.Quality) * 2;
}
if (!release.Quality.Proper)
{
release.QualityWeight++;
}
result.Add(release); result.Add(release);
} }

@ -10,6 +10,7 @@ namespace NzbDrone.Api.Indexers
public class ReleaseResource : RestResource public class ReleaseResource : RestResource
{ {
public QualityModel Quality { get; set; } public QualityModel Quality { get; set; }
public Int32 QualityWeight { get; set; }
public Int32 Age { get; set; } public Int32 Age { get; set; }
public Double AgeHours { get; set; } public Double AgeHours { get; set; }
public Int64 Size { get; set; } public Int64 Size { get; set; }
@ -35,6 +36,7 @@ namespace NzbDrone.Api.Indexers
public String InfoUrl { get; set; } public String InfoUrl { get; set; }
public Boolean DownloadAllowed { get; set; } public Boolean DownloadAllowed { get; set; }
public DownloadProtocol DownloadProtocol { get; set; } public DownloadProtocol DownloadProtocol { get; set; }
public Int32 ReleaseWeight { get; set; }
public Boolean IsDaily { get; set; } public Boolean IsDaily { get; set; }
public Boolean IsAbsoluteNumbering { get; set; } public Boolean IsAbsoluteNumbering { get; set; }

@ -1,20 +1,21 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using FizzWare.NBuilder; using NzbDrone.Core.Tv;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.DecisionEngine.Specifications;
using NUnit.Framework;
using FluentAssertions;
using FizzWare.NBuilder;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
[TestFixture] [TestFixture]
public class GetQualifiedReportsFixture : CoreTest<DownloadApprovedReports> public class PrioritizeDownloadDecisionFixture : CoreTest<DownloadDecisionPriorizationService>
{ {
private Episode GetEpisode(int id) private Episode GetEpisode(int id)
{ {
@ -44,16 +45,6 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
return remoteEpisode; return remoteEpisode;
} }
[Test]
public void should_return_an_empty_list_when_none_are_appproved()
{
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(null, "Failure!"));
decisions.Add(new DownloadDecision(null, "Failure!"));
Subject.GetQualifiedReports(decisions).Should().BeEmpty();
}
[Test] [Test]
public void should_put_propers_before_non_propers() public void should_put_propers_before_non_propers()
{ {
@ -64,7 +55,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteEpisode1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteEpisode2));
var qualifiedReports = Subject.GetQualifiedReports(decisions); var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.ParsedEpisodeInfo.Quality.Proper.Should().BeTrue(); qualifiedReports.First().RemoteEpisode.ParsedEpisodeInfo.Quality.Proper.Should().BeTrue();
} }
@ -78,7 +69,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteEpisode1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteEpisode2));
var qualifiedReports = Subject.GetQualifiedReports(decisions); var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.ParsedEpisodeInfo.Quality.Quality.Should().Be(Quality.HDTV720p); qualifiedReports.First().RemoteEpisode.ParsedEpisodeInfo.Quality.Quality.Should().Be(Quality.HDTV720p);
} }
@ -92,7 +83,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteEpisode1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteEpisode2));
var qualifiedReports = Subject.GetQualifiedReports(decisions); var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.Episodes.First().EpisodeNumber.Should().Be(1); qualifiedReports.First().RemoteEpisode.Episodes.First().EpisodeNumber.Should().Be(1);
} }
@ -106,7 +97,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteEpisode1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteEpisode2));
var qualifiedReports = Subject.GetQualifiedReports(decisions); var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.Episodes.First().EpisodeNumber.Should().Be(1); qualifiedReports.First().RemoteEpisode.Episodes.First().EpisodeNumber.Should().Be(1);
} }
@ -125,7 +116,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
decisions.Add(new DownloadDecision(remoteEpisodeHdSmallYounge)); decisions.Add(new DownloadDecision(remoteEpisodeHdSmallYounge));
decisions.Add(new DownloadDecision(remoteEpisodeHdLargeYounge)); decisions.Add(new DownloadDecision(remoteEpisodeHdLargeYounge));
var qualifiedReports = Subject.GetQualifiedReports(decisions); var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.Should().Be(remoteEpisodeHdSmallYounge); qualifiedReports.First().RemoteEpisode.Should().Be(remoteEpisodeHdSmallYounge);
} }
@ -140,7 +131,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
decisions.Add(new DownloadDecision(remoteEpisode1)); decisions.Add(new DownloadDecision(remoteEpisode1));
decisions.Add(new DownloadDecision(remoteEpisode2)); decisions.Add(new DownloadDecision(remoteEpisode2));
var qualifiedReports = Subject.GetQualifiedReports(decisions); var qualifiedReports = Subject.PrioritizeDecisions(decisions);
qualifiedReports.First().RemoteEpisode.Should().Be(remoteEpisode2); qualifiedReports.First().RemoteEpisode.Should().Be(remoteEpisode2);
} }
} }

@ -11,12 +11,21 @@ using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Test.Common; using NzbDrone.Test.Common;
using NzbDrone.Core.DecisionEngine;
namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
{ {
[TestFixture] [TestFixture]
public class DownloadApprovedFixture : CoreTest<DownloadApprovedReports> public class DownloadApprovedFixture : CoreTest<DownloadApprovedReports>
{ {
[SetUp]
public void SetUp()
{
Mocker.GetMock<IPrioritizeDownloadDecision>()
.Setup(v => v.PrioritizeDecisions(It.IsAny<List<DownloadDecision>>()))
.Returns<List<DownloadDecision>>(v => v);
}
private Episode GetEpisode(int id) private Episode GetEpisode(int id)
{ {
return Builder<Episode>.CreateNew() return Builder<Episode>.CreateNew()
@ -163,5 +172,15 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
Subject.DownloadApproved(decisions).Should().BeEmpty(); Subject.DownloadApproved(decisions).Should().BeEmpty();
ExceptionVerification.ExpectedWarns(1); ExceptionVerification.ExpectedWarns(1);
} }
[Test]
public void should_return_an_empty_list_when_none_are_appproved()
{
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(null, "Failure!"));
decisions.Add(new DownloadDecision(null, "Failure!"));
Subject.GetQualifiedReports(decisions).Should().BeEmpty();
}
} }
} }

@ -114,7 +114,7 @@
<Compile Include="DecisionEngineTests\RssSync\ProperSpecificationFixture.cs" /> <Compile Include="DecisionEngineTests\RssSync\ProperSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\Search\SeriesSpecificationFixture.cs" /> <Compile Include="DecisionEngineTests\Search\SeriesSpecificationFixture.cs" />
<Compile Include="Download\DownloadApprovedReportsTests\DownloadApprovedFixture.cs" /> <Compile Include="Download\DownloadApprovedReportsTests\DownloadApprovedFixture.cs" />
<Compile Include="Download\DownloadApprovedReportsTests\GetQualifiedReportsFixture.cs" /> <Compile Include="DecisionEngineTests\PrioritizeDownloadDecisionFixture.cs" />
<Compile Include="Download\DownloadClientTests\Blackhole\UsenetBlackholeFixture.cs" /> <Compile Include="Download\DownloadClientTests\Blackhole\UsenetBlackholeFixture.cs" />
<Compile Include="Download\DownloadClientTests\DownloadClientFixtureBase.cs" /> <Compile Include="Download\DownloadClientTests\DownloadClientFixtureBase.cs" />
<Compile Include="Download\DownloadClientTests\NzbgetTests\NzbgetFixture.cs" /> <Compile Include="Download\DownloadClientTests\NzbgetTests\NzbgetFixture.cs" />

@ -3,12 +3,13 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Instrumentation.Extensions; using NzbDrone.Core.Instrumentation.Extensions;
using NzbDrone.Core.Parser; using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Parser.Model;
using NzbDrone.Common.Serializer; using NzbDrone.Core.Qualities;
namespace NzbDrone.Core.DecisionEngine namespace NzbDrone.Core.DecisionEngine
{ {

@ -0,0 +1,31 @@
using System;
using System.Linq;
using System.Text;
using System.Collections.Generic;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.DecisionEngine.Specifications;
namespace NzbDrone.Core.DecisionEngine
{
public interface IPrioritizeDownloadDecision
{
List<DownloadDecision> PrioritizeDecisions(List<DownloadDecision> decisions);
}
public class DownloadDecisionPriorizationService : IPrioritizeDownloadDecision
{
public List<DownloadDecision> PrioritizeDecisions(List<DownloadDecision> decisions)
{
return decisions
.Where(c => c.RemoteEpisode.Series != null)
.GroupBy(c => c.RemoteEpisode.Series.Id, (i, s) => s
.OrderByDescending(c => c.RemoteEpisode.ParsedEpisodeInfo.Quality, new QualityModelComparer(s.First().RemoteEpisode.Series.QualityProfile))
.ThenBy(c => c.RemoteEpisode.Episodes.Select(e => e.EpisodeNumber).MinOrDefault())
.ThenBy(c => c.RemoteEpisode.Release.Size.Round(200.Megabytes()) / c.RemoteEpisode.Episodes.Count)
.ThenBy(c => c.RemoteEpisode.Release.Age))
.SelectMany(c => c)
.Union(decisions.Where(c => c.RemoteEpisode.Series == null))
.ToList();
}
}
}

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
@ -15,20 +16,23 @@ namespace NzbDrone.Core.Download
public class DownloadApprovedReports : IDownloadApprovedReports public class DownloadApprovedReports : IDownloadApprovedReports
{ {
private readonly IDownloadService _downloadService; private readonly IDownloadService _downloadService;
private readonly IPrioritizeDownloadDecision _prioritizeDownloadDecision;
private readonly Logger _logger; private readonly Logger _logger;
public DownloadApprovedReports(IDownloadService downloadService, Logger logger) public DownloadApprovedReports(IDownloadService downloadService, IPrioritizeDownloadDecision prioritizeDownloadDecision, Logger logger)
{ {
_downloadService = downloadService; _downloadService = downloadService;
_prioritizeDownloadDecision = prioritizeDownloadDecision;
_logger = logger; _logger = logger;
} }
public List<DownloadDecision> DownloadApproved(List<DownloadDecision> decisions) public List<DownloadDecision> DownloadApproved(List<DownloadDecision> decisions)
{ {
var qualifiedReports = GetQualifiedReports(decisions); var qualifiedReports = GetQualifiedReports(decisions);
var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisions(qualifiedReports);
var downloadedReports = new List<DownloadDecision>(); var downloadedReports = new List<DownloadDecision>();
foreach (var report in qualifiedReports) foreach (var report in prioritizedDecisions)
{ {
var remoteEpisode = report.RemoteEpisode; var remoteEpisode = report.RemoteEpisode;
@ -57,14 +61,7 @@ namespace NzbDrone.Core.Download
public List<DownloadDecision> GetQualifiedReports(IEnumerable<DownloadDecision> decisions) public List<DownloadDecision> GetQualifiedReports(IEnumerable<DownloadDecision> decisions)
{ {
return decisions.Where(c => c.Approved && c.RemoteEpisode.Episodes.Any()) return decisions.Where(c => c.Approved && c.RemoteEpisode.Episodes.Any()).ToList();
.GroupBy(c => c.RemoteEpisode.Series.Id, (i,s) => s
.OrderByDescending(c => c.RemoteEpisode.ParsedEpisodeInfo.Quality, new QualityModelComparer(s.First().RemoteEpisode.Series.QualityProfile))
.ThenBy(c => c.RemoteEpisode.Episodes.Select(e => e.EpisodeNumber).MinOrDefault())
.ThenBy(c => c.RemoteEpisode.Release.Size.Round(200.Megabytes()) / c.RemoteEpisode.Episodes.Count)
.ThenBy(c => c.RemoteEpisode.Release.Age))
.SelectMany(c => c)
.ToList();
} }
} }
} }

@ -223,6 +223,7 @@
<Compile Include="Datastore\PagingSpec.cs" /> <Compile Include="Datastore\PagingSpec.cs" />
<Compile Include="Datastore\TableMapping.cs" /> <Compile Include="Datastore\TableMapping.cs" />
<Compile Include="DecisionEngine\Specifications\RetrySpecification.cs" /> <Compile Include="DecisionEngine\Specifications\RetrySpecification.cs" />
<Compile Include="DecisionEngine\DownloadDecisionPriorizationService.cs" />
<Compile Include="DecisionEngine\Specifications\BlacklistSpecification.cs" /> <Compile Include="DecisionEngine\Specifications\BlacklistSpecification.cs" />
<Compile Include="DecisionEngine\Specifications\DownloadDecision.cs" /> <Compile Include="DecisionEngine\Specifications\DownloadDecision.cs" />
<Compile Include="DecisionEngine\IRejectWithReason.cs" /> <Compile Include="DecisionEngine\IRejectWithReason.cs" />

@ -32,7 +32,7 @@ namespace NzbDrone.Update.Test
Subject.Start(AppType.Service, targetFolder); Subject.Start(AppType.Service, targetFolder);
Mocker.GetMock<IProcessProvider>().Verify(c => c.SpawnNewProcess("c:\\NzbDrone\\NzbDrone.Console.exe", StartupContext.NO_BROWSER), Times.Once()); Mocker.GetMock<IProcessProvider>().Verify(c => c.SpawnNewProcess("c:\\NzbDrone\\NzbDrone.Console.exe", "--" + StartupContext.NO_BROWSER), Times.Once());
ExceptionVerification.ExpectedWarns(1); ExceptionVerification.ExpectedWarns(1);
} }

@ -22,45 +22,37 @@ define(
{ {
name : 'age', name : 'age',
label : 'Age', label : 'Age',
sortable: true,
cell : AgeCell cell : AgeCell
}, },
{ {
name : 'title', name : 'title',
label : 'Title', label : 'Title',
sortable: true,
cell : Backgrid.StringCell.extend({ className: 'nzb-title-cell' }) cell : Backgrid.StringCell.extend({ className: 'nzb-title-cell' })
}, },
{ {
name : 'indexer', name : 'indexer',
label : 'Indexer', label : 'Indexer',
sortable: true,
cell : Backgrid.StringCell cell : Backgrid.StringCell
}, },
{ {
name : 'size', name : 'size',
label : 'Size', label : 'Size',
sortable: true,
cell : FileSizeCell cell : FileSizeCell
}, },
{ {
name : 'quality', name : 'quality',
label : 'Quality', label : 'Quality',
sortable : true, cell : QualityCell
cell : QualityCell,
sortValue : function (model) {
return model.get('quality').quality.weight;
}
}, },
{ {
name : 'rejections', name : 'rejections',
label: '', label : '',
cell : ApprovalStatusCell cell : ApprovalStatusCell
}, },
{ {
name : 'download', name : 'download',
label: '', label : '',
cell : DownloadReportCell cell : DownloadReportCell
} }
], ],

@ -1,19 +1,44 @@
'use strict'; 'use strict';
define( define(
[ [
'backbone', 'backbone.pageable',
'Release/ReleaseModel' 'Release/ReleaseModel',
], function (Backbone, ReleaseModel) { 'Mixins/AsSortedCollection'
return Backbone.Collection.extend({ ], function (PagableCollection, ReleaseModel, AsSortedCollection) {
var Collection = PagableCollection.extend({
url : window.NzbDrone.ApiRoot + '/release', url : window.NzbDrone.ApiRoot + '/release',
model: ReleaseModel, model: ReleaseModel,
state: { state: {
pageSize: 2000 pageSize : 2000,
sortKey : 'download',
order : -1
},
mode: 'client',
sortMappings: {
'quality' : { sortKey: 'qualityWeight' },
'rejections' : { sortValue: function (model, attr) {
var rejections = model.get('rejections');
var releaseWeight = model.get('releaseWeight');
if (rejections.length !== 0) {
return releaseWeight + 1000000;
}
return releaseWeight;
}
},
'download' : { sortKey: 'releaseWeight' }
}, },
fetchEpisodeReleases: function (episodeId) { fetchEpisodeReleases: function (episodeId) {
return this.fetch({ data: { episodeId: episodeId }}); return this.fetch({ data: { episodeId: episodeId }});
} }
}); });
Collection = AsSortedCollection.call(Collection);
return Collection;
}); });

Loading…
Cancel
Save