mirror of
https://github.com/sphildreth/roadie
synced 2024-11-21 19:53:11 +00:00
Performance improvements, async work, and formatting with CodeRush.
This commit is contained in:
parent
625fdf7266
commit
3cfd12a330
111 changed files with 6249 additions and 5370 deletions
4
.editorconfig
Normal file
4
.editorconfig
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[*.cs]
|
||||||
|
|
||||||
|
# Default severity for analyzer diagnostics with category 'Style'
|
||||||
|
dotnet_analyzer_diagnostic.category-Style.severity = none
|
|
@ -29,7 +29,13 @@ namespace Inspector
|
||||||
|
|
||||||
public static int Main(string[] args) => CommandLineApplication.Execute<Program>(args);
|
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()
|
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();
|
var inspector = new Roadie.Library.Inspect.Inspector();
|
||||||
inspector.Inspect(DoCopy, IsReadOnly, Folder, Destination ?? Folder, DontAppendSubFolder, IsReadOnly ? true : DontDeleteEmptyFolders, DontRunPreScript);
|
inspector.Inspect(DoCopy, IsReadOnly, Folder, Destination ?? Folder, DontAppendSubFolder, IsReadOnly ? true : DontDeleteEmptyFolders, DontRunPreScript);
|
||||||
|
|
|
@ -6,9 +6,9 @@ namespace Roadie.Api.Hubs
|
||||||
{
|
{
|
||||||
public class PlayActivityHub : Hub
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,9 +5,9 @@ namespace Roadie.Api.Hubs
|
||||||
{
|
{
|
||||||
public class ScanActivityHub : Hub
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -26,7 +26,7 @@ namespace Roadie.Library.Tests
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return this.MessageLogger as ILogger;
|
return MessageLogger as ILogger;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,17 +38,17 @@ namespace Roadie.Library.Tests
|
||||||
|
|
||||||
public ArtistLookupEngineTests()
|
public ArtistLookupEngineTests()
|
||||||
{
|
{
|
||||||
this.MessageLogger = new EventMessageLogger<ArtistLookupEngineTests>();
|
MessageLogger = new EventMessageLogger<ArtistLookupEngineTests>();
|
||||||
this.MessageLogger.Messages += MessageLogger_Messages;
|
MessageLogger.Messages += MessageLogger_Messages;
|
||||||
|
|
||||||
var settings = new RoadieSettings();
|
var settings = new RoadieSettings();
|
||||||
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
|
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
|
||||||
configurationBuilder.AddJsonFile("appsettings.test.json");
|
configurationBuilder.AddJsonFile("appsettings.test.json");
|
||||||
IConfiguration configuration = configurationBuilder.Build();
|
IConfiguration configuration = configurationBuilder.Build();
|
||||||
configuration.GetSection("RoadieSettings").Bind(settings);
|
configuration.GetSection("RoadieSettings").Bind(settings);
|
||||||
this.Configuration = settings;
|
Configuration = settings;
|
||||||
this.CacheManager = new DictionaryCacheManager(this.Logger, new CachePolicy(TimeSpan.FromHours(4)));
|
CacheManager = new DictionaryCacheManager(Logger, new CachePolicy(TimeSpan.FromHours(4)));
|
||||||
this.HttpEncoder = new Encoding.DummyHttpEncoder();
|
HttpEncoder = new Encoding.DummyHttpEncoder();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MessageLogger_Messages(object sender, EventMessage e)
|
private void MessageLogger_Messages(object sender, EventMessage e)
|
||||||
|
|
|
@ -18,37 +18,30 @@ namespace Roadie.Library.Tests
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly IRoadieSettings _settings = null;
|
private readonly IRoadieSettings _settings;
|
||||||
|
|
||||||
private readonly IConfiguration _configuration;
|
private readonly IConfiguration _configuration;
|
||||||
private IConfiguration Configuration
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return this._configuration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IRoadieSettings Settings
|
private IRoadieSettings Settings
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return this._settings;
|
return _settings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConfigurationTests()
|
public ConfigurationTests()
|
||||||
{
|
{
|
||||||
this._configuration = InitConfiguration();
|
_configuration = InitConfiguration();
|
||||||
this._settings = new RoadieSettings();
|
_settings = new RoadieSettings();
|
||||||
this._configuration.GetSection("RoadieSettings").Bind(this._settings);
|
_configuration.GetSection("RoadieSettings").Bind(_settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void LoadRootLevelConfiguration()
|
public void LoadRootLevelConfiguration()
|
||||||
{
|
{
|
||||||
var inboundFolder = @"C:\roadie_dev_root\inbound";
|
var inboundFolder = @"C:\roadie_dev_root\inbound";
|
||||||
var configInboundFolder = this.Settings.InboundFolder;
|
var configInboundFolder = Settings.InboundFolder;
|
||||||
Assert.Equal(inboundFolder, configInboundFolder);
|
Assert.Equal(inboundFolder, configInboundFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -220,8 +220,8 @@ namespace Roadie.Library.Tests
|
||||||
var lastTrack = shuffledTracks.First();
|
var lastTrack = shuffledTracks.First();
|
||||||
foreach(var track in shuffledTracks.Skip(1))
|
foreach(var track in shuffledTracks.Skip(1))
|
||||||
{
|
{
|
||||||
Assert.False(track.Artist.Artist.Text == lastTrack.Artist.Artist.Text &&
|
Assert.False(string.Equals(track.Artist.Artist.Text, lastTrack.Artist.Artist.Text, StringComparison.Ordinal) &&
|
||||||
track.Release.Release.Text == lastTrack.Release.Release.Text);
|
string.Equals(track.Release.Release.Text, lastTrack.Release.Release.Text, StringComparison.Ordinal));
|
||||||
lastTrack = track;
|
lastTrack = track;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace Roadie.Library.Tests
|
||||||
configurationBuilder.AddJsonFile("appsettings.test.json");
|
configurationBuilder.AddJsonFile("appsettings.test.json");
|
||||||
IConfiguration configuration = configurationBuilder.Build();
|
IConfiguration configuration = configurationBuilder.Build();
|
||||||
configuration.GetSection("RoadieSettings").Bind(settings);
|
configuration.GetSection("RoadieSettings").Bind(settings);
|
||||||
this.Configuration = settings;
|
Configuration = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace Roadie.Library.Tests
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return this.MessageLogger as ILogger;
|
return MessageLogger as ILogger;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,8 +32,8 @@ namespace Roadie.Library.Tests
|
||||||
|
|
||||||
public ID3TagsHelperTests()
|
public ID3TagsHelperTests()
|
||||||
{
|
{
|
||||||
this.MessageLogger = new EventMessageLogger<ID3TagsHelperTests>();
|
MessageLogger = new EventMessageLogger<ID3TagsHelperTests>();
|
||||||
this.MessageLogger.Messages += MessageLoggerMessages;
|
MessageLogger.Messages += MessageLoggerMessages;
|
||||||
|
|
||||||
var settings = new RoadieSettings();
|
var settings = new RoadieSettings();
|
||||||
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
|
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
|
||||||
|
@ -41,11 +41,11 @@ namespace Roadie.Library.Tests
|
||||||
IConfiguration configuration = configurationBuilder.Build();
|
IConfiguration configuration = configurationBuilder.Build();
|
||||||
configuration.GetSection("RoadieSettings").Bind(settings);
|
configuration.GetSection("RoadieSettings").Bind(settings);
|
||||||
settings.ConnectionString = configuration.GetConnectionString("RoadieDatabaseConnection");
|
settings.ConnectionString = configuration.GetConnectionString("RoadieDatabaseConnection");
|
||||||
this.Configuration = settings;
|
Configuration = settings;
|
||||||
this.CacheManager = new DictionaryCacheManager(this.Logger, new CachePolicy(TimeSpan.FromHours(4)));
|
CacheManager = new DictionaryCacheManager(Logger, new CachePolicy(TimeSpan.FromHours(4)));
|
||||||
var tagHelperLooper = new EventMessageLogger<ID3TagsHelper>();
|
var tagHelperLooper = new EventMessageLogger<ID3TagsHelper>();
|
||||||
tagHelperLooper.Messages += MessageLoggerMessages;
|
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)
|
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");
|
var file = new FileInfo(@"C:\roadie_dev_root\mp3_tests\01 O.P.D. (Obsessive Personality Disorder).mp3");
|
||||||
if (file.Exists)
|
if (file.Exists)
|
||||||
{
|
{
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName, true);
|
var tagLib = TagsHelper.MetaDataForFile(file.FullName, true);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
Assert.NotNull(metaData.Artist);
|
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");
|
var file = new FileInfo(@"C:\roadie_dev_root\library\Dream Theater\[2016] The Astonishing\01 2285 Entr acte.mp3");
|
||||||
if (file.Exists)
|
if (file.Exists)
|
||||||
{
|
{
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
Assert.NotNull(metaData.Artist);
|
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");
|
var file = new FileInfo(@"E:\Roadie_Test_Files\13-anna_kendrick-true_colors-a57e270d\01-justin_timberlake-hair_up-ef53c026.mp3");
|
||||||
if (file.Exists)
|
if (file.Exists)
|
||||||
{
|
{
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
Assert.NotNull(metaData.Artist);
|
Assert.NotNull(metaData.Artist);
|
||||||
|
@ -473,7 +473,7 @@ namespace Roadie.Library.Tests
|
||||||
var folderFiles = Directory.GetFiles(folderName, "*.mp3", SearchOption.AllDirectories);
|
var folderFiles = Directory.GetFiles(folderName, "*.mp3", SearchOption.AllDirectories);
|
||||||
foreach(var file in folderFiles)
|
foreach(var file in folderFiles)
|
||||||
{
|
{
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file);
|
var tagLib = TagsHelper.MetaDataForFile(file);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
Assert.NotNull(metaData.Artist);
|
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");
|
var file = new FileInfo(@"E:\Roadie_Test_Files\01 01 Angel Of Death.mp3");
|
||||||
if (file.Exists)
|
if (file.Exists)
|
||||||
{
|
{
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
Assert.NotNull(metaData.Artist);
|
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");
|
var file = new FileInfo(@"E:\Roadie_Test_Files\06 You'Re Sensational.mp3");
|
||||||
if (file.Exists)
|
if (file.Exists)
|
||||||
{
|
{
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
Assert.NotNull(metaData.Artist);
|
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");
|
var file = new FileInfo(@"M:\inbound\MEGAPACK ---METAL-DEATH-BLACK---\ebony_tears-evil_as_hell-2001-ss\01-deviation-ss.mp3");
|
||||||
if (file.Exists)
|
if (file.Exists)
|
||||||
{
|
{
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
Assert.NotNull(metaData.Artist);
|
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");
|
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)
|
if (file.Exists)
|
||||||
{
|
{
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
Assert.NotNull(metaData.Artist);
|
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");
|
var file = new FileInfo(@"M:\library_old\Perverse\[2014] Champion Dub\01 Champion Dub (Original Mix).mp3");
|
||||||
if (file.Exists)
|
if (file.Exists)
|
||||||
{
|
{
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
Assert.NotNull(metaData.Artist);
|
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");
|
var file = new FileInfo(@"C:\roadie_dev_root\inbound\Dreadful Fate - Vengeance (2018)\01-dreadful_fate-vengeance.mp3");
|
||||||
if (file.Exists)
|
if (file.Exists)
|
||||||
{
|
{
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
Assert.NotNull(metaData.Artist);
|
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");
|
var file = new FileInfo(@"M:\library\Blind Melon\[1992] Blind Melon\01. Blind Melon - Soak The Sin.mp3");
|
||||||
if (file.Exists)
|
if (file.Exists)
|
||||||
{
|
{
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
Assert.NotNull(metaData.Artist);
|
Assert.NotNull(metaData.Artist);
|
||||||
|
@ -680,7 +680,7 @@ namespace Roadie.Library.Tests
|
||||||
var file = new FileInfo(@"E:\Roadie_Test_Files\Test.mp3");
|
var file = new FileInfo(@"E:\Roadie_Test_Files\Test.mp3");
|
||||||
if (file.Exists)
|
if (file.Exists)
|
||||||
{
|
{
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
Assert.NotNull(metaData.Artist);
|
Assert.NotNull(metaData.Artist);
|
||||||
|
@ -714,14 +714,14 @@ namespace Roadie.Library.Tests
|
||||||
short trackNumber = 15;
|
short trackNumber = 15;
|
||||||
var numberOfTracks = 25;
|
var numberOfTracks = 25;
|
||||||
|
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
metaData.TrackNumber = trackNumber;
|
metaData.TrackNumber = trackNumber;
|
||||||
metaData.TotalTrackNumbers = numberOfTracks;
|
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.True(tagLib.IsSuccess);
|
||||||
Assert.Equal(metaData.Artist, tagLibAfterWrite.Data.Artist);
|
Assert.Equal(metaData.Artist, tagLibAfterWrite.Data.Artist);
|
||||||
Assert.Equal(metaData.Release, tagLibAfterWrite.Data.Release);
|
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");
|
var file = new FileInfo(@"M:\library\Denver, John\[1972] Aerie\10 Readjustment Blues.mp3");
|
||||||
if (file.Exists)
|
if (file.Exists)
|
||||||
{
|
{
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
Assert.True(metaData.IsValid);
|
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");
|
var file = new FileInfo(@"E:\Roadie_Test_Files\01. What's Yesterday.mp3");
|
||||||
if (file.Exists)
|
if (file.Exists)
|
||||||
{
|
{
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
Assert.NotNull(metaData.Artist);
|
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");
|
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)
|
if (file.Exists)
|
||||||
{
|
{
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
Assert.NotNull(metaData.Artist);
|
Assert.NotNull(metaData.Artist);
|
||||||
|
@ -825,7 +825,7 @@ namespace Roadie.Library.Tests
|
||||||
var file = new FileInfo(@"E:\Roadie_Test_Files\01 Martian.mp3");
|
var file = new FileInfo(@"E:\Roadie_Test_Files\01 Martian.mp3");
|
||||||
if (file.Exists)
|
if (file.Exists)
|
||||||
{
|
{
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
Assert.NotNull(metaData.Artist);
|
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");
|
var file = new FileInfo(@"C:\roadie_dev_root\inbound\[2016] Invention Of Knowledge\01 Invention.mp3");
|
||||||
if (file.Exists)
|
if (file.Exists)
|
||||||
{
|
{
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
Assert.NotNull(metaData.Artist);
|
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");
|
var file = new FileInfo(@"C:\roadie_dev_root\1985 - Sacred Heart\Dio - Sacred Heart (1).mp3");
|
||||||
if (file.Exists)
|
if (file.Exists)
|
||||||
{
|
{
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
Assert.NotNull(metaData.Artist);
|
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");
|
var file = new FileInfo(@"C:\roadie_dev_root\Grift\2017 Arvet\01 - Flyktfast.mp3");
|
||||||
if (file.Exists)
|
if (file.Exists)
|
||||||
{
|
{
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
Assert.NotNull(metaData.Artist);
|
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");
|
var file = new FileInfo(@"C:\roadie_dev_root\Distorted Harmony - A Way Out - 2018\kWlZr0N_o72dwo0_CD001_0001.mp3");
|
||||||
if (file.Exists)
|
if (file.Exists)
|
||||||
{
|
{
|
||||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||||
Assert.True(tagLib.IsSuccess);
|
Assert.True(tagLib.IsSuccess);
|
||||||
var metaData = tagLib.Data;
|
var metaData = tagLib.Data;
|
||||||
Assert.NotNull(metaData.Artist);
|
Assert.NotNull(metaData.Artist);
|
||||||
|
|
|
@ -1,12 +1,5 @@
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Roadie.Library.Imaging;
|
||||||
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 System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
@ -38,6 +31,9 @@ namespace Roadie.Library.Tests
|
||||||
[InlineData("logo.png")]
|
[InlineData("logo.png")]
|
||||||
[InlineData("Logo.Jpg")]
|
[InlineData("Logo.Jpg")]
|
||||||
[InlineData("logo.gif")]
|
[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")]
|
[InlineData("Artist_logo.jpg")]
|
||||||
[InlineData("ARTIST_LOGO.JPG")]
|
[InlineData("ARTIST_LOGO.JPG")]
|
||||||
|
@ -61,7 +57,7 @@ namespace Roadie.Library.Tests
|
||||||
[InlineData("cover.png")]
|
[InlineData("cover.png")]
|
||||||
[InlineData("Cover.Jpg")]
|
[InlineData("Cover.Jpg")]
|
||||||
[InlineData("Cover.JPG")]
|
[InlineData("Cover.JPG")]
|
||||||
[InlineData("Cover.PNG")]
|
[InlineData("Cover.PNG")]
|
||||||
[InlineData("CvR.Jpg")]
|
[InlineData("CvR.Jpg")]
|
||||||
[InlineData("Release.JPG")]
|
[InlineData("Release.JPG")]
|
||||||
[InlineData("folder.JPG")]
|
[InlineData("folder.JPG")]
|
||||||
|
@ -79,7 +75,7 @@ namespace Roadie.Library.Tests
|
||||||
[InlineData("f.jpg")]
|
[InlineData("f.jpg")]
|
||||||
[InlineData("F1.jpg")]
|
[InlineData("F1.jpg")]
|
||||||
[InlineData("F 1.jpg")]
|
[InlineData("F 1.jpg")]
|
||||||
[InlineData("F-1.jpg")]
|
[InlineData("F-1.jpg")]
|
||||||
[InlineData("front_.jpg")]
|
[InlineData("front_.jpg")]
|
||||||
[InlineData("BIG.JPg")]
|
[InlineData("BIG.JPg")]
|
||||||
[InlineData("bigart.JPg")]
|
[InlineData("bigart.JPg")]
|
||||||
|
@ -185,9 +181,9 @@ namespace Roadie.Library.Tests
|
||||||
|
|
||||||
[InlineData("Booklet-1.jpg")]
|
[InlineData("Booklet-1.jpg")]
|
||||||
[InlineData("Booklet-10.jpg")]
|
[InlineData("Booklet-10.jpg")]
|
||||||
[InlineData("Booklet_1.jpg")]
|
[InlineData("Booklet_1.jpg")]
|
||||||
[InlineData("Booklet 3.jpg")]
|
[InlineData("Booklet 3.jpg")]
|
||||||
[InlineData("Digipack (01).jpg")]
|
[InlineData("Digipack (01).jpg")]
|
||||||
[InlineData("Eagles - Long Road Out Of Eden - Booklet-6.jpg")]
|
[InlineData("Eagles - Long Road Out Of Eden - Booklet-6.jpg")]
|
||||||
[InlineData("Long Road Out Of Eden - Booklet-6.jpg")]
|
[InlineData("Long Road Out Of Eden - Booklet-6.jpg")]
|
||||||
[InlineData("Long Road Out Of Eden Booklet-6.jpg")]
|
[InlineData("Long Road Out Of Eden Booklet-6.jpg")]
|
||||||
|
@ -204,10 +200,10 @@ namespace Roadie.Library.Tests
|
||||||
[InlineData("Back.jpg")]
|
[InlineData("Back.jpg")]
|
||||||
[InlineData("BAcK.JPg")]
|
[InlineData("BAcK.JPg")]
|
||||||
[InlineData("Cd.jpg")]
|
[InlineData("Cd.jpg")]
|
||||||
[InlineData("CD.JPG")]
|
[InlineData("CD.JPG")]
|
||||||
[InlineData("Cd1.jpg")]
|
[InlineData("Cd1.jpg")]
|
||||||
[InlineData("CD (01).jpg")]
|
[InlineData("CD (01).jpg")]
|
||||||
[InlineData("CD (02).jpg")]
|
[InlineData("CD (02).jpg")]
|
||||||
[InlineData("CD-1.jpg")]
|
[InlineData("CD-1.jpg")]
|
||||||
[InlineData("CD 1.jpg")]
|
[InlineData("CD 1.jpg")]
|
||||||
[InlineData("CD_1.jpg")]
|
[InlineData("CD_1.jpg")]
|
||||||
|
@ -242,16 +238,16 @@ namespace Roadie.Library.Tests
|
||||||
[InlineData("release 3.jpg")]
|
[InlineData("release 3.jpg")]
|
||||||
[InlineData("release 10.jpg")]
|
[InlineData("release 10.jpg")]
|
||||||
[InlineData("Dixieland-Label-Side 1.JPG")]
|
[InlineData("Dixieland-Label-Side 1.JPG")]
|
||||||
[InlineData("Dixieland-Label-Side 2.JPG")]
|
[InlineData("Dixieland-Label-Side 2.JPG")]
|
||||||
[InlineData("Hearing Is Believing-Inside 1.jpg")]
|
[InlineData("Hearing Is Believing-Inside 1.jpg")]
|
||||||
[InlineData("Booklet (2-3).jpg")]
|
[InlineData("Booklet (2-3).jpg")]
|
||||||
[InlineData("Booklet (14-15).jpg")]
|
[InlineData("Booklet (14-15).jpg")]
|
||||||
[InlineData("Booklet#2.jpg")]
|
[InlineData("Booklet#2.jpg")]
|
||||||
[InlineData("traycard.png")]
|
[InlineData("traycard.png")]
|
||||||
[InlineData("Jewel Case.jpg")]
|
[InlineData("Jewel Case.jpg")]
|
||||||
[InlineData("Matrix-1.jpg")]
|
[InlineData("Matrix-1.jpg")]
|
||||||
[InlineData("Matrix 1.jpg")]
|
[InlineData("Matrix 1.jpg")]
|
||||||
[InlineData("IMG_20160921_0004.jpg")]
|
[InlineData("IMG_20160921_0004.jpg")]
|
||||||
public void TestShouldBeReleaseSecondaryImages(string input)
|
public void TestShouldBeReleaseSecondaryImages(string input)
|
||||||
{
|
{
|
||||||
Assert.True(ImageHelper.IsReleaseSecondaryImage(new FileInfo(input)));
|
Assert.True(ImageHelper.IsReleaseSecondaryImage(new FileInfo(input)));
|
||||||
|
@ -292,7 +288,7 @@ namespace Roadie.Library.Tests
|
||||||
public void GetReleaseImageInFolder()
|
public void GetReleaseImageInFolder()
|
||||||
{
|
{
|
||||||
var folder = new DirectoryInfo(@"C:\roadie_dev_root\image_tests");
|
var folder = new DirectoryInfo(@"C:\roadie_dev_root\image_tests");
|
||||||
if(!folder.Exists)
|
if (!folder.Exists)
|
||||||
{
|
{
|
||||||
Assert.True(true);
|
Assert.True(true);
|
||||||
return;
|
return;
|
||||||
|
@ -318,6 +314,6 @@ namespace Roadie.Library.Tests
|
||||||
Assert.Single(artist);
|
Assert.Single(artist);
|
||||||
Assert.Equal("artist.jpg", artist.First().Name);
|
Assert.Equal("artist.jpg", artist.First().Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -23,7 +23,7 @@ namespace Roadie.Library.Tests
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return this.MessageLogger as ILogger;
|
return MessageLogger as ILogger;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,8 +35,8 @@ namespace Roadie.Library.Tests
|
||||||
|
|
||||||
public InspectorTests()
|
public InspectorTests()
|
||||||
{
|
{
|
||||||
this.MessageLogger = new EventMessageLogger<ID3TagsHelperTests>();
|
MessageLogger = new EventMessageLogger<ID3TagsHelperTests>();
|
||||||
this.MessageLogger.Messages += MessageLoggerMessages;
|
MessageLogger.Messages += MessageLoggerMessages;
|
||||||
|
|
||||||
var settings = new configuration.RoadieSettings();
|
var settings = new configuration.RoadieSettings();
|
||||||
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
|
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
|
||||||
|
@ -44,11 +44,11 @@ namespace Roadie.Library.Tests
|
||||||
IConfiguration configuration = configurationBuilder.Build();
|
IConfiguration configuration = configurationBuilder.Build();
|
||||||
configuration.GetSection("RoadieSettings").Bind(settings);
|
configuration.GetSection("RoadieSettings").Bind(settings);
|
||||||
settings.ConnectionString = configuration.GetConnectionString("RoadieDatabaseConnection");
|
settings.ConnectionString = configuration.GetConnectionString("RoadieDatabaseConnection");
|
||||||
this.Configuration = settings;
|
Configuration = settings;
|
||||||
this.CacheManager = new DictionaryCacheManager(this.Logger, new CachePolicy(TimeSpan.FromHours(4)));
|
CacheManager = new DictionaryCacheManager(Logger, new CachePolicy(TimeSpan.FromHours(4)));
|
||||||
var tagHelperLooper = new EventMessageLogger<ID3TagsHelper>();
|
var tagHelperLooper = new EventMessageLogger<ID3TagsHelper>();
|
||||||
tagHelperLooper.Messages += MessageLoggerMessages;
|
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)
|
private void MessageLoggerMessages(object sender, EventMessage e)
|
||||||
|
|
|
@ -6,10 +6,8 @@ using Roadie.Library.MetaData.MusicBrainz;
|
||||||
using Roadie.Library.Processors;
|
using Roadie.Library.Processors;
|
||||||
using Roadie.Library.SearchEngines.MetaData.Discogs;
|
using Roadie.Library.SearchEngines.MetaData.Discogs;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
@ -50,7 +48,7 @@ namespace Roadie.Library.Tests
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task DiscogsHelperReleaseSearch()
|
public async Task DiscogsHelperReleaseSearch()
|
||||||
{
|
{
|
||||||
if(!Configuration.Integrations.DiscogsProviderEnabled)
|
if (!Configuration.Integrations.DiscogsProviderEnabled)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -62,7 +60,7 @@ namespace Roadie.Library.Tests
|
||||||
var artistName = "With The Dead";
|
var artistName = "With The Dead";
|
||||||
var title = "Love From 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.NotNull(result);
|
||||||
Assert.NotEmpty(result.Data);
|
Assert.NotEmpty(result.Data);
|
||||||
|
|
||||||
|
@ -84,10 +82,9 @@ namespace Roadie.Library.Tests
|
||||||
|
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
|
|
||||||
var result = await mb.PerformArtistSearch(artistName, 1);
|
var result = await mb.PerformArtistSearchAsync(artistName, 1).ConfigureAwait(false);
|
||||||
|
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
var elapsedTime = sw.ElapsedMilliseconds;
|
|
||||||
|
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
Assert.NotNull(result.Data);
|
Assert.NotNull(result.Data);
|
||||||
|
@ -113,10 +110,9 @@ namespace Roadie.Library.Tests
|
||||||
var title = "Piano Man";
|
var title = "Piano Man";
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
|
|
||||||
var result = await mb.PerformReleaseSearch(artistName, title, 1);
|
var result = await mb.PerformReleaseSearch(artistName, title, 1).ConfigureAwait(false);
|
||||||
|
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
var elapsedTime = sw.ElapsedMilliseconds;
|
|
||||||
|
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
Assert.NotNull(result.Data);
|
Assert.NotNull(result.Data);
|
||||||
|
|
|
@ -12,21 +12,21 @@ namespace Roadie.Library.Tests
|
||||||
{
|
{
|
||||||
private readonly IConfiguration _configuration;
|
private readonly IConfiguration _configuration;
|
||||||
|
|
||||||
private readonly IRoadieSettings _settings = null;
|
private readonly IRoadieSettings _settings;
|
||||||
|
|
||||||
private IRoadieSettings Configuration
|
private IRoadieSettings Configuration
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return this._settings;
|
return _settings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public StringExtensionTests()
|
public StringExtensionTests()
|
||||||
{
|
{
|
||||||
this._configuration = InitConfiguration();
|
_configuration = InitConfiguration();
|
||||||
this._settings = new RoadieSettings();
|
_settings = new RoadieSettings();
|
||||||
this._configuration.GetSection("RoadieSettings").Bind(this._settings);
|
_configuration.GetSection("RoadieSettings").Bind(_settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IConfiguration InitConfiguration()
|
public static IConfiguration InitConfiguration()
|
||||||
|
@ -102,7 +102,7 @@ namespace Roadie.Library.Tests
|
||||||
public void CleanStringReleaseShouldBeAngie(string input)
|
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 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);
|
Assert.Equal("Angie", cleaned);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
"RoadieSettings": {
|
"RoadieSettings": {
|
||||||
"InboundFolder": "C:\\roadie_dev_root\\inbound",
|
"InboundFolder": "C:\\roadie_dev_root\\inbound",
|
||||||
"LibraryFolder": "C:\\\\roadie_dev_root\\\\library",
|
"LibraryFolder": "C:\\\\roadie_dev_root\\\\library",
|
||||||
|
"SearchEngineReposFolder": "C:\\\\roadie_dev_root\\\\repos",
|
||||||
"Processing": {
|
"Processing": {
|
||||||
"RemoveStringsRegex": "\\b[0-9]+\\s#\\s\\b",
|
"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)+(]|\\\\)*))",
|
"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)+(]|\\\\)*))",
|
||||||
|
|
|
@ -113,7 +113,7 @@ namespace Roadie.Library.Caching
|
||||||
var r = Get<TOut>(key, region);
|
var r = Get<TOut>(key, region);
|
||||||
if (r == null)
|
if (r == null)
|
||||||
{
|
{
|
||||||
r = await getItem();
|
r = await getItem().ConfigureAwait(false);
|
||||||
Add(key, r, region);
|
Add(key, r, region);
|
||||||
Logger.LogTrace($"-+> Cache Miss for Key [{key}], Region [{region}]");
|
Logger.LogTrace($"-+> Cache Miss for Key [{key}], Region [{region}]");
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,7 @@ namespace Roadie.Library.Caching
|
||||||
var r = Get<TOut>(key, region);
|
var r = Get<TOut>(key, region);
|
||||||
if (r == null)
|
if (r == null)
|
||||||
{
|
{
|
||||||
r = await getItem();
|
r = await getItem().ConfigureAwait(false);
|
||||||
Add(key, r, region);
|
Add(key, r, region);
|
||||||
Logger.LogTrace($"-+> Cache Miss for Key [{key}], Region [{region}]");
|
Logger.LogTrace($"-+> Cache Miss for Key [{key}], Region [{region}]");
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,14 +5,14 @@ namespace Roadie.Library.Data.Context
|
||||||
{
|
{
|
||||||
public interface IRoadieDbRandomizer
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
return (from ut in UserTracks
|
||||||
join t in Tracks on ut.TrackId equals t.Id
|
join t in Tracks on ut.TrackId equals t.Id
|
||||||
join rm in ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
join rm in ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||||
join r in Releases on rm.ReleaseId equals r.Id
|
join r in Releases on rm.ReleaseId equals r.Id
|
||||||
join a in Artists on r.ArtistId equals a.Id
|
join a in Artists on r.ArtistId equals a.Id
|
||||||
where ut.UserId == userId
|
where ut.UserId == userId
|
||||||
orderby ut.LastPlayed descending
|
orderby ut.LastPlayed descending
|
||||||
select a).FirstOrDefaultAsync();
|
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 t in Tracks on ut.TrackId equals t.Id
|
||||||
join rm in ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
join rm in ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||||
join r in Releases on rm.ReleaseId equals r.Id
|
join r in Releases on rm.ReleaseId equals r.Id
|
||||||
|
@ -39,9 +39,9 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
select r).FirstOrDefaultAsync();
|
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
|
join t in Tracks on ut.TrackId equals t.Id
|
||||||
where ut.UserId == userId
|
where ut.UserId == userId
|
||||||
orderby ut.LastPlayed descending
|
orderby ut.LastPlayed descending
|
||||||
|
@ -50,7 +50,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
|
|
||||||
public override async Task<Artist> MostPlayedArtist(int userId)
|
public override async Task<Artist> MostPlayedArtist(int userId)
|
||||||
{
|
{
|
||||||
var mostPlayedTrack = await MostPlayedTrack(userId);
|
var mostPlayedTrack = await MostPlayedTrack(userId).ConfigureAwait(false);
|
||||||
if (mostPlayedTrack != null)
|
if (mostPlayedTrack != null)
|
||||||
{
|
{
|
||||||
return await (from t in Tracks
|
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 r in Releases on rm.ReleaseId equals r.Id
|
||||||
join a in Artists on r.ArtistId equals a.Id
|
join a in Artists on r.ArtistId equals a.Id
|
||||||
where t.Id == mostPlayedTrack.Id
|
where t.Id == mostPlayedTrack.Id
|
||||||
select a).FirstOrDefaultAsync();
|
select a).FirstOrDefaultAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<Release> MostPlayedRelease(int userId)
|
public override async Task<Release> MostPlayedRelease(int userId)
|
||||||
{
|
{
|
||||||
var mostPlayedTrack = await MostPlayedTrack(userId);
|
var mostPlayedTrack = await MostPlayedTrack(userId).ConfigureAwait(false);
|
||||||
if (mostPlayedTrack != null)
|
if (mostPlayedTrack != null)
|
||||||
{
|
{
|
||||||
return await (from t in Tracks
|
return await (from t in Tracks
|
||||||
join rm in ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
join rm in ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||||
join r in Releases on rm.ReleaseId equals r.Id
|
join r in Releases on rm.ReleaseId equals r.Id
|
||||||
where t.Id == mostPlayedTrack.Id
|
where t.Id == mostPlayedTrack.Id
|
||||||
select r).FirstOrDefaultAsync();
|
select r).FirstOrDefaultAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
return null;
|
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
|
join t in Tracks on ut.TrackId equals t.Id
|
||||||
where ut.UserId == userId
|
where ut.UserId == userId
|
||||||
orderby ut.PlayedCount descending
|
orderby ut.PlayedCount descending
|
||||||
select t).FirstOrDefaultAsync();
|
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;
|
List<Artist> randomArtists = null;
|
||||||
if (doOnlyFavorites)
|
if (doOnlyFavorites)
|
||||||
|
@ -98,7 +98,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
select a
|
select a
|
||||||
).OrderBy(x => Guid.NewGuid())
|
).OrderBy(x => Guid.NewGuid())
|
||||||
.Take(randomLimit)
|
.Take(randomLimit)
|
||||||
.ToListAsync();
|
.ToListAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else if (doOnlyRated)
|
else if (doOnlyRated)
|
||||||
{
|
{
|
||||||
|
@ -109,7 +109,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
select a
|
select a
|
||||||
).OrderBy(x => Guid.NewGuid())
|
).OrderBy(x => Guid.NewGuid())
|
||||||
.Take(randomLimit)
|
.Take(randomLimit)
|
||||||
.ToListAsync();
|
.ToListAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -120,29 +120,29 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
select a)
|
select a)
|
||||||
.OrderBy(x => Guid.NewGuid())
|
.OrderBy(x => Guid.NewGuid())
|
||||||
.Take(randomLimit)
|
.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);
|
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);
|
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())
|
var randomGenres = await Genres.OrderBy(x => Guid.NewGuid())
|
||||||
.Take(randomLimit)
|
.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);
|
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);
|
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);
|
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);
|
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;
|
List<Release> randomReleases = null;
|
||||||
if (doOnlyFavorites)
|
if (doOnlyFavorites)
|
||||||
|
@ -154,7 +154,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
select r
|
select r
|
||||||
).OrderBy(x => Guid.NewGuid())
|
).OrderBy(x => Guid.NewGuid())
|
||||||
.Take(randomLimit)
|
.Take(randomLimit)
|
||||||
.ToListAsync();
|
.ToListAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else if (doOnlyRated)
|
else if (doOnlyRated)
|
||||||
{
|
{
|
||||||
|
@ -165,7 +165,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
select r
|
select r
|
||||||
).OrderBy(x => Guid.NewGuid())
|
).OrderBy(x => Guid.NewGuid())
|
||||||
.Take(randomLimit)
|
.Take(randomLimit)
|
||||||
.ToListAsync();
|
.ToListAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -176,13 +176,13 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
select r)
|
select r)
|
||||||
.OrderBy(x => Guid.NewGuid())
|
.OrderBy(x => Guid.NewGuid())
|
||||||
.Take(randomLimit)
|
.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);
|
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);
|
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;
|
List<Track> randomTracks = null;
|
||||||
if (doOnlyFavorites)
|
if (doOnlyFavorites)
|
||||||
|
@ -194,7 +194,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
select t
|
select t
|
||||||
).OrderBy(x => Guid.NewGuid())
|
).OrderBy(x => Guid.NewGuid())
|
||||||
.Take(randomLimit)
|
.Take(randomLimit)
|
||||||
.ToListAsync();
|
.ToListAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else if (doOnlyRated)
|
else if (doOnlyRated)
|
||||||
{
|
{
|
||||||
|
@ -205,7 +205,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
select t
|
select t
|
||||||
).OrderBy(x => Guid.NewGuid())
|
).OrderBy(x => Guid.NewGuid())
|
||||||
.Take(randomLimit)
|
.Take(randomLimit)
|
||||||
.ToListAsync();
|
.ToListAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -216,7 +216,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
select t)
|
select t)
|
||||||
.OrderBy(x => Guid.NewGuid())
|
.OrderBy(x => Guid.NewGuid())
|
||||||
.Take(randomLimit)
|
.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);
|
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);
|
return new SortedDictionary<int, int>(dict);
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
where ut.userId = {0}
|
where ut.userId = {0}
|
||||||
ORDER by ut.lastPlayed desc
|
ORDER by ut.lastPlayed desc
|
||||||
LIMIT 1";
|
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)
|
public override async Task<Release> LastPlayedRelease(int userId)
|
||||||
|
@ -41,7 +41,8 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
LIMIT 1";
|
LIMIT 1";
|
||||||
return await Releases.FromSqlRaw(sql, userId)
|
return await Releases.FromSqlRaw(sql, userId)
|
||||||
.Include(x => x.Artist)
|
.Include(x => x.Artist)
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync()
|
||||||
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<Track> LastPlayedTrack(int userId)
|
public override async Task<Track> LastPlayedTrack(int userId)
|
||||||
|
@ -57,7 +58,8 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
.Include(x => x.ReleaseMedia)
|
.Include(x => x.ReleaseMedia)
|
||||||
.Include("ReleaseMedia.Release")
|
.Include("ReleaseMedia.Release")
|
||||||
.Include("ReleaseMedia.Release.Artist")
|
.Include("ReleaseMedia.Release.Artist")
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync()
|
||||||
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<Artist> MostPlayedArtist(int userId)
|
public override async Task<Artist> MostPlayedArtist(int userId)
|
||||||
|
@ -72,7 +74,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
group by r.id
|
group by r.id
|
||||||
order by SUM(ut.playedCount) desc
|
order by SUM(ut.playedCount) desc
|
||||||
LIMIT 1";
|
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)
|
public override async Task<Release> MostPlayedRelease(int userId)
|
||||||
|
@ -88,7 +90,8 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
LIMIT 1";
|
LIMIT 1";
|
||||||
return await Releases.FromSqlRaw(sql, userId)
|
return await Releases.FromSqlRaw(sql, userId)
|
||||||
.Include(x => x.Artist)
|
.Include(x => x.Artist)
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync()
|
||||||
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<Track> MostPlayedTrack(int userId)
|
public override async Task<Track> MostPlayedTrack(int userId)
|
||||||
|
@ -105,10 +108,11 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
.Include(x => x.ReleaseMedia)
|
.Include(x => x.ReleaseMedia)
|
||||||
.Include("ReleaseMedia.Release")
|
.Include("ReleaseMedia.Release")
|
||||||
.Include("ReleaseMedia.Release.Artist")
|
.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
|
var sql = @"SELECT a.id
|
||||||
FROM `artist` a
|
FROM `artist` a
|
||||||
|
@ -117,34 +121,34 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
AND {2} = 1)
|
AND {2} = 1)
|
||||||
order BY RIGHT(HEX((1 << 24) * (1 + RAND())), 6)
|
order BY RIGHT(HEX((1 << 24) * (1 + RAND())), 6)
|
||||||
LIMIT 0, {0}";
|
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);
|
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||||
return new SortedDictionary<int, int>(dict);
|
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
|
var sql = @"SELECT g.id
|
||||||
FROM `genre` g
|
FROM `genre` g
|
||||||
ORDER BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
|
ORDER BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
|
||||||
LIMIT 0, {0}";
|
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);
|
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||||
return new SortedDictionary<int, int>(dict);
|
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
|
var sql = @"SELECT l.id
|
||||||
FROM `label` l
|
FROM `label` l
|
||||||
ORDER BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
|
ORDER BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
|
||||||
LIMIT 0, {0}";
|
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);
|
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||||
return new SortedDictionary<int, int>(dict);
|
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
|
var sql = @"SELECT r.id
|
||||||
FROM `release` r
|
FROM `release` r
|
||||||
|
@ -153,12 +157,12 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
AND {2} = 1)
|
AND {2} = 1)
|
||||||
ORDER BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
|
ORDER BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
|
||||||
LIMIT 0, {0}";
|
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);
|
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||||
return new SortedDictionary<int, int>(dict);
|
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
|
var sql = @"SELECT t.id
|
||||||
FROM `track` t
|
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)
|
WHERE ut.userId = {1} AND ut.isFavorite = 1) AND {2} = 1) OR {2} = 0)
|
||||||
order BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
|
order BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
|
||||||
LIMIT 0, {0}";
|
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);
|
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||||
return new SortedDictionary<int, int>(dict);
|
return new SortedDictionary<int, int>(dict);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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?
|
// TODO Rating?
|
||||||
var sql = @"SELECT a.id
|
var sql = @"SELECT a.id
|
||||||
|
@ -32,34 +32,34 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
AND {2} = 1)
|
AND {2} = 1)
|
||||||
order by random()
|
order by random()
|
||||||
LIMIT 0, {0}";
|
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);
|
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||||
return new SortedDictionary<int, int>(dict);
|
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
|
var sql = @"SELECT g.id
|
||||||
FROM genre g
|
FROM genre g
|
||||||
order by random()
|
order by random()
|
||||||
LIMIT 0, {0}";
|
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);
|
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||||
return new SortedDictionary<int, int>(dict);
|
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
|
var sql = @"SELECT l.id
|
||||||
FROM label l
|
FROM label l
|
||||||
order by random()
|
order by random()
|
||||||
LIMIT 0, {0}";
|
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);
|
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||||
return new SortedDictionary<int, int>(dict);
|
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?
|
// TODO Rating?
|
||||||
var sql = @"SELECT r.id
|
var sql = @"SELECT r.id
|
||||||
|
@ -69,12 +69,12 @@ namespace Roadie.Library.Data.Context.Implementation
|
||||||
AND {2} = 1)
|
AND {2} = 1)
|
||||||
order by random()
|
order by random()
|
||||||
LIMIT 0, {0}";
|
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);
|
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||||
return new SortedDictionary<int, int>(dict);
|
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.
|
// 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)
|
WHERE ut.userId = {userId} AND ut.isFavorite = 1) AND {df} = 1) OR {df} = 0)
|
||||||
order by random()
|
order by random()
|
||||||
LIMIT 0, {randomLimit}";
|
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);
|
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||||
return new SortedDictionary<int, int>(dict);
|
return new SortedDictionary<int, int>(dict);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,15 +6,15 @@ namespace Roadie.Library.Data.Context
|
||||||
{
|
{
|
||||||
public abstract partial class RoadieDbContext : DbContext, IRoadieDbContext
|
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);
|
public abstract Task<Artist> MostPlayedArtist(int userId);
|
||||||
|
|
||||||
|
|
|
@ -349,7 +349,7 @@ namespace Roadie.Library.Engines
|
||||||
if (ITunesArtistSearchEngine.IsEnabled)
|
if (ITunesArtistSearchEngine.IsEnabled)
|
||||||
{
|
{
|
||||||
var sw2 = Stopwatch.StartNew();
|
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)
|
if (iTunesResult.IsSuccess)
|
||||||
{
|
{
|
||||||
var i = iTunesResult.Data.First();
|
var i = iTunesResult.Data.First();
|
||||||
|
@ -406,7 +406,7 @@ namespace Roadie.Library.Engines
|
||||||
if (MusicBrainzArtistSearchEngine.IsEnabled)
|
if (MusicBrainzArtistSearchEngine.IsEnabled)
|
||||||
{
|
{
|
||||||
var sw2 = Stopwatch.StartNew();
|
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)
|
if (mbResult.IsSuccess)
|
||||||
{
|
{
|
||||||
var mb = mbResult.Data.First();
|
var mb = mbResult.Data.First();
|
||||||
|
@ -471,7 +471,7 @@ namespace Roadie.Library.Engines
|
||||||
if (LastFmArtistSearchEngine.IsEnabled)
|
if (LastFmArtistSearchEngine.IsEnabled)
|
||||||
{
|
{
|
||||||
var sw2 = Stopwatch.StartNew();
|
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)
|
if (lastFmResult.IsSuccess)
|
||||||
{
|
{
|
||||||
var l = lastFmResult.Data.First();
|
var l = lastFmResult.Data.First();
|
||||||
|
@ -515,7 +515,7 @@ namespace Roadie.Library.Engines
|
||||||
if (SpotifyArtistSearchEngine.IsEnabled)
|
if (SpotifyArtistSearchEngine.IsEnabled)
|
||||||
{
|
{
|
||||||
var sw2 = Stopwatch.StartNew();
|
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)
|
if (spotifyResult.IsSuccess)
|
||||||
{
|
{
|
||||||
var s = spotifyResult.Data.First();
|
var s = spotifyResult.Data.First();
|
||||||
|
@ -557,7 +557,7 @@ namespace Roadie.Library.Engines
|
||||||
if (DiscogsArtistSearchEngine.IsEnabled)
|
if (DiscogsArtistSearchEngine.IsEnabled)
|
||||||
{
|
{
|
||||||
var sw2 = Stopwatch.StartNew();
|
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)
|
if (discogsResult.IsSuccess)
|
||||||
{
|
{
|
||||||
var d = discogsResult?.Data?.FirstOrDefault();
|
var d = discogsResult?.Data?.FirstOrDefault();
|
||||||
|
@ -614,7 +614,7 @@ namespace Roadie.Library.Engines
|
||||||
{
|
{
|
||||||
wikiName += " band";
|
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?.Data != null)
|
||||||
{
|
{
|
||||||
if (wikipediaResult.IsSuccess)
|
if (wikipediaResult.IsSuccess)
|
||||||
|
|
|
@ -455,7 +455,7 @@ namespace Roadie.Library.Engines
|
||||||
{
|
{
|
||||||
var sw2 = Stopwatch.StartNew();
|
var sw2 = Stopwatch.StartNew();
|
||||||
Logger.LogTrace("ITunesReleaseSearchEngine Release Search for ArtistName [{0}], ReleaseTitle [{1}]", metaData.Artist, result.Title);
|
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)
|
if (iTunesResult.IsSuccess)
|
||||||
{
|
{
|
||||||
var i = iTunesResult.Data.First();
|
var i = iTunesResult.Data.First();
|
||||||
|
|
|
@ -26,24 +26,23 @@ namespace Roadie.Library.Imaging
|
||||||
|
|
||||||
public static byte[] ConvertToJpegFormat(byte[] imageBytes)
|
public static byte[] ConvertToJpegFormat(byte[] imageBytes)
|
||||||
{
|
{
|
||||||
if (imageBytes == null || !imageBytes.Any())
|
if(imageBytes?.Any() != true)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var outStream = new MemoryStream())
|
using(var outStream = new MemoryStream())
|
||||||
{
|
{
|
||||||
IImageFormat imageFormat = null;
|
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);
|
image.SaveAsJpeg(outStream);
|
||||||
}
|
}
|
||||||
return outStream.ToArray();
|
return outStream.ToArray();
|
||||||
}
|
}
|
||||||
}
|
} catch(Exception ex)
|
||||||
catch (Exception ex)
|
|
||||||
{
|
{
|
||||||
Trace.WriteLine($"Error Converting Image to Jpg [{ ex.Message }]", "Warning");
|
Trace.WriteLine($"Error Converting Image to Jpg [{ ex.Message }]", "Warning");
|
||||||
}
|
}
|
||||||
|
@ -55,44 +54,48 @@ namespace Roadie.Library.Imaging
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static byte[] ConvertToGifFormat(byte[] imageBytes)
|
public static byte[] ConvertToGifFormat(byte[] imageBytes)
|
||||||
{
|
{
|
||||||
if (imageBytes == null || !imageBytes.Any())
|
if(imageBytes?.Any() != true)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var outStream = new MemoryStream())
|
using(var outStream = new MemoryStream())
|
||||||
{
|
{
|
||||||
IImageFormat imageFormat = null;
|
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);
|
image.SaveAsGif(outStream);
|
||||||
}
|
}
|
||||||
return outStream.ToArray();
|
return outStream.ToArray();
|
||||||
}
|
}
|
||||||
}
|
} catch(Exception ex)
|
||||||
catch (Exception ex)
|
|
||||||
{
|
{
|
||||||
Trace.WriteLine($"Error Converting Image to Gif [{ ex.Message }]", "Warning");
|
Trace.WriteLine($"Error Converting Image to Gif [{ ex.Message }]", "Warning");
|
||||||
}
|
}
|
||||||
return null;
|
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>();
|
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);
|
var imageFilesInFolder = ImageFilesInFolder(directory.FullName, folderSearchOptions);
|
||||||
if (imageFilesInFolder == null || !imageFilesInFolder.Any()) return result;
|
if(imageFilesInFolder?.Any() != true)
|
||||||
if (imageFilesInFolder.Any())
|
return result;
|
||||||
|
if(imageFilesInFolder.Length > 0)
|
||||||
{
|
{
|
||||||
name = name.ToAlphanumericName();
|
name = name.ToAlphanumericName();
|
||||||
foreach (var imageFileInFolder in imageFilesInFolder)
|
foreach(var imageFileInFolder in imageFilesInFolder)
|
||||||
{
|
{
|
||||||
var image = new FileInfo(imageFileInFolder);
|
var image = new FileInfo(imageFileInFolder);
|
||||||
var filenameWithoutExtension = Path.GetFileName(imageFileInFolder).ToAlphanumericName();
|
var filenameWithoutExtension = Path.GetFileName(imageFileInFolder).ToAlphanumericName();
|
||||||
var imageName = image.Name.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
|
try
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(image1) || !File.Exists(image1))
|
if(string.IsNullOrEmpty(image1) || !File.Exists(image1))
|
||||||
{
|
{
|
||||||
return File.Exists(compareToImage);
|
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
|
// Generally a larger image is the preferred image
|
||||||
var isBigger = imageToCompare.Height > imageComparing.Height && imageToCompare.Width > imageComparing.Width;
|
var isBigger = imageToCompare.Height > imageComparing.Height &&
|
||||||
if (isBigger)
|
imageToCompare.Width > imageComparing.Width;
|
||||||
|
if(isBigger)
|
||||||
{
|
{
|
||||||
return true;
|
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;
|
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>();
|
var result = new List<FileInfo>();
|
||||||
if (directory == null || !directory.Exists) return result;
|
if (directory?.Exists != true)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
var imageFilesInFolder = ImageFilesInFolder(directory.FullName, folderSearchOptions);
|
var imageFilesInFolder = ImageFilesInFolder(directory.FullName, folderSearchOptions);
|
||||||
if (imageFilesInFolder == null || !imageFilesInFolder.Any()) return result;
|
if (imageFilesInFolder?.Any() != true)
|
||||||
foreach (var imageFile in imageFilesInFolder)
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
foreach(var imageFile in imageFilesInFolder)
|
||||||
{
|
{
|
||||||
var image = new FileInfo(imageFile);
|
var image = new FileInfo(imageFile);
|
||||||
switch (type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case ImageType.Artist:
|
case ImageType.Artist:
|
||||||
if (IsArtistImage(image)) result.Add(image);
|
if (IsArtistImage(image))
|
||||||
|
{
|
||||||
|
result.Add(image);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ImageType.ArtistSecondary:
|
case ImageType.ArtistSecondary:
|
||||||
if (IsArtistSecondaryImage(image)) result.Add(image);
|
if (IsArtistSecondaryImage(image))
|
||||||
|
{
|
||||||
|
result.Add(image);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ImageType.Release:
|
case ImageType.Release:
|
||||||
if (IsReleaseImage(image)) result.Add(image);
|
if (IsReleaseImage(image))
|
||||||
|
{
|
||||||
|
result.Add(image);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ImageType.ReleaseSecondary:
|
case ImageType.ReleaseSecondary:
|
||||||
if (IsReleaseSecondaryImage(image)) result.Add(image);
|
if (IsReleaseSecondaryImage(image))
|
||||||
|
{
|
||||||
|
result.Add(image);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ImageType.Label:
|
case ImageType.Label:
|
||||||
if (IsLabelImage(image)) result.Add(image);
|
if (IsLabelImage(image))
|
||||||
|
{
|
||||||
|
result.Add(image);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.OrderBy(x => x.Name);
|
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];
|
return new string[0];
|
||||||
}
|
}
|
||||||
if (patterns == null || patterns.Length == 0)
|
if(patterns == null || patterns.Length == 0)
|
||||||
{
|
{
|
||||||
return Directory.GetFiles(path, "*", options);
|
return Directory.GetFiles(path, "*", options);
|
||||||
}
|
}
|
||||||
if (patterns.Length == 1)
|
if(patterns.Length == 1)
|
||||||
{
|
{
|
||||||
return Directory.GetFiles(path, patterns[0], options);
|
return Directory.GetFiles(path, patterns[0], options);
|
||||||
}
|
}
|
||||||
|
@ -186,9 +214,10 @@ namespace Roadie.Library.Imaging
|
||||||
|
|
||||||
public static byte[] ImageDataFromUrl(string imageUrl)
|
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/jpeg;base64,", "")
|
||||||
.Replace("data:image/bmp;base64,", "")
|
.Replace("data:image/bmp;base64,", "")
|
||||||
.Replace("data:image/gif;base64,", "")
|
.Replace("data:image/gif;base64,", "")
|
||||||
|
@ -200,27 +229,22 @@ namespace Roadie.Library.Imaging
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string[] ImageExtensions()
|
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)
|
public static string[] ImageFilesInFolder(string folder, SearchOption searchOption)
|
||||||
{
|
{ return GetFiles(folder, ImageExtensions(), searchOption); }
|
||||||
return GetFiles(folder, ImageExtensions(), searchOption);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string[] ImageMimeTypes()
|
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)
|
public static ImageSearchResult ImageSearchResultForImageUrl(string imageUrl)
|
||||||
{
|
{
|
||||||
if (!WebHelper.IsStringUrl(imageUrl)) return null;
|
if(!WebHelper.IsStringUrl(imageUrl))
|
||||||
|
return null;
|
||||||
var result = new ImageSearchResult();
|
var result = new ImageSearchResult();
|
||||||
var imageBytes = WebHelper.BytesForImageUrl(imageUrl);
|
var imageBytes = WebHelper.BytesForImageUrl(imageUrl);
|
||||||
IImageFormat imageFormat = null;
|
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.Height = image.Height.ToString();
|
||||||
result.Width = image.Width.ToString();
|
result.Width = image.Width.ToString();
|
||||||
|
@ -232,43 +256,54 @@ namespace Roadie.Library.Imaging
|
||||||
|
|
||||||
public static bool IsArtistImage(FileInfo fileinfo)
|
public static bool IsArtistImage(FileInfo fileinfo)
|
||||||
{
|
{
|
||||||
if (fileinfo == null) return false;
|
if(fileinfo == null)
|
||||||
return Regex.IsMatch(fileinfo.Name, @"(band|artist|group|photo)\.(jpg|jpeg|png|bmp|gif)",
|
return false;
|
||||||
RegexOptions.IgnoreCase);
|
return Regex.IsMatch(fileinfo.Name,
|
||||||
|
@"(band|artist|group|photo)\.(jpg|jpeg|png|bmp|gif)",
|
||||||
|
RegexOptions.IgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsArtistSecondaryImage(FileInfo fileinfo)
|
public static bool IsArtistSecondaryImage(FileInfo fileinfo)
|
||||||
{
|
{
|
||||||
if (fileinfo == null) return false;
|
if(fileinfo == null)
|
||||||
|
return false;
|
||||||
return Regex.IsMatch(fileinfo.Name,
|
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)",
|
@"(artist_logo|logo|photo[-_\s]*[0-9]+|(artist[\s_-]+[0-9]+)|(band[\s_-]+[0-9]+))\.(jpg|jpeg|png|bmp|gif)",
|
||||||
RegexOptions.IgnoreCase);
|
RegexOptions.IgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsLabelImage(FileInfo fileinfo)
|
public static bool IsLabelImage(FileInfo fileinfo)
|
||||||
{
|
{
|
||||||
if (fileinfo == null) return false;
|
if(fileinfo == null)
|
||||||
return Regex.IsMatch(fileinfo.Name, @"(label|recordlabel|record_label)\.(jpg|jpeg|png|bmp|gif)",
|
return false;
|
||||||
RegexOptions.IgnoreCase);
|
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)
|
public static bool IsReleaseImage(FileInfo fileinfo, string releaseName = null)
|
||||||
{
|
{
|
||||||
if (fileinfo == null) return false;
|
if(fileinfo == null)
|
||||||
|
return false;
|
||||||
return Regex.IsMatch(fileinfo.Name,
|
return Regex.IsMatch(fileinfo.Name,
|
||||||
@"((f[-_\s]*[0-9]*)|00|art|big[art]*|cover|cvr|folder|release|front[-_\s]*)\.(jpg|jpeg|png|bmp|gif)",
|
@"((f[-_\s]*[0-9]*)|00|art|big[art]*|cover|cvr|folder|release|front[-_\s]*)\.(jpg|jpeg|png|bmp|gif)",
|
||||||
RegexOptions.IgnoreCase);
|
RegexOptions.IgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsReleaseSecondaryImage(FileInfo fileinfo)
|
public static bool IsReleaseSecondaryImage(FileInfo fileinfo)
|
||||||
{
|
{
|
||||||
if (fileinfo == null) return false;
|
if(fileinfo == null)
|
||||||
|
return false;
|
||||||
return Regex.IsMatch(fileinfo.Name,
|
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)",
|
@"((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);
|
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>
|
/// <summary>
|
||||||
/// Resize a given image to given dimensions if needed
|
/// 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="height">Resize to height</param>
|
||||||
/// <param name="forceResize">Force resize</param>
|
/// <param name="forceResize">Force resize</param>
|
||||||
/// <returns>Tuple with bool for did resize and byte array of image</returns>
|
/// <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;
|
return null;
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var outStream = new MemoryStream())
|
using(var outStream = new MemoryStream())
|
||||||
{
|
{
|
||||||
var resized = false;
|
var resized = false;
|
||||||
IImageFormat imageFormat = null;
|
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;
|
var doForce = forceResize ?? false;
|
||||||
if (doForce || image.Width > width || image.Height > height)
|
if(doForce || image.Width > width || image.Height > height)
|
||||||
{
|
{
|
||||||
int newWidth, newHeight;
|
int newWidth, newHeight;
|
||||||
if (doForce)
|
if(doForce)
|
||||||
{
|
{
|
||||||
newWidth = width;
|
newWidth = width;
|
||||||
newHeight = height;
|
newHeight = height;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
{
|
{
|
||||||
float aspect = image.Width / (float)image.Height;
|
float aspect = image.Width / (float)image.Height;
|
||||||
if (aspect < 1)
|
if(aspect < 1)
|
||||||
{
|
{
|
||||||
newWidth = (int)(width * aspect);
|
newWidth = (int)(width * aspect);
|
||||||
newHeight = (int)(newWidth / aspect);
|
newHeight = (int)(newWidth / aspect);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
{
|
{
|
||||||
newHeight = (int)(height / aspect);
|
newHeight = (int)(height / aspect);
|
||||||
newWidth = (int)(newHeight * aspect);
|
newWidth = (int)(newHeight * aspect);
|
||||||
|
@ -322,8 +358,7 @@ namespace Roadie.Library.Imaging
|
||||||
}
|
}
|
||||||
return new Tuple<bool, byte[]>(resized, outStream.ToArray());
|
return new Tuple<bool, byte[]>(resized, outStream.ToArray());
|
||||||
}
|
}
|
||||||
}
|
} catch(Exception ex)
|
||||||
catch (Exception ex)
|
|
||||||
{
|
{
|
||||||
Trace.WriteLine($"Error Resizing Image [{ex}]", "Warning");
|
Trace.WriteLine($"Error Resizing Image [{ex}]", "Warning");
|
||||||
}
|
}
|
||||||
|
@ -331,12 +366,13 @@ namespace Roadie.Library.Imaging
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get image data from all sources for either fileanme or MetaData
|
/// Get image data from all sources for either fileanme or MetaData
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filename">Name of the File (ie a CUE file)</param>
|
/// <param name="filename">Name of the File (ie a CUE file)</param>
|
||||||
/// <param name="metaData">Populated MetaData</param>
|
/// <param name="metaData">Populated MetaData</param>
|
||||||
/// <returns></returns>
|
public static AudioMetaDataImage GetPictureForMetaData(IRoadieSettings configuration,
|
||||||
public static AudioMetaDataImage GetPictureForMetaData(IRoadieSettings configuration, string filename, AudioMetaData metaData)
|
string filename,
|
||||||
|
AudioMetaData metaData)
|
||||||
{
|
{
|
||||||
SimpleContract.Requires<ArgumentException>(!string.IsNullOrEmpty(filename), "Invalid Filename");
|
SimpleContract.Requires<ArgumentException>(!string.IsNullOrEmpty(filename), "Invalid Filename");
|
||||||
SimpleContract.Requires<ArgumentException>(metaData != null, "Invalid MetaData");
|
SimpleContract.Requires<ArgumentException>(metaData != null, "Invalid MetaData");
|
||||||
|
@ -345,7 +381,7 @@ namespace Roadie.Library.Imaging
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Does image exist with the same filename
|
/// Does image exist with the same filename
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filename">Name of the File (ie a CUE file)</param>
|
/// <param name="filename">Name of the File (ie a CUE file)</param>
|
||||||
/// <returns>Null if not found else populated image</returns>
|
/// <returns>Null if not found else populated image</returns>
|
||||||
|
@ -353,7 +389,7 @@ namespace Roadie.Library.Imaging
|
||||||
{
|
{
|
||||||
AudioMetaDataImage imageMetaData = null;
|
AudioMetaDataImage imageMetaData = null;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(filename))
|
if(string.IsNullOrEmpty(filename))
|
||||||
{
|
{
|
||||||
return imageMetaData;
|
return imageMetaData;
|
||||||
}
|
}
|
||||||
|
@ -361,9 +397,9 @@ namespace Roadie.Library.Imaging
|
||||||
{
|
{
|
||||||
var fileInfo = new FileInfo(filename);
|
var fileInfo = new FileInfo(filename);
|
||||||
var ReleaseCover = Path.ChangeExtension(filename, "jpg");
|
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
|
imageMetaData = new AudioMetaDataImage
|
||||||
{
|
{
|
||||||
|
@ -372,24 +408,23 @@ namespace Roadie.Library.Imaging
|
||||||
MimeType = Library.Processors.FileProcessor.DetermineFileType(fileInfo)
|
MimeType = Library.Processors.FileProcessor.DetermineFileType(fileInfo)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// Is there a picture in filename folder (for the Release)
|
// Is there a picture in filename folder (for the Release)
|
||||||
var pictures = fileInfo.Directory.GetFiles("*.jpg");
|
var pictures = fileInfo.Directory.GetFiles("*.jpg");
|
||||||
var tagImages = new List<AudioMetaDataImage>();
|
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
|
// See if there is a "cover" or "front" jpg file if so use it
|
||||||
picture = pictures.FirstOrDefault(x =>
|
FileInfo picture = Array.Find(pictures,
|
||||||
x.Name.Equals("cover", StringComparison.OrdinalIgnoreCase));
|
x => x.Name.Equals("cover", StringComparison.OrdinalIgnoreCase));
|
||||||
if (picture == null)
|
if(picture == null)
|
||||||
picture = pictures.FirstOrDefault(x =>
|
picture = Array.Find(pictures,
|
||||||
x.Name.Equals("front", StringComparison.OrdinalIgnoreCase));
|
x => x.Name.Equals("front", StringComparison.OrdinalIgnoreCase));
|
||||||
if (picture == null) picture = pictures.First();
|
if(picture == null)
|
||||||
if (picture != null)
|
picture = pictures[0];
|
||||||
using (var processor = new ImageProcessor(configuration))
|
if(picture != null)
|
||||||
|
using(var processor = new ImageProcessor(configuration))
|
||||||
{
|
{
|
||||||
imageMetaData = new AudioMetaDataImage
|
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());
|
Trace.WriteLine(ex, ex.Serialize());
|
||||||
}
|
}
|
||||||
|
@ -412,97 +445,138 @@ namespace Roadie.Library.Imaging
|
||||||
return imageMetaData;
|
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)
|
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)
|
public static models.Image MakePlaylistThumbnailImage(IRoadieSettings configuration,
|
||||||
{
|
IHttpContext httpContext,
|
||||||
return MakeThumbnailImage(configuration, httpContext, id, "playlist");
|
Guid id)
|
||||||
}
|
{ return MakeThumbnailImage(configuration, httpContext, id, "playlist"); }
|
||||||
|
|
||||||
public static models.Image MakeReleaseThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
|
public static models.Image MakeReleaseThumbnailImage(IRoadieSettings configuration,
|
||||||
{
|
IHttpContext httpContext,
|
||||||
return MakeThumbnailImage(configuration, httpContext, id, "release");
|
Guid id)
|
||||||
}
|
{ return MakeThumbnailImage(configuration, httpContext, id, "release"); }
|
||||||
|
|
||||||
public static models.Image MakeTrackThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
|
public static models.Image MakeTrackThumbnailImage(IRoadieSettings configuration,
|
||||||
{
|
IHttpContext httpContext,
|
||||||
return MakeThumbnailImage(configuration, httpContext, id, "track");
|
Guid id)
|
||||||
}
|
{ return MakeThumbnailImage(configuration, httpContext, id, "track"); }
|
||||||
|
|
||||||
public static models.Image MakeUserThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
|
public static models.Image MakeUserThumbnailImage(IRoadieSettings configuration,
|
||||||
{
|
IHttpContext httpContext,
|
||||||
return MakeThumbnailImage(configuration, httpContext, id, "user");
|
Guid id)
|
||||||
}
|
{ return MakeThumbnailImage(configuration, httpContext, id, "user"); }
|
||||||
|
|
||||||
public static models.Image MakeLabelThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
|
public static models.Image MakeLabelThumbnailImage(IRoadieSettings configuration,
|
||||||
{
|
IHttpContext httpContext,
|
||||||
return MakeThumbnailImage(configuration, httpContext, id, "label");
|
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");
|
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,
|
if(type == ImageType.ArtistSecondary)
|
||||||
$"{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)
|
|
||||||
{
|
{
|
||||||
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)
|
public static models.Image MakeGenreThumbnailImage(IRoadieSettings configuration,
|
||||||
{
|
IHttpContext httpContext,
|
||||||
return MakeThumbnailImage(configuration, httpContext, id, "genre");
|
Guid id)
|
||||||
}
|
{ return MakeThumbnailImage(configuration, httpContext, id, "genre"); }
|
||||||
|
|
||||||
public static models.Image MakeUnknownImage(IHttpContext httpContext, string unknownType = "unknown")
|
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)}",
|
return new models.Image($"{httpContext.ImageBaseUrl}/{id}/{width}/{height}/{(includeCachebuster ? DateTime.UtcNow.Ticks.ToString() : string.Empty)}",
|
||||||
caption,
|
caption,
|
||||||
$"{httpContext.ImageBaseUrl}/{id}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
|
$"{httpContext.ImageBaseUrl}/{id}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static models.Image MakeImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, string type, IImageSize imageSize)
|
public static models.Image MakeImage(IRoadieSettings configuration,
|
||||||
{
|
IHttpContext httpContext,
|
||||||
return MakeImage(configuration, httpContext, id, type, imageSize.Width, imageSize.Height);
|
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 ||
|
if(width.HasValue &&
|
||||||
height.Value != configuration.ThumbnailImageSize.Height))
|
height.HasValue &&
|
||||||
return new models.Image(
|
(width.Value != configuration.ThumbnailImageSize.Width ||
|
||||||
$"{httpContext.ImageBaseUrl}/{type}/{id}/{width}/{height}/{(includeCachebuster ? DateTime.UtcNow.Ticks.ToString() : string.Empty)}",
|
height.Value != configuration.ThumbnailImageSize.Height))
|
||||||
caption,
|
return new models.Image($"{httpContext.ImageBaseUrl}/{type}/{id}/{width}/{height}/{(includeCachebuster ? DateTime.UtcNow.Ticks.ToString() : string.Empty)}",
|
||||||
$"{httpContext.ImageBaseUrl}/{type}/{id}/{configuration.ThumbnailImageSize.Width}/{configuration.ThumbnailImageSize.Height}");
|
caption,
|
||||||
|
$"{httpContext.ImageBaseUrl}/{type}/{id}/{configuration.ThumbnailImageSize.Width}/{configuration.ThumbnailImageSize.Height}");
|
||||||
return new models.Image($"{httpContext.ImageBaseUrl}/{type}/{id}", caption, null);
|
return new models.Image($"{httpContext.ImageBaseUrl}/{type}/{id}", caption, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace Roadie.Library.Inspect
|
||||||
{
|
{
|
||||||
public class Inspector
|
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<IInspectorDirectoryPlugin> _directoryPlugins;
|
||||||
private IEnumerable<IInspectorFilePlugin> _filePlugins;
|
private IEnumerable<IInspectorFilePlugin> _filePlugins;
|
||||||
|
@ -49,13 +49,15 @@ namespace Roadie.Library.Inspect
|
||||||
foreach (var t in types)
|
foreach (var t in types)
|
||||||
if (t.GetInterface("IInspectorDirectoryPlugin") != null && !t.IsAbstract && !t.IsInterface)
|
if (t.GetInterface("IInspectorDirectoryPlugin") != null && !t.IsAbstract && !t.IsInterface)
|
||||||
{
|
{
|
||||||
var plugin =
|
var plugin = Activator.CreateInstance(t, Configuration, CacheManager, Logger, TagsHelper) as IInspectorDirectoryPlugin;
|
||||||
Activator.CreateInstance(t, Configuration, CacheManager, Logger, TagsHelper) as
|
|
||||||
IInspectorDirectoryPlugin;
|
|
||||||
if (plugin.IsEnabled)
|
if (plugin.IsEnabled)
|
||||||
|
{
|
||||||
plugins.Add(plugin);
|
plugins.Add(plugin);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
Console.WriteLine($"╠╣ Not Loading Disabled Plugin [{plugin.Description}]");
|
Console.WriteLine($"╠╣ Not Loading Disabled Plugin [{plugin.Description}]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -84,17 +86,20 @@ namespace Roadie.Library.Inspect
|
||||||
.SelectMany(s => s.GetTypes())
|
.SelectMany(s => s.GetTypes())
|
||||||
.Where(p => type.IsAssignableFrom(p));
|
.Where(p => type.IsAssignableFrom(p));
|
||||||
foreach (var t in types)
|
foreach (var t in types)
|
||||||
|
{
|
||||||
if (t.GetInterface("IInspectorFilePlugin") != null && !t.IsAbstract && !t.IsInterface)
|
if (t.GetInterface("IInspectorFilePlugin") != null && !t.IsAbstract && !t.IsInterface)
|
||||||
{
|
{
|
||||||
var plugin =
|
var plugin = Activator.CreateInstance(t, Configuration, CacheManager, Logger, TagsHelper) as IInspectorFilePlugin;
|
||||||
Activator.CreateInstance(t, Configuration, CacheManager, Logger, TagsHelper) as
|
|
||||||
IInspectorFilePlugin;
|
|
||||||
|
|
||||||
if (plugin.IsEnabled)
|
if (plugin.IsEnabled)
|
||||||
|
{
|
||||||
plugins.Add(plugin);
|
plugins.Add(plugin);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
Console.WriteLine($"╠╣ Not Loading Disabled Plugin [{plugin.Description}]");
|
Console.WriteLine($"╠╣ Not Loading Disabled Plugin [{plugin.Description}]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -147,10 +152,12 @@ namespace Roadie.Library.Inspect
|
||||||
var numbers = 0;
|
var numbers = 0;
|
||||||
var bytes = System.Text.Encoding.ASCII.GetBytes(input);
|
var bytes = System.Text.Encoding.ASCII.GetBytes(input);
|
||||||
var looper = bytes.Length / 4;
|
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;
|
if (numbers < 0) numbers *= -1;
|
||||||
var token = hashids.Encode(numbers);
|
return hashids.Encode(numbers);
|
||||||
return token;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Inspect(bool doCopy, bool isReadOnly, string directoryToInspect, string destination, bool dontAppendSubFolder, bool dontDeleteEmptyFolders, bool dontRunPreScripts)
|
public void Inspect(bool doCopy, bool isReadOnly, string directoryToInspect, string destination, bool dontAppendSubFolder, bool dontDeleteEmptyFolders, bool dontRunPreScripts)
|
||||||
|
@ -171,15 +178,15 @@ namespace Roadie.Library.Inspect
|
||||||
|
|
||||||
string scriptResult = null;
|
string scriptResult = null;
|
||||||
// Run PreInspect script
|
// Run PreInspect script
|
||||||
if(dontRunPreScripts)
|
if (dontRunPreScripts)
|
||||||
{
|
{
|
||||||
Console.BackgroundColor = ConsoleColor.Blue;
|
Console.BackgroundColor = ConsoleColor.Blue;
|
||||||
Console.ForegroundColor = ConsoleColor.White;
|
Console.ForegroundColor = ConsoleColor.White;
|
||||||
Console.WriteLine($"Skipping PreInspectScript.");
|
Console.WriteLine("Skipping PreInspectScript.");
|
||||||
Console.ResetColor();
|
Console.ResetColor();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
scriptResult = RunScript(Configuration.Processing.PreInspectScript, doCopy, isReadOnly, directoryToInspect, destination);
|
scriptResult = RunScript(Configuration.Processing.PreInspectScript, doCopy, isReadOnly, directoryToInspect, destination);
|
||||||
if (!string.IsNullOrEmpty(scriptResult))
|
if (!string.IsNullOrEmpty(scriptResult))
|
||||||
{
|
{
|
||||||
|
@ -217,7 +224,7 @@ namespace Roadie.Library.Inspect
|
||||||
|
|
||||||
// Get all the MP3 files in 'directory'
|
// Get all the MP3 files in 'directory'
|
||||||
var files = Directory.GetFiles(directory, "*.mp3", SearchOption.TopDirectoryOnly);
|
var files = Directory.GetFiles(directory, "*.mp3", SearchOption.TopDirectoryOnly);
|
||||||
if (files != null && files.Any())
|
if (files?.Any() == true)
|
||||||
{
|
{
|
||||||
if (!isReadOnly && !createdDestinationFolder && !Directory.Exists(dest))
|
if (!isReadOnly && !createdDestinationFolder && !Directory.Exists(dest))
|
||||||
{
|
{
|
||||||
|
@ -226,20 +233,19 @@ namespace Roadie.Library.Inspect
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run directory plugins against current directory
|
// Run directory plugins against current directory
|
||||||
foreach (var plugin in DirectoryPlugins.Where(x => !x.IsPostProcessingPlugin)
|
foreach (var plugin in DirectoryPlugins.Where(x => !x.IsPostProcessingPlugin).OrderBy(x => x.Order))
|
||||||
.OrderBy(x => x.Order))
|
|
||||||
{
|
{
|
||||||
Console.WriteLine($"╠╬═ Running Directory Plugin {plugin.Description}");
|
Console.WriteLine($"╠╬═ Running Directory Plugin {plugin.Description}");
|
||||||
var pluginResult = plugin.Process(directoryInfo);
|
var pluginResult = plugin.Process(directoryInfo);
|
||||||
if (!pluginResult.IsSuccess)
|
if (!pluginResult.IsSuccess)
|
||||||
{
|
{
|
||||||
Console.WriteLine(
|
Console.WriteLine($"📛 Plugin Failed: Error [{JsonConvert.SerializeObject(pluginResult)}]");
|
||||||
$"📛 Plugin Failed: Error [{JsonConvert.SerializeObject(pluginResult)}]");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(pluginResult.Data))
|
if (!string.IsNullOrEmpty(pluginResult.Data))
|
||||||
|
{
|
||||||
Console.WriteLine($"╠╣ Directory Plugin Message: {pluginResult.Data}");
|
Console.WriteLine($"╠╣ Directory Plugin Message: {pluginResult.Data}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("╠╝");
|
Console.WriteLine("╠╝");
|
||||||
|
@ -263,8 +269,7 @@ namespace Roadie.Library.Inspect
|
||||||
if (!originalMetaData.IsValid)
|
if (!originalMetaData.IsValid)
|
||||||
{
|
{
|
||||||
Console.ForegroundColor = ConsoleColor.DarkYellow;
|
Console.ForegroundColor = ConsoleColor.DarkYellow;
|
||||||
Console.WriteLine(
|
Console.WriteLine($"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(originalMetaData)}");
|
||||||
$"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(originalMetaData)}");
|
|
||||||
Console.WriteLine($"╟ [{JsonConvert.SerializeObject(tagLib, Newtonsoft.Json.Formatting.Indented)}]");
|
Console.WriteLine($"╟ [{JsonConvert.SerializeObject(tagLib, Newtonsoft.Json.Formatting.Indented)}]");
|
||||||
Console.ResetColor();
|
Console.ResetColor();
|
||||||
}
|
}
|
||||||
|
@ -274,13 +279,11 @@ namespace Roadie.Library.Inspect
|
||||||
foreach (var plugin in FilePlugins.OrderBy(x => x.Order))
|
foreach (var plugin in FilePlugins.OrderBy(x => x.Order))
|
||||||
{
|
{
|
||||||
Console.WriteLine($"╟┤ Running File Plugin {plugin.Description}");
|
Console.WriteLine($"╟┤ Running File Plugin {plugin.Description}");
|
||||||
OperationResult<AudioMetaData> pluginResult = null;
|
OperationResult<AudioMetaData> pluginResult = plugin.Process(pluginMetaData);
|
||||||
pluginResult = plugin.Process(pluginMetaData);
|
|
||||||
if (!pluginResult.IsSuccess)
|
if (!pluginResult.IsSuccess)
|
||||||
{
|
{
|
||||||
Console.ForegroundColor = ConsoleColor.Red;
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
Console.WriteLine(
|
Console.WriteLine($"📛 Plugin Failed: Error [{JsonConvert.SerializeObject(pluginResult)}]");
|
||||||
$"📛 Plugin Failed: Error [{JsonConvert.SerializeObject(pluginResult)}]");
|
|
||||||
Console.ResetColor();
|
Console.ResetColor();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -291,8 +294,7 @@ namespace Roadie.Library.Inspect
|
||||||
if (!pluginMetaData.IsValid)
|
if (!pluginMetaData.IsValid)
|
||||||
{
|
{
|
||||||
Console.ForegroundColor = ConsoleColor.Red;
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
Console.WriteLine(
|
Console.WriteLine($"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(pluginMetaData)}");
|
||||||
$"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(pluginMetaData)}");
|
|
||||||
Console.ResetColor();
|
Console.ResetColor();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -301,16 +303,17 @@ namespace Roadie.Library.Inspect
|
||||||
if (originalMetaData != null && pluginMetaData != null)
|
if (originalMetaData != null && pluginMetaData != null)
|
||||||
{
|
{
|
||||||
var differences = Comparer.Compare(originalMetaData, pluginMetaData);
|
var differences = Comparer.Compare(originalMetaData, pluginMetaData);
|
||||||
if (differences.Any())
|
if (differences.Count > 0)
|
||||||
{
|
{
|
||||||
var skipDifferences = new List<string>
|
var skipDifferences = new List<string> { "AudioMetaDataWeights", "FileInfo", "Images", "TrackArtists" };
|
||||||
{"AudioMetaDataWeights", "FileInfo", "Images", "TrackArtists"};
|
|
||||||
var differencesDescription = $"{Environment.NewLine}";
|
var differencesDescription = $"{Environment.NewLine}";
|
||||||
foreach (var difference in differences)
|
foreach (var difference in differences)
|
||||||
{
|
{
|
||||||
if (skipDifferences.Contains(difference.Name)) continue;
|
if (skipDifferences.Contains(difference.Name))
|
||||||
differencesDescription +=
|
{
|
||||||
$"╟ || {difference.Name} : Was [{difference.OldValue}] Now [{difference.NewValue}]{Environment.NewLine}";
|
continue;
|
||||||
|
}
|
||||||
|
differencesDescription += $"╟ || {difference.Name} : Was [{difference.OldValue}] Now [{difference.NewValue}]{Environment.NewLine}";
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.Write($"╟ ≡ != ID3 Tag Modified: {differencesDescription}");
|
Console.Write($"╟ ≡ != ID3 Tag Modified: {differencesDescription}");
|
||||||
|
@ -339,15 +342,13 @@ namespace Roadie.Library.Inspect
|
||||||
{
|
{
|
||||||
var oBad = originalMetaData == null;
|
var oBad = originalMetaData == null;
|
||||||
var pBad = pluginMetaData == null;
|
var pBad = pluginMetaData == null;
|
||||||
Console.WriteLine(
|
Console.WriteLine($"╟ !! MetaData comparison skipped. {(oBad ? "Pre MetaData is Invalid" : string.Empty)} {(pBad ? "Post MetaData is Invalid" : string.Empty)}");
|
||||||
$"╟ !! MetaData comparison skipped. {(oBad ? "Pre MetaData is Invalid" : "")} {(pBad ? "Post MetaData is Invalid" : "")}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pluginMetaData.IsValid)
|
if (!pluginMetaData.IsValid)
|
||||||
{
|
{
|
||||||
Console.ForegroundColor = ConsoleColor.Red;
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
Console.WriteLine(
|
Console.WriteLine($"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(pluginMetaData)}");
|
||||||
$"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(pluginMetaData)}");
|
|
||||||
Console.ResetColor();
|
Console.ResetColor();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -357,11 +358,16 @@ namespace Roadie.Library.Inspect
|
||||||
Console.ResetColor();
|
Console.ResetColor();
|
||||||
|
|
||||||
var artistToken = ArtistInspectorToken(tagLib.Data);
|
var artistToken = ArtistInspectorToken(tagLib.Data);
|
||||||
if (!artistsFound.Contains(artistToken)) artistsFound.Add(artistToken);
|
if (!artistsFound.Contains(artistToken))
|
||||||
|
{
|
||||||
|
artistsFound.Add(artistToken);
|
||||||
|
}
|
||||||
var releaseToken = ReleaseInspectorToken(tagLib.Data);
|
var releaseToken = ReleaseInspectorToken(tagLib.Data);
|
||||||
if (!releasesFound.Contains(releaseToken)) releasesFound.Add(releaseToken);
|
if (!releasesFound.Contains(releaseToken))
|
||||||
var newFileName =
|
{
|
||||||
$"CD{(tagLib.Data.Disc ?? ID3TagsHelper.DetermineDiscNumber(tagLib.Data)).ToString("000")}_{tagLib.Data.TrackNumber.Value.ToString("0000")}.mp3";
|
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
|
// Artist sub folder is created to hold Releases for Artist and Artist Images
|
||||||
var artistSubDirectory = directory == dest
|
var artistSubDirectory = directory == dest
|
||||||
? fileInfo.DirectoryName
|
? fileInfo.DirectoryName
|
||||||
|
@ -371,40 +377,35 @@ namespace Roadie.Library.Inspect
|
||||||
? fileInfo.DirectoryName
|
? fileInfo.DirectoryName
|
||||||
: Path.Combine(dest, artistToken, releaseToken);
|
: Path.Combine(dest, artistToken, releaseToken);
|
||||||
if (!isReadOnly && !Directory.Exists(subDirectory))
|
if (!isReadOnly && !Directory.Exists(subDirectory))
|
||||||
|
{
|
||||||
Directory.CreateDirectory(subDirectory);
|
Directory.CreateDirectory(subDirectory);
|
||||||
|
}
|
||||||
// Inspect images
|
// Inspect images
|
||||||
if (!inspectedImagesInDirectories.Contains(directoryInfo.FullName))
|
if (!inspectedImagesInDirectories.Contains(directoryInfo.FullName))
|
||||||
{
|
{
|
||||||
// Get all artist images and move to artist folder
|
// Get all artist images and move to artist folder
|
||||||
var foundArtistImages = new List<FileInfo>();
|
var foundArtistImages = new List<FileInfo>();
|
||||||
foundArtistImages.AddRange(ImageHelper.FindImagesByName(directoryInfo,
|
foundArtistImages.AddRange(ImageHelper.FindImagesByName(directoryInfo, tagLib.Data.Artist, SearchOption.TopDirectoryOnly));
|
||||||
tagLib.Data.Artist, SearchOption.TopDirectoryOnly));
|
foundArtistImages.AddRange(ImageHelper.FindImagesByName(directoryInfo.Parent, tagLib.Data.Artist, SearchOption.TopDirectoryOnly));
|
||||||
foundArtistImages.AddRange(ImageHelper.FindImagesByName(directoryInfo.Parent,
|
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo.Parent, ImageType.Artist, SearchOption.TopDirectoryOnly));
|
||||||
tagLib.Data.Artist, SearchOption.TopDirectoryOnly));
|
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo.Parent, ImageType.ArtistSecondary, SearchOption.TopDirectoryOnly));
|
||||||
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(
|
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo, ImageType.Artist, SearchOption.TopDirectoryOnly));
|
||||||
directoryInfo.Parent, ImageType.Artist, SearchOption.TopDirectoryOnly));
|
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo, ImageType.ArtistSecondary, 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)
|
foreach (var artistImage in foundArtistImages)
|
||||||
|
{
|
||||||
InspectImage(isReadOnly, doCopy, dest, artistSubDirectory, artistImage);
|
InspectImage(isReadOnly, doCopy, dest, artistSubDirectory, artistImage);
|
||||||
|
}
|
||||||
|
|
||||||
// Get all release images and move to release folder
|
// Get all release images and move to release folder
|
||||||
var foundReleaseImages = new List<FileInfo>();
|
var foundReleaseImages = new List<FileInfo>();
|
||||||
foundReleaseImages.AddRange(
|
foundReleaseImages.AddRange(ImageHelper.FindImagesByName(directoryInfo, tagLib.Data.Release));
|
||||||
ImageHelper.FindImagesByName(directoryInfo, tagLib.Data.Release));
|
foundReleaseImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo, ImageType.Release));
|
||||||
foundReleaseImages.AddRange(
|
foundReleaseImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo, ImageType.ReleaseSecondary));
|
||||||
ImageHelper.FindImageTypeInDirectory(directoryInfo, ImageType.Release));
|
|
||||||
foundReleaseImages.AddRange(
|
|
||||||
ImageHelper.FindImageTypeInDirectory(directoryInfo,
|
|
||||||
ImageType.ReleaseSecondary));
|
|
||||||
foreach (var foundReleaseImage in foundReleaseImages)
|
foreach (var foundReleaseImage in foundReleaseImages)
|
||||||
|
{
|
||||||
InspectImage(isReadOnly, doCopy, dest, subDirectory, foundReleaseImage);
|
InspectImage(isReadOnly, doCopy, dest, subDirectory, foundReleaseImage);
|
||||||
|
}
|
||||||
inspectedImagesInDirectories.Add(directoryInfo.FullName);
|
inspectedImagesInDirectories.Add(directoryInfo.FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,8 +413,7 @@ namespace Roadie.Library.Inspect
|
||||||
var newPath = Path.Combine(dest, subDirectory, newFileName.ToFileNameFriendly());
|
var newPath = Path.Combine(dest, subDirectory, newFileName.ToFileNameFriendly());
|
||||||
if (isReadOnly)
|
if (isReadOnly)
|
||||||
{
|
{
|
||||||
Console.WriteLine(
|
Console.WriteLine($"╟ 🔒 Read Only Mode: File would be [{(doCopy ? "Copied" : "Moved")}] to [{newPath}]");
|
||||||
$"╟ 🔒 Read Only Mode: File would be [{(doCopy ? "Copied" : "Moved")}] to [{newPath}]");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -464,8 +464,7 @@ namespace Roadie.Library.Inspect
|
||||||
|
|
||||||
Console.WriteLine("╠╝");
|
Console.WriteLine("╠╝");
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
Console.WriteLine(
|
Console.WriteLine($"╚═ Elapsed Time {sw.ElapsedMilliseconds.ToString("0000000")}, Artists {artistsFound.Count}, Releases {releasesFound.Count}, MP3s {mp3FilesFoundCount} ═╝");
|
||||||
$"╚═ Elapsed Time {sw.ElapsedMilliseconds.ToString("0000000")}, Artists {artistsFound.Count()}, Releases {releasesFound.Count()}, MP3s {mp3FilesFoundCount} ═╝");
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -492,8 +491,7 @@ namespace Roadie.Library.Inspect
|
||||||
{
|
{
|
||||||
Console.BackgroundColor = ConsoleColor.Blue;
|
Console.BackgroundColor = ConsoleColor.Blue;
|
||||||
Console.ForegroundColor = ConsoleColor.White;
|
Console.ForegroundColor = ConsoleColor.White;
|
||||||
Console.WriteLine(
|
Console.WriteLine($"PostInspectScript Results: {Environment.NewLine + scriptResult + Environment.NewLine}");
|
||||||
$"PostInspectScript Results: {Environment.NewLine + scriptResult + Environment.NewLine}");
|
|
||||||
Console.ResetColor();
|
Console.ResetColor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -521,17 +519,22 @@ namespace Roadie.Library.Inspect
|
||||||
looper++;
|
looper++;
|
||||||
newImagePath = Path.Combine(dest, subdirectory, looper.ToString("00"), image.Name);
|
newImagePath = Path.Combine(dest, subdirectory, looper.ToString("00"), image.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isReadOnly)
|
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
|
else
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!doCopy)
|
if (!doCopy)
|
||||||
|
{
|
||||||
image.MoveTo(newImagePath);
|
image.MoveTo(newImagePath);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
image.CopyTo(newImagePath, true);
|
image.CopyTo(newImagePath, true);
|
||||||
|
}
|
||||||
Console.ForegroundColor = ConsoleColor.DarkYellow;
|
Console.ForegroundColor = ConsoleColor.DarkYellow;
|
||||||
Console.WriteLine($"╠═ 🚛 {(doCopy ? "Copied" : "Moved")} Image File to [{newImagePath}]");
|
Console.WriteLine($"╠═ 🚛 {(doCopy ? "Copied" : "Moved")} Image File to [{newImagePath}]");
|
||||||
}
|
}
|
||||||
|
@ -539,9 +542,9 @@ namespace Roadie.Library.Inspect
|
||||||
{
|
{
|
||||||
Logger.LogError(ex);
|
Logger.LogError(ex);
|
||||||
Console.ForegroundColor = ConsoleColor.Red;
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
Console.WriteLine(
|
Console.WriteLine($"📛 Error file [{image.FullName}], newImagePath [{newImagePath}], Exception: [{ex}]");
|
||||||
$"📛 Error file [{image.FullName}], newImagePath [{newImagePath}], Exception: [{ex}]");
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.ResetColor();
|
Console.ResetColor();
|
||||||
|
@ -588,9 +591,17 @@ namespace Roadie.Library.Inspect
|
||||||
var script = File.ReadAllText(scriptFilename);
|
var script = File.ReadAllText(scriptFilename);
|
||||||
using (var ps = PowerShell.Create())
|
using (var ps = PowerShell.Create())
|
||||||
{
|
{
|
||||||
var r = "";
|
var r = string.Empty;
|
||||||
var results = ps.AddScript(script).Invoke();
|
var results = ps.AddScript(script)
|
||||||
foreach (var result in results) r += result + Environment.NewLine;
|
.AddParameter("DoCopy", doCopy)
|
||||||
|
.AddParameter("IsReadOnly", isReadOnly)
|
||||||
|
.AddParameter("DirectoryToInspect", directoryToInspect)
|
||||||
|
.AddParameter("Dest", dest)
|
||||||
|
.Invoke();
|
||||||
|
foreach (var result in results)
|
||||||
|
{
|
||||||
|
r += result + Environment.NewLine;
|
||||||
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -604,7 +615,6 @@ namespace Roadie.Library.Inspect
|
||||||
|
|
||||||
public class LoggingTraceListener : TraceListener
|
public class LoggingTraceListener : TraceListener
|
||||||
{
|
{
|
||||||
|
|
||||||
public override void Write(string message)
|
public override void Write(string message)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"╠╬═ { message }");
|
Console.WriteLine($"╠╬═ { message }");
|
||||||
|
@ -614,7 +624,5 @@ namespace Roadie.Library.Inspect
|
||||||
{
|
{
|
||||||
Console.WriteLine($"╠╬═ { message }");
|
Console.WriteLine($"╠╬═ { message }");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -33,7 +33,7 @@ namespace Roadie.Library.Scrobble
|
||||||
/// indication of what music player they're using.
|
/// indication of what music player they're using.
|
||||||
/// </remark>
|
/// </remark>
|
||||||
/// </summary>
|
/// </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>
|
/// <summary>
|
||||||
/// Send a Scrobble Request
|
/// Send a Scrobble Request
|
||||||
|
@ -42,7 +42,7 @@ namespace Roadie.Library.Scrobble
|
||||||
/// listening history and generate personalised charts and recommendations (and more).
|
/// listening history and generate personalised charts and recommendations (and more).
|
||||||
/// </remark>
|
/// </remark>
|
||||||
/// </summary>
|
/// </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);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -37,7 +37,7 @@ namespace Roadie.Library.Scrobble
|
||||||
{
|
{
|
||||||
Data = true,
|
Data = true,
|
||||||
IsSuccess = true
|
IsSuccess = true
|
||||||
});
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -59,12 +59,13 @@ namespace Roadie.Library.Scrobble
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
var track = DbContext.Tracks
|
var track = await DbContext.Tracks
|
||||||
.Include(x => x.ReleaseMedia)
|
.Include(x => x.ReleaseMedia)
|
||||||
.Include(x => x.ReleaseMedia.Release)
|
.Include(x => x.ReleaseMedia.Release)
|
||||||
.Include(x => x.ReleaseMedia.Release.Artist)
|
.Include(x => x.ReleaseMedia.Release.Artist)
|
||||||
.Include(x => x.TrackArtist)
|
.Include(x => x.TrackArtist)
|
||||||
.FirstOrDefault(x => x.RoadieId == scrobble.TrackId);
|
.FirstOrDefaultAsync(x => x.RoadieId == scrobble.TrackId)
|
||||||
|
.ConfigureAwait(false);
|
||||||
if (track == null)
|
if (track == null)
|
||||||
{
|
{
|
||||||
return new OperationResult<bool>($"Scrobble: Unable To Find Track [{scrobble.TrackId}]");
|
return new OperationResult<bool>($"Scrobble: Unable To Find Track [{scrobble.TrackId}]");
|
||||||
|
@ -80,8 +81,8 @@ namespace Roadie.Library.Scrobble
|
||||||
{
|
{
|
||||||
if (roadieUser != null)
|
if (roadieUser != null)
|
||||||
{
|
{
|
||||||
var user = DbContext.Users.FirstOrDefault(x => x.RoadieId == roadieUser.UserId);
|
var user = await DbContext.Users.FirstOrDefaultAsync(x => x.RoadieId == roadieUser.UserId).ConfigureAwait(false);
|
||||||
userTrack = DbContext.UserTracks.FirstOrDefault(x => x.UserId == user.Id && x.TrackId == track.Id);
|
userTrack = await DbContext.UserTracks.FirstOrDefaultAsync(x => x.UserId == user.Id && x.TrackId == track.Id).ConfigureAwait(false);
|
||||||
if (userTrack == null)
|
if (userTrack == null)
|
||||||
{
|
{
|
||||||
userTrack = new data.UserTrack(now)
|
userTrack = new data.UserTrack(now)
|
||||||
|
@ -89,7 +90,7 @@ namespace Roadie.Library.Scrobble
|
||||||
UserId = user.Id,
|
UserId = user.Id,
|
||||||
TrackId = track.Id
|
TrackId = track.Id
|
||||||
};
|
};
|
||||||
DbContext.UserTracks.Add(userTrack);
|
await DbContext.UserTracks.AddAsync(userTrack).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
userTrack.LastPlayed = now;
|
userTrack.LastPlayed = now;
|
||||||
|
@ -101,20 +102,21 @@ namespace Roadie.Library.Scrobble
|
||||||
track.PlayedCount = (track.PlayedCount ?? 0) + 1;
|
track.PlayedCount = (track.PlayedCount ?? 0) + 1;
|
||||||
track.LastPlayed = now;
|
track.LastPlayed = now;
|
||||||
|
|
||||||
var release = DbContext.Releases
|
var release = await DbContext.Releases
|
||||||
.Include(x => x.Artist)
|
.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.LastPlayed = now;
|
||||||
release.PlayedCount = (release.PlayedCount ?? 0) + 1;
|
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.LastPlayed = now;
|
||||||
artist.PlayedCount = (artist.PlayedCount ?? 0) + 1;
|
artist.PlayedCount = (artist.PlayedCount ?? 0) + 1;
|
||||||
|
|
||||||
data.Artist trackArtist = null;
|
data.Artist trackArtist = null;
|
||||||
if (track.ArtistId.HasValue)
|
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)
|
if (trackArtist != null)
|
||||||
{
|
{
|
||||||
trackArtist.LastPlayed = now;
|
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.CacheRegion);
|
||||||
CacheManager.ClearRegion(track.ReleaseMedia.Release.CacheRegion);
|
CacheManager.ClearRegion(track.ReleaseMedia.Release.CacheRegion);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Roadie.Library.Caching;
|
using Roadie.Library.Caching;
|
||||||
using Roadie.Library.Configuration;
|
using Roadie.Library.Configuration;
|
||||||
using Roadie.Library.Data.Context;
|
using Roadie.Library.Data.Context;
|
||||||
|
@ -10,7 +11,6 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using data = Roadie.Library.Data;
|
|
||||||
|
|
||||||
namespace Roadie.Library.Scrobble
|
namespace Roadie.Library.Scrobble
|
||||||
{
|
{
|
||||||
|
@ -31,6 +31,18 @@ namespace Roadie.Library.Scrobble
|
||||||
|
|
||||||
private IEnumerable<IScrobblerIntegration> Scrobblers { get; }
|
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,
|
public ScrobbleHandler(IRoadieSettings configuration, ILogger<ScrobbleHandler> logger, IRoadieDbContext dbContext,
|
||||||
ICacheManager cacheManager, IHttpEncoder httpEncoder, IHttpContext httpContext,
|
ICacheManager cacheManager, IHttpEncoder httpEncoder, IHttpContext httpContext,
|
||||||
ILastFmHelper lastFmHelper, IRoadieScrobbler roadieScrobbler, ILastFMScrobbler lastFMScrobbler)
|
ILastFmHelper lastFmHelper, IRoadieScrobbler roadieScrobbler, ILastFMScrobbler lastFMScrobbler)
|
||||||
|
@ -51,16 +63,28 @@ namespace Roadie.Library.Scrobble
|
||||||
Scrobblers = scrobblers;
|
Scrobblers = scrobblers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScrobbleHandler(IRoadieSettings configuration, ILogger logger, IRoadieDbContext dbContext, ICacheManager cacheManager, RoadieScrobbler roadieScrobbler)
|
private async Task<ScrobbleInfo> GetScrobbleInfoDetailsAsync(ScrobbleInfo scrobble)
|
||||||
{
|
{
|
||||||
Logger = logger;
|
var scrobbleInfo = await (from t in DbContext.Tracks
|
||||||
Configuration = configuration;
|
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||||
DbContext = dbContext;
|
join r in DbContext.Releases on rm.ReleaseId equals r.Id
|
||||||
var scrobblers = new List<IScrobblerIntegration>
|
join a in DbContext.Artists on r.ArtistId equals a.Id
|
||||||
{
|
where t.RoadieId == scrobble.TrackId
|
||||||
roadieScrobbler
|
select new
|
||||||
};
|
{
|
||||||
Scrobblers = scrobblers;
|
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>
|
/// <summary>
|
||||||
|
@ -68,8 +92,11 @@ namespace Roadie.Library.Scrobble
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<OperationResult<bool>> NowPlaying(User user, ScrobbleInfo scrobble)
|
public async Task<OperationResult<bool>> NowPlaying(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.NowPlaying(user, s));
|
foreach (var scrobbler in Scrobblers)
|
||||||
|
{
|
||||||
|
await scrobbler.NowPlaying(user, s).ConfigureAwait(false);
|
||||||
|
}
|
||||||
return new OperationResult<bool>
|
return new OperationResult<bool>
|
||||||
{
|
{
|
||||||
Data = true,
|
Data = true,
|
||||||
|
@ -82,10 +109,10 @@ namespace Roadie.Library.Scrobble
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<OperationResult<bool>> Scrobble(User user, ScrobbleInfo scrobble)
|
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)
|
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>
|
return new OperationResult<bool>
|
||||||
{
|
{
|
||||||
|
@ -93,29 +120,5 @@ namespace Roadie.Library.Scrobble
|
||||||
IsSuccess = true
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -44,11 +44,11 @@ namespace Roadie.Library.SearchEngines.Imaging
|
||||||
return request;
|
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 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)
|
if (response.StatusCode == HttpStatusCode.Unauthorized)
|
||||||
throw new AuthenticationException("Api Key is not correct");
|
throw new AuthenticationException("Api Key is not correct");
|
||||||
|
|
|
@ -10,6 +10,6 @@ namespace Roadie.Library.SearchEngines.Imaging
|
||||||
|
|
||||||
RestRequest BuildRequest(string query, int resultsCount);
|
RestRequest BuildRequest(string query, int resultsCount);
|
||||||
|
|
||||||
Task<IEnumerable<ImageSearchResult>> PerformImageSearch(string query, int resultsCount);
|
Task<IEnumerable<ImageSearchResult>> PerformImageSearchAsync(string query, int resultsCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -25,14 +25,14 @@ namespace Roadie.Library.SearchEngines.Imaging
|
||||||
|
|
||||||
public override bool IsEnabled => Configuration.Integrations.ITunesProviderEnabled;
|
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;
|
ArtistSearchResult data = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var request = BuildRequest(query, 1, "musicArtist");
|
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.ResponseStatus == ResponseStatus.Error)
|
||||||
{
|
{
|
||||||
if (response.StatusCode == HttpStatusCode.Unauthorized)
|
if (response.StatusCode == HttpStatusCode.Unauthorized)
|
||||||
|
@ -79,7 +79,7 @@ namespace Roadie.Library.SearchEngines.Imaging
|
||||||
|
|
||||||
#pragma warning disable CS1998
|
#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);
|
var request = BuildRequest(query, resultsCount);
|
||||||
ImageSearchResult[] result = null;
|
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)
|
public async Task<OperationResult<IEnumerable<ReleaseSearchResult>>> PerformReleaseSearch(string artistName, string query, int resultsCount)
|
||||||
{
|
{
|
||||||
var request = BuildRequest(query, 1, "album");
|
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.ResponseStatus == ResponseStatus.Error)
|
||||||
{
|
{
|
||||||
if (response.StatusCode == HttpStatusCode.Unauthorized)
|
if (response.StatusCode == HttpStatusCode.Unauthorized)
|
||||||
|
|
|
@ -50,7 +50,7 @@ namespace Roadie.Library.SearchEngines.Imaging
|
||||||
|
|
||||||
public abstract RestRequest BuildRequest(string query, int resultsCount);
|
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();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace Roadie.Library.SearchEngines.Imaging
|
||||||
}
|
}
|
||||||
if (Configuration.Integrations.BingImageSearchEngineEnabled)
|
if (Configuration.Integrations.BingImageSearchEngineEnabled)
|
||||||
{
|
{
|
||||||
var bingResults = await _bingSearchEngine.PerformImageSearch(query, count);
|
var bingResults = await _bingSearchEngine.PerformImageSearchAsync(query, count).ConfigureAwait(false);
|
||||||
if (bingResults != null)
|
if (bingResults != null)
|
||||||
{
|
{
|
||||||
result.AddRange(bingResults);
|
result.AddRange(bingResults);
|
||||||
|
@ -45,7 +45,7 @@ namespace Roadie.Library.SearchEngines.Imaging
|
||||||
}
|
}
|
||||||
if (Configuration.Integrations.ITunesProviderEnabled)
|
if (Configuration.Integrations.ITunesProviderEnabled)
|
||||||
{
|
{
|
||||||
var iTunesResults = await _itunesSearchEngine.PerformImageSearch(query, count);
|
var iTunesResults = await _itunesSearchEngine.PerformImageSearchAsync(query, count).ConfigureAwait(false);
|
||||||
if (iTunesResults != null)
|
if (iTunesResults != null)
|
||||||
{
|
{
|
||||||
result.AddRange(iTunesResults);
|
result.AddRange(iTunesResults);
|
||||||
|
|
|
@ -103,11 +103,11 @@ namespace Roadie.Library.MetaData.Audio
|
||||||
if (!result.IsValid)
|
if (!result.IsValid)
|
||||||
{
|
{
|
||||||
tagSources.Add("MusicBrainz");
|
tagSources.Add("MusicBrainz");
|
||||||
result = await ParseFromMusicBrainz(result);
|
result = await ParseFromMusicBrainzAsync(result).ConfigureAwait(false);
|
||||||
if (!result.IsValid)
|
if (!result.IsValid)
|
||||||
{
|
{
|
||||||
tagSources.Add("LastFm");
|
tagSources.Add("LastFm");
|
||||||
result = await GetFromLastFmIntegration(result);
|
result = await GetFromLastFmIntegrationAsync(result).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,15 +183,18 @@ namespace Roadie.Library.MetaData.Audio
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<AudioMetaData> GetFromLastFmIntegration(AudioMetaData metaData)
|
private async Task<AudioMetaData> GetFromLastFmIntegrationAsync(AudioMetaData metaData)
|
||||||
{
|
{
|
||||||
var artistName = metaData.Artist;
|
var artistName = metaData.Artist;
|
||||||
var ReleaseName = metaData.Release;
|
var ReleaseName = metaData.Release;
|
||||||
|
|
||||||
if (DoParseFromLastFM)
|
if (DoParseFromLastFM)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(artistName) && string.IsNullOrEmpty(ReleaseName)) return metaData;
|
if (string.IsNullOrEmpty(artistName) && string.IsNullOrEmpty(ReleaseName))
|
||||||
var lastFmReleaseTracks = await LastFmHelper.TracksForRelease(artistName, ReleaseName);
|
{
|
||||||
|
return metaData;
|
||||||
|
}
|
||||||
|
var lastFmReleaseTracks = await LastFmHelper.TracksForReleaseAsync(artistName, ReleaseName).ConfigureAwait(false);
|
||||||
if (lastFmReleaseTracks != null)
|
if (lastFmReleaseTracks != null)
|
||||||
{
|
{
|
||||||
var lastFmReleaseTrack = lastFmReleaseTracks.FirstOrDefault(x =>
|
var lastFmReleaseTrack = lastFmReleaseTracks.FirstOrDefault(x =>
|
||||||
|
@ -224,12 +227,11 @@ namespace Roadie.Library.MetaData.Audio
|
||||||
return metaData;
|
return metaData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<AudioMetaData> ParseFromMusicBrainz(AudioMetaData metaData)
|
private async Task<AudioMetaData> ParseFromMusicBrainzAsync(AudioMetaData metaData)
|
||||||
{
|
{
|
||||||
if (DoParseFromMusicBrainz)
|
if (DoParseFromMusicBrainz)
|
||||||
{
|
{
|
||||||
var musicBrainzReleaseTracks =
|
var musicBrainzReleaseTracks = await MusicBrainzProvider.MusicBrainzReleaseTracksAsync(metaData.Artist, metaData.Release).ConfigureAwait(false);
|
||||||
await MusicBrainzProvider.MusicBrainzReleaseTracks(metaData.Artist, metaData.Release);
|
|
||||||
if (musicBrainzReleaseTracks != null)
|
if (musicBrainzReleaseTracks != null)
|
||||||
{
|
{
|
||||||
var musicBrainzReleaseTrack = musicBrainzReleaseTracks.FirstOrDefault(x =>
|
var musicBrainzReleaseTrack = musicBrainzReleaseTracks.FirstOrDefault(x =>
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
||||||
_apiKey = configuration.Integrations.ApiKeys.FirstOrDefault(x => x.ApiName == "DiscogsConsumerKey") ?? new ApiKey();
|
_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;
|
ArtistSearchResult data = null;
|
||||||
try
|
try
|
||||||
|
@ -40,7 +40,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
||||||
UserAgent = WebHelper.UserAgent
|
UserAgent = WebHelper.UserAgent
|
||||||
};
|
};
|
||||||
|
|
||||||
var response = await client.ExecuteAsync<DiscogsResult>(request);
|
var response = await client.ExecuteAsync<DiscogsResult>(request).ConfigureAwait(false);
|
||||||
|
|
||||||
if (response.ResponseStatus == ResponseStatus.Error)
|
if (response.ResponseStatus == ResponseStatus.Error)
|
||||||
{
|
{
|
||||||
|
@ -61,7 +61,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
||||||
{
|
{
|
||||||
UserAgent = WebHelper.UserAgent
|
UserAgent = WebHelper.UserAgent
|
||||||
};
|
};
|
||||||
var artistResponse = await c2.ExecuteTaskAsync<DiscogArtistResponse>(request);
|
var artistResponse = await c2.ExecuteTaskAsync<DiscogArtistResponse>(request).ConfigureAwait(false);
|
||||||
var artist = artistResponse.Data;
|
var artist = artistResponse.Data;
|
||||||
if (artist != null)
|
if (artist != null)
|
||||||
{
|
{
|
||||||
|
@ -99,7 +99,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}, "uri:metadata");
|
}, "uri:metadata").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -126,7 +126,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
||||||
var client = new RestClient("https://api.discogs.com/database");
|
var client = new RestClient("https://api.discogs.com/database");
|
||||||
client.UserAgent = WebHelper.UserAgent;
|
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)
|
if (response.ResponseStatus == ResponseStatus.Error)
|
||||||
{
|
{
|
||||||
|
@ -144,7 +144,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
||||||
request = BuildLabelRequest(responseData.id);
|
request = BuildLabelRequest(responseData.id);
|
||||||
var c2 = new RestClient("https://api.discogs.com/");
|
var c2 = new RestClient("https://api.discogs.com/");
|
||||||
c2.UserAgent = WebHelper.UserAgent;
|
c2.UserAgent = WebHelper.UserAgent;
|
||||||
var labelResponse = await c2.ExecuteTaskAsync<DiscogsLabelResult>(request);
|
var labelResponse = await c2.ExecuteTaskAsync<DiscogsLabelResult>(request).ConfigureAwait(false);
|
||||||
var label = labelResponse.Data;
|
var label = labelResponse.Data;
|
||||||
if (label != null)
|
if (label != null)
|
||||||
{
|
{
|
||||||
|
@ -157,7 +157,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
||||||
if (label.images != null)
|
if (label.images != null)
|
||||||
{
|
{
|
||||||
images.AddRange(label.images.Where(x => x.type != "primary").Select(x => x.uri));
|
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 (primaryImage != null) labelThumbnailUrl = primaryImage.uri;
|
||||||
if (string.IsNullOrEmpty(labelThumbnailUrl))
|
if (string.IsNullOrEmpty(labelThumbnailUrl))
|
||||||
labelThumbnailUrl = label.images.First(x => !string.IsNullOrEmpty(x.uri)).uri;
|
labelThumbnailUrl = label.images.First(x => !string.IsNullOrEmpty(x.uri)).uri;
|
||||||
|
@ -176,7 +176,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}, "uri:metadata");
|
}, "uri:metadata").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -207,7 +207,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
||||||
Timeout = SafeParser.ToNumber<int>(Configuration.Integrations.DiscogsTimeout)
|
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?.ResponseStatus == null || response.ResponseStatus == ResponseStatus.Error)
|
||||||
{
|
{
|
||||||
if (response.StatusCode == HttpStatusCode.Unauthorized)
|
if (response.StatusCode == HttpStatusCode.Unauthorized)
|
||||||
|
@ -225,7 +225,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
||||||
{
|
{
|
||||||
UserAgent = WebHelper.UserAgent
|
UserAgent = WebHelper.UserAgent
|
||||||
};
|
};
|
||||||
var releaseResult = await c2.ExecuteTaskAsync<DiscogReleaseDetail>(request);
|
var releaseResult = await c2.ExecuteTaskAsync<DiscogReleaseDetail>(request).ConfigureAwait(false);
|
||||||
var release = releaseResult?.Data;
|
var release = releaseResult?.Data;
|
||||||
if (release != null)
|
if (release != null)
|
||||||
{
|
{
|
||||||
|
@ -296,7 +296,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
||||||
|
|
||||||
if (release.identifiers != null)
|
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)
|
if (barcode?.value != null)
|
||||||
{
|
{
|
||||||
data.Tags = new[] { "barcode:" + barcode.value };
|
data.Tags = new[] { "barcode:" + barcode.value };
|
||||||
|
@ -305,7 +305,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}, "uri:metadata");
|
}, "uri:metadata").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,6 +7,6 @@ namespace Roadie.Library.SearchEngines.MetaData
|
||||||
{
|
{
|
||||||
bool IsEnabled { get; }
|
bool IsEnabled { get; }
|
||||||
|
|
||||||
Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearch(string query, int resultsCount);
|
Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearchAsync(string query, int resultsCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,6 +10,6 @@ namespace Roadie.Library.MetaData.LastFm
|
||||||
{
|
{
|
||||||
Task<OperationResult<string>> GetSessionKeyForUserToken(string token);
|
Task<OperationResult<string>> GetSessionKeyForUserToken(string token);
|
||||||
|
|
||||||
Task<IEnumerable<AudioMetaData>> TracksForRelease(string artist, string Release);
|
Task<IEnumerable<AudioMetaData>> TracksForReleaseAsync(string artist, string Release);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -86,7 +86,7 @@ namespace Roadie.Library.MetaData.LastFm
|
||||||
};
|
};
|
||||||
var request = new RestRequest(Method.GET);
|
var request = new RestRequest(Method.GET);
|
||||||
var client = new RestClient(BuildUrl("auth.getSession", parameters));
|
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();
|
var doc = new XmlDocument();
|
||||||
doc.LoadXml(responseXML.Content);
|
doc.LoadXml(responseXML.Content);
|
||||||
var sessionKey = doc.GetElementsByTagName("key")[0].InnerText;
|
var sessionKey = doc.GetElementsByTagName("key")[0].InnerText;
|
||||||
|
@ -139,7 +139,7 @@ namespace Roadie.Library.MetaData.LastFm
|
||||||
var xp = GetResponseAsXml(request);
|
var xp = GetResponseAsXml(request);
|
||||||
Logger.LogTrace($"LastFmHelper: RoadieUser `{roadieUser}` NowPlaying `{scrobble}` LastFmResult [{xp.InnerXml}]");
|
Logger.LogTrace($"LastFmHelper: RoadieUser `{roadieUser}` NowPlaying `{scrobble}` LastFmResult [{xp.InnerXml}]");
|
||||||
result = true;
|
result = true;
|
||||||
});
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
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
|
try
|
||||||
{
|
{
|
||||||
|
@ -163,7 +163,7 @@ namespace Roadie.Library.MetaData.LastFm
|
||||||
Logger.LogTrace("LastFmHelper:PerformArtistSearch:{0}", query);
|
Logger.LogTrace("LastFmHelper:PerformArtistSearch:{0}", query);
|
||||||
var auth = new LastAuth(ApiKey.Key, ApiKey.KeySecret);
|
var auth = new LastAuth(ApiKey.Key, ApiKey.KeySecret);
|
||||||
var albumApi = new ArtistApi(auth);
|
var albumApi = new ArtistApi(auth);
|
||||||
var response = await albumApi.GetInfoAsync(query);
|
var response = await albumApi.GetInfoAsync(query).ConfigureAwait(false);
|
||||||
if (!response.Success)
|
if (!response.Success)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
|
@ -183,7 +183,7 @@ namespace Roadie.Library.MetaData.LastFm
|
||||||
result.Urls = new[] { lastFmArtist.Url.ToString() };
|
result.Urls = new[] { lastFmArtist.Url.ToString() };
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}, "uri:metadata");
|
}, "uri:metadata").ConfigureAwait(false);
|
||||||
return new OperationResult<IEnumerable<ArtistSearchResult>>
|
return new OperationResult<IEnumerable<ArtistSearchResult>>
|
||||||
{
|
{
|
||||||
IsSuccess = data != null,
|
IsSuccess = data != null,
|
||||||
|
@ -205,7 +205,7 @@ namespace Roadie.Library.MetaData.LastFm
|
||||||
{
|
{
|
||||||
var request = new RestRequest(Method.GET);
|
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 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;
|
ReleaseSearchResult result = null;
|
||||||
|
|
||||||
|
@ -246,7 +246,7 @@ namespace Roadie.Library.MetaData.LastFm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}, "uri:metadata");
|
}, "uri:metadata").ConfigureAwait(false);
|
||||||
return new OperationResult<IEnumerable<ReleaseSearchResult>>
|
return new OperationResult<IEnumerable<ReleaseSearchResult>>
|
||||||
{
|
{
|
||||||
IsSuccess = data != null,
|
IsSuccess = data != null,
|
||||||
|
@ -269,7 +269,7 @@ namespace Roadie.Library.MetaData.LastFm
|
||||||
// If less than half of duration then create a NowPlaying
|
// If less than half of duration then create a NowPlaying
|
||||||
if (scrobble.ElapsedTimeOfTrackPlayed.TotalMinutes < 4 ||
|
if (scrobble.ElapsedTimeOfTrackPlayed.TotalMinutes < 4 ||
|
||||||
scrobble.ElapsedTimeOfTrackPlayed.TotalSeconds < scrobble.TrackDuration.TotalSeconds / 2)
|
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);
|
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;
|
if (string.IsNullOrEmpty(artist) || string.IsNullOrEmpty(Release)) return null;
|
||||||
var result = new List<AudioMetaData>();
|
var result = new List<AudioMetaData>();
|
||||||
|
@ -333,7 +333,7 @@ namespace Roadie.Library.MetaData.LastFm
|
||||||
{
|
{
|
||||||
var auth = new LastAuth(ApiKey.Key, ApiKey.KeySecret);
|
var auth = new LastAuth(ApiKey.Key, ApiKey.KeySecret);
|
||||||
var albumApi = new AlbumApi(auth); // this is an unauthenticated call to the API
|
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;
|
releaseInfo = response.Content;
|
||||||
if (releaseInfo != null) CacheManager.Add(responseCacheKey, releaseInfo);
|
if (releaseInfo != null) CacheManager.Add(responseCacheKey, releaseInfo);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,6 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
||||||
{
|
{
|
||||||
public interface IMusicBrainzProvider : IArtistSearchEngine, IReleaseSearchEngine
|
public interface IMusicBrainzProvider : IArtistSearchEngine, IReleaseSearchEngine
|
||||||
{
|
{
|
||||||
Task<IEnumerable<AudioMetaData>> MusicBrainzReleaseTracks(string artistName, string releaseTitle);
|
Task<IEnumerable<AudioMetaData>> MusicBrainzReleaseTracksAsync(string artistName, string releaseTitle);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -23,14 +23,14 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
||||||
Repository = new MusicBrainzRepository(configuration, logger);
|
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
|
try
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(artistName) && string.IsNullOrEmpty(releaseTitle)) return null;
|
if (string.IsNullOrEmpty(artistName) && string.IsNullOrEmpty(releaseTitle)) return null;
|
||||||
// Find the Artist
|
// Find the Artist
|
||||||
var artistCacheKey = string.Format("uri:musicbrainz:artist:{0}", artistName);
|
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;
|
if (!artistSearch.IsSuccess) return null;
|
||||||
var artist = artistSearch.Data.First();
|
var artist = artistSearch.Data.First();
|
||||||
|
|
||||||
|
@ -56,8 +56,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now get The Release Details
|
// Now get The Release Details
|
||||||
release = await MusicBrainzRequestHelper.GetAsync<Release>(
|
release = await MusicBrainzRequestHelper.GetAsync<Release>(MusicBrainzRequestHelper.CreateLookupUrl("release", ReleaseResult.MusicBrainzId, "recordings")).ConfigureAwait(false);
|
||||||
MusicBrainzRequestHelper.CreateLookupUrl("release", ReleaseResult.MusicBrainzId, "recordings"));
|
|
||||||
if (release == null) return null;
|
if (release == null) return null;
|
||||||
CacheManager.Add(ReleaseCacheKey, release);
|
CacheManager.Add(ReleaseCacheKey, release);
|
||||||
}
|
}
|
||||||
|
@ -113,12 +112,12 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
||||||
return null;
|
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;
|
ArtistSearchResult result = null;
|
||||||
|
|
||||||
Logger.LogTrace("MusicBrainzProvider:PerformArtistSearch:{0}", query);
|
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)
|
if (a != null)
|
||||||
{
|
{
|
||||||
var imageUrls = a.relations?.Where(x => x.type.Equals("image", StringComparison.OrdinalIgnoreCase)).Select(x => x.url.resource).Distinct().ToArray();
|
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;
|
ReleaseSearchResult result = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var releaseInfosForArtist = await ReleasesForArtist(artistName);
|
var releaseInfosForArtist = await ReleasesForArtistAsync(artistName).ConfigureAwait(false);
|
||||||
if (releaseInfosForArtist != null)
|
if (releaseInfosForArtist != null)
|
||||||
{
|
{
|
||||||
var r = releaseInfosForArtist.FirstOrDefault(x => x.title.Equals(query, StringComparison.OrdinalIgnoreCase));
|
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(),
|
ReleaseGenres = r.releasegroup?.genres?.Select(x => x.name).Distinct().ToArray(),
|
||||||
ReleaseType = r.releasegroup?.primarytype
|
ReleaseType = r.releasegroup?.primarytype
|
||||||
};
|
};
|
||||||
var coverUrls = await CoverArtForMusicBrainzReleaseById(r.id);
|
var coverUrls = await CoverArtForMusicBrainzReleaseByIdAsync(r.id).ConfigureAwait(false);
|
||||||
if (coverUrls != null)
|
if (coverUrls != null)
|
||||||
{
|
{
|
||||||
var frontCover = coverUrls.images.FirstOrDefault(i => i.front);
|
var frontCover = coverUrls.images.FirstOrDefault(i => i.front);
|
||||||
|
@ -296,16 +295,13 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<CoverArtArchivesResult> CoverArtForMusicBrainzReleaseById(string musicBrainzId)
|
private Task<CoverArtArchivesResult> CoverArtForMusicBrainzReleaseByIdAsync(string musicBrainzId) => MusicBrainzRequestHelper.GetAsync<CoverArtArchivesResult>(MusicBrainzRequestHelper.CreateCoverArtReleaseUrl(musicBrainzId));
|
||||||
{
|
|
||||||
return await 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))
|
if (string.IsNullOrEmpty(artistMusicBrainzId))
|
||||||
{
|
{
|
||||||
var artistSearch = await PerformArtistSearch(artist, 1);
|
var artistSearch = await PerformArtistSearchAsync(artist, 1).ConfigureAwait(false);
|
||||||
if (artistSearch == null || !artistSearch.IsSuccess)
|
if (artistSearch == null || !artistSearch.IsSuccess)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
|
@ -317,7 +313,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
||||||
}
|
}
|
||||||
artistMusicBrainzId = mbArtist.MusicBrainzId;
|
artistMusicBrainzId = mbArtist.MusicBrainzId;
|
||||||
}
|
}
|
||||||
return await Repository.ReleasesForArtist(artistMusicBrainzId);
|
return await Repository.ReleasesForArtist(artistMusicBrainzId).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,7 +6,6 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Roadie.Library.MetaData.MusicBrainz
|
namespace Roadie.Library.MetaData.MusicBrainz
|
||||||
|
@ -21,7 +20,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
var location = System.Reflection.Assembly.GetEntryAssembly().Location;
|
var location = System.Reflection.Assembly.GetEntryAssembly().Location;
|
||||||
var directory = configuration.SearchEngineReposFolder ?? Path.Combine(System.IO.Path.GetDirectoryName(location), "SearchEngineRepos");
|
var directory = configuration.SearchEngineReposFolder ?? Path.Combine(System.IO.Path.GetDirectoryName(location), "SearchEngineRepos");
|
||||||
if(!Directory.Exists(directory))
|
if (!Directory.Exists(directory))
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(directory);
|
Directory.CreateDirectory(directory);
|
||||||
}
|
}
|
||||||
|
@ -33,7 +32,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">Query name of Artist</param>
|
/// <param name="name">Query name of Artist</param>
|
||||||
/// <param name="resultsCount">Maximum Number of Results</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;
|
Artist result = null;
|
||||||
|
|
||||||
|
@ -48,14 +47,14 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
||||||
if (artist == null)
|
if (artist == null)
|
||||||
{
|
{
|
||||||
// Perform a query to get the MbId for the Name
|
// 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)
|
if (artistResult == null || artistResult.artists == null || !artistResult.artists.Any() || artistResult.count < 1)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var mbId = artistResult.artists.First().id;
|
var mbId = artistResult.artists.First().id;
|
||||||
// Now perform a detail request to get the details by the MbId
|
// 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)
|
if (result != null)
|
||||||
{
|
{
|
||||||
col.Insert(new RepositoryArtist
|
col.Insert(new RepositoryArtist
|
||||||
|
@ -99,13 +98,13 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
||||||
col.EnsureIndex(x => x.ArtistMbId);
|
col.EnsureIndex(x => x.ArtistMbId);
|
||||||
col.EnsureIndex(x => x.Release.id);
|
col.EnsureIndex(x => x.Release.id);
|
||||||
var releases = col.Find(x => x.ArtistMbId == artistMbId);
|
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
|
// Query to get collection of Releases for Artist
|
||||||
var pageSize = 50;
|
var pageSize = 50;
|
||||||
var page = 0;
|
var page = 0;
|
||||||
var url = MusicBrainzRequestHelper.CreateArtistBrowseTemplate(artistMbId, pageSize, 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 totalReleases = mbReleaseBrowseResult != null ? mbReleaseBrowseResult.releasecount : 0;
|
||||||
var totalPages = Math.Ceiling((decimal)totalReleases / pageSize);
|
var totalPages = Math.Ceiling((decimal)totalReleases / pageSize);
|
||||||
var fetchResult = new List<Release>();
|
var fetchResult = new List<Release>();
|
||||||
|
@ -116,7 +115,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
||||||
fetchResult.AddRange(mbReleaseBrowseResult.releases.Where(x => !string.IsNullOrEmpty(x.date)));
|
fetchResult.AddRange(mbReleaseBrowseResult.releases.Where(x => !string.IsNullOrEmpty(x.date)));
|
||||||
}
|
}
|
||||||
page++;
|
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);
|
} while (page < totalPages);
|
||||||
col.InsertBulk(fetchResult.Select(x => new RepositoryRelease
|
col.InsertBulk(fetchResult.Select(x => new RepositoryRelease
|
||||||
{
|
{
|
||||||
|
@ -129,7 +128,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
||||||
{
|
{
|
||||||
results = releases.Select(x => x.Release).ToArray();
|
results = releases.Select(x => x.Release).ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (HttpRequestException ex)
|
catch (HttpRequestException ex)
|
||||||
{
|
{
|
||||||
|
|
|
@ -55,7 +55,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
||||||
using (var webClient = new WebClient())
|
using (var webClient = new WebClient())
|
||||||
{
|
{
|
||||||
webClient.Headers.Add("user-agent", WebHelper.UserAgent);
|
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)
|
catch (WebException ex)
|
||||||
|
|
|
@ -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)
|
int resultsCount)
|
||||||
{
|
{
|
||||||
ArtistSearchResult data = null;
|
ArtistSearchResult data = null;
|
||||||
|
@ -37,7 +37,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Spotify
|
||||||
var client = new RestClient("http://api.spotify.com/v1");
|
var client = new RestClient("http://api.spotify.com/v1");
|
||||||
client.UserAgent = WebHelper.UserAgent;
|
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)
|
if (response.ResponseStatus == ResponseStatus.Error)
|
||||||
{
|
{
|
||||||
|
@ -79,7 +79,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Spotify
|
||||||
public async Task<OperationResult<IEnumerable<ReleaseSearchResult>>> PerformReleaseSearch(string artistName,
|
public async Task<OperationResult<IEnumerable<ReleaseSearchResult>>> PerformReleaseSearch(string artistName,
|
||||||
string query, int resultsCount)
|
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>>();
|
if (!artistResult.IsSuccess) return new OperationResult<IEnumerable<ReleaseSearchResult>>();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -88,7 +88,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Spotify
|
||||||
|
|
||||||
ReleaseSearchResult result = null;
|
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)
|
if (response != null && response.items != null)
|
||||||
{
|
{
|
||||||
string foundByAlternateName = 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 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)
|
if (albumResult != null && albumResult.Data != null)
|
||||||
{
|
{
|
||||||
var sa = albumResult.Data;
|
var sa = albumResult.Data;
|
||||||
|
@ -203,7 +203,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Spotify
|
||||||
return new OperationResult<IEnumerable<ReleaseSearchResult>>();
|
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 cacheKey = string.Format("uri:spotify:AlbumsForArtist:{0}", spotifyId);
|
||||||
var result = CacheManager.Get<Albums>(cacheKey);
|
var result = CacheManager.Get<Albums>(cacheKey);
|
||||||
|
@ -213,7 +213,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Spotify
|
||||||
var client = new RestClient(string.Format(
|
var client = new RestClient(string.Format(
|
||||||
"http://api.spotify.com/v1/artists/{0}/albums?offset=0&limit=25&album_type=album&market=US",
|
"http://api.spotify.com/v1/artists/{0}/albums?offset=0&limit=25&album_type=album&market=US",
|
||||||
spotifyId));
|
spotifyId));
|
||||||
var artistAlbumsResponse = await client.ExecuteAsync<Albums>(request);
|
var artistAlbumsResponse = await client.ExecuteAsync<Albums>(request).ConfigureAwait(false);
|
||||||
result = artistAlbumsResponse != null && artistAlbumsResponse.Data != null
|
result = artistAlbumsResponse != null && artistAlbumsResponse.Data != null
|
||||||
? artistAlbumsResponse.Data
|
? artistAlbumsResponse.Data
|
||||||
: null;
|
: null;
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Wikipedia
|
||||||
HttpEncoder = httpEncoder;
|
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)
|
if(string.IsNullOrEmpty(query) || resultsCount == 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -66,7 +66,7 @@ namespace Roadie.Library.Utility
|
||||||
using (var webClient = new WebClient())
|
using (var webClient = new WebClient())
|
||||||
{
|
{
|
||||||
webClient.Headers.Add("user-agent", UserAgent);
|
webClient.Headers.Add("user-agent", UserAgent);
|
||||||
imageBytes = await webClient.DownloadDataTaskAsync(new Uri(url));
|
imageBytes = await webClient.DownloadDataTaskAsync(new Uri(url)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using Mapster;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Identity;
|
|
||||||
using Microsoft.AspNetCore.SignalR;
|
using Microsoft.AspNetCore.SignalR;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
@ -29,9 +28,10 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
public class AdminService : ServiceBase, IAdminService
|
public class AdminService : ServiceBase, IAdminService
|
||||||
{
|
{
|
||||||
protected IHubContext<ScanActivityHub> ScanActivityHub { get; }
|
private IArtistLookupEngine ArtistLookupEngine { get; }
|
||||||
|
|
||||||
private IArtistService ArtistService { get; }
|
private IArtistService ArtistService { get; }
|
||||||
|
private IBookmarkService BookmarkService { get; }
|
||||||
|
|
||||||
private IEventMessageLogger EventMessageLogger { get; }
|
private IEventMessageLogger EventMessageLogger { get; }
|
||||||
|
|
||||||
|
@ -39,16 +39,16 @@ namespace Roadie.Api.Services
|
||||||
|
|
||||||
private IGenreService GenreService { get; }
|
private IGenreService GenreService { get; }
|
||||||
private ILabelService LabelService { get; }
|
private ILabelService LabelService { get; }
|
||||||
private IArtistLookupEngine ArtistLookupEngine { get; }
|
|
||||||
private IReleaseLookupEngine ReleaseLookupEngine { get; }
|
private IReleaseLookupEngine ReleaseLookupEngine { get; }
|
||||||
private IBookmarkService BookmarkService { get; }
|
|
||||||
|
|
||||||
private IReleaseService ReleaseService { get; }
|
private IReleaseService ReleaseService { get; }
|
||||||
|
|
||||||
|
protected IHubContext<ScanActivityHub> ScanActivityHub { get; }
|
||||||
|
|
||||||
public AdminService(IRoadieSettings configuration, IHttpEncoder httpEncoder, IHttpContext httpContext,
|
public AdminService(IRoadieSettings configuration, IHttpEncoder httpEncoder, IHttpContext httpContext,
|
||||||
IRoadieDbContext context, ICacheManager cacheManager, ILogger<ArtistService> logger,
|
IRoadieDbContext context, ICacheManager cacheManager, ILogger<ArtistService> logger,
|
||||||
IHubContext<ScanActivityHub> scanActivityHub, IFileDirectoryProcessorService fileDirectoryProcessorService, IArtistService artistService,
|
IHubContext<ScanActivityHub> scanActivityHub, IFileDirectoryProcessorService fileDirectoryProcessorService, IArtistService artistService,
|
||||||
IReleaseService releaseService, IArtistLookupEngine artistLookupEngine, IReleaseLookupEngine releaseLookupEngine,
|
IReleaseService releaseService, IArtistLookupEngine artistLookupEngine, IReleaseLookupEngine releaseLookupEngine,
|
||||||
ILabelService labelService, IGenreService genreService, IBookmarkService bookmarkService
|
ILabelService labelService, IGenreService genreService, IBookmarkService bookmarkService
|
||||||
)
|
)
|
||||||
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
|
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
|
||||||
|
@ -67,21 +67,94 @@ namespace Roadie.Api.Services
|
||||||
BookmarkService = bookmarkService;
|
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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
var errors = new List<Exception>();
|
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)
|
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}]");
|
return new OperationResult<bool>(true, $"Artist Not Found [{artistId}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await ArtistService.Delete(user, artist, deleteFolder);
|
var result = await ArtistService.DeleteAsync(user, artist, deleteFolder).ConfigureAwait(false);
|
||||||
if (!result.IsSuccess)
|
if (!result.IsSuccess)
|
||||||
{
|
{
|
||||||
return new OperationResult<bool>
|
return new OperationResult<bool>
|
||||||
|
@ -93,22 +166,22 @@ namespace Roadie.Api.Services
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError(ex);
|
Logger.LogError(ex);
|
||||||
await LogAndPublish("Error deleting artist.");
|
await LogAndPublishAsync("Error deleting artist.").ConfigureAwait(false);
|
||||||
errors.Add(ex);
|
errors.Add(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.Stop();
|
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>
|
return new OperationResult<bool>
|
||||||
{
|
{
|
||||||
IsSuccess = !errors.Any(),
|
IsSuccess = errors.Count == 0,
|
||||||
Data = true,
|
Data = true,
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
OperationTime = sw.ElapsedMilliseconds,
|
||||||
Errors = errors
|
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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
@ -116,34 +189,34 @@ namespace Roadie.Api.Services
|
||||||
var artist = DbContext.Artists.FirstOrDefault(x => x.RoadieId == artistId);
|
var artist = DbContext.Artists.FirstOrDefault(x => x.RoadieId == artistId);
|
||||||
if (artist == null)
|
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}]");
|
return new OperationResult<bool>(true, $"Artist Not Found [{artistId}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await ReleaseService.DeleteReleases(user, DbContext.Releases.Where(x => x.ArtistId == artist.Id).Select(x => x.RoadieId).ToArray(), doDeleteFiles);
|
await ReleaseService.DeleteReleasesAsync(user, DbContext.Releases.Where(x => x.ArtistId == artist.Id).Select(x => x.RoadieId).ToArray(), doDeleteFiles).ConfigureAwait(false);
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError(ex);
|
Logger.LogError(ex);
|
||||||
await LogAndPublish("Error deleting artist.");
|
await LogAndPublishAsync("Error deleting artist.").ConfigureAwait(false);
|
||||||
errors.Add(ex);
|
errors.Add(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.Stop();
|
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>
|
return new OperationResult<bool>
|
||||||
{
|
{
|
||||||
IsSuccess = !errors.Any(),
|
IsSuccess = errors.Count == 0,
|
||||||
Data = true,
|
Data = true,
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
OperationTime = sw.ElapsedMilliseconds,
|
||||||
Errors = errors
|
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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
@ -151,7 +224,7 @@ namespace Roadie.Api.Services
|
||||||
var artist = DbContext.Artists.FirstOrDefault(x => x.RoadieId == artistId);
|
var artist = DbContext.Artists.FirstOrDefault(x => x.RoadieId == artistId);
|
||||||
if (artist == null)
|
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}]");
|
return new OperationResult<bool>(true, $"Artist Not Found [{artistId}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,22 +242,22 @@ namespace Roadie.Api.Services
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError(ex);
|
Logger.LogError(ex);
|
||||||
await LogAndPublish("Error deleting artist secondary image.");
|
await LogAndPublishAsync("Error deleting artist secondary image.").ConfigureAwait(false);
|
||||||
errors.Add(ex);
|
errors.Add(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.Stop();
|
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>
|
return new OperationResult<bool>
|
||||||
{
|
{
|
||||||
IsSuccess = !errors.Any(),
|
IsSuccess = errors.Count == 0,
|
||||||
Data = true,
|
Data = true,
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
OperationTime = sw.ElapsedMilliseconds,
|
||||||
Errors = errors
|
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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
@ -192,34 +265,34 @@ namespace Roadie.Api.Services
|
||||||
var genre = DbContext.Genres.FirstOrDefault(x => x.RoadieId == genreId);
|
var genre = DbContext.Genres.FirstOrDefault(x => x.RoadieId == genreId);
|
||||||
if (genre == null)
|
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}]");
|
return new OperationResult<bool>(true, $"Genre Not Found [{genreId}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await GenreService.Delete(user, genreId);
|
await GenreService.DeleteAsync(user, genreId).ConfigureAwait(false);
|
||||||
CacheManager.ClearRegion(genre.CacheRegion);
|
CacheManager.ClearRegion(genre.CacheRegion);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError(ex);
|
Logger.LogError(ex);
|
||||||
await LogAndPublish("Error deleting Genre.");
|
await LogAndPublishAsync("Error deleting Genre.").ConfigureAwait(false);
|
||||||
errors.Add(ex);
|
errors.Add(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.Stop();
|
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>
|
return new OperationResult<bool>
|
||||||
{
|
{
|
||||||
IsSuccess = !errors.Any(),
|
IsSuccess = errors.Count == 0,
|
||||||
Data = true,
|
Data = true,
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
OperationTime = sw.ElapsedMilliseconds,
|
||||||
Errors = errors
|
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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
@ -227,34 +300,34 @@ namespace Roadie.Api.Services
|
||||||
var label = DbContext.Labels.FirstOrDefault(x => x.RoadieId == labelId);
|
var label = DbContext.Labels.FirstOrDefault(x => x.RoadieId == labelId);
|
||||||
if (label == null)
|
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}]");
|
return new OperationResult<bool>(true, $"Label Not Found [{labelId}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await LabelService.Delete(user, labelId);
|
await LabelService.DeleteAsync(user, labelId).ConfigureAwait(false);
|
||||||
CacheManager.ClearRegion(label.CacheRegion);
|
CacheManager.ClearRegion(label.CacheRegion);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError(ex);
|
Logger.LogError(ex);
|
||||||
await LogAndPublish("Error deleting Label.");
|
await LogAndPublishAsync("Error deleting Label.").ConfigureAwait(false);
|
||||||
errors.Add(ex);
|
errors.Add(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.Stop();
|
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>
|
return new OperationResult<bool>
|
||||||
{
|
{
|
||||||
IsSuccess = !errors.Any(),
|
IsSuccess = errors.Count == 0,
|
||||||
Data = true,
|
Data = true,
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
OperationTime = sw.ElapsedMilliseconds,
|
||||||
Errors = errors
|
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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
@ -266,31 +339,31 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
if (release == null)
|
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}]");
|
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)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError(ex);
|
Logger.LogError(ex);
|
||||||
await LogAndPublish("Error deleting release.");
|
await LogAndPublishAsync("Error deleting release.").ConfigureAwait(false);
|
||||||
errors.Add(ex);
|
errors.Add(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
await LogAndPublish($"DeleteRelease `{release}`, By User `{user}`", LogLevel.Information);
|
await LogAndPublishAsync($"DeleteRelease `{release}`, By User `{user}`", LogLevel.Information).ConfigureAwait(false);
|
||||||
CacheManager.Clear();
|
CacheManager.Clear();
|
||||||
return new OperationResult<bool>
|
return new OperationResult<bool>
|
||||||
{
|
{
|
||||||
IsSuccess = !errors.Any(),
|
IsSuccess = errors.Count == 0,
|
||||||
Data = true,
|
Data = true,
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
OperationTime = sw.ElapsedMilliseconds,
|
||||||
Errors = errors
|
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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
@ -298,7 +371,7 @@ namespace Roadie.Api.Services
|
||||||
var release = DbContext.Releases.Include(x => x.Artist).FirstOrDefault(x => x.RoadieId == releaseId);
|
var release = DbContext.Releases.Include(x => x.Artist).FirstOrDefault(x => x.RoadieId == releaseId);
|
||||||
if (release == null)
|
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}]");
|
return new OperationResult<bool>(true, $"Release Not Found [{releaseId}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,22 +389,22 @@ namespace Roadie.Api.Services
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError(ex);
|
Logger.LogError(ex);
|
||||||
await LogAndPublish("Error deleting release secondary image.");
|
await LogAndPublishAsync("Error deleting release secondary image.").ConfigureAwait(false);
|
||||||
errors.Add(ex);
|
errors.Add(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.Stop();
|
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>
|
return new OperationResult<bool>
|
||||||
{
|
{
|
||||||
IsSuccess = !errors.Any(),
|
IsSuccess = errors.Count == 0,
|
||||||
Data = true,
|
Data = true,
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
OperationTime = sw.ElapsedMilliseconds,
|
||||||
Errors = errors
|
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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
@ -348,12 +421,12 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
if (track == null)
|
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}]");
|
return new OperationResult<bool>(true, $"Track Not Found [{trackId}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
DbContext.Tracks.Remove(track);
|
DbContext.Tracks.Remove(track);
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
if (doDeleteFile ?? false)
|
if (doDeleteFile ?? false)
|
||||||
{
|
{
|
||||||
string trackPath = null;
|
string trackPath = null;
|
||||||
|
@ -375,33 +448,33 @@ namespace Roadie.Api.Services
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
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 ReleaseService.ScanReleaseFolderAsync(user, track.ReleaseMedia.Release.RoadieId, false, track.ReleaseMedia.Release).ConfigureAwait(false);
|
||||||
await BookmarkService.RemoveAllBookmarksForItem(BookmarkType.Track, track.Id);
|
await BookmarkService.RemoveAllBookmarksForItemAsync(BookmarkType.Track, track.Id).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError(ex);
|
Logger.LogError(ex);
|
||||||
await LogAndPublish("Error deleting track.");
|
await LogAndPublishAsync("Error deleting track.").ConfigureAwait(false);
|
||||||
errors.Add(ex);
|
errors.Add(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
await LogAndPublish($"DeleteTracks `{track}`, By User `{user}`", LogLevel.Warning);
|
await LogAndPublishAsync($"DeleteTracks `{track}`, By User `{user}`", LogLevel.Warning).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
CacheManager.Clear();
|
CacheManager.Clear();
|
||||||
return new OperationResult<bool>
|
return new OperationResult<bool>
|
||||||
{
|
{
|
||||||
IsSuccess = !errors.Any(),
|
IsSuccess = errors.Count == 0,
|
||||||
Data = true,
|
Data = true,
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
OperationTime = sw.ElapsedMilliseconds,
|
||||||
Errors = errors
|
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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
@ -412,7 +485,7 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
var ex = new Exception("User cannot self.");
|
var ex = new Exception("User cannot self.");
|
||||||
Logger.LogError(ex);
|
Logger.LogError(ex);
|
||||||
await LogAndPublish("Error deleting user.");
|
await LogAndPublishAsync("Error deleting user.").ConfigureAwait(false);
|
||||||
errors.Add(ex);
|
errors.Add(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,12 +493,12 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
if (user == null)
|
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}]");
|
return new OperationResult<bool>(true, $"User Not Found [{userId}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
DbContext.Users.Remove(user);
|
DbContext.Users.Remove(user);
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
var userImageFilename = user.PathToImage(Configuration);
|
var userImageFilename = user.PathToImage(Configuration);
|
||||||
if (File.Exists(userImageFilename))
|
if (File.Exists(userImageFilename))
|
||||||
{
|
{
|
||||||
|
@ -435,16 +508,16 @@ namespace Roadie.Api.Services
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError(ex);
|
Logger.LogError(ex);
|
||||||
await LogAndPublish("Error deleting user.");
|
await LogAndPublishAsync("Error deleting user.").ConfigureAwait(false);
|
||||||
errors.Add(ex);
|
errors.Add(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
await LogAndPublish($"DeleteUser `{user}`, By User `{user}`", LogLevel.Warning);
|
await LogAndPublishAsync($"DeleteUser `{user}`, By User `{user}`", LogLevel.Warning).ConfigureAwait(false);
|
||||||
CacheManager.Clear();
|
CacheManager.Clear();
|
||||||
return new OperationResult<bool>
|
return new OperationResult<bool>
|
||||||
{
|
{
|
||||||
IsSuccess = !errors.Any(),
|
IsSuccess = errors.Count == 0,
|
||||||
Data = true,
|
Data = true,
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
OperationTime = sw.ElapsedMilliseconds,
|
||||||
Errors = errors
|
Errors = errors
|
||||||
|
@ -454,7 +527,7 @@ namespace Roadie.Api.Services
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This is a very simple way to seed the database or setup configuration when the first (who becomes "Admin") user registers
|
/// This is a very simple way to seed the database or setup configuration when the first (who becomes "Admin") user registers
|
||||||
/// </summary>
|
/// </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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
@ -483,10 +556,10 @@ namespace Roadie.Api.Services
|
||||||
Description = "Users who have Edit Permissions",
|
Description = "Users who have Edit Permissions",
|
||||||
NormalizedName = "EDITOR"
|
NormalizedName = "EDITOR"
|
||||||
});
|
});
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
// Add given user to Admin role
|
// 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'
|
// Create special system artists of 'Sound Tracks' and 'Various Artists'
|
||||||
DbContext.Artists.Add(new data.Artist
|
DbContext.Artists.Add(new data.Artist
|
||||||
|
@ -515,7 +588,7 @@ namespace Roadie.Api.Services
|
||||||
Tags = "compilations|various",
|
Tags = "compilations|various",
|
||||||
URLs = "https://en.wikipedia.org/wiki/Compilation_album"
|
URLs = "https://en.wikipedia.org/wiki/Compilation_album"
|
||||||
});
|
});
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
return new OperationResult<bool>
|
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();
|
var sw = Stopwatch.StartNew();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
@ -567,7 +640,7 @@ namespace Roadie.Api.Services
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
return Task.FromResult(new OperationResult<Dictionary<string, List<string>>>
|
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,
|
IsSuccess = true,
|
||||||
OperationTime = sw.ElapsedMilliseconds
|
OperationTime = sw.ElapsedMilliseconds
|
||||||
});
|
});
|
||||||
|
@ -619,13 +692,10 @@ namespace Roadie.Api.Services
|
||||||
Directory.CreateDirectory(Configuration.LabelImageFolder);
|
Directory.CreateDirectory(Configuration.LabelImageFolder);
|
||||||
Logger.LogInformation($"Created Label Image Folder [{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)
|
catch (Exception ex)
|
||||||
|
@ -640,7 +710,7 @@ namespace Roadie.Api.Services
|
||||||
Logger.LogInformation($"Administration startup tasks completed, elapsed time [{ sw.ElapsedMilliseconds }]");
|
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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
@ -652,7 +722,7 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
try
|
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)
|
if (!result.IsSuccess)
|
||||||
{
|
{
|
||||||
errors.AddRange(result.Errors);
|
errors.AddRange(result.Errors);
|
||||||
|
@ -661,7 +731,7 @@ namespace Roadie.Api.Services
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await LogAndPublish(ex.ToString(), LogLevel.Error).ConfigureAwait(false);
|
await LogAndPublishAsync(ex.ToString(), LogLevel.Error).ConfigureAwait(false);
|
||||||
errors.Add(ex);
|
errors.Add(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -671,7 +741,7 @@ namespace Roadie.Api.Services
|
||||||
await UpdateReleaseRank(updatedReleaseId).ConfigureAwait(false);
|
await UpdateReleaseRank(updatedReleaseId).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
sw.Stop();
|
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>
|
return new OperationResult<bool>
|
||||||
{
|
{
|
||||||
IsSuccess = errors.Count == 0,
|
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();
|
var sw = Stopwatch.StartNew();
|
||||||
|
|
||||||
|
@ -689,18 +759,18 @@ namespace Roadie.Api.Services
|
||||||
var artist = DbContext.Artists.FirstOrDefault(x => x.RoadieId == artistId);
|
var artist = DbContext.Artists.FirstOrDefault(x => x.RoadieId == artistId);
|
||||||
if (artist == null)
|
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}]");
|
return new OperationResult<bool>(true, $"Artist Not Found [{artistId}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
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);
|
CacheManager.ClearRegion(artist.CacheRegion);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await LogAndPublish(ex.ToString(), LogLevel.Error);
|
await LogAndPublishAsync(ex.ToString(), LogLevel.Error).ConfigureAwait(false);
|
||||||
errors.Add(ex);
|
errors.Add(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -713,56 +783,52 @@ namespace Roadie.Api.Services
|
||||||
NewTracks = ReleaseService.AddedTrackIds.Count(),
|
NewTracks = ReleaseService.AddedTrackIds.Count(),
|
||||||
TimeSpanInSeconds = (int)sw.Elapsed.TotalSeconds
|
TimeSpanInSeconds = (int)sw.Elapsed.TotalSeconds
|
||||||
});
|
});
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
await UpdateArtistRank(artist.Id, true);
|
await UpdateArtistRank(artist.Id, true).ConfigureAwait(false);
|
||||||
return new OperationResult<bool>
|
return new OperationResult<bool>
|
||||||
{
|
{
|
||||||
IsSuccess = !errors.Any(),
|
IsSuccess = errors.Count == 0,
|
||||||
AdditionalData = new Dictionary<string, object> { { "artistAverage", artist.Rating } },
|
AdditionalData = new Dictionary<string, object> { { "artistAverage", artist.Rating } },
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
OperationTime = sw.ElapsedMilliseconds,
|
||||||
Errors = errors
|
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 sw = Stopwatch.StartNew();
|
||||||
|
|
||||||
var errors = new List<Exception>();
|
var errors = new List<Exception>();
|
||||||
foreach (var artistId in artistIds)
|
foreach (var artistId in artistIds)
|
||||||
{
|
{
|
||||||
var result = await ScanArtist(user, artistId, isReadOnly);
|
var result = await ScanArtistAsync(user, artistId, isReadOnly).ConfigureAwait(false);
|
||||||
if (!result.IsSuccess)
|
if (!result.IsSuccess && (result.Errors?.Any() ?? false))
|
||||||
{
|
{
|
||||||
if (result.Errors?.Any() ?? false)
|
errors.AddRange(result.Errors);
|
||||||
{
|
|
||||||
errors.AddRange(result.Errors);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sw.Stop();
|
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>
|
return new OperationResult<bool>
|
||||||
{
|
{
|
||||||
IsSuccess = !errors.Any(),
|
IsSuccess = errors.Count == 0,
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
OperationTime = sw.ElapsedMilliseconds,
|
||||||
Errors = errors
|
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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
|
||||||
var releaseIdsInCollection = new List<int>();
|
var releaseIdsInCollection = new List<int>();
|
||||||
var updatedReleaseIds = new List<int>();
|
var updatedReleaseIds = new List<int>();
|
||||||
var result = new List<data.PositionArtistRelease>();
|
|
||||||
var errors = new List<Exception>();
|
var errors = new List<Exception>();
|
||||||
var collection = await DbContext.Collections.FirstOrDefaultAsync(x => x.RoadieId == collectionId).ConfigureAwait(false);
|
var collection = await DbContext.Collections.FirstOrDefaultAsync(x => x.RoadieId == collectionId).ConfigureAwait(false);
|
||||||
if (collection == null)
|
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}]");
|
return new OperationResult<bool>(true, $"Collection Not Found [{collectionId}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -770,7 +836,7 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
if (doPurgeFirst)
|
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);
|
var crs = await DbContext.CollectionReleases.Where(x => x.CollectionId == collection.Id).ToArrayAsync().ConfigureAwait(false);
|
||||||
DbContext.CollectionReleases.RemoveRange(crs);
|
DbContext.CollectionReleases.RemoveRange(crs);
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
@ -790,8 +856,8 @@ namespace Roadie.Api.Services
|
||||||
data.Release release = null;
|
data.Release release = null;
|
||||||
|
|
||||||
var isArtistNameDbKey = csvRelease.Artist.StartsWith(Roadie.Library.Data.Collection.DatabaseIdKey);
|
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;
|
int? artistId = isArtistNameDbKey ? SafeParser.ToNumber<int?>(csvRelease.Artist.Replace(Roadie.Library.Data.Collection.DatabaseIdKey, string.Empty)) : null;
|
||||||
if(artistId.HasValue)
|
if (artistId.HasValue)
|
||||||
{
|
{
|
||||||
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == artistId.Value);
|
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == artistId.Value);
|
||||||
if (artist != null)
|
if (artist != null)
|
||||||
|
@ -802,9 +868,9 @@ namespace Roadie.Api.Services
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
artistsMatchingName = await ArtistLookupEngine.DatabaseQueryForArtistName(csvRelease.Artist).ConfigureAwait(false);
|
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;
|
csvRelease.Status = Statuses.Missing;
|
||||||
await DbContext.CollectionMissings.AddAsync(new data.CollectionMissing
|
await DbContext.CollectionMissings.AddAsync(new data.CollectionMissing
|
||||||
{
|
{
|
||||||
|
@ -817,13 +883,13 @@ namespace Roadie.Api.Services
|
||||||
}
|
}
|
||||||
else if (artistsMatchingName.Count() > 1)
|
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)
|
foreach (var artist in artistsMatchingName)
|
||||||
{
|
{
|
||||||
var isReleaseNameDbKey = csvRelease.Release.StartsWith(Roadie.Library.Data.Collection.DatabaseIdKey);
|
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)
|
if (releaseId.HasValue)
|
||||||
{
|
{
|
||||||
release = await DbContext.Releases.FirstOrDefaultAsync(x => x.Id == releaseId.Value).ConfigureAwait(false);
|
release = await DbContext.Releases.FirstOrDefaultAsync(x => x.Id == releaseId.Value).ConfigureAwait(false);
|
||||||
|
@ -840,7 +906,7 @@ namespace Roadie.Api.Services
|
||||||
|
|
||||||
if (release == null)
|
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;
|
csvRelease.Status = Statuses.Missing;
|
||||||
await DbContext.CollectionMissings.AddAsync(new data.CollectionMissing
|
await DbContext.CollectionMissings.AddAsync(new data.CollectionMissing
|
||||||
{
|
{
|
||||||
|
@ -867,7 +933,7 @@ namespace Roadie.Api.Services
|
||||||
CollectionId = collection.Id,
|
CollectionId = collection.Id,
|
||||||
ReleaseId = release.Id,
|
ReleaseId = release.Id,
|
||||||
ListNumber = csvRelease.Position
|
ListNumber = csvRelease.Position
|
||||||
});
|
}).ConfigureAwait(false);
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
// If Item in Collection is at different List number update CollectionRelease
|
// 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
|
var collectionReleasesToRemove = await (from cr in DbContext.CollectionReleases
|
||||||
where cr.CollectionId == collection.Id
|
where cr.CollectionId == collection.Id
|
||||||
where !releaseIdsInCollection.Contains(cr.ReleaseId)
|
where !releaseIdsInCollection.Contains(cr.ReleaseId)
|
||||||
select cr).ToArrayAsync().ConfigureAwait(false);
|
select cr).ToArrayAsync().ConfigureAwait(false);
|
||||||
if (collectionReleasesToRemove.Any())
|
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);
|
DbContext.CollectionReleases.RemoveRange(collectionReleasesToRemove);
|
||||||
}
|
}
|
||||||
|
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
if (doUpdateRanks)
|
if (doUpdateRanks)
|
||||||
{
|
{
|
||||||
foreach (var updatedReleaseId in updatedReleaseIds)
|
foreach (var updatedReleaseId in updatedReleaseIds)
|
||||||
|
@ -933,31 +999,23 @@ namespace Roadie.Api.Services
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.Stop();
|
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>
|
return new OperationResult<bool>
|
||||||
{
|
{
|
||||||
AdditionalData = new Dictionary<string, object> { { "updatedReleaseIds", updatedReleaseIds.ToArray() } },
|
AdditionalData = new Dictionary<string, object> { { "updatedReleaseIds", updatedReleaseIds.ToArray() } },
|
||||||
IsSuccess = !errors.Any(),
|
IsSuccess = errors.Count == 0,
|
||||||
Data = true,
|
Data = true,
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
OperationTime = sw.ElapsedMilliseconds,
|
||||||
Errors = errors
|
Errors = errors
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<OperationResult<bool>> ScanInboundFolder(User user, bool isReadOnly = false)
|
public Task<OperationResult<bool>> ScanInboundFolderAsync(User user, bool isReadOnly = false) => ScanFolderAsync(user, new DirectoryInfo(Configuration.InboundFolder), isReadOnly);
|
||||||
{
|
|
||||||
var d = new DirectoryInfo(Configuration.InboundFolder);
|
|
||||||
return await ScanFolder(user, d, isReadOnly);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<OperationResult<bool>> ScanLibraryFolder(User user, bool isReadOnly = false)
|
public Task<OperationResult<bool>> ScanLibraryFolderAsync(User user, bool isReadOnly = false) => ScanFolderAsync(user, new DirectoryInfo(Configuration.LibraryFolder), isReadOnly, false);
|
||||||
{
|
|
||||||
var d = new DirectoryInfo(Configuration.LibraryFolder);
|
|
||||||
return await ScanFolder(user, d, 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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
@ -969,17 +1027,17 @@ namespace Roadie.Api.Services
|
||||||
.FirstOrDefault(x => x.RoadieId == releaseId);
|
.FirstOrDefault(x => x.RoadieId == releaseId);
|
||||||
if (release == null)
|
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}]");
|
return new OperationResult<bool>(true, $"Release Not Found [{releaseId}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await ReleaseService.ScanReleaseFolder(user, release.RoadieId, isReadOnly, release);
|
await ReleaseService.ScanReleaseFolderAsync(user, release.RoadieId, isReadOnly, release).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await LogAndPublish(ex.ToString(), LogLevel.Error);
|
await LogAndPublishAsync(ex.ToString(), LogLevel.Error).ConfigureAwait(false);
|
||||||
errors.Add(ex);
|
errors.Add(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -992,43 +1050,40 @@ namespace Roadie.Api.Services
|
||||||
NewTracks = ReleaseService.AddedTrackIds.Count(),
|
NewTracks = ReleaseService.AddedTrackIds.Count(),
|
||||||
TimeSpanInSeconds = (int)sw.Elapsed.TotalSeconds
|
TimeSpanInSeconds = (int)sw.Elapsed.TotalSeconds
|
||||||
});
|
});
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
return new OperationResult<bool>
|
return new OperationResult<bool>
|
||||||
{
|
{
|
||||||
IsSuccess = !errors.Any(),
|
IsSuccess = errors.Count == 0,
|
||||||
Data = true,
|
Data = true,
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
OperationTime = sw.ElapsedMilliseconds,
|
||||||
Errors = errors
|
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 sw = Stopwatch.StartNew();
|
||||||
|
|
||||||
var errors = new List<Exception>();
|
var errors = new List<Exception>();
|
||||||
foreach (var releaseId in releaseIds)
|
foreach (var releaseId in releaseIds)
|
||||||
{
|
{
|
||||||
var result = await ScanRelease(user, releaseId, isReadOnly, wasDoneForInvalidTrackPlay);
|
var result = await ScanReleaseAsync(user, releaseId, isReadOnly, wasDoneForInvalidTrackPlay).ConfigureAwait(false);
|
||||||
if (!result.IsSuccess)
|
if (!result.IsSuccess && (result.Errors?.Any() ?? false))
|
||||||
{
|
{
|
||||||
if (result.Errors?.Any() ?? false)
|
errors.AddRange(result.Errors);
|
||||||
{
|
|
||||||
errors.AddRange(result.Errors);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sw.Stop();
|
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>
|
return new OperationResult<bool>
|
||||||
{
|
{
|
||||||
IsSuccess = !errors.Any(),
|
IsSuccess = errors.Count == 0,
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
OperationTime = sw.ElapsedMilliseconds,
|
||||||
Errors = errors
|
Errors = errors
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<OperationResult<bool>> UpdateInviteTokenUsed(Guid? tokenId)
|
public async Task<OperationResult<bool>> UpdateInviteTokenUsedAsync(Guid? tokenId)
|
||||||
{
|
{
|
||||||
var sw = new Stopwatch();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
@ -1044,17 +1099,17 @@ namespace Roadie.Api.Services
|
||||||
}
|
}
|
||||||
token.Status = Statuses.Complete;
|
token.Status = Statuses.Complete;
|
||||||
token.LastUpdated = DateTime.UtcNow;
|
token.LastUpdated = DateTime.UtcNow;
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
return new OperationResult<bool>
|
return new OperationResult<bool>
|
||||||
{
|
{
|
||||||
IsSuccess = !errors.Any(),
|
IsSuccess = errors.Count == 0,
|
||||||
Data = true,
|
Data = true,
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
OperationTime = sw.ElapsedMilliseconds,
|
||||||
Errors = errors
|
Errors = errors
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<OperationResult<bool>> ValidateInviteToken(Guid? tokenId)
|
public async Task<OperationResult<bool>> ValidateInviteTokenAsync(Guid? tokenId)
|
||||||
{
|
{
|
||||||
var sw = new Stopwatch();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
@ -1072,7 +1127,7 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
token.Status = Statuses.Expired;
|
token.Status = Statuses.Expired;
|
||||||
token.LastUpdated = DateTime.UtcNow;
|
token.LastUpdated = DateTime.UtcNow;
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
return new OperationResult<bool>(true, $"Invite Token [{tokenId}] Expired [{ token.ExpiresDate }]");
|
return new OperationResult<bool>(true, $"Invite Token [{tokenId}] Expired [{ token.ExpiresDate }]");
|
||||||
}
|
}
|
||||||
if (token.Status == Statuses.Complete)
|
if (token.Status == Statuses.Complete)
|
||||||
|
@ -1081,84 +1136,11 @@ namespace Roadie.Api.Services
|
||||||
}
|
}
|
||||||
return new OperationResult<bool>
|
return new OperationResult<bool>
|
||||||
{
|
{
|
||||||
IsSuccess = !errors.Any(),
|
IsSuccess = errors.Count == 0,
|
||||||
Data = true,
|
Data = true,
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
OperationTime = sw.ElapsedMilliseconds,
|
||||||
Errors = errors
|
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
|
@ -1,5 +1,4 @@
|
||||||
using Mapster;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Roadie.Library;
|
using Roadie.Library;
|
||||||
using Roadie.Library.Caching;
|
using Roadie.Library.Caching;
|
||||||
|
@ -20,7 +19,6 @@ using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Dynamic.Core;
|
using System.Linq.Dynamic.Core;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using data = Roadie.Library.Data;
|
|
||||||
using models = Roadie.Library.Models;
|
using models = Roadie.Library.Models;
|
||||||
|
|
||||||
namespace Roadie.Api.Services
|
namespace Roadie.Api.Services
|
||||||
|
@ -41,30 +39,7 @@ namespace Roadie.Api.Services
|
||||||
UserService = userService;
|
UserService = userService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public async Task<Library.Models.Pagination.PagedResult<models.BookmarkList>> ListAsync(User roadieUser, PagedRequest request, bool? doRandomize = false, BookmarkType? filterType = null)
|
||||||
/// 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)
|
|
||||||
{
|
{
|
||||||
var sw = new Stopwatch();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
@ -95,14 +70,19 @@ namespace Roadie.Api.Services
|
||||||
var rowCount = result.Count();
|
var rowCount = result.Count();
|
||||||
var rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
|
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)
|
foreach (var row in rows)
|
||||||
|
{
|
||||||
switch (row.Type)
|
switch (row.Type)
|
||||||
{
|
{
|
||||||
case BookmarkType.Artist:
|
case BookmarkType.Artist:
|
||||||
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
|
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
|
||||||
if (artist == null) continue;
|
if (artist == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
row.Bookmark = new models.DataToken
|
row.Bookmark = new models.DataToken
|
||||||
{
|
{
|
||||||
Text = artist.Name,
|
Text = artist.Name,
|
||||||
|
@ -117,7 +97,11 @@ namespace Roadie.Api.Services
|
||||||
case BookmarkType.Release:
|
case BookmarkType.Release:
|
||||||
var release = DbContext.Releases.Include(x => x.Artist)
|
var release = DbContext.Releases.Include(x => x.Artist)
|
||||||
.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
|
.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
|
||||||
if (release == null) continue;
|
if (release == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
row.Bookmark = new models.DataToken
|
row.Bookmark = new models.DataToken
|
||||||
{
|
{
|
||||||
Text = release.Title,
|
Text = release.Title,
|
||||||
|
@ -137,7 +121,11 @@ namespace Roadie.Api.Services
|
||||||
.Include(x => x.ReleaseMedia.Release.Artist)
|
.Include(x => x.ReleaseMedia.Release.Artist)
|
||||||
.Include(x => x.TrackArtist)
|
.Include(x => x.TrackArtist)
|
||||||
.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
|
.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
|
||||||
if (track == null) continue;
|
if (track == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
row.Bookmark = new models.DataToken
|
row.Bookmark = new models.DataToken
|
||||||
{
|
{
|
||||||
Text = track.Title,
|
Text = track.Title,
|
||||||
|
@ -165,7 +153,11 @@ namespace Roadie.Api.Services
|
||||||
var playlist = DbContext.Playlists
|
var playlist = DbContext.Playlists
|
||||||
.Include(x => x.User)
|
.Include(x => x.User)
|
||||||
.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
|
.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
|
||||||
if (playlist == null) continue;
|
if (playlist == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
row.Bookmark = new models.DataToken
|
row.Bookmark = new models.DataToken
|
||||||
{
|
{
|
||||||
Text = playlist.Name,
|
Text = playlist.Name,
|
||||||
|
@ -180,7 +172,11 @@ namespace Roadie.Api.Services
|
||||||
|
|
||||||
case BookmarkType.Collection:
|
case BookmarkType.Collection:
|
||||||
var collection = DbContext.Collections.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
|
var collection = DbContext.Collections.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
|
||||||
if (collection == null) continue;
|
if (collection == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
row.Bookmark = new models.DataToken
|
row.Bookmark = new models.DataToken
|
||||||
{
|
{
|
||||||
Text = collection.Name,
|
Text = collection.Name,
|
||||||
|
@ -196,7 +192,11 @@ namespace Roadie.Api.Services
|
||||||
|
|
||||||
case BookmarkType.Label:
|
case BookmarkType.Label:
|
||||||
var label = DbContext.Labels.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
|
var label = DbContext.Labels.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
|
||||||
if (label == null) continue;
|
if (label == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
row.Bookmark = new models.DataToken
|
row.Bookmark = new models.DataToken
|
||||||
{
|
{
|
||||||
Text = label.Name,
|
Text = label.Name,
|
||||||
|
@ -207,8 +207,7 @@ namespace Roadie.Api.Services
|
||||||
row.SortName = label.SortName ?? label.Name;
|
row.SortName = label.SortName ?? label.Name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
;
|
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
return new Library.Models.Pagination.PagedResult<models.BookmarkList>
|
return new Library.Models.Pagination.PagedResult<models.BookmarkList>
|
||||||
{
|
{
|
||||||
|
@ -219,5 +218,29 @@ namespace Roadie.Api.Services
|
||||||
Rows = rows
|
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
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -43,307 +43,7 @@ namespace Roadie.Api.Services
|
||||||
BookmarkService = bookmarkService;
|
BookmarkService = bookmarkService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private async Task<OperationResult<Collection>> CollectionByIdActionAsync(Guid id, IEnumerable<string> includes = null)
|
||||||
/// 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)
|
|
||||||
{
|
{
|
||||||
var timings = new Dictionary<string, long>();
|
var timings = new Dictionary<string, long>();
|
||||||
var tsw = new Stopwatch();
|
var tsw = new Stopwatch();
|
||||||
|
@ -352,13 +52,13 @@ namespace Roadie.Api.Services
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
|
||||||
tsw.Restart();
|
tsw.Restart();
|
||||||
var collection = await GetCollection(id);
|
var collection = await GetCollection(id).ConfigureAwait(false);
|
||||||
tsw.Stop();
|
tsw.Stop();
|
||||||
timings.Add("getCollection", tsw.ElapsedMilliseconds);
|
timings.Add("getCollection", tsw.ElapsedMilliseconds);
|
||||||
|
|
||||||
if (collection == null)
|
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 result = collection.Adapt<Collection>();
|
||||||
var maintainer = DbContext.Users.FirstOrDefault(x => x.Id == collection.MaintainerId);
|
var maintainer = DbContext.Users.FirstOrDefault(x => x.Id == collection.MaintainerId);
|
||||||
|
@ -474,5 +174,309 @@ namespace Roadie.Api.Services
|
||||||
OperationTime = sw.ElapsedMilliseconds
|
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
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Roadie.Library;
|
using Roadie.Library;
|
||||||
using Roadie.Library.Caching;
|
using Roadie.Library.Caching;
|
||||||
using Roadie.Library.Configuration;
|
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 sw = Stopwatch.StartNew();
|
||||||
var result = false;
|
var result = false;
|
||||||
var errors = new List<Exception>();
|
var errors = new List<Exception>();
|
||||||
var artist = DbContext.Artists
|
var artist = await DbContext.Artists.FirstOrDefaultAsync(x => x.RoadieId == artistId).ConfigureAwait(false);
|
||||||
.FirstOrDefault(x => x.RoadieId == artistId);
|
|
||||||
if (artist == null)
|
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
|
var newComment = new data.Comment
|
||||||
{
|
{
|
||||||
|
@ -44,8 +115,8 @@ namespace Roadie.Api.Services
|
||||||
UserId = user.Id.Value,
|
UserId = user.Id.Value,
|
||||||
Cmt = cmt
|
Cmt = cmt
|
||||||
};
|
};
|
||||||
DbContext.Comments.Add(newComment);
|
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
CacheManager.ClearRegion(artist.CacheRegion);
|
CacheManager.ClearRegion(artist.CacheRegion);
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
result = true;
|
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 sw = Stopwatch.StartNew();
|
||||||
var result = false;
|
var result = false;
|
||||||
var errors = new List<Exception>();
|
var errors = new List<Exception>();
|
||||||
var collection = DbContext.Collections
|
var collection = await DbContext.Collections.FirstOrDefaultAsync(x => x.RoadieId == collectionId).ConfigureAwait(false);
|
||||||
.FirstOrDefault(x => x.RoadieId == collectionId);
|
|
||||||
if (collection == null)
|
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
|
var newComment = new data.Comment
|
||||||
{
|
{
|
||||||
|
@ -74,8 +146,8 @@ namespace Roadie.Api.Services
|
||||||
UserId = user.Id.Value,
|
UserId = user.Id.Value,
|
||||||
Cmt = cmt
|
Cmt = cmt
|
||||||
};
|
};
|
||||||
DbContext.Comments.Add(newComment);
|
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
CacheManager.ClearRegion(collection.CacheRegion);
|
CacheManager.ClearRegion(collection.CacheRegion);
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
result = true;
|
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 sw = Stopwatch.StartNew();
|
||||||
var result = false;
|
var result = false;
|
||||||
var errors = new List<Exception>();
|
var errors = new List<Exception>();
|
||||||
var genre = DbContext.Genres
|
var genre = await DbContext.Genres.FirstOrDefaultAsync(x => x.RoadieId == genreId).ConfigureAwait(false);
|
||||||
.FirstOrDefault(x => x.RoadieId == genreId);
|
if (genre == null)
|
||||||
if (genre == null) return new OperationResult<bool>(true, string.Format("Genre Not Found [{0}]", genreId));
|
{
|
||||||
|
return new OperationResult<bool>(true, $"Genre Not Found [{genreId}]");
|
||||||
|
}
|
||||||
|
|
||||||
var newComment = new data.Comment
|
var newComment = new data.Comment
|
||||||
{
|
{
|
||||||
|
@ -103,8 +177,8 @@ namespace Roadie.Api.Services
|
||||||
UserId = user.Id.Value,
|
UserId = user.Id.Value,
|
||||||
Cmt = cmt
|
Cmt = cmt
|
||||||
};
|
};
|
||||||
DbContext.Comments.Add(newComment);
|
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
CacheManager.ClearRegion(genre.CacheRegion);
|
CacheManager.ClearRegion(genre.CacheRegion);
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
result = true;
|
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 sw = Stopwatch.StartNew();
|
||||||
var result = false;
|
var result = false;
|
||||||
var errors = new List<Exception>();
|
var errors = new List<Exception>();
|
||||||
var label = DbContext.Labels
|
var label = await DbContext.Labels.FirstOrDefaultAsync(x => x.RoadieId == labelId).ConfigureAwait(false);
|
||||||
.FirstOrDefault(x => x.RoadieId == labelId);
|
if (label == null)
|
||||||
if (label == null) return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", labelId));
|
{
|
||||||
|
return new OperationResult<bool>(true, $"Label Not Found [{labelId}]");
|
||||||
|
}
|
||||||
|
|
||||||
var newComment = new data.Comment
|
var newComment = new data.Comment
|
||||||
{
|
{
|
||||||
|
@ -132,8 +208,8 @@ namespace Roadie.Api.Services
|
||||||
UserId = user.Id.Value,
|
UserId = user.Id.Value,
|
||||||
Cmt = cmt
|
Cmt = cmt
|
||||||
};
|
};
|
||||||
DbContext.Comments.Add(newComment);
|
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
CacheManager.ClearRegion(label.CacheRegion);
|
CacheManager.ClearRegion(label.CacheRegion);
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
result = true;
|
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 sw = Stopwatch.StartNew();
|
||||||
var result = false;
|
var result = false;
|
||||||
var errors = new List<Exception>();
|
var errors = new List<Exception>();
|
||||||
var playlist = DbContext.Playlists
|
var playlist = await DbContext.Playlists.FirstOrDefaultAsync(x => x.RoadieId == playlistId).ConfigureAwait(false);
|
||||||
.FirstOrDefault(x => x.RoadieId == playlistId);
|
|
||||||
if (playlist == null)
|
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
|
var newComment = new data.Comment
|
||||||
{
|
{
|
||||||
|
@ -162,8 +239,8 @@ namespace Roadie.Api.Services
|
||||||
UserId = user.Id.Value,
|
UserId = user.Id.Value,
|
||||||
Cmt = cmt
|
Cmt = cmt
|
||||||
};
|
};
|
||||||
DbContext.Comments.Add(newComment);
|
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
CacheManager.ClearRegion(playlist.CacheRegion);
|
CacheManager.ClearRegion(playlist.CacheRegion);
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
result = true;
|
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 sw = Stopwatch.StartNew();
|
||||||
var result = false;
|
var result = false;
|
||||||
var errors = new List<Exception>();
|
var errors = new List<Exception>();
|
||||||
var release = DbContext.Releases
|
var release = await DbContext.Releases.FirstOrDefaultAsync(x => x.RoadieId == releaseId).ConfigureAwait(false);
|
||||||
.FirstOrDefault(x => x.RoadieId == releaseId);
|
|
||||||
if (release == null)
|
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
|
var newComment = new data.Comment
|
||||||
{
|
{
|
||||||
|
@ -192,8 +270,8 @@ namespace Roadie.Api.Services
|
||||||
UserId = user.Id.Value,
|
UserId = user.Id.Value,
|
||||||
Cmt = cmt
|
Cmt = cmt
|
||||||
};
|
};
|
||||||
DbContext.Comments.Add(newComment);
|
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
CacheManager.ClearRegion(release.CacheRegion);
|
CacheManager.ClearRegion(release.CacheRegion);
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
result = true;
|
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 sw = Stopwatch.StartNew();
|
||||||
var result = false;
|
var result = false;
|
||||||
var errors = new List<Exception>();
|
var errors = new List<Exception>();
|
||||||
var track = DbContext.Tracks
|
var track = await DbContext.Tracks.FirstOrDefaultAsync(x => x.RoadieId == trackId).ConfigureAwait(false);
|
||||||
.FirstOrDefault(x => x.RoadieId == trackId);
|
if (track == null)
|
||||||
if (track == null) return new OperationResult<bool>(true, string.Format("Track Not Found [{0}]", trackId));
|
{
|
||||||
|
return new OperationResult<bool>(true, $"Track Not Found [{trackId}]");
|
||||||
|
}
|
||||||
|
|
||||||
var newComment = new data.Comment
|
var newComment = new data.Comment
|
||||||
{
|
{
|
||||||
|
@ -221,8 +301,8 @@ namespace Roadie.Api.Services
|
||||||
UserId = user.Id.Value,
|
UserId = user.Id.Value,
|
||||||
Cmt = cmt
|
Cmt = cmt
|
||||||
};
|
};
|
||||||
DbContext.Comments.Add(newComment);
|
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
CacheManager.ClearRegion(track.CacheRegion);
|
CacheManager.ClearRegion(track.CacheRegion);
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
result = true;
|
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 sw = Stopwatch.StartNew();
|
||||||
var result = false;
|
var result = false;
|
||||||
var errors = new List<Exception>();
|
var errors = new List<Exception>();
|
||||||
var comment = DbContext.Comments.FirstOrDefault(x => x.RoadieId == id);
|
var comment = await DbContext.Comments.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||||
if (comment == null) return new OperationResult<bool>(true, string.Format("Comment Not Found [{0}]", id));
|
if (comment == null)
|
||||||
|
{
|
||||||
|
return new OperationResult<bool>(true, $"Comment Not Found [{id}]");
|
||||||
|
}
|
||||||
|
|
||||||
DbContext.Remove(comment);
|
DbContext.Remove(comment);
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
ClearCaches(comment);
|
ClearCaches(comment);
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
result = true;
|
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 sw = Stopwatch.StartNew();
|
||||||
var result = false;
|
var result = false;
|
||||||
var errors = new List<Exception>();
|
var errors = new List<Exception>();
|
||||||
var comment = DbContext.Comments.FirstOrDefault(x => x.RoadieId == id);
|
var comment = await DbContext.Comments.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||||
if (comment == null) return new OperationResult<bool>(true, string.Format("Comment Not Found [{0}]", id));
|
if (comment == null)
|
||||||
var userCommentReaction =
|
{
|
||||||
DbContext.CommentReactions.FirstOrDefault(x => x.CommentId == comment.Id && x.UserId == user.Id);
|
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)
|
if (userCommentReaction == null)
|
||||||
{
|
{
|
||||||
userCommentReaction = new data.CommentReaction
|
userCommentReaction = new data.CommentReaction
|
||||||
|
@ -272,20 +359,20 @@ namespace Roadie.Api.Services
|
||||||
CommentId = comment.Id,
|
CommentId = comment.Id,
|
||||||
UserId = user.Id.Value
|
UserId = user.Id.Value
|
||||||
};
|
};
|
||||||
DbContext.CommentReactions.Add(userCommentReaction);
|
await DbContext.CommentReactions.AddAsync(userCommentReaction).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
userCommentReaction.Reaction = reaction == CommentReaction.Unknown ? null : reaction.ToString();
|
userCommentReaction.Reaction = reaction == CommentReaction.Unknown ? null : reaction.ToString();
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
ClearCaches(comment);
|
ClearCaches(comment);
|
||||||
var userCommentReactions = (from cr in DbContext.CommentReactions
|
var userCommentReactions = await (from cr in DbContext.CommentReactions
|
||||||
where cr.CommentId == comment.Id
|
where cr.CommentId == comment.Id
|
||||||
select cr).ToArray();
|
select cr)
|
||||||
|
.ToArrayAsync()
|
||||||
|
.ConfigureAwait(false);
|
||||||
var additionalData = new Dictionary<string, object>();
|
var additionalData = new Dictionary<string, object>();
|
||||||
additionalData.Add("likedCount",
|
additionalData.Add("likedCount", userCommentReactions.Where(x => x.ReactionValue == CommentReaction.Like).Count());
|
||||||
userCommentReactions.Where(x => x.ReactionValue == CommentReaction.Like).Count());
|
additionalData.Add("dislikedCount", userCommentReactions.Where(x => x.ReactionValue == CommentReaction.Dislike).Count());
|
||||||
additionalData.Add("dislikedCount",
|
|
||||||
userCommentReactions.Where(x => x.ReactionValue == CommentReaction.Dislike).Count());
|
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
result = true;
|
result = true;
|
||||||
return new OperationResult<bool>
|
return new OperationResult<bool>
|
||||||
|
@ -297,46 +384,5 @@ namespace Roadie.Api.Services
|
||||||
OperationTime = sw.ElapsedMilliseconds
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,7 +18,7 @@ namespace Roadie.Api.Services
|
||||||
|
|
||||||
public async Task SendEmailAsync(string email, string subject, string htmlMessage)
|
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");
|
Trace.WriteLine("Email Server (Configuration.SmtpHost) Not Configured", "Warning");
|
||||||
return;
|
return;
|
||||||
|
@ -37,7 +37,7 @@ namespace Roadie.Api.Services
|
||||||
mail.IsBodyHtml = true;
|
mail.IsBodyHtml = true;
|
||||||
mail.Body = htmlMessage;
|
mail.Body = htmlMessage;
|
||||||
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
|
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
|
||||||
await client.SendMailAsync(mail);
|
await client.SendMailAsync(mail).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,12 +18,20 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Dynamic.Core;
|
using System.Linq.Dynamic.Core;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using data = Roadie.Library.Data;
|
|
||||||
|
|
||||||
namespace Roadie.Api.Services
|
namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
public class FileDirectoryProcessorService : ServiceBase, IFileDirectoryProcessorService
|
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> _addedArtistIds = new List<int>();
|
||||||
private List<int> _addedReleaseIds = new List<int>();
|
private List<int> _addedReleaseIds = new List<int>();
|
||||||
private List<int> _addedTrackIds = new List<int>();
|
private List<int> _addedTrackIds = new List<int>();
|
||||||
|
@ -34,14 +42,6 @@ namespace Roadie.Api.Services
|
||||||
|
|
||||||
public int? ProcessLimit { get; set; }
|
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,
|
public FileDirectoryProcessorService(IRoadieSettings configuration,
|
||||||
IHttpEncoder httpEncoder,
|
IHttpEncoder httpEncoder,
|
||||||
IHttpContext httpContext,
|
IHttpContext httpContext,
|
||||||
|
@ -62,73 +62,17 @@ namespace Roadie.Api.Services
|
||||||
FileProcessor = fileProcessor;
|
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>
|
/// <summary>
|
||||||
/// Perform any operations to the given folder and the plugin results after processing
|
/// Perform any operations to the given folder and the plugin results after processing
|
||||||
/// </summary>
|
/// </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");
|
SimpleContract.Requires<ArgumentNullException>(inboundFolder != null, "Invalid InboundFolder");
|
||||||
if (pluginResults != null)
|
if (pluginResults != null)
|
||||||
{
|
{
|
||||||
foreach (var releasesInfo in pluginResults.GroupBy(x => x.ReleaseId).Select(x => x.First()))
|
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);
|
_addedTrackIds.AddRange(ReleaseService.AddedTrackIds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,6 +80,7 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
var fileExtensionsToDelete = Configuration.FileExtensionsToDelete ?? new string[0];
|
var fileExtensionsToDelete = Configuration.FileExtensionsToDelete ?? new string[0];
|
||||||
if (fileExtensionsToDelete.Any())
|
if (fileExtensionsToDelete.Any())
|
||||||
|
{
|
||||||
foreach (var fileInFolder in inboundFolder.GetFiles("*.*", SearchOption.AllDirectories))
|
foreach (var fileInFolder in inboundFolder.GetFiles("*.*", SearchOption.AllDirectories))
|
||||||
{
|
{
|
||||||
if (fileExtensionsToDelete.Any(x => x.Equals(fileInFolder.Extension, StringComparison.OrdinalIgnoreCase)))
|
if (fileExtensionsToDelete.Any(x => x.Equals(fileInFolder.Extension, StringComparison.OrdinalIgnoreCase)))
|
||||||
|
@ -148,6 +93,7 @@ namespace Roadie.Api.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DeleteEmptyFolders(inboundFolder, Logger);
|
DeleteEmptyFolders(inboundFolder, Logger);
|
||||||
}
|
}
|
||||||
|
@ -158,9 +104,67 @@ namespace Roadie.Api.Services
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Perform any operations to the given folder before processing
|
/// Perform any operations to the given folder before processing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private Task<bool> PreProcessFolder(DirectoryInfo inboundFolder, bool doJustInfo = false)
|
private Task<bool> PreProcessFolderAsync(DirectoryInfo inboundFolder, bool doJustInfo = false)
|
||||||
{
|
{
|
||||||
return Task.FromResult(true);
|
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
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,11 +9,9 @@ using Roadie.Library.Data.Context;
|
||||||
using Roadie.Library.Encoding;
|
using Roadie.Library.Encoding;
|
||||||
using Roadie.Library.Enums;
|
using Roadie.Library.Enums;
|
||||||
using Roadie.Library.Extensions;
|
using Roadie.Library.Extensions;
|
||||||
using Roadie.Library.Identity;
|
|
||||||
using Roadie.Library.Imaging;
|
using Roadie.Library.Imaging;
|
||||||
using Roadie.Library.Models;
|
using Roadie.Library.Models;
|
||||||
using Roadie.Library.Models.Pagination;
|
using Roadie.Library.Models.Pagination;
|
||||||
using Roadie.Library.Models.Users;
|
|
||||||
using Roadie.Library.Utility;
|
using Roadie.Library.Utility;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
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();
|
var sw = Stopwatch.StartNew();
|
||||||
sw.Start();
|
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 () =>
|
var result = await CacheManager.GetAsync(cacheKey, async () =>
|
||||||
{
|
{
|
||||||
return await GenreByIdAction(id, includes);
|
return await GenreByIdAction(id, includes).ConfigureAwait(false);
|
||||||
}, data.Genre.CacheRegionUrn(id));
|
}, data.Genre.CacheRegionUrn(id)).ConfigureAwait(false);
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
return new OperationResult<Genre>(result.Messages)
|
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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
var genre = DbContext.Genres.FirstOrDefault(x => x.RoadieId == id);
|
var genre = await DbContext.Genres.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||||
if (genre == null) return new OperationResult<bool>(true, string.Format("Genre Not Found [{0}]", id));
|
if (genre == null)
|
||||||
|
{
|
||||||
|
return new OperationResult<bool>(true, $"Genre Not Found [{id}]");
|
||||||
|
}
|
||||||
|
|
||||||
DbContext.Genres.Remove(genre);
|
DbContext.Genres.Remove(genre);
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
var genreImageFilename = genre.PathToImage(Configuration);
|
var genreImageFilename = genre.PathToImage(Configuration);
|
||||||
if (File.Exists(genreImageFilename))
|
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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
@ -102,7 +198,7 @@ namespace Roadie.Api.Services
|
||||||
if (doRandomize ?? false)
|
if (doRandomize ?? false)
|
||||||
{
|
{
|
||||||
var randomLimit = request.Limit ?? roadieUser?.RandomReleaseLimit ?? request.LimitValue;
|
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();
|
randomGenreIds = randomGenreData.Select(x => x.Value).ToArray();
|
||||||
rowCount = DbContext.Genres.Count();
|
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)
|
public Task<OperationResult<Library.Models.Image>> SetGenreImageByUrlAsync(Library.Models.Users.User user, Guid id, string imageUrl) => SaveImageBytes(user, id, WebHelper.BytesForImageUrl(imageUrl));
|
||||||
{
|
|
||||||
return await 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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
var errors = new List<Exception>();
|
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)
|
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
|
// If genre is being renamed, see if genre already exists with new model supplied name
|
||||||
var genreName = genre.SortNameValue;
|
var genreName = genre.SortNameValue;
|
||||||
|
@ -229,7 +322,7 @@ namespace Roadie.Api.Services
|
||||||
File.WriteAllBytes(genre.PathToImage(Configuration), ImageHelper.ConvertToJpegFormat(genreImage));
|
File.WriteAllBytes(genre.PathToImage(Configuration), ImageHelper.ConvertToJpegFormat(genreImage));
|
||||||
}
|
}
|
||||||
genre.LastUpdated = now;
|
genre.LastUpdated = now;
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
CacheManager.ClearRegion(genre.CacheRegion);
|
CacheManager.ClearRegion(genre.CacheRegion);
|
||||||
Logger.LogInformation($"UpdateGenre `{genre}` By User `{user}`");
|
Logger.LogInformation($"UpdateGenre `{genre}` By User `{user}`");
|
||||||
|
@ -244,14 +337,14 @@ namespace Roadie.Api.Services
|
||||||
|
|
||||||
return new OperationResult<bool>
|
return new OperationResult<bool>
|
||||||
{
|
{
|
||||||
IsSuccess = !errors.Any(),
|
IsSuccess = errors.Count == 0,
|
||||||
Data = !errors.Any(),
|
Data = errors.Count == 0,
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
OperationTime = sw.ElapsedMilliseconds,
|
||||||
Errors = errors
|
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];
|
var bytes = new byte[0];
|
||||||
using (var ms = new MemoryStream())
|
using (var ms = new MemoryStream())
|
||||||
|
@ -259,102 +352,7 @@ namespace Roadie.Api.Services
|
||||||
file.CopyTo(ms);
|
file.CopyTo(ms);
|
||||||
bytes = ms.ToArray();
|
bytes = ms.ToArray();
|
||||||
}
|
}
|
||||||
|
return await SaveImageBytes(user, id, bytes).ConfigureAwait(false);
|
||||||
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
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,10 +14,17 @@ namespace Roadie.Api.Services
|
||||||
public HttpContext(IRoadieSettings configuration, IUrlHelper urlHelper)
|
public HttpContext(IRoadieSettings configuration, IUrlHelper urlHelper)
|
||||||
{
|
{
|
||||||
var scheme = urlHelper.ActionContext.HttpContext.Request.Scheme;
|
var scheme = urlHelper.ActionContext.HttpContext.Request.Scheme;
|
||||||
if (configuration.UseSSLBehindProxy) scheme = "https";
|
if (configuration.UseSSLBehindProxy)
|
||||||
|
{
|
||||||
|
scheme = "https";
|
||||||
|
}
|
||||||
|
|
||||||
var host = urlHelper.ActionContext.HttpContext.Request.Host;
|
var host = urlHelper.ActionContext.HttpContext.Request.Host;
|
||||||
if (!string.IsNullOrEmpty(configuration.BehindProxyHost))
|
if (!string.IsNullOrEmpty(configuration.BehindProxyHost))
|
||||||
|
{
|
||||||
host = new HostString(configuration.BehindProxyHost);
|
host = new HostString(configuration.BehindProxyHost);
|
||||||
|
}
|
||||||
|
|
||||||
BaseUrl = $"{scheme}://{host}";
|
BaseUrl = $"{scheme}://{host}";
|
||||||
ImageBaseUrl = $"{BaseUrl}/images";
|
ImageBaseUrl = $"{BaseUrl}/images";
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,48 +9,48 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
public interface IAdminService
|
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();
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,7 @@
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Roadie.Library;
|
using Roadie.Library;
|
||||||
using Roadie.Library.Identity;
|
|
||||||
using Roadie.Library.Models;
|
using Roadie.Library.Models;
|
||||||
using Roadie.Library.Models.Pagination;
|
using Roadie.Library.Models.Pagination;
|
||||||
using Roadie.Library.Models.Users;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -12,22 +10,22 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
public interface IArtistService
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,7 +9,7 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
public interface IBookmarkService
|
public interface IBookmarkService
|
||||||
{
|
{
|
||||||
Task<OperationResult<bool>> RemoveAllBookmarksForItem(BookmarkType type, int id);
|
Task<PagedResult<BookmarkList>> ListAsync(User roadieUser, PagedRequest request, bool? doRandomize = false, BookmarkType? filterType = null);
|
||||||
Task<PagedResult<BookmarkList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, BookmarkType? filterType = null);
|
Task<OperationResult<bool>> RemoveAllBookmarksForItemAsync(BookmarkType type, int id);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,13 +12,12 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
OperationResult<Collection> Add(User roadieUser);
|
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,
|
Task<PagedResult<CollectionList>> ListAsync(User roadieUser, PagedRequest request, bool? doRandomize = false, Guid? releaseId = null, Guid? artistId = null);
|
||||||
Guid? releaseId = null, Guid? artistId = null);
|
|
||||||
|
|
||||||
Task<OperationResult<bool>> UpdateCollection(User roadieUser, Collection collection);
|
Task<OperationResult<bool>> UpdateCollectionAsync(User roadieUser, Collection collection);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,22 +8,22 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
public interface ICommentService
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,6 +14,6 @@ namespace Roadie.Api.Services
|
||||||
|
|
||||||
int? ProcessLimit { get; set; }
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,7 @@
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Roadie.Library;
|
using Roadie.Library;
|
||||||
using Roadie.Library.Identity;
|
|
||||||
using Roadie.Library.Models;
|
using Roadie.Library.Models;
|
||||||
using Roadie.Library.Models.Pagination;
|
using Roadie.Library.Models.Pagination;
|
||||||
using Roadie.Library.Models.Users;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -12,16 +10,16 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
public interface IGenreService
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Roadie.Library;
|
using Roadie.Library;
|
||||||
using Roadie.Library.Identity;
|
|
||||||
using Roadie.Library.Imaging;
|
using Roadie.Library.Imaging;
|
||||||
using Roadie.Library.Models;
|
|
||||||
using Roadie.Library.SearchEngines.Imaging;
|
using Roadie.Library.SearchEngines.Imaging;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -16,26 +14,26 @@ namespace Roadie.Api.Services
|
||||||
|
|
||||||
string RequestIp { get; set; }
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,7 @@
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Roadie.Library;
|
using Roadie.Library;
|
||||||
using Roadie.Library.Identity;
|
|
||||||
using Roadie.Library.Models;
|
using Roadie.Library.Models;
|
||||||
using Roadie.Library.Models.Pagination;
|
using Roadie.Library.Models.Pagination;
|
||||||
using Roadie.Library.Models.Users;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -12,18 +10,18 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
public interface ILabelService
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,24 +7,24 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
public interface ILookupService
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,10 +10,10 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
public interface IPlayActivityService
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,20 +11,20 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
public interface IPlaylistService
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,10 +1,8 @@
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Roadie.Library;
|
using Roadie.Library;
|
||||||
using Roadie.Library.Identity;
|
|
||||||
using Roadie.Library.Models;
|
using Roadie.Library.Models;
|
||||||
using Roadie.Library.Models.Pagination;
|
using Roadie.Library.Models.Pagination;
|
||||||
using Roadie.Library.Models.Releases;
|
using Roadie.Library.Models.Releases;
|
||||||
using Roadie.Library.Models.Users;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -15,26 +13,26 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
IEnumerable<int> AddedTrackIds { get; }
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,17 +7,17 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
public interface IStatisticsService
|
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();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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 System.Threading.Tasks;
|
||||||
using User = Roadie.Library.Models.Users.User;
|
using User = Roadie.Library.Models.Users.User;
|
||||||
|
|
||||||
|
@ -7,85 +6,85 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
public interface ISubsonicService
|
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> GetLicense(Request request);
|
||||||
|
|
||||||
SubsonicOperationResult<Response> GetLyrics(Request request, string artistId, string title);
|
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> GetVideos(Request request);
|
||||||
|
|
||||||
SubsonicOperationResult<Response> Ping(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,
|
string name = null, string comment = null, bool? isPublic = null, string[] songIdsToAdd = null,
|
||||||
int[] songIndexesToRemove = null);
|
int[] songIndexesToRemove = null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,6 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
public interface ITokenService
|
public interface ITokenService
|
||||||
{
|
{
|
||||||
Task<string> GenerateToken(User user, UserManager<User> userManager);
|
Task<string> GenerateTokenAsync(User user, UserManager<User> userManager);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,16 +10,14 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
public interface ITrackService
|
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,
|
Task<PagedResult<TrackList>> ListAsync(PagedRequest request, User roadieUser, bool? doRandomize = false, Guid? releaseId = null);
|
||||||
Guid? releaseId = null);
|
|
||||||
|
|
||||||
OperationResult<Track> StreamCheckAndInfo(User roadieUser, Guid id);
|
OperationResult<Track> StreamCheckAndInfo(User roadieUser, Guid id);
|
||||||
|
|
||||||
Task<OperationResult<TrackStreamInfo>> TrackStreamInfo(Guid trackId, long beginBytes, long endBytes,
|
Task<OperationResult<TrackStreamInfo>> TrackStreamInfoAsync(Guid trackId, long beginBytes, long endBytes, User roadieUser);
|
||||||
User roadieUser);
|
|
||||||
|
|
||||||
Task<OperationResult<bool>> UpdateTrack(User user, Track track);
|
Task<OperationResult<bool>> UpdateTrackAsync(User user, Track track);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,44 +9,44 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
public interface IUserService
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -23,12 +23,20 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
public class ImageService : ServiceBase, IImageService
|
public class ImageService : ServiceBase, IImageService
|
||||||
{
|
{
|
||||||
public string Referrer { get; set; }
|
|
||||||
public string RequestIp { get; set; }
|
|
||||||
private IDefaultNotFoundImages DefaultNotFoundImages { get; }
|
private IDefaultNotFoundImages DefaultNotFoundImages { get; }
|
||||||
|
|
||||||
private IImageSearchManager ImageSearchManager { 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,
|
public ImageService(IRoadieSettings configuration,
|
||||||
IHttpEncoder httpEncoder,
|
IHttpEncoder httpEncoder,
|
||||||
IHttpContext httpContext,
|
IHttpContext httpContext,
|
||||||
|
@ -43,149 +51,6 @@ namespace Roadie.Api.Services
|
||||||
ImageSearchManager = imageSearchManager;
|
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>
|
/// <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.
|
/// 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>
|
/// </summary>
|
||||||
|
@ -193,10 +58,10 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var artist = await GetArtist(id);
|
var artist = await GetArtist(id).ConfigureAwait(false);
|
||||||
if (artist == null)
|
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;
|
byte[] imageBytes = null;
|
||||||
string artistFolder = null;
|
string artistFolder = null;
|
||||||
|
@ -226,7 +91,7 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
Bytes = imageBytes,
|
Bytes = imageBytes,
|
||||||
};
|
};
|
||||||
if (imageBytes == null || !imageBytes.Any())
|
if (imageBytes?.Any() != true)
|
||||||
{
|
{
|
||||||
image = DefaultNotFoundImages.Artist;
|
image = DefaultNotFoundImages.Artist;
|
||||||
}
|
}
|
||||||
|
@ -244,10 +109,10 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var artist = await GetArtist(id);
|
var artist = await GetArtist(id).ConfigureAwait(false);
|
||||||
if (artist == null)
|
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;
|
byte[] imageBytes = null;
|
||||||
string artistFolder = null;
|
string artistFolder = null;
|
||||||
|
@ -265,7 +130,9 @@ namespace Roadie.Api.Services
|
||||||
.FindImageTypeInDirectory(new DirectoryInfo(artistFolder), ImageType.ArtistSecondary)
|
.FindImageTypeInDirectory(new DirectoryInfo(artistFolder), ImageType.ArtistSecondary)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
if (artistSecondaryImages.Length >= imageId && artistSecondaryImages[imageId] != null)
|
if (artistSecondaryImages.Length >= imageId && artistSecondaryImages[imageId] != null)
|
||||||
|
{
|
||||||
imageBytes = File.ReadAllBytes(artistSecondaryImages[imageId].FullName);
|
imageBytes = File.ReadAllBytes(artistSecondaryImages[imageId].FullName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -292,10 +159,10 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var collection = await GetCollection(id);
|
var collection = await GetCollection(id).ConfigureAwait(false);
|
||||||
if (collection == null)
|
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)
|
IImage image = new Library.Imaging.Image(id)
|
||||||
{
|
{
|
||||||
|
@ -313,7 +180,7 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
Logger.LogError(ex, $"Error Reading Image File [{collectionImageFilename}]");
|
Logger.LogError(ex, $"Error Reading Image File [{collectionImageFilename}]");
|
||||||
}
|
}
|
||||||
if (image.Bytes == null || !image.Bytes.Any())
|
if (image.Bytes?.Any() != true)
|
||||||
{
|
{
|
||||||
image = DefaultNotFoundImages.Collection;
|
image = DefaultNotFoundImages.Collection;
|
||||||
}
|
}
|
||||||
|
@ -336,7 +203,7 @@ namespace Roadie.Api.Services
|
||||||
}
|
}
|
||||||
if (image?.Bytes?.Any() != true)
|
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
|
return new FileOperationResult<IImage>(image?.Bytes?.Any() ?? false
|
||||||
? OperationMessages.OkMessage
|
? OperationMessages.OkMessage
|
||||||
|
@ -354,10 +221,10 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var genre = await GetGenre(id);
|
var genre = await GetGenre(id).ConfigureAwait(false);
|
||||||
if (genre == null)
|
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)
|
IImage image = new Library.Imaging.Image(id)
|
||||||
{
|
{
|
||||||
|
@ -375,7 +242,7 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
Logger.LogError(ex, $"Error Reading Image File [{genreImageFilename}]");
|
Logger.LogError(ex, $"Error Reading Image File [{genreImageFilename}]");
|
||||||
}
|
}
|
||||||
if (image.Bytes == null || !image.Bytes.Any())
|
if (image.Bytes?.Any() != true)
|
||||||
{
|
{
|
||||||
image = DefaultNotFoundImages.Genre;
|
image = DefaultNotFoundImages.Genre;
|
||||||
}
|
}
|
||||||
|
@ -395,7 +262,7 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
var sizeHash = (width ?? 0) + (height ?? 0);
|
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)
|
if (!result.IsSuccess)
|
||||||
{
|
{
|
||||||
return new FileOperationResult<IImage>(result.IsNotFoundResult, result.Messages);
|
return new FileOperationResult<IImage>(result.IsNotFoundResult, result.Messages);
|
||||||
|
@ -450,10 +317,10 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var label = await GetLabel(id);
|
var label = await GetLabel(id).ConfigureAwait(false);
|
||||||
if (label == null)
|
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)
|
IImage image = new Library.Imaging.Image(id)
|
||||||
{
|
{
|
||||||
|
@ -471,7 +338,7 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
Logger.LogError(ex, $"Error Reading Image File [{labelImageFilename}]");
|
Logger.LogError(ex, $"Error Reading Image File [{labelImageFilename}]");
|
||||||
}
|
}
|
||||||
if (image.Bytes == null || !image.Bytes.Any())
|
if (image.Bytes?.Any() != true)
|
||||||
{
|
{
|
||||||
image = DefaultNotFoundImages.Label;
|
image = DefaultNotFoundImages.Label;
|
||||||
}
|
}
|
||||||
|
@ -489,10 +356,10 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var playlist = await GetPlaylist(id);
|
var playlist = await GetPlaylist(id).ConfigureAwait(false);
|
||||||
if (playlist == null)
|
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)
|
IImage image = new Library.Imaging.Image(id)
|
||||||
{
|
{
|
||||||
|
@ -510,7 +377,7 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
Logger.LogError(ex, $"Error Reading Image File [{playlistImageFilename}]");
|
Logger.LogError(ex, $"Error Reading Image File [{playlistImageFilename}]");
|
||||||
}
|
}
|
||||||
if (image.Bytes == null || !image.Bytes.Any())
|
if (image.Bytes?.Any() != true)
|
||||||
{
|
{
|
||||||
image = DefaultNotFoundImages.Playlist;
|
image = DefaultNotFoundImages.Playlist;
|
||||||
}
|
}
|
||||||
|
@ -531,10 +398,10 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var release = await GetRelease(id);
|
var release = await GetRelease(id).ConfigureAwait(false);
|
||||||
if (release == null)
|
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;
|
byte[] imageBytes = null;
|
||||||
string artistFolder = null;
|
string artistFolder = null;
|
||||||
|
@ -591,10 +458,10 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var release = await GetRelease(id);
|
var release = await GetRelease(id).ConfigureAwait(false);
|
||||||
if (release == null)
|
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;
|
byte[] imageBytes = null;
|
||||||
string artistFolder = null;
|
string artistFolder = null;
|
||||||
|
@ -620,7 +487,9 @@ namespace Roadie.Api.Services
|
||||||
.FindImageTypeInDirectory(new DirectoryInfo(releaseFolder), ImageType.ReleaseSecondary)
|
.FindImageTypeInDirectory(new DirectoryInfo(releaseFolder), ImageType.ReleaseSecondary)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
if (releaseSecondaryImages.Length >= imageId && releaseSecondaryImages[imageId] != null)
|
if (releaseSecondaryImages.Length >= imageId && releaseSecondaryImages[imageId] != null)
|
||||||
|
{
|
||||||
imageBytes = File.ReadAllBytes(releaseSecondaryImages[imageId].FullName);
|
imageBytes = File.ReadAllBytes(releaseSecondaryImages[imageId].FullName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -649,10 +518,10 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var track = await GetTrack(id);
|
var track = await GetTrack(id).ConfigureAwait(false);
|
||||||
if (track == null)
|
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)
|
IImage image = new Library.Imaging.Image(id)
|
||||||
{
|
{
|
||||||
|
@ -663,10 +532,10 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
image.Bytes = File.ReadAllBytes(trackImageFileName);
|
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
|
// 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);
|
return GenerateFileOperationResult(id, image, etag);
|
||||||
}
|
}
|
||||||
|
@ -682,10 +551,10 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var user = await GetUser(id);
|
var user = await GetUser(id).ConfigureAwait(false);
|
||||||
if (user == null)
|
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)
|
IImage image = new Library.Imaging.Image(id)
|
||||||
{
|
{
|
||||||
|
@ -703,7 +572,7 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
Logger.LogError(ex, $"Error Reading Image File [{userImageFilename}]");
|
Logger.LogError(ex, $"Error Reading Image File [{userImageFilename}]");
|
||||||
}
|
}
|
||||||
if (image.Bytes == null || !image.Bytes.Any())
|
if (image.Bytes?.Any() != true)
|
||||||
{
|
{
|
||||||
image = DefaultNotFoundImages.User;
|
image = DefaultNotFoundImages.User;
|
||||||
}
|
}
|
||||||
|
@ -716,5 +585,141 @@ namespace Roadie.Api.Services
|
||||||
|
|
||||||
return new FileOperationResult<IImage>(OperationMessages.ErrorOccured);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,7 +9,6 @@ using Roadie.Library.Data.Context;
|
||||||
using Roadie.Library.Encoding;
|
using Roadie.Library.Encoding;
|
||||||
using Roadie.Library.Enums;
|
using Roadie.Library.Enums;
|
||||||
using Roadie.Library.Extensions;
|
using Roadie.Library.Extensions;
|
||||||
using Roadie.Library.Identity;
|
|
||||||
using Roadie.Library.Imaging;
|
using Roadie.Library.Imaging;
|
||||||
using Roadie.Library.Models;
|
using Roadie.Library.Models;
|
||||||
using Roadie.Library.Models.Pagination;
|
using Roadie.Library.Models.Pagination;
|
||||||
|
@ -43,318 +42,6 @@ namespace Roadie.Api.Services
|
||||||
BookmarkService = bookmarkService;
|
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)
|
private async Task<OperationResult<Label>> LabelByIdAction(Guid id, IEnumerable<string> includes = null)
|
||||||
{
|
{
|
||||||
var timings = new Dictionary<string, long>();
|
var timings = new Dictionary<string, long>();
|
||||||
|
@ -364,12 +51,12 @@ namespace Roadie.Api.Services
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
|
||||||
tsw.Restart();
|
tsw.Restart();
|
||||||
var label = await GetLabel(id);
|
var label = await GetLabel(id).ConfigureAwait(false);
|
||||||
tsw.Stop();
|
tsw.Stop();
|
||||||
timings.Add("GetLabel", tsw.ElapsedMilliseconds);
|
timings.Add(nameof(GetLabel), tsw.ElapsedMilliseconds);
|
||||||
if (label == null)
|
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();
|
tsw.Restart();
|
||||||
var result = label.Adapt<Label>();
|
var result = label.Adapt<Label>();
|
||||||
|
@ -456,8 +143,12 @@ namespace Roadie.Api.Services
|
||||||
var sw = new Stopwatch();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
var errors = new List<Exception>();
|
var errors = new List<Exception>();
|
||||||
var label = DbContext.Labels.FirstOrDefault(x => x.RoadieId == id);
|
var label = await DbContext.Labels.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||||
if (label == null) return new OperationResult<Library.Models.Image>(true, string.Format("Label Not Found [{0}]", id));
|
if (label == null)
|
||||||
|
{
|
||||||
|
return new OperationResult<Library.Models.Image>(true, $"Label Not Found [{id}]");
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
|
@ -467,7 +158,7 @@ namespace Roadie.Api.Services
|
||||||
File.WriteAllBytes(label.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(imageBytes));
|
File.WriteAllBytes(label.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(imageBytes));
|
||||||
}
|
}
|
||||||
label.LastUpdated = now;
|
label.LastUpdated = now;
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
CacheManager.ClearRegion(label.CacheRegion);
|
CacheManager.ClearRegion(label.CacheRegion);
|
||||||
Logger.LogInformation($"UploadLabelImage `{label}` By User `{user}`");
|
Logger.LogInformation($"UploadLabelImage `{label}` By User `{user}`");
|
||||||
}
|
}
|
||||||
|
@ -481,11 +172,324 @@ namespace Roadie.Api.Services
|
||||||
|
|
||||||
return new OperationResult<Library.Models.Image>
|
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),
|
Data = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "label", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height, true),
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
OperationTime = sw.ElapsedMilliseconds,
|
||||||
Errors = errors
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -34,7 +34,7 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<OperationResult<IEnumerable<DataToken>>> ArtistTypes()
|
public Task<OperationResult<IEnumerable<DataToken>>> ArtistTypesAsync()
|
||||||
{
|
{
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
|
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();
|
var sw = Stopwatch.StartNew();
|
||||||
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
|
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();
|
var sw = Stopwatch.StartNew();
|
||||||
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
|
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();
|
var sw = Stopwatch.StartNew();
|
||||||
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
|
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();
|
var sw = Stopwatch.StartNew();
|
||||||
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
|
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();
|
var sw = Stopwatch.StartNew();
|
||||||
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
|
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();
|
var sw = Stopwatch.StartNew();
|
||||||
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
|
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();
|
var sw = Stopwatch.StartNew();
|
||||||
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
|
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 sw = Stopwatch.StartNew();
|
||||||
var data = await CacheManager.GetAsync(CreditCategoriesCacheKey, async () =>
|
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(),
|
Value = x.RoadieId.ToString(),
|
||||||
Text = x.Name
|
Text = x.Name
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
}, CacheManagerBase.SystemCacheRegionUrn);
|
}, CacheManagerBase.SystemCacheRegionUrn).ConfigureAwait(false);
|
||||||
return new OperationResult<IEnumerable<DataToken>>
|
return new OperationResult<IEnumerable<DataToken>>
|
||||||
{
|
{
|
||||||
Data = data,
|
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();
|
var sw = Stopwatch.StartNew();
|
||||||
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
|
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
|
||||||
|
|
|
@ -19,7 +19,6 @@ using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Dynamic.Core;
|
using System.Linq.Dynamic.Core;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using data = Roadie.Library.Data;
|
|
||||||
|
|
||||||
namespace Roadie.Api.Services
|
namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
|
@ -29,8 +28,15 @@ namespace Roadie.Api.Services
|
||||||
|
|
||||||
protected IScrobbleHandler ScrobblerHandler { get; }
|
protected IScrobbleHandler ScrobblerHandler { get; }
|
||||||
|
|
||||||
public PlayActivityService(IRoadieSettings configuration, IHttpEncoder httpEncoder,IHttpContext httpContext,
|
public PlayActivityService(IRoadieSettings configuration, IRoadieDbContext dbContext, ICacheManager cacheManager,
|
||||||
IRoadieDbContext dbContext, ICacheManager cacheManager,ILogger<PlayActivityService> logger,
|
ILogger logger, ScrobbleHandler scrobbleHandler)
|
||||||
|
: base(configuration, null, dbContext, cacheManager, logger, null)
|
||||||
|
{
|
||||||
|
ScrobblerHandler = scrobbleHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayActivityService(IRoadieSettings configuration, IHttpEncoder httpEncoder, IHttpContext httpContext,
|
||||||
|
IRoadieDbContext dbContext, ICacheManager cacheManager, ILogger<PlayActivityService> logger,
|
||||||
IScrobbleHandler scrobbleHandler, IHubContext<PlayActivityHub> playActivityHub)
|
IScrobbleHandler scrobbleHandler, IHubContext<PlayActivityHub> playActivityHub)
|
||||||
: base(configuration, httpEncoder, dbContext, cacheManager, logger, httpContext)
|
: base(configuration, httpEncoder, dbContext, cacheManager, logger, httpContext)
|
||||||
{
|
{
|
||||||
|
@ -38,14 +44,84 @@ namespace Roadie.Api.Services
|
||||||
ScrobblerHandler = scrobbleHandler;
|
ScrobblerHandler = scrobbleHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayActivityService(IRoadieSettings configuration, IRoadieDbContext dbContext, ICacheManager cacheManager,
|
private async Task PublishPlayActivity(User roadieUser, ScrobbleInfo scrobble, bool isNowPlaying)
|
||||||
ILogger logger, ScrobbleHandler scrobbleHandler)
|
|
||||||
: base(configuration, null, dbContext, cacheManager, logger, null)
|
|
||||||
{
|
{
|
||||||
ScrobblerHandler = scrobbleHandler;
|
// 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 Task<Library.Models.Pagination.PagedResult<PlayActivityList>> List(PagedRequest request,User roadieUser = null, DateTime? newerThan = null)
|
public async Task<Library.Models.Pagination.PagedResult<PlayActivityList>> ListAsync(PagedRequest request, User roadieUser = null, DateTime? newerThan = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -119,118 +195,46 @@ namespace Roadie.Api.Services
|
||||||
? request.OrderValue(new Dictionary<string, string> { { "PlayedDateDateTime", "DESC" } })
|
? request.OrderValue(new Dictionary<string, string> { { "PlayedDateDateTime", "DESC" } })
|
||||||
: request.OrderValue();
|
: request.OrderValue();
|
||||||
var rowCount = result.Count();
|
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();
|
sw.Stop();
|
||||||
return Task.FromResult(new Library.Models.Pagination.PagedResult<PlayActivityList>
|
return new Library.Models.Pagination.PagedResult<PlayActivityList>
|
||||||
{
|
{
|
||||||
TotalCount = rowCount,
|
TotalCount = rowCount,
|
||||||
CurrentPage = request.PageValue,
|
CurrentPage = request.PageValue,
|
||||||
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
|
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
|
||||||
OperationTime = sw.ElapsedMilliseconds,
|
OperationTime = sw.ElapsedMilliseconds,
|
||||||
Rows = rows
|
Rows = rows
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError(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);
|
var scrobbleResult = await ScrobblerHandler.NowPlaying(roadieUser, scrobble).ConfigureAwait(false);
|
||||||
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);
|
|
||||||
if (!scrobbleResult.IsSuccess)
|
if (!scrobbleResult.IsSuccess)
|
||||||
{
|
{
|
||||||
return scrobbleResult;
|
return scrobbleResult;
|
||||||
}
|
}
|
||||||
await PublishPlayActivity(roadieUser, scrobble, false);
|
|
||||||
|
await PublishPlayActivity(roadieUser, scrobble, true).ConfigureAwait(false);
|
||||||
return scrobbleResult;
|
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
|
var scrobbleResult = await ScrobblerHandler.Scrobble(roadieUser, scrobble).ConfigureAwait(false);
|
||||||
if (roadieUser?.IsPrivate != true &&
|
if (!scrobbleResult.IsSuccess)
|
||||||
scrobble.ElapsedTimeOfTrackPlayed.TotalSeconds > scrobble.TrackDuration.TotalSeconds / 2)
|
|
||||||
{
|
{
|
||||||
var sw = Stopwatch.StartNew();
|
return scrobbleResult;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
await PublishPlayActivity(roadieUser, scrobble, false).ConfigureAwait(false);
|
||||||
|
return scrobbleResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -42,412 +42,6 @@ namespace Roadie.Api.Services
|
||||||
BookmarkService = bookmarkService;
|
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)
|
private async Task<OperationResult<Playlist>> PlaylistByIdAction(Guid id, IEnumerable<string> includes = null)
|
||||||
{
|
{
|
||||||
var timings = new Dictionary<string, long>();
|
var timings = new Dictionary<string, long>();
|
||||||
|
@ -457,13 +51,13 @@ namespace Roadie.Api.Services
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
|
||||||
tsw.Restart();
|
tsw.Restart();
|
||||||
var playlist = await GetPlaylist(id);
|
var playlist = await GetPlaylist(id).ConfigureAwait(false);
|
||||||
tsw.Stop();
|
tsw.Stop();
|
||||||
timings.Add("getPlaylist", tsw.ElapsedMilliseconds);
|
timings.Add("getPlaylist", tsw.ElapsedMilliseconds);
|
||||||
|
|
||||||
if (playlist == null)
|
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();
|
tsw.Restart();
|
||||||
var result = playlist.Adapt<Playlist>();
|
var result = playlist.Adapt<Playlist>();
|
||||||
|
@ -563,5 +157,416 @@ namespace Roadie.Api.Services
|
||||||
OperationTime = sw.ElapsedMilliseconds
|
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
|
@ -99,91 +99,91 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
return null;
|
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)
|
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(x => x.Genres)
|
||||||
.Include("Genres.Genre")
|
.Include("Genres.Genre")
|
||||||
.FirstOrDefaultAsync(x => x.RoadieId == id);
|
.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||||
}, data.Artist.CacheRegionUrn(id));
|
}, 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)
|
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);
|
return await DbContext.Collections.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||||
}, data.Collection.CacheRegionUrn(id));
|
}, 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)
|
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);
|
return await DbContext.Genres.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||||
}, data.Genre.CacheRegionUrn(id));
|
}, 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)
|
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);
|
return await DbContext.Labels.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||||
}, data.Label.CacheRegionUrn(id));
|
}, 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)
|
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)
|
.Include(x => x.User)
|
||||||
.FirstOrDefaultAsync(x => x.RoadieId == id);
|
.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||||
}, data.Playlist.CacheRegionUrn(id));
|
}, 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)
|
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.Artist)
|
||||||
.Include(x => x.Genres)
|
.Include(x => x.Genres)
|
||||||
.Include("Genres.Genre")
|
.Include("Genres.Genre")
|
||||||
.Include(x => x.Medias)
|
.Include(x => x.Medias)
|
||||||
.Include("Medias.Tracks")
|
.Include("Medias.Tracks")
|
||||||
.Include("Medias.Tracks.TrackArtist")
|
.Include("Medias.Tracks.TrackArtist")
|
||||||
.FirstOrDefaultAsync(x => x.RoadieId == id);
|
.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||||
}, data.Release.CacheRegionUrn(id));
|
}, data.Release.CacheRegionUrn(id)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -193,27 +193,27 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
if (Guid.TryParse(id, out Guid trackId))
|
if (Guid.TryParse(id, out Guid trackId))
|
||||||
{
|
{
|
||||||
return await GetTrack(trackId);
|
return await GetTrack(trackId).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only read operations
|
// Only read operations
|
||||||
protected Task<data.Track> GetTrack(Guid id)
|
protected async Task<data.Track> GetTrack(Guid id)
|
||||||
{
|
{
|
||||||
if(id == Guid.Empty)
|
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)
|
||||||
.Include(x => x.ReleaseMedia.Release)
|
.Include(x => x.ReleaseMedia.Release)
|
||||||
.Include(x => x.ReleaseMedia.Release.Artist)
|
.Include(x => x.ReleaseMedia.Release.Artist)
|
||||||
.Include(x => x.TrackArtist)
|
.Include(x => x.TrackArtist)
|
||||||
.FirstOrDefaultAsync(x => x.RoadieId == id);
|
.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||||
}, data.Track.CacheRegionUrn(id));
|
}, data.Track.CacheRegionUrn(id)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task<User> GetUser(string username)
|
protected async Task<User> GetUser(string username)
|
||||||
|
@ -225,40 +225,41 @@ namespace Roadie.Api.Services
|
||||||
var userByUsername = await CacheManager.GetAsync(User.CacheUrnByUsername(username), () =>
|
var userByUsername = await CacheManager.GetAsync(User.CacheUrnByUsername(username), () =>
|
||||||
{
|
{
|
||||||
return DbContext.Users.FirstOrDefaultAsync(x => x.UserName == username);
|
return DbContext.Users.FirstOrDefaultAsync(x => x.UserName == username);
|
||||||
}, null);
|
}, null).ConfigureAwait(false);
|
||||||
return await GetUser(userByUsername?.RoadieId).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)
|
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(x => x.UserRoles)
|
||||||
.Include("UserRoles.Role")
|
.Include("UserRoles.Role")
|
||||||
.Include("UserRoles.Role.RoleClaims")
|
.Include("UserRoles.Role.RoleClaims")
|
||||||
.Include(x => x.UserClaims)
|
.Include(x => x.UserClaims)
|
||||||
.Include(x => x.UserQues)
|
.Include(x => x.UserQues)
|
||||||
.Include("UserQues.Track")
|
.Include("UserQues.Track")
|
||||||
.FirstOrDefaultAsync(x => x.RoadieId == id);
|
.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||||
}, User.CacheRegionUrn(id.Value));
|
}, User.CacheRegionUrn(id.Value)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected string MakeLastFmUrl(string artistName, string releaseTitle) => "http://www.last.fm/music/" + HttpEncoder.UrlEncode($"{artistName}/{releaseTitle}");
|
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)
|
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(x => x.Genres)
|
||||||
.Include("Genres.Genre")
|
.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}]");
|
if (artist == null) return new OperationResult<short>(true, $"Invalid Artist Id [{artistId}]");
|
||||||
var now = DateTime.UtcNow;
|
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)
|
if (userArtist == null)
|
||||||
{
|
{
|
||||||
userArtist = new data.UserArtist
|
userArtist = new data.UserArtist
|
||||||
|
@ -278,7 +279,7 @@ namespace Roadie.Api.Services
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
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);
|
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);
|
artist.Rating = (short)ratings.Average(x => (decimal)x);
|
||||||
}
|
}
|
||||||
|
@ -288,7 +289,7 @@ namespace Roadie.Api.Services
|
||||||
}
|
}
|
||||||
artist.LastUpdated = now;
|
artist.LastUpdated = now;
|
||||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
await UpdateArtistRank(artist.Id);
|
await UpdateArtistRank(artist.Id).ConfigureAwait(false);
|
||||||
CacheManager.ClearRegion(user.CacheRegion);
|
CacheManager.ClearRegion(user.CacheRegion);
|
||||||
CacheManager.ClearRegion(artist.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)
|
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.Artist)
|
||||||
.Include(x => x.Genres)
|
.Include(x => x.Genres)
|
||||||
.Include("Genres.Genre")
|
.Include("Genres.Genre")
|
||||||
.Include(x => x.Medias)
|
.Include(x => x.Medias)
|
||||||
.Include("Medias.Tracks")
|
.Include("Medias.Tracks")
|
||||||
.Include("Medias.Tracks.TrackArtist")
|
.Include("Medias.Tracks.TrackArtist")
|
||||||
.FirstOrDefault(x => x.RoadieId == releaseId);
|
.FirstOrDefaultAsync(x => x.RoadieId == releaseId).ConfigureAwait(false);
|
||||||
if (release == null)
|
if (release == null)
|
||||||
{
|
{
|
||||||
return new OperationResult<short>(true, $"Invalid Release Id [{releaseId}]");
|
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;
|
var now = DateTime.UtcNow;
|
||||||
if (userRelease == null)
|
if (userRelease == null)
|
||||||
{
|
{
|
||||||
|
@ -325,7 +326,7 @@ namespace Roadie.Api.Services
|
||||||
UserId = user.Id,
|
UserId = user.Id,
|
||||||
ReleaseId = release.Id
|
ReleaseId = release.Id
|
||||||
};
|
};
|
||||||
DbContext.UserReleases.Add(userRelease);
|
await DbContext.UserReleases.AddAsync(userRelease).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -333,10 +334,10 @@ namespace Roadie.Api.Services
|
||||||
userRelease.LastUpdated = now;
|
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();
|
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.Any())
|
if (ratings != null && ratings.Count > 0)
|
||||||
{
|
{
|
||||||
release.Rating = (short)ratings.Average(x => (decimal)x);
|
release.Rating = (short)ratings.Average(x => (decimal)x);
|
||||||
}
|
}
|
||||||
|
@ -345,13 +346,13 @@ namespace Roadie.Api.Services
|
||||||
release.Rating = 0;
|
release.Rating = 0;
|
||||||
}
|
}
|
||||||
release.LastUpdated = now;
|
release.LastUpdated = now;
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
await UpdateReleaseRank(release.Id);
|
await UpdateReleaseRank(release.Id).ConfigureAwait(false);
|
||||||
CacheManager.ClearRegion(user.CacheRegion);
|
CacheManager.ClearRegion(user.CacheRegion);
|
||||||
CacheManager.ClearRegion(release.CacheRegion);
|
CacheManager.ClearRegion(release.CacheRegion);
|
||||||
CacheManager.ClearRegion(release.Artist.CacheRegion);
|
CacheManager.ClearRegion(release.Artist.CacheRegion);
|
||||||
|
|
||||||
release = await GetRelease(releaseId);
|
release = await GetRelease(releaseId).ConfigureAwait(false);
|
||||||
|
|
||||||
return new OperationResult<short>
|
return new OperationResult<short>
|
||||||
{
|
{
|
||||||
|
@ -364,18 +365,19 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
|
|
||||||
var track = DbContext.Tracks
|
var track = await DbContext.Tracks
|
||||||
.Include(x => x.ReleaseMedia)
|
.Include(x => x.ReleaseMedia)
|
||||||
.Include(x => x.ReleaseMedia.Release)
|
.Include(x => x.ReleaseMedia.Release)
|
||||||
.Include(x => x.ReleaseMedia.Release.Artist)
|
.Include(x => x.ReleaseMedia.Release.Artist)
|
||||||
.Include(x => x.TrackArtist)
|
.Include(x => x.TrackArtist)
|
||||||
.FirstOrDefault(x => x.RoadieId == trackId);
|
.FirstOrDefaultAsync(x => x.RoadieId == trackId)
|
||||||
|
.ConfigureAwait(false);
|
||||||
if (track == null)
|
if (track == null)
|
||||||
{
|
{
|
||||||
return new OperationResult<short>(true, $"Invalid Track Id [{trackId}]");
|
return new OperationResult<short>(true, $"Invalid Track Id [{trackId}]");
|
||||||
}
|
}
|
||||||
var now = DateTime.UtcNow;
|
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)
|
if (userTrack == null)
|
||||||
{
|
{
|
||||||
userTrack = new data.UserTrack
|
userTrack = new data.UserTrack
|
||||||
|
@ -384,7 +386,7 @@ namespace Roadie.Api.Services
|
||||||
UserId = user.Id,
|
UserId = user.Id,
|
||||||
TrackId = track.Id
|
TrackId = track.Id
|
||||||
};
|
};
|
||||||
DbContext.UserTracks.Add(userTrack);
|
await DbContext.UserTracks.AddAsync(userTrack).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -392,10 +394,10 @@ namespace Roadie.Api.Services
|
||||||
userTrack.LastUpdated = now;
|
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();
|
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.Any())
|
if (ratings != null && ratings.Count > 0)
|
||||||
{
|
{
|
||||||
track.Rating = (short)ratings.Average(x => (double)x);
|
track.Rating = (short)ratings.Average(x => (double)x);
|
||||||
}
|
}
|
||||||
|
@ -404,8 +406,8 @@ namespace Roadie.Api.Services
|
||||||
track.Rating = 0;
|
track.Rating = 0;
|
||||||
}
|
}
|
||||||
track.LastUpdated = now;
|
track.LastUpdated = now;
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
await UpdateReleaseRank(track.ReleaseMedia.Release.Id);
|
await UpdateReleaseRank(track.ReleaseMedia.Release.Id).ConfigureAwait(false);
|
||||||
|
|
||||||
CacheManager.ClearRegion(user.CacheRegion);
|
CacheManager.ClearRegion(user.CacheRegion);
|
||||||
CacheManager.ClearRegion(track.CacheRegion);
|
CacheManager.ClearRegion(track.CacheRegion);
|
||||||
|
@ -430,12 +432,13 @@ namespace Roadie.Api.Services
|
||||||
var result = false;
|
var result = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var artist = DbContext.Artists
|
var artist = await DbContext.Artists
|
||||||
.Include(x => x.Genres)
|
.Include(x => x.Genres)
|
||||||
.Include("Genres.Genre")
|
.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}]");
|
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)
|
if (userArtist == null)
|
||||||
{
|
{
|
||||||
userArtist = new data.UserArtist
|
userArtist = new data.UserArtist
|
||||||
|
@ -444,7 +447,7 @@ namespace Roadie.Api.Services
|
||||||
UserId = user.Id,
|
UserId = user.Id,
|
||||||
ArtistId = artist.Id
|
ArtistId = artist.Id
|
||||||
};
|
};
|
||||||
DbContext.UserArtists.Add(userArtist);
|
await DbContext.UserArtists.AddAsync(userArtist).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -452,7 +455,7 @@ namespace Roadie.Api.Services
|
||||||
userArtist.LastUpdated = DateTime.UtcNow;
|
userArtist.LastUpdated = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
CacheManager.ClearRegion(user.CacheRegion);
|
CacheManager.ClearRegion(user.CacheRegion);
|
||||||
CacheManager.ClearRegion(artist.CacheRegion);
|
CacheManager.ClearRegion(artist.CacheRegion);
|
||||||
|
@ -474,12 +477,13 @@ namespace Roadie.Api.Services
|
||||||
var result = false;
|
var result = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var artist = DbContext.Artists
|
var artist = await DbContext.Artists
|
||||||
.Include(x => x.Genres)
|
.Include(x => x.Genres)
|
||||||
.Include("Genres.Genre")
|
.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}]");
|
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)
|
if (userArtist == null)
|
||||||
{
|
{
|
||||||
userArtist = new data.UserArtist
|
userArtist = new data.UserArtist
|
||||||
|
@ -488,7 +492,7 @@ namespace Roadie.Api.Services
|
||||||
UserId = user.Id,
|
UserId = user.Id,
|
||||||
ArtistId = artist.Id
|
ArtistId = artist.Id
|
||||||
};
|
};
|
||||||
DbContext.UserArtists.Add(userArtist);
|
await DbContext.UserArtists.AddAsync(userArtist).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -496,7 +500,7 @@ namespace Roadie.Api.Services
|
||||||
userArtist.LastUpdated = DateTime.UtcNow;
|
userArtist.LastUpdated = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
CacheManager.ClearRegion(user.CacheRegion);
|
CacheManager.ClearRegion(user.CacheRegion);
|
||||||
CacheManager.ClearRegion(artist.CacheRegion);
|
CacheManager.ClearRegion(artist.CacheRegion);
|
||||||
|
@ -518,19 +522,20 @@ namespace Roadie.Api.Services
|
||||||
var result = false;
|
var result = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var release = DbContext.Releases
|
var release = await DbContext.Releases
|
||||||
.Include(x => x.Artist)
|
.Include(x => x.Artist)
|
||||||
.Include(x => x.Genres)
|
.Include(x => x.Genres)
|
||||||
.Include("Genres.Genre")
|
.Include("Genres.Genre")
|
||||||
.Include(x => x.Medias)
|
.Include(x => x.Medias)
|
||||||
.Include("Medias.Tracks")
|
.Include("Medias.Tracks")
|
||||||
.Include("Medias.Tracks.TrackArtist")
|
.Include("Medias.Tracks.TrackArtist")
|
||||||
.FirstOrDefault(x => x.RoadieId == releaseId);
|
.FirstOrDefaultAsync(x => x.RoadieId == releaseId)
|
||||||
|
.ConfigureAwait(false);
|
||||||
if (release == null)
|
if (release == null)
|
||||||
{
|
{
|
||||||
return new OperationResult<bool>(true, $"Invalid Release Id [{releaseId}]");
|
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)
|
if (userRelease == null)
|
||||||
{
|
{
|
||||||
userRelease = new data.UserRelease
|
userRelease = new data.UserRelease
|
||||||
|
@ -539,7 +544,7 @@ namespace Roadie.Api.Services
|
||||||
UserId = user.Id,
|
UserId = user.Id,
|
||||||
ReleaseId = release.Id
|
ReleaseId = release.Id
|
||||||
};
|
};
|
||||||
DbContext.UserReleases.Add(userRelease);
|
await DbContext.UserReleases.AddAsync(userRelease).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -547,7 +552,7 @@ namespace Roadie.Api.Services
|
||||||
userRelease.LastUpdated = DateTime.UtcNow;
|
userRelease.LastUpdated = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
CacheManager.ClearRegion(user.CacheRegion);
|
CacheManager.ClearRegion(user.CacheRegion);
|
||||||
CacheManager.ClearRegion(release.CacheRegion);
|
CacheManager.ClearRegion(release.CacheRegion);
|
||||||
|
@ -582,7 +587,7 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
return new OperationResult<bool>(true, $"Invalid Release Id [{releaseId}]");
|
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)
|
if (userRelease == null)
|
||||||
{
|
{
|
||||||
userRelease = new data.UserRelease
|
userRelease = new data.UserRelease
|
||||||
|
@ -591,7 +596,7 @@ namespace Roadie.Api.Services
|
||||||
UserId = user.Id,
|
UserId = user.Id,
|
||||||
ReleaseId = release.Id
|
ReleaseId = release.Id
|
||||||
};
|
};
|
||||||
DbContext.UserReleases.Add(userRelease);
|
await DbContext.UserReleases.AddAsync(userRelease).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -599,7 +604,7 @@ namespace Roadie.Api.Services
|
||||||
userRelease.LastUpdated = DateTime.UtcNow;
|
userRelease.LastUpdated = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
CacheManager.ClearRegion(user.CacheRegion);
|
CacheManager.ClearRegion(user.CacheRegion);
|
||||||
CacheManager.ClearRegion(release.CacheRegion);
|
CacheManager.ClearRegion(release.CacheRegion);
|
||||||
|
@ -622,17 +627,18 @@ namespace Roadie.Api.Services
|
||||||
var result = false;
|
var result = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var track = DbContext.Tracks
|
var track = await DbContext.Tracks
|
||||||
.Include(x => x.ReleaseMedia)
|
.Include(x => x.ReleaseMedia)
|
||||||
.Include(x => x.ReleaseMedia.Release)
|
.Include(x => x.ReleaseMedia.Release)
|
||||||
.Include(x => x.ReleaseMedia.Release.Artist)
|
.Include(x => x.ReleaseMedia.Release.Artist)
|
||||||
.Include(x => x.TrackArtist)
|
.Include(x => x.TrackArtist)
|
||||||
.FirstOrDefault(x => x.RoadieId == trackId);
|
.FirstOrDefaultAsync(x => x.RoadieId == trackId)
|
||||||
|
.ConfigureAwait(false);
|
||||||
if (track == null)
|
if (track == null)
|
||||||
{
|
{
|
||||||
return new OperationResult<bool>(true, $"Invalid Track Id [{trackId}]");
|
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)
|
if (userTrack == null)
|
||||||
{
|
{
|
||||||
userTrack = new data.UserTrack
|
userTrack = new data.UserTrack
|
||||||
|
@ -641,7 +647,7 @@ namespace Roadie.Api.Services
|
||||||
UserId = user.Id,
|
UserId = user.Id,
|
||||||
TrackId = track.Id
|
TrackId = track.Id
|
||||||
};
|
};
|
||||||
DbContext.UserTracks.Add(userTrack);
|
await DbContext.UserTracks.AddAsync(userTrack).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -649,7 +655,7 @@ namespace Roadie.Api.Services
|
||||||
userTrack.LastUpdated = DateTime.UtcNow;
|
userTrack.LastUpdated = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
CacheManager.ClearRegion(user.CacheRegion);
|
CacheManager.ClearRegion(user.CacheRegion);
|
||||||
CacheManager.ClearRegion(track.CacheRegion);
|
CacheManager.ClearRegion(track.CacheRegion);
|
||||||
|
@ -673,17 +679,18 @@ namespace Roadie.Api.Services
|
||||||
var result = false;
|
var result = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var track = DbContext.Tracks
|
var track = await DbContext.Tracks
|
||||||
.Include(x => x.ReleaseMedia)
|
.Include(x => x.ReleaseMedia)
|
||||||
.Include(x => x.ReleaseMedia.Release)
|
.Include(x => x.ReleaseMedia.Release)
|
||||||
.Include(x => x.ReleaseMedia.Release.Artist)
|
.Include(x => x.ReleaseMedia.Release.Artist)
|
||||||
.Include(x => x.TrackArtist)
|
.Include(x => x.TrackArtist)
|
||||||
.FirstOrDefault(x => x.RoadieId == trackId);
|
.FirstOrDefaultAsync(x => x.RoadieId == trackId)
|
||||||
|
.ConfigureAwait(false);
|
||||||
if (track == null)
|
if (track == null)
|
||||||
{
|
{
|
||||||
return new OperationResult<bool>(true, $"Invalid Track Id [{trackId}]");
|
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)
|
if (userTrack == null)
|
||||||
{
|
{
|
||||||
userTrack = new data.UserTrack
|
userTrack = new data.UserTrack
|
||||||
|
@ -692,7 +699,7 @@ namespace Roadie.Api.Services
|
||||||
UserId = user.Id,
|
UserId = user.Id,
|
||||||
TrackId = track.Id
|
TrackId = track.Id
|
||||||
};
|
};
|
||||||
DbContext.UserTracks.Add(userTrack);
|
await DbContext.UserTracks.AddAsync(userTrack).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -700,7 +707,7 @@ namespace Roadie.Api.Services
|
||||||
userTrack.LastUpdated = DateTime.UtcNow;
|
userTrack.LastUpdated = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
CacheManager.ClearRegion(user.CacheRegion);
|
CacheManager.ClearRegion(user.CacheRegion);
|
||||||
CacheManager.ClearRegion(track.CacheRegion);
|
CacheManager.ClearRegion(track.CacheRegion);
|
||||||
|
@ -724,18 +731,18 @@ namespace Roadie.Api.Services
|
||||||
|
|
||||||
protected async Task UpdateArtistCounts(int artistId, DateTime now)
|
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)
|
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
|
artist.TrackCount = await (from r in DbContext.Releases
|
||||||
join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
|
join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
|
||||||
join tr in DbContext.Tracks on rm.Id equals tr.ReleaseMediaId
|
join tr in DbContext.Tracks on rm.Id equals tr.ReleaseMediaId
|
||||||
where tr.ArtistId == artistId || r.ArtistId == artistId
|
where tr.ArtistId == artistId || r.ArtistId == artistId
|
||||||
select tr).CountAsync();
|
select tr).CountAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
artist.LastUpdated = now;
|
artist.LastUpdated = now;
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
CacheManager.ClearRegion(artist.CacheRegion);
|
CacheManager.ClearRegion(artist.CacheRegion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -750,10 +757,10 @@ namespace Roadie.Api.Services
|
||||||
join tr in DbContext.Tracks on rm.Id equals tr.ReleaseMediaId
|
join tr in DbContext.Tracks on rm.Id equals tr.ReleaseMediaId
|
||||||
join plt in DbContext.PlaylistTracks on tr.Id equals plt.TrackId
|
join plt in DbContext.PlaylistTracks on tr.Id equals plt.TrackId
|
||||||
where r.ArtistId == artistId
|
where r.ArtistId == artistId
|
||||||
select plt.PlayListId).ToListAsync();
|
select plt.PlayListId).ToListAsync().ConfigureAwait(false);
|
||||||
foreach (var playlistId in playlistIds.Distinct())
|
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 tr in DbContext.Tracks on rm.Id equals tr.ReleaseMediaId
|
||||||
join plt in DbContext.PlaylistTracks on tr.Id equals plt.TrackId
|
join plt in DbContext.PlaylistTracks on tr.Id equals plt.TrackId
|
||||||
where r.Id == releaseId
|
where r.Id == releaseId
|
||||||
select plt.PlayListId).ToListAsync();
|
select plt.PlayListId).ToListAsync().ConfigureAwait(false);
|
||||||
foreach(var playlistId in playlistIds.Distinct())
|
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
|
join tr in DbContext.Tracks on rm.Id equals tr.ReleaseMediaId
|
||||||
where r.Id == releaseId
|
where r.Id == releaseId
|
||||||
where tr.ArtistId != null
|
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);
|
trackArtistIds.Add(DbContext.Releases.FirstOrDefault(x => x.Id == releaseId).ArtistId);
|
||||||
foreach (var artistId in trackArtistIds.Distinct())
|
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
|
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 (artist != null)
|
||||||
{
|
{
|
||||||
if (updateReleaseRanks)
|
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)
|
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 rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||||
join ut in DbContext.UserTracks on t.Id equals ut.TrackId
|
join ut in DbContext.UserTracks on t.Id equals ut.TrackId
|
||||||
where t.ArtistId == artist.Id
|
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
|
var artistReleaseRatingRating = (await (from r in DbContext.Releases
|
||||||
join ur in DbContext.UserReleases on r.Id equals ur.ReleaseId
|
join ur in DbContext.UserReleases on r.Id equals ur.ReleaseId
|
||||||
where r.ArtistId == artist.Id
|
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
|
var artistReleaseRankSum = (await (from r in DbContext.Releases
|
||||||
where r.ArtistId == artist.Id
|
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;
|
artist.Rank = SafeParser.ToNumber<decimal>(artistTrackAverage + artistReleaseRatingRating) + artistReleaseRankSum + artist.Rating;
|
||||||
|
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
CacheManager.ClearRegion(artist.CacheRegion);
|
CacheManager.ClearRegion(artist.CacheRegion);
|
||||||
Logger.LogTrace("UpdatedArtistRank For Artist `{0}`", artist);
|
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
|
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||||
where rm.ReleaseId == release.Id
|
where rm.ReleaseId == release.Id
|
||||||
where t.ArtistId.HasValue
|
where t.ArtistId.HasValue
|
||||||
select t.ArtistId.Value).ToArrayAsync();
|
select t.ArtistId.Value).ToArrayAsync().ConfigureAwait(false);
|
||||||
artistsForRelease.AddRange(trackArtistsForRelease);
|
artistsForRelease.AddRange(trackArtistsForRelease);
|
||||||
foreach (var artistId in artistsForRelease.Distinct())
|
foreach (var artistId in artistsForRelease.Distinct())
|
||||||
{
|
{
|
||||||
await UpdateArtistRank(artistId);
|
await UpdateArtistRank(artistId).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task UpdateLabelCounts(int labelId, DateTime now)
|
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)
|
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
|
label.ArtistCount = await (from r in DbContext.Releases
|
||||||
join rl in DbContext.ReleaseLabels on r.Id equals rl.ReleaseId
|
join rl in DbContext.ReleaseLabels on r.Id equals rl.ReleaseId
|
||||||
join a in DbContext.Artists on r.ArtistId equals a.Id
|
join a in DbContext.Artists on r.ArtistId equals a.Id
|
||||||
where rl.LabelId == label.Id
|
where rl.LabelId == label.Id
|
||||||
group a by a.Id
|
group a by a.Id
|
||||||
into artists
|
into artists
|
||||||
select artists).Select(x => x.Key).CountAsync();
|
select artists).Select(x => x.Key).CountAsync().ConfigureAwait(false);
|
||||||
label.TrackCount = await (from r in DbContext.Releases
|
label.TrackCount = await (from r in DbContext.Releases
|
||||||
join rl in DbContext.ReleaseLabels on r.Id equals rl.ReleaseId
|
join rl in DbContext.ReleaseLabels on r.Id equals rl.ReleaseId
|
||||||
join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
|
join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
|
||||||
join t in DbContext.Tracks on rm.Id equals t.ReleaseMediaId
|
join t in DbContext.Tracks on rm.Id equals t.ReleaseMediaId
|
||||||
where rl.LabelId == label.Id
|
where rl.LabelId == label.Id
|
||||||
select t).CountAsync();
|
select t).CountAsync().ConfigureAwait(false);
|
||||||
label.LastUpdated = now;
|
label.LastUpdated = now;
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
CacheManager.ClearRegion(label.CacheRegion);
|
CacheManager.ClearRegion(label.CacheRegion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task UpdatePlaylistCounts(int playlistId, DateTime now)
|
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)
|
if (playlist != null)
|
||||||
{
|
{
|
||||||
var playlistTracks = await DbContext.PlaylistTracks
|
var playlistTracks = await DbContext.PlaylistTracks
|
||||||
.Include(x => x.Track)
|
.Include(x => x.Track)
|
||||||
.Include("Track.ReleaseMedia")
|
.Include("Track.ReleaseMedia")
|
||||||
.Where(x => x.PlayListId == playlist.Id).ToArrayAsync();
|
.Where(x => x.PlayListId == playlist.Id).ToArrayAsync().ConfigureAwait(false);
|
||||||
playlist.TrackCount = (short)playlistTracks.Count();
|
playlist.TrackCount = (short)playlistTracks.Length;
|
||||||
playlist.Duration = playlistTracks.Sum(x => x.Track.Duration);
|
playlist.Duration = playlistTracks.Sum(x => x.Track.Duration);
|
||||||
playlist.ReleaseCount = (short)playlistTracks.Select(x => x.Track.ReleaseMedia.ReleaseId).Distinct().Count();
|
playlist.ReleaseCount = (short)playlistTracks.Select(x => x.Track.ReleaseMedia.ReleaseId).Distinct().Count();
|
||||||
playlist.LastUpdated = now;
|
playlist.LastUpdated = now;
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
CacheManager.ClearRegion(playlist.CacheRegion);
|
CacheManager.ClearRegion(playlist.CacheRegion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task UpdateReleaseCounts(int releaseId, DateTime now)
|
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)
|
if (release != null)
|
||||||
{
|
{
|
||||||
release.PlayedCount = await (from t in DbContext.Tracks
|
release.PlayedCount = await (from t in DbContext.Tracks
|
||||||
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||||
where rm.ReleaseId == releaseId
|
where rm.ReleaseId == releaseId
|
||||||
where t.PlayedCount.HasValue
|
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
|
release.Duration = await (from t in DbContext.Tracks
|
||||||
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||||
where rm.ReleaseId == releaseId
|
where rm.ReleaseId == releaseId
|
||||||
select t).SumAsync(x => x.Duration);
|
select t).SumAsync(x => x.Duration).ConfigureAwait(false);
|
||||||
release.LastUpdated = now;
|
release.LastUpdated = now;
|
||||||
await DbContext.SaveChangesAsync();
|
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||||
CacheManager.ClearRegion(release.CacheRegion);
|
CacheManager.ClearRegion(release.CacheRegion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -939,7 +946,7 @@ namespace Roadie.Api.Services
|
||||||
{
|
{
|
||||||
try
|
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)
|
if (release != null)
|
||||||
{
|
{
|
||||||
var releaseTrackAverage = (await (from ut in DbContext.UserTracks
|
var releaseTrackAverage = (await (from ut in DbContext.UserTracks
|
||||||
|
|
|
@ -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;
|
LibraryStats result = null;
|
||||||
var sw = new Stopwatch();
|
var sw = new Stopwatch();
|
||||||
|
@ -65,39 +97,7 @@ namespace Roadie.Api.Services
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<OperationResult<IEnumerable<DateAndCount>>> ArtistsByDate()
|
public Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDateAsync()
|
||||||
{
|
|
||||||
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()
|
|
||||||
{
|
{
|
||||||
var sw = new Stopwatch();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
@ -129,78 +129,14 @@ namespace Roadie.Api.Services
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByUser()
|
public Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDecadeAsync()
|
||||||
{
|
|
||||||
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()
|
|
||||||
{
|
{
|
||||||
var sw = new Stopwatch();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
var result = new List<DateAndCount>();
|
var result = new List<DateAndCount>();
|
||||||
var decadeInfos = (from r in DbContext.Releases
|
var decadeInfos = (from r in DbContext.Releases
|
||||||
orderby r.ReleaseDate
|
orderby r.ReleaseDate
|
||||||
select r.ReleaseDate ?? r.CreatedDate)
|
select r.ReleaseDate ?? r.CreatedDate)
|
||||||
.ToArray()
|
.ToArray()
|
||||||
.GroupBy(x => x.ToString("yyyy"))
|
.GroupBy(x => x.ToString("yyyy"))
|
||||||
.Select(x => new
|
.Select(x => new
|
||||||
|
@ -235,5 +171,69 @@ namespace Roadie.Api.Services
|
||||||
Data = result
|
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
|
@ -20,11 +20,11 @@ namespace Roadie.Api.Services
|
||||||
_configuration = configuration;
|
_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 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 userRoles = roles.Select(r => new Claim(ClaimTypes.Role, r)).ToArray();
|
||||||
|
|
||||||
var tokenHandler = new JwtSecurityTokenHandler();
|
var tokenHandler = new JwtSecurityTokenHandler();
|
||||||
|
|
|
@ -37,9 +37,25 @@ namespace Roadie.Api.Services
|
||||||
|
|
||||||
private IBookmarkService BookmarkService { get; }
|
private IBookmarkService BookmarkService { get; }
|
||||||
|
|
||||||
public TrackService(IRoadieSettings configuration, IHttpEncoder httpEncoder, IHttpContext httpContext,
|
public TrackService(
|
||||||
IRoadieDbContext dbContext, ICacheManager cacheManager, ILogger<TrackService> logger,
|
IRoadieSettings configuration,
|
||||||
IBookmarkService bookmarkService, IAdminService adminService, IAudioMetaDataHelper audioMetaDataHelper)
|
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)
|
: base(configuration, httpEncoder, dbContext, cacheManager, logger, httpContext)
|
||||||
{
|
{
|
||||||
BookmarkService = bookmarkService;
|
BookmarkService = bookmarkService;
|
||||||
|
@ -47,82 +63,167 @@ namespace Roadie.Api.Services
|
||||||
AdminService = adminService;
|
AdminService = adminService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TrackService(IRoadieSettings configuration, IRoadieDbContext dbContext, ICacheManager cacheManager, ILogger logger)
|
private async Task<OperationResult<Track>> TrackByIdActionAsync(Guid id, IEnumerable<string> includes)
|
||||||
: 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)
|
|
||||||
{
|
{
|
||||||
var timings = new Dictionary<string, long>();
|
var timings = new Dictionary<string, long>();
|
||||||
var tsw = new Stopwatch();
|
var tsw = new Stopwatch();
|
||||||
|
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
sw.Start();
|
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 () =>
|
var result = await CacheManager.GetAsync(cacheKey, async () =>
|
||||||
{
|
{
|
||||||
tsw.Restart();
|
tsw.Restart();
|
||||||
var rr = await TrackByIdAction(id, includes).ConfigureAwait(false);
|
var rr = await TrackByIdActionAsync(id, includes).ConfigureAwait(false);
|
||||||
tsw.Stop();
|
tsw.Stop();
|
||||||
timings.Add("TrackByIdAction", tsw.ElapsedMilliseconds);
|
timings.Add(nameof(TrackByIdActionAsync), tsw.ElapsedMilliseconds);
|
||||||
return rr;
|
return rr;
|
||||||
}, data.Track.CacheRegionUrn(id)).ConfigureAwait(false);
|
}, data.Track.CacheRegionUrn(id)).ConfigureAwait(false);
|
||||||
if (result?.Data != null && roadieUser != null)
|
if (result?.Data != null && roadieUser != null)
|
||||||
|
@ -140,7 +241,7 @@ namespace Roadie.Api.Services
|
||||||
result.Data.TrackPlayUrl = MakeTrackPlayUrl(user, HttpContext.BaseUrl, track.RoadieId);
|
result.Data.TrackPlayUrl = MakeTrackPlayUrl(user, HttpContext.BaseUrl, track.RoadieId);
|
||||||
|
|
||||||
tsw.Restart();
|
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)
|
if (userBookmarkResult.IsSuccess)
|
||||||
{
|
{
|
||||||
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x?.Bookmark?.Value == track?.RoadieId.ToString()) != null;
|
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
|
try
|
||||||
{
|
{
|
||||||
|
@ -285,7 +443,7 @@ namespace Roadie.Api.Services
|
||||||
if (doRandomize ?? false)
|
if (doRandomize ?? false)
|
||||||
{
|
{
|
||||||
var randomLimit = roadieUser?.RandomReleaseLimit ?? request.LimitValue;
|
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();
|
randomTrackIds = randomTrackData.Select(x => x.Value).ToArray();
|
||||||
rowCount = DbContext.Releases.Count();
|
rowCount = DbContext.Releases.Count();
|
||||||
}
|
}
|
||||||
|
@ -341,14 +499,14 @@ namespace Roadie.Api.Services
|
||||||
where filterToTrackIds == null || filterToTrackIds.Contains(t.RoadieId)
|
where filterToTrackIds == null || filterToTrackIds.Contains(t.RoadieId)
|
||||||
where releaseId == null || r.RoadieId == releaseId
|
where releaseId == null || r.RoadieId == releaseId
|
||||||
where request.FilterMinimumRating == null || t.Rating >= request.FilterMinimumRating.Value
|
where request.FilterMinimumRating == null || t.Rating >= request.FilterMinimumRating.Value
|
||||||
where string.IsNullOrEmpty(normalizedFilterValue) ||
|
where string.IsNullOrEmpty(normalizedFilterValue) ||
|
||||||
(trackArtist != null && trackArtist.Name.ToLower().Contains(normalizedFilterValue)) ||
|
(trackArtist != null && trackArtist.Name.ToLower().Contains(normalizedFilterValue)) ||
|
||||||
t.Title.ToLower().Contains(normalizedFilterValue) ||
|
t.Title.ToLower().Contains(normalizedFilterValue) ||
|
||||||
t.AlternateNames.Contains(normalizedFilterValue) ||
|
t.AlternateNames.Contains(normalizedFilterValue) ||
|
||||||
t.PartTitles.ToLower().Contains(normalizedFilterValue)
|
t.PartTitles.ToLower().Contains(normalizedFilterValue)
|
||||||
where !isEqualFilter ||
|
where !isEqualFilter ||
|
||||||
t.Title.ToLower().Equals(normalizedFilterValue) ||
|
t.Title.ToLower().Equals(normalizedFilterValue) ||
|
||||||
t.AlternateNames.ToLower().Equals(normalizedFilterValue) ||
|
t.AlternateNames.ToLower().Equals(normalizedFilterValue) ||
|
||||||
t.PartTitles.ToLower().Equals(request.FilterValue)
|
t.PartTitles.ToLower().Equals(request.FilterValue)
|
||||||
where !request.FilterFavoriteOnly || favoriteTrackIds.Contains(t.Id)
|
where !request.FilterFavoriteOnly || favoriteTrackIds.Contains(t.Id)
|
||||||
where request.FilterToPlaylistId == null || playlistTrackIds.Contains(t.Id)
|
where request.FilterToPlaylistId == null || playlistTrackIds.Contains(t.Id)
|
||||||
|
@ -450,7 +608,7 @@ namespace Roadie.Api.Services
|
||||||
if (!string.IsNullOrEmpty(request.FilterValue) && request.FilterValue.StartsWith("#"))
|
if (!string.IsNullOrEmpty(request.FilterValue) && request.FilterValue.StartsWith("#"))
|
||||||
{
|
{
|
||||||
// Find any releases by tags
|
// 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));
|
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);
|
var track = DbContext.Tracks.FirstOrDefault(x => x.RoadieId == id);
|
||||||
if (track == null)
|
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>
|
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);
|
var track = DbContext.Tracks.FirstOrDefault(x => x.RoadieId == trackId);
|
||||||
if (!(track?.IsValid ?? true))
|
if (!(track?.IsValid ?? true))
|
||||||
|
@ -671,7 +829,7 @@ namespace Roadie.Api.Services
|
||||||
select r).FirstOrDefault();
|
select r).FirstOrDefault();
|
||||||
if (!release.IsLocked ?? false && roadieUser != null)
|
if (!release.IsLocked ?? false && roadieUser != null)
|
||||||
{
|
{
|
||||||
await AdminService.ScanRelease(new Library.Identity.User
|
await AdminService.ScanReleaseAsync(new Library.Identity.User
|
||||||
{
|
{
|
||||||
Id = roadieUser.Id.Value
|
Id = roadieUser.Id.Value
|
||||||
}, release.RoadieId, false, true).ConfigureAwait(false);
|
}, release.RoadieId, false, true).ConfigureAwait(false);
|
||||||
|
@ -710,7 +868,7 @@ namespace Roadie.Api.Services
|
||||||
select r).FirstOrDefault();
|
select r).FirstOrDefault();
|
||||||
if (!release.IsLocked ?? false && roadieUser != null)
|
if (!release.IsLocked ?? false && roadieUser != null)
|
||||||
{
|
{
|
||||||
await AdminService.ScanRelease(new Library.Identity.User
|
await AdminService.ScanReleaseAsync(new Library.Identity.User
|
||||||
{
|
{
|
||||||
Id = roadieUser.Id.Value
|
Id = roadieUser.Id.Value
|
||||||
}, release.RoadieId, false, true).ConfigureAwait(false);
|
}, 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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
@ -800,7 +958,7 @@ namespace Roadie.Api.Services
|
||||||
.FirstOrDefault(x => x.RoadieId == model.Id);
|
.FirstOrDefault(x => x.RoadieId == model.Id);
|
||||||
if (track == null)
|
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
|
try
|
||||||
|
@ -938,152 +1096,5 @@ namespace Roadie.Api.Services
|
||||||
Errors = errors
|
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
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -50,7 +50,179 @@ namespace Roadie.Api.Services
|
||||||
LastFmHelper = lastFmHelper;
|
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)
|
if (isAccountSettingsEdit && user.UserId != id && !user.IsAdmin)
|
||||||
{
|
{
|
||||||
|
@ -61,7 +233,7 @@ namespace Roadie.Api.Services
|
||||||
}
|
}
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
sw.Start();
|
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);
|
var result = await CacheManager.GetAsync(cacheKey, async () => await UserByIdAction(id, includes).ConfigureAwait(false), Library.Identity.User.CacheRegionUrn(id)).ConfigureAwait(false);
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
if (result?.Data != null)
|
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();
|
var sw = new Stopwatch();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
@ -162,27 +354,7 @@ namespace Roadie.Api.Services
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<OperationResult<bool>> DeleteAllBookmarks(User roadieUser)
|
public async Task<OperationResult<bool>> SetArtistBookmarkAsync(Guid artistId, User roadieUser, bool isBookmarked)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||||
if (user == null)
|
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);
|
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
|
@ -216,7 +388,7 @@ namespace Roadie.Api.Services
|
||||||
return await ToggleArtistDisliked(artistId, user, isDisliked).ConfigureAwait(false);
|
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);
|
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
|
@ -226,7 +398,7 @@ namespace Roadie.Api.Services
|
||||||
return await ToggleArtistFavorite(artistId, user, isFavorite).ConfigureAwait(false);
|
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);
|
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
|
@ -236,7 +408,7 @@ namespace Roadie.Api.Services
|
||||||
return await SetArtistRating(artistId, user, rating).ConfigureAwait(false);
|
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);
|
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||||
if (user == null)
|
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);
|
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||||
if (user == null)
|
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)
|
bool isBookmarked)
|
||||||
{
|
{
|
||||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
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);
|
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||||
if (user == null)
|
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);
|
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
|
@ -339,7 +511,7 @@ namespace Roadie.Api.Services
|
||||||
return await ToggleReleaseDisliked(releaseId, user, isDisliked).ConfigureAwait(false);
|
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);
|
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
|
@ -349,7 +521,7 @@ namespace Roadie.Api.Services
|
||||||
return await ToggleReleaseFavorite(releaseId, user, isFavorite).ConfigureAwait(false);
|
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);
|
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
|
@ -359,7 +531,7 @@ namespace Roadie.Api.Services
|
||||||
return await SetReleaseRating(releaseId, user, rating).ConfigureAwait(false);
|
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);
|
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||||
if (user == null)
|
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);
|
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
|
@ -392,7 +564,7 @@ namespace Roadie.Api.Services
|
||||||
return await ToggleTrackDisliked(trackId, user, isDisliked).ConfigureAwait(false);
|
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);
|
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
|
@ -402,13 +574,13 @@ namespace Roadie.Api.Services
|
||||||
return await ToggleTrackFavorite(trackId, user, isFavorite).ConfigureAwait(false);
|
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 timings = new Dictionary<string, long>();
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
timings.Add("GetUser", sw.ElapsedMilliseconds);
|
timings.Add(nameof(GetUser), sw.ElapsedMilliseconds);
|
||||||
|
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
|
@ -417,7 +589,7 @@ namespace Roadie.Api.Services
|
||||||
sw.Start();
|
sw.Start();
|
||||||
var result = await SetTrackRating(trackId, user, rating).ConfigureAwait(false);
|
var result = await SetTrackRating(trackId, user, rating).ConfigureAwait(false);
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
timings.Add("SetTrackRating", sw.ElapsedMilliseconds);
|
timings.Add(nameof(SetTrackRatingAsync), sw.ElapsedMilliseconds);
|
||||||
|
|
||||||
result.AdditionalData.Add("Timing", sw.ElapsedMilliseconds);
|
result.AdditionalData.Add("Timing", sw.ElapsedMilliseconds);
|
||||||
Logger.LogTrace(
|
Logger.LogTrace(
|
||||||
|
@ -425,7 +597,7 @@ namespace Roadie.Api.Services
|
||||||
return result;
|
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);
|
var user = DbContext.Users.FirstOrDefault(x => x.RoadieId == userId);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
|
@ -439,12 +611,12 @@ namespace Roadie.Api.Services
|
||||||
throw new NotImplementedException();
|
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);
|
var user = DbContext.Users.FirstOrDefault(x => x.RoadieId == userBeingUpdatedModel.UserId);
|
||||||
if (user == null)
|
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)
|
if (user.Id != userPerformingUpdate.Id && !userPerformingUpdate.IsAdmin)
|
||||||
{
|
{
|
||||||
|
@ -556,175 +728,5 @@ namespace Roadie.Api.Services
|
||||||
Data = true
|
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
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -28,11 +28,6 @@ namespace Roadie.Api.Controllers
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
public class AccountController : ControllerBase
|
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; }
|
private IAdminService AdminService { get; }
|
||||||
|
|
||||||
|
@ -43,10 +38,17 @@ namespace Roadie.Api.Controllers
|
||||||
if (_baseUrl == null)
|
if (_baseUrl == null)
|
||||||
{
|
{
|
||||||
var scheme = Request.Scheme;
|
var scheme = Request.Scheme;
|
||||||
if (RoadieSettings.UseSSLBehindProxy) scheme = "https";
|
if (RoadieSettings.UseSSLBehindProxy)
|
||||||
|
{
|
||||||
|
scheme = "https";
|
||||||
|
}
|
||||||
|
|
||||||
var host = Request.Host;
|
var host = Request.Host;
|
||||||
if (!string.IsNullOrEmpty(RoadieSettings.BehindProxyHost))
|
if (!string.IsNullOrEmpty(RoadieSettings.BehindProxyHost))
|
||||||
|
{
|
||||||
host = new HostString(RoadieSettings.BehindProxyHost);
|
host = new HostString(RoadieSettings.BehindProxyHost);
|
||||||
|
}
|
||||||
|
|
||||||
_baseUrl = $"{scheme}://{host}";
|
_baseUrl = $"{scheme}://{host}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,9 +64,22 @@ namespace Roadie.Api.Controllers
|
||||||
|
|
||||||
private IRoadieSettings RoadieSettings { get; }
|
private IRoadieSettings RoadieSettings { get; }
|
||||||
|
|
||||||
public AccountController(IAdminService adminService, UserManager<User> userManager, SignInManager<User> signInManager,
|
private string _baseUrl;
|
||||||
IConfiguration configuration, ILogger<AccountController> logger, ITokenService tokenService,
|
private readonly ILogger<AccountController> Logger;
|
||||||
ICacheManager cacheManager, IEmailSender emailSender, IHttpContext httpContext)
|
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;
|
UserManager = userManager;
|
||||||
SignInManager = signInManager;
|
SignInManager = signInManager;
|
||||||
|
@ -73,7 +88,7 @@ namespace Roadie.Api.Controllers
|
||||||
CacheManager = cacheManager;
|
CacheManager = cacheManager;
|
||||||
|
|
||||||
RoadieSettings = new RoadieSettings();
|
RoadieSettings = new RoadieSettings();
|
||||||
configuration.GetSection("RoadieSettings").Bind(RoadieSettings);
|
configuration.GetSection(nameof(RoadieSettings)).Bind(RoadieSettings);
|
||||||
AdminService = adminService;
|
AdminService = adminService;
|
||||||
EmailSender = emailSender;
|
EmailSender = emailSender;
|
||||||
RoadieHttpContext = httpContext;
|
RoadieHttpContext = httpContext;
|
||||||
|
@ -101,38 +116,41 @@ namespace Roadie.Api.Controllers
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Route("token")]
|
[Route("token")]
|
||||||
public async Task<IActionResult> CreateToken([FromBody] LoginModel model)
|
public async Task<IActionResult> CreateTokenAsync([FromBody] LoginModel model)
|
||||||
{
|
{
|
||||||
if (ModelState.IsValid)
|
if (ModelState.IsValid)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Login user
|
// 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)
|
if (!loginResult.Succeeded)
|
||||||
{
|
{
|
||||||
return BadRequest();
|
return BadRequest();
|
||||||
}
|
}
|
||||||
var user = await UserManager.FindByNameAsync(model.Username);
|
var user = await UserManager.FindByNameAsync(model.Username).ConfigureAwait(false);
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
user.LastLogin = now;
|
user.LastLogin = now;
|
||||||
user.LastUpdated = now;
|
user.LastUpdated = now;
|
||||||
await UserManager.UpdateAsync(user);
|
await UserManager.UpdateAsync(user).ConfigureAwait(false);
|
||||||
var t = await TokenService.GenerateToken(user, UserManager);
|
var t = await TokenService.GenerateTokenAsync(user, UserManager).ConfigureAwait(false);
|
||||||
Logger.LogTrace($"Successfully authenticated User [{model.Username}]");
|
Logger.LogTrace($"Successfully authenticated User [{model.Username}]");
|
||||||
if (!user.EmailConfirmed)
|
if (!user.EmailConfirmed)
|
||||||
|
{
|
||||||
try
|
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}";
|
var callbackUrl = $"{BaseUrl}/auth/confirmemail?userId={user.Id}&code={code}";
|
||||||
await EmailSender.SendEmailAsync(user.Email,
|
await EmailSender.SendEmailAsync(user.Email,
|
||||||
$"Confirm your {RoadieSettings.SiteName} 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)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError(ex, "Error sending confirmation Email");
|
Logger.LogError(ex, "Error sending confirmation Email");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CacheManager.ClearRegion(EntityControllerBase.ControllerCacheRegionUrn);
|
CacheManager.ClearRegion(EntityControllerBase.ControllerCacheRegionUrn);
|
||||||
var avatarUrl = $"{RoadieHttpContext.ImageBaseUrl}/user/{user.RoadieId}/{RoadieSettings.ThumbnailImageSize.Width}/{RoadieSettings.ThumbnailImageSize.Height}";
|
var avatarUrl = $"{RoadieHttpContext.ImageBaseUrl}/user/{user.RoadieId}/{RoadieSettings.ThumbnailImageSize.Width}/{RoadieSettings.ThumbnailImageSize.Height}";
|
||||||
|
@ -163,7 +181,7 @@ namespace Roadie.Api.Controllers
|
||||||
[Authorize]
|
[Authorize]
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Route("refreshtoken")]
|
[Route("refreshtoken")]
|
||||||
public async Task<IActionResult> RefreshToken()
|
public async Task<IActionResult> RefreshTokenAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -172,8 +190,8 @@ namespace Roadie.Api.Controllers
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
if (!string.IsNullOrWhiteSpace(username))
|
if (!string.IsNullOrWhiteSpace(username))
|
||||||
{
|
{
|
||||||
var user = await UserManager.FindByNameAsync(username);
|
var user = await UserManager.FindByNameAsync(username).ConfigureAwait(false);
|
||||||
return Ok(await TokenService.GenerateToken(user, UserManager));
|
return Ok(await TokenService.GenerateTokenAsync(user, UserManager).ConfigureAwait(false));
|
||||||
}
|
}
|
||||||
ModelState.AddModelError("Authentication", "Authentication failed!");
|
ModelState.AddModelError("Authentication", "Authentication failed!");
|
||||||
}
|
}
|
||||||
|
@ -187,7 +205,7 @@ namespace Roadie.Api.Controllers
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Route("register")]
|
[Route("register")]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
public async Task<IActionResult> Register([FromBody] RegisterModel registerModel)
|
public async Task<IActionResult> RegisterAsync([FromBody] RegisterModel registerModel)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -205,7 +223,7 @@ namespace Roadie.Api.Controllers
|
||||||
|
|
||||||
if (RoadieSettings.UseRegistrationTokens)
|
if (RoadieSettings.UseRegistrationTokens)
|
||||||
{
|
{
|
||||||
var tokenValidation = await AdminService.ValidateInviteToken(registerModel.InviteToken);
|
var tokenValidation = await AdminService.ValidateInviteTokenAsync(registerModel.InviteToken).ConfigureAwait(false);
|
||||||
if (!tokenValidation.IsSuccess)
|
if (!tokenValidation.IsSuccess)
|
||||||
{
|
{
|
||||||
Logger.LogTrace("Invalid Invite Token");
|
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)
|
if (existinUserByUsername != null)
|
||||||
{
|
{
|
||||||
return StatusCode((int)HttpStatusCode.BadRequest, new { Title = "User With Username Already Exists!" });
|
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)
|
if (existingUserByEmail != null)
|
||||||
{
|
{
|
||||||
return StatusCode((int)HttpStatusCode.BadRequest, new { Title = "User With Email Already Exists!" });
|
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 (identityResult.Succeeded)
|
||||||
{
|
{
|
||||||
if (user.Id == 1) await AdminService.DoInitialSetup(user, UserManager);
|
if (user.Id == 1)
|
||||||
|
{
|
||||||
|
await AdminService.DoInitialSetupAsync(user, UserManager).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
try
|
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}";
|
var callbackUrl = $"{BaseUrl}/auth/confirmemail?userId={user.Id}&code={code}";
|
||||||
await EmailSender.SendEmailAsync(user.Email, $"Confirm your {RoadieSettings.SiteName} email",
|
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)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.LogError(ex, $"Error Sending Register Email to [{registerModel.Email}]");
|
Logger.LogError(ex, $"Error Sending Register Email to [{registerModel.Email}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
await SignInManager.SignInAsync(user, false);
|
await SignInManager.SignInAsync(user, false).ConfigureAwait(false);
|
||||||
var t = await TokenService.GenerateToken(user, UserManager);
|
var t = await TokenService.GenerateTokenAsync(user, UserManager).ConfigureAwait(false);
|
||||||
Logger.LogTrace($"Successfully created and authenticated User [{registerModel.Username}]");
|
Logger.LogTrace($"Successfully created and authenticated User [{registerModel.Username}]");
|
||||||
CacheManager.ClearRegion(EntityControllerBase.ControllerCacheRegionUrn);
|
CacheManager.ClearRegion(EntityControllerBase.ControllerCacheRegionUrn);
|
||||||
var avatarUrl = $"{RoadieHttpContext.ImageBaseUrl}/user/{user.RoadieId}/{RoadieSettings.ThumbnailImageSize.Width}/{RoadieSettings.ThumbnailImageSize.Height}";
|
var avatarUrl = $"{RoadieHttpContext.ImageBaseUrl}/user/{user.RoadieId}/{RoadieSettings.ThumbnailImageSize.Width}/{RoadieSettings.ThumbnailImageSize.Height}";
|
||||||
if (registerModel.InviteToken.HasValue)
|
if (registerModel.InviteToken.HasValue)
|
||||||
{
|
{
|
||||||
await AdminService.UpdateInviteTokenUsed(registerModel.InviteToken);
|
await AdminService.UpdateInviteTokenUsedAsync(registerModel.InviteToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
return Ok(new
|
return Ok(new
|
||||||
{
|
{
|
||||||
|
@ -286,22 +308,22 @@ namespace Roadie.Api.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("resetpassword")]
|
[HttpPost("resetpassword")]
|
||||||
public async Task<IActionResult> ResetPassword([FromBody] ResetPasswordModel resetPasswordModel)
|
public async Task<IActionResult> ResetPasswordAsync([FromBody] ResetPasswordModel resetPasswordModel)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (ModelState.IsValid)
|
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 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)
|
if (identityResult.Succeeded)
|
||||||
{
|
{
|
||||||
CacheManager.ClearRegion(EntityControllerBase.ControllerCacheRegionUrn);
|
CacheManager.ClearRegion(EntityControllerBase.ControllerCacheRegionUrn);
|
||||||
await SignInManager.SignInAsync(user, false);
|
await SignInManager.SignInAsync(user, false).ConfigureAwait(false);
|
||||||
var avatarUrl =
|
var avatarUrl =
|
||||||
$"{RoadieHttpContext.ImageBaseUrl}/user/{user.RoadieId}/{RoadieSettings.ThumbnailImageSize.Width}/{RoadieSettings.ThumbnailImageSize.Height}";
|
$"{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
|
return Ok(new
|
||||||
{
|
{
|
||||||
Username = user.UserName,
|
Username = user.UserName,
|
||||||
|
@ -329,22 +351,22 @@ namespace Roadie.Api.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("sendpasswordresetemail")]
|
[HttpGet("sendpasswordresetemail")]
|
||||||
public async Task<IActionResult> SendPasswordResetEmail(string username, string callbackUrl)
|
public async Task<IActionResult> SendPasswordResetEmailAsync(string username, string callbackUrl)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var user = await UserManager.FindByNameAsync(username);
|
var user = await UserManager.FindByNameAsync(username).ConfigureAwait(false);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
Logger.LogError($"Unable to find user by username [{username}]");
|
Logger.LogError($"Unable to find user by username [{username}]");
|
||||||
return StatusCode(500);
|
return StatusCode(500);
|
||||||
}
|
}
|
||||||
|
|
||||||
var token = await UserManager.GeneratePasswordResetTokenAsync(user);
|
var token = await UserManager.GeneratePasswordResetTokenAsync(user).ConfigureAwait(false);
|
||||||
callbackUrl = callbackUrl + "?username=" + username + "&token=" +
|
callbackUrl = $"{callbackUrl}?username={username}&token={WebEncoders.Base64UrlEncode(Encoding.ASCII.GetBytes(token))}";
|
||||||
WebEncoders.Base64UrlEncode(Encoding.ASCII.GetBytes(token));
|
|
||||||
await EmailSender.SendEmailAsync(user.Email, $"Reset your {RoadieSettings.SiteName} password",
|
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,
|
Logger.LogTrace("User [{0}] Email [{1}] Requested Password Reset Callback [{2}]", username,
|
||||||
user.Email, callbackUrl);
|
user.Email, callbackUrl);
|
||||||
return Ok();
|
return Ok();
|
||||||
|
|
|
@ -21,8 +21,12 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
private IAdminService AdminService { get; }
|
private IAdminService AdminService { get; }
|
||||||
|
|
||||||
public AdminController(IAdminService adminService, ILogger<AdminController> logger, ICacheManager cacheManager,
|
public AdminController(
|
||||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
IAdminService adminService,
|
||||||
|
ILogger<AdminController> logger,
|
||||||
|
ICacheManager cacheManager,
|
||||||
|
UserManager<User> userManager,
|
||||||
|
IRoadieSettings roadieSettings)
|
||||||
: base(cacheManager, roadieSettings, userManager)
|
: base(cacheManager, roadieSettings, userManager)
|
||||||
{
|
{
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
|
@ -42,7 +46,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> DeleteArtist(Guid id, bool? doDeleteFile)
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.Messages?.Any() ?? false)
|
if (result.Messages?.Any() ?? false)
|
||||||
|
@ -58,7 +62,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> DeleteArtistReleases(Guid id)
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.Messages?.Any() ?? false)
|
if (result.Messages?.Any() ?? false)
|
||||||
|
@ -74,39 +78,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> DeleteArtistSecondaryImage(Guid id, int index)
|
public async Task<IActionResult> DeleteArtistSecondaryImage(Guid id, int index)
|
||||||
{
|
{
|
||||||
var result = await AdminService.DeleteArtistSecondaryImage(await UserManager.GetUserAsync(User), id, index);
|
var result = await AdminService.DeleteArtistSecondaryImageAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, index).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.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);
|
|
||||||
if (!result.IsSuccess)
|
if (!result.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.Messages?.Any() ?? false)
|
if (result.Messages?.Any() ?? false)
|
||||||
|
@ -122,7 +94,39 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> DeleteGenre(Guid id)
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.Messages?.Any() ?? false)
|
if (result.Messages?.Any() ?? false)
|
||||||
|
@ -139,16 +143,20 @@ namespace Roadie.Api.Controllers
|
||||||
public async Task<IActionResult> DeleteReleaseSecondaryImage(Guid id, int index)
|
public async Task<IActionResult> DeleteReleaseSecondaryImage(Guid id, int index)
|
||||||
{
|
{
|
||||||
var result =
|
var result =
|
||||||
await AdminService.DeleteReleaseSecondaryImage(await UserManager.GetUserAsync(User), id, index);
|
await AdminService.DeleteReleaseSecondaryImageAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, index).ConfigureAwait(false);
|
||||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
if (!result.IsSuccess)
|
||||||
|
{
|
||||||
|
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("delete/tracks")]
|
[HttpPost("delete/track/{id}")]
|
||||||
[ProducesResponseType(200)]
|
[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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.Messages?.Any() ?? false)
|
if (result.Messages?.Any() ?? false)
|
||||||
|
@ -160,11 +168,11 @@ namespace Roadie.Api.Controllers
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("delete/track/{id}")]
|
[HttpPost("delete/tracks")]
|
||||||
[ProducesResponseType(200)]
|
[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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.Messages?.Any() ?? false)
|
if (result.Messages?.Any() ?? false)
|
||||||
|
@ -180,7 +188,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> DeleteUser(Guid id)
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.Messages?.Any() ?? false)
|
if (result.Messages?.Any() ?? false)
|
||||||
|
@ -196,7 +204,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> MissingCollectionReleases()
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.Messages?.Any() ?? false)
|
if (result.Messages?.Any() ?? false)
|
||||||
|
@ -212,7 +220,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> ScanAllCollections()
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.Messages?.Any() ?? false)
|
if (result.Messages?.Any() ?? false)
|
||||||
|
@ -228,7 +236,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> ScanArtist(Guid id)
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.Messages?.Any() ?? false)
|
if (result.Messages?.Any() ?? false)
|
||||||
|
@ -244,7 +252,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> ScanArtists(IEnumerable<Guid> ids)
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.Messages?.Any() ?? false)
|
if (result.Messages?.Any() ?? false)
|
||||||
|
@ -260,7 +268,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> ScanCollection(Guid id, bool doPurgeFirst = false)
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.Messages?.Any() ?? false)
|
if (result.Messages?.Any() ?? false)
|
||||||
|
@ -276,7 +284,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> ScanInbound()
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.Messages?.Any() ?? false)
|
if (result.Messages?.Any() ?? false)
|
||||||
|
@ -292,7 +300,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> ScanLibrary()
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.Messages?.Any() ?? false)
|
if (result.Messages?.Any() ?? false)
|
||||||
|
@ -308,7 +316,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> ScanRelease(Guid id)
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.Messages?.Any() ?? false)
|
if (result.Messages?.Any() ?? false)
|
||||||
|
@ -324,7 +332,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> ScanReleases(IEnumerable<Guid> ids)
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.Messages?.Any() ?? false)
|
if (result.Messages?.Any() ?? false)
|
||||||
|
|
|
@ -25,8 +25,12 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
private IArtistService ArtistService { get; }
|
private IArtistService ArtistService { get; }
|
||||||
|
|
||||||
public ArtistController(IArtistService artistService, ILogger<ArtistController> logger, ICacheManager cacheManager,
|
public ArtistController(
|
||||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
IArtistService artistService,
|
||||||
|
ILogger<ArtistController> logger,
|
||||||
|
ICacheManager cacheManager,
|
||||||
|
UserManager<User> userManager,
|
||||||
|
IRoadieSettings roadieSettings)
|
||||||
: base(cacheManager, roadieSettings, userManager)
|
: base(cacheManager, roadieSettings, userManager)
|
||||||
{
|
{
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
|
@ -41,13 +45,17 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
var user = await CurrentUserModel().ConfigureAwait(false);
|
var user = await CurrentUserModel().ConfigureAwait(false);
|
||||||
var result =
|
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)
|
if (result?.IsNotFoundResult != false)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
if (!result.IsSuccess)
|
||||||
|
{
|
||||||
|
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,11 +65,15 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
PagedResult<models.ArtistList> result = await ArtistService.List(await CurrentUserModel().ConfigureAwait(false),
|
PagedResult<models.ArtistList> result = await ArtistService.ListAsync(await CurrentUserModel().ConfigureAwait(false),
|
||||||
request,
|
request,
|
||||||
doRandomize ?? false,
|
doRandomize ?? false,
|
||||||
false).ConfigureAwait(false);
|
false).ConfigureAwait(false);
|
||||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
if (!result.IsSuccess)
|
||||||
|
{
|
||||||
|
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
catch (UnauthorizedAccessException)
|
catch (UnauthorizedAccessException)
|
||||||
|
@ -82,7 +94,7 @@ namespace Roadie.Api.Controllers
|
||||||
[Authorize(Policy = "Editor")]
|
[Authorize(Policy = "Editor")]
|
||||||
public async Task<IActionResult> MergeArtists(Guid artistToMergeId, Guid artistToMergeIntoId)
|
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)
|
if (result?.IsNotFoundResult != false)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -110,8 +122,12 @@ namespace Roadie.Api.Controllers
|
||||||
public async Task<IActionResult> SetArtistImageByUrl(Guid id, string imageUrl)
|
public async Task<IActionResult> SetArtistImageByUrl(Guid id, string imageUrl)
|
||||||
{
|
{
|
||||||
var result =
|
var result =
|
||||||
await ArtistService.SetReleaseImageByUrl(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, HttpUtility.UrlDecode(imageUrl)).ConfigureAwait(false);
|
await ArtistService.SetReleaseImageByUrlAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, HttpUtility.UrlDecode(imageUrl)).ConfigureAwait(false);
|
||||||
if (result?.IsNotFoundResult != false) return NotFound();
|
if (result?.IsNotFoundResult != false)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
if (!result.IsSuccess)
|
if (!result.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.IsAccessDeniedResult)
|
if (result.IsAccessDeniedResult)
|
||||||
|
@ -137,7 +153,7 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
return BadRequest(ModelState);
|
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)
|
if (result?.IsNotFoundResult != false)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -163,7 +179,7 @@ namespace Roadie.Api.Controllers
|
||||||
[Authorize(Policy = "Editor")]
|
[Authorize(Policy = "Editor")]
|
||||||
public async Task<IActionResult> UploadImage(Guid id, IFormFile file)
|
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)
|
if (result?.IsNotFoundResult != false)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
|
@ -21,8 +21,12 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
private IBookmarkService BookmarkService { get; }
|
private IBookmarkService BookmarkService { get; }
|
||||||
|
|
||||||
public BookmarkController(IBookmarkService bookmarkService, ILogger<BookmarkController> logger, ICacheManager cacheManager,
|
public BookmarkController(
|
||||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
IBookmarkService bookmarkService,
|
||||||
|
ILogger<BookmarkController> logger,
|
||||||
|
ICacheManager cacheManager,
|
||||||
|
UserManager<User> userManager,
|
||||||
|
IRoadieSettings roadieSettings)
|
||||||
: base(cacheManager, roadieSettings, userManager)
|
: base(cacheManager, roadieSettings, userManager)
|
||||||
{
|
{
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
|
@ -35,9 +39,12 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await BookmarkService.List(await CurrentUserModel(),
|
var result = await BookmarkService.ListAsync(await CurrentUserModel().ConfigureAwait(false), request).ConfigureAwait(false);
|
||||||
request);
|
if (!result.IsSuccess)
|
||||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
{
|
||||||
|
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
catch (UnauthorizedAccessException)
|
catch (UnauthorizedAccessException)
|
||||||
|
|
|
@ -23,9 +23,12 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
private ICollectionService CollectionService { get; }
|
private ICollectionService CollectionService { get; }
|
||||||
|
|
||||||
public CollectionController(ICollectionService collectionService, ILogger<CollectionController> logger,
|
public CollectionController(
|
||||||
ICacheManager cacheManager,
|
ICollectionService collectionService,
|
||||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
ILogger<CollectionController> logger,
|
||||||
|
ICacheManager cacheManager,
|
||||||
|
UserManager<User> userManager,
|
||||||
|
IRoadieSettings roadieSettings)
|
||||||
: base(cacheManager, roadieSettings, userManager)
|
: base(cacheManager, roadieSettings, userManager)
|
||||||
{
|
{
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
|
@ -37,7 +40,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> Add()
|
public async Task<IActionResult> Add()
|
||||||
{
|
{
|
||||||
var result = CollectionService.Add(await CurrentUserModel());
|
var result = CollectionService.Add(await CurrentUserModel().ConfigureAwait(false));
|
||||||
if (!result.IsSuccess)
|
if (!result.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.IsAccessDeniedResult)
|
if (result.IsAccessDeniedResult)
|
||||||
|
@ -59,7 +62,7 @@ namespace Roadie.Api.Controllers
|
||||||
[Authorize(Policy = "Editor")]
|
[Authorize(Policy = "Editor")]
|
||||||
public async Task<IActionResult> DeleteCollection(Guid id)
|
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)
|
if (result == null || result.IsNotFoundResult)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -84,9 +87,13 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> Get(Guid id, string inc = null)
|
public async Task<IActionResult> Get(Guid id, string inc = null)
|
||||||
{
|
{
|
||||||
var result = await CollectionService.ById(await CurrentUserModel(), id,
|
var result = await CollectionService.ByIdAsync(await CurrentUserModel().ConfigureAwait(false), id,
|
||||||
(inc ?? Collection.DefaultIncludes).ToLower().Split(","));
|
(inc ?? Collection.DefaultIncludes).ToLower().Split(",")).ConfigureAwait(false);
|
||||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
if (result == null || result.IsNotFoundResult)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
if (!result.IsSuccess)
|
if (!result.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.IsAccessDeniedResult)
|
if (result.IsAccessDeniedResult)
|
||||||
|
@ -108,8 +115,12 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await CollectionService.List(await CurrentUserModel(), request);
|
var result = await CollectionService.ListAsync(await CurrentUserModel().ConfigureAwait(false), request).ConfigureAwait(false);
|
||||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
if (!result.IsSuccess)
|
||||||
|
{
|
||||||
|
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
catch (UnauthorizedAccessException)
|
catch (UnauthorizedAccessException)
|
||||||
|
@ -134,7 +145,7 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
return BadRequest(ModelState);
|
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)
|
if (result == null || result.IsNotFoundResult)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
|
@ -23,9 +23,12 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
private ICommentService CommentService { get; }
|
private ICommentService CommentService { get; }
|
||||||
|
|
||||||
public CommentController(ILogger<CommentController> logger, ICacheManager cacheManager,
|
public CommentController(
|
||||||
UserManager<User> userManager,
|
ILogger<CommentController> logger,
|
||||||
IRoadieSettings roadieSettings, ICommentService commentService)
|
ICacheManager cacheManager,
|
||||||
|
UserManager<User> userManager,
|
||||||
|
IRoadieSettings roadieSettings,
|
||||||
|
ICommentService commentService)
|
||||||
: base(cacheManager, roadieSettings, userManager)
|
: base(cacheManager, roadieSettings, userManager)
|
||||||
{
|
{
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
|
@ -37,9 +40,17 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> AddNewArtistComment(Guid id, models.Comment model)
|
public async Task<IActionResult> AddNewArtistComment(Guid id, models.Comment model)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
if (string.IsNullOrEmpty(model.Cmt))
|
||||||
var result = await CommentService.AddNewArtistComment(await CurrentUserModel(), id, model.Cmt);
|
{
|
||||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.IsAccessDeniedResult)
|
if (result.IsAccessDeniedResult)
|
||||||
|
@ -60,9 +71,17 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> AddNewCollectionComment(Guid id, models.Comment model)
|
public async Task<IActionResult> AddNewCollectionComment(Guid id, models.Comment model)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
if (string.IsNullOrEmpty(model.Cmt))
|
||||||
var result = await CommentService.AddNewCollectionComment(await CurrentUserModel(), id, model.Cmt);
|
{
|
||||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.IsAccessDeniedResult)
|
if (result.IsAccessDeniedResult)
|
||||||
|
@ -83,9 +102,17 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> AddNewGenreComment(Guid id, models.Comment model)
|
public async Task<IActionResult> AddNewGenreComment(Guid id, models.Comment model)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
if (string.IsNullOrEmpty(model.Cmt))
|
||||||
var result = await CommentService.AddNewGenreComment(await CurrentUserModel(), id, model.Cmt);
|
{
|
||||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.IsAccessDeniedResult)
|
if (result.IsAccessDeniedResult)
|
||||||
|
@ -106,9 +133,17 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> AddNewLabelComment(Guid id, models.Comment model)
|
public async Task<IActionResult> AddNewLabelComment(Guid id, models.Comment model)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
if (string.IsNullOrEmpty(model.Cmt))
|
||||||
var result = await CommentService.AddNewLabelComment(await CurrentUserModel(), id, model.Cmt);
|
{
|
||||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.IsAccessDeniedResult)
|
if (result.IsAccessDeniedResult)
|
||||||
|
@ -129,9 +164,17 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> AddNewPlaylistComment(Guid id, models.Comment model)
|
public async Task<IActionResult> AddNewPlaylistComment(Guid id, models.Comment model)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
if (string.IsNullOrEmpty(model.Cmt))
|
||||||
var result = await CommentService.AddNewPlaylistComment(await CurrentUserModel(), id, model.Cmt);
|
{
|
||||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.IsAccessDeniedResult)
|
if (result.IsAccessDeniedResult)
|
||||||
|
@ -152,9 +195,17 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> AddNewReleaseComment(Guid id, models.Comment model)
|
public async Task<IActionResult> AddNewReleaseComment(Guid id, models.Comment model)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
if (string.IsNullOrEmpty(model.Cmt))
|
||||||
var result = await CommentService.AddNewReleaseComment(await CurrentUserModel(), id, model.Cmt);
|
{
|
||||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.IsAccessDeniedResult)
|
if (result.IsAccessDeniedResult)
|
||||||
|
@ -175,9 +226,17 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> AddNewTrackComment(Guid id, models.Comment model)
|
public async Task<IActionResult> AddNewTrackComment(Guid id, models.Comment model)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
if (string.IsNullOrEmpty(model.Cmt))
|
||||||
var result = await CommentService.AddNewTrackComment(await CurrentUserModel(), id, model.Cmt);
|
{
|
||||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.IsAccessDeniedResult)
|
if (result.IsAccessDeniedResult)
|
||||||
|
@ -198,8 +257,12 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> DeleteComment(Guid id)
|
public async Task<IActionResult> DeleteComment(Guid id)
|
||||||
{
|
{
|
||||||
var result = await CommentService.DeleteComment(await CurrentUserModel(), id);
|
var result = await CommentService.DeleteCommentAsync(await CurrentUserModel().ConfigureAwait(false), id).ConfigureAwait(false);
|
||||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
if (result == null || result.IsNotFoundResult)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
if (!result.IsSuccess)
|
if (!result.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.IsAccessDeniedResult)
|
if (result.IsAccessDeniedResult)
|
||||||
|
@ -220,8 +283,12 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> SetCommentReaction(Guid id, CommentReaction reaction)
|
public async Task<IActionResult> SetCommentReaction(Guid id, CommentReaction reaction)
|
||||||
{
|
{
|
||||||
var result = await CommentService.SetCommentReaction(await CurrentUserModel(), id, reaction);
|
var result = await CommentService.SetCommentReactionAsync(await CurrentUserModel().ConfigureAwait(false), id, reaction).ConfigureAwait(false);
|
||||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
if (result == null || result.IsNotFoundResult)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
if (!result.IsSuccess)
|
if (!result.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.IsAccessDeniedResult)
|
if (result.IsAccessDeniedResult)
|
||||||
|
|
|
@ -22,8 +22,6 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
public const string ControllerCacheRegionUrn = "urn:controller_cache";
|
public const string ControllerCacheRegionUrn = "urn:controller_cache";
|
||||||
|
|
||||||
private models.User _currentUser;
|
|
||||||
|
|
||||||
protected ICacheManager CacheManager { get; }
|
protected ICacheManager CacheManager { get; }
|
||||||
|
|
||||||
protected ILogger Logger { get; set; }
|
protected ILogger Logger { get; set; }
|
||||||
|
@ -32,8 +30,12 @@ namespace Roadie.Api.Controllers
|
||||||
|
|
||||||
protected UserManager<User> UserManager { get; }
|
protected UserManager<User> UserManager { get; }
|
||||||
|
|
||||||
public EntityControllerBase(ICacheManager cacheManager, IRoadieSettings roadieSettings,
|
private models.User _currentUser;
|
||||||
UserManager<User> userManager)
|
|
||||||
|
protected EntityControllerBase(
|
||||||
|
ICacheManager cacheManager,
|
||||||
|
IRoadieSettings roadieSettings,
|
||||||
|
UserManager<User> userManager)
|
||||||
{
|
{
|
||||||
CacheManager = cacheManager;
|
CacheManager = cacheManager;
|
||||||
RoadieSettings = roadieSettings;
|
RoadieSettings = roadieSettings;
|
||||||
|
@ -48,8 +50,8 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
_currentUser = await CacheManager.GetAsync($"urn:controller_user:{User.Identity.Name}", async () =>
|
_currentUser = await CacheManager.GetAsync($"urn:controller_user:{User.Identity.Name}", async () =>
|
||||||
{
|
{
|
||||||
return UserModelForUser(await UserManager.GetUserAsync(User));
|
return UserModelForUser(await UserManager.GetUserAsync(User).ConfigureAwait(false));
|
||||||
}, ControllerCacheRegionUrn);
|
}, ControllerCacheRegionUrn).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_currentUser == null)
|
if (_currentUser == null)
|
||||||
|
@ -67,7 +69,7 @@ namespace Roadie.Api.Controllers
|
||||||
var tsw = new Stopwatch();
|
var tsw = new Stopwatch();
|
||||||
|
|
||||||
tsw.Restart();
|
tsw.Restart();
|
||||||
var user = currentUser ?? await CurrentUserModel();
|
var user = currentUser ?? await CurrentUserModel().ConfigureAwait(false); ;
|
||||||
var track = trackService.StreamCheckAndInfo(user, id);
|
var track = trackService.StreamCheckAndInfo(user, id);
|
||||||
if (track == null || (track?.IsNotFoundResult ?? false))
|
if (track == null || (track?.IsNotFoundResult ?? false))
|
||||||
{
|
{
|
||||||
|
@ -86,18 +88,23 @@ namespace Roadie.Api.Controllers
|
||||||
timings.Add("TrackService.StreamCheckAndInfo", tsw.ElapsedMilliseconds);
|
timings.Add("TrackService.StreamCheckAndInfo", tsw.ElapsedMilliseconds);
|
||||||
tsw.Restart();
|
tsw.Restart();
|
||||||
|
|
||||||
var info = await trackService.TrackStreamInfo(id,
|
var info = await trackService.TrackStreamInfoAsync(id,
|
||||||
TrackService.DetermineByteStartFromHeaders(Request.Headers),
|
TrackService.DetermineByteStartFromHeaders(Request.Headers),
|
||||||
TrackService.DetermineByteEndFromHeaders(Request.Headers, track.Data.FileSize),
|
TrackService.DetermineByteEndFromHeaders(Request.Headers, track.Data.FileSize),
|
||||||
user);
|
user).ConfigureAwait(false);
|
||||||
if (!info?.IsSuccess ?? false || info?.Data == null)
|
if (!info?.IsSuccess ?? false || info?.Data == null)
|
||||||
{
|
{
|
||||||
if (info?.Errors != null && (info?.Errors.Any() ?? false))
|
if (info?.Errors != null && (info?.Errors.Any() ?? false))
|
||||||
|
{
|
||||||
Logger.LogCritical(
|
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
|
else
|
||||||
|
{
|
||||||
Logger.LogCritical(
|
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");
|
return NotFound("Unknown TrackId");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +136,7 @@ namespace Roadie.Api.Controllers
|
||||||
}
|
}
|
||||||
Response.Headers.Add("Expires", info.Data.Expires);
|
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
|
var scrobble = new ScrobbleInfo
|
||||||
{
|
{
|
||||||
|
@ -137,7 +144,7 @@ namespace Roadie.Api.Controllers
|
||||||
TimePlayed = DateTime.UtcNow,
|
TimePlayed = DateTime.UtcNow,
|
||||||
TrackId = id
|
TrackId = id
|
||||||
};
|
};
|
||||||
await playActivityService.NowPlaying(user, scrobble);
|
await playActivityService.NowPlayingAsync(user, scrobble).ConfigureAwait(false);
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
Logger.LogTrace($"StreamTrack ElapsedTime [{sw.ElapsedMilliseconds}], Timings [{JsonConvert.SerializeObject(timings)}], StreamInfo `{info?.Data}`");
|
Logger.LogTrace($"StreamTrack ElapsedTime [{sw.ElapsedMilliseconds}], Timings [{JsonConvert.SerializeObject(timings)}], StreamInfo `{info?.Data}`");
|
||||||
return new EmptyResult();
|
return new EmptyResult();
|
||||||
|
@ -145,7 +152,11 @@ namespace Roadie.Api.Controllers
|
||||||
|
|
||||||
protected models.User UserModelForUser(User user)
|
protected models.User UserModelForUser(User user)
|
||||||
{
|
{
|
||||||
if (user == null) return null;
|
if (user == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var result = user.Adapt<models.User>();
|
var result = user.Adapt<models.User>();
|
||||||
result.IsAdmin = User.IsInRole("Admin");
|
result.IsAdmin = User.IsInRole("Admin");
|
||||||
result.IsEditor = User.IsInRole("Editor") || result.IsAdmin;
|
result.IsEditor = User.IsInRole("Editor") || result.IsAdmin;
|
||||||
|
|
|
@ -25,8 +25,12 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
private IGenreService GenreService { get; }
|
private IGenreService GenreService { get; }
|
||||||
|
|
||||||
public GenreController(IGenreService genreService, ILogger<GenreController> logger, ICacheManager cacheManager,
|
public GenreController(
|
||||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
IGenreService genreService,
|
||||||
|
ILogger<GenreController> logger,
|
||||||
|
ICacheManager cacheManager,
|
||||||
|
UserManager<User> userManager,
|
||||||
|
IRoadieSettings roadieSettings)
|
||||||
: base(cacheManager, roadieSettings, userManager)
|
: base(cacheManager, roadieSettings, userManager)
|
||||||
{
|
{
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
|
@ -38,9 +42,17 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> Get(Guid id, string inc = null)
|
public async Task<IActionResult> Get(Guid id, string inc = null)
|
||||||
{
|
{
|
||||||
var result = await GenreService.ById(await CurrentUserModel(), id, (inc ?? models.Genre.DefaultIncludes).ToLower().Split(","));
|
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 == null || result.IsNotFoundResult)
|
||||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.IsSuccess)
|
||||||
|
{
|
||||||
|
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,10 +62,14 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await GenreService.List(await CurrentUserModel(),
|
var result = await GenreService.ListAsync(await CurrentUserModel().ConfigureAwait(false),
|
||||||
request,
|
request,
|
||||||
doRandomize);
|
doRandomize).ConfigureAwait(false);
|
||||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
if (!result.IsSuccess)
|
||||||
|
{
|
||||||
|
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
catch (UnauthorizedAccessException)
|
catch (UnauthorizedAccessException)
|
||||||
|
@ -74,7 +90,7 @@ namespace Roadie.Api.Controllers
|
||||||
[Authorize(Policy = "Editor")]
|
[Authorize(Policy = "Editor")]
|
||||||
public async Task<IActionResult> SetGenreImageByUrl(Guid id, string imageUrl)
|
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)
|
if (result == null || result.IsNotFoundResult)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -94,29 +110,6 @@ namespace Roadie.Api.Controllers
|
||||||
return Ok(result);
|
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")]
|
[HttpPost("edit")]
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
|
@ -127,7 +120,7 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
return BadRequest(ModelState);
|
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)
|
if (result == null || result.IsNotFoundResult)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -142,5 +135,32 @@ namespace Roadie.Api.Controllers
|
||||||
}
|
}
|
||||||
return Ok(result);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,20 +20,26 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
private IImageService ImageService { get; }
|
private IImageService ImageService { get; }
|
||||||
|
|
||||||
public ImageController(IImageService imageService, ILogger<ImageController> logger, ICacheManager cacheManager,
|
public ImageController(
|
||||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
IImageService imageService,
|
||||||
|
ILogger<ImageController> logger,
|
||||||
|
ICacheManager cacheManager,
|
||||||
|
UserManager<User> userManager,
|
||||||
|
IRoadieSettings roadieSettings)
|
||||||
: base(cacheManager, roadieSettings, userManager)
|
: base(cacheManager, roadieSettings, userManager)
|
||||||
{
|
{
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
ImageService = imageService;
|
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?}")]
|
[HttpGet("artist/{id}/{width:int?}/{height:int?}/{cacheBuster?}")]
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> ArtistImage(Guid id, int? width, int? height)
|
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)
|
if (result?.IsNotFoundResult != false)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -50,7 +56,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> ArtistSecondaryImage(Guid id, int imageId, int? width, int? height)
|
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)
|
if (result?.IsNotFoundResult != false)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -67,24 +73,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> CollectionImage(Guid id, int? width, int? height)
|
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);
|
var result = await ImageService.CollectionImageAsync(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);
|
|
||||||
if (result?.IsNotFoundResult != false)
|
if (result?.IsNotFoundResult != false)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -101,7 +90,24 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> GenreImage(Guid id, int? width, int? height)
|
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)
|
if (result?.IsNotFoundResult != false)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -118,7 +124,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> PlaylistImage(Guid id, int? width, int? height)
|
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)
|
if (result?.IsNotFoundResult != false)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -135,7 +141,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> ReleaseImage(Guid id, int? width, int? height)
|
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)
|
if (result?.IsNotFoundResult != false)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -152,7 +158,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> ReleaseSecondaryImage(Guid id, int imageId, int? width, int? height)
|
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)
|
if (result?.IsNotFoundResult != false)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -169,24 +175,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> SearchForArtistImage(string query, int? resultsCount)
|
public async Task<IActionResult> SearchForArtistImage(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();
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
if (result?.IsNotFoundResult != false)
|
if (result?.IsNotFoundResult != false)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -203,9 +192,34 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> SearchForGenreImage(string query, int? resultsCount)
|
public async Task<IActionResult> SearchForGenreImage(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();
|
if (result?.IsNotFoundResult != false)
|
||||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
{
|
||||||
|
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);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,9 +228,17 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> SearchForReleaseCover(string query, int? resultsCount)
|
public async Task<IActionResult> SearchForReleaseCover(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();
|
if (result?.IsNotFoundResult != false)
|
||||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.IsSuccess)
|
||||||
|
{
|
||||||
|
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +247,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> TrackImage(Guid id, int? width, int? height)
|
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)
|
if (result?.IsNotFoundResult != false)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -237,8 +259,6 @@ namespace Roadie.Api.Controllers
|
||||||
return MakeFileResult(result.Data.Bytes, $"{id}.jpg", result.ContentType, result.LastModified, result.ETag);
|
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>
|
/// <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.
|
/// 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>
|
/// </summary>
|
||||||
|
@ -247,7 +267,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> UserImage(Guid id, int? width, int? height)
|
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)
|
if (result?.IsNotFoundResult != false)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
|
@ -25,8 +25,12 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
private ILabelService LabelService { get; }
|
private ILabelService LabelService { get; }
|
||||||
|
|
||||||
public LabelController(ILabelService labelService, ILogger<LabelController> logger, ICacheManager cacheManager,
|
public LabelController(
|
||||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
ILabelService labelService,
|
||||||
|
ILogger<LabelController> logger,
|
||||||
|
ICacheManager cacheManager,
|
||||||
|
UserManager<User> userManager,
|
||||||
|
IRoadieSettings roadieSettings)
|
||||||
: base(cacheManager, roadieSettings, userManager)
|
: base(cacheManager, roadieSettings, userManager)
|
||||||
{
|
{
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
|
@ -38,7 +42,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> Get(Guid id, string inc = null)
|
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)
|
if (result == null || result.IsNotFoundResult)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -56,10 +60,14 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await LabelService.List(await CurrentUserModel(),
|
var result = await LabelService.ListAsync(await CurrentUserModel().ConfigureAwait(false),
|
||||||
request,
|
request,
|
||||||
doRandomize);
|
doRandomize).ConfigureAwait(false);
|
||||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
if (!result.IsSuccess)
|
||||||
|
{
|
||||||
|
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
catch (UnauthorizedAccessException)
|
catch (UnauthorizedAccessException)
|
||||||
|
@ -80,7 +88,7 @@ namespace Roadie.Api.Controllers
|
||||||
[Authorize(Policy = "Editor")]
|
[Authorize(Policy = "Editor")]
|
||||||
public async Task<IActionResult> MergeLabels(Guid labelToMergeId, Guid labelToMergeIntoId)
|
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)
|
if (result == null || result.IsNotFoundResult)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -98,7 +106,7 @@ namespace Roadie.Api.Controllers
|
||||||
[Authorize(Policy = "Editor")]
|
[Authorize(Policy = "Editor")]
|
||||||
public async Task<IActionResult> SetLabelImageByUrl(Guid id, string imageUrl)
|
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)
|
if (result == null || result.IsNotFoundResult)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -120,7 +128,7 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
return BadRequest(ModelState);
|
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)
|
if (result == null || result.IsNotFoundResult)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -142,9 +150,17 @@ namespace Roadie.Api.Controllers
|
||||||
[Authorize(Policy = "Editor")]
|
[Authorize(Policy = "Editor")]
|
||||||
public async Task<IActionResult> UploadImage(Guid id, IFormFile file)
|
public async Task<IActionResult> UploadImage(Guid id, IFormFile file)
|
||||||
{
|
{
|
||||||
var result = await LabelService.UploadLabelImage(await CurrentUserModel(), id, file);
|
var result = await LabelService.UploadLabelImageAsync(await CurrentUserModel().ConfigureAwait(false), id, file).ConfigureAwait(false);
|
||||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
if (result == null || result.IsNotFoundResult)
|
||||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.IsSuccess)
|
||||||
|
{
|
||||||
|
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,12 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
private ILookupService LookupService { get; }
|
private ILookupService LookupService { get; }
|
||||||
|
|
||||||
public LookupController(ILabelService labelService, ILogger<LookupController> logger, ICacheManager cacheManager,
|
public LookupController(
|
||||||
UserManager<User> userManager, ILookupService lookupService, IRoadieSettings roadieSettings)
|
ILogger<LookupController> logger,
|
||||||
|
ICacheManager cacheManager,
|
||||||
|
UserManager<User> userManager,
|
||||||
|
ILookupService lookupService,
|
||||||
|
IRoadieSettings roadieSettings)
|
||||||
: base(cacheManager, roadieSettings, userManager)
|
: base(cacheManager, roadieSettings, userManager)
|
||||||
{
|
{
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
|
@ -33,8 +37,12 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> ArtistTypes(Guid id, string inc = null)
|
public async Task<IActionResult> ArtistTypes(Guid id, string inc = null)
|
||||||
{
|
{
|
||||||
var result = await LookupService.ArtistTypes();
|
var result = await LookupService.ArtistTypesAsync().ConfigureAwait(false);
|
||||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
if (!result.IsSuccess)
|
||||||
|
{
|
||||||
|
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,8 +51,12 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> BandStatus(Guid id, string inc = null)
|
public async Task<IActionResult> BandStatus(Guid id, string inc = null)
|
||||||
{
|
{
|
||||||
var result = await LookupService.BandStatus();
|
var result = await LookupService.BandStatusAsync().ConfigureAwait(false);
|
||||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
if (!result.IsSuccess)
|
||||||
|
{
|
||||||
|
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,8 +65,12 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> BookmarkTypes(Guid id, string inc = null)
|
public async Task<IActionResult> BookmarkTypes(Guid id, string inc = null)
|
||||||
{
|
{
|
||||||
var result = await LookupService.BookmarkTypes();
|
var result = await LookupService.BookmarkTypesAsync().ConfigureAwait(false);
|
||||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
if (!result.IsSuccess)
|
||||||
|
{
|
||||||
|
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,58 +79,12 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> CollectionTypes(Guid id, string inc = null)
|
public async Task<IActionResult> CollectionTypes(Guid id, string inc = null)
|
||||||
{
|
{
|
||||||
var result = await LookupService.CollectionTypes();
|
var result = await LookupService.CollectionTypesAsync().ConfigureAwait(false);
|
||||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
if (!result.IsSuccess)
|
||||||
return Ok(result);
|
{
|
||||||
}
|
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);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,8 +93,82 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> CreditCategories(Guid id, string inc = null)
|
public async Task<IActionResult> CreditCategories(Guid id, string inc = null)
|
||||||
{
|
{
|
||||||
var result = await LookupService.Status();
|
var result = await LookupService.StatusAsync().ConfigureAwait(false);
|
||||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
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);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,9 +22,12 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
private IPlayActivityService PlayActivityService { get; }
|
private IPlayActivityService PlayActivityService { get; }
|
||||||
|
|
||||||
public PlayActivityController(IPlayActivityService playActivityService, ILogger<PlayActivityController> logger,
|
public PlayActivityController(
|
||||||
ICacheManager cacheManager,
|
IPlayActivityService playActivityService,
|
||||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
ILogger<PlayActivityController> logger,
|
||||||
|
ICacheManager cacheManager,
|
||||||
|
UserManager<User> userManager,
|
||||||
|
IRoadieSettings roadieSettings)
|
||||||
: base(cacheManager, roadieSettings, userManager)
|
: base(cacheManager, roadieSettings, userManager)
|
||||||
{
|
{
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
|
@ -35,8 +38,12 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> PlayActivity([FromQuery] PagedRequest request)
|
public async Task<IActionResult> PlayActivity([FromQuery] PagedRequest request)
|
||||||
{
|
{
|
||||||
var result = await PlayActivityService.List(request).ConfigureAwait(false);
|
var result = await PlayActivityService.ListAsync(request).ConfigureAwait(false);
|
||||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
if (!result.IsSuccess)
|
||||||
|
{
|
||||||
|
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,11 +52,19 @@ namespace Roadie.Api.Controllers
|
||||||
public async Task<IActionResult> PlayActivity([FromQuery] PagedRequest request, Guid userId)
|
public async Task<IActionResult> PlayActivity([FromQuery] PagedRequest request, Guid userId)
|
||||||
{
|
{
|
||||||
var user = UserManager.Users.FirstOrDefault(x => x.RoadieId == userId);
|
var user = UserManager.Users.FirstOrDefault(x => x.RoadieId == userId);
|
||||||
if (user == null) return NotFound();
|
if (user == null)
|
||||||
var result = await PlayActivityService.List(request,
|
{
|
||||||
UserModelForUser(user)).ConfigureAwait(false);
|
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);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,13 @@ namespace Roadie.Api.Controllers
|
||||||
|
|
||||||
private ITrackService TrackService { get; }
|
private ITrackService TrackService { get; }
|
||||||
|
|
||||||
public PlayController(ITrackService trackService, IReleaseService releaseService, IPlayActivityService playActivityService,
|
public PlayController(
|
||||||
ILogger<PlayController> logger, ICacheManager cacheManager, UserManager<User> userManager,
|
ITrackService trackService,
|
||||||
|
IReleaseService releaseService,
|
||||||
|
IPlayActivityService playActivityService,
|
||||||
|
ILogger<PlayController> logger,
|
||||||
|
ICacheManager cacheManager,
|
||||||
|
UserManager<User> userManager,
|
||||||
IRoadieSettings roadieSettings)
|
IRoadieSettings roadieSettings)
|
||||||
: base(cacheManager, roadieSettings, userManager)
|
: base(cacheManager, roadieSettings, userManager)
|
||||||
{
|
{
|
||||||
|
@ -43,8 +48,12 @@ namespace Roadie.Api.Controllers
|
||||||
public async Task<FileResult> M3uForRelease(Guid id)
|
public async Task<FileResult> M3uForRelease(Guid id)
|
||||||
{
|
{
|
||||||
var user = await CurrentUserModel().ConfigureAwait(false);
|
var user = await CurrentUserModel().ConfigureAwait(false);
|
||||||
var release = await ReleaseService.ById(user, id, new string[1] { "tracks" }).ConfigureAwait(false);
|
var release = await ReleaseService.ByIdAsync(user, id, new string[1] { "tracks" }).ConfigureAwait(false);
|
||||||
if (release?.IsNotFoundResult != false) Response.StatusCode = (int)HttpStatusCode.NotFound;
|
if (release?.IsNotFoundResult != false)
|
||||||
|
{
|
||||||
|
Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||||
|
}
|
||||||
|
|
||||||
var m3u = M3uHelper.M3uContentForTracks(release.Data.Medias.SelectMany(x => x.Tracks));
|
var m3u = M3uHelper.M3uContentForTracks(release.Data.Medias.SelectMany(x => x.Tracks));
|
||||||
return File(Encoding.Default.GetBytes(m3u), "audio/mpeg-url");
|
return File(Encoding.Default.GetBytes(m3u), "audio/mpeg-url");
|
||||||
}
|
}
|
||||||
|
@ -53,12 +62,20 @@ namespace Roadie.Api.Controllers
|
||||||
public async Task<FileResult> M3uForTrack(Guid id)
|
public async Task<FileResult> M3uForTrack(Guid id)
|
||||||
{
|
{
|
||||||
var user = await CurrentUserModel().ConfigureAwait(false);
|
var user = await CurrentUserModel().ConfigureAwait(false);
|
||||||
var track = await TrackService.ById(user, id, null).ConfigureAwait(false);
|
var track = await TrackService.ByIdAsyncAsync(user, id, null).ConfigureAwait(false);
|
||||||
if (track?.IsNotFoundResult != false) Response.StatusCode = (int)HttpStatusCode.NotFound;
|
if (track?.IsNotFoundResult != false)
|
||||||
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;
|
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(
|
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");
|
return File(Encoding.Default.GetBytes(m3u), "audio/mpeg-url");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,14 +88,22 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> Scrobble(Guid id, string startedPlaying, bool isRandom)
|
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,
|
TrackId = id,
|
||||||
TimePlayed = SafeParser.ToDateTime(startedPlaying) ?? DateTime.UtcNow,
|
TimePlayed = SafeParser.ToDateTime(startedPlaying) ?? DateTime.UtcNow,
|
||||||
IsRandomizedScrobble = isRandom
|
IsRandomizedScrobble = isRandom
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
if (result?.IsNotFoundResult != false) return NotFound();
|
if (result?.IsNotFoundResult != false)
|
||||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.IsSuccess)
|
||||||
|
{
|
||||||
|
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +115,11 @@ namespace Roadie.Api.Controllers
|
||||||
public async Task<IActionResult> StreamTrack(int userId, string trackPlayToken, Guid id)
|
public async Task<IActionResult> StreamTrack(int userId, string trackPlayToken, Guid id)
|
||||||
{
|
{
|
||||||
var user = UserManager.Users.FirstOrDefault(x => x.Id == userId);
|
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))
|
if (!ServiceBase.ConfirmTrackPlayToken(user, id, trackPlayToken))
|
||||||
{
|
{
|
||||||
return StatusCode((int)HttpStatusCode.Unauthorized);
|
return StatusCode((int)HttpStatusCode.Unauthorized);
|
||||||
|
|
|
@ -23,8 +23,12 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
private IPlaylistService PlaylistService { get; }
|
private IPlaylistService PlaylistService { get; }
|
||||||
|
|
||||||
public PlaylistController(IPlaylistService playlistService, ILogger<PlaylistController> logger, ICacheManager cacheManager,
|
public PlaylistController(
|
||||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
IPlaylistService playlistService,
|
||||||
|
ILogger<PlaylistController> logger,
|
||||||
|
ICacheManager cacheManager,
|
||||||
|
UserManager<User> userManager,
|
||||||
|
IRoadieSettings roadieSettings)
|
||||||
: base(cacheManager, roadieSettings, userManager)
|
: base(cacheManager, roadieSettings, userManager)
|
||||||
{
|
{
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
|
@ -36,7 +40,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> AddNewPlaylist([FromBody] Playlist model)
|
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.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.IsAccessDeniedResult)
|
if (result.IsAccessDeniedResult)
|
||||||
|
@ -57,7 +61,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> DeletePlaylist(Guid id)
|
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)
|
if (result == null || result.IsNotFoundResult)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -82,7 +86,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> Get(Guid id, string inc = null)
|
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)
|
if (result == null || result.IsNotFoundResult)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -106,9 +110,12 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> List([FromQuery] PagedRequest request, string inc)
|
public async Task<IActionResult> List([FromQuery] PagedRequest request, string inc)
|
||||||
{
|
{
|
||||||
var result = await PlaylistService.List(roadieUser: await CurrentUserModel(),
|
var result = await PlaylistService.ListAsync(roadieUser: await CurrentUserModel().ConfigureAwait(false), request: request).ConfigureAwait(false);
|
||||||
request: request);
|
if (!result.IsSuccess)
|
||||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
{
|
||||||
|
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,8 +124,12 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> Update(Playlist playlist)
|
public async Task<IActionResult> Update(Playlist playlist)
|
||||||
{
|
{
|
||||||
if (!ModelState.IsValid) return BadRequest(ModelState);
|
if (!ModelState.IsValid)
|
||||||
var result = await PlaylistService.UpdatePlaylist(await CurrentUserModel(), playlist);
|
{
|
||||||
|
return BadRequest(ModelState);
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await PlaylistService.UpdatePlaylistAsync(await CurrentUserModel().ConfigureAwait(false), playlist).ConfigureAwait(false);
|
||||||
if (result == null || result.IsNotFoundResult)
|
if (result == null || result.IsNotFoundResult)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -143,7 +154,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> UpdateTracks(PlaylistTrackModifyRequest request)
|
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)
|
if (result == null || result.IsNotFoundResult)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
|
@ -25,8 +25,12 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
private IReleaseService ReleaseService { get; }
|
private IReleaseService ReleaseService { get; }
|
||||||
|
|
||||||
public ReleaseController(IReleaseService releaseService, ILogger<ReleaseController> logger, ICacheManager cacheManager,
|
public ReleaseController(
|
||||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
IReleaseService releaseService,
|
||||||
|
ILogger<ReleaseController> logger,
|
||||||
|
ICacheManager cacheManager,
|
||||||
|
UserManager<User> userManager,
|
||||||
|
IRoadieSettings roadieSettings)
|
||||||
: base(cacheManager, roadieSettings, userManager)
|
: base(cacheManager, roadieSettings, userManager)
|
||||||
{
|
{
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
|
@ -38,7 +42,7 @@ namespace Roadie.Api.Controllers
|
||||||
[ProducesResponseType(404)]
|
[ProducesResponseType(404)]
|
||||||
public async Task<IActionResult> Get(Guid id, string inc = null)
|
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)
|
if (result?.IsNotFoundResult != false)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -56,11 +60,15 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await ReleaseService.List(await CurrentUserModel().ConfigureAwait(false),
|
var result = await ReleaseService.ListAsync(await CurrentUserModel().ConfigureAwait(false),
|
||||||
request,
|
request,
|
||||||
doRandomize ?? false,
|
doRandomize ?? false,
|
||||||
(inc ?? Release.DefaultListIncludes).ToLower().Split(",")).ConfigureAwait(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);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
catch (UnauthorizedAccessException)
|
catch (UnauthorizedAccessException)
|
||||||
|
@ -81,8 +89,12 @@ namespace Roadie.Api.Controllers
|
||||||
[Authorize(Policy = "Editor")]
|
[Authorize(Policy = "Editor")]
|
||||||
public async Task<IActionResult> MergeReleases(Guid releaseToMergeId, Guid releaseToMergeIntoId, bool addAsMedia)
|
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);
|
var result = await ReleaseService.MergeReleasesAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), releaseToMergeId, releaseToMergeIntoId, addAsMedia).ConfigureAwait(false);
|
||||||
if (result?.IsNotFoundResult != false) return NotFound();
|
if (result?.IsNotFoundResult != false)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
if (!result.IsSuccess)
|
if (!result.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.IsAccessDeniedResult)
|
if (result.IsAccessDeniedResult)
|
||||||
|
@ -104,8 +116,12 @@ namespace Roadie.Api.Controllers
|
||||||
[Authorize(Policy = "Editor")]
|
[Authorize(Policy = "Editor")]
|
||||||
public async Task<IActionResult> SetReleaseImageByUrl(Guid id, string imageUrl)
|
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);
|
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?.IsNotFoundResult != false)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
if (!result.IsSuccess)
|
if (!result.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.IsAccessDeniedResult)
|
if (result.IsAccessDeniedResult)
|
||||||
|
@ -131,7 +147,7 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
return BadRequest(ModelState);
|
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)
|
if (result?.IsNotFoundResult != false)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
@ -153,8 +169,12 @@ namespace Roadie.Api.Controllers
|
||||||
[Authorize(Policy = "Editor")]
|
[Authorize(Policy = "Editor")]
|
||||||
public async Task<IActionResult> UploadImage(Guid id, IFormFile file)
|
public async Task<IActionResult> UploadImage(Guid id, IFormFile file)
|
||||||
{
|
{
|
||||||
var result = await ReleaseService.UploadReleaseImage(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, file).ConfigureAwait(false);
|
var result = await ReleaseService.UploadReleaseImageAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, file).ConfigureAwait(false);
|
||||||
if (result?.IsNotFoundResult != false) return NotFound();
|
if (result?.IsNotFoundResult != false)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
if (!result.IsSuccess)
|
if (!result.IsSuccess)
|
||||||
{
|
{
|
||||||
if (result.IsAccessDeniedResult)
|
if (result.IsAccessDeniedResult)
|
||||||
|
|
|
@ -20,14 +20,22 @@ namespace Roadie.Api.Controllers
|
||||||
{
|
{
|
||||||
private IStatisticsService StatisticsService { get; }
|
private IStatisticsService StatisticsService { get; }
|
||||||
|
|
||||||
public StatsController(IStatisticsService statisticsService, ILogger<StatsController> logger, ICacheManager cacheManager,
|
public StatsController(
|
||||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
IStatisticsService statisticsService,
|
||||||
|
ILogger<StatsController> logger,
|
||||||
|
ICacheManager cacheManager,
|
||||||
|
UserManager<User> userManager,
|
||||||
|
IRoadieSettings roadieSettings)
|
||||||
: base(cacheManager, roadieSettings, userManager)
|
: base(cacheManager, roadieSettings, userManager)
|
||||||
{
|
{
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
StatisticsService = statisticsService;
|
StatisticsService = statisticsService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("artistsByDate")]
|
||||||
|
[ProducesResponseType(200)]
|
||||||
|
public async Task<IActionResult> ArtistsByDate() => Ok(await StatisticsService.ArtistsByDateAsync().ConfigureAwait(false));
|
||||||
|
|
||||||
[HttpGet("info")]
|
[HttpGet("info")]
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
|
@ -39,12 +47,14 @@ namespace Roadie.Api.Controllers
|
||||||
var messages = new List<string>
|
var messages = new List<string>
|
||||||
{
|
{
|
||||||
"▜ Memory Information: ",
|
"▜ Memory Information: ",
|
||||||
string.Format("My process used working set {0:n3} K of working set and CPU {1:n} msec",
|
$"My process used working set {mem / 1024.0:n3} K of working set and CPU {cpu.TotalMilliseconds:n} msec"
|
||||||
mem / 1024.0, cpu.TotalMilliseconds)
|
|
||||||
};
|
};
|
||||||
foreach (var aProc in Process.GetProcesses())
|
foreach (var aProc in Process.GetProcesses())
|
||||||
|
{
|
||||||
messages.Add(string.Format("Proc {0,30} CPU {1,-20:n} msec", aProc.ProcessName,
|
messages.Add(string.Format("Proc {0,30} CPU {1,-20:n} msec", aProc.ProcessName,
|
||||||
cpu.TotalMilliseconds));
|
cpu.TotalMilliseconds));
|
||||||
|
}
|
||||||
|
|
||||||
messages.Add("▟ Memory Information: ");
|
messages.Add("▟ Memory Information: ");
|
||||||
|
|
||||||
return Ok(messages);
|
return Ok(messages);
|
||||||
|
@ -52,31 +62,27 @@ namespace Roadie.Api.Controllers
|
||||||
|
|
||||||
[HttpGet("library")]
|
[HttpGet("library")]
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> Library() => Ok(await StatisticsService.LibraryStatistics());
|
public async Task<IActionResult> Library() => Ok(await StatisticsService.LibraryStatisticsAsync().ConfigureAwait(false));
|
||||||
|
|
||||||
[HttpGet("ping")]
|
[HttpGet("ping")]
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
public IActionResult Ping() => Ok("pong");
|
public IActionResult Ping() => Ok("pong");
|
||||||
|
|
||||||
[HttpGet("artistsByDate")]
|
|
||||||
[ProducesResponseType(200)]
|
|
||||||
public async Task<IActionResult> ArtistsByDate() => Ok(await StatisticsService.ArtistsByDate());
|
|
||||||
|
|
||||||
[HttpGet("releasesByDate")]
|
[HttpGet("releasesByDate")]
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> ReleasesByDate() => Ok(await StatisticsService.ReleasesByDate());
|
public async Task<IActionResult> ReleasesByDate() => Ok(await StatisticsService.ReleasesByDateAsync().ConfigureAwait(false));
|
||||||
|
|
||||||
[HttpGet("releasesByDecade")]
|
[HttpGet("releasesByDecade")]
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> ReleasesByDecade() => Ok(await StatisticsService.ReleasesByDecade());
|
public async Task<IActionResult> ReleasesByDecade() => Ok(await StatisticsService.ReleasesByDecadeAsync().ConfigureAwait(false));
|
||||||
|
|
||||||
[HttpGet("songsPlayedByDate")]
|
[HttpGet("songsPlayedByDate")]
|
||||||
[ProducesResponseType(200)]
|
[ProducesResponseType(200)]
|
||||||
public async Task<IActionResult> SongsPlayedByDate() => Ok(await StatisticsService.SongsPlayedByDate());
|
public async Task<IActionResult> SongsPlayedByDate() => Ok(await StatisticsService.SongsPlayedByDateAsync().ConfigureAwait(false));
|
||||||
|
|
||||||
[HttpGet("songsPlayedByUser")]
|
[HttpGet("songsPlayedByUser")]
|
||||||
[ProducesResponseType(200)]
|
[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
Loading…
Reference in a new issue