mirror of
https://github.com/Radarr/Radarr.git
synced 2024-11-09 04:22:30 +01:00
Merge branch 'because-kayone' into develop
This commit is contained in:
commit
298bc07be7
@ -5,9 +5,9 @@ namespace NzbDrone.Api.RootFolders
|
|||||||
{
|
{
|
||||||
public class RootFolderModule : NzbDroneRestModule<RootFolderResource>
|
public class RootFolderModule : NzbDroneRestModule<RootFolderResource>
|
||||||
{
|
{
|
||||||
private readonly RootFolderService _rootFolderService;
|
private readonly IRootFolderService _rootFolderService;
|
||||||
|
|
||||||
public RootFolderModule(RootFolderService rootFolderService)
|
public RootFolderModule(IRootFolderService rootFolderService)
|
||||||
{
|
{
|
||||||
_rootFolderService = rootFolderService;
|
_rootFolderService = rootFolderService;
|
||||||
|
|
||||||
|
@ -91,6 +91,7 @@
|
|||||||
<Compile Include="Exceptions\NzbDroneException.cs" />
|
<Compile Include="Exceptions\NzbDroneException.cs" />
|
||||||
<Compile Include="Instrumentation\GlobalExceptionHandlers.cs" />
|
<Compile Include="Instrumentation\GlobalExceptionHandlers.cs" />
|
||||||
<Compile Include="Instrumentation\ExceptronTarget.cs" />
|
<Compile Include="Instrumentation\ExceptronTarget.cs" />
|
||||||
|
<Compile Include="PathEqualityComparer.cs" />
|
||||||
<Compile Include="TPL\LimitedConcurrencyLevelTaskScheduler.cs" />
|
<Compile Include="TPL\LimitedConcurrencyLevelTaskScheduler.cs" />
|
||||||
<Compile Include="Security\IgnoreCertErrorPolicy.cs" />
|
<Compile Include="Security\IgnoreCertErrorPolicy.cs" />
|
||||||
<Compile Include="StringExtensions.cs" />
|
<Compile Include="StringExtensions.cs" />
|
||||||
|
20
NzbDrone.Common/PathEqualityComparer.cs
Normal file
20
NzbDrone.Common/PathEqualityComparer.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NzbDrone.Common
|
||||||
|
{
|
||||||
|
public class PathEqualityComparer : IEqualityComparer<String>
|
||||||
|
{
|
||||||
|
public bool Equals(string x, string y)
|
||||||
|
{
|
||||||
|
return x.PathEquals(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetHashCode(string obj)
|
||||||
|
{
|
||||||
|
return obj.CleanFilePath().GetHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -35,11 +35,12 @@ public static string CleanFilePath(this string path)
|
|||||||
return info.FullName.TrimEnd('/').Trim('\\', ' ');
|
return info.FullName.TrimEnd('/').Trim('\\', ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static bool PathEquals(this string firstPath, string secondPath)
|
public static bool PathEquals(this string firstPath, string secondPath)
|
||||||
{
|
{
|
||||||
Ensure.That(() => firstPath).IsValidPath();
|
if (OsInfo.IsLinux)
|
||||||
Ensure.That(() => secondPath).IsValidPath();
|
{
|
||||||
|
return String.Equals(firstPath.CleanFilePath(), secondPath.CleanFilePath());
|
||||||
|
}
|
||||||
|
|
||||||
return String.Equals(firstPath.CleanFilePath(), secondPath.CleanFilePath(), StringComparison.InvariantCultureIgnoreCase);
|
return String.Equals(firstPath.CleanFilePath(), secondPath.CleanFilePath(), StringComparison.InvariantCultureIgnoreCase);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Linq;
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -40,14 +41,14 @@ public RootFolderService(IBasicRepository<RootFolder> rootFolderRepository,
|
|||||||
_configService = configService;
|
_configService = configService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual List<RootFolder> All()
|
public List<RootFolder> All()
|
||||||
{
|
{
|
||||||
var rootFolders = _rootFolderRepository.All().ToList();
|
var rootFolders = _rootFolderRepository.All().ToList();
|
||||||
|
|
||||||
return rootFolders;
|
return rootFolders;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual List<RootFolder> AllWithUnmappedFolders()
|
public List<RootFolder> AllWithUnmappedFolders()
|
||||||
{
|
{
|
||||||
var rootFolders = _rootFolderRepository.All().ToList();
|
var rootFolders = _rootFolderRepository.All().ToList();
|
||||||
|
|
||||||
@ -63,7 +64,7 @@ public virtual List<RootFolder> AllWithUnmappedFolders()
|
|||||||
return rootFolders;
|
return rootFolders;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual RootFolder Add(RootFolder rootFolder)
|
public RootFolder Add(RootFolder rootFolder)
|
||||||
{
|
{
|
||||||
var all = All();
|
var all = All();
|
||||||
|
|
||||||
@ -87,12 +88,12 @@ public virtual RootFolder Add(RootFolder rootFolder)
|
|||||||
return rootFolder;
|
return rootFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Remove(int id)
|
public void Remove(int id)
|
||||||
{
|
{
|
||||||
_rootFolderRepository.Delete(id);
|
_rootFolderRepository.Delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual List<UnmappedFolder> GetUnmappedFolders(string path)
|
public List<UnmappedFolder> GetUnmappedFolders(string path)
|
||||||
{
|
{
|
||||||
Logger.Debug("Generating list of unmapped folders");
|
Logger.Debug("Generating list of unmapped folders");
|
||||||
if (String.IsNullOrEmpty(path))
|
if (String.IsNullOrEmpty(path))
|
||||||
@ -107,14 +108,14 @@ public virtual List<UnmappedFolder> GetUnmappedFolders(string path)
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (string seriesFolder in _diskProvider.GetDirectories(path))
|
var seriesFolders = _diskProvider.GetDirectories(path).ToList();
|
||||||
|
var unmappedFolders = seriesFolders.Except(series.Select(s => s.Path), new PathEqualityComparer()).ToList();
|
||||||
|
|
||||||
|
foreach (string unmappedFolder in unmappedFolders)
|
||||||
{
|
{
|
||||||
if (!series.Any(s => s.Path.PathEquals(seriesFolder)))
|
var di = new DirectoryInfo(unmappedFolder.Normalize());
|
||||||
{
|
|
||||||
var di = new DirectoryInfo(seriesFolder.Normalize());
|
|
||||||
results.Add(new UnmappedFolder { Name = di.Name, Path = di.FullName });
|
results.Add(new UnmappedFolder { Name = di.Name, Path = di.FullName });
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (Path.GetPathRoot(path).Equals(path, StringComparison.InvariantCultureIgnoreCase))
|
if (Path.GetPathRoot(path).Equals(path, StringComparison.InvariantCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
@ -126,7 +127,7 @@ public virtual List<UnmappedFolder> GetUnmappedFolders(string path)
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual Dictionary<string, long> FreeSpaceOnDrives()
|
public Dictionary<string, long> FreeSpaceOnDrives()
|
||||||
{
|
{
|
||||||
var freeSpace = new Dictionary<string, long>();
|
var freeSpace = new Dictionary<string, long>();
|
||||||
|
|
||||||
|
69
UI/Cells/Edit/QualityCellEditor.js
Normal file
69
UI/Cells/Edit/QualityCellEditor.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
'use strict';
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'backgrid',
|
||||||
|
'Settings/Quality/Profile/QualityProfileSchemaCollection'
|
||||||
|
], function (Backgrid, QualityProfileSchemaCollection) {
|
||||||
|
return Backgrid.CellEditor.extend({
|
||||||
|
|
||||||
|
className: 'quality-cell-editor',
|
||||||
|
template : 'Cells/Edit/QualityCellEditorTemplate',
|
||||||
|
tagName : 'select',
|
||||||
|
|
||||||
|
events: {
|
||||||
|
'change': 'save',
|
||||||
|
'blur': 'close',
|
||||||
|
'keydown': 'close'
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function () {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var qualityProfileSchemaCollection = new QualityProfileSchemaCollection();
|
||||||
|
var promise = qualityProfileSchemaCollection.fetch();
|
||||||
|
|
||||||
|
promise.done(function () {
|
||||||
|
var templateName = self.template;
|
||||||
|
self.schema = qualityProfileSchemaCollection.first();
|
||||||
|
|
||||||
|
var selected = _.find(self.schema.get('available'), { 'id': self.cell.cellValue.get('quality').id });
|
||||||
|
selected.selected = true;
|
||||||
|
|
||||||
|
self.templateFunction = Marionette.TemplateCache.get(templateName);
|
||||||
|
var data = self.schema.toJSON();
|
||||||
|
var html = self.templateFunction(data);
|
||||||
|
self.$el.html(html);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
save: function (e) {
|
||||||
|
var model = this.model;
|
||||||
|
var column = this.column;
|
||||||
|
var selected = parseInt(this.$el.val());
|
||||||
|
|
||||||
|
var quality = _.find(this.schema.get('available'), { 'id': selected });
|
||||||
|
|
||||||
|
var newQuality = {
|
||||||
|
proper: false,
|
||||||
|
quality: quality
|
||||||
|
};
|
||||||
|
|
||||||
|
model.set(column.get("name"), newQuality);
|
||||||
|
model.trigger("backgrid:edited", model, column, new Backgrid.Command(e));
|
||||||
|
},
|
||||||
|
|
||||||
|
close: function (e) {
|
||||||
|
var model = this.model;
|
||||||
|
var column = this.column;
|
||||||
|
var command = new Backgrid.Command(e);
|
||||||
|
|
||||||
|
model.trigger("backgrid:edited", model, column, command);
|
||||||
|
},
|
||||||
|
|
||||||
|
_setOptions: function (options) {
|
||||||
|
this.cell = options.cell
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
7
UI/Cells/Edit/QualityCellEditorTemplate.html
Normal file
7
UI/Cells/Edit/QualityCellEditorTemplate.html
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{{#each available}}
|
||||||
|
{{#if selected}}
|
||||||
|
<option value="{{id}}" selected="selected">{{name}}</option>
|
||||||
|
{{else}}
|
||||||
|
<option value="{{id}}">{{name}}</option>
|
||||||
|
{{/if}}
|
||||||
|
{{/each}}
|
@ -14,6 +14,12 @@ define(
|
|||||||
this.cellValue = this._getValue();
|
this.cellValue = this._getValue();
|
||||||
|
|
||||||
this.listenTo(this.model, 'change', this._refresh);
|
this.listenTo(this.model, 'change', this._refresh);
|
||||||
|
|
||||||
|
this.listenTo(this.model, "backgrid:edit", function (model, column, cell, editor) {
|
||||||
|
if (column.get("name") == this.column.get("name")) {
|
||||||
|
this._startEditing(model, column, cell, editor);
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_refresh: function () {
|
_refresh: function () {
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
define(
|
define(
|
||||||
[
|
[
|
||||||
'Cells/TemplatedCell'
|
'Cells/TemplatedCell',
|
||||||
], function (TemplatedCell) {
|
'Cells/Edit/QualityCellEditor'
|
||||||
|
], function (TemplatedCell, QualityCellEditor) {
|
||||||
return TemplatedCell.extend({
|
return TemplatedCell.extend({
|
||||||
|
|
||||||
className: 'quality-cell',
|
className: 'quality-cell',
|
||||||
template : 'Cells/QualityCellTemplate'
|
template : 'Cells/QualityCellTemplate',
|
||||||
|
editor : QualityCellEditor,
|
||||||
|
|
||||||
|
_startEditing: function (model, column, cell, editor) {
|
||||||
|
editor._setOptions({ cell: cell });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -7,7 +7,6 @@ define(
|
|||||||
], function (Marionette, NzbDroneCell) {
|
], function (Marionette, NzbDroneCell) {
|
||||||
return NzbDroneCell.extend({
|
return NzbDroneCell.extend({
|
||||||
|
|
||||||
|
|
||||||
render: function () {
|
render: function () {
|
||||||
|
|
||||||
var templateName = this.column.get('template') || this.template;
|
var templateName = this.column.get('template') || this.template;
|
||||||
@ -17,6 +16,7 @@ define(
|
|||||||
var html = this.templateFunction(data);
|
var html = this.templateFunction(data);
|
||||||
this.$el.html(html);
|
this.$el.html(html);
|
||||||
|
|
||||||
|
this.delegateEvents();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -5,11 +5,10 @@
|
|||||||
<h3>
|
<h3>
|
||||||
<i class="icon-bookmark x-episode-monitored" title="Toggle monitored status" />
|
<i class="icon-bookmark x-episode-monitored" title="Toggle monitored status" />
|
||||||
{{#if episodeTitle}}
|
{{#if episodeTitle}}
|
||||||
{{episodeTitle}}
|
{{title}} - {{EpisodeNumber}} - {{episodeTitle}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{title}}
|
{{series.title}} - {{EpisodeNumber}} - {{title}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
- {{EpisodeNumber}}
|
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,7 +34,8 @@ define(
|
|||||||
name : 'quality',
|
name : 'quality',
|
||||||
label : 'Quality',
|
label : 'Quality',
|
||||||
cell : QualityCell,
|
cell : QualityCell,
|
||||||
sortable: false
|
sortable: false,
|
||||||
|
editable: true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -1,4 +1,14 @@
|
|||||||
<div class="episode-overview">
|
<div class="episode-info">
|
||||||
|
{{#with series}}
|
||||||
|
{{qualityProfile qualityProfileId}}
|
||||||
|
<span class="label label-info">{{network}}</span>
|
||||||
|
{{/with}}
|
||||||
|
<span class="label label-info">{{StartTime airDateUtc}}</span>
|
||||||
|
<span class="label label-info">{{NextAiring airDateUtc}}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="episode-overview">
|
||||||
{{overview}}
|
{{overview}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="episode-file-info"></div>
|
<div class="episode-file-info"></div>
|
||||||
|
@ -197,13 +197,15 @@
|
|||||||
|
|
||||||
.episode-detail-modal {
|
.episode-detail-modal {
|
||||||
|
|
||||||
.episode-overview {
|
.episode-info {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.episode-overview {
|
||||||
font-style : italic;
|
font-style : italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
.episode-file-info {
|
.episode-file-info {
|
||||||
|
|
||||||
margin-top : 30px;
|
margin-top : 30px;
|
||||||
font-size : 12px;
|
font-size : 12px;
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,8 @@ define(['app',
|
|||||||
'marionette',
|
'marionette',
|
||||||
'Settings/Quality/Profile/QualityProfileView',
|
'Settings/Quality/Profile/QualityProfileView',
|
||||||
'Settings/Quality/Profile/EditQualityProfileView',
|
'Settings/Quality/Profile/EditQualityProfileView',
|
||||||
'Settings/Quality/Profile/QualityProfileSchemaCollection'],
|
'Settings/Quality/Profile/QualityProfileSchemaCollection'
|
||||||
function (App, Marionette, QualityProfileView, EditProfileView, ProfileCollection) {
|
], function (App, Marionette, QualityProfileView, EditProfileView, ProfileCollection) {
|
||||||
|
|
||||||
return Marionette.CompositeView.extend({
|
return Marionette.CompositeView.extend({
|
||||||
itemView : QualityProfileView,
|
itemView : QualityProfileView,
|
||||||
@ -24,7 +24,6 @@ define(['app',
|
|||||||
collectionView.ui.addCard.parent('li').before(itemView.el);
|
collectionView.ui.addCard.parent('li').before(itemView.el);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
_addProfile: function () {
|
_addProfile: function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
var schemaCollection = new ProfileCollection();
|
var schemaCollection = new ProfileCollection();
|
||||||
|
Loading…
Reference in New Issue
Block a user