Skip to content
This repository was archived by the owner on Feb 28, 2022. It is now read-only.

Commit 80a2f14

Browse files
authored
Merge pull request #19 from mark-monteiro/integrate-fx-cop
Integrate FxCop Analyzer
2 parents b15d168 + 4ee500a commit 80a2f14

23 files changed

+302
-276
lines changed

Emby.AutoOrganize/Api/FileOrganizationService.cs

+8-19
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
using System.Collections.Generic;
2+
using System.Diagnostics.CodeAnalysis;
23
using System.Threading.Tasks;
34
using Emby.AutoOrganize.Core;
45
using Emby.AutoOrganize.Model;
56
using MediaBrowser.Controller.Net;
67
using MediaBrowser.Model.Dto;
78
using MediaBrowser.Model.Querying;
8-
using MediaBrowser.Model.Serialization;
99
using MediaBrowser.Model.Services;
1010

1111
namespace Emby.AutoOrganize.Api
@@ -82,6 +82,7 @@ public class OrganizeEpisode
8282
public bool RememberCorrection { get; set; }
8383

8484
[ApiMember(Name = "NewSeriesProviderIds", Description = "A list of provider IDs identifying a new series.", IsRequired = false, DataType = "Dictionary<string, string>", ParameterType = "query", Verb = "POST")]
85+
[SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "ServiceStack cannot deserialize readonly dictionaries.")]
8586
public Dictionary<string, string> NewSeriesProviderIds { get; set; }
8687

8788
[ApiMember(Name = "NewSeriesName", Description = "Name of a series to add.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
@@ -104,6 +105,7 @@ public class OrganizeMovie
104105
public string MovieId { get; set; }
105106

106107
[ApiMember(Name = "NewMovieProviderIds", Description = "A list of provider IDs identifying a new movie.", IsRequired = false, DataType = "Dictionary<string, string>", ParameterType = "query", Verb = "POST")]
108+
[SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "ServiceStack cannot deserialize readonly dictionaries.")]
107109
public Dictionary<string, string> NewMovieProviderIds { get; set; }
108110

109111
[ApiMember(Name = "NewMovieName", Description = "Name of a movie to add.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")]
@@ -138,7 +140,7 @@ public class GetSmartMatchInfos : IReturn<QueryResult<SmartMatchInfo>>
138140
public class DeleteSmartMatchEntry
139141
{
140142
[ApiMember(Name = "Entries", Description = "SmartMatch Entry", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
141-
public List<NameValuePair> Entries { get; set; }
143+
public IReadOnlyList<NameValuePair> Entries { get; set; }
142144
}
143145

144146
[Authenticated(Roles = "Admin")]
@@ -176,14 +178,15 @@ public void Delete(DeleteOriginalFile request)
176178
Task.WaitAll(task);
177179
}
178180

181+
[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "Parameter is used to define an API route.")]
179182
public void Delete(ClearOrganizationLog request)
180183
{
181184
var task = InternalFileOrganizationService.ClearLog();
182185

183186
Task.WaitAll(task);
184187
}
185188

186-
189+
[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", Justification = "Parameter is used to define an API route.")]
187190
public void Delete(ClearOrganizationCompletedLog request)
188191
{
189192
var task = InternalFileOrganizationService.ClearCompleted();
@@ -204,13 +207,6 @@ public void Post(PerformOrganization request)
204207

205208
public void Post(OrganizeEpisode request)
206209
{
207-
var dicNewProviderIds = new Dictionary<string, string>();
208-
209-
if (request.NewSeriesProviderIds != null)
210-
{
211-
dicNewProviderIds = request.NewSeriesProviderIds;
212-
}
213-
214210
// Don't await this
215211
var task = InternalFileOrganizationService.PerformOrganization(new EpisodeFileOrganizationRequest
216212
{
@@ -222,7 +218,7 @@ public void Post(OrganizeEpisode request)
222218
SeriesId = request.SeriesId,
223219
NewSeriesName = request.NewSeriesName,
224220
NewSeriesYear = request.NewSeriesYear,
225-
NewSeriesProviderIds = dicNewProviderIds,
221+
NewSeriesProviderIds = request.NewSeriesProviderIds ?? new Dictionary<string, string>(),
226222
TargetFolder = request.TargetFolder
227223
});
228224

@@ -233,21 +229,14 @@ public void Post(OrganizeEpisode request)
233229

234230
public void Post(OrganizeMovie request)
235231
{
236-
var dicNewProviderIds = new Dictionary<string, string>();
237-
238-
if (request.NewMovieProviderIds != null)
239-
{
240-
dicNewProviderIds = request.NewMovieProviderIds;
241-
}
242-
243232
// Don't await this
244233
var task = InternalFileOrganizationService.PerformOrganization(new MovieFileOrganizationRequest
245234
{
246235
ResultId = request.Id,
247236
MovieId = request.MovieId,
248237
NewMovieName = request.NewMovieName,
249238
NewMovieYear = request.NewMovieYear,
250-
NewMovieProviderIds = dicNewProviderIds,
239+
NewMovieProviderIds = request.NewMovieProviderIds ?? new Dictionary<string, string>(),
251240
TargetFolder = request.TargetFolder
252241
});
253242

Emby.AutoOrganize/Core/EpisodeFileOrganizer.cs

+38-35
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,19 @@ public class EpisodeFileOrganizer
3030
private readonly ILogger _logger;
3131
private readonly IFileSystem _fileSystem;
3232
private readonly IFileOrganizationService _organizationService;
33-
private readonly IServerConfigurationManager _config;
3433
private readonly IProviderManager _providerManager;
3534

3635
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
3736

3837
public EpisodeFileOrganizer(
3938
IFileOrganizationService organizationService,
40-
IServerConfigurationManager config,
4139
IFileSystem fileSystem,
4240
ILogger logger,
4341
ILibraryManager libraryManager,
4442
ILibraryMonitor libraryMonitor,
4543
IProviderManager providerManager)
4644
{
4745
_organizationService = organizationService;
48-
_config = config;
4946
_fileSystem = fileSystem;
5047
_logger = logger;
5148
_libraryManager = libraryManager;
@@ -167,15 +164,15 @@ await OrganizeEpisode(path,
167164
}
168165
else
169166
{
170-
var msg = string.Format("Unable to determine episode number from {0}", path);
167+
var msg = "Unable to determine episode number from " + path;
171168
result.Status = FileSortingStatus.Failure;
172169
result.StatusMessage = msg;
173170
_logger.LogWarning(msg);
174171
}
175172
}
176173
else
177174
{
178-
var msg = string.Format("Unable to determine series name from {0}", path);
175+
var msg = "Unable to determine series name from " + path;
179176
result.Status = FileSortingStatus.Failure;
180177
result.StatusMessage = msg;
181178
_logger.LogWarning(msg);
@@ -228,16 +225,13 @@ private async Task<Series> AutoDetectSeries(
228225
Year = seriesYear
229226
};
230227

231-
var searchResultsTask = await _providerManager.GetRemoteSearchResults<Series, SeriesInfo>(new RemoteSearchQuery<SeriesInfo>
232-
{
233-
SearchInfo = seriesInfo
234-
235-
}, cancellationToken);
228+
var searchQuery = new RemoteSearchQuery<SeriesInfo> { SearchInfo = seriesInfo };
229+
var searchResults = await _providerManager.GetRemoteSearchResults<Series, SeriesInfo>(searchQuery, cancellationToken).ConfigureAwait(false);
236230

237231
#endregion
238232

239233
// Group series by name and year (if 2 series with the exact same name, the same year ...)
240-
var groupedResult = searchResultsTask.GroupBy(p => new { p.Name, p.ProductionYear },
234+
var groupedResult = searchResults.GroupBy(p => new { p.Name, p.ProductionYear },
241235
p => p,
242236
(key, g) => new { Key = key, Result = g.ToList() }).ToList();
243237

@@ -307,7 +301,7 @@ private async Task<Series> CreateNewSeries(
307301
// Create the folder
308302
Directory.CreateDirectory(series.Path);
309303

310-
series.ProviderIds = request.NewSeriesProviderIds;
304+
series.ProviderIds = request.NewSeriesProviderIds.ToDictionary(x => x.Key, x => x.Value);
311305
}
312306
}
313307

@@ -388,7 +382,7 @@ private Task OrganizeEpisode(string sourcePath,
388382

389383
if (series == null)
390384
{
391-
var msg = string.Format("Unable to find series in library matching name {0}", seriesName);
385+
var msg = "Unable to find series in library matching name " + seriesName;
392386
result.Status = FileSortingStatus.Failure;
393387
result.StatusMessage = msg;
394388
_logger.LogWarning(msg);
@@ -418,7 +412,6 @@ private Task OrganizeEpisode(string sourcePath,
418412
/// <param name="endingEpiosdeNumber"></param>
419413
/// <param name="premiereDate"></param>
420414
/// <param name="options"></param>
421-
/// <param name="smartMatch"></param>
422415
/// <param name="rememberCorrection"></param>
423416
/// <param name="result"></param>
424417
/// <param name="cancellationToken"></param>
@@ -434,29 +427,38 @@ private async Task OrganizeEpisode(string sourcePath,
434427
FileOrganizationResult result,
435428
CancellationToken cancellationToken)
436429
{
437-
var episode = await GetMatchingEpisode(series, seasonNumber, episodeNumber, endingEpiosdeNumber, result, premiereDate, cancellationToken);
430+
var episode = await GetMatchingEpisode(
431+
series,
432+
seasonNumber,
433+
episodeNumber,
434+
endingEpiosdeNumber,
435+
result,
436+
premiereDate,
437+
cancellationToken).ConfigureAwait(false);
438438

439439
Season season;
440440
season = !string.IsNullOrEmpty(episode.Season?.Path)
441441
? episode.Season
442-
: GetMatchingSeason(series, episode, options, cancellationToken);
442+
: GetMatchingSeason(series, episode, options);
443443

444444
// Now we can check the episode Path
445445
if (string.IsNullOrEmpty(episode.Path))
446446
{
447447
SetEpisodeFileName(sourcePath, series, season, episode, options);
448448
}
449449

450-
await OrganizeEpisode(sourcePath,
450+
await OrganizeEpisode(
451+
sourcePath,
451452
series,
452453
episode,
453454
options,
454455
rememberCorrection,
455456
result,
456-
cancellationToken);
457+
cancellationToken).ConfigureAwait(false);
457458
}
458459

459-
private async Task OrganizeEpisode(string sourcePath,
460+
private Task OrganizeEpisode(
461+
string sourcePath,
460462
Series series,
461463
Episode episode,
462464
TvFileOrganizationOptions options,
@@ -487,7 +489,7 @@ private async Task OrganizeEpisode(string sourcePath,
487489

488490
if (string.IsNullOrEmpty(newPath))
489491
{
490-
var msg = string.Format("Unable to sort {0} because target path could not be determined.", sourcePath);
492+
var msg = $"Unable to sort {sourcePath} because target path could not be determined.";
491493
throw new OrganizationException(msg);
492494
}
493495

@@ -501,31 +503,31 @@ private async Task OrganizeEpisode(string sourcePath,
501503
{
502504
if (options.CopyOriginalFile && fileExists && IsSameEpisode(sourcePath, newPath))
503505
{
504-
var msg = string.Format("File '{0}' already copied to new path '{1}', stopping organization", sourcePath, newPath);
506+
var msg = $"File '{sourcePath}' already copied to new path '{newPath}', stopping organization";
505507
_logger.LogInformation(msg);
506508
result.Status = FileSortingStatus.SkippedExisting;
507509
result.StatusMessage = msg;
508-
return;
510+
return Task.CompletedTask;
509511
}
510512

511513
if (fileExists)
512514
{
513-
var msg = string.Format("File '{0}' already exists as '{1}', stopping organization", sourcePath, newPath);
515+
var msg = $"File '{sourcePath}' already exists as '{newPath}', stopping organization";
514516
_logger.LogInformation(msg);
515517
result.Status = FileSortingStatus.SkippedExisting;
516518
result.StatusMessage = msg;
517519
result.TargetPath = newPath;
518-
return;
520+
return Task.CompletedTask;
519521
}
520522

521523
if (otherDuplicatePaths.Count > 0)
522524
{
523-
var msg = string.Format("File '{0}' already exists as these:'{1}'. Stopping organization", sourcePath, string.Join("', '", otherDuplicatePaths));
525+
var msg = $"File '{sourcePath}' already exists as these:'{string.Join("', '", otherDuplicatePaths)}'. Stopping organization";
524526
_logger.LogInformation(msg);
525527
result.Status = FileSortingStatus.SkippedExisting;
526528
result.StatusMessage = msg;
527529
result.DuplicatePaths = otherDuplicatePaths;
528-
return;
530+
return Task.CompletedTask;
529531
}
530532
}
531533

@@ -569,7 +571,7 @@ private async Task OrganizeEpisode(string sourcePath,
569571
result.Status = FileSortingStatus.Failure;
570572
result.StatusMessage = ex.Message;
571573
_logger.LogError(ex, "Caught a generic exception while organizing an episode");
572-
return;
574+
return Task.CompletedTask;
573575
}
574576
finally
575577
{
@@ -580,6 +582,8 @@ private async Task OrganizeEpisode(string sourcePath,
580582
{
581583
SaveSmartMatchString(originalExtractedSeriesString, series, cancellationToken);
582584
}
585+
586+
return Task.CompletedTask;
583587
}
584588

585589
private void SaveSmartMatchString(string matchString, Series series, CancellationToken cancellationToken)
@@ -734,7 +738,7 @@ private void PerformFileSorting(TvFileOrganizationOptions options, FileOrganizat
734738
}
735739
catch (Exception ex)
736740
{
737-
var errorMsg = string.Format("Failed to move file from {0} to {1}: {2}", result.OriginalPath, result.TargetPath, ex.Message);
741+
var errorMsg = $"Failed to move file from {result.OriginalPath} to {result.TargetPath}: {ex.Message}";
738742

739743
result.Status = FileSortingStatus.Failure;
740744
result.StatusMessage = errorMsg;
@@ -784,7 +788,7 @@ private async Task<Episode> GetMatchingEpisode(Series series,
784788
return episode;
785789
}
786790

787-
private Season GetMatchingSeason(Series series, Episode episode, TvFileOrganizationOptions options, CancellationToken cancellationToken)
791+
private Season GetMatchingSeason(Series series, Episode episode, TvFileOrganizationOptions options)
788792
{
789793
var season = episode.Season;
790794

@@ -799,8 +803,7 @@ private Season GetMatchingSeason(Series series, Episode episode, TvFileOrganizat
799803
{
800804
if (!episode.ParentIndexNumber.HasValue)
801805
{
802-
var msg = string.Format("No season found for {0} season {1} episode {2}", series.Name,
803-
episode.ParentIndexNumber, episode.IndexNumber);
806+
var msg = $"No season found for {series.Name} season {episode.ParentIndexNumber} episode {episode.IndexNumber}.";
804807
_logger.LogWarning(msg);
805808
throw new OrganizationException(msg);
806809
}
@@ -843,7 +846,7 @@ private Series GetMatchingSeries(string seriesName, int? seriesYear, string targ
843846
.Where(i => i.Item2 > 0)
844847
.OrderByDescending(i => i.Item2)
845848
.Select(i => i.Item1)
846-
.FirstOrDefault(s => s.Path.StartsWith(targetFolder));
849+
.FirstOrDefault(s => s.Path.StartsWith(targetFolder, StringComparison.Ordinal));
847850

848851
if (series == null)
849852
{
@@ -858,7 +861,7 @@ private Series GetMatchingSeries(string seriesName, int? seriesYear, string targ
858861
Name = info.ItemName,
859862
DtoOptions = new DtoOptions(true)
860863

861-
}).Cast<Series>().FirstOrDefault(s => s.Path.StartsWith(targetFolder));
864+
}).Cast<Series>().FirstOrDefault(s => s.Path.StartsWith(targetFolder, StringComparison.Ordinal));
862865
}
863866
}
864867

@@ -878,7 +881,7 @@ private string GetSeriesDirectoryName(Series series, TvFileOrganizationOptions o
878881
var seriesFullName = seriesName;
879882
if (series.ProductionYear.HasValue)
880883
{
881-
seriesFullName = string.Format("{0} ({1})", seriesFullName, series.ProductionYear);
884+
seriesFullName = $"{seriesFullName} ({series.ProductionYear})";
882885
}
883886

884887
var seasonFolderName = options.SeriesFolderPattern.
@@ -930,7 +933,7 @@ private async Task<Episode> CreateNewEpisode(
930933

931934
if (episodeSearch == null)
932935
{
933-
var msg = string.Format("No provider metadata found for {0} season {1} episode {2}", series.Name, seasonNumber, episodeNumber);
936+
var msg = $"No provider metadata found for {series.Name} season {seasonNumber} episode {episodeNumber}";
934937
_logger.LogWarning(msg);
935938
throw new OrganizationException(msg);
936939
}

Emby.AutoOrganize/Core/Extensions.cs

+4-3
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@ public static void Convert(this IConfigurationManager manager, IFileOrganization
1919

2020
foreach (SmartMatchInfo optionsSmartMatchInfo in options.SmartMatchInfos)
2121
{
22-
service.SaveResult(new SmartMatchResult
22+
var result = new SmartMatchResult
2323
{
2424
DisplayName = optionsSmartMatchInfo.DisplayName,
2525
ItemName = optionsSmartMatchInfo.ItemName,
2626
OrganizerType = optionsSmartMatchInfo.OrganizerType,
27-
MatchStrings = optionsSmartMatchInfo.MatchStrings.ToList(),
28-
}, CancellationToken.None);
27+
};
28+
result.MatchStrings.AddRange(optionsSmartMatchInfo.MatchStrings);
29+
service.SaveResult(result, CancellationToken.None);
2930
}
3031

3132
manager.SaveAutoOrganizeOptions(options);

0 commit comments

Comments
 (0)