Performance improvements, async work, and formatting with CodeRush.

This commit is contained in:
Steven Hildreth 2020-06-07 17:46:24 -05:00
parent 625fdf7266
commit 3cfd12a330
111 changed files with 6249 additions and 5370 deletions

4
.editorconfig Normal file
View file

@ -0,0 +1,4 @@
[*.cs]
# Default severity for analyzer diagnostics with category 'Style'
dotnet_analyzer_diagnostic.category-Style.severity = none

View file

@ -29,7 +29,13 @@ namespace Inspector
public static int Main(string[] args) => CommandLineApplication.Execute<Program>(args);
#pragma warning disable RCS1213 // Remove unused member declaration.
#pragma warning disable IDE0051 // Remove unused private members
#pragma warning disable CRR0026
private void OnExecute()
#pragma warning restore IDE0051 // Remove unused private members
#pragma warning restore RCS1213 // Remove unused member declaration.
#pragma warning restore CRR0026
{
var inspector = new Roadie.Library.Inspect.Inspector();
inspector.Inspect(DoCopy, IsReadOnly, Folder, Destination ?? Folder, DontAppendSubFolder, IsReadOnly ? true : DontDeleteEmptyFolders, DontRunPreScript);

View file

@ -6,9 +6,9 @@ namespace Roadie.Api.Hubs
{
public class PlayActivityHub : Hub
{
public async Task SendActivity(PlayActivityList playActivity)
public Task SendActivityAsync(PlayActivityList playActivity, System.Threading.CancellationToken cancellationToken)
{
await Clients.All.SendAsync("PlayActivity", playActivity);
return Clients.All.SendAsync("PlayActivity", playActivity, cancellationToken);
}
}
}

View file

@ -5,9 +5,9 @@ namespace Roadie.Api.Hubs
{
public class ScanActivityHub : Hub
{
public async Task SendSystemActivity(string scanActivity)
public Task SendSystemActivityAsync(string scanActivity, System.Threading.CancellationToken cancellationToken)
{
await Clients.All.SendAsync("SendSystemActivity", scanActivity);
return Clients.All.SendAsync("SendSystemActivity", scanActivity, cancellationToken);
}
}
}

View file

@ -26,7 +26,7 @@ namespace Roadie.Library.Tests
{
get
{
return this.MessageLogger as ILogger;
return MessageLogger as ILogger;
}
}
@ -38,17 +38,17 @@ namespace Roadie.Library.Tests
public ArtistLookupEngineTests()
{
this.MessageLogger = new EventMessageLogger<ArtistLookupEngineTests>();
this.MessageLogger.Messages += MessageLogger_Messages;
MessageLogger = new EventMessageLogger<ArtistLookupEngineTests>();
MessageLogger.Messages += MessageLogger_Messages;
var settings = new RoadieSettings();
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddJsonFile("appsettings.test.json");
IConfiguration configuration = configurationBuilder.Build();
configuration.GetSection("RoadieSettings").Bind(settings);
this.Configuration = settings;
this.CacheManager = new DictionaryCacheManager(this.Logger, new CachePolicy(TimeSpan.FromHours(4)));
this.HttpEncoder = new Encoding.DummyHttpEncoder();
Configuration = settings;
CacheManager = new DictionaryCacheManager(Logger, new CachePolicy(TimeSpan.FromHours(4)));
HttpEncoder = new Encoding.DummyHttpEncoder();
}
private void MessageLogger_Messages(object sender, EventMessage e)

View file

@ -18,37 +18,30 @@ namespace Roadie.Library.Tests
return config;
}
private readonly IRoadieSettings _settings = null;
private readonly IRoadieSettings _settings;
private readonly IConfiguration _configuration;
private IConfiguration Configuration
{
get
{
return this._configuration;
}
}
private IRoadieSettings Settings
{
get
{
return this._settings;
return _settings;
}
}
public ConfigurationTests()
{
this._configuration = InitConfiguration();
this._settings = new RoadieSettings();
this._configuration.GetSection("RoadieSettings").Bind(this._settings);
_configuration = InitConfiguration();
_settings = new RoadieSettings();
_configuration.GetSection("RoadieSettings").Bind(_settings);
}
[Fact]
public void LoadRootLevelConfiguration()
{
var inboundFolder = @"C:\roadie_dev_root\inbound";
var configInboundFolder = this.Settings.InboundFolder;
var configInboundFolder = Settings.InboundFolder;
Assert.Equal(inboundFolder, configInboundFolder);
}

View file

@ -220,8 +220,8 @@ namespace Roadie.Library.Tests
var lastTrack = shuffledTracks.First();
foreach(var track in shuffledTracks.Skip(1))
{
Assert.False(track.Artist.Artist.Text == lastTrack.Artist.Artist.Text &&
track.Release.Release.Text == lastTrack.Release.Release.Text);
Assert.False(string.Equals(track.Artist.Artist.Text, lastTrack.Artist.Artist.Text, StringComparison.Ordinal) &&
string.Equals(track.Release.Release.Text, lastTrack.Release.Release.Text, StringComparison.Ordinal));
lastTrack = track;
}

View file

@ -17,7 +17,7 @@ namespace Roadie.Library.Tests
configurationBuilder.AddJsonFile("appsettings.test.json");
IConfiguration configuration = configurationBuilder.Build();
configuration.GetSection("RoadieSettings").Bind(settings);
this.Configuration = settings;
Configuration = settings;
}
[Theory]

View file

@ -21,7 +21,7 @@ namespace Roadie.Library.Tests
{
get
{
return this.MessageLogger as ILogger;
return MessageLogger as ILogger;
}
}
@ -32,8 +32,8 @@ namespace Roadie.Library.Tests
public ID3TagsHelperTests()
{
this.MessageLogger = new EventMessageLogger<ID3TagsHelperTests>();
this.MessageLogger.Messages += MessageLoggerMessages;
MessageLogger = new EventMessageLogger<ID3TagsHelperTests>();
MessageLogger.Messages += MessageLoggerMessages;
var settings = new RoadieSettings();
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
@ -41,11 +41,11 @@ namespace Roadie.Library.Tests
IConfiguration configuration = configurationBuilder.Build();
configuration.GetSection("RoadieSettings").Bind(settings);
settings.ConnectionString = configuration.GetConnectionString("RoadieDatabaseConnection");
this.Configuration = settings;
this.CacheManager = new DictionaryCacheManager(this.Logger, new CachePolicy(TimeSpan.FromHours(4)));
Configuration = settings;
CacheManager = new DictionaryCacheManager(Logger, new CachePolicy(TimeSpan.FromHours(4)));
var tagHelperLooper = new EventMessageLogger<ID3TagsHelper>();
tagHelperLooper.Messages += MessageLoggerMessages;
this.TagsHelper = new ID3TagsHelper(this.Configuration, this.CacheManager, tagHelperLooper);
TagsHelper = new ID3TagsHelper(Configuration, CacheManager, tagHelperLooper);
}
private void MessageLoggerMessages(object sender, EventMessage e)
@ -384,7 +384,7 @@ namespace Roadie.Library.Tests
var file = new FileInfo(@"C:\roadie_dev_root\mp3_tests\01 O.P.D. (Obsessive Personality Disorder).mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName, true);
var tagLib = TagsHelper.MetaDataForFile(file.FullName, true);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
@ -410,7 +410,7 @@ namespace Roadie.Library.Tests
var file = new FileInfo(@"C:\roadie_dev_root\library\Dream Theater\[2016] The Astonishing\01 2285 Entr acte.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
@ -436,7 +436,7 @@ namespace Roadie.Library.Tests
var file = new FileInfo(@"E:\Roadie_Test_Files\13-anna_kendrick-true_colors-a57e270d\01-justin_timberlake-hair_up-ef53c026.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
@ -473,7 +473,7 @@ namespace Roadie.Library.Tests
var folderFiles = Directory.GetFiles(folderName, "*.mp3", SearchOption.AllDirectories);
foreach(var file in folderFiles)
{
var tagLib = this.TagsHelper.MetaDataForFile(file);
var tagLib = TagsHelper.MetaDataForFile(file);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
@ -493,7 +493,7 @@ namespace Roadie.Library.Tests
var file = new FileInfo(@"E:\Roadie_Test_Files\01 01 Angel Of Death.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
@ -519,7 +519,7 @@ namespace Roadie.Library.Tests
var file = new FileInfo(@"E:\Roadie_Test_Files\06 You'Re Sensational.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
@ -545,7 +545,7 @@ namespace Roadie.Library.Tests
var file = new FileInfo(@"M:\inbound\MEGAPACK ---METAL-DEATH-BLACK---\ebony_tears-evil_as_hell-2001-ss\01-deviation-ss.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
@ -571,7 +571,7 @@ namespace Roadie.Library.Tests
var file = new FileInfo(@"M:\unknown\2eec19bd-3575-4b7f-84dd-db2a0ec3e2f3~[2009] Dolly - Disc 1 Of 4~06 Nobody But You (Previously Unissued).mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
@ -598,7 +598,7 @@ namespace Roadie.Library.Tests
var file = new FileInfo(@"M:\library_old\Perverse\[2014] Champion Dub\01 Champion Dub (Original Mix).mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
@ -625,7 +625,7 @@ namespace Roadie.Library.Tests
var file = new FileInfo(@"C:\roadie_dev_root\inbound\Dreadful Fate - Vengeance (2018)\01-dreadful_fate-vengeance.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
@ -653,7 +653,7 @@ namespace Roadie.Library.Tests
var file = new FileInfo(@"M:\library\Blind Melon\[1992] Blind Melon\01. Blind Melon - Soak The Sin.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
@ -680,7 +680,7 @@ namespace Roadie.Library.Tests
var file = new FileInfo(@"E:\Roadie_Test_Files\Test.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
@ -714,14 +714,14 @@ namespace Roadie.Library.Tests
short trackNumber = 15;
var numberOfTracks = 25;
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
metaData.TrackNumber = trackNumber;
metaData.TotalTrackNumbers = numberOfTracks;
this.TagsHelper.WriteTags(metaData, file.FullName);
TagsHelper.WriteTags(metaData, file.FullName);
var tagLibAfterWrite = this.TagsHelper.MetaDataForFile(file.FullName);
var tagLibAfterWrite = TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
Assert.Equal(metaData.Artist, tagLibAfterWrite.Data.Artist);
Assert.Equal(metaData.Release, tagLibAfterWrite.Data.Release);
@ -745,7 +745,7 @@ namespace Roadie.Library.Tests
var file = new FileInfo(@"M:\library\Denver, John\[1972] Aerie\10 Readjustment Blues.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.True(metaData.IsValid);
@ -772,7 +772,7 @@ namespace Roadie.Library.Tests
var file = new FileInfo(@"E:\Roadie_Test_Files\01. What's Yesterday.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
@ -799,7 +799,7 @@ namespace Roadie.Library.Tests
var file = new FileInfo(@"M:\library\Ac Dc\[1975] T.N.T\01 It'S A Long Way To The Top (If You Wanna Rock 'N' Roll).mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
@ -825,7 +825,7 @@ namespace Roadie.Library.Tests
var file = new FileInfo(@"E:\Roadie_Test_Files\01 Martian.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
@ -851,7 +851,7 @@ namespace Roadie.Library.Tests
var file = new FileInfo(@"C:\roadie_dev_root\inbound\[2016] Invention Of Knowledge\01 Invention.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
@ -877,7 +877,7 @@ namespace Roadie.Library.Tests
var file = new FileInfo(@"C:\roadie_dev_root\1985 - Sacred Heart\Dio - Sacred Heart (1).mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
@ -903,7 +903,7 @@ namespace Roadie.Library.Tests
var file = new FileInfo(@"C:\roadie_dev_root\Grift\2017 Arvet\01 - Flyktfast.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);
@ -929,7 +929,7 @@ namespace Roadie.Library.Tests
var file = new FileInfo(@"C:\roadie_dev_root\Distorted Harmony - A Way Out - 2018\kWlZr0N_o72dwo0_CD001_0001.mp3");
if (file.Exists)
{
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
Assert.True(tagLib.IsSuccess);
var metaData = tagLib.Data;
Assert.NotNull(metaData.Artist);

View file

@ -1,12 +1,5 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Roadie.Library.Configuration;
using Roadie.Library.Data;
using Roadie.Library.Data.Context;
using Roadie.Library.FilePlugins;
using Roadie.Library.Imaging;
using Roadie.Library.Imaging;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Xunit;
@ -38,6 +31,9 @@ namespace Roadie.Library.Tests
[InlineData("logo.png")]
[InlineData("Logo.Jpg")]
[InlineData("logo.gif")]
[InlineData("band_logo.gif")]
[InlineData("134logo.gif")]
[InlineData("Dream_Theater_Logo.gif")]
[InlineData("artist_logo.jpg")]
[InlineData("Artist_logo.jpg")]
[InlineData("ARTIST_LOGO.JPG")]
@ -292,7 +288,7 @@ namespace Roadie.Library.Tests
public void GetReleaseImageInFolder()
{
var folder = new DirectoryInfo(@"C:\roadie_dev_root\image_tests");
if(!folder.Exists)
if (!folder.Exists)
{
Assert.True(true);
return;

View file

@ -23,7 +23,7 @@ namespace Roadie.Library.Tests
{
get
{
return this.MessageLogger as ILogger;
return MessageLogger as ILogger;
}
}
@ -35,8 +35,8 @@ namespace Roadie.Library.Tests
public InspectorTests()
{
this.MessageLogger = new EventMessageLogger<ID3TagsHelperTests>();
this.MessageLogger.Messages += MessageLoggerMessages;
MessageLogger = new EventMessageLogger<ID3TagsHelperTests>();
MessageLogger.Messages += MessageLoggerMessages;
var settings = new configuration.RoadieSettings();
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
@ -44,11 +44,11 @@ namespace Roadie.Library.Tests
IConfiguration configuration = configurationBuilder.Build();
configuration.GetSection("RoadieSettings").Bind(settings);
settings.ConnectionString = configuration.GetConnectionString("RoadieDatabaseConnection");
this.Configuration = settings;
this.CacheManager = new DictionaryCacheManager(this.Logger, new CachePolicy(TimeSpan.FromHours(4)));
Configuration = settings;
CacheManager = new DictionaryCacheManager(Logger, new CachePolicy(TimeSpan.FromHours(4)));
var tagHelperLooper = new EventMessageLogger<ID3TagsHelper>();
tagHelperLooper.Messages += MessageLoggerMessages;
this.TagsHelper = new ID3TagsHelper(this.Configuration, this.CacheManager, tagHelperLooper);
TagsHelper = new ID3TagsHelper(Configuration, CacheManager, tagHelperLooper);
}
private void MessageLoggerMessages(object sender, EventMessage e)

View file

@ -6,10 +6,8 @@ using Roadie.Library.MetaData.MusicBrainz;
using Roadie.Library.Processors;
using Roadie.Library.SearchEngines.MetaData.Discogs;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
@ -50,7 +48,7 @@ namespace Roadie.Library.Tests
[Fact]
public async Task DiscogsHelperReleaseSearch()
{
if(!Configuration.Integrations.DiscogsProviderEnabled)
if (!Configuration.Integrations.DiscogsProviderEnabled)
{
return;
}
@ -62,7 +60,7 @@ namespace Roadie.Library.Tests
var artistName = "With The Dead";
var title = "Love From With The Dead";
var result = await engine.PerformReleaseSearch(artistName, title, 1);
var result = await engine.PerformReleaseSearch(artistName, title, 1).ConfigureAwait(false);
Assert.NotNull(result);
Assert.NotEmpty(result.Data);
@ -84,10 +82,9 @@ namespace Roadie.Library.Tests
var sw = Stopwatch.StartNew();
var result = await mb.PerformArtistSearch(artistName, 1);
var result = await mb.PerformArtistSearchAsync(artistName, 1).ConfigureAwait(false);
sw.Stop();
var elapsedTime = sw.ElapsedMilliseconds;
Assert.NotNull(result);
Assert.NotNull(result.Data);
@ -113,10 +110,9 @@ namespace Roadie.Library.Tests
var title = "Piano Man";
var sw = Stopwatch.StartNew();
var result = await mb.PerformReleaseSearch(artistName, title, 1);
var result = await mb.PerformReleaseSearch(artistName, title, 1).ConfigureAwait(false);
sw.Stop();
var elapsedTime = sw.ElapsedMilliseconds;
Assert.NotNull(result);
Assert.NotNull(result.Data);

View file

@ -12,21 +12,21 @@ namespace Roadie.Library.Tests
{
private readonly IConfiguration _configuration;
private readonly IRoadieSettings _settings = null;
private readonly IRoadieSettings _settings;
private IRoadieSettings Configuration
{
get
{
return this._settings;
return _settings;
}
}
public StringExtensionTests()
{
this._configuration = InitConfiguration();
this._settings = new RoadieSettings();
this._configuration.GetSection("RoadieSettings").Bind(this._settings);
_configuration = InitConfiguration();
_settings = new RoadieSettings();
_configuration.GetSection("RoadieSettings").Bind(_settings);
}
public static IConfiguration InitConfiguration()
@ -102,7 +102,7 @@ namespace Roadie.Library.Tests
public void CleanStringReleaseShouldBeAngie(string input)
{
var r = @"(\s*(-\s)*((CD[_\-#\s]*[0-9]*)))|((\(|\[)+([0-9]|,|self|bonus|re(leas|master|(e|d)*)*|th|anniversary|cd|disc|deluxe|dig(ipack)*|vinyl|japan(ese)*|asian|remastered|limited|ltd|expanded|edition|\s)+(]|\)*))";
var cleaned = input.CleanString(this.Configuration, r);
var cleaned = input.CleanString(Configuration, r);
Assert.Equal("Angie", cleaned);
}

View file

@ -2,6 +2,7 @@
"RoadieSettings": {
"InboundFolder": "C:\\roadie_dev_root\\inbound",
"LibraryFolder": "C:\\\\roadie_dev_root\\\\library",
"SearchEngineReposFolder": "C:\\\\roadie_dev_root\\\\repos",
"Processing": {
"RemoveStringsRegex": "\\b[0-9]+\\s#\\s\\b",
"ReleaseRemoveStringsRegex": "(\\\\s*(-\\\\s)*((CD[_\\-#\\s]*[0-9]*)))|((\\\\(|\\\\[)+([0-9]|,|self|bonus|re(leas|master|(e|d)*)*|th|anniversary|cd|disc|deluxe|dig(ipack)*|vinyl|japan(ese)*|asian|remastered|limited|ltd|expanded|edition|\\\\s)+(]|\\\\)*))",

View file

@ -113,7 +113,7 @@ namespace Roadie.Library.Caching
var r = Get<TOut>(key, region);
if (r == null)
{
r = await getItem();
r = await getItem().ConfigureAwait(false);
Add(key, r, region);
Logger.LogTrace($"-+> Cache Miss for Key [{key}], Region [{region}]");
}

View file

@ -95,7 +95,7 @@ namespace Roadie.Library.Caching
var r = Get<TOut>(key, region);
if (r == null)
{
r = await getItem();
r = await getItem().ConfigureAwait(false);
Add(key, r, region);
Logger.LogTrace($"-+> Cache Miss for Key [{key}], Region [{region}]");
}

View file

@ -5,14 +5,14 @@ namespace Roadie.Library.Data.Context
{
public interface IRoadieDbRandomizer
{
Task<SortedDictionary<int, int>> RandomArtistIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
Task<SortedDictionary<int, int>> RandomArtistIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
Task<SortedDictionary<int, int>> RandomGenreIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
Task<SortedDictionary<int, int>> RandomGenreIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
Task<SortedDictionary<int, int>> RandomLabelIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
Task<SortedDictionary<int, int>> RandomLabelIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
Task<SortedDictionary<int, int>> RandomReleaseIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
Task<SortedDictionary<int, int>> RandomReleaseIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
Task<SortedDictionary<int, int>> RandomTrackIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
Task<SortedDictionary<int, int>> RandomTrackIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
}
}

View file

@ -16,21 +16,21 @@ namespace Roadie.Library.Data.Context.Implementation
{
}
public override async Task<Artist> LastPlayedArtist(int userId)
public override Task<Artist> LastPlayedArtist(int userId)
{
return await (from ut in UserTracks
join t in Tracks on ut.TrackId equals t.Id
join rm in ReleaseMedias on t.ReleaseMediaId equals rm.Id
join r in Releases on rm.ReleaseId equals r.Id
join a in Artists on r.ArtistId equals a.Id
where ut.UserId == userId
orderby ut.LastPlayed descending
select a).FirstOrDefaultAsync();
return (from ut in UserTracks
join t in Tracks on ut.TrackId equals t.Id
join rm in ReleaseMedias on t.ReleaseMediaId equals rm.Id
join r in Releases on rm.ReleaseId equals r.Id
join a in Artists on r.ArtistId equals a.Id
where ut.UserId == userId
orderby ut.LastPlayed descending
select a).FirstOrDefaultAsync();
}
public override async Task<Release> LastPlayedRelease(int userId)
public override Task<Release> LastPlayedRelease(int userId)
{
return await (from ut in UserTracks
return (from ut in UserTracks
join t in Tracks on ut.TrackId equals t.Id
join rm in ReleaseMedias on t.ReleaseMediaId equals rm.Id
join r in Releases on rm.ReleaseId equals r.Id
@ -39,9 +39,9 @@ namespace Roadie.Library.Data.Context.Implementation
select r).FirstOrDefaultAsync();
}
public override async Task<Track> LastPlayedTrack(int userId)
public override Task<Track> LastPlayedTrack(int userId)
{
return await (from ut in UserTracks
return (from ut in UserTracks
join t in Tracks on ut.TrackId equals t.Id
where ut.UserId == userId
orderby ut.LastPlayed descending
@ -50,7 +50,7 @@ namespace Roadie.Library.Data.Context.Implementation
public override async Task<Artist> MostPlayedArtist(int userId)
{
var mostPlayedTrack = await MostPlayedTrack(userId);
var mostPlayedTrack = await MostPlayedTrack(userId).ConfigureAwait(false);
if (mostPlayedTrack != null)
{
return await (from t in Tracks
@ -58,35 +58,35 @@ namespace Roadie.Library.Data.Context.Implementation
join r in Releases on rm.ReleaseId equals r.Id
join a in Artists on r.ArtistId equals a.Id
where t.Id == mostPlayedTrack.Id
select a).FirstOrDefaultAsync();
select a).FirstOrDefaultAsync().ConfigureAwait(false);
}
return null;
}
public override async Task<Release> MostPlayedRelease(int userId)
{
var mostPlayedTrack = await MostPlayedTrack(userId);
var mostPlayedTrack = await MostPlayedTrack(userId).ConfigureAwait(false);
if (mostPlayedTrack != null)
{
return await (from t in Tracks
join rm in ReleaseMedias on t.ReleaseMediaId equals rm.Id
join r in Releases on rm.ReleaseId equals r.Id
where t.Id == mostPlayedTrack.Id
select r).FirstOrDefaultAsync();
select r).FirstOrDefaultAsync().ConfigureAwait(false);
}
return null;
}
public override async Task<Track> MostPlayedTrack(int userId)
public override Task<Track> MostPlayedTrack(int userId)
{
return await (from ut in UserTracks
return (from ut in UserTracks
join t in Tracks on ut.TrackId equals t.Id
where ut.UserId == userId
orderby ut.PlayedCount descending
select t).FirstOrDefaultAsync();
}
public override async Task<SortedDictionary<int, int>> RandomArtistIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
public override async Task<SortedDictionary<int, int>> RandomArtistIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
{
List<Artist> randomArtists = null;
if (doOnlyFavorites)
@ -98,7 +98,7 @@ namespace Roadie.Library.Data.Context.Implementation
select a
).OrderBy(x => Guid.NewGuid())
.Take(randomLimit)
.ToListAsync();
.ToListAsync().ConfigureAwait(false);
}
else if (doOnlyRated)
{
@ -109,7 +109,7 @@ namespace Roadie.Library.Data.Context.Implementation
select a
).OrderBy(x => Guid.NewGuid())
.Take(randomLimit)
.ToListAsync();
.ToListAsync().ConfigureAwait(false);
}
else
{
@ -120,29 +120,29 @@ namespace Roadie.Library.Data.Context.Implementation
select a)
.OrderBy(x => Guid.NewGuid())
.Take(randomLimit)
.ToListAsync();
.ToListAsync().ConfigureAwait(false);
}
var dict = randomArtists.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);
}
public override async Task<SortedDictionary<int, int>> RandomGenreIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
public override async Task<SortedDictionary<int, int>> RandomGenreIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
{
var randomGenres = await Genres.OrderBy(x => Guid.NewGuid())
.Take(randomLimit)
.ToListAsync();
.ToListAsync().ConfigureAwait(false);
var dict = randomGenres.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);
}
public override async Task<SortedDictionary<int, int>> RandomLabelIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
public override async Task<SortedDictionary<int, int>> RandomLabelIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
{
var randomLabels = await Labels.OrderBy(x => Guid.NewGuid()).Take(randomLimit).ToListAsync();
var randomLabels = await Labels.OrderBy(x => Guid.NewGuid()).Take(randomLimit).ToListAsync().ConfigureAwait(false);
var dict = randomLabels.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);
}
public override async Task<SortedDictionary<int, int>> RandomReleaseIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
public override async Task<SortedDictionary<int, int>> RandomReleaseIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
{
List<Release> randomReleases = null;
if (doOnlyFavorites)
@ -154,7 +154,7 @@ namespace Roadie.Library.Data.Context.Implementation
select r
).OrderBy(x => Guid.NewGuid())
.Take(randomLimit)
.ToListAsync();
.ToListAsync().ConfigureAwait(false);
}
else if (doOnlyRated)
{
@ -165,7 +165,7 @@ namespace Roadie.Library.Data.Context.Implementation
select r
).OrderBy(x => Guid.NewGuid())
.Take(randomLimit)
.ToListAsync();
.ToListAsync().ConfigureAwait(false);
}
else
{
@ -176,13 +176,13 @@ namespace Roadie.Library.Data.Context.Implementation
select r)
.OrderBy(x => Guid.NewGuid())
.Take(randomLimit)
.ToListAsync();
.ToListAsync().ConfigureAwait(false);
}
var dict = randomReleases.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);
}
public override async Task<SortedDictionary<int, int>> RandomTrackIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
public override async Task<SortedDictionary<int, int>> RandomTrackIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
{
List<Track> randomTracks = null;
if (doOnlyFavorites)
@ -194,7 +194,7 @@ namespace Roadie.Library.Data.Context.Implementation
select t
).OrderBy(x => Guid.NewGuid())
.Take(randomLimit)
.ToListAsync();
.ToListAsync().ConfigureAwait(false);
}
else if (doOnlyRated)
{
@ -205,7 +205,7 @@ namespace Roadie.Library.Data.Context.Implementation
select t
).OrderBy(x => Guid.NewGuid())
.Take(randomLimit)
.ToListAsync();
.ToListAsync().ConfigureAwait(false);
}
else
{
@ -216,7 +216,7 @@ namespace Roadie.Library.Data.Context.Implementation
select t)
.OrderBy(x => Guid.NewGuid())
.Take(randomLimit)
.ToListAsync();
.ToListAsync().ConfigureAwait(false);
}
var dict = randomTracks.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);

View file

@ -26,7 +26,7 @@ namespace Roadie.Library.Data.Context.Implementation
where ut.userId = {0}
ORDER by ut.lastPlayed desc
LIMIT 1";
return await Artists.FromSqlRaw(sql, userId).FirstOrDefaultAsync();
return await Artists.FromSqlRaw(sql, userId).FirstOrDefaultAsync().ConfigureAwait(false);
}
public override async Task<Release> LastPlayedRelease(int userId)
@ -41,7 +41,8 @@ namespace Roadie.Library.Data.Context.Implementation
LIMIT 1";
return await Releases.FromSqlRaw(sql, userId)
.Include(x => x.Artist)
.FirstOrDefaultAsync();
.FirstOrDefaultAsync()
.ConfigureAwait(false);
}
public override async Task<Track> LastPlayedTrack(int userId)
@ -57,7 +58,8 @@ namespace Roadie.Library.Data.Context.Implementation
.Include(x => x.ReleaseMedia)
.Include("ReleaseMedia.Release")
.Include("ReleaseMedia.Release.Artist")
.FirstOrDefaultAsync();
.FirstOrDefaultAsync()
.ConfigureAwait(false);
}
public override async Task<Artist> MostPlayedArtist(int userId)
@ -72,7 +74,7 @@ namespace Roadie.Library.Data.Context.Implementation
group by r.id
order by SUM(ut.playedCount) desc
LIMIT 1";
return await Artists.FromSqlRaw(sql, userId).FirstOrDefaultAsync();
return await Artists.FromSqlRaw(sql, userId).FirstOrDefaultAsync().ConfigureAwait(false);
}
public override async Task<Release> MostPlayedRelease(int userId)
@ -88,7 +90,8 @@ namespace Roadie.Library.Data.Context.Implementation
LIMIT 1";
return await Releases.FromSqlRaw(sql, userId)
.Include(x => x.Artist)
.FirstOrDefaultAsync();
.FirstOrDefaultAsync()
.ConfigureAwait(false);
}
public override async Task<Track> MostPlayedTrack(int userId)
@ -105,10 +108,11 @@ namespace Roadie.Library.Data.Context.Implementation
.Include(x => x.ReleaseMedia)
.Include("ReleaseMedia.Release")
.Include("ReleaseMedia.Release.Artist")
.FirstOrDefaultAsync();
.FirstOrDefaultAsync()
.ConfigureAwait(false);
}
public override async Task<SortedDictionary<int, int>> RandomArtistIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
public override async Task<SortedDictionary<int, int>> RandomArtistIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
{
var sql = @"SELECT a.id
FROM `artist` a
@ -117,34 +121,34 @@ namespace Roadie.Library.Data.Context.Implementation
AND {2} = 1)
order BY RIGHT(HEX((1 << 24) * (1 + RAND())), 6)
LIMIT 0, {0}";
var ids = await Artists.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToListAsync();
var ids = await Artists.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToListAsync().ConfigureAwait(false);
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);
}
public override async Task<SortedDictionary<int, int>> RandomGenreIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
public override async Task<SortedDictionary<int, int>> RandomGenreIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
{
var sql = @"SELECT g.id
FROM `genre` g
ORDER BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
LIMIT 0, {0}";
var ids = await Genres.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync();
var ids = await Genres.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync().ConfigureAwait(false);
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);
}
public override async Task<SortedDictionary<int, int>> RandomLabelIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
public override async Task<SortedDictionary<int, int>> RandomLabelIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
{
var sql = @"SELECT l.id
FROM `label` l
ORDER BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
LIMIT 0, {0}";
var ids = await Labels.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync();
var ids = await Labels.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync().ConfigureAwait(false);
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);
}
public override async Task<SortedDictionary<int, int>> RandomReleaseIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
public override async Task<SortedDictionary<int, int>> RandomReleaseIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
{
var sql = @"SELECT r.id
FROM `release` r
@ -153,12 +157,12 @@ namespace Roadie.Library.Data.Context.Implementation
AND {2} = 1)
ORDER BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
LIMIT 0, {0}";
var ids = await Releases.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToListAsync();
var ids = await Releases.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToListAsync().ConfigureAwait(false);
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);
}
public override async Task<SortedDictionary<int, int>> RandomTrackIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
public override async Task<SortedDictionary<int, int>> RandomTrackIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
{
var sql = @"SELECT t.id
FROM `track` t
@ -194,7 +198,7 @@ namespace Roadie.Library.Data.Context.Implementation
WHERE ut.userId = {1} AND ut.isFavorite = 1) AND {2} = 1) OR {2} = 0)
order BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
LIMIT 0, {0}";
var ids = await Tracks.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0", doOnlyRated ? "1" : "0").Select(x => x.Id).ToListAsync();
var ids = await Tracks.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0", doOnlyRated ? "1" : "0").Select(x => x.Id).ToListAsync().ConfigureAwait(false);
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);
}

View file

@ -22,7 +22,7 @@ namespace Roadie.Library.Data.Context.Implementation
}
}
public override async Task<SortedDictionary<int, int>> RandomArtistIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
public override async Task<SortedDictionary<int, int>> RandomArtistIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
{
// TODO Rating?
var sql = @"SELECT a.id
@ -32,34 +32,34 @@ namespace Roadie.Library.Data.Context.Implementation
AND {2} = 1)
order by random()
LIMIT 0, {0}";
var ids = await Artists.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToListAsync();
var ids = await Artists.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToListAsync().ConfigureAwait(false);
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);
}
public override async Task<SortedDictionary<int, int>> RandomGenreIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
public override async Task<SortedDictionary<int, int>> RandomGenreIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
{
var sql = @"SELECT g.id
FROM genre g
order by random()
LIMIT 0, {0}";
var ids = await Genres.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync();
var ids = await Genres.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync().ConfigureAwait(false);
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);
}
public override async Task<SortedDictionary<int, int>> RandomLabelIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
public override async Task<SortedDictionary<int, int>> RandomLabelIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
{
var sql = @"SELECT l.id
FROM label l
order by random()
LIMIT 0, {0}";
var ids = await Labels.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync();
var ids = await Labels.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync().ConfigureAwait(false);
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);
}
public override async Task<SortedDictionary<int, int>> RandomReleaseIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
public override async Task<SortedDictionary<int, int>> RandomReleaseIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
{
// TODO Rating?
var sql = @"SELECT r.id
@ -69,12 +69,12 @@ namespace Roadie.Library.Data.Context.Implementation
AND {2} = 1)
order by random()
LIMIT 0, {0}";
var ids = await Releases.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToListAsync();
var ids = await Releases.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToListAsync().ConfigureAwait(false);
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);
}
public override async Task<SortedDictionary<int, int>> RandomTrackIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
public override async Task<SortedDictionary<int, int>> RandomTrackIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
{
// When using the regular 'FromSqlRaw' with parameters SQLite returns no records.
@ -103,7 +103,7 @@ namespace Roadie.Library.Data.Context.Implementation
WHERE ut.userId = {userId} AND ut.isFavorite = 1) AND {df} = 1) OR {df} = 0)
order by random()
LIMIT 0, {randomLimit}";
var ids = await Tracks.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync();
var ids = await Tracks.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync().ConfigureAwait(false);
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);
}

View file

@ -6,15 +6,15 @@ namespace Roadie.Library.Data.Context
{
public abstract partial class RoadieDbContext : DbContext, IRoadieDbContext
{
public abstract Task<SortedDictionary<int, int>> RandomArtistIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
public abstract Task<SortedDictionary<int, int>> RandomArtistIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
public abstract Task<SortedDictionary<int, int>> RandomGenreIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
public abstract Task<SortedDictionary<int, int>> RandomGenreIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
public abstract Task<SortedDictionary<int, int>> RandomLabelIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
public abstract Task<SortedDictionary<int, int>> RandomLabelIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
public abstract Task<SortedDictionary<int, int>> RandomReleaseIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
public abstract Task<SortedDictionary<int, int>> RandomReleaseIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
public abstract Task<SortedDictionary<int, int>> RandomTrackIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
public abstract Task<SortedDictionary<int, int>> RandomTrackIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
public abstract Task<Artist> MostPlayedArtist(int userId);

View file

@ -349,7 +349,7 @@ namespace Roadie.Library.Engines
if (ITunesArtistSearchEngine.IsEnabled)
{
var sw2 = Stopwatch.StartNew();
var iTunesResult = await ITunesArtistSearchEngine.PerformArtistSearch(artistName, 1).ConfigureAwait(false);
var iTunesResult = await ITunesArtistSearchEngine.PerformArtistSearchAsync(artistName, 1).ConfigureAwait(false);
if (iTunesResult.IsSuccess)
{
var i = iTunesResult.Data.First();
@ -406,7 +406,7 @@ namespace Roadie.Library.Engines
if (MusicBrainzArtistSearchEngine.IsEnabled)
{
var sw2 = Stopwatch.StartNew();
var mbResult = await MusicBrainzArtistSearchEngine.PerformArtistSearch(result.Name, 1).ConfigureAwait(false);
var mbResult = await MusicBrainzArtistSearchEngine.PerformArtistSearchAsync(result.Name, 1).ConfigureAwait(false);
if (mbResult.IsSuccess)
{
var mb = mbResult.Data.First();
@ -471,7 +471,7 @@ namespace Roadie.Library.Engines
if (LastFmArtistSearchEngine.IsEnabled)
{
var sw2 = Stopwatch.StartNew();
var lastFmResult = await LastFmArtistSearchEngine.PerformArtistSearch(result.Name, 1).ConfigureAwait(false);
var lastFmResult = await LastFmArtistSearchEngine.PerformArtistSearchAsync(result.Name, 1).ConfigureAwait(false);
if (lastFmResult.IsSuccess)
{
var l = lastFmResult.Data.First();
@ -515,7 +515,7 @@ namespace Roadie.Library.Engines
if (SpotifyArtistSearchEngine.IsEnabled)
{
var sw2 = Stopwatch.StartNew();
var spotifyResult = await SpotifyArtistSearchEngine.PerformArtistSearch(result.Name, 1).ConfigureAwait(false);
var spotifyResult = await SpotifyArtistSearchEngine.PerformArtistSearchAsync(result.Name, 1).ConfigureAwait(false);
if (spotifyResult.IsSuccess)
{
var s = spotifyResult.Data.First();
@ -557,7 +557,7 @@ namespace Roadie.Library.Engines
if (DiscogsArtistSearchEngine.IsEnabled)
{
var sw2 = Stopwatch.StartNew();
var discogsResult = await DiscogsArtistSearchEngine.PerformArtistSearch(result.Name, 1).ConfigureAwait(false);
var discogsResult = await DiscogsArtistSearchEngine.PerformArtistSearchAsync(result.Name, 1).ConfigureAwait(false);
if (discogsResult.IsSuccess)
{
var d = discogsResult?.Data?.FirstOrDefault();
@ -614,7 +614,7 @@ namespace Roadie.Library.Engines
{
wikiName += " band";
}
var wikipediaResult = await WikipediaArtistSearchEngine.PerformArtistSearch(wikiName, 1).ConfigureAwait(false);
var wikipediaResult = await WikipediaArtistSearchEngine.PerformArtistSearchAsync(wikiName, 1).ConfigureAwait(false);
if (wikipediaResult?.Data != null)
{
if (wikipediaResult.IsSuccess)

View file

@ -455,7 +455,7 @@ namespace Roadie.Library.Engines
{
var sw2 = Stopwatch.StartNew();
Logger.LogTrace("ITunesReleaseSearchEngine Release Search for ArtistName [{0}], ReleaseTitle [{1}]", metaData.Artist, result.Title);
var iTunesResult = await ITunesReleaseSearchEngine.PerformReleaseSearch(metaData.Artist, result.Title, 1);
var iTunesResult = await ITunesReleaseSearchEngine.PerformReleaseSearch(metaData.Artist, result.Title, 1).ConfigureAwait(false);
if (iTunesResult.IsSuccess)
{
var i = iTunesResult.Data.First();

View file

@ -26,24 +26,23 @@ namespace Roadie.Library.Imaging
public static byte[] ConvertToJpegFormat(byte[] imageBytes)
{
if (imageBytes == null || !imageBytes.Any())
if(imageBytes?.Any() != true)
{
return null;
}
try
{
using (var outStream = new MemoryStream())
using(var outStream = new MemoryStream())
{
IImageFormat imageFormat = null;
using (var image = SixLabors.ImageSharp.Image.Load(imageBytes, out imageFormat))
using(var image = SixLabors.ImageSharp.Image.Load(imageBytes, out imageFormat))
{
image.SaveAsJpeg(outStream);
}
return outStream.ToArray();
}
}
catch (Exception ex)
} catch(Exception ex)
{
Trace.WriteLine($"Error Converting Image to Jpg [{ ex.Message }]", "Warning");
}
@ -55,44 +54,48 @@ namespace Roadie.Library.Imaging
/// </summary>
public static byte[] ConvertToGifFormat(byte[] imageBytes)
{
if (imageBytes == null || !imageBytes.Any())
if(imageBytes?.Any() != true)
{
return null;
}
try
{
using (var outStream = new MemoryStream())
using(var outStream = new MemoryStream())
{
IImageFormat imageFormat = null;
using (var image = SixLabors.ImageSharp.Image.Load(imageBytes, out imageFormat))
using(var image = SixLabors.ImageSharp.Image.Load(imageBytes, out imageFormat))
{
image.SaveAsGif(outStream);
}
return outStream.ToArray();
}
}
catch (Exception ex)
} catch(Exception ex)
{
Trace.WriteLine($"Error Converting Image to Gif [{ ex.Message }]", "Warning");
}
return null;
}
public static IEnumerable<FileInfo> FindImagesByName(DirectoryInfo directory, string name, SearchOption folderSearchOptions = SearchOption.AllDirectories)
public static IEnumerable<FileInfo> FindImagesByName(DirectoryInfo directory,
string name,
SearchOption folderSearchOptions = SearchOption.AllDirectories)
{
var result = new List<FileInfo>();
if (directory == null || !directory.Exists || string.IsNullOrEmpty(name)) return result;
if(directory?.Exists != true || string.IsNullOrEmpty(name))
return result;
var imageFilesInFolder = ImageFilesInFolder(directory.FullName, folderSearchOptions);
if (imageFilesInFolder == null || !imageFilesInFolder.Any()) return result;
if (imageFilesInFolder.Any())
if(imageFilesInFolder?.Any() != true)
return result;
if(imageFilesInFolder.Length > 0)
{
name = name.ToAlphanumericName();
foreach (var imageFileInFolder in imageFilesInFolder)
foreach(var imageFileInFolder in imageFilesInFolder)
{
var image = new FileInfo(imageFileInFolder);
var filenameWithoutExtension = Path.GetFileName(imageFileInFolder).ToAlphanumericName();
var imageName = image.Name.ToAlphanumericName();
if (imageName.Equals(name) || filenameWithoutExtension.Equals(name)) result.Add(image);
if(imageName.Equals(name) || filenameWithoutExtension.Equals(name))
result.Add(image);
}
}
@ -107,77 +110,102 @@ namespace Roadie.Library.Imaging
}
try
{
if (string.IsNullOrEmpty(image1) || !File.Exists(image1))
if(string.IsNullOrEmpty(image1) || !File.Exists(image1))
{
return File.Exists(compareToImage);
}
using (var imageComparing = SixLabors.ImageSharp.Image.Load(image1))
using(var imageComparing = SixLabors.ImageSharp.Image.Load(image1))
{
using (var imageToCompare = SixLabors.ImageSharp.Image.Load(compareToImage))
using(var imageToCompare = SixLabors.ImageSharp.Image.Load(compareToImage))
{
// Generally a larger image is the preferred image
var isBigger = imageToCompare.Height > imageComparing.Height && imageToCompare.Width > imageComparing.Width;
if (isBigger)
var isBigger = imageToCompare.Height > imageComparing.Height &&
imageToCompare.Width > imageComparing.Width;
if(isBigger)
{
return true;
}
}
}
}
catch (Exception ex)
} catch(Exception ex)
{
Trace.WriteLine($"Error IsImageBetterQuality Image Comparing [{ image1 }] to [{ compareToImage }], Error [{ ex }]", "Warning");
Trace.WriteLine($"Error IsImageBetterQuality Image Comparing [{ image1 }] to [{ compareToImage }], Error [{ ex }]",
"Warning");
}
return false;
}
public static IEnumerable<FileInfo> FindImageTypeInDirectory(DirectoryInfo directory, ImageType type, SearchOption folderSearchOptions = SearchOption.AllDirectories)
public static IEnumerable<FileInfo> FindImageTypeInDirectory(DirectoryInfo directory,
ImageType type,
SearchOption folderSearchOptions = SearchOption.AllDirectories)
{
var result = new List<FileInfo>();
if (directory == null || !directory.Exists) return result;
if (directory?.Exists != true)
{
return result;
}
var imageFilesInFolder = ImageFilesInFolder(directory.FullName, folderSearchOptions);
if (imageFilesInFolder == null || !imageFilesInFolder.Any()) return result;
foreach (var imageFile in imageFilesInFolder)
if (imageFilesInFolder?.Any() != true)
{
return result;
}
foreach(var imageFile in imageFilesInFolder)
{
var image = new FileInfo(imageFile);
switch (type)
switch(type)
{
case ImageType.Artist:
if (IsArtistImage(image)) result.Add(image);
if (IsArtistImage(image))
{
result.Add(image);
}
break;
case ImageType.ArtistSecondary:
if (IsArtistSecondaryImage(image)) result.Add(image);
if (IsArtistSecondaryImage(image))
{
result.Add(image);
}
break;
case ImageType.Release:
if (IsReleaseImage(image)) result.Add(image);
if (IsReleaseImage(image))
{
result.Add(image);
}
break;
case ImageType.ReleaseSecondary:
if (IsReleaseSecondaryImage(image)) result.Add(image);
if (IsReleaseSecondaryImage(image))
{
result.Add(image);
}
break;
case ImageType.Label:
if (IsLabelImage(image)) result.Add(image);
if (IsLabelImage(image))
{
result.Add(image);
}
break;
}
}
return result.OrderBy(x => x.Name);
}
public static string[] GetFiles(string path, string[] patterns = null, SearchOption options = SearchOption.TopDirectoryOnly)
public static string[] GetFiles(string path,
string[] patterns = null,
SearchOption options = SearchOption.TopDirectoryOnly)
{
if (!Directory.Exists(path))
if(!Directory.Exists(path))
{
return new string[0];
}
if (patterns == null || patterns.Length == 0)
if(patterns == null || patterns.Length == 0)
{
return Directory.GetFiles(path, "*", options);
}
if (patterns.Length == 1)
if(patterns.Length == 1)
{
return Directory.GetFiles(path, patterns[0], options);
}
@ -186,9 +214,10 @@ namespace Roadie.Library.Imaging
public static byte[] ImageDataFromUrl(string imageUrl)
{
if (!string.IsNullOrEmpty(imageUrl) && !imageUrl.StartsWith("http", StringComparison.OrdinalIgnoreCase))
if(!string.IsNullOrEmpty(imageUrl) && !imageUrl.StartsWith("http", StringComparison.OrdinalIgnoreCase))
{
var dataString = imageUrl.Trim().Replace('-', '+')
var dataString = imageUrl.Trim()
.Replace('-', '+')
.Replace("data:image/jpeg;base64,", "")
.Replace("data:image/bmp;base64,", "")
.Replace("data:image/gif;base64,", "")
@ -200,27 +229,22 @@ namespace Roadie.Library.Imaging
}
public static string[] ImageExtensions()
{
return new string[6] { "*.bmp", "*.jpeg", "*.jpe", "*.jpg", "*.png", "*.gif" };
}
{ return new string[6] { "*.bmp", "*.jpeg", "*.jpe", "*.jpg", "*.png", "*.gif" }; }
public static string[] ImageFilesInFolder(string folder, SearchOption searchOption)
{
return GetFiles(folder, ImageExtensions(), searchOption);
}
{ return GetFiles(folder, ImageExtensions(), searchOption); }
public static string[] ImageMimeTypes()
{
return new string[4] { "image/bmp", "image/jpeg", "image/png", "image/gif" };
}
{ return new string[4] { "image/bmp", "image/jpeg", "image/png", "image/gif" }; }
public static ImageSearchResult ImageSearchResultForImageUrl(string imageUrl)
{
if (!WebHelper.IsStringUrl(imageUrl)) return null;
if(!WebHelper.IsStringUrl(imageUrl))
return null;
var result = new ImageSearchResult();
var imageBytes = WebHelper.BytesForImageUrl(imageUrl);
IImageFormat imageFormat = null;
using (var image = SixLabors.ImageSharp.Image.Load(imageBytes, out imageFormat))
using(var image = SixLabors.ImageSharp.Image.Load(imageBytes, out imageFormat))
{
result.Height = image.Height.ToString();
result.Width = image.Width.ToString();
@ -232,43 +256,54 @@ namespace Roadie.Library.Imaging
public static bool IsArtistImage(FileInfo fileinfo)
{
if (fileinfo == null) return false;
return Regex.IsMatch(fileinfo.Name, @"(band|artist|group|photo)\.(jpg|jpeg|png|bmp|gif)",
RegexOptions.IgnoreCase);
if(fileinfo == null)
return false;
return Regex.IsMatch(fileinfo.Name,
@"(band|artist|group|photo)\.(jpg|jpeg|png|bmp|gif)",
RegexOptions.IgnoreCase);
}
public static bool IsArtistSecondaryImage(FileInfo fileinfo)
{
if (fileinfo == null) return false;
if(fileinfo == null)
return false;
return Regex.IsMatch(fileinfo.Name,
@"(artist_logo|logo|photo[-_\s]*[0-9]+|(artist[\s_-]+[0-9]+)|(band[\s_-]+[0-9]+))\.(jpg|jpeg|png|bmp|gif)",
RegexOptions.IgnoreCase);
@"(artist_logo|logo|photo[-_\s]*[0-9]+|(artist[\s_-]+[0-9]+)|(band[\s_-]+[0-9]+))\.(jpg|jpeg|png|bmp|gif)",
RegexOptions.IgnoreCase);
}
public static bool IsLabelImage(FileInfo fileinfo)
{
if (fileinfo == null) return false;
return Regex.IsMatch(fileinfo.Name, @"(label|recordlabel|record_label)\.(jpg|jpeg|png|bmp|gif)",
RegexOptions.IgnoreCase);
if(fileinfo == null)
return false;
return Regex.IsMatch(fileinfo.Name,
@"(label|recordlabel|record_label)\.(jpg|jpeg|png|bmp|gif)",
RegexOptions.IgnoreCase);
}
public static bool IsReleaseImage(FileInfo fileinfo, string releaseName = null)
{
if (fileinfo == null) return false;
if(fileinfo == null)
return false;
return Regex.IsMatch(fileinfo.Name,
@"((f[-_\s]*[0-9]*)|00|art|big[art]*|cover|cvr|folder|release|front[-_\s]*)\.(jpg|jpeg|png|bmp|gif)",
RegexOptions.IgnoreCase);
@"((f[-_\s]*[0-9]*)|00|art|big[art]*|cover|cvr|folder|release|front[-_\s]*)\.(jpg|jpeg|png|bmp|gif)",
RegexOptions.IgnoreCase);
}
public static bool IsReleaseSecondaryImage(FileInfo fileinfo)
{
if (fileinfo == null) return false;
if(fileinfo == null)
return false;
return Regex.IsMatch(fileinfo.Name,
@"((img[\s-_]*[0-9]*[\s-_]*[0-9]*)|(book[let]*[#-_\s(]*[0-9]*-*[0-9]*(\))*)|(encartes[-_\s]*[(]*[0-9]*[)]*)|sc[an]*(.)?[0-9]*|matrix(.)?[0-9]*|(cover[\s_-]*[0-9]+)|back|traycard|jewel case|disc|(.*)[in]*side(.*)|in([side|lay|let|site])*[0-9]*|digipack.?\[?\(?([0-9]*)\]?\)?|cd.?\[?\(?([0-9]*)\]?\)?|(release[\s_-]+[0-9]+))\.(jpg|jpeg|png|bmp|gif)",
RegexOptions.IgnoreCase);
@"((img[\s-_]*[0-9]*[\s-_]*[0-9]*)|(book[let]*[#-_\s(]*[0-9]*-*[0-9]*(\))*)|(encartes[-_\s]*[(]*[0-9]*[)]*)|sc[an]*(.)?[0-9]*|matrix(.)?[0-9]*|(cover[\s_-]*[0-9]+)|back|traycard|jewel case|disc|(.*)[in]*side(.*)|in([side|lay|let|site])*[0-9]*|digipack.?\[?\(?([0-9]*)\]?\)?|cd.?\[?\(?([0-9]*)\]?\)?|(release[\s_-]+[0-9]+))\.(jpg|jpeg|png|bmp|gif)",
RegexOptions.IgnoreCase);
}
public static byte[] ResizeImage(byte[] imageBytes, int width, int height) => ImageHelper.ResizeImage(imageBytes, width, height, false).Item2;
public static byte[] ResizeImage(byte[] imageBytes, int width, int height) => ImageHelper.ResizeImage(imageBytes,
width,
height,
false)
.Item2;
/// <summary>
/// Resize a given image to given dimensions if needed
@ -278,38 +313,39 @@ namespace Roadie.Library.Imaging
/// <param name="height">Resize to height</param>
/// <param name="forceResize">Force resize</param>
/// <returns>Tuple with bool for did resize and byte array of image</returns>
public static Tuple<bool, byte[]> ResizeImage(byte[] imageBytes, int width, int height, bool? forceResize = false)
public static Tuple<bool, byte[]> ResizeImage(byte[] imageBytes,
int width,
int height,
bool? forceResize = false)
{
if (imageBytes == null)
if(imageBytes == null)
{
return null;
}
try
{
using (var outStream = new MemoryStream())
using(var outStream = new MemoryStream())
{
var resized = false;
IImageFormat imageFormat = null;
using (var image = SixLabors.ImageSharp.Image.Load(imageBytes, out imageFormat))
using(var image = SixLabors.ImageSharp.Image.Load(imageBytes, out imageFormat))
{
var doForce = forceResize ?? false;
if (doForce || image.Width > width || image.Height > height)
if(doForce || image.Width > width || image.Height > height)
{
int newWidth, newHeight;
if (doForce)
if(doForce)
{
newWidth = width;
newHeight = height;
}
else
} else
{
float aspect = image.Width / (float)image.Height;
if (aspect < 1)
if(aspect < 1)
{
newWidth = (int)(width * aspect);
newHeight = (int)(newWidth / aspect);
}
else
} else
{
newHeight = (int)(height / aspect);
newWidth = (int)(newHeight * aspect);
@ -322,8 +358,7 @@ namespace Roadie.Library.Imaging
}
return new Tuple<bool, byte[]>(resized, outStream.ToArray());
}
}
catch (Exception ex)
} catch(Exception ex)
{
Trace.WriteLine($"Error Resizing Image [{ex}]", "Warning");
}
@ -331,12 +366,13 @@ namespace Roadie.Library.Imaging
}
/// <summary>
/// Get image data from all sources for either fileanme or MetaData
/// Get image data from all sources for either fileanme or MetaData
/// </summary>
/// <param name="filename">Name of the File (ie a CUE file)</param>
/// <param name="metaData">Populated MetaData</param>
/// <returns></returns>
public static AudioMetaDataImage GetPictureForMetaData(IRoadieSettings configuration, string filename, AudioMetaData metaData)
public static AudioMetaDataImage GetPictureForMetaData(IRoadieSettings configuration,
string filename,
AudioMetaData metaData)
{
SimpleContract.Requires<ArgumentException>(!string.IsNullOrEmpty(filename), "Invalid Filename");
SimpleContract.Requires<ArgumentException>(metaData != null, "Invalid MetaData");
@ -345,7 +381,7 @@ namespace Roadie.Library.Imaging
}
/// <summary>
/// Does image exist with the same filename
/// Does image exist with the same filename
/// </summary>
/// <param name="filename">Name of the File (ie a CUE file)</param>
/// <returns>Null if not found else populated image</returns>
@ -353,7 +389,7 @@ namespace Roadie.Library.Imaging
{
AudioMetaDataImage imageMetaData = null;
if (string.IsNullOrEmpty(filename))
if(string.IsNullOrEmpty(filename))
{
return imageMetaData;
}
@ -361,9 +397,9 @@ namespace Roadie.Library.Imaging
{
var fileInfo = new FileInfo(filename);
var ReleaseCover = Path.ChangeExtension(filename, "jpg");
if (File.Exists(ReleaseCover))
if(File.Exists(ReleaseCover))
{
using (var processor = new ImageProcessor(configuration))
using(var processor = new ImageProcessor(configuration))
{
imageMetaData = new AudioMetaDataImage
{
@ -372,24 +408,23 @@ namespace Roadie.Library.Imaging
MimeType = Library.Processors.FileProcessor.DetermineFileType(fileInfo)
};
}
}
else
} else
{
// Is there a picture in filename folder (for the Release)
var pictures = fileInfo.Directory.GetFiles("*.jpg");
var tagImages = new List<AudioMetaDataImage>();
if (pictures != null && pictures.Any())
if(pictures?.Any() == true)
{
FileInfo picture = null;
// See if there is a "cover" or "front" jpg file if so use it
picture = pictures.FirstOrDefault(x =>
x.Name.Equals("cover", StringComparison.OrdinalIgnoreCase));
if (picture == null)
picture = pictures.FirstOrDefault(x =>
x.Name.Equals("front", StringComparison.OrdinalIgnoreCase));
if (picture == null) picture = pictures.First();
if (picture != null)
using (var processor = new ImageProcessor(configuration))
FileInfo picture = Array.Find(pictures,
x => x.Name.Equals("cover", StringComparison.OrdinalIgnoreCase));
if(picture == null)
picture = Array.Find(pictures,
x => x.Name.Equals("front", StringComparison.OrdinalIgnoreCase));
if(picture == null)
picture = pictures[0];
if(picture != null)
using(var processor = new ImageProcessor(configuration))
{
imageMetaData = new AudioMetaDataImage
{
@ -400,11 +435,9 @@ namespace Roadie.Library.Imaging
}
}
}
}
catch (FileNotFoundException)
} catch(FileNotFoundException)
{
}
catch (Exception ex)
} catch(Exception ex)
{
Trace.WriteLine(ex, ex.Serialize());
}
@ -412,97 +445,138 @@ namespace Roadie.Library.Imaging
return imageMetaData;
}
public static models.Image MakeThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, string type, int? width = null, int? height = null, bool includeCachebuster = false)
public static models.Image MakeThumbnailImage(IRoadieSettings configuration,
IHttpContext httpContext,
Guid id,
string type,
int? width = null,
int? height = null,
bool includeCachebuster = false)
{
return MakeImage(configuration, httpContext, id, type, width ?? configuration.ThumbnailImageSize.Width, height ?? configuration.ThumbnailImageSize.Height, null, includeCachebuster);
return MakeImage(configuration,
httpContext,
id,
type,
width ?? configuration.ThumbnailImageSize.Width,
height ?? configuration.ThumbnailImageSize.Height,
null,
includeCachebuster);
}
public static models.Image MakeNewImage(IHttpContext httpContext, string type)
{
return new models.Image($"{httpContext.ImageBaseUrl}/{type}.jpg", null, null);
}
{ return new models.Image($"{httpContext.ImageBaseUrl}/{type}.jpg", null, null); }
public static models.Image MakePlaylistThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
{
return MakeThumbnailImage(configuration, httpContext, id, "playlist");
}
public static models.Image MakePlaylistThumbnailImage(IRoadieSettings configuration,
IHttpContext httpContext,
Guid id)
{ return MakeThumbnailImage(configuration, httpContext, id, "playlist"); }
public static models.Image MakeReleaseThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
{
return MakeThumbnailImage(configuration, httpContext, id, "release");
}
public static models.Image MakeReleaseThumbnailImage(IRoadieSettings configuration,
IHttpContext httpContext,
Guid id)
{ return MakeThumbnailImage(configuration, httpContext, id, "release"); }
public static models.Image MakeTrackThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
{
return MakeThumbnailImage(configuration, httpContext, id, "track");
}
public static models.Image MakeTrackThumbnailImage(IRoadieSettings configuration,
IHttpContext httpContext,
Guid id)
{ return MakeThumbnailImage(configuration, httpContext, id, "track"); }
public static models.Image MakeUserThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
{
return MakeThumbnailImage(configuration, httpContext, id, "user");
}
public static models.Image MakeUserThumbnailImage(IRoadieSettings configuration,
IHttpContext httpContext,
Guid id)
{ return MakeThumbnailImage(configuration, httpContext, id, "user"); }
public static models.Image MakeLabelThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
{
return MakeThumbnailImage(configuration, httpContext, id, "label");
}
public static models.Image MakeLabelThumbnailImage(IRoadieSettings configuration,
IHttpContext httpContext,
Guid id)
{ return MakeThumbnailImage(configuration, httpContext, id, "label"); }
public static models.Image MakeArtistThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid? id)
public static models.Image MakeArtistThumbnailImage(IRoadieSettings configuration,
IHttpContext httpContext,
Guid? id)
{
if (!id.HasValue) return null;
if(!id.HasValue)
return null;
return MakeThumbnailImage(configuration, httpContext, id.Value, "artist");
}
public static models.Image MakeCollectionThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
public static models.Image MakeCollectionThumbnailImage(IRoadieSettings configuration,
IHttpContext httpContext,
Guid id)
{ return MakeThumbnailImage(configuration, httpContext, id, "collection"); }
public static models.Image MakeFullsizeImage(IRoadieSettings configuration,
IHttpContext httpContext,
Guid id,
string caption = null)
{
return MakeThumbnailImage(configuration, httpContext, id, "collection");
return new models.Image($"{httpContext.ImageBaseUrl}/{id}",
caption,
$"{httpContext.ImageBaseUrl}/{id}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
}
public static models.Image MakeFullsizeImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, string caption = null)
public static models.Image MakeFullsizeSecondaryImage(IRoadieSettings configuration,
IHttpContext httpContext,
Guid id,
ImageType type,
int imageId,
string caption = null)
{
return new models.Image($"{httpContext.ImageBaseUrl}/{id}", caption,
$"{httpContext.ImageBaseUrl}/{id}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
}
public static models.Image MakeFullsizeSecondaryImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, ImageType type, int imageId, string caption = null)
{
if (type == ImageType.ArtistSecondary)
if(type == ImageType.ArtistSecondary)
{
return new models.Image($"{httpContext.ImageBaseUrl}/artist-secondary/{id}/{imageId}", caption, $"{httpContext.ImageBaseUrl}/artist-secondary/{id}/{imageId}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
return new models.Image($"{httpContext.ImageBaseUrl}/artist-secondary/{id}/{imageId}",
caption,
$"{httpContext.ImageBaseUrl}/artist-secondary/{id}/{imageId}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
}
return new models.Image($"{httpContext.ImageBaseUrl}/release-secondary/{id}/{imageId}", caption, $"{httpContext.ImageBaseUrl}/release-secondary/{id}/{imageId}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
return new models.Image($"{httpContext.ImageBaseUrl}/release-secondary/{id}/{imageId}",
caption,
$"{httpContext.ImageBaseUrl}/release-secondary/{id}/{imageId}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
}
public static models.Image MakeGenreThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
{
return MakeThumbnailImage(configuration, httpContext, id, "genre");
}
public static models.Image MakeGenreThumbnailImage(IRoadieSettings configuration,
IHttpContext httpContext,
Guid id)
{ return MakeThumbnailImage(configuration, httpContext, id, "genre"); }
public static models.Image MakeUnknownImage(IHttpContext httpContext, string unknownType = "unknown")
{
return new models.Image($"{httpContext.ImageBaseUrl}/{ unknownType }.jpg");
}
{ return new models.Image($"{httpContext.ImageBaseUrl}/{ unknownType }.jpg"); }
public static models.Image MakeImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, int width = 200, int height = 200, string caption = null, bool includeCachebuster = false)
public static models.Image MakeImage(IRoadieSettings configuration,
IHttpContext httpContext,
Guid id,
int width = 200,
int height = 200,
string caption = null,
bool includeCachebuster = false)
{
return new models.Image($"{httpContext.ImageBaseUrl}/{id}/{width}/{height}/{(includeCachebuster ? DateTime.UtcNow.Ticks.ToString() : string.Empty)}",
caption,
$"{httpContext.ImageBaseUrl}/{id}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
caption,
$"{httpContext.ImageBaseUrl}/{id}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
}
public static models.Image MakeImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, string type, IImageSize imageSize)
{
return MakeImage(configuration, httpContext, id, type, imageSize.Width, imageSize.Height);
}
public static models.Image MakeImage(IRoadieSettings configuration,
IHttpContext httpContext,
Guid id,
string type,
IImageSize imageSize)
{ return MakeImage(configuration, httpContext, id, type, imageSize.Width, imageSize.Height); }
public static models.Image MakeImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, string type, int? width, int? height, string caption = null, bool includeCachebuster = false)
public static models.Image MakeImage(IRoadieSettings configuration,
IHttpContext httpContext,
Guid id,
string type,
int? width,
int? height,
string caption = null,
bool includeCachebuster = false)
{
if (width.HasValue && height.HasValue && (width.Value != configuration.ThumbnailImageSize.Width ||
height.Value != configuration.ThumbnailImageSize.Height))
return new models.Image(
$"{httpContext.ImageBaseUrl}/{type}/{id}/{width}/{height}/{(includeCachebuster ? DateTime.UtcNow.Ticks.ToString() : string.Empty)}",
caption,
$"{httpContext.ImageBaseUrl}/{type}/{id}/{configuration.ThumbnailImageSize.Width}/{configuration.ThumbnailImageSize.Height}");
if(width.HasValue &&
height.HasValue &&
(width.Value != configuration.ThumbnailImageSize.Width ||
height.Value != configuration.ThumbnailImageSize.Height))
return new models.Image($"{httpContext.ImageBaseUrl}/{type}/{id}/{width}/{height}/{(includeCachebuster ? DateTime.UtcNow.Ticks.ToString() : string.Empty)}",
caption,
$"{httpContext.ImageBaseUrl}/{type}/{id}/{configuration.ThumbnailImageSize.Width}/{configuration.ThumbnailImageSize.Height}");
return new models.Image($"{httpContext.ImageBaseUrl}/{type}/{id}", caption, null);
}
}

View file

@ -26,7 +26,7 @@ namespace Roadie.Library.Inspect
{
public class Inspector
{
private static readonly string Salt = "6856F2EE-5965-4345-884B-2CCA457AAF59";
private const string Salt = "6856F2EE-5965-4345-884B-2CCA457AAF59";
private IEnumerable<IInspectorDirectoryPlugin> _directoryPlugins;
private IEnumerable<IInspectorFilePlugin> _filePlugins;
@ -49,13 +49,15 @@ namespace Roadie.Library.Inspect
foreach (var t in types)
if (t.GetInterface("IInspectorDirectoryPlugin") != null && !t.IsAbstract && !t.IsInterface)
{
var plugin =
Activator.CreateInstance(t, Configuration, CacheManager, Logger, TagsHelper) as
IInspectorDirectoryPlugin;
var plugin = Activator.CreateInstance(t, Configuration, CacheManager, Logger, TagsHelper) as IInspectorDirectoryPlugin;
if (plugin.IsEnabled)
{
plugins.Add(plugin);
}
else
{
Console.WriteLine($"╠╣ Not Loading Disabled Plugin [{plugin.Description}]");
}
}
}
catch (Exception ex)
@ -84,17 +86,20 @@ namespace Roadie.Library.Inspect
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
foreach (var t in types)
{
if (t.GetInterface("IInspectorFilePlugin") != null && !t.IsAbstract && !t.IsInterface)
{
var plugin =
Activator.CreateInstance(t, Configuration, CacheManager, Logger, TagsHelper) as
IInspectorFilePlugin;
var plugin = Activator.CreateInstance(t, Configuration, CacheManager, Logger, TagsHelper) as IInspectorFilePlugin;
if (plugin.IsEnabled)
{
plugins.Add(plugin);
}
else
{
Console.WriteLine($"╠╣ Not Loading Disabled Plugin [{plugin.Description}]");
}
}
}
}
catch (Exception ex)
{
@ -147,10 +152,12 @@ namespace Roadie.Library.Inspect
var numbers = 0;
var bytes = System.Text.Encoding.ASCII.GetBytes(input);
var looper = bytes.Length / 4;
for (var i = 0; i < looper; i++) numbers += BitConverter.ToInt32(bytes, i * 4);
for (var i = 0; i < looper; i++)
{
numbers += BitConverter.ToInt32(bytes, i * 4);
}
if (numbers < 0) numbers *= -1;
var token = hashids.Encode(numbers);
return token;
return hashids.Encode(numbers);
}
public void Inspect(bool doCopy, bool isReadOnly, string directoryToInspect, string destination, bool dontAppendSubFolder, bool dontDeleteEmptyFolders, bool dontRunPreScripts)
@ -171,11 +178,11 @@ namespace Roadie.Library.Inspect
string scriptResult = null;
// Run PreInspect script
if(dontRunPreScripts)
if (dontRunPreScripts)
{
Console.BackgroundColor = ConsoleColor.Blue;
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine($"Skipping PreInspectScript.");
Console.WriteLine("Skipping PreInspectScript.");
Console.ResetColor();
}
else
@ -217,7 +224,7 @@ namespace Roadie.Library.Inspect
// Get all the MP3 files in 'directory'
var files = Directory.GetFiles(directory, "*.mp3", SearchOption.TopDirectoryOnly);
if (files != null && files.Any())
if (files?.Any() == true)
{
if (!isReadOnly && !createdDestinationFolder && !Directory.Exists(dest))
{
@ -226,20 +233,19 @@ namespace Roadie.Library.Inspect
}
// Run directory plugins against current directory
foreach (var plugin in DirectoryPlugins.Where(x => !x.IsPostProcessingPlugin)
.OrderBy(x => x.Order))
foreach (var plugin in DirectoryPlugins.Where(x => !x.IsPostProcessingPlugin).OrderBy(x => x.Order))
{
Console.WriteLine($"╠╬═ Running Directory Plugin {plugin.Description}");
var pluginResult = plugin.Process(directoryInfo);
if (!pluginResult.IsSuccess)
{
Console.WriteLine(
$"📛 Plugin Failed: Error [{JsonConvert.SerializeObject(pluginResult)}]");
Console.WriteLine($"📛 Plugin Failed: Error [{JsonConvert.SerializeObject(pluginResult)}]");
return;
}
if (!string.IsNullOrEmpty(pluginResult.Data))
{
Console.WriteLine($"╠╣ Directory Plugin Message: {pluginResult.Data}");
}
}
Console.WriteLine("╠╝");
@ -263,8 +269,7 @@ namespace Roadie.Library.Inspect
if (!originalMetaData.IsValid)
{
Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine(
$"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(originalMetaData)}");
Console.WriteLine($"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(originalMetaData)}");
Console.WriteLine($"╟ [{JsonConvert.SerializeObject(tagLib, Newtonsoft.Json.Formatting.Indented)}]");
Console.ResetColor();
}
@ -274,13 +279,11 @@ namespace Roadie.Library.Inspect
foreach (var plugin in FilePlugins.OrderBy(x => x.Order))
{
Console.WriteLine($"╟┤ Running File Plugin {plugin.Description}");
OperationResult<AudioMetaData> pluginResult = null;
pluginResult = plugin.Process(pluginMetaData);
OperationResult<AudioMetaData> pluginResult = plugin.Process(pluginMetaData);
if (!pluginResult.IsSuccess)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(
$"📛 Plugin Failed: Error [{JsonConvert.SerializeObject(pluginResult)}]");
Console.WriteLine($"📛 Plugin Failed: Error [{JsonConvert.SerializeObject(pluginResult)}]");
Console.ResetColor();
return;
}
@ -291,8 +294,7 @@ namespace Roadie.Library.Inspect
if (!pluginMetaData.IsValid)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(
$"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(pluginMetaData)}");
Console.WriteLine($"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(pluginMetaData)}");
Console.ResetColor();
return;
}
@ -301,16 +303,17 @@ namespace Roadie.Library.Inspect
if (originalMetaData != null && pluginMetaData != null)
{
var differences = Comparer.Compare(originalMetaData, pluginMetaData);
if (differences.Any())
if (differences.Count > 0)
{
var skipDifferences = new List<string>
{"AudioMetaDataWeights", "FileInfo", "Images", "TrackArtists"};
var skipDifferences = new List<string> { "AudioMetaDataWeights", "FileInfo", "Images", "TrackArtists" };
var differencesDescription = $"{Environment.NewLine}";
foreach (var difference in differences)
{
if (skipDifferences.Contains(difference.Name)) continue;
differencesDescription +=
$"╟ || {difference.Name} : Was [{difference.OldValue}] Now [{difference.NewValue}]{Environment.NewLine}";
if (skipDifferences.Contains(difference.Name))
{
continue;
}
differencesDescription += $"╟ || {difference.Name} : Was [{difference.OldValue}] Now [{difference.NewValue}]{Environment.NewLine}";
}
Console.Write($"╟ ≡ != ID3 Tag Modified: {differencesDescription}");
@ -339,15 +342,13 @@ namespace Roadie.Library.Inspect
{
var oBad = originalMetaData == null;
var pBad = pluginMetaData == null;
Console.WriteLine(
$"╟ !! MetaData comparison skipped. {(oBad ? "Pre MetaData is Invalid" : "")} {(pBad ? "Post MetaData is Invalid" : "")}");
Console.WriteLine($"╟ !! MetaData comparison skipped. {(oBad ? "Pre MetaData is Invalid" : string.Empty)} {(pBad ? "Post MetaData is Invalid" : string.Empty)}");
}
if (!pluginMetaData.IsValid)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(
$"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(pluginMetaData)}");
Console.WriteLine($"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(pluginMetaData)}");
Console.ResetColor();
}
else
@ -357,11 +358,16 @@ namespace Roadie.Library.Inspect
Console.ResetColor();
var artistToken = ArtistInspectorToken(tagLib.Data);
if (!artistsFound.Contains(artistToken)) artistsFound.Add(artistToken);
if (!artistsFound.Contains(artistToken))
{
artistsFound.Add(artistToken);
}
var releaseToken = ReleaseInspectorToken(tagLib.Data);
if (!releasesFound.Contains(releaseToken)) releasesFound.Add(releaseToken);
var newFileName =
$"CD{(tagLib.Data.Disc ?? ID3TagsHelper.DetermineDiscNumber(tagLib.Data)).ToString("000")}_{tagLib.Data.TrackNumber.Value.ToString("0000")}.mp3";
if (!releasesFound.Contains(releaseToken))
{
releasesFound.Add(releaseToken);
}
var newFileName = $"CD{(tagLib.Data.Disc ?? ID3TagsHelper.DetermineDiscNumber(tagLib.Data)).ToString("000")}_{tagLib.Data.TrackNumber.Value.ToString("0000")}.mp3";
// Artist sub folder is created to hold Releases for Artist and Artist Images
var artistSubDirectory = directory == dest
? fileInfo.DirectoryName
@ -371,40 +377,35 @@ namespace Roadie.Library.Inspect
? fileInfo.DirectoryName
: Path.Combine(dest, artistToken, releaseToken);
if (!isReadOnly && !Directory.Exists(subDirectory))
{
Directory.CreateDirectory(subDirectory);
}
// Inspect images
if (!inspectedImagesInDirectories.Contains(directoryInfo.FullName))
{
// Get all artist images and move to artist folder
var foundArtistImages = new List<FileInfo>();
foundArtistImages.AddRange(ImageHelper.FindImagesByName(directoryInfo,
tagLib.Data.Artist, SearchOption.TopDirectoryOnly));
foundArtistImages.AddRange(ImageHelper.FindImagesByName(directoryInfo.Parent,
tagLib.Data.Artist, SearchOption.TopDirectoryOnly));
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(
directoryInfo.Parent, ImageType.Artist, SearchOption.TopDirectoryOnly));
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(
directoryInfo.Parent, ImageType.ArtistSecondary,
SearchOption.TopDirectoryOnly));
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo,
ImageType.Artist, SearchOption.TopDirectoryOnly));
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo,
ImageType.ArtistSecondary, SearchOption.TopDirectoryOnly));
foundArtistImages.AddRange(ImageHelper.FindImagesByName(directoryInfo, tagLib.Data.Artist, SearchOption.TopDirectoryOnly));
foundArtistImages.AddRange(ImageHelper.FindImagesByName(directoryInfo.Parent, tagLib.Data.Artist, SearchOption.TopDirectoryOnly));
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo.Parent, ImageType.Artist, SearchOption.TopDirectoryOnly));
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo.Parent, ImageType.ArtistSecondary, SearchOption.TopDirectoryOnly));
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo, ImageType.Artist, SearchOption.TopDirectoryOnly));
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo, ImageType.ArtistSecondary, SearchOption.TopDirectoryOnly));
foreach (var artistImage in foundArtistImages)
{
InspectImage(isReadOnly, doCopy, dest, artistSubDirectory, artistImage);
}
// Get all release images and move to release folder
var foundReleaseImages = new List<FileInfo>();
foundReleaseImages.AddRange(
ImageHelper.FindImagesByName(directoryInfo, tagLib.Data.Release));
foundReleaseImages.AddRange(
ImageHelper.FindImageTypeInDirectory(directoryInfo, ImageType.Release));
foundReleaseImages.AddRange(
ImageHelper.FindImageTypeInDirectory(directoryInfo,
ImageType.ReleaseSecondary));
foundReleaseImages.AddRange(ImageHelper.FindImagesByName(directoryInfo, tagLib.Data.Release));
foundReleaseImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo, ImageType.Release));
foundReleaseImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo, ImageType.ReleaseSecondary));
foreach (var foundReleaseImage in foundReleaseImages)
{
InspectImage(isReadOnly, doCopy, dest, subDirectory, foundReleaseImage);
}
inspectedImagesInDirectories.Add(directoryInfo.FullName);
}
@ -412,8 +413,7 @@ namespace Roadie.Library.Inspect
var newPath = Path.Combine(dest, subDirectory, newFileName.ToFileNameFriendly());
if (isReadOnly)
{
Console.WriteLine(
$"╟ 🔒 Read Only Mode: File would be [{(doCopy ? "Copied" : "Moved")}] to [{newPath}]");
Console.WriteLine($"╟ 🔒 Read Only Mode: File would be [{(doCopy ? "Copied" : "Moved")}] to [{newPath}]");
}
else
{
@ -464,8 +464,7 @@ namespace Roadie.Library.Inspect
Console.WriteLine("╠╝");
sw.Stop();
Console.WriteLine(
$"╚═ Elapsed Time {sw.ElapsedMilliseconds.ToString("0000000")}, Artists {artistsFound.Count()}, Releases {releasesFound.Count()}, MP3s {mp3FilesFoundCount} ═╝");
Console.WriteLine($"╚═ Elapsed Time {sw.ElapsedMilliseconds.ToString("0000000")}, Artists {artistsFound.Count}, Releases {releasesFound.Count}, MP3s {mp3FilesFoundCount} ═╝");
}
catch (Exception ex)
{
@ -492,8 +491,7 @@ namespace Roadie.Library.Inspect
{
Console.BackgroundColor = ConsoleColor.Blue;
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine(
$"PostInspectScript Results: {Environment.NewLine + scriptResult + Environment.NewLine}");
Console.WriteLine($"PostInspectScript Results: {Environment.NewLine + scriptResult + Environment.NewLine}");
Console.ResetColor();
}
}
@ -521,17 +519,22 @@ namespace Roadie.Library.Inspect
looper++;
newImagePath = Path.Combine(dest, subdirectory, looper.ToString("00"), image.Name);
}
if (isReadOnly)
Console.WriteLine(
$"╟ 🔒 Read Only Mode: Would be [{(doCopy ? "Copied" : "Moved")}] to [{newImagePath}]");
{
Console.WriteLine($"╟ 🔒 Read Only Mode: Would be [{(doCopy ? "Copied" : "Moved")}] to [{newImagePath}]");
}
else
{
try
{
if (!doCopy)
{
image.MoveTo(newImagePath);
}
else
{
image.CopyTo(newImagePath, true);
}
Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine($"╠═ 🚛 {(doCopy ? "Copied" : "Moved")} Image File to [{newImagePath}]");
}
@ -539,9 +542,9 @@ namespace Roadie.Library.Inspect
{
Logger.LogError(ex);
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(
$"📛 Error file [{image.FullName}], newImagePath [{newImagePath}], Exception: [{ex}]");
Console.WriteLine($"📛 Error file [{image.FullName}], newImagePath [{newImagePath}], Exception: [{ex}]");
}
}
}
Console.ResetColor();
@ -588,9 +591,17 @@ namespace Roadie.Library.Inspect
var script = File.ReadAllText(scriptFilename);
using (var ps = PowerShell.Create())
{
var r = "";
var results = ps.AddScript(script).Invoke();
foreach (var result in results) r += result + Environment.NewLine;
var r = string.Empty;
var results = ps.AddScript(script)
.AddParameter("DoCopy", doCopy)
.AddParameter("IsReadOnly", isReadOnly)
.AddParameter("DirectoryToInspect", directoryToInspect)
.AddParameter("Dest", dest)
.Invoke();
foreach (var result in results)
{
r += result + Environment.NewLine;
}
return r;
}
}
@ -604,7 +615,6 @@ namespace Roadie.Library.Inspect
public class LoggingTraceListener : TraceListener
{
public override void Write(string message)
{
Console.WriteLine($"╠╬═ { message }");
@ -614,7 +624,5 @@ namespace Roadie.Library.Inspect
{
Console.WriteLine($"╠╬═ { message }");
}
}
}

View file

@ -33,7 +33,7 @@ namespace Roadie.Library.Scrobble
/// indication of what music player they're using.
/// </remark>
/// </summary>
public override async Task<OperationResult<bool>> NowPlaying(User roadieUser, ScrobbleInfo scrobble) => await LastFmHelper.NowPlaying(roadieUser, scrobble);
public override async Task<OperationResult<bool>> NowPlaying(User roadieUser, ScrobbleInfo scrobble) => await LastFmHelper.NowPlaying(roadieUser, scrobble).ConfigureAwait(false);
/// <summary>
/// Send a Scrobble Request
@ -42,7 +42,7 @@ namespace Roadie.Library.Scrobble
/// listening history and generate personalised charts and recommendations (and more).
/// </remark>
/// </summary>
public override async Task<OperationResult<bool>> Scrobble(User roadieUser, ScrobbleInfo scrobble) => await LastFmHelper.Scrobble(roadieUser, scrobble);
public override async Task<OperationResult<bool>> Scrobble(User roadieUser, ScrobbleInfo scrobble) => await LastFmHelper.Scrobble(roadieUser, scrobble).ConfigureAwait(false);
}
}

View file

@ -37,7 +37,7 @@ namespace Roadie.Library.Scrobble
{
Data = true,
IsSuccess = true
});
}).ConfigureAwait(false);
}
/// <summary>
@ -59,12 +59,13 @@ namespace Roadie.Library.Scrobble
};
}
var sw = Stopwatch.StartNew();
var track = DbContext.Tracks
var track = await DbContext.Tracks
.Include(x => x.ReleaseMedia)
.Include(x => x.ReleaseMedia.Release)
.Include(x => x.ReleaseMedia.Release.Artist)
.Include(x => x.TrackArtist)
.FirstOrDefault(x => x.RoadieId == scrobble.TrackId);
.FirstOrDefaultAsync(x => x.RoadieId == scrobble.TrackId)
.ConfigureAwait(false);
if (track == null)
{
return new OperationResult<bool>($"Scrobble: Unable To Find Track [{scrobble.TrackId}]");
@ -80,8 +81,8 @@ namespace Roadie.Library.Scrobble
{
if (roadieUser != null)
{
var user = DbContext.Users.FirstOrDefault(x => x.RoadieId == roadieUser.UserId);
userTrack = DbContext.UserTracks.FirstOrDefault(x => x.UserId == user.Id && x.TrackId == track.Id);
var user = await DbContext.Users.FirstOrDefaultAsync(x => x.RoadieId == roadieUser.UserId).ConfigureAwait(false);
userTrack = await DbContext.UserTracks.FirstOrDefaultAsync(x => x.UserId == user.Id && x.TrackId == track.Id).ConfigureAwait(false);
if (userTrack == null)
{
userTrack = new data.UserTrack(now)
@ -89,7 +90,7 @@ namespace Roadie.Library.Scrobble
UserId = user.Id,
TrackId = track.Id
};
DbContext.UserTracks.Add(userTrack);
await DbContext.UserTracks.AddAsync(userTrack).ConfigureAwait(false);
}
userTrack.LastPlayed = now;
@ -101,20 +102,21 @@ namespace Roadie.Library.Scrobble
track.PlayedCount = (track.PlayedCount ?? 0) + 1;
track.LastPlayed = now;
var release = DbContext.Releases
var release = await DbContext.Releases
.Include(x => x.Artist)
.FirstOrDefault(x => x.RoadieId == track.ReleaseMedia.Release.RoadieId);
.FirstOrDefaultAsync(x => x.RoadieId == track.ReleaseMedia.Release.RoadieId)
.ConfigureAwait(false);
release.LastPlayed = now;
release.PlayedCount = (release.PlayedCount ?? 0) + 1;
var artist = DbContext.Artists.FirstOrDefault(x => x.RoadieId == release.Artist.RoadieId);
var artist = await DbContext.Artists.FirstOrDefaultAsync(x => x.RoadieId == release.Artist.RoadieId).ConfigureAwait(false);
artist.LastPlayed = now;
artist.PlayedCount = (artist.PlayedCount ?? 0) + 1;
data.Artist trackArtist = null;
if (track.ArtistId.HasValue)
{
trackArtist = DbContext.Artists.FirstOrDefault(x => x.Id == track.ArtistId);
trackArtist = await DbContext.Artists.FirstOrDefaultAsync(x => x.Id == track.ArtistId).ConfigureAwait(false);
if (trackArtist != null)
{
trackArtist.LastPlayed = now;
@ -127,7 +129,7 @@ namespace Roadie.Library.Scrobble
}
}
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(track.CacheRegion);
CacheManager.ClearRegion(track.ReleaseMedia.Release.CacheRegion);

View file

@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Data.Context;
@ -10,7 +11,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using data = Roadie.Library.Data;
namespace Roadie.Library.Scrobble
{
@ -31,6 +31,18 @@ namespace Roadie.Library.Scrobble
private IEnumerable<IScrobblerIntegration> Scrobblers { get; }
public ScrobbleHandler(IRoadieSettings configuration, ILogger logger, IRoadieDbContext dbContext, ICacheManager cacheManager, RoadieScrobbler roadieScrobbler)
{
Logger = logger;
Configuration = configuration;
DbContext = dbContext;
var scrobblers = new List<IScrobblerIntegration>
{
roadieScrobbler
};
Scrobblers = scrobblers;
}
public ScrobbleHandler(IRoadieSettings configuration, ILogger<ScrobbleHandler> logger, IRoadieDbContext dbContext,
ICacheManager cacheManager, IHttpEncoder httpEncoder, IHttpContext httpContext,
ILastFmHelper lastFmHelper, IRoadieScrobbler roadieScrobbler, ILastFMScrobbler lastFMScrobbler)
@ -51,16 +63,28 @@ namespace Roadie.Library.Scrobble
Scrobblers = scrobblers;
}
public ScrobbleHandler(IRoadieSettings configuration, ILogger logger, IRoadieDbContext dbContext, ICacheManager cacheManager, RoadieScrobbler roadieScrobbler)
private async Task<ScrobbleInfo> GetScrobbleInfoDetailsAsync(ScrobbleInfo scrobble)
{
Logger = logger;
Configuration = configuration;
DbContext = dbContext;
var scrobblers = new List<IScrobblerIntegration>
{
roadieScrobbler
};
Scrobblers = scrobblers;
var scrobbleInfo = await (from t in DbContext.Tracks
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
join r in DbContext.Releases on rm.ReleaseId equals r.Id
join a in DbContext.Artists on r.ArtistId equals a.Id
where t.RoadieId == scrobble.TrackId
select new
{
ArtistName = a.Name,
ReleaseTitle = r.Title,
TrackTitle = t.Title,
t.TrackNumber,
t.Duration
}).FirstOrDefaultAsync().ConfigureAwait(false);
scrobble.ArtistName = scrobbleInfo.ArtistName;
scrobble.ReleaseTitle = scrobbleInfo.ReleaseTitle;
scrobble.TrackTitle = scrobbleInfo.TrackTitle;
scrobble.TrackNumber = scrobbleInfo.TrackNumber.ToString();
scrobble.TrackDuration = TimeSpan.FromMilliseconds(scrobbleInfo.Duration ?? 0);
return scrobble;
}
/// <summary>
@ -68,8 +92,11 @@ namespace Roadie.Library.Scrobble
/// </summary>
public async Task<OperationResult<bool>> NowPlaying(User user, ScrobbleInfo scrobble)
{
var s = GetScrobbleInfoDetails(scrobble);
foreach (var scrobbler in Scrobblers) await Task.Run(async () => await scrobbler.NowPlaying(user, s));
var s = await GetScrobbleInfoDetailsAsync(scrobble).ConfigureAwait(false);
foreach (var scrobbler in Scrobblers)
{
await scrobbler.NowPlaying(user, s).ConfigureAwait(false);
}
return new OperationResult<bool>
{
Data = true,
@ -82,10 +109,10 @@ namespace Roadie.Library.Scrobble
/// </summary>
public async Task<OperationResult<bool>> Scrobble(User user, ScrobbleInfo scrobble)
{
var s = GetScrobbleInfoDetails(scrobble);
var s = await GetScrobbleInfoDetailsAsync(scrobble).ConfigureAwait(false);
foreach (var scrobbler in Scrobblers)
{
await Task.Run(async () => await scrobbler.Scrobble(user, s));
await scrobbler.Scrobble(user, s).ConfigureAwait(false);
}
return new OperationResult<bool>
{
@ -93,29 +120,5 @@ namespace Roadie.Library.Scrobble
IsSuccess = true
};
}
private ScrobbleInfo GetScrobbleInfoDetails(ScrobbleInfo scrobble)
{
var scrobbleInfo = (from t in DbContext.Tracks
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
join r in DbContext.Releases on rm.ReleaseId equals r.Id
join a in DbContext.Artists on r.ArtistId equals a.Id
where t.RoadieId == scrobble.TrackId
select new
{
ArtistName = a.Name,
ReleaseTitle = r.Title,
TrackTitle = t.Title,
t.TrackNumber,
t.Duration
}).FirstOrDefault();
scrobble.ArtistName = scrobbleInfo.ArtistName;
scrobble.ReleaseTitle = scrobbleInfo.ReleaseTitle;
scrobble.TrackTitle = scrobbleInfo.TrackTitle;
scrobble.TrackNumber = scrobbleInfo.TrackNumber.ToString();
scrobble.TrackDuration = TimeSpan.FromMilliseconds(scrobbleInfo.Duration ?? 0);
return scrobble;
}
}
}

View file

@ -44,11 +44,11 @@ namespace Roadie.Library.SearchEngines.Imaging
return request;
}
public override async Task<IEnumerable<ImageSearchResult>> PerformImageSearch(string query, int resultsCount)
public override async Task<IEnumerable<ImageSearchResult>> PerformImageSearchAsync(string query, int resultsCount)
{
var request = BuildRequest(query, resultsCount);
var response = await _client.ExecuteAsync<BingImageResult>(request);
var response = await _client.ExecuteAsync<BingImageResult>(request).ConfigureAwait(false);
if (response.StatusCode == HttpStatusCode.Unauthorized)
throw new AuthenticationException("Api Key is not correct");

View file

@ -10,6 +10,6 @@ namespace Roadie.Library.SearchEngines.Imaging
RestRequest BuildRequest(string query, int resultsCount);
Task<IEnumerable<ImageSearchResult>> PerformImageSearch(string query, int resultsCount);
Task<IEnumerable<ImageSearchResult>> PerformImageSearchAsync(string query, int resultsCount);
}
}

View file

@ -25,14 +25,14 @@ namespace Roadie.Library.SearchEngines.Imaging
public override bool IsEnabled => Configuration.Integrations.ITunesProviderEnabled;
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearch(string query, int resultsCount)
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearchAsync(string query, int resultsCount)
{
ArtistSearchResult data = null;
try
{
var request = BuildRequest(query, 1, "musicArtist");
var response = await _client.ExecuteAsync<ITunesSearchResult>(request);
var response = await _client.ExecuteAsync<ITunesSearchResult>(request).ConfigureAwait(false);
if (response.ResponseStatus == ResponseStatus.Error)
{
if (response.StatusCode == HttpStatusCode.Unauthorized)
@ -79,7 +79,7 @@ namespace Roadie.Library.SearchEngines.Imaging
#pragma warning disable CS1998
public override async Task<IEnumerable<ImageSearchResult>> PerformImageSearch(string query, int resultsCount)
public override async Task<IEnumerable<ImageSearchResult>> PerformImageSearchAsync(string query, int resultsCount)
{
var request = BuildRequest(query, resultsCount);
ImageSearchResult[] result = null;
@ -116,7 +116,7 @@ namespace Roadie.Library.SearchEngines.Imaging
public async Task<OperationResult<IEnumerable<ReleaseSearchResult>>> PerformReleaseSearch(string artistName, string query, int resultsCount)
{
var request = BuildRequest(query, 1, "album");
var response = await _client.ExecuteAsync<ITunesSearchResult>(request);
var response = await _client.ExecuteAsync<ITunesSearchResult>(request).ConfigureAwait(false);
if (response.ResponseStatus == ResponseStatus.Error)
{
if (response.StatusCode == HttpStatusCode.Unauthorized)

View file

@ -50,7 +50,7 @@ namespace Roadie.Library.SearchEngines.Imaging
public abstract RestRequest BuildRequest(string query, int resultsCount);
public virtual Task<IEnumerable<ImageSearchResult>> PerformImageSearch(string query, int resultsCount)
public virtual Task<IEnumerable<ImageSearchResult>> PerformImageSearchAsync(string query, int resultsCount)
{
throw new NotImplementedException();
}

View file

@ -37,7 +37,7 @@ namespace Roadie.Library.SearchEngines.Imaging
}
if (Configuration.Integrations.BingImageSearchEngineEnabled)
{
var bingResults = await _bingSearchEngine.PerformImageSearch(query, count);
var bingResults = await _bingSearchEngine.PerformImageSearchAsync(query, count).ConfigureAwait(false);
if (bingResults != null)
{
result.AddRange(bingResults);
@ -45,7 +45,7 @@ namespace Roadie.Library.SearchEngines.Imaging
}
if (Configuration.Integrations.ITunesProviderEnabled)
{
var iTunesResults = await _itunesSearchEngine.PerformImageSearch(query, count);
var iTunesResults = await _itunesSearchEngine.PerformImageSearchAsync(query, count).ConfigureAwait(false);
if (iTunesResults != null)
{
result.AddRange(iTunesResults);

View file

@ -103,11 +103,11 @@ namespace Roadie.Library.MetaData.Audio
if (!result.IsValid)
{
tagSources.Add("MusicBrainz");
result = await ParseFromMusicBrainz(result);
result = await ParseFromMusicBrainzAsync(result).ConfigureAwait(false);
if (!result.IsValid)
{
tagSources.Add("LastFm");
result = await GetFromLastFmIntegration(result);
result = await GetFromLastFmIntegrationAsync(result).ConfigureAwait(false);
}
}
@ -183,15 +183,18 @@ namespace Roadie.Library.MetaData.Audio
return result;
}
private async Task<AudioMetaData> GetFromLastFmIntegration(AudioMetaData metaData)
private async Task<AudioMetaData> GetFromLastFmIntegrationAsync(AudioMetaData metaData)
{
var artistName = metaData.Artist;
var ReleaseName = metaData.Release;
if (DoParseFromLastFM)
{
if (string.IsNullOrEmpty(artistName) && string.IsNullOrEmpty(ReleaseName)) return metaData;
var lastFmReleaseTracks = await LastFmHelper.TracksForRelease(artistName, ReleaseName);
if (string.IsNullOrEmpty(artistName) && string.IsNullOrEmpty(ReleaseName))
{
return metaData;
}
var lastFmReleaseTracks = await LastFmHelper.TracksForReleaseAsync(artistName, ReleaseName).ConfigureAwait(false);
if (lastFmReleaseTracks != null)
{
var lastFmReleaseTrack = lastFmReleaseTracks.FirstOrDefault(x =>
@ -224,12 +227,11 @@ namespace Roadie.Library.MetaData.Audio
return metaData;
}
private async Task<AudioMetaData> ParseFromMusicBrainz(AudioMetaData metaData)
private async Task<AudioMetaData> ParseFromMusicBrainzAsync(AudioMetaData metaData)
{
if (DoParseFromMusicBrainz)
{
var musicBrainzReleaseTracks =
await MusicBrainzProvider.MusicBrainzReleaseTracks(metaData.Artist, metaData.Release);
var musicBrainzReleaseTracks = await MusicBrainzProvider.MusicBrainzReleaseTracksAsync(metaData.Artist, metaData.Release).ConfigureAwait(false);
if (musicBrainzReleaseTracks != null)
{
var musicBrainzReleaseTrack = musicBrainzReleaseTracks.FirstOrDefault(x =>

View file

@ -24,7 +24,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
_apiKey = configuration.Integrations.ApiKeys.FirstOrDefault(x => x.ApiName == "DiscogsConsumerKey") ?? new ApiKey();
}
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearch(string query, int resultsCount)
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearchAsync(string query, int resultsCount)
{
ArtistSearchResult data = null;
try
@ -40,7 +40,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
UserAgent = WebHelper.UserAgent
};
var response = await client.ExecuteAsync<DiscogsResult>(request);
var response = await client.ExecuteAsync<DiscogsResult>(request).ConfigureAwait(false);
if (response.ResponseStatus == ResponseStatus.Error)
{
@ -61,7 +61,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
{
UserAgent = WebHelper.UserAgent
};
var artistResponse = await c2.ExecuteTaskAsync<DiscogArtistResponse>(request);
var artistResponse = await c2.ExecuteTaskAsync<DiscogArtistResponse>(request).ConfigureAwait(false);
var artist = artistResponse.Data;
if (artist != null)
{
@ -99,7 +99,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
}
}
return null;
}, "uri:metadata");
}, "uri:metadata").ConfigureAwait(false);
}
catch (Exception ex)
{
@ -126,7 +126,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
var client = new RestClient("https://api.discogs.com/database");
client.UserAgent = WebHelper.UserAgent;
var response = await client.ExecuteAsync<DiscogsResult>(request);
var response = await client.ExecuteAsync<DiscogsResult>(request).ConfigureAwait(false);
if (response.ResponseStatus == ResponseStatus.Error)
{
@ -144,7 +144,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
request = BuildLabelRequest(responseData.id);
var c2 = new RestClient("https://api.discogs.com/");
c2.UserAgent = WebHelper.UserAgent;
var labelResponse = await c2.ExecuteTaskAsync<DiscogsLabelResult>(request);
var labelResponse = await c2.ExecuteTaskAsync<DiscogsLabelResult>(request).ConfigureAwait(false);
var label = labelResponse.Data;
if (label != null)
{
@ -157,7 +157,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
if (label.images != null)
{
images.AddRange(label.images.Where(x => x.type != "primary").Select(x => x.uri));
var primaryImage = label.images.FirstOrDefault(x => x.type == "primary");
var primaryImage = label.images.Find(x => x.type == "primary");
if (primaryImage != null) labelThumbnailUrl = primaryImage.uri;
if (string.IsNullOrEmpty(labelThumbnailUrl))
labelThumbnailUrl = label.images.First(x => !string.IsNullOrEmpty(x.uri)).uri;
@ -176,7 +176,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
}
}
return null;
}, "uri:metadata");
}, "uri:metadata").ConfigureAwait(false);
}
catch (Exception ex)
{
@ -207,7 +207,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
Timeout = SafeParser.ToNumber<int>(Configuration.Integrations.DiscogsTimeout)
};
var response = await client.ExecuteAsync<DiscogsReleaseSearchResult>(request);
var response = await client.ExecuteAsync<DiscogsReleaseSearchResult>(request).ConfigureAwait(false);
if (response?.ResponseStatus == null || response.ResponseStatus == ResponseStatus.Error)
{
if (response.StatusCode == HttpStatusCode.Unauthorized)
@ -225,7 +225,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
{
UserAgent = WebHelper.UserAgent
};
var releaseResult = await c2.ExecuteTaskAsync<DiscogReleaseDetail>(request);
var releaseResult = await c2.ExecuteTaskAsync<DiscogReleaseDetail>(request).ConfigureAwait(false);
var release = releaseResult?.Data;
if (release != null)
{
@ -296,7 +296,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
if (release.identifiers != null)
{
var barcode = release.identifiers.FirstOrDefault(x => (x.type ?? string.Empty) == "Barcode");
var barcode = release.identifiers.Find(x => (x.type ?? string.Empty) == "Barcode");
if (barcode?.value != null)
{
data.Tags = new[] { "barcode:" + barcode.value };
@ -305,7 +305,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
}
}
return null;
}, "uri:metadata");
}, "uri:metadata").ConfigureAwait(false);
}
catch (Exception ex)
{

View file

@ -7,6 +7,6 @@ namespace Roadie.Library.SearchEngines.MetaData
{
bool IsEnabled { get; }
Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearch(string query, int resultsCount);
Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearchAsync(string query, int resultsCount);
}
}

View file

@ -10,6 +10,6 @@ namespace Roadie.Library.MetaData.LastFm
{
Task<OperationResult<string>> GetSessionKeyForUserToken(string token);
Task<IEnumerable<AudioMetaData>> TracksForRelease(string artist, string Release);
Task<IEnumerable<AudioMetaData>> TracksForReleaseAsync(string artist, string Release);
}
}

View file

@ -86,7 +86,7 @@ namespace Roadie.Library.MetaData.LastFm
};
var request = new RestRequest(Method.GET);
var client = new RestClient(BuildUrl("auth.getSession", parameters));
var responseXML = await client.ExecuteAsync<string>(request);
var responseXML = await client.ExecuteAsync<string>(request).ConfigureAwait(false);
var doc = new XmlDocument();
doc.LoadXml(responseXML.Content);
var sessionKey = doc.GetElementsByTagName("key")[0].InnerText;
@ -139,7 +139,7 @@ namespace Roadie.Library.MetaData.LastFm
var xp = GetResponseAsXml(request);
Logger.LogTrace($"LastFmHelper: RoadieUser `{roadieUser}` NowPlaying `{scrobble}` LastFmResult [{xp.InnerXml}]");
result = true;
});
}).ConfigureAwait(false);
}
catch (Exception ex)
{
@ -153,7 +153,7 @@ namespace Roadie.Library.MetaData.LastFm
};
}
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearch(string query, int resultsCount)
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearchAsync(string query, int resultsCount)
{
try
{
@ -163,7 +163,7 @@ namespace Roadie.Library.MetaData.LastFm
Logger.LogTrace("LastFmHelper:PerformArtistSearch:{0}", query);
var auth = new LastAuth(ApiKey.Key, ApiKey.KeySecret);
var albumApi = new ArtistApi(auth);
var response = await albumApi.GetInfoAsync(query);
var response = await albumApi.GetInfoAsync(query).ConfigureAwait(false);
if (!response.Success)
{
return null;
@ -183,7 +183,7 @@ namespace Roadie.Library.MetaData.LastFm
result.Urls = new[] { lastFmArtist.Url.ToString() };
}
return result;
}, "uri:metadata");
}, "uri:metadata").ConfigureAwait(false);
return new OperationResult<IEnumerable<ArtistSearchResult>>
{
IsSuccess = data != null,
@ -205,7 +205,7 @@ namespace Roadie.Library.MetaData.LastFm
{
var request = new RestRequest(Method.GET);
var client = new RestClient(string.Format("http://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key={0}&artist={1}&album={2}&format=xml", ApiKey.Key, artistName, query));
var responseData = await client.ExecuteAsync<lfm>(request);
var responseData = await client.ExecuteAsync<lfm>(request).ConfigureAwait(false);
ReleaseSearchResult result = null;
@ -246,7 +246,7 @@ namespace Roadie.Library.MetaData.LastFm
}
}
return result;
}, "uri:metadata");
}, "uri:metadata").ConfigureAwait(false);
return new OperationResult<IEnumerable<ReleaseSearchResult>>
{
IsSuccess = data != null,
@ -269,7 +269,7 @@ namespace Roadie.Library.MetaData.LastFm
// If less than half of duration then create a NowPlaying
if (scrobble.ElapsedTimeOfTrackPlayed.TotalMinutes < 4 ||
scrobble.ElapsedTimeOfTrackPlayed.TotalSeconds < scrobble.TrackDuration.TotalSeconds / 2)
return await NowPlaying(roadieUser, scrobble);
return await NowPlaying(roadieUser, scrobble).ConfigureAwait(false);
var user = DbContext.Users.FirstOrDefault(x => x.RoadieId == roadieUser.UserId);
@ -319,7 +319,7 @@ namespace Roadie.Library.MetaData.LastFm
};
}
public async Task<IEnumerable<AudioMetaData>> TracksForRelease(string artist, string Release)
public async Task<IEnumerable<AudioMetaData>> TracksForReleaseAsync(string artist, string Release)
{
if (string.IsNullOrEmpty(artist) || string.IsNullOrEmpty(Release)) return null;
var result = new List<AudioMetaData>();
@ -333,7 +333,7 @@ namespace Roadie.Library.MetaData.LastFm
{
var auth = new LastAuth(ApiKey.Key, ApiKey.KeySecret);
var albumApi = new AlbumApi(auth); // this is an unauthenticated call to the API
var response = await albumApi.GetInfoAsync(artist, Release);
var response = await albumApi.GetInfoAsync(artist, Release).ConfigureAwait(false);
releaseInfo = response.Content;
if (releaseInfo != null) CacheManager.Add(responseCacheKey, releaseInfo);
}

View file

@ -7,6 +7,6 @@ namespace Roadie.Library.MetaData.MusicBrainz
{
public interface IMusicBrainzProvider : IArtistSearchEngine, IReleaseSearchEngine
{
Task<IEnumerable<AudioMetaData>> MusicBrainzReleaseTracks(string artistName, string releaseTitle);
Task<IEnumerable<AudioMetaData>> MusicBrainzReleaseTracksAsync(string artistName, string releaseTitle);
}
}

View file

@ -23,14 +23,14 @@ namespace Roadie.Library.MetaData.MusicBrainz
Repository = new MusicBrainzRepository(configuration, logger);
}
public async Task<IEnumerable<AudioMetaData>> MusicBrainzReleaseTracks(string artistName, string releaseTitle)
public async Task<IEnumerable<AudioMetaData>> MusicBrainzReleaseTracksAsync(string artistName, string releaseTitle)
{
try
{
if (string.IsNullOrEmpty(artistName) && string.IsNullOrEmpty(releaseTitle)) return null;
// Find the Artist
var artistCacheKey = string.Format("uri:musicbrainz:artist:{0}", artistName);
var artistSearch = await PerformArtistSearch(artistName, 1);
var artistSearch = await PerformArtistSearchAsync(artistName, 1).ConfigureAwait(false);
if (!artistSearch.IsSuccess) return null;
var artist = artistSearch.Data.First();
@ -56,8 +56,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
}
// Now get The Release Details
release = await MusicBrainzRequestHelper.GetAsync<Release>(
MusicBrainzRequestHelper.CreateLookupUrl("release", ReleaseResult.MusicBrainzId, "recordings"));
release = await MusicBrainzRequestHelper.GetAsync<Release>(MusicBrainzRequestHelper.CreateLookupUrl("release", ReleaseResult.MusicBrainzId, "recordings")).ConfigureAwait(false);
if (release == null) return null;
CacheManager.Add(ReleaseCacheKey, release);
}
@ -113,12 +112,12 @@ namespace Roadie.Library.MetaData.MusicBrainz
return null;
}
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearch(string query, int resultsCount)
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearchAsync(string query, int resultsCount)
{
ArtistSearchResult result = null;
Logger.LogTrace("MusicBrainzProvider:PerformArtistSearch:{0}", query);
var a = await Repository.ArtistByName(query, resultsCount);
var a = await Repository.ArtistByNameAsync(query, resultsCount).ConfigureAwait(false);
if (a != null)
{
var imageUrls = a.relations?.Where(x => x.type.Equals("image", StringComparison.OrdinalIgnoreCase)).Select(x => x.url.resource).Distinct().ToArray();
@ -174,7 +173,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
ReleaseSearchResult result = null;
try
{
var releaseInfosForArtist = await ReleasesForArtist(artistName);
var releaseInfosForArtist = await ReleasesForArtistAsync(artistName).ConfigureAwait(false);
if (releaseInfosForArtist != null)
{
var r = releaseInfosForArtist.FirstOrDefault(x => x.title.Equals(query, StringComparison.OrdinalIgnoreCase));
@ -208,7 +207,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
ReleaseGenres = r.releasegroup?.genres?.Select(x => x.name).Distinct().ToArray(),
ReleaseType = r.releasegroup?.primarytype
};
var coverUrls = await CoverArtForMusicBrainzReleaseById(r.id);
var coverUrls = await CoverArtForMusicBrainzReleaseByIdAsync(r.id).ConfigureAwait(false);
if (coverUrls != null)
{
var frontCover = coverUrls.images.FirstOrDefault(i => i.front);
@ -296,16 +295,13 @@ namespace Roadie.Library.MetaData.MusicBrainz
};
}
private async Task<CoverArtArchivesResult> CoverArtForMusicBrainzReleaseById(string musicBrainzId)
{
return await MusicBrainzRequestHelper.GetAsync<CoverArtArchivesResult>(MusicBrainzRequestHelper.CreateCoverArtReleaseUrl(musicBrainzId));
}
private Task<CoverArtArchivesResult> CoverArtForMusicBrainzReleaseByIdAsync(string musicBrainzId) => MusicBrainzRequestHelper.GetAsync<CoverArtArchivesResult>(MusicBrainzRequestHelper.CreateCoverArtReleaseUrl(musicBrainzId));
private async Task<IEnumerable<Release>> ReleasesForArtist(string artist, string artistMusicBrainzId = null)
private async Task<IEnumerable<Release>> ReleasesForArtistAsync(string artist, string artistMusicBrainzId = null)
{
if (string.IsNullOrEmpty(artistMusicBrainzId))
{
var artistSearch = await PerformArtistSearch(artist, 1);
var artistSearch = await PerformArtistSearchAsync(artist, 1).ConfigureAwait(false);
if (artistSearch == null || !artistSearch.IsSuccess)
{
return null;
@ -317,7 +313,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
}
artistMusicBrainzId = mbArtist.MusicBrainzId;
}
return await Repository.ReleasesForArtist(artistMusicBrainzId);
return await Repository.ReleasesForArtist(artistMusicBrainzId).ConfigureAwait(false);
}
}
}

View file

@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace Roadie.Library.MetaData.MusicBrainz
@ -21,7 +20,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
Logger = logger;
var location = System.Reflection.Assembly.GetEntryAssembly().Location;
var directory = configuration.SearchEngineReposFolder ?? Path.Combine(System.IO.Path.GetDirectoryName(location), "SearchEngineRepos");
if(!Directory.Exists(directory))
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
@ -33,7 +32,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
/// </summary>
/// <param name="name">Query name of Artist</param>
/// <param name="resultsCount">Maximum Number of Results</param>
public async Task<Artist> ArtistByName(string name, int? resultsCount = null)
public async Task<Artist> ArtistByNameAsync(string name, int? resultsCount = null)
{
Artist result = null;
@ -48,14 +47,14 @@ namespace Roadie.Library.MetaData.MusicBrainz
if (artist == null)
{
// Perform a query to get the MbId for the Name
var artistResult = await MusicBrainzRequestHelper.GetAsync<ArtistResult>(MusicBrainzRequestHelper.CreateSearchTemplate("artist", name, resultsCount ?? 1, 0));
var artistResult = await MusicBrainzRequestHelper.GetAsync<ArtistResult>(MusicBrainzRequestHelper.CreateSearchTemplate("artist", name, resultsCount ?? 1, 0)).ConfigureAwait(false);
if (artistResult == null || artistResult.artists == null || !artistResult.artists.Any() || artistResult.count < 1)
{
return null;
}
var mbId = artistResult.artists.First().id;
// Now perform a detail request to get the details by the MbId
result = await MusicBrainzRequestHelper.GetAsync<Artist>(MusicBrainzRequestHelper.CreateLookupUrl("artist", mbId, "aliases+tags+genres+url-rels"));
result = await MusicBrainzRequestHelper.GetAsync<Artist>(MusicBrainzRequestHelper.CreateLookupUrl("artist", mbId, "aliases+tags+genres+url-rels")).ConfigureAwait(false);
if (result != null)
{
col.Insert(new RepositoryArtist
@ -99,13 +98,13 @@ namespace Roadie.Library.MetaData.MusicBrainz
col.EnsureIndex(x => x.ArtistMbId);
col.EnsureIndex(x => x.Release.id);
var releases = col.Find(x => x.ArtistMbId == artistMbId);
if(releases == null || !releases.Any())
if (releases == null || !releases.Any())
{
// Query to get collection of Releases for Artist
var pageSize = 50;
var page = 0;
var url = MusicBrainzRequestHelper.CreateArtistBrowseTemplate(artistMbId, pageSize, 0);
var mbReleaseBrowseResult = await MusicBrainzRequestHelper.GetAsync<ReleaseBrowseResult>(url);
var mbReleaseBrowseResult = await MusicBrainzRequestHelper.GetAsync<ReleaseBrowseResult>(url).ConfigureAwait(false);
var totalReleases = mbReleaseBrowseResult != null ? mbReleaseBrowseResult.releasecount : 0;
var totalPages = Math.Ceiling((decimal)totalReleases / pageSize);
var fetchResult = new List<Release>();
@ -116,7 +115,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
fetchResult.AddRange(mbReleaseBrowseResult.releases.Where(x => !string.IsNullOrEmpty(x.date)));
}
page++;
mbReleaseBrowseResult = await MusicBrainzRequestHelper.GetAsync<ReleaseBrowseResult>(MusicBrainzRequestHelper.CreateArtistBrowseTemplate(artistMbId, pageSize, pageSize * page));
mbReleaseBrowseResult = await MusicBrainzRequestHelper.GetAsync<ReleaseBrowseResult>(MusicBrainzRequestHelper.CreateArtistBrowseTemplate(artistMbId, pageSize, pageSize * page)).ConfigureAwait(false);
} while (page < totalPages);
col.InsertBulk(fetchResult.Select(x => new RepositoryRelease
{
@ -129,7 +128,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
{
results = releases.Select(x => x.Release).ToArray();
}
}
}
}
catch (HttpRequestException ex)
{

View file

@ -55,7 +55,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
using (var webClient = new WebClient())
{
webClient.Headers.Add("user-agent", WebHelper.UserAgent);
result = JsonConvert.DeserializeObject<T>(await webClient.DownloadStringTaskAsync(new Uri(url)));
result = JsonConvert.DeserializeObject<T>(await webClient.DownloadStringTaskAsync(new Uri(url)).ConfigureAwait(false));
}
}
catch (WebException ex)

View file

@ -23,7 +23,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Spotify
{
}
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearch(string query,
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearchAsync(string query,
int resultsCount)
{
ArtistSearchResult data = null;
@ -37,7 +37,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Spotify
var client = new RestClient("http://api.spotify.com/v1");
client.UserAgent = WebHelper.UserAgent;
var response = await client.ExecuteAsync<SpotifyResult>(request);
var response = await client.ExecuteAsync<SpotifyResult>(request).ConfigureAwait(false);
if (response.ResponseStatus == ResponseStatus.Error)
{
@ -79,7 +79,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Spotify
public async Task<OperationResult<IEnumerable<ReleaseSearchResult>>> PerformReleaseSearch(string artistName,
string query, int resultsCount)
{
var artistResult = await PerformArtistSearch(artistName, resultsCount);
var artistResult = await PerformArtistSearchAsync(artistName, resultsCount).ConfigureAwait(false);
if (!artistResult.IsSuccess) return new OperationResult<IEnumerable<ReleaseSearchResult>>();
try
{
@ -88,7 +88,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Spotify
ReleaseSearchResult result = null;
var response = await AlbumsForArtist(artistResult.Data.First().SpotifyId);
var response = await AlbumsForArtistAsync(artistResult.Data.First().SpotifyId).ConfigureAwait(false);
if (response != null && response.items != null)
{
string foundByAlternateName = null;
@ -104,7 +104,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Spotify
}
var client = new RestClient(string.Format("http://api.spotify.com/v1/albums/{0}", spotifyAlbum.id));
var albumResult = await client.ExecuteAsync<AlbumResult>(request);
var albumResult = await client.ExecuteAsync<AlbumResult>(request).ConfigureAwait(false);
if (albumResult != null && albumResult.Data != null)
{
var sa = albumResult.Data;
@ -203,7 +203,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Spotify
return new OperationResult<IEnumerable<ReleaseSearchResult>>();
}
private async Task<Albums> AlbumsForArtist(string spotifyId)
private async Task<Albums> AlbumsForArtistAsync(string spotifyId)
{
var cacheKey = string.Format("uri:spotify:AlbumsForArtist:{0}", spotifyId);
var result = CacheManager.Get<Albums>(cacheKey);
@ -213,7 +213,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Spotify
var client = new RestClient(string.Format(
"http://api.spotify.com/v1/artists/{0}/albums?offset=0&limit=25&album_type=album&market=US",
spotifyId));
var artistAlbumsResponse = await client.ExecuteAsync<Albums>(request);
var artistAlbumsResponse = await client.ExecuteAsync<Albums>(request).ConfigureAwait(false);
result = artistAlbumsResponse != null && artistAlbumsResponse.Data != null
? artistAlbumsResponse.Data
: null;

View file

@ -21,7 +21,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Wikipedia
HttpEncoder = httpEncoder;
}
public Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearch(string query, int resultsCount)
public Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearchAsync(string query, int resultsCount)
{
if(string.IsNullOrEmpty(query) || resultsCount == 0)
{

View file

@ -66,7 +66,7 @@ namespace Roadie.Library.Utility
using (var webClient = new WebClient())
{
webClient.Headers.Add("user-agent", UserAgent);
imageBytes = await webClient.DownloadDataTaskAsync(new Uri(url));
imageBytes = await webClient.DownloadDataTaskAsync(new Uri(url)).ConfigureAwait(false);
}
}
catch

View file

@ -1,5 +1,4 @@
using Mapster;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
@ -29,9 +28,10 @@ namespace Roadie.Api.Services
{
public class AdminService : ServiceBase, IAdminService
{
protected IHubContext<ScanActivityHub> ScanActivityHub { get; }
private IArtistLookupEngine ArtistLookupEngine { get; }
private IArtistService ArtistService { get; }
private IBookmarkService BookmarkService { get; }
private IEventMessageLogger EventMessageLogger { get; }
@ -39,12 +39,12 @@ namespace Roadie.Api.Services
private IGenreService GenreService { get; }
private ILabelService LabelService { get; }
private IArtistLookupEngine ArtistLookupEngine { get; }
private IReleaseLookupEngine ReleaseLookupEngine { get; }
private IBookmarkService BookmarkService { get; }
private IReleaseService ReleaseService { get; }
protected IHubContext<ScanActivityHub> ScanActivityHub { get; }
public AdminService(IRoadieSettings configuration, IHttpEncoder httpEncoder, IHttpContext httpContext,
IRoadieDbContext context, ICacheManager cacheManager, ILogger<ArtistService> logger,
IHubContext<ScanActivityHub> scanActivityHub, IFileDirectoryProcessorService fileDirectoryProcessorService, IArtistService artistService,
@ -67,21 +67,94 @@ namespace Roadie.Api.Services
BookmarkService = bookmarkService;
}
public async Task<OperationResult<bool>> DeleteArtist(User user, Guid artistId, bool deleteFolder)
private void EventMessageLogger_Messages(object sender, EventMessage e) => Task.WaitAll(LogAndPublishAsync(e.Message, e.Level));
private async Task LogAndPublishAsync(string message, LogLevel level = LogLevel.Trace)
{
switch (level)
{
case LogLevel.Trace:
Logger.LogTrace(message);
break;
case LogLevel.Debug:
Logger.LogDebug(message);
break;
case LogLevel.Information:
Logger.LogInformation(message);
break;
case LogLevel.Warning:
Logger.LogWarning(message);
break;
case LogLevel.Critical:
Logger.LogCritical(message);
break;
}
await ScanActivityHub.Clients.All.SendAsync("SendSystemActivityAsync", message).ConfigureAwait(false);
}
private async Task<OperationResult<bool>> ScanFolderAsync(User user, DirectoryInfo d, bool isReadOnly, bool doDeleteFiles = true)
{
var sw = new Stopwatch();
sw.Start();
long processedFiles = 0;
await LogAndPublishAsync($"** Processing Folder: [{d.FullName}]").ConfigureAwait(false);
long processedFolders = 0;
foreach (var folder in Directory.EnumerateDirectories(d.FullName).ToArray())
{
var directoryProcessResult = await FileDirectoryProcessorService.ProcessAsync(user: user,
folder: new DirectoryInfo(folder),
doJustInfo: isReadOnly,
doDeleteFiles: doDeleteFiles).ConfigureAwait(false);
processedFolders++;
processedFiles += SafeParser.ToNumber<int>(directoryProcessResult.AdditionalData["ProcessedFiles"]);
}
CacheManager.Clear();
if (!isReadOnly)
{
Services.FileDirectoryProcessorService.DeleteEmptyFolders(d, Logger);
}
sw.Stop();
var newScanHistory = new data.ScanHistory
{
UserId = user.Id,
NewArtists = FileDirectoryProcessorService.AddedArtistIds.Count(),
NewReleases = FileDirectoryProcessorService.AddedReleaseIds.Count(),
NewTracks = FileDirectoryProcessorService.AddedTrackIds.Count(),
TimeSpanInSeconds = (int)sw.Elapsed.TotalSeconds
};
DbContext.ScanHistories.Add(newScanHistory);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
await LogAndPublishAsync($"** Completed! Processed Folders [{processedFolders}], Processed Files [{processedFiles}], New Artists [{ newScanHistory.NewArtists }], New Releases [{ newScanHistory.NewReleases }], New Tracks [{ newScanHistory.NewTracks }] : Elapsed Time [{sw.Elapsed}]").ConfigureAwait(false);
return new OperationResult<bool>
{
Data = true,
IsSuccess = true,
OperationTime = sw.ElapsedMilliseconds
};
}
public async Task<OperationResult<bool>> DeleteArtistAsync(User user, Guid artistId, bool deleteFolder)
{
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var artist = DbContext.Artists.FirstOrDefault(x => x.RoadieId == artistId);
var artist = await DbContext.Artists.FirstOrDefaultAsync(x => x.RoadieId == artistId).ConfigureAwait(false);
if (artist == null)
{
await LogAndPublish($"DeleteArtist Unknown Artist [{artistId}]", LogLevel.Warning);
await LogAndPublishAsync($"DeleteArtist Unknown Artist [{artistId}]", LogLevel.Warning).ConfigureAwait(false);
return new OperationResult<bool>(true, $"Artist Not Found [{artistId}]");
}
try
{
var result = await ArtistService.Delete(user, artist, deleteFolder);
var result = await ArtistService.DeleteAsync(user, artist, deleteFolder).ConfigureAwait(false);
if (!result.IsSuccess)
{
return new OperationResult<bool>
@ -93,22 +166,22 @@ namespace Roadie.Api.Services
catch (Exception ex)
{
Logger.LogError(ex);
await LogAndPublish("Error deleting artist.");
await LogAndPublishAsync("Error deleting artist.").ConfigureAwait(false);
errors.Add(ex);
}
sw.Stop();
await LogAndPublish($"DeleteArtist `{artist}`, By User `{user}`", LogLevel.Information);
await LogAndPublishAsync($"DeleteArtist `{artist}`, By User `{user}`", LogLevel.Information).ConfigureAwait(false);
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
IsSuccess = errors.Count == 0,
Data = true,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<bool>> DeleteArtistReleases(User user, Guid artistId, bool doDeleteFiles = false)
public async Task<OperationResult<bool>> DeleteArtistReleasesAsync(User user, Guid artistId, bool doDeleteFiles = false)
{
var sw = new Stopwatch();
sw.Start();
@ -116,34 +189,34 @@ namespace Roadie.Api.Services
var artist = DbContext.Artists.FirstOrDefault(x => x.RoadieId == artistId);
if (artist == null)
{
await LogAndPublish($"DeleteArtistReleases Unknown Artist [{artistId}]", LogLevel.Warning);
await LogAndPublishAsync($"DeleteArtistReleases Unknown Artist [{artistId}]", LogLevel.Warning).ConfigureAwait(false);
return new OperationResult<bool>(true, $"Artist Not Found [{artistId}]");
}
try
{
await ReleaseService.DeleteReleases(user, DbContext.Releases.Where(x => x.ArtistId == artist.Id).Select(x => x.RoadieId).ToArray(), doDeleteFiles);
await DbContext.SaveChangesAsync();
await ReleaseService.DeleteReleasesAsync(user, DbContext.Releases.Where(x => x.ArtistId == artist.Id).Select(x => x.RoadieId).ToArray(), doDeleteFiles).ConfigureAwait(false);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.LogError(ex);
await LogAndPublish("Error deleting artist.");
await LogAndPublishAsync("Error deleting artist.").ConfigureAwait(false);
errors.Add(ex);
}
sw.Stop();
await LogAndPublish($"DeleteArtistReleases `{artist}`, By User `{user}`", LogLevel.Information);
await LogAndPublishAsync($"DeleteArtistReleases `{artist}`, By User `{user}`", LogLevel.Information).ConfigureAwait(false);
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
IsSuccess = errors.Count == 0,
Data = true,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<bool>> DeleteArtistSecondaryImage(User user, Guid artistId, int index)
public async Task<OperationResult<bool>> DeleteArtistSecondaryImageAsync(User user, Guid artistId, int index)
{
var sw = new Stopwatch();
sw.Start();
@ -151,7 +224,7 @@ namespace Roadie.Api.Services
var artist = DbContext.Artists.FirstOrDefault(x => x.RoadieId == artistId);
if (artist == null)
{
await LogAndPublish($"DeleteArtistSecondaryImage Unknown Artist [{artistId}]", LogLevel.Warning);
await LogAndPublishAsync($"DeleteArtistSecondaryImage Unknown Artist [{artistId}]", LogLevel.Warning).ConfigureAwait(false);
return new OperationResult<bool>(true, $"Artist Not Found [{artistId}]");
}
@ -169,22 +242,22 @@ namespace Roadie.Api.Services
catch (Exception ex)
{
Logger.LogError(ex);
await LogAndPublish("Error deleting artist secondary image.");
await LogAndPublishAsync("Error deleting artist secondary image.").ConfigureAwait(false);
errors.Add(ex);
}
sw.Stop();
await LogAndPublish($"DeleteArtistSecondaryImage `{artist}` Index [{index}], By User `{user}`", LogLevel.Information);
await LogAndPublishAsync($"DeleteArtistSecondaryImage `{artist}` Index [{index}], By User `{user}`", LogLevel.Information).ConfigureAwait(false);
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
IsSuccess = errors.Count == 0,
Data = true,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<bool>> DeleteGenre(User user, Guid genreId)
public async Task<OperationResult<bool>> DeleteGenreAsync(User user, Guid genreId)
{
var sw = new Stopwatch();
sw.Start();
@ -192,34 +265,34 @@ namespace Roadie.Api.Services
var genre = DbContext.Genres.FirstOrDefault(x => x.RoadieId == genreId);
if (genre == null)
{
await LogAndPublish($"DeleteLabel Unknown Genre [{genreId}]", LogLevel.Warning);
await LogAndPublishAsync($"DeleteLabel Unknown Genre [{genreId}]", LogLevel.Warning).ConfigureAwait(false);
return new OperationResult<bool>(true, $"Genre Not Found [{genreId}]");
}
try
{
await GenreService.Delete(user, genreId);
await GenreService.DeleteAsync(user, genreId).ConfigureAwait(false);
CacheManager.ClearRegion(genre.CacheRegion);
}
catch (Exception ex)
{
Logger.LogError(ex);
await LogAndPublish("Error deleting Genre.");
await LogAndPublishAsync("Error deleting Genre.").ConfigureAwait(false);
errors.Add(ex);
}
sw.Stop();
await LogAndPublish($"DeleteGenre `{genre}`, By User `{user}`", LogLevel.Information);
await LogAndPublishAsync($"DeleteGenre `{genre}`, By User `{user}`", LogLevel.Information).ConfigureAwait(false);
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
IsSuccess = errors.Count == 0,
Data = true,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<bool>> DeleteLabel(User user, Guid labelId)
public async Task<OperationResult<bool>> DeleteLabelAsync(User user, Guid labelId)
{
var sw = new Stopwatch();
sw.Start();
@ -227,34 +300,34 @@ namespace Roadie.Api.Services
var label = DbContext.Labels.FirstOrDefault(x => x.RoadieId == labelId);
if (label == null)
{
await LogAndPublish($"DeleteLabel Unknown Label [{labelId}]", LogLevel.Warning);
await LogAndPublishAsync($"DeleteLabel Unknown Label [{labelId}]", LogLevel.Warning).ConfigureAwait(false);
return new OperationResult<bool>(true, $"Label Not Found [{labelId}]");
}
try
{
await LabelService.Delete(user, labelId);
await LabelService.DeleteAsync(user, labelId).ConfigureAwait(false);
CacheManager.ClearRegion(label.CacheRegion);
}
catch (Exception ex)
{
Logger.LogError(ex);
await LogAndPublish("Error deleting Label.");
await LogAndPublishAsync("Error deleting Label.").ConfigureAwait(false);
errors.Add(ex);
}
sw.Stop();
await LogAndPublish($"DeleteLabel `{label}`, By User `{user}`", LogLevel.Information);
await LogAndPublishAsync($"DeleteLabel `{label}`, By User `{user}`", LogLevel.Information).ConfigureAwait(false);
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
IsSuccess = errors.Count == 0,
Data = true,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<bool>> DeleteRelease(User user, Guid releaseId, bool? doDeleteFiles)
public async Task<OperationResult<bool>> DeleteReleaseAsync(User user, Guid releaseId, bool? doDeleteFiles)
{
var sw = new Stopwatch();
sw.Start();
@ -266,31 +339,31 @@ namespace Roadie.Api.Services
{
if (release == null)
{
await LogAndPublish($"DeleteRelease Unknown Release [{releaseId}]", LogLevel.Warning);
await LogAndPublishAsync($"DeleteRelease Unknown Release [{releaseId}]", LogLevel.Warning).ConfigureAwait(false);
return new OperationResult<bool>(true, $"Release Not Found [{releaseId}]");
}
await ReleaseService.Delete(user, release, doDeleteFiles ?? false);
await ReleaseService.DeleteAsync(user, release, doDeleteFiles ?? false).ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.LogError(ex);
await LogAndPublish("Error deleting release.");
await LogAndPublishAsync("Error deleting release.").ConfigureAwait(false);
errors.Add(ex);
}
sw.Stop();
await LogAndPublish($"DeleteRelease `{release}`, By User `{user}`", LogLevel.Information);
await LogAndPublishAsync($"DeleteRelease `{release}`, By User `{user}`", LogLevel.Information).ConfigureAwait(false);
CacheManager.Clear();
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
IsSuccess = errors.Count == 0,
Data = true,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<bool>> DeleteReleaseSecondaryImage(User user, Guid releaseId, int index)
public async Task<OperationResult<bool>> DeleteReleaseSecondaryImageAsync(User user, Guid releaseId, int index)
{
var sw = new Stopwatch();
sw.Start();
@ -298,7 +371,7 @@ namespace Roadie.Api.Services
var release = DbContext.Releases.Include(x => x.Artist).FirstOrDefault(x => x.RoadieId == releaseId);
if (release == null)
{
await LogAndPublish($"DeleteReleaseSecondaryImage Unknown Release [{releaseId}]", LogLevel.Warning);
await LogAndPublishAsync($"DeleteReleaseSecondaryImage Unknown Release [{releaseId}]", LogLevel.Warning).ConfigureAwait(false);
return new OperationResult<bool>(true, $"Release Not Found [{releaseId}]");
}
@ -316,22 +389,22 @@ namespace Roadie.Api.Services
catch (Exception ex)
{
Logger.LogError(ex);
await LogAndPublish("Error deleting release secondary image.");
await LogAndPublishAsync("Error deleting release secondary image.").ConfigureAwait(false);
errors.Add(ex);
}
sw.Stop();
await LogAndPublish($"DeleteReleaseSecondaryImage `{release}` Index [{index}], By User `{user}`", LogLevel.Information);
await LogAndPublishAsync($"DeleteReleaseSecondaryImage `{release}` Index [{index}], By User `{user}`", LogLevel.Information).ConfigureAwait(false);
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
IsSuccess = errors.Count == 0,
Data = true,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<bool>> DeleteTracks(User user, IEnumerable<Guid> trackIds, bool? doDeleteFile)
public async Task<OperationResult<bool>> DeleteTracksAsync(User user, IEnumerable<Guid> trackIds, bool? doDeleteFile)
{
var sw = new Stopwatch();
sw.Start();
@ -348,12 +421,12 @@ namespace Roadie.Api.Services
{
if (track == null)
{
await LogAndPublish($"DeleteTracks Unknown Track [{trackId}]", LogLevel.Warning);
await LogAndPublishAsync($"DeleteTracks Unknown Track [{trackId}]", LogLevel.Warning).ConfigureAwait(false);
return new OperationResult<bool>(true, $"Track Not Found [{trackId}]");
}
DbContext.Tracks.Remove(track);
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
if (doDeleteFile ?? false)
{
string trackPath = null;
@ -375,33 +448,33 @@ namespace Roadie.Api.Services
}
catch (Exception ex)
{
Logger.LogError(ex, string.Format("Error Deleting File [{0}] For Track [{1}] Exception [{2}]", trackPath, track.Id, ex.Serialize()));
Logger.LogError(ex, $"Error Deleting File [{trackPath}] For Track [{track.Id}] Exception [{ex.Serialize()}]");
}
}
await ReleaseService.ScanReleaseFolder(user, track.ReleaseMedia.Release.RoadieId, false, track.ReleaseMedia.Release);
await BookmarkService.RemoveAllBookmarksForItem(BookmarkType.Track, track.Id);
await ReleaseService.ScanReleaseFolderAsync(user, track.ReleaseMedia.Release.RoadieId, false, track.ReleaseMedia.Release).ConfigureAwait(false);
await BookmarkService.RemoveAllBookmarksForItemAsync(BookmarkType.Track, track.Id).ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.LogError(ex);
await LogAndPublish("Error deleting track.");
await LogAndPublishAsync("Error deleting track.").ConfigureAwait(false);
errors.Add(ex);
}
sw.Stop();
await LogAndPublish($"DeleteTracks `{track}`, By User `{user}`", LogLevel.Warning);
await LogAndPublishAsync($"DeleteTracks `{track}`, By User `{user}`", LogLevel.Warning).ConfigureAwait(false);
}
CacheManager.Clear();
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
IsSuccess = errors.Count == 0,
Data = true,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<bool>> DeleteUser(User applicationUser, Guid userId)
public async Task<OperationResult<bool>> DeleteUserAsync(User applicationUser, Guid userId)
{
var sw = new Stopwatch();
sw.Start();
@ -412,7 +485,7 @@ namespace Roadie.Api.Services
{
var ex = new Exception("User cannot self.");
Logger.LogError(ex);
await LogAndPublish("Error deleting user.");
await LogAndPublishAsync("Error deleting user.").ConfigureAwait(false);
errors.Add(ex);
}
@ -420,12 +493,12 @@ namespace Roadie.Api.Services
{
if (user == null)
{
await LogAndPublish($"DeleteUser Unknown User [{userId}]", LogLevel.Warning);
await LogAndPublishAsync($"DeleteUser Unknown User [{userId}]", LogLevel.Warning).ConfigureAwait(false);
return new OperationResult<bool>(true, $"User Not Found [{userId}]");
}
DbContext.Users.Remove(user);
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
var userImageFilename = user.PathToImage(Configuration);
if (File.Exists(userImageFilename))
{
@ -435,16 +508,16 @@ namespace Roadie.Api.Services
catch (Exception ex)
{
Logger.LogError(ex);
await LogAndPublish("Error deleting user.");
await LogAndPublishAsync("Error deleting user.").ConfigureAwait(false);
errors.Add(ex);
}
sw.Stop();
await LogAndPublish($"DeleteUser `{user}`, By User `{user}`", LogLevel.Warning);
await LogAndPublishAsync($"DeleteUser `{user}`, By User `{user}`", LogLevel.Warning).ConfigureAwait(false);
CacheManager.Clear();
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
IsSuccess = errors.Count == 0,
Data = true,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
@ -454,7 +527,7 @@ namespace Roadie.Api.Services
/// <summary>
/// This is a very simple way to seed the database or setup configuration when the first (who becomes "Admin") user registers
/// </summary>
public async Task<OperationResult<bool>> DoInitialSetup(User user, UserManager<User> userManager)
public async Task<OperationResult<bool>> DoInitialSetupAsync(User user, UserManager<User> userManager)
{
var sw = new Stopwatch();
sw.Start();
@ -483,10 +556,10 @@ namespace Roadie.Api.Services
Description = "Users who have Edit Permissions",
NormalizedName = "EDITOR"
});
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
// Add given user to Admin role
await userManager.AddToRoleAsync(user, "Admin");
await userManager.AddToRoleAsync(user, "Admin").ConfigureAwait(false);
// Create special system artists of 'Sound Tracks' and 'Various Artists'
DbContext.Artists.Add(new data.Artist
@ -515,7 +588,7 @@ namespace Roadie.Api.Services
Tags = "compilations|various",
URLs = "https://en.wikipedia.org/wiki/Compilation_album"
});
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
return new OperationResult<bool>
{
@ -525,7 +598,7 @@ namespace Roadie.Api.Services
};
}
public Task<OperationResult<Dictionary<string, List<string>>>> MissingCollectionReleases(User user)
public Task<OperationResult<Dictionary<string, List<string>>>> MissingCollectionReleasesAsync(User user)
{
var sw = Stopwatch.StartNew();
sw.Start();
@ -567,7 +640,7 @@ namespace Roadie.Api.Services
sw.Stop();
return Task.FromResult(new OperationResult<Dictionary<string, List<string>>>
{
Data = missingData.OrderBy(x => x.Value.Count()).ToDictionary(x => x.Key, x => x.Value),
Data = missingData.OrderBy(x => x.Value.Count).ToDictionary(x => x.Key, x => x.Value),
IsSuccess = true,
OperationTime = sw.ElapsedMilliseconds
});
@ -619,13 +692,10 @@ namespace Roadie.Api.Services
Directory.CreateDirectory(Configuration.LabelImageFolder);
Logger.LogInformation($"Created Label Image Folder [{Configuration.LabelImageFolder}]");
}
if (Configuration.DbContextToUse != DbContexts.MySQL)
if (Configuration.DbContextToUse != DbContexts.MySQL && !Directory.Exists(Configuration.FileDatabaseOptions.DatabaseFolder))
{
if (!Directory.Exists(Configuration.FileDatabaseOptions.DatabaseFolder))
{
Directory.CreateDirectory(Configuration.FileDatabaseOptions.DatabaseFolder);
Logger.LogInformation($"Created File Database Folder [{Configuration.FileDatabaseOptions.DatabaseFolder}]");
}
Directory.CreateDirectory(Configuration.FileDatabaseOptions.DatabaseFolder);
Logger.LogInformation($"Created File Database Folder [{Configuration.FileDatabaseOptions.DatabaseFolder}]");
}
}
catch (Exception ex)
@ -640,7 +710,7 @@ namespace Roadie.Api.Services
Logger.LogInformation($"Administration startup tasks completed, elapsed time [{ sw.ElapsedMilliseconds }]");
}
public async Task<OperationResult<bool>> ScanAllCollections(User user, bool isReadOnly = false, bool doPurgeFirst = false)
public async Task<OperationResult<bool>> ScanAllCollectionsAsync(User user, bool isReadOnly = false, bool doPurgeFirst = false)
{
var sw = new Stopwatch();
sw.Start();
@ -652,7 +722,7 @@ namespace Roadie.Api.Services
{
try
{
var result = await ScanCollection(user, collection.RoadieId, isReadOnly, doPurgeFirst, false).ConfigureAwait(false);
var result = await ScanCollectionAsync(user, collection.RoadieId, isReadOnly, doPurgeFirst, false).ConfigureAwait(false);
if (!result.IsSuccess)
{
errors.AddRange(result.Errors);
@ -661,7 +731,7 @@ namespace Roadie.Api.Services
}
catch (Exception ex)
{
await LogAndPublish(ex.ToString(), LogLevel.Error).ConfigureAwait(false);
await LogAndPublishAsync(ex.ToString(), LogLevel.Error).ConfigureAwait(false);
errors.Add(ex);
}
}
@ -671,7 +741,7 @@ namespace Roadie.Api.Services
await UpdateReleaseRank(updatedReleaseId).ConfigureAwait(false);
}
sw.Stop();
await LogAndPublish($"ScanAllCollections, By User `{user}`, Updated Release Count [{updatedReleaseIds.Distinct().Count()}], ElapsedTime [{sw.ElapsedMilliseconds}]", LogLevel.Warning).ConfigureAwait(false);
await LogAndPublishAsync($"ScanAllCollections, By User `{user}`, Updated Release Count [{updatedReleaseIds.Distinct().Count()}], ElapsedTime [{sw.ElapsedMilliseconds}]", LogLevel.Warning).ConfigureAwait(false);
return new OperationResult<bool>
{
IsSuccess = errors.Count == 0,
@ -681,7 +751,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> ScanArtist(User user, Guid artistId, bool isReadOnly = false)
public async Task<OperationResult<bool>> ScanArtistAsync(User user, Guid artistId, bool isReadOnly = false)
{
var sw = Stopwatch.StartNew();
@ -689,18 +759,18 @@ namespace Roadie.Api.Services
var artist = DbContext.Artists.FirstOrDefault(x => x.RoadieId == artistId);
if (artist == null)
{
await LogAndPublish($"ScanArtist Unknown Artist [{artistId}]", LogLevel.Warning);
await LogAndPublishAsync($"ScanArtist Unknown Artist [{artistId}]", LogLevel.Warning).ConfigureAwait(false);
return new OperationResult<bool>(true, $"Artist Not Found [{artistId}]");
}
try
{
var result = await ArtistService.ScanArtistReleasesFolders(user, artist.RoadieId, Configuration.LibraryFolder, isReadOnly);
await ArtistService.ScanArtistReleasesFoldersAsync(user, artist.RoadieId, Configuration.LibraryFolder, isReadOnly).ConfigureAwait(false);
CacheManager.ClearRegion(artist.CacheRegion);
}
catch (Exception ex)
{
await LogAndPublish(ex.ToString(), LogLevel.Error);
await LogAndPublishAsync(ex.ToString(), LogLevel.Error).ConfigureAwait(false);
errors.Add(ex);
}
@ -713,56 +783,52 @@ namespace Roadie.Api.Services
NewTracks = ReleaseService.AddedTrackIds.Count(),
TimeSpanInSeconds = (int)sw.Elapsed.TotalSeconds
});
await DbContext.SaveChangesAsync();
await UpdateArtistRank(artist.Id, true);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
await UpdateArtistRank(artist.Id, true).ConfigureAwait(false);
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
IsSuccess = errors.Count == 0,
AdditionalData = new Dictionary<string, object> { { "artistAverage", artist.Rating } },
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<bool>> ScanArtists(User user, IEnumerable<Guid> artistIds, bool isReadOnly = false)
public async Task<OperationResult<bool>> ScanArtistsAsync(User user, IEnumerable<Guid> artistIds, bool isReadOnly = false)
{
var sw = Stopwatch.StartNew();
var errors = new List<Exception>();
foreach (var artistId in artistIds)
{
var result = await ScanArtist(user, artistId, isReadOnly);
if (!result.IsSuccess)
var result = await ScanArtistAsync(user, artistId, isReadOnly).ConfigureAwait(false);
if (!result.IsSuccess && (result.Errors?.Any() ?? false))
{
if (result.Errors?.Any() ?? false)
{
errors.AddRange(result.Errors);
}
errors.AddRange(result.Errors);
}
}
sw.Stop();
await LogAndPublish($"** Completed! ScanArtists: Artist Count [{ artistIds.Count() }], Elapsed Time [{sw.Elapsed}]");
await LogAndPublishAsync($"** Completed! ScanArtists: Artist Count [{ artistIds.Count() }], Elapsed Time [{sw.Elapsed}]").ConfigureAwait(false);
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
IsSuccess = errors.Count == 0,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<bool>> ScanCollection(User user, Guid collectionId, bool isReadOnly = false, bool doPurgeFirst = false, bool doUpdateRanks = true)
public async Task<OperationResult<bool>> ScanCollectionAsync(User user, Guid collectionId, bool isReadOnly = false, bool doPurgeFirst = false, bool doUpdateRanks = true)
{
var sw = new Stopwatch();
sw.Start();
var releaseIdsInCollection = new List<int>();
var updatedReleaseIds = new List<int>();
var result = new List<data.PositionArtistRelease>();
var errors = new List<Exception>();
var collection = await DbContext.Collections.FirstOrDefaultAsync(x => x.RoadieId == collectionId).ConfigureAwait(false);
if (collection == null)
{
await LogAndPublish($"ScanCollection Unknown Collection [{collectionId}]", LogLevel.Warning).ConfigureAwait(false);
await LogAndPublishAsync($"ScanCollection Unknown Collection [{collectionId}]", LogLevel.Warning).ConfigureAwait(false);
return new OperationResult<bool>(true, $"Collection Not Found [{collectionId}]");
}
@ -770,7 +836,7 @@ namespace Roadie.Api.Services
{
if (doPurgeFirst)
{
await LogAndPublish($"ScanCollection Purging Collection [{collectionId}]", LogLevel.Warning).ConfigureAwait(false);
await LogAndPublishAsync($"ScanCollection Purging Collection [{collectionId}]", LogLevel.Warning).ConfigureAwait(false);
var crs = await DbContext.CollectionReleases.Where(x => x.CollectionId == collection.Id).ToArrayAsync().ConfigureAwait(false);
DbContext.CollectionReleases.RemoveRange(crs);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
@ -790,8 +856,8 @@ namespace Roadie.Api.Services
data.Release release = null;
var isArtistNameDbKey = csvRelease.Artist.StartsWith(Roadie.Library.Data.Collection.DatabaseIdKey);
int? artistId = isArtistNameDbKey ? SafeParser.ToNumber<int?>(csvRelease.Artist.Replace(Roadie.Library.Data.Collection.DatabaseIdKey, "")) : null;
if(artistId.HasValue)
int? artistId = isArtistNameDbKey ? SafeParser.ToNumber<int?>(csvRelease.Artist.Replace(Roadie.Library.Data.Collection.DatabaseIdKey, string.Empty)) : null;
if (artistId.HasValue)
{
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == artistId.Value);
if (artist != null)
@ -802,9 +868,9 @@ namespace Roadie.Api.Services
else
{
artistsMatchingName = await ArtistLookupEngine.DatabaseQueryForArtistName(csvRelease.Artist).ConfigureAwait(false);
if (artistsMatchingName == null || !artistsMatchingName.Any())
if (artistsMatchingName?.Any() != true)
{
await LogAndPublish($"CSV Position [{ csvRelease.Position }] Unable To Find Artist [{csvRelease.Artist}]", LogLevel.Warning).ConfigureAwait(false);
await LogAndPublishAsync($"CSV Position [{ csvRelease.Position }] Unable To Find Artist [{csvRelease.Artist}]", LogLevel.Warning).ConfigureAwait(false);
csvRelease.Status = Statuses.Missing;
await DbContext.CollectionMissings.AddAsync(new data.CollectionMissing
{
@ -817,13 +883,13 @@ namespace Roadie.Api.Services
}
else if (artistsMatchingName.Count() > 1)
{
await LogAndPublish($"CSV Position [{ csvRelease.Position }] Found [{ artistsMatchingName.Count() }] Artists by [{csvRelease.Artist}]", LogLevel.Information).ConfigureAwait(false);
await LogAndPublishAsync($"CSV Position [{ csvRelease.Position }] Found [{ artistsMatchingName.Count() }] Artists by [{csvRelease.Artist}]", LogLevel.Information).ConfigureAwait(false);
}
}
foreach (var artist in artistsMatchingName)
{
var isReleaseNameDbKey = csvRelease.Release.StartsWith(Roadie.Library.Data.Collection.DatabaseIdKey);
int? releaseId = isReleaseNameDbKey ? SafeParser.ToNumber<int?>(csvRelease.Release.Replace(Roadie.Library.Data.Collection.DatabaseIdKey, "")) : null;
int? releaseId = isReleaseNameDbKey ? SafeParser.ToNumber<int?>(csvRelease.Release.Replace(Roadie.Library.Data.Collection.DatabaseIdKey, string.Empty)) : null;
if (releaseId.HasValue)
{
release = await DbContext.Releases.FirstOrDefaultAsync(x => x.Id == releaseId.Value).ConfigureAwait(false);
@ -840,7 +906,7 @@ namespace Roadie.Api.Services
if (release == null)
{
await LogAndPublish($"CSV Position [{ csvRelease.Position }] Unable To Find Release [{csvRelease.Release}], for Artist [{csvRelease.Artist}]", LogLevel.Warning).ConfigureAwait(false);
await LogAndPublishAsync($"CSV Position [{ csvRelease.Position }] Unable To Find Release [{csvRelease.Release}], for Artist [{csvRelease.Artist}]", LogLevel.Warning).ConfigureAwait(false);
csvRelease.Status = Statuses.Missing;
await DbContext.CollectionMissings.AddAsync(new data.CollectionMissing
{
@ -867,7 +933,7 @@ namespace Roadie.Api.Services
CollectionId = collection.Id,
ReleaseId = release.Id,
ListNumber = csvRelease.Position
});
}).ConfigureAwait(false);
updated = true;
}
// If Item in Collection is at different List number update CollectionRelease
@ -906,16 +972,16 @@ namespace Roadie.Api.Services
}
var collectionReleasesToRemove = await (from cr in DbContext.CollectionReleases
where cr.CollectionId == collection.Id
where !releaseIdsInCollection.Contains(cr.ReleaseId)
select cr).ToArrayAsync().ConfigureAwait(false);
if (collectionReleasesToRemove.Any())
where cr.CollectionId == collection.Id
where !releaseIdsInCollection.Contains(cr.ReleaseId)
select cr).ToArrayAsync().ConfigureAwait(false);
if (collectionReleasesToRemove.Length > 0)
{
await LogAndPublish($"Removing [{collectionReleasesToRemove.Count()}] Stale Release Records from Collection.", LogLevel.Information);
await LogAndPublishAsync($"Removing [{collectionReleasesToRemove.Length}] Stale Release Records from Collection.", LogLevel.Information).ConfigureAwait(false);
DbContext.CollectionReleases.RemoveRange(collectionReleasesToRemove);
}
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
if (doUpdateRanks)
{
foreach (var updatedReleaseId in updatedReleaseIds)
@ -933,31 +999,23 @@ namespace Roadie.Api.Services
}
sw.Stop();
Logger.LogWarning(string.Format("RescanCollection `{0}`, By User `{1}`, ElapsedTime [{2}]", collection, user, sw.ElapsedMilliseconds));
Logger.LogWarning($"RescanCollection `{collection}`, By User `{user}`, ElapsedTime [{sw.ElapsedMilliseconds}]");
return new OperationResult<bool>
{
AdditionalData = new Dictionary<string, object> { { "updatedReleaseIds", updatedReleaseIds.ToArray() } },
IsSuccess = !errors.Any(),
IsSuccess = errors.Count == 0,
Data = true,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<bool>> ScanInboundFolder(User user, bool isReadOnly = false)
{
var d = new DirectoryInfo(Configuration.InboundFolder);
return await ScanFolder(user, d, isReadOnly);
}
public Task<OperationResult<bool>> ScanInboundFolderAsync(User user, bool isReadOnly = false) => ScanFolderAsync(user, new DirectoryInfo(Configuration.InboundFolder), isReadOnly);
public async Task<OperationResult<bool>> ScanLibraryFolder(User user, bool isReadOnly = false)
{
var d = new DirectoryInfo(Configuration.LibraryFolder);
return await ScanFolder(user, d, isReadOnly, false);
}
public Task<OperationResult<bool>> ScanLibraryFolderAsync(User user, bool isReadOnly = false) => ScanFolderAsync(user, new DirectoryInfo(Configuration.LibraryFolder), isReadOnly, false);
public async Task<OperationResult<bool>> ScanRelease(User user, Guid releaseId, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false)
public async Task<OperationResult<bool>> ScanReleaseAsync(User user, Guid releaseId, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false)
{
var sw = new Stopwatch();
sw.Start();
@ -969,17 +1027,17 @@ namespace Roadie.Api.Services
.FirstOrDefault(x => x.RoadieId == releaseId);
if (release == null)
{
await LogAndPublish($"ScanRelease Unknown Release [{releaseId}]", LogLevel.Warning);
await LogAndPublishAsync($"ScanRelease Unknown Release [{releaseId}]", LogLevel.Warning).ConfigureAwait(false);
return new OperationResult<bool>(true, $"Release Not Found [{releaseId}]");
}
try
{
var result = await ReleaseService.ScanReleaseFolder(user, release.RoadieId, isReadOnly, release);
await ReleaseService.ScanReleaseFolderAsync(user, release.RoadieId, isReadOnly, release).ConfigureAwait(false);
}
catch (Exception ex)
{
await LogAndPublish(ex.ToString(), LogLevel.Error);
await LogAndPublishAsync(ex.ToString(), LogLevel.Error).ConfigureAwait(false);
errors.Add(ex);
}
@ -992,43 +1050,40 @@ namespace Roadie.Api.Services
NewTracks = ReleaseService.AddedTrackIds.Count(),
TimeSpanInSeconds = (int)sw.Elapsed.TotalSeconds
});
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
IsSuccess = errors.Count == 0,
Data = true,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<bool>> ScanReleases(User user, IEnumerable<Guid> releaseIds, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false)
public async Task<OperationResult<bool>> ScanReleasesAsync(User user, IEnumerable<Guid> releaseIds, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false)
{
var sw = Stopwatch.StartNew();
var errors = new List<Exception>();
foreach (var releaseId in releaseIds)
{
var result = await ScanRelease(user, releaseId, isReadOnly, wasDoneForInvalidTrackPlay);
if (!result.IsSuccess)
var result = await ScanReleaseAsync(user, releaseId, isReadOnly, wasDoneForInvalidTrackPlay).ConfigureAwait(false);
if (!result.IsSuccess && (result.Errors?.Any() ?? false))
{
if (result.Errors?.Any() ?? false)
{
errors.AddRange(result.Errors);
}
errors.AddRange(result.Errors);
}
}
sw.Stop();
await LogAndPublish($"** Completed! ScanReleases: Release Count [{ releaseIds.Count() }], Elapsed Time [{sw.Elapsed}]");
await LogAndPublishAsync($"** Completed! ScanReleases: Release Count [{ releaseIds.Count() }], Elapsed Time [{sw.Elapsed}]").ConfigureAwait(false);
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
IsSuccess = errors.Count == 0,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<bool>> UpdateInviteTokenUsed(Guid? tokenId)
public async Task<OperationResult<bool>> UpdateInviteTokenUsedAsync(Guid? tokenId)
{
var sw = new Stopwatch();
sw.Start();
@ -1044,17 +1099,17 @@ namespace Roadie.Api.Services
}
token.Status = Statuses.Complete;
token.LastUpdated = DateTime.UtcNow;
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
IsSuccess = errors.Count == 0,
Data = true,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<bool>> ValidateInviteToken(Guid? tokenId)
public async Task<OperationResult<bool>> ValidateInviteTokenAsync(Guid? tokenId)
{
var sw = new Stopwatch();
sw.Start();
@ -1072,7 +1127,7 @@ namespace Roadie.Api.Services
{
token.Status = Statuses.Expired;
token.LastUpdated = DateTime.UtcNow;
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
return new OperationResult<bool>(true, $"Invite Token [{tokenId}] Expired [{ token.ExpiresDate }]");
}
if (token.Status == Statuses.Complete)
@ -1081,84 +1136,11 @@ namespace Roadie.Api.Services
}
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
IsSuccess = errors.Count == 0,
Data = true,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
private void EventMessageLogger_Messages(object sender, EventMessage e) => Task.WaitAll(LogAndPublish(e.Message, e.Level));
private async Task LogAndPublish(string message, LogLevel level = LogLevel.Trace)
{
switch (level)
{
case LogLevel.Trace:
Logger.LogTrace(message);
break;
case LogLevel.Debug:
Logger.LogDebug(message);
break;
case LogLevel.Information:
Logger.LogInformation(message);
break;
case LogLevel.Warning:
Logger.LogWarning(message);
break;
case LogLevel.Critical:
Logger.LogCritical(message);
break;
}
await ScanActivityHub.Clients.All.SendAsync("SendSystemActivity", message).ConfigureAwait(false);
}
private async Task<OperationResult<bool>> ScanFolder(User user, DirectoryInfo d, bool isReadOnly, bool doDeleteFiles = true)
{
var sw = new Stopwatch();
sw.Start();
long processedFiles = 0;
await LogAndPublish($"** Processing Folder: [{d.FullName}]");
long processedFolders = 0;
foreach (var folder in Directory.EnumerateDirectories(d.FullName).ToArray())
{
var directoryProcessResult = await FileDirectoryProcessorService.Process(user:user,
folder: new DirectoryInfo(folder),
doJustInfo: isReadOnly,
doDeleteFiles: doDeleteFiles);
processedFolders++;
processedFiles += SafeParser.ToNumber<int>(directoryProcessResult.AdditionalData["ProcessedFiles"]);
}
CacheManager.Clear();
if (!isReadOnly)
{
Services.FileDirectoryProcessorService.DeleteEmptyFolders(d, Logger);
}
sw.Stop();
var newScanHistory = new data.ScanHistory
{
UserId = user.Id,
NewArtists = FileDirectoryProcessorService.AddedArtistIds.Count(),
NewReleases = FileDirectoryProcessorService.AddedReleaseIds.Count(),
NewTracks = FileDirectoryProcessorService.AddedTrackIds.Count(),
TimeSpanInSeconds = (int)sw.Elapsed.TotalSeconds
};
DbContext.ScanHistories.Add(newScanHistory);
await DbContext.SaveChangesAsync();
await LogAndPublish($"** Completed! Processed Folders [{processedFolders}], Processed Files [{processedFiles}], New Artists [{ newScanHistory.NewArtists }], New Releases [{ newScanHistory.NewReleases }], New Tracks [{ newScanHistory.NewTracks }] : Elapsed Time [{sw.Elapsed}]");
return new OperationResult<bool>
{
Data = true,
IsSuccess = true,
OperationTime = sw.ElapsedMilliseconds
};
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,4 @@
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Roadie.Library;
using Roadie.Library.Caching;
@ -20,7 +19,6 @@ using System.Diagnostics;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using data = Roadie.Library.Data;
using models = Roadie.Library.Models;
namespace Roadie.Api.Services
@ -41,30 +39,7 @@ namespace Roadie.Api.Services
UserService = userService;
}
/// <summary>
/// When a bookmarkable item gets deleted then delete any bookmarks to that item, since its a generic column there is not FK setup.
/// </summary>
public async Task<OperationResult<bool>> RemoveAllBookmarksForItem(BookmarkType type, int id)
{
var bookmarks = await DbContext.Bookmarks.Include(x => x.User)
.Where(x => x.BookmarkType == type && x.BookmarkTargetId == id)
.ToListAsync();
var users = bookmarks.Select(x => x.User).ToList().Distinct();
DbContext.Bookmarks.RemoveRange(bookmarks);
await DbContext.SaveChangesAsync();
foreach(var user in users)
{
CacheManager.ClearRegion(user.CacheRegion);
}
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
public async Task<Library.Models.Pagination.PagedResult<models.BookmarkList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, BookmarkType? filterType = null)
public async Task<Library.Models.Pagination.PagedResult<models.BookmarkList>> ListAsync(User roadieUser, PagedRequest request, bool? doRandomize = false, BookmarkType? filterType = null)
{
var sw = new Stopwatch();
sw.Start();
@ -95,14 +70,19 @@ namespace Roadie.Api.Services
var rowCount = result.Count();
var rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
var user = await GetUser(roadieUser.UserId);
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
foreach (var row in rows)
{
switch (row.Type)
{
case BookmarkType.Artist:
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
if (artist == null) continue;
if (artist == null)
{
continue;
}
row.Bookmark = new models.DataToken
{
Text = artist.Name,
@ -117,7 +97,11 @@ namespace Roadie.Api.Services
case BookmarkType.Release:
var release = DbContext.Releases.Include(x => x.Artist)
.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
if (release == null) continue;
if (release == null)
{
continue;
}
row.Bookmark = new models.DataToken
{
Text = release.Title,
@ -137,7 +121,11 @@ namespace Roadie.Api.Services
.Include(x => x.ReleaseMedia.Release.Artist)
.Include(x => x.TrackArtist)
.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
if (track == null) continue;
if (track == null)
{
continue;
}
row.Bookmark = new models.DataToken
{
Text = track.Title,
@ -165,7 +153,11 @@ namespace Roadie.Api.Services
var playlist = DbContext.Playlists
.Include(x => x.User)
.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
if (playlist == null) continue;
if (playlist == null)
{
continue;
}
row.Bookmark = new models.DataToken
{
Text = playlist.Name,
@ -180,7 +172,11 @@ namespace Roadie.Api.Services
case BookmarkType.Collection:
var collection = DbContext.Collections.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
if (collection == null) continue;
if (collection == null)
{
continue;
}
row.Bookmark = new models.DataToken
{
Text = collection.Name,
@ -196,7 +192,11 @@ namespace Roadie.Api.Services
case BookmarkType.Label:
var label = DbContext.Labels.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
if (label == null) continue;
if (label == null)
{
continue;
}
row.Bookmark = new models.DataToken
{
Text = label.Name,
@ -207,8 +207,7 @@ namespace Roadie.Api.Services
row.SortName = label.SortName ?? label.Name;
break;
}
;
};
sw.Stop();
return new Library.Models.Pagination.PagedResult<models.BookmarkList>
{
@ -219,5 +218,29 @@ namespace Roadie.Api.Services
Rows = rows
};
}
/// <summary>
/// When a bookmarkable item gets deleted then delete any bookmarks to that item, since its a generic column there is not FK setup.
/// </summary>
public async Task<OperationResult<bool>> RemoveAllBookmarksForItemAsync(BookmarkType type, int id)
{
var bookmarks = await DbContext.Bookmarks.Include(x => x.User)
.Where(x => x.BookmarkType == type && x.BookmarkTargetId == id)
.ToListAsync()
.ConfigureAwait(false);
var users = bookmarks.Select(x => x.User).ToList().Distinct();
DbContext.Bookmarks.RemoveRange(bookmarks);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
foreach (var user in users)
{
CacheManager.ClearRegion(user.CacheRegion);
}
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
}
}

View file

@ -43,307 +43,7 @@ namespace Roadie.Api.Services
BookmarkService = bookmarkService;
}
/// <summary>
/// Get blank Collection to add
/// </summary>
/// <param name="roadieUser"></param>
/// <returns></returns>
public OperationResult<Collection> Add(User roadieUser)
{
var sw = Stopwatch.StartNew();
sw.Start();
var id = Guid.Empty;
var collection = new data.Collection
{
Status = Statuses.New
};
var result = collection.Adapt<Collection>();
result.Id = id;
result.Thumbnail = ImageHelper.MakeNewImage(HttpContext,"collection");
result.MediumThumbnail = ImageHelper.MakeNewImage(HttpContext,"collection");
result.Maintainer = new DataToken
{
Value = roadieUser.UserId.ToString(),
Text = roadieUser.UserName
};
sw.Stop();
return new OperationResult<Collection>
{
Data = result,
IsSuccess = true,
OperationTime = sw.ElapsedMilliseconds
};
}
public async Task<OperationResult<Collection>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null)
{
var sw = Stopwatch.StartNew();
sw.Start();
var cacheKey = string.Format("urn:collection_by_id_operation:{0}:{1}", id, includes == null ? "0" : string.Join("|", includes));
var result = await CacheManager.GetAsync(cacheKey, async () =>
{
return await CollectionByIdAction(id, includes);
}, data.Artist.CacheRegionUrn(id));
sw.Stop();
if (result?.Data != null && roadieUser != null)
{
var userBookmarkResult = await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Collection);
if (userBookmarkResult.IsSuccess)
{
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x?.Bookmark?.Value == result?.Data?.Id?.ToString()) != null;
}
if (result.Data.Comments.Any())
{
var commentIds = result.Data.Comments.Select(x => x.DatabaseId).ToArray();
var userCommentReactions = (from cr in DbContext.CommentReactions
where commentIds.Contains(cr.CommentId)
where cr.UserId == roadieUser.Id
select cr).ToArray();
foreach (var comment in result.Data.Comments)
{
var userCommentReaction =
userCommentReactions.FirstOrDefault(x => x.CommentId == comment.DatabaseId);
comment.IsDisliked = userCommentReaction?.ReactionValue == CommentReaction.Dislike;
comment.IsLiked = userCommentReaction?.ReactionValue == CommentReaction.Like;
}
}
}
return new OperationResult<Collection>(result.Messages)
{
Data = result?.Data,
IsNotFoundResult = result?.IsNotFoundResult ?? false,
Errors = result?.Errors,
IsSuccess = result?.IsSuccess ?? false,
OperationTime = sw.ElapsedMilliseconds
};
}
public async Task<OperationResult<bool>> DeleteCollection(User user, Guid id)
{
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var collection = DbContext.Collections.FirstOrDefault(x => x.RoadieId == id);
if (collection == null) return new OperationResult<bool>(true, $"Collection Not Found [{id}]");
if (!user.IsEditor)
{
Logger.LogWarning($"DeleteCollection: Access Denied: `{collection}`, By User `{user}`");
var r = new OperationResult<bool>("Access Denied");
r.IsAccessDeniedResult = true;
return r;
}
try
{
DbContext.Collections.Remove(collection);
await DbContext.SaveChangesAsync();
await BookmarkService.RemoveAllBookmarksForItem(BookmarkType.Collection, collection.Id);
var collectionImageFilename = collection.PathToImage(Configuration);
if (File.Exists(collectionImageFilename))
{
File.Delete(collectionImageFilename);
}
}
catch (Exception ex)
{
Logger.LogError(ex);
errors.Add(ex);
}
sw.Stop();
Logger.LogWarning($"DeleteCollection `{collection}`, By User `{user}`");
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
Data = true,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public Task<Library.Models.Pagination.PagedResult<CollectionList>> List(User roadieUser, PagedRequest request,
bool? doRandomize = false, Guid? releaseId = null, Guid? artistId = null)
{
var sw = new Stopwatch();
sw.Start();
IQueryable<data.Collection> collections = null;
if (artistId.HasValue)
{
collections = (from cr in DbContext.CollectionReleases
join c in DbContext.Collections on cr.CollectionId equals c.Id
join r in DbContext.Releases on cr.ReleaseId equals r.Id
join a in DbContext.Artists on r.ArtistId equals a.Id
where a.RoadieId == artistId
select c).Distinct();
}
else if (releaseId.HasValue)
{
collections = (from cr in DbContext.CollectionReleases
join c in DbContext.Collections on cr.CollectionId equals c.Id
join r in DbContext.Releases on cr.ReleaseId equals r.Id
where r.RoadieId == releaseId
select c).Distinct();
}
else
{
collections = DbContext.Collections;
}
var normalizedFilterValue = !string.IsNullOrEmpty(request.FilterValue)
? request.FilterValue.ToAlphanumericName()
: null;
var result = from c in collections
let collectionCount = (from crc in DbContext.CollectionReleases
where crc.CollectionId == c.Id
select crc.Id).Count()
where string.IsNullOrEmpty(normalizedFilterValue) || (
c.Name.ToLower().Contains(normalizedFilterValue) ||
c.SortName.ToLower().Contains(normalizedFilterValue) ||
c.AlternateNames.ToLower().Contains(normalizedFilterValue)
)
where request.FilterToStatusValue == Statuses.Ok || c.Status == request.FilterToStatusValue
select new CollectionList
{
DatabaseId = c.Id,
Collection = new DataToken
{
Text = c.Name,
Value = c.RoadieId.ToString()
},
Id = c.RoadieId,
CollectionCount = c.CollectionCount,
CollectionType = (c.CollectionType ?? CollectionType.Unknown).ToString(),
CollectionFoundCount = collectionCount,
CreatedDate = c.CreatedDate,
IsLocked = c.IsLocked,
LastUpdated = c.LastUpdated,
Thumbnail = ImageHelper.MakeCollectionThumbnailImage(Configuration, HttpContext, c.RoadieId)
};
var sortBy = string.IsNullOrEmpty(request.Sort)
? request.OrderValue(new Dictionary<string, string> { { "Collection.Text", "ASC" } })
: request.OrderValue();
var rowCount = result.Count();
var rows = result
.OrderBy(sortBy)
.Skip(request.SkipValue)
.Take(request.LimitValue)
.ToArray();
if (request.FilterToStatusValue == Statuses.Incomplete)
{
rows = rows.OrderByDescending(x => x.PercentComplete).ThenBy(x => x.SortName).ToArray();
}
sw.Stop();
return Task.FromResult(new Library.Models.Pagination.PagedResult<CollectionList>
{
TotalCount = rowCount,
CurrentPage = request.PageValue,
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
OperationTime = sw.ElapsedMilliseconds,
Rows = rows
});
}
/// <summary>
/// Updates (or Adds) Collection
/// </summary>
public async Task<OperationResult<bool>> UpdateCollection(User user, Collection model)
{
var isNew = model.Id == Guid.Empty;
var now = DateTime.UtcNow;
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var collection = new data.Collection();
if (!isNew)
{
collection = DbContext.Collections.FirstOrDefault(x => x.RoadieId == model.Id);
if (collection == null)
{
return new OperationResult<bool>(true, string.Format("Collection Not Found [{0}]", model.Id));
}
// If collection is being renamed, see if collection already exists with new model supplied name
var collectionName = collection.SortNameValue;
var collectionModelName = model.SortNameValue;
if (collectionName.ToAlphanumericName() != collectionModelName.ToAlphanumericName())
{
var existingCollection = DbContext.Collections.FirstOrDefault(x => x.Name == model.Name || x.SortName == model.SortName);
if (existingCollection != null)
{
return new OperationResult<bool>($"Collection already exists `{ collection }` with name [{ collectionModelName }].");
}
}
}
collection.IsLocked = model.IsLocked;
var oldPathToImage = collection.PathToImage(Configuration);
var didChangeName = collection.Name != model.Name && !isNew;
collection.Name = model.Name;
collection.SortName = model.SortName;
collection.Edition = model.Edition;
collection.ListInCSVFormat = model.ListInCSVFormat;
collection.ListInCSV = model.ListInCSV;
collection.Description = model.Description;
collection.URLs = model.URLs;
collection.Status = SafeParser.ToEnum<Statuses>(model.Status);
collection.CollectionType = SafeParser.ToEnum<CollectionType>(model.CollectionType);
collection.Tags = model.TagsList.ToDelimitedList();
collection.URLs = model.URLsList.ToDelimitedList();
collection.AlternateNames = model.AlternateNamesList.ToDelimitedList();
collection.CollectionCount = model.CollectionCount;
if (model.Maintainer?.Value != null)
{
var maintainer = DbContext.Users.FirstOrDefault(x => x.RoadieId == SafeParser.ToGuid(model.Maintainer.Value));
if (maintainer != null)
{
collection.MaintainerId = maintainer.Id;
}
}
if (isNew)
{
await DbContext.Collections.AddAsync(collection);
await DbContext.SaveChangesAsync();
}
if (didChangeName)
{
if (File.Exists(oldPathToImage))
{
File.Move(oldPathToImage, collection.PathToImage(Configuration));
}
}
var collectionImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
if (collectionImage != null)
{
// Save unaltered collection image
File.WriteAllBytes(collection.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(collectionImage));
}
collection.LastUpdated = now;
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(collection.CacheRegion);
Logger.LogInformation($"UpdateCollection `{collection}` By User `{user}`");
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
Data = !errors.Any(),
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
private async Task<OperationResult<Collection>> CollectionByIdAction(Guid id, IEnumerable<string> includes = null)
private async Task<OperationResult<Collection>> CollectionByIdActionAsync(Guid id, IEnumerable<string> includes = null)
{
var timings = new Dictionary<string, long>();
var tsw = new Stopwatch();
@ -352,13 +52,13 @@ namespace Roadie.Api.Services
sw.Start();
tsw.Restart();
var collection = await GetCollection(id);
var collection = await GetCollection(id).ConfigureAwait(false);
tsw.Stop();
timings.Add("getCollection", tsw.ElapsedMilliseconds);
if (collection == null)
{
return new OperationResult<Collection>(true, string.Format("Collection Not Found [{0}]", id));
return new OperationResult<Collection>(true, $"Collection Not Found [{id}]");
}
var result = collection.Adapt<Collection>();
var maintainer = DbContext.Users.FirstOrDefault(x => x.Id == collection.MaintainerId);
@ -474,5 +174,309 @@ namespace Roadie.Api.Services
OperationTime = sw.ElapsedMilliseconds
};
}
/// <summary>
/// Get blank Collection to add
/// </summary>
/// <param name="roadieUser"></param>
/// <returns></returns>
public OperationResult<Collection> Add(User roadieUser)
{
var sw = Stopwatch.StartNew();
sw.Start();
var id = Guid.Empty;
var collection = new data.Collection
{
Status = Statuses.New
};
var result = collection.Adapt<Collection>();
result.Id = id;
result.Thumbnail = ImageHelper.MakeNewImage(HttpContext, "collection");
result.MediumThumbnail = ImageHelper.MakeNewImage(HttpContext, "collection");
result.Maintainer = new DataToken
{
Value = roadieUser.UserId.ToString(),
Text = roadieUser.UserName
};
sw.Stop();
return new OperationResult<Collection>
{
Data = result,
IsSuccess = true,
OperationTime = sw.ElapsedMilliseconds
};
}
public async Task<OperationResult<Collection>> ByIdAsync(User roadieUser, Guid id, IEnumerable<string> includes = null)
{
var sw = Stopwatch.StartNew();
sw.Start();
var cacheKey = $"urn:collection_by_id_operation:{id}:{(includes == null ? "0" : string.Join("|", includes))}";
var result = await CacheManager.GetAsync(cacheKey, async () =>
{
return await CollectionByIdActionAsync(id, includes).ConfigureAwait(false);
}, data.Artist.CacheRegionUrn(id)).ConfigureAwait(false);
sw.Stop();
if (result?.Data != null && roadieUser != null)
{
var userBookmarkResult = await BookmarkService.ListAsync(roadieUser, new PagedRequest(), false, BookmarkType.Collection).ConfigureAwait(false);
if (userBookmarkResult.IsSuccess)
{
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x?.Bookmark?.Value == result?.Data?.Id?.ToString()) != null;
}
if (result.Data.Comments.Any())
{
var commentIds = result.Data.Comments.Select(x => x.DatabaseId).ToArray();
var userCommentReactions = (from cr in DbContext.CommentReactions
where commentIds.Contains(cr.CommentId)
where cr.UserId == roadieUser.Id
select cr).ToArray();
foreach (var comment in result.Data.Comments)
{
var userCommentReaction =
userCommentReactions.FirstOrDefault(x => x.CommentId == comment.DatabaseId);
comment.IsDisliked = userCommentReaction?.ReactionValue == CommentReaction.Dislike;
comment.IsLiked = userCommentReaction?.ReactionValue == CommentReaction.Like;
}
}
}
return new OperationResult<Collection>(result.Messages)
{
Data = result?.Data,
IsNotFoundResult = result?.IsNotFoundResult ?? false,
Errors = result?.Errors,
IsSuccess = result?.IsSuccess ?? false,
OperationTime = sw.ElapsedMilliseconds
};
}
public async Task<OperationResult<bool>> DeleteCollectionAsync(User user, Guid id)
{
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var collection = DbContext.Collections.FirstOrDefault(x => x.RoadieId == id);
if (collection == null)
{
return new OperationResult<bool>(true, $"Collection Not Found [{id}]");
}
if (!user.IsEditor)
{
Logger.LogWarning($"DeleteCollection: Access Denied: `{collection}`, By User `{user}`");
var r = new OperationResult<bool>("Access Denied");
r.IsAccessDeniedResult = true;
return r;
}
try
{
DbContext.Collections.Remove(collection);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
await BookmarkService.RemoveAllBookmarksForItemAsync(BookmarkType.Collection, collection.Id).ConfigureAwait(false);
var collectionImageFilename = collection.PathToImage(Configuration);
if (File.Exists(collectionImageFilename))
{
File.Delete(collectionImageFilename);
}
}
catch (Exception ex)
{
Logger.LogError(ex);
errors.Add(ex);
}
sw.Stop();
Logger.LogWarning($"DeleteCollection `{collection}`, By User `{user}`");
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
Data = true,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public Task<Library.Models.Pagination.PagedResult<CollectionList>> ListAsync(User roadieUser, PagedRequest request,
bool? doRandomize = false, Guid? releaseId = null, Guid? artistId = null)
{
var sw = new Stopwatch();
sw.Start();
IQueryable<data.Collection> collections = null;
if (artistId.HasValue)
{
collections = (from cr in DbContext.CollectionReleases
join c in DbContext.Collections on cr.CollectionId equals c.Id
join r in DbContext.Releases on cr.ReleaseId equals r.Id
join a in DbContext.Artists on r.ArtistId equals a.Id
where a.RoadieId == artistId
select c).Distinct();
}
else if (releaseId.HasValue)
{
collections = (from cr in DbContext.CollectionReleases
join c in DbContext.Collections on cr.CollectionId equals c.Id
join r in DbContext.Releases on cr.ReleaseId equals r.Id
where r.RoadieId == releaseId
select c).Distinct();
}
else
{
collections = DbContext.Collections;
}
var normalizedFilterValue = !string.IsNullOrEmpty(request.FilterValue)
? request.FilterValue.ToAlphanumericName()
: null;
var result = from c in collections
let collectionCount = (from crc in DbContext.CollectionReleases
where crc.CollectionId == c.Id
select crc.Id).Count()
where string.IsNullOrEmpty(normalizedFilterValue) || (
c.Name.ToLower().Contains(normalizedFilterValue) ||
c.SortName.ToLower().Contains(normalizedFilterValue) ||
c.AlternateNames.ToLower().Contains(normalizedFilterValue)
)
where request.FilterToStatusValue == Statuses.Ok || c.Status == request.FilterToStatusValue
select new CollectionList
{
DatabaseId = c.Id,
Collection = new DataToken
{
Text = c.Name,
Value = c.RoadieId.ToString()
},
Id = c.RoadieId,
CollectionCount = c.CollectionCount,
CollectionType = (c.CollectionType ?? CollectionType.Unknown).ToString(),
CollectionFoundCount = collectionCount,
CreatedDate = c.CreatedDate,
IsLocked = c.IsLocked,
LastUpdated = c.LastUpdated,
Thumbnail = ImageHelper.MakeCollectionThumbnailImage(Configuration, HttpContext, c.RoadieId)
};
var sortBy = string.IsNullOrEmpty(request.Sort)
? request.OrderValue(new Dictionary<string, string> { { "Collection.Text", "ASC" } })
: request.OrderValue();
var rowCount = result.Count();
var rows = result
.OrderBy(sortBy)
.Skip(request.SkipValue)
.Take(request.LimitValue)
.ToArray();
if (request.FilterToStatusValue == Statuses.Incomplete)
{
rows = rows.OrderByDescending(x => x.PercentComplete).ThenBy(x => x.SortName).ToArray();
}
sw.Stop();
return Task.FromResult(new Library.Models.Pagination.PagedResult<CollectionList>
{
TotalCount = rowCount,
CurrentPage = request.PageValue,
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
OperationTime = sw.ElapsedMilliseconds,
Rows = rows
});
}
/// <summary>
/// Updates (or Adds) Collection
/// </summary>
public async Task<OperationResult<bool>> UpdateCollectionAsync(User user, Collection model)
{
var isNew = model.Id == Guid.Empty;
var now = DateTime.UtcNow;
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var collection = new data.Collection();
if (!isNew)
{
collection = DbContext.Collections.FirstOrDefault(x => x.RoadieId == model.Id);
if (collection == null)
{
return new OperationResult<bool>(true, $"Collection Not Found [{model.Id}]");
}
// If collection is being renamed, see if collection already exists with new model supplied name
var collectionName = collection.SortNameValue;
var collectionModelName = model.SortNameValue;
if (collectionName.ToAlphanumericName() != collectionModelName.ToAlphanumericName())
{
var existingCollection = DbContext.Collections.FirstOrDefault(x => x.Name == model.Name || x.SortName == model.SortName);
if (existingCollection != null)
{
return new OperationResult<bool>($"Collection already exists `{ collection }` with name [{ collectionModelName }].");
}
}
}
collection.IsLocked = model.IsLocked;
var oldPathToImage = collection.PathToImage(Configuration);
var didChangeName = collection.Name != model.Name && !isNew;
collection.Name = model.Name;
collection.SortName = model.SortName;
collection.Edition = model.Edition;
collection.ListInCSVFormat = model.ListInCSVFormat;
collection.ListInCSV = model.ListInCSV;
collection.Description = model.Description;
collection.URLs = model.URLs;
collection.Status = SafeParser.ToEnum<Statuses>(model.Status);
collection.CollectionType = SafeParser.ToEnum<CollectionType>(model.CollectionType);
collection.Tags = model.TagsList.ToDelimitedList();
collection.URLs = model.URLsList.ToDelimitedList();
collection.AlternateNames = model.AlternateNamesList.ToDelimitedList();
collection.CollectionCount = model.CollectionCount;
if (model.Maintainer?.Value != null)
{
var maintainer = await DbContext.Users.FirstOrDefaultAsync(x => x.RoadieId == SafeParser.ToGuid(model.Maintainer.Value)).ConfigureAwait(false);
if (maintainer != null)
{
collection.MaintainerId = maintainer.Id;
}
}
if (isNew)
{
await DbContext.Collections.AddAsync(collection).ConfigureAwait(false);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
}
if (didChangeName)
{
if (File.Exists(oldPathToImage))
{
File.Move(oldPathToImage, collection.PathToImage(Configuration));
}
}
var collectionImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
if (collectionImage != null)
{
// Save unaltered collection image
File.WriteAllBytes(collection.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(collectionImage));
}
collection.LastUpdated = now;
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(collection.CacheRegion);
Logger.LogInformation($"UpdateCollection `{collection}` By User `{user}`");
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
Data = !errors.Any(),
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
}
}

View file

@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Roadie.Library;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
@ -28,15 +29,85 @@ namespace Roadie.Api.Services
{
}
public async Task<OperationResult<bool>> AddNewArtistComment(User user, Guid artistId, string cmt)
private void ClearCaches(data.Comment comment)
{
switch (comment.CommentType)
{
case CommentType.Artist:
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == comment.ArtistId);
if (artist != null)
{
CacheManager.ClearRegion(artist.CacheRegion);
}
break;
case CommentType.Collection:
var collection = DbContext.Collections.FirstOrDefault(x => x.Id == comment.CollectionId);
if (collection != null)
{
CacheManager.ClearRegion(collection.CacheRegion);
}
break;
case CommentType.Genre:
var genre = DbContext.Genres.FirstOrDefault(x => x.Id == comment.GenreId);
if (genre != null)
{
CacheManager.ClearRegion(genre.CacheRegion);
}
break;
case CommentType.Label:
var label = DbContext.Labels.FirstOrDefault(x => x.Id == comment.LabelId);
if (label != null)
{
CacheManager.ClearRegion(label.CacheRegion);
}
break;
case CommentType.Playlist:
var playlist = DbContext.Playlists.FirstOrDefault(x => x.Id == comment.PlaylistId);
if (playlist != null)
{
CacheManager.ClearRegion(playlist.CacheRegion);
}
break;
case CommentType.Release:
var release = DbContext.Releases.FirstOrDefault(x => x.Id == comment.ReleaseId);
if (release != null)
{
CacheManager.ClearRegion(release.CacheRegion);
}
break;
case CommentType.Track:
var track = DbContext.Tracks.FirstOrDefault(x => x.Id == comment.TrackId);
if (track != null)
{
CacheManager.ClearRegion(track.CacheRegion);
}
break;
}
}
public async Task<OperationResult<bool>> AddNewArtistCommentAsync(User user, Guid artistId, string cmt)
{
var sw = Stopwatch.StartNew();
var result = false;
var errors = new List<Exception>();
var artist = DbContext.Artists
.FirstOrDefault(x => x.RoadieId == artistId);
var artist = await DbContext.Artists.FirstOrDefaultAsync(x => x.RoadieId == artistId).ConfigureAwait(false);
if (artist == null)
return new OperationResult<bool>(true, string.Format("Artist Not Found [{0}]", artistId));
{
return new OperationResult<bool>(true, $"Artist Not Found [{artistId}]");
}
var newComment = new data.Comment
{
@ -44,8 +115,8 @@ namespace Roadie.Api.Services
UserId = user.Id.Value,
Cmt = cmt
};
DbContext.Comments.Add(newComment);
await DbContext.SaveChangesAsync();
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(artist.CacheRegion);
sw.Stop();
result = true;
@ -58,15 +129,16 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> AddNewCollectionComment(User user, Guid collectionId, string cmt)
public async Task<OperationResult<bool>> AddNewCollectionCommentAsync(User user, Guid collectionId, string cmt)
{
var sw = Stopwatch.StartNew();
var result = false;
var errors = new List<Exception>();
var collection = DbContext.Collections
.FirstOrDefault(x => x.RoadieId == collectionId);
var collection = await DbContext.Collections.FirstOrDefaultAsync(x => x.RoadieId == collectionId).ConfigureAwait(false);
if (collection == null)
return new OperationResult<bool>(true, string.Format("Collection Not Found [{0}]", collectionId));
{
return new OperationResult<bool>(true, $"Collection Not Found [{collectionId}]");
}
var newComment = new data.Comment
{
@ -74,8 +146,8 @@ namespace Roadie.Api.Services
UserId = user.Id.Value,
Cmt = cmt
};
DbContext.Comments.Add(newComment);
await DbContext.SaveChangesAsync();
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(collection.CacheRegion);
sw.Stop();
result = true;
@ -88,14 +160,16 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> AddNewGenreComment(User user, Guid genreId, string cmt)
public async Task<OperationResult<bool>> AddNewGenreCommentAsync(User user, Guid genreId, string cmt)
{
var sw = Stopwatch.StartNew();
var result = false;
var errors = new List<Exception>();
var genre = DbContext.Genres
.FirstOrDefault(x => x.RoadieId == genreId);
if (genre == null) return new OperationResult<bool>(true, string.Format("Genre Not Found [{0}]", genreId));
var genre = await DbContext.Genres.FirstOrDefaultAsync(x => x.RoadieId == genreId).ConfigureAwait(false);
if (genre == null)
{
return new OperationResult<bool>(true, $"Genre Not Found [{genreId}]");
}
var newComment = new data.Comment
{
@ -103,8 +177,8 @@ namespace Roadie.Api.Services
UserId = user.Id.Value,
Cmt = cmt
};
DbContext.Comments.Add(newComment);
await DbContext.SaveChangesAsync();
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(genre.CacheRegion);
sw.Stop();
result = true;
@ -117,14 +191,16 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> AddNewLabelComment(User user, Guid labelId, string cmt)
public async Task<OperationResult<bool>> AddNewLabelCommentAsync(User user, Guid labelId, string cmt)
{
var sw = Stopwatch.StartNew();
var result = false;
var errors = new List<Exception>();
var label = DbContext.Labels
.FirstOrDefault(x => x.RoadieId == labelId);
if (label == null) return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", labelId));
var label = await DbContext.Labels.FirstOrDefaultAsync(x => x.RoadieId == labelId).ConfigureAwait(false);
if (label == null)
{
return new OperationResult<bool>(true, $"Label Not Found [{labelId}]");
}
var newComment = new data.Comment
{
@ -132,8 +208,8 @@ namespace Roadie.Api.Services
UserId = user.Id.Value,
Cmt = cmt
};
DbContext.Comments.Add(newComment);
await DbContext.SaveChangesAsync();
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(label.CacheRegion);
sw.Stop();
result = true;
@ -146,15 +222,16 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> AddNewPlaylistComment(User user, Guid playlistId, string cmt)
public async Task<OperationResult<bool>> AddNewPlaylistCommentAsync(User user, Guid playlistId, string cmt)
{
var sw = Stopwatch.StartNew();
var result = false;
var errors = new List<Exception>();
var playlist = DbContext.Playlists
.FirstOrDefault(x => x.RoadieId == playlistId);
var playlist = await DbContext.Playlists.FirstOrDefaultAsync(x => x.RoadieId == playlistId).ConfigureAwait(false);
if (playlist == null)
return new OperationResult<bool>(true, string.Format("Playlist Not Found [{0}]", playlistId));
{
return new OperationResult<bool>(true, $"Playlist Not Found [{playlistId}]");
}
var newComment = new data.Comment
{
@ -162,8 +239,8 @@ namespace Roadie.Api.Services
UserId = user.Id.Value,
Cmt = cmt
};
DbContext.Comments.Add(newComment);
await DbContext.SaveChangesAsync();
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(playlist.CacheRegion);
sw.Stop();
result = true;
@ -176,15 +253,16 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> AddNewReleaseComment(User user, Guid releaseId, string cmt)
public async Task<OperationResult<bool>> AddNewReleaseCommentAsync(User user, Guid releaseId, string cmt)
{
var sw = Stopwatch.StartNew();
var result = false;
var errors = new List<Exception>();
var release = DbContext.Releases
.FirstOrDefault(x => x.RoadieId == releaseId);
var release = await DbContext.Releases.FirstOrDefaultAsync(x => x.RoadieId == releaseId).ConfigureAwait(false);
if (release == null)
return new OperationResult<bool>(true, string.Format("Release Not Found [{0}]", releaseId));
{
return new OperationResult<bool>(true, $"Release Not Found [{releaseId}]");
}
var newComment = new data.Comment
{
@ -192,8 +270,8 @@ namespace Roadie.Api.Services
UserId = user.Id.Value,
Cmt = cmt
};
DbContext.Comments.Add(newComment);
await DbContext.SaveChangesAsync();
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(release.CacheRegion);
sw.Stop();
result = true;
@ -206,14 +284,16 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> AddNewTrackComment(User user, Guid trackId, string cmt)
public async Task<OperationResult<bool>> AddNewTrackCommentAsync(User user, Guid trackId, string cmt)
{
var sw = Stopwatch.StartNew();
var result = false;
var errors = new List<Exception>();
var track = DbContext.Tracks
.FirstOrDefault(x => x.RoadieId == trackId);
if (track == null) return new OperationResult<bool>(true, string.Format("Track Not Found [{0}]", trackId));
var track = await DbContext.Tracks.FirstOrDefaultAsync(x => x.RoadieId == trackId).ConfigureAwait(false);
if (track == null)
{
return new OperationResult<bool>(true, $"Track Not Found [{trackId}]");
}
var newComment = new data.Comment
{
@ -221,8 +301,8 @@ namespace Roadie.Api.Services
UserId = user.Id.Value,
Cmt = cmt
};
DbContext.Comments.Add(newComment);
await DbContext.SaveChangesAsync();
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(track.CacheRegion);
sw.Stop();
result = true;
@ -235,15 +315,19 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> DeleteComment(User user, Guid id)
public async Task<OperationResult<bool>> DeleteCommentAsync(User user, Guid id)
{
var sw = Stopwatch.StartNew();
var result = false;
var errors = new List<Exception>();
var comment = DbContext.Comments.FirstOrDefault(x => x.RoadieId == id);
if (comment == null) return new OperationResult<bool>(true, string.Format("Comment Not Found [{0}]", id));
var comment = await DbContext.Comments.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
if (comment == null)
{
return new OperationResult<bool>(true, $"Comment Not Found [{id}]");
}
DbContext.Remove(comment);
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
ClearCaches(comment);
sw.Stop();
result = true;
@ -256,15 +340,18 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> SetCommentReaction(User user, Guid id, CommentReaction reaction)
public async Task<OperationResult<bool>> SetCommentReactionAsync(User user, Guid id, CommentReaction reaction)
{
var sw = Stopwatch.StartNew();
var result = false;
var errors = new List<Exception>();
var comment = DbContext.Comments.FirstOrDefault(x => x.RoadieId == id);
if (comment == null) return new OperationResult<bool>(true, string.Format("Comment Not Found [{0}]", id));
var userCommentReaction =
DbContext.CommentReactions.FirstOrDefault(x => x.CommentId == comment.Id && x.UserId == user.Id);
var comment = await DbContext.Comments.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
if (comment == null)
{
return new OperationResult<bool>(true, $"Comment Not Found [{id}]");
}
var userCommentReaction = await DbContext.CommentReactions.FirstOrDefaultAsync(x => x.CommentId == comment.Id && x.UserId == user.Id).ConfigureAwait(false);
if (userCommentReaction == null)
{
userCommentReaction = new data.CommentReaction
@ -272,20 +359,20 @@ namespace Roadie.Api.Services
CommentId = comment.Id,
UserId = user.Id.Value
};
DbContext.CommentReactions.Add(userCommentReaction);
await DbContext.CommentReactions.AddAsync(userCommentReaction).ConfigureAwait(false);
}
userCommentReaction.Reaction = reaction == CommentReaction.Unknown ? null : reaction.ToString();
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
ClearCaches(comment);
var userCommentReactions = (from cr in DbContext.CommentReactions
var userCommentReactions = await (from cr in DbContext.CommentReactions
where cr.CommentId == comment.Id
select cr).ToArray();
select cr)
.ToArrayAsync()
.ConfigureAwait(false);
var additionalData = new Dictionary<string, object>();
additionalData.Add("likedCount",
userCommentReactions.Where(x => x.ReactionValue == CommentReaction.Like).Count());
additionalData.Add("dislikedCount",
userCommentReactions.Where(x => x.ReactionValue == CommentReaction.Dislike).Count());
additionalData.Add("likedCount", userCommentReactions.Where(x => x.ReactionValue == CommentReaction.Like).Count());
additionalData.Add("dislikedCount", userCommentReactions.Where(x => x.ReactionValue == CommentReaction.Dislike).Count());
sw.Stop();
result = true;
return new OperationResult<bool>
@ -297,46 +384,5 @@ namespace Roadie.Api.Services
OperationTime = sw.ElapsedMilliseconds
};
}
private void ClearCaches(data.Comment comment)
{
switch (comment.CommentType)
{
case CommentType.Artist:
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == comment.ArtistId);
if (artist != null) CacheManager.ClearRegion(artist.CacheRegion);
break;
case CommentType.Collection:
var collection = DbContext.Collections.FirstOrDefault(x => x.Id == comment.CollectionId);
if (collection != null) CacheManager.ClearRegion(collection.CacheRegion);
break;
case CommentType.Genre:
var genre = DbContext.Genres.FirstOrDefault(x => x.Id == comment.GenreId);
if (genre != null) CacheManager.ClearRegion(genre.CacheRegion);
break;
case CommentType.Label:
var label = DbContext.Labels.FirstOrDefault(x => x.Id == comment.LabelId);
if (label != null) CacheManager.ClearRegion(label.CacheRegion);
break;
case CommentType.Playlist:
var playlist = DbContext.Playlists.FirstOrDefault(x => x.Id == comment.PlaylistId);
if (playlist != null) CacheManager.ClearRegion(playlist.CacheRegion);
break;
case CommentType.Release:
var release = DbContext.Releases.FirstOrDefault(x => x.Id == comment.ReleaseId);
if (release != null) CacheManager.ClearRegion(release.CacheRegion);
break;
case CommentType.Track:
var track = DbContext.Tracks.FirstOrDefault(x => x.Id == comment.TrackId);
if (track != null) CacheManager.ClearRegion(track.CacheRegion);
break;
}
}
}
}

View file

@ -18,7 +18,7 @@ namespace Roadie.Api.Services
public async Task SendEmailAsync(string email, string subject, string htmlMessage)
{
if(string.IsNullOrEmpty(Configuration.SmtpHost))
if (string.IsNullOrEmpty(Configuration.SmtpHost))
{
Trace.WriteLine("Email Server (Configuration.SmtpHost) Not Configured", "Warning");
return;
@ -37,7 +37,7 @@ namespace Roadie.Api.Services
mail.IsBodyHtml = true;
mail.Body = htmlMessage;
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
await client.SendMailAsync(mail);
await client.SendMailAsync(mail).ConfigureAwait(false);
}
}
}

View file

@ -18,12 +18,20 @@ using System.IO;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using data = Roadie.Library.Data;
namespace Roadie.Api.Services
{
public class FileDirectoryProcessorService : ServiceBase, IFileDirectoryProcessorService
{
private IArtistLookupEngine ArtistLookupEngine { get; }
private IAudioMetaDataHelper AudioMetaDataHelper { get; }
private IFileProcessor FileProcessor { get; }
private IReleaseLookupEngine ReleaseLookupEngine { get; }
private IReleaseService ReleaseService { get; }
private List<int> _addedArtistIds = new List<int>();
private List<int> _addedReleaseIds = new List<int>();
private List<int> _addedTrackIds = new List<int>();
@ -34,14 +42,6 @@ namespace Roadie.Api.Services
public int? ProcessLimit { get; set; }
private IArtistLookupEngine ArtistLookupEngine { get; }
private IAudioMetaDataHelper AudioMetaDataHelper { get; }
private IFileProcessor FileProcessor { get; }
private IReleaseLookupEngine ReleaseLookupEngine { get; }
private IReleaseService ReleaseService { get; }
public FileDirectoryProcessorService(IRoadieSettings configuration,
IHttpEncoder httpEncoder,
IHttpContext httpContext,
@ -62,73 +62,17 @@ namespace Roadie.Api.Services
FileProcessor = fileProcessor;
}
public static OperationResult<bool> DeleteEmptyFolders(DirectoryInfo processingFolder, ILogger logger)
{
var result = new OperationResult<bool>();
try
{
result.IsSuccess = FolderPathHelper.DeleteEmptyFolders(processingFolder);
}
catch (Exception ex)
{
logger.LogError(ex, string.Format("Error Deleting Empty Folder [{0}] Error [{1}]", processingFolder.FullName, ex.Serialize()));
}
return result;
}
public async Task<OperationResult<bool>> Process(User user, DirectoryInfo folder, bool doJustInfo, int? submissionId = null, bool doDeleteFiles = true)
{
var sw = new Stopwatch();
sw.Start();
await PreProcessFolder(folder, doJustInfo);
var processedFiles = 0;
var pluginResultInfos = new List<PluginResultInfo>();
var errors = new List<string>();
_addedArtistIds.Clear();
_addedReleaseIds.Clear();
_addedTrackIds.Clear();
FileProcessor.SubmissionId = submissionId;
foreach (var file in Directory.EnumerateFiles(folder.FullName, "*.*", SearchOption.AllDirectories)
.ToArray())
{
var operation = await FileProcessor.Process(file, doJustInfo);
if (operation != null && operation.AdditionalData != null &&
operation.AdditionalData.ContainsKey(PluginResultInfo.AdditionalDataKeyPluginResultInfo))
{
pluginResultInfos.Add(operation.AdditionalData[PluginResultInfo.AdditionalDataKeyPluginResultInfo] as PluginResultInfo);
processedFiles++;
}
if (ProcessLimit.HasValue && processedFiles > ProcessLimit.Value) break;
}
await PostProcessFolder(user, folder, pluginResultInfos, doJustInfo, doDeleteFiles);
sw.Stop();
_addedArtistIds.AddRange(ArtistLookupEngine.AddedArtistIds);
_addedReleaseIds.AddRange(ReleaseLookupEngine.AddedReleaseIds);
_addedTrackIds.AddRange(ReleaseLookupEngine.AddedTrackIds);
Logger.LogInformation("Completed! Processed Folder [{0}]: Processed Files [{1}] : Elapsed Time [{2}]", folder.FullName, processedFiles, sw.Elapsed);
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
AdditionalData = new Dictionary<string, object> { { "ProcessedFiles", processedFiles } },
OperationTime = sw.ElapsedMilliseconds
};
}
/// <summary>
/// Perform any operations to the given folder and the plugin results after processing
/// </summary>
private async Task<bool> PostProcessFolder(User user, DirectoryInfo inboundFolder, IEnumerable<PluginResultInfo> pluginResults, bool doJustInfo, bool doDeleteFiles = true)
private async Task<bool> PostProcessFolderAsync(User user, DirectoryInfo inboundFolder, IEnumerable<PluginResultInfo> pluginResults, bool doJustInfo, bool doDeleteFiles = true)
{
SimpleContract.Requires<ArgumentNullException>(inboundFolder != null, "Invalid InboundFolder");
if (pluginResults != null)
{
foreach (var releasesInfo in pluginResults.GroupBy(x => x.ReleaseId).Select(x => x.First()))
{
await ReleaseService.ScanReleaseFolder(user, releasesInfo.ReleaseId, doJustInfo);
await ReleaseService.ScanReleaseFolderAsync(user, releasesInfo.ReleaseId, doJustInfo).ConfigureAwait(false);
_addedTrackIds.AddRange(ReleaseService.AddedTrackIds);
}
}
@ -136,6 +80,7 @@ namespace Roadie.Api.Services
{
var fileExtensionsToDelete = Configuration.FileExtensionsToDelete ?? new string[0];
if (fileExtensionsToDelete.Any())
{
foreach (var fileInFolder in inboundFolder.GetFiles("*.*", SearchOption.AllDirectories))
{
if (fileExtensionsToDelete.Any(x => x.Equals(fileInFolder.Extension, StringComparison.OrdinalIgnoreCase)))
@ -148,6 +93,7 @@ namespace Roadie.Api.Services
}
}
}
}
DeleteEmptyFolders(inboundFolder, Logger);
}
@ -158,9 +104,67 @@ namespace Roadie.Api.Services
/// <summary>
/// Perform any operations to the given folder before processing
/// </summary>
private Task<bool> PreProcessFolder(DirectoryInfo inboundFolder, bool doJustInfo = false)
private Task<bool> PreProcessFolderAsync(DirectoryInfo inboundFolder, bool doJustInfo = false)
{
return Task.FromResult(true);
}
public static OperationResult<bool> DeleteEmptyFolders(DirectoryInfo processingFolder, ILogger logger)
{
var result = new OperationResult<bool>();
try
{
result.IsSuccess = FolderPathHelper.DeleteEmptyFolders(processingFolder);
}
catch (Exception ex)
{
logger.LogError(ex, $"Error Deleting Empty Folder [{processingFolder.FullName}] Error [{ex.Serialize()}]");
}
return result;
}
public async Task<OperationResult<bool>> ProcessAsync(User user, DirectoryInfo folder, bool doJustInfo, int? submissionId = null, bool doDeleteFiles = true)
{
var sw = new Stopwatch();
sw.Start();
await PreProcessFolderAsync(folder, doJustInfo).ConfigureAwait(false);
var processedFiles = 0;
var pluginResultInfos = new List<PluginResultInfo>();
var errors = new List<string>();
_addedArtistIds.Clear();
_addedReleaseIds.Clear();
_addedTrackIds.Clear();
FileProcessor.SubmissionId = submissionId;
foreach (var file in Directory.EnumerateFiles(folder.FullName, "*.*", SearchOption.AllDirectories) .ToArray())
{
var operation = await FileProcessor.Process(file, doJustInfo).ConfigureAwait(false);
if (operation != null && operation.AdditionalData != null &&
operation.AdditionalData.ContainsKey(PluginResultInfo.AdditionalDataKeyPluginResultInfo))
{
pluginResultInfos.Add(operation.AdditionalData[PluginResultInfo.AdditionalDataKeyPluginResultInfo] as PluginResultInfo);
processedFiles++;
}
if (ProcessLimit.HasValue && processedFiles > ProcessLimit.Value)
{
break;
}
}
await PostProcessFolderAsync(user, folder, pluginResultInfos, doJustInfo, doDeleteFiles).ConfigureAwait(false);
sw.Stop();
_addedArtistIds.AddRange(ArtistLookupEngine.AddedArtistIds);
_addedReleaseIds.AddRange(ReleaseLookupEngine.AddedReleaseIds);
_addedTrackIds.AddRange(ReleaseLookupEngine.AddedTrackIds);
Logger.LogInformation("Completed! Processed Folder [{0}]: Processed Files [{1}] : Elapsed Time [{2}]", folder.FullName, processedFiles, sw.Elapsed);
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
AdditionalData = new Dictionary<string, object> { { "ProcessedFiles", processedFiles } },
OperationTime = sw.ElapsedMilliseconds
};
}
}
}

View file

@ -9,11 +9,9 @@ using Roadie.Library.Data.Context;
using Roadie.Library.Encoding;
using Roadie.Library.Enums;
using Roadie.Library.Extensions;
using Roadie.Library.Identity;
using Roadie.Library.Imaging;
using Roadie.Library.Models;
using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Users;
using Roadie.Library.Utility;
using System;
using System.Collections.Generic;
@ -38,15 +36,109 @@ namespace Roadie.Api.Services
{
}
public async Task<OperationResult<Genre>> ById(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null)
private Task<OperationResult<Genre>> GenreByIdAction(Guid id, IEnumerable<string> includes = null)
{
var timings = new Dictionary<string, long>();
var tsw = new Stopwatch();
var sw = Stopwatch.StartNew();
sw.Start();
var genre = DbContext.Genres.FirstOrDefault(x => x.RoadieId == id);
if (genre == null)
{
return Task.FromResult(new OperationResult<Genre>(true, $"Genre Not Found [{id}]"));
}
tsw.Stop();
timings.Add("getGenre", tsw.ElapsedMilliseconds);
tsw.Restart();
var result = genre.Adapt<Genre>();
result.AlternateNames = genre.AlternateNames;
result.Tags = genre.Tags;
result.Thumbnail = ImageHelper.MakeGenreThumbnailImage(Configuration, HttpContext, genre.RoadieId);
result.MediumThumbnail = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "genre", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
tsw.Stop();
timings.Add("adapt", tsw.ElapsedMilliseconds);
if (includes != null && includes.Any())
{
if (includes.Contains("stats"))
{
tsw.Restart();
var releaseCount = (from rg in DbContext.ReleaseGenres
where rg.GenreId == genre.Id
select rg.Id).Count();
var artistCount = (from rg in DbContext.ArtistGenres
where rg.GenreId == genre.Id
select rg.Id).Count();
result.Statistics = new Library.Models.Statistics.ReleaseGroupingStatistics
{
ArtistCount = artistCount,
ReleaseCount = releaseCount
};
tsw.Stop();
timings.Add("stats", tsw.ElapsedMilliseconds);
}
}
sw.Stop();
Logger.LogInformation($"ByIdAction: Genre `{ genre }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]");
return Task.FromResult(new OperationResult<Genre>
{
Data = result,
IsSuccess = result != null,
OperationTime = sw.ElapsedMilliseconds
});
}
private async Task<OperationResult<Library.Models.Image>> SaveImageBytes(Library.Models.Users.User user, Guid id, byte[] imageBytes)
{
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var genre = await DbContext.Genres.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
if (genre == null)
{
return new OperationResult<Library.Models.Image>(true, $"Genre Not Found [{id}]");
}
try
{
var now = DateTime.UtcNow;
if (imageBytes != null)
{
// Save unaltered genre image
File.WriteAllBytes(genre.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(imageBytes));
}
genre.LastUpdated = now;
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(genre.CacheRegion);
Logger.LogInformation($"UploadGenreImage `{genre}` By User `{user}`");
}
catch (Exception ex)
{
Logger.LogError(ex);
errors.Add(ex);
}
sw.Stop();
return new OperationResult<Library.Models.Image>
{
IsSuccess = !errors.Any(),
Data = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "genre", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height, true),
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<Genre>> ByIdAsync(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null)
{
var sw = Stopwatch.StartNew();
sw.Start();
var cacheKey = string.Format("urn:genre_by_id_operation:{0}:{1}", id, includes == null ? "0" : string.Join("|", includes));
var cacheKey = $"urn:genre_by_id_operation:{id}:{(includes == null ? "0" : string.Join("|", includes))}";
var result = await CacheManager.GetAsync(cacheKey, async () =>
{
return await GenreByIdAction(id, includes);
}, data.Genre.CacheRegionUrn(id));
return await GenreByIdAction(id, includes).ConfigureAwait(false);
}, data.Genre.CacheRegionUrn(id)).ConfigureAwait(false);
sw.Stop();
return new OperationResult<Genre>(result.Messages)
{
@ -58,14 +150,18 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> Delete(Library.Identity.User user, Guid id)
public async Task<OperationResult<bool>> DeleteAsync(Library.Identity.User user, Guid id)
{
var sw = new Stopwatch();
sw.Start();
var genre = DbContext.Genres.FirstOrDefault(x => x.RoadieId == id);
if (genre == null) return new OperationResult<bool>(true, string.Format("Genre Not Found [{0}]", id));
var genre = await DbContext.Genres.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
if (genre == null)
{
return new OperationResult<bool>(true, $"Genre Not Found [{id}]");
}
DbContext.Genres.Remove(genre);
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
var genreImageFilename = genre.PathToImage(Configuration);
if (File.Exists(genreImageFilename))
@ -84,7 +180,7 @@ namespace Roadie.Api.Services
};
}
public async Task<Library.Models.Pagination.PagedResult<GenreList>> List(Library.Models.Users.User roadieUser, PagedRequest request, bool? doRandomize = false)
public async Task<Library.Models.Pagination.PagedResult<GenreList>> ListAsync(Library.Models.Users.User roadieUser, PagedRequest request, bool? doRandomize = false)
{
var sw = new Stopwatch();
sw.Start();
@ -102,7 +198,7 @@ namespace Roadie.Api.Services
if (doRandomize ?? false)
{
var randomLimit = request.Limit ?? roadieUser?.RandomReleaseLimit ?? request.LimitValue;
randomGenreData = await DbContext.RandomGenreIds(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly);
randomGenreData = await DbContext.RandomGenreIdsAsync(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly).ConfigureAwait(false);
randomGenreIds = randomGenreData.Select(x => x.Value).ToArray();
rowCount = DbContext.Genres.Count();
}
@ -169,20 +265,17 @@ namespace Roadie.Api.Services
});
}
public async Task<OperationResult<Library.Models.Image>> SetGenreImageByUrl(Library.Models.Users.User user, Guid id, string imageUrl)
{
return await SaveImageBytes(user, id, WebHelper.BytesForImageUrl(imageUrl));
}
public Task<OperationResult<Library.Models.Image>> SetGenreImageByUrlAsync(Library.Models.Users.User user, Guid id, string imageUrl) => SaveImageBytes(user, id, WebHelper.BytesForImageUrl(imageUrl));
public async Task<OperationResult<bool>> UpdateGenre(Library.Models.Users.User user, Genre model)
public async Task<OperationResult<bool>> UpdateGenreAsync(Library.Models.Users.User user, Genre model)
{
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var genre = DbContext.Genres.FirstOrDefault(x => x.RoadieId == model.Id);
var genre = await DbContext.Genres.FirstOrDefaultAsync(x => x.RoadieId == model.Id).ConfigureAwait(false);
if (genre == null)
{
return new OperationResult<bool>(true, string.Format("Genre Not Found [{0}]", model.Id));
return new OperationResult<bool>(true, $"Genre Not Found [{model.Id}]");
}
// If genre is being renamed, see if genre already exists with new model supplied name
var genreName = genre.SortNameValue;
@ -229,7 +322,7 @@ namespace Roadie.Api.Services
File.WriteAllBytes(genre.PathToImage(Configuration), ImageHelper.ConvertToJpegFormat(genreImage));
}
genre.LastUpdated = now;
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(genre.CacheRegion);
Logger.LogInformation($"UpdateGenre `{genre}` By User `{user}`");
@ -244,14 +337,14 @@ namespace Roadie.Api.Services
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
Data = !errors.Any(),
IsSuccess = errors.Count == 0,
Data = errors.Count == 0,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<Library.Models.Image>> UploadGenreImage(Library.Models.Users.User user, Guid id, IFormFile file)
public async Task<OperationResult<Library.Models.Image>> UploadGenreImageAsync(Library.Models.Users.User user, Guid id, IFormFile file)
{
var bytes = new byte[0];
using (var ms = new MemoryStream())
@ -259,102 +352,7 @@ namespace Roadie.Api.Services
file.CopyTo(ms);
bytes = ms.ToArray();
}
return await SaveImageBytes(user, id, bytes);
}
private Task<OperationResult<Genre>> GenreByIdAction(Guid id, IEnumerable<string> includes = null)
{
var timings = new Dictionary<string, long>();
var tsw = new Stopwatch();
var sw = Stopwatch.StartNew();
sw.Start();
var genre = DbContext.Genres.FirstOrDefault(x => x.RoadieId == id);
if (genre == null)
{
return Task.FromResult(new OperationResult<Genre>(true, string.Format("Genre Not Found [{0}]", id)));
}
tsw.Stop();
timings.Add("getGenre", tsw.ElapsedMilliseconds);
tsw.Restart();
var result = genre.Adapt<Genre>();
result.AlternateNames = genre.AlternateNames;
result.Tags = genre.Tags;
result.Thumbnail = ImageHelper.MakeGenreThumbnailImage(Configuration, HttpContext, genre.RoadieId);
result.MediumThumbnail = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "genre", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
tsw.Stop();
timings.Add("adapt", tsw.ElapsedMilliseconds);
if (includes != null && includes.Any())
{
if (includes.Contains("stats"))
{
tsw.Restart();
var releaseCount = (from rg in DbContext.ReleaseGenres
where rg.GenreId == genre.Id
select rg.Id).Count();
var artistCount = (from rg in DbContext.ArtistGenres
where rg.GenreId == genre.Id
select rg.Id).Count();
result.Statistics = new Library.Models.Statistics.ReleaseGroupingStatistics
{
ArtistCount = artistCount,
ReleaseCount = releaseCount
};
tsw.Stop();
timings.Add("stats", tsw.ElapsedMilliseconds);
}
}
sw.Stop();
Logger.LogInformation($"ByIdAction: Genre `{ genre }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]");
return Task.FromResult(new OperationResult<Genre>
{
Data = result,
IsSuccess = result != null,
OperationTime = sw.ElapsedMilliseconds
});
}
private async Task<OperationResult<Library.Models.Image>> SaveImageBytes(Library.Models.Users.User user, Guid id, byte[] imageBytes)
{
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var genre = DbContext.Genres.FirstOrDefault(x => x.RoadieId == id);
if (genre == null)
{
return new OperationResult<Library.Models.Image>(true, string.Format("Genre Not Found [{0}]", id));
}
try
{
var now = DateTime.UtcNow;
if (imageBytes != null)
{
// Save unaltered genre image
File.WriteAllBytes(genre.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(imageBytes));
}
genre.LastUpdated = now;
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(genre.CacheRegion);
Logger.LogInformation($"UploadGenreImage `{genre}` By User `{user}`");
}
catch (Exception ex)
{
Logger.LogError(ex);
errors.Add(ex);
}
sw.Stop();
return new OperationResult<Library.Models.Image>
{
IsSuccess = !errors.Any(),
Data = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "genre", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height, true),
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
return await SaveImageBytes(user, id, bytes).ConfigureAwait(false);
}
}
}

View file

@ -14,10 +14,17 @@ namespace Roadie.Api.Services
public HttpContext(IRoadieSettings configuration, IUrlHelper urlHelper)
{
var scheme = urlHelper.ActionContext.HttpContext.Request.Scheme;
if (configuration.UseSSLBehindProxy) scheme = "https";
if (configuration.UseSSLBehindProxy)
{
scheme = "https";
}
var host = urlHelper.ActionContext.HttpContext.Request.Host;
if (!string.IsNullOrEmpty(configuration.BehindProxyHost))
{
host = new HostString(configuration.BehindProxyHost);
}
BaseUrl = $"{scheme}://{host}";
ImageBaseUrl = $"{BaseUrl}/images";
}

View file

@ -9,48 +9,48 @@ namespace Roadie.Api.Services
{
public interface IAdminService
{
Task<OperationResult<bool>> DeleteArtist(User user, Guid artistId, bool deleteFolder);
Task<OperationResult<bool>> DeleteArtistAsync(User user, Guid artistId, bool deleteFolder);
Task<OperationResult<bool>> DeleteArtistReleases(User user, Guid artistId, bool doDeleteFiles = false);
Task<OperationResult<bool>> DeleteArtistReleasesAsync(User user, Guid artistId, bool doDeleteFiles = false);
Task<OperationResult<bool>> DeleteArtistSecondaryImage(User user, Guid artistId, int index);
Task<OperationResult<bool>> DeleteArtistSecondaryImageAsync(User user, Guid artistId, int index);
Task<OperationResult<bool>> DeleteGenre(User user, Guid genreId);
Task<OperationResult<bool>> DeleteGenreAsync(User user, Guid genreId);
Task<OperationResult<bool>> DeleteLabel(User user, Guid labelId);
Task<OperationResult<bool>> DeleteLabelAsync(User user, Guid labelId);
Task<OperationResult<bool>> DeleteRelease(User user, Guid releaseId, bool? doDeleteFiles);
Task<OperationResult<bool>> DeleteReleaseAsync(User user, Guid releaseId, bool? doDeleteFiles);
Task<OperationResult<bool>> DeleteReleaseSecondaryImage(User user, Guid releaseId, int index);
Task<OperationResult<bool>> DeleteReleaseSecondaryImageAsync(User user, Guid releaseId, int index);
Task<OperationResult<bool>> DeleteTracks(User user, IEnumerable<Guid> trackIds, bool? doDeleteFile);
Task<OperationResult<bool>> DeleteTracksAsync(User user, IEnumerable<Guid> trackIds, bool? doDeleteFile);
Task<OperationResult<bool>> DeleteUser(User applicationUser, Guid id);
Task<OperationResult<bool>> DeleteUserAsync(User applicationUser, Guid id);
Task<OperationResult<bool>> DoInitialSetup(User user, UserManager<User> userManager);
Task<OperationResult<bool>> DoInitialSetupAsync(User user, UserManager<User> userManager);
Task<OperationResult<Dictionary<string, List<string>>>> MissingCollectionReleases(User user);
Task<OperationResult<Dictionary<string, List<string>>>> MissingCollectionReleasesAsync(User user);
void PerformStartUpTasks();
Task<OperationResult<bool>> ScanAllCollections(User user, bool isReadOnly = false, bool doPurgeFirst = false);
Task<OperationResult<bool>> ScanAllCollectionsAsync(User user, bool isReadOnly = false, bool doPurgeFirst = false);
Task<OperationResult<bool>> ScanArtist(User user, Guid artistId, bool isReadOnly = false);
Task<OperationResult<bool>> ScanArtistAsync(User user, Guid artistId, bool isReadOnly = false);
Task<OperationResult<bool>> ScanArtists(User user, IEnumerable<Guid> artistIds, bool isReadOnly = false);
Task<OperationResult<bool>> ScanArtistsAsync(User user, IEnumerable<Guid> artistIds, bool isReadOnly = false);
Task<OperationResult<bool>> ScanCollection(User user, Guid collectionId, bool isReadOnly = false, bool doPurgeFirst = false, bool doUpdateRanks = true);
Task<OperationResult<bool>> ScanCollectionAsync(User user, Guid collectionId, bool isReadOnly = false, bool doPurgeFirst = false, bool doUpdateRanks = true);
Task<OperationResult<bool>> ScanInboundFolder(User user, bool isReadOnly = false);
Task<OperationResult<bool>> ScanInboundFolderAsync(User user, bool isReadOnly = false);
Task<OperationResult<bool>> ScanLibraryFolder(User user, bool isReadOnly = false);
Task<OperationResult<bool>> ScanLibraryFolderAsync(User user, bool isReadOnly = false);
Task<OperationResult<bool>> ScanRelease(User user, Guid releaseIds, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false);
Task<OperationResult<bool>> ScanReleaseAsync(User user, Guid releaseIds, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false);
Task<OperationResult<bool>> ScanReleases(User user, IEnumerable<Guid> releaseId, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false);
Task<OperationResult<bool>> ScanReleasesAsync(User user, IEnumerable<Guid> releaseId, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false);
Task<OperationResult<bool>> UpdateInviteTokenUsed(Guid? tokenId);
Task<OperationResult<bool>> UpdateInviteTokenUsedAsync(Guid? tokenId);
Task<OperationResult<bool>> ValidateInviteToken(Guid? tokenId);
Task<OperationResult<bool>> ValidateInviteTokenAsync(Guid? tokenId);
}
}

View file

@ -1,9 +1,7 @@
using Microsoft.AspNetCore.Http;
using Roadie.Library;
using Roadie.Library.Identity;
using Roadie.Library.Models;
using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Users;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
@ -12,22 +10,22 @@ namespace Roadie.Api.Services
{
public interface IArtistService
{
Task<OperationResult<Artist>> ById(Library.Models.Users.User user, Guid id, IEnumerable<string> includes);
Task<OperationResult<Artist>> ByIdAsync(Library.Models.Users.User user, Guid id, IEnumerable<string> includes);
Task<OperationResult<bool>> Delete(Library.Identity.User user, Library.Data.Artist Artist, bool deleteFolder);
Task<OperationResult<bool>> DeleteAsync(Library.Identity.User user, Library.Data.Artist Artist, bool deleteFolder);
Task<PagedResult<ArtistList>> List(Library.Models.Users.User user, PagedRequest request, bool? doRandomize = false, bool? onlyIncludeWithReleases = true);
Task<PagedResult<ArtistList>> ListAsync(Library.Models.Users.User user, PagedRequest request, bool? doRandomize = false, bool? onlyIncludeWithReleases = true);
Task<OperationResult<bool>> MergeArtists(Library.Identity.User user, Guid artistToMergeId, Guid artistToMergeIntoId);
Task<OperationResult<bool>> MergeArtistsAsync(Library.Identity.User user, Guid artistToMergeId, Guid artistToMergeIntoId);
Task<OperationResult<bool>> RefreshArtistMetadata(Library.Identity.User user, Guid ArtistId);
Task<OperationResult<bool>> RefreshArtistMetadataAsync(Library.Identity.User user, Guid ArtistId);
Task<OperationResult<bool>> ScanArtistReleasesFolders(Library.Identity.User user, Guid artistId, string destinationFolder, bool doJustInfo);
Task<OperationResult<bool>> ScanArtistReleasesFoldersAsync(Library.Identity.User user, Guid artistId, string destinationFolder, bool doJustInfo);
Task<OperationResult<Image>> SetReleaseImageByUrl(Library.Identity.User user, Guid id, string imageUrl);
Task<OperationResult<Image>> SetReleaseImageByUrlAsync(Library.Identity.User user, Guid id, string imageUrl);
Task<OperationResult<bool>> UpdateArtist(Library.Identity.User user, Artist artist);
Task<OperationResult<bool>> UpdateArtistAsync(Library.Identity.User user, Artist artist);
Task<OperationResult<Image>> UploadArtistImage(Library.Identity.User user, Guid id, IFormFile file);
Task<OperationResult<Image>> UploadArtistImageAsync(Library.Identity.User user, Guid id, IFormFile file);
}
}

View file

@ -9,7 +9,7 @@ namespace Roadie.Api.Services
{
public interface IBookmarkService
{
Task<OperationResult<bool>> RemoveAllBookmarksForItem(BookmarkType type, int id);
Task<PagedResult<BookmarkList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, BookmarkType? filterType = null);
Task<PagedResult<BookmarkList>> ListAsync(User roadieUser, PagedRequest request, bool? doRandomize = false, BookmarkType? filterType = null);
Task<OperationResult<bool>> RemoveAllBookmarksForItemAsync(BookmarkType type, int id);
}
}

View file

@ -12,13 +12,12 @@ namespace Roadie.Api.Services
{
OperationResult<Collection> Add(User roadieUser);
Task<OperationResult<Collection>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null);
Task<OperationResult<Collection>> ByIdAsync(User roadieUser, Guid id, IEnumerable<string> includes = null);
Task<OperationResult<bool>> DeleteCollection(User user, Guid id);
Task<OperationResult<bool>> DeleteCollectionAsync(User user, Guid id);
Task<PagedResult<CollectionList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false,
Guid? releaseId = null, Guid? artistId = null);
Task<PagedResult<CollectionList>> ListAsync(User roadieUser, PagedRequest request, bool? doRandomize = false, Guid? releaseId = null, Guid? artistId = null);
Task<OperationResult<bool>> UpdateCollection(User roadieUser, Collection collection);
Task<OperationResult<bool>> UpdateCollectionAsync(User roadieUser, Collection collection);
}
}

View file

@ -8,22 +8,22 @@ namespace Roadie.Api.Services
{
public interface ICommentService
{
Task<OperationResult<bool>> AddNewArtistComment(User user, Guid artistId, string cmt);
Task<OperationResult<bool>> AddNewArtistCommentAsync(User user, Guid artistId, string cmt);
Task<OperationResult<bool>> AddNewCollectionComment(User user, Guid collectionId, string cmt);
Task<OperationResult<bool>> AddNewCollectionCommentAsync(User user, Guid collectionId, string cmt);
Task<OperationResult<bool>> AddNewGenreComment(User user, Guid genreId, string cmt);
Task<OperationResult<bool>> AddNewGenreCommentAsync(User user, Guid genreId, string cmt);
Task<OperationResult<bool>> AddNewLabelComment(User user, Guid labelId, string cmt);
Task<OperationResult<bool>> AddNewLabelCommentAsync(User user, Guid labelId, string cmt);
Task<OperationResult<bool>> AddNewPlaylistComment(User user, Guid playlistId, string cmt);
Task<OperationResult<bool>> AddNewPlaylistCommentAsync(User user, Guid playlistId, string cmt);
Task<OperationResult<bool>> AddNewReleaseComment(User user, Guid releaseId, string cmt);
Task<OperationResult<bool>> AddNewReleaseCommentAsync(User user, Guid releaseId, string cmt);
Task<OperationResult<bool>> AddNewTrackComment(User user, Guid trackId, string cmt);
Task<OperationResult<bool>> AddNewTrackCommentAsync(User user, Guid trackId, string cmt);
Task<OperationResult<bool>> DeleteComment(User user, Guid id);
Task<OperationResult<bool>> DeleteCommentAsync(User user, Guid id);
Task<OperationResult<bool>> SetCommentReaction(User user, Guid id, CommentReaction reaction);
Task<OperationResult<bool>> SetCommentReactionAsync(User user, Guid id, CommentReaction reaction);
}
}

View file

@ -14,6 +14,6 @@ namespace Roadie.Api.Services
int? ProcessLimit { get; set; }
Task<OperationResult<bool>> Process(User user, DirectoryInfo folder, bool doJustInfo, int? submissionId = null, bool doDeleteFiles = true);
Task<OperationResult<bool>> ProcessAsync(User user, DirectoryInfo folder, bool doJustInfo, int? submissionId = null, bool doDeleteFiles = true);
}
}

View file

@ -1,9 +1,7 @@
using Microsoft.AspNetCore.Http;
using Roadie.Library;
using Roadie.Library.Identity;
using Roadie.Library.Models;
using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Users;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
@ -12,16 +10,16 @@ namespace Roadie.Api.Services
{
public interface IGenreService
{
Task<OperationResult<Genre>> ById(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null);
Task<OperationResult<Genre>> ByIdAsync(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null);
Task<OperationResult<bool>> Delete(Library.Identity.User user, Guid id);
Task<OperationResult<bool>> DeleteAsync(Library.Identity.User user, Guid id);
Task<PagedResult<GenreList>> List(Library.Models.Users.User roadieUser, PagedRequest request, bool? doRandomize = false);
Task<PagedResult<GenreList>> ListAsync(Library.Models.Users.User roadieUser, PagedRequest request, bool? doRandomize = false);
Task<OperationResult<Image>> SetGenreImageByUrl(Library.Models.Users.User user, Guid id, string imageUrl);
Task<OperationResult<Image>> SetGenreImageByUrlAsync(Library.Models.Users.User user, Guid id, string imageUrl);
Task<OperationResult<bool>> UpdateGenre(Library.Models.Users.User user, Genre model);
Task<OperationResult<bool>> UpdateGenreAsync(Library.Models.Users.User user, Genre model);
Task<OperationResult<Image>> UploadGenreImage(Library.Models.Users.User user, Guid id, IFormFile file);
Task<OperationResult<Image>> UploadGenreImageAsync(Library.Models.Users.User user, Guid id, IFormFile file);
}
}

View file

@ -1,8 +1,6 @@
using Microsoft.Net.Http.Headers;
using Roadie.Library;
using Roadie.Library.Identity;
using Roadie.Library.Imaging;
using Roadie.Library.Models;
using Roadie.Library.SearchEngines.Imaging;
using System;
using System.Collections.Generic;
@ -16,26 +14,26 @@ namespace Roadie.Api.Services
string RequestIp { get; set; }
Task<FileOperationResult<IImage>> ArtistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> ArtistImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> ArtistSecondaryImage(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> ArtistSecondaryImageAsync(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> CollectionImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> CollectionImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> GenreImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> GenreImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> LabelImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> LabelImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> PlaylistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> PlaylistImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> ReleaseImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> ReleaseImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> ReleaseSecondaryImage(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> ReleaseSecondaryImageAsync(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null);
Task<OperationResult<IEnumerable<ImageSearchResult>>> Search(string query, int resultsCount = 10);
Task<OperationResult<IEnumerable<ImageSearchResult>>> SearchAsync(string query, int resultsCount = 10);
Task<FileOperationResult<IImage>> TrackImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> TrackImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> UserImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
Task<FileOperationResult<IImage>> UserImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
}
}

View file

@ -1,9 +1,7 @@
using Microsoft.AspNetCore.Http;
using Roadie.Library;
using Roadie.Library.Identity;
using Roadie.Library.Models;
using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Users;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
@ -12,18 +10,18 @@ namespace Roadie.Api.Services
{
public interface ILabelService
{
Task<OperationResult<Label>> ById(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null);
Task<OperationResult<Label>> ByIdAsync(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null);
Task<OperationResult<bool>> Delete(Library.Identity.User user, Guid id);
Task<OperationResult<bool>> DeleteAsync(Library.Identity.User user, Guid id);
Task<PagedResult<LabelList>> List(Library.Models.Users.User roadieUser, PagedRequest request, bool? doRandomize = false);
Task<PagedResult<LabelList>> ListAsync(Library.Models.Users.User roadieUser, PagedRequest request, bool? doRandomize = false);
Task<OperationResult<bool>> MergeLabelsIntoLabel(Library.Identity.User user, Guid intoLabelId, IEnumerable<Guid> labelIdsToMerge);
Task<OperationResult<bool>> MergeLabelsIntoLabelAsync(Library.Identity.User user, Guid intoLabelId, IEnumerable<Guid> labelIdsToMerge);
Task<OperationResult<Image>> SetLabelImageByUrl(Library.Models.Users.User user, Guid id, string imageUrl);
Task<OperationResult<Image>> SetLabelImageByUrlAsync(Library.Models.Users.User user, Guid id, string imageUrl);
Task<OperationResult<bool>> UpdateLabel(Library.Models.Users.User user, Label label);
Task<OperationResult<bool>> UpdateLabelAsync(Library.Models.Users.User user, Label label);
Task<OperationResult<Image>> UploadLabelImage(Library.Models.Users.User user, Guid id, IFormFile file);
Task<OperationResult<Image>> UploadLabelImageAsync(Library.Models.Users.User user, Guid id, IFormFile file);
}
}

View file

@ -7,24 +7,24 @@ namespace Roadie.Api.Services
{
public interface ILookupService
{
Task<OperationResult<IEnumerable<DataToken>>> ArtistTypes();
Task<OperationResult<IEnumerable<DataToken>>> ArtistTypesAsync();
Task<OperationResult<IEnumerable<DataToken>>> BandStatus();
Task<OperationResult<IEnumerable<DataToken>>> BandStatusAsync();
Task<OperationResult<IEnumerable<DataToken>>> BookmarkTypes();
Task<OperationResult<IEnumerable<DataToken>>> BookmarkTypesAsync();
Task<OperationResult<IEnumerable<DataToken>>> CollectionTypes();
Task<OperationResult<IEnumerable<DataToken>>> CollectionTypesAsync();
Task<OperationResult<IEnumerable<DataToken>>> LibraryStatus();
Task<OperationResult<IEnumerable<DataToken>>> CreditCategoriesAsync();
Task<OperationResult<IEnumerable<DataToken>>> QueMessageTypes();
Task<OperationResult<IEnumerable<DataToken>>> LibraryStatusAsync();
Task<OperationResult<IEnumerable<DataToken>>> ReleaseTypes();
Task<OperationResult<IEnumerable<DataToken>>> QueMessageTypesAsync();
Task<OperationResult<IEnumerable<DataToken>>> RequestStatus();
Task<OperationResult<IEnumerable<DataToken>>> ReleaseTypesAsync();
Task<OperationResult<IEnumerable<DataToken>>> Status();
Task<OperationResult<IEnumerable<DataToken>>> RequestStatusAsync();
Task<OperationResult<IEnumerable<DataToken>>> CreditCategories();
Task<OperationResult<IEnumerable<DataToken>>> StatusAsync();
}
}

View file

@ -10,10 +10,10 @@ namespace Roadie.Api.Services
{
public interface IPlayActivityService
{
Task<PagedResult<PlayActivityList>> List(PagedRequest request, User roadieUser = null, DateTime? newerThan = null);
Task<PagedResult<PlayActivityList>> ListAsync(PagedRequest request, User roadieUser = null, DateTime? newerThan = null);
Task<OperationResult<bool>> NowPlaying(User roadieUser, ScrobbleInfo scrobble);
Task<OperationResult<bool>> NowPlayingAsync(User roadieUser, ScrobbleInfo scrobble);
Task<OperationResult<bool>> Scrobble(User roadieUser, ScrobbleInfo scrobble);
Task<OperationResult<bool>> ScrobbleAsync(User roadieUser, ScrobbleInfo scrobble);
}
}

View file

@ -11,20 +11,20 @@ namespace Roadie.Api.Services
{
public interface IPlaylistService
{
Task<OperationResult<PlaylistList>> AddNewPlaylist(User user, Playlist model);
Task<OperationResult<PlaylistList>> AddNewPlaylistAsync(User user, Playlist model);
Task<OperationResult<bool>> AddTracksToPlaylist(data.Playlist playlist, IEnumerable<Guid> trackIds);
Task<OperationResult<bool>> AddTracksToPlaylistAsync(data.Playlist playlist, IEnumerable<Guid> trackIds);
Task<OperationResult<Playlist>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null);
Task<OperationResult<Playlist>> ByIdAsync(User roadieUser, Guid id, IEnumerable<string> includes = null);
Task<OperationResult<bool>> DeletePlaylist(User user, Guid id);
Task<OperationResult<bool>> DeletePlaylistAsync(User user, Guid id);
Task<PagedResult<PlaylistList>> List(PagedRequest request, User roadieUser = null);
Task<PagedResult<PlaylistList>> ListAsync(PagedRequest request, User roadieUser = null);
Task<OperationResult<bool>> ReorderPlaylist(data.Playlist playlist);
Task<OperationResult<bool>> ReorderPlaylistAsync(data.Playlist playlist);
Task<OperationResult<bool>> UpdatePlaylist(User user, Playlist label);
Task<OperationResult<bool>> UpdatePlaylistAsync(User user, Playlist label);
Task<OperationResult<bool>> UpdatePlaylistTracks(User user, PlaylistTrackModifyRequest request);
Task<OperationResult<bool>> UpdatePlaylistTracksAsync(User user, PlaylistTrackModifyRequest request);
}
}

View file

@ -1,10 +1,8 @@
using Microsoft.AspNetCore.Http;
using Roadie.Library;
using Roadie.Library.Identity;
using Roadie.Library.Models;
using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Releases;
using Roadie.Library.Models.Users;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
@ -15,26 +13,26 @@ namespace Roadie.Api.Services
{
IEnumerable<int> AddedTrackIds { get; }
Task<OperationResult<Release>> ById(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null);
Task<OperationResult<Release>> ByIdAsync(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null);
Task<OperationResult<bool>> Delete(Library.Identity.User user, Library.Data.Release release, bool doDeleteFiles = false, bool doUpdateArtistCounts = true);
Task<OperationResult<bool>> DeleteAsync(Library.Identity.User user, Library.Data.Release release, bool doDeleteFiles = false, bool doUpdateArtistCounts = true);
Task<OperationResult<bool>> DeleteReleases(Library.Identity.User user, IEnumerable<Guid> releaseIds, bool doDeleteFiles = false);
Task<OperationResult<bool>> DeleteReleasesAsync(Library.Identity.User user, IEnumerable<Guid> releaseIds, bool doDeleteFiles = false);
Task<PagedResult<ReleaseList>> List(Library.Models.Users.User user, PagedRequest request, bool? doRandomize = false, IEnumerable<string> includes = null);
Task<PagedResult<ReleaseList>> ListAsync(Library.Models.Users.User user, PagedRequest request, bool? doRandomize = false, IEnumerable<string> includes = null);
Task<OperationResult<bool>> MergeReleases(Library.Identity.User user, Guid releaseToMergeId, Guid releaseToMergeIntoId, bool addAsMedia);
Task<OperationResult<bool>> MergeReleasesAsync(Library.Identity.User user, Guid releaseToMergeId, Guid releaseToMergeIntoId, bool addAsMedia);
Task<OperationResult<bool>> MergeReleases(Library.Identity.User user, Library.Data.Release releaseToMerge, Library.Data.Release releaseToMergeInto, bool addAsMedia);
Task<OperationResult<bool>> MergeReleasesAsync(Library.Identity.User user, Library.Data.Release releaseToMerge, Library.Data.Release releaseToMergeInto, bool addAsMedia);
Task<FileOperationResult<byte[]>> ReleaseZipped(Library.Models.Users.User roadieUser, Guid id);
Task<FileOperationResult<byte[]>> ReleaseZippedAsync(Library.Models.Users.User roadieUser, Guid id);
Task<OperationResult<bool>> ScanReleaseFolder(Library.Identity.User user, Guid releaseId, bool doJustInfo, Library.Data.Release releaseToScan = null);
Task<OperationResult<bool>> ScanReleaseFolderAsync(Library.Identity.User user, Guid releaseId, bool doJustInfo, Library.Data.Release releaseToScan = null);
Task<OperationResult<Image>> SetReleaseImageByUrl(Library.Identity.User user, Guid id, string imageUrl);
Task<OperationResult<Image>> SetReleaseImageByUrlAsync(Library.Identity.User user, Guid id, string imageUrl);
Task<OperationResult<bool>> UpdateRelease(Library.Identity.User user, Release release, string originalReleaseFolder = null);
Task<OperationResult<bool>> UpdateReleaseAsync(Library.Identity.User user, Release release, string originalReleaseFolder = null);
Task<OperationResult<Image>> UploadReleaseImage(Library.Identity.User user, Guid id, IFormFile file);
Task<OperationResult<Image>> UploadReleaseImageAsync(Library.Identity.User user, Guid id, IFormFile file);
}
}

View file

@ -7,17 +7,17 @@ namespace Roadie.Api.Services
{
public interface IStatisticsService
{
Task<OperationResult<LibraryStats>> LibraryStatistics();
Task<OperationResult<IEnumerable<DateAndCount>>> ArtistsByDate();
Task<OperationResult<IEnumerable<DateAndCount>>> ArtistsByDateAsync();
Task<OperationResult<LibraryStats>> LibraryStatisticsAsync();
Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDate();
Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDateAsync();
Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDecade();
Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDecadeAsync();
Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByDate();
Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByDateAsync();
Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByUser();
Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByUserAsync();
}
}

View file

@ -1,5 +1,4 @@
using Roadie.Library.Models;
using Roadie.Library.Models.ThirdPartyApi.Subsonic;
using Roadie.Library.Models.ThirdPartyApi.Subsonic;
using System.Threading.Tasks;
using User = Roadie.Library.Models.Users.User;
@ -7,85 +6,85 @@ namespace Roadie.Api.Services
{
public interface ISubsonicService
{
Task<SubsonicOperationResult<Response>> AddChatMessage(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> AddChatMessageAsync(Request request, User roadieUser);
Task<SubsonicOperationResult<SubsonicAuthenticateResponse>> Authenticate(Request request);
Task<SubsonicOperationResult<SubsonicAuthenticateResponse>> AuthenticateAsync(Request request);
Task<SubsonicOperationResult<Response>> CreateBookmark(Request request, User roadieUser, int position, string comment);
Task<SubsonicOperationResult<Response>> CreateBookmarkAsync(Request request, User roadieUser, int position, string comment);
Task<SubsonicOperationResult<Response>> CreatePlaylist(Request request, User roadieUser, string name, string[] songIds, string playlistId = null);
Task<SubsonicOperationResult<Response>> CreatePlaylistAsync(Request request, User roadieUser, string name, string[] songIds, string playlistId = null);
Task<SubsonicOperationResult<Response>> DeleteBookmark(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> DeleteBookmarkAsync(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> DeletePlaylist(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> DeletePlaylistAsync(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetAlbum(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetAlbumAsync(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetAlbumInfo(Request request, User roadieUser, AlbumInfoVersion version);
Task<SubsonicOperationResult<Response>> GetAlbumInfoAsync(Request request, User roadieUser, AlbumInfoVersion version);
Task<SubsonicOperationResult<Response>> GetAlbumList(Request request, User roadieUser, AlbumListVersions version);
Task<SubsonicOperationResult<Response>> GetAlbumListAsync(Request request, User roadieUser, AlbumListVersions version);
Task<SubsonicOperationResult<Response>> GetArtist(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetArtistAsync(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetArtistInfo(Request request, int? count, bool includeNotPresent, ArtistInfoVersion version);
Task<SubsonicOperationResult<Response>> GetArtistInfoAsync(Request request, int? count, bool includeNotPresent, ArtistInfoVersion version);
Task<SubsonicOperationResult<Response>> GetArtists(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetArtistsAsync(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetBookmarks(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetBookmarksAsync(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetChatMessages(Request request, User roadieUser, long? since);
Task<SubsonicOperationResult<Response>> GetChatMessagesAsync(Request request, User roadieUser, long? since);
Task<SubsonicFileOperationResult<Library.Models.Image>> GetCoverArt(Request request, int? size);
Task<SubsonicFileOperationResult<Library.Models.Image>> GetCoverArtAsync(Request request, int? size);
Task<SubsonicOperationResult<Response>> GetGenres(Request request);
Task<SubsonicOperationResult<Response>> GetGenresAsync(Request request);
Task<SubsonicOperationResult<Response>> GetIndexes(Request request, User roadieUser, long? ifModifiedSince = null);
Task<SubsonicOperationResult<Response>> GetIndexesAsync(Request request, User roadieUser, long? ifModifiedSince = null);
SubsonicOperationResult<Response> GetLicense(Request request);
SubsonicOperationResult<Response> GetLyrics(Request request, string artistId, string title);
Task<SubsonicOperationResult<Response>> GetMusicDirectory(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetMusicDirectoryAsync(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetMusicFolders(Request request);
Task<SubsonicOperationResult<Response>> GetMusicFoldersAsync(Request request);
Task<SubsonicOperationResult<Response>> GetNowPlaying(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetNowPlayingAsync(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetPlaylist(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetPlaylistAsync(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetPlaylists(Request request, User roadieUser, string filterToUserName);
Task<SubsonicOperationResult<Response>> GetPlaylistsAsync(Request request, User roadieUser, string filterToUserName);
Task<SubsonicOperationResult<Response>> GetPlayQueue(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetPlayQueueAsync(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetPodcasts(Request request);
Task<SubsonicOperationResult<Response>> GetPodcastsAsync(Request request);
Task<SubsonicOperationResult<Response>> GetRandomSongs(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetRandomSongsAsync(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetSimliarSongs(Request request, User roadieUser, SimilarSongsVersion version, int? count = 50);
Task<SubsonicOperationResult<Response>> GetSimliarSongsAsync(Request request, User roadieUser, SimilarSongsVersion version, int? count = 50);
Task<SubsonicOperationResult<Response>> GetSong(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetSongAsync(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetSongsByGenre(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetSongsByGenreAsync(Request request, User roadieUser);
Task<SubsonicOperationResult<Response>> GetStarred(Request request, User roadieUser, StarredVersion version);
Task<SubsonicOperationResult<Response>> GetStarredAsync(Request request, User roadieUser, StarredVersion version);
Task<SubsonicOperationResult<Response>> GetTopSongs(Request request, User roadieUser, int? count = 50);
Task<SubsonicOperationResult<Response>> GetTopSongsAsync(Request request, User roadieUser, int? count = 50);
Task<SubsonicOperationResult<Response>> GetUser(Request request, string username);
Task<SubsonicOperationResult<Response>> GetUserAsync(Request request, string username);
SubsonicOperationResult<Response> GetVideos(Request request);
SubsonicOperationResult<Response> Ping(Request request);
Task<SubsonicOperationResult<Response>> SavePlayQueue(Request request, User roadieUser, string current, long? position);
Task<SubsonicOperationResult<Response>> SavePlayQueueAsync(Request request, User roadieUser, string current, long? position);
Task<SubsonicOperationResult<Response>> Search(Request request, User roadieUser, SearchVersion version);
Task<SubsonicOperationResult<Response>> SearchAsync(Request request, User roadieUser, SearchVersion version);
Task<SubsonicOperationResult<Response>> SetRating(Request request, User roadieUser, short rating);
Task<SubsonicOperationResult<Response>> SetRatingAsync(Request request, User roadieUser, short rating);
Task<SubsonicOperationResult<Response>> ToggleStar(Request request, User roadieUser, bool star, string[] albumIds = null, string[] artistIds = null);
Task<SubsonicOperationResult<Response>> ToggleStarAsync(Request request, User roadieUser, bool star, string[] albumIds = null, string[] artistIds = null);
Task<SubsonicOperationResult<Response>> UpdatePlaylist(Request request, User roadieUser, string playlistId,
Task<SubsonicOperationResult<Response>> UpdatePlaylistAsync(Request request, User roadieUser, string playlistId,
string name = null, string comment = null, bool? isPublic = null, string[] songIdsToAdd = null,
int[] songIndexesToRemove = null);
}

View file

@ -6,6 +6,6 @@ namespace Roadie.Api.Services
{
public interface ITokenService
{
Task<string> GenerateToken(User user, UserManager<User> userManager);
Task<string> GenerateTokenAsync(User user, UserManager<User> userManager);
}
}

View file

@ -10,16 +10,14 @@ namespace Roadie.Api.Services
{
public interface ITrackService
{
Task<OperationResult<Track>> ById(User roadieUser, Guid id, IEnumerable<string> includes);
Task<OperationResult<Track>> ByIdAsyncAsync(User roadieUser, Guid id, IEnumerable<string> includes);
Task<PagedResult<TrackList>> List(PagedRequest request, User roadieUser, bool? doRandomize = false,
Guid? releaseId = null);
Task<PagedResult<TrackList>> ListAsync(PagedRequest request, User roadieUser, bool? doRandomize = false, Guid? releaseId = null);
OperationResult<Track> StreamCheckAndInfo(User roadieUser, Guid id);
Task<OperationResult<TrackStreamInfo>> TrackStreamInfo(Guid trackId, long beginBytes, long endBytes,
User roadieUser);
Task<OperationResult<TrackStreamInfo>> TrackStreamInfoAsync(Guid trackId, long beginBytes, long endBytes, User roadieUser);
Task<OperationResult<bool>> UpdateTrack(User user, Track track);
Task<OperationResult<bool>> UpdateTrackAsync(User user, Track track);
}
}

View file

@ -9,44 +9,44 @@ namespace Roadie.Api.Services
{
public interface IUserService
{
Task<OperationResult<User>> ById(User user, Guid id, IEnumerable<string> includes, bool isAccountSettingsEdit = false);
Task<OperationResult<User>> ByIdAsync(User user, Guid id, IEnumerable<string> includes, bool isAccountSettingsEdit = false);
Task<PagedResult<UserList>> List(PagedRequest request);
Task<OperationResult<bool>> DeleteAllBookmarksAsync(User roadieUser);
Task<OperationResult<bool>> DeleteAllBookmarks(User roadieUser);
Task<PagedResult<UserList>> ListAsync(PagedRequest request);
Task<OperationResult<bool>> SetArtistBookmark(Guid artistId, User roadieUser, bool isBookmarked);
Task<OperationResult<bool>> SetArtistBookmarkAsync(Guid artistId, User roadieUser, bool isBookmarked);
Task<OperationResult<bool>> SetArtistDisliked(Guid artistId, User roadieUser, bool isDisliked);
Task<OperationResult<bool>> SetArtistDislikedAsync(Guid artistId, User roadieUser, bool isDisliked);
Task<OperationResult<bool>> SetArtistFavorite(Guid artistId, User roadieUser, bool isFavorite);
Task<OperationResult<bool>> SetArtistFavoriteAsync(Guid artistId, User roadieUser, bool isFavorite);
Task<OperationResult<short>> SetArtistRating(Guid artistId, User roadieUser, short rating);
Task<OperationResult<short>> SetArtistRatingAsync(Guid artistId, User roadieUser, short rating);
Task<OperationResult<bool>> SetCollectionBookmark(Guid collectionId, User roadieUser, bool isBookmarked);
Task<OperationResult<bool>> SetCollectionBookmarkAsync(Guid collectionId, User roadieUser, bool isBookmarked);
Task<OperationResult<bool>> SetLabelBookmark(Guid labelId, User roadieUser, bool isBookmarked);
Task<OperationResult<bool>> SetLabelBookmarkAsync(Guid labelId, User roadieUser, bool isBookmarked);
Task<OperationResult<bool>> SetPlaylistBookmark(Guid playlistId, User roadieUser, bool isBookmarked);
Task<OperationResult<bool>> SetPlaylistBookmarkAsync(Guid playlistId, User roadieUser, bool isBookmarked);
Task<OperationResult<bool>> SetReleaseBookmark(Guid releaseid, User roadieUser, bool isBookmarked);
Task<OperationResult<bool>> SetReleaseBookmarkAsync(Guid releaseid, User roadieUser, bool isBookmarked);
Task<OperationResult<bool>> SetReleaseDisliked(Guid releaseId, User roadieUser, bool isDisliked);
Task<OperationResult<bool>> SetReleaseDislikedAsync(Guid releaseId, User roadieUser, bool isDisliked);
Task<OperationResult<bool>> SetReleaseFavorite(Guid releaseId, User roadieUser, bool isFavorite);
Task<OperationResult<bool>> SetReleaseFavoriteAsync(Guid releaseId, User roadieUser, bool isFavorite);
Task<OperationResult<short>> SetReleaseRating(Guid releaseId, User roadieUser, short rating);
Task<OperationResult<short>> SetReleaseRatingAsync(Guid releaseId, User roadieUser, short rating);
Task<OperationResult<bool>> SetTrackBookmark(Guid trackId, User roadieUser, bool isBookmarked);
Task<OperationResult<bool>> SetTrackBookmarkAsync(Guid trackId, User roadieUser, bool isBookmarked);
Task<OperationResult<bool>> SetTrackDisliked(Guid trackId, User roadieUser, bool isDisliked);
Task<OperationResult<bool>> SetTrackDislikedAsync(Guid trackId, User roadieUser, bool isDisliked);
Task<OperationResult<bool>> SetTrackFavorite(Guid releaseId, User roadieUser, bool isFavorite);
Task<OperationResult<bool>> SetTrackFavoriteAsync(Guid releaseId, User roadieUser, bool isFavorite);
Task<OperationResult<short>> SetTrackRating(Guid trackId, User roadieUser, short rating);
Task<OperationResult<short>> SetTrackRatingAsync(Guid trackId, User roadieUser, short rating);
Task<OperationResult<bool>> UpdateIntegrationGrant(Guid userId, string integrationName, string token);
Task<OperationResult<bool>> UpdateIntegrationGrantAsync(Guid userId, string integrationName, string token);
Task<OperationResult<bool>> UpdateProfile(User userPerformingUpdate, User userBeingUpdatedModel);
Task<OperationResult<bool>> UpdateProfileAsync(User userPerformingUpdate, User userBeingUpdatedModel);
}
}

View file

@ -23,12 +23,20 @@ namespace Roadie.Api.Services
{
public class ImageService : ServiceBase, IImageService
{
public string Referrer { get; set; }
public string RequestIp { get; set; }
private IDefaultNotFoundImages DefaultNotFoundImages { get; }
private IImageSearchManager ImageSearchManager { get; }
public string Referrer { get; set; }
public string RequestIp { get; set; }
public ImageService(IRoadieSettings configuration, IRoadieDbContext dbContext, ICacheManager cacheManager,
ILogger logger, DefaultNotFoundImages defaultNotFoundImages)
: base(configuration, null, dbContext, cacheManager, logger, null)
{
DefaultNotFoundImages = defaultNotFoundImages;
}
public ImageService(IRoadieSettings configuration,
IHttpEncoder httpEncoder,
IHttpContext httpContext,
@ -43,149 +51,6 @@ namespace Roadie.Api.Services
ImageSearchManager = imageSearchManager;
}
public ImageService(IRoadieSettings configuration, IRoadieDbContext dbContext, ICacheManager cacheManager,
ILogger logger, DefaultNotFoundImages defaultNotFoundImages)
: base(configuration, null, dbContext, cacheManager, logger, null)
{
DefaultNotFoundImages = defaultNotFoundImages;
}
public async Task<FileOperationResult<IImage>> ArtistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return await GetImageFileOperation("ArtistImage",
data.Artist.CacheRegionUrn(id),
id,
width,
height,
async () => { return await ArtistImageAction(id, etag); },
etag);
}
public async Task<FileOperationResult<IImage>> ArtistSecondaryImage(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null)
{
return await GetImageFileOperation($"ArtistSecondaryThumbnail.{imageId}",
data.Artist.CacheRegionUrn(id),
id,
width,
height,
async () => { return await ArtistSecondaryImageAction(id, imageId, etag); },
etag);
}
public async Task<FileOperationResult<IImage>> CollectionImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return await GetImageFileOperation("CollectionThumbnail",
data.Collection.CacheRegionUrn(id),
id,
width,
height,
async () => { return await CollectionImageAction(id, etag); },
etag);
}
public async Task<FileOperationResult<IImage>> GenreImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return await GetImageFileOperation("GenreThumbnail",
data.Genre.CacheRegionUrn(id),
id,
width,
height,
async () => await GenreImageAction(id, etag),
etag);
}
public async Task<FileOperationResult<IImage>> LabelImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return await GetImageFileOperation("LabelThumbnail",
data.Label.CacheRegionUrn(id),
id,
width,
height,
async () => await LabelImageAction(id, etag),
etag);
}
public async Task<FileOperationResult<IImage>> PlaylistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return await GetImageFileOperation("PlaylistThumbnail",
data.Playlist.CacheRegionUrn(id),
id,
width,
height,
async () => await PlaylistImageAction(id, etag),
etag);
}
public async Task<FileOperationResult<IImage>> ReleaseImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return await GetImageFileOperation("ReleaseThumbnail",
data.Release.CacheRegionUrn(id),
id,
width,
height,
async () => await ReleaseImageAction(id, etag),
etag);
}
public async Task<FileOperationResult<IImage>> ReleaseSecondaryImage(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null)
{
return await GetImageFileOperation($"ReleaseSecondaryThumbnail-{imageId}",
data.Release.CacheRegionUrn(id),
id,
width,
height,
async () => { return await ReleaseSecondaryImageAction(id, imageId, etag); },
etag);
}
public async Task<OperationResult<IEnumerable<ImageSearchResult>>> Search(string query, int resultsCount = 10)
{
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
IEnumerable<ImageSearchResult> searchResults = null;
try
{
searchResults = await ImageSearchManager.ImageSearch(query);
}
catch (Exception ex)
{
Logger.LogError(ex);
errors.Add(ex);
}
sw.Stop();
return new OperationResult<IEnumerable<ImageSearchResult>>
{
Data = searchResults,
IsSuccess = !errors.Any(),
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<FileOperationResult<IImage>> TrackImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return await GetImageFileOperation("TrackThumbnail",
data.Track.CacheRegionUrn(id),
id,
width,
height,
async () => await TrackImageAction(id, width, height, etag),
etag);
}
public async Task<FileOperationResult<IImage>> UserImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return await GetImageFileOperation("UserById",
User.CacheRegionUrn(id),
id,
width,
height,
async () => await UserImageAction(id, etag),
etag);
}
/// <summary>
/// Get image for an artist, see if the artist has an image in their folder and use that else use Artist.Thumbnail, is also not found use Artist DefaultNotFound image.
/// </summary>
@ -193,10 +58,10 @@ namespace Roadie.Api.Services
{
try
{
var artist = await GetArtist(id);
var artist = await GetArtist(id).ConfigureAwait(false);
if (artist == null)
{
return new FileOperationResult<IImage>(true, string.Format("Artist Not Found [{0}]", id));
return new FileOperationResult<IImage>(true, $"Artist Not Found [{id}]");
}
byte[] imageBytes = null;
string artistFolder = null;
@ -226,7 +91,7 @@ namespace Roadie.Api.Services
{
Bytes = imageBytes,
};
if (imageBytes == null || !imageBytes.Any())
if (imageBytes?.Any() != true)
{
image = DefaultNotFoundImages.Artist;
}
@ -244,10 +109,10 @@ namespace Roadie.Api.Services
{
try
{
var artist = await GetArtist(id);
var artist = await GetArtist(id).ConfigureAwait(false);
if (artist == null)
{
return new FileOperationResult<IImage>(true, string.Format("Release Not Found [{0}]", id));
return new FileOperationResult<IImage>(true, $"Release Not Found [{id}]");
}
byte[] imageBytes = null;
string artistFolder = null;
@ -265,7 +130,9 @@ namespace Roadie.Api.Services
.FindImageTypeInDirectory(new DirectoryInfo(artistFolder), ImageType.ArtistSecondary)
.ToArray();
if (artistSecondaryImages.Length >= imageId && artistSecondaryImages[imageId] != null)
{
imageBytes = File.ReadAllBytes(artistSecondaryImages[imageId].FullName);
}
}
}
catch (Exception ex)
@ -292,10 +159,10 @@ namespace Roadie.Api.Services
{
try
{
var collection = await GetCollection(id);
var collection = await GetCollection(id).ConfigureAwait(false);
if (collection == null)
{
return new FileOperationResult<IImage>(true, string.Format("Collection Not Found [{0}]", id));
return new FileOperationResult<IImage>(true, $"Collection Not Found [{id}]");
}
IImage image = new Library.Imaging.Image(id)
{
@ -313,7 +180,7 @@ namespace Roadie.Api.Services
{
Logger.LogError(ex, $"Error Reading Image File [{collectionImageFilename}]");
}
if (image.Bytes == null || !image.Bytes.Any())
if (image.Bytes?.Any() != true)
{
image = DefaultNotFoundImages.Collection;
}
@ -336,7 +203,7 @@ namespace Roadie.Api.Services
}
if (image?.Bytes?.Any() != true)
{
return new FileOperationResult<IImage>(string.Format("ImageById Not Set [{0}]", id));
return new FileOperationResult<IImage>($"ImageById Not Set [{id}]");
}
return new FileOperationResult<IImage>(image?.Bytes?.Any() ?? false
? OperationMessages.OkMessage
@ -354,10 +221,10 @@ namespace Roadie.Api.Services
{
try
{
var genre = await GetGenre(id);
var genre = await GetGenre(id).ConfigureAwait(false);
if (genre == null)
{
return new FileOperationResult<IImage>(true, string.Format("Genre Not Found [{0}]", id));
return new FileOperationResult<IImage>(true, $"Genre Not Found [{id}]");
}
IImage image = new Library.Imaging.Image(id)
{
@ -375,7 +242,7 @@ namespace Roadie.Api.Services
{
Logger.LogError(ex, $"Error Reading Image File [{genreImageFilename}]");
}
if (image.Bytes == null || !image.Bytes.Any())
if (image.Bytes?.Any() != true)
{
image = DefaultNotFoundImages.Genre;
}
@ -395,7 +262,7 @@ namespace Roadie.Api.Services
{
var sw = Stopwatch.StartNew();
var sizeHash = (width ?? 0) + (height ?? 0);
var result = await CacheManager.GetAsync($"urn:{type}_by_id_operation:{id}:{sizeHash}", action, regionUrn);
var result = await CacheManager.GetAsync($"urn:{type}_by_id_operation:{id}:{sizeHash}", action, regionUrn).ConfigureAwait(false);
if (!result.IsSuccess)
{
return new FileOperationResult<IImage>(result.IsNotFoundResult, result.Messages);
@ -450,10 +317,10 @@ namespace Roadie.Api.Services
{
try
{
var label = await GetLabel(id);
var label = await GetLabel(id).ConfigureAwait(false);
if (label == null)
{
return new FileOperationResult<IImage>(true, string.Format("Label Not Found [{0}]", id));
return new FileOperationResult<IImage>(true, $"Label Not Found [{id}]");
}
IImage image = new Library.Imaging.Image(id)
{
@ -471,7 +338,7 @@ namespace Roadie.Api.Services
{
Logger.LogError(ex, $"Error Reading Image File [{labelImageFilename}]");
}
if (image.Bytes == null || !image.Bytes.Any())
if (image.Bytes?.Any() != true)
{
image = DefaultNotFoundImages.Label;
}
@ -489,10 +356,10 @@ namespace Roadie.Api.Services
{
try
{
var playlist = await GetPlaylist(id);
var playlist = await GetPlaylist(id).ConfigureAwait(false);
if (playlist == null)
{
return new FileOperationResult<IImage>(true, string.Format("Playlist Not Found [{0}]", id));
return new FileOperationResult<IImage>(true, $"Playlist Not Found [{id}]");
}
IImage image = new Library.Imaging.Image(id)
{
@ -510,7 +377,7 @@ namespace Roadie.Api.Services
{
Logger.LogError(ex, $"Error Reading Image File [{playlistImageFilename}]");
}
if (image.Bytes == null || !image.Bytes.Any())
if (image.Bytes?.Any() != true)
{
image = DefaultNotFoundImages.Playlist;
}
@ -531,10 +398,10 @@ namespace Roadie.Api.Services
{
try
{
var release = await GetRelease(id);
var release = await GetRelease(id).ConfigureAwait(false);
if (release == null)
{
return new FileOperationResult<IImage>(true, string.Format("Release Not Found [{0}]", id));
return new FileOperationResult<IImage>(true, $"Release Not Found [{id}]");
}
byte[] imageBytes = null;
string artistFolder = null;
@ -591,10 +458,10 @@ namespace Roadie.Api.Services
{
try
{
var release = await GetRelease(id);
var release = await GetRelease(id).ConfigureAwait(false);
if (release == null)
{
return new FileOperationResult<IImage>(true, string.Format("Release Not Found [{0}]", id));
return new FileOperationResult<IImage>(true, $"Release Not Found [{id}]");
}
byte[] imageBytes = null;
string artistFolder = null;
@ -620,7 +487,9 @@ namespace Roadie.Api.Services
.FindImageTypeInDirectory(new DirectoryInfo(releaseFolder), ImageType.ReleaseSecondary)
.ToArray();
if (releaseSecondaryImages.Length >= imageId && releaseSecondaryImages[imageId] != null)
{
imageBytes = File.ReadAllBytes(releaseSecondaryImages[imageId].FullName);
}
}
}
}
@ -649,10 +518,10 @@ namespace Roadie.Api.Services
{
try
{
var track = await GetTrack(id);
var track = await GetTrack(id).ConfigureAwait(false);
if (track == null)
{
return new FileOperationResult<IImage>(true, string.Format("Track Not Found [{0}]", id));
return new FileOperationResult<IImage>(true, $"Track Not Found [{id}]");
}
IImage image = new Library.Imaging.Image(id)
{
@ -663,10 +532,10 @@ namespace Roadie.Api.Services
{
image.Bytes = File.ReadAllBytes(trackImageFileName);
}
if (image.Bytes == null || !image.Bytes.Any())
if (image.Bytes?.Any() != true)
{
// If no track image is found then return image for release
return await ReleaseImage(track.ReleaseMedia.Release.RoadieId, width, height, etag);
return await ReleaseImageAsync(track.ReleaseMedia.Release.RoadieId, width, height, etag).ConfigureAwait(false);
}
return GenerateFileOperationResult(id, image, etag);
}
@ -682,10 +551,10 @@ namespace Roadie.Api.Services
{
try
{
var user = await GetUser(id);
var user = await GetUser(id).ConfigureAwait(false);
if (user == null)
{
return new FileOperationResult<IImage>(true, string.Format("User Not Found [{0}]", id));
return new FileOperationResult<IImage>(true, $"User Not Found [{id}]");
}
IImage image = new Library.Imaging.Image(id)
{
@ -703,7 +572,7 @@ namespace Roadie.Api.Services
{
Logger.LogError(ex, $"Error Reading Image File [{userImageFilename}]");
}
if (image.Bytes == null || !image.Bytes.Any())
if (image.Bytes?.Any() != true)
{
image = DefaultNotFoundImages.User;
}
@ -716,5 +585,141 @@ namespace Roadie.Api.Services
return new FileOperationResult<IImage>(OperationMessages.ErrorOccured);
}
public Task<FileOperationResult<IImage>> ArtistImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return GetImageFileOperation(nameof(ArtistImageAsync),
data.Artist.CacheRegionUrn(id),
id,
width,
height,
async () => { return await ArtistImageAction(id, etag).ConfigureAwait(false); },
etag);
}
public Task<FileOperationResult<IImage>> ArtistSecondaryImageAsync(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null)
{
return GetImageFileOperation($"ArtistSecondaryThumbnail.{imageId}",
data.Artist.CacheRegionUrn(id),
id,
width,
height,
async () => { return await ArtistSecondaryImageAction(id, imageId, etag).ConfigureAwait(false); },
etag);
}
public Task<FileOperationResult<IImage>> CollectionImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return GetImageFileOperation("CollectionThumbnail",
data.Collection.CacheRegionUrn(id),
id,
width,
height,
async () => { return await CollectionImageAction(id, etag).ConfigureAwait(false); },
etag);
}
public Task<FileOperationResult<IImage>> GenreImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return GetImageFileOperation("GenreThumbnail",
data.Genre.CacheRegionUrn(id),
id,
width,
height,
async () => await GenreImageAction(id, etag).ConfigureAwait(false),
etag);
}
public Task<FileOperationResult<IImage>> LabelImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return GetImageFileOperation("LabelThumbnail",
data.Label.CacheRegionUrn(id),
id,
width,
height,
async () => await LabelImageAction(id, etag).ConfigureAwait(false),
etag);
}
public Task<FileOperationResult<IImage>> PlaylistImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return GetImageFileOperation("PlaylistThumbnail",
data.Playlist.CacheRegionUrn(id),
id,
width,
height,
async () => await PlaylistImageAction(id, etag).ConfigureAwait(false),
etag);
}
public Task<FileOperationResult<IImage>> ReleaseImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return GetImageFileOperation("ReleaseThumbnail",
data.Release.CacheRegionUrn(id),
id,
width,
height,
async () => await ReleaseImageAction(id, etag).ConfigureAwait(false),
etag);
}
public Task<FileOperationResult<IImage>> ReleaseSecondaryImageAsync(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null)
{
return GetImageFileOperation($"ReleaseSecondaryThumbnail-{imageId}",
data.Release.CacheRegionUrn(id),
id,
width,
height,
async () => { return await ReleaseSecondaryImageAction(id, imageId, etag).ConfigureAwait(false); },
etag);
}
public async Task<OperationResult<IEnumerable<ImageSearchResult>>> SearchAsync(string query, int resultsCount = 10)
{
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
IEnumerable<ImageSearchResult> searchResults = null;
try
{
searchResults = await ImageSearchManager.ImageSearch(query).ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.LogError(ex);
errors.Add(ex);
}
sw.Stop();
return new OperationResult<IEnumerable<ImageSearchResult>>
{
Data = searchResults,
IsSuccess = errors.Count == 0,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public Task<FileOperationResult<IImage>> TrackImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return GetImageFileOperation("TrackThumbnail",
data.Track.CacheRegionUrn(id),
id,
width,
height,
async () => await TrackImageAction(id, width, height, etag).ConfigureAwait(false),
etag);
}
public Task<FileOperationResult<IImage>> UserImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return GetImageFileOperation("UserById",
User.CacheRegionUrn(id),
id,
width,
height,
async () => await UserImageAction(id, etag).ConfigureAwait(false),
etag);
}
}
}

View file

@ -9,7 +9,6 @@ using Roadie.Library.Data.Context;
using Roadie.Library.Encoding;
using Roadie.Library.Enums;
using Roadie.Library.Extensions;
using Roadie.Library.Identity;
using Roadie.Library.Imaging;
using Roadie.Library.Models;
using Roadie.Library.Models.Pagination;
@ -43,318 +42,6 @@ namespace Roadie.Api.Services
BookmarkService = bookmarkService;
}
public async Task<OperationResult<Label>> ById(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null)
{
var sw = Stopwatch.StartNew();
sw.Start();
var cacheKey = string.Format("urn:label_by_id_operation:{0}:{1}", id,
includes == null ? "0" : string.Join("|", includes));
var result = await CacheManager.GetAsync(cacheKey,
async () => { return await LabelByIdAction(id, includes); }, data.Label.CacheRegionUrn(id));
sw.Stop();
if (result?.Data != null && roadieUser != null)
{
var userBookmarkResult = await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Label);
if (userBookmarkResult.IsSuccess)
{
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x?.Bookmark?.Value == result?.Data?.Id?.ToString()) != null;
}
if (result.Data.Comments.Any())
{
var commentIds = result.Data.Comments.Select(x => x.DatabaseId).ToArray();
var userCommentReactions = (from cr in DbContext.CommentReactions
where commentIds.Contains(cr.CommentId)
where cr.UserId == roadieUser.Id
select cr).ToArray();
foreach (var comment in result.Data.Comments)
{
var userCommentReaction = userCommentReactions.FirstOrDefault(x => x.CommentId == comment.DatabaseId);
comment.IsDisliked = userCommentReaction?.ReactionValue == CommentReaction.Dislike;
comment.IsLiked = userCommentReaction?.ReactionValue == CommentReaction.Like;
}
}
}
return new OperationResult<Label>(result.Messages)
{
Data = result?.Data,
IsNotFoundResult = result?.IsNotFoundResult ?? false,
Errors = result?.Errors,
IsSuccess = result?.IsSuccess ?? false,
OperationTime = sw.ElapsedMilliseconds
};
}
public async Task<OperationResult<bool>> Delete(Library.Identity.User user, Guid id)
{
var sw = new Stopwatch();
sw.Start();
var label = DbContext.Labels.FirstOrDefault(x => x.RoadieId == id);
if (label == null) return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", id));
DbContext.Labels.Remove(label);
await DbContext.SaveChangesAsync();
var labelImageFilename = label.PathToImage(Configuration);
if (File.Exists(labelImageFilename))
{
File.Delete(labelImageFilename);
}
await BookmarkService.RemoveAllBookmarksForItem(BookmarkType.Label, label.Id);
Logger.LogWarning("User `{0}` deleted Label `{1}]`", user, label);
CacheManager.ClearRegion(label.CacheRegion);
sw.Stop();
return new OperationResult<bool>
{
IsSuccess = true,
Data = true,
OperationTime = sw.ElapsedMilliseconds
};
}
public async Task<Library.Models.Pagination.PagedResult<LabelList>> List(Library.Models.Users.User roadieUser, PagedRequest request,
bool? doRandomize = false)
{
var sw = new Stopwatch();
sw.Start();
int? rowCount = null;
if (!string.IsNullOrEmpty(request.Sort))
{
request.Sort = request.Sort.Replace("createdDate", "createdDateTime");
request.Sort = request.Sort.Replace("lastUpdated", "lastUpdatedDateTime");
}
var normalizedFilterValue = !string.IsNullOrEmpty(request.FilterValue)
? request.FilterValue.ToAlphanumericName()
: null;
int[] randomLabelIds = null;
SortedDictionary<int, int> randomLabelData = null;
if (doRandomize ?? false)
{
var randomLimit = request.Limit ?? roadieUser?.RandomReleaseLimit ?? request.LimitValue;
randomLabelData = await DbContext.RandomLabelIds(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly);
randomLabelIds = randomLabelData.Select(x => x.Value).ToArray();
rowCount = DbContext.Labels.Count();
}
var result = from l in DbContext.Labels
where randomLabelIds == null || randomLabelIds.Contains(l.Id)
where string.IsNullOrEmpty(normalizedFilterValue) || (
l.Name.ToLower().Contains(normalizedFilterValue) ||
l.SortName.ToLower().Contains(normalizedFilterValue) ||
l.AlternateNames.ToLower().Contains(normalizedFilterValue)
)
select new LabelList
{
DatabaseId = l.Id,
Id = l.RoadieId,
Label = new DataToken
{
Text = l.Name,
Value = l.RoadieId.ToString()
},
SortName = l.SortName,
CreatedDate = l.CreatedDate,
LastUpdated = l.LastUpdated,
ArtistCount = l.ArtistCount,
ReleaseCount = l.ReleaseCount,
TrackCount = l.TrackCount,
Thumbnail = ImageHelper.MakeLabelThumbnailImage(Configuration, HttpContext, l.RoadieId)
};
LabelList[] rows = null;
rowCount = rowCount ?? result.Count();
if (doRandomize ?? false)
{
var resultData = result.ToArray();
rows = (from r in resultData
join ra in randomLabelData on r.DatabaseId equals ra.Value
orderby ra.Key
select r
).ToArray();
}
else
{
var sortBy = string.IsNullOrEmpty(request.Sort)
? request.OrderValue(new Dictionary<string, string> { { "SortName", "ASC" }, { "Label.Text", "ASC" } })
: request.OrderValue();
rows = result
.OrderBy(sortBy)
.Skip(request.SkipValue)
.Take(request.LimitValue)
.ToArray();
}
sw.Stop();
return new Library.Models.Pagination.PagedResult<LabelList>
{
TotalCount = rowCount.Value,
CurrentPage = request.PageValue,
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
OperationTime = sw.ElapsedMilliseconds,
Rows = rows
};
}
public async Task<OperationResult<bool>> MergeLabelsIntoLabel(Library.Identity.User user, Guid intoLabelId, IEnumerable<Guid> labelIdsToMerge)
{
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var label = DbContext.Labels.FirstOrDefault(x => x.RoadieId == intoLabelId);
if (label == null)
{
return new OperationResult<bool>(true, string.Format("Merge Into Label Not Found [{0}]", intoLabelId));
}
var now = DateTime.UtcNow;
var labelsToMerge = (from l in DbContext.Labels
join ltm in labelIdsToMerge on l.RoadieId equals ltm
select l);
foreach (var labelToMerge in labelsToMerge)
{
label.MusicBrainzId = label.MusicBrainzId ?? labelToMerge.MusicBrainzId;
label.SortName = label.SortName ?? labelToMerge.SortName;
label.Profile = label.Profile ?? labelToMerge.Profile;
label.BeginDate = label.BeginDate ?? labelToMerge.BeginDate;
label.EndDate = label.EndDate ?? labelToMerge.EndDate;
label.Profile = label.Profile ?? labelToMerge.Profile;
label.DiscogsId = label.DiscogsId ?? labelToMerge.DiscogsId;
label.ImageUrl = label.ImageUrl ?? labelToMerge.ImageUrl;
label.Tags = label.Tags.AddToDelimitedList(labelToMerge.Tags.ToListFromDelimited());
var altNames = labelToMerge.AlternateNames.ToListFromDelimited().ToList();
altNames.Add(labelToMerge.Name);
altNames.Add(labelToMerge.SortName);
altNames.Add(labelToMerge.Name.ToAlphanumericName());
label.AlternateNames = label.AlternateNames.AddToDelimitedList(altNames);
label.URLs = label.URLs.AddToDelimitedList(labelToMerge.URLs.ToListFromDelimited());
var labelToMergeReleases = (from rl in DbContext.ReleaseLabels
where rl.LabelId == labelToMerge.Id
select rl);
foreach (var labelToMergeRelease in labelToMergeReleases)
{
labelToMergeRelease.LabelId = label.Id;
labelToMergeRelease.LastUpdated = now;
}
label.LastUpdated = now;
await DbContext.SaveChangesAsync();
}
await UpdateLabelCounts(label.Id, now);
CacheManager.ClearRegion(label.CacheRegion);
Logger.LogInformation($"MergeLabelsIntoLabel `{label}`, Merged Label Ids [{ string.Join(",", labelIdsToMerge) }] By User `{user}`");
sw.Stop();
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
Data = !errors.Any(),
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<Library.Models.Image>> SetLabelImageByUrl(Library.Models.Users.User user, Guid id, string imageUrl)
{
return await SaveImageBytes(user, id, WebHelper.BytesForImageUrl(imageUrl));
}
public async Task<OperationResult<bool>> UpdateLabel(Library.Models.Users.User user, Label model)
{
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var label = DbContext.Labels.FirstOrDefault(x => x.RoadieId == model.Id);
if (label == null)
{
return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", model.Id));
}
// If label is being renamed, see if label already exists with new model supplied name
var labelName = label.SortNameValue;
var labelModelName = model.SortNameValue;
var oldPathToImage = label.PathToImage(Configuration);
var didChangeName = !labelName.ToAlphanumericName().Equals(labelModelName.ToAlphanumericName(), StringComparison.OrdinalIgnoreCase);
if (didChangeName)
{
var existingLabel = DbContext.Labels.FirstOrDefault(x => x.Name == model.Name || x.SortName == model.SortName );
if (existingLabel != null)
{
return new OperationResult<bool>($"Label already exists `{ existingLabel }` with name [{ labelModelName }].");
}
}
try
{
var now = DateTime.UtcNow;
var specialLabelName = model.Name.ToAlphanumericName();
var alt = new List<string>(model.AlternateNamesList);
if (!model.AlternateNamesList.Contains(specialLabelName, StringComparer.OrdinalIgnoreCase))
{
alt.Add(specialLabelName);
}
label.AlternateNames = alt.ToDelimitedList();
label.BeginDate = model.BeginDate;
label.DiscogsId = model.DiscogsId;
label.EndDate = model.EndDate;
label.IsLocked = model.IsLocked;
label.MusicBrainzId = model.MusicBrainzId;
label.Name = model.Name;
label.Profile = model.Profile;
label.SortName = model.SortName;
label.Status = SafeParser.ToEnum<Statuses>(model.Status);
label.Tags = model.TagsList.ToDelimitedList();
label.URLs = model.URLsList.ToDelimitedList();
if (didChangeName)
{
if (File.Exists(oldPathToImage))
{
File.Move(oldPathToImage, label.PathToImage(Configuration));
}
}
var labelImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
if (labelImage != null)
{
// Save unaltered label image
File.WriteAllBytes(label.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(labelImage));
}
label.LastUpdated = now;
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(label.CacheRegion);
Logger.LogInformation($"UpdateLabel `{label}` By User `{user}`");
}
catch (Exception ex)
{
Logger.LogError(ex);
errors.Add(ex);
}
sw.Stop();
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
Data = !errors.Any(),
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<Library.Models.Image>> UploadLabelImage(Library.Models.Users.User user, Guid id, IFormFile file)
{
var bytes = new byte[0];
using (var ms = new MemoryStream())
{
file.CopyTo(ms);
bytes = ms.ToArray();
}
return await SaveImageBytes(user, id, bytes);
}
private async Task<OperationResult<Label>> LabelByIdAction(Guid id, IEnumerable<string> includes = null)
{
var timings = new Dictionary<string, long>();
@ -364,12 +51,12 @@ namespace Roadie.Api.Services
sw.Start();
tsw.Restart();
var label = await GetLabel(id);
var label = await GetLabel(id).ConfigureAwait(false);
tsw.Stop();
timings.Add("GetLabel", tsw.ElapsedMilliseconds);
timings.Add(nameof(GetLabel), tsw.ElapsedMilliseconds);
if (label == null)
{
return new OperationResult<Label>(true, string.Format("Label Not Found [{0}]", id));
return new OperationResult<Label>(true, $"Label Not Found [{id}]");
}
tsw.Restart();
var result = label.Adapt<Label>();
@ -456,8 +143,12 @@ namespace Roadie.Api.Services
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var label = DbContext.Labels.FirstOrDefault(x => x.RoadieId == id);
if (label == null) return new OperationResult<Library.Models.Image>(true, string.Format("Label Not Found [{0}]", id));
var label = await DbContext.Labels.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
if (label == null)
{
return new OperationResult<Library.Models.Image>(true, $"Label Not Found [{id}]");
}
try
{
var now = DateTime.UtcNow;
@ -467,7 +158,7 @@ namespace Roadie.Api.Services
File.WriteAllBytes(label.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(imageBytes));
}
label.LastUpdated = now;
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(label.CacheRegion);
Logger.LogInformation($"UploadLabelImage `{label}` By User `{user}`");
}
@ -481,11 +172,324 @@ namespace Roadie.Api.Services
return new OperationResult<Library.Models.Image>
{
IsSuccess = !errors.Any(),
IsSuccess = errors.Count == 0,
Data = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "label", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height, true),
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<Label>> ByIdAsync(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null)
{
var sw = Stopwatch.StartNew();
sw.Start();
var cacheKey = $"urn:label_by_id_operation:{id}:{(includes == null ? "0" : string.Join("|", includes))}";
var result = await CacheManager.GetAsync(cacheKey,
async () => await LabelByIdAction(id, includes).ConfigureAwait(false), data.Label.CacheRegionUrn(id)
).ConfigureAwait(false);
sw.Stop();
if (result?.Data != null && roadieUser != null)
{
var userBookmarkResult = await BookmarkService.ListAsync(roadieUser, new PagedRequest(), false, BookmarkType.Label).ConfigureAwait(false);
if (userBookmarkResult.IsSuccess)
{
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x?.Bookmark?.Value == result?.Data?.Id?.ToString()) != null;
}
if (result.Data.Comments.Any())
{
var commentIds = result.Data.Comments.Select(x => x.DatabaseId).ToArray();
var userCommentReactions = (from cr in DbContext.CommentReactions
where commentIds.Contains(cr.CommentId)
where cr.UserId == roadieUser.Id
select cr).ToArray();
foreach (var comment in result.Data.Comments)
{
var userCommentReaction = userCommentReactions.FirstOrDefault(x => x.CommentId == comment.DatabaseId);
comment.IsDisliked = userCommentReaction?.ReactionValue == CommentReaction.Dislike;
comment.IsLiked = userCommentReaction?.ReactionValue == CommentReaction.Like;
}
}
}
return new OperationResult<Label>(result.Messages)
{
Data = result?.Data,
IsNotFoundResult = result?.IsNotFoundResult ?? false,
Errors = result?.Errors,
IsSuccess = result?.IsSuccess ?? false,
OperationTime = sw.ElapsedMilliseconds
};
}
public async Task<OperationResult<bool>> DeleteAsync(Library.Identity.User user, Guid id)
{
var sw = new Stopwatch();
sw.Start();
var label = await DbContext.Labels.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
if (label == null)
{
return new OperationResult<bool>(true, $"Label Not Found [{id}]");
}
DbContext.Labels.Remove(label);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
var labelImageFilename = label.PathToImage(Configuration);
if (File.Exists(labelImageFilename))
{
File.Delete(labelImageFilename);
}
await BookmarkService.RemoveAllBookmarksForItemAsync(BookmarkType.Label, label.Id).ConfigureAwait(false);
Logger.LogWarning("User `{0}` deleted Label `{1}]`", user, label);
CacheManager.ClearRegion(label.CacheRegion);
sw.Stop();
return new OperationResult<bool>
{
IsSuccess = true,
Data = true,
OperationTime = sw.ElapsedMilliseconds
};
}
public async Task<Library.Models.Pagination.PagedResult<LabelList>> ListAsync(Library.Models.Users.User roadieUser, PagedRequest request,
bool? doRandomize = false)
{
var sw = new Stopwatch();
sw.Start();
int? rowCount = null;
if (!string.IsNullOrEmpty(request.Sort))
{
request.Sort = request.Sort.Replace("createdDate", "createdDateTime");
request.Sort = request.Sort.Replace("lastUpdated", "lastUpdatedDateTime");
}
var normalizedFilterValue = !string.IsNullOrEmpty(request.FilterValue)
? request.FilterValue.ToAlphanumericName()
: null;
int[] randomLabelIds = null;
SortedDictionary<int, int> randomLabelData = null;
if (doRandomize ?? false)
{
var randomLimit = request.Limit ?? roadieUser?.RandomReleaseLimit ?? request.LimitValue;
randomLabelData = await DbContext.RandomLabelIdsAsync(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly).ConfigureAwait(false);
randomLabelIds = randomLabelData.Select(x => x.Value).ToArray();
rowCount = DbContext.Labels.Count();
}
var result = from l in DbContext.Labels
where randomLabelIds == null || randomLabelIds.Contains(l.Id)
where string.IsNullOrEmpty(normalizedFilterValue) || (
l.Name.ToLower().Contains(normalizedFilterValue) ||
l.SortName.ToLower().Contains(normalizedFilterValue) ||
l.AlternateNames.ToLower().Contains(normalizedFilterValue)
)
select new LabelList
{
DatabaseId = l.Id,
Id = l.RoadieId,
Label = new DataToken
{
Text = l.Name,
Value = l.RoadieId.ToString()
},
SortName = l.SortName,
CreatedDate = l.CreatedDate,
LastUpdated = l.LastUpdated,
ArtistCount = l.ArtistCount,
ReleaseCount = l.ReleaseCount,
TrackCount = l.TrackCount,
Thumbnail = ImageHelper.MakeLabelThumbnailImage(Configuration, HttpContext, l.RoadieId)
};
LabelList[] rows = null;
rowCount = rowCount ?? result.Count();
if (doRandomize ?? false)
{
var resultData = await result.ToArrayAsync().ConfigureAwait(false);
rows = (from r in resultData
join ra in randomLabelData on r.DatabaseId equals ra.Value
orderby ra.Key
select r
)
.ToArray();
}
else
{
var sortBy = string.IsNullOrEmpty(request.Sort)
? request.OrderValue(new Dictionary<string, string> { { "SortName", "ASC" }, { "Label.Text", "ASC" } })
: request.OrderValue();
rows = await result
.OrderBy(sortBy)
.Skip(request.SkipValue)
.Take(request.LimitValue)
.ToArrayAsync()
.ConfigureAwait(false);
}
sw.Stop();
return new Library.Models.Pagination.PagedResult<LabelList>
{
TotalCount = rowCount.Value,
CurrentPage = request.PageValue,
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
OperationTime = sw.ElapsedMilliseconds,
Rows = rows
};
}
public async Task<OperationResult<bool>> MergeLabelsIntoLabelAsync(Library.Identity.User user, Guid intoLabelId, IEnumerable<Guid> labelIdsToMerge)
{
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var label = await DbContext.Labels.FirstOrDefaultAsync(x => x.RoadieId == intoLabelId).ConfigureAwait(false);
if (label == null)
{
return new OperationResult<bool>(true, $"Merge Into Label Not Found [{intoLabelId}]");
}
var now = DateTime.UtcNow;
var labelsToMerge = (from l in DbContext.Labels
join ltm in labelIdsToMerge on l.RoadieId equals ltm
select l);
foreach (var labelToMerge in labelsToMerge)
{
label.MusicBrainzId = label.MusicBrainzId ?? labelToMerge.MusicBrainzId;
label.SortName = label.SortName ?? labelToMerge.SortName;
label.Profile = label.Profile ?? labelToMerge.Profile;
label.BeginDate = label.BeginDate ?? labelToMerge.BeginDate;
label.EndDate = label.EndDate ?? labelToMerge.EndDate;
label.Profile = label.Profile ?? labelToMerge.Profile;
label.DiscogsId = label.DiscogsId ?? labelToMerge.DiscogsId;
label.ImageUrl = label.ImageUrl ?? labelToMerge.ImageUrl;
label.Tags = label.Tags.AddToDelimitedList(labelToMerge.Tags.ToListFromDelimited());
var altNames = labelToMerge.AlternateNames.ToListFromDelimited().ToList();
altNames.Add(labelToMerge.Name);
altNames.Add(labelToMerge.SortName);
altNames.Add(labelToMerge.Name.ToAlphanumericName());
label.AlternateNames = label.AlternateNames.AddToDelimitedList(altNames);
label.URLs = label.URLs.AddToDelimitedList(labelToMerge.URLs.ToListFromDelimited());
var labelToMergeReleases = (from rl in DbContext.ReleaseLabels
where rl.LabelId == labelToMerge.Id
select rl);
foreach (var labelToMergeRelease in labelToMergeReleases)
{
labelToMergeRelease.LabelId = label.Id;
labelToMergeRelease.LastUpdated = now;
}
label.LastUpdated = now;
await DbContext.SaveChangesAsync().ConfigureAwait(false);
}
await UpdateLabelCounts(label.Id, now).ConfigureAwait(false);
CacheManager.ClearRegion(label.CacheRegion);
Logger.LogInformation($"MergeLabelsIntoLabel `{label}`, Merged Label Ids [{ string.Join(",", labelIdsToMerge) }] By User `{user}`");
sw.Stop();
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
Data = !errors.Any(),
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public Task<OperationResult<Library.Models.Image>> SetLabelImageByUrlAsync(Library.Models.Users.User user, Guid id, string imageUrl) => SaveImageBytes(user, id, WebHelper.BytesForImageUrl(imageUrl));
public async Task<OperationResult<bool>> UpdateLabelAsync(Library.Models.Users.User user, Label model)
{
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var label = await DbContext.Labels.FirstOrDefaultAsync(x => x.RoadieId == model.Id).ConfigureAwait(false);
if (label == null)
{
return new OperationResult<bool>(true, $"Label Not Found [{model.Id}]");
}
// If label is being renamed, see if label already exists with new model supplied name
var labelName = label.SortNameValue;
var labelModelName = model.SortNameValue;
var oldPathToImage = label.PathToImage(Configuration);
var didChangeName = !labelName.ToAlphanumericName().Equals(labelModelName.ToAlphanumericName(), StringComparison.OrdinalIgnoreCase);
if (didChangeName)
{
var existingLabel = DbContext.Labels.FirstOrDefault(x => x.Name == model.Name || x.SortName == model.SortName);
if (existingLabel != null)
{
return new OperationResult<bool>($"Label already exists `{ existingLabel }` with name [{ labelModelName }].");
}
}
try
{
var now = DateTime.UtcNow;
var specialLabelName = model.Name.ToAlphanumericName();
var alt = new List<string>(model.AlternateNamesList);
if (!model.AlternateNamesList.Contains(specialLabelName, StringComparer.OrdinalIgnoreCase))
{
alt.Add(specialLabelName);
}
label.AlternateNames = alt.ToDelimitedList();
label.BeginDate = model.BeginDate;
label.DiscogsId = model.DiscogsId;
label.EndDate = model.EndDate;
label.IsLocked = model.IsLocked;
label.MusicBrainzId = model.MusicBrainzId;
label.Name = model.Name;
label.Profile = model.Profile;
label.SortName = model.SortName;
label.Status = SafeParser.ToEnum<Statuses>(model.Status);
label.Tags = model.TagsList.ToDelimitedList();
label.URLs = model.URLsList.ToDelimitedList();
if (didChangeName)
{
if (File.Exists(oldPathToImage))
{
File.Move(oldPathToImage, label.PathToImage(Configuration));
}
}
var labelImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
if (labelImage != null)
{
// Save unaltered label image
File.WriteAllBytes(label.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(labelImage));
}
label.LastUpdated = now;
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(label.CacheRegion);
Logger.LogInformation($"UpdateLabel `{label}` By User `{user}`");
}
catch (Exception ex)
{
Logger.LogError(ex);
errors.Add(ex);
}
sw.Stop();
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
Data = !errors.Any(),
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<Library.Models.Image>> UploadLabelImageAsync(Library.Models.Users.User user, Guid id, IFormFile file)
{
var bytes = new byte[0];
using (var ms = new MemoryStream())
{
file.CopyTo(ms);
bytes = ms.ToArray();
}
return await SaveImageBytes(user, id, bytes).ConfigureAwait(false);
}
}
}

View file

@ -34,7 +34,7 @@ namespace Roadie.Api.Services
{
}
public Task<OperationResult<IEnumerable<DataToken>>> ArtistTypes()
public Task<OperationResult<IEnumerable<DataToken>>> ArtistTypesAsync()
{
var sw = Stopwatch.StartNew();
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
@ -45,7 +45,7 @@ namespace Roadie.Api.Services
});
}
public Task<OperationResult<IEnumerable<DataToken>>> BandStatus()
public Task<OperationResult<IEnumerable<DataToken>>> BandStatusAsync()
{
var sw = Stopwatch.StartNew();
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
@ -56,7 +56,7 @@ namespace Roadie.Api.Services
});
}
public Task<OperationResult<IEnumerable<DataToken>>> BookmarkTypes()
public Task<OperationResult<IEnumerable<DataToken>>> BookmarkTypesAsync()
{
var sw = Stopwatch.StartNew();
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
@ -67,7 +67,7 @@ namespace Roadie.Api.Services
});
}
public Task<OperationResult<IEnumerable<DataToken>>> CollectionTypes()
public Task<OperationResult<IEnumerable<DataToken>>> CollectionTypesAsync()
{
var sw = Stopwatch.StartNew();
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
@ -78,7 +78,7 @@ namespace Roadie.Api.Services
});
}
public Task<OperationResult<IEnumerable<DataToken>>> LibraryStatus()
public Task<OperationResult<IEnumerable<DataToken>>> LibraryStatusAsync()
{
var sw = Stopwatch.StartNew();
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
@ -89,7 +89,7 @@ namespace Roadie.Api.Services
});
}
public Task<OperationResult<IEnumerable<DataToken>>> QueMessageTypes()
public Task<OperationResult<IEnumerable<DataToken>>> QueMessageTypesAsync()
{
var sw = Stopwatch.StartNew();
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
@ -100,7 +100,7 @@ namespace Roadie.Api.Services
});
}
public Task<OperationResult<IEnumerable<DataToken>>> ReleaseTypes()
public Task<OperationResult<IEnumerable<DataToken>>> ReleaseTypesAsync()
{
var sw = Stopwatch.StartNew();
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
@ -111,7 +111,7 @@ namespace Roadie.Api.Services
});
}
public Task<OperationResult<IEnumerable<DataToken>>> RequestStatus()
public Task<OperationResult<IEnumerable<DataToken>>> RequestStatusAsync()
{
var sw = Stopwatch.StartNew();
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
@ -122,17 +122,17 @@ namespace Roadie.Api.Services
});
}
public async Task<OperationResult<IEnumerable<DataToken>>> CreditCategories()
public async Task<OperationResult<IEnumerable<DataToken>>> CreditCategoriesAsync()
{
var sw = Stopwatch.StartNew();
var data = await CacheManager.GetAsync(CreditCategoriesCacheKey, async () =>
{
return (await DbContext.CreditCategory.ToListAsync()).Select(x => new DataToken
return (await DbContext.CreditCategory.ToListAsync().ConfigureAwait(false)).Select(x => new DataToken
{
Value = x.RoadieId.ToString(),
Text = x.Name
}).ToArray();
}, CacheManagerBase.SystemCacheRegionUrn);
}, CacheManagerBase.SystemCacheRegionUrn).ConfigureAwait(false);
return new OperationResult<IEnumerable<DataToken>>
{
Data = data,
@ -141,7 +141,7 @@ namespace Roadie.Api.Services
};
}
public Task<OperationResult<IEnumerable<DataToken>>> Status()
public Task<OperationResult<IEnumerable<DataToken>>> StatusAsync()
{
var sw = Stopwatch.StartNew();
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>

View file

@ -19,7 +19,6 @@ using System.Diagnostics;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using data = Roadie.Library.Data;
namespace Roadie.Api.Services
{
@ -29,15 +28,6 @@ namespace Roadie.Api.Services
protected IScrobbleHandler ScrobblerHandler { get; }
public PlayActivityService(IRoadieSettings configuration, IHttpEncoder httpEncoder,IHttpContext httpContext,
IRoadieDbContext dbContext, ICacheManager cacheManager,ILogger<PlayActivityService> logger,
IScrobbleHandler scrobbleHandler, IHubContext<PlayActivityHub> playActivityHub)
: base(configuration, httpEncoder, dbContext, cacheManager, logger, httpContext)
{
PlayActivityHub = playActivityHub;
ScrobblerHandler = scrobbleHandler;
}
public PlayActivityService(IRoadieSettings configuration, IRoadieDbContext dbContext, ICacheManager cacheManager,
ILogger logger, ScrobbleHandler scrobbleHandler)
: base(configuration, null, dbContext, cacheManager, logger, null)
@ -45,7 +35,93 @@ namespace Roadie.Api.Services
ScrobblerHandler = scrobbleHandler;
}
public Task<Library.Models.Pagination.PagedResult<PlayActivityList>> List(PagedRequest request,User roadieUser = null, DateTime? newerThan = null)
public PlayActivityService(IRoadieSettings configuration, IHttpEncoder httpEncoder, IHttpContext httpContext,
IRoadieDbContext dbContext, ICacheManager cacheManager, ILogger<PlayActivityService> logger,
IScrobbleHandler scrobbleHandler, IHubContext<PlayActivityHub> playActivityHub)
: base(configuration, httpEncoder, dbContext, cacheManager, logger, httpContext)
{
PlayActivityHub = playActivityHub;
ScrobblerHandler = scrobbleHandler;
}
private async Task PublishPlayActivity(User roadieUser, ScrobbleInfo scrobble, bool isNowPlaying)
{
// Only broadcast if the user is not public and played duration is more than half of duration
if (roadieUser?.IsPrivate != true &&
scrobble.ElapsedTimeOfTrackPlayed.TotalSeconds > scrobble.TrackDuration.TotalSeconds / 2)
{
var sw = Stopwatch.StartNew();
var track = await DbContext.Tracks
.Include(x => x.ReleaseMedia)
.Include(x => x.ReleaseMedia.Release)
.Include(x => x.ReleaseMedia.Release.Artist)
.Include(x => x.TrackArtist)
.FirstOrDefaultAsync(x => x.RoadieId == scrobble.TrackId)
.ConfigureAwait(false);
var user = DbContext.Users.FirstOrDefault(x => x.RoadieId == roadieUser.UserId);
var userTrack =
DbContext.UserTracks.FirstOrDefault(x => x.UserId == roadieUser.Id && x.TrackId == track.Id);
var pl = new PlayActivityList
{
Artist = new DataToken
{
Text = track.ReleaseMedia.Release.Artist.Name,
Value = track.ReleaseMedia.Release.Artist.RoadieId.ToString()
},
TrackArtist = track.TrackArtist == null
? null
: new DataToken
{
Text = track.TrackArtist.Name,
Value = track.TrackArtist.RoadieId.ToString()
},
Release = new DataToken
{
Text = track.ReleaseMedia.Release.Title,
Value = track.ReleaseMedia.Release.RoadieId.ToString()
},
Track = TrackList.FromDataTrack(null,
track,
track.ReleaseMedia.MediaNumber,
track.ReleaseMedia.Release,
track.ReleaseMedia.Release.Artist,
track.TrackArtist,
HttpContext.BaseUrl,
ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, track.RoadieId),
ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId),
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId),
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.TrackArtist == null
? null
: (Guid?)track.TrackArtist.RoadieId)),
User = new DataToken
{
Text = roadieUser.UserName,
Value = roadieUser.UserId.ToString()
},
ArtistThumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.TrackArtist != null
? track.TrackArtist.RoadieId
: track.ReleaseMedia.Release.Artist.RoadieId),
PlayedDateDateTime = scrobble.TimePlayed,
IsNowPlaying = isNowPlaying,
Rating = track.Rating,
ReleasePlayUrl = $"{HttpContext.BaseUrl}/play/release/{track.ReleaseMedia.Release.RoadieId}",
ReleaseThumbnail = ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId),
TrackPlayUrl = $"{HttpContext.BaseUrl}/play/track/{track.RoadieId}.mp3",
UserRating = userTrack?.Rating,
UserThumbnail = ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, roadieUser.UserId)
};
try
{
await PlayActivityHub.Clients.All.SendAsync("SendActivityAsync", pl).ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.LogError(ex);
}
}
}
public async Task<Library.Models.Pagination.PagedResult<PlayActivityList>> ListAsync(PagedRequest request, User roadieUser = null, DateTime? newerThan = null)
{
try
{
@ -119,118 +195,46 @@ namespace Roadie.Api.Services
? request.OrderValue(new Dictionary<string, string> { { "PlayedDateDateTime", "DESC" } })
: request.OrderValue();
var rowCount = result.Count();
var rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
var rows = await result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArrayAsync().ConfigureAwait(false);
sw.Stop();
return Task.FromResult(new Library.Models.Pagination.PagedResult<PlayActivityList>
return new Library.Models.Pagination.PagedResult<PlayActivityList>
{
TotalCount = rowCount,
CurrentPage = request.PageValue,
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
OperationTime = sw.ElapsedMilliseconds,
Rows = rows
});
};
}
catch (Exception ex)
{
Logger.LogError(ex);
}
return Task.FromResult(new Library.Models.Pagination.PagedResult<PlayActivityList>());
return new Library.Models.Pagination.PagedResult<PlayActivityList>();
}
public async Task<OperationResult<bool>> NowPlaying(User roadieUser, ScrobbleInfo scrobble)
public async Task<OperationResult<bool>> NowPlayingAsync(User roadieUser, ScrobbleInfo scrobble)
{
var scrobbleResult = await ScrobblerHandler.NowPlaying(roadieUser, scrobble);
if (!scrobbleResult.IsSuccess) return scrobbleResult;
await PublishPlayActivity(roadieUser, scrobble, true);
return scrobbleResult;
}
public async Task<OperationResult<bool>> Scrobble(User roadieUser, ScrobbleInfo scrobble)
{
var scrobbleResult = await ScrobblerHandler.Scrobble(roadieUser, scrobble);
var scrobbleResult = await ScrobblerHandler.NowPlaying(roadieUser, scrobble).ConfigureAwait(false);
if (!scrobbleResult.IsSuccess)
{
return scrobbleResult;
}
await PublishPlayActivity(roadieUser, scrobble, false);
await PublishPlayActivity(roadieUser, scrobble, true).ConfigureAwait(false);
return scrobbleResult;
}
private async Task PublishPlayActivity(User roadieUser, ScrobbleInfo scrobble, bool isNowPlaying)
public async Task<OperationResult<bool>> ScrobbleAsync(User roadieUser, ScrobbleInfo scrobble)
{
// Only broadcast if the user is not public and played duration is more than half of duration
if (roadieUser?.IsPrivate != true &&
scrobble.ElapsedTimeOfTrackPlayed.TotalSeconds > scrobble.TrackDuration.TotalSeconds / 2)
var scrobbleResult = await ScrobblerHandler.Scrobble(roadieUser, scrobble).ConfigureAwait(false);
if (!scrobbleResult.IsSuccess)
{
var sw = Stopwatch.StartNew();
var track = DbContext.Tracks
.Include(x => x.ReleaseMedia)
.Include(x => x.ReleaseMedia.Release)
.Include(x => x.ReleaseMedia.Release.Artist)
.Include(x => x.TrackArtist)
.FirstOrDefault(x => x.RoadieId == scrobble.TrackId);
var user = DbContext.Users.FirstOrDefault(x => x.RoadieId == roadieUser.UserId);
var userTrack =
DbContext.UserTracks.FirstOrDefault(x => x.UserId == roadieUser.Id && x.TrackId == track.Id);
var pl = new PlayActivityList
{
Artist = new DataToken
{
Text = track.ReleaseMedia.Release.Artist.Name,
Value = track.ReleaseMedia.Release.Artist.RoadieId.ToString()
},
TrackArtist = track.TrackArtist == null
? null
: new DataToken
{
Text = track.TrackArtist.Name,
Value = track.TrackArtist.RoadieId.ToString()
},
Release = new DataToken
{
Text = track.ReleaseMedia.Release.Title,
Value = track.ReleaseMedia.Release.RoadieId.ToString()
},
Track = TrackList.FromDataTrack(null,
track,
track.ReleaseMedia.MediaNumber,
track.ReleaseMedia.Release,
track.ReleaseMedia.Release.Artist,
track.TrackArtist,
HttpContext.BaseUrl,
ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, track.RoadieId),
ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId),
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId),
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.TrackArtist == null
? null
: (Guid?)track.TrackArtist.RoadieId)),
User = new DataToken
{
Text = roadieUser.UserName,
Value = roadieUser.UserId.ToString()
},
ArtistThumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.TrackArtist != null
? track.TrackArtist.RoadieId
: track.ReleaseMedia.Release.Artist.RoadieId),
PlayedDateDateTime = scrobble.TimePlayed,
IsNowPlaying = isNowPlaying,
Rating = track.Rating,
ReleasePlayUrl = $"{HttpContext.BaseUrl}/play/release/{track.ReleaseMedia.Release.RoadieId}",
ReleaseThumbnail = ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId),
TrackPlayUrl = $"{HttpContext.BaseUrl}/play/track/{track.RoadieId}.mp3",
UserRating = userTrack?.Rating,
UserThumbnail = ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, roadieUser.UserId)
};
try
{
await PlayActivityHub.Clients.All.SendAsync("SendActivity", pl);
}
catch (Exception ex)
{
Logger.LogError(ex);
}
return scrobbleResult;
}
await PublishPlayActivity(roadieUser, scrobble, false).ConfigureAwait(false);
return scrobbleResult;
}
}
}

View file

@ -42,412 +42,6 @@ namespace Roadie.Api.Services
BookmarkService = bookmarkService;
}
public async Task<OperationResult<PlaylistList>> AddNewPlaylist(User user, Playlist model)
{
var playlist = new data.Playlist
{
IsPublic = model.IsPublic,
Description = model.Description,
Name = model.Name,
UserId = user.Id
};
DbContext.Playlists.Add(playlist);
await DbContext.SaveChangesAsync();
var r = await AddTracksToPlaylist(playlist,
model.Tracks.OrderBy(x => x.ListNumber).Select(x => x.Track.Id));
var request = new PagedRequest
{
FilterToPlaylistId = playlist.RoadieId
};
var result = await List(request, user);
return new OperationResult<PlaylistList>
{
Data = result.Rows.First(),
IsSuccess = true
};
}
public async Task<OperationResult<bool>> AddTracksToPlaylist(data.Playlist playlist, IEnumerable<Guid> trackIds)
{
var sw = new Stopwatch();
sw.Start();
var result = false;
var now = DateTime.UtcNow;
var existingTracksForPlaylist = from plt in DbContext.PlaylistTracks
join t in DbContext.Tracks on plt.TrackId equals t.Id
where plt.PlayListId == playlist.Id
select t;
var newTracksForPlaylist = (from t in DbContext.Tracks
where (from x in trackIds select x).Contains(t.RoadieId)
where !(from x in existingTracksForPlaylist select x.RoadieId).Contains(t.RoadieId)
select t).ToArray();
foreach (var newTrackForPlaylist in newTracksForPlaylist)
DbContext.PlaylistTracks.Add(new data.PlaylistTrack
{
TrackId = newTrackForPlaylist.Id,
PlayListId = playlist.Id
});
playlist.LastUpdated = now;
await DbContext.SaveChangesAsync();
result = true;
var r = await ReorderPlaylist(playlist);
result = result && r.IsSuccess;
await UpdatePlaylistCounts(playlist.Id, now);
sw.Stop();
return new OperationResult<bool>
{
IsSuccess = result,
Data = result,
OperationTime = sw.ElapsedMilliseconds
};
}
public async Task<OperationResult<Playlist>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null)
{
var sw = Stopwatch.StartNew();
sw.Start();
var cacheKey = string.Format("urn:playlist_by_id_operation:{0}:{1}", id,
includes == null ? "0" : string.Join("|", includes));
var result = await CacheManager.GetAsync(cacheKey, async () =>
{
return await PlaylistByIdAction(id, includes);
}, data.Artist.CacheRegionUrn(id));
sw.Stop();
if (result?.Data != null && roadieUser != null)
{
if (result?.Data?.Tracks != null)
{
var user = await GetUser(roadieUser.UserId);
foreach (var track in result.Data.Tracks)
{
track.Track.TrackPlayUrl = MakeTrackPlayUrl(user, HttpContext.BaseUrl, track.Track.Id);
}
}
result.Data.UserCanEdit = result.Data.Maintainer.Id == roadieUser.UserId || roadieUser.IsAdmin;
var userBookmarkResult = await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Playlist);
if (userBookmarkResult.IsSuccess)
{
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x?.Bookmark?.Value == result?.Data?.Id?.ToString()) != null;
}
if (result.Data.Comments.Any())
{
var commentIds = result.Data.Comments.Select(x => x.DatabaseId).ToArray();
var userCommentReactions = (from cr in DbContext.CommentReactions
where commentIds.Contains(cr.CommentId)
where cr.UserId == roadieUser.Id
select cr).ToArray();
foreach (var comment in result.Data.Comments)
{
var userCommentReaction = userCommentReactions.FirstOrDefault(x => x.CommentId == comment.DatabaseId);
comment.IsDisliked = userCommentReaction?.ReactionValue == CommentReaction.Dislike;
comment.IsLiked = userCommentReaction?.ReactionValue == CommentReaction.Like;
}
}
}
return new OperationResult<Playlist>(result.Messages)
{
Data = result?.Data,
IsNotFoundResult = result?.IsNotFoundResult ?? false,
Errors = result?.Errors,
IsSuccess = result?.IsSuccess ?? false,
OperationTime = sw.ElapsedMilliseconds
};
}
public async Task<OperationResult<bool>> DeletePlaylist(User user, Guid id)
{
var sw = new Stopwatch();
sw.Start();
var playlist = DbContext.Playlists.FirstOrDefault(x => x.RoadieId == id);
if (playlist == null)
{
return new OperationResult<bool>(true, string.Format("Playlist Not Found [{0}]", id));
}
if (!user.IsAdmin && user.Id != playlist.UserId)
{
Logger.LogWarning("User `{0}` attempted to delete Playlist `{1}`", user, playlist);
return new OperationResult<bool>("Access Denied")
{
IsAccessDeniedResult = true
};
}
DbContext.Playlists.Remove(playlist);
await DbContext.SaveChangesAsync();
await BookmarkService.RemoveAllBookmarksForItem(BookmarkType.Playlist, playlist.Id);
var playlistImageFilename = playlist.PathToImage(Configuration);
if (File.Exists(playlistImageFilename))
{
File.Delete(playlistImageFilename);
}
Logger.LogWarning("User `{0}` deleted Playlist `{1}]`", user, playlist);
CacheManager.ClearRegion(playlist.CacheRegion);
sw.Stop();
return new OperationResult<bool>
{
IsSuccess = true,
Data = true,
OperationTime = sw.ElapsedMilliseconds
};
}
public Task<Library.Models.Pagination.PagedResult<PlaylistList>> List(PagedRequest request, User roadieUser = null)
{
var sw = new Stopwatch();
sw.Start();
var playlistWithArtistTrackIds = new int[0];
if (request.FilterToArtistId.HasValue)
{
playlistWithArtistTrackIds = (from pl in DbContext.Playlists
join pltr in DbContext.PlaylistTracks on pl.Id equals pltr.PlayListId
join t in DbContext.Tracks on pltr.TrackId equals t.Id
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
join r in DbContext.Releases on rm.ReleaseId equals r.Id
join a in DbContext.Artists on r.ArtistId equals a.Id
where a.RoadieId == request.FilterToArtistId
select pl.Id
).ToArray();
}
var playlistReleaseTrackIds = new int[0];
if (request.FilterToReleaseId.HasValue)
{
playlistReleaseTrackIds = (from pl in DbContext.Playlists
join pltr in DbContext.PlaylistTracks on pl.Id equals pltr.PlayListId
join t in DbContext.Tracks on pltr.TrackId equals t.Id
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
join r in DbContext.Releases on rm.ReleaseId equals r.Id
where r.RoadieId == request.FilterToReleaseId
select pl.Id
).ToArray();
}
var normalizedFilterValue = !string.IsNullOrEmpty(request.FilterValue)
? request.FilterValue.ToAlphanumericName()
: null;
var result = from pl in DbContext.Playlists
join u in DbContext.Users on pl.UserId equals u.Id
where request.FilterToPlaylistId == null || pl.RoadieId == request.FilterToPlaylistId
where request.FilterToArtistId == null || playlistWithArtistTrackIds.Contains(pl.Id)
where request.FilterToReleaseId == null || playlistReleaseTrackIds.Contains(pl.Id)
where roadieUser == null && pl.IsPublic || roadieUser != null && u.RoadieId == roadieUser.UserId || pl.IsPublic
where string.IsNullOrEmpty(normalizedFilterValue) || (
pl.Name.ToLower().Contains(normalizedFilterValue) ||
pl.AlternateNames.ToLower().Contains(normalizedFilterValue)
)
select new PlaylistList
{
Playlist = new DataToken
{
Text = pl.Name,
Value = pl.RoadieId.ToString()
},
User = new DataToken
{
Text = u.UserName,
Value = u.RoadieId.ToString()
},
PlaylistCount = pl.TrackCount,
IsPublic = pl.IsPublic,
Duration = pl.Duration,
TrackCount = pl.TrackCount,
CreatedDate = pl.CreatedDate,
LastUpdated = pl.LastUpdated,
UserThumbnail = ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, u.RoadieId),
Id = pl.RoadieId,
Thumbnail = ImageHelper.MakePlaylistThumbnailImage(Configuration, HttpContext, pl.RoadieId)
};
var sortBy = string.IsNullOrEmpty(request.Sort)
? request.OrderValue(new Dictionary<string, string> { { "Playlist.Text", "ASC" } })
: request.OrderValue();
var rowCount = result.Count();
var rows = result
.OrderBy(sortBy)
.Skip(request.SkipValue)
.Take(request.LimitValue)
.ToArray();
sw.Stop();
return Task.FromResult(new Library.Models.Pagination.PagedResult<PlaylistList>
{
TotalCount = rowCount,
CurrentPage = request.PageValue,
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
OperationTime = sw.ElapsedMilliseconds,
Rows = rows
});
}
public async Task<OperationResult<bool>> ReorderPlaylist(data.Playlist playlist)
{
var sw = new Stopwatch();
sw.Start();
var result = false;
var now = DateTime.UtcNow;
if (playlist != null)
{
var looper = 0;
foreach (var playlistTrack in DbContext.PlaylistTracks.Where(x => x.PlayListId == playlist.Id)
.OrderBy(x => x.CreatedDate))
{
looper++;
playlistTrack.ListNumber = looper;
playlistTrack.LastUpdated = now;
}
await DbContext.SaveChangesAsync();
result = true;
}
return new OperationResult<bool>
{
IsSuccess = result,
Data = result
};
}
public async Task<OperationResult<bool>> UpdatePlaylist(User user, Playlist model)
{
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var playlist = DbContext.Playlists.FirstOrDefault(x => x.RoadieId == model.Id);
if (playlist == null)
{
return new OperationResult<bool>(true, string.Format("Playlist Not Found [{0}]", model.Id));
}
if (!user.IsAdmin && user.Id != playlist.UserId)
{
Logger.LogWarning("User `{0}` attempted to update Playlist `{1}`", user, playlist);
return new OperationResult<bool>("Access Denied")
{
IsAccessDeniedResult = true
};
}
try
{
var now = DateTime.UtcNow;
playlist.AlternateNames = model.AlternateNamesList.ToDelimitedList();
playlist.Description = model.Description;
playlist.IsLocked = model.IsLocked;
playlist.IsPublic = model.IsPublic;
var oldPathToImage = playlist.PathToImage(Configuration);
var didChangeName = playlist.Name != model.Name;
playlist.Name = model.Name;
playlist.Status = SafeParser.ToEnum<Statuses>(model.Status);
playlist.Tags = model.TagsList.ToDelimitedList();
playlist.URLs = model.URLsList.ToDelimitedList();
if (didChangeName)
{
if (File.Exists(oldPathToImage))
{
File.Move(oldPathToImage, playlist.PathToImage(Configuration));
}
}
var playlistImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
if (playlistImage != null)
{
// Save unaltered playlist image
File.WriteAllBytes(playlist.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(playlistImage));
}
playlist.LastUpdated = now;
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(playlist.CacheRegion);
Logger.LogInformation($"UpdatePlaylist `{playlist}` By User `{user}`");
}
catch (Exception ex)
{
Logger.LogError(ex);
errors.Add(ex);
}
sw.Stop();
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
Data = !errors.Any(),
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<bool>> UpdatePlaylistTracks(User user, PlaylistTrackModifyRequest request)
{
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var playlist = DbContext.Playlists.Include(x => x.Tracks).FirstOrDefault(x => x.RoadieId == request.Id);
if (playlist == null)
{
return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", request.Id));
}
if (!user.IsAdmin && user.Id != playlist.UserId)
{
Logger.LogWarning("User `{0}` attempted to update Playlist Tracks `{1}`", user, playlist);
return new OperationResult<bool>("Access Denied")
{
IsAccessDeniedResult = true
};
}
try
{
var now = DateTime.UtcNow;
playlist.Tracks.Clear();
var tracks = (from t in DbContext.Tracks
join plt in request.Tracks on t.RoadieId equals plt.Track.Id
select t).ToArray();
foreach (var newPlaylistTrack in request.Tracks.OrderBy(x => x.ListNumber))
{
var track = tracks.FirstOrDefault(x => x.RoadieId == newPlaylistTrack.Track.Id);
playlist.Tracks.Add(new data.PlaylistTrack
{
ListNumber = newPlaylistTrack.ListNumber,
PlayListId = playlist.Id,
CreatedDate = now,
TrackId = track.Id
});
}
playlist.LastUpdated = now;
await DbContext.SaveChangesAsync();
// await base.UpdatePlaylistCounts(playlist.Id, now);
Logger.LogInformation($"UpdatePlaylistTracks `{playlist}` By User `{user}`");
}
catch (Exception ex)
{
Logger.LogError(ex);
errors.Add(ex);
}
sw.Stop();
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),
Data = !errors.Any(),
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
private async Task<OperationResult<Playlist>> PlaylistByIdAction(Guid id, IEnumerable<string> includes = null)
{
var timings = new Dictionary<string, long>();
@ -457,13 +51,13 @@ namespace Roadie.Api.Services
sw.Start();
tsw.Restart();
var playlist = await GetPlaylist(id);
var playlist = await GetPlaylist(id).ConfigureAwait(false);
tsw.Stop();
timings.Add("getPlaylist", tsw.ElapsedMilliseconds);
if (playlist == null)
{
return new OperationResult<Playlist>(true, string.Format("Playlist Not Found [{0}]", id));
return new OperationResult<Playlist>(true, $"Playlist Not Found [{id}]");
}
tsw.Restart();
var result = playlist.Adapt<Playlist>();
@ -563,5 +157,416 @@ namespace Roadie.Api.Services
OperationTime = sw.ElapsedMilliseconds
};
}
public async Task<OperationResult<PlaylistList>> AddNewPlaylistAsync(User user, Playlist model)
{
var playlist = new data.Playlist
{
IsPublic = model.IsPublic,
Description = model.Description,
Name = model.Name,
UserId = user.Id
};
DbContext.Playlists.Add(playlist);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
var r = await AddTracksToPlaylistAsync(playlist, model.Tracks.OrderBy(x => x.ListNumber).Select(x => x.Track.Id)).ConfigureAwait(false);
var request = new PagedRequest
{
FilterToPlaylistId = playlist.RoadieId
};
var result = await ListAsync(request, user).ConfigureAwait(false);
return new OperationResult<PlaylistList>
{
Data = result.Rows.First(),
IsSuccess = true
};
}
public async Task<OperationResult<bool>> AddTracksToPlaylistAsync(data.Playlist playlist, IEnumerable<Guid> trackIds)
{
var sw = new Stopwatch();
sw.Start();
var result = false;
var now = DateTime.UtcNow;
var existingTracksForPlaylist = from plt in DbContext.PlaylistTracks
join t in DbContext.Tracks on plt.TrackId equals t.Id
where plt.PlayListId == playlist.Id
select t;
var newTracksForPlaylist = await (from t in DbContext.Tracks
where (from x in trackIds select x).Contains(t.RoadieId)
where !(from x in existingTracksForPlaylist select x.RoadieId).Contains(t.RoadieId)
select t)
.ToArrayAsync()
.ConfigureAwait(false);
foreach (var newTrackForPlaylist in newTracksForPlaylist)
{
DbContext.PlaylistTracks.Add(new data.PlaylistTrack
{
TrackId = newTrackForPlaylist.Id,
PlayListId = playlist.Id
});
}
playlist.LastUpdated = now;
await DbContext.SaveChangesAsync().ConfigureAwait(false);
result = true;
var r = await ReorderPlaylistAsync(playlist).ConfigureAwait(false);
result = result && r.IsSuccess;
await UpdatePlaylistCounts(playlist.Id, now).ConfigureAwait(false);
sw.Stop();
return new OperationResult<bool>
{
IsSuccess = result,
Data = result,
OperationTime = sw.ElapsedMilliseconds
};
}
public async Task<OperationResult<Playlist>> ByIdAsync(User roadieUser, Guid id, IEnumerable<string> includes = null)
{
var sw = Stopwatch.StartNew();
sw.Start();
var cacheKey = $"urn:playlist_by_id_operation:{id}:{(includes == null ? "0" : string.Join("|", includes))}";
var result = await CacheManager.GetAsync(cacheKey, async () =>
{
return await PlaylistByIdAction(id, includes).ConfigureAwait(false);
}, data.Artist.CacheRegionUrn(id)).ConfigureAwait(false);
sw.Stop();
if (result?.Data != null && roadieUser != null)
{
if (result?.Data?.Tracks != null)
{
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
foreach (var track in result.Data.Tracks)
{
track.Track.TrackPlayUrl = MakeTrackPlayUrl(user, HttpContext.BaseUrl, track.Track.Id);
}
}
result.Data.UserCanEdit = result.Data.Maintainer.Id == roadieUser.UserId || roadieUser.IsAdmin;
var userBookmarkResult = await BookmarkService.ListAsync(roadieUser, new PagedRequest(), false, BookmarkType.Playlist).ConfigureAwait(false);
if (userBookmarkResult.IsSuccess)
{
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x?.Bookmark?.Value == result?.Data?.Id?.ToString()) != null;
}
if (result.Data.Comments.Any())
{
var commentIds = result.Data.Comments.Select(x => x.DatabaseId).ToArray();
var userCommentReactions = await (from cr in DbContext.CommentReactions
where commentIds.Contains(cr.CommentId)
where cr.UserId == roadieUser.Id
select cr)
.ToArrayAsync()
.ConfigureAwait(false);
foreach (var comment in result.Data.Comments)
{
var userCommentReaction = Array.Find(userCommentReactions, x => x.CommentId == comment.DatabaseId);
comment.IsDisliked = userCommentReaction?.ReactionValue == CommentReaction.Dislike;
comment.IsLiked = userCommentReaction?.ReactionValue == CommentReaction.Like;
}
}
}
return new OperationResult<Playlist>(result.Messages)
{
Data = result?.Data,
IsNotFoundResult = result?.IsNotFoundResult ?? false,
Errors = result?.Errors,
IsSuccess = result?.IsSuccess ?? false,
OperationTime = sw.ElapsedMilliseconds
};
}
public async Task<OperationResult<bool>> DeletePlaylistAsync(User user, Guid id)
{
var sw = new Stopwatch();
sw.Start();
var playlist = await DbContext.Playlists.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
if (playlist == null)
{
return new OperationResult<bool>(true, $"Playlist Not Found [{id}]");
}
if (!user.IsAdmin && user.Id != playlist.UserId)
{
Logger.LogWarning("User `{0}` attempted to delete Playlist `{1}`", user, playlist);
return new OperationResult<bool>("Access Denied")
{
IsAccessDeniedResult = true
};
}
DbContext.Playlists.Remove(playlist);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
await BookmarkService.RemoveAllBookmarksForItemAsync(BookmarkType.Playlist, playlist.Id).ConfigureAwait(false);
var playlistImageFilename = playlist.PathToImage(Configuration);
if (File.Exists(playlistImageFilename))
{
File.Delete(playlistImageFilename);
}
Logger.LogWarning("User `{0}` deleted Playlist `{1}]`", user, playlist);
CacheManager.ClearRegion(playlist.CacheRegion);
sw.Stop();
return new OperationResult<bool>
{
IsSuccess = true,
Data = true,
OperationTime = sw.ElapsedMilliseconds
};
}
public async Task<Library.Models.Pagination.PagedResult<PlaylistList>> ListAsync(PagedRequest request, User roadieUser = null)
{
var sw = new Stopwatch();
sw.Start();
var playlistWithArtistTrackIds = new int[0];
if (request.FilterToArtistId.HasValue)
{
playlistWithArtistTrackIds = await (from pl in DbContext.Playlists
join pltr in DbContext.PlaylistTracks on pl.Id equals pltr.PlayListId
join t in DbContext.Tracks on pltr.TrackId equals t.Id
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
join r in DbContext.Releases on rm.ReleaseId equals r.Id
join a in DbContext.Artists on r.ArtistId equals a.Id
where a.RoadieId == request.FilterToArtistId
select pl.Id
).ToArrayAsync().ConfigureAwait(false);
}
var playlistReleaseTrackIds = new int[0];
if (request.FilterToReleaseId.HasValue)
{
playlistReleaseTrackIds = await (from pl in DbContext.Playlists
join pltr in DbContext.PlaylistTracks on pl.Id equals pltr.PlayListId
join t in DbContext.Tracks on pltr.TrackId equals t.Id
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
join r in DbContext.Releases on rm.ReleaseId equals r.Id
where r.RoadieId == request.FilterToReleaseId
select pl.Id
).ToArrayAsync().ConfigureAwait(false);
}
var normalizedFilterValue = !string.IsNullOrEmpty(request.FilterValue)
? request.FilterValue.ToAlphanumericName()
: null;
var result = from pl in DbContext.Playlists
join u in DbContext.Users on pl.UserId equals u.Id
where request.FilterToPlaylistId == null || pl.RoadieId == request.FilterToPlaylistId
where request.FilterToArtistId == null || playlistWithArtistTrackIds.Contains(pl.Id)
where request.FilterToReleaseId == null || playlistReleaseTrackIds.Contains(pl.Id)
where roadieUser == null && pl.IsPublic || roadieUser != null && u.RoadieId == roadieUser.UserId || pl.IsPublic
where string.IsNullOrEmpty(normalizedFilterValue) || (
pl.Name.ToLower().Contains(normalizedFilterValue) ||
pl.AlternateNames.ToLower().Contains(normalizedFilterValue)
)
select new PlaylistList
{
Playlist = new DataToken
{
Text = pl.Name,
Value = pl.RoadieId.ToString()
},
User = new DataToken
{
Text = u.UserName,
Value = u.RoadieId.ToString()
},
PlaylistCount = pl.TrackCount,
IsPublic = pl.IsPublic,
Duration = pl.Duration,
TrackCount = pl.TrackCount,
CreatedDate = pl.CreatedDate,
LastUpdated = pl.LastUpdated,
UserThumbnail = ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, u.RoadieId),
Id = pl.RoadieId,
Thumbnail = ImageHelper.MakePlaylistThumbnailImage(Configuration, HttpContext, pl.RoadieId)
};
var sortBy = string.IsNullOrEmpty(request.Sort)
? request.OrderValue(new Dictionary<string, string> { { "Playlist.Text", "ASC" } })
: request.OrderValue();
var rowCount = await result.CountAsync().ConfigureAwait(false);
var rows = await result
.OrderBy(sortBy)
.Skip(request.SkipValue)
.Take(request.LimitValue)
.ToArrayAsync()
.ConfigureAwait(false);
sw.Stop();
return new Library.Models.Pagination.PagedResult<PlaylistList>
{
TotalCount = rowCount,
CurrentPage = request.PageValue,
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
OperationTime = sw.ElapsedMilliseconds,
Rows = rows
};
}
public async Task<OperationResult<bool>> ReorderPlaylistAsync(data.Playlist playlist)
{
var sw = new Stopwatch();
sw.Start();
var result = false;
var now = DateTime.UtcNow;
if (playlist != null)
{
var looper = 0;
foreach (var playlistTrack in DbContext.PlaylistTracks.Where(x => x.PlayListId == playlist.Id).OrderBy(x => x.CreatedDate))
{
looper++;
playlistTrack.ListNumber = looper;
playlistTrack.LastUpdated = now;
}
await DbContext.SaveChangesAsync().ConfigureAwait(false);
result = true;
}
return new OperationResult<bool>
{
IsSuccess = result,
Data = result
};
}
public async Task<OperationResult<bool>> UpdatePlaylistAsync(User user, Playlist model)
{
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var playlist = await DbContext.Playlists.FirstOrDefaultAsync(x => x.RoadieId == model.Id).ConfigureAwait(false);
if (playlist == null)
{
return new OperationResult<bool>(true, $"Playlist Not Found [{model.Id}]");
}
if (!user.IsAdmin && user.Id != playlist.UserId)
{
Logger.LogWarning("User `{0}` attempted to update Playlist `{1}`", user, playlist);
return new OperationResult<bool>("Access Denied")
{
IsAccessDeniedResult = true
};
}
try
{
var now = DateTime.UtcNow;
playlist.AlternateNames = model.AlternateNamesList.ToDelimitedList();
playlist.Description = model.Description;
playlist.IsLocked = model.IsLocked;
playlist.IsPublic = model.IsPublic;
var oldPathToImage = playlist.PathToImage(Configuration);
var didChangeName = playlist.Name != model.Name;
playlist.Name = model.Name;
playlist.Status = SafeParser.ToEnum<Statuses>(model.Status);
playlist.Tags = model.TagsList.ToDelimitedList();
playlist.URLs = model.URLsList.ToDelimitedList();
if (didChangeName)
{
if (File.Exists(oldPathToImage))
{
File.Move(oldPathToImage, playlist.PathToImage(Configuration));
}
}
var playlistImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
if (playlistImage != null)
{
// Save unaltered playlist image
await File.WriteAllBytesAsync(playlist.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(playlistImage)).ConfigureAwait(false);
}
playlist.LastUpdated = now;
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(playlist.CacheRegion);
Logger.LogInformation($"UpdatePlaylist `{playlist}` By User `{user}`");
}
catch (Exception ex)
{
Logger.LogError(ex);
errors.Add(ex);
}
sw.Stop();
return new OperationResult<bool>
{
IsSuccess = errors.Count == 0,
Data = errors.Count == 0,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
public async Task<OperationResult<bool>> UpdatePlaylistTracksAsync(User user, PlaylistTrackModifyRequest request)
{
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var playlist = await DbContext.Playlists.Include(x => x.Tracks).FirstOrDefaultAsync(x => x.RoadieId == request.Id).ConfigureAwait(false);
if (playlist == null)
{
return new OperationResult<bool>(true, $"Label Not Found [{request.Id}]");
}
if (!user.IsAdmin && user.Id != playlist.UserId)
{
Logger.LogWarning("User `{0}` attempted to update Playlist Tracks `{1}`", user, playlist);
return new OperationResult<bool>("Access Denied")
{
IsAccessDeniedResult = true
};
}
try
{
var now = DateTime.UtcNow;
playlist.Tracks.Clear();
var tracks = await (from t in DbContext.Tracks
join plt in request.Tracks on t.RoadieId equals plt.Track.Id
select t).ToArrayAsync().ConfigureAwait(false);
foreach (var newPlaylistTrack in request.Tracks.OrderBy(x => x.ListNumber))
{
var track = Array.Find(tracks, x => x.RoadieId == newPlaylistTrack.Track.Id);
playlist.Tracks.Add(new data.PlaylistTrack
{
ListNumber = newPlaylistTrack.ListNumber,
PlayListId = playlist.Id,
CreatedDate = now,
TrackId = track.Id
});
}
playlist.LastUpdated = now;
await DbContext.SaveChangesAsync().ConfigureAwait(false);
// await base.UpdatePlaylistCounts(playlist.Id, now);
Logger.LogInformation($"UpdatePlaylistTracks `{playlist}` By User `{user}`");
}
catch (Exception ex)
{
Logger.LogError(ex);
errors.Add(ex);
}
sw.Stop();
return new OperationResult<bool>
{
IsSuccess = errors.Count == 0,
Data = errors.Count == 0,
OperationTime = sw.ElapsedMilliseconds,
Errors = errors
};
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -99,91 +99,91 @@ namespace Roadie.Api.Services
{
return null;
}
return await GetArtist(artistByName.RoadieId);
return await GetArtist(artistByName.RoadieId).ConfigureAwait(false);
}
protected Task<data.Artist> GetArtist(Guid id)
protected async Task<data.Artist> GetArtist(Guid id)
{
if (id == Guid.Empty)
{
return Task.FromResult<data.Artist>(null);
return null;
}
return CacheManager.GetAsync(data.Artist.CacheUrn(id), () =>
return await CacheManager.GetAsync(data.Artist.CacheUrn(id), async () =>
{
return DbContext.Artists
return await DbContext.Artists
.Include(x => x.Genres)
.Include("Genres.Genre")
.FirstOrDefaultAsync(x => x.RoadieId == id);
}, data.Artist.CacheRegionUrn(id));
.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
}, data.Artist.CacheRegionUrn(id)).ConfigureAwait(false);
}
protected Task<data.Collection> GetCollection(Guid id)
protected async Task<data.Collection> GetCollection(Guid id)
{
if (id == Guid.Empty)
{
return Task.FromResult<data.Collection>(null);
return null;
}
return CacheManager.GetAsync(data.Collection.CacheUrn(id), () =>
return await CacheManager.GetAsync(data.Collection.CacheUrn(id), async () =>
{
return DbContext.Collections.FirstOrDefaultAsync(x => x.RoadieId == id);
}, data.Collection.CacheRegionUrn(id));
return await DbContext.Collections.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
}, data.Collection.CacheRegionUrn(id)).ConfigureAwait(false);
}
protected Task<data.Genre> GetGenre(Guid id)
protected async Task<data.Genre> GetGenre(Guid id)
{
if (id == Guid.Empty)
{
return Task.FromResult<data.Genre>(null);
return null;
}
return CacheManager.GetAsync(data.Genre.CacheUrn(id), () =>
return await CacheManager.GetAsync(data.Genre.CacheUrn(id), async () =>
{
return DbContext.Genres.FirstOrDefaultAsync(x => x.RoadieId == id);
}, data.Genre.CacheRegionUrn(id));
return await DbContext.Genres.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
}, data.Genre.CacheRegionUrn(id)).ConfigureAwait(false);
}
protected Task<data.Label> GetLabel(Guid id)
protected async Task<data.Label> GetLabel(Guid id)
{
if (id == Guid.Empty)
{
return Task.FromResult<data.Label>(null);
return null;
}
return CacheManager.GetAsync(data.Label.CacheUrn(id), () =>
return await CacheManager.GetAsync(data.Label.CacheUrn(id), async () =>
{
return DbContext.Labels.FirstOrDefaultAsync(x => x.RoadieId == id);
}, data.Label.CacheRegionUrn(id));
return await DbContext.Labels.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
}, data.Label.CacheRegionUrn(id)).ConfigureAwait(false);
}
protected Task<data.Playlist> GetPlaylist(Guid id)
protected async Task<data.Playlist> GetPlaylist(Guid id)
{
if (id == Guid.Empty)
{
return Task.FromResult<data.Playlist>(null);
return null;
}
return CacheManager.GetAsync(data.Playlist.CacheUrn(id), () =>
return await CacheManager.GetAsync(data.Playlist.CacheUrn(id), async () =>
{
return DbContext.Playlists
return await DbContext.Playlists
.Include(x => x.User)
.FirstOrDefaultAsync(x => x.RoadieId == id);
}, data.Playlist.CacheRegionUrn(id));
.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
}, data.Playlist.CacheRegionUrn(id)).ConfigureAwait(false);
}
protected Task<data.Release> GetRelease(Guid id)
protected async Task<data.Release> GetRelease(Guid id)
{
if (id == Guid.Empty)
{
return Task.FromResult<data.Release>(null);
return null;
}
return CacheManager.GetAsync(data.Release.CacheUrn(id), () =>
return await CacheManager.GetAsync(data.Release.CacheUrn(id), async () =>
{
return DbContext.Releases
return await DbContext.Releases
.Include(x => x.Artist)
.Include(x => x.Genres)
.Include("Genres.Genre")
.Include(x => x.Medias)
.Include("Medias.Tracks")
.Include("Medias.Tracks.TrackArtist")
.FirstOrDefaultAsync(x => x.RoadieId == id);
}, data.Release.CacheRegionUrn(id));
.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
}, data.Release.CacheRegionUrn(id)).ConfigureAwait(false);
}
/// <summary>
@ -193,27 +193,27 @@ namespace Roadie.Api.Services
{
if (Guid.TryParse(id, out Guid trackId))
{
return await GetTrack(trackId);
return await GetTrack(trackId).ConfigureAwait(false);
}
return null;
}
// Only read operations
protected Task<data.Track> GetTrack(Guid id)
protected async Task<data.Track> GetTrack(Guid id)
{
if(id == Guid.Empty)
{
return Task.FromResult<data.Track>(null);
return null;
}
return CacheManager.GetAsync(data.Track.CacheUrn(id), () =>
return await CacheManager.GetAsync(data.Track.CacheUrn(id), async () =>
{
return DbContext.Tracks
return await DbContext.Tracks
.Include(x => x.ReleaseMedia)
.Include(x => x.ReleaseMedia.Release)
.Include(x => x.ReleaseMedia.Release.Artist)
.Include(x => x.TrackArtist)
.FirstOrDefaultAsync(x => x.RoadieId == id);
}, data.Track.CacheRegionUrn(id));
.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
}, data.Track.CacheRegionUrn(id)).ConfigureAwait(false);
}
protected async Task<User> GetUser(string username)
@ -225,40 +225,41 @@ namespace Roadie.Api.Services
var userByUsername = await CacheManager.GetAsync(User.CacheUrnByUsername(username), () =>
{
return DbContext.Users.FirstOrDefaultAsync(x => x.UserName == username);
}, null);
}, null).ConfigureAwait(false);
return await GetUser(userByUsername?.RoadieId).ConfigureAwait(false);
}
protected Task<User> GetUser(Guid? id)
protected async Task<User> GetUser(Guid? id)
{
if (!id.HasValue)
{
return Task.FromResult<User>(null);
return null;
}
return CacheManager.GetAsync(User.CacheUrn(id.Value), () =>
return await CacheManager.GetAsync(User.CacheUrn(id.Value), async () =>
{
return DbContext.Users
return await DbContext.Users
.Include(x => x.UserRoles)
.Include("UserRoles.Role")
.Include("UserRoles.Role.RoleClaims")
.Include(x => x.UserClaims)
.Include(x => x.UserQues)
.Include("UserQues.Track")
.FirstOrDefaultAsync(x => x.RoadieId == id);
}, User.CacheRegionUrn(id.Value));
.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
}, User.CacheRegionUrn(id.Value)).ConfigureAwait(false);
}
protected string MakeLastFmUrl(string artistName, string releaseTitle) => "http://www.last.fm/music/" + HttpEncoder.UrlEncode($"{artistName}/{releaseTitle}");
protected async Task<OperationResult<short>> SetArtistRating(Guid artistId, User user, short rating)
{
var artist = DbContext.Artists
var artist = await DbContext.Artists
.Include(x => x.Genres)
.Include("Genres.Genre")
.FirstOrDefault(x => x.RoadieId == artistId);
.FirstOrDefaultAsync(x => x.RoadieId == artistId)
.ConfigureAwait(false);
if (artist == null) return new OperationResult<short>(true, $"Invalid Artist Id [{artistId}]");
var now = DateTime.UtcNow;
var userArtist = DbContext.UserArtists.FirstOrDefault(x => x.ArtistId == artist.Id && x.UserId == user.Id);
var userArtist = await DbContext.UserArtists.FirstOrDefaultAsync(x => x.ArtistId == artist.Id && x.UserId == user.Id).ConfigureAwait(false);
if (userArtist == null)
{
userArtist = new data.UserArtist
@ -278,7 +279,7 @@ namespace Roadie.Api.Services
await DbContext.SaveChangesAsync().ConfigureAwait(false);
var ratings = await DbContext.UserArtists.Where(x => x.ArtistId == artist.Id && x.Rating > 0).Select(x => x.Rating).ToListAsync().ConfigureAwait(false);
if (ratings != null && ratings.Any())
if (ratings != null && ratings.Count > 0)
{
artist.Rating = (short)ratings.Average(x => (decimal)x);
}
@ -288,7 +289,7 @@ namespace Roadie.Api.Services
}
artist.LastUpdated = now;
await DbContext.SaveChangesAsync().ConfigureAwait(false);
await UpdateArtistRank(artist.Id);
await UpdateArtistRank(artist.Id).ConfigureAwait(false);
CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(artist.CacheRegion);
@ -303,19 +304,19 @@ namespace Roadie.Api.Services
protected async Task<OperationResult<short>> SetReleaseRating(Guid releaseId, User user, short rating)
{
var release = DbContext.Releases
var release = await DbContext.Releases
.Include(x => x.Artist)
.Include(x => x.Genres)
.Include("Genres.Genre")
.Include(x => x.Medias)
.Include("Medias.Tracks")
.Include("Medias.Tracks.TrackArtist")
.FirstOrDefault(x => x.RoadieId == releaseId);
.FirstOrDefaultAsync(x => x.RoadieId == releaseId).ConfigureAwait(false);
if (release == null)
{
return new OperationResult<short>(true, $"Invalid Release Id [{releaseId}]");
}
var userRelease = DbContext.UserReleases.FirstOrDefault(x => x.ReleaseId == release.Id && x.UserId == user.Id);
var userRelease = await DbContext.UserReleases.FirstOrDefaultAsync(x => x.ReleaseId == release.Id && x.UserId == user.Id).ConfigureAwait(false);
var now = DateTime.UtcNow;
if (userRelease == null)
{
@ -325,7 +326,7 @@ namespace Roadie.Api.Services
UserId = user.Id,
ReleaseId = release.Id
};
DbContext.UserReleases.Add(userRelease);
await DbContext.UserReleases.AddAsync(userRelease).ConfigureAwait(false);
}
else
{
@ -333,10 +334,10 @@ namespace Roadie.Api.Services
userRelease.LastUpdated = now;
}
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
var ratings = await DbContext.UserReleases.Where(x => x.ReleaseId == release.Id && x.Rating > 0).Select(x => x.Rating).ToListAsync();
if (ratings != null && ratings.Any())
var ratings = await DbContext.UserReleases.Where(x => x.ReleaseId == release.Id && x.Rating > 0).Select(x => x.Rating).ToListAsync().ConfigureAwait(false);
if (ratings != null && ratings.Count > 0)
{
release.Rating = (short)ratings.Average(x => (decimal)x);
}
@ -345,13 +346,13 @@ namespace Roadie.Api.Services
release.Rating = 0;
}
release.LastUpdated = now;
await DbContext.SaveChangesAsync();
await UpdateReleaseRank(release.Id);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
await UpdateReleaseRank(release.Id).ConfigureAwait(false);
CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(release.CacheRegion);
CacheManager.ClearRegion(release.Artist.CacheRegion);
release = await GetRelease(releaseId);
release = await GetRelease(releaseId).ConfigureAwait(false);
return new OperationResult<short>
{
@ -364,18 +365,19 @@ namespace Roadie.Api.Services
{
var sw = Stopwatch.StartNew();
var track = DbContext.Tracks
var track = await DbContext.Tracks
.Include(x => x.ReleaseMedia)
.Include(x => x.ReleaseMedia.Release)
.Include(x => x.ReleaseMedia.Release.Artist)
.Include(x => x.TrackArtist)
.FirstOrDefault(x => x.RoadieId == trackId);
.FirstOrDefaultAsync(x => x.RoadieId == trackId)
.ConfigureAwait(false);
if (track == null)
{
return new OperationResult<short>(true, $"Invalid Track Id [{trackId}]");
}
var now = DateTime.UtcNow;
var userTrack = DbContext.UserTracks.FirstOrDefault(x => x.TrackId == track.Id && x.UserId == user.Id);
var userTrack = await DbContext.UserTracks.FirstOrDefaultAsync(x => x.TrackId == track.Id && x.UserId == user.Id).ConfigureAwait(false);
if (userTrack == null)
{
userTrack = new data.UserTrack
@ -384,7 +386,7 @@ namespace Roadie.Api.Services
UserId = user.Id,
TrackId = track.Id
};
DbContext.UserTracks.Add(userTrack);
await DbContext.UserTracks.AddAsync(userTrack).ConfigureAwait(false);
}
else
{
@ -392,10 +394,10 @@ namespace Roadie.Api.Services
userTrack.LastUpdated = now;
}
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
var ratings = await DbContext.UserTracks.Where(x => x.TrackId == track.Id && x.Rating > 0).Select(x => x.Rating).ToListAsync();
if (ratings != null && ratings.Any())
var ratings = await DbContext.UserTracks.Where(x => x.TrackId == track.Id && x.Rating > 0).Select(x => x.Rating).ToListAsync().ConfigureAwait(false);
if (ratings != null && ratings.Count > 0)
{
track.Rating = (short)ratings.Average(x => (double)x);
}
@ -404,8 +406,8 @@ namespace Roadie.Api.Services
track.Rating = 0;
}
track.LastUpdated = now;
await DbContext.SaveChangesAsync();
await UpdateReleaseRank(track.ReleaseMedia.Release.Id);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
await UpdateReleaseRank(track.ReleaseMedia.Release.Id).ConfigureAwait(false);
CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(track.CacheRegion);
@ -430,12 +432,13 @@ namespace Roadie.Api.Services
var result = false;
try
{
var artist = DbContext.Artists
var artist = await DbContext.Artists
.Include(x => x.Genres)
.Include("Genres.Genre")
.FirstOrDefault(x => x.RoadieId == artistId);
.FirstOrDefaultAsync(x => x.RoadieId == artistId)
.ConfigureAwait(false);
if (artist == null) return new OperationResult<bool>(true, $"Invalid Artist Id [{artistId}]");
var userArtist = DbContext.UserArtists.FirstOrDefault(x => x.ArtistId == artist.Id && x.UserId == user.Id);
var userArtist = await DbContext.UserArtists.FirstOrDefaultAsync(x => x.ArtistId == artist.Id && x.UserId == user.Id).ConfigureAwait(false);
if (userArtist == null)
{
userArtist = new data.UserArtist
@ -444,7 +447,7 @@ namespace Roadie.Api.Services
UserId = user.Id,
ArtistId = artist.Id
};
DbContext.UserArtists.Add(userArtist);
await DbContext.UserArtists.AddAsync(userArtist).ConfigureAwait(false);
}
else
{
@ -452,7 +455,7 @@ namespace Roadie.Api.Services
userArtist.LastUpdated = DateTime.UtcNow;
}
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(artist.CacheRegion);
@ -474,12 +477,13 @@ namespace Roadie.Api.Services
var result = false;
try
{
var artist = DbContext.Artists
var artist = await DbContext.Artists
.Include(x => x.Genres)
.Include("Genres.Genre")
.FirstOrDefault(x => x.RoadieId == artistId);
.FirstOrDefaultAsync(x => x.RoadieId == artistId)
.ConfigureAwait(false);
if (artist == null) return new OperationResult<bool>(true, $"Invalid Artist Id [{artistId}]");
var userArtist = DbContext.UserArtists.FirstOrDefault(x => x.ArtistId == artist.Id && x.UserId == user.Id);
var userArtist = await DbContext.UserArtists.FirstOrDefaultAsync(x => x.ArtistId == artist.Id && x.UserId == user.Id).ConfigureAwait(false);
if (userArtist == null)
{
userArtist = new data.UserArtist
@ -488,7 +492,7 @@ namespace Roadie.Api.Services
UserId = user.Id,
ArtistId = artist.Id
};
DbContext.UserArtists.Add(userArtist);
await DbContext.UserArtists.AddAsync(userArtist).ConfigureAwait(false);
}
else
{
@ -496,7 +500,7 @@ namespace Roadie.Api.Services
userArtist.LastUpdated = DateTime.UtcNow;
}
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(artist.CacheRegion);
@ -518,19 +522,20 @@ namespace Roadie.Api.Services
var result = false;
try
{
var release = DbContext.Releases
var release = await DbContext.Releases
.Include(x => x.Artist)
.Include(x => x.Genres)
.Include("Genres.Genre")
.Include(x => x.Medias)
.Include("Medias.Tracks")
.Include("Medias.Tracks.TrackArtist")
.FirstOrDefault(x => x.RoadieId == releaseId);
.FirstOrDefaultAsync(x => x.RoadieId == releaseId)
.ConfigureAwait(false);
if (release == null)
{
return new OperationResult<bool>(true, $"Invalid Release Id [{releaseId}]");
}
var userRelease = DbContext.UserReleases.FirstOrDefault(x => x.ReleaseId == release.Id && x.UserId == user.Id);
var userRelease = await DbContext.UserReleases.FirstOrDefaultAsync(x => x.ReleaseId == release.Id && x.UserId == user.Id).ConfigureAwait(false);
if (userRelease == null)
{
userRelease = new data.UserRelease
@ -539,7 +544,7 @@ namespace Roadie.Api.Services
UserId = user.Id,
ReleaseId = release.Id
};
DbContext.UserReleases.Add(userRelease);
await DbContext.UserReleases.AddAsync(userRelease).ConfigureAwait(false);
}
else
{
@ -547,7 +552,7 @@ namespace Roadie.Api.Services
userRelease.LastUpdated = DateTime.UtcNow;
}
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(release.CacheRegion);
@ -582,7 +587,7 @@ namespace Roadie.Api.Services
{
return new OperationResult<bool>(true, $"Invalid Release Id [{releaseId}]");
}
var userRelease = DbContext.UserReleases.FirstOrDefault(x => x.ReleaseId == release.Id && x.UserId == user.Id);
var userRelease = await DbContext.UserReleases.FirstOrDefaultAsync(x => x.ReleaseId == release.Id && x.UserId == user.Id).ConfigureAwait(false);
if (userRelease == null)
{
userRelease = new data.UserRelease
@ -591,7 +596,7 @@ namespace Roadie.Api.Services
UserId = user.Id,
ReleaseId = release.Id
};
DbContext.UserReleases.Add(userRelease);
await DbContext.UserReleases.AddAsync(userRelease).ConfigureAwait(false);
}
else
{
@ -599,7 +604,7 @@ namespace Roadie.Api.Services
userRelease.LastUpdated = DateTime.UtcNow;
}
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(release.CacheRegion);
@ -622,17 +627,18 @@ namespace Roadie.Api.Services
var result = false;
try
{
var track = DbContext.Tracks
var track = await DbContext.Tracks
.Include(x => x.ReleaseMedia)
.Include(x => x.ReleaseMedia.Release)
.Include(x => x.ReleaseMedia.Release.Artist)
.Include(x => x.TrackArtist)
.FirstOrDefault(x => x.RoadieId == trackId);
.FirstOrDefaultAsync(x => x.RoadieId == trackId)
.ConfigureAwait(false);
if (track == null)
{
return new OperationResult<bool>(true, $"Invalid Track Id [{trackId}]");
}
var userTrack = DbContext.UserTracks.FirstOrDefault(x => x.TrackId == track.Id && x.UserId == user.Id);
var userTrack = await DbContext.UserTracks.FirstOrDefaultAsync(x => x.TrackId == track.Id && x.UserId == user.Id).ConfigureAwait(false);
if (userTrack == null)
{
userTrack = new data.UserTrack
@ -641,7 +647,7 @@ namespace Roadie.Api.Services
UserId = user.Id,
TrackId = track.Id
};
DbContext.UserTracks.Add(userTrack);
await DbContext.UserTracks.AddAsync(userTrack).ConfigureAwait(false);
}
else
{
@ -649,7 +655,7 @@ namespace Roadie.Api.Services
userTrack.LastUpdated = DateTime.UtcNow;
}
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(track.CacheRegion);
@ -673,17 +679,18 @@ namespace Roadie.Api.Services
var result = false;
try
{
var track = DbContext.Tracks
var track = await DbContext.Tracks
.Include(x => x.ReleaseMedia)
.Include(x => x.ReleaseMedia.Release)
.Include(x => x.ReleaseMedia.Release.Artist)
.Include(x => x.TrackArtist)
.FirstOrDefault(x => x.RoadieId == trackId);
.FirstOrDefaultAsync(x => x.RoadieId == trackId)
.ConfigureAwait(false);
if (track == null)
{
return new OperationResult<bool>(true, $"Invalid Track Id [{trackId}]");
}
var userTrack = DbContext.UserTracks.FirstOrDefault(x => x.TrackId == track.Id && x.UserId == user.Id);
var userTrack = await DbContext.UserTracks.FirstOrDefaultAsync(x => x.TrackId == track.Id && x.UserId == user.Id).ConfigureAwait(false);
if (userTrack == null)
{
userTrack = new data.UserTrack
@ -692,7 +699,7 @@ namespace Roadie.Api.Services
UserId = user.Id,
TrackId = track.Id
};
DbContext.UserTracks.Add(userTrack);
await DbContext.UserTracks.AddAsync(userTrack).ConfigureAwait(false);
}
else
{
@ -700,7 +707,7 @@ namespace Roadie.Api.Services
userTrack.LastUpdated = DateTime.UtcNow;
}
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(user.CacheRegion);
CacheManager.ClearRegion(track.CacheRegion);
@ -724,18 +731,18 @@ namespace Roadie.Api.Services
protected async Task UpdateArtistCounts(int artistId, DateTime now)
{
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == artistId);
var artist = await DbContext.Artists.FirstOrDefaultAsync(x => x.Id == artistId).ConfigureAwait(false);
if (artist != null)
{
artist.ReleaseCount = await DbContext.Releases.Where(x => x.ArtistId == artistId).CountAsync();
artist.ReleaseCount = await DbContext.Releases.Where(x => x.ArtistId == artistId).CountAsync().ConfigureAwait(false);
artist.TrackCount = await (from r in DbContext.Releases
join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
join tr in DbContext.Tracks on rm.Id equals tr.ReleaseMediaId
where tr.ArtistId == artistId || r.ArtistId == artistId
select tr).CountAsync();
select tr).CountAsync().ConfigureAwait(false);
artist.LastUpdated = now;
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(artist.CacheRegion);
}
}
@ -750,10 +757,10 @@ namespace Roadie.Api.Services
join tr in DbContext.Tracks on rm.Id equals tr.ReleaseMediaId
join plt in DbContext.PlaylistTracks on tr.Id equals plt.TrackId
where r.ArtistId == artistId
select plt.PlayListId).ToListAsync();
select plt.PlayListId).ToListAsync().ConfigureAwait(false);
foreach (var playlistId in playlistIds.Distinct())
{
await UpdatePlaylistCounts(playlistId, now);
await UpdatePlaylistCounts(playlistId, now).ConfigureAwait(false);
}
}
@ -768,10 +775,10 @@ namespace Roadie.Api.Services
join tr in DbContext.Tracks on rm.Id equals tr.ReleaseMediaId
join plt in DbContext.PlaylistTracks on tr.Id equals plt.TrackId
where r.Id == releaseId
select plt.PlayListId).ToListAsync();
foreach(var playlistId in playlistIds.Distinct())
select plt.PlayListId).ToListAsync().ConfigureAwait(false);
foreach (var playlistId in playlistIds.Distinct())
{
await UpdatePlaylistCounts(playlistId, now);
await UpdatePlaylistCounts(playlistId, now).ConfigureAwait(false);
}
}
@ -786,11 +793,11 @@ namespace Roadie.Api.Services
join tr in DbContext.Tracks on rm.Id equals tr.ReleaseMediaId
where r.Id == releaseId
where tr.ArtistId != null
select tr.ArtistId.Value).ToListAsync();
select tr.ArtistId.Value).ToListAsync().ConfigureAwait(false);
trackArtistIds.Add(DbContext.Releases.FirstOrDefault(x => x.Id == releaseId).ArtistId);
foreach (var artistId in trackArtistIds.Distinct())
{
await UpdateArtistCounts(artistId, now);
await UpdateArtistCounts(artistId, now).ConfigureAwait(false);
}
}
@ -802,15 +809,15 @@ namespace Roadie.Api.Services
{
try
{
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == artistId);
var artist = await DbContext.Artists.FirstOrDefaultAsync(x => x.Id == artistId).ConfigureAwait(false);
if (artist != null)
{
if (updateReleaseRanks)
{
var artistReleaseIds = await DbContext.Releases.Where(x => x.ArtistId == artistId).Select(x => x.Id).ToArrayAsync();
var artistReleaseIds = await DbContext.Releases.Where(x => x.ArtistId == artistId).Select(x => x.Id).ToArrayAsync().ConfigureAwait(false);
foreach (var artistReleaseId in artistReleaseIds)
{
await UpdateReleaseRank(artistReleaseId, false);
await UpdateReleaseRank(artistReleaseId, false).ConfigureAwait(false);
}
}
@ -818,20 +825,20 @@ namespace Roadie.Api.Services
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
join ut in DbContext.UserTracks on t.Id equals ut.TrackId
where t.ArtistId == artist.Id
select ut.Rating).Select(x => (decimal?)x).ToArrayAsync()).Average();
select ut.Rating).Select(x => (decimal?)x).ToArrayAsync().ConfigureAwait(false)).Average();
var artistReleaseRatingRating = (await (from r in DbContext.Releases
join ur in DbContext.UserReleases on r.Id equals ur.ReleaseId
where r.ArtistId == artist.Id
select ur.Rating).Select(x => (decimal?)x).ToArrayAsync()).Average();
select ur.Rating).Select(x => (decimal?)x).ToArrayAsync().ConfigureAwait(false)).Average();
var artistReleaseRankSum = (await (from r in DbContext.Releases
where r.ArtistId == artist.Id
select r.Rank).ToArrayAsync()).Sum(x => x) ?? 0;
select r.Rank).ToArrayAsync().ConfigureAwait(false)).Sum(x => x) ?? 0;
artist.Rank = SafeParser.ToNumber<decimal>(artistTrackAverage + artistReleaseRatingRating) + artistReleaseRankSum + artist.Rating;
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(artist.CacheRegion);
Logger.LogTrace("UpdatedArtistRank For Artist `{0}`", artist);
}
@ -858,74 +865,74 @@ namespace Roadie.Api.Services
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
where rm.ReleaseId == release.Id
where t.ArtistId.HasValue
select t.ArtistId.Value).ToArrayAsync();
select t.ArtistId.Value).ToArrayAsync().ConfigureAwait(false);
artistsForRelease.AddRange(trackArtistsForRelease);
foreach (var artistId in artistsForRelease.Distinct())
{
await UpdateArtistRank(artistId);
await UpdateArtistRank(artistId).ConfigureAwait(false);
}
}
}
protected async Task UpdateLabelCounts(int labelId, DateTime now)
{
var label = DbContext.Labels.FirstOrDefault(x => x.Id == labelId);
var label = await DbContext.Labels.FirstOrDefaultAsync(x => x.Id == labelId).ConfigureAwait(false);
if (label != null)
{
label.ReleaseCount = await DbContext.ReleaseLabels.Where(x => x.LabelId == label.Id).CountAsync();
label.ReleaseCount = await DbContext.ReleaseLabels.Where(x => x.LabelId == label.Id).CountAsync().ConfigureAwait(false);
label.ArtistCount = await (from r in DbContext.Releases
join rl in DbContext.ReleaseLabels on r.Id equals rl.ReleaseId
join a in DbContext.Artists on r.ArtistId equals a.Id
where rl.LabelId == label.Id
group a by a.Id
into artists
select artists).Select(x => x.Key).CountAsync();
into artists
select artists).Select(x => x.Key).CountAsync().ConfigureAwait(false);
label.TrackCount = await (from r in DbContext.Releases
join rl in DbContext.ReleaseLabels on r.Id equals rl.ReleaseId
join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
join t in DbContext.Tracks on rm.Id equals t.ReleaseMediaId
where rl.LabelId == label.Id
select t).CountAsync();
select t).CountAsync().ConfigureAwait(false);
label.LastUpdated = now;
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(label.CacheRegion);
}
}
protected async Task UpdatePlaylistCounts(int playlistId, DateTime now)
{
var playlist = DbContext.Playlists.FirstOrDefault(x => x.Id == playlistId);
var playlist = await DbContext.Playlists.FirstOrDefaultAsync(x => x.Id == playlistId).ConfigureAwait(false);
if (playlist != null)
{
var playlistTracks = await DbContext.PlaylistTracks
.Include(x => x.Track)
.Include("Track.ReleaseMedia")
.Where(x => x.PlayListId == playlist.Id).ToArrayAsync();
playlist.TrackCount = (short)playlistTracks.Count();
.Where(x => x.PlayListId == playlist.Id).ToArrayAsync().ConfigureAwait(false);
playlist.TrackCount = (short)playlistTracks.Length;
playlist.Duration = playlistTracks.Sum(x => x.Track.Duration);
playlist.ReleaseCount = (short)playlistTracks.Select(x => x.Track.ReleaseMedia.ReleaseId).Distinct().Count();
playlist.LastUpdated = now;
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(playlist.CacheRegion);
}
}
protected async Task UpdateReleaseCounts(int releaseId, DateTime now)
{
var release = DbContext.Releases.FirstOrDefault(x => x.Id == releaseId);
var release = await DbContext.Releases.FirstOrDefaultAsync(x => x.Id == releaseId).ConfigureAwait(false);
if (release != null)
{
release.PlayedCount = await (from t in DbContext.Tracks
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
where rm.ReleaseId == releaseId
where t.PlayedCount.HasValue
select t).SumAsync(x => x.PlayedCount);
select t).SumAsync(x => x.PlayedCount).ConfigureAwait(false);
release.Duration = await (from t in DbContext.Tracks
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
where rm.ReleaseId == releaseId
select t).SumAsync(x => x.Duration);
select t).SumAsync(x => x.Duration).ConfigureAwait(false);
release.LastUpdated = now;
await DbContext.SaveChangesAsync();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(release.CacheRegion);
}
}
@ -939,7 +946,7 @@ namespace Roadie.Api.Services
{
try
{
var release = DbContext.Releases.FirstOrDefault(x => x.Id == releaseId);
var release = await DbContext.Releases.FirstOrDefaultAsync(x => x.Id == releaseId).ConfigureAwait(false);
if (release != null)
{
var releaseTrackAverage = (await (from ut in DbContext.UserTracks

View file

@ -26,7 +26,39 @@ namespace Roadie.Api.Services
{
}
public Task<OperationResult<LibraryStats>> LibraryStatistics()
public Task<OperationResult<IEnumerable<DateAndCount>>> ArtistsByDateAsync()
{
var sw = new Stopwatch();
sw.Start();
var result = new List<DateAndCount>();
var dateInfos = (from r in DbContext.Artists
orderby r.CreatedDate
select r.CreatedDate)
.ToArray()
.GroupBy(x => x.ToString("yyyy-MM-dd"))
.Select(x => new
{
date = x.Key,
count = x.Count()
});
foreach (var dateInfo in dateInfos)
{
result.Add(new DateAndCount
{
Date = dateInfo.date,
Count = dateInfo.count
});
}
sw.Stop();
return Task.FromResult(new OperationResult<IEnumerable<DateAndCount>>
{
OperationTime = sw.ElapsedMilliseconds,
IsSuccess = result != null,
Data = result
});
}
public Task<OperationResult<LibraryStats>> LibraryStatisticsAsync()
{
LibraryStats result = null;
var sw = new Stopwatch();
@ -65,39 +97,7 @@ namespace Roadie.Api.Services
});
}
public Task<OperationResult<IEnumerable<DateAndCount>>> ArtistsByDate()
{
var sw = new Stopwatch();
sw.Start();
var result = new List<DateAndCount>();
var dateInfos = (from r in DbContext.Artists
orderby r.CreatedDate
select r.CreatedDate)
.ToArray()
.GroupBy(x => x.ToString("yyyy-MM-dd"))
.Select(x => new
{
date = x.Key,
count = x.Count()
});
foreach (var dateInfo in dateInfos)
{
result.Add(new DateAndCount
{
Date = dateInfo.date,
Count = dateInfo.count
});
}
sw.Stop();
return Task.FromResult(new OperationResult<IEnumerable<DateAndCount>>
{
OperationTime = sw.ElapsedMilliseconds,
IsSuccess = result != null,
Data = result
});
}
public Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDate()
public Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDateAsync()
{
var sw = new Stopwatch();
sw.Start();
@ -129,78 +129,14 @@ namespace Roadie.Api.Services
});
}
public Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByUser()
{
var sw = new Stopwatch();
sw.Start();
var result = new List<DateAndCount>();
var dateInfos = (from r in DbContext.UserTracks
join u in DbContext.Users on r.UserId equals u.Id
select new { u.UserName, r.PlayedCount })
.ToArray()
.GroupBy(x => x.UserName)
.Select(x => new
{
username = x.Key,
count = x.Count()
});
foreach (var dateInfo in dateInfos)
{
result.Add(new DateAndCount
{
Date = dateInfo.username,
Count = dateInfo.count
});
}
sw.Stop();
return Task.FromResult(new OperationResult<IEnumerable<DateAndCount>>
{
OperationTime = sw.ElapsedMilliseconds,
IsSuccess = result != null,
Data = result
});
}
public Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByDate()
{
var sw = new Stopwatch();
sw.Start();
var result = new List<DateAndCount>();
var dateInfos = (from r in DbContext.UserTracks
orderby r.LastPlayed
select r.LastPlayed ?? r.CreatedDate)
.ToArray()
.GroupBy(x => x.ToString("yyyy-MM-dd"))
.Select(x => new
{
date = x.Key,
count = x.Count()
});
foreach (var dateInfo in dateInfos)
{
result.Add(new DateAndCount
{
Date = dateInfo.date,
Count = dateInfo.count
});
}
sw.Stop();
return Task.FromResult(new OperationResult<IEnumerable<DateAndCount>>
{
OperationTime = sw.ElapsedMilliseconds,
IsSuccess = result != null,
Data = result
});
}
public Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDecade()
public Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDecadeAsync()
{
var sw = new Stopwatch();
sw.Start();
var result = new List<DateAndCount>();
var decadeInfos = (from r in DbContext.Releases
orderby r.ReleaseDate
select r.ReleaseDate ?? r.CreatedDate)
orderby r.ReleaseDate
select r.ReleaseDate ?? r.CreatedDate)
.ToArray()
.GroupBy(x => x.ToString("yyyy"))
.Select(x => new
@ -235,5 +171,69 @@ namespace Roadie.Api.Services
Data = result
});
}
public Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByDateAsync()
{
var sw = new Stopwatch();
sw.Start();
var result = new List<DateAndCount>();
var dateInfos = (from r in DbContext.UserTracks
orderby r.LastPlayed
select r.LastPlayed ?? r.CreatedDate)
.ToArray()
.GroupBy(x => x.ToString("yyyy-MM-dd"))
.Select(x => new
{
date = x.Key,
count = x.Count()
});
foreach (var dateInfo in dateInfos)
{
result.Add(new DateAndCount
{
Date = dateInfo.date,
Count = dateInfo.count
});
}
sw.Stop();
return Task.FromResult(new OperationResult<IEnumerable<DateAndCount>>
{
OperationTime = sw.ElapsedMilliseconds,
IsSuccess = result != null,
Data = result
});
}
public Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByUserAsync()
{
var sw = new Stopwatch();
sw.Start();
var result = new List<DateAndCount>();
var dateInfos = (from r in DbContext.UserTracks
join u in DbContext.Users on r.UserId equals u.Id
select new { u.UserName, r.PlayedCount })
.ToArray()
.GroupBy(x => x.UserName)
.Select(x => new
{
username = x.Key,
count = x.Count()
});
foreach (var dateInfo in dateInfos)
{
result.Add(new DateAndCount
{
Date = dateInfo.username,
Count = dateInfo.count
});
}
sw.Stop();
return Task.FromResult(new OperationResult<IEnumerable<DateAndCount>>
{
OperationTime = sw.ElapsedMilliseconds,
IsSuccess = result != null,
Data = result
});
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -20,11 +20,11 @@ namespace Roadie.Api.Services
_configuration = configuration;
}
public async Task<string> GenerateToken(User user, UserManager<User> userManager)
public async Task<string> GenerateTokenAsync(User user, UserManager<User> userManager)
{
var utcNow = DateTime.UtcNow;
var roles = await userManager.GetRolesAsync(user);
var roles = await userManager.GetRolesAsync(user).ConfigureAwait(false);
var userRoles = roles.Select(r => new Claim(ClaimTypes.Role, r)).ToArray();
var tokenHandler = new JwtSecurityTokenHandler();

View file

@ -37,9 +37,25 @@ namespace Roadie.Api.Services
private IBookmarkService BookmarkService { get; }
public TrackService(IRoadieSettings configuration, IHttpEncoder httpEncoder, IHttpContext httpContext,
IRoadieDbContext dbContext, ICacheManager cacheManager, ILogger<TrackService> logger,
IBookmarkService bookmarkService, IAdminService adminService, IAudioMetaDataHelper audioMetaDataHelper)
public TrackService(
IRoadieSettings configuration,
IRoadieDbContext dbContext,
ICacheManager cacheManager,
ILogger logger)
: base(configuration, null, dbContext, cacheManager, logger, null)
{
}
public TrackService(
IRoadieSettings configuration,
IHttpEncoder httpEncoder,
IHttpContext httpContext,
IRoadieDbContext dbContext,
ICacheManager cacheManager,
ILogger<TrackService> logger,
IBookmarkService bookmarkService,
IAdminService adminService,
IAudioMetaDataHelper audioMetaDataHelper)
: base(configuration, httpEncoder, dbContext, cacheManager, logger, httpContext)
{
BookmarkService = bookmarkService;
@ -47,82 +63,167 @@ namespace Roadie.Api.Services
AdminService = adminService;
}
public TrackService(IRoadieSettings configuration, IRoadieDbContext dbContext, ICacheManager cacheManager, ILogger logger)
: base(configuration, null, dbContext, cacheManager, logger, null)
{
}
public static long DetermineByteEndFromHeaders(IHeaderDictionary headers, long fileLength)
{
var defaultFileLength = fileLength - 1;
if (headers?.Any(x => x.Key == "Range") != true)
{
return defaultFileLength;
}
long? result = null;
var rangeHeader = headers["Range"];
string rangeEnd = null;
var rangeBegin = rangeHeader.FirstOrDefault();
if (!string.IsNullOrEmpty(rangeBegin))
{
//bytes=0-
rangeBegin = rangeBegin.Replace("bytes=", "");
var parts = rangeBegin.Split('-');
rangeBegin = parts[0];
if (parts.Length > 1)
{
rangeEnd = parts[1];
}
if (!string.IsNullOrEmpty(rangeEnd))
{
result = long.TryParse(rangeEnd, out var outValue) ? (int?)outValue : null;
}
}
return result ?? defaultFileLength;
}
public static long DetermineByteStartFromHeaders(IHeaderDictionary headers)
{
if (headers?.Any(x => x.Key == "Range") != true)
{
return 0;
}
long result = 0;
var rangeHeader = headers["Range"];
var rangeBegin = rangeHeader.FirstOrDefault();
if (!string.IsNullOrEmpty(rangeBegin))
{
//bytes=0-
rangeBegin = rangeBegin.Replace("bytes=", "");
var parts = rangeBegin.Split('-');
rangeBegin = parts[0];
if (!string.IsNullOrEmpty(rangeBegin))
{
long.TryParse(rangeBegin, out result);
}
}
return result;
}
public async Task<OperationResult<Track>> ById(User roadieUser, Guid id, IEnumerable<string> includes)
private async Task<OperationResult<Track>> TrackByIdActionAsync(Guid id, IEnumerable<string> includes)
{
var timings = new Dictionary<string, long>();
var tsw = new Stopwatch();
var sw = Stopwatch.StartNew();
sw.Start();
var cacheKey = string.Format("urn:track_by_id_operation:{0}:{1}", id, includes == null ? "0" : string.Join("|", includes));
tsw.Restart();
var track = await GetTrack(id).ConfigureAwait(false);
tsw.Stop();
timings.Add("getTrack", tsw.ElapsedMilliseconds);
if (track == null)
{
return new OperationResult<Track>(true, $"Track Not Found [{id}]");
}
tsw.Restart();
var result = track.Adapt<Track>();
result.IsLocked = (track.IsLocked ?? false) ||
(track.ReleaseMedia.IsLocked ?? false) ||
(track.ReleaseMedia.Release.IsLocked ?? false) ||
(track.ReleaseMedia.Release.Artist.IsLocked ?? false);
result.Thumbnail = ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, id);
result.MediumThumbnail = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "track", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
result.ReleaseMediaId = track.ReleaseMedia.RoadieId.ToString();
result.Artist = ArtistList.FromDataArtist(track.ReleaseMedia.Release.Artist,
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId));
result.ArtistThumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId);
result.Release = ReleaseList.FromDataRelease(track.ReleaseMedia.Release, track.ReleaseMedia.Release.Artist,
HttpContext.BaseUrl, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId),
ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId));
result.ReleaseThumbnail = ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId);
tsw.Stop();
timings.Add("adapt", tsw.ElapsedMilliseconds);
if (track.ArtistId.HasValue)
{
tsw.Restart();
var trackArtist = DbContext.Artists.FirstOrDefault(x => x.Id == track.ArtistId);
if (trackArtist == null)
{
Logger.LogWarning($"Unable to find Track Artist [{track.ArtistId}");
}
else
{
result.TrackArtist =
ArtistList.FromDataArtist(trackArtist, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, trackArtist.RoadieId));
result.TrackArtistToken = result.TrackArtist.Artist;
result.TrackArtistThumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, trackArtist.RoadieId);
}
tsw.Stop();
timings.Add("trackArtist", tsw.ElapsedMilliseconds);
}
if (includes?.Any() == true)
{
if (includes.Contains("credits"))
{
tsw.Restart();
result.Credits = (await (from c in DbContext.Credits
join cc in DbContext.CreditCategory on c.CreditCategoryId equals cc.Id
join a in DbContext.Artists on c.ArtistId equals a.Id into agg
from a in agg.DefaultIfEmpty()
where c.TrackId == track.Id
select new { c, cc, a })
.ToListAsync().ConfigureAwait(false))
.Select(x => new CreditList
{
Id = x.c.RoadieId,
Artist = x.a == null ? null : ArtistList.FromDataArtist(x.a, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, x.a.RoadieId)),
Category = new DataToken
{
Text = x.cc.Name,
Value = x.cc.RoadieId.ToString()
},
CreditName = x.a?.Name ?? x.c.CreditToName,
Description = x.c.Description
}).ToArray();
tsw.Stop();
timings.Add("credits", tsw.ElapsedMilliseconds);
}
if (includes.Contains("stats"))
{
tsw.Restart();
result.Statistics = new TrackStatistics
{
FileSizeFormatted = ((long?)track.FileSize).ToFileSize(),
Time = new TimeInfo((decimal)track.Duration).ToFullFormattedString(),
PlayedCount = track.PlayedCount
};
var userTracks = (from t in DbContext.Tracks
join ut in DbContext.UserTracks on t.Id equals ut.TrackId
where t.Id == track.Id
select ut).ToArray();
if (userTracks?.Any() == true)
{
result.Statistics.DislikedCount = userTracks.Count(x => x.IsDisliked ?? false);
result.Statistics.FavoriteCount = userTracks.Count(x => x.IsFavorite ?? false);
}
tsw.Stop();
timings.Add("stats", tsw.ElapsedMilliseconds);
}
if (includes.Contains("comments"))
{
tsw.Restart();
var trackComments = DbContext.Comments.Include(x => x.User).Where(x => x.TrackId == track.Id)
.OrderByDescending(x => x.CreatedDate).ToArray();
if (trackComments.Length > 0)
{
var comments = new List<Comment>();
var commentIds = trackComments.Select(x => x.Id).ToArray();
var userCommentReactions = (from cr in DbContext.CommentReactions
where commentIds.Contains(cr.CommentId)
select cr).ToArray();
foreach (var trackComment in trackComments)
{
var comment = trackComment.Adapt<Comment>();
comment.DatabaseId = trackComment.Id;
comment.User = UserList.FromDataUser(trackComment.User,
ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, trackComment.User.RoadieId));
comment.DislikedCount = userCommentReactions.Count(x =>
x.CommentId == trackComment.Id && x.ReactionValue == CommentReaction.Dislike);
comment.LikedCount = userCommentReactions.Count(x =>
x.CommentId == trackComment.Id && x.ReactionValue == CommentReaction.Like);
comments.Add(comment);
}
result.Comments = comments;
}
tsw.Stop();
timings.Add("comments", tsw.ElapsedMilliseconds);
}
}
sw.Stop();
Logger.LogInformation($"ByIdAction: Track `{ track }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]");
return new OperationResult<Track>
{
Data = result,
IsSuccess = result != null,
OperationTime = sw.ElapsedMilliseconds
};
}
public async Task<OperationResult<Track>> ByIdAsyncAsync(User roadieUser, Guid id, IEnumerable<string> includes)
{
var timings = new Dictionary<string, long>();
var tsw = new Stopwatch();
var sw = Stopwatch.StartNew();
sw.Start();
var cacheKey = $"urn:track_by_id_operation:{id}:{(includes == null ? "0" : string.Join("|", includes))}";
var result = await CacheManager.GetAsync(cacheKey, async () =>
{
tsw.Restart();
var rr = await TrackByIdAction(id, includes).ConfigureAwait(false);
var rr = await TrackByIdActionAsync(id, includes).ConfigureAwait(false);
tsw.Stop();
timings.Add("TrackByIdAction", tsw.ElapsedMilliseconds);
timings.Add(nameof(TrackByIdActionAsync), tsw.ElapsedMilliseconds);
return rr;
}, data.Track.CacheRegionUrn(id)).ConfigureAwait(false);
if (result?.Data != null && roadieUser != null)
@ -140,7 +241,7 @@ namespace Roadie.Api.Services
result.Data.TrackPlayUrl = MakeTrackPlayUrl(user, HttpContext.BaseUrl, track.RoadieId);
tsw.Restart();
var userBookmarkResult = await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Track).ConfigureAwait(false);
var userBookmarkResult = await BookmarkService.ListAsync(roadieUser, new PagedRequest(), false, BookmarkType.Track).ConfigureAwait(false);
if (userBookmarkResult.IsSuccess)
{
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x?.Bookmark?.Value == track?.RoadieId.ToString()) != null;
@ -195,7 +296,64 @@ namespace Roadie.Api.Services
};
}
public async Task<Library.Models.Pagination.PagedResult<TrackList>> List(PagedRequest request, User roadieUser, bool? doRandomize = false, Guid? releaseId = null)
public static long DetermineByteEndFromHeaders(IHeaderDictionary headers, long fileLength)
{
var defaultFileLength = fileLength - 1;
if (headers?.Any(x => x.Key == "Range") != true)
{
return defaultFileLength;
}
long? result = null;
var rangeHeader = headers["Range"];
string rangeEnd = null;
var rangeBegin = rangeHeader.FirstOrDefault();
if (!string.IsNullOrEmpty(rangeBegin))
{
//bytes=0-
rangeBegin = rangeBegin.Replace("bytes=", string.Empty);
var parts = rangeBegin.Split('-');
rangeBegin = parts[0];
if (parts.Length > 1)
{
rangeEnd = parts[1];
}
if (!string.IsNullOrEmpty(rangeEnd))
{
result = long.TryParse(rangeEnd, out var outValue) ? (int?)outValue : null;
}
}
return result ?? defaultFileLength;
}
public static long DetermineByteStartFromHeaders(IHeaderDictionary headers)
{
if (headers?.Any(x => x.Key == "Range") != true)
{
return 0;
}
long result = 0;
var rangeHeader = headers["Range"];
var rangeBegin = rangeHeader.FirstOrDefault();
if (!string.IsNullOrEmpty(rangeBegin))
{
//bytes=0-
rangeBegin = rangeBegin.Replace("bytes=", string.Empty);
var parts = rangeBegin.Split('-');
rangeBegin = parts[0];
if (!string.IsNullOrEmpty(rangeBegin))
{
long.TryParse(rangeBegin, out result);
}
}
return result;
}
public async Task<Library.Models.Pagination.PagedResult<TrackList>> ListAsync(PagedRequest request, User roadieUser, bool? doRandomize = false, Guid? releaseId = null)
{
try
{
@ -285,7 +443,7 @@ namespace Roadie.Api.Services
if (doRandomize ?? false)
{
var randomLimit = roadieUser?.RandomReleaseLimit ?? request.LimitValue;
randomTrackData = await DbContext.RandomTrackIds(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly).ConfigureAwait(false);
randomTrackData = await DbContext.RandomTrackIdsAsync(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly).ConfigureAwait(false);
randomTrackIds = randomTrackData.Select(x => x.Value).ToArray();
rowCount = DbContext.Releases.Count();
}
@ -450,7 +608,7 @@ namespace Roadie.Api.Services
if (!string.IsNullOrEmpty(request.FilterValue) && request.FilterValue.StartsWith("#"))
{
// Find any releases by tags
var tagValue = request.FilterValue.Replace("#", "");
var tagValue = request.FilterValue.Replace("#", string.Empty);
resultQuery = resultQuery.Where(x => x.ti.Tags != null && x.ti.Tags.Contains(tagValue));
}
@ -649,7 +807,7 @@ namespace Roadie.Api.Services
var track = DbContext.Tracks.FirstOrDefault(x => x.RoadieId == id);
if (track == null)
{
return new OperationResult<Track>(true, string.Format("Track Not Found [{0}]", id));
return new OperationResult<Track>(true, $"Track Not Found [{id}]");
}
return new OperationResult<Track>
@ -659,7 +817,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<TrackStreamInfo>> TrackStreamInfo(Guid trackId, long beginBytes, long endBytes, User roadieUser)
public async Task<OperationResult<TrackStreamInfo>> TrackStreamInfoAsync(Guid trackId, long beginBytes, long endBytes, User roadieUser)
{
var track = DbContext.Tracks.FirstOrDefault(x => x.RoadieId == trackId);
if (!(track?.IsValid ?? true))
@ -671,7 +829,7 @@ namespace Roadie.Api.Services
select r).FirstOrDefault();
if (!release.IsLocked ?? false && roadieUser != null)
{
await AdminService.ScanRelease(new Library.Identity.User
await AdminService.ScanReleaseAsync(new Library.Identity.User
{
Id = roadieUser.Id.Value
}, release.RoadieId, false, true).ConfigureAwait(false);
@ -710,7 +868,7 @@ namespace Roadie.Api.Services
select r).FirstOrDefault();
if (!release.IsLocked ?? false && roadieUser != null)
{
await AdminService.ScanRelease(new Library.Identity.User
await AdminService.ScanReleaseAsync(new Library.Identity.User
{
Id = roadieUser.Id.Value
}, release.RoadieId, false, true).ConfigureAwait(false);
@ -788,7 +946,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> UpdateTrack(User user, Track model)
public async Task<OperationResult<bool>> UpdateTrackAsync(User user, Track model)
{
var sw = new Stopwatch();
sw.Start();
@ -800,7 +958,7 @@ namespace Roadie.Api.Services
.FirstOrDefault(x => x.RoadieId == model.Id);
if (track == null)
{
return new OperationResult<bool>(true, string.Format("Track Not Found [{0}]", model.Id));
return new OperationResult<bool>(true, $"Track Not Found [{model.Id}]");
}
try
@ -938,152 +1096,5 @@ namespace Roadie.Api.Services
Errors = errors
};
}
private async Task<OperationResult<Track>> TrackByIdAction(Guid id, IEnumerable<string> includes)
{
var timings = new Dictionary<string, long>();
var tsw = new Stopwatch();
var sw = Stopwatch.StartNew();
sw.Start();
tsw.Restart();
var track = await GetTrack(id).ConfigureAwait(false);
tsw.Stop();
timings.Add("getTrack", tsw.ElapsedMilliseconds);
if (track == null)
{
return new OperationResult<Track>(true, string.Format("Track Not Found [{0}]", id));
}
tsw.Restart();
var result = track.Adapt<Track>();
result.IsLocked = (track.IsLocked ?? false) ||
(track.ReleaseMedia.IsLocked ?? false) ||
(track.ReleaseMedia.Release.IsLocked ?? false) ||
(track.ReleaseMedia.Release.Artist.IsLocked ?? false);
result.Thumbnail = ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, id);
result.MediumThumbnail = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "track", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
result.ReleaseMediaId = track.ReleaseMedia.RoadieId.ToString();
result.Artist = ArtistList.FromDataArtist(track.ReleaseMedia.Release.Artist,
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId));
result.ArtistThumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId);
result.Release = ReleaseList.FromDataRelease(track.ReleaseMedia.Release, track.ReleaseMedia.Release.Artist,
HttpContext.BaseUrl, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId),
ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId));
result.ReleaseThumbnail = ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId);
tsw.Stop();
timings.Add("adapt", tsw.ElapsedMilliseconds);
if (track.ArtistId.HasValue)
{
tsw.Restart();
var trackArtist = DbContext.Artists.FirstOrDefault(x => x.Id == track.ArtistId);
if (trackArtist == null)
{
Logger.LogWarning($"Unable to find Track Artist [{track.ArtistId}");
}
else
{
result.TrackArtist =
ArtistList.FromDataArtist(trackArtist, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, trackArtist.RoadieId));
result.TrackArtistToken = result.TrackArtist.Artist;
result.TrackArtistThumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, trackArtist.RoadieId);
}
tsw.Stop();
timings.Add("trackArtist", tsw.ElapsedMilliseconds);
}
if (includes?.Any() == true)
{
if (includes.Contains("credits"))
{
tsw.Restart();
result.Credits = (await (from c in DbContext.Credits
join cc in DbContext.CreditCategory on c.CreditCategoryId equals cc.Id
join a in DbContext.Artists on c.ArtistId equals a.Id into agg
from a in agg.DefaultIfEmpty()
where c.TrackId == track.Id
select new { c, cc, a })
.ToListAsync().ConfigureAwait(false))
.Select(x => new CreditList
{
Id = x.c.RoadieId,
Artist = x.a == null ? null : ArtistList.FromDataArtist(x.a, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, x.a.RoadieId)),
Category = new DataToken
{
Text = x.cc.Name,
Value = x.cc.RoadieId.ToString()
},
CreditName = x.a?.Name ?? x.c.CreditToName,
Description = x.c.Description
}).ToArray();
tsw.Stop();
timings.Add("credits", tsw.ElapsedMilliseconds);
}
if (includes.Contains("stats"))
{
tsw.Restart();
result.Statistics = new TrackStatistics
{
FileSizeFormatted = ((long?)track.FileSize).ToFileSize(),
Time = new TimeInfo((decimal)track.Duration).ToFullFormattedString(),
PlayedCount = track.PlayedCount
};
var userTracks = (from t in DbContext.Tracks
join ut in DbContext.UserTracks on t.Id equals ut.TrackId
where t.Id == track.Id
select ut).ToArray();
if (userTracks?.Any() == true)
{
result.Statistics.DislikedCount = userTracks.Count(x => x.IsDisliked ?? false);
result.Statistics.FavoriteCount = userTracks.Count(x => x.IsFavorite ?? false);
}
tsw.Stop();
timings.Add("stats", tsw.ElapsedMilliseconds);
}
if (includes.Contains("comments"))
{
tsw.Restart();
var trackComments = DbContext.Comments.Include(x => x.User).Where(x => x.TrackId == track.Id)
.OrderByDescending(x => x.CreatedDate).ToArray();
if (trackComments.Length > 0)
{
var comments = new List<Comment>();
var commentIds = trackComments.Select(x => x.Id).ToArray();
var userCommentReactions = (from cr in DbContext.CommentReactions
where commentIds.Contains(cr.CommentId)
select cr).ToArray();
foreach (var trackComment in trackComments)
{
var comment = trackComment.Adapt<Comment>();
comment.DatabaseId = trackComment.Id;
comment.User = UserList.FromDataUser(trackComment.User,
ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, trackComment.User.RoadieId));
comment.DislikedCount = userCommentReactions.Count(x =>
x.CommentId == trackComment.Id && x.ReactionValue == CommentReaction.Dislike);
comment.LikedCount = userCommentReactions.Count(x =>
x.CommentId == trackComment.Id && x.ReactionValue == CommentReaction.Like);
comments.Add(comment);
}
result.Comments = comments;
}
tsw.Stop();
timings.Add("comments", tsw.ElapsedMilliseconds);
}
}
sw.Stop();
Logger.LogInformation($"ByIdAction: Track `{ track }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]");
return new OperationResult<Track>
{
Data = result,
IsSuccess = result != null,
OperationTime = sw.ElapsedMilliseconds
};
}
}
}

View file

@ -50,7 +50,179 @@ namespace Roadie.Api.Services
LastFmHelper = lastFmHelper;
}
public async Task<OperationResult<User>> ById(User user, Guid id, IEnumerable<string> includes, bool isAccountSettingsEdit = false)
private async Task<OperationResult<bool>> SetBookmark(Library.Identity.User user, BookmarkType bookmarktype, int bookmarkTargetId, bool isBookmarked)
{
var bookmark = DbContext.Bookmarks.FirstOrDefault(x => x.BookmarkTargetId == bookmarkTargetId &&
x.BookmarkType == bookmarktype &&
x.UserId == user.Id);
if (!isBookmarked)
{
// Remove bookmark
if (bookmark != null)
{
DbContext.Bookmarks.Remove(bookmark);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
}
}
else
{
// Add bookmark
if (bookmark == null)
{
await DbContext.Bookmarks.AddAsync(new data.Bookmark
{
UserId = user.Id,
BookmarkTargetId = bookmarkTargetId,
BookmarkType = bookmarktype,
CreatedDate = DateTime.UtcNow,
Status = Statuses.Ok
}).ConfigureAwait(false);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
}
}
CacheManager.ClearRegion(user.CacheRegion);
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
private async Task<OperationResult<bool>> UpdateLastFMSessionKey(Library.Identity.User user, string token)
{
var lastFmSessionKeyResult = await LastFmHelper.GetSessionKeyForUserToken(token).ConfigureAwait(false);
if (!lastFmSessionKeyResult.IsSuccess)
{
return new OperationResult<bool>(false, $"Unable to Get LastFM Session Key For Token [{token}]");
}
// Check concurrency stamp
if (user.ConcurrencyStamp != user.ConcurrencyStamp)
{
return new OperationResult<bool>
{
Errors = new List<Exception> { new Exception("User data is stale.") }
};
}
user.LastFMSessionKey = lastFmSessionKeyResult.Data;
user.LastUpdated = DateTime.UtcNow;
user.ConcurrencyStamp = Guid.NewGuid().ToString();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(Library.Identity.User.CacheRegionUrn(user.RoadieId));
Logger.LogTrace($"User `{user}` Updated LastFm SessionKey");
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
private async Task<OperationResult<User>> UserByIdAction(Guid id, IEnumerable<string> includes)
{
var timings = new Dictionary<string, long>();
var tsw = new Stopwatch();
tsw.Restart();
var user = await GetUser(id).ConfigureAwait(false);
tsw.Stop();
timings.Add("getUser", tsw.ElapsedMilliseconds);
if (user == null)
{
return new OperationResult<User>(true, $"User Not Found [{id}]");
}
tsw.Restart();
var model = user.Adapt<User>();
model.MediumThumbnail = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "user", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
model.IsAdmin = user.UserRoles?.Any(x => x.Role?.NormalizedName == "ADMIN") ?? false;
model.IsEditor = model.IsAdmin || (user.UserRoles?.Any(x => x.Role?.NormalizedName == "EDITOR") ?? false);
tsw.Stop();
timings.Add("adapt", tsw.ElapsedMilliseconds);
if (includes?.Any() == true && includes.Contains("stats"))
{
tsw.Restart();
var userArtists = DbContext.UserArtists.Include(x => x.Artist).Where(x => x.UserId == user.Id).ToArray() ?? new data.UserArtist[0];
var userReleases = DbContext.UserReleases.Include(x => x.Release).Where(x => x.UserId == user.Id).ToArray() ?? new data.UserRelease[0];
var userTracks = DbContext.UserTracks.Include(x => x.Track).Where(x => x.UserId == user.Id).ToArray() ?? new data.UserTrack[0];
var mostPlayedArtist = await DbContext.MostPlayedArtist(user.Id).ConfigureAwait(false);
var mostPlayedRelease = await DbContext.MostPlayedRelease(user.Id).ConfigureAwait(false);
var lastPlayedTrack = await GetTrack((await DbContext.MostPlayedTrack(user.Id).ConfigureAwait(false))?.RoadieId ?? Guid.Empty).ConfigureAwait(false);
var mostPlayedTrack = await GetTrack((await DbContext.LastPlayedTrack(user.Id).ConfigureAwait(false))?.RoadieId ?? Guid.Empty).ConfigureAwait(false);
model.Statistics = new UserStatistics
{
LastPlayedTrack = lastPlayedTrack == null
? null
: models.TrackList.FromDataTrack(
MakeTrackPlayUrl(user, HttpContext.BaseUrl, lastPlayedTrack.RoadieId),
lastPlayedTrack,
lastPlayedTrack.ReleaseMedia.MediaNumber,
lastPlayedTrack.ReleaseMedia.Release,
lastPlayedTrack.ReleaseMedia.Release.Artist,
lastPlayedTrack.TrackArtist,
HttpContext.BaseUrl,
ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, lastPlayedTrack.RoadieId),
ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, lastPlayedTrack.ReleaseMedia.Release.RoadieId),
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, lastPlayedTrack.ReleaseMedia.Release.Artist.RoadieId),
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, lastPlayedTrack.TrackArtist == null
? null
: (Guid?)lastPlayedTrack.TrackArtist.RoadieId)),
MostPlayedArtist = mostPlayedArtist == null
? null
: models.ArtistList.FromDataArtist(mostPlayedArtist,
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedArtist.RoadieId)),
MostPlayedRelease = mostPlayedRelease == null
? null
: ReleaseList.FromDataRelease(mostPlayedRelease,
mostPlayedRelease.Artist,
HttpContext.BaseUrl,
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedRelease.Artist.RoadieId),
ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, mostPlayedRelease.RoadieId)),
MostPlayedTrack = mostPlayedTrack == null
? null
: models.TrackList.FromDataTrack(
MakeTrackPlayUrl(user, HttpContext.BaseUrl, mostPlayedTrack.RoadieId),
mostPlayedTrack,
mostPlayedTrack.ReleaseMedia.MediaNumber,
mostPlayedTrack.ReleaseMedia.Release,
mostPlayedTrack.ReleaseMedia.Release.Artist,
mostPlayedTrack.TrackArtist,
HttpContext.BaseUrl,
ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, mostPlayedTrack.RoadieId),
ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, mostPlayedTrack.ReleaseMedia.Release.RoadieId),
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedTrack.ReleaseMedia.Release.Artist.RoadieId),
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedTrack.TrackArtist == null
? null
: (Guid?)mostPlayedTrack.TrackArtist.RoadieId)),
RatedArtists = userArtists.Count(x => x.Rating > 0),
FavoritedArtists = userArtists.Count(x => x.IsFavorite ?? false),
DislikedArtists = userArtists.Count(x => x.IsDisliked ?? false),
RatedReleases = userReleases.Count(x => x.Rating > 0),
FavoritedReleases = userReleases.Count(x => x.IsFavorite ?? false),
DislikedReleases = userReleases.Count(x => x.IsDisliked ?? false),
RatedTracks = userTracks.Count(x => x.Rating > 0),
PlayedTracks = userTracks.Where(x => x.PlayedCount.HasValue).Select(x => x.PlayedCount).Sum(),
FavoritedTracks = userTracks.Count(x => x.IsFavorite ?? false),
DislikedTracks = userTracks.Count(x => x.IsDisliked ?? false)
};
tsw.Stop();
timings.Add("stats", tsw.ElapsedMilliseconds);
}
Logger.LogInformation($"ByIdAction: User `{ user }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]");
return new OperationResult<User>
{
IsSuccess = true,
Data = model
};
}
public async Task<OperationResult<User>> ByIdAsync(User user, Guid id, IEnumerable<string> includes, bool isAccountSettingsEdit = false)
{
if (isAccountSettingsEdit && user.UserId != id && !user.IsAdmin)
{
@ -61,7 +233,7 @@ namespace Roadie.Api.Services
}
var sw = Stopwatch.StartNew();
sw.Start();
var cacheKey = string.Format("urn:user_by_id_operation:{0}:{1}", id, isAccountSettingsEdit);
var cacheKey = $"urn:user_by_id_operation:{id}:{isAccountSettingsEdit}";
var result = await CacheManager.GetAsync(cacheKey, async () => await UserByIdAction(id, includes).ConfigureAwait(false), Library.Identity.User.CacheRegionUrn(id)).ConfigureAwait(false);
sw.Stop();
if (result?.Data != null)
@ -83,7 +255,27 @@ namespace Roadie.Api.Services
};
}
public Task<models.Pagination.PagedResult<UserList>> List(PagedRequest request)
public async Task<OperationResult<bool>> DeleteAllBookmarksAsync(User roadieUser)
{
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
if (user == null)
{
return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
}
DbContext.Bookmarks.RemoveRange(DbContext.Bookmarks.Where(x => x.UserId == user.Id));
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(user.CacheRegion);
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
public Task<models.Pagination.PagedResult<UserList>> ListAsync(PagedRequest request)
{
var sw = new Stopwatch();
sw.Start();
@ -162,27 +354,7 @@ namespace Roadie.Api.Services
});
}
public async Task<OperationResult<bool>> DeleteAllBookmarks(User roadieUser)
{
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
if (user == null)
{
return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
}
DbContext.Bookmarks.RemoveRange(DbContext.Bookmarks.Where(x => x.UserId == user.Id));
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(user.CacheRegion);
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
public async Task<OperationResult<bool>> SetArtistBookmark(Guid artistId, User roadieUser, bool isBookmarked)
public async Task<OperationResult<bool>> SetArtistBookmarkAsync(Guid artistId, User roadieUser, bool isBookmarked)
{
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
if (user == null)
@ -206,7 +378,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> SetArtistDisliked(Guid artistId, User roadieUser, bool isDisliked)
public async Task<OperationResult<bool>> SetArtistDislikedAsync(Guid artistId, User roadieUser, bool isDisliked)
{
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
if (user == null)
@ -216,7 +388,7 @@ namespace Roadie.Api.Services
return await ToggleArtistDisliked(artistId, user, isDisliked).ConfigureAwait(false);
}
public async Task<OperationResult<bool>> SetArtistFavorite(Guid artistId, User roadieUser, bool isFavorite)
public async Task<OperationResult<bool>> SetArtistFavoriteAsync(Guid artistId, User roadieUser, bool isFavorite)
{
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
if (user == null)
@ -226,7 +398,7 @@ namespace Roadie.Api.Services
return await ToggleArtistFavorite(artistId, user, isFavorite).ConfigureAwait(false);
}
public async Task<OperationResult<short>> SetArtistRating(Guid artistId, User roadieUser, short rating)
public async Task<OperationResult<short>> SetArtistRatingAsync(Guid artistId, User roadieUser, short rating)
{
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
if (user == null)
@ -236,7 +408,7 @@ namespace Roadie.Api.Services
return await SetArtistRating(artistId, user, rating).ConfigureAwait(false);
}
public async Task<OperationResult<bool>> SetCollectionBookmark(Guid collectionId, User roadieUser, bool isBookmarked)
public async Task<OperationResult<bool>> SetCollectionBookmarkAsync(Guid collectionId, User roadieUser, bool isBookmarked)
{
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
if (user == null)
@ -259,7 +431,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> SetLabelBookmark(Guid labelId, User roadieUser, bool isBookmarked)
public async Task<OperationResult<bool>> SetLabelBookmarkAsync(Guid labelId, User roadieUser, bool isBookmarked)
{
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
if (user == null)
@ -282,7 +454,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> SetPlaylistBookmark(Guid playlistId, User roadieUser,
public async Task<OperationResult<bool>> SetPlaylistBookmarkAsync(Guid playlistId, User roadieUser,
bool isBookmarked)
{
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
@ -306,7 +478,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> SetReleaseBookmark(Guid releaseid, User roadieUser, bool isBookmarked)
public async Task<OperationResult<bool>> SetReleaseBookmarkAsync(Guid releaseid, User roadieUser, bool isBookmarked)
{
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
if (user == null)
@ -329,7 +501,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> SetReleaseDisliked(Guid releaseId, User roadieUser, bool isDisliked)
public async Task<OperationResult<bool>> SetReleaseDislikedAsync(Guid releaseId, User roadieUser, bool isDisliked)
{
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
if (user == null)
@ -339,7 +511,7 @@ namespace Roadie.Api.Services
return await ToggleReleaseDisliked(releaseId, user, isDisliked).ConfigureAwait(false);
}
public async Task<OperationResult<bool>> SetReleaseFavorite(Guid releaseId, User roadieUser, bool isFavorite)
public async Task<OperationResult<bool>> SetReleaseFavoriteAsync(Guid releaseId, User roadieUser, bool isFavorite)
{
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
if (user == null)
@ -349,7 +521,7 @@ namespace Roadie.Api.Services
return await ToggleReleaseFavorite(releaseId, user, isFavorite).ConfigureAwait(false);
}
public async Task<OperationResult<short>> SetReleaseRating(Guid releaseId, User roadieUser, short rating)
public async Task<OperationResult<short>> SetReleaseRatingAsync(Guid releaseId, User roadieUser, short rating)
{
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
if (user == null)
@ -359,7 +531,7 @@ namespace Roadie.Api.Services
return await SetReleaseRating(releaseId, user, rating).ConfigureAwait(false);
}
public async Task<OperationResult<bool>> SetTrackBookmark(Guid trackId, User roadieUser, bool isBookmarked)
public async Task<OperationResult<bool>> SetTrackBookmarkAsync(Guid trackId, User roadieUser, bool isBookmarked)
{
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
if (user == null)
@ -382,7 +554,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> SetTrackDisliked(Guid trackId, User roadieUser, bool isDisliked)
public async Task<OperationResult<bool>> SetTrackDislikedAsync(Guid trackId, User roadieUser, bool isDisliked)
{
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
if (user == null)
@ -392,7 +564,7 @@ namespace Roadie.Api.Services
return await ToggleTrackDisliked(trackId, user, isDisliked).ConfigureAwait(false);
}
public async Task<OperationResult<bool>> SetTrackFavorite(Guid trackId, User roadieUser, bool isFavorite)
public async Task<OperationResult<bool>> SetTrackFavoriteAsync(Guid trackId, User roadieUser, bool isFavorite)
{
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
if (user == null)
@ -402,13 +574,13 @@ namespace Roadie.Api.Services
return await ToggleTrackFavorite(trackId, user, isFavorite).ConfigureAwait(false);
}
public async Task<OperationResult<short>> SetTrackRating(Guid trackId, User roadieUser, short rating)
public async Task<OperationResult<short>> SetTrackRatingAsync(Guid trackId, User roadieUser, short rating)
{
var timings = new Dictionary<string, long>();
var sw = Stopwatch.StartNew();
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
sw.Stop();
timings.Add("GetUser", sw.ElapsedMilliseconds);
timings.Add(nameof(GetUser), sw.ElapsedMilliseconds);
if (user == null)
{
@ -417,7 +589,7 @@ namespace Roadie.Api.Services
sw.Start();
var result = await SetTrackRating(trackId, user, rating).ConfigureAwait(false);
sw.Stop();
timings.Add("SetTrackRating", sw.ElapsedMilliseconds);
timings.Add(nameof(SetTrackRatingAsync), sw.ElapsedMilliseconds);
result.AdditionalData.Add("Timing", sw.ElapsedMilliseconds);
Logger.LogTrace(
@ -425,7 +597,7 @@ namespace Roadie.Api.Services
return result;
}
public async Task<OperationResult<bool>> UpdateIntegrationGrant(Guid userId, string integrationName, string token)
public async Task<OperationResult<bool>> UpdateIntegrationGrantAsync(Guid userId, string integrationName, string token)
{
var user = DbContext.Users.FirstOrDefault(x => x.RoadieId == userId);
if (user == null)
@ -439,12 +611,12 @@ namespace Roadie.Api.Services
throw new NotImplementedException();
}
public async Task<OperationResult<bool>> UpdateProfile(User userPerformingUpdate, User userBeingUpdatedModel)
public async Task<OperationResult<bool>> UpdateProfileAsync(User userPerformingUpdate, User userBeingUpdatedModel)
{
var user = DbContext.Users.FirstOrDefault(x => x.RoadieId == userBeingUpdatedModel.UserId);
if (user == null)
{
return new OperationResult<bool>(true, string.Format("User Not Found [{0}]", userBeingUpdatedModel.UserId));
return new OperationResult<bool>(true, $"User Not Found [{userBeingUpdatedModel.UserId}]");
}
if (user.Id != userPerformingUpdate.Id && !userPerformingUpdate.IsAdmin)
{
@ -556,175 +728,5 @@ namespace Roadie.Api.Services
Data = true
};
}
private async Task<OperationResult<bool>> SetBookmark(Library.Identity.User user, BookmarkType bookmarktype, int bookmarkTargetId, bool isBookmarked)
{
var bookmark = DbContext.Bookmarks.FirstOrDefault(x => x.BookmarkTargetId == bookmarkTargetId &&
x.BookmarkType == bookmarktype &&
x.UserId == user.Id);
if (!isBookmarked)
{
// Remove bookmark
if (bookmark != null)
{
DbContext.Bookmarks.Remove(bookmark);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
}
}
else
{
// Add bookmark
if (bookmark == null)
{
await DbContext.Bookmarks.AddAsync(new data.Bookmark
{
UserId = user.Id,
BookmarkTargetId = bookmarkTargetId,
BookmarkType = bookmarktype,
CreatedDate = DateTime.UtcNow,
Status = Statuses.Ok
}).ConfigureAwait(false);
await DbContext.SaveChangesAsync().ConfigureAwait(false);
}
}
CacheManager.ClearRegion(user.CacheRegion);
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
private async Task<OperationResult<bool>> UpdateLastFMSessionKey(Library.Identity.User user, string token)
{
var lastFmSessionKeyResult = await LastFmHelper.GetSessionKeyForUserToken(token).ConfigureAwait(false);
if (!lastFmSessionKeyResult.IsSuccess)
return new OperationResult<bool>(false, $"Unable to Get LastFM Session Key For Token [{token}]");
// Check concurrency stamp
if (user.ConcurrencyStamp != user.ConcurrencyStamp)
{
return new OperationResult<bool>
{
Errors = new List<Exception> { new Exception("User data is stale.") }
};
}
user.LastFMSessionKey = lastFmSessionKeyResult.Data;
user.LastUpdated = DateTime.UtcNow;
user.ConcurrencyStamp = Guid.NewGuid().ToString();
await DbContext.SaveChangesAsync().ConfigureAwait(false);
CacheManager.ClearRegion(Library.Identity.User.CacheRegionUrn(user.RoadieId));
Logger.LogTrace($"User `{user}` Updated LastFm SessionKey");
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
private async Task<OperationResult<User>> UserByIdAction(Guid id, IEnumerable<string> includes)
{
var timings = new Dictionary<string, long>();
var tsw = new Stopwatch();
tsw.Restart();
var user = await GetUser(id).ConfigureAwait(false);
tsw.Stop();
timings.Add("getUser", tsw.ElapsedMilliseconds);
if (user == null)
{
return new OperationResult<User>(true, string.Format("User Not Found [{0}]", id));
}
tsw.Restart();
var model = user.Adapt<User>();
model.MediumThumbnail = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "user", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
model.IsAdmin = user.UserRoles?.Any(x => x.Role?.NormalizedName == "ADMIN") ?? false;
model.IsEditor = model.IsAdmin || (user.UserRoles?.Any(x => x.Role?.NormalizedName == "EDITOR") ?? false);
tsw.Stop();
timings.Add("adapt", tsw.ElapsedMilliseconds);
if (includes?.Any() == true && includes.Contains("stats"))
{
tsw.Restart();
var userArtists = DbContext.UserArtists.Include(x => x.Artist).Where(x => x.UserId == user.Id).ToArray() ?? new data.UserArtist[0];
var userReleases = DbContext.UserReleases.Include(x => x.Release).Where(x => x.UserId == user.Id).ToArray() ?? new data.UserRelease[0];
var userTracks = DbContext.UserTracks.Include(x => x.Track).Where(x => x.UserId == user.Id).ToArray() ?? new data.UserTrack[0];
var mostPlayedArtist = await DbContext.MostPlayedArtist(user.Id).ConfigureAwait(false);
var mostPlayedRelease = await DbContext.MostPlayedRelease(user.Id).ConfigureAwait(false);
var lastPlayedTrack = await GetTrack((await DbContext.MostPlayedTrack(user.Id).ConfigureAwait(false))?.RoadieId ?? Guid.Empty).ConfigureAwait(false);
var mostPlayedTrack = await GetTrack((await DbContext.LastPlayedTrack(user.Id).ConfigureAwait(false))?.RoadieId ?? Guid.Empty).ConfigureAwait(false);
model.Statistics = new UserStatistics
{
LastPlayedTrack = lastPlayedTrack == null
? null
: models.TrackList.FromDataTrack(
MakeTrackPlayUrl(user, HttpContext.BaseUrl, lastPlayedTrack.RoadieId),
lastPlayedTrack,
lastPlayedTrack.ReleaseMedia.MediaNumber,
lastPlayedTrack.ReleaseMedia.Release,
lastPlayedTrack.ReleaseMedia.Release.Artist,
lastPlayedTrack.TrackArtist,
HttpContext.BaseUrl,
ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, lastPlayedTrack.RoadieId),
ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, lastPlayedTrack.ReleaseMedia.Release.RoadieId),
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, lastPlayedTrack.ReleaseMedia.Release.Artist.RoadieId),
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, lastPlayedTrack.TrackArtist == null
? null
: (Guid?)lastPlayedTrack.TrackArtist.RoadieId)),
MostPlayedArtist = mostPlayedArtist == null
? null
: models.ArtistList.FromDataArtist(mostPlayedArtist,
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedArtist.RoadieId)),
MostPlayedRelease = mostPlayedRelease == null
? null
: ReleaseList.FromDataRelease(mostPlayedRelease,
mostPlayedRelease.Artist,
HttpContext.BaseUrl,
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedRelease.Artist.RoadieId),
ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, mostPlayedRelease.RoadieId)),
MostPlayedTrack = mostPlayedTrack == null
? null
: models.TrackList.FromDataTrack(
MakeTrackPlayUrl(user, HttpContext.BaseUrl, mostPlayedTrack.RoadieId),
mostPlayedTrack,
mostPlayedTrack.ReleaseMedia.MediaNumber,
mostPlayedTrack.ReleaseMedia.Release,
mostPlayedTrack.ReleaseMedia.Release.Artist,
mostPlayedTrack.TrackArtist,
HttpContext.BaseUrl,
ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, mostPlayedTrack.RoadieId),
ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, mostPlayedTrack.ReleaseMedia.Release.RoadieId),
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedTrack.ReleaseMedia.Release.Artist.RoadieId),
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedTrack.TrackArtist == null
? null
: (Guid?)mostPlayedTrack.TrackArtist.RoadieId)),
RatedArtists = userArtists.Count(x => x.Rating > 0),
FavoritedArtists = userArtists.Count(x => x.IsFavorite ?? false),
DislikedArtists = userArtists.Count(x => x.IsDisliked ?? false),
RatedReleases = userReleases.Count(x => x.Rating > 0),
FavoritedReleases = userReleases.Count(x => x.IsFavorite ?? false),
DislikedReleases = userReleases.Count(x => x.IsDisliked ?? false),
RatedTracks = userTracks.Count(x => x.Rating > 0),
PlayedTracks = userTracks.Where(x => x.PlayedCount.HasValue).Select(x => x.PlayedCount).Sum(),
FavoritedTracks = userTracks.Count(x => x.IsFavorite ?? false),
DislikedTracks = userTracks.Count(x => x.IsDisliked ?? false)
};
tsw.Stop();
timings.Add("stats", tsw.ElapsedMilliseconds);
}
Logger.LogInformation($"ByIdAction: User `{ user }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]");
return new OperationResult<User>
{
IsSuccess = true,
Data = model
};
}
}
}

View file

@ -28,11 +28,6 @@ namespace Roadie.Api.Controllers
[AllowAnonymous]
public class AccountController : ControllerBase
{
private readonly ILogger<AccountController> Logger;
private readonly SignInManager<User> SignInManager;
private readonly ITokenService TokenService;
private readonly UserManager<User> UserManager;
private string _baseUrl;
private IAdminService AdminService { get; }
@ -43,10 +38,17 @@ namespace Roadie.Api.Controllers
if (_baseUrl == null)
{
var scheme = Request.Scheme;
if (RoadieSettings.UseSSLBehindProxy) scheme = "https";
if (RoadieSettings.UseSSLBehindProxy)
{
scheme = "https";
}
var host = Request.Host;
if (!string.IsNullOrEmpty(RoadieSettings.BehindProxyHost))
{
host = new HostString(RoadieSettings.BehindProxyHost);
}
_baseUrl = $"{scheme}://{host}";
}
@ -62,9 +64,22 @@ namespace Roadie.Api.Controllers
private IRoadieSettings RoadieSettings { get; }
public AccountController(IAdminService adminService, UserManager<User> userManager, SignInManager<User> signInManager,
IConfiguration configuration, ILogger<AccountController> logger, ITokenService tokenService,
ICacheManager cacheManager, IEmailSender emailSender, IHttpContext httpContext)
private string _baseUrl;
private readonly ILogger<AccountController> Logger;
private readonly SignInManager<User> SignInManager;
private readonly ITokenService TokenService;
private readonly UserManager<User> UserManager;
public AccountController(
IAdminService adminService,
UserManager<User> userManager,
SignInManager<User> signInManager,
IConfiguration configuration,
ILogger<AccountController> logger,
ITokenService tokenService,
ICacheManager cacheManager,
IEmailSender emailSender,
IHttpContext httpContext)
{
UserManager = userManager;
SignInManager = signInManager;
@ -73,7 +88,7 @@ namespace Roadie.Api.Controllers
CacheManager = cacheManager;
RoadieSettings = new RoadieSettings();
configuration.GetSection("RoadieSettings").Bind(RoadieSettings);
configuration.GetSection(nameof(RoadieSettings)).Bind(RoadieSettings);
AdminService = adminService;
EmailSender = emailSender;
RoadieHttpContext = httpContext;
@ -101,38 +116,41 @@ namespace Roadie.Api.Controllers
[HttpPost]
[Route("token")]
public async Task<IActionResult> CreateToken([FromBody] LoginModel model)
public async Task<IActionResult> CreateTokenAsync([FromBody] LoginModel model)
{
if (ModelState.IsValid)
{
try
{
// Login user
var loginResult = await SignInManager.PasswordSignInAsync(model.Username, model.Password, false, false);
var loginResult = await SignInManager.PasswordSignInAsync(model.Username, model.Password, false, false).ConfigureAwait(false);
if (!loginResult.Succeeded)
{
return BadRequest();
}
var user = await UserManager.FindByNameAsync(model.Username);
var user = await UserManager.FindByNameAsync(model.Username).ConfigureAwait(false);
var now = DateTime.UtcNow;
user.LastLogin = now;
user.LastUpdated = now;
await UserManager.UpdateAsync(user);
var t = await TokenService.GenerateToken(user, UserManager);
await UserManager.UpdateAsync(user).ConfigureAwait(false);
var t = await TokenService.GenerateTokenAsync(user, UserManager).ConfigureAwait(false);
Logger.LogTrace($"Successfully authenticated User [{model.Username}]");
if (!user.EmailConfirmed)
{
try
{
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user);
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user).ConfigureAwait(false);
var callbackUrl = $"{BaseUrl}/auth/confirmemail?userId={user.Id}&code={code}";
await EmailSender.SendEmailAsync(user.Email,
$"Confirm your {RoadieSettings.SiteName} email",
$"Please confirm your {RoadieSettings.SiteName} account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
$"Please confirm your {RoadieSettings.SiteName} account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.")
.ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.LogError(ex, "Error sending confirmation Email");
}
}
CacheManager.ClearRegion(EntityControllerBase.ControllerCacheRegionUrn);
var avatarUrl = $"{RoadieHttpContext.ImageBaseUrl}/user/{user.RoadieId}/{RoadieSettings.ThumbnailImageSize.Width}/{RoadieSettings.ThumbnailImageSize.Height}";
@ -163,7 +181,7 @@ namespace Roadie.Api.Controllers
[Authorize]
[HttpPost]
[Route("refreshtoken")]
public async Task<IActionResult> RefreshToken()
public async Task<IActionResult> RefreshTokenAsync()
{
try
{
@ -172,8 +190,8 @@ namespace Roadie.Api.Controllers
.FirstOrDefault();
if (!string.IsNullOrWhiteSpace(username))
{
var user = await UserManager.FindByNameAsync(username);
return Ok(await TokenService.GenerateToken(user, UserManager));
var user = await UserManager.FindByNameAsync(username).ConfigureAwait(false);
return Ok(await TokenService.GenerateTokenAsync(user, UserManager).ConfigureAwait(false));
}
ModelState.AddModelError("Authentication", "Authentication failed!");
}
@ -187,7 +205,7 @@ namespace Roadie.Api.Controllers
[HttpPost]
[Route("register")]
[AllowAnonymous]
public async Task<IActionResult> Register([FromBody] RegisterModel registerModel)
public async Task<IActionResult> RegisterAsync([FromBody] RegisterModel registerModel)
{
try
{
@ -205,7 +223,7 @@ namespace Roadie.Api.Controllers
if (RoadieSettings.UseRegistrationTokens)
{
var tokenValidation = await AdminService.ValidateInviteToken(registerModel.InviteToken);
var tokenValidation = await AdminService.ValidateInviteTokenAsync(registerModel.InviteToken).ConfigureAwait(false);
if (!tokenValidation.IsSuccess)
{
Logger.LogTrace("Invalid Invite Token");
@ -213,42 +231,46 @@ namespace Roadie.Api.Controllers
}
}
var existinUserByUsername = await UserManager.FindByNameAsync(registerModel.Username);
var existinUserByUsername = await UserManager.FindByNameAsync(registerModel.Username).ConfigureAwait(false);
if (existinUserByUsername != null)
{
return StatusCode((int)HttpStatusCode.BadRequest, new { Title = "User With Username Already Exists!" });
}
var existingUserByEmail = await UserManager.FindByEmailAsync(registerModel.Email);
var existingUserByEmail = await UserManager.FindByEmailAsync(registerModel.Email).ConfigureAwait(false);
if (existingUserByEmail != null)
{
return StatusCode((int)HttpStatusCode.BadRequest, new { Title = "User With Email Already Exists!" });
}
var identityResult = await UserManager.CreateAsync(user, registerModel.Password);
var identityResult = await UserManager.CreateAsync(user, registerModel.Password).ConfigureAwait(false);
if (identityResult.Succeeded)
{
if (user.Id == 1) await AdminService.DoInitialSetup(user, UserManager);
if (user.Id == 1)
{
await AdminService.DoInitialSetupAsync(user, UserManager).ConfigureAwait(false);
}
try
{
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user);
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user).ConfigureAwait(false);
var callbackUrl = $"{BaseUrl}/auth/confirmemail?userId={user.Id}&code={code}";
await EmailSender.SendEmailAsync(user.Email, $"Confirm your {RoadieSettings.SiteName} email",
$"Please confirm your {RoadieSettings.SiteName} account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
$"Please confirm your {RoadieSettings.SiteName} account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.").ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.LogError(ex, $"Error Sending Register Email to [{registerModel.Email}]");
}
await SignInManager.SignInAsync(user, false);
var t = await TokenService.GenerateToken(user, UserManager);
await SignInManager.SignInAsync(user, false).ConfigureAwait(false);
var t = await TokenService.GenerateTokenAsync(user, UserManager).ConfigureAwait(false);
Logger.LogTrace($"Successfully created and authenticated User [{registerModel.Username}]");
CacheManager.ClearRegion(EntityControllerBase.ControllerCacheRegionUrn);
var avatarUrl = $"{RoadieHttpContext.ImageBaseUrl}/user/{user.RoadieId}/{RoadieSettings.ThumbnailImageSize.Width}/{RoadieSettings.ThumbnailImageSize.Height}";
if (registerModel.InviteToken.HasValue)
{
await AdminService.UpdateInviteTokenUsed(registerModel.InviteToken);
await AdminService.UpdateInviteTokenUsedAsync(registerModel.InviteToken).ConfigureAwait(false);
}
return Ok(new
{
@ -286,22 +308,22 @@ namespace Roadie.Api.Controllers
}
[HttpPost("resetpassword")]
public async Task<IActionResult> ResetPassword([FromBody] ResetPasswordModel resetPasswordModel)
public async Task<IActionResult> ResetPasswordAsync([FromBody] ResetPasswordModel resetPasswordModel)
{
try
{
if (ModelState.IsValid)
{
var user = await UserManager.FindByNameAsync(resetPasswordModel.Username);
var user = await UserManager.FindByNameAsync(resetPasswordModel.Username).ConfigureAwait(false);
var token = Encoding.ASCII.GetString(WebEncoders.Base64UrlDecode(resetPasswordModel.Token));
var identityResult = await UserManager.ResetPasswordAsync(user, token, resetPasswordModel.Password);
var identityResult = await UserManager.ResetPasswordAsync(user, token, resetPasswordModel.Password).ConfigureAwait(false);
if (identityResult.Succeeded)
{
CacheManager.ClearRegion(EntityControllerBase.ControllerCacheRegionUrn);
await SignInManager.SignInAsync(user, false);
await SignInManager.SignInAsync(user, false).ConfigureAwait(false);
var avatarUrl =
$"{RoadieHttpContext.ImageBaseUrl}/user/{user.RoadieId}/{RoadieSettings.ThumbnailImageSize.Width}/{RoadieSettings.ThumbnailImageSize.Height}";
var t = await TokenService.GenerateToken(user, UserManager);
var t = await TokenService.GenerateTokenAsync(user, UserManager).ConfigureAwait(false);
return Ok(new
{
Username = user.UserName,
@ -329,22 +351,22 @@ namespace Roadie.Api.Controllers
}
[HttpGet("sendpasswordresetemail")]
public async Task<IActionResult> SendPasswordResetEmail(string username, string callbackUrl)
public async Task<IActionResult> SendPasswordResetEmailAsync(string username, string callbackUrl)
{
try
{
var user = await UserManager.FindByNameAsync(username);
var user = await UserManager.FindByNameAsync(username).ConfigureAwait(false);
if (user == null)
{
Logger.LogError($"Unable to find user by username [{username}]");
return StatusCode(500);
}
var token = await UserManager.GeneratePasswordResetTokenAsync(user);
callbackUrl = callbackUrl + "?username=" + username + "&token=" +
WebEncoders.Base64UrlEncode(Encoding.ASCII.GetBytes(token));
var token = await UserManager.GeneratePasswordResetTokenAsync(user).ConfigureAwait(false);
callbackUrl = $"{callbackUrl}?username={username}&token={WebEncoders.Base64UrlEncode(Encoding.ASCII.GetBytes(token))}";
await EmailSender.SendEmailAsync(user.Email, $"Reset your {RoadieSettings.SiteName} password",
$"A request has been made to reset your password for your {RoadieSettings.SiteName} account. To proceed <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>click here</a>.");
$"A request has been made to reset your password for your {RoadieSettings.SiteName} account. To proceed <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>click here</a>.")
.ConfigureAwait(false);
Logger.LogTrace("User [{0}] Email [{1}] Requested Password Reset Callback [{2}]", username,
user.Email, callbackUrl);
return Ok();

View file

@ -21,8 +21,12 @@ namespace Roadie.Api.Controllers
{
private IAdminService AdminService { get; }
public AdminController(IAdminService adminService, ILogger<AdminController> logger, ICacheManager cacheManager,
UserManager<User> userManager, IRoadieSettings roadieSettings)
public AdminController(
IAdminService adminService,
ILogger<AdminController> logger,
ICacheManager cacheManager,
UserManager<User> userManager,
IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
{
Logger = logger;
@ -42,7 +46,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(200)]
public async Task<IActionResult> DeleteArtist(Guid id, bool? doDeleteFile)
{
var result = await AdminService.DeleteArtist(await UserManager.GetUserAsync(User), id, doDeleteFile ?? true);
var result = await AdminService.DeleteArtistAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, doDeleteFile ?? true).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)
@ -58,7 +62,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(200)]
public async Task<IActionResult> DeleteArtistReleases(Guid id)
{
var result = await AdminService.DeleteArtistReleases(await UserManager.GetUserAsync(User), id);
var result = await AdminService.DeleteArtistReleasesAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)
@ -74,39 +78,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(200)]
public async Task<IActionResult> DeleteArtistSecondaryImage(Guid id, int index)
{
var result = await AdminService.DeleteArtistSecondaryImage(await UserManager.GetUserAsync(User), id, index);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)
{
return StatusCode((int)HttpStatusCode.BadRequest, result.Messages);
}
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
[HttpPost("delete/release/{id}")]
[ProducesResponseType(200)]
public async Task<IActionResult> DeleteRelease(Guid id, bool? doDeleteFiles)
{
var result = await AdminService.DeleteRelease(await UserManager.GetUserAsync(User), id, doDeleteFiles);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)
{
return StatusCode((int)HttpStatusCode.BadRequest, result.Messages);
}
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
[HttpPost("delete/label/{id}")]
[ProducesResponseType(200)]
public async Task<IActionResult> DeleteLabel(Guid id)
{
var result = await AdminService.DeleteLabel(await UserManager.GetUserAsync(User), id);
var result = await AdminService.DeleteArtistSecondaryImageAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, index).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)
@ -122,7 +94,39 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(200)]
public async Task<IActionResult> DeleteGenre(Guid id)
{
var result = await AdminService.DeleteGenre(await UserManager.GetUserAsync(User), id);
var result = await AdminService.DeleteGenreAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)
{
return StatusCode((int)HttpStatusCode.BadRequest, result.Messages);
}
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
[HttpPost("delete/label/{id}")]
[ProducesResponseType(200)]
public async Task<IActionResult> DeleteLabel(Guid id)
{
var result = await AdminService.DeleteLabelAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)
{
return StatusCode((int)HttpStatusCode.BadRequest, result.Messages);
}
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
[HttpPost("delete/release/{id}")]
[ProducesResponseType(200)]
public async Task<IActionResult> DeleteRelease(Guid id, bool? doDeleteFiles)
{
var result = await AdminService.DeleteReleaseAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, doDeleteFiles).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)
@ -139,16 +143,20 @@ namespace Roadie.Api.Controllers
public async Task<IActionResult> DeleteReleaseSecondaryImage(Guid id, int index)
{
var result =
await AdminService.DeleteReleaseSecondaryImage(await UserManager.GetUserAsync(User), id, index);
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
await AdminService.DeleteReleaseSecondaryImageAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, index).ConfigureAwait(false);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
[HttpPost("delete/tracks")]
[HttpPost("delete/track/{id}")]
[ProducesResponseType(200)]
public async Task<IActionResult> DeleteTracks([FromBody]IEnumerable<Guid> ids, bool? doDeleteFile)
public async Task<IActionResult> DeleteTrack(Guid id, bool? doDeleteFile)
{
var result = await AdminService.DeleteTracks(await UserManager.GetUserAsync(User), ids, doDeleteFile);
var result = await AdminService.DeleteTracksAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), new Guid[1] { id }, doDeleteFile).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)
@ -160,11 +168,11 @@ namespace Roadie.Api.Controllers
return Ok(result);
}
[HttpPost("delete/track/{id}")]
[HttpPost("delete/tracks")]
[ProducesResponseType(200)]
public async Task<IActionResult> DeleteTrack(Guid id, bool? doDeleteFile)
public async Task<IActionResult> DeleteTracks([FromBody] IEnumerable<Guid> ids, bool? doDeleteFile)
{
var result = await AdminService.DeleteTracks(await UserManager.GetUserAsync(User), new Guid[1] { id }, doDeleteFile);
var result = await AdminService.DeleteTracksAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), ids, doDeleteFile).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)
@ -180,7 +188,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(200)]
public async Task<IActionResult> DeleteUser(Guid id)
{
var result = await AdminService.DeleteUser(await UserManager.GetUserAsync(User), id);
var result = await AdminService.DeleteUserAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)
@ -196,7 +204,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(200)]
public async Task<IActionResult> MissingCollectionReleases()
{
var result = await AdminService.MissingCollectionReleases(await UserManager.GetUserAsync(User));
var result = await AdminService.MissingCollectionReleasesAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false)).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)
@ -212,7 +220,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(200)]
public async Task<IActionResult> ScanAllCollections()
{
var result = await AdminService.ScanAllCollections(await UserManager.GetUserAsync(User).ConfigureAwait(false)).ConfigureAwait(false);
var result = await AdminService.ScanAllCollectionsAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false)).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)
@ -228,7 +236,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(200)]
public async Task<IActionResult> ScanArtist(Guid id)
{
var result = await AdminService.ScanArtist(await UserManager.GetUserAsync(User), id);
var result = await AdminService.ScanArtistAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)
@ -244,7 +252,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(200)]
public async Task<IActionResult> ScanArtists(IEnumerable<Guid> ids)
{
var result = await AdminService.ScanArtists(await UserManager.GetUserAsync(User), ids);
var result = await AdminService.ScanArtistsAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), ids).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)
@ -260,7 +268,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(200)]
public async Task<IActionResult> ScanCollection(Guid id, bool doPurgeFirst = false)
{
var result = await AdminService.ScanCollection(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, doPurgeFirst: doPurgeFirst).ConfigureAwait(false);
var result = await AdminService.ScanCollectionAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, doPurgeFirst: doPurgeFirst).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)
@ -276,7 +284,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(200)]
public async Task<IActionResult> ScanInbound()
{
var result = await AdminService.ScanInboundFolder(await UserManager.GetUserAsync(User));
var result = await AdminService.ScanInboundFolderAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false)).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)
@ -292,7 +300,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(200)]
public async Task<IActionResult> ScanLibrary()
{
var result = await AdminService.ScanLibraryFolder(await UserManager.GetUserAsync(User));
var result = await AdminService.ScanLibraryFolderAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false)).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)
@ -308,7 +316,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(200)]
public async Task<IActionResult> ScanRelease(Guid id)
{
var result = await AdminService.ScanRelease(await UserManager.GetUserAsync(User), id);
var result = await AdminService.ScanReleaseAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)
@ -324,7 +332,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(200)]
public async Task<IActionResult> ScanReleases(IEnumerable<Guid> ids)
{
var result = await AdminService.ScanReleases(await UserManager.GetUserAsync(User), ids);
var result = await AdminService.ScanReleasesAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), ids).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.Messages?.Any() ?? false)

View file

@ -25,8 +25,12 @@ namespace Roadie.Api.Controllers
{
private IArtistService ArtistService { get; }
public ArtistController(IArtistService artistService, ILogger<ArtistController> logger, ICacheManager cacheManager,
UserManager<User> userManager, IRoadieSettings roadieSettings)
public ArtistController(
IArtistService artistService,
ILogger<ArtistController> logger,
ICacheManager cacheManager,
UserManager<User> userManager,
IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
{
Logger = logger;
@ -41,13 +45,17 @@ namespace Roadie.Api.Controllers
{
var user = await CurrentUserModel().ConfigureAwait(false);
var result =
await ArtistService.ById(user, id, (inc ?? models.Artist.DefaultIncludes).ToLower().Split(",")).ConfigureAwait(false);
await ArtistService.ByIdAsync(user, id, (inc ?? models.Artist.DefaultIncludes).ToLower().Split(",")).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
}
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
@ -57,11 +65,15 @@ namespace Roadie.Api.Controllers
{
try
{
PagedResult<models.ArtistList> result = await ArtistService.List(await CurrentUserModel().ConfigureAwait(false),
PagedResult<models.ArtistList> result = await ArtistService.ListAsync(await CurrentUserModel().ConfigureAwait(false),
request,
doRandomize ?? false,
false).ConfigureAwait(false);
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
catch (UnauthorizedAccessException)
@ -82,7 +94,7 @@ namespace Roadie.Api.Controllers
[Authorize(Policy = "Editor")]
public async Task<IActionResult> MergeArtists(Guid artistToMergeId, Guid artistToMergeIntoId)
{
var result = await ArtistService.MergeArtists(await UserManager.GetUserAsync(User).ConfigureAwait(false), artistToMergeId, artistToMergeIntoId).ConfigureAwait(false);
var result = await ArtistService.MergeArtistsAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), artistToMergeId, artistToMergeIntoId).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
@ -110,8 +122,12 @@ namespace Roadie.Api.Controllers
public async Task<IActionResult> SetArtistImageByUrl(Guid id, string imageUrl)
{
var result =
await ArtistService.SetReleaseImageByUrl(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, HttpUtility.UrlDecode(imageUrl)).ConfigureAwait(false);
if (result?.IsNotFoundResult != false) return NotFound();
await ArtistService.SetReleaseImageByUrlAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, HttpUtility.UrlDecode(imageUrl)).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
}
if (!result.IsSuccess)
{
if (result.IsAccessDeniedResult)
@ -137,7 +153,7 @@ namespace Roadie.Api.Controllers
{
return BadRequest(ModelState);
}
var result = await ArtistService.UpdateArtist(await UserManager.GetUserAsync(User).ConfigureAwait(false), artist).ConfigureAwait(false);
var result = await ArtistService.UpdateArtistAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), artist).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
@ -163,7 +179,7 @@ namespace Roadie.Api.Controllers
[Authorize(Policy = "Editor")]
public async Task<IActionResult> UploadImage(Guid id, IFormFile file)
{
var result = await ArtistService.UploadArtistImage(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, file).ConfigureAwait(false);
var result = await ArtistService.UploadArtistImageAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, file).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();

View file

@ -21,8 +21,12 @@ namespace Roadie.Api.Controllers
{
private IBookmarkService BookmarkService { get; }
public BookmarkController(IBookmarkService bookmarkService, ILogger<BookmarkController> logger, ICacheManager cacheManager,
UserManager<User> userManager, IRoadieSettings roadieSettings)
public BookmarkController(
IBookmarkService bookmarkService,
ILogger<BookmarkController> logger,
ICacheManager cacheManager,
UserManager<User> userManager,
IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
{
Logger = logger;
@ -35,9 +39,12 @@ namespace Roadie.Api.Controllers
{
try
{
var result = await BookmarkService.List(await CurrentUserModel(),
request);
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
var result = await BookmarkService.ListAsync(await CurrentUserModel().ConfigureAwait(false), request).ConfigureAwait(false);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
catch (UnauthorizedAccessException)

View file

@ -23,9 +23,12 @@ namespace Roadie.Api.Controllers
{
private ICollectionService CollectionService { get; }
public CollectionController(ICollectionService collectionService, ILogger<CollectionController> logger,
ICacheManager cacheManager,
UserManager<User> userManager, IRoadieSettings roadieSettings)
public CollectionController(
ICollectionService collectionService,
ILogger<CollectionController> logger,
ICacheManager cacheManager,
UserManager<User> userManager,
IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
{
Logger = logger;
@ -37,7 +40,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> Add()
{
var result = CollectionService.Add(await CurrentUserModel());
var result = CollectionService.Add(await CurrentUserModel().ConfigureAwait(false));
if (!result.IsSuccess)
{
if (result.IsAccessDeniedResult)
@ -59,7 +62,7 @@ namespace Roadie.Api.Controllers
[Authorize(Policy = "Editor")]
public async Task<IActionResult> DeleteCollection(Guid id)
{
var result = await CollectionService.DeleteCollection(await CurrentUserModel(), id);
var result = await CollectionService.DeleteCollectionAsync(await CurrentUserModel().ConfigureAwait(false), id).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
@ -84,9 +87,13 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> Get(Guid id, string inc = null)
{
var result = await CollectionService.ById(await CurrentUserModel(), id,
(inc ?? Collection.DefaultIncludes).ToLower().Split(","));
if (result == null || result.IsNotFoundResult) return NotFound();
var result = await CollectionService.ByIdAsync(await CurrentUserModel().ConfigureAwait(false), id,
(inc ?? Collection.DefaultIncludes).ToLower().Split(",")).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
}
if (!result.IsSuccess)
{
if (result.IsAccessDeniedResult)
@ -108,8 +115,12 @@ namespace Roadie.Api.Controllers
{
try
{
var result = await CollectionService.List(await CurrentUserModel(), request);
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
var result = await CollectionService.ListAsync(await CurrentUserModel().ConfigureAwait(false), request).ConfigureAwait(false);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
catch (UnauthorizedAccessException)
@ -134,7 +145,7 @@ namespace Roadie.Api.Controllers
{
return BadRequest(ModelState);
}
var result = await CollectionService.UpdateCollection(await CurrentUserModel(), collection);
var result = await CollectionService.UpdateCollectionAsync(await CurrentUserModel().ConfigureAwait(false), collection).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();

View file

@ -23,9 +23,12 @@ namespace Roadie.Api.Controllers
{
private ICommentService CommentService { get; }
public CommentController(ILogger<CommentController> logger, ICacheManager cacheManager,
UserManager<User> userManager,
IRoadieSettings roadieSettings, ICommentService commentService)
public CommentController(
ILogger<CommentController> logger,
ICacheManager cacheManager,
UserManager<User> userManager,
IRoadieSettings roadieSettings,
ICommentService commentService)
: base(cacheManager, roadieSettings, userManager)
{
Logger = logger;
@ -37,9 +40,17 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> AddNewArtistComment(Guid id, models.Comment model)
{
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
var result = await CommentService.AddNewArtistComment(await CurrentUserModel(), id, model.Cmt);
if (result == null || result.IsNotFoundResult) return NotFound();
if (string.IsNullOrEmpty(model.Cmt))
{
return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
}
var result = await CommentService.AddNewArtistCommentAsync(await CurrentUserModel().ConfigureAwait(false), id, model.Cmt).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
}
if (!result.IsSuccess)
{
if (result.IsAccessDeniedResult)
@ -60,9 +71,17 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> AddNewCollectionComment(Guid id, models.Comment model)
{
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
var result = await CommentService.AddNewCollectionComment(await CurrentUserModel(), id, model.Cmt);
if (result == null || result.IsNotFoundResult) return NotFound();
if (string.IsNullOrEmpty(model.Cmt))
{
return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
}
var result = await CommentService.AddNewCollectionCommentAsync(await CurrentUserModel().ConfigureAwait(false), id, model.Cmt).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
}
if (!result.IsSuccess)
{
if (result.IsAccessDeniedResult)
@ -83,9 +102,17 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> AddNewGenreComment(Guid id, models.Comment model)
{
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
var result = await CommentService.AddNewGenreComment(await CurrentUserModel(), id, model.Cmt);
if (result == null || result.IsNotFoundResult) return NotFound();
if (string.IsNullOrEmpty(model.Cmt))
{
return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
}
var result = await CommentService.AddNewGenreCommentAsync(await CurrentUserModel().ConfigureAwait(false), id, model.Cmt).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
}
if (!result.IsSuccess)
{
if (result.IsAccessDeniedResult)
@ -106,9 +133,17 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> AddNewLabelComment(Guid id, models.Comment model)
{
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
var result = await CommentService.AddNewLabelComment(await CurrentUserModel(), id, model.Cmt);
if (result == null || result.IsNotFoundResult) return NotFound();
if (string.IsNullOrEmpty(model.Cmt))
{
return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
}
var result = await CommentService.AddNewLabelCommentAsync(await CurrentUserModel().ConfigureAwait(false), id, model.Cmt).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
}
if (!result.IsSuccess)
{
if (result.IsAccessDeniedResult)
@ -129,9 +164,17 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> AddNewPlaylistComment(Guid id, models.Comment model)
{
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
var result = await CommentService.AddNewPlaylistComment(await CurrentUserModel(), id, model.Cmt);
if (result == null || result.IsNotFoundResult) return NotFound();
if (string.IsNullOrEmpty(model.Cmt))
{
return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
}
var result = await CommentService.AddNewPlaylistCommentAsync(await CurrentUserModel().ConfigureAwait(false), id, model.Cmt).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
}
if (!result.IsSuccess)
{
if (result.IsAccessDeniedResult)
@ -152,9 +195,17 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> AddNewReleaseComment(Guid id, models.Comment model)
{
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
var result = await CommentService.AddNewReleaseComment(await CurrentUserModel(), id, model.Cmt);
if (result == null || result.IsNotFoundResult) return NotFound();
if (string.IsNullOrEmpty(model.Cmt))
{
return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
}
var result = await CommentService.AddNewReleaseCommentAsync(await CurrentUserModel().ConfigureAwait(false), id, model.Cmt).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
}
if (!result.IsSuccess)
{
if (result.IsAccessDeniedResult)
@ -175,9 +226,17 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> AddNewTrackComment(Guid id, models.Comment model)
{
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
var result = await CommentService.AddNewTrackComment(await CurrentUserModel(), id, model.Cmt);
if (result == null || result.IsNotFoundResult) return NotFound();
if (string.IsNullOrEmpty(model.Cmt))
{
return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
}
var result = await CommentService.AddNewTrackCommentAsync(await CurrentUserModel().ConfigureAwait(false), id, model.Cmt).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
}
if (!result.IsSuccess)
{
if (result.IsAccessDeniedResult)
@ -198,8 +257,12 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> DeleteComment(Guid id)
{
var result = await CommentService.DeleteComment(await CurrentUserModel(), id);
if (result == null || result.IsNotFoundResult) return NotFound();
var result = await CommentService.DeleteCommentAsync(await CurrentUserModel().ConfigureAwait(false), id).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
}
if (!result.IsSuccess)
{
if (result.IsAccessDeniedResult)
@ -220,8 +283,12 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> SetCommentReaction(Guid id, CommentReaction reaction)
{
var result = await CommentService.SetCommentReaction(await CurrentUserModel(), id, reaction);
if (result == null || result.IsNotFoundResult) return NotFound();
var result = await CommentService.SetCommentReactionAsync(await CurrentUserModel().ConfigureAwait(false), id, reaction).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
}
if (!result.IsSuccess)
{
if (result.IsAccessDeniedResult)

View file

@ -22,8 +22,6 @@ namespace Roadie.Api.Controllers
{
public const string ControllerCacheRegionUrn = "urn:controller_cache";
private models.User _currentUser;
protected ICacheManager CacheManager { get; }
protected ILogger Logger { get; set; }
@ -32,8 +30,12 @@ namespace Roadie.Api.Controllers
protected UserManager<User> UserManager { get; }
public EntityControllerBase(ICacheManager cacheManager, IRoadieSettings roadieSettings,
UserManager<User> userManager)
private models.User _currentUser;
protected EntityControllerBase(
ICacheManager cacheManager,
IRoadieSettings roadieSettings,
UserManager<User> userManager)
{
CacheManager = cacheManager;
RoadieSettings = roadieSettings;
@ -48,8 +50,8 @@ namespace Roadie.Api.Controllers
{
_currentUser = await CacheManager.GetAsync($"urn:controller_user:{User.Identity.Name}", async () =>
{
return UserModelForUser(await UserManager.GetUserAsync(User));
}, ControllerCacheRegionUrn);
return UserModelForUser(await UserManager.GetUserAsync(User).ConfigureAwait(false));
}, ControllerCacheRegionUrn).ConfigureAwait(false);
}
}
if (_currentUser == null)
@ -67,7 +69,7 @@ namespace Roadie.Api.Controllers
var tsw = new Stopwatch();
tsw.Restart();
var user = currentUser ?? await CurrentUserModel();
var user = currentUser ?? await CurrentUserModel().ConfigureAwait(false); ;
var track = trackService.StreamCheckAndInfo(user, id);
if (track == null || (track?.IsNotFoundResult ?? false))
{
@ -86,18 +88,23 @@ namespace Roadie.Api.Controllers
timings.Add("TrackService.StreamCheckAndInfo", tsw.ElapsedMilliseconds);
tsw.Restart();
var info = await trackService.TrackStreamInfo(id,
var info = await trackService.TrackStreamInfoAsync(id,
TrackService.DetermineByteStartFromHeaders(Request.Headers),
TrackService.DetermineByteEndFromHeaders(Request.Headers, track.Data.FileSize),
user);
user).ConfigureAwait(false);
if (!info?.IsSuccess ?? false || info?.Data == null)
{
if (info?.Errors != null && (info?.Errors.Any() ?? false))
{
Logger.LogCritical(
$"StreamTrack: TrackStreamInfo Invalid For TrackId [{id}] OperationResult Errors [{string.Join('|', info?.Errors ?? new Exception[0])}], For User [{currentUser}]");
$"StreamTrack: TrackStreamInfo Invalid For TrackId [{id}] OperationResult Errors [{string.Join('|', info?.Errors ?? new Exception[0])}], For User [{currentUser}]");
}
else
{
Logger.LogCritical(
$"StreamTrack: TrackStreamInfo Invalid For TrackId [{id}] OperationResult Messages [{string.Join('|', info?.Messages ?? new string[0])}], For User [{currentUser}]");
$"StreamTrack: TrackStreamInfo Invalid For TrackId [{id}] OperationResult Messages [{string.Join('|', info?.Messages ?? new string[0])}], For User [{currentUser}]");
}
return NotFound("Unknown TrackId");
}
@ -129,7 +136,7 @@ namespace Roadie.Api.Controllers
}
Response.Headers.Add("Expires", info.Data.Expires);
await Response.Body.WriteAsync(info.Data.Bytes, 0, info.Data.Bytes.Length);
await Response.Body.WriteAsync(info.Data.Bytes, 0, info.Data.Bytes.Length).ConfigureAwait(false);
var scrobble = new ScrobbleInfo
{
@ -137,7 +144,7 @@ namespace Roadie.Api.Controllers
TimePlayed = DateTime.UtcNow,
TrackId = id
};
await playActivityService.NowPlaying(user, scrobble);
await playActivityService.NowPlayingAsync(user, scrobble).ConfigureAwait(false);
sw.Stop();
Logger.LogTrace($"StreamTrack ElapsedTime [{sw.ElapsedMilliseconds}], Timings [{JsonConvert.SerializeObject(timings)}], StreamInfo `{info?.Data}`");
return new EmptyResult();
@ -145,7 +152,11 @@ namespace Roadie.Api.Controllers
protected models.User UserModelForUser(User user)
{
if (user == null) return null;
if (user == null)
{
return null;
}
var result = user.Adapt<models.User>();
result.IsAdmin = User.IsInRole("Admin");
result.IsEditor = User.IsInRole("Editor") || result.IsAdmin;

View file

@ -25,8 +25,12 @@ namespace Roadie.Api.Controllers
{
private IGenreService GenreService { get; }
public GenreController(IGenreService genreService, ILogger<GenreController> logger, ICacheManager cacheManager,
UserManager<User> userManager, IRoadieSettings roadieSettings)
public GenreController(
IGenreService genreService,
ILogger<GenreController> logger,
ICacheManager cacheManager,
UserManager<User> userManager,
IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
{
Logger = logger;
@ -38,9 +42,17 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> Get(Guid id, string inc = null)
{
var result = await GenreService.ById(await CurrentUserModel(), id, (inc ?? models.Genre.DefaultIncludes).ToLower().Split(","));
if (result == null || result.IsNotFoundResult) return NotFound();
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
var result = await GenreService.ByIdAsync(await CurrentUserModel().ConfigureAwait(false), id, (inc ?? models.Genre.DefaultIncludes).ToLower().Split(",")).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
}
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
@ -50,10 +62,14 @@ namespace Roadie.Api.Controllers
{
try
{
var result = await GenreService.List(await CurrentUserModel(),
var result = await GenreService.ListAsync(await CurrentUserModel().ConfigureAwait(false),
request,
doRandomize);
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
doRandomize).ConfigureAwait(false);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
catch (UnauthorizedAccessException)
@ -74,7 +90,7 @@ namespace Roadie.Api.Controllers
[Authorize(Policy = "Editor")]
public async Task<IActionResult> SetGenreImageByUrl(Guid id, string imageUrl)
{
var result = await GenreService.SetGenreImageByUrl(await CurrentUserModel(), id, HttpUtility.UrlDecode(imageUrl));
var result = await GenreService.SetGenreImageByUrlAsync(await CurrentUserModel().ConfigureAwait(false), id, HttpUtility.UrlDecode(imageUrl)).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
@ -94,29 +110,6 @@ namespace Roadie.Api.Controllers
return Ok(result);
}
[HttpPost("uploadImage/{id}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
[Authorize(Policy = "Editor")]
public async Task<IActionResult> UploadImage(Guid id, IFormFile file)
{
var result = await GenreService.UploadGenreImage(await CurrentUserModel(), id, file);
if (result == null || result.IsNotFoundResult) return NotFound();
if (!result.IsSuccess)
{
if (result.IsAccessDeniedResult)
{
return StatusCode((int)HttpStatusCode.Forbidden);
}
if (result.Messages?.Any() ?? false)
{
return StatusCode((int)HttpStatusCode.BadRequest, result.Messages);
}
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
[HttpPost("edit")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
@ -127,7 +120,7 @@ namespace Roadie.Api.Controllers
{
return BadRequest(ModelState);
}
var result = await GenreService.UpdateGenre(await CurrentUserModel(), genre);
var result = await GenreService.UpdateGenreAsync(await CurrentUserModel().ConfigureAwait(false), genre).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
@ -142,5 +135,32 @@ namespace Roadie.Api.Controllers
}
return Ok(result);
}
[HttpPost("uploadImage/{id}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
[Authorize(Policy = "Editor")]
public async Task<IActionResult> UploadImage(Guid id, IFormFile file)
{
var result = await GenreService.UploadGenreImageAsync(await CurrentUserModel().ConfigureAwait(false), id, file).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
}
if (!result.IsSuccess)
{
if (result.IsAccessDeniedResult)
{
return StatusCode((int)HttpStatusCode.Forbidden);
}
if (result.Messages?.Any() ?? false)
{
return StatusCode((int)HttpStatusCode.BadRequest, result.Messages);
}
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
}
}

View file

@ -20,20 +20,26 @@ namespace Roadie.Api.Controllers
{
private IImageService ImageService { get; }
public ImageController(IImageService imageService, ILogger<ImageController> logger, ICacheManager cacheManager,
UserManager<User> userManager, IRoadieSettings roadieSettings)
public ImageController(
IImageService imageService,
ILogger<ImageController> logger,
ICacheManager cacheManager,
UserManager<User> userManager,
IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
{
Logger = logger;
ImageService = imageService;
}
private IActionResult MakeFileResult(byte[] bytes, string fileName, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue eTag) => File(bytes, contentType, fileName, lastModified, eTag);
[HttpGet("artist/{id}/{width:int?}/{height:int?}/{cacheBuster?}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> ArtistImage(Guid id, int? width, int? height)
{
var result = await ImageService.ArtistImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
var result = await ImageService.ArtistImageAsync(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
@ -50,7 +56,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> ArtistSecondaryImage(Guid id, int imageId, int? width, int? height)
{
var result = await ImageService.ArtistSecondaryImage(id, imageId, width, height).ConfigureAwait(false);
var result = await ImageService.ArtistSecondaryImageAsync(id, imageId, width, height).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
@ -67,24 +73,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> CollectionImage(Guid id, int? width, int? height)
{
var result = await ImageService.CollectionImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
}
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return MakeFileResult(result.Data.Bytes, $"{id}.jpg", result.ContentType, result.LastModified, result.ETag);
}
[HttpGet("label/{id}/{width:int?}/{height:int?}/{cacheBuster?}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> LabelImage(Guid id, int? width, int? height)
{
var result = await ImageService.LabelImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
var result = await ImageService.CollectionImageAsync(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
@ -101,7 +90,24 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> GenreImage(Guid id, int? width, int? height)
{
var result = await ImageService.GenreImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
var result = await ImageService.GenreImageAsync(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
}
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return MakeFileResult(result.Data.Bytes, $"{id}.jpg", result.ContentType, result.LastModified, result.ETag);
}
[HttpGet("label/{id}/{width:int?}/{height:int?}/{cacheBuster?}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> LabelImage(Guid id, int? width, int? height)
{
var result = await ImageService.LabelImageAsync(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
@ -118,7 +124,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> PlaylistImage(Guid id, int? width, int? height)
{
var result = await ImageService.PlaylistImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
var result = await ImageService.PlaylistImageAsync(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
@ -135,7 +141,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> ReleaseImage(Guid id, int? width, int? height)
{
var result = await ImageService.ReleaseImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
var result = await ImageService.ReleaseImageAsync(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
@ -152,7 +158,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> ReleaseSecondaryImage(Guid id, int imageId, int? width, int? height)
{
var result = await ImageService.ReleaseSecondaryImage(id, imageId, width ?? RoadieSettings.MaximumImageSize.Width, height ?? RoadieSettings.MaximumImageSize.Height).ConfigureAwait(false);
var result = await ImageService.ReleaseSecondaryImageAsync(id, imageId, width ?? RoadieSettings.MaximumImageSize.Width, height ?? RoadieSettings.MaximumImageSize.Height).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
@ -169,24 +175,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> SearchForArtistImage(string query, int? resultsCount)
{
var result = await ImageService.Search(query, resultsCount ?? 10).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
}
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
[HttpPost("search/label/{query}/{resultsCount:int?}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> SearchForLabelImage(string query, int? resultsCount)
{
var result = await ImageService.Search(query, resultsCount ?? 10).ConfigureAwait(false);
var result = await ImageService.SearchAsync(query, resultsCount ?? 10).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
@ -203,9 +192,34 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> SearchForGenreImage(string query, int? resultsCount)
{
var result = await ImageService.Search(query, resultsCount ?? 10).ConfigureAwait(false);
if (result?.IsNotFoundResult != false) return NotFound();
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
var result = await ImageService.SearchAsync(query, resultsCount ?? 10).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
}
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
[HttpPost("search/label/{query}/{resultsCount:int?}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> SearchForLabelImage(string query, int? resultsCount)
{
var result = await ImageService.SearchAsync(query, resultsCount ?? 10).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
}
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
@ -214,9 +228,17 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> SearchForReleaseCover(string query, int? resultsCount)
{
var result = await ImageService.Search(query, resultsCount ?? 10).ConfigureAwait(false);
if (result?.IsNotFoundResult != false) return NotFound();
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
var result = await ImageService.SearchAsync(query, resultsCount ?? 10).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
}
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
@ -225,7 +247,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> TrackImage(Guid id, int? width, int? height)
{
var result = await ImageService.TrackImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
var result = await ImageService.TrackImageAsync(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
@ -237,8 +259,6 @@ namespace Roadie.Api.Controllers
return MakeFileResult(result.Data.Bytes, $"{id}.jpg", result.ContentType, result.LastModified, result.ETag);
}
private IActionResult MakeFileResult(byte[] bytes, string fileName, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue eTag) => File(bytes, contentType, fileName, lastModified, eTag);
/// <summary>
/// NOTE that user images/avatars are GIF not JPG this is so it looks better in the menus/applications and allows for animated avatars.
/// </summary>
@ -247,7 +267,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> UserImage(Guid id, int? width, int? height)
{
var result = await ImageService.UserImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
var result = await ImageService.UserImageAsync(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();

View file

@ -25,8 +25,12 @@ namespace Roadie.Api.Controllers
{
private ILabelService LabelService { get; }
public LabelController(ILabelService labelService, ILogger<LabelController> logger, ICacheManager cacheManager,
UserManager<User> userManager, IRoadieSettings roadieSettings)
public LabelController(
ILabelService labelService,
ILogger<LabelController> logger,
ICacheManager cacheManager,
UserManager<User> userManager,
IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
{
Logger = logger;
@ -38,7 +42,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> Get(Guid id, string inc = null)
{
var result = await LabelService.ById(await CurrentUserModel(), id, (inc ?? models.Label.DefaultIncludes).ToLower().Split(","));
var result = await LabelService.ByIdAsync(await CurrentUserModel().ConfigureAwait(false), id, (inc ?? models.Label.DefaultIncludes).ToLower().Split(",")).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
@ -56,10 +60,14 @@ namespace Roadie.Api.Controllers
{
try
{
var result = await LabelService.List(await CurrentUserModel(),
var result = await LabelService.ListAsync(await CurrentUserModel().ConfigureAwait(false),
request,
doRandomize);
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
doRandomize).ConfigureAwait(false);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
catch (UnauthorizedAccessException)
@ -80,7 +88,7 @@ namespace Roadie.Api.Controllers
[Authorize(Policy = "Editor")]
public async Task<IActionResult> MergeLabels(Guid labelToMergeId, Guid labelToMergeIntoId)
{
var result = await LabelService.MergeLabelsIntoLabel(await UserManager.GetUserAsync(User), labelToMergeIntoId, new Guid[1] { labelToMergeId });
var result = await LabelService.MergeLabelsIntoLabelAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), labelToMergeIntoId, new Guid[1] { labelToMergeId }).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
@ -98,7 +106,7 @@ namespace Roadie.Api.Controllers
[Authorize(Policy = "Editor")]
public async Task<IActionResult> SetLabelImageByUrl(Guid id, string imageUrl)
{
var result = await LabelService.SetLabelImageByUrl(await CurrentUserModel(), id, HttpUtility.UrlDecode(imageUrl));
var result = await LabelService.SetLabelImageByUrlAsync(await CurrentUserModel().ConfigureAwait(false), id, HttpUtility.UrlDecode(imageUrl)).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
@ -120,7 +128,7 @@ namespace Roadie.Api.Controllers
{
return BadRequest(ModelState);
}
var result = await LabelService.UpdateLabel(await CurrentUserModel(), label);
var result = await LabelService.UpdateLabelAsync(await CurrentUserModel().ConfigureAwait(false), label).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
@ -142,9 +150,17 @@ namespace Roadie.Api.Controllers
[Authorize(Policy = "Editor")]
public async Task<IActionResult> UploadImage(Guid id, IFormFile file)
{
var result = await LabelService.UploadLabelImage(await CurrentUserModel(), id, file);
if (result == null || result.IsNotFoundResult) return NotFound();
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
var result = await LabelService.UploadLabelImageAsync(await CurrentUserModel().ConfigureAwait(false), id, file).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
}
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
}

View file

@ -20,8 +20,12 @@ namespace Roadie.Api.Controllers
{
private ILookupService LookupService { get; }
public LookupController(ILabelService labelService, ILogger<LookupController> logger, ICacheManager cacheManager,
UserManager<User> userManager, ILookupService lookupService, IRoadieSettings roadieSettings)
public LookupController(
ILogger<LookupController> logger,
ICacheManager cacheManager,
UserManager<User> userManager,
ILookupService lookupService,
IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
{
Logger = logger;
@ -33,8 +37,12 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> ArtistTypes(Guid id, string inc = null)
{
var result = await LookupService.ArtistTypes();
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
var result = await LookupService.ArtistTypesAsync().ConfigureAwait(false);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
@ -43,8 +51,12 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> BandStatus(Guid id, string inc = null)
{
var result = await LookupService.BandStatus();
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
var result = await LookupService.BandStatusAsync().ConfigureAwait(false);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
@ -53,8 +65,12 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> BookmarkTypes(Guid id, string inc = null)
{
var result = await LookupService.BookmarkTypes();
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
var result = await LookupService.BookmarkTypesAsync().ConfigureAwait(false);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
@ -63,58 +79,12 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> CollectionTypes(Guid id, string inc = null)
{
var result = await LookupService.CollectionTypes();
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
return Ok(result);
}
var result = await LookupService.CollectionTypesAsync().ConfigureAwait(false);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
[HttpGet("libraryStatus")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> LibraryStatus(Guid id, string inc = null)
{
var result = await LookupService.LibraryStatus();
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
return Ok(result);
}
[HttpGet("queMessageTypes")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> QueMessageTypes(Guid id, string inc = null)
{
var result = await LookupService.QueMessageTypes();
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
return Ok(result);
}
[HttpGet("releaseTypes")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> ReleaseTypes(Guid id, string inc = null)
{
var result = await LookupService.ReleaseTypes();
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
return Ok(result);
}
[HttpGet("requestStatus")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> RequestStatus(Guid id, string inc = null)
{
var result = await LookupService.RequestStatus();
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
return Ok(result);
}
[HttpGet("status")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> Status(Guid id, string inc = null)
{
var result = await LookupService.Status();
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
return Ok(result);
}
@ -123,8 +93,82 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> CreditCategories(Guid id, string inc = null)
{
var result = await LookupService.Status();
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
var result = await LookupService.StatusAsync().ConfigureAwait(false);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
[HttpGet("libraryStatus")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> LibraryStatus(Guid id, string inc = null)
{
var result = await LookupService.LibraryStatusAsync().ConfigureAwait(false);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
[HttpGet("queMessageTypes")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> QueMessageTypes(Guid id, string inc = null)
{
var result = await LookupService.QueMessageTypesAsync().ConfigureAwait(false);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
[HttpGet("releaseTypes")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> ReleaseTypes(Guid id, string inc = null)
{
var result = await LookupService.ReleaseTypesAsync().ConfigureAwait(false);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
[HttpGet("requestStatus")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> RequestStatus(Guid id, string inc = null)
{
var result = await LookupService.RequestStatusAsync().ConfigureAwait(false);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
[HttpGet("status")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
public async Task<IActionResult> Status(Guid id, string inc = null)
{
var result = await LookupService.StatusAsync().ConfigureAwait(false);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
}

View file

@ -22,9 +22,12 @@ namespace Roadie.Api.Controllers
{
private IPlayActivityService PlayActivityService { get; }
public PlayActivityController(IPlayActivityService playActivityService, ILogger<PlayActivityController> logger,
ICacheManager cacheManager,
UserManager<User> userManager, IRoadieSettings roadieSettings)
public PlayActivityController(
IPlayActivityService playActivityService,
ILogger<PlayActivityController> logger,
ICacheManager cacheManager,
UserManager<User> userManager,
IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
{
Logger = logger;
@ -35,8 +38,12 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(200)]
public async Task<IActionResult> PlayActivity([FromQuery] PagedRequest request)
{
var result = await PlayActivityService.List(request).ConfigureAwait(false);
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
var result = await PlayActivityService.ListAsync(request).ConfigureAwait(false);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
@ -45,11 +52,19 @@ namespace Roadie.Api.Controllers
public async Task<IActionResult> PlayActivity([FromQuery] PagedRequest request, Guid userId)
{
var user = UserManager.Users.FirstOrDefault(x => x.RoadieId == userId);
if (user == null) return NotFound();
var result = await PlayActivityService.List(request,
UserModelForUser(user)).ConfigureAwait(false);
if (user == null)
{
return NotFound();
}
var result = await PlayActivityService.ListAsync(request,
UserModelForUser(user)).ConfigureAwait(false);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
return Ok(result);
}
}

View file

@ -28,8 +28,13 @@ namespace Roadie.Api.Controllers
private ITrackService TrackService { get; }
public PlayController(ITrackService trackService, IReleaseService releaseService, IPlayActivityService playActivityService,
ILogger<PlayController> logger, ICacheManager cacheManager, UserManager<User> userManager,
public PlayController(
ITrackService trackService,
IReleaseService releaseService,
IPlayActivityService playActivityService,
ILogger<PlayController> logger,
ICacheManager cacheManager,
UserManager<User> userManager,
IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
{
@ -43,8 +48,12 @@ namespace Roadie.Api.Controllers
public async Task<FileResult> M3uForRelease(Guid id)
{
var user = await CurrentUserModel().ConfigureAwait(false);
var release = await ReleaseService.ById(user, id, new string[1] { "tracks" }).ConfigureAwait(false);
if (release?.IsNotFoundResult != false) Response.StatusCode = (int)HttpStatusCode.NotFound;
var release = await ReleaseService.ByIdAsync(user, id, new string[1] { "tracks" }).ConfigureAwait(false);
if (release?.IsNotFoundResult != false)
{
Response.StatusCode = (int)HttpStatusCode.NotFound;
}
var m3u = M3uHelper.M3uContentForTracks(release.Data.Medias.SelectMany(x => x.Tracks));
return File(Encoding.Default.GetBytes(m3u), "audio/mpeg-url");
}
@ -53,12 +62,20 @@ namespace Roadie.Api.Controllers
public async Task<FileResult> M3uForTrack(Guid id)
{
var user = await CurrentUserModel().ConfigureAwait(false);
var track = await TrackService.ById(user, id, null).ConfigureAwait(false);
if (track?.IsNotFoundResult != false) Response.StatusCode = (int)HttpStatusCode.NotFound;
var release = await ReleaseService.ById(user, track.Data.Release.Id, new string[1] { "tracks" }).ConfigureAwait(false);
if (release?.IsNotFoundResult != false) Response.StatusCode = (int)HttpStatusCode.NotFound;
var track = await TrackService.ByIdAsyncAsync(user, id, null).ConfigureAwait(false);
if (track?.IsNotFoundResult != false)
{
Response.StatusCode = (int)HttpStatusCode.NotFound;
}
var release = await ReleaseService.ByIdAsync(user, track.Data.Release.Id, new string[1] { "tracks" }).ConfigureAwait(false);
if (release?.IsNotFoundResult != false)
{
Response.StatusCode = (int)HttpStatusCode.NotFound;
}
var m3u = M3uHelper.M3uContentForTracks(
release.Data.Medias.SelectMany(x => x.Tracks).Where(x => x.Id == id));
release.Data.Medias.SelectMany(x => x.Tracks).Where(x => x.Id == id));
return File(Encoding.Default.GetBytes(m3u), "audio/mpeg-url");
}
@ -71,14 +88,22 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> Scrobble(Guid id, string startedPlaying, bool isRandom)
{
var result = await PlayActivityService.Scrobble(await CurrentUserModel().ConfigureAwait(false), new ScrobbleInfo
var result = await PlayActivityService.ScrobbleAsync(await CurrentUserModel().ConfigureAwait(false), new ScrobbleInfo
{
TrackId = id,
TimePlayed = SafeParser.ToDateTime(startedPlaying) ?? DateTime.UtcNow,
IsRandomizedScrobble = isRandom
}).ConfigureAwait(false);
if (result?.IsNotFoundResult != false) return NotFound();
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
if (result?.IsNotFoundResult != false)
{
return NotFound();
}
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
@ -90,7 +115,11 @@ namespace Roadie.Api.Controllers
public async Task<IActionResult> StreamTrack(int userId, string trackPlayToken, Guid id)
{
var user = UserManager.Users.FirstOrDefault(x => x.Id == userId);
if (user == null) return StatusCode((int)HttpStatusCode.Unauthorized);
if (user == null)
{
return StatusCode((int)HttpStatusCode.Unauthorized);
}
if (!ServiceBase.ConfirmTrackPlayToken(user, id, trackPlayToken))
{
return StatusCode((int)HttpStatusCode.Unauthorized);

View file

@ -23,8 +23,12 @@ namespace Roadie.Api.Controllers
{
private IPlaylistService PlaylistService { get; }
public PlaylistController(IPlaylistService playlistService, ILogger<PlaylistController> logger, ICacheManager cacheManager,
UserManager<User> userManager, IRoadieSettings roadieSettings)
public PlaylistController(
IPlaylistService playlistService,
ILogger<PlaylistController> logger,
ICacheManager cacheManager,
UserManager<User> userManager,
IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
{
Logger = logger;
@ -36,7 +40,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> AddNewPlaylist([FromBody] Playlist model)
{
var result = await PlaylistService.AddNewPlaylist(await CurrentUserModel(), model);
var result = await PlaylistService.AddNewPlaylistAsync(await CurrentUserModel().ConfigureAwait(false), model).ConfigureAwait(false);
if (!result.IsSuccess)
{
if (result.IsAccessDeniedResult)
@ -57,7 +61,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> DeletePlaylist(Guid id)
{
var result = await PlaylistService.DeletePlaylist(await CurrentUserModel(), id);
var result = await PlaylistService.DeletePlaylistAsync(await CurrentUserModel().ConfigureAwait(false), id).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
@ -82,7 +86,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> Get(Guid id, string inc = null)
{
var result = await PlaylistService.ById(await CurrentUserModel(), id, (inc ?? Playlist.DefaultIncludes).ToLower().Split(","));
var result = await PlaylistService.ByIdAsync(await CurrentUserModel().ConfigureAwait(false), id, (inc ?? Playlist.DefaultIncludes).ToLower().Split(",")).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
@ -106,9 +110,12 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(200)]
public async Task<IActionResult> List([FromQuery] PagedRequest request, string inc)
{
var result = await PlaylistService.List(roadieUser: await CurrentUserModel(),
request: request);
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
var result = await PlaylistService.ListAsync(roadieUser: await CurrentUserModel().ConfigureAwait(false), request: request).ConfigureAwait(false);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
@ -117,8 +124,12 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> Update(Playlist playlist)
{
if (!ModelState.IsValid) return BadRequest(ModelState);
var result = await PlaylistService.UpdatePlaylist(await CurrentUserModel(), playlist);
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var result = await PlaylistService.UpdatePlaylistAsync(await CurrentUserModel().ConfigureAwait(false), playlist).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();
@ -143,7 +154,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> UpdateTracks(PlaylistTrackModifyRequest request)
{
var result = await PlaylistService.UpdatePlaylistTracks(await CurrentUserModel(), request);
var result = await PlaylistService.UpdatePlaylistTracksAsync(await CurrentUserModel().ConfigureAwait(false), request).ConfigureAwait(false);
if (result == null || result.IsNotFoundResult)
{
return NotFound();

View file

@ -25,8 +25,12 @@ namespace Roadie.Api.Controllers
{
private IReleaseService ReleaseService { get; }
public ReleaseController(IReleaseService releaseService, ILogger<ReleaseController> logger, ICacheManager cacheManager,
UserManager<User> userManager, IRoadieSettings roadieSettings)
public ReleaseController(
IReleaseService releaseService,
ILogger<ReleaseController> logger,
ICacheManager cacheManager,
UserManager<User> userManager,
IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
{
Logger = logger;
@ -38,7 +42,7 @@ namespace Roadie.Api.Controllers
[ProducesResponseType(404)]
public async Task<IActionResult> Get(Guid id, string inc = null)
{
var result = await ReleaseService.ById(await CurrentUserModel().ConfigureAwait(false), id, (inc ?? Release.DefaultIncludes).ToLower().Split(",")).ConfigureAwait(false);
var result = await ReleaseService.ByIdAsync(await CurrentUserModel().ConfigureAwait(false), id, (inc ?? Release.DefaultIncludes).ToLower().Split(",")).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
@ -56,11 +60,15 @@ namespace Roadie.Api.Controllers
{
try
{
var result = await ReleaseService.List(await CurrentUserModel().ConfigureAwait(false),
var result = await ReleaseService.ListAsync(await CurrentUserModel().ConfigureAwait(false),
request,
doRandomize ?? false,
(inc ?? Release.DefaultListIncludes).ToLower().Split(",")).ConfigureAwait(false);
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
if (!result.IsSuccess)
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
return Ok(result);
}
catch (UnauthorizedAccessException)
@ -81,8 +89,12 @@ namespace Roadie.Api.Controllers
[Authorize(Policy = "Editor")]
public async Task<IActionResult> MergeReleases(Guid releaseToMergeId, Guid releaseToMergeIntoId, bool addAsMedia)
{
var result = await ReleaseService.MergeReleases(await UserManager.GetUserAsync(User).ConfigureAwait(false), releaseToMergeId, releaseToMergeIntoId, addAsMedia).ConfigureAwait(false);
if (result?.IsNotFoundResult != false) return NotFound();
var result = await ReleaseService.MergeReleasesAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), releaseToMergeId, releaseToMergeIntoId, addAsMedia).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
}
if (!result.IsSuccess)
{
if (result.IsAccessDeniedResult)
@ -104,8 +116,12 @@ namespace Roadie.Api.Controllers
[Authorize(Policy = "Editor")]
public async Task<IActionResult> SetReleaseImageByUrl(Guid id, string imageUrl)
{
var result = await ReleaseService.SetReleaseImageByUrl(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, HttpUtility.UrlDecode(imageUrl)).ConfigureAwait(false);
if (result?.IsNotFoundResult != false) return NotFound();
var result = await ReleaseService.SetReleaseImageByUrlAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, HttpUtility.UrlDecode(imageUrl)).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
}
if (!result.IsSuccess)
{
if (result.IsAccessDeniedResult)
@ -131,7 +147,7 @@ namespace Roadie.Api.Controllers
{
return BadRequest(ModelState);
}
var result = await ReleaseService.UpdateRelease(await UserManager.GetUserAsync(User).ConfigureAwait(false), release).ConfigureAwait(false);
var result = await ReleaseService.UpdateReleaseAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), release).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
@ -153,8 +169,12 @@ namespace Roadie.Api.Controllers
[Authorize(Policy = "Editor")]
public async Task<IActionResult> UploadImage(Guid id, IFormFile file)
{
var result = await ReleaseService.UploadReleaseImage(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, file).ConfigureAwait(false);
if (result?.IsNotFoundResult != false) return NotFound();
var result = await ReleaseService.UploadReleaseImageAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, file).ConfigureAwait(false);
if (result?.IsNotFoundResult != false)
{
return NotFound();
}
if (!result.IsSuccess)
{
if (result.IsAccessDeniedResult)

View file

@ -20,14 +20,22 @@ namespace Roadie.Api.Controllers
{
private IStatisticsService StatisticsService { get; }
public StatsController(IStatisticsService statisticsService, ILogger<StatsController> logger, ICacheManager cacheManager,
UserManager<User> userManager, IRoadieSettings roadieSettings)
public StatsController(
IStatisticsService statisticsService,
ILogger<StatsController> logger,
ICacheManager cacheManager,
UserManager<User> userManager,
IRoadieSettings roadieSettings)
: base(cacheManager, roadieSettings, userManager)
{
Logger = logger;
StatisticsService = statisticsService;
}
[HttpGet("artistsByDate")]
[ProducesResponseType(200)]
public async Task<IActionResult> ArtistsByDate() => Ok(await StatisticsService.ArtistsByDateAsync().ConfigureAwait(false));
[HttpGet("info")]
[ProducesResponseType(200)]
[AllowAnonymous]
@ -39,12 +47,14 @@ namespace Roadie.Api.Controllers
var messages = new List<string>
{
"▜ Memory Information: ",
string.Format("My process used working set {0:n3} K of working set and CPU {1:n} msec",
mem / 1024.0, cpu.TotalMilliseconds)
$"My process used working set {mem / 1024.0:n3} K of working set and CPU {cpu.TotalMilliseconds:n} msec"
};
foreach (var aProc in Process.GetProcesses())
{
messages.Add(string.Format("Proc {0,30} CPU {1,-20:n} msec", aProc.ProcessName,
cpu.TotalMilliseconds));
cpu.TotalMilliseconds));
}
messages.Add("▟ Memory Information: ");
return Ok(messages);
@ -52,31 +62,27 @@ namespace Roadie.Api.Controllers
[HttpGet("library")]
[ProducesResponseType(200)]
public async Task<IActionResult> Library() => Ok(await StatisticsService.LibraryStatistics());
public async Task<IActionResult> Library() => Ok(await StatisticsService.LibraryStatisticsAsync().ConfigureAwait(false));
[HttpGet("ping")]
[ProducesResponseType(200)]
[AllowAnonymous]
public IActionResult Ping() => Ok("pong");
[HttpGet("artistsByDate")]
[ProducesResponseType(200)]
public async Task<IActionResult> ArtistsByDate() => Ok(await StatisticsService.ArtistsByDate());
[HttpGet("releasesByDate")]
[ProducesResponseType(200)]
public async Task<IActionResult> ReleasesByDate() => Ok(await StatisticsService.ReleasesByDate());
public async Task<IActionResult> ReleasesByDate() => Ok(await StatisticsService.ReleasesByDateAsync().ConfigureAwait(false));
[HttpGet("releasesByDecade")]
[ProducesResponseType(200)]
public async Task<IActionResult> ReleasesByDecade() => Ok(await StatisticsService.ReleasesByDecade());
public async Task<IActionResult> ReleasesByDecade() => Ok(await StatisticsService.ReleasesByDecadeAsync().ConfigureAwait(false));
[HttpGet("songsPlayedByDate")]
[ProducesResponseType(200)]
public async Task<IActionResult> SongsPlayedByDate() => Ok(await StatisticsService.SongsPlayedByDate());
public async Task<IActionResult> SongsPlayedByDate() => Ok(await StatisticsService.SongsPlayedByDateAsync().ConfigureAwait(false));
[HttpGet("songsPlayedByUser")]
[ProducesResponseType(200)]
public async Task<IActionResult> SongsPlayedByUser() => Ok(await StatisticsService.SongsPlayedByUser());
public async Task<IActionResult> SongsPlayedByUser() => Ok(await StatisticsService.SongsPlayedByUserAsync().ConfigureAwait(false));
}
}

Some files were not shown because too many files have changed in this diff Show more