mirror of https://github.com/Radarr/Radarr
Bulk Import. (#583)
* First pass at bulk import. * First pass at paging implementation for bulk import. * Another pass at UI for bulk import WHY WON'T THE ROWS SELECT?!?! * Paging mostly done. UI needs to show loading still. * Fix for selection * fixes. * Add caching to bulk import * Tried to fix paging. * Fix has next * Fix link error. * Pageable now works almost perfectly. Collection now works really nicely when paged. Also movies from different pages can be added no problemo. * /bulk-import: ProfileCell Various other QoL changes * Profile selection works now Still kinda hacky * Default monitored to true. * Add Monitor Cell Update styling, added path tooltip as well * Update model when changing tmdbId Ensure monitor status doesn't change as well * Added spinner feedback for tmdbid cell. * /bulk-import: Add page-size selector
This commit is contained in:
parent
0d1150d4d2
commit
35b384439f
|
@ -1,8 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Nancy;
|
||||||
using NzbDrone.Api.Episodes;
|
using NzbDrone.Api.Episodes;
|
||||||
using NzbDrone.Api.Movie;
|
using NzbDrone.Api.Movie;
|
||||||
|
using NzbDrone.Api.Series;
|
||||||
using NzbDrone.Core.Datastore.Events;
|
using NzbDrone.Core.Datastore.Events;
|
||||||
using NzbDrone.Core.MediaCover;
|
using NzbDrone.Core.MediaCover;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Nancy;
|
||||||
|
using NzbDrone.Api.Extensions;
|
||||||
|
using NzbDrone.Core.MediaCover;
|
||||||
|
using NzbDrone.Core.MetadataSource;
|
||||||
|
using NzbDrone.Core.Parser;
|
||||||
|
using System.Linq;
|
||||||
|
using System;
|
||||||
|
using Marr.Data;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||||
|
using NzbDrone.Core.RootFolders;
|
||||||
|
using NzbDrone.Common.Cache;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.Movie
|
||||||
|
{
|
||||||
|
|
||||||
|
public class UnmappedComparer : IComparer<UnmappedFolder>
|
||||||
|
{
|
||||||
|
public int Compare(UnmappedFolder a, UnmappedFolder b)
|
||||||
|
{
|
||||||
|
return a.Name.CompareTo(b.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MovieBulkImportModule : NzbDroneRestModule<MovieResource>
|
||||||
|
{
|
||||||
|
private readonly ISearchForNewMovie _searchProxy;
|
||||||
|
private readonly IRootFolderService _rootFolderService;
|
||||||
|
private readonly IMakeImportDecision _importDecisionMaker;
|
||||||
|
private readonly IDiskScanService _diskScanService;
|
||||||
|
private readonly ICached<Core.Tv.Movie> _mappedMovies;
|
||||||
|
|
||||||
|
public MovieBulkImportModule(ISearchForNewMovie searchProxy, IRootFolderService rootFolderService, IMakeImportDecision importDecisionMaker,
|
||||||
|
IDiskScanService diskScanService, ICacheManager cacheManager)
|
||||||
|
: base("/movies/bulkimport")
|
||||||
|
{
|
||||||
|
_searchProxy = searchProxy;
|
||||||
|
_rootFolderService = rootFolderService;
|
||||||
|
_importDecisionMaker = importDecisionMaker;
|
||||||
|
_diskScanService = diskScanService;
|
||||||
|
_mappedMovies = cacheManager.GetCache<Core.Tv.Movie>(GetType(), "mappedMoviesCache");
|
||||||
|
Get["/"] = x => Search();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Response Search()
|
||||||
|
{
|
||||||
|
if (Request.Query.Id == 0)
|
||||||
|
{
|
||||||
|
//Todo error handling
|
||||||
|
}
|
||||||
|
|
||||||
|
RootFolder rootFolder = _rootFolderService.Get(Request.Query.Id);
|
||||||
|
|
||||||
|
int page = Request.Query.page;
|
||||||
|
int per_page = Request.Query.per_page;
|
||||||
|
|
||||||
|
int min = (page - 1) * per_page;
|
||||||
|
|
||||||
|
int max = page * per_page;
|
||||||
|
|
||||||
|
var unmapped = rootFolder.UnmappedFolders.OrderBy(f => f.Name).ToList();
|
||||||
|
|
||||||
|
int total_count = unmapped.Count;
|
||||||
|
|
||||||
|
if (Request.Query.total_entries.HasValue)
|
||||||
|
{
|
||||||
|
total_count = Request.Query.total_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
max = total_count >= max ? max : total_count;
|
||||||
|
|
||||||
|
var paged = unmapped.GetRange(min, max-min);
|
||||||
|
|
||||||
|
var mapped = paged.Select(f =>
|
||||||
|
{
|
||||||
|
Core.Tv.Movie m = null;
|
||||||
|
|
||||||
|
var mappedMovie = _mappedMovies.Find(f.Name);
|
||||||
|
|
||||||
|
if (mappedMovie != null)
|
||||||
|
{
|
||||||
|
return mappedMovie;
|
||||||
|
}
|
||||||
|
|
||||||
|
var parsedTitle = Parser.ParseMoviePath(f.Name);
|
||||||
|
if (parsedTitle == null)
|
||||||
|
{
|
||||||
|
m = new Core.Tv.Movie
|
||||||
|
{
|
||||||
|
Title = f.Name.Replace(".", " ").Replace("-", " "),
|
||||||
|
Path = f.Path,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m = new Core.Tv.Movie
|
||||||
|
{
|
||||||
|
Title = parsedTitle.MovieTitle,
|
||||||
|
Year = parsedTitle.Year,
|
||||||
|
ImdbId = parsedTitle.ImdbId,
|
||||||
|
Path = f.Path
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var files = _diskScanService.GetVideoFiles(f.Path);
|
||||||
|
|
||||||
|
var decisions = _importDecisionMaker.GetImportDecisions(files.ToList(), m);
|
||||||
|
|
||||||
|
var decision = decisions.Where(d => d.Approved && !d.Rejections.Any()).FirstOrDefault();
|
||||||
|
|
||||||
|
if (decision != null)
|
||||||
|
{
|
||||||
|
var local = decision.LocalMovie;
|
||||||
|
|
||||||
|
m.MovieFile = new LazyLoaded<MovieFile>(new MovieFile
|
||||||
|
{
|
||||||
|
Path = local.Path,
|
||||||
|
Edition = local.ParsedMovieInfo.Edition,
|
||||||
|
Quality = local.Quality,
|
||||||
|
MediaInfo = local.MediaInfo,
|
||||||
|
ReleaseGroup = local.ParsedMovieInfo.ReleaseGroup,
|
||||||
|
RelativePath = f.Path.GetRelativePath(local.Path)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
mappedMovie = _searchProxy.MapMovieToTmdbMovie(m);
|
||||||
|
mappedMovie.Monitored = true;
|
||||||
|
|
||||||
|
_mappedMovies.Set(f.Name, mappedMovie, TimeSpan.FromDays(2));
|
||||||
|
|
||||||
|
return mappedMovie;
|
||||||
|
});
|
||||||
|
|
||||||
|
return new PagingResource<MovieResource>
|
||||||
|
{
|
||||||
|
Page = page,
|
||||||
|
PageSize = per_page,
|
||||||
|
SortDirection = SortDirection.Ascending,
|
||||||
|
SortKey = Request.Query.sort_by,
|
||||||
|
TotalRecords = total_count - mapped.Where(m => m == null).Count(),
|
||||||
|
Records = MapToResource(mapped.Where(m => m != null)).ToList()
|
||||||
|
}.AsResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static IEnumerable<MovieResource> MapToResource(IEnumerable<Core.Tv.Movie> movies)
|
||||||
|
{
|
||||||
|
foreach (var currentSeries in movies)
|
||||||
|
{
|
||||||
|
var resource = currentSeries.ToResource();
|
||||||
|
var poster = currentSeries.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster);
|
||||||
|
if (poster != null)
|
||||||
|
{
|
||||||
|
resource.RemotePoster = poster.Url;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return resource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -118,8 +118,9 @@
|
||||||
<Compile Include="Frontend\Mappers\RobotsTxtMapper.cs" />
|
<Compile Include="Frontend\Mappers\RobotsTxtMapper.cs" />
|
||||||
<Compile Include="Indexers\ReleaseModuleBase.cs" />
|
<Compile Include="Indexers\ReleaseModuleBase.cs" />
|
||||||
<Compile Include="Indexers\ReleasePushModule.cs" />
|
<Compile Include="Indexers\ReleasePushModule.cs" />
|
||||||
|
<Compile Include="Movies\MovieBulkImportModule.cs" />
|
||||||
<Compile Include="Movies\MovieFileModule.cs" />
|
<Compile Include="Movies\MovieFileModule.cs" />
|
||||||
<Compile Include="Movies\MovieModule.cs" />
|
<Compile Include="Series\MovieModule.cs" />
|
||||||
<Compile Include="Movies\RenameMovieModule.cs" />
|
<Compile Include="Movies\RenameMovieModule.cs" />
|
||||||
<Compile Include="Movies\RenameMovieResource.cs" />
|
<Compile Include="Movies\RenameMovieResource.cs" />
|
||||||
<Compile Include="Movies\MovieEditorModule.cs" />
|
<Compile Include="Movies\MovieEditorModule.cs" />
|
||||||
|
@ -245,7 +246,6 @@
|
||||||
<Compile Include="Series\SeriesEditorModule.cs" />
|
<Compile Include="Series\SeriesEditorModule.cs" />
|
||||||
<Compile Include="Series\MovieLookupModule.cs" />
|
<Compile Include="Series\MovieLookupModule.cs" />
|
||||||
<Compile Include="Series\SeriesLookupModule.cs" />
|
<Compile Include="Series\SeriesLookupModule.cs" />
|
||||||
<Compile Include="Series\MovieModule.cs" />
|
|
||||||
<Compile Include="Series\SeriesModule.cs" />
|
<Compile Include="Series\SeriesModule.cs" />
|
||||||
<Compile Include="Series\MovieResource.cs" />
|
<Compile Include="Series\MovieResource.cs" />
|
||||||
<Compile Include="Series\SeriesResource.cs" />
|
<Compile Include="Series\SeriesResource.cs" />
|
||||||
|
@ -295,11 +295,11 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup />
|
<ItemGroup />
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
<Target Name="BeforeBuild">
|
<Target Name="BeforeBuild">
|
||||||
</Target>
|
</Target>
|
||||||
<Target Name="AfterBuild">
|
<Target Name="AfterBuild">
|
||||||
</Target>
|
</Target>
|
||||||
-->
|
-->
|
||||||
</Project>
|
</Project>
|
|
@ -4,18 +4,35 @@ using NzbDrone.Api.Extensions;
|
||||||
using NzbDrone.Core.MediaCover;
|
using NzbDrone.Core.MediaCover;
|
||||||
using NzbDrone.Core.MetadataSource;
|
using NzbDrone.Core.MetadataSource;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System;
|
||||||
|
using NzbDrone.Api.REST;
|
||||||
|
|
||||||
namespace NzbDrone.Api.Movie
|
namespace NzbDrone.Api.Movie
|
||||||
{
|
{
|
||||||
public class MovieLookupModule : NzbDroneRestModule<MovieResource>
|
public class MovieLookupModule : NzbDroneRestModule<MovieResource>
|
||||||
{
|
{
|
||||||
private readonly ISearchForNewMovie _searchProxy;
|
private readonly ISearchForNewMovie _searchProxy;
|
||||||
|
private readonly IProvideMovieInfo _movieInfo;
|
||||||
|
|
||||||
public MovieLookupModule(ISearchForNewMovie searchProxy)
|
public MovieLookupModule(ISearchForNewMovie searchProxy, IProvideMovieInfo movieInfo)
|
||||||
: base("/movies/lookup")
|
: base("/movies/lookup")
|
||||||
{
|
{
|
||||||
|
_movieInfo = movieInfo;
|
||||||
_searchProxy = searchProxy;
|
_searchProxy = searchProxy;
|
||||||
Get["/"] = x => Search();
|
Get["/"] = x => Search();
|
||||||
|
Get["/tmdb"] = x => SearchByTmdbId();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Response SearchByTmdbId()
|
||||||
|
{
|
||||||
|
int tmdbId = -1;
|
||||||
|
if(Int32.TryParse(Request.Query.tmdbId, out tmdbId))
|
||||||
|
{
|
||||||
|
var result = _movieInfo.GetMovieInfo(tmdbId, null);
|
||||||
|
return result.ToResource().AsResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new BadRequestException("Tmdb Id was not valid");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,7 +42,6 @@ namespace NzbDrone.Api.Movie
|
||||||
return MapToResource(imdbResults).AsResponse();
|
return MapToResource(imdbResults).AsResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static IEnumerable<MovieResource> MapToResource(IEnumerable<Core.Tv.Movie> movies)
|
private static IEnumerable<MovieResource> MapToResource(IEnumerable<Core.Tv.Movie> movies)
|
||||||
{
|
{
|
||||||
foreach (var currentSeries in movies)
|
foreach (var currentSeries in movies)
|
||||||
|
|
|
@ -637,6 +637,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
||||||
newMovie.RootFolderPath = movie.RootFolderPath;
|
newMovie.RootFolderPath = movie.RootFolderPath;
|
||||||
newMovie.ProfileId = movie.ProfileId;
|
newMovie.ProfileId = movie.ProfileId;
|
||||||
newMovie.Monitored = movie.Monitored;
|
newMovie.Monitored = movie.Monitored;
|
||||||
|
newMovie.MovieFile = movie.MovieFile;
|
||||||
|
|
||||||
return newMovie;
|
return newMovie;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ var AddMoviesView = require('./AddMoviesView');
|
||||||
var ProfileCollection = require('../Profile/ProfileCollection');
|
var ProfileCollection = require('../Profile/ProfileCollection');
|
||||||
var AddFromListView = require("./List/AddFromListView");
|
var AddFromListView = require("./List/AddFromListView");
|
||||||
var RootFolderCollection = require('./RootFolders/RootFolderCollection');
|
var RootFolderCollection = require('./RootFolders/RootFolderCollection');
|
||||||
|
var BulkImportView = require("./BulkImport/BulkImportView");
|
||||||
require('../Movies/MoviesCollection');
|
require('../Movies/MoviesCollection');
|
||||||
|
|
||||||
module.exports = Marionette.Layout.extend({
|
module.exports = Marionette.Layout.extend({
|
||||||
|
@ -22,6 +23,7 @@ module.exports = Marionette.Layout.extend({
|
||||||
|
|
||||||
events : {
|
events : {
|
||||||
'click .x-import' : '_importMovies',
|
'click .x-import' : '_importMovies',
|
||||||
|
'click .x-bulk-import' : '_bulkImport',
|
||||||
'click .x-add-new' : '_addMovies',
|
'click .x-add-new' : '_addMovies',
|
||||||
"click .x-add-lists" : "_addFromList",
|
"click .x-add-lists" : "_addFromList",
|
||||||
'click .x-show-existing' : '_toggleExisting'
|
'click .x-show-existing' : '_toggleExisting'
|
||||||
|
@ -59,6 +61,11 @@ module.exports = Marionette.Layout.extend({
|
||||||
this.workspace.show(new ExistingMoviesCollectionView({ model : options.model }));
|
this.workspace.show(new ExistingMoviesCollectionView({ model : options.model }));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_bulkFolderSelected : function(options) {
|
||||||
|
vent.trigger(vent.Commands.CloseModalCommand);
|
||||||
|
this.workspace.show(new BulkImportView({ model : options.model}));
|
||||||
|
},
|
||||||
|
|
||||||
_importMovies : function() {
|
_importMovies : function() {
|
||||||
this.rootFolderLayout = new RootFolderLayout();
|
this.rootFolderLayout = new RootFolderLayout();
|
||||||
this.listenTo(this.rootFolderLayout, 'folderSelected', this._folderSelected);
|
this.listenTo(this.rootFolderLayout, 'folderSelected', this._folderSelected);
|
||||||
|
@ -72,5 +79,11 @@ module.exports = Marionette.Layout.extend({
|
||||||
_addFromList : function() {
|
_addFromList : function() {
|
||||||
//this.ui.$existing.hide();
|
//this.ui.$existing.hide();
|
||||||
this.workspace.show(new AddFromListView());
|
this.workspace.show(new AddFromListView());
|
||||||
|
},
|
||||||
|
|
||||||
|
_bulkImport : function() {
|
||||||
|
this.bulkRootFolderLayout = new RootFolderLayout();
|
||||||
|
this.listenTo(this.bulkRootFolderLayout, 'folderSelected', this._bulkFolderSelected);
|
||||||
|
AppLayout.modalRegion.show(this.bulkRootFolderLayout);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div class="btn-group add-movies-btn-group btn-group-lg btn-block">
|
<div class="btn-group add-movies-btn-group btn-group-lg btn-block">
|
||||||
<button type="button" class="btn btn-default col-md-7 col-xs-4 add-movies-import-btn x-import">
|
<button class="btn btn-default col-md-3 col-xs-4 x-bulk-import"><i class="icon-sonarr-view-list hidden-xs"></i> Bulk Import Movies</button>
|
||||||
|
<button type="button" class="btn btn-default col-md-4 col-xs-4 add-movies-import-btn x-import">
|
||||||
<i class="icon-sonarr-hdd"/>
|
<i class="icon-sonarr-hdd"/>
|
||||||
Import existing movies on disk
|
Import existing movies on disk
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -26,7 +26,6 @@ module.exports = Marionette.Layout.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
initialize : function(options) {
|
initialize : function(options) {
|
||||||
console.log(options);
|
|
||||||
|
|
||||||
this.isExisting = options.isExisting;
|
this.isExisting = options.isExisting;
|
||||||
this.collection = new AddMoviesCollection();
|
this.collection = new AddMoviesCollection();
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
var _ = require('underscore');
|
||||||
|
var PageableCollection = require('backbone.pageable');
|
||||||
|
var MovieModel = require('../../Movies/MovieModel');
|
||||||
|
var AsSortedCollection = require('../../Mixins/AsSortedCollection');
|
||||||
|
var AsPageableCollection = require('../../Mixins/AsPageableCollection');
|
||||||
|
var AsPersistedStateCollection = require('../../Mixins/AsPersistedStateCollection');
|
||||||
|
|
||||||
|
var BulkImportCollection = PageableCollection.extend({
|
||||||
|
url : window.NzbDrone.ApiRoot + '/movies/bulkimport',
|
||||||
|
model : MovieModel,
|
||||||
|
mode: "infinite",
|
||||||
|
tableName : 'bulkimport',
|
||||||
|
|
||||||
|
state : {
|
||||||
|
pageSize : 15,
|
||||||
|
sortKey: 'sortTitle',
|
||||||
|
firstPage: 1
|
||||||
|
},
|
||||||
|
|
||||||
|
queryParams: {
|
||||||
|
totalPages: null,
|
||||||
|
totalRecords: null,
|
||||||
|
sortKey: "sort",
|
||||||
|
order: "direction",
|
||||||
|
directions: {
|
||||||
|
"-1": "asc",
|
||||||
|
"1": "desc"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// queryParams : {
|
||||||
|
// totalPages : null,
|
||||||
|
// totalRecords : null,
|
||||||
|
// pageSize : 'pageSize',
|
||||||
|
// sortKey : 'sortKey'
|
||||||
|
// },
|
||||||
|
|
||||||
|
/*parse : function(response) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
_.each(response.records, function(model) {
|
||||||
|
model.id = undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
},*/
|
||||||
|
|
||||||
|
parseState : function(resp) {
|
||||||
|
return { totalRecords : resp.totalRecords };
|
||||||
|
},
|
||||||
|
|
||||||
|
parseRecords : function(resp) {
|
||||||
|
if (resp) {
|
||||||
|
return resp.records;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp;
|
||||||
|
},
|
||||||
|
|
||||||
|
fetch : function(options) {
|
||||||
|
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
var data = options.data || {};
|
||||||
|
|
||||||
|
if (data.id === undefined || data.folder === undefined) {
|
||||||
|
data.id = this.folderId;
|
||||||
|
data.folder = this.folder;
|
||||||
|
}
|
||||||
|
|
||||||
|
options.data = data;
|
||||||
|
|
||||||
|
return PageableCollection.prototype.fetch.call(this, options);
|
||||||
|
},
|
||||||
|
|
||||||
|
parseLinks : function(options) {
|
||||||
|
console.log(options);
|
||||||
|
return {
|
||||||
|
first : this.url,
|
||||||
|
next: this.url,
|
||||||
|
last : this.url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
BulkImportCollection = AsSortedCollection.call(BulkImportCollection);
|
||||||
|
BulkImportCollection = AsPageableCollection.call(BulkImportCollection);
|
||||||
|
BulkImportCollection = AsPersistedStateCollection.call(BulkImportCollection);
|
||||||
|
|
||||||
|
module.exports = BulkImportCollection;
|
|
@ -0,0 +1,79 @@
|
||||||
|
var Backgrid = require('backgrid');
|
||||||
|
var Config = require('../../Config');
|
||||||
|
var _ = require('underscore');
|
||||||
|
var vent = require("vent");
|
||||||
|
var TemplatedCell = require('../../Cells/TemplatedCell');
|
||||||
|
var NzbDroneCell = require("../../Cells/NzbDroneCell");
|
||||||
|
|
||||||
|
module.exports = TemplatedCell.extend({
|
||||||
|
className : 'monitor-cell',
|
||||||
|
template : 'AddMovies/BulkImport/BulkImportMonitorCell',
|
||||||
|
|
||||||
|
_orig : TemplatedCell.prototype.initialize,
|
||||||
|
_origRender : TemplatedCell.prototype.initialize,
|
||||||
|
|
||||||
|
ui : {
|
||||||
|
monitor : ".x-monitor",
|
||||||
|
},
|
||||||
|
|
||||||
|
events: { "change .x-monitor" : "_monitorChanged" },
|
||||||
|
|
||||||
|
initialize : function () {
|
||||||
|
this._orig.apply(this, arguments);
|
||||||
|
|
||||||
|
this.listenTo(vent, Config.Events.ConfigUpdatedEvent, this._onConfigUpdated);
|
||||||
|
|
||||||
|
this.defaultMonitor = Config.getValue(Config.Keys.MonitorEpisodes, 'all');
|
||||||
|
|
||||||
|
this.model.set('monitored', this._convertMonitorToBool(this.defaultMonitor));
|
||||||
|
|
||||||
|
this.$el.find('.x-monitor').val(this.defaultMonitor);
|
||||||
|
// this.ui.monitor.val(this.defaultProfile);//this.ui.profile.val(this.defaultProfile);
|
||||||
|
// this.model.set("profileId", this.defaultProfile);
|
||||||
|
|
||||||
|
// this.cellValue = ProfileCollection;
|
||||||
|
|
||||||
|
|
||||||
|
//this.render();
|
||||||
|
//this.listenTo(ProfileCollection, 'sync', this.render);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
_convertMonitorToBool : function(monitorString) {
|
||||||
|
return monitorString === 'all' ? true : false;
|
||||||
|
},
|
||||||
|
|
||||||
|
_monitorChanged : function() {
|
||||||
|
Config.setValue(Config.Keys.MonitorEpisodes, this.$el.find('.x-monitor').val());
|
||||||
|
this.defaultMonitor = this.$el.find('.x-monitor').val();
|
||||||
|
this.model.set("monitored", this._convertMonitorToBool(this.$el.find('.x-monitor').val()));
|
||||||
|
},
|
||||||
|
|
||||||
|
_onConfigUpdated : function(options) {
|
||||||
|
if (options.key === Config.Keys.MonitorEpisodes) {
|
||||||
|
this.$el.find('.x-monitor').val(options.value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
render : function() {
|
||||||
|
var templateName = this.column.get('template') || this.template;
|
||||||
|
|
||||||
|
// this.cellValue = ProfileCollection;
|
||||||
|
|
||||||
|
this.templateFunction = Marionette.TemplateCache.get(templateName);
|
||||||
|
this.$el.empty();
|
||||||
|
|
||||||
|
if (this.cellValue) {
|
||||||
|
var data = this.cellValue.toJSON();
|
||||||
|
var html = this.templateFunction(data);
|
||||||
|
this.$el.html(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.delegateEvents();
|
||||||
|
|
||||||
|
this.$el.find('.x-monitor').val(this.defaultMonitor);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,4 @@
|
||||||
|
<select class="col-md-2 form-control x-monitor">
|
||||||
|
<option value="all">Yes</option>
|
||||||
|
<option value="none">No</option>
|
||||||
|
</select>
|
|
@ -0,0 +1,21 @@
|
||||||
|
var NzbDroneCell = require('../../Cells/NzbDroneCell');
|
||||||
|
var BulkImportCollection = require("./BulkImportCollection");
|
||||||
|
|
||||||
|
module.exports = NzbDroneCell.extend({
|
||||||
|
className : 'series-title-cell',
|
||||||
|
|
||||||
|
render : function() {
|
||||||
|
var collection = this.model.collection;
|
||||||
|
//this.listenTo(collection, 'sync', this._renderCell);
|
||||||
|
|
||||||
|
this._renderCell();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
_renderCell : function() {
|
||||||
|
this.$el.empty();
|
||||||
|
|
||||||
|
this.$el.html('<a href="https://www.themoviedb.org/movie/' + this.cellValue.get('tmdbId') +'">' + this.cellValue.get('title') + ' (' + this.cellValue.get('year') + ')' +'</a>');
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,45 @@
|
||||||
|
var Backgrid = require('backgrid');
|
||||||
|
var ProfileCollection = require('../../Profile/ProfileCollection');
|
||||||
|
var Config = require('../../Config');
|
||||||
|
var _ = require('underscore');
|
||||||
|
|
||||||
|
module.exports = Backgrid.SelectCell.extend({
|
||||||
|
className : 'profile-cell',
|
||||||
|
|
||||||
|
_orig : Backgrid.SelectCell.prototype.initialize,
|
||||||
|
|
||||||
|
initialize : function () {
|
||||||
|
this._orig.apply(this, arguments);
|
||||||
|
|
||||||
|
this.defaultProfile = Config.getValue(Config.Keys.DefaultProfileId);
|
||||||
|
if(ProfileCollection.get(this.defaultProfile))
|
||||||
|
{
|
||||||
|
this.profile = this.defaultProfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.render();
|
||||||
|
//this.listenTo(ProfileCollection, 'sync', this.render);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
optionValues : function() {
|
||||||
|
//debugger;
|
||||||
|
return _.map(ProfileCollection.models, function(model){
|
||||||
|
return [model.get("name"), model.get("id")+""];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*render : function() {
|
||||||
|
|
||||||
|
this.$el.empty();
|
||||||
|
var profileId = this.model.get(this.column.get('name'));
|
||||||
|
|
||||||
|
var profile = _.findWhere(ProfileCollection.models, { id : profileId });
|
||||||
|
|
||||||
|
if (profile) {
|
||||||
|
this.$el.html(profile.get('name'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}*/
|
||||||
|
});
|
|
@ -0,0 +1,77 @@
|
||||||
|
var Backgrid = require('backgrid');
|
||||||
|
var ProfileCollection = require('../../Profile/ProfileCollection');
|
||||||
|
var Config = require('../../Config');
|
||||||
|
var _ = require('underscore');
|
||||||
|
var vent = require("vent");
|
||||||
|
var TemplatedCell = require('../../Cells/TemplatedCell');
|
||||||
|
var NzbDroneCell = require("../../Cells/NzbDroneCell");
|
||||||
|
|
||||||
|
module.exports = TemplatedCell.extend({
|
||||||
|
className : 'profile-cell',
|
||||||
|
template : 'AddMovies/BulkImport/BulkImportProfileCell',
|
||||||
|
|
||||||
|
_orig : TemplatedCell.prototype.initialize,
|
||||||
|
_origRender : TemplatedCell.prototype.initialize,
|
||||||
|
|
||||||
|
ui : {
|
||||||
|
profile : ".x-profile",
|
||||||
|
},
|
||||||
|
|
||||||
|
events: { "change .x-profile" : "_profileChanged" },
|
||||||
|
|
||||||
|
initialize : function () {
|
||||||
|
this._orig.apply(this, arguments);
|
||||||
|
|
||||||
|
this.listenTo(vent, Config.Events.ConfigUpdatedEvent, this._onConfigUpdated);
|
||||||
|
|
||||||
|
this.defaultProfile = Config.getValue(Config.Keys.DefaultProfileId);
|
||||||
|
if(ProfileCollection.get(this.defaultProfile))
|
||||||
|
{
|
||||||
|
this.profile = this.defaultProfile;
|
||||||
|
this.$(".x-profile").val(this.defaultProfile);//this.ui.profile.val(this.defaultProfile);
|
||||||
|
this.model.set("profileId", this.defaultProfile)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cellValue = ProfileCollection;
|
||||||
|
|
||||||
|
|
||||||
|
//this.render();
|
||||||
|
//this.listenTo(ProfileCollection, 'sync', this.render);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
_profileChanged : function() {
|
||||||
|
Config.setValue(Config.Keys.DefaultProfileId, this.$(".x-profile").val());
|
||||||
|
this.model.set("profileId", this.$(".x-profile").val());
|
||||||
|
},
|
||||||
|
|
||||||
|
_onConfigUpdated : function(options) {
|
||||||
|
if (options.key === Config.Keys.DefaultProfileId) {
|
||||||
|
this.defaultProfile = options.value;
|
||||||
|
this.$(".x-profile").val(this.defaultProfile);
|
||||||
|
//
|
||||||
|
//this.render();
|
||||||
|
//this.ui.profile.val(options.value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
render : function() {
|
||||||
|
var templateName = this.column.get('template') || this.template;
|
||||||
|
|
||||||
|
this.cellValue = ProfileCollection;
|
||||||
|
|
||||||
|
this.templateFunction = Marionette.TemplateCache.get(templateName);
|
||||||
|
this.$el.empty();
|
||||||
|
|
||||||
|
if (this.cellValue) {
|
||||||
|
var data = this.cellValue.toJSON();
|
||||||
|
var html = this.templateFunction(data);
|
||||||
|
this.$el.html(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.delegateEvents();
|
||||||
|
this.$(".x-profile").val(this.defaultProfile);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,5 @@
|
||||||
|
<select class="col-md-2 form-control x-profile">
|
||||||
|
{{#each this}}
|
||||||
|
<option value="{{id}}">{{name}}</option>
|
||||||
|
{{/each}}
|
||||||
|
</select>
|
|
@ -0,0 +1,219 @@
|
||||||
|
var $ = require('jquery');
|
||||||
|
var _ = require('underscore');
|
||||||
|
var Marionette = require('marionette');
|
||||||
|
var Backgrid = require('backgrid');
|
||||||
|
var MovieTitleCell = require('./BulkImportMovieTitleCell');
|
||||||
|
var BulkImportCollection = require("./BulkImportCollection");
|
||||||
|
var QualityCell = require('./QualityCell');
|
||||||
|
var TmdbIdCell = require('./TmdbIdCell');
|
||||||
|
var GridPager = require('../../Shared/Grid/Pager');
|
||||||
|
var SelectAllCell = require('../../Cells/SelectAllCell');
|
||||||
|
var ProfileCell = require('./BulkImportProfileCellT');
|
||||||
|
var MonitorCell = require('./BulkImportMonitorCell');
|
||||||
|
var MoviePathCell = require("./MoviePathCell");
|
||||||
|
var LoadingView = require('../../Shared/LoadingView');
|
||||||
|
var EmptyView = require("./EmptyView");
|
||||||
|
var ToolbarLayout = require('../../Shared/Toolbar/ToolbarLayout');
|
||||||
|
var CommandController = require('../../Commands/CommandController');
|
||||||
|
var Messenger = require('../../Shared/Messenger');
|
||||||
|
var MoviesCollection = require('../../Movies/MoviesCollection');
|
||||||
|
var ProfileCollection = require('../../Profile/ProfileCollection');
|
||||||
|
|
||||||
|
require('backgrid.selectall');
|
||||||
|
require('../../Mixins/backbone.signalr.mixin');
|
||||||
|
|
||||||
|
module.exports = Marionette.Layout.extend({
|
||||||
|
template : 'AddMovies/BulkImport/BulkImportViewTemplate',
|
||||||
|
|
||||||
|
regions : {
|
||||||
|
toolbar : '#x-toolbar',
|
||||||
|
table : '#x-movies-bulk',
|
||||||
|
pager : '#x-movies-bulk-pager'
|
||||||
|
},
|
||||||
|
|
||||||
|
ui : {
|
||||||
|
addSelectdBtn : '.x-add-selected',
|
||||||
|
addAllBtn : '.x-add-all',
|
||||||
|
pageSizeSelector : '.x-page-size'
|
||||||
|
},
|
||||||
|
|
||||||
|
events: { "change .x-page-size" : "_pageSizeChanged" },
|
||||||
|
|
||||||
|
initialize : function(options) {
|
||||||
|
ProfileCollection.fetch();
|
||||||
|
this.bulkImportCollection = new BulkImportCollection().bindSignalR({ updateOnly : true });
|
||||||
|
this.model = options.model;
|
||||||
|
this.folder = this.model.get("path");
|
||||||
|
this.folderId = this.model.get("id");
|
||||||
|
this.bulkImportCollection.folderId = this.folderId;
|
||||||
|
this.bulkImportCollection.folder = this.folder;
|
||||||
|
this.bulkImportCollection.fetch();
|
||||||
|
this.listenTo(this.bulkImportCollection, {"sync" : this._showContent, "error" : this._showContent, "backgrid:selected" : this._select});
|
||||||
|
},
|
||||||
|
|
||||||
|
_pageSizeChanged : function(event) {
|
||||||
|
var pageSize = parseInt($(event.target).val());
|
||||||
|
this.bulkImportCollection.setPageSize(pageSize);
|
||||||
|
this.bulkImportCollection.fetch();
|
||||||
|
},
|
||||||
|
|
||||||
|
columns : [
|
||||||
|
{
|
||||||
|
name : '',
|
||||||
|
cell : SelectAllCell,
|
||||||
|
headerCell : 'select-all',
|
||||||
|
sortable : false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'movie',
|
||||||
|
label : 'Movie',
|
||||||
|
cell : MovieTitleCell,
|
||||||
|
cellValue : 'this',
|
||||||
|
sortable : false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : "path",
|
||||||
|
label : "Path",
|
||||||
|
cell : MoviePathCell,
|
||||||
|
cellValue : 'this',
|
||||||
|
sortable : false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'tmdbId',
|
||||||
|
label : 'Tmdb Id',
|
||||||
|
cell : TmdbIdCell,
|
||||||
|
cellValue : 'this',
|
||||||
|
sortable: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name :'monitor',
|
||||||
|
label: 'Monitor',
|
||||||
|
cell : MonitorCell,
|
||||||
|
cellValue : 'this'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'profileId',
|
||||||
|
label : 'Profile',
|
||||||
|
cell : ProfileCell,
|
||||||
|
cellValue : "this",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'quality',
|
||||||
|
label : 'Quality',
|
||||||
|
cell : QualityCell,
|
||||||
|
cellValue : 'this',
|
||||||
|
sortable : false
|
||||||
|
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
_showContent : function() {
|
||||||
|
this._showToolbar();
|
||||||
|
this._showTable();
|
||||||
|
},
|
||||||
|
|
||||||
|
onShow : function() {
|
||||||
|
this.table.show(new LoadingView());
|
||||||
|
},
|
||||||
|
|
||||||
|
_showToolbar : function() {
|
||||||
|
var leftSideButtons = {
|
||||||
|
type : 'default',
|
||||||
|
storeState: false,
|
||||||
|
collapse : true,
|
||||||
|
items : [
|
||||||
|
{
|
||||||
|
title : 'Add Selected',
|
||||||
|
icon : 'icon-sonarr-add',
|
||||||
|
callback : this._addSelected,
|
||||||
|
ownerContext : this,
|
||||||
|
className : 'x-add-selected'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title : 'Add All',
|
||||||
|
icon : 'icon-sonarr-add',
|
||||||
|
callback : this._addAll,
|
||||||
|
ownerContext : this,
|
||||||
|
className : 'x-add-all'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
this.toolbar.show(new ToolbarLayout({
|
||||||
|
left : [leftSideButtons],
|
||||||
|
right : [],
|
||||||
|
context : this
|
||||||
|
}));
|
||||||
|
|
||||||
|
$('#x-toolbar').addClass('inline');
|
||||||
|
},
|
||||||
|
|
||||||
|
_addSelected : function() {
|
||||||
|
var selected = _.filter(this.bulkImportCollection.fullCollection.models, function(elem){
|
||||||
|
return elem.selected;
|
||||||
|
})
|
||||||
|
console.log(selected);
|
||||||
|
|
||||||
|
var promise = MoviesCollection.importFromList(selected);
|
||||||
|
this.ui.addSelectdBtn.spinForPromise(promise);
|
||||||
|
this.ui.addSelectdBtn.addClass('disabled');
|
||||||
|
this.ui.addAllBtn.addClass('disabled');
|
||||||
|
|
||||||
|
if (selected.length === 0) {
|
||||||
|
Messenger.show({
|
||||||
|
type : 'error',
|
||||||
|
message : 'No movies selected'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Messenger.show({
|
||||||
|
message : "Importing {0} movies. This can take multiple minutes depending on how many movies should be imported. Don't close this browser window until it is finished!".format(selected.length),
|
||||||
|
hideOnNavigate : false,
|
||||||
|
hideAfter : 30,
|
||||||
|
type : "error"
|
||||||
|
});
|
||||||
|
|
||||||
|
promise.done(function() {
|
||||||
|
Messenger.show({
|
||||||
|
message : "Imported movies from list.",
|
||||||
|
hideAfter : 8,
|
||||||
|
hideOnNavigate : true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_addAll : function() {
|
||||||
|
console.log("TODO");
|
||||||
|
},
|
||||||
|
|
||||||
|
_handleEvent : function(event_name, data) {
|
||||||
|
if (event_name == "sync" || event_name == "content") {
|
||||||
|
this._showContent()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_select : function(model, selected) {
|
||||||
|
model.selected = selected;
|
||||||
|
},
|
||||||
|
|
||||||
|
_showTable : function() {
|
||||||
|
if (this.bulkImportCollection.length === 0) {
|
||||||
|
this.table.show(new EmptyView({ folder : this.folder }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.importGrid = new Backgrid.Grid({
|
||||||
|
columns : this.columns,
|
||||||
|
collection : this.bulkImportCollection,
|
||||||
|
className : 'table table-hover'
|
||||||
|
});
|
||||||
|
|
||||||
|
this.table.show(this.importGrid);
|
||||||
|
|
||||||
|
this.pager.show(new GridPager({
|
||||||
|
columns : this.columns,
|
||||||
|
collection : this.bulkImportCollection
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,13 @@
|
||||||
|
<div id="x-toolbar"/>
|
||||||
|
{{> PageSizePartial }}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div id="x-movies-bulk" class="queue table-responsive"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div id="x-movies-bulk-pager"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,11 @@
|
||||||
|
var Marionette = require('marionette');
|
||||||
|
|
||||||
|
module.exports = Marionette.CompositeView.extend({
|
||||||
|
template : 'AddMovies/BulkImport/EmptyViewTemplate',
|
||||||
|
|
||||||
|
|
||||||
|
initialize : function (options) {
|
||||||
|
this.templateHelpers = {};
|
||||||
|
this.templateHelpers.folder = options.folder;
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,3 @@
|
||||||
|
<div class="text-center hint col-md-12">
|
||||||
|
<span>No movies found in folder {{folder}}. Have you already added all of them?</span>
|
||||||
|
</div>
|
|
@ -0,0 +1,7 @@
|
||||||
|
var TemplatedCell = require('../../Cells/TemplatedCell');
|
||||||
|
|
||||||
|
module.exports = TemplatedCell.extend({
|
||||||
|
className : 'series-title-cell',
|
||||||
|
template : 'AddMovies/BulkImport/MoviePathTemplate',
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,2 @@
|
||||||
|
{{path}}<br>
|
||||||
|
<span title="{{#if movieFile.relativePath}} {{movieFile.relativePath}}{{/if}}" class="hint" style="font-size: 12px;">{{#if movieFile.relativePath}} {{movieFile.relativePath}}{{else}} Movie File Not Found{{/if}}</span>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<select class="col-md-2 form-control page-size x-page-size">
|
||||||
|
<option value="15">15</option>
|
||||||
|
<option value="30">30</option>
|
||||||
|
<option value="50">50</option>
|
||||||
|
<option value="100">100</option>
|
||||||
|
<option value="500">500</option>
|
||||||
|
<option value="1000">1000</option>
|
||||||
|
</select>
|
|
@ -0,0 +1,8 @@
|
||||||
|
var TemplatedCell = require('../../Cells/TemplatedCell');
|
||||||
|
var QualityCellEditor = require('../../Cells/Edit/QualityCellEditor');
|
||||||
|
|
||||||
|
module.exports = TemplatedCell.extend({
|
||||||
|
className : 'quality-cell',
|
||||||
|
template : 'AddMovies/BulkImport/QualityCellTemplate',
|
||||||
|
editor : QualityCellEditor
|
||||||
|
});
|
|
@ -0,0 +1,5 @@
|
||||||
|
{{#if_gt proper compare="1"}}
|
||||||
|
<span class="badge badge-info" title="PROPER">{{movieFile.quality.quality.name}}</span>
|
||||||
|
{{else}}
|
||||||
|
<span class="badge" title="{{#if movieFile.quality.hardcodedSubs}}Warning: {{movieFile.quality.hardcodedSubs}}{{/if}}">{{movieFile.quality.quality.name}}</span>
|
||||||
|
{{/if_gt}}
|
|
@ -0,0 +1,62 @@
|
||||||
|
var vent = require('vent');
|
||||||
|
var _ = require('underscore');
|
||||||
|
var $ = require('jquery');
|
||||||
|
var NzbDroneCell = require('../../Cells/NzbDroneCell');
|
||||||
|
var CommandController = require('../../Commands/CommandController');
|
||||||
|
|
||||||
|
module.exports = NzbDroneCell.extend({
|
||||||
|
className : 'tmdbId-cell',
|
||||||
|
|
||||||
|
// would like to use change with a _.debounce eventually
|
||||||
|
events : {
|
||||||
|
'blur input.tmdbId-input' : '_updateId'
|
||||||
|
},
|
||||||
|
|
||||||
|
render : function() {
|
||||||
|
this.$el.empty();
|
||||||
|
|
||||||
|
this.$el.html('<i class="icon-sonarr-info hidden"></i><input type="text" class="x-tmdbId tmdbId-input form-control" value="' + this.cellValue.get('tmdbId') + '" />');
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateId : function() {
|
||||||
|
var field = this.$el.find('.x-tmdbId');
|
||||||
|
var data = field.val();
|
||||||
|
|
||||||
|
var promise = $.ajax({
|
||||||
|
url : window.NzbDrone.ApiRoot + '/movies/lookup/tmdb?tmdbId=' + data,
|
||||||
|
type : 'GET',
|
||||||
|
});
|
||||||
|
|
||||||
|
//field.spinForPromise(promise);
|
||||||
|
|
||||||
|
field.prop("disabled", true)
|
||||||
|
|
||||||
|
var icon = this.$(".icon-sonarr-info");
|
||||||
|
|
||||||
|
icon.removeClass("hidden");
|
||||||
|
|
||||||
|
icon.spinForPromise(promise);
|
||||||
|
var _self = this;
|
||||||
|
var cacheMonitored = this.model.get('monitored');
|
||||||
|
var cacheProfile = this.model.get("profileId");
|
||||||
|
var cachePath = this.model.get("path");
|
||||||
|
var cacheFile = this.model.get("movieFile");
|
||||||
|
var cacheRoot = this.model.get("rootFolderPath");
|
||||||
|
|
||||||
|
promise.success(function(response) {
|
||||||
|
_self.model.set(response);
|
||||||
|
_self.model.set('monitored', cacheMonitored); //reset to the previous monitored value
|
||||||
|
_self.model.set('profileId', cacheProfile);
|
||||||
|
_self.model.set('path', cachePath);
|
||||||
|
_self.model.set('movieFile', cacheFile); // may be unneccessary.
|
||||||
|
field.prop("disabled", false)
|
||||||
|
});
|
||||||
|
|
||||||
|
promise.error(function(request, status, error) {
|
||||||
|
console.error("Status: " + status, "Error: " + error);
|
||||||
|
field.prop("disabled", false)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,6 +1,17 @@
|
||||||
@import "../Shared/Styles/card.less";
|
@import "../Shared/Styles/card.less";
|
||||||
@import "../Shared/Styles/clickable.less";
|
@import "../Shared/Styles/clickable.less";
|
||||||
|
|
||||||
|
.inline {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-size {
|
||||||
|
display: inline-block;
|
||||||
|
width: 200px;
|
||||||
|
float: right;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
#add-movies-screen {
|
#add-movies-screen {
|
||||||
.existing-movies {
|
.existing-movies {
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,34 @@
|
||||||
.series-title-cell {
|
.series-title-cell {
|
||||||
.text-overflow();
|
.text-overflow();
|
||||||
|
|
||||||
max-width: 450px;
|
max-width: 350px;
|
||||||
|
|
||||||
@media @sm {
|
@media @sm {
|
||||||
max-width: 250px
|
max-width: 250px
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tmdbId-cell {
|
||||||
|
.text-overflow();
|
||||||
|
|
||||||
|
max-width: 100px;
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.monitor-cell {
|
||||||
|
.text-overflow();
|
||||||
|
|
||||||
|
max-width: 150px;
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-cell {
|
||||||
|
.text-overflow();
|
||||||
|
|
||||||
|
max-width: 150px;
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
.episode-title-cell {
|
.episode-title-cell {
|
||||||
.text-overflow();
|
.text-overflow();
|
||||||
|
|
||||||
|
|
|
@ -572,7 +572,7 @@
|
||||||
|
|
||||||
if (mode == "infinite") {
|
if (mode == "infinite") {
|
||||||
if (!links[currentPage + '']) {
|
if (!links[currentPage + '']) {
|
||||||
throw new RangeError("No link found for page " + currentPage);
|
//throw new RangeError("No link found for page " + currentPage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (currentPage < firstPage ||
|
else if (currentPage < firstPage ||
|
||||||
|
@ -756,7 +756,7 @@
|
||||||
hasNext: function () {
|
hasNext: function () {
|
||||||
var state = this.state;
|
var state = this.state;
|
||||||
var currentPage = this.state.currentPage;
|
var currentPage = this.state.currentPage;
|
||||||
if (this.mode != "infinite") return currentPage < state.lastPage;
|
if (true/*this.mode != "infinite"*/) return currentPage < state.lastPage;
|
||||||
return !!this.links[currentPage + 1];
|
return !!this.links[currentPage + 1];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1207,9 +1207,16 @@
|
||||||
if (_isUndefined(options.silent)) delete opts.silent;
|
if (_isUndefined(options.silent)) delete opts.silent;
|
||||||
else opts.silent = options.silent;
|
else opts.silent = options.silent;
|
||||||
|
|
||||||
|
//console.log(_extend({at: fullCol.length}, opts));
|
||||||
|
|
||||||
var models = col.models;
|
var models = col.models;
|
||||||
if (mode == "client") fullCol.reset(models, opts);
|
if (mode == "client") {
|
||||||
else fullCol.add(models, _extend({at: fullCol.length}, opts));
|
fullCol.reset(models, opts);
|
||||||
|
} else {
|
||||||
|
opts.remove = false;
|
||||||
|
fullCol.add(models, _extend({at: fullCol.length}, opts));
|
||||||
|
opts.remove = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (success) success(col, resp, opts);
|
if (success) success(col, resp, opts);
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tmdbId-input {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.movie-tabs-card {
|
.movie-tabs-card {
|
||||||
.card;
|
.card;
|
||||||
.opacity(0.9);
|
.opacity(0.9);
|
||||||
|
|
|
@ -83,7 +83,7 @@ module.exports = Paginator.extend({
|
||||||
var windowStart = Math.floor(currentPage / this.windowSize) * this.windowSize;
|
var windowStart = Math.floor(currentPage / this.windowSize) * this.windowSize;
|
||||||
var windowEnd = Math.min(lastPage + 1, windowStart + this.windowSize);
|
var windowEnd = Math.min(lastPage + 1, windowStart + this.windowSize);
|
||||||
|
|
||||||
if (collection.mode !== 'infinite') {
|
if (true/*collection.mode !== 'infinite'*/) {
|
||||||
for (var i = windowStart; i < windowEnd; i++) {
|
for (var i = windowStart; i < windowEnd; i++) {
|
||||||
handles.push({
|
handles.push({
|
||||||
label : i + 1,
|
label : i + 1,
|
||||||
|
@ -185,4 +185,4 @@ module.exports = Paginator.extend({
|
||||||
this.$el.find('.x-page-number').html('<i class="icon-sonarr-spinner fa-spin"></i>');
|
this.$el.find('.x-page-number').html('<i class="icon-sonarr-spinner fa-spin"></i>');
|
||||||
this.collection.getPage(selectedPage);
|
this.collection.getPage(selectedPage);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue