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);
|
||||
|
||||
#pragma warning disable RCS1213 // Remove unused member declaration.
|
||||
#pragma warning disable IDE0051 // Remove unused private members
|
||||
#pragma warning disable CRR0026
|
||||
private void OnExecute()
|
||||
#pragma warning restore IDE0051 // Remove unused private members
|
||||
#pragma warning restore RCS1213 // Remove unused member declaration.
|
||||
#pragma warning restore CRR0026
|
||||
{
|
||||
var inspector = new Roadie.Library.Inspect.Inspector();
|
||||
inspector.Inspect(DoCopy, IsReadOnly, Folder, Destination ?? Folder, DontAppendSubFolder, IsReadOnly ? true : DontDeleteEmptyFolders, DontRunPreScript);
|
||||
|
|
|
@ -6,9 +6,9 @@ namespace Roadie.Api.Hubs
|
|||
{
|
||||
public class PlayActivityHub : Hub
|
||||
{
|
||||
public async Task SendActivity(PlayActivityList playActivity)
|
||||
public Task SendActivityAsync(PlayActivityList playActivity, System.Threading.CancellationToken cancellationToken)
|
||||
{
|
||||
await Clients.All.SendAsync("PlayActivity", playActivity);
|
||||
return Clients.All.SendAsync("PlayActivity", playActivity, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,9 +5,9 @@ namespace Roadie.Api.Hubs
|
|||
{
|
||||
public class ScanActivityHub : Hub
|
||||
{
|
||||
public async Task SendSystemActivity(string scanActivity)
|
||||
public Task SendSystemActivityAsync(string scanActivity, System.Threading.CancellationToken cancellationToken)
|
||||
{
|
||||
await Clients.All.SendAsync("SendSystemActivity", scanActivity);
|
||||
return Clients.All.SendAsync("SendSystemActivity", scanActivity, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@ namespace Roadie.Library.Tests
|
|||
{
|
||||
get
|
||||
{
|
||||
return this.MessageLogger as ILogger;
|
||||
return MessageLogger as ILogger;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,17 +38,17 @@ namespace Roadie.Library.Tests
|
|||
|
||||
public ArtistLookupEngineTests()
|
||||
{
|
||||
this.MessageLogger = new EventMessageLogger<ArtistLookupEngineTests>();
|
||||
this.MessageLogger.Messages += MessageLogger_Messages;
|
||||
MessageLogger = new EventMessageLogger<ArtistLookupEngineTests>();
|
||||
MessageLogger.Messages += MessageLogger_Messages;
|
||||
|
||||
var settings = new RoadieSettings();
|
||||
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
|
||||
configurationBuilder.AddJsonFile("appsettings.test.json");
|
||||
IConfiguration configuration = configurationBuilder.Build();
|
||||
configuration.GetSection("RoadieSettings").Bind(settings);
|
||||
this.Configuration = settings;
|
||||
this.CacheManager = new DictionaryCacheManager(this.Logger, new CachePolicy(TimeSpan.FromHours(4)));
|
||||
this.HttpEncoder = new Encoding.DummyHttpEncoder();
|
||||
Configuration = settings;
|
||||
CacheManager = new DictionaryCacheManager(Logger, new CachePolicy(TimeSpan.FromHours(4)));
|
||||
HttpEncoder = new Encoding.DummyHttpEncoder();
|
||||
}
|
||||
|
||||
private void MessageLogger_Messages(object sender, EventMessage e)
|
||||
|
|
|
@ -18,37 +18,30 @@ namespace Roadie.Library.Tests
|
|||
return config;
|
||||
}
|
||||
|
||||
private readonly IRoadieSettings _settings = null;
|
||||
private readonly IRoadieSettings _settings;
|
||||
|
||||
private readonly IConfiguration _configuration;
|
||||
private IConfiguration Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._configuration;
|
||||
}
|
||||
}
|
||||
|
||||
private IRoadieSettings Settings
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._settings;
|
||||
return _settings;
|
||||
}
|
||||
}
|
||||
|
||||
public ConfigurationTests()
|
||||
{
|
||||
this._configuration = InitConfiguration();
|
||||
this._settings = new RoadieSettings();
|
||||
this._configuration.GetSection("RoadieSettings").Bind(this._settings);
|
||||
_configuration = InitConfiguration();
|
||||
_settings = new RoadieSettings();
|
||||
_configuration.GetSection("RoadieSettings").Bind(_settings);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LoadRootLevelConfiguration()
|
||||
{
|
||||
var inboundFolder = @"C:\roadie_dev_root\inbound";
|
||||
var configInboundFolder = this.Settings.InboundFolder;
|
||||
var configInboundFolder = Settings.InboundFolder;
|
||||
Assert.Equal(inboundFolder, configInboundFolder);
|
||||
}
|
||||
|
||||
|
|
|
@ -220,8 +220,8 @@ namespace Roadie.Library.Tests
|
|||
var lastTrack = shuffledTracks.First();
|
||||
foreach(var track in shuffledTracks.Skip(1))
|
||||
{
|
||||
Assert.False(track.Artist.Artist.Text == lastTrack.Artist.Artist.Text &&
|
||||
track.Release.Release.Text == lastTrack.Release.Release.Text);
|
||||
Assert.False(string.Equals(track.Artist.Artist.Text, lastTrack.Artist.Artist.Text, StringComparison.Ordinal) &&
|
||||
string.Equals(track.Release.Release.Text, lastTrack.Release.Release.Text, StringComparison.Ordinal));
|
||||
lastTrack = track;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Roadie.Library.Tests
|
|||
configurationBuilder.AddJsonFile("appsettings.test.json");
|
||||
IConfiguration configuration = configurationBuilder.Build();
|
||||
configuration.GetSection("RoadieSettings").Bind(settings);
|
||||
this.Configuration = settings;
|
||||
Configuration = settings;
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace Roadie.Library.Tests
|
|||
{
|
||||
get
|
||||
{
|
||||
return this.MessageLogger as ILogger;
|
||||
return MessageLogger as ILogger;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,8 +32,8 @@ namespace Roadie.Library.Tests
|
|||
|
||||
public ID3TagsHelperTests()
|
||||
{
|
||||
this.MessageLogger = new EventMessageLogger<ID3TagsHelperTests>();
|
||||
this.MessageLogger.Messages += MessageLoggerMessages;
|
||||
MessageLogger = new EventMessageLogger<ID3TagsHelperTests>();
|
||||
MessageLogger.Messages += MessageLoggerMessages;
|
||||
|
||||
var settings = new RoadieSettings();
|
||||
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
|
||||
|
@ -41,11 +41,11 @@ namespace Roadie.Library.Tests
|
|||
IConfiguration configuration = configurationBuilder.Build();
|
||||
configuration.GetSection("RoadieSettings").Bind(settings);
|
||||
settings.ConnectionString = configuration.GetConnectionString("RoadieDatabaseConnection");
|
||||
this.Configuration = settings;
|
||||
this.CacheManager = new DictionaryCacheManager(this.Logger, new CachePolicy(TimeSpan.FromHours(4)));
|
||||
Configuration = settings;
|
||||
CacheManager = new DictionaryCacheManager(Logger, new CachePolicy(TimeSpan.FromHours(4)));
|
||||
var tagHelperLooper = new EventMessageLogger<ID3TagsHelper>();
|
||||
tagHelperLooper.Messages += MessageLoggerMessages;
|
||||
this.TagsHelper = new ID3TagsHelper(this.Configuration, this.CacheManager, tagHelperLooper);
|
||||
TagsHelper = new ID3TagsHelper(Configuration, CacheManager, tagHelperLooper);
|
||||
}
|
||||
|
||||
private void MessageLoggerMessages(object sender, EventMessage e)
|
||||
|
@ -384,7 +384,7 @@ namespace Roadie.Library.Tests
|
|||
var file = new FileInfo(@"C:\roadie_dev_root\mp3_tests\01 O.P.D. (Obsessive Personality Disorder).mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName, true);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file.FullName, true);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
Assert.NotNull(metaData.Artist);
|
||||
|
@ -410,7 +410,7 @@ namespace Roadie.Library.Tests
|
|||
var file = new FileInfo(@"C:\roadie_dev_root\library\Dream Theater\[2016] The Astonishing\01 2285 Entr acte.mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
Assert.NotNull(metaData.Artist);
|
||||
|
@ -436,7 +436,7 @@ namespace Roadie.Library.Tests
|
|||
var file = new FileInfo(@"E:\Roadie_Test_Files\13-anna_kendrick-true_colors-a57e270d\01-justin_timberlake-hair_up-ef53c026.mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
Assert.NotNull(metaData.Artist);
|
||||
|
@ -473,7 +473,7 @@ namespace Roadie.Library.Tests
|
|||
var folderFiles = Directory.GetFiles(folderName, "*.mp3", SearchOption.AllDirectories);
|
||||
foreach(var file in folderFiles)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
Assert.NotNull(metaData.Artist);
|
||||
|
@ -493,7 +493,7 @@ namespace Roadie.Library.Tests
|
|||
var file = new FileInfo(@"E:\Roadie_Test_Files\01 01 Angel Of Death.mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
Assert.NotNull(metaData.Artist);
|
||||
|
@ -519,7 +519,7 @@ namespace Roadie.Library.Tests
|
|||
var file = new FileInfo(@"E:\Roadie_Test_Files\06 You'Re Sensational.mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
Assert.NotNull(metaData.Artist);
|
||||
|
@ -545,7 +545,7 @@ namespace Roadie.Library.Tests
|
|||
var file = new FileInfo(@"M:\inbound\MEGAPACK ---METAL-DEATH-BLACK---\ebony_tears-evil_as_hell-2001-ss\01-deviation-ss.mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
Assert.NotNull(metaData.Artist);
|
||||
|
@ -571,7 +571,7 @@ namespace Roadie.Library.Tests
|
|||
var file = new FileInfo(@"M:\unknown\2eec19bd-3575-4b7f-84dd-db2a0ec3e2f3~[2009] Dolly - Disc 1 Of 4~06 Nobody But You (Previously Unissued).mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
Assert.NotNull(metaData.Artist);
|
||||
|
@ -598,7 +598,7 @@ namespace Roadie.Library.Tests
|
|||
var file = new FileInfo(@"M:\library_old\Perverse\[2014] Champion Dub\01 Champion Dub (Original Mix).mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
Assert.NotNull(metaData.Artist);
|
||||
|
@ -625,7 +625,7 @@ namespace Roadie.Library.Tests
|
|||
var file = new FileInfo(@"C:\roadie_dev_root\inbound\Dreadful Fate - Vengeance (2018)\01-dreadful_fate-vengeance.mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
Assert.NotNull(metaData.Artist);
|
||||
|
@ -653,7 +653,7 @@ namespace Roadie.Library.Tests
|
|||
var file = new FileInfo(@"M:\library\Blind Melon\[1992] Blind Melon\01. Blind Melon - Soak The Sin.mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
Assert.NotNull(metaData.Artist);
|
||||
|
@ -680,7 +680,7 @@ namespace Roadie.Library.Tests
|
|||
var file = new FileInfo(@"E:\Roadie_Test_Files\Test.mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
Assert.NotNull(metaData.Artist);
|
||||
|
@ -714,14 +714,14 @@ namespace Roadie.Library.Tests
|
|||
short trackNumber = 15;
|
||||
var numberOfTracks = 25;
|
||||
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
metaData.TrackNumber = trackNumber;
|
||||
metaData.TotalTrackNumbers = numberOfTracks;
|
||||
this.TagsHelper.WriteTags(metaData, file.FullName);
|
||||
TagsHelper.WriteTags(metaData, file.FullName);
|
||||
|
||||
var tagLibAfterWrite = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
var tagLibAfterWrite = TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
Assert.Equal(metaData.Artist, tagLibAfterWrite.Data.Artist);
|
||||
Assert.Equal(metaData.Release, tagLibAfterWrite.Data.Release);
|
||||
|
@ -745,7 +745,7 @@ namespace Roadie.Library.Tests
|
|||
var file = new FileInfo(@"M:\library\Denver, John\[1972] Aerie\10 Readjustment Blues.mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
Assert.True(metaData.IsValid);
|
||||
|
@ -772,7 +772,7 @@ namespace Roadie.Library.Tests
|
|||
var file = new FileInfo(@"E:\Roadie_Test_Files\01. What's Yesterday.mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
Assert.NotNull(metaData.Artist);
|
||||
|
@ -799,7 +799,7 @@ namespace Roadie.Library.Tests
|
|||
var file = new FileInfo(@"M:\library\Ac Dc\[1975] T.N.T\01 It'S A Long Way To The Top (If You Wanna Rock 'N' Roll).mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
Assert.NotNull(metaData.Artist);
|
||||
|
@ -825,7 +825,7 @@ namespace Roadie.Library.Tests
|
|||
var file = new FileInfo(@"E:\Roadie_Test_Files\01 Martian.mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
Assert.NotNull(metaData.Artist);
|
||||
|
@ -851,7 +851,7 @@ namespace Roadie.Library.Tests
|
|||
var file = new FileInfo(@"C:\roadie_dev_root\inbound\[2016] Invention Of Knowledge\01 Invention.mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
Assert.NotNull(metaData.Artist);
|
||||
|
@ -877,7 +877,7 @@ namespace Roadie.Library.Tests
|
|||
var file = new FileInfo(@"C:\roadie_dev_root\1985 - Sacred Heart\Dio - Sacred Heart (1).mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
Assert.NotNull(metaData.Artist);
|
||||
|
@ -903,7 +903,7 @@ namespace Roadie.Library.Tests
|
|||
var file = new FileInfo(@"C:\roadie_dev_root\Grift\2017 Arvet\01 - Flyktfast.mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
Assert.NotNull(metaData.Artist);
|
||||
|
@ -929,7 +929,7 @@ namespace Roadie.Library.Tests
|
|||
var file = new FileInfo(@"C:\roadie_dev_root\Distorted Harmony - A Way Out - 2018\kWlZr0N_o72dwo0_CD001_0001.mp3");
|
||||
if (file.Exists)
|
||||
{
|
||||
var tagLib = this.TagsHelper.MetaDataForFile(file.FullName);
|
||||
var tagLib = TagsHelper.MetaDataForFile(file.FullName);
|
||||
Assert.True(tagLib.IsSuccess);
|
||||
var metaData = tagLib.Data;
|
||||
Assert.NotNull(metaData.Artist);
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.Data;
|
||||
using Roadie.Library.Data.Context;
|
||||
using Roadie.Library.FilePlugins;
|
||||
using Roadie.Library.Imaging;
|
||||
using Roadie.Library.Imaging;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
|
@ -38,6 +31,9 @@ namespace Roadie.Library.Tests
|
|||
[InlineData("logo.png")]
|
||||
[InlineData("Logo.Jpg")]
|
||||
[InlineData("logo.gif")]
|
||||
[InlineData("band_logo.gif")]
|
||||
[InlineData("134logo.gif")]
|
||||
[InlineData("Dream_Theater_Logo.gif")]
|
||||
[InlineData("artist_logo.jpg")]
|
||||
[InlineData("Artist_logo.jpg")]
|
||||
[InlineData("ARTIST_LOGO.JPG")]
|
||||
|
@ -61,7 +57,7 @@ namespace Roadie.Library.Tests
|
|||
[InlineData("cover.png")]
|
||||
[InlineData("Cover.Jpg")]
|
||||
[InlineData("Cover.JPG")]
|
||||
[InlineData("Cover.PNG")]
|
||||
[InlineData("Cover.PNG")]
|
||||
[InlineData("CvR.Jpg")]
|
||||
[InlineData("Release.JPG")]
|
||||
[InlineData("folder.JPG")]
|
||||
|
@ -79,7 +75,7 @@ namespace Roadie.Library.Tests
|
|||
[InlineData("f.jpg")]
|
||||
[InlineData("F1.jpg")]
|
||||
[InlineData("F 1.jpg")]
|
||||
[InlineData("F-1.jpg")]
|
||||
[InlineData("F-1.jpg")]
|
||||
[InlineData("front_.jpg")]
|
||||
[InlineData("BIG.JPg")]
|
||||
[InlineData("bigart.JPg")]
|
||||
|
@ -185,9 +181,9 @@ namespace Roadie.Library.Tests
|
|||
|
||||
[InlineData("Booklet-1.jpg")]
|
||||
[InlineData("Booklet-10.jpg")]
|
||||
[InlineData("Booklet_1.jpg")]
|
||||
[InlineData("Booklet 3.jpg")]
|
||||
[InlineData("Digipack (01).jpg")]
|
||||
[InlineData("Booklet_1.jpg")]
|
||||
[InlineData("Booklet 3.jpg")]
|
||||
[InlineData("Digipack (01).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")]
|
||||
|
@ -204,10 +200,10 @@ namespace Roadie.Library.Tests
|
|||
[InlineData("Back.jpg")]
|
||||
[InlineData("BAcK.JPg")]
|
||||
[InlineData("Cd.jpg")]
|
||||
[InlineData("CD.JPG")]
|
||||
[InlineData("CD.JPG")]
|
||||
[InlineData("Cd1.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")]
|
||||
|
@ -242,16 +238,16 @@ namespace Roadie.Library.Tests
|
|||
[InlineData("release 3.jpg")]
|
||||
[InlineData("release 10.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("Booklet (2-3).jpg")]
|
||||
[InlineData("Booklet (14-15).jpg")]
|
||||
[InlineData("Booklet#2.jpg")]
|
||||
[InlineData("traycard.png")]
|
||||
[InlineData("Booklet (2-3).jpg")]
|
||||
[InlineData("Booklet (14-15).jpg")]
|
||||
[InlineData("Booklet#2.jpg")]
|
||||
[InlineData("traycard.png")]
|
||||
[InlineData("Jewel Case.jpg")]
|
||||
[InlineData("Matrix-1.jpg")]
|
||||
[InlineData("Matrix 1.jpg")]
|
||||
[InlineData("IMG_20160921_0004.jpg")]
|
||||
[InlineData("IMG_20160921_0004.jpg")]
|
||||
public void TestShouldBeReleaseSecondaryImages(string input)
|
||||
{
|
||||
Assert.True(ImageHelper.IsReleaseSecondaryImage(new FileInfo(input)));
|
||||
|
@ -292,7 +288,7 @@ namespace Roadie.Library.Tests
|
|||
public void GetReleaseImageInFolder()
|
||||
{
|
||||
var folder = new DirectoryInfo(@"C:\roadie_dev_root\image_tests");
|
||||
if(!folder.Exists)
|
||||
if (!folder.Exists)
|
||||
{
|
||||
Assert.True(true);
|
||||
return;
|
||||
|
@ -318,6 +314,6 @@ namespace Roadie.Library.Tests
|
|||
Assert.Single(artist);
|
||||
Assert.Equal("artist.jpg", artist.First().Name);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@ namespace Roadie.Library.Tests
|
|||
{
|
||||
get
|
||||
{
|
||||
return this.MessageLogger as ILogger;
|
||||
return MessageLogger as ILogger;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,8 +35,8 @@ namespace Roadie.Library.Tests
|
|||
|
||||
public InspectorTests()
|
||||
{
|
||||
this.MessageLogger = new EventMessageLogger<ID3TagsHelperTests>();
|
||||
this.MessageLogger.Messages += MessageLoggerMessages;
|
||||
MessageLogger = new EventMessageLogger<ID3TagsHelperTests>();
|
||||
MessageLogger.Messages += MessageLoggerMessages;
|
||||
|
||||
var settings = new configuration.RoadieSettings();
|
||||
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
|
||||
|
@ -44,11 +44,11 @@ namespace Roadie.Library.Tests
|
|||
IConfiguration configuration = configurationBuilder.Build();
|
||||
configuration.GetSection("RoadieSettings").Bind(settings);
|
||||
settings.ConnectionString = configuration.GetConnectionString("RoadieDatabaseConnection");
|
||||
this.Configuration = settings;
|
||||
this.CacheManager = new DictionaryCacheManager(this.Logger, new CachePolicy(TimeSpan.FromHours(4)));
|
||||
Configuration = settings;
|
||||
CacheManager = new DictionaryCacheManager(Logger, new CachePolicy(TimeSpan.FromHours(4)));
|
||||
var tagHelperLooper = new EventMessageLogger<ID3TagsHelper>();
|
||||
tagHelperLooper.Messages += MessageLoggerMessages;
|
||||
this.TagsHelper = new ID3TagsHelper(this.Configuration, this.CacheManager, tagHelperLooper);
|
||||
TagsHelper = new ID3TagsHelper(Configuration, CacheManager, tagHelperLooper);
|
||||
}
|
||||
|
||||
private void MessageLoggerMessages(object sender, EventMessage e)
|
||||
|
|
|
@ -6,10 +6,8 @@ using Roadie.Library.MetaData.MusicBrainz;
|
|||
using Roadie.Library.Processors;
|
||||
using Roadie.Library.SearchEngines.MetaData.Discogs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
|
@ -50,7 +48,7 @@ namespace Roadie.Library.Tests
|
|||
[Fact]
|
||||
public async Task DiscogsHelperReleaseSearch()
|
||||
{
|
||||
if(!Configuration.Integrations.DiscogsProviderEnabled)
|
||||
if (!Configuration.Integrations.DiscogsProviderEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -62,7 +60,7 @@ namespace Roadie.Library.Tests
|
|||
var artistName = "With The Dead";
|
||||
var title = "Love From With The Dead";
|
||||
|
||||
var result = await engine.PerformReleaseSearch(artistName, title, 1);
|
||||
var result = await engine.PerformReleaseSearch(artistName, title, 1).ConfigureAwait(false);
|
||||
Assert.NotNull(result);
|
||||
Assert.NotEmpty(result.Data);
|
||||
|
||||
|
@ -84,10 +82,9 @@ namespace Roadie.Library.Tests
|
|||
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
var result = await mb.PerformArtistSearch(artistName, 1);
|
||||
var result = await mb.PerformArtistSearchAsync(artistName, 1).ConfigureAwait(false);
|
||||
|
||||
sw.Stop();
|
||||
var elapsedTime = sw.ElapsedMilliseconds;
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotNull(result.Data);
|
||||
|
@ -113,10 +110,9 @@ namespace Roadie.Library.Tests
|
|||
var title = "Piano Man";
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
var result = await mb.PerformReleaseSearch(artistName, title, 1);
|
||||
var result = await mb.PerformReleaseSearch(artistName, title, 1).ConfigureAwait(false);
|
||||
|
||||
sw.Stop();
|
||||
var elapsedTime = sw.ElapsedMilliseconds;
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotNull(result.Data);
|
||||
|
|
|
@ -12,21 +12,21 @@ namespace Roadie.Library.Tests
|
|||
{
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
private readonly IRoadieSettings _settings = null;
|
||||
private readonly IRoadieSettings _settings;
|
||||
|
||||
private IRoadieSettings Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._settings;
|
||||
return _settings;
|
||||
}
|
||||
}
|
||||
|
||||
public StringExtensionTests()
|
||||
{
|
||||
this._configuration = InitConfiguration();
|
||||
this._settings = new RoadieSettings();
|
||||
this._configuration.GetSection("RoadieSettings").Bind(this._settings);
|
||||
_configuration = InitConfiguration();
|
||||
_settings = new RoadieSettings();
|
||||
_configuration.GetSection("RoadieSettings").Bind(_settings);
|
||||
}
|
||||
|
||||
public static IConfiguration InitConfiguration()
|
||||
|
@ -102,7 +102,7 @@ namespace Roadie.Library.Tests
|
|||
public void CleanStringReleaseShouldBeAngie(string input)
|
||||
{
|
||||
var r = @"(\s*(-\s)*((CD[_\-#\s]*[0-9]*)))|((\(|\[)+([0-9]|,|self|bonus|re(leas|master|(e|d)*)*|th|anniversary|cd|disc|deluxe|dig(ipack)*|vinyl|japan(ese)*|asian|remastered|limited|ltd|expanded|edition|\s)+(]|\)*))";
|
||||
var cleaned = input.CleanString(this.Configuration, r);
|
||||
var cleaned = input.CleanString(Configuration, r);
|
||||
Assert.Equal("Angie", cleaned);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"RoadieSettings": {
|
||||
"InboundFolder": "C:\\roadie_dev_root\\inbound",
|
||||
"LibraryFolder": "C:\\\\roadie_dev_root\\\\library",
|
||||
"SearchEngineReposFolder": "C:\\\\roadie_dev_root\\\\repos",
|
||||
"Processing": {
|
||||
"RemoveStringsRegex": "\\b[0-9]+\\s#\\s\\b",
|
||||
"ReleaseRemoveStringsRegex": "(\\\\s*(-\\\\s)*((CD[_\\-#\\s]*[0-9]*)))|((\\\\(|\\\\[)+([0-9]|,|self|bonus|re(leas|master|(e|d)*)*|th|anniversary|cd|disc|deluxe|dig(ipack)*|vinyl|japan(ese)*|asian|remastered|limited|ltd|expanded|edition|\\\\s)+(]|\\\\)*))",
|
||||
|
|
|
@ -113,7 +113,7 @@ namespace Roadie.Library.Caching
|
|||
var r = Get<TOut>(key, region);
|
||||
if (r == null)
|
||||
{
|
||||
r = await getItem();
|
||||
r = await getItem().ConfigureAwait(false);
|
||||
Add(key, r, region);
|
||||
Logger.LogTrace($"-+> Cache Miss for Key [{key}], Region [{region}]");
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@ namespace Roadie.Library.Caching
|
|||
var r = Get<TOut>(key, region);
|
||||
if (r == null)
|
||||
{
|
||||
r = await getItem();
|
||||
r = await getItem().ConfigureAwait(false);
|
||||
Add(key, r, region);
|
||||
Logger.LogTrace($"-+> Cache Miss for Key [{key}], Region [{region}]");
|
||||
}
|
||||
|
|
|
@ -5,14 +5,14 @@ namespace Roadie.Library.Data.Context
|
|||
{
|
||||
public interface IRoadieDbRandomizer
|
||||
{
|
||||
Task<SortedDictionary<int, int>> RandomArtistIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
Task<SortedDictionary<int, int>> RandomArtistIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
|
||||
Task<SortedDictionary<int, int>> RandomGenreIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
Task<SortedDictionary<int, int>> RandomGenreIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
|
||||
Task<SortedDictionary<int, int>> RandomLabelIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
Task<SortedDictionary<int, int>> RandomLabelIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
|
||||
Task<SortedDictionary<int, int>> RandomReleaseIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
Task<SortedDictionary<int, int>> RandomReleaseIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
|
||||
Task<SortedDictionary<int, int>> RandomTrackIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
Task<SortedDictionary<int, int>> RandomTrackIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
}
|
||||
}
|
|
@ -16,21 +16,21 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
{
|
||||
}
|
||||
|
||||
public override async Task<Artist> LastPlayedArtist(int userId)
|
||||
public override Task<Artist> LastPlayedArtist(int userId)
|
||||
{
|
||||
return await (from ut in UserTracks
|
||||
join t in Tracks on ut.TrackId equals t.Id
|
||||
join rm in ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
join r in Releases on rm.ReleaseId equals r.Id
|
||||
join a in Artists on r.ArtistId equals a.Id
|
||||
where ut.UserId == userId
|
||||
orderby ut.LastPlayed descending
|
||||
select a).FirstOrDefaultAsync();
|
||||
return (from ut in UserTracks
|
||||
join t in Tracks on ut.TrackId equals t.Id
|
||||
join rm in ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
join r in Releases on rm.ReleaseId equals r.Id
|
||||
join a in Artists on r.ArtistId equals a.Id
|
||||
where ut.UserId == userId
|
||||
orderby ut.LastPlayed descending
|
||||
select a).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public override async Task<Release> LastPlayedRelease(int userId)
|
||||
public override Task<Release> LastPlayedRelease(int userId)
|
||||
{
|
||||
return await (from ut in UserTracks
|
||||
return (from ut in UserTracks
|
||||
join t in Tracks on ut.TrackId equals t.Id
|
||||
join rm in ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
join r in Releases on rm.ReleaseId equals r.Id
|
||||
|
@ -39,9 +39,9 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
select r).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public override async Task<Track> LastPlayedTrack(int userId)
|
||||
public override Task<Track> LastPlayedTrack(int userId)
|
||||
{
|
||||
return await (from ut in UserTracks
|
||||
return (from ut in UserTracks
|
||||
join t in Tracks on ut.TrackId equals t.Id
|
||||
where ut.UserId == userId
|
||||
orderby ut.LastPlayed descending
|
||||
|
@ -50,7 +50,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
|
||||
public override async Task<Artist> MostPlayedArtist(int userId)
|
||||
{
|
||||
var mostPlayedTrack = await MostPlayedTrack(userId);
|
||||
var mostPlayedTrack = await MostPlayedTrack(userId).ConfigureAwait(false);
|
||||
if (mostPlayedTrack != null)
|
||||
{
|
||||
return await (from t in Tracks
|
||||
|
@ -58,35 +58,35 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
join r in Releases on rm.ReleaseId equals r.Id
|
||||
join a in Artists on r.ArtistId equals a.Id
|
||||
where t.Id == mostPlayedTrack.Id
|
||||
select a).FirstOrDefaultAsync();
|
||||
select a).FirstOrDefaultAsync().ConfigureAwait(false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public override async Task<Release> MostPlayedRelease(int userId)
|
||||
{
|
||||
var mostPlayedTrack = await MostPlayedTrack(userId);
|
||||
var mostPlayedTrack = await MostPlayedTrack(userId).ConfigureAwait(false);
|
||||
if (mostPlayedTrack != null)
|
||||
{
|
||||
return await (from t in Tracks
|
||||
join rm in ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
join r in Releases on rm.ReleaseId equals r.Id
|
||||
where t.Id == mostPlayedTrack.Id
|
||||
select r).FirstOrDefaultAsync();
|
||||
select r).FirstOrDefaultAsync().ConfigureAwait(false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public override async Task<Track> MostPlayedTrack(int userId)
|
||||
public override Task<Track> MostPlayedTrack(int userId)
|
||||
{
|
||||
return await (from ut in UserTracks
|
||||
return (from ut in UserTracks
|
||||
join t in Tracks on ut.TrackId equals t.Id
|
||||
where ut.UserId == userId
|
||||
orderby ut.PlayedCount descending
|
||||
select t).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public override async Task<SortedDictionary<int, int>> RandomArtistIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
public override async Task<SortedDictionary<int, int>> RandomArtistIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
{
|
||||
List<Artist> randomArtists = null;
|
||||
if (doOnlyFavorites)
|
||||
|
@ -98,7 +98,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
select a
|
||||
).OrderBy(x => Guid.NewGuid())
|
||||
.Take(randomLimit)
|
||||
.ToListAsync();
|
||||
.ToListAsync().ConfigureAwait(false);
|
||||
}
|
||||
else if (doOnlyRated)
|
||||
{
|
||||
|
@ -109,7 +109,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
select a
|
||||
).OrderBy(x => Guid.NewGuid())
|
||||
.Take(randomLimit)
|
||||
.ToListAsync();
|
||||
.ToListAsync().ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -120,29 +120,29 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
select a)
|
||||
.OrderBy(x => Guid.NewGuid())
|
||||
.Take(randomLimit)
|
||||
.ToListAsync();
|
||||
.ToListAsync().ConfigureAwait(false);
|
||||
}
|
||||
var dict = randomArtists.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value);
|
||||
return new SortedDictionary<int, int>(dict);
|
||||
}
|
||||
|
||||
public override async Task<SortedDictionary<int, int>> RandomGenreIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
public override async Task<SortedDictionary<int, int>> RandomGenreIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
{
|
||||
var randomGenres = await Genres.OrderBy(x => Guid.NewGuid())
|
||||
.Take(randomLimit)
|
||||
.ToListAsync();
|
||||
.ToListAsync().ConfigureAwait(false);
|
||||
var dict = randomGenres.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value);
|
||||
return new SortedDictionary<int, int>(dict);
|
||||
}
|
||||
|
||||
public override async Task<SortedDictionary<int, int>> RandomLabelIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
public override async Task<SortedDictionary<int, int>> RandomLabelIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
{
|
||||
var randomLabels = await Labels.OrderBy(x => Guid.NewGuid()).Take(randomLimit).ToListAsync();
|
||||
var randomLabels = await Labels.OrderBy(x => Guid.NewGuid()).Take(randomLimit).ToListAsync().ConfigureAwait(false);
|
||||
var dict = randomLabels.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value);
|
||||
return new SortedDictionary<int, int>(dict);
|
||||
}
|
||||
|
||||
public override async Task<SortedDictionary<int, int>> RandomReleaseIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
public override async Task<SortedDictionary<int, int>> RandomReleaseIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
{
|
||||
List<Release> randomReleases = null;
|
||||
if (doOnlyFavorites)
|
||||
|
@ -154,7 +154,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
select r
|
||||
).OrderBy(x => Guid.NewGuid())
|
||||
.Take(randomLimit)
|
||||
.ToListAsync();
|
||||
.ToListAsync().ConfigureAwait(false);
|
||||
}
|
||||
else if (doOnlyRated)
|
||||
{
|
||||
|
@ -165,7 +165,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
select r
|
||||
).OrderBy(x => Guid.NewGuid())
|
||||
.Take(randomLimit)
|
||||
.ToListAsync();
|
||||
.ToListAsync().ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -176,13 +176,13 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
select r)
|
||||
.OrderBy(x => Guid.NewGuid())
|
||||
.Take(randomLimit)
|
||||
.ToListAsync();
|
||||
.ToListAsync().ConfigureAwait(false);
|
||||
}
|
||||
var dict = randomReleases.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value);
|
||||
return new SortedDictionary<int, int>(dict);
|
||||
}
|
||||
|
||||
public override async Task<SortedDictionary<int, int>> RandomTrackIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
public override async Task<SortedDictionary<int, int>> RandomTrackIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
{
|
||||
List<Track> randomTracks = null;
|
||||
if (doOnlyFavorites)
|
||||
|
@ -194,7 +194,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
select t
|
||||
).OrderBy(x => Guid.NewGuid())
|
||||
.Take(randomLimit)
|
||||
.ToListAsync();
|
||||
.ToListAsync().ConfigureAwait(false);
|
||||
}
|
||||
else if (doOnlyRated)
|
||||
{
|
||||
|
@ -205,7 +205,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
select t
|
||||
).OrderBy(x => Guid.NewGuid())
|
||||
.Take(randomLimit)
|
||||
.ToListAsync();
|
||||
.ToListAsync().ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -216,7 +216,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
select t)
|
||||
.OrderBy(x => Guid.NewGuid())
|
||||
.Take(randomLimit)
|
||||
.ToListAsync();
|
||||
.ToListAsync().ConfigureAwait(false);
|
||||
}
|
||||
var dict = randomTracks.Select((x, i) => new { key = i, value = x.Id }).Take(randomLimit).ToDictionary(x => x.key, x => x.value);
|
||||
return new SortedDictionary<int, int>(dict);
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
where ut.userId = {0}
|
||||
ORDER by ut.lastPlayed desc
|
||||
LIMIT 1";
|
||||
return await Artists.FromSqlRaw(sql, userId).FirstOrDefaultAsync();
|
||||
return await Artists.FromSqlRaw(sql, userId).FirstOrDefaultAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public override async Task<Release> LastPlayedRelease(int userId)
|
||||
|
@ -41,7 +41,8 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
LIMIT 1";
|
||||
return await Releases.FromSqlRaw(sql, userId)
|
||||
.Include(x => x.Artist)
|
||||
.FirstOrDefaultAsync();
|
||||
.FirstOrDefaultAsync()
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public override async Task<Track> LastPlayedTrack(int userId)
|
||||
|
@ -57,7 +58,8 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
.Include(x => x.ReleaseMedia)
|
||||
.Include("ReleaseMedia.Release")
|
||||
.Include("ReleaseMedia.Release.Artist")
|
||||
.FirstOrDefaultAsync();
|
||||
.FirstOrDefaultAsync()
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public override async Task<Artist> MostPlayedArtist(int userId)
|
||||
|
@ -72,7 +74,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
group by r.id
|
||||
order by SUM(ut.playedCount) desc
|
||||
LIMIT 1";
|
||||
return await Artists.FromSqlRaw(sql, userId).FirstOrDefaultAsync();
|
||||
return await Artists.FromSqlRaw(sql, userId).FirstOrDefaultAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public override async Task<Release> MostPlayedRelease(int userId)
|
||||
|
@ -88,7 +90,8 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
LIMIT 1";
|
||||
return await Releases.FromSqlRaw(sql, userId)
|
||||
.Include(x => x.Artist)
|
||||
.FirstOrDefaultAsync();
|
||||
.FirstOrDefaultAsync()
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public override async Task<Track> MostPlayedTrack(int userId)
|
||||
|
@ -105,10 +108,11 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
.Include(x => x.ReleaseMedia)
|
||||
.Include("ReleaseMedia.Release")
|
||||
.Include("ReleaseMedia.Release.Artist")
|
||||
.FirstOrDefaultAsync();
|
||||
.FirstOrDefaultAsync()
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public override async Task<SortedDictionary<int, int>> RandomArtistIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
public override async Task<SortedDictionary<int, int>> RandomArtistIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
{
|
||||
var sql = @"SELECT a.id
|
||||
FROM `artist` a
|
||||
|
@ -117,34 +121,34 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
AND {2} = 1)
|
||||
order BY RIGHT(HEX((1 << 24) * (1 + RAND())), 6)
|
||||
LIMIT 0, {0}";
|
||||
var ids = await Artists.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToListAsync();
|
||||
var ids = await Artists.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToListAsync().ConfigureAwait(false);
|
||||
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||
return new SortedDictionary<int, int>(dict);
|
||||
}
|
||||
|
||||
public override async Task<SortedDictionary<int, int>> RandomGenreIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
public override async Task<SortedDictionary<int, int>> RandomGenreIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
{
|
||||
var sql = @"SELECT g.id
|
||||
FROM `genre` g
|
||||
ORDER BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
|
||||
LIMIT 0, {0}";
|
||||
var ids = await Genres.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync();
|
||||
var ids = await Genres.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync().ConfigureAwait(false);
|
||||
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||
return new SortedDictionary<int, int>(dict);
|
||||
}
|
||||
|
||||
public override async Task<SortedDictionary<int, int>> RandomLabelIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
public override async Task<SortedDictionary<int, int>> RandomLabelIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
{
|
||||
var sql = @"SELECT l.id
|
||||
FROM `label` l
|
||||
ORDER BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
|
||||
LIMIT 0, {0}";
|
||||
var ids = await Labels.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync();
|
||||
var ids = await Labels.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync().ConfigureAwait(false);
|
||||
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||
return new SortedDictionary<int, int>(dict);
|
||||
}
|
||||
|
||||
public override async Task<SortedDictionary<int, int>> RandomReleaseIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
public override async Task<SortedDictionary<int, int>> RandomReleaseIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
{
|
||||
var sql = @"SELECT r.id
|
||||
FROM `release` r
|
||||
|
@ -153,12 +157,12 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
AND {2} = 1)
|
||||
ORDER BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
|
||||
LIMIT 0, {0}";
|
||||
var ids = await Releases.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToListAsync();
|
||||
var ids = await Releases.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToListAsync().ConfigureAwait(false);
|
||||
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||
return new SortedDictionary<int, int>(dict);
|
||||
}
|
||||
|
||||
public override async Task<SortedDictionary<int, int>> RandomTrackIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
public override async Task<SortedDictionary<int, int>> RandomTrackIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
{
|
||||
var sql = @"SELECT t.id
|
||||
FROM `track` t
|
||||
|
@ -194,7 +198,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
WHERE ut.userId = {1} AND ut.isFavorite = 1) AND {2} = 1) OR {2} = 0)
|
||||
order BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
|
||||
LIMIT 0, {0}";
|
||||
var ids = await Tracks.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0", doOnlyRated ? "1" : "0").Select(x => x.Id).ToListAsync();
|
||||
var ids = await Tracks.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0", doOnlyRated ? "1" : "0").Select(x => x.Id).ToListAsync().ConfigureAwait(false);
|
||||
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||
return new SortedDictionary<int, int>(dict);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
}
|
||||
}
|
||||
|
||||
public override async Task<SortedDictionary<int, int>> RandomArtistIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
public override async Task<SortedDictionary<int, int>> RandomArtistIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
{
|
||||
// TODO Rating?
|
||||
var sql = @"SELECT a.id
|
||||
|
@ -32,34 +32,34 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
AND {2} = 1)
|
||||
order by random()
|
||||
LIMIT 0, {0}";
|
||||
var ids = await Artists.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToListAsync();
|
||||
var ids = await Artists.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToListAsync().ConfigureAwait(false);
|
||||
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||
return new SortedDictionary<int, int>(dict);
|
||||
}
|
||||
|
||||
public override async Task<SortedDictionary<int, int>> RandomGenreIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
public override async Task<SortedDictionary<int, int>> RandomGenreIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
{
|
||||
var sql = @"SELECT g.id
|
||||
FROM genre g
|
||||
order by random()
|
||||
LIMIT 0, {0}";
|
||||
var ids = await Genres.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync();
|
||||
var ids = await Genres.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync().ConfigureAwait(false);
|
||||
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||
return new SortedDictionary<int, int>(dict);
|
||||
}
|
||||
|
||||
public override async Task<SortedDictionary<int, int>> RandomLabelIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
public override async Task<SortedDictionary<int, int>> RandomLabelIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
{
|
||||
var sql = @"SELECT l.id
|
||||
FROM label l
|
||||
order by random()
|
||||
LIMIT 0, {0}";
|
||||
var ids = await Labels.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync();
|
||||
var ids = await Labels.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync().ConfigureAwait(false);
|
||||
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||
return new SortedDictionary<int, int>(dict);
|
||||
}
|
||||
|
||||
public override async Task<SortedDictionary<int, int>> RandomReleaseIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
public override async Task<SortedDictionary<int, int>> RandomReleaseIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
{
|
||||
// TODO Rating?
|
||||
var sql = @"SELECT r.id
|
||||
|
@ -69,12 +69,12 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
AND {2} = 1)
|
||||
order by random()
|
||||
LIMIT 0, {0}";
|
||||
var ids = await Releases.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToListAsync();
|
||||
var ids = await Releases.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToListAsync().ConfigureAwait(false);
|
||||
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||
return new SortedDictionary<int, int>(dict);
|
||||
}
|
||||
|
||||
public override async Task<SortedDictionary<int, int>> RandomTrackIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
public override async Task<SortedDictionary<int, int>> RandomTrackIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
|
||||
{
|
||||
// When using the regular 'FromSqlRaw' with parameters SQLite returns no records.
|
||||
|
||||
|
@ -103,7 +103,7 @@ namespace Roadie.Library.Data.Context.Implementation
|
|||
WHERE ut.userId = {userId} AND ut.isFavorite = 1) AND {df} = 1) OR {df} = 0)
|
||||
order by random()
|
||||
LIMIT 0, {randomLimit}";
|
||||
var ids = await Tracks.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync();
|
||||
var ids = await Tracks.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync().ConfigureAwait(false);
|
||||
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
|
||||
return new SortedDictionary<int, int>(dict);
|
||||
}
|
||||
|
|
|
@ -6,15 +6,15 @@ namespace Roadie.Library.Data.Context
|
|||
{
|
||||
public abstract partial class RoadieDbContext : DbContext, IRoadieDbContext
|
||||
{
|
||||
public abstract Task<SortedDictionary<int, int>> RandomArtistIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
public abstract Task<SortedDictionary<int, int>> RandomArtistIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
|
||||
public abstract Task<SortedDictionary<int, int>> RandomGenreIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
public abstract Task<SortedDictionary<int, int>> RandomGenreIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
|
||||
public abstract Task<SortedDictionary<int, int>> RandomLabelIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
public abstract Task<SortedDictionary<int, int>> RandomLabelIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
|
||||
public abstract Task<SortedDictionary<int, int>> RandomReleaseIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
public abstract Task<SortedDictionary<int, int>> RandomReleaseIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
|
||||
public abstract Task<SortedDictionary<int, int>> RandomTrackIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
public abstract Task<SortedDictionary<int, int>> RandomTrackIdsAsync(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false);
|
||||
|
||||
public abstract Task<Artist> MostPlayedArtist(int userId);
|
||||
|
||||
|
|
|
@ -349,7 +349,7 @@ namespace Roadie.Library.Engines
|
|||
if (ITunesArtistSearchEngine.IsEnabled)
|
||||
{
|
||||
var sw2 = Stopwatch.StartNew();
|
||||
var iTunesResult = await ITunesArtistSearchEngine.PerformArtistSearch(artistName, 1).ConfigureAwait(false);
|
||||
var iTunesResult = await ITunesArtistSearchEngine.PerformArtistSearchAsync(artistName, 1).ConfigureAwait(false);
|
||||
if (iTunesResult.IsSuccess)
|
||||
{
|
||||
var i = iTunesResult.Data.First();
|
||||
|
@ -406,7 +406,7 @@ namespace Roadie.Library.Engines
|
|||
if (MusicBrainzArtistSearchEngine.IsEnabled)
|
||||
{
|
||||
var sw2 = Stopwatch.StartNew();
|
||||
var mbResult = await MusicBrainzArtistSearchEngine.PerformArtistSearch(result.Name, 1).ConfigureAwait(false);
|
||||
var mbResult = await MusicBrainzArtistSearchEngine.PerformArtistSearchAsync(result.Name, 1).ConfigureAwait(false);
|
||||
if (mbResult.IsSuccess)
|
||||
{
|
||||
var mb = mbResult.Data.First();
|
||||
|
@ -471,7 +471,7 @@ namespace Roadie.Library.Engines
|
|||
if (LastFmArtistSearchEngine.IsEnabled)
|
||||
{
|
||||
var sw2 = Stopwatch.StartNew();
|
||||
var lastFmResult = await LastFmArtistSearchEngine.PerformArtistSearch(result.Name, 1).ConfigureAwait(false);
|
||||
var lastFmResult = await LastFmArtistSearchEngine.PerformArtistSearchAsync(result.Name, 1).ConfigureAwait(false);
|
||||
if (lastFmResult.IsSuccess)
|
||||
{
|
||||
var l = lastFmResult.Data.First();
|
||||
|
@ -515,7 +515,7 @@ namespace Roadie.Library.Engines
|
|||
if (SpotifyArtistSearchEngine.IsEnabled)
|
||||
{
|
||||
var sw2 = Stopwatch.StartNew();
|
||||
var spotifyResult = await SpotifyArtistSearchEngine.PerformArtistSearch(result.Name, 1).ConfigureAwait(false);
|
||||
var spotifyResult = await SpotifyArtistSearchEngine.PerformArtistSearchAsync(result.Name, 1).ConfigureAwait(false);
|
||||
if (spotifyResult.IsSuccess)
|
||||
{
|
||||
var s = spotifyResult.Data.First();
|
||||
|
@ -557,7 +557,7 @@ namespace Roadie.Library.Engines
|
|||
if (DiscogsArtistSearchEngine.IsEnabled)
|
||||
{
|
||||
var sw2 = Stopwatch.StartNew();
|
||||
var discogsResult = await DiscogsArtistSearchEngine.PerformArtistSearch(result.Name, 1).ConfigureAwait(false);
|
||||
var discogsResult = await DiscogsArtistSearchEngine.PerformArtistSearchAsync(result.Name, 1).ConfigureAwait(false);
|
||||
if (discogsResult.IsSuccess)
|
||||
{
|
||||
var d = discogsResult?.Data?.FirstOrDefault();
|
||||
|
@ -614,7 +614,7 @@ namespace Roadie.Library.Engines
|
|||
{
|
||||
wikiName += " band";
|
||||
}
|
||||
var wikipediaResult = await WikipediaArtistSearchEngine.PerformArtistSearch(wikiName, 1).ConfigureAwait(false);
|
||||
var wikipediaResult = await WikipediaArtistSearchEngine.PerformArtistSearchAsync(wikiName, 1).ConfigureAwait(false);
|
||||
if (wikipediaResult?.Data != null)
|
||||
{
|
||||
if (wikipediaResult.IsSuccess)
|
||||
|
|
|
@ -455,7 +455,7 @@ namespace Roadie.Library.Engines
|
|||
{
|
||||
var sw2 = Stopwatch.StartNew();
|
||||
Logger.LogTrace("ITunesReleaseSearchEngine Release Search for ArtistName [{0}], ReleaseTitle [{1}]", metaData.Artist, result.Title);
|
||||
var iTunesResult = await ITunesReleaseSearchEngine.PerformReleaseSearch(metaData.Artist, result.Title, 1);
|
||||
var iTunesResult = await ITunesReleaseSearchEngine.PerformReleaseSearch(metaData.Artist, result.Title, 1).ConfigureAwait(false);
|
||||
if (iTunesResult.IsSuccess)
|
||||
{
|
||||
var i = iTunesResult.Data.First();
|
||||
|
|
|
@ -26,24 +26,23 @@ namespace Roadie.Library.Imaging
|
|||
|
||||
public static byte[] ConvertToJpegFormat(byte[] imageBytes)
|
||||
{
|
||||
if (imageBytes == null || !imageBytes.Any())
|
||||
if(imageBytes?.Any() != true)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using (var outStream = new MemoryStream())
|
||||
using(var outStream = new MemoryStream())
|
||||
{
|
||||
IImageFormat imageFormat = null;
|
||||
using (var image = SixLabors.ImageSharp.Image.Load(imageBytes, out imageFormat))
|
||||
using(var image = SixLabors.ImageSharp.Image.Load(imageBytes, out imageFormat))
|
||||
{
|
||||
image.SaveAsJpeg(outStream);
|
||||
}
|
||||
return outStream.ToArray();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
} catch(Exception ex)
|
||||
{
|
||||
Trace.WriteLine($"Error Converting Image to Jpg [{ ex.Message }]", "Warning");
|
||||
}
|
||||
|
@ -55,44 +54,48 @@ namespace Roadie.Library.Imaging
|
|||
/// </summary>
|
||||
public static byte[] ConvertToGifFormat(byte[] imageBytes)
|
||||
{
|
||||
if (imageBytes == null || !imageBytes.Any())
|
||||
if(imageBytes?.Any() != true)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
using (var outStream = new MemoryStream())
|
||||
using(var outStream = new MemoryStream())
|
||||
{
|
||||
IImageFormat imageFormat = null;
|
||||
using (var image = SixLabors.ImageSharp.Image.Load(imageBytes, out imageFormat))
|
||||
using(var image = SixLabors.ImageSharp.Image.Load(imageBytes, out imageFormat))
|
||||
{
|
||||
image.SaveAsGif(outStream);
|
||||
}
|
||||
return outStream.ToArray();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
} catch(Exception ex)
|
||||
{
|
||||
Trace.WriteLine($"Error Converting Image to Gif [{ ex.Message }]", "Warning");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static IEnumerable<FileInfo> FindImagesByName(DirectoryInfo directory, string name, SearchOption folderSearchOptions = SearchOption.AllDirectories)
|
||||
public static IEnumerable<FileInfo> FindImagesByName(DirectoryInfo directory,
|
||||
string name,
|
||||
SearchOption folderSearchOptions = SearchOption.AllDirectories)
|
||||
{
|
||||
var result = new List<FileInfo>();
|
||||
if (directory == null || !directory.Exists || string.IsNullOrEmpty(name)) return result;
|
||||
if(directory?.Exists != true || string.IsNullOrEmpty(name))
|
||||
return result;
|
||||
var imageFilesInFolder = ImageFilesInFolder(directory.FullName, folderSearchOptions);
|
||||
if (imageFilesInFolder == null || !imageFilesInFolder.Any()) return result;
|
||||
if (imageFilesInFolder.Any())
|
||||
if(imageFilesInFolder?.Any() != true)
|
||||
return result;
|
||||
if(imageFilesInFolder.Length > 0)
|
||||
{
|
||||
name = name.ToAlphanumericName();
|
||||
foreach (var imageFileInFolder in imageFilesInFolder)
|
||||
foreach(var imageFileInFolder in imageFilesInFolder)
|
||||
{
|
||||
var image = new FileInfo(imageFileInFolder);
|
||||
var filenameWithoutExtension = Path.GetFileName(imageFileInFolder).ToAlphanumericName();
|
||||
var imageName = image.Name.ToAlphanumericName();
|
||||
if (imageName.Equals(name) || filenameWithoutExtension.Equals(name)) result.Add(image);
|
||||
if(imageName.Equals(name) || filenameWithoutExtension.Equals(name))
|
||||
result.Add(image);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,77 +110,102 @@ namespace Roadie.Library.Imaging
|
|||
}
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(image1) || !File.Exists(image1))
|
||||
if(string.IsNullOrEmpty(image1) || !File.Exists(image1))
|
||||
{
|
||||
return File.Exists(compareToImage);
|
||||
}
|
||||
using (var imageComparing = SixLabors.ImageSharp.Image.Load(image1))
|
||||
using(var imageComparing = SixLabors.ImageSharp.Image.Load(image1))
|
||||
{
|
||||
using (var imageToCompare = SixLabors.ImageSharp.Image.Load(compareToImage))
|
||||
using(var imageToCompare = SixLabors.ImageSharp.Image.Load(compareToImage))
|
||||
{
|
||||
// Generally a larger image is the preferred image
|
||||
var isBigger = imageToCompare.Height > imageComparing.Height && imageToCompare.Width > imageComparing.Width;
|
||||
if (isBigger)
|
||||
var isBigger = imageToCompare.Height > imageComparing.Height &&
|
||||
imageToCompare.Width > imageComparing.Width;
|
||||
if(isBigger)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
} catch(Exception ex)
|
||||
{
|
||||
Trace.WriteLine($"Error IsImageBetterQuality Image Comparing [{ image1 }] to [{ compareToImage }], Error [{ ex }]", "Warning");
|
||||
Trace.WriteLine($"Error IsImageBetterQuality Image Comparing [{ image1 }] to [{ compareToImage }], Error [{ ex }]",
|
||||
"Warning");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static IEnumerable<FileInfo> FindImageTypeInDirectory(DirectoryInfo directory, ImageType type, SearchOption folderSearchOptions = SearchOption.AllDirectories)
|
||||
public static IEnumerable<FileInfo> FindImageTypeInDirectory(DirectoryInfo directory,
|
||||
ImageType type,
|
||||
SearchOption folderSearchOptions = SearchOption.AllDirectories)
|
||||
{
|
||||
var result = new List<FileInfo>();
|
||||
if (directory == null || !directory.Exists) return result;
|
||||
if (directory?.Exists != true)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
var imageFilesInFolder = ImageFilesInFolder(directory.FullName, folderSearchOptions);
|
||||
if (imageFilesInFolder == null || !imageFilesInFolder.Any()) return result;
|
||||
foreach (var imageFile in imageFilesInFolder)
|
||||
if (imageFilesInFolder?.Any() != true)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
foreach(var imageFile in imageFilesInFolder)
|
||||
{
|
||||
var image = new FileInfo(imageFile);
|
||||
switch (type)
|
||||
switch(type)
|
||||
{
|
||||
case ImageType.Artist:
|
||||
if (IsArtistImage(image)) result.Add(image);
|
||||
if (IsArtistImage(image))
|
||||
{
|
||||
result.Add(image);
|
||||
}
|
||||
break;
|
||||
|
||||
case ImageType.ArtistSecondary:
|
||||
if (IsArtistSecondaryImage(image)) result.Add(image);
|
||||
if (IsArtistSecondaryImage(image))
|
||||
{
|
||||
result.Add(image);
|
||||
}
|
||||
break;
|
||||
|
||||
case ImageType.Release:
|
||||
if (IsReleaseImage(image)) result.Add(image);
|
||||
if (IsReleaseImage(image))
|
||||
{
|
||||
result.Add(image);
|
||||
}
|
||||
break;
|
||||
|
||||
case ImageType.ReleaseSecondary:
|
||||
if (IsReleaseSecondaryImage(image)) result.Add(image);
|
||||
if (IsReleaseSecondaryImage(image))
|
||||
{
|
||||
result.Add(image);
|
||||
}
|
||||
break;
|
||||
|
||||
case ImageType.Label:
|
||||
if (IsLabelImage(image)) result.Add(image);
|
||||
if (IsLabelImage(image))
|
||||
{
|
||||
result.Add(image);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result.OrderBy(x => x.Name);
|
||||
}
|
||||
|
||||
public static string[] GetFiles(string path, string[] patterns = null, SearchOption options = SearchOption.TopDirectoryOnly)
|
||||
public static string[] GetFiles(string path,
|
||||
string[] patterns = null,
|
||||
SearchOption options = SearchOption.TopDirectoryOnly)
|
||||
{
|
||||
if (!Directory.Exists(path))
|
||||
if(!Directory.Exists(path))
|
||||
{
|
||||
return new string[0];
|
||||
}
|
||||
if (patterns == null || patterns.Length == 0)
|
||||
if(patterns == null || patterns.Length == 0)
|
||||
{
|
||||
return Directory.GetFiles(path, "*", options);
|
||||
}
|
||||
if (patterns.Length == 1)
|
||||
if(patterns.Length == 1)
|
||||
{
|
||||
return Directory.GetFiles(path, patterns[0], options);
|
||||
}
|
||||
|
@ -186,9 +214,10 @@ namespace Roadie.Library.Imaging
|
|||
|
||||
public static byte[] ImageDataFromUrl(string imageUrl)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(imageUrl) && !imageUrl.StartsWith("http", StringComparison.OrdinalIgnoreCase))
|
||||
if(!string.IsNullOrEmpty(imageUrl) && !imageUrl.StartsWith("http", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var dataString = imageUrl.Trim().Replace('-', '+')
|
||||
var dataString = imageUrl.Trim()
|
||||
.Replace('-', '+')
|
||||
.Replace("data:image/jpeg;base64,", "")
|
||||
.Replace("data:image/bmp;base64,", "")
|
||||
.Replace("data:image/gif;base64,", "")
|
||||
|
@ -200,27 +229,22 @@ namespace Roadie.Library.Imaging
|
|||
}
|
||||
|
||||
public static string[] ImageExtensions()
|
||||
{
|
||||
return new string[6] { "*.bmp", "*.jpeg", "*.jpe", "*.jpg", "*.png", "*.gif" };
|
||||
}
|
||||
{ return new string[6] { "*.bmp", "*.jpeg", "*.jpe", "*.jpg", "*.png", "*.gif" }; }
|
||||
|
||||
public static string[] ImageFilesInFolder(string folder, SearchOption searchOption)
|
||||
{
|
||||
return GetFiles(folder, ImageExtensions(), searchOption);
|
||||
}
|
||||
{ return GetFiles(folder, ImageExtensions(), searchOption); }
|
||||
|
||||
public static string[] ImageMimeTypes()
|
||||
{
|
||||
return new string[4] { "image/bmp", "image/jpeg", "image/png", "image/gif" };
|
||||
}
|
||||
{ return new string[4] { "image/bmp", "image/jpeg", "image/png", "image/gif" }; }
|
||||
|
||||
public static ImageSearchResult ImageSearchResultForImageUrl(string imageUrl)
|
||||
{
|
||||
if (!WebHelper.IsStringUrl(imageUrl)) return null;
|
||||
if(!WebHelper.IsStringUrl(imageUrl))
|
||||
return null;
|
||||
var result = new ImageSearchResult();
|
||||
var imageBytes = WebHelper.BytesForImageUrl(imageUrl);
|
||||
IImageFormat imageFormat = null;
|
||||
using (var image = SixLabors.ImageSharp.Image.Load(imageBytes, out imageFormat))
|
||||
using(var image = SixLabors.ImageSharp.Image.Load(imageBytes, out imageFormat))
|
||||
{
|
||||
result.Height = image.Height.ToString();
|
||||
result.Width = image.Width.ToString();
|
||||
|
@ -232,43 +256,54 @@ namespace Roadie.Library.Imaging
|
|||
|
||||
public static bool IsArtistImage(FileInfo fileinfo)
|
||||
{
|
||||
if (fileinfo == null) return false;
|
||||
return Regex.IsMatch(fileinfo.Name, @"(band|artist|group|photo)\.(jpg|jpeg|png|bmp|gif)",
|
||||
RegexOptions.IgnoreCase);
|
||||
if(fileinfo == null)
|
||||
return false;
|
||||
return Regex.IsMatch(fileinfo.Name,
|
||||
@"(band|artist|group|photo)\.(jpg|jpeg|png|bmp|gif)",
|
||||
RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
public static bool IsArtistSecondaryImage(FileInfo fileinfo)
|
||||
{
|
||||
if (fileinfo == null) return false;
|
||||
if(fileinfo == null)
|
||||
return false;
|
||||
return Regex.IsMatch(fileinfo.Name,
|
||||
@"(artist_logo|logo|photo[-_\s]*[0-9]+|(artist[\s_-]+[0-9]+)|(band[\s_-]+[0-9]+))\.(jpg|jpeg|png|bmp|gif)",
|
||||
RegexOptions.IgnoreCase);
|
||||
@"(artist_logo|logo|photo[-_\s]*[0-9]+|(artist[\s_-]+[0-9]+)|(band[\s_-]+[0-9]+))\.(jpg|jpeg|png|bmp|gif)",
|
||||
RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
public static bool IsLabelImage(FileInfo fileinfo)
|
||||
{
|
||||
if (fileinfo == null) return false;
|
||||
return Regex.IsMatch(fileinfo.Name, @"(label|recordlabel|record_label)\.(jpg|jpeg|png|bmp|gif)",
|
||||
RegexOptions.IgnoreCase);
|
||||
if(fileinfo == null)
|
||||
return false;
|
||||
return Regex.IsMatch(fileinfo.Name,
|
||||
@"(label|recordlabel|record_label)\.(jpg|jpeg|png|bmp|gif)",
|
||||
RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
public static bool IsReleaseImage(FileInfo fileinfo, string releaseName = null)
|
||||
{
|
||||
if (fileinfo == null) return false;
|
||||
if(fileinfo == null)
|
||||
return false;
|
||||
return Regex.IsMatch(fileinfo.Name,
|
||||
@"((f[-_\s]*[0-9]*)|00|art|big[art]*|cover|cvr|folder|release|front[-_\s]*)\.(jpg|jpeg|png|bmp|gif)",
|
||||
RegexOptions.IgnoreCase);
|
||||
@"((f[-_\s]*[0-9]*)|00|art|big[art]*|cover|cvr|folder|release|front[-_\s]*)\.(jpg|jpeg|png|bmp|gif)",
|
||||
RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
public static bool IsReleaseSecondaryImage(FileInfo fileinfo)
|
||||
{
|
||||
if (fileinfo == null) return false;
|
||||
if(fileinfo == null)
|
||||
return false;
|
||||
return Regex.IsMatch(fileinfo.Name,
|
||||
@"((img[\s-_]*[0-9]*[\s-_]*[0-9]*)|(book[let]*[#-_\s(]*[0-9]*-*[0-9]*(\))*)|(encartes[-_\s]*[(]*[0-9]*[)]*)|sc[an]*(.)?[0-9]*|matrix(.)?[0-9]*|(cover[\s_-]*[0-9]+)|back|traycard|jewel case|disc|(.*)[in]*side(.*)|in([side|lay|let|site])*[0-9]*|digipack.?\[?\(?([0-9]*)\]?\)?|cd.?\[?\(?([0-9]*)\]?\)?|(release[\s_-]+[0-9]+))\.(jpg|jpeg|png|bmp|gif)",
|
||||
RegexOptions.IgnoreCase);
|
||||
@"((img[\s-_]*[0-9]*[\s-_]*[0-9]*)|(book[let]*[#-_\s(]*[0-9]*-*[0-9]*(\))*)|(encartes[-_\s]*[(]*[0-9]*[)]*)|sc[an]*(.)?[0-9]*|matrix(.)?[0-9]*|(cover[\s_-]*[0-9]+)|back|traycard|jewel case|disc|(.*)[in]*side(.*)|in([side|lay|let|site])*[0-9]*|digipack.?\[?\(?([0-9]*)\]?\)?|cd.?\[?\(?([0-9]*)\]?\)?|(release[\s_-]+[0-9]+))\.(jpg|jpeg|png|bmp|gif)",
|
||||
RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
public static byte[] ResizeImage(byte[] imageBytes, int width, int height) => ImageHelper.ResizeImage(imageBytes, width, height, false).Item2;
|
||||
public static byte[] ResizeImage(byte[] imageBytes, int width, int height) => ImageHelper.ResizeImage(imageBytes,
|
||||
width,
|
||||
height,
|
||||
false)
|
||||
.Item2;
|
||||
|
||||
/// <summary>
|
||||
/// Resize a given image to given dimensions if needed
|
||||
|
@ -278,38 +313,39 @@ namespace Roadie.Library.Imaging
|
|||
/// <param name="height">Resize to height</param>
|
||||
/// <param name="forceResize">Force resize</param>
|
||||
/// <returns>Tuple with bool for did resize and byte array of image</returns>
|
||||
public static Tuple<bool, byte[]> ResizeImage(byte[] imageBytes, int width, int height, bool? forceResize = false)
|
||||
public static Tuple<bool, byte[]> ResizeImage(byte[] imageBytes,
|
||||
int width,
|
||||
int height,
|
||||
bool? forceResize = false)
|
||||
{
|
||||
if (imageBytes == null)
|
||||
if(imageBytes == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
using (var outStream = new MemoryStream())
|
||||
using(var outStream = new MemoryStream())
|
||||
{
|
||||
var resized = false;
|
||||
IImageFormat imageFormat = null;
|
||||
using (var image = SixLabors.ImageSharp.Image.Load(imageBytes, out imageFormat))
|
||||
using(var image = SixLabors.ImageSharp.Image.Load(imageBytes, out imageFormat))
|
||||
{
|
||||
var doForce = forceResize ?? false;
|
||||
if (doForce || image.Width > width || image.Height > height)
|
||||
if(doForce || image.Width > width || image.Height > height)
|
||||
{
|
||||
int newWidth, newHeight;
|
||||
if (doForce)
|
||||
if(doForce)
|
||||
{
|
||||
newWidth = width;
|
||||
newHeight = height;
|
||||
}
|
||||
else
|
||||
} else
|
||||
{
|
||||
float aspect = image.Width / (float)image.Height;
|
||||
if (aspect < 1)
|
||||
if(aspect < 1)
|
||||
{
|
||||
newWidth = (int)(width * aspect);
|
||||
newHeight = (int)(newWidth / aspect);
|
||||
}
|
||||
else
|
||||
} else
|
||||
{
|
||||
newHeight = (int)(height / aspect);
|
||||
newWidth = (int)(newHeight * aspect);
|
||||
|
@ -322,8 +358,7 @@ namespace Roadie.Library.Imaging
|
|||
}
|
||||
return new Tuple<bool, byte[]>(resized, outStream.ToArray());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
} catch(Exception ex)
|
||||
{
|
||||
Trace.WriteLine($"Error Resizing Image [{ex}]", "Warning");
|
||||
}
|
||||
|
@ -331,12 +366,13 @@ namespace Roadie.Library.Imaging
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get image data from all sources for either fileanme or MetaData
|
||||
/// Get image data from all sources for either fileanme or MetaData
|
||||
/// </summary>
|
||||
/// <param name="filename">Name of the File (ie a CUE file)</param>
|
||||
/// <param name="metaData">Populated MetaData</param>
|
||||
/// <returns></returns>
|
||||
public static AudioMetaDataImage GetPictureForMetaData(IRoadieSettings configuration, string filename, AudioMetaData metaData)
|
||||
public static AudioMetaDataImage GetPictureForMetaData(IRoadieSettings configuration,
|
||||
string filename,
|
||||
AudioMetaData metaData)
|
||||
{
|
||||
SimpleContract.Requires<ArgumentException>(!string.IsNullOrEmpty(filename), "Invalid Filename");
|
||||
SimpleContract.Requires<ArgumentException>(metaData != null, "Invalid MetaData");
|
||||
|
@ -345,7 +381,7 @@ namespace Roadie.Library.Imaging
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does image exist with the same filename
|
||||
/// Does image exist with the same filename
|
||||
/// </summary>
|
||||
/// <param name="filename">Name of the File (ie a CUE file)</param>
|
||||
/// <returns>Null if not found else populated image</returns>
|
||||
|
@ -353,7 +389,7 @@ namespace Roadie.Library.Imaging
|
|||
{
|
||||
AudioMetaDataImage imageMetaData = null;
|
||||
|
||||
if (string.IsNullOrEmpty(filename))
|
||||
if(string.IsNullOrEmpty(filename))
|
||||
{
|
||||
return imageMetaData;
|
||||
}
|
||||
|
@ -361,9 +397,9 @@ namespace Roadie.Library.Imaging
|
|||
{
|
||||
var fileInfo = new FileInfo(filename);
|
||||
var ReleaseCover = Path.ChangeExtension(filename, "jpg");
|
||||
if (File.Exists(ReleaseCover))
|
||||
if(File.Exists(ReleaseCover))
|
||||
{
|
||||
using (var processor = new ImageProcessor(configuration))
|
||||
using(var processor = new ImageProcessor(configuration))
|
||||
{
|
||||
imageMetaData = new AudioMetaDataImage
|
||||
{
|
||||
|
@ -372,24 +408,23 @@ namespace Roadie.Library.Imaging
|
|||
MimeType = Library.Processors.FileProcessor.DetermineFileType(fileInfo)
|
||||
};
|
||||
}
|
||||
}
|
||||
else
|
||||
} else
|
||||
{
|
||||
// Is there a picture in filename folder (for the Release)
|
||||
var pictures = fileInfo.Directory.GetFiles("*.jpg");
|
||||
var tagImages = new List<AudioMetaDataImage>();
|
||||
if (pictures != null && pictures.Any())
|
||||
if(pictures?.Any() == true)
|
||||
{
|
||||
FileInfo picture = null;
|
||||
// See if there is a "cover" or "front" jpg file if so use it
|
||||
picture = pictures.FirstOrDefault(x =>
|
||||
x.Name.Equals("cover", StringComparison.OrdinalIgnoreCase));
|
||||
if (picture == null)
|
||||
picture = pictures.FirstOrDefault(x =>
|
||||
x.Name.Equals("front", StringComparison.OrdinalIgnoreCase));
|
||||
if (picture == null) picture = pictures.First();
|
||||
if (picture != null)
|
||||
using (var processor = new ImageProcessor(configuration))
|
||||
FileInfo picture = Array.Find(pictures,
|
||||
x => x.Name.Equals("cover", StringComparison.OrdinalIgnoreCase));
|
||||
if(picture == null)
|
||||
picture = Array.Find(pictures,
|
||||
x => x.Name.Equals("front", StringComparison.OrdinalIgnoreCase));
|
||||
if(picture == null)
|
||||
picture = pictures[0];
|
||||
if(picture != null)
|
||||
using(var processor = new ImageProcessor(configuration))
|
||||
{
|
||||
imageMetaData = new AudioMetaDataImage
|
||||
{
|
||||
|
@ -400,11 +435,9 @@ namespace Roadie.Library.Imaging
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
} catch(FileNotFoundException)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
} catch(Exception ex)
|
||||
{
|
||||
Trace.WriteLine(ex, ex.Serialize());
|
||||
}
|
||||
|
@ -412,97 +445,138 @@ namespace Roadie.Library.Imaging
|
|||
return imageMetaData;
|
||||
}
|
||||
|
||||
public static models.Image MakeThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, string type, int? width = null, int? height = null, bool includeCachebuster = false)
|
||||
public static models.Image MakeThumbnailImage(IRoadieSettings configuration,
|
||||
IHttpContext httpContext,
|
||||
Guid id,
|
||||
string type,
|
||||
int? width = null,
|
||||
int? height = null,
|
||||
bool includeCachebuster = false)
|
||||
{
|
||||
return MakeImage(configuration, httpContext, id, type, width ?? configuration.ThumbnailImageSize.Width, height ?? configuration.ThumbnailImageSize.Height, null, includeCachebuster);
|
||||
return MakeImage(configuration,
|
||||
httpContext,
|
||||
id,
|
||||
type,
|
||||
width ?? configuration.ThumbnailImageSize.Width,
|
||||
height ?? configuration.ThumbnailImageSize.Height,
|
||||
null,
|
||||
includeCachebuster);
|
||||
}
|
||||
|
||||
public static models.Image MakeNewImage(IHttpContext httpContext, string type)
|
||||
{
|
||||
return new models.Image($"{httpContext.ImageBaseUrl}/{type}.jpg", null, null);
|
||||
}
|
||||
{ return new models.Image($"{httpContext.ImageBaseUrl}/{type}.jpg", null, null); }
|
||||
|
||||
public static models.Image MakePlaylistThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
|
||||
{
|
||||
return MakeThumbnailImage(configuration, httpContext, id, "playlist");
|
||||
}
|
||||
public static models.Image MakePlaylistThumbnailImage(IRoadieSettings configuration,
|
||||
IHttpContext httpContext,
|
||||
Guid id)
|
||||
{ return MakeThumbnailImage(configuration, httpContext, id, "playlist"); }
|
||||
|
||||
public static models.Image MakeReleaseThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
|
||||
{
|
||||
return MakeThumbnailImage(configuration, httpContext, id, "release");
|
||||
}
|
||||
public static models.Image MakeReleaseThumbnailImage(IRoadieSettings configuration,
|
||||
IHttpContext httpContext,
|
||||
Guid id)
|
||||
{ return MakeThumbnailImage(configuration, httpContext, id, "release"); }
|
||||
|
||||
public static models.Image MakeTrackThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
|
||||
{
|
||||
return MakeThumbnailImage(configuration, httpContext, id, "track");
|
||||
}
|
||||
public static models.Image MakeTrackThumbnailImage(IRoadieSettings configuration,
|
||||
IHttpContext httpContext,
|
||||
Guid id)
|
||||
{ return MakeThumbnailImage(configuration, httpContext, id, "track"); }
|
||||
|
||||
public static models.Image MakeUserThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
|
||||
{
|
||||
return MakeThumbnailImage(configuration, httpContext, id, "user");
|
||||
}
|
||||
public static models.Image MakeUserThumbnailImage(IRoadieSettings configuration,
|
||||
IHttpContext httpContext,
|
||||
Guid id)
|
||||
{ return MakeThumbnailImage(configuration, httpContext, id, "user"); }
|
||||
|
||||
public static models.Image MakeLabelThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
|
||||
{
|
||||
return MakeThumbnailImage(configuration, httpContext, id, "label");
|
||||
}
|
||||
public static models.Image MakeLabelThumbnailImage(IRoadieSettings configuration,
|
||||
IHttpContext httpContext,
|
||||
Guid id)
|
||||
{ return MakeThumbnailImage(configuration, httpContext, id, "label"); }
|
||||
|
||||
public static models.Image MakeArtistThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid? id)
|
||||
public static models.Image MakeArtistThumbnailImage(IRoadieSettings configuration,
|
||||
IHttpContext httpContext,
|
||||
Guid? id)
|
||||
{
|
||||
if (!id.HasValue) return null;
|
||||
if(!id.HasValue)
|
||||
return null;
|
||||
return MakeThumbnailImage(configuration, httpContext, id.Value, "artist");
|
||||
}
|
||||
|
||||
public static models.Image MakeCollectionThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
|
||||
public static models.Image MakeCollectionThumbnailImage(IRoadieSettings configuration,
|
||||
IHttpContext httpContext,
|
||||
Guid id)
|
||||
{ return MakeThumbnailImage(configuration, httpContext, id, "collection"); }
|
||||
|
||||
public static models.Image MakeFullsizeImage(IRoadieSettings configuration,
|
||||
IHttpContext httpContext,
|
||||
Guid id,
|
||||
string caption = null)
|
||||
{
|
||||
return MakeThumbnailImage(configuration, httpContext, id, "collection");
|
||||
return new models.Image($"{httpContext.ImageBaseUrl}/{id}",
|
||||
caption,
|
||||
$"{httpContext.ImageBaseUrl}/{id}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
|
||||
}
|
||||
|
||||
public static models.Image MakeFullsizeImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, string caption = null)
|
||||
public static models.Image MakeFullsizeSecondaryImage(IRoadieSettings configuration,
|
||||
IHttpContext httpContext,
|
||||
Guid id,
|
||||
ImageType type,
|
||||
int imageId,
|
||||
string caption = null)
|
||||
{
|
||||
return new models.Image($"{httpContext.ImageBaseUrl}/{id}", caption,
|
||||
$"{httpContext.ImageBaseUrl}/{id}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
|
||||
}
|
||||
|
||||
public static models.Image MakeFullsizeSecondaryImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, ImageType type, int imageId, string caption = null)
|
||||
{
|
||||
if (type == ImageType.ArtistSecondary)
|
||||
if(type == ImageType.ArtistSecondary)
|
||||
{
|
||||
return new models.Image($"{httpContext.ImageBaseUrl}/artist-secondary/{id}/{imageId}", caption, $"{httpContext.ImageBaseUrl}/artist-secondary/{id}/{imageId}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
|
||||
return new models.Image($"{httpContext.ImageBaseUrl}/artist-secondary/{id}/{imageId}",
|
||||
caption,
|
||||
$"{httpContext.ImageBaseUrl}/artist-secondary/{id}/{imageId}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
|
||||
}
|
||||
return new models.Image($"{httpContext.ImageBaseUrl}/release-secondary/{id}/{imageId}", caption, $"{httpContext.ImageBaseUrl}/release-secondary/{id}/{imageId}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
|
||||
return new models.Image($"{httpContext.ImageBaseUrl}/release-secondary/{id}/{imageId}",
|
||||
caption,
|
||||
$"{httpContext.ImageBaseUrl}/release-secondary/{id}/{imageId}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
|
||||
}
|
||||
|
||||
public static models.Image MakeGenreThumbnailImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id)
|
||||
{
|
||||
return MakeThumbnailImage(configuration, httpContext, id, "genre");
|
||||
}
|
||||
public static models.Image MakeGenreThumbnailImage(IRoadieSettings configuration,
|
||||
IHttpContext httpContext,
|
||||
Guid id)
|
||||
{ return MakeThumbnailImage(configuration, httpContext, id, "genre"); }
|
||||
|
||||
public static models.Image MakeUnknownImage(IHttpContext httpContext, string unknownType = "unknown")
|
||||
{
|
||||
return new models.Image($"{httpContext.ImageBaseUrl}/{ unknownType }.jpg");
|
||||
}
|
||||
{ return new models.Image($"{httpContext.ImageBaseUrl}/{ unknownType }.jpg"); }
|
||||
|
||||
public static models.Image MakeImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, int width = 200, int height = 200, string caption = null, bool includeCachebuster = false)
|
||||
public static models.Image MakeImage(IRoadieSettings configuration,
|
||||
IHttpContext httpContext,
|
||||
Guid id,
|
||||
int width = 200,
|
||||
int height = 200,
|
||||
string caption = null,
|
||||
bool includeCachebuster = false)
|
||||
{
|
||||
return new models.Image($"{httpContext.ImageBaseUrl}/{id}/{width}/{height}/{(includeCachebuster ? DateTime.UtcNow.Ticks.ToString() : string.Empty)}",
|
||||
caption,
|
||||
$"{httpContext.ImageBaseUrl}/{id}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
|
||||
caption,
|
||||
$"{httpContext.ImageBaseUrl}/{id}/{configuration.SmallImageSize.Width}/{configuration.SmallImageSize.Height}");
|
||||
}
|
||||
|
||||
public static models.Image MakeImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, string type, IImageSize imageSize)
|
||||
{
|
||||
return MakeImage(configuration, httpContext, id, type, imageSize.Width, imageSize.Height);
|
||||
}
|
||||
public static models.Image MakeImage(IRoadieSettings configuration,
|
||||
IHttpContext httpContext,
|
||||
Guid id,
|
||||
string type,
|
||||
IImageSize imageSize)
|
||||
{ return MakeImage(configuration, httpContext, id, type, imageSize.Width, imageSize.Height); }
|
||||
|
||||
public static models.Image MakeImage(IRoadieSettings configuration, IHttpContext httpContext, Guid id, string type, int? width, int? height, string caption = null, bool includeCachebuster = false)
|
||||
public static models.Image MakeImage(IRoadieSettings configuration,
|
||||
IHttpContext httpContext,
|
||||
Guid id,
|
||||
string type,
|
||||
int? width,
|
||||
int? height,
|
||||
string caption = null,
|
||||
bool includeCachebuster = false)
|
||||
{
|
||||
if (width.HasValue && height.HasValue && (width.Value != configuration.ThumbnailImageSize.Width ||
|
||||
height.Value != configuration.ThumbnailImageSize.Height))
|
||||
return new models.Image(
|
||||
$"{httpContext.ImageBaseUrl}/{type}/{id}/{width}/{height}/{(includeCachebuster ? DateTime.UtcNow.Ticks.ToString() : string.Empty)}",
|
||||
caption,
|
||||
$"{httpContext.ImageBaseUrl}/{type}/{id}/{configuration.ThumbnailImageSize.Width}/{configuration.ThumbnailImageSize.Height}");
|
||||
if(width.HasValue &&
|
||||
height.HasValue &&
|
||||
(width.Value != configuration.ThumbnailImageSize.Width ||
|
||||
height.Value != configuration.ThumbnailImageSize.Height))
|
||||
return new models.Image($"{httpContext.ImageBaseUrl}/{type}/{id}/{width}/{height}/{(includeCachebuster ? DateTime.UtcNow.Ticks.ToString() : string.Empty)}",
|
||||
caption,
|
||||
$"{httpContext.ImageBaseUrl}/{type}/{id}/{configuration.ThumbnailImageSize.Width}/{configuration.ThumbnailImageSize.Height}");
|
||||
return new models.Image($"{httpContext.ImageBaseUrl}/{type}/{id}", caption, null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace Roadie.Library.Inspect
|
|||
{
|
||||
public class Inspector
|
||||
{
|
||||
private static readonly string Salt = "6856F2EE-5965-4345-884B-2CCA457AAF59";
|
||||
private const string Salt = "6856F2EE-5965-4345-884B-2CCA457AAF59";
|
||||
|
||||
private IEnumerable<IInspectorDirectoryPlugin> _directoryPlugins;
|
||||
private IEnumerable<IInspectorFilePlugin> _filePlugins;
|
||||
|
@ -49,13 +49,15 @@ namespace Roadie.Library.Inspect
|
|||
foreach (var t in types)
|
||||
if (t.GetInterface("IInspectorDirectoryPlugin") != null && !t.IsAbstract && !t.IsInterface)
|
||||
{
|
||||
var plugin =
|
||||
Activator.CreateInstance(t, Configuration, CacheManager, Logger, TagsHelper) as
|
||||
IInspectorDirectoryPlugin;
|
||||
var plugin = Activator.CreateInstance(t, Configuration, CacheManager, Logger, TagsHelper) as IInspectorDirectoryPlugin;
|
||||
if (plugin.IsEnabled)
|
||||
{
|
||||
plugins.Add(plugin);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"╠╣ Not Loading Disabled Plugin [{plugin.Description}]");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -84,17 +86,20 @@ namespace Roadie.Library.Inspect
|
|||
.SelectMany(s => s.GetTypes())
|
||||
.Where(p => type.IsAssignableFrom(p));
|
||||
foreach (var t in types)
|
||||
{
|
||||
if (t.GetInterface("IInspectorFilePlugin") != null && !t.IsAbstract && !t.IsInterface)
|
||||
{
|
||||
var plugin =
|
||||
Activator.CreateInstance(t, Configuration, CacheManager, Logger, TagsHelper) as
|
||||
IInspectorFilePlugin;
|
||||
|
||||
var plugin = Activator.CreateInstance(t, Configuration, CacheManager, Logger, TagsHelper) as IInspectorFilePlugin;
|
||||
if (plugin.IsEnabled)
|
||||
{
|
||||
plugins.Add(plugin);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"╠╣ Not Loading Disabled Plugin [{plugin.Description}]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -147,10 +152,12 @@ namespace Roadie.Library.Inspect
|
|||
var numbers = 0;
|
||||
var bytes = System.Text.Encoding.ASCII.GetBytes(input);
|
||||
var looper = bytes.Length / 4;
|
||||
for (var i = 0; i < looper; i++) numbers += BitConverter.ToInt32(bytes, i * 4);
|
||||
for (var i = 0; i < looper; i++)
|
||||
{
|
||||
numbers += BitConverter.ToInt32(bytes, i * 4);
|
||||
}
|
||||
if (numbers < 0) numbers *= -1;
|
||||
var token = hashids.Encode(numbers);
|
||||
return token;
|
||||
return hashids.Encode(numbers);
|
||||
}
|
||||
|
||||
public void Inspect(bool doCopy, bool isReadOnly, string directoryToInspect, string destination, bool dontAppendSubFolder, bool dontDeleteEmptyFolders, bool dontRunPreScripts)
|
||||
|
@ -171,15 +178,15 @@ namespace Roadie.Library.Inspect
|
|||
|
||||
string scriptResult = null;
|
||||
// Run PreInspect script
|
||||
if(dontRunPreScripts)
|
||||
if (dontRunPreScripts)
|
||||
{
|
||||
Console.BackgroundColor = ConsoleColor.Blue;
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.WriteLine($"Skipping PreInspectScript.");
|
||||
Console.WriteLine("Skipping PreInspectScript.");
|
||||
Console.ResetColor();
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
scriptResult = RunScript(Configuration.Processing.PreInspectScript, doCopy, isReadOnly, directoryToInspect, destination);
|
||||
if (!string.IsNullOrEmpty(scriptResult))
|
||||
{
|
||||
|
@ -217,7 +224,7 @@ namespace Roadie.Library.Inspect
|
|||
|
||||
// Get all the MP3 files in 'directory'
|
||||
var files = Directory.GetFiles(directory, "*.mp3", SearchOption.TopDirectoryOnly);
|
||||
if (files != null && files.Any())
|
||||
if (files?.Any() == true)
|
||||
{
|
||||
if (!isReadOnly && !createdDestinationFolder && !Directory.Exists(dest))
|
||||
{
|
||||
|
@ -226,20 +233,19 @@ namespace Roadie.Library.Inspect
|
|||
}
|
||||
|
||||
// Run directory plugins against current directory
|
||||
foreach (var plugin in DirectoryPlugins.Where(x => !x.IsPostProcessingPlugin)
|
||||
.OrderBy(x => x.Order))
|
||||
foreach (var plugin in DirectoryPlugins.Where(x => !x.IsPostProcessingPlugin).OrderBy(x => x.Order))
|
||||
{
|
||||
Console.WriteLine($"╠╬═ Running Directory Plugin {plugin.Description}");
|
||||
var pluginResult = plugin.Process(directoryInfo);
|
||||
if (!pluginResult.IsSuccess)
|
||||
{
|
||||
Console.WriteLine(
|
||||
$"📛 Plugin Failed: Error [{JsonConvert.SerializeObject(pluginResult)}]");
|
||||
Console.WriteLine($"📛 Plugin Failed: Error [{JsonConvert.SerializeObject(pluginResult)}]");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(pluginResult.Data))
|
||||
{
|
||||
Console.WriteLine($"╠╣ Directory Plugin Message: {pluginResult.Data}");
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("╠╝");
|
||||
|
@ -263,8 +269,7 @@ namespace Roadie.Library.Inspect
|
|||
if (!originalMetaData.IsValid)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.DarkYellow;
|
||||
Console.WriteLine(
|
||||
$"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(originalMetaData)}");
|
||||
Console.WriteLine($"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(originalMetaData)}");
|
||||
Console.WriteLine($"╟ [{JsonConvert.SerializeObject(tagLib, Newtonsoft.Json.Formatting.Indented)}]");
|
||||
Console.ResetColor();
|
||||
}
|
||||
|
@ -274,13 +279,11 @@ namespace Roadie.Library.Inspect
|
|||
foreach (var plugin in FilePlugins.OrderBy(x => x.Order))
|
||||
{
|
||||
Console.WriteLine($"╟┤ Running File Plugin {plugin.Description}");
|
||||
OperationResult<AudioMetaData> pluginResult = null;
|
||||
pluginResult = plugin.Process(pluginMetaData);
|
||||
OperationResult<AudioMetaData> pluginResult = plugin.Process(pluginMetaData);
|
||||
if (!pluginResult.IsSuccess)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine(
|
||||
$"📛 Plugin Failed: Error [{JsonConvert.SerializeObject(pluginResult)}]");
|
||||
Console.WriteLine($"📛 Plugin Failed: Error [{JsonConvert.SerializeObject(pluginResult)}]");
|
||||
Console.ResetColor();
|
||||
return;
|
||||
}
|
||||
|
@ -291,8 +294,7 @@ namespace Roadie.Library.Inspect
|
|||
if (!pluginMetaData.IsValid)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine(
|
||||
$"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(pluginMetaData)}");
|
||||
Console.WriteLine($"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(pluginMetaData)}");
|
||||
Console.ResetColor();
|
||||
return;
|
||||
}
|
||||
|
@ -301,16 +303,17 @@ namespace Roadie.Library.Inspect
|
|||
if (originalMetaData != null && pluginMetaData != null)
|
||||
{
|
||||
var differences = Comparer.Compare(originalMetaData, pluginMetaData);
|
||||
if (differences.Any())
|
||||
if (differences.Count > 0)
|
||||
{
|
||||
var skipDifferences = new List<string>
|
||||
{"AudioMetaDataWeights", "FileInfo", "Images", "TrackArtists"};
|
||||
var skipDifferences = new List<string> { "AudioMetaDataWeights", "FileInfo", "Images", "TrackArtists" };
|
||||
var differencesDescription = $"{Environment.NewLine}";
|
||||
foreach (var difference in differences)
|
||||
{
|
||||
if (skipDifferences.Contains(difference.Name)) continue;
|
||||
differencesDescription +=
|
||||
$"╟ || {difference.Name} : Was [{difference.OldValue}] Now [{difference.NewValue}]{Environment.NewLine}";
|
||||
if (skipDifferences.Contains(difference.Name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
differencesDescription += $"╟ || {difference.Name} : Was [{difference.OldValue}] Now [{difference.NewValue}]{Environment.NewLine}";
|
||||
}
|
||||
|
||||
Console.Write($"╟ ≡ != ID3 Tag Modified: {differencesDescription}");
|
||||
|
@ -339,15 +342,13 @@ namespace Roadie.Library.Inspect
|
|||
{
|
||||
var oBad = originalMetaData == null;
|
||||
var pBad = pluginMetaData == null;
|
||||
Console.WriteLine(
|
||||
$"╟ !! MetaData comparison skipped. {(oBad ? "Pre MetaData is Invalid" : "")} {(pBad ? "Post MetaData is Invalid" : "")}");
|
||||
Console.WriteLine($"╟ !! MetaData comparison skipped. {(oBad ? "Pre MetaData is Invalid" : string.Empty)} {(pBad ? "Post MetaData is Invalid" : string.Empty)}");
|
||||
}
|
||||
|
||||
if (!pluginMetaData.IsValid)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine(
|
||||
$"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(pluginMetaData)}");
|
||||
Console.WriteLine($"╟ ❗ INVALID: Missing: {ID3TagsHelper.DetermineMissingRequiredMetaData(pluginMetaData)}");
|
||||
Console.ResetColor();
|
||||
}
|
||||
else
|
||||
|
@ -357,11 +358,16 @@ namespace Roadie.Library.Inspect
|
|||
Console.ResetColor();
|
||||
|
||||
var artistToken = ArtistInspectorToken(tagLib.Data);
|
||||
if (!artistsFound.Contains(artistToken)) artistsFound.Add(artistToken);
|
||||
if (!artistsFound.Contains(artistToken))
|
||||
{
|
||||
artistsFound.Add(artistToken);
|
||||
}
|
||||
var releaseToken = ReleaseInspectorToken(tagLib.Data);
|
||||
if (!releasesFound.Contains(releaseToken)) releasesFound.Add(releaseToken);
|
||||
var newFileName =
|
||||
$"CD{(tagLib.Data.Disc ?? ID3TagsHelper.DetermineDiscNumber(tagLib.Data)).ToString("000")}_{tagLib.Data.TrackNumber.Value.ToString("0000")}.mp3";
|
||||
if (!releasesFound.Contains(releaseToken))
|
||||
{
|
||||
releasesFound.Add(releaseToken);
|
||||
}
|
||||
var newFileName = $"CD{(tagLib.Data.Disc ?? ID3TagsHelper.DetermineDiscNumber(tagLib.Data)).ToString("000")}_{tagLib.Data.TrackNumber.Value.ToString("0000")}.mp3";
|
||||
// Artist sub folder is created to hold Releases for Artist and Artist Images
|
||||
var artistSubDirectory = directory == dest
|
||||
? fileInfo.DirectoryName
|
||||
|
@ -371,40 +377,35 @@ namespace Roadie.Library.Inspect
|
|||
? fileInfo.DirectoryName
|
||||
: Path.Combine(dest, artistToken, releaseToken);
|
||||
if (!isReadOnly && !Directory.Exists(subDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(subDirectory);
|
||||
}
|
||||
// Inspect images
|
||||
if (!inspectedImagesInDirectories.Contains(directoryInfo.FullName))
|
||||
{
|
||||
// Get all artist images and move to artist folder
|
||||
var foundArtistImages = new List<FileInfo>();
|
||||
foundArtistImages.AddRange(ImageHelper.FindImagesByName(directoryInfo,
|
||||
tagLib.Data.Artist, SearchOption.TopDirectoryOnly));
|
||||
foundArtistImages.AddRange(ImageHelper.FindImagesByName(directoryInfo.Parent,
|
||||
tagLib.Data.Artist, SearchOption.TopDirectoryOnly));
|
||||
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(
|
||||
directoryInfo.Parent, ImageType.Artist, SearchOption.TopDirectoryOnly));
|
||||
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(
|
||||
directoryInfo.Parent, ImageType.ArtistSecondary,
|
||||
SearchOption.TopDirectoryOnly));
|
||||
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo,
|
||||
ImageType.Artist, SearchOption.TopDirectoryOnly));
|
||||
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo,
|
||||
ImageType.ArtistSecondary, SearchOption.TopDirectoryOnly));
|
||||
foundArtistImages.AddRange(ImageHelper.FindImagesByName(directoryInfo, tagLib.Data.Artist, SearchOption.TopDirectoryOnly));
|
||||
foundArtistImages.AddRange(ImageHelper.FindImagesByName(directoryInfo.Parent, tagLib.Data.Artist, SearchOption.TopDirectoryOnly));
|
||||
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo.Parent, ImageType.Artist, SearchOption.TopDirectoryOnly));
|
||||
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo.Parent, ImageType.ArtistSecondary, SearchOption.TopDirectoryOnly));
|
||||
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo, ImageType.Artist, SearchOption.TopDirectoryOnly));
|
||||
foundArtistImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo, ImageType.ArtistSecondary, SearchOption.TopDirectoryOnly));
|
||||
|
||||
foreach (var artistImage in foundArtistImages)
|
||||
{
|
||||
InspectImage(isReadOnly, doCopy, dest, artistSubDirectory, artistImage);
|
||||
}
|
||||
|
||||
// Get all release images and move to release folder
|
||||
var foundReleaseImages = new List<FileInfo>();
|
||||
foundReleaseImages.AddRange(
|
||||
ImageHelper.FindImagesByName(directoryInfo, tagLib.Data.Release));
|
||||
foundReleaseImages.AddRange(
|
||||
ImageHelper.FindImageTypeInDirectory(directoryInfo, ImageType.Release));
|
||||
foundReleaseImages.AddRange(
|
||||
ImageHelper.FindImageTypeInDirectory(directoryInfo,
|
||||
ImageType.ReleaseSecondary));
|
||||
foundReleaseImages.AddRange(ImageHelper.FindImagesByName(directoryInfo, tagLib.Data.Release));
|
||||
foundReleaseImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo, ImageType.Release));
|
||||
foundReleaseImages.AddRange(ImageHelper.FindImageTypeInDirectory(directoryInfo, ImageType.ReleaseSecondary));
|
||||
foreach (var foundReleaseImage in foundReleaseImages)
|
||||
{
|
||||
InspectImage(isReadOnly, doCopy, dest, subDirectory, foundReleaseImage);
|
||||
}
|
||||
inspectedImagesInDirectories.Add(directoryInfo.FullName);
|
||||
}
|
||||
|
||||
|
@ -412,8 +413,7 @@ namespace Roadie.Library.Inspect
|
|||
var newPath = Path.Combine(dest, subDirectory, newFileName.ToFileNameFriendly());
|
||||
if (isReadOnly)
|
||||
{
|
||||
Console.WriteLine(
|
||||
$"╟ 🔒 Read Only Mode: File would be [{(doCopy ? "Copied" : "Moved")}] to [{newPath}]");
|
||||
Console.WriteLine($"╟ 🔒 Read Only Mode: File would be [{(doCopy ? "Copied" : "Moved")}] to [{newPath}]");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -464,8 +464,7 @@ namespace Roadie.Library.Inspect
|
|||
|
||||
Console.WriteLine("╠╝");
|
||||
sw.Stop();
|
||||
Console.WriteLine(
|
||||
$"╚═ Elapsed Time {sw.ElapsedMilliseconds.ToString("0000000")}, Artists {artistsFound.Count()}, Releases {releasesFound.Count()}, MP3s {mp3FilesFoundCount} ═╝");
|
||||
Console.WriteLine($"╚═ Elapsed Time {sw.ElapsedMilliseconds.ToString("0000000")}, Artists {artistsFound.Count}, Releases {releasesFound.Count}, MP3s {mp3FilesFoundCount} ═╝");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -492,8 +491,7 @@ namespace Roadie.Library.Inspect
|
|||
{
|
||||
Console.BackgroundColor = ConsoleColor.Blue;
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.WriteLine(
|
||||
$"PostInspectScript Results: {Environment.NewLine + scriptResult + Environment.NewLine}");
|
||||
Console.WriteLine($"PostInspectScript Results: {Environment.NewLine + scriptResult + Environment.NewLine}");
|
||||
Console.ResetColor();
|
||||
}
|
||||
}
|
||||
|
@ -521,17 +519,22 @@ namespace Roadie.Library.Inspect
|
|||
looper++;
|
||||
newImagePath = Path.Combine(dest, subdirectory, looper.ToString("00"), image.Name);
|
||||
}
|
||||
|
||||
if (isReadOnly)
|
||||
Console.WriteLine(
|
||||
$"╟ 🔒 Read Only Mode: Would be [{(doCopy ? "Copied" : "Moved")}] to [{newImagePath}]");
|
||||
{
|
||||
Console.WriteLine($"╟ 🔒 Read Only Mode: Would be [{(doCopy ? "Copied" : "Moved")}] to [{newImagePath}]");
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!doCopy)
|
||||
{
|
||||
image.MoveTo(newImagePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
image.CopyTo(newImagePath, true);
|
||||
}
|
||||
Console.ForegroundColor = ConsoleColor.DarkYellow;
|
||||
Console.WriteLine($"╠═ 🚛 {(doCopy ? "Copied" : "Moved")} Image File to [{newImagePath}]");
|
||||
}
|
||||
|
@ -539,9 +542,9 @@ namespace Roadie.Library.Inspect
|
|||
{
|
||||
Logger.LogError(ex);
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine(
|
||||
$"📛 Error file [{image.FullName}], newImagePath [{newImagePath}], Exception: [{ex}]");
|
||||
Console.WriteLine($"📛 Error file [{image.FullName}], newImagePath [{newImagePath}], Exception: [{ex}]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Console.ResetColor();
|
||||
|
@ -588,9 +591,17 @@ namespace Roadie.Library.Inspect
|
|||
var script = File.ReadAllText(scriptFilename);
|
||||
using (var ps = PowerShell.Create())
|
||||
{
|
||||
var r = "";
|
||||
var results = ps.AddScript(script).Invoke();
|
||||
foreach (var result in results) r += result + Environment.NewLine;
|
||||
var r = string.Empty;
|
||||
var results = ps.AddScript(script)
|
||||
.AddParameter("DoCopy", doCopy)
|
||||
.AddParameter("IsReadOnly", isReadOnly)
|
||||
.AddParameter("DirectoryToInspect", directoryToInspect)
|
||||
.AddParameter("Dest", dest)
|
||||
.Invoke();
|
||||
foreach (var result in results)
|
||||
{
|
||||
r += result + Environment.NewLine;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
@ -604,7 +615,6 @@ namespace Roadie.Library.Inspect
|
|||
|
||||
public class LoggingTraceListener : TraceListener
|
||||
{
|
||||
|
||||
public override void Write(string message)
|
||||
{
|
||||
Console.WriteLine($"╠╬═ { message }");
|
||||
|
@ -614,7 +624,5 @@ namespace Roadie.Library.Inspect
|
|||
{
|
||||
Console.WriteLine($"╠╬═ { message }");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -33,7 +33,7 @@ namespace Roadie.Library.Scrobble
|
|||
/// indication of what music player they're using.
|
||||
/// </remark>
|
||||
/// </summary>
|
||||
public override async Task<OperationResult<bool>> NowPlaying(User roadieUser, ScrobbleInfo scrobble) => await LastFmHelper.NowPlaying(roadieUser, scrobble);
|
||||
public override async Task<OperationResult<bool>> NowPlaying(User roadieUser, ScrobbleInfo scrobble) => await LastFmHelper.NowPlaying(roadieUser, scrobble).ConfigureAwait(false);
|
||||
|
||||
/// <summary>
|
||||
/// Send a Scrobble Request
|
||||
|
@ -42,7 +42,7 @@ namespace Roadie.Library.Scrobble
|
|||
/// listening history and generate personalised charts and recommendations (and more).
|
||||
/// </remark>
|
||||
/// </summary>
|
||||
public override async Task<OperationResult<bool>> Scrobble(User roadieUser, ScrobbleInfo scrobble) => await LastFmHelper.Scrobble(roadieUser, scrobble);
|
||||
public override async Task<OperationResult<bool>> Scrobble(User roadieUser, ScrobbleInfo scrobble) => await LastFmHelper.Scrobble(roadieUser, scrobble).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
}
|
|
@ -37,7 +37,7 @@ namespace Roadie.Library.Scrobble
|
|||
{
|
||||
Data = true,
|
||||
IsSuccess = true
|
||||
});
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -59,12 +59,13 @@ namespace Roadie.Library.Scrobble
|
|||
};
|
||||
}
|
||||
var sw = Stopwatch.StartNew();
|
||||
var track = DbContext.Tracks
|
||||
var track = await DbContext.Tracks
|
||||
.Include(x => x.ReleaseMedia)
|
||||
.Include(x => x.ReleaseMedia.Release)
|
||||
.Include(x => x.ReleaseMedia.Release.Artist)
|
||||
.Include(x => x.TrackArtist)
|
||||
.FirstOrDefault(x => x.RoadieId == scrobble.TrackId);
|
||||
.FirstOrDefaultAsync(x => x.RoadieId == scrobble.TrackId)
|
||||
.ConfigureAwait(false);
|
||||
if (track == null)
|
||||
{
|
||||
return new OperationResult<bool>($"Scrobble: Unable To Find Track [{scrobble.TrackId}]");
|
||||
|
@ -80,8 +81,8 @@ namespace Roadie.Library.Scrobble
|
|||
{
|
||||
if (roadieUser != null)
|
||||
{
|
||||
var user = DbContext.Users.FirstOrDefault(x => x.RoadieId == roadieUser.UserId);
|
||||
userTrack = DbContext.UserTracks.FirstOrDefault(x => x.UserId == user.Id && x.TrackId == track.Id);
|
||||
var user = await DbContext.Users.FirstOrDefaultAsync(x => x.RoadieId == roadieUser.UserId).ConfigureAwait(false);
|
||||
userTrack = await DbContext.UserTracks.FirstOrDefaultAsync(x => x.UserId == user.Id && x.TrackId == track.Id).ConfigureAwait(false);
|
||||
if (userTrack == null)
|
||||
{
|
||||
userTrack = new data.UserTrack(now)
|
||||
|
@ -89,7 +90,7 @@ namespace Roadie.Library.Scrobble
|
|||
UserId = user.Id,
|
||||
TrackId = track.Id
|
||||
};
|
||||
DbContext.UserTracks.Add(userTrack);
|
||||
await DbContext.UserTracks.AddAsync(userTrack).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
userTrack.LastPlayed = now;
|
||||
|
@ -101,20 +102,21 @@ namespace Roadie.Library.Scrobble
|
|||
track.PlayedCount = (track.PlayedCount ?? 0) + 1;
|
||||
track.LastPlayed = now;
|
||||
|
||||
var release = DbContext.Releases
|
||||
var release = await DbContext.Releases
|
||||
.Include(x => x.Artist)
|
||||
.FirstOrDefault(x => x.RoadieId == track.ReleaseMedia.Release.RoadieId);
|
||||
.FirstOrDefaultAsync(x => x.RoadieId == track.ReleaseMedia.Release.RoadieId)
|
||||
.ConfigureAwait(false);
|
||||
release.LastPlayed = now;
|
||||
release.PlayedCount = (release.PlayedCount ?? 0) + 1;
|
||||
|
||||
var artist = DbContext.Artists.FirstOrDefault(x => x.RoadieId == release.Artist.RoadieId);
|
||||
var artist = await DbContext.Artists.FirstOrDefaultAsync(x => x.RoadieId == release.Artist.RoadieId).ConfigureAwait(false);
|
||||
artist.LastPlayed = now;
|
||||
artist.PlayedCount = (artist.PlayedCount ?? 0) + 1;
|
||||
|
||||
data.Artist trackArtist = null;
|
||||
if (track.ArtistId.HasValue)
|
||||
{
|
||||
trackArtist = DbContext.Artists.FirstOrDefault(x => x.Id == track.ArtistId);
|
||||
trackArtist = await DbContext.Artists.FirstOrDefaultAsync(x => x.Id == track.ArtistId).ConfigureAwait(false);
|
||||
if (trackArtist != null)
|
||||
{
|
||||
trackArtist.LastPlayed = now;
|
||||
|
@ -127,7 +129,7 @@ namespace Roadie.Library.Scrobble
|
|||
}
|
||||
}
|
||||
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
CacheManager.ClearRegion(track.CacheRegion);
|
||||
CacheManager.ClearRegion(track.ReleaseMedia.Release.CacheRegion);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Configuration;
|
||||
using Roadie.Library.Data.Context;
|
||||
|
@ -10,7 +11,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using data = Roadie.Library.Data;
|
||||
|
||||
namespace Roadie.Library.Scrobble
|
||||
{
|
||||
|
@ -31,6 +31,18 @@ namespace Roadie.Library.Scrobble
|
|||
|
||||
private IEnumerable<IScrobblerIntegration> Scrobblers { get; }
|
||||
|
||||
public ScrobbleHandler(IRoadieSettings configuration, ILogger logger, IRoadieDbContext dbContext, ICacheManager cacheManager, RoadieScrobbler roadieScrobbler)
|
||||
{
|
||||
Logger = logger;
|
||||
Configuration = configuration;
|
||||
DbContext = dbContext;
|
||||
var scrobblers = new List<IScrobblerIntegration>
|
||||
{
|
||||
roadieScrobbler
|
||||
};
|
||||
Scrobblers = scrobblers;
|
||||
}
|
||||
|
||||
public ScrobbleHandler(IRoadieSettings configuration, ILogger<ScrobbleHandler> logger, IRoadieDbContext dbContext,
|
||||
ICacheManager cacheManager, IHttpEncoder httpEncoder, IHttpContext httpContext,
|
||||
ILastFmHelper lastFmHelper, IRoadieScrobbler roadieScrobbler, ILastFMScrobbler lastFMScrobbler)
|
||||
|
@ -51,16 +63,28 @@ namespace Roadie.Library.Scrobble
|
|||
Scrobblers = scrobblers;
|
||||
}
|
||||
|
||||
public ScrobbleHandler(IRoadieSettings configuration, ILogger logger, IRoadieDbContext dbContext, ICacheManager cacheManager, RoadieScrobbler roadieScrobbler)
|
||||
private async Task<ScrobbleInfo> GetScrobbleInfoDetailsAsync(ScrobbleInfo scrobble)
|
||||
{
|
||||
Logger = logger;
|
||||
Configuration = configuration;
|
||||
DbContext = dbContext;
|
||||
var scrobblers = new List<IScrobblerIntegration>
|
||||
{
|
||||
roadieScrobbler
|
||||
};
|
||||
Scrobblers = scrobblers;
|
||||
var scrobbleInfo = await (from t in DbContext.Tracks
|
||||
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
join r in DbContext.Releases on rm.ReleaseId equals r.Id
|
||||
join a in DbContext.Artists on r.ArtistId equals a.Id
|
||||
where t.RoadieId == scrobble.TrackId
|
||||
select new
|
||||
{
|
||||
ArtistName = a.Name,
|
||||
ReleaseTitle = r.Title,
|
||||
TrackTitle = t.Title,
|
||||
t.TrackNumber,
|
||||
t.Duration
|
||||
}).FirstOrDefaultAsync().ConfigureAwait(false);
|
||||
|
||||
scrobble.ArtistName = scrobbleInfo.ArtistName;
|
||||
scrobble.ReleaseTitle = scrobbleInfo.ReleaseTitle;
|
||||
scrobble.TrackTitle = scrobbleInfo.TrackTitle;
|
||||
scrobble.TrackNumber = scrobbleInfo.TrackNumber.ToString();
|
||||
scrobble.TrackDuration = TimeSpan.FromMilliseconds(scrobbleInfo.Duration ?? 0);
|
||||
return scrobble;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -68,8 +92,11 @@ namespace Roadie.Library.Scrobble
|
|||
/// </summary>
|
||||
public async Task<OperationResult<bool>> NowPlaying(User user, ScrobbleInfo scrobble)
|
||||
{
|
||||
var s = GetScrobbleInfoDetails(scrobble);
|
||||
foreach (var scrobbler in Scrobblers) await Task.Run(async () => await scrobbler.NowPlaying(user, s));
|
||||
var s = await GetScrobbleInfoDetailsAsync(scrobble).ConfigureAwait(false);
|
||||
foreach (var scrobbler in Scrobblers)
|
||||
{
|
||||
await scrobbler.NowPlaying(user, s).ConfigureAwait(false);
|
||||
}
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
Data = true,
|
||||
|
@ -82,10 +109,10 @@ namespace Roadie.Library.Scrobble
|
|||
/// </summary>
|
||||
public async Task<OperationResult<bool>> Scrobble(User user, ScrobbleInfo scrobble)
|
||||
{
|
||||
var s = GetScrobbleInfoDetails(scrobble);
|
||||
var s = await GetScrobbleInfoDetailsAsync(scrobble).ConfigureAwait(false);
|
||||
foreach (var scrobbler in Scrobblers)
|
||||
{
|
||||
await Task.Run(async () => await scrobbler.Scrobble(user, s));
|
||||
await scrobbler.Scrobble(user, s).ConfigureAwait(false);
|
||||
}
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
|
@ -93,29 +120,5 @@ namespace Roadie.Library.Scrobble
|
|||
IsSuccess = true
|
||||
};
|
||||
}
|
||||
|
||||
private ScrobbleInfo GetScrobbleInfoDetails(ScrobbleInfo scrobble)
|
||||
{
|
||||
var scrobbleInfo = (from t in DbContext.Tracks
|
||||
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
join r in DbContext.Releases on rm.ReleaseId equals r.Id
|
||||
join a in DbContext.Artists on r.ArtistId equals a.Id
|
||||
where t.RoadieId == scrobble.TrackId
|
||||
select new
|
||||
{
|
||||
ArtistName = a.Name,
|
||||
ReleaseTitle = r.Title,
|
||||
TrackTitle = t.Title,
|
||||
t.TrackNumber,
|
||||
t.Duration
|
||||
}).FirstOrDefault();
|
||||
|
||||
scrobble.ArtistName = scrobbleInfo.ArtistName;
|
||||
scrobble.ReleaseTitle = scrobbleInfo.ReleaseTitle;
|
||||
scrobble.TrackTitle = scrobbleInfo.TrackTitle;
|
||||
scrobble.TrackNumber = scrobbleInfo.TrackNumber.ToString();
|
||||
scrobble.TrackDuration = TimeSpan.FromMilliseconds(scrobbleInfo.Duration ?? 0);
|
||||
return scrobble;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -44,11 +44,11 @@ namespace Roadie.Library.SearchEngines.Imaging
|
|||
return request;
|
||||
}
|
||||
|
||||
public override async Task<IEnumerable<ImageSearchResult>> PerformImageSearch(string query, int resultsCount)
|
||||
public override async Task<IEnumerable<ImageSearchResult>> PerformImageSearchAsync(string query, int resultsCount)
|
||||
{
|
||||
var request = BuildRequest(query, resultsCount);
|
||||
|
||||
var response = await _client.ExecuteAsync<BingImageResult>(request);
|
||||
var response = await _client.ExecuteAsync<BingImageResult>(request).ConfigureAwait(false);
|
||||
|
||||
if (response.StatusCode == HttpStatusCode.Unauthorized)
|
||||
throw new AuthenticationException("Api Key is not correct");
|
||||
|
|
|
@ -10,6 +10,6 @@ namespace Roadie.Library.SearchEngines.Imaging
|
|||
|
||||
RestRequest BuildRequest(string query, int resultsCount);
|
||||
|
||||
Task<IEnumerable<ImageSearchResult>> PerformImageSearch(string query, int resultsCount);
|
||||
Task<IEnumerable<ImageSearchResult>> PerformImageSearchAsync(string query, int resultsCount);
|
||||
}
|
||||
}
|
|
@ -25,14 +25,14 @@ namespace Roadie.Library.SearchEngines.Imaging
|
|||
|
||||
public override bool IsEnabled => Configuration.Integrations.ITunesProviderEnabled;
|
||||
|
||||
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearch(string query, int resultsCount)
|
||||
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearchAsync(string query, int resultsCount)
|
||||
{
|
||||
ArtistSearchResult data = null;
|
||||
|
||||
try
|
||||
{
|
||||
var request = BuildRequest(query, 1, "musicArtist");
|
||||
var response = await _client.ExecuteAsync<ITunesSearchResult>(request);
|
||||
var response = await _client.ExecuteAsync<ITunesSearchResult>(request).ConfigureAwait(false);
|
||||
if (response.ResponseStatus == ResponseStatus.Error)
|
||||
{
|
||||
if (response.StatusCode == HttpStatusCode.Unauthorized)
|
||||
|
@ -79,7 +79,7 @@ namespace Roadie.Library.SearchEngines.Imaging
|
|||
|
||||
#pragma warning disable CS1998
|
||||
|
||||
public override async Task<IEnumerable<ImageSearchResult>> PerformImageSearch(string query, int resultsCount)
|
||||
public override async Task<IEnumerable<ImageSearchResult>> PerformImageSearchAsync(string query, int resultsCount)
|
||||
{
|
||||
var request = BuildRequest(query, resultsCount);
|
||||
ImageSearchResult[] result = null;
|
||||
|
@ -116,7 +116,7 @@ namespace Roadie.Library.SearchEngines.Imaging
|
|||
public async Task<OperationResult<IEnumerable<ReleaseSearchResult>>> PerformReleaseSearch(string artistName, string query, int resultsCount)
|
||||
{
|
||||
var request = BuildRequest(query, 1, "album");
|
||||
var response = await _client.ExecuteAsync<ITunesSearchResult>(request);
|
||||
var response = await _client.ExecuteAsync<ITunesSearchResult>(request).ConfigureAwait(false);
|
||||
if (response.ResponseStatus == ResponseStatus.Error)
|
||||
{
|
||||
if (response.StatusCode == HttpStatusCode.Unauthorized)
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace Roadie.Library.SearchEngines.Imaging
|
|||
|
||||
public abstract RestRequest BuildRequest(string query, int resultsCount);
|
||||
|
||||
public virtual Task<IEnumerable<ImageSearchResult>> PerformImageSearch(string query, int resultsCount)
|
||||
public virtual Task<IEnumerable<ImageSearchResult>> PerformImageSearchAsync(string query, int resultsCount)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace Roadie.Library.SearchEngines.Imaging
|
|||
}
|
||||
if (Configuration.Integrations.BingImageSearchEngineEnabled)
|
||||
{
|
||||
var bingResults = await _bingSearchEngine.PerformImageSearch(query, count);
|
||||
var bingResults = await _bingSearchEngine.PerformImageSearchAsync(query, count).ConfigureAwait(false);
|
||||
if (bingResults != null)
|
||||
{
|
||||
result.AddRange(bingResults);
|
||||
|
@ -45,7 +45,7 @@ namespace Roadie.Library.SearchEngines.Imaging
|
|||
}
|
||||
if (Configuration.Integrations.ITunesProviderEnabled)
|
||||
{
|
||||
var iTunesResults = await _itunesSearchEngine.PerformImageSearch(query, count);
|
||||
var iTunesResults = await _itunesSearchEngine.PerformImageSearchAsync(query, count).ConfigureAwait(false);
|
||||
if (iTunesResults != null)
|
||||
{
|
||||
result.AddRange(iTunesResults);
|
||||
|
|
|
@ -103,11 +103,11 @@ namespace Roadie.Library.MetaData.Audio
|
|||
if (!result.IsValid)
|
||||
{
|
||||
tagSources.Add("MusicBrainz");
|
||||
result = await ParseFromMusicBrainz(result);
|
||||
result = await ParseFromMusicBrainzAsync(result).ConfigureAwait(false);
|
||||
if (!result.IsValid)
|
||||
{
|
||||
tagSources.Add("LastFm");
|
||||
result = await GetFromLastFmIntegration(result);
|
||||
result = await GetFromLastFmIntegrationAsync(result).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,15 +183,18 @@ namespace Roadie.Library.MetaData.Audio
|
|||
return result;
|
||||
}
|
||||
|
||||
private async Task<AudioMetaData> GetFromLastFmIntegration(AudioMetaData metaData)
|
||||
private async Task<AudioMetaData> GetFromLastFmIntegrationAsync(AudioMetaData metaData)
|
||||
{
|
||||
var artistName = metaData.Artist;
|
||||
var ReleaseName = metaData.Release;
|
||||
|
||||
if (DoParseFromLastFM)
|
||||
{
|
||||
if (string.IsNullOrEmpty(artistName) && string.IsNullOrEmpty(ReleaseName)) return metaData;
|
||||
var lastFmReleaseTracks = await LastFmHelper.TracksForRelease(artistName, ReleaseName);
|
||||
if (string.IsNullOrEmpty(artistName) && string.IsNullOrEmpty(ReleaseName))
|
||||
{
|
||||
return metaData;
|
||||
}
|
||||
var lastFmReleaseTracks = await LastFmHelper.TracksForReleaseAsync(artistName, ReleaseName).ConfigureAwait(false);
|
||||
if (lastFmReleaseTracks != null)
|
||||
{
|
||||
var lastFmReleaseTrack = lastFmReleaseTracks.FirstOrDefault(x =>
|
||||
|
@ -224,12 +227,11 @@ namespace Roadie.Library.MetaData.Audio
|
|||
return metaData;
|
||||
}
|
||||
|
||||
private async Task<AudioMetaData> ParseFromMusicBrainz(AudioMetaData metaData)
|
||||
private async Task<AudioMetaData> ParseFromMusicBrainzAsync(AudioMetaData metaData)
|
||||
{
|
||||
if (DoParseFromMusicBrainz)
|
||||
{
|
||||
var musicBrainzReleaseTracks =
|
||||
await MusicBrainzProvider.MusicBrainzReleaseTracks(metaData.Artist, metaData.Release);
|
||||
var musicBrainzReleaseTracks = await MusicBrainzProvider.MusicBrainzReleaseTracksAsync(metaData.Artist, metaData.Release).ConfigureAwait(false);
|
||||
if (musicBrainzReleaseTracks != null)
|
||||
{
|
||||
var musicBrainzReleaseTrack = musicBrainzReleaseTracks.FirstOrDefault(x =>
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
|||
_apiKey = configuration.Integrations.ApiKeys.FirstOrDefault(x => x.ApiName == "DiscogsConsumerKey") ?? new ApiKey();
|
||||
}
|
||||
|
||||
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearch(string query, int resultsCount)
|
||||
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearchAsync(string query, int resultsCount)
|
||||
{
|
||||
ArtistSearchResult data = null;
|
||||
try
|
||||
|
@ -40,7 +40,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
|||
UserAgent = WebHelper.UserAgent
|
||||
};
|
||||
|
||||
var response = await client.ExecuteAsync<DiscogsResult>(request);
|
||||
var response = await client.ExecuteAsync<DiscogsResult>(request).ConfigureAwait(false);
|
||||
|
||||
if (response.ResponseStatus == ResponseStatus.Error)
|
||||
{
|
||||
|
@ -61,7 +61,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
|||
{
|
||||
UserAgent = WebHelper.UserAgent
|
||||
};
|
||||
var artistResponse = await c2.ExecuteTaskAsync<DiscogArtistResponse>(request);
|
||||
var artistResponse = await c2.ExecuteTaskAsync<DiscogArtistResponse>(request).ConfigureAwait(false);
|
||||
var artist = artistResponse.Data;
|
||||
if (artist != null)
|
||||
{
|
||||
|
@ -99,7 +99,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
|||
}
|
||||
}
|
||||
return null;
|
||||
}, "uri:metadata");
|
||||
}, "uri:metadata").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -126,7 +126,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
|||
var client = new RestClient("https://api.discogs.com/database");
|
||||
client.UserAgent = WebHelper.UserAgent;
|
||||
|
||||
var response = await client.ExecuteAsync<DiscogsResult>(request);
|
||||
var response = await client.ExecuteAsync<DiscogsResult>(request).ConfigureAwait(false);
|
||||
|
||||
if (response.ResponseStatus == ResponseStatus.Error)
|
||||
{
|
||||
|
@ -144,7 +144,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
|||
request = BuildLabelRequest(responseData.id);
|
||||
var c2 = new RestClient("https://api.discogs.com/");
|
||||
c2.UserAgent = WebHelper.UserAgent;
|
||||
var labelResponse = await c2.ExecuteTaskAsync<DiscogsLabelResult>(request);
|
||||
var labelResponse = await c2.ExecuteTaskAsync<DiscogsLabelResult>(request).ConfigureAwait(false);
|
||||
var label = labelResponse.Data;
|
||||
if (label != null)
|
||||
{
|
||||
|
@ -157,7 +157,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
|||
if (label.images != null)
|
||||
{
|
||||
images.AddRange(label.images.Where(x => x.type != "primary").Select(x => x.uri));
|
||||
var primaryImage = label.images.FirstOrDefault(x => x.type == "primary");
|
||||
var primaryImage = label.images.Find(x => x.type == "primary");
|
||||
if (primaryImage != null) labelThumbnailUrl = primaryImage.uri;
|
||||
if (string.IsNullOrEmpty(labelThumbnailUrl))
|
||||
labelThumbnailUrl = label.images.First(x => !string.IsNullOrEmpty(x.uri)).uri;
|
||||
|
@ -176,7 +176,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
|||
}
|
||||
}
|
||||
return null;
|
||||
}, "uri:metadata");
|
||||
}, "uri:metadata").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -207,7 +207,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
|||
Timeout = SafeParser.ToNumber<int>(Configuration.Integrations.DiscogsTimeout)
|
||||
};
|
||||
|
||||
var response = await client.ExecuteAsync<DiscogsReleaseSearchResult>(request);
|
||||
var response = await client.ExecuteAsync<DiscogsReleaseSearchResult>(request).ConfigureAwait(false);
|
||||
if (response?.ResponseStatus == null || response.ResponseStatus == ResponseStatus.Error)
|
||||
{
|
||||
if (response.StatusCode == HttpStatusCode.Unauthorized)
|
||||
|
@ -225,7 +225,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
|||
{
|
||||
UserAgent = WebHelper.UserAgent
|
||||
};
|
||||
var releaseResult = await c2.ExecuteTaskAsync<DiscogReleaseDetail>(request);
|
||||
var releaseResult = await c2.ExecuteTaskAsync<DiscogReleaseDetail>(request).ConfigureAwait(false);
|
||||
var release = releaseResult?.Data;
|
||||
if (release != null)
|
||||
{
|
||||
|
@ -296,7 +296,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
|||
|
||||
if (release.identifiers != null)
|
||||
{
|
||||
var barcode = release.identifiers.FirstOrDefault(x => (x.type ?? string.Empty) == "Barcode");
|
||||
var barcode = release.identifiers.Find(x => (x.type ?? string.Empty) == "Barcode");
|
||||
if (barcode?.value != null)
|
||||
{
|
||||
data.Tags = new[] { "barcode:" + barcode.value };
|
||||
|
@ -305,7 +305,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Discogs
|
|||
}
|
||||
}
|
||||
return null;
|
||||
}, "uri:metadata");
|
||||
}, "uri:metadata").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
@ -7,6 +7,6 @@ namespace Roadie.Library.SearchEngines.MetaData
|
|||
{
|
||||
bool IsEnabled { get; }
|
||||
|
||||
Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearch(string query, int resultsCount);
|
||||
Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearchAsync(string query, int resultsCount);
|
||||
}
|
||||
}
|
|
@ -10,6 +10,6 @@ namespace Roadie.Library.MetaData.LastFm
|
|||
{
|
||||
Task<OperationResult<string>> GetSessionKeyForUserToken(string token);
|
||||
|
||||
Task<IEnumerable<AudioMetaData>> TracksForRelease(string artist, string Release);
|
||||
Task<IEnumerable<AudioMetaData>> TracksForReleaseAsync(string artist, string Release);
|
||||
}
|
||||
}
|
|
@ -86,7 +86,7 @@ namespace Roadie.Library.MetaData.LastFm
|
|||
};
|
||||
var request = new RestRequest(Method.GET);
|
||||
var client = new RestClient(BuildUrl("auth.getSession", parameters));
|
||||
var responseXML = await client.ExecuteAsync<string>(request);
|
||||
var responseXML = await client.ExecuteAsync<string>(request).ConfigureAwait(false);
|
||||
var doc = new XmlDocument();
|
||||
doc.LoadXml(responseXML.Content);
|
||||
var sessionKey = doc.GetElementsByTagName("key")[0].InnerText;
|
||||
|
@ -139,7 +139,7 @@ namespace Roadie.Library.MetaData.LastFm
|
|||
var xp = GetResponseAsXml(request);
|
||||
Logger.LogTrace($"LastFmHelper: RoadieUser `{roadieUser}` NowPlaying `{scrobble}` LastFmResult [{xp.InnerXml}]");
|
||||
result = true;
|
||||
});
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -153,7 +153,7 @@ namespace Roadie.Library.MetaData.LastFm
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearch(string query, int resultsCount)
|
||||
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearchAsync(string query, int resultsCount)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -163,7 +163,7 @@ namespace Roadie.Library.MetaData.LastFm
|
|||
Logger.LogTrace("LastFmHelper:PerformArtistSearch:{0}", query);
|
||||
var auth = new LastAuth(ApiKey.Key, ApiKey.KeySecret);
|
||||
var albumApi = new ArtistApi(auth);
|
||||
var response = await albumApi.GetInfoAsync(query);
|
||||
var response = await albumApi.GetInfoAsync(query).ConfigureAwait(false);
|
||||
if (!response.Success)
|
||||
{
|
||||
return null;
|
||||
|
@ -183,7 +183,7 @@ namespace Roadie.Library.MetaData.LastFm
|
|||
result.Urls = new[] { lastFmArtist.Url.ToString() };
|
||||
}
|
||||
return result;
|
||||
}, "uri:metadata");
|
||||
}, "uri:metadata").ConfigureAwait(false);
|
||||
return new OperationResult<IEnumerable<ArtistSearchResult>>
|
||||
{
|
||||
IsSuccess = data != null,
|
||||
|
@ -205,7 +205,7 @@ namespace Roadie.Library.MetaData.LastFm
|
|||
{
|
||||
var request = new RestRequest(Method.GET);
|
||||
var client = new RestClient(string.Format("http://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key={0}&artist={1}&album={2}&format=xml", ApiKey.Key, artistName, query));
|
||||
var responseData = await client.ExecuteAsync<lfm>(request);
|
||||
var responseData = await client.ExecuteAsync<lfm>(request).ConfigureAwait(false);
|
||||
|
||||
ReleaseSearchResult result = null;
|
||||
|
||||
|
@ -246,7 +246,7 @@ namespace Roadie.Library.MetaData.LastFm
|
|||
}
|
||||
}
|
||||
return result;
|
||||
}, "uri:metadata");
|
||||
}, "uri:metadata").ConfigureAwait(false);
|
||||
return new OperationResult<IEnumerable<ReleaseSearchResult>>
|
||||
{
|
||||
IsSuccess = data != null,
|
||||
|
@ -269,7 +269,7 @@ namespace Roadie.Library.MetaData.LastFm
|
|||
// If less than half of duration then create a NowPlaying
|
||||
if (scrobble.ElapsedTimeOfTrackPlayed.TotalMinutes < 4 ||
|
||||
scrobble.ElapsedTimeOfTrackPlayed.TotalSeconds < scrobble.TrackDuration.TotalSeconds / 2)
|
||||
return await NowPlaying(roadieUser, scrobble);
|
||||
return await NowPlaying(roadieUser, scrobble).ConfigureAwait(false);
|
||||
|
||||
var user = DbContext.Users.FirstOrDefault(x => x.RoadieId == roadieUser.UserId);
|
||||
|
||||
|
@ -319,7 +319,7 @@ namespace Roadie.Library.MetaData.LastFm
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<AudioMetaData>> TracksForRelease(string artist, string Release)
|
||||
public async Task<IEnumerable<AudioMetaData>> TracksForReleaseAsync(string artist, string Release)
|
||||
{
|
||||
if (string.IsNullOrEmpty(artist) || string.IsNullOrEmpty(Release)) return null;
|
||||
var result = new List<AudioMetaData>();
|
||||
|
@ -333,7 +333,7 @@ namespace Roadie.Library.MetaData.LastFm
|
|||
{
|
||||
var auth = new LastAuth(ApiKey.Key, ApiKey.KeySecret);
|
||||
var albumApi = new AlbumApi(auth); // this is an unauthenticated call to the API
|
||||
var response = await albumApi.GetInfoAsync(artist, Release);
|
||||
var response = await albumApi.GetInfoAsync(artist, Release).ConfigureAwait(false);
|
||||
releaseInfo = response.Content;
|
||||
if (releaseInfo != null) CacheManager.Add(responseCacheKey, releaseInfo);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,6 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
|||
{
|
||||
public interface IMusicBrainzProvider : IArtistSearchEngine, IReleaseSearchEngine
|
||||
{
|
||||
Task<IEnumerable<AudioMetaData>> MusicBrainzReleaseTracks(string artistName, string releaseTitle);
|
||||
Task<IEnumerable<AudioMetaData>> MusicBrainzReleaseTracksAsync(string artistName, string releaseTitle);
|
||||
}
|
||||
}
|
|
@ -23,14 +23,14 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
|||
Repository = new MusicBrainzRepository(configuration, logger);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<AudioMetaData>> MusicBrainzReleaseTracks(string artistName, string releaseTitle)
|
||||
public async Task<IEnumerable<AudioMetaData>> MusicBrainzReleaseTracksAsync(string artistName, string releaseTitle)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(artistName) && string.IsNullOrEmpty(releaseTitle)) return null;
|
||||
// Find the Artist
|
||||
var artistCacheKey = string.Format("uri:musicbrainz:artist:{0}", artistName);
|
||||
var artistSearch = await PerformArtistSearch(artistName, 1);
|
||||
var artistSearch = await PerformArtistSearchAsync(artistName, 1).ConfigureAwait(false);
|
||||
if (!artistSearch.IsSuccess) return null;
|
||||
var artist = artistSearch.Data.First();
|
||||
|
||||
|
@ -56,8 +56,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
|||
}
|
||||
|
||||
// Now get The Release Details
|
||||
release = await MusicBrainzRequestHelper.GetAsync<Release>(
|
||||
MusicBrainzRequestHelper.CreateLookupUrl("release", ReleaseResult.MusicBrainzId, "recordings"));
|
||||
release = await MusicBrainzRequestHelper.GetAsync<Release>(MusicBrainzRequestHelper.CreateLookupUrl("release", ReleaseResult.MusicBrainzId, "recordings")).ConfigureAwait(false);
|
||||
if (release == null) return null;
|
||||
CacheManager.Add(ReleaseCacheKey, release);
|
||||
}
|
||||
|
@ -113,12 +112,12 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
|||
return null;
|
||||
}
|
||||
|
||||
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearch(string query, int resultsCount)
|
||||
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearchAsync(string query, int resultsCount)
|
||||
{
|
||||
ArtistSearchResult result = null;
|
||||
|
||||
Logger.LogTrace("MusicBrainzProvider:PerformArtistSearch:{0}", query);
|
||||
var a = await Repository.ArtistByName(query, resultsCount);
|
||||
var a = await Repository.ArtistByNameAsync(query, resultsCount).ConfigureAwait(false);
|
||||
if (a != null)
|
||||
{
|
||||
var imageUrls = a.relations?.Where(x => x.type.Equals("image", StringComparison.OrdinalIgnoreCase)).Select(x => x.url.resource).Distinct().ToArray();
|
||||
|
@ -174,7 +173,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
|||
ReleaseSearchResult result = null;
|
||||
try
|
||||
{
|
||||
var releaseInfosForArtist = await ReleasesForArtist(artistName);
|
||||
var releaseInfosForArtist = await ReleasesForArtistAsync(artistName).ConfigureAwait(false);
|
||||
if (releaseInfosForArtist != null)
|
||||
{
|
||||
var r = releaseInfosForArtist.FirstOrDefault(x => x.title.Equals(query, StringComparison.OrdinalIgnoreCase));
|
||||
|
@ -208,7 +207,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
|||
ReleaseGenres = r.releasegroup?.genres?.Select(x => x.name).Distinct().ToArray(),
|
||||
ReleaseType = r.releasegroup?.primarytype
|
||||
};
|
||||
var coverUrls = await CoverArtForMusicBrainzReleaseById(r.id);
|
||||
var coverUrls = await CoverArtForMusicBrainzReleaseByIdAsync(r.id).ConfigureAwait(false);
|
||||
if (coverUrls != null)
|
||||
{
|
||||
var frontCover = coverUrls.images.FirstOrDefault(i => i.front);
|
||||
|
@ -296,16 +295,13 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
|||
};
|
||||
}
|
||||
|
||||
private async Task<CoverArtArchivesResult> CoverArtForMusicBrainzReleaseById(string musicBrainzId)
|
||||
{
|
||||
return await MusicBrainzRequestHelper.GetAsync<CoverArtArchivesResult>(MusicBrainzRequestHelper.CreateCoverArtReleaseUrl(musicBrainzId));
|
||||
}
|
||||
private Task<CoverArtArchivesResult> CoverArtForMusicBrainzReleaseByIdAsync(string musicBrainzId) => MusicBrainzRequestHelper.GetAsync<CoverArtArchivesResult>(MusicBrainzRequestHelper.CreateCoverArtReleaseUrl(musicBrainzId));
|
||||
|
||||
private async Task<IEnumerable<Release>> ReleasesForArtist(string artist, string artistMusicBrainzId = null)
|
||||
private async Task<IEnumerable<Release>> ReleasesForArtistAsync(string artist, string artistMusicBrainzId = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(artistMusicBrainzId))
|
||||
{
|
||||
var artistSearch = await PerformArtistSearch(artist, 1);
|
||||
var artistSearch = await PerformArtistSearchAsync(artist, 1).ConfigureAwait(false);
|
||||
if (artistSearch == null || !artistSearch.IsSuccess)
|
||||
{
|
||||
return null;
|
||||
|
@ -317,7 +313,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
|||
}
|
||||
artistMusicBrainzId = mbArtist.MusicBrainzId;
|
||||
}
|
||||
return await Repository.ReleasesForArtist(artistMusicBrainzId);
|
||||
return await Repository.ReleasesForArtist(artistMusicBrainzId).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,6 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Roadie.Library.MetaData.MusicBrainz
|
||||
|
@ -21,7 +20,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
|||
Logger = logger;
|
||||
var location = System.Reflection.Assembly.GetEntryAssembly().Location;
|
||||
var directory = configuration.SearchEngineReposFolder ?? Path.Combine(System.IO.Path.GetDirectoryName(location), "SearchEngineRepos");
|
||||
if(!Directory.Exists(directory))
|
||||
if (!Directory.Exists(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
@ -33,7 +32,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
|||
/// </summary>
|
||||
/// <param name="name">Query name of Artist</param>
|
||||
/// <param name="resultsCount">Maximum Number of Results</param>
|
||||
public async Task<Artist> ArtistByName(string name, int? resultsCount = null)
|
||||
public async Task<Artist> ArtistByNameAsync(string name, int? resultsCount = null)
|
||||
{
|
||||
Artist result = null;
|
||||
|
||||
|
@ -48,14 +47,14 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
|||
if (artist == null)
|
||||
{
|
||||
// Perform a query to get the MbId for the Name
|
||||
var artistResult = await MusicBrainzRequestHelper.GetAsync<ArtistResult>(MusicBrainzRequestHelper.CreateSearchTemplate("artist", name, resultsCount ?? 1, 0));
|
||||
var artistResult = await MusicBrainzRequestHelper.GetAsync<ArtistResult>(MusicBrainzRequestHelper.CreateSearchTemplate("artist", name, resultsCount ?? 1, 0)).ConfigureAwait(false);
|
||||
if (artistResult == null || artistResult.artists == null || !artistResult.artists.Any() || artistResult.count < 1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var mbId = artistResult.artists.First().id;
|
||||
// Now perform a detail request to get the details by the MbId
|
||||
result = await MusicBrainzRequestHelper.GetAsync<Artist>(MusicBrainzRequestHelper.CreateLookupUrl("artist", mbId, "aliases+tags+genres+url-rels"));
|
||||
result = await MusicBrainzRequestHelper.GetAsync<Artist>(MusicBrainzRequestHelper.CreateLookupUrl("artist", mbId, "aliases+tags+genres+url-rels")).ConfigureAwait(false);
|
||||
if (result != null)
|
||||
{
|
||||
col.Insert(new RepositoryArtist
|
||||
|
@ -99,13 +98,13 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
|||
col.EnsureIndex(x => x.ArtistMbId);
|
||||
col.EnsureIndex(x => x.Release.id);
|
||||
var releases = col.Find(x => x.ArtistMbId == artistMbId);
|
||||
if(releases == null || !releases.Any())
|
||||
if (releases == null || !releases.Any())
|
||||
{
|
||||
// Query to get collection of Releases for Artist
|
||||
var pageSize = 50;
|
||||
var page = 0;
|
||||
var url = MusicBrainzRequestHelper.CreateArtistBrowseTemplate(artistMbId, pageSize, 0);
|
||||
var mbReleaseBrowseResult = await MusicBrainzRequestHelper.GetAsync<ReleaseBrowseResult>(url);
|
||||
var mbReleaseBrowseResult = await MusicBrainzRequestHelper.GetAsync<ReleaseBrowseResult>(url).ConfigureAwait(false);
|
||||
var totalReleases = mbReleaseBrowseResult != null ? mbReleaseBrowseResult.releasecount : 0;
|
||||
var totalPages = Math.Ceiling((decimal)totalReleases / pageSize);
|
||||
var fetchResult = new List<Release>();
|
||||
|
@ -116,7 +115,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
|||
fetchResult.AddRange(mbReleaseBrowseResult.releases.Where(x => !string.IsNullOrEmpty(x.date)));
|
||||
}
|
||||
page++;
|
||||
mbReleaseBrowseResult = await MusicBrainzRequestHelper.GetAsync<ReleaseBrowseResult>(MusicBrainzRequestHelper.CreateArtistBrowseTemplate(artistMbId, pageSize, pageSize * page));
|
||||
mbReleaseBrowseResult = await MusicBrainzRequestHelper.GetAsync<ReleaseBrowseResult>(MusicBrainzRequestHelper.CreateArtistBrowseTemplate(artistMbId, pageSize, pageSize * page)).ConfigureAwait(false);
|
||||
} while (page < totalPages);
|
||||
col.InsertBulk(fetchResult.Select(x => new RepositoryRelease
|
||||
{
|
||||
|
@ -129,7 +128,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
|||
{
|
||||
results = releases.Select(x => x.Release).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace Roadie.Library.MetaData.MusicBrainz
|
|||
using (var webClient = new WebClient())
|
||||
{
|
||||
webClient.Headers.Add("user-agent", WebHelper.UserAgent);
|
||||
result = JsonConvert.DeserializeObject<T>(await webClient.DownloadStringTaskAsync(new Uri(url)));
|
||||
result = JsonConvert.DeserializeObject<T>(await webClient.DownloadStringTaskAsync(new Uri(url)).ConfigureAwait(false));
|
||||
}
|
||||
}
|
||||
catch (WebException ex)
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Spotify
|
|||
{
|
||||
}
|
||||
|
||||
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearch(string query,
|
||||
public async Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearchAsync(string query,
|
||||
int resultsCount)
|
||||
{
|
||||
ArtistSearchResult data = null;
|
||||
|
@ -37,7 +37,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Spotify
|
|||
var client = new RestClient("http://api.spotify.com/v1");
|
||||
client.UserAgent = WebHelper.UserAgent;
|
||||
|
||||
var response = await client.ExecuteAsync<SpotifyResult>(request);
|
||||
var response = await client.ExecuteAsync<SpotifyResult>(request).ConfigureAwait(false);
|
||||
|
||||
if (response.ResponseStatus == ResponseStatus.Error)
|
||||
{
|
||||
|
@ -79,7 +79,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Spotify
|
|||
public async Task<OperationResult<IEnumerable<ReleaseSearchResult>>> PerformReleaseSearch(string artistName,
|
||||
string query, int resultsCount)
|
||||
{
|
||||
var artistResult = await PerformArtistSearch(artistName, resultsCount);
|
||||
var artistResult = await PerformArtistSearchAsync(artistName, resultsCount).ConfigureAwait(false);
|
||||
if (!artistResult.IsSuccess) return new OperationResult<IEnumerable<ReleaseSearchResult>>();
|
||||
try
|
||||
{
|
||||
|
@ -88,7 +88,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Spotify
|
|||
|
||||
ReleaseSearchResult result = null;
|
||||
|
||||
var response = await AlbumsForArtist(artistResult.Data.First().SpotifyId);
|
||||
var response = await AlbumsForArtistAsync(artistResult.Data.First().SpotifyId).ConfigureAwait(false);
|
||||
if (response != null && response.items != null)
|
||||
{
|
||||
string foundByAlternateName = null;
|
||||
|
@ -104,7 +104,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Spotify
|
|||
}
|
||||
|
||||
var client = new RestClient(string.Format("http://api.spotify.com/v1/albums/{0}", spotifyAlbum.id));
|
||||
var albumResult = await client.ExecuteAsync<AlbumResult>(request);
|
||||
var albumResult = await client.ExecuteAsync<AlbumResult>(request).ConfigureAwait(false);
|
||||
if (albumResult != null && albumResult.Data != null)
|
||||
{
|
||||
var sa = albumResult.Data;
|
||||
|
@ -203,7 +203,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Spotify
|
|||
return new OperationResult<IEnumerable<ReleaseSearchResult>>();
|
||||
}
|
||||
|
||||
private async Task<Albums> AlbumsForArtist(string spotifyId)
|
||||
private async Task<Albums> AlbumsForArtistAsync(string spotifyId)
|
||||
{
|
||||
var cacheKey = string.Format("uri:spotify:AlbumsForArtist:{0}", spotifyId);
|
||||
var result = CacheManager.Get<Albums>(cacheKey);
|
||||
|
@ -213,7 +213,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Spotify
|
|||
var client = new RestClient(string.Format(
|
||||
"http://api.spotify.com/v1/artists/{0}/albums?offset=0&limit=25&album_type=album&market=US",
|
||||
spotifyId));
|
||||
var artistAlbumsResponse = await client.ExecuteAsync<Albums>(request);
|
||||
var artistAlbumsResponse = await client.ExecuteAsync<Albums>(request).ConfigureAwait(false);
|
||||
result = artistAlbumsResponse != null && artistAlbumsResponse.Data != null
|
||||
? artistAlbumsResponse.Data
|
||||
: null;
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace Roadie.Library.SearchEngines.MetaData.Wikipedia
|
|||
HttpEncoder = httpEncoder;
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearch(string query, int resultsCount)
|
||||
public Task<OperationResult<IEnumerable<ArtistSearchResult>>> PerformArtistSearchAsync(string query, int resultsCount)
|
||||
{
|
||||
if(string.IsNullOrEmpty(query) || resultsCount == 0)
|
||||
{
|
||||
|
|
|
@ -66,7 +66,7 @@ namespace Roadie.Library.Utility
|
|||
using (var webClient = new WebClient())
|
||||
{
|
||||
webClient.Headers.Add("user-agent", UserAgent);
|
||||
imageBytes = await webClient.DownloadDataTaskAsync(new Uri(url));
|
||||
imageBytes = await webClient.DownloadDataTaskAsync(new Uri(url)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using Mapster;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
@ -29,9 +28,10 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public class AdminService : ServiceBase, IAdminService
|
||||
{
|
||||
protected IHubContext<ScanActivityHub> ScanActivityHub { get; }
|
||||
private IArtistLookupEngine ArtistLookupEngine { get; }
|
||||
|
||||
private IArtistService ArtistService { get; }
|
||||
private IBookmarkService BookmarkService { get; }
|
||||
|
||||
private IEventMessageLogger EventMessageLogger { get; }
|
||||
|
||||
|
@ -39,16 +39,16 @@ namespace Roadie.Api.Services
|
|||
|
||||
private IGenreService GenreService { get; }
|
||||
private ILabelService LabelService { get; }
|
||||
private IArtistLookupEngine ArtistLookupEngine { get; }
|
||||
private IReleaseLookupEngine ReleaseLookupEngine { get; }
|
||||
private IBookmarkService BookmarkService { get; }
|
||||
|
||||
private IReleaseService ReleaseService { get; }
|
||||
|
||||
protected IHubContext<ScanActivityHub> ScanActivityHub { get; }
|
||||
|
||||
public AdminService(IRoadieSettings configuration, IHttpEncoder httpEncoder, IHttpContext httpContext,
|
||||
IRoadieDbContext context, ICacheManager cacheManager, ILogger<ArtistService> logger,
|
||||
IHubContext<ScanActivityHub> scanActivityHub, IFileDirectoryProcessorService fileDirectoryProcessorService, IArtistService artistService,
|
||||
IReleaseService releaseService, IArtistLookupEngine artistLookupEngine, IReleaseLookupEngine releaseLookupEngine,
|
||||
IReleaseService releaseService, IArtistLookupEngine artistLookupEngine, IReleaseLookupEngine releaseLookupEngine,
|
||||
ILabelService labelService, IGenreService genreService, IBookmarkService bookmarkService
|
||||
)
|
||||
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
|
||||
|
@ -67,21 +67,94 @@ namespace Roadie.Api.Services
|
|||
BookmarkService = bookmarkService;
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteArtist(User user, Guid artistId, bool deleteFolder)
|
||||
private void EventMessageLogger_Messages(object sender, EventMessage e) => Task.WaitAll(LogAndPublishAsync(e.Message, e.Level));
|
||||
|
||||
private async Task LogAndPublishAsync(string message, LogLevel level = LogLevel.Trace)
|
||||
{
|
||||
switch (level)
|
||||
{
|
||||
case LogLevel.Trace:
|
||||
Logger.LogTrace(message);
|
||||
break;
|
||||
|
||||
case LogLevel.Debug:
|
||||
Logger.LogDebug(message);
|
||||
break;
|
||||
|
||||
case LogLevel.Information:
|
||||
Logger.LogInformation(message);
|
||||
break;
|
||||
|
||||
case LogLevel.Warning:
|
||||
Logger.LogWarning(message);
|
||||
break;
|
||||
|
||||
case LogLevel.Critical:
|
||||
Logger.LogCritical(message);
|
||||
break;
|
||||
}
|
||||
|
||||
await ScanActivityHub.Clients.All.SendAsync("SendSystemActivityAsync", message).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task<OperationResult<bool>> ScanFolderAsync(User user, DirectoryInfo d, bool isReadOnly, bool doDeleteFiles = true)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
long processedFiles = 0;
|
||||
await LogAndPublishAsync($"** Processing Folder: [{d.FullName}]").ConfigureAwait(false);
|
||||
|
||||
long processedFolders = 0;
|
||||
foreach (var folder in Directory.EnumerateDirectories(d.FullName).ToArray())
|
||||
{
|
||||
var directoryProcessResult = await FileDirectoryProcessorService.ProcessAsync(user: user,
|
||||
folder: new DirectoryInfo(folder),
|
||||
doJustInfo: isReadOnly,
|
||||
doDeleteFiles: doDeleteFiles).ConfigureAwait(false);
|
||||
processedFolders++;
|
||||
processedFiles += SafeParser.ToNumber<int>(directoryProcessResult.AdditionalData["ProcessedFiles"]);
|
||||
}
|
||||
CacheManager.Clear();
|
||||
if (!isReadOnly)
|
||||
{
|
||||
Services.FileDirectoryProcessorService.DeleteEmptyFolders(d, Logger);
|
||||
}
|
||||
sw.Stop();
|
||||
var newScanHistory = new data.ScanHistory
|
||||
{
|
||||
UserId = user.Id,
|
||||
NewArtists = FileDirectoryProcessorService.AddedArtistIds.Count(),
|
||||
NewReleases = FileDirectoryProcessorService.AddedReleaseIds.Count(),
|
||||
NewTracks = FileDirectoryProcessorService.AddedTrackIds.Count(),
|
||||
TimeSpanInSeconds = (int)sw.Elapsed.TotalSeconds
|
||||
};
|
||||
DbContext.ScanHistories.Add(newScanHistory);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
await LogAndPublishAsync($"** Completed! Processed Folders [{processedFolders}], Processed Files [{processedFiles}], New Artists [{ newScanHistory.NewArtists }], New Releases [{ newScanHistory.NewReleases }], New Tracks [{ newScanHistory.NewTracks }] : Elapsed Time [{sw.Elapsed}]").ConfigureAwait(false);
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
Data = true,
|
||||
IsSuccess = true,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteArtistAsync(User user, Guid artistId, bool deleteFolder)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var artist = DbContext.Artists.FirstOrDefault(x => x.RoadieId == artistId);
|
||||
var artist = await DbContext.Artists.FirstOrDefaultAsync(x => x.RoadieId == artistId).ConfigureAwait(false);
|
||||
if (artist == null)
|
||||
{
|
||||
await LogAndPublish($"DeleteArtist Unknown Artist [{artistId}]", LogLevel.Warning);
|
||||
await LogAndPublishAsync($"DeleteArtist Unknown Artist [{artistId}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
return new OperationResult<bool>(true, $"Artist Not Found [{artistId}]");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var result = await ArtistService.Delete(user, artist, deleteFolder);
|
||||
var result = await ArtistService.DeleteAsync(user, artist, deleteFolder).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return new OperationResult<bool>
|
||||
|
@ -93,22 +166,22 @@ namespace Roadie.Api.Services
|
|||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
await LogAndPublish("Error deleting artist.");
|
||||
await LogAndPublishAsync("Error deleting artist.").ConfigureAwait(false);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
await LogAndPublish($"DeleteArtist `{artist}`, By User `{user}`", LogLevel.Information);
|
||||
await LogAndPublishAsync($"DeleteArtist `{artist}`, By User `{user}`", LogLevel.Information).ConfigureAwait(false);
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
IsSuccess = errors.Count == 0,
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteArtistReleases(User user, Guid artistId, bool doDeleteFiles = false)
|
||||
public async Task<OperationResult<bool>> DeleteArtistReleasesAsync(User user, Guid artistId, bool doDeleteFiles = false)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -116,34 +189,34 @@ namespace Roadie.Api.Services
|
|||
var artist = DbContext.Artists.FirstOrDefault(x => x.RoadieId == artistId);
|
||||
if (artist == null)
|
||||
{
|
||||
await LogAndPublish($"DeleteArtistReleases Unknown Artist [{artistId}]", LogLevel.Warning);
|
||||
await LogAndPublishAsync($"DeleteArtistReleases Unknown Artist [{artistId}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
return new OperationResult<bool>(true, $"Artist Not Found [{artistId}]");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await ReleaseService.DeleteReleases(user, DbContext.Releases.Where(x => x.ArtistId == artist.Id).Select(x => x.RoadieId).ToArray(), doDeleteFiles);
|
||||
await DbContext.SaveChangesAsync();
|
||||
await ReleaseService.DeleteReleasesAsync(user, DbContext.Releases.Where(x => x.ArtistId == artist.Id).Select(x => x.RoadieId).ToArray(), doDeleteFiles).ConfigureAwait(false);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
await LogAndPublish("Error deleting artist.");
|
||||
await LogAndPublishAsync("Error deleting artist.").ConfigureAwait(false);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
await LogAndPublish($"DeleteArtistReleases `{artist}`, By User `{user}`", LogLevel.Information);
|
||||
await LogAndPublishAsync($"DeleteArtistReleases `{artist}`, By User `{user}`", LogLevel.Information).ConfigureAwait(false);
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
IsSuccess = errors.Count == 0,
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteArtistSecondaryImage(User user, Guid artistId, int index)
|
||||
public async Task<OperationResult<bool>> DeleteArtistSecondaryImageAsync(User user, Guid artistId, int index)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -151,7 +224,7 @@ namespace Roadie.Api.Services
|
|||
var artist = DbContext.Artists.FirstOrDefault(x => x.RoadieId == artistId);
|
||||
if (artist == null)
|
||||
{
|
||||
await LogAndPublish($"DeleteArtistSecondaryImage Unknown Artist [{artistId}]", LogLevel.Warning);
|
||||
await LogAndPublishAsync($"DeleteArtistSecondaryImage Unknown Artist [{artistId}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
return new OperationResult<bool>(true, $"Artist Not Found [{artistId}]");
|
||||
}
|
||||
|
||||
|
@ -169,22 +242,22 @@ namespace Roadie.Api.Services
|
|||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
await LogAndPublish("Error deleting artist secondary image.");
|
||||
await LogAndPublishAsync("Error deleting artist secondary image.").ConfigureAwait(false);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
await LogAndPublish($"DeleteArtistSecondaryImage `{artist}` Index [{index}], By User `{user}`", LogLevel.Information);
|
||||
await LogAndPublishAsync($"DeleteArtistSecondaryImage `{artist}` Index [{index}], By User `{user}`", LogLevel.Information).ConfigureAwait(false);
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
IsSuccess = errors.Count == 0,
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteGenre(User user, Guid genreId)
|
||||
public async Task<OperationResult<bool>> DeleteGenreAsync(User user, Guid genreId)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -192,34 +265,34 @@ namespace Roadie.Api.Services
|
|||
var genre = DbContext.Genres.FirstOrDefault(x => x.RoadieId == genreId);
|
||||
if (genre == null)
|
||||
{
|
||||
await LogAndPublish($"DeleteLabel Unknown Genre [{genreId}]", LogLevel.Warning);
|
||||
await LogAndPublishAsync($"DeleteLabel Unknown Genre [{genreId}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
return new OperationResult<bool>(true, $"Genre Not Found [{genreId}]");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await GenreService.Delete(user, genreId);
|
||||
await GenreService.DeleteAsync(user, genreId).ConfigureAwait(false);
|
||||
CacheManager.ClearRegion(genre.CacheRegion);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
await LogAndPublish("Error deleting Genre.");
|
||||
await LogAndPublishAsync("Error deleting Genre.").ConfigureAwait(false);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
await LogAndPublish($"DeleteGenre `{genre}`, By User `{user}`", LogLevel.Information);
|
||||
sw.Stop();
|
||||
await LogAndPublishAsync($"DeleteGenre `{genre}`, By User `{user}`", LogLevel.Information).ConfigureAwait(false);
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
IsSuccess = errors.Count == 0,
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteLabel(User user, Guid labelId)
|
||||
public async Task<OperationResult<bool>> DeleteLabelAsync(User user, Guid labelId)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -227,34 +300,34 @@ namespace Roadie.Api.Services
|
|||
var label = DbContext.Labels.FirstOrDefault(x => x.RoadieId == labelId);
|
||||
if (label == null)
|
||||
{
|
||||
await LogAndPublish($"DeleteLabel Unknown Label [{labelId}]", LogLevel.Warning);
|
||||
await LogAndPublishAsync($"DeleteLabel Unknown Label [{labelId}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
return new OperationResult<bool>(true, $"Label Not Found [{labelId}]");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await LabelService.Delete(user, labelId);
|
||||
await LabelService.DeleteAsync(user, labelId).ConfigureAwait(false);
|
||||
CacheManager.ClearRegion(label.CacheRegion);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
await LogAndPublish("Error deleting Label.");
|
||||
await LogAndPublishAsync("Error deleting Label.").ConfigureAwait(false);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
await LogAndPublish($"DeleteLabel `{label}`, By User `{user}`", LogLevel.Information);
|
||||
await LogAndPublishAsync($"DeleteLabel `{label}`, By User `{user}`", LogLevel.Information).ConfigureAwait(false);
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
IsSuccess = errors.Count == 0,
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteRelease(User user, Guid releaseId, bool? doDeleteFiles)
|
||||
public async Task<OperationResult<bool>> DeleteReleaseAsync(User user, Guid releaseId, bool? doDeleteFiles)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -266,31 +339,31 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
if (release == null)
|
||||
{
|
||||
await LogAndPublish($"DeleteRelease Unknown Release [{releaseId}]", LogLevel.Warning);
|
||||
await LogAndPublishAsync($"DeleteRelease Unknown Release [{releaseId}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
return new OperationResult<bool>(true, $"Release Not Found [{releaseId}]");
|
||||
}
|
||||
await ReleaseService.Delete(user, release, doDeleteFiles ?? false);
|
||||
await ReleaseService.DeleteAsync(user, release, doDeleteFiles ?? false).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
await LogAndPublish("Error deleting release.");
|
||||
await LogAndPublishAsync("Error deleting release.").ConfigureAwait(false);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
await LogAndPublish($"DeleteRelease `{release}`, By User `{user}`", LogLevel.Information);
|
||||
await LogAndPublishAsync($"DeleteRelease `{release}`, By User `{user}`", LogLevel.Information).ConfigureAwait(false);
|
||||
CacheManager.Clear();
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
IsSuccess = errors.Count == 0,
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteReleaseSecondaryImage(User user, Guid releaseId, int index)
|
||||
public async Task<OperationResult<bool>> DeleteReleaseSecondaryImageAsync(User user, Guid releaseId, int index)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -298,7 +371,7 @@ namespace Roadie.Api.Services
|
|||
var release = DbContext.Releases.Include(x => x.Artist).FirstOrDefault(x => x.RoadieId == releaseId);
|
||||
if (release == null)
|
||||
{
|
||||
await LogAndPublish($"DeleteReleaseSecondaryImage Unknown Release [{releaseId}]", LogLevel.Warning);
|
||||
await LogAndPublishAsync($"DeleteReleaseSecondaryImage Unknown Release [{releaseId}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
return new OperationResult<bool>(true, $"Release Not Found [{releaseId}]");
|
||||
}
|
||||
|
||||
|
@ -316,22 +389,22 @@ namespace Roadie.Api.Services
|
|||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
await LogAndPublish("Error deleting release secondary image.");
|
||||
await LogAndPublishAsync("Error deleting release secondary image.").ConfigureAwait(false);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
await LogAndPublish($"DeleteReleaseSecondaryImage `{release}` Index [{index}], By User `{user}`", LogLevel.Information);
|
||||
await LogAndPublishAsync($"DeleteReleaseSecondaryImage `{release}` Index [{index}], By User `{user}`", LogLevel.Information).ConfigureAwait(false);
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
IsSuccess = errors.Count == 0,
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteTracks(User user, IEnumerable<Guid> trackIds, bool? doDeleteFile)
|
||||
public async Task<OperationResult<bool>> DeleteTracksAsync(User user, IEnumerable<Guid> trackIds, bool? doDeleteFile)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -348,12 +421,12 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
if (track == null)
|
||||
{
|
||||
await LogAndPublish($"DeleteTracks Unknown Track [{trackId}]", LogLevel.Warning);
|
||||
await LogAndPublishAsync($"DeleteTracks Unknown Track [{trackId}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
return new OperationResult<bool>(true, $"Track Not Found [{trackId}]");
|
||||
}
|
||||
|
||||
DbContext.Tracks.Remove(track);
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
if (doDeleteFile ?? false)
|
||||
{
|
||||
string trackPath = null;
|
||||
|
@ -375,33 +448,33 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, string.Format("Error Deleting File [{0}] For Track [{1}] Exception [{2}]", trackPath, track.Id, ex.Serialize()));
|
||||
Logger.LogError(ex, $"Error Deleting File [{trackPath}] For Track [{track.Id}] Exception [{ex.Serialize()}]");
|
||||
}
|
||||
}
|
||||
await ReleaseService.ScanReleaseFolder(user, track.ReleaseMedia.Release.RoadieId, false, track.ReleaseMedia.Release);
|
||||
await BookmarkService.RemoveAllBookmarksForItem(BookmarkType.Track, track.Id);
|
||||
await ReleaseService.ScanReleaseFolderAsync(user, track.ReleaseMedia.Release.RoadieId, false, track.ReleaseMedia.Release).ConfigureAwait(false);
|
||||
await BookmarkService.RemoveAllBookmarksForItemAsync(BookmarkType.Track, track.Id).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
await LogAndPublish("Error deleting track.");
|
||||
await LogAndPublishAsync("Error deleting track.").ConfigureAwait(false);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
await LogAndPublish($"DeleteTracks `{track}`, By User `{user}`", LogLevel.Warning);
|
||||
await LogAndPublishAsync($"DeleteTracks `{track}`, By User `{user}`", LogLevel.Warning).ConfigureAwait(false);
|
||||
}
|
||||
CacheManager.Clear();
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
IsSuccess = errors.Count == 0,
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteUser(User applicationUser, Guid userId)
|
||||
public async Task<OperationResult<bool>> DeleteUserAsync(User applicationUser, Guid userId)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -412,7 +485,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
var ex = new Exception("User cannot self.");
|
||||
Logger.LogError(ex);
|
||||
await LogAndPublish("Error deleting user.");
|
||||
await LogAndPublishAsync("Error deleting user.").ConfigureAwait(false);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
|
@ -420,12 +493,12 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
if (user == null)
|
||||
{
|
||||
await LogAndPublish($"DeleteUser Unknown User [{userId}]", LogLevel.Warning);
|
||||
await LogAndPublishAsync($"DeleteUser Unknown User [{userId}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
return new OperationResult<bool>(true, $"User Not Found [{userId}]");
|
||||
}
|
||||
|
||||
DbContext.Users.Remove(user);
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
var userImageFilename = user.PathToImage(Configuration);
|
||||
if (File.Exists(userImageFilename))
|
||||
{
|
||||
|
@ -435,16 +508,16 @@ namespace Roadie.Api.Services
|
|||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
await LogAndPublish("Error deleting user.");
|
||||
await LogAndPublishAsync("Error deleting user.").ConfigureAwait(false);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
await LogAndPublish($"DeleteUser `{user}`, By User `{user}`", LogLevel.Warning);
|
||||
await LogAndPublishAsync($"DeleteUser `{user}`, By User `{user}`", LogLevel.Warning).ConfigureAwait(false);
|
||||
CacheManager.Clear();
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
IsSuccess = errors.Count == 0,
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
|
@ -454,7 +527,7 @@ namespace Roadie.Api.Services
|
|||
/// <summary>
|
||||
/// This is a very simple way to seed the database or setup configuration when the first (who becomes "Admin") user registers
|
||||
/// </summary>
|
||||
public async Task<OperationResult<bool>> DoInitialSetup(User user, UserManager<User> userManager)
|
||||
public async Task<OperationResult<bool>> DoInitialSetupAsync(User user, UserManager<User> userManager)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -483,10 +556,10 @@ namespace Roadie.Api.Services
|
|||
Description = "Users who have Edit Permissions",
|
||||
NormalizedName = "EDITOR"
|
||||
});
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
// Add given user to Admin role
|
||||
await userManager.AddToRoleAsync(user, "Admin");
|
||||
await userManager.AddToRoleAsync(user, "Admin").ConfigureAwait(false);
|
||||
|
||||
// Create special system artists of 'Sound Tracks' and 'Various Artists'
|
||||
DbContext.Artists.Add(new data.Artist
|
||||
|
@ -515,7 +588,7 @@ namespace Roadie.Api.Services
|
|||
Tags = "compilations|various",
|
||||
URLs = "https://en.wikipedia.org/wiki/Compilation_album"
|
||||
});
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
|
@ -525,7 +598,7 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public Task<OperationResult<Dictionary<string, List<string>>>> MissingCollectionReleases(User user)
|
||||
public Task<OperationResult<Dictionary<string, List<string>>>> MissingCollectionReleasesAsync(User user)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
|
@ -567,7 +640,7 @@ namespace Roadie.Api.Services
|
|||
sw.Stop();
|
||||
return Task.FromResult(new OperationResult<Dictionary<string, List<string>>>
|
||||
{
|
||||
Data = missingData.OrderBy(x => x.Value.Count()).ToDictionary(x => x.Key, x => x.Value),
|
||||
Data = missingData.OrderBy(x => x.Value.Count).ToDictionary(x => x.Key, x => x.Value),
|
||||
IsSuccess = true,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
});
|
||||
|
@ -619,13 +692,10 @@ namespace Roadie.Api.Services
|
|||
Directory.CreateDirectory(Configuration.LabelImageFolder);
|
||||
Logger.LogInformation($"Created Label Image Folder [{Configuration.LabelImageFolder}]");
|
||||
}
|
||||
if (Configuration.DbContextToUse != DbContexts.MySQL)
|
||||
if (Configuration.DbContextToUse != DbContexts.MySQL && !Directory.Exists(Configuration.FileDatabaseOptions.DatabaseFolder))
|
||||
{
|
||||
if (!Directory.Exists(Configuration.FileDatabaseOptions.DatabaseFolder))
|
||||
{
|
||||
Directory.CreateDirectory(Configuration.FileDatabaseOptions.DatabaseFolder);
|
||||
Logger.LogInformation($"Created File Database Folder [{Configuration.FileDatabaseOptions.DatabaseFolder}]");
|
||||
}
|
||||
Directory.CreateDirectory(Configuration.FileDatabaseOptions.DatabaseFolder);
|
||||
Logger.LogInformation($"Created File Database Folder [{Configuration.FileDatabaseOptions.DatabaseFolder}]");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -640,7 +710,7 @@ namespace Roadie.Api.Services
|
|||
Logger.LogInformation($"Administration startup tasks completed, elapsed time [{ sw.ElapsedMilliseconds }]");
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ScanAllCollections(User user, bool isReadOnly = false, bool doPurgeFirst = false)
|
||||
public async Task<OperationResult<bool>> ScanAllCollectionsAsync(User user, bool isReadOnly = false, bool doPurgeFirst = false)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -652,7 +722,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
try
|
||||
{
|
||||
var result = await ScanCollection(user, collection.RoadieId, isReadOnly, doPurgeFirst, false).ConfigureAwait(false);
|
||||
var result = await ScanCollectionAsync(user, collection.RoadieId, isReadOnly, doPurgeFirst, false).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
errors.AddRange(result.Errors);
|
||||
|
@ -661,7 +731,7 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await LogAndPublish(ex.ToString(), LogLevel.Error).ConfigureAwait(false);
|
||||
await LogAndPublishAsync(ex.ToString(), LogLevel.Error).ConfigureAwait(false);
|
||||
errors.Add(ex);
|
||||
}
|
||||
}
|
||||
|
@ -671,7 +741,7 @@ namespace Roadie.Api.Services
|
|||
await UpdateReleaseRank(updatedReleaseId).ConfigureAwait(false);
|
||||
}
|
||||
sw.Stop();
|
||||
await LogAndPublish($"ScanAllCollections, By User `{user}`, Updated Release Count [{updatedReleaseIds.Distinct().Count()}], ElapsedTime [{sw.ElapsedMilliseconds}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
await LogAndPublishAsync($"ScanAllCollections, By User `{user}`, Updated Release Count [{updatedReleaseIds.Distinct().Count()}], ElapsedTime [{sw.ElapsedMilliseconds}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = errors.Count == 0,
|
||||
|
@ -681,7 +751,7 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ScanArtist(User user, Guid artistId, bool isReadOnly = false)
|
||||
public async Task<OperationResult<bool>> ScanArtistAsync(User user, Guid artistId, bool isReadOnly = false)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
|
@ -689,18 +759,18 @@ namespace Roadie.Api.Services
|
|||
var artist = DbContext.Artists.FirstOrDefault(x => x.RoadieId == artistId);
|
||||
if (artist == null)
|
||||
{
|
||||
await LogAndPublish($"ScanArtist Unknown Artist [{artistId}]", LogLevel.Warning);
|
||||
await LogAndPublishAsync($"ScanArtist Unknown Artist [{artistId}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
return new OperationResult<bool>(true, $"Artist Not Found [{artistId}]");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var result = await ArtistService.ScanArtistReleasesFolders(user, artist.RoadieId, Configuration.LibraryFolder, isReadOnly);
|
||||
await ArtistService.ScanArtistReleasesFoldersAsync(user, artist.RoadieId, Configuration.LibraryFolder, isReadOnly).ConfigureAwait(false);
|
||||
CacheManager.ClearRegion(artist.CacheRegion);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await LogAndPublish(ex.ToString(), LogLevel.Error);
|
||||
await LogAndPublishAsync(ex.ToString(), LogLevel.Error).ConfigureAwait(false);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
|
@ -713,56 +783,52 @@ namespace Roadie.Api.Services
|
|||
NewTracks = ReleaseService.AddedTrackIds.Count(),
|
||||
TimeSpanInSeconds = (int)sw.Elapsed.TotalSeconds
|
||||
});
|
||||
await DbContext.SaveChangesAsync();
|
||||
await UpdateArtistRank(artist.Id, true);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
await UpdateArtistRank(artist.Id, true).ConfigureAwait(false);
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
IsSuccess = errors.Count == 0,
|
||||
AdditionalData = new Dictionary<string, object> { { "artistAverage", artist.Rating } },
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ScanArtists(User user, IEnumerable<Guid> artistIds, bool isReadOnly = false)
|
||||
public async Task<OperationResult<bool>> ScanArtistsAsync(User user, IEnumerable<Guid> artistIds, bool isReadOnly = false)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
var errors = new List<Exception>();
|
||||
foreach (var artistId in artistIds)
|
||||
{
|
||||
var result = await ScanArtist(user, artistId, isReadOnly);
|
||||
if (!result.IsSuccess)
|
||||
var result = await ScanArtistAsync(user, artistId, isReadOnly).ConfigureAwait(false);
|
||||
if (!result.IsSuccess && (result.Errors?.Any() ?? false))
|
||||
{
|
||||
if (result.Errors?.Any() ?? false)
|
||||
{
|
||||
errors.AddRange(result.Errors);
|
||||
}
|
||||
errors.AddRange(result.Errors);
|
||||
}
|
||||
}
|
||||
sw.Stop();
|
||||
await LogAndPublish($"** Completed! ScanArtists: Artist Count [{ artistIds.Count() }], Elapsed Time [{sw.Elapsed}]");
|
||||
await LogAndPublishAsync($"** Completed! ScanArtists: Artist Count [{ artistIds.Count() }], Elapsed Time [{sw.Elapsed}]").ConfigureAwait(false);
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
IsSuccess = errors.Count == 0,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ScanCollection(User user, Guid collectionId, bool isReadOnly = false, bool doPurgeFirst = false, bool doUpdateRanks = true)
|
||||
public async Task<OperationResult<bool>> ScanCollectionAsync(User user, Guid collectionId, bool isReadOnly = false, bool doPurgeFirst = false, bool doUpdateRanks = true)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
var releaseIdsInCollection = new List<int>();
|
||||
var updatedReleaseIds = new List<int>();
|
||||
var result = new List<data.PositionArtistRelease>();
|
||||
var errors = new List<Exception>();
|
||||
var collection = await DbContext.Collections.FirstOrDefaultAsync(x => x.RoadieId == collectionId).ConfigureAwait(false);
|
||||
if (collection == null)
|
||||
{
|
||||
await LogAndPublish($"ScanCollection Unknown Collection [{collectionId}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
await LogAndPublishAsync($"ScanCollection Unknown Collection [{collectionId}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
return new OperationResult<bool>(true, $"Collection Not Found [{collectionId}]");
|
||||
}
|
||||
|
||||
|
@ -770,7 +836,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
if (doPurgeFirst)
|
||||
{
|
||||
await LogAndPublish($"ScanCollection Purging Collection [{collectionId}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
await LogAndPublishAsync($"ScanCollection Purging Collection [{collectionId}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
var crs = await DbContext.CollectionReleases.Where(x => x.CollectionId == collection.Id).ToArrayAsync().ConfigureAwait(false);
|
||||
DbContext.CollectionReleases.RemoveRange(crs);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
@ -790,8 +856,8 @@ namespace Roadie.Api.Services
|
|||
data.Release release = null;
|
||||
|
||||
var isArtistNameDbKey = csvRelease.Artist.StartsWith(Roadie.Library.Data.Collection.DatabaseIdKey);
|
||||
int? artistId = isArtistNameDbKey ? SafeParser.ToNumber<int?>(csvRelease.Artist.Replace(Roadie.Library.Data.Collection.DatabaseIdKey, "")) : null;
|
||||
if(artistId.HasValue)
|
||||
int? artistId = isArtistNameDbKey ? SafeParser.ToNumber<int?>(csvRelease.Artist.Replace(Roadie.Library.Data.Collection.DatabaseIdKey, string.Empty)) : null;
|
||||
if (artistId.HasValue)
|
||||
{
|
||||
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == artistId.Value);
|
||||
if (artist != null)
|
||||
|
@ -802,9 +868,9 @@ namespace Roadie.Api.Services
|
|||
else
|
||||
{
|
||||
artistsMatchingName = await ArtistLookupEngine.DatabaseQueryForArtistName(csvRelease.Artist).ConfigureAwait(false);
|
||||
if (artistsMatchingName == null || !artistsMatchingName.Any())
|
||||
if (artistsMatchingName?.Any() != true)
|
||||
{
|
||||
await LogAndPublish($"CSV Position [{ csvRelease.Position }] Unable To Find Artist [{csvRelease.Artist}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
await LogAndPublishAsync($"CSV Position [{ csvRelease.Position }] Unable To Find Artist [{csvRelease.Artist}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
csvRelease.Status = Statuses.Missing;
|
||||
await DbContext.CollectionMissings.AddAsync(new data.CollectionMissing
|
||||
{
|
||||
|
@ -817,13 +883,13 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
else if (artistsMatchingName.Count() > 1)
|
||||
{
|
||||
await LogAndPublish($"CSV Position [{ csvRelease.Position }] Found [{ artistsMatchingName.Count() }] Artists by [{csvRelease.Artist}]", LogLevel.Information).ConfigureAwait(false);
|
||||
await LogAndPublishAsync($"CSV Position [{ csvRelease.Position }] Found [{ artistsMatchingName.Count() }] Artists by [{csvRelease.Artist}]", LogLevel.Information).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
foreach (var artist in artistsMatchingName)
|
||||
{
|
||||
var isReleaseNameDbKey = csvRelease.Release.StartsWith(Roadie.Library.Data.Collection.DatabaseIdKey);
|
||||
int? releaseId = isReleaseNameDbKey ? SafeParser.ToNumber<int?>(csvRelease.Release.Replace(Roadie.Library.Data.Collection.DatabaseIdKey, "")) : null;
|
||||
int? releaseId = isReleaseNameDbKey ? SafeParser.ToNumber<int?>(csvRelease.Release.Replace(Roadie.Library.Data.Collection.DatabaseIdKey, string.Empty)) : null;
|
||||
if (releaseId.HasValue)
|
||||
{
|
||||
release = await DbContext.Releases.FirstOrDefaultAsync(x => x.Id == releaseId.Value).ConfigureAwait(false);
|
||||
|
@ -840,7 +906,7 @@ namespace Roadie.Api.Services
|
|||
|
||||
if (release == null)
|
||||
{
|
||||
await LogAndPublish($"CSV Position [{ csvRelease.Position }] Unable To Find Release [{csvRelease.Release}], for Artist [{csvRelease.Artist}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
await LogAndPublishAsync($"CSV Position [{ csvRelease.Position }] Unable To Find Release [{csvRelease.Release}], for Artist [{csvRelease.Artist}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
csvRelease.Status = Statuses.Missing;
|
||||
await DbContext.CollectionMissings.AddAsync(new data.CollectionMissing
|
||||
{
|
||||
|
@ -867,7 +933,7 @@ namespace Roadie.Api.Services
|
|||
CollectionId = collection.Id,
|
||||
ReleaseId = release.Id,
|
||||
ListNumber = csvRelease.Position
|
||||
});
|
||||
}).ConfigureAwait(false);
|
||||
updated = true;
|
||||
}
|
||||
// If Item in Collection is at different List number update CollectionRelease
|
||||
|
@ -906,16 +972,16 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
|
||||
var collectionReleasesToRemove = await (from cr in DbContext.CollectionReleases
|
||||
where cr.CollectionId == collection.Id
|
||||
where !releaseIdsInCollection.Contains(cr.ReleaseId)
|
||||
select cr).ToArrayAsync().ConfigureAwait(false);
|
||||
if (collectionReleasesToRemove.Any())
|
||||
where cr.CollectionId == collection.Id
|
||||
where !releaseIdsInCollection.Contains(cr.ReleaseId)
|
||||
select cr).ToArrayAsync().ConfigureAwait(false);
|
||||
if (collectionReleasesToRemove.Length > 0)
|
||||
{
|
||||
await LogAndPublish($"Removing [{collectionReleasesToRemove.Count()}] Stale Release Records from Collection.", LogLevel.Information);
|
||||
await LogAndPublishAsync($"Removing [{collectionReleasesToRemove.Length}] Stale Release Records from Collection.", LogLevel.Information).ConfigureAwait(false);
|
||||
DbContext.CollectionReleases.RemoveRange(collectionReleasesToRemove);
|
||||
}
|
||||
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
if (doUpdateRanks)
|
||||
{
|
||||
foreach (var updatedReleaseId in updatedReleaseIds)
|
||||
|
@ -933,31 +999,23 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
|
||||
sw.Stop();
|
||||
Logger.LogWarning(string.Format("RescanCollection `{0}`, By User `{1}`, ElapsedTime [{2}]", collection, user, sw.ElapsedMilliseconds));
|
||||
Logger.LogWarning($"RescanCollection `{collection}`, By User `{user}`, ElapsedTime [{sw.ElapsedMilliseconds}]");
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
AdditionalData = new Dictionary<string, object> { { "updatedReleaseIds", updatedReleaseIds.ToArray() } },
|
||||
IsSuccess = !errors.Any(),
|
||||
IsSuccess = errors.Count == 0,
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ScanInboundFolder(User user, bool isReadOnly = false)
|
||||
{
|
||||
var d = new DirectoryInfo(Configuration.InboundFolder);
|
||||
return await ScanFolder(user, d, isReadOnly);
|
||||
}
|
||||
public Task<OperationResult<bool>> ScanInboundFolderAsync(User user, bool isReadOnly = false) => ScanFolderAsync(user, new DirectoryInfo(Configuration.InboundFolder), isReadOnly);
|
||||
|
||||
public async Task<OperationResult<bool>> ScanLibraryFolder(User user, bool isReadOnly = false)
|
||||
{
|
||||
var d = new DirectoryInfo(Configuration.LibraryFolder);
|
||||
return await ScanFolder(user, d, isReadOnly, false);
|
||||
}
|
||||
public Task<OperationResult<bool>> ScanLibraryFolderAsync(User user, bool isReadOnly = false) => ScanFolderAsync(user, new DirectoryInfo(Configuration.LibraryFolder), isReadOnly, false);
|
||||
|
||||
public async Task<OperationResult<bool>> ScanRelease(User user, Guid releaseId, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false)
|
||||
public async Task<OperationResult<bool>> ScanReleaseAsync(User user, Guid releaseId, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -969,17 +1027,17 @@ namespace Roadie.Api.Services
|
|||
.FirstOrDefault(x => x.RoadieId == releaseId);
|
||||
if (release == null)
|
||||
{
|
||||
await LogAndPublish($"ScanRelease Unknown Release [{releaseId}]", LogLevel.Warning);
|
||||
await LogAndPublishAsync($"ScanRelease Unknown Release [{releaseId}]", LogLevel.Warning).ConfigureAwait(false);
|
||||
return new OperationResult<bool>(true, $"Release Not Found [{releaseId}]");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var result = await ReleaseService.ScanReleaseFolder(user, release.RoadieId, isReadOnly, release);
|
||||
await ReleaseService.ScanReleaseFolderAsync(user, release.RoadieId, isReadOnly, release).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await LogAndPublish(ex.ToString(), LogLevel.Error);
|
||||
await LogAndPublishAsync(ex.ToString(), LogLevel.Error).ConfigureAwait(false);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
|
@ -992,43 +1050,40 @@ namespace Roadie.Api.Services
|
|||
NewTracks = ReleaseService.AddedTrackIds.Count(),
|
||||
TimeSpanInSeconds = (int)sw.Elapsed.TotalSeconds
|
||||
});
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
IsSuccess = errors.Count == 0,
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ScanReleases(User user, IEnumerable<Guid> releaseIds, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false)
|
||||
public async Task<OperationResult<bool>> ScanReleasesAsync(User user, IEnumerable<Guid> releaseIds, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
var errors = new List<Exception>();
|
||||
foreach (var releaseId in releaseIds)
|
||||
{
|
||||
var result = await ScanRelease(user, releaseId, isReadOnly, wasDoneForInvalidTrackPlay);
|
||||
if (!result.IsSuccess)
|
||||
var result = await ScanReleaseAsync(user, releaseId, isReadOnly, wasDoneForInvalidTrackPlay).ConfigureAwait(false);
|
||||
if (!result.IsSuccess && (result.Errors?.Any() ?? false))
|
||||
{
|
||||
if (result.Errors?.Any() ?? false)
|
||||
{
|
||||
errors.AddRange(result.Errors);
|
||||
}
|
||||
errors.AddRange(result.Errors);
|
||||
}
|
||||
}
|
||||
sw.Stop();
|
||||
await LogAndPublish($"** Completed! ScanReleases: Release Count [{ releaseIds.Count() }], Elapsed Time [{sw.Elapsed}]");
|
||||
await LogAndPublishAsync($"** Completed! ScanReleases: Release Count [{ releaseIds.Count() }], Elapsed Time [{sw.Elapsed}]").ConfigureAwait(false);
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
IsSuccess = errors.Count == 0,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> UpdateInviteTokenUsed(Guid? tokenId)
|
||||
public async Task<OperationResult<bool>> UpdateInviteTokenUsedAsync(Guid? tokenId)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -1044,17 +1099,17 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
token.Status = Statuses.Complete;
|
||||
token.LastUpdated = DateTime.UtcNow;
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
IsSuccess = errors.Count == 0,
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ValidateInviteToken(Guid? tokenId)
|
||||
public async Task<OperationResult<bool>> ValidateInviteTokenAsync(Guid? tokenId)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -1072,7 +1127,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
token.Status = Statuses.Expired;
|
||||
token.LastUpdated = DateTime.UtcNow;
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
return new OperationResult<bool>(true, $"Invite Token [{tokenId}] Expired [{ token.ExpiresDate }]");
|
||||
}
|
||||
if (token.Status == Statuses.Complete)
|
||||
|
@ -1081,84 +1136,11 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
IsSuccess = errors.Count == 0,
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
private void EventMessageLogger_Messages(object sender, EventMessage e) => Task.WaitAll(LogAndPublish(e.Message, e.Level));
|
||||
|
||||
private async Task LogAndPublish(string message, LogLevel level = LogLevel.Trace)
|
||||
{
|
||||
switch (level)
|
||||
{
|
||||
case LogLevel.Trace:
|
||||
Logger.LogTrace(message);
|
||||
break;
|
||||
|
||||
case LogLevel.Debug:
|
||||
Logger.LogDebug(message);
|
||||
break;
|
||||
|
||||
case LogLevel.Information:
|
||||
Logger.LogInformation(message);
|
||||
break;
|
||||
|
||||
case LogLevel.Warning:
|
||||
Logger.LogWarning(message);
|
||||
break;
|
||||
|
||||
case LogLevel.Critical:
|
||||
Logger.LogCritical(message);
|
||||
break;
|
||||
}
|
||||
|
||||
await ScanActivityHub.Clients.All.SendAsync("SendSystemActivity", message).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task<OperationResult<bool>> ScanFolder(User user, DirectoryInfo d, bool isReadOnly, bool doDeleteFiles = true)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
long processedFiles = 0;
|
||||
await LogAndPublish($"** Processing Folder: [{d.FullName}]");
|
||||
|
||||
long processedFolders = 0;
|
||||
foreach (var folder in Directory.EnumerateDirectories(d.FullName).ToArray())
|
||||
{
|
||||
var directoryProcessResult = await FileDirectoryProcessorService.Process(user:user,
|
||||
folder: new DirectoryInfo(folder),
|
||||
doJustInfo: isReadOnly,
|
||||
doDeleteFiles: doDeleteFiles);
|
||||
processedFolders++;
|
||||
processedFiles += SafeParser.ToNumber<int>(directoryProcessResult.AdditionalData["ProcessedFiles"]);
|
||||
}
|
||||
CacheManager.Clear();
|
||||
if (!isReadOnly)
|
||||
{
|
||||
Services.FileDirectoryProcessorService.DeleteEmptyFolders(d, Logger);
|
||||
}
|
||||
sw.Stop();
|
||||
var newScanHistory = new data.ScanHistory
|
||||
{
|
||||
UserId = user.Id,
|
||||
NewArtists = FileDirectoryProcessorService.AddedArtistIds.Count(),
|
||||
NewReleases = FileDirectoryProcessorService.AddedReleaseIds.Count(),
|
||||
NewTracks = FileDirectoryProcessorService.AddedTrackIds.Count(),
|
||||
TimeSpanInSeconds = (int)sw.Elapsed.TotalSeconds
|
||||
};
|
||||
DbContext.ScanHistories.Add(newScanHistory);
|
||||
await DbContext.SaveChangesAsync();
|
||||
await LogAndPublish($"** Completed! Processed Folders [{processedFolders}], Processed Files [{processedFiles}], New Artists [{ newScanHistory.NewArtists }], New Releases [{ newScanHistory.NewReleases }], New Tracks [{ newScanHistory.NewTracks }] : Elapsed Time [{sw.Elapsed}]");
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
Data = true,
|
||||
IsSuccess = true,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,4 @@
|
|||
using Mapster;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Roadie.Library;
|
||||
using Roadie.Library.Caching;
|
||||
|
@ -20,7 +19,6 @@ using System.Diagnostics;
|
|||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Threading.Tasks;
|
||||
using data = Roadie.Library.Data;
|
||||
using models = Roadie.Library.Models;
|
||||
|
||||
namespace Roadie.Api.Services
|
||||
|
@ -41,30 +39,7 @@ namespace Roadie.Api.Services
|
|||
UserService = userService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When a bookmarkable item gets deleted then delete any bookmarks to that item, since its a generic column there is not FK setup.
|
||||
/// </summary>
|
||||
public async Task<OperationResult<bool>> RemoveAllBookmarksForItem(BookmarkType type, int id)
|
||||
{
|
||||
var bookmarks = await DbContext.Bookmarks.Include(x => x.User)
|
||||
.Where(x => x.BookmarkType == type && x.BookmarkTargetId == id)
|
||||
.ToListAsync();
|
||||
|
||||
var users = bookmarks.Select(x => x.User).ToList().Distinct();
|
||||
DbContext.Bookmarks.RemoveRange(bookmarks);
|
||||
await DbContext.SaveChangesAsync();
|
||||
foreach(var user in users)
|
||||
{
|
||||
CacheManager.ClearRegion(user.CacheRegion);
|
||||
}
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = true
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<Library.Models.Pagination.PagedResult<models.BookmarkList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, BookmarkType? filterType = null)
|
||||
public async Task<Library.Models.Pagination.PagedResult<models.BookmarkList>> ListAsync(User roadieUser, PagedRequest request, bool? doRandomize = false, BookmarkType? filterType = null)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -95,14 +70,19 @@ namespace Roadie.Api.Services
|
|||
var rowCount = result.Count();
|
||||
var rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
|
||||
|
||||
var user = await GetUser(roadieUser.UserId);
|
||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||
|
||||
foreach (var row in rows)
|
||||
{
|
||||
switch (row.Type)
|
||||
{
|
||||
case BookmarkType.Artist:
|
||||
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
|
||||
if (artist == null) continue;
|
||||
if (artist == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
row.Bookmark = new models.DataToken
|
||||
{
|
||||
Text = artist.Name,
|
||||
|
@ -117,7 +97,11 @@ namespace Roadie.Api.Services
|
|||
case BookmarkType.Release:
|
||||
var release = DbContext.Releases.Include(x => x.Artist)
|
||||
.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
|
||||
if (release == null) continue;
|
||||
if (release == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
row.Bookmark = new models.DataToken
|
||||
{
|
||||
Text = release.Title,
|
||||
|
@ -137,7 +121,11 @@ namespace Roadie.Api.Services
|
|||
.Include(x => x.ReleaseMedia.Release.Artist)
|
||||
.Include(x => x.TrackArtist)
|
||||
.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
|
||||
if (track == null) continue;
|
||||
if (track == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
row.Bookmark = new models.DataToken
|
||||
{
|
||||
Text = track.Title,
|
||||
|
@ -165,7 +153,11 @@ namespace Roadie.Api.Services
|
|||
var playlist = DbContext.Playlists
|
||||
.Include(x => x.User)
|
||||
.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
|
||||
if (playlist == null) continue;
|
||||
if (playlist == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
row.Bookmark = new models.DataToken
|
||||
{
|
||||
Text = playlist.Name,
|
||||
|
@ -180,7 +172,11 @@ namespace Roadie.Api.Services
|
|||
|
||||
case BookmarkType.Collection:
|
||||
var collection = DbContext.Collections.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
|
||||
if (collection == null) continue;
|
||||
if (collection == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
row.Bookmark = new models.DataToken
|
||||
{
|
||||
Text = collection.Name,
|
||||
|
@ -196,7 +192,11 @@ namespace Roadie.Api.Services
|
|||
|
||||
case BookmarkType.Label:
|
||||
var label = DbContext.Labels.FirstOrDefault(x => x.Id == row.BookmarkTargetId);
|
||||
if (label == null) continue;
|
||||
if (label == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
row.Bookmark = new models.DataToken
|
||||
{
|
||||
Text = label.Name,
|
||||
|
@ -207,8 +207,7 @@ namespace Roadie.Api.Services
|
|||
row.SortName = label.SortName ?? label.Name;
|
||||
break;
|
||||
}
|
||||
|
||||
;
|
||||
};
|
||||
sw.Stop();
|
||||
return new Library.Models.Pagination.PagedResult<models.BookmarkList>
|
||||
{
|
||||
|
@ -219,5 +218,29 @@ namespace Roadie.Api.Services
|
|||
Rows = rows
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When a bookmarkable item gets deleted then delete any bookmarks to that item, since its a generic column there is not FK setup.
|
||||
/// </summary>
|
||||
public async Task<OperationResult<bool>> RemoveAllBookmarksForItemAsync(BookmarkType type, int id)
|
||||
{
|
||||
var bookmarks = await DbContext.Bookmarks.Include(x => x.User)
|
||||
.Where(x => x.BookmarkType == type && x.BookmarkTargetId == id)
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var users = bookmarks.Select(x => x.User).ToList().Distinct();
|
||||
DbContext.Bookmarks.RemoveRange(bookmarks);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
foreach (var user in users)
|
||||
{
|
||||
CacheManager.ClearRegion(user.CacheRegion);
|
||||
}
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = true
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,307 +43,7 @@ namespace Roadie.Api.Services
|
|||
BookmarkService = bookmarkService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get blank Collection to add
|
||||
/// </summary>
|
||||
/// <param name="roadieUser"></param>
|
||||
/// <returns></returns>
|
||||
public OperationResult<Collection> Add(User roadieUser)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
|
||||
var id = Guid.Empty;
|
||||
var collection = new data.Collection
|
||||
{
|
||||
Status = Statuses.New
|
||||
};
|
||||
var result = collection.Adapt<Collection>();
|
||||
result.Id = id;
|
||||
result.Thumbnail = ImageHelper.MakeNewImage(HttpContext,"collection");
|
||||
result.MediumThumbnail = ImageHelper.MakeNewImage(HttpContext,"collection");
|
||||
result.Maintainer = new DataToken
|
||||
{
|
||||
Value = roadieUser.UserId.ToString(),
|
||||
Text = roadieUser.UserName
|
||||
};
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<Collection>
|
||||
{
|
||||
Data = result,
|
||||
IsSuccess = true,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Collection>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
|
||||
var cacheKey = string.Format("urn:collection_by_id_operation:{0}:{1}", id, includes == null ? "0" : string.Join("|", includes));
|
||||
var result = await CacheManager.GetAsync(cacheKey, async () =>
|
||||
{
|
||||
return await CollectionByIdAction(id, includes);
|
||||
}, data.Artist.CacheRegionUrn(id));
|
||||
sw.Stop();
|
||||
if (result?.Data != null && roadieUser != null)
|
||||
{
|
||||
var userBookmarkResult = await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Collection);
|
||||
if (userBookmarkResult.IsSuccess)
|
||||
{
|
||||
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x?.Bookmark?.Value == result?.Data?.Id?.ToString()) != null;
|
||||
}
|
||||
if (result.Data.Comments.Any())
|
||||
{
|
||||
var commentIds = result.Data.Comments.Select(x => x.DatabaseId).ToArray();
|
||||
var userCommentReactions = (from cr in DbContext.CommentReactions
|
||||
where commentIds.Contains(cr.CommentId)
|
||||
where cr.UserId == roadieUser.Id
|
||||
select cr).ToArray();
|
||||
foreach (var comment in result.Data.Comments)
|
||||
{
|
||||
var userCommentReaction =
|
||||
userCommentReactions.FirstOrDefault(x => x.CommentId == comment.DatabaseId);
|
||||
comment.IsDisliked = userCommentReaction?.ReactionValue == CommentReaction.Dislike;
|
||||
comment.IsLiked = userCommentReaction?.ReactionValue == CommentReaction.Like;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new OperationResult<Collection>(result.Messages)
|
||||
{
|
||||
Data = result?.Data,
|
||||
IsNotFoundResult = result?.IsNotFoundResult ?? false,
|
||||
Errors = result?.Errors,
|
||||
IsSuccess = result?.IsSuccess ?? false,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteCollection(User user, Guid id)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var collection = DbContext.Collections.FirstOrDefault(x => x.RoadieId == id);
|
||||
if (collection == null) return new OperationResult<bool>(true, $"Collection Not Found [{id}]");
|
||||
if (!user.IsEditor)
|
||||
{
|
||||
Logger.LogWarning($"DeleteCollection: Access Denied: `{collection}`, By User `{user}`");
|
||||
var r = new OperationResult<bool>("Access Denied");
|
||||
r.IsAccessDeniedResult = true;
|
||||
return r;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
DbContext.Collections.Remove(collection);
|
||||
await DbContext.SaveChangesAsync();
|
||||
await BookmarkService.RemoveAllBookmarksForItem(BookmarkType.Collection, collection.Id);
|
||||
var collectionImageFilename = collection.PathToImage(Configuration);
|
||||
if (File.Exists(collectionImageFilename))
|
||||
{
|
||||
File.Delete(collectionImageFilename);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
Logger.LogWarning($"DeleteCollection `{collection}`, By User `{user}`");
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public Task<Library.Models.Pagination.PagedResult<CollectionList>> List(User roadieUser, PagedRequest request,
|
||||
bool? doRandomize = false, Guid? releaseId = null, Guid? artistId = null)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
IQueryable<data.Collection> collections = null;
|
||||
if (artistId.HasValue)
|
||||
{
|
||||
collections = (from cr in DbContext.CollectionReleases
|
||||
join c in DbContext.Collections on cr.CollectionId equals c.Id
|
||||
join r in DbContext.Releases on cr.ReleaseId equals r.Id
|
||||
join a in DbContext.Artists on r.ArtistId equals a.Id
|
||||
where a.RoadieId == artistId
|
||||
select c).Distinct();
|
||||
}
|
||||
else if (releaseId.HasValue)
|
||||
{
|
||||
collections = (from cr in DbContext.CollectionReleases
|
||||
join c in DbContext.Collections on cr.CollectionId equals c.Id
|
||||
join r in DbContext.Releases on cr.ReleaseId equals r.Id
|
||||
where r.RoadieId == releaseId
|
||||
select c).Distinct();
|
||||
}
|
||||
else
|
||||
{
|
||||
collections = DbContext.Collections;
|
||||
}
|
||||
|
||||
var normalizedFilterValue = !string.IsNullOrEmpty(request.FilterValue)
|
||||
? request.FilterValue.ToAlphanumericName()
|
||||
: null;
|
||||
|
||||
var result = from c in collections
|
||||
let collectionCount = (from crc in DbContext.CollectionReleases
|
||||
where crc.CollectionId == c.Id
|
||||
select crc.Id).Count()
|
||||
where string.IsNullOrEmpty(normalizedFilterValue) || (
|
||||
c.Name.ToLower().Contains(normalizedFilterValue) ||
|
||||
c.SortName.ToLower().Contains(normalizedFilterValue) ||
|
||||
c.AlternateNames.ToLower().Contains(normalizedFilterValue)
|
||||
)
|
||||
where request.FilterToStatusValue == Statuses.Ok || c.Status == request.FilterToStatusValue
|
||||
select new CollectionList
|
||||
{
|
||||
DatabaseId = c.Id,
|
||||
Collection = new DataToken
|
||||
{
|
||||
Text = c.Name,
|
||||
Value = c.RoadieId.ToString()
|
||||
},
|
||||
Id = c.RoadieId,
|
||||
CollectionCount = c.CollectionCount,
|
||||
CollectionType = (c.CollectionType ?? CollectionType.Unknown).ToString(),
|
||||
CollectionFoundCount = collectionCount,
|
||||
CreatedDate = c.CreatedDate,
|
||||
IsLocked = c.IsLocked,
|
||||
LastUpdated = c.LastUpdated,
|
||||
Thumbnail = ImageHelper.MakeCollectionThumbnailImage(Configuration, HttpContext, c.RoadieId)
|
||||
};
|
||||
|
||||
var sortBy = string.IsNullOrEmpty(request.Sort)
|
||||
? request.OrderValue(new Dictionary<string, string> { { "Collection.Text", "ASC" } })
|
||||
: request.OrderValue();
|
||||
var rowCount = result.Count();
|
||||
var rows = result
|
||||
.OrderBy(sortBy)
|
||||
.Skip(request.SkipValue)
|
||||
.Take(request.LimitValue)
|
||||
.ToArray();
|
||||
if (request.FilterToStatusValue == Statuses.Incomplete)
|
||||
{
|
||||
rows = rows.OrderByDescending(x => x.PercentComplete).ThenBy(x => x.SortName).ToArray();
|
||||
}
|
||||
sw.Stop();
|
||||
return Task.FromResult(new Library.Models.Pagination.PagedResult<CollectionList>
|
||||
{
|
||||
TotalCount = rowCount,
|
||||
CurrentPage = request.PageValue,
|
||||
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Rows = rows
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates (or Adds) Collection
|
||||
/// </summary>
|
||||
public async Task<OperationResult<bool>> UpdateCollection(User user, Collection model)
|
||||
{
|
||||
var isNew = model.Id == Guid.Empty;
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
|
||||
var collection = new data.Collection();
|
||||
|
||||
if (!isNew)
|
||||
{
|
||||
collection = DbContext.Collections.FirstOrDefault(x => x.RoadieId == model.Id);
|
||||
if (collection == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, string.Format("Collection Not Found [{0}]", model.Id));
|
||||
}
|
||||
// If collection is being renamed, see if collection already exists with new model supplied name
|
||||
var collectionName = collection.SortNameValue;
|
||||
var collectionModelName = model.SortNameValue;
|
||||
if (collectionName.ToAlphanumericName() != collectionModelName.ToAlphanumericName())
|
||||
{
|
||||
var existingCollection = DbContext.Collections.FirstOrDefault(x => x.Name == model.Name || x.SortName == model.SortName);
|
||||
if (existingCollection != null)
|
||||
{
|
||||
return new OperationResult<bool>($"Collection already exists `{ collection }` with name [{ collectionModelName }].");
|
||||
}
|
||||
}
|
||||
}
|
||||
collection.IsLocked = model.IsLocked;
|
||||
var oldPathToImage = collection.PathToImage(Configuration);
|
||||
var didChangeName = collection.Name != model.Name && !isNew;
|
||||
collection.Name = model.Name;
|
||||
collection.SortName = model.SortName;
|
||||
collection.Edition = model.Edition;
|
||||
collection.ListInCSVFormat = model.ListInCSVFormat;
|
||||
collection.ListInCSV = model.ListInCSV;
|
||||
collection.Description = model.Description;
|
||||
collection.URLs = model.URLs;
|
||||
collection.Status = SafeParser.ToEnum<Statuses>(model.Status);
|
||||
collection.CollectionType = SafeParser.ToEnum<CollectionType>(model.CollectionType);
|
||||
collection.Tags = model.TagsList.ToDelimitedList();
|
||||
collection.URLs = model.URLsList.ToDelimitedList();
|
||||
collection.AlternateNames = model.AlternateNamesList.ToDelimitedList();
|
||||
collection.CollectionCount = model.CollectionCount;
|
||||
|
||||
if (model.Maintainer?.Value != null)
|
||||
{
|
||||
var maintainer = DbContext.Users.FirstOrDefault(x => x.RoadieId == SafeParser.ToGuid(model.Maintainer.Value));
|
||||
if (maintainer != null)
|
||||
{
|
||||
collection.MaintainerId = maintainer.Id;
|
||||
}
|
||||
}
|
||||
|
||||
if (isNew)
|
||||
{
|
||||
await DbContext.Collections.AddAsync(collection);
|
||||
await DbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
if (didChangeName)
|
||||
{
|
||||
if (File.Exists(oldPathToImage))
|
||||
{
|
||||
File.Move(oldPathToImage, collection.PathToImage(Configuration));
|
||||
}
|
||||
}
|
||||
|
||||
var collectionImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
|
||||
if (collectionImage != null)
|
||||
{
|
||||
// Save unaltered collection image
|
||||
File.WriteAllBytes(collection.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(collectionImage));
|
||||
}
|
||||
|
||||
collection.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync();
|
||||
|
||||
CacheManager.ClearRegion(collection.CacheRegion);
|
||||
Logger.LogInformation($"UpdateCollection `{collection}` By User `{user}`");
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<OperationResult<Collection>> CollectionByIdAction(Guid id, IEnumerable<string> includes = null)
|
||||
private async Task<OperationResult<Collection>> CollectionByIdActionAsync(Guid id, IEnumerable<string> includes = null)
|
||||
{
|
||||
var timings = new Dictionary<string, long>();
|
||||
var tsw = new Stopwatch();
|
||||
|
@ -352,13 +52,13 @@ namespace Roadie.Api.Services
|
|||
sw.Start();
|
||||
|
||||
tsw.Restart();
|
||||
var collection = await GetCollection(id);
|
||||
var collection = await GetCollection(id).ConfigureAwait(false);
|
||||
tsw.Stop();
|
||||
timings.Add("getCollection", tsw.ElapsedMilliseconds);
|
||||
|
||||
if (collection == null)
|
||||
{
|
||||
return new OperationResult<Collection>(true, string.Format("Collection Not Found [{0}]", id));
|
||||
return new OperationResult<Collection>(true, $"Collection Not Found [{id}]");
|
||||
}
|
||||
var result = collection.Adapt<Collection>();
|
||||
var maintainer = DbContext.Users.FirstOrDefault(x => x.Id == collection.MaintainerId);
|
||||
|
@ -474,5 +174,309 @@ namespace Roadie.Api.Services
|
|||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get blank Collection to add
|
||||
/// </summary>
|
||||
/// <param name="roadieUser"></param>
|
||||
/// <returns></returns>
|
||||
public OperationResult<Collection> Add(User roadieUser)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
|
||||
var id = Guid.Empty;
|
||||
var collection = new data.Collection
|
||||
{
|
||||
Status = Statuses.New
|
||||
};
|
||||
var result = collection.Adapt<Collection>();
|
||||
result.Id = id;
|
||||
result.Thumbnail = ImageHelper.MakeNewImage(HttpContext, "collection");
|
||||
result.MediumThumbnail = ImageHelper.MakeNewImage(HttpContext, "collection");
|
||||
result.Maintainer = new DataToken
|
||||
{
|
||||
Value = roadieUser.UserId.ToString(),
|
||||
Text = roadieUser.UserName
|
||||
};
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<Collection>
|
||||
{
|
||||
Data = result,
|
||||
IsSuccess = true,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Collection>> ByIdAsync(User roadieUser, Guid id, IEnumerable<string> includes = null)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
|
||||
var cacheKey = $"urn:collection_by_id_operation:{id}:{(includes == null ? "0" : string.Join("|", includes))}";
|
||||
var result = await CacheManager.GetAsync(cacheKey, async () =>
|
||||
{
|
||||
return await CollectionByIdActionAsync(id, includes).ConfigureAwait(false);
|
||||
}, data.Artist.CacheRegionUrn(id)).ConfigureAwait(false);
|
||||
sw.Stop();
|
||||
if (result?.Data != null && roadieUser != null)
|
||||
{
|
||||
var userBookmarkResult = await BookmarkService.ListAsync(roadieUser, new PagedRequest(), false, BookmarkType.Collection).ConfigureAwait(false);
|
||||
if (userBookmarkResult.IsSuccess)
|
||||
{
|
||||
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x?.Bookmark?.Value == result?.Data?.Id?.ToString()) != null;
|
||||
}
|
||||
if (result.Data.Comments.Any())
|
||||
{
|
||||
var commentIds = result.Data.Comments.Select(x => x.DatabaseId).ToArray();
|
||||
var userCommentReactions = (from cr in DbContext.CommentReactions
|
||||
where commentIds.Contains(cr.CommentId)
|
||||
where cr.UserId == roadieUser.Id
|
||||
select cr).ToArray();
|
||||
foreach (var comment in result.Data.Comments)
|
||||
{
|
||||
var userCommentReaction =
|
||||
userCommentReactions.FirstOrDefault(x => x.CommentId == comment.DatabaseId);
|
||||
comment.IsDisliked = userCommentReaction?.ReactionValue == CommentReaction.Dislike;
|
||||
comment.IsLiked = userCommentReaction?.ReactionValue == CommentReaction.Like;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new OperationResult<Collection>(result.Messages)
|
||||
{
|
||||
Data = result?.Data,
|
||||
IsNotFoundResult = result?.IsNotFoundResult ?? false,
|
||||
Errors = result?.Errors,
|
||||
IsSuccess = result?.IsSuccess ?? false,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteCollectionAsync(User user, Guid id)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var collection = DbContext.Collections.FirstOrDefault(x => x.RoadieId == id);
|
||||
if (collection == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Collection Not Found [{id}]");
|
||||
}
|
||||
|
||||
if (!user.IsEditor)
|
||||
{
|
||||
Logger.LogWarning($"DeleteCollection: Access Denied: `{collection}`, By User `{user}`");
|
||||
var r = new OperationResult<bool>("Access Denied");
|
||||
r.IsAccessDeniedResult = true;
|
||||
return r;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
DbContext.Collections.Remove(collection);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
await BookmarkService.RemoveAllBookmarksForItemAsync(BookmarkType.Collection, collection.Id).ConfigureAwait(false);
|
||||
var collectionImageFilename = collection.PathToImage(Configuration);
|
||||
if (File.Exists(collectionImageFilename))
|
||||
{
|
||||
File.Delete(collectionImageFilename);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
Logger.LogWarning($"DeleteCollection `{collection}`, By User `{user}`");
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public Task<Library.Models.Pagination.PagedResult<CollectionList>> ListAsync(User roadieUser, PagedRequest request,
|
||||
bool? doRandomize = false, Guid? releaseId = null, Guid? artistId = null)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
IQueryable<data.Collection> collections = null;
|
||||
if (artistId.HasValue)
|
||||
{
|
||||
collections = (from cr in DbContext.CollectionReleases
|
||||
join c in DbContext.Collections on cr.CollectionId equals c.Id
|
||||
join r in DbContext.Releases on cr.ReleaseId equals r.Id
|
||||
join a in DbContext.Artists on r.ArtistId equals a.Id
|
||||
where a.RoadieId == artistId
|
||||
select c).Distinct();
|
||||
}
|
||||
else if (releaseId.HasValue)
|
||||
{
|
||||
collections = (from cr in DbContext.CollectionReleases
|
||||
join c in DbContext.Collections on cr.CollectionId equals c.Id
|
||||
join r in DbContext.Releases on cr.ReleaseId equals r.Id
|
||||
where r.RoadieId == releaseId
|
||||
select c).Distinct();
|
||||
}
|
||||
else
|
||||
{
|
||||
collections = DbContext.Collections;
|
||||
}
|
||||
|
||||
var normalizedFilterValue = !string.IsNullOrEmpty(request.FilterValue)
|
||||
? request.FilterValue.ToAlphanumericName()
|
||||
: null;
|
||||
|
||||
var result = from c in collections
|
||||
let collectionCount = (from crc in DbContext.CollectionReleases
|
||||
where crc.CollectionId == c.Id
|
||||
select crc.Id).Count()
|
||||
where string.IsNullOrEmpty(normalizedFilterValue) || (
|
||||
c.Name.ToLower().Contains(normalizedFilterValue) ||
|
||||
c.SortName.ToLower().Contains(normalizedFilterValue) ||
|
||||
c.AlternateNames.ToLower().Contains(normalizedFilterValue)
|
||||
)
|
||||
where request.FilterToStatusValue == Statuses.Ok || c.Status == request.FilterToStatusValue
|
||||
select new CollectionList
|
||||
{
|
||||
DatabaseId = c.Id,
|
||||
Collection = new DataToken
|
||||
{
|
||||
Text = c.Name,
|
||||
Value = c.RoadieId.ToString()
|
||||
},
|
||||
Id = c.RoadieId,
|
||||
CollectionCount = c.CollectionCount,
|
||||
CollectionType = (c.CollectionType ?? CollectionType.Unknown).ToString(),
|
||||
CollectionFoundCount = collectionCount,
|
||||
CreatedDate = c.CreatedDate,
|
||||
IsLocked = c.IsLocked,
|
||||
LastUpdated = c.LastUpdated,
|
||||
Thumbnail = ImageHelper.MakeCollectionThumbnailImage(Configuration, HttpContext, c.RoadieId)
|
||||
};
|
||||
|
||||
var sortBy = string.IsNullOrEmpty(request.Sort)
|
||||
? request.OrderValue(new Dictionary<string, string> { { "Collection.Text", "ASC" } })
|
||||
: request.OrderValue();
|
||||
var rowCount = result.Count();
|
||||
var rows = result
|
||||
.OrderBy(sortBy)
|
||||
.Skip(request.SkipValue)
|
||||
.Take(request.LimitValue)
|
||||
.ToArray();
|
||||
if (request.FilterToStatusValue == Statuses.Incomplete)
|
||||
{
|
||||
rows = rows.OrderByDescending(x => x.PercentComplete).ThenBy(x => x.SortName).ToArray();
|
||||
}
|
||||
sw.Stop();
|
||||
return Task.FromResult(new Library.Models.Pagination.PagedResult<CollectionList>
|
||||
{
|
||||
TotalCount = rowCount,
|
||||
CurrentPage = request.PageValue,
|
||||
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Rows = rows
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates (or Adds) Collection
|
||||
/// </summary>
|
||||
public async Task<OperationResult<bool>> UpdateCollectionAsync(User user, Collection model)
|
||||
{
|
||||
var isNew = model.Id == Guid.Empty;
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
|
||||
var collection = new data.Collection();
|
||||
|
||||
if (!isNew)
|
||||
{
|
||||
collection = DbContext.Collections.FirstOrDefault(x => x.RoadieId == model.Id);
|
||||
if (collection == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Collection Not Found [{model.Id}]");
|
||||
}
|
||||
// If collection is being renamed, see if collection already exists with new model supplied name
|
||||
var collectionName = collection.SortNameValue;
|
||||
var collectionModelName = model.SortNameValue;
|
||||
if (collectionName.ToAlphanumericName() != collectionModelName.ToAlphanumericName())
|
||||
{
|
||||
var existingCollection = DbContext.Collections.FirstOrDefault(x => x.Name == model.Name || x.SortName == model.SortName);
|
||||
if (existingCollection != null)
|
||||
{
|
||||
return new OperationResult<bool>($"Collection already exists `{ collection }` with name [{ collectionModelName }].");
|
||||
}
|
||||
}
|
||||
}
|
||||
collection.IsLocked = model.IsLocked;
|
||||
var oldPathToImage = collection.PathToImage(Configuration);
|
||||
var didChangeName = collection.Name != model.Name && !isNew;
|
||||
collection.Name = model.Name;
|
||||
collection.SortName = model.SortName;
|
||||
collection.Edition = model.Edition;
|
||||
collection.ListInCSVFormat = model.ListInCSVFormat;
|
||||
collection.ListInCSV = model.ListInCSV;
|
||||
collection.Description = model.Description;
|
||||
collection.URLs = model.URLs;
|
||||
collection.Status = SafeParser.ToEnum<Statuses>(model.Status);
|
||||
collection.CollectionType = SafeParser.ToEnum<CollectionType>(model.CollectionType);
|
||||
collection.Tags = model.TagsList.ToDelimitedList();
|
||||
collection.URLs = model.URLsList.ToDelimitedList();
|
||||
collection.AlternateNames = model.AlternateNamesList.ToDelimitedList();
|
||||
collection.CollectionCount = model.CollectionCount;
|
||||
|
||||
if (model.Maintainer?.Value != null)
|
||||
{
|
||||
var maintainer = await DbContext.Users.FirstOrDefaultAsync(x => x.RoadieId == SafeParser.ToGuid(model.Maintainer.Value)).ConfigureAwait(false);
|
||||
if (maintainer != null)
|
||||
{
|
||||
collection.MaintainerId = maintainer.Id;
|
||||
}
|
||||
}
|
||||
|
||||
if (isNew)
|
||||
{
|
||||
await DbContext.Collections.AddAsync(collection).ConfigureAwait(false);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (didChangeName)
|
||||
{
|
||||
if (File.Exists(oldPathToImage))
|
||||
{
|
||||
File.Move(oldPathToImage, collection.PathToImage(Configuration));
|
||||
}
|
||||
}
|
||||
|
||||
var collectionImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
|
||||
if (collectionImage != null)
|
||||
{
|
||||
// Save unaltered collection image
|
||||
File.WriteAllBytes(collection.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(collectionImage));
|
||||
}
|
||||
|
||||
collection.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
CacheManager.ClearRegion(collection.CacheRegion);
|
||||
Logger.LogInformation($"UpdateCollection `{collection}` By User `{user}`");
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Roadie.Library;
|
||||
using Roadie.Library.Caching;
|
||||
using Roadie.Library.Configuration;
|
||||
|
@ -28,15 +29,85 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> AddNewArtistComment(User user, Guid artistId, string cmt)
|
||||
private void ClearCaches(data.Comment comment)
|
||||
{
|
||||
switch (comment.CommentType)
|
||||
{
|
||||
case CommentType.Artist:
|
||||
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == comment.ArtistId);
|
||||
if (artist != null)
|
||||
{
|
||||
CacheManager.ClearRegion(artist.CacheRegion);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CommentType.Collection:
|
||||
var collection = DbContext.Collections.FirstOrDefault(x => x.Id == comment.CollectionId);
|
||||
if (collection != null)
|
||||
{
|
||||
CacheManager.ClearRegion(collection.CacheRegion);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CommentType.Genre:
|
||||
var genre = DbContext.Genres.FirstOrDefault(x => x.Id == comment.GenreId);
|
||||
if (genre != null)
|
||||
{
|
||||
CacheManager.ClearRegion(genre.CacheRegion);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CommentType.Label:
|
||||
var label = DbContext.Labels.FirstOrDefault(x => x.Id == comment.LabelId);
|
||||
if (label != null)
|
||||
{
|
||||
CacheManager.ClearRegion(label.CacheRegion);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CommentType.Playlist:
|
||||
var playlist = DbContext.Playlists.FirstOrDefault(x => x.Id == comment.PlaylistId);
|
||||
if (playlist != null)
|
||||
{
|
||||
CacheManager.ClearRegion(playlist.CacheRegion);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CommentType.Release:
|
||||
var release = DbContext.Releases.FirstOrDefault(x => x.Id == comment.ReleaseId);
|
||||
if (release != null)
|
||||
{
|
||||
CacheManager.ClearRegion(release.CacheRegion);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CommentType.Track:
|
||||
var track = DbContext.Tracks.FirstOrDefault(x => x.Id == comment.TrackId);
|
||||
if (track != null)
|
||||
{
|
||||
CacheManager.ClearRegion(track.CacheRegion);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> AddNewArtistCommentAsync(User user, Guid artistId, string cmt)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
var result = false;
|
||||
var errors = new List<Exception>();
|
||||
var artist = DbContext.Artists
|
||||
.FirstOrDefault(x => x.RoadieId == artistId);
|
||||
var artist = await DbContext.Artists.FirstOrDefaultAsync(x => x.RoadieId == artistId).ConfigureAwait(false);
|
||||
if (artist == null)
|
||||
return new OperationResult<bool>(true, string.Format("Artist Not Found [{0}]", artistId));
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Artist Not Found [{artistId}]");
|
||||
}
|
||||
|
||||
var newComment = new data.Comment
|
||||
{
|
||||
|
@ -44,8 +115,8 @@ namespace Roadie.Api.Services
|
|||
UserId = user.Id.Value,
|
||||
Cmt = cmt
|
||||
};
|
||||
DbContext.Comments.Add(newComment);
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
CacheManager.ClearRegion(artist.CacheRegion);
|
||||
sw.Stop();
|
||||
result = true;
|
||||
|
@ -58,15 +129,16 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> AddNewCollectionComment(User user, Guid collectionId, string cmt)
|
||||
public async Task<OperationResult<bool>> AddNewCollectionCommentAsync(User user, Guid collectionId, string cmt)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
var result = false;
|
||||
var errors = new List<Exception>();
|
||||
var collection = DbContext.Collections
|
||||
.FirstOrDefault(x => x.RoadieId == collectionId);
|
||||
var collection = await DbContext.Collections.FirstOrDefaultAsync(x => x.RoadieId == collectionId).ConfigureAwait(false);
|
||||
if (collection == null)
|
||||
return new OperationResult<bool>(true, string.Format("Collection Not Found [{0}]", collectionId));
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Collection Not Found [{collectionId}]");
|
||||
}
|
||||
|
||||
var newComment = new data.Comment
|
||||
{
|
||||
|
@ -74,8 +146,8 @@ namespace Roadie.Api.Services
|
|||
UserId = user.Id.Value,
|
||||
Cmt = cmt
|
||||
};
|
||||
DbContext.Comments.Add(newComment);
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
CacheManager.ClearRegion(collection.CacheRegion);
|
||||
sw.Stop();
|
||||
result = true;
|
||||
|
@ -88,14 +160,16 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> AddNewGenreComment(User user, Guid genreId, string cmt)
|
||||
public async Task<OperationResult<bool>> AddNewGenreCommentAsync(User user, Guid genreId, string cmt)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
var result = false;
|
||||
var errors = new List<Exception>();
|
||||
var genre = DbContext.Genres
|
||||
.FirstOrDefault(x => x.RoadieId == genreId);
|
||||
if (genre == null) return new OperationResult<bool>(true, string.Format("Genre Not Found [{0}]", genreId));
|
||||
var genre = await DbContext.Genres.FirstOrDefaultAsync(x => x.RoadieId == genreId).ConfigureAwait(false);
|
||||
if (genre == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Genre Not Found [{genreId}]");
|
||||
}
|
||||
|
||||
var newComment = new data.Comment
|
||||
{
|
||||
|
@ -103,8 +177,8 @@ namespace Roadie.Api.Services
|
|||
UserId = user.Id.Value,
|
||||
Cmt = cmt
|
||||
};
|
||||
DbContext.Comments.Add(newComment);
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
CacheManager.ClearRegion(genre.CacheRegion);
|
||||
sw.Stop();
|
||||
result = true;
|
||||
|
@ -117,14 +191,16 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> AddNewLabelComment(User user, Guid labelId, string cmt)
|
||||
public async Task<OperationResult<bool>> AddNewLabelCommentAsync(User user, Guid labelId, string cmt)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
var result = false;
|
||||
var errors = new List<Exception>();
|
||||
var label = DbContext.Labels
|
||||
.FirstOrDefault(x => x.RoadieId == labelId);
|
||||
if (label == null) return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", labelId));
|
||||
var label = await DbContext.Labels.FirstOrDefaultAsync(x => x.RoadieId == labelId).ConfigureAwait(false);
|
||||
if (label == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Label Not Found [{labelId}]");
|
||||
}
|
||||
|
||||
var newComment = new data.Comment
|
||||
{
|
||||
|
@ -132,8 +208,8 @@ namespace Roadie.Api.Services
|
|||
UserId = user.Id.Value,
|
||||
Cmt = cmt
|
||||
};
|
||||
DbContext.Comments.Add(newComment);
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
CacheManager.ClearRegion(label.CacheRegion);
|
||||
sw.Stop();
|
||||
result = true;
|
||||
|
@ -146,15 +222,16 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> AddNewPlaylistComment(User user, Guid playlistId, string cmt)
|
||||
public async Task<OperationResult<bool>> AddNewPlaylistCommentAsync(User user, Guid playlistId, string cmt)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
var result = false;
|
||||
var errors = new List<Exception>();
|
||||
var playlist = DbContext.Playlists
|
||||
.FirstOrDefault(x => x.RoadieId == playlistId);
|
||||
var playlist = await DbContext.Playlists.FirstOrDefaultAsync(x => x.RoadieId == playlistId).ConfigureAwait(false);
|
||||
if (playlist == null)
|
||||
return new OperationResult<bool>(true, string.Format("Playlist Not Found [{0}]", playlistId));
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Playlist Not Found [{playlistId}]");
|
||||
}
|
||||
|
||||
var newComment = new data.Comment
|
||||
{
|
||||
|
@ -162,8 +239,8 @@ namespace Roadie.Api.Services
|
|||
UserId = user.Id.Value,
|
||||
Cmt = cmt
|
||||
};
|
||||
DbContext.Comments.Add(newComment);
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
CacheManager.ClearRegion(playlist.CacheRegion);
|
||||
sw.Stop();
|
||||
result = true;
|
||||
|
@ -176,15 +253,16 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> AddNewReleaseComment(User user, Guid releaseId, string cmt)
|
||||
public async Task<OperationResult<bool>> AddNewReleaseCommentAsync(User user, Guid releaseId, string cmt)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
var result = false;
|
||||
var errors = new List<Exception>();
|
||||
var release = DbContext.Releases
|
||||
.FirstOrDefault(x => x.RoadieId == releaseId);
|
||||
var release = await DbContext.Releases.FirstOrDefaultAsync(x => x.RoadieId == releaseId).ConfigureAwait(false);
|
||||
if (release == null)
|
||||
return new OperationResult<bool>(true, string.Format("Release Not Found [{0}]", releaseId));
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Release Not Found [{releaseId}]");
|
||||
}
|
||||
|
||||
var newComment = new data.Comment
|
||||
{
|
||||
|
@ -192,8 +270,8 @@ namespace Roadie.Api.Services
|
|||
UserId = user.Id.Value,
|
||||
Cmt = cmt
|
||||
};
|
||||
DbContext.Comments.Add(newComment);
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
CacheManager.ClearRegion(release.CacheRegion);
|
||||
sw.Stop();
|
||||
result = true;
|
||||
|
@ -206,14 +284,16 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> AddNewTrackComment(User user, Guid trackId, string cmt)
|
||||
public async Task<OperationResult<bool>> AddNewTrackCommentAsync(User user, Guid trackId, string cmt)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
var result = false;
|
||||
var errors = new List<Exception>();
|
||||
var track = DbContext.Tracks
|
||||
.FirstOrDefault(x => x.RoadieId == trackId);
|
||||
if (track == null) return new OperationResult<bool>(true, string.Format("Track Not Found [{0}]", trackId));
|
||||
var track = await DbContext.Tracks.FirstOrDefaultAsync(x => x.RoadieId == trackId).ConfigureAwait(false);
|
||||
if (track == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Track Not Found [{trackId}]");
|
||||
}
|
||||
|
||||
var newComment = new data.Comment
|
||||
{
|
||||
|
@ -221,8 +301,8 @@ namespace Roadie.Api.Services
|
|||
UserId = user.Id.Value,
|
||||
Cmt = cmt
|
||||
};
|
||||
DbContext.Comments.Add(newComment);
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.Comments.AddAsync(newComment).ConfigureAwait(false);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
CacheManager.ClearRegion(track.CacheRegion);
|
||||
sw.Stop();
|
||||
result = true;
|
||||
|
@ -235,15 +315,19 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteComment(User user, Guid id)
|
||||
public async Task<OperationResult<bool>> DeleteCommentAsync(User user, Guid id)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
var result = false;
|
||||
var errors = new List<Exception>();
|
||||
var comment = DbContext.Comments.FirstOrDefault(x => x.RoadieId == id);
|
||||
if (comment == null) return new OperationResult<bool>(true, string.Format("Comment Not Found [{0}]", id));
|
||||
var comment = await DbContext.Comments.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||
if (comment == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Comment Not Found [{id}]");
|
||||
}
|
||||
|
||||
DbContext.Remove(comment);
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
ClearCaches(comment);
|
||||
sw.Stop();
|
||||
result = true;
|
||||
|
@ -256,15 +340,18 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> SetCommentReaction(User user, Guid id, CommentReaction reaction)
|
||||
public async Task<OperationResult<bool>> SetCommentReactionAsync(User user, Guid id, CommentReaction reaction)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
var result = false;
|
||||
var errors = new List<Exception>();
|
||||
var comment = DbContext.Comments.FirstOrDefault(x => x.RoadieId == id);
|
||||
if (comment == null) return new OperationResult<bool>(true, string.Format("Comment Not Found [{0}]", id));
|
||||
var userCommentReaction =
|
||||
DbContext.CommentReactions.FirstOrDefault(x => x.CommentId == comment.Id && x.UserId == user.Id);
|
||||
var comment = await DbContext.Comments.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||
if (comment == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Comment Not Found [{id}]");
|
||||
}
|
||||
|
||||
var userCommentReaction = await DbContext.CommentReactions.FirstOrDefaultAsync(x => x.CommentId == comment.Id && x.UserId == user.Id).ConfigureAwait(false);
|
||||
if (userCommentReaction == null)
|
||||
{
|
||||
userCommentReaction = new data.CommentReaction
|
||||
|
@ -272,20 +359,20 @@ namespace Roadie.Api.Services
|
|||
CommentId = comment.Id,
|
||||
UserId = user.Id.Value
|
||||
};
|
||||
DbContext.CommentReactions.Add(userCommentReaction);
|
||||
await DbContext.CommentReactions.AddAsync(userCommentReaction).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
userCommentReaction.Reaction = reaction == CommentReaction.Unknown ? null : reaction.ToString();
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
ClearCaches(comment);
|
||||
var userCommentReactions = (from cr in DbContext.CommentReactions
|
||||
var userCommentReactions = await (from cr in DbContext.CommentReactions
|
||||
where cr.CommentId == comment.Id
|
||||
select cr).ToArray();
|
||||
select cr)
|
||||
.ToArrayAsync()
|
||||
.ConfigureAwait(false);
|
||||
var additionalData = new Dictionary<string, object>();
|
||||
additionalData.Add("likedCount",
|
||||
userCommentReactions.Where(x => x.ReactionValue == CommentReaction.Like).Count());
|
||||
additionalData.Add("dislikedCount",
|
||||
userCommentReactions.Where(x => x.ReactionValue == CommentReaction.Dislike).Count());
|
||||
additionalData.Add("likedCount", userCommentReactions.Where(x => x.ReactionValue == CommentReaction.Like).Count());
|
||||
additionalData.Add("dislikedCount", userCommentReactions.Where(x => x.ReactionValue == CommentReaction.Dislike).Count());
|
||||
sw.Stop();
|
||||
result = true;
|
||||
return new OperationResult<bool>
|
||||
|
@ -297,46 +384,5 @@ namespace Roadie.Api.Services
|
|||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
private void ClearCaches(data.Comment comment)
|
||||
{
|
||||
switch (comment.CommentType)
|
||||
{
|
||||
case CommentType.Artist:
|
||||
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == comment.ArtistId);
|
||||
if (artist != null) CacheManager.ClearRegion(artist.CacheRegion);
|
||||
break;
|
||||
|
||||
case CommentType.Collection:
|
||||
var collection = DbContext.Collections.FirstOrDefault(x => x.Id == comment.CollectionId);
|
||||
if (collection != null) CacheManager.ClearRegion(collection.CacheRegion);
|
||||
break;
|
||||
|
||||
case CommentType.Genre:
|
||||
var genre = DbContext.Genres.FirstOrDefault(x => x.Id == comment.GenreId);
|
||||
if (genre != null) CacheManager.ClearRegion(genre.CacheRegion);
|
||||
break;
|
||||
|
||||
case CommentType.Label:
|
||||
var label = DbContext.Labels.FirstOrDefault(x => x.Id == comment.LabelId);
|
||||
if (label != null) CacheManager.ClearRegion(label.CacheRegion);
|
||||
break;
|
||||
|
||||
case CommentType.Playlist:
|
||||
var playlist = DbContext.Playlists.FirstOrDefault(x => x.Id == comment.PlaylistId);
|
||||
if (playlist != null) CacheManager.ClearRegion(playlist.CacheRegion);
|
||||
break;
|
||||
|
||||
case CommentType.Release:
|
||||
var release = DbContext.Releases.FirstOrDefault(x => x.Id == comment.ReleaseId);
|
||||
if (release != null) CacheManager.ClearRegion(release.CacheRegion);
|
||||
break;
|
||||
|
||||
case CommentType.Track:
|
||||
var track = DbContext.Tracks.FirstOrDefault(x => x.Id == comment.TrackId);
|
||||
if (track != null) CacheManager.ClearRegion(track.CacheRegion);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ namespace Roadie.Api.Services
|
|||
|
||||
public async Task SendEmailAsync(string email, string subject, string htmlMessage)
|
||||
{
|
||||
if(string.IsNullOrEmpty(Configuration.SmtpHost))
|
||||
if (string.IsNullOrEmpty(Configuration.SmtpHost))
|
||||
{
|
||||
Trace.WriteLine("Email Server (Configuration.SmtpHost) Not Configured", "Warning");
|
||||
return;
|
||||
|
@ -37,7 +37,7 @@ namespace Roadie.Api.Services
|
|||
mail.IsBodyHtml = true;
|
||||
mail.Body = htmlMessage;
|
||||
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
|
||||
await client.SendMailAsync(mail);
|
||||
await client.SendMailAsync(mail).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,12 +18,20 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Threading.Tasks;
|
||||
using data = Roadie.Library.Data;
|
||||
|
||||
namespace Roadie.Api.Services
|
||||
{
|
||||
public class FileDirectoryProcessorService : ServiceBase, IFileDirectoryProcessorService
|
||||
{
|
||||
|
||||
private IArtistLookupEngine ArtistLookupEngine { get; }
|
||||
|
||||
private IAudioMetaDataHelper AudioMetaDataHelper { get; }
|
||||
|
||||
private IFileProcessor FileProcessor { get; }
|
||||
private IReleaseLookupEngine ReleaseLookupEngine { get; }
|
||||
private IReleaseService ReleaseService { get; }
|
||||
|
||||
private List<int> _addedArtistIds = new List<int>();
|
||||
private List<int> _addedReleaseIds = new List<int>();
|
||||
private List<int> _addedTrackIds = new List<int>();
|
||||
|
@ -34,14 +42,6 @@ namespace Roadie.Api.Services
|
|||
|
||||
public int? ProcessLimit { get; set; }
|
||||
|
||||
private IArtistLookupEngine ArtistLookupEngine { get; }
|
||||
|
||||
private IAudioMetaDataHelper AudioMetaDataHelper { get; }
|
||||
|
||||
private IFileProcessor FileProcessor { get; }
|
||||
private IReleaseLookupEngine ReleaseLookupEngine { get; }
|
||||
private IReleaseService ReleaseService { get; }
|
||||
|
||||
public FileDirectoryProcessorService(IRoadieSettings configuration,
|
||||
IHttpEncoder httpEncoder,
|
||||
IHttpContext httpContext,
|
||||
|
@ -62,73 +62,17 @@ namespace Roadie.Api.Services
|
|||
FileProcessor = fileProcessor;
|
||||
}
|
||||
|
||||
public static OperationResult<bool> DeleteEmptyFolders(DirectoryInfo processingFolder, ILogger logger)
|
||||
{
|
||||
var result = new OperationResult<bool>();
|
||||
try
|
||||
{
|
||||
result.IsSuccess = FolderPathHelper.DeleteEmptyFolders(processingFolder);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, string.Format("Error Deleting Empty Folder [{0}] Error [{1}]", processingFolder.FullName, ex.Serialize()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> Process(User user, DirectoryInfo folder, bool doJustInfo, int? submissionId = null, bool doDeleteFiles = true)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
await PreProcessFolder(folder, doJustInfo);
|
||||
var processedFiles = 0;
|
||||
var pluginResultInfos = new List<PluginResultInfo>();
|
||||
var errors = new List<string>();
|
||||
|
||||
_addedArtistIds.Clear();
|
||||
_addedReleaseIds.Clear();
|
||||
_addedTrackIds.Clear();
|
||||
|
||||
FileProcessor.SubmissionId = submissionId;
|
||||
|
||||
foreach (var file in Directory.EnumerateFiles(folder.FullName, "*.*", SearchOption.AllDirectories)
|
||||
.ToArray())
|
||||
{
|
||||
var operation = await FileProcessor.Process(file, doJustInfo);
|
||||
if (operation != null && operation.AdditionalData != null &&
|
||||
operation.AdditionalData.ContainsKey(PluginResultInfo.AdditionalDataKeyPluginResultInfo))
|
||||
{
|
||||
pluginResultInfos.Add(operation.AdditionalData[PluginResultInfo.AdditionalDataKeyPluginResultInfo] as PluginResultInfo);
|
||||
processedFiles++;
|
||||
}
|
||||
if (ProcessLimit.HasValue && processedFiles > ProcessLimit.Value) break;
|
||||
}
|
||||
|
||||
await PostProcessFolder(user, folder, pluginResultInfos, doJustInfo, doDeleteFiles);
|
||||
sw.Stop();
|
||||
_addedArtistIds.AddRange(ArtistLookupEngine.AddedArtistIds);
|
||||
_addedReleaseIds.AddRange(ReleaseLookupEngine.AddedReleaseIds);
|
||||
_addedTrackIds.AddRange(ReleaseLookupEngine.AddedTrackIds);
|
||||
Logger.LogInformation("Completed! Processed Folder [{0}]: Processed Files [{1}] : Elapsed Time [{2}]", folder.FullName, processedFiles, sw.Elapsed);
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
AdditionalData = new Dictionary<string, object> { { "ProcessedFiles", processedFiles } },
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform any operations to the given folder and the plugin results after processing
|
||||
/// </summary>
|
||||
private async Task<bool> PostProcessFolder(User user, DirectoryInfo inboundFolder, IEnumerable<PluginResultInfo> pluginResults, bool doJustInfo, bool doDeleteFiles = true)
|
||||
private async Task<bool> PostProcessFolderAsync(User user, DirectoryInfo inboundFolder, IEnumerable<PluginResultInfo> pluginResults, bool doJustInfo, bool doDeleteFiles = true)
|
||||
{
|
||||
SimpleContract.Requires<ArgumentNullException>(inboundFolder != null, "Invalid InboundFolder");
|
||||
if (pluginResults != null)
|
||||
{
|
||||
foreach (var releasesInfo in pluginResults.GroupBy(x => x.ReleaseId).Select(x => x.First()))
|
||||
{
|
||||
await ReleaseService.ScanReleaseFolder(user, releasesInfo.ReleaseId, doJustInfo);
|
||||
await ReleaseService.ScanReleaseFolderAsync(user, releasesInfo.ReleaseId, doJustInfo).ConfigureAwait(false);
|
||||
_addedTrackIds.AddRange(ReleaseService.AddedTrackIds);
|
||||
}
|
||||
}
|
||||
|
@ -136,6 +80,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
var fileExtensionsToDelete = Configuration.FileExtensionsToDelete ?? new string[0];
|
||||
if (fileExtensionsToDelete.Any())
|
||||
{
|
||||
foreach (var fileInFolder in inboundFolder.GetFiles("*.*", SearchOption.AllDirectories))
|
||||
{
|
||||
if (fileExtensionsToDelete.Any(x => x.Equals(fileInFolder.Extension, StringComparison.OrdinalIgnoreCase)))
|
||||
|
@ -148,6 +93,7 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DeleteEmptyFolders(inboundFolder, Logger);
|
||||
}
|
||||
|
@ -158,9 +104,67 @@ namespace Roadie.Api.Services
|
|||
/// <summary>
|
||||
/// Perform any operations to the given folder before processing
|
||||
/// </summary>
|
||||
private Task<bool> PreProcessFolder(DirectoryInfo inboundFolder, bool doJustInfo = false)
|
||||
private Task<bool> PreProcessFolderAsync(DirectoryInfo inboundFolder, bool doJustInfo = false)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
public static OperationResult<bool> DeleteEmptyFolders(DirectoryInfo processingFolder, ILogger logger)
|
||||
{
|
||||
var result = new OperationResult<bool>();
|
||||
try
|
||||
{
|
||||
result.IsSuccess = FolderPathHelper.DeleteEmptyFolders(processingFolder);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, $"Error Deleting Empty Folder [{processingFolder.FullName}] Error [{ex.Serialize()}]");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ProcessAsync(User user, DirectoryInfo folder, bool doJustInfo, int? submissionId = null, bool doDeleteFiles = true)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
await PreProcessFolderAsync(folder, doJustInfo).ConfigureAwait(false);
|
||||
var processedFiles = 0;
|
||||
var pluginResultInfos = new List<PluginResultInfo>();
|
||||
var errors = new List<string>();
|
||||
|
||||
_addedArtistIds.Clear();
|
||||
_addedReleaseIds.Clear();
|
||||
_addedTrackIds.Clear();
|
||||
|
||||
FileProcessor.SubmissionId = submissionId;
|
||||
|
||||
foreach (var file in Directory.EnumerateFiles(folder.FullName, "*.*", SearchOption.AllDirectories) .ToArray())
|
||||
{
|
||||
var operation = await FileProcessor.Process(file, doJustInfo).ConfigureAwait(false);
|
||||
if (operation != null && operation.AdditionalData != null &&
|
||||
operation.AdditionalData.ContainsKey(PluginResultInfo.AdditionalDataKeyPluginResultInfo))
|
||||
{
|
||||
pluginResultInfos.Add(operation.AdditionalData[PluginResultInfo.AdditionalDataKeyPluginResultInfo] as PluginResultInfo);
|
||||
processedFiles++;
|
||||
}
|
||||
if (ProcessLimit.HasValue && processedFiles > ProcessLimit.Value)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
await PostProcessFolderAsync(user, folder, pluginResultInfos, doJustInfo, doDeleteFiles).ConfigureAwait(false);
|
||||
sw.Stop();
|
||||
_addedArtistIds.AddRange(ArtistLookupEngine.AddedArtistIds);
|
||||
_addedReleaseIds.AddRange(ReleaseLookupEngine.AddedReleaseIds);
|
||||
_addedTrackIds.AddRange(ReleaseLookupEngine.AddedTrackIds);
|
||||
Logger.LogInformation("Completed! Processed Folder [{0}]: Processed Files [{1}] : Elapsed Time [{2}]", folder.FullName, processedFiles, sw.Elapsed);
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
AdditionalData = new Dictionary<string, object> { { "ProcessedFiles", processedFiles } },
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,11 +9,9 @@ using Roadie.Library.Data.Context;
|
|||
using Roadie.Library.Encoding;
|
||||
using Roadie.Library.Enums;
|
||||
using Roadie.Library.Extensions;
|
||||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Imaging;
|
||||
using Roadie.Library.Models;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
using Roadie.Library.Models.Users;
|
||||
using Roadie.Library.Utility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -38,15 +36,109 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Genre>> ById(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null)
|
||||
private Task<OperationResult<Genre>> GenreByIdAction(Guid id, IEnumerable<string> includes = null)
|
||||
{
|
||||
var timings = new Dictionary<string, long>();
|
||||
var tsw = new Stopwatch();
|
||||
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
|
||||
var genre = DbContext.Genres.FirstOrDefault(x => x.RoadieId == id);
|
||||
if (genre == null)
|
||||
{
|
||||
return Task.FromResult(new OperationResult<Genre>(true, $"Genre Not Found [{id}]"));
|
||||
}
|
||||
tsw.Stop();
|
||||
timings.Add("getGenre", tsw.ElapsedMilliseconds);
|
||||
|
||||
tsw.Restart();
|
||||
var result = genre.Adapt<Genre>();
|
||||
result.AlternateNames = genre.AlternateNames;
|
||||
result.Tags = genre.Tags;
|
||||
result.Thumbnail = ImageHelper.MakeGenreThumbnailImage(Configuration, HttpContext, genre.RoadieId);
|
||||
result.MediumThumbnail = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "genre", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
|
||||
tsw.Stop();
|
||||
timings.Add("adapt", tsw.ElapsedMilliseconds);
|
||||
if (includes != null && includes.Any())
|
||||
{
|
||||
if (includes.Contains("stats"))
|
||||
{
|
||||
tsw.Restart();
|
||||
var releaseCount = (from rg in DbContext.ReleaseGenres
|
||||
where rg.GenreId == genre.Id
|
||||
select rg.Id).Count();
|
||||
var artistCount = (from rg in DbContext.ArtistGenres
|
||||
where rg.GenreId == genre.Id
|
||||
select rg.Id).Count();
|
||||
result.Statistics = new Library.Models.Statistics.ReleaseGroupingStatistics
|
||||
{
|
||||
ArtistCount = artistCount,
|
||||
ReleaseCount = releaseCount
|
||||
};
|
||||
tsw.Stop();
|
||||
timings.Add("stats", tsw.ElapsedMilliseconds);
|
||||
}
|
||||
}
|
||||
sw.Stop();
|
||||
Logger.LogInformation($"ByIdAction: Genre `{ genre }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]");
|
||||
return Task.FromResult(new OperationResult<Genre>
|
||||
{
|
||||
Data = result,
|
||||
IsSuccess = result != null,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<OperationResult<Library.Models.Image>> SaveImageBytes(Library.Models.Users.User user, Guid id, byte[] imageBytes)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var genre = await DbContext.Genres.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||
if (genre == null)
|
||||
{
|
||||
return new OperationResult<Library.Models.Image>(true, $"Genre Not Found [{id}]");
|
||||
}
|
||||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
if (imageBytes != null)
|
||||
{
|
||||
// Save unaltered genre image
|
||||
File.WriteAllBytes(genre.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(imageBytes));
|
||||
}
|
||||
genre.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
CacheManager.ClearRegion(genre.CacheRegion);
|
||||
Logger.LogInformation($"UploadGenreImage `{genre}` By User `{user}`");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<Library.Models.Image>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "genre", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height, true),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Genre>> ByIdAsync(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
var cacheKey = string.Format("urn:genre_by_id_operation:{0}:{1}", id, includes == null ? "0" : string.Join("|", includes));
|
||||
var cacheKey = $"urn:genre_by_id_operation:{id}:{(includes == null ? "0" : string.Join("|", includes))}";
|
||||
var result = await CacheManager.GetAsync(cacheKey, async () =>
|
||||
{
|
||||
return await GenreByIdAction(id, includes);
|
||||
}, data.Genre.CacheRegionUrn(id));
|
||||
return await GenreByIdAction(id, includes).ConfigureAwait(false);
|
||||
}, data.Genre.CacheRegionUrn(id)).ConfigureAwait(false);
|
||||
sw.Stop();
|
||||
return new OperationResult<Genre>(result.Messages)
|
||||
{
|
||||
|
@ -58,14 +150,18 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> Delete(Library.Identity.User user, Guid id)
|
||||
public async Task<OperationResult<bool>> DeleteAsync(Library.Identity.User user, Guid id)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var genre = DbContext.Genres.FirstOrDefault(x => x.RoadieId == id);
|
||||
if (genre == null) return new OperationResult<bool>(true, string.Format("Genre Not Found [{0}]", id));
|
||||
var genre = await DbContext.Genres.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||
if (genre == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Genre Not Found [{id}]");
|
||||
}
|
||||
|
||||
DbContext.Genres.Remove(genre);
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
var genreImageFilename = genre.PathToImage(Configuration);
|
||||
if (File.Exists(genreImageFilename))
|
||||
|
@ -84,7 +180,7 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<Library.Models.Pagination.PagedResult<GenreList>> List(Library.Models.Users.User roadieUser, PagedRequest request, bool? doRandomize = false)
|
||||
public async Task<Library.Models.Pagination.PagedResult<GenreList>> ListAsync(Library.Models.Users.User roadieUser, PagedRequest request, bool? doRandomize = false)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -102,7 +198,7 @@ namespace Roadie.Api.Services
|
|||
if (doRandomize ?? false)
|
||||
{
|
||||
var randomLimit = request.Limit ?? roadieUser?.RandomReleaseLimit ?? request.LimitValue;
|
||||
randomGenreData = await DbContext.RandomGenreIds(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly);
|
||||
randomGenreData = await DbContext.RandomGenreIdsAsync(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly).ConfigureAwait(false);
|
||||
randomGenreIds = randomGenreData.Select(x => x.Value).ToArray();
|
||||
rowCount = DbContext.Genres.Count();
|
||||
}
|
||||
|
@ -169,20 +265,17 @@ namespace Roadie.Api.Services
|
|||
});
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Library.Models.Image>> SetGenreImageByUrl(Library.Models.Users.User user, Guid id, string imageUrl)
|
||||
{
|
||||
return await SaveImageBytes(user, id, WebHelper.BytesForImageUrl(imageUrl));
|
||||
}
|
||||
public Task<OperationResult<Library.Models.Image>> SetGenreImageByUrlAsync(Library.Models.Users.User user, Guid id, string imageUrl) => SaveImageBytes(user, id, WebHelper.BytesForImageUrl(imageUrl));
|
||||
|
||||
public async Task<OperationResult<bool>> UpdateGenre(Library.Models.Users.User user, Genre model)
|
||||
public async Task<OperationResult<bool>> UpdateGenreAsync(Library.Models.Users.User user, Genre model)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var genre = DbContext.Genres.FirstOrDefault(x => x.RoadieId == model.Id);
|
||||
var genre = await DbContext.Genres.FirstOrDefaultAsync(x => x.RoadieId == model.Id).ConfigureAwait(false);
|
||||
if (genre == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, string.Format("Genre Not Found [{0}]", model.Id));
|
||||
return new OperationResult<bool>(true, $"Genre Not Found [{model.Id}]");
|
||||
}
|
||||
// If genre is being renamed, see if genre already exists with new model supplied name
|
||||
var genreName = genre.SortNameValue;
|
||||
|
@ -229,7 +322,7 @@ namespace Roadie.Api.Services
|
|||
File.WriteAllBytes(genre.PathToImage(Configuration), ImageHelper.ConvertToJpegFormat(genreImage));
|
||||
}
|
||||
genre.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
CacheManager.ClearRegion(genre.CacheRegion);
|
||||
Logger.LogInformation($"UpdateGenre `{genre}` By User `{user}`");
|
||||
|
@ -244,14 +337,14 @@ namespace Roadie.Api.Services
|
|||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = !errors.Any(),
|
||||
IsSuccess = errors.Count == 0,
|
||||
Data = errors.Count == 0,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Library.Models.Image>> UploadGenreImage(Library.Models.Users.User user, Guid id, IFormFile file)
|
||||
public async Task<OperationResult<Library.Models.Image>> UploadGenreImageAsync(Library.Models.Users.User user, Guid id, IFormFile file)
|
||||
{
|
||||
var bytes = new byte[0];
|
||||
using (var ms = new MemoryStream())
|
||||
|
@ -259,102 +352,7 @@ namespace Roadie.Api.Services
|
|||
file.CopyTo(ms);
|
||||
bytes = ms.ToArray();
|
||||
}
|
||||
|
||||
return await SaveImageBytes(user, id, bytes);
|
||||
}
|
||||
|
||||
private Task<OperationResult<Genre>> GenreByIdAction(Guid id, IEnumerable<string> includes = null)
|
||||
{
|
||||
var timings = new Dictionary<string, long>();
|
||||
var tsw = new Stopwatch();
|
||||
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
|
||||
var genre = DbContext.Genres.FirstOrDefault(x => x.RoadieId == id);
|
||||
if (genre == null)
|
||||
{
|
||||
return Task.FromResult(new OperationResult<Genre>(true, string.Format("Genre Not Found [{0}]", id)));
|
||||
}
|
||||
tsw.Stop();
|
||||
timings.Add("getGenre", tsw.ElapsedMilliseconds);
|
||||
|
||||
tsw.Restart();
|
||||
var result = genre.Adapt<Genre>();
|
||||
result.AlternateNames = genre.AlternateNames;
|
||||
result.Tags = genre.Tags;
|
||||
result.Thumbnail = ImageHelper.MakeGenreThumbnailImage(Configuration, HttpContext, genre.RoadieId);
|
||||
result.MediumThumbnail = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "genre", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
|
||||
tsw.Stop();
|
||||
timings.Add("adapt", tsw.ElapsedMilliseconds);
|
||||
if (includes != null && includes.Any())
|
||||
{
|
||||
if (includes.Contains("stats"))
|
||||
{
|
||||
tsw.Restart();
|
||||
var releaseCount = (from rg in DbContext.ReleaseGenres
|
||||
where rg.GenreId == genre.Id
|
||||
select rg.Id).Count();
|
||||
var artistCount = (from rg in DbContext.ArtistGenres
|
||||
where rg.GenreId == genre.Id
|
||||
select rg.Id).Count();
|
||||
result.Statistics = new Library.Models.Statistics.ReleaseGroupingStatistics
|
||||
{
|
||||
ArtistCount = artistCount,
|
||||
ReleaseCount = releaseCount
|
||||
};
|
||||
tsw.Stop();
|
||||
timings.Add("stats", tsw.ElapsedMilliseconds);
|
||||
}
|
||||
}
|
||||
sw.Stop();
|
||||
Logger.LogInformation($"ByIdAction: Genre `{ genre }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]");
|
||||
return Task.FromResult(new OperationResult<Genre>
|
||||
{
|
||||
Data = result,
|
||||
IsSuccess = result != null,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<OperationResult<Library.Models.Image>> SaveImageBytes(Library.Models.Users.User user, Guid id, byte[] imageBytes)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var genre = DbContext.Genres.FirstOrDefault(x => x.RoadieId == id);
|
||||
if (genre == null)
|
||||
{
|
||||
return new OperationResult<Library.Models.Image>(true, string.Format("Genre Not Found [{0}]", id));
|
||||
}
|
||||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
if (imageBytes != null)
|
||||
{
|
||||
// Save unaltered genre image
|
||||
File.WriteAllBytes(genre.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(imageBytes));
|
||||
}
|
||||
genre.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync();
|
||||
CacheManager.ClearRegion(genre.CacheRegion);
|
||||
Logger.LogInformation($"UploadGenreImage `{genre}` By User `{user}`");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<Library.Models.Image>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "genre", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height, true),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
return await SaveImageBytes(user, id, bytes).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,10 +14,17 @@ namespace Roadie.Api.Services
|
|||
public HttpContext(IRoadieSettings configuration, IUrlHelper urlHelper)
|
||||
{
|
||||
var scheme = urlHelper.ActionContext.HttpContext.Request.Scheme;
|
||||
if (configuration.UseSSLBehindProxy) scheme = "https";
|
||||
if (configuration.UseSSLBehindProxy)
|
||||
{
|
||||
scheme = "https";
|
||||
}
|
||||
|
||||
var host = urlHelper.ActionContext.HttpContext.Request.Host;
|
||||
if (!string.IsNullOrEmpty(configuration.BehindProxyHost))
|
||||
{
|
||||
host = new HostString(configuration.BehindProxyHost);
|
||||
}
|
||||
|
||||
BaseUrl = $"{scheme}://{host}";
|
||||
ImageBaseUrl = $"{BaseUrl}/images";
|
||||
}
|
||||
|
|
|
@ -9,48 +9,48 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public interface IAdminService
|
||||
{
|
||||
Task<OperationResult<bool>> DeleteArtist(User user, Guid artistId, bool deleteFolder);
|
||||
Task<OperationResult<bool>> DeleteArtistAsync(User user, Guid artistId, bool deleteFolder);
|
||||
|
||||
Task<OperationResult<bool>> DeleteArtistReleases(User user, Guid artistId, bool doDeleteFiles = false);
|
||||
Task<OperationResult<bool>> DeleteArtistReleasesAsync(User user, Guid artistId, bool doDeleteFiles = false);
|
||||
|
||||
Task<OperationResult<bool>> DeleteArtistSecondaryImage(User user, Guid artistId, int index);
|
||||
Task<OperationResult<bool>> DeleteArtistSecondaryImageAsync(User user, Guid artistId, int index);
|
||||
|
||||
Task<OperationResult<bool>> DeleteGenre(User user, Guid genreId);
|
||||
Task<OperationResult<bool>> DeleteGenreAsync(User user, Guid genreId);
|
||||
|
||||
Task<OperationResult<bool>> DeleteLabel(User user, Guid labelId);
|
||||
Task<OperationResult<bool>> DeleteLabelAsync(User user, Guid labelId);
|
||||
|
||||
Task<OperationResult<bool>> DeleteRelease(User user, Guid releaseId, bool? doDeleteFiles);
|
||||
Task<OperationResult<bool>> DeleteReleaseAsync(User user, Guid releaseId, bool? doDeleteFiles);
|
||||
|
||||
Task<OperationResult<bool>> DeleteReleaseSecondaryImage(User user, Guid releaseId, int index);
|
||||
Task<OperationResult<bool>> DeleteReleaseSecondaryImageAsync(User user, Guid releaseId, int index);
|
||||
|
||||
Task<OperationResult<bool>> DeleteTracks(User user, IEnumerable<Guid> trackIds, bool? doDeleteFile);
|
||||
Task<OperationResult<bool>> DeleteTracksAsync(User user, IEnumerable<Guid> trackIds, bool? doDeleteFile);
|
||||
|
||||
Task<OperationResult<bool>> DeleteUser(User applicationUser, Guid id);
|
||||
Task<OperationResult<bool>> DeleteUserAsync(User applicationUser, Guid id);
|
||||
|
||||
Task<OperationResult<bool>> DoInitialSetup(User user, UserManager<User> userManager);
|
||||
Task<OperationResult<bool>> DoInitialSetupAsync(User user, UserManager<User> userManager);
|
||||
|
||||
Task<OperationResult<Dictionary<string, List<string>>>> MissingCollectionReleases(User user);
|
||||
Task<OperationResult<Dictionary<string, List<string>>>> MissingCollectionReleasesAsync(User user);
|
||||
|
||||
void PerformStartUpTasks();
|
||||
|
||||
Task<OperationResult<bool>> ScanAllCollections(User user, bool isReadOnly = false, bool doPurgeFirst = false);
|
||||
Task<OperationResult<bool>> ScanAllCollectionsAsync(User user, bool isReadOnly = false, bool doPurgeFirst = false);
|
||||
|
||||
Task<OperationResult<bool>> ScanArtist(User user, Guid artistId, bool isReadOnly = false);
|
||||
Task<OperationResult<bool>> ScanArtistAsync(User user, Guid artistId, bool isReadOnly = false);
|
||||
|
||||
Task<OperationResult<bool>> ScanArtists(User user, IEnumerable<Guid> artistIds, bool isReadOnly = false);
|
||||
Task<OperationResult<bool>> ScanArtistsAsync(User user, IEnumerable<Guid> artistIds, bool isReadOnly = false);
|
||||
|
||||
Task<OperationResult<bool>> ScanCollection(User user, Guid collectionId, bool isReadOnly = false, bool doPurgeFirst = false, bool doUpdateRanks = true);
|
||||
Task<OperationResult<bool>> ScanCollectionAsync(User user, Guid collectionId, bool isReadOnly = false, bool doPurgeFirst = false, bool doUpdateRanks = true);
|
||||
|
||||
Task<OperationResult<bool>> ScanInboundFolder(User user, bool isReadOnly = false);
|
||||
Task<OperationResult<bool>> ScanInboundFolderAsync(User user, bool isReadOnly = false);
|
||||
|
||||
Task<OperationResult<bool>> ScanLibraryFolder(User user, bool isReadOnly = false);
|
||||
Task<OperationResult<bool>> ScanLibraryFolderAsync(User user, bool isReadOnly = false);
|
||||
|
||||
Task<OperationResult<bool>> ScanRelease(User user, Guid releaseIds, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false);
|
||||
Task<OperationResult<bool>> ScanReleaseAsync(User user, Guid releaseIds, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false);
|
||||
|
||||
Task<OperationResult<bool>> ScanReleases(User user, IEnumerable<Guid> releaseId, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false);
|
||||
Task<OperationResult<bool>> ScanReleasesAsync(User user, IEnumerable<Guid> releaseId, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false);
|
||||
|
||||
Task<OperationResult<bool>> UpdateInviteTokenUsed(Guid? tokenId);
|
||||
Task<OperationResult<bool>> UpdateInviteTokenUsedAsync(Guid? tokenId);
|
||||
|
||||
Task<OperationResult<bool>> ValidateInviteToken(Guid? tokenId);
|
||||
Task<OperationResult<bool>> ValidateInviteTokenAsync(Guid? tokenId);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,7 @@
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Roadie.Library;
|
||||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Models;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
using Roadie.Library.Models.Users;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -12,22 +10,22 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public interface IArtistService
|
||||
{
|
||||
Task<OperationResult<Artist>> ById(Library.Models.Users.User user, Guid id, IEnumerable<string> includes);
|
||||
Task<OperationResult<Artist>> ByIdAsync(Library.Models.Users.User user, Guid id, IEnumerable<string> includes);
|
||||
|
||||
Task<OperationResult<bool>> Delete(Library.Identity.User user, Library.Data.Artist Artist, bool deleteFolder);
|
||||
Task<OperationResult<bool>> DeleteAsync(Library.Identity.User user, Library.Data.Artist Artist, bool deleteFolder);
|
||||
|
||||
Task<PagedResult<ArtistList>> List(Library.Models.Users.User user, PagedRequest request, bool? doRandomize = false, bool? onlyIncludeWithReleases = true);
|
||||
Task<PagedResult<ArtistList>> ListAsync(Library.Models.Users.User user, PagedRequest request, bool? doRandomize = false, bool? onlyIncludeWithReleases = true);
|
||||
|
||||
Task<OperationResult<bool>> MergeArtists(Library.Identity.User user, Guid artistToMergeId, Guid artistToMergeIntoId);
|
||||
Task<OperationResult<bool>> MergeArtistsAsync(Library.Identity.User user, Guid artistToMergeId, Guid artistToMergeIntoId);
|
||||
|
||||
Task<OperationResult<bool>> RefreshArtistMetadata(Library.Identity.User user, Guid ArtistId);
|
||||
Task<OperationResult<bool>> RefreshArtistMetadataAsync(Library.Identity.User user, Guid ArtistId);
|
||||
|
||||
Task<OperationResult<bool>> ScanArtistReleasesFolders(Library.Identity.User user, Guid artistId, string destinationFolder, bool doJustInfo);
|
||||
Task<OperationResult<bool>> ScanArtistReleasesFoldersAsync(Library.Identity.User user, Guid artistId, string destinationFolder, bool doJustInfo);
|
||||
|
||||
Task<OperationResult<Image>> SetReleaseImageByUrl(Library.Identity.User user, Guid id, string imageUrl);
|
||||
Task<OperationResult<Image>> SetReleaseImageByUrlAsync(Library.Identity.User user, Guid id, string imageUrl);
|
||||
|
||||
Task<OperationResult<bool>> UpdateArtist(Library.Identity.User user, Artist artist);
|
||||
Task<OperationResult<bool>> UpdateArtistAsync(Library.Identity.User user, Artist artist);
|
||||
|
||||
Task<OperationResult<Image>> UploadArtistImage(Library.Identity.User user, Guid id, IFormFile file);
|
||||
Task<OperationResult<Image>> UploadArtistImageAsync(Library.Identity.User user, Guid id, IFormFile file);
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public interface IBookmarkService
|
||||
{
|
||||
Task<OperationResult<bool>> RemoveAllBookmarksForItem(BookmarkType type, int id);
|
||||
Task<PagedResult<BookmarkList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, BookmarkType? filterType = null);
|
||||
Task<PagedResult<BookmarkList>> ListAsync(User roadieUser, PagedRequest request, bool? doRandomize = false, BookmarkType? filterType = null);
|
||||
Task<OperationResult<bool>> RemoveAllBookmarksForItemAsync(BookmarkType type, int id);
|
||||
}
|
||||
}
|
|
@ -12,13 +12,12 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
OperationResult<Collection> Add(User roadieUser);
|
||||
|
||||
Task<OperationResult<Collection>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null);
|
||||
Task<OperationResult<Collection>> ByIdAsync(User roadieUser, Guid id, IEnumerable<string> includes = null);
|
||||
|
||||
Task<OperationResult<bool>> DeleteCollection(User user, Guid id);
|
||||
Task<OperationResult<bool>> DeleteCollectionAsync(User user, Guid id);
|
||||
|
||||
Task<PagedResult<CollectionList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false,
|
||||
Guid? releaseId = null, Guid? artistId = null);
|
||||
Task<PagedResult<CollectionList>> ListAsync(User roadieUser, PagedRequest request, bool? doRandomize = false, Guid? releaseId = null, Guid? artistId = null);
|
||||
|
||||
Task<OperationResult<bool>> UpdateCollection(User roadieUser, Collection collection);
|
||||
Task<OperationResult<bool>> UpdateCollectionAsync(User roadieUser, Collection collection);
|
||||
}
|
||||
}
|
|
@ -8,22 +8,22 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public interface ICommentService
|
||||
{
|
||||
Task<OperationResult<bool>> AddNewArtistComment(User user, Guid artistId, string cmt);
|
||||
Task<OperationResult<bool>> AddNewArtistCommentAsync(User user, Guid artistId, string cmt);
|
||||
|
||||
Task<OperationResult<bool>> AddNewCollectionComment(User user, Guid collectionId, string cmt);
|
||||
Task<OperationResult<bool>> AddNewCollectionCommentAsync(User user, Guid collectionId, string cmt);
|
||||
|
||||
Task<OperationResult<bool>> AddNewGenreComment(User user, Guid genreId, string cmt);
|
||||
Task<OperationResult<bool>> AddNewGenreCommentAsync(User user, Guid genreId, string cmt);
|
||||
|
||||
Task<OperationResult<bool>> AddNewLabelComment(User user, Guid labelId, string cmt);
|
||||
Task<OperationResult<bool>> AddNewLabelCommentAsync(User user, Guid labelId, string cmt);
|
||||
|
||||
Task<OperationResult<bool>> AddNewPlaylistComment(User user, Guid playlistId, string cmt);
|
||||
Task<OperationResult<bool>> AddNewPlaylistCommentAsync(User user, Guid playlistId, string cmt);
|
||||
|
||||
Task<OperationResult<bool>> AddNewReleaseComment(User user, Guid releaseId, string cmt);
|
||||
Task<OperationResult<bool>> AddNewReleaseCommentAsync(User user, Guid releaseId, string cmt);
|
||||
|
||||
Task<OperationResult<bool>> AddNewTrackComment(User user, Guid trackId, string cmt);
|
||||
Task<OperationResult<bool>> AddNewTrackCommentAsync(User user, Guid trackId, string cmt);
|
||||
|
||||
Task<OperationResult<bool>> DeleteComment(User user, Guid id);
|
||||
Task<OperationResult<bool>> DeleteCommentAsync(User user, Guid id);
|
||||
|
||||
Task<OperationResult<bool>> SetCommentReaction(User user, Guid id, CommentReaction reaction);
|
||||
Task<OperationResult<bool>> SetCommentReactionAsync(User user, Guid id, CommentReaction reaction);
|
||||
}
|
||||
}
|
|
@ -14,6 +14,6 @@ namespace Roadie.Api.Services
|
|||
|
||||
int? ProcessLimit { get; set; }
|
||||
|
||||
Task<OperationResult<bool>> Process(User user, DirectoryInfo folder, bool doJustInfo, int? submissionId = null, bool doDeleteFiles = true);
|
||||
Task<OperationResult<bool>> ProcessAsync(User user, DirectoryInfo folder, bool doJustInfo, int? submissionId = null, bool doDeleteFiles = true);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,7 @@
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Roadie.Library;
|
||||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Models;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
using Roadie.Library.Models.Users;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -12,16 +10,16 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public interface IGenreService
|
||||
{
|
||||
Task<OperationResult<Genre>> ById(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null);
|
||||
Task<OperationResult<Genre>> ByIdAsync(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null);
|
||||
|
||||
Task<OperationResult<bool>> Delete(Library.Identity.User user, Guid id);
|
||||
Task<OperationResult<bool>> DeleteAsync(Library.Identity.User user, Guid id);
|
||||
|
||||
Task<PagedResult<GenreList>> List(Library.Models.Users.User roadieUser, PagedRequest request, bool? doRandomize = false);
|
||||
Task<PagedResult<GenreList>> ListAsync(Library.Models.Users.User roadieUser, PagedRequest request, bool? doRandomize = false);
|
||||
|
||||
Task<OperationResult<Image>> SetGenreImageByUrl(Library.Models.Users.User user, Guid id, string imageUrl);
|
||||
Task<OperationResult<Image>> SetGenreImageByUrlAsync(Library.Models.Users.User user, Guid id, string imageUrl);
|
||||
|
||||
Task<OperationResult<bool>> UpdateGenre(Library.Models.Users.User user, Genre model);
|
||||
Task<OperationResult<bool>> UpdateGenreAsync(Library.Models.Users.User user, Genre model);
|
||||
|
||||
Task<OperationResult<Image>> UploadGenreImage(Library.Models.Users.User user, Guid id, IFormFile file);
|
||||
Task<OperationResult<Image>> UploadGenreImageAsync(Library.Models.Users.User user, Guid id, IFormFile file);
|
||||
}
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
using Microsoft.Net.Http.Headers;
|
||||
using Roadie.Library;
|
||||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Imaging;
|
||||
using Roadie.Library.Models;
|
||||
using Roadie.Library.SearchEngines.Imaging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -16,26 +14,26 @@ namespace Roadie.Api.Services
|
|||
|
||||
string RequestIp { get; set; }
|
||||
|
||||
Task<FileOperationResult<IImage>> ArtistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
Task<FileOperationResult<IImage>> ArtistImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
|
||||
Task<FileOperationResult<IImage>> ArtistSecondaryImage(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
Task<FileOperationResult<IImage>> ArtistSecondaryImageAsync(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
|
||||
Task<FileOperationResult<IImage>> CollectionImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
Task<FileOperationResult<IImage>> CollectionImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
|
||||
Task<FileOperationResult<IImage>> GenreImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
Task<FileOperationResult<IImage>> GenreImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
|
||||
Task<FileOperationResult<IImage>> LabelImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
Task<FileOperationResult<IImage>> LabelImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
|
||||
Task<FileOperationResult<IImage>> PlaylistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
Task<FileOperationResult<IImage>> PlaylistImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
|
||||
Task<FileOperationResult<IImage>> ReleaseImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
Task<FileOperationResult<IImage>> ReleaseImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
|
||||
Task<FileOperationResult<IImage>> ReleaseSecondaryImage(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
Task<FileOperationResult<IImage>> ReleaseSecondaryImageAsync(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
|
||||
Task<OperationResult<IEnumerable<ImageSearchResult>>> Search(string query, int resultsCount = 10);
|
||||
Task<OperationResult<IEnumerable<ImageSearchResult>>> SearchAsync(string query, int resultsCount = 10);
|
||||
|
||||
Task<FileOperationResult<IImage>> TrackImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
Task<FileOperationResult<IImage>> TrackImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
|
||||
Task<FileOperationResult<IImage>> UserImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
Task<FileOperationResult<IImage>> UserImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,7 @@
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Roadie.Library;
|
||||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Models;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
using Roadie.Library.Models.Users;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -12,18 +10,18 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public interface ILabelService
|
||||
{
|
||||
Task<OperationResult<Label>> ById(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null);
|
||||
Task<OperationResult<Label>> ByIdAsync(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null);
|
||||
|
||||
Task<OperationResult<bool>> Delete(Library.Identity.User user, Guid id);
|
||||
Task<OperationResult<bool>> DeleteAsync(Library.Identity.User user, Guid id);
|
||||
|
||||
Task<PagedResult<LabelList>> List(Library.Models.Users.User roadieUser, PagedRequest request, bool? doRandomize = false);
|
||||
Task<PagedResult<LabelList>> ListAsync(Library.Models.Users.User roadieUser, PagedRequest request, bool? doRandomize = false);
|
||||
|
||||
Task<OperationResult<bool>> MergeLabelsIntoLabel(Library.Identity.User user, Guid intoLabelId, IEnumerable<Guid> labelIdsToMerge);
|
||||
Task<OperationResult<bool>> MergeLabelsIntoLabelAsync(Library.Identity.User user, Guid intoLabelId, IEnumerable<Guid> labelIdsToMerge);
|
||||
|
||||
Task<OperationResult<Image>> SetLabelImageByUrl(Library.Models.Users.User user, Guid id, string imageUrl);
|
||||
Task<OperationResult<Image>> SetLabelImageByUrlAsync(Library.Models.Users.User user, Guid id, string imageUrl);
|
||||
|
||||
Task<OperationResult<bool>> UpdateLabel(Library.Models.Users.User user, Label label);
|
||||
Task<OperationResult<bool>> UpdateLabelAsync(Library.Models.Users.User user, Label label);
|
||||
|
||||
Task<OperationResult<Image>> UploadLabelImage(Library.Models.Users.User user, Guid id, IFormFile file);
|
||||
Task<OperationResult<Image>> UploadLabelImageAsync(Library.Models.Users.User user, Guid id, IFormFile file);
|
||||
}
|
||||
}
|
|
@ -7,24 +7,24 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public interface ILookupService
|
||||
{
|
||||
Task<OperationResult<IEnumerable<DataToken>>> ArtistTypes();
|
||||
Task<OperationResult<IEnumerable<DataToken>>> ArtistTypesAsync();
|
||||
|
||||
Task<OperationResult<IEnumerable<DataToken>>> BandStatus();
|
||||
Task<OperationResult<IEnumerable<DataToken>>> BandStatusAsync();
|
||||
|
||||
Task<OperationResult<IEnumerable<DataToken>>> BookmarkTypes();
|
||||
Task<OperationResult<IEnumerable<DataToken>>> BookmarkTypesAsync();
|
||||
|
||||
Task<OperationResult<IEnumerable<DataToken>>> CollectionTypes();
|
||||
Task<OperationResult<IEnumerable<DataToken>>> CollectionTypesAsync();
|
||||
|
||||
Task<OperationResult<IEnumerable<DataToken>>> LibraryStatus();
|
||||
Task<OperationResult<IEnumerable<DataToken>>> CreditCategoriesAsync();
|
||||
|
||||
Task<OperationResult<IEnumerable<DataToken>>> QueMessageTypes();
|
||||
Task<OperationResult<IEnumerable<DataToken>>> LibraryStatusAsync();
|
||||
|
||||
Task<OperationResult<IEnumerable<DataToken>>> ReleaseTypes();
|
||||
Task<OperationResult<IEnumerable<DataToken>>> QueMessageTypesAsync();
|
||||
|
||||
Task<OperationResult<IEnumerable<DataToken>>> RequestStatus();
|
||||
Task<OperationResult<IEnumerable<DataToken>>> ReleaseTypesAsync();
|
||||
|
||||
Task<OperationResult<IEnumerable<DataToken>>> Status();
|
||||
Task<OperationResult<IEnumerable<DataToken>>> RequestStatusAsync();
|
||||
|
||||
Task<OperationResult<IEnumerable<DataToken>>> CreditCategories();
|
||||
Task<OperationResult<IEnumerable<DataToken>>> StatusAsync();
|
||||
}
|
||||
}
|
|
@ -10,10 +10,10 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public interface IPlayActivityService
|
||||
{
|
||||
Task<PagedResult<PlayActivityList>> List(PagedRequest request, User roadieUser = null, DateTime? newerThan = null);
|
||||
Task<PagedResult<PlayActivityList>> ListAsync(PagedRequest request, User roadieUser = null, DateTime? newerThan = null);
|
||||
|
||||
Task<OperationResult<bool>> NowPlaying(User roadieUser, ScrobbleInfo scrobble);
|
||||
Task<OperationResult<bool>> NowPlayingAsync(User roadieUser, ScrobbleInfo scrobble);
|
||||
|
||||
Task<OperationResult<bool>> Scrobble(User roadieUser, ScrobbleInfo scrobble);
|
||||
Task<OperationResult<bool>> ScrobbleAsync(User roadieUser, ScrobbleInfo scrobble);
|
||||
}
|
||||
}
|
|
@ -11,20 +11,20 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public interface IPlaylistService
|
||||
{
|
||||
Task<OperationResult<PlaylistList>> AddNewPlaylist(User user, Playlist model);
|
||||
Task<OperationResult<PlaylistList>> AddNewPlaylistAsync(User user, Playlist model);
|
||||
|
||||
Task<OperationResult<bool>> AddTracksToPlaylist(data.Playlist playlist, IEnumerable<Guid> trackIds);
|
||||
Task<OperationResult<bool>> AddTracksToPlaylistAsync(data.Playlist playlist, IEnumerable<Guid> trackIds);
|
||||
|
||||
Task<OperationResult<Playlist>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null);
|
||||
Task<OperationResult<Playlist>> ByIdAsync(User roadieUser, Guid id, IEnumerable<string> includes = null);
|
||||
|
||||
Task<OperationResult<bool>> DeletePlaylist(User user, Guid id);
|
||||
Task<OperationResult<bool>> DeletePlaylistAsync(User user, Guid id);
|
||||
|
||||
Task<PagedResult<PlaylistList>> List(PagedRequest request, User roadieUser = null);
|
||||
Task<PagedResult<PlaylistList>> ListAsync(PagedRequest request, User roadieUser = null);
|
||||
|
||||
Task<OperationResult<bool>> ReorderPlaylist(data.Playlist playlist);
|
||||
Task<OperationResult<bool>> ReorderPlaylistAsync(data.Playlist playlist);
|
||||
|
||||
Task<OperationResult<bool>> UpdatePlaylist(User user, Playlist label);
|
||||
Task<OperationResult<bool>> UpdatePlaylistAsync(User user, Playlist label);
|
||||
|
||||
Task<OperationResult<bool>> UpdatePlaylistTracks(User user, PlaylistTrackModifyRequest request);
|
||||
Task<OperationResult<bool>> UpdatePlaylistTracksAsync(User user, PlaylistTrackModifyRequest request);
|
||||
}
|
||||
}
|
|
@ -1,10 +1,8 @@
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Roadie.Library;
|
||||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Models;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
using Roadie.Library.Models.Releases;
|
||||
using Roadie.Library.Models.Users;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -15,26 +13,26 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
IEnumerable<int> AddedTrackIds { get; }
|
||||
|
||||
Task<OperationResult<Release>> ById(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null);
|
||||
Task<OperationResult<Release>> ByIdAsync(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null);
|
||||
|
||||
Task<OperationResult<bool>> Delete(Library.Identity.User user, Library.Data.Release release, bool doDeleteFiles = false, bool doUpdateArtistCounts = true);
|
||||
Task<OperationResult<bool>> DeleteAsync(Library.Identity.User user, Library.Data.Release release, bool doDeleteFiles = false, bool doUpdateArtistCounts = true);
|
||||
|
||||
Task<OperationResult<bool>> DeleteReleases(Library.Identity.User user, IEnumerable<Guid> releaseIds, bool doDeleteFiles = false);
|
||||
Task<OperationResult<bool>> DeleteReleasesAsync(Library.Identity.User user, IEnumerable<Guid> releaseIds, bool doDeleteFiles = false);
|
||||
|
||||
Task<PagedResult<ReleaseList>> List(Library.Models.Users.User user, PagedRequest request, bool? doRandomize = false, IEnumerable<string> includes = null);
|
||||
Task<PagedResult<ReleaseList>> ListAsync(Library.Models.Users.User user, PagedRequest request, bool? doRandomize = false, IEnumerable<string> includes = null);
|
||||
|
||||
Task<OperationResult<bool>> MergeReleases(Library.Identity.User user, Guid releaseToMergeId, Guid releaseToMergeIntoId, bool addAsMedia);
|
||||
Task<OperationResult<bool>> MergeReleasesAsync(Library.Identity.User user, Guid releaseToMergeId, Guid releaseToMergeIntoId, bool addAsMedia);
|
||||
|
||||
Task<OperationResult<bool>> MergeReleases(Library.Identity.User user, Library.Data.Release releaseToMerge, Library.Data.Release releaseToMergeInto, bool addAsMedia);
|
||||
Task<OperationResult<bool>> MergeReleasesAsync(Library.Identity.User user, Library.Data.Release releaseToMerge, Library.Data.Release releaseToMergeInto, bool addAsMedia);
|
||||
|
||||
Task<FileOperationResult<byte[]>> ReleaseZipped(Library.Models.Users.User roadieUser, Guid id);
|
||||
Task<FileOperationResult<byte[]>> ReleaseZippedAsync(Library.Models.Users.User roadieUser, Guid id);
|
||||
|
||||
Task<OperationResult<bool>> ScanReleaseFolder(Library.Identity.User user, Guid releaseId, bool doJustInfo, Library.Data.Release releaseToScan = null);
|
||||
Task<OperationResult<bool>> ScanReleaseFolderAsync(Library.Identity.User user, Guid releaseId, bool doJustInfo, Library.Data.Release releaseToScan = null);
|
||||
|
||||
Task<OperationResult<Image>> SetReleaseImageByUrl(Library.Identity.User user, Guid id, string imageUrl);
|
||||
Task<OperationResult<Image>> SetReleaseImageByUrlAsync(Library.Identity.User user, Guid id, string imageUrl);
|
||||
|
||||
Task<OperationResult<bool>> UpdateRelease(Library.Identity.User user, Release release, string originalReleaseFolder = null);
|
||||
Task<OperationResult<bool>> UpdateReleaseAsync(Library.Identity.User user, Release release, string originalReleaseFolder = null);
|
||||
|
||||
Task<OperationResult<Image>> UploadReleaseImage(Library.Identity.User user, Guid id, IFormFile file);
|
||||
Task<OperationResult<Image>> UploadReleaseImageAsync(Library.Identity.User user, Guid id, IFormFile file);
|
||||
}
|
||||
}
|
|
@ -7,17 +7,17 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public interface IStatisticsService
|
||||
{
|
||||
Task<OperationResult<LibraryStats>> LibraryStatistics();
|
||||
|
||||
Task<OperationResult<IEnumerable<DateAndCount>>> ArtistsByDate();
|
||||
Task<OperationResult<IEnumerable<DateAndCount>>> ArtistsByDateAsync();
|
||||
Task<OperationResult<LibraryStats>> LibraryStatisticsAsync();
|
||||
|
||||
Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDate();
|
||||
Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDateAsync();
|
||||
|
||||
Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDecade();
|
||||
Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDecadeAsync();
|
||||
|
||||
Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByDate();
|
||||
Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByDateAsync();
|
||||
|
||||
Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByUser();
|
||||
Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByUserAsync();
|
||||
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using Roadie.Library.Models;
|
||||
using Roadie.Library.Models.ThirdPartyApi.Subsonic;
|
||||
using Roadie.Library.Models.ThirdPartyApi.Subsonic;
|
||||
using System.Threading.Tasks;
|
||||
using User = Roadie.Library.Models.Users.User;
|
||||
|
||||
|
@ -7,85 +6,85 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public interface ISubsonicService
|
||||
{
|
||||
Task<SubsonicOperationResult<Response>> AddChatMessage(Request request, User roadieUser);
|
||||
Task<SubsonicOperationResult<Response>> AddChatMessageAsync(Request request, User roadieUser);
|
||||
|
||||
Task<SubsonicOperationResult<SubsonicAuthenticateResponse>> Authenticate(Request request);
|
||||
Task<SubsonicOperationResult<SubsonicAuthenticateResponse>> AuthenticateAsync(Request request);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> CreateBookmark(Request request, User roadieUser, int position, string comment);
|
||||
Task<SubsonicOperationResult<Response>> CreateBookmarkAsync(Request request, User roadieUser, int position, string comment);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> CreatePlaylist(Request request, User roadieUser, string name, string[] songIds, string playlistId = null);
|
||||
Task<SubsonicOperationResult<Response>> CreatePlaylistAsync(Request request, User roadieUser, string name, string[] songIds, string playlistId = null);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> DeleteBookmark(Request request, User roadieUser);
|
||||
Task<SubsonicOperationResult<Response>> DeleteBookmarkAsync(Request request, User roadieUser);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> DeletePlaylist(Request request, User roadieUser);
|
||||
Task<SubsonicOperationResult<Response>> DeletePlaylistAsync(Request request, User roadieUser);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetAlbum(Request request, User roadieUser);
|
||||
Task<SubsonicOperationResult<Response>> GetAlbumAsync(Request request, User roadieUser);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetAlbumInfo(Request request, User roadieUser, AlbumInfoVersion version);
|
||||
Task<SubsonicOperationResult<Response>> GetAlbumInfoAsync(Request request, User roadieUser, AlbumInfoVersion version);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetAlbumList(Request request, User roadieUser, AlbumListVersions version);
|
||||
Task<SubsonicOperationResult<Response>> GetAlbumListAsync(Request request, User roadieUser, AlbumListVersions version);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetArtist(Request request, User roadieUser);
|
||||
Task<SubsonicOperationResult<Response>> GetArtistAsync(Request request, User roadieUser);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetArtistInfo(Request request, int? count, bool includeNotPresent, ArtistInfoVersion version);
|
||||
Task<SubsonicOperationResult<Response>> GetArtistInfoAsync(Request request, int? count, bool includeNotPresent, ArtistInfoVersion version);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetArtists(Request request, User roadieUser);
|
||||
Task<SubsonicOperationResult<Response>> GetArtistsAsync(Request request, User roadieUser);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetBookmarks(Request request, User roadieUser);
|
||||
Task<SubsonicOperationResult<Response>> GetBookmarksAsync(Request request, User roadieUser);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetChatMessages(Request request, User roadieUser, long? since);
|
||||
Task<SubsonicOperationResult<Response>> GetChatMessagesAsync(Request request, User roadieUser, long? since);
|
||||
|
||||
Task<SubsonicFileOperationResult<Library.Models.Image>> GetCoverArt(Request request, int? size);
|
||||
Task<SubsonicFileOperationResult<Library.Models.Image>> GetCoverArtAsync(Request request, int? size);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetGenres(Request request);
|
||||
Task<SubsonicOperationResult<Response>> GetGenresAsync(Request request);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetIndexes(Request request, User roadieUser, long? ifModifiedSince = null);
|
||||
Task<SubsonicOperationResult<Response>> GetIndexesAsync(Request request, User roadieUser, long? ifModifiedSince = null);
|
||||
|
||||
SubsonicOperationResult<Response> GetLicense(Request request);
|
||||
|
||||
SubsonicOperationResult<Response> GetLyrics(Request request, string artistId, string title);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetMusicDirectory(Request request, User roadieUser);
|
||||
Task<SubsonicOperationResult<Response>> GetMusicDirectoryAsync(Request request, User roadieUser);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetMusicFolders(Request request);
|
||||
Task<SubsonicOperationResult<Response>> GetMusicFoldersAsync(Request request);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetNowPlaying(Request request, User roadieUser);
|
||||
Task<SubsonicOperationResult<Response>> GetNowPlayingAsync(Request request, User roadieUser);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetPlaylist(Request request, User roadieUser);
|
||||
Task<SubsonicOperationResult<Response>> GetPlaylistAsync(Request request, User roadieUser);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetPlaylists(Request request, User roadieUser, string filterToUserName);
|
||||
Task<SubsonicOperationResult<Response>> GetPlaylistsAsync(Request request, User roadieUser, string filterToUserName);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetPlayQueue(Request request, User roadieUser);
|
||||
Task<SubsonicOperationResult<Response>> GetPlayQueueAsync(Request request, User roadieUser);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetPodcasts(Request request);
|
||||
Task<SubsonicOperationResult<Response>> GetPodcastsAsync(Request request);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetRandomSongs(Request request, User roadieUser);
|
||||
Task<SubsonicOperationResult<Response>> GetRandomSongsAsync(Request request, User roadieUser);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetSimliarSongs(Request request, User roadieUser, SimilarSongsVersion version, int? count = 50);
|
||||
Task<SubsonicOperationResult<Response>> GetSimliarSongsAsync(Request request, User roadieUser, SimilarSongsVersion version, int? count = 50);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetSong(Request request, User roadieUser);
|
||||
Task<SubsonicOperationResult<Response>> GetSongAsync(Request request, User roadieUser);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetSongsByGenre(Request request, User roadieUser);
|
||||
Task<SubsonicOperationResult<Response>> GetSongsByGenreAsync(Request request, User roadieUser);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetStarred(Request request, User roadieUser, StarredVersion version);
|
||||
Task<SubsonicOperationResult<Response>> GetStarredAsync(Request request, User roadieUser, StarredVersion version);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetTopSongs(Request request, User roadieUser, int? count = 50);
|
||||
Task<SubsonicOperationResult<Response>> GetTopSongsAsync(Request request, User roadieUser, int? count = 50);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> GetUser(Request request, string username);
|
||||
Task<SubsonicOperationResult<Response>> GetUserAsync(Request request, string username);
|
||||
|
||||
SubsonicOperationResult<Response> GetVideos(Request request);
|
||||
|
||||
SubsonicOperationResult<Response> Ping(Request request);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> SavePlayQueue(Request request, User roadieUser, string current, long? position);
|
||||
Task<SubsonicOperationResult<Response>> SavePlayQueueAsync(Request request, User roadieUser, string current, long? position);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> Search(Request request, User roadieUser, SearchVersion version);
|
||||
Task<SubsonicOperationResult<Response>> SearchAsync(Request request, User roadieUser, SearchVersion version);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> SetRating(Request request, User roadieUser, short rating);
|
||||
Task<SubsonicOperationResult<Response>> SetRatingAsync(Request request, User roadieUser, short rating);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> ToggleStar(Request request, User roadieUser, bool star, string[] albumIds = null, string[] artistIds = null);
|
||||
Task<SubsonicOperationResult<Response>> ToggleStarAsync(Request request, User roadieUser, bool star, string[] albumIds = null, string[] artistIds = null);
|
||||
|
||||
Task<SubsonicOperationResult<Response>> UpdatePlaylist(Request request, User roadieUser, string playlistId,
|
||||
Task<SubsonicOperationResult<Response>> UpdatePlaylistAsync(Request request, User roadieUser, string playlistId,
|
||||
string name = null, string comment = null, bool? isPublic = null, string[] songIdsToAdd = null,
|
||||
int[] songIndexesToRemove = null);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,6 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public interface ITokenService
|
||||
{
|
||||
Task<string> GenerateToken(User user, UserManager<User> userManager);
|
||||
Task<string> GenerateTokenAsync(User user, UserManager<User> userManager);
|
||||
}
|
||||
}
|
|
@ -10,16 +10,14 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public interface ITrackService
|
||||
{
|
||||
Task<OperationResult<Track>> ById(User roadieUser, Guid id, IEnumerable<string> includes);
|
||||
Task<OperationResult<Track>> ByIdAsyncAsync(User roadieUser, Guid id, IEnumerable<string> includes);
|
||||
|
||||
Task<PagedResult<TrackList>> List(PagedRequest request, User roadieUser, bool? doRandomize = false,
|
||||
Guid? releaseId = null);
|
||||
Task<PagedResult<TrackList>> ListAsync(PagedRequest request, User roadieUser, bool? doRandomize = false, Guid? releaseId = null);
|
||||
|
||||
OperationResult<Track> StreamCheckAndInfo(User roadieUser, Guid id);
|
||||
|
||||
Task<OperationResult<TrackStreamInfo>> TrackStreamInfo(Guid trackId, long beginBytes, long endBytes,
|
||||
User roadieUser);
|
||||
Task<OperationResult<TrackStreamInfo>> TrackStreamInfoAsync(Guid trackId, long beginBytes, long endBytes, User roadieUser);
|
||||
|
||||
Task<OperationResult<bool>> UpdateTrack(User user, Track track);
|
||||
Task<OperationResult<bool>> UpdateTrackAsync(User user, Track track);
|
||||
}
|
||||
}
|
|
@ -9,44 +9,44 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public interface IUserService
|
||||
{
|
||||
Task<OperationResult<User>> ById(User user, Guid id, IEnumerable<string> includes, bool isAccountSettingsEdit = false);
|
||||
Task<OperationResult<User>> ByIdAsync(User user, Guid id, IEnumerable<string> includes, bool isAccountSettingsEdit = false);
|
||||
|
||||
Task<PagedResult<UserList>> List(PagedRequest request);
|
||||
Task<OperationResult<bool>> DeleteAllBookmarksAsync(User roadieUser);
|
||||
|
||||
Task<OperationResult<bool>> DeleteAllBookmarks(User roadieUser);
|
||||
Task<PagedResult<UserList>> ListAsync(PagedRequest request);
|
||||
|
||||
Task<OperationResult<bool>> SetArtistBookmark(Guid artistId, User roadieUser, bool isBookmarked);
|
||||
Task<OperationResult<bool>> SetArtistBookmarkAsync(Guid artistId, User roadieUser, bool isBookmarked);
|
||||
|
||||
Task<OperationResult<bool>> SetArtistDisliked(Guid artistId, User roadieUser, bool isDisliked);
|
||||
Task<OperationResult<bool>> SetArtistDislikedAsync(Guid artistId, User roadieUser, bool isDisliked);
|
||||
|
||||
Task<OperationResult<bool>> SetArtistFavorite(Guid artistId, User roadieUser, bool isFavorite);
|
||||
Task<OperationResult<bool>> SetArtistFavoriteAsync(Guid artistId, User roadieUser, bool isFavorite);
|
||||
|
||||
Task<OperationResult<short>> SetArtistRating(Guid artistId, User roadieUser, short rating);
|
||||
Task<OperationResult<short>> SetArtistRatingAsync(Guid artistId, User roadieUser, short rating);
|
||||
|
||||
Task<OperationResult<bool>> SetCollectionBookmark(Guid collectionId, User roadieUser, bool isBookmarked);
|
||||
Task<OperationResult<bool>> SetCollectionBookmarkAsync(Guid collectionId, User roadieUser, bool isBookmarked);
|
||||
|
||||
Task<OperationResult<bool>> SetLabelBookmark(Guid labelId, User roadieUser, bool isBookmarked);
|
||||
Task<OperationResult<bool>> SetLabelBookmarkAsync(Guid labelId, User roadieUser, bool isBookmarked);
|
||||
|
||||
Task<OperationResult<bool>> SetPlaylistBookmark(Guid playlistId, User roadieUser, bool isBookmarked);
|
||||
Task<OperationResult<bool>> SetPlaylistBookmarkAsync(Guid playlistId, User roadieUser, bool isBookmarked);
|
||||
|
||||
Task<OperationResult<bool>> SetReleaseBookmark(Guid releaseid, User roadieUser, bool isBookmarked);
|
||||
Task<OperationResult<bool>> SetReleaseBookmarkAsync(Guid releaseid, User roadieUser, bool isBookmarked);
|
||||
|
||||
Task<OperationResult<bool>> SetReleaseDisliked(Guid releaseId, User roadieUser, bool isDisliked);
|
||||
Task<OperationResult<bool>> SetReleaseDislikedAsync(Guid releaseId, User roadieUser, bool isDisliked);
|
||||
|
||||
Task<OperationResult<bool>> SetReleaseFavorite(Guid releaseId, User roadieUser, bool isFavorite);
|
||||
Task<OperationResult<bool>> SetReleaseFavoriteAsync(Guid releaseId, User roadieUser, bool isFavorite);
|
||||
|
||||
Task<OperationResult<short>> SetReleaseRating(Guid releaseId, User roadieUser, short rating);
|
||||
Task<OperationResult<short>> SetReleaseRatingAsync(Guid releaseId, User roadieUser, short rating);
|
||||
|
||||
Task<OperationResult<bool>> SetTrackBookmark(Guid trackId, User roadieUser, bool isBookmarked);
|
||||
Task<OperationResult<bool>> SetTrackBookmarkAsync(Guid trackId, User roadieUser, bool isBookmarked);
|
||||
|
||||
Task<OperationResult<bool>> SetTrackDisliked(Guid trackId, User roadieUser, bool isDisliked);
|
||||
Task<OperationResult<bool>> SetTrackDislikedAsync(Guid trackId, User roadieUser, bool isDisliked);
|
||||
|
||||
Task<OperationResult<bool>> SetTrackFavorite(Guid releaseId, User roadieUser, bool isFavorite);
|
||||
Task<OperationResult<bool>> SetTrackFavoriteAsync(Guid releaseId, User roadieUser, bool isFavorite);
|
||||
|
||||
Task<OperationResult<short>> SetTrackRating(Guid trackId, User roadieUser, short rating);
|
||||
Task<OperationResult<short>> SetTrackRatingAsync(Guid trackId, User roadieUser, short rating);
|
||||
|
||||
Task<OperationResult<bool>> UpdateIntegrationGrant(Guid userId, string integrationName, string token);
|
||||
Task<OperationResult<bool>> UpdateIntegrationGrantAsync(Guid userId, string integrationName, string token);
|
||||
|
||||
Task<OperationResult<bool>> UpdateProfile(User userPerformingUpdate, User userBeingUpdatedModel);
|
||||
Task<OperationResult<bool>> UpdateProfileAsync(User userPerformingUpdate, User userBeingUpdatedModel);
|
||||
}
|
||||
}
|
|
@ -23,12 +23,20 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
public class ImageService : ServiceBase, IImageService
|
||||
{
|
||||
public string Referrer { get; set; }
|
||||
public string RequestIp { get; set; }
|
||||
private IDefaultNotFoundImages DefaultNotFoundImages { get; }
|
||||
|
||||
private IImageSearchManager ImageSearchManager { get; }
|
||||
|
||||
public string Referrer { get; set; }
|
||||
public string RequestIp { get; set; }
|
||||
|
||||
public ImageService(IRoadieSettings configuration, IRoadieDbContext dbContext, ICacheManager cacheManager,
|
||||
ILogger logger, DefaultNotFoundImages defaultNotFoundImages)
|
||||
: base(configuration, null, dbContext, cacheManager, logger, null)
|
||||
{
|
||||
DefaultNotFoundImages = defaultNotFoundImages;
|
||||
}
|
||||
|
||||
public ImageService(IRoadieSettings configuration,
|
||||
IHttpEncoder httpEncoder,
|
||||
IHttpContext httpContext,
|
||||
|
@ -43,149 +51,6 @@ namespace Roadie.Api.Services
|
|||
ImageSearchManager = imageSearchManager;
|
||||
}
|
||||
|
||||
public ImageService(IRoadieSettings configuration, IRoadieDbContext dbContext, ICacheManager cacheManager,
|
||||
ILogger logger, DefaultNotFoundImages defaultNotFoundImages)
|
||||
: base(configuration, null, dbContext, cacheManager, logger, null)
|
||||
{
|
||||
DefaultNotFoundImages = defaultNotFoundImages;
|
||||
}
|
||||
|
||||
public async Task<FileOperationResult<IImage>> ArtistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return await GetImageFileOperation("ArtistImage",
|
||||
data.Artist.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => { return await ArtistImageAction(id, etag); },
|
||||
etag);
|
||||
}
|
||||
|
||||
public async Task<FileOperationResult<IImage>> ArtistSecondaryImage(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return await GetImageFileOperation($"ArtistSecondaryThumbnail.{imageId}",
|
||||
data.Artist.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => { return await ArtistSecondaryImageAction(id, imageId, etag); },
|
||||
etag);
|
||||
}
|
||||
|
||||
public async Task<FileOperationResult<IImage>> CollectionImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return await GetImageFileOperation("CollectionThumbnail",
|
||||
data.Collection.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => { return await CollectionImageAction(id, etag); },
|
||||
etag);
|
||||
}
|
||||
|
||||
public async Task<FileOperationResult<IImage>> GenreImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return await GetImageFileOperation("GenreThumbnail",
|
||||
data.Genre.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => await GenreImageAction(id, etag),
|
||||
etag);
|
||||
}
|
||||
|
||||
public async Task<FileOperationResult<IImage>> LabelImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return await GetImageFileOperation("LabelThumbnail",
|
||||
data.Label.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => await LabelImageAction(id, etag),
|
||||
etag);
|
||||
}
|
||||
|
||||
public async Task<FileOperationResult<IImage>> PlaylistImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return await GetImageFileOperation("PlaylistThumbnail",
|
||||
data.Playlist.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => await PlaylistImageAction(id, etag),
|
||||
etag);
|
||||
}
|
||||
|
||||
public async Task<FileOperationResult<IImage>> ReleaseImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return await GetImageFileOperation("ReleaseThumbnail",
|
||||
data.Release.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => await ReleaseImageAction(id, etag),
|
||||
etag);
|
||||
}
|
||||
|
||||
public async Task<FileOperationResult<IImage>> ReleaseSecondaryImage(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return await GetImageFileOperation($"ReleaseSecondaryThumbnail-{imageId}",
|
||||
data.Release.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => { return await ReleaseSecondaryImageAction(id, imageId, etag); },
|
||||
etag);
|
||||
}
|
||||
|
||||
public async Task<OperationResult<IEnumerable<ImageSearchResult>>> Search(string query, int resultsCount = 10)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
IEnumerable<ImageSearchResult> searchResults = null;
|
||||
try
|
||||
{
|
||||
searchResults = await ImageSearchManager.ImageSearch(query);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
return new OperationResult<IEnumerable<ImageSearchResult>>
|
||||
{
|
||||
Data = searchResults,
|
||||
IsSuccess = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<FileOperationResult<IImage>> TrackImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return await GetImageFileOperation("TrackThumbnail",
|
||||
data.Track.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => await TrackImageAction(id, width, height, etag),
|
||||
etag);
|
||||
}
|
||||
|
||||
public async Task<FileOperationResult<IImage>> UserImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return await GetImageFileOperation("UserById",
|
||||
User.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => await UserImageAction(id, etag),
|
||||
etag);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get image for an artist, see if the artist has an image in their folder and use that else use Artist.Thumbnail, is also not found use Artist DefaultNotFound image.
|
||||
/// </summary>
|
||||
|
@ -193,10 +58,10 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
try
|
||||
{
|
||||
var artist = await GetArtist(id);
|
||||
var artist = await GetArtist(id).ConfigureAwait(false);
|
||||
if (artist == null)
|
||||
{
|
||||
return new FileOperationResult<IImage>(true, string.Format("Artist Not Found [{0}]", id));
|
||||
return new FileOperationResult<IImage>(true, $"Artist Not Found [{id}]");
|
||||
}
|
||||
byte[] imageBytes = null;
|
||||
string artistFolder = null;
|
||||
|
@ -226,7 +91,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
Bytes = imageBytes,
|
||||
};
|
||||
if (imageBytes == null || !imageBytes.Any())
|
||||
if (imageBytes?.Any() != true)
|
||||
{
|
||||
image = DefaultNotFoundImages.Artist;
|
||||
}
|
||||
|
@ -244,10 +109,10 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
try
|
||||
{
|
||||
var artist = await GetArtist(id);
|
||||
var artist = await GetArtist(id).ConfigureAwait(false);
|
||||
if (artist == null)
|
||||
{
|
||||
return new FileOperationResult<IImage>(true, string.Format("Release Not Found [{0}]", id));
|
||||
return new FileOperationResult<IImage>(true, $"Release Not Found [{id}]");
|
||||
}
|
||||
byte[] imageBytes = null;
|
||||
string artistFolder = null;
|
||||
|
@ -265,7 +130,9 @@ namespace Roadie.Api.Services
|
|||
.FindImageTypeInDirectory(new DirectoryInfo(artistFolder), ImageType.ArtistSecondary)
|
||||
.ToArray();
|
||||
if (artistSecondaryImages.Length >= imageId && artistSecondaryImages[imageId] != null)
|
||||
{
|
||||
imageBytes = File.ReadAllBytes(artistSecondaryImages[imageId].FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -292,10 +159,10 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
try
|
||||
{
|
||||
var collection = await GetCollection(id);
|
||||
var collection = await GetCollection(id).ConfigureAwait(false);
|
||||
if (collection == null)
|
||||
{
|
||||
return new FileOperationResult<IImage>(true, string.Format("Collection Not Found [{0}]", id));
|
||||
return new FileOperationResult<IImage>(true, $"Collection Not Found [{id}]");
|
||||
}
|
||||
IImage image = new Library.Imaging.Image(id)
|
||||
{
|
||||
|
@ -313,7 +180,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
Logger.LogError(ex, $"Error Reading Image File [{collectionImageFilename}]");
|
||||
}
|
||||
if (image.Bytes == null || !image.Bytes.Any())
|
||||
if (image.Bytes?.Any() != true)
|
||||
{
|
||||
image = DefaultNotFoundImages.Collection;
|
||||
}
|
||||
|
@ -336,7 +203,7 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
if (image?.Bytes?.Any() != true)
|
||||
{
|
||||
return new FileOperationResult<IImage>(string.Format("ImageById Not Set [{0}]", id));
|
||||
return new FileOperationResult<IImage>($"ImageById Not Set [{id}]");
|
||||
}
|
||||
return new FileOperationResult<IImage>(image?.Bytes?.Any() ?? false
|
||||
? OperationMessages.OkMessage
|
||||
|
@ -354,10 +221,10 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
try
|
||||
{
|
||||
var genre = await GetGenre(id);
|
||||
var genre = await GetGenre(id).ConfigureAwait(false);
|
||||
if (genre == null)
|
||||
{
|
||||
return new FileOperationResult<IImage>(true, string.Format("Genre Not Found [{0}]", id));
|
||||
return new FileOperationResult<IImage>(true, $"Genre Not Found [{id}]");
|
||||
}
|
||||
IImage image = new Library.Imaging.Image(id)
|
||||
{
|
||||
|
@ -375,7 +242,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
Logger.LogError(ex, $"Error Reading Image File [{genreImageFilename}]");
|
||||
}
|
||||
if (image.Bytes == null || !image.Bytes.Any())
|
||||
if (image.Bytes?.Any() != true)
|
||||
{
|
||||
image = DefaultNotFoundImages.Genre;
|
||||
}
|
||||
|
@ -395,7 +262,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
var sizeHash = (width ?? 0) + (height ?? 0);
|
||||
var result = await CacheManager.GetAsync($"urn:{type}_by_id_operation:{id}:{sizeHash}", action, regionUrn);
|
||||
var result = await CacheManager.GetAsync($"urn:{type}_by_id_operation:{id}:{sizeHash}", action, regionUrn).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return new FileOperationResult<IImage>(result.IsNotFoundResult, result.Messages);
|
||||
|
@ -450,10 +317,10 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
try
|
||||
{
|
||||
var label = await GetLabel(id);
|
||||
var label = await GetLabel(id).ConfigureAwait(false);
|
||||
if (label == null)
|
||||
{
|
||||
return new FileOperationResult<IImage>(true, string.Format("Label Not Found [{0}]", id));
|
||||
return new FileOperationResult<IImage>(true, $"Label Not Found [{id}]");
|
||||
}
|
||||
IImage image = new Library.Imaging.Image(id)
|
||||
{
|
||||
|
@ -471,7 +338,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
Logger.LogError(ex, $"Error Reading Image File [{labelImageFilename}]");
|
||||
}
|
||||
if (image.Bytes == null || !image.Bytes.Any())
|
||||
if (image.Bytes?.Any() != true)
|
||||
{
|
||||
image = DefaultNotFoundImages.Label;
|
||||
}
|
||||
|
@ -489,10 +356,10 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
try
|
||||
{
|
||||
var playlist = await GetPlaylist(id);
|
||||
var playlist = await GetPlaylist(id).ConfigureAwait(false);
|
||||
if (playlist == null)
|
||||
{
|
||||
return new FileOperationResult<IImage>(true, string.Format("Playlist Not Found [{0}]", id));
|
||||
return new FileOperationResult<IImage>(true, $"Playlist Not Found [{id}]");
|
||||
}
|
||||
IImage image = new Library.Imaging.Image(id)
|
||||
{
|
||||
|
@ -510,7 +377,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
Logger.LogError(ex, $"Error Reading Image File [{playlistImageFilename}]");
|
||||
}
|
||||
if (image.Bytes == null || !image.Bytes.Any())
|
||||
if (image.Bytes?.Any() != true)
|
||||
{
|
||||
image = DefaultNotFoundImages.Playlist;
|
||||
}
|
||||
|
@ -531,10 +398,10 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
try
|
||||
{
|
||||
var release = await GetRelease(id);
|
||||
var release = await GetRelease(id).ConfigureAwait(false);
|
||||
if (release == null)
|
||||
{
|
||||
return new FileOperationResult<IImage>(true, string.Format("Release Not Found [{0}]", id));
|
||||
return new FileOperationResult<IImage>(true, $"Release Not Found [{id}]");
|
||||
}
|
||||
byte[] imageBytes = null;
|
||||
string artistFolder = null;
|
||||
|
@ -591,10 +458,10 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
try
|
||||
{
|
||||
var release = await GetRelease(id);
|
||||
var release = await GetRelease(id).ConfigureAwait(false);
|
||||
if (release == null)
|
||||
{
|
||||
return new FileOperationResult<IImage>(true, string.Format("Release Not Found [{0}]", id));
|
||||
return new FileOperationResult<IImage>(true, $"Release Not Found [{id}]");
|
||||
}
|
||||
byte[] imageBytes = null;
|
||||
string artistFolder = null;
|
||||
|
@ -620,7 +487,9 @@ namespace Roadie.Api.Services
|
|||
.FindImageTypeInDirectory(new DirectoryInfo(releaseFolder), ImageType.ReleaseSecondary)
|
||||
.ToArray();
|
||||
if (releaseSecondaryImages.Length >= imageId && releaseSecondaryImages[imageId] != null)
|
||||
{
|
||||
imageBytes = File.ReadAllBytes(releaseSecondaryImages[imageId].FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -649,10 +518,10 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
try
|
||||
{
|
||||
var track = await GetTrack(id);
|
||||
var track = await GetTrack(id).ConfigureAwait(false);
|
||||
if (track == null)
|
||||
{
|
||||
return new FileOperationResult<IImage>(true, string.Format("Track Not Found [{0}]", id));
|
||||
return new FileOperationResult<IImage>(true, $"Track Not Found [{id}]");
|
||||
}
|
||||
IImage image = new Library.Imaging.Image(id)
|
||||
{
|
||||
|
@ -663,10 +532,10 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
image.Bytes = File.ReadAllBytes(trackImageFileName);
|
||||
}
|
||||
if (image.Bytes == null || !image.Bytes.Any())
|
||||
if (image.Bytes?.Any() != true)
|
||||
{
|
||||
// If no track image is found then return image for release
|
||||
return await ReleaseImage(track.ReleaseMedia.Release.RoadieId, width, height, etag);
|
||||
return await ReleaseImageAsync(track.ReleaseMedia.Release.RoadieId, width, height, etag).ConfigureAwait(false);
|
||||
}
|
||||
return GenerateFileOperationResult(id, image, etag);
|
||||
}
|
||||
|
@ -682,10 +551,10 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
try
|
||||
{
|
||||
var user = await GetUser(id);
|
||||
var user = await GetUser(id).ConfigureAwait(false);
|
||||
if (user == null)
|
||||
{
|
||||
return new FileOperationResult<IImage>(true, string.Format("User Not Found [{0}]", id));
|
||||
return new FileOperationResult<IImage>(true, $"User Not Found [{id}]");
|
||||
}
|
||||
IImage image = new Library.Imaging.Image(id)
|
||||
{
|
||||
|
@ -703,7 +572,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
Logger.LogError(ex, $"Error Reading Image File [{userImageFilename}]");
|
||||
}
|
||||
if (image.Bytes == null || !image.Bytes.Any())
|
||||
if (image.Bytes?.Any() != true)
|
||||
{
|
||||
image = DefaultNotFoundImages.User;
|
||||
}
|
||||
|
@ -716,5 +585,141 @@ namespace Roadie.Api.Services
|
|||
|
||||
return new FileOperationResult<IImage>(OperationMessages.ErrorOccured);
|
||||
}
|
||||
|
||||
public Task<FileOperationResult<IImage>> ArtistImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return GetImageFileOperation(nameof(ArtistImageAsync),
|
||||
data.Artist.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => { return await ArtistImageAction(id, etag).ConfigureAwait(false); },
|
||||
etag);
|
||||
}
|
||||
|
||||
public Task<FileOperationResult<IImage>> ArtistSecondaryImageAsync(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return GetImageFileOperation($"ArtistSecondaryThumbnail.{imageId}",
|
||||
data.Artist.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => { return await ArtistSecondaryImageAction(id, imageId, etag).ConfigureAwait(false); },
|
||||
etag);
|
||||
}
|
||||
|
||||
public Task<FileOperationResult<IImage>> CollectionImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return GetImageFileOperation("CollectionThumbnail",
|
||||
data.Collection.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => { return await CollectionImageAction(id, etag).ConfigureAwait(false); },
|
||||
etag);
|
||||
}
|
||||
|
||||
public Task<FileOperationResult<IImage>> GenreImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return GetImageFileOperation("GenreThumbnail",
|
||||
data.Genre.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => await GenreImageAction(id, etag).ConfigureAwait(false),
|
||||
etag);
|
||||
}
|
||||
|
||||
public Task<FileOperationResult<IImage>> LabelImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return GetImageFileOperation("LabelThumbnail",
|
||||
data.Label.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => await LabelImageAction(id, etag).ConfigureAwait(false),
|
||||
etag);
|
||||
}
|
||||
|
||||
public Task<FileOperationResult<IImage>> PlaylistImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return GetImageFileOperation("PlaylistThumbnail",
|
||||
data.Playlist.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => await PlaylistImageAction(id, etag).ConfigureAwait(false),
|
||||
etag);
|
||||
}
|
||||
|
||||
public Task<FileOperationResult<IImage>> ReleaseImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return GetImageFileOperation("ReleaseThumbnail",
|
||||
data.Release.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => await ReleaseImageAction(id, etag).ConfigureAwait(false),
|
||||
etag);
|
||||
}
|
||||
|
||||
public Task<FileOperationResult<IImage>> ReleaseSecondaryImageAsync(Guid id, int imageId, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return GetImageFileOperation($"ReleaseSecondaryThumbnail-{imageId}",
|
||||
data.Release.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => { return await ReleaseSecondaryImageAction(id, imageId, etag).ConfigureAwait(false); },
|
||||
etag);
|
||||
}
|
||||
|
||||
public async Task<OperationResult<IEnumerable<ImageSearchResult>>> SearchAsync(string query, int resultsCount = 10)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
IEnumerable<ImageSearchResult> searchResults = null;
|
||||
try
|
||||
{
|
||||
searchResults = await ImageSearchManager.ImageSearch(query).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
return new OperationResult<IEnumerable<ImageSearchResult>>
|
||||
{
|
||||
Data = searchResults,
|
||||
IsSuccess = errors.Count == 0,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public Task<FileOperationResult<IImage>> TrackImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return GetImageFileOperation("TrackThumbnail",
|
||||
data.Track.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => await TrackImageAction(id, width, height, etag).ConfigureAwait(false),
|
||||
etag);
|
||||
}
|
||||
|
||||
public Task<FileOperationResult<IImage>> UserImageAsync(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
|
||||
{
|
||||
return GetImageFileOperation("UserById",
|
||||
User.CacheRegionUrn(id),
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
async () => await UserImageAction(id, etag).ConfigureAwait(false),
|
||||
etag);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,7 +9,6 @@ using Roadie.Library.Data.Context;
|
|||
using Roadie.Library.Encoding;
|
||||
using Roadie.Library.Enums;
|
||||
using Roadie.Library.Extensions;
|
||||
using Roadie.Library.Identity;
|
||||
using Roadie.Library.Imaging;
|
||||
using Roadie.Library.Models;
|
||||
using Roadie.Library.Models.Pagination;
|
||||
|
@ -43,318 +42,6 @@ namespace Roadie.Api.Services
|
|||
BookmarkService = bookmarkService;
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Label>> ById(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
var cacheKey = string.Format("urn:label_by_id_operation:{0}:{1}", id,
|
||||
includes == null ? "0" : string.Join("|", includes));
|
||||
var result = await CacheManager.GetAsync(cacheKey,
|
||||
async () => { return await LabelByIdAction(id, includes); }, data.Label.CacheRegionUrn(id));
|
||||
sw.Stop();
|
||||
if (result?.Data != null && roadieUser != null)
|
||||
{
|
||||
var userBookmarkResult = await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Label);
|
||||
if (userBookmarkResult.IsSuccess)
|
||||
{
|
||||
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x?.Bookmark?.Value == result?.Data?.Id?.ToString()) != null;
|
||||
}
|
||||
if (result.Data.Comments.Any())
|
||||
{
|
||||
var commentIds = result.Data.Comments.Select(x => x.DatabaseId).ToArray();
|
||||
var userCommentReactions = (from cr in DbContext.CommentReactions
|
||||
where commentIds.Contains(cr.CommentId)
|
||||
where cr.UserId == roadieUser.Id
|
||||
select cr).ToArray();
|
||||
foreach (var comment in result.Data.Comments)
|
||||
{
|
||||
var userCommentReaction = userCommentReactions.FirstOrDefault(x => x.CommentId == comment.DatabaseId);
|
||||
comment.IsDisliked = userCommentReaction?.ReactionValue == CommentReaction.Dislike;
|
||||
comment.IsLiked = userCommentReaction?.ReactionValue == CommentReaction.Like;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new OperationResult<Label>(result.Messages)
|
||||
{
|
||||
Data = result?.Data,
|
||||
IsNotFoundResult = result?.IsNotFoundResult ?? false,
|
||||
Errors = result?.Errors,
|
||||
IsSuccess = result?.IsSuccess ?? false,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> Delete(Library.Identity.User user, Guid id)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var label = DbContext.Labels.FirstOrDefault(x => x.RoadieId == id);
|
||||
if (label == null) return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", id));
|
||||
DbContext.Labels.Remove(label);
|
||||
await DbContext.SaveChangesAsync();
|
||||
|
||||
var labelImageFilename = label.PathToImage(Configuration);
|
||||
if (File.Exists(labelImageFilename))
|
||||
{
|
||||
File.Delete(labelImageFilename);
|
||||
}
|
||||
await BookmarkService.RemoveAllBookmarksForItem(BookmarkType.Label, label.Id);
|
||||
Logger.LogWarning("User `{0}` deleted Label `{1}]`", user, label);
|
||||
CacheManager.ClearRegion(label.CacheRegion);
|
||||
sw.Stop();
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<Library.Models.Pagination.PagedResult<LabelList>> List(Library.Models.Users.User roadieUser, PagedRequest request,
|
||||
bool? doRandomize = false)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
int? rowCount = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(request.Sort))
|
||||
{
|
||||
request.Sort = request.Sort.Replace("createdDate", "createdDateTime");
|
||||
request.Sort = request.Sort.Replace("lastUpdated", "lastUpdatedDateTime");
|
||||
}
|
||||
|
||||
var normalizedFilterValue = !string.IsNullOrEmpty(request.FilterValue)
|
||||
? request.FilterValue.ToAlphanumericName()
|
||||
: null;
|
||||
|
||||
int[] randomLabelIds = null;
|
||||
SortedDictionary<int, int> randomLabelData = null;
|
||||
if (doRandomize ?? false)
|
||||
{
|
||||
var randomLimit = request.Limit ?? roadieUser?.RandomReleaseLimit ?? request.LimitValue;
|
||||
randomLabelData = await DbContext.RandomLabelIds(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly);
|
||||
randomLabelIds = randomLabelData.Select(x => x.Value).ToArray();
|
||||
rowCount = DbContext.Labels.Count();
|
||||
}
|
||||
|
||||
var result = from l in DbContext.Labels
|
||||
where randomLabelIds == null || randomLabelIds.Contains(l.Id)
|
||||
where string.IsNullOrEmpty(normalizedFilterValue) || (
|
||||
l.Name.ToLower().Contains(normalizedFilterValue) ||
|
||||
l.SortName.ToLower().Contains(normalizedFilterValue) ||
|
||||
l.AlternateNames.ToLower().Contains(normalizedFilterValue)
|
||||
)
|
||||
select new LabelList
|
||||
{
|
||||
DatabaseId = l.Id,
|
||||
Id = l.RoadieId,
|
||||
Label = new DataToken
|
||||
{
|
||||
Text = l.Name,
|
||||
Value = l.RoadieId.ToString()
|
||||
},
|
||||
SortName = l.SortName,
|
||||
CreatedDate = l.CreatedDate,
|
||||
LastUpdated = l.LastUpdated,
|
||||
ArtistCount = l.ArtistCount,
|
||||
ReleaseCount = l.ReleaseCount,
|
||||
TrackCount = l.TrackCount,
|
||||
Thumbnail = ImageHelper.MakeLabelThumbnailImage(Configuration, HttpContext, l.RoadieId)
|
||||
};
|
||||
LabelList[] rows = null;
|
||||
rowCount = rowCount ?? result.Count();
|
||||
if (doRandomize ?? false)
|
||||
{
|
||||
var resultData = result.ToArray();
|
||||
rows = (from r in resultData
|
||||
join ra in randomLabelData on r.DatabaseId equals ra.Value
|
||||
orderby ra.Key
|
||||
select r
|
||||
).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
var sortBy = string.IsNullOrEmpty(request.Sort)
|
||||
? request.OrderValue(new Dictionary<string, string> { { "SortName", "ASC" }, { "Label.Text", "ASC" } })
|
||||
: request.OrderValue();
|
||||
rows = result
|
||||
.OrderBy(sortBy)
|
||||
.Skip(request.SkipValue)
|
||||
.Take(request.LimitValue)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
return new Library.Models.Pagination.PagedResult<LabelList>
|
||||
{
|
||||
TotalCount = rowCount.Value,
|
||||
CurrentPage = request.PageValue,
|
||||
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Rows = rows
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> MergeLabelsIntoLabel(Library.Identity.User user, Guid intoLabelId, IEnumerable<Guid> labelIdsToMerge)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
var errors = new List<Exception>();
|
||||
var label = DbContext.Labels.FirstOrDefault(x => x.RoadieId == intoLabelId);
|
||||
if (label == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, string.Format("Merge Into Label Not Found [{0}]", intoLabelId));
|
||||
}
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
var labelsToMerge = (from l in DbContext.Labels
|
||||
join ltm in labelIdsToMerge on l.RoadieId equals ltm
|
||||
select l);
|
||||
foreach (var labelToMerge in labelsToMerge)
|
||||
{
|
||||
label.MusicBrainzId = label.MusicBrainzId ?? labelToMerge.MusicBrainzId;
|
||||
label.SortName = label.SortName ?? labelToMerge.SortName;
|
||||
label.Profile = label.Profile ?? labelToMerge.Profile;
|
||||
label.BeginDate = label.BeginDate ?? labelToMerge.BeginDate;
|
||||
label.EndDate = label.EndDate ?? labelToMerge.EndDate;
|
||||
label.Profile = label.Profile ?? labelToMerge.Profile;
|
||||
label.DiscogsId = label.DiscogsId ?? labelToMerge.DiscogsId;
|
||||
label.ImageUrl = label.ImageUrl ?? labelToMerge.ImageUrl;
|
||||
label.Tags = label.Tags.AddToDelimitedList(labelToMerge.Tags.ToListFromDelimited());
|
||||
var altNames = labelToMerge.AlternateNames.ToListFromDelimited().ToList();
|
||||
altNames.Add(labelToMerge.Name);
|
||||
altNames.Add(labelToMerge.SortName);
|
||||
altNames.Add(labelToMerge.Name.ToAlphanumericName());
|
||||
label.AlternateNames = label.AlternateNames.AddToDelimitedList(altNames);
|
||||
label.URLs = label.URLs.AddToDelimitedList(labelToMerge.URLs.ToListFromDelimited());
|
||||
|
||||
var labelToMergeReleases = (from rl in DbContext.ReleaseLabels
|
||||
where rl.LabelId == labelToMerge.Id
|
||||
select rl);
|
||||
foreach (var labelToMergeRelease in labelToMergeReleases)
|
||||
{
|
||||
labelToMergeRelease.LabelId = label.Id;
|
||||
labelToMergeRelease.LastUpdated = now;
|
||||
}
|
||||
label.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync();
|
||||
}
|
||||
await UpdateLabelCounts(label.Id, now);
|
||||
|
||||
CacheManager.ClearRegion(label.CacheRegion);
|
||||
Logger.LogInformation($"MergeLabelsIntoLabel `{label}`, Merged Label Ids [{ string.Join(",", labelIdsToMerge) }] By User `{user}`");
|
||||
|
||||
sw.Stop();
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Library.Models.Image>> SetLabelImageByUrl(Library.Models.Users.User user, Guid id, string imageUrl)
|
||||
{
|
||||
return await SaveImageBytes(user, id, WebHelper.BytesForImageUrl(imageUrl));
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> UpdateLabel(Library.Models.Users.User user, Label model)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var label = DbContext.Labels.FirstOrDefault(x => x.RoadieId == model.Id);
|
||||
if (label == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", model.Id));
|
||||
}
|
||||
// If label is being renamed, see if label already exists with new model supplied name
|
||||
var labelName = label.SortNameValue;
|
||||
var labelModelName = model.SortNameValue;
|
||||
var oldPathToImage = label.PathToImage(Configuration);
|
||||
var didChangeName = !labelName.ToAlphanumericName().Equals(labelModelName.ToAlphanumericName(), StringComparison.OrdinalIgnoreCase);
|
||||
if (didChangeName)
|
||||
{
|
||||
var existingLabel = DbContext.Labels.FirstOrDefault(x => x.Name == model.Name || x.SortName == model.SortName );
|
||||
if (existingLabel != null)
|
||||
{
|
||||
return new OperationResult<bool>($"Label already exists `{ existingLabel }` with name [{ labelModelName }].");
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
var specialLabelName = model.Name.ToAlphanumericName();
|
||||
var alt = new List<string>(model.AlternateNamesList);
|
||||
if (!model.AlternateNamesList.Contains(specialLabelName, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
alt.Add(specialLabelName);
|
||||
}
|
||||
label.AlternateNames = alt.ToDelimitedList();
|
||||
label.BeginDate = model.BeginDate;
|
||||
label.DiscogsId = model.DiscogsId;
|
||||
label.EndDate = model.EndDate;
|
||||
label.IsLocked = model.IsLocked;
|
||||
label.MusicBrainzId = model.MusicBrainzId;
|
||||
label.Name = model.Name;
|
||||
label.Profile = model.Profile;
|
||||
label.SortName = model.SortName;
|
||||
label.Status = SafeParser.ToEnum<Statuses>(model.Status);
|
||||
label.Tags = model.TagsList.ToDelimitedList();
|
||||
label.URLs = model.URLsList.ToDelimitedList();
|
||||
|
||||
if (didChangeName)
|
||||
{
|
||||
if (File.Exists(oldPathToImage))
|
||||
{
|
||||
File.Move(oldPathToImage, label.PathToImage(Configuration));
|
||||
}
|
||||
}
|
||||
var labelImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
|
||||
if (labelImage != null)
|
||||
{
|
||||
// Save unaltered label image
|
||||
File.WriteAllBytes(label.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(labelImage));
|
||||
}
|
||||
label.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync();
|
||||
|
||||
CacheManager.ClearRegion(label.CacheRegion);
|
||||
Logger.LogInformation($"UpdateLabel `{label}` By User `{user}`");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Library.Models.Image>> UploadLabelImage(Library.Models.Users.User user, Guid id, IFormFile file)
|
||||
{
|
||||
var bytes = new byte[0];
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
file.CopyTo(ms);
|
||||
bytes = ms.ToArray();
|
||||
}
|
||||
|
||||
return await SaveImageBytes(user, id, bytes);
|
||||
}
|
||||
|
||||
private async Task<OperationResult<Label>> LabelByIdAction(Guid id, IEnumerable<string> includes = null)
|
||||
{
|
||||
var timings = new Dictionary<string, long>();
|
||||
|
@ -364,12 +51,12 @@ namespace Roadie.Api.Services
|
|||
sw.Start();
|
||||
|
||||
tsw.Restart();
|
||||
var label = await GetLabel(id);
|
||||
var label = await GetLabel(id).ConfigureAwait(false);
|
||||
tsw.Stop();
|
||||
timings.Add("GetLabel", tsw.ElapsedMilliseconds);
|
||||
timings.Add(nameof(GetLabel), tsw.ElapsedMilliseconds);
|
||||
if (label == null)
|
||||
{
|
||||
return new OperationResult<Label>(true, string.Format("Label Not Found [{0}]", id));
|
||||
return new OperationResult<Label>(true, $"Label Not Found [{id}]");
|
||||
}
|
||||
tsw.Restart();
|
||||
var result = label.Adapt<Label>();
|
||||
|
@ -456,8 +143,12 @@ namespace Roadie.Api.Services
|
|||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var label = DbContext.Labels.FirstOrDefault(x => x.RoadieId == id);
|
||||
if (label == null) return new OperationResult<Library.Models.Image>(true, string.Format("Label Not Found [{0}]", id));
|
||||
var label = await DbContext.Labels.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||
if (label == null)
|
||||
{
|
||||
return new OperationResult<Library.Models.Image>(true, $"Label Not Found [{id}]");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
|
@ -467,7 +158,7 @@ namespace Roadie.Api.Services
|
|||
File.WriteAllBytes(label.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(imageBytes));
|
||||
}
|
||||
label.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
CacheManager.ClearRegion(label.CacheRegion);
|
||||
Logger.LogInformation($"UploadLabelImage `{label}` By User `{user}`");
|
||||
}
|
||||
|
@ -481,11 +172,324 @@ namespace Roadie.Api.Services
|
|||
|
||||
return new OperationResult<Library.Models.Image>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
IsSuccess = errors.Count == 0,
|
||||
Data = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "label", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height, true),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Label>> ByIdAsync(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
var cacheKey = $"urn:label_by_id_operation:{id}:{(includes == null ? "0" : string.Join("|", includes))}";
|
||||
var result = await CacheManager.GetAsync(cacheKey,
|
||||
async () => await LabelByIdAction(id, includes).ConfigureAwait(false), data.Label.CacheRegionUrn(id)
|
||||
).ConfigureAwait(false);
|
||||
sw.Stop();
|
||||
if (result?.Data != null && roadieUser != null)
|
||||
{
|
||||
var userBookmarkResult = await BookmarkService.ListAsync(roadieUser, new PagedRequest(), false, BookmarkType.Label).ConfigureAwait(false);
|
||||
if (userBookmarkResult.IsSuccess)
|
||||
{
|
||||
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x?.Bookmark?.Value == result?.Data?.Id?.ToString()) != null;
|
||||
}
|
||||
if (result.Data.Comments.Any())
|
||||
{
|
||||
var commentIds = result.Data.Comments.Select(x => x.DatabaseId).ToArray();
|
||||
var userCommentReactions = (from cr in DbContext.CommentReactions
|
||||
where commentIds.Contains(cr.CommentId)
|
||||
where cr.UserId == roadieUser.Id
|
||||
select cr).ToArray();
|
||||
foreach (var comment in result.Data.Comments)
|
||||
{
|
||||
var userCommentReaction = userCommentReactions.FirstOrDefault(x => x.CommentId == comment.DatabaseId);
|
||||
comment.IsDisliked = userCommentReaction?.ReactionValue == CommentReaction.Dislike;
|
||||
comment.IsLiked = userCommentReaction?.ReactionValue == CommentReaction.Like;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new OperationResult<Label>(result.Messages)
|
||||
{
|
||||
Data = result?.Data,
|
||||
IsNotFoundResult = result?.IsNotFoundResult ?? false,
|
||||
Errors = result?.Errors,
|
||||
IsSuccess = result?.IsSuccess ?? false,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteAsync(Library.Identity.User user, Guid id)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var label = await DbContext.Labels.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||
if (label == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Label Not Found [{id}]");
|
||||
}
|
||||
|
||||
DbContext.Labels.Remove(label);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
var labelImageFilename = label.PathToImage(Configuration);
|
||||
if (File.Exists(labelImageFilename))
|
||||
{
|
||||
File.Delete(labelImageFilename);
|
||||
}
|
||||
await BookmarkService.RemoveAllBookmarksForItemAsync(BookmarkType.Label, label.Id).ConfigureAwait(false);
|
||||
Logger.LogWarning("User `{0}` deleted Label `{1}]`", user, label);
|
||||
CacheManager.ClearRegion(label.CacheRegion);
|
||||
sw.Stop();
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<Library.Models.Pagination.PagedResult<LabelList>> ListAsync(Library.Models.Users.User roadieUser, PagedRequest request,
|
||||
bool? doRandomize = false)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
int? rowCount = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(request.Sort))
|
||||
{
|
||||
request.Sort = request.Sort.Replace("createdDate", "createdDateTime");
|
||||
request.Sort = request.Sort.Replace("lastUpdated", "lastUpdatedDateTime");
|
||||
}
|
||||
|
||||
var normalizedFilterValue = !string.IsNullOrEmpty(request.FilterValue)
|
||||
? request.FilterValue.ToAlphanumericName()
|
||||
: null;
|
||||
|
||||
int[] randomLabelIds = null;
|
||||
SortedDictionary<int, int> randomLabelData = null;
|
||||
if (doRandomize ?? false)
|
||||
{
|
||||
var randomLimit = request.Limit ?? roadieUser?.RandomReleaseLimit ?? request.LimitValue;
|
||||
randomLabelData = await DbContext.RandomLabelIdsAsync(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly).ConfigureAwait(false);
|
||||
randomLabelIds = randomLabelData.Select(x => x.Value).ToArray();
|
||||
rowCount = DbContext.Labels.Count();
|
||||
}
|
||||
|
||||
var result = from l in DbContext.Labels
|
||||
where randomLabelIds == null || randomLabelIds.Contains(l.Id)
|
||||
where string.IsNullOrEmpty(normalizedFilterValue) || (
|
||||
l.Name.ToLower().Contains(normalizedFilterValue) ||
|
||||
l.SortName.ToLower().Contains(normalizedFilterValue) ||
|
||||
l.AlternateNames.ToLower().Contains(normalizedFilterValue)
|
||||
)
|
||||
select new LabelList
|
||||
{
|
||||
DatabaseId = l.Id,
|
||||
Id = l.RoadieId,
|
||||
Label = new DataToken
|
||||
{
|
||||
Text = l.Name,
|
||||
Value = l.RoadieId.ToString()
|
||||
},
|
||||
SortName = l.SortName,
|
||||
CreatedDate = l.CreatedDate,
|
||||
LastUpdated = l.LastUpdated,
|
||||
ArtistCount = l.ArtistCount,
|
||||
ReleaseCount = l.ReleaseCount,
|
||||
TrackCount = l.TrackCount,
|
||||
Thumbnail = ImageHelper.MakeLabelThumbnailImage(Configuration, HttpContext, l.RoadieId)
|
||||
};
|
||||
LabelList[] rows = null;
|
||||
rowCount = rowCount ?? result.Count();
|
||||
if (doRandomize ?? false)
|
||||
{
|
||||
var resultData = await result.ToArrayAsync().ConfigureAwait(false);
|
||||
rows = (from r in resultData
|
||||
join ra in randomLabelData on r.DatabaseId equals ra.Value
|
||||
orderby ra.Key
|
||||
select r
|
||||
)
|
||||
.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
var sortBy = string.IsNullOrEmpty(request.Sort)
|
||||
? request.OrderValue(new Dictionary<string, string> { { "SortName", "ASC" }, { "Label.Text", "ASC" } })
|
||||
: request.OrderValue();
|
||||
rows = await result
|
||||
.OrderBy(sortBy)
|
||||
.Skip(request.SkipValue)
|
||||
.Take(request.LimitValue)
|
||||
.ToArrayAsync()
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
return new Library.Models.Pagination.PagedResult<LabelList>
|
||||
{
|
||||
TotalCount = rowCount.Value,
|
||||
CurrentPage = request.PageValue,
|
||||
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Rows = rows
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> MergeLabelsIntoLabelAsync(Library.Identity.User user, Guid intoLabelId, IEnumerable<Guid> labelIdsToMerge)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
var errors = new List<Exception>();
|
||||
var label = await DbContext.Labels.FirstOrDefaultAsync(x => x.RoadieId == intoLabelId).ConfigureAwait(false);
|
||||
if (label == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Merge Into Label Not Found [{intoLabelId}]");
|
||||
}
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
var labelsToMerge = (from l in DbContext.Labels
|
||||
join ltm in labelIdsToMerge on l.RoadieId equals ltm
|
||||
select l);
|
||||
foreach (var labelToMerge in labelsToMerge)
|
||||
{
|
||||
label.MusicBrainzId = label.MusicBrainzId ?? labelToMerge.MusicBrainzId;
|
||||
label.SortName = label.SortName ?? labelToMerge.SortName;
|
||||
label.Profile = label.Profile ?? labelToMerge.Profile;
|
||||
label.BeginDate = label.BeginDate ?? labelToMerge.BeginDate;
|
||||
label.EndDate = label.EndDate ?? labelToMerge.EndDate;
|
||||
label.Profile = label.Profile ?? labelToMerge.Profile;
|
||||
label.DiscogsId = label.DiscogsId ?? labelToMerge.DiscogsId;
|
||||
label.ImageUrl = label.ImageUrl ?? labelToMerge.ImageUrl;
|
||||
label.Tags = label.Tags.AddToDelimitedList(labelToMerge.Tags.ToListFromDelimited());
|
||||
var altNames = labelToMerge.AlternateNames.ToListFromDelimited().ToList();
|
||||
altNames.Add(labelToMerge.Name);
|
||||
altNames.Add(labelToMerge.SortName);
|
||||
altNames.Add(labelToMerge.Name.ToAlphanumericName());
|
||||
label.AlternateNames = label.AlternateNames.AddToDelimitedList(altNames);
|
||||
label.URLs = label.URLs.AddToDelimitedList(labelToMerge.URLs.ToListFromDelimited());
|
||||
|
||||
var labelToMergeReleases = (from rl in DbContext.ReleaseLabels
|
||||
where rl.LabelId == labelToMerge.Id
|
||||
select rl);
|
||||
foreach (var labelToMergeRelease in labelToMergeReleases)
|
||||
{
|
||||
labelToMergeRelease.LabelId = label.Id;
|
||||
labelToMergeRelease.LastUpdated = now;
|
||||
}
|
||||
label.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
}
|
||||
await UpdateLabelCounts(label.Id, now).ConfigureAwait(false);
|
||||
|
||||
CacheManager.ClearRegion(label.CacheRegion);
|
||||
Logger.LogInformation($"MergeLabelsIntoLabel `{label}`, Merged Label Ids [{ string.Join(",", labelIdsToMerge) }] By User `{user}`");
|
||||
|
||||
sw.Stop();
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public Task<OperationResult<Library.Models.Image>> SetLabelImageByUrlAsync(Library.Models.Users.User user, Guid id, string imageUrl) => SaveImageBytes(user, id, WebHelper.BytesForImageUrl(imageUrl));
|
||||
|
||||
public async Task<OperationResult<bool>> UpdateLabelAsync(Library.Models.Users.User user, Label model)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var label = await DbContext.Labels.FirstOrDefaultAsync(x => x.RoadieId == model.Id).ConfigureAwait(false);
|
||||
if (label == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Label Not Found [{model.Id}]");
|
||||
}
|
||||
// If label is being renamed, see if label already exists with new model supplied name
|
||||
var labelName = label.SortNameValue;
|
||||
var labelModelName = model.SortNameValue;
|
||||
var oldPathToImage = label.PathToImage(Configuration);
|
||||
var didChangeName = !labelName.ToAlphanumericName().Equals(labelModelName.ToAlphanumericName(), StringComparison.OrdinalIgnoreCase);
|
||||
if (didChangeName)
|
||||
{
|
||||
var existingLabel = DbContext.Labels.FirstOrDefault(x => x.Name == model.Name || x.SortName == model.SortName);
|
||||
if (existingLabel != null)
|
||||
{
|
||||
return new OperationResult<bool>($"Label already exists `{ existingLabel }` with name [{ labelModelName }].");
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
var specialLabelName = model.Name.ToAlphanumericName();
|
||||
var alt = new List<string>(model.AlternateNamesList);
|
||||
if (!model.AlternateNamesList.Contains(specialLabelName, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
alt.Add(specialLabelName);
|
||||
}
|
||||
label.AlternateNames = alt.ToDelimitedList();
|
||||
label.BeginDate = model.BeginDate;
|
||||
label.DiscogsId = model.DiscogsId;
|
||||
label.EndDate = model.EndDate;
|
||||
label.IsLocked = model.IsLocked;
|
||||
label.MusicBrainzId = model.MusicBrainzId;
|
||||
label.Name = model.Name;
|
||||
label.Profile = model.Profile;
|
||||
label.SortName = model.SortName;
|
||||
label.Status = SafeParser.ToEnum<Statuses>(model.Status);
|
||||
label.Tags = model.TagsList.ToDelimitedList();
|
||||
label.URLs = model.URLsList.ToDelimitedList();
|
||||
|
||||
if (didChangeName)
|
||||
{
|
||||
if (File.Exists(oldPathToImage))
|
||||
{
|
||||
File.Move(oldPathToImage, label.PathToImage(Configuration));
|
||||
}
|
||||
}
|
||||
var labelImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
|
||||
if (labelImage != null)
|
||||
{
|
||||
// Save unaltered label image
|
||||
File.WriteAllBytes(label.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(labelImage));
|
||||
}
|
||||
label.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
CacheManager.ClearRegion(label.CacheRegion);
|
||||
Logger.LogInformation($"UpdateLabel `{label}` By User `{user}`");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Library.Models.Image>> UploadLabelImageAsync(Library.Models.Users.User user, Guid id, IFormFile file)
|
||||
{
|
||||
var bytes = new byte[0];
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
file.CopyTo(ms);
|
||||
bytes = ms.ToArray();
|
||||
}
|
||||
return await SaveImageBytes(user, id, bytes).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,7 +34,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DataToken>>> ArtistTypes()
|
||||
public Task<OperationResult<IEnumerable<DataToken>>> ArtistTypesAsync()
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
|
||||
|
@ -45,7 +45,7 @@ namespace Roadie.Api.Services
|
|||
});
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DataToken>>> BandStatus()
|
||||
public Task<OperationResult<IEnumerable<DataToken>>> BandStatusAsync()
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
|
||||
|
@ -56,7 +56,7 @@ namespace Roadie.Api.Services
|
|||
});
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DataToken>>> BookmarkTypes()
|
||||
public Task<OperationResult<IEnumerable<DataToken>>> BookmarkTypesAsync()
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
|
||||
|
@ -67,7 +67,7 @@ namespace Roadie.Api.Services
|
|||
});
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DataToken>>> CollectionTypes()
|
||||
public Task<OperationResult<IEnumerable<DataToken>>> CollectionTypesAsync()
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
|
||||
|
@ -78,7 +78,7 @@ namespace Roadie.Api.Services
|
|||
});
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DataToken>>> LibraryStatus()
|
||||
public Task<OperationResult<IEnumerable<DataToken>>> LibraryStatusAsync()
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
|
||||
|
@ -89,7 +89,7 @@ namespace Roadie.Api.Services
|
|||
});
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DataToken>>> QueMessageTypes()
|
||||
public Task<OperationResult<IEnumerable<DataToken>>> QueMessageTypesAsync()
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
|
||||
|
@ -100,7 +100,7 @@ namespace Roadie.Api.Services
|
|||
});
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DataToken>>> ReleaseTypes()
|
||||
public Task<OperationResult<IEnumerable<DataToken>>> ReleaseTypesAsync()
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
|
||||
|
@ -111,7 +111,7 @@ namespace Roadie.Api.Services
|
|||
});
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DataToken>>> RequestStatus()
|
||||
public Task<OperationResult<IEnumerable<DataToken>>> RequestStatusAsync()
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
|
||||
|
@ -122,17 +122,17 @@ namespace Roadie.Api.Services
|
|||
});
|
||||
}
|
||||
|
||||
public async Task<OperationResult<IEnumerable<DataToken>>> CreditCategories()
|
||||
public async Task<OperationResult<IEnumerable<DataToken>>> CreditCategoriesAsync()
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
var data = await CacheManager.GetAsync(CreditCategoriesCacheKey, async () =>
|
||||
{
|
||||
return (await DbContext.CreditCategory.ToListAsync()).Select(x => new DataToken
|
||||
return (await DbContext.CreditCategory.ToListAsync().ConfigureAwait(false)).Select(x => new DataToken
|
||||
{
|
||||
Value = x.RoadieId.ToString(),
|
||||
Text = x.Name
|
||||
}).ToArray();
|
||||
}, CacheManagerBase.SystemCacheRegionUrn);
|
||||
}, CacheManagerBase.SystemCacheRegionUrn).ConfigureAwait(false);
|
||||
return new OperationResult<IEnumerable<DataToken>>
|
||||
{
|
||||
Data = data,
|
||||
|
@ -141,7 +141,7 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DataToken>>> Status()
|
||||
public Task<OperationResult<IEnumerable<DataToken>>> StatusAsync()
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
return Task.FromResult(new OperationResult<IEnumerable<DataToken>>
|
||||
|
|
|
@ -19,7 +19,6 @@ using System.Diagnostics;
|
|||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Threading.Tasks;
|
||||
using data = Roadie.Library.Data;
|
||||
|
||||
namespace Roadie.Api.Services
|
||||
{
|
||||
|
@ -29,8 +28,15 @@ namespace Roadie.Api.Services
|
|||
|
||||
protected IScrobbleHandler ScrobblerHandler { get; }
|
||||
|
||||
public PlayActivityService(IRoadieSettings configuration, IHttpEncoder httpEncoder,IHttpContext httpContext,
|
||||
IRoadieDbContext dbContext, ICacheManager cacheManager,ILogger<PlayActivityService> logger,
|
||||
public PlayActivityService(IRoadieSettings configuration, IRoadieDbContext dbContext, ICacheManager cacheManager,
|
||||
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)
|
||||
: base(configuration, httpEncoder, dbContext, cacheManager, logger, httpContext)
|
||||
{
|
||||
|
@ -38,14 +44,84 @@ namespace Roadie.Api.Services
|
|||
ScrobblerHandler = scrobbleHandler;
|
||||
}
|
||||
|
||||
public PlayActivityService(IRoadieSettings configuration, IRoadieDbContext dbContext, ICacheManager cacheManager,
|
||||
ILogger logger, ScrobbleHandler scrobbleHandler)
|
||||
: base(configuration, null, dbContext, cacheManager, logger, null)
|
||||
private async Task PublishPlayActivity(User roadieUser, ScrobbleInfo scrobble, bool isNowPlaying)
|
||||
{
|
||||
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
|
||||
{
|
||||
|
@ -119,118 +195,46 @@ namespace Roadie.Api.Services
|
|||
? request.OrderValue(new Dictionary<string, string> { { "PlayedDateDateTime", "DESC" } })
|
||||
: request.OrderValue();
|
||||
var rowCount = result.Count();
|
||||
var rows = result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArray();
|
||||
var rows = await result.OrderBy(sortBy).Skip(request.SkipValue).Take(request.LimitValue).ToArrayAsync().ConfigureAwait(false);
|
||||
sw.Stop();
|
||||
return Task.FromResult(new Library.Models.Pagination.PagedResult<PlayActivityList>
|
||||
return new Library.Models.Pagination.PagedResult<PlayActivityList>
|
||||
{
|
||||
TotalCount = rowCount,
|
||||
CurrentPage = request.PageValue,
|
||||
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Rows = rows
|
||||
});
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
}
|
||||
|
||||
return Task.FromResult(new Library.Models.Pagination.PagedResult<PlayActivityList>());
|
||||
return new Library.Models.Pagination.PagedResult<PlayActivityList>();
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> NowPlaying(User roadieUser, ScrobbleInfo scrobble)
|
||||
public async Task<OperationResult<bool>> NowPlayingAsync(User roadieUser, ScrobbleInfo scrobble)
|
||||
{
|
||||
var scrobbleResult = await ScrobblerHandler.NowPlaying(roadieUser, scrobble);
|
||||
if (!scrobbleResult.IsSuccess) return scrobbleResult;
|
||||
await PublishPlayActivity(roadieUser, scrobble, true);
|
||||
return scrobbleResult;
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> Scrobble(User roadieUser, ScrobbleInfo scrobble)
|
||||
{
|
||||
var scrobbleResult = await ScrobblerHandler.Scrobble(roadieUser, scrobble);
|
||||
var scrobbleResult = await ScrobblerHandler.NowPlaying(roadieUser, scrobble).ConfigureAwait(false);
|
||||
if (!scrobbleResult.IsSuccess)
|
||||
{
|
||||
return scrobbleResult;
|
||||
}
|
||||
await PublishPlayActivity(roadieUser, scrobble, false);
|
||||
|
||||
await PublishPlayActivity(roadieUser, scrobble, true).ConfigureAwait(false);
|
||||
return scrobbleResult;
|
||||
}
|
||||
|
||||
private async Task PublishPlayActivity(User roadieUser, ScrobbleInfo scrobble, bool isNowPlaying)
|
||||
public async Task<OperationResult<bool>> ScrobbleAsync(User roadieUser, ScrobbleInfo scrobble)
|
||||
{
|
||||
// Only broadcast if the user is not public and played duration is more than half of duration
|
||||
if (roadieUser?.IsPrivate != true &&
|
||||
scrobble.ElapsedTimeOfTrackPlayed.TotalSeconds > scrobble.TrackDuration.TotalSeconds / 2)
|
||||
var scrobbleResult = await ScrobblerHandler.Scrobble(roadieUser, scrobble).ConfigureAwait(false);
|
||||
if (!scrobbleResult.IsSuccess)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
var track = DbContext.Tracks
|
||||
.Include(x => x.ReleaseMedia)
|
||||
.Include(x => x.ReleaseMedia.Release)
|
||||
.Include(x => x.ReleaseMedia.Release.Artist)
|
||||
.Include(x => x.TrackArtist)
|
||||
.FirstOrDefault(x => x.RoadieId == scrobble.TrackId);
|
||||
var user = DbContext.Users.FirstOrDefault(x => x.RoadieId == roadieUser.UserId);
|
||||
var userTrack =
|
||||
DbContext.UserTracks.FirstOrDefault(x => x.UserId == roadieUser.Id && x.TrackId == track.Id);
|
||||
var pl = new PlayActivityList
|
||||
{
|
||||
Artist = new DataToken
|
||||
{
|
||||
Text = track.ReleaseMedia.Release.Artist.Name,
|
||||
Value = track.ReleaseMedia.Release.Artist.RoadieId.ToString()
|
||||
},
|
||||
TrackArtist = track.TrackArtist == null
|
||||
? null
|
||||
: new DataToken
|
||||
{
|
||||
Text = track.TrackArtist.Name,
|
||||
Value = track.TrackArtist.RoadieId.ToString()
|
||||
},
|
||||
Release = new DataToken
|
||||
{
|
||||
Text = track.ReleaseMedia.Release.Title,
|
||||
Value = track.ReleaseMedia.Release.RoadieId.ToString()
|
||||
},
|
||||
Track = TrackList.FromDataTrack(null,
|
||||
track,
|
||||
track.ReleaseMedia.MediaNumber,
|
||||
track.ReleaseMedia.Release,
|
||||
track.ReleaseMedia.Release.Artist,
|
||||
track.TrackArtist,
|
||||
HttpContext.BaseUrl,
|
||||
ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, track.RoadieId),
|
||||
ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId),
|
||||
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId),
|
||||
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.TrackArtist == null
|
||||
? null
|
||||
: (Guid?)track.TrackArtist.RoadieId)),
|
||||
User = new DataToken
|
||||
{
|
||||
Text = roadieUser.UserName,
|
||||
Value = roadieUser.UserId.ToString()
|
||||
},
|
||||
ArtistThumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.TrackArtist != null
|
||||
? track.TrackArtist.RoadieId
|
||||
: track.ReleaseMedia.Release.Artist.RoadieId),
|
||||
PlayedDateDateTime = scrobble.TimePlayed,
|
||||
IsNowPlaying = isNowPlaying,
|
||||
Rating = track.Rating,
|
||||
ReleasePlayUrl = $"{HttpContext.BaseUrl}/play/release/{track.ReleaseMedia.Release.RoadieId}",
|
||||
ReleaseThumbnail = ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId),
|
||||
TrackPlayUrl = $"{HttpContext.BaseUrl}/play/track/{track.RoadieId}.mp3",
|
||||
UserRating = userTrack?.Rating,
|
||||
UserThumbnail = ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, roadieUser.UserId)
|
||||
};
|
||||
try
|
||||
{
|
||||
await PlayActivityHub.Clients.All.SendAsync("SendActivity", pl);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
}
|
||||
return scrobbleResult;
|
||||
}
|
||||
await PublishPlayActivity(roadieUser, scrobble, false).ConfigureAwait(false);
|
||||
return scrobbleResult;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -42,412 +42,6 @@ namespace Roadie.Api.Services
|
|||
BookmarkService = bookmarkService;
|
||||
}
|
||||
|
||||
public async Task<OperationResult<PlaylistList>> AddNewPlaylist(User user, Playlist model)
|
||||
{
|
||||
var playlist = new data.Playlist
|
||||
{
|
||||
IsPublic = model.IsPublic,
|
||||
Description = model.Description,
|
||||
Name = model.Name,
|
||||
UserId = user.Id
|
||||
};
|
||||
DbContext.Playlists.Add(playlist);
|
||||
await DbContext.SaveChangesAsync();
|
||||
var r = await AddTracksToPlaylist(playlist,
|
||||
model.Tracks.OrderBy(x => x.ListNumber).Select(x => x.Track.Id));
|
||||
var request = new PagedRequest
|
||||
{
|
||||
FilterToPlaylistId = playlist.RoadieId
|
||||
};
|
||||
var result = await List(request, user);
|
||||
return new OperationResult<PlaylistList>
|
||||
{
|
||||
Data = result.Rows.First(),
|
||||
IsSuccess = true
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> AddTracksToPlaylist(data.Playlist playlist, IEnumerable<Guid> trackIds)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
var result = false;
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
var existingTracksForPlaylist = from plt in DbContext.PlaylistTracks
|
||||
join t in DbContext.Tracks on plt.TrackId equals t.Id
|
||||
where plt.PlayListId == playlist.Id
|
||||
select t;
|
||||
var newTracksForPlaylist = (from t in DbContext.Tracks
|
||||
where (from x in trackIds select x).Contains(t.RoadieId)
|
||||
where !(from x in existingTracksForPlaylist select x.RoadieId).Contains(t.RoadieId)
|
||||
select t).ToArray();
|
||||
foreach (var newTrackForPlaylist in newTracksForPlaylist)
|
||||
DbContext.PlaylistTracks.Add(new data.PlaylistTrack
|
||||
{
|
||||
TrackId = newTrackForPlaylist.Id,
|
||||
PlayListId = playlist.Id
|
||||
});
|
||||
playlist.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync();
|
||||
result = true;
|
||||
|
||||
var r = await ReorderPlaylist(playlist);
|
||||
result = result && r.IsSuccess;
|
||||
|
||||
await UpdatePlaylistCounts(playlist.Id, now);
|
||||
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = result,
|
||||
Data = result,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Playlist>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
var cacheKey = string.Format("urn:playlist_by_id_operation:{0}:{1}", id,
|
||||
includes == null ? "0" : string.Join("|", includes));
|
||||
var result = await CacheManager.GetAsync(cacheKey, async () =>
|
||||
{
|
||||
return await PlaylistByIdAction(id, includes);
|
||||
}, data.Artist.CacheRegionUrn(id));
|
||||
sw.Stop();
|
||||
if (result?.Data != null && roadieUser != null)
|
||||
{
|
||||
if (result?.Data?.Tracks != null)
|
||||
{
|
||||
var user = await GetUser(roadieUser.UserId);
|
||||
foreach (var track in result.Data.Tracks)
|
||||
{
|
||||
track.Track.TrackPlayUrl = MakeTrackPlayUrl(user, HttpContext.BaseUrl, track.Track.Id);
|
||||
}
|
||||
}
|
||||
|
||||
result.Data.UserCanEdit = result.Data.Maintainer.Id == roadieUser.UserId || roadieUser.IsAdmin;
|
||||
var userBookmarkResult = await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Playlist);
|
||||
if (userBookmarkResult.IsSuccess)
|
||||
{
|
||||
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x?.Bookmark?.Value == result?.Data?.Id?.ToString()) != null;
|
||||
}
|
||||
if (result.Data.Comments.Any())
|
||||
{
|
||||
var commentIds = result.Data.Comments.Select(x => x.DatabaseId).ToArray();
|
||||
var userCommentReactions = (from cr in DbContext.CommentReactions
|
||||
where commentIds.Contains(cr.CommentId)
|
||||
where cr.UserId == roadieUser.Id
|
||||
select cr).ToArray();
|
||||
foreach (var comment in result.Data.Comments)
|
||||
{
|
||||
var userCommentReaction = userCommentReactions.FirstOrDefault(x => x.CommentId == comment.DatabaseId);
|
||||
comment.IsDisliked = userCommentReaction?.ReactionValue == CommentReaction.Dislike;
|
||||
comment.IsLiked = userCommentReaction?.ReactionValue == CommentReaction.Like;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new OperationResult<Playlist>(result.Messages)
|
||||
{
|
||||
Data = result?.Data,
|
||||
IsNotFoundResult = result?.IsNotFoundResult ?? false,
|
||||
Errors = result?.Errors,
|
||||
IsSuccess = result?.IsSuccess ?? false,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeletePlaylist(User user, Guid id)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var playlist = DbContext.Playlists.FirstOrDefault(x => x.RoadieId == id);
|
||||
if (playlist == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, string.Format("Playlist Not Found [{0}]", id));
|
||||
}
|
||||
if (!user.IsAdmin && user.Id != playlist.UserId)
|
||||
{
|
||||
Logger.LogWarning("User `{0}` attempted to delete Playlist `{1}`", user, playlist);
|
||||
return new OperationResult<bool>("Access Denied")
|
||||
{
|
||||
IsAccessDeniedResult = true
|
||||
};
|
||||
}
|
||||
|
||||
DbContext.Playlists.Remove(playlist);
|
||||
await DbContext.SaveChangesAsync();
|
||||
await BookmarkService.RemoveAllBookmarksForItem(BookmarkType.Playlist, playlist.Id);
|
||||
|
||||
var playlistImageFilename = playlist.PathToImage(Configuration);
|
||||
if (File.Exists(playlistImageFilename))
|
||||
{
|
||||
File.Delete(playlistImageFilename);
|
||||
}
|
||||
|
||||
Logger.LogWarning("User `{0}` deleted Playlist `{1}]`", user, playlist);
|
||||
CacheManager.ClearRegion(playlist.CacheRegion);
|
||||
sw.Stop();
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public Task<Library.Models.Pagination.PagedResult<PlaylistList>> List(PagedRequest request, User roadieUser = null)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
var playlistWithArtistTrackIds = new int[0];
|
||||
if (request.FilterToArtistId.HasValue)
|
||||
{
|
||||
playlistWithArtistTrackIds = (from pl in DbContext.Playlists
|
||||
join pltr in DbContext.PlaylistTracks on pl.Id equals pltr.PlayListId
|
||||
join t in DbContext.Tracks on pltr.TrackId equals t.Id
|
||||
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
join r in DbContext.Releases on rm.ReleaseId equals r.Id
|
||||
join a in DbContext.Artists on r.ArtistId equals a.Id
|
||||
where a.RoadieId == request.FilterToArtistId
|
||||
select pl.Id
|
||||
).ToArray();
|
||||
}
|
||||
var playlistReleaseTrackIds = new int[0];
|
||||
if (request.FilterToReleaseId.HasValue)
|
||||
{
|
||||
playlistReleaseTrackIds = (from pl in DbContext.Playlists
|
||||
join pltr in DbContext.PlaylistTracks on pl.Id equals pltr.PlayListId
|
||||
join t in DbContext.Tracks on pltr.TrackId equals t.Id
|
||||
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
join r in DbContext.Releases on rm.ReleaseId equals r.Id
|
||||
where r.RoadieId == request.FilterToReleaseId
|
||||
select pl.Id
|
||||
).ToArray();
|
||||
}
|
||||
var normalizedFilterValue = !string.IsNullOrEmpty(request.FilterValue)
|
||||
? request.FilterValue.ToAlphanumericName()
|
||||
: null;
|
||||
var result = from pl in DbContext.Playlists
|
||||
join u in DbContext.Users on pl.UserId equals u.Id
|
||||
where request.FilterToPlaylistId == null || pl.RoadieId == request.FilterToPlaylistId
|
||||
where request.FilterToArtistId == null || playlistWithArtistTrackIds.Contains(pl.Id)
|
||||
where request.FilterToReleaseId == null || playlistReleaseTrackIds.Contains(pl.Id)
|
||||
where roadieUser == null && pl.IsPublic || roadieUser != null && u.RoadieId == roadieUser.UserId || pl.IsPublic
|
||||
where string.IsNullOrEmpty(normalizedFilterValue) || (
|
||||
pl.Name.ToLower().Contains(normalizedFilterValue) ||
|
||||
pl.AlternateNames.ToLower().Contains(normalizedFilterValue)
|
||||
)
|
||||
select new PlaylistList
|
||||
{
|
||||
Playlist = new DataToken
|
||||
{
|
||||
Text = pl.Name,
|
||||
Value = pl.RoadieId.ToString()
|
||||
},
|
||||
User = new DataToken
|
||||
{
|
||||
Text = u.UserName,
|
||||
Value = u.RoadieId.ToString()
|
||||
},
|
||||
PlaylistCount = pl.TrackCount,
|
||||
IsPublic = pl.IsPublic,
|
||||
Duration = pl.Duration,
|
||||
TrackCount = pl.TrackCount,
|
||||
CreatedDate = pl.CreatedDate,
|
||||
LastUpdated = pl.LastUpdated,
|
||||
UserThumbnail = ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, u.RoadieId),
|
||||
Id = pl.RoadieId,
|
||||
Thumbnail = ImageHelper.MakePlaylistThumbnailImage(Configuration, HttpContext, pl.RoadieId)
|
||||
};
|
||||
var sortBy = string.IsNullOrEmpty(request.Sort)
|
||||
? request.OrderValue(new Dictionary<string, string> { { "Playlist.Text", "ASC" } })
|
||||
: request.OrderValue();
|
||||
var rowCount = result.Count();
|
||||
var rows = result
|
||||
.OrderBy(sortBy)
|
||||
.Skip(request.SkipValue)
|
||||
.Take(request.LimitValue)
|
||||
.ToArray();
|
||||
sw.Stop();
|
||||
return Task.FromResult(new Library.Models.Pagination.PagedResult<PlaylistList>
|
||||
{
|
||||
TotalCount = rowCount,
|
||||
CurrentPage = request.PageValue,
|
||||
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Rows = rows
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ReorderPlaylist(data.Playlist playlist)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
var result = false;
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
if (playlist != null)
|
||||
{
|
||||
var looper = 0;
|
||||
foreach (var playlistTrack in DbContext.PlaylistTracks.Where(x => x.PlayListId == playlist.Id)
|
||||
.OrderBy(x => x.CreatedDate))
|
||||
{
|
||||
looper++;
|
||||
playlistTrack.ListNumber = looper;
|
||||
playlistTrack.LastUpdated = now;
|
||||
}
|
||||
|
||||
await DbContext.SaveChangesAsync();
|
||||
result = true;
|
||||
}
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = result,
|
||||
Data = result
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> UpdatePlaylist(User user, Playlist model)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var playlist = DbContext.Playlists.FirstOrDefault(x => x.RoadieId == model.Id);
|
||||
if (playlist == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, string.Format("Playlist Not Found [{0}]", model.Id));
|
||||
}
|
||||
if (!user.IsAdmin && user.Id != playlist.UserId)
|
||||
{
|
||||
Logger.LogWarning("User `{0}` attempted to update Playlist `{1}`", user, playlist);
|
||||
return new OperationResult<bool>("Access Denied")
|
||||
{
|
||||
IsAccessDeniedResult = true
|
||||
};
|
||||
}
|
||||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
playlist.AlternateNames = model.AlternateNamesList.ToDelimitedList();
|
||||
playlist.Description = model.Description;
|
||||
playlist.IsLocked = model.IsLocked;
|
||||
playlist.IsPublic = model.IsPublic;
|
||||
var oldPathToImage = playlist.PathToImage(Configuration);
|
||||
var didChangeName = playlist.Name != model.Name;
|
||||
playlist.Name = model.Name;
|
||||
playlist.Status = SafeParser.ToEnum<Statuses>(model.Status);
|
||||
playlist.Tags = model.TagsList.ToDelimitedList();
|
||||
playlist.URLs = model.URLsList.ToDelimitedList();
|
||||
|
||||
if (didChangeName)
|
||||
{
|
||||
if (File.Exists(oldPathToImage))
|
||||
{
|
||||
File.Move(oldPathToImage, playlist.PathToImage(Configuration));
|
||||
}
|
||||
}
|
||||
|
||||
var playlistImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
|
||||
if (playlistImage != null)
|
||||
{
|
||||
// Save unaltered playlist image
|
||||
File.WriteAllBytes(playlist.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(playlistImage));
|
||||
}
|
||||
playlist.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync();
|
||||
|
||||
CacheManager.ClearRegion(playlist.CacheRegion);
|
||||
Logger.LogInformation($"UpdatePlaylist `{playlist}` By User `{user}`");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> UpdatePlaylistTracks(User user, PlaylistTrackModifyRequest request)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var playlist = DbContext.Playlists.Include(x => x.Tracks).FirstOrDefault(x => x.RoadieId == request.Id);
|
||||
if (playlist == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, string.Format("Label Not Found [{0}]", request.Id));
|
||||
}
|
||||
if (!user.IsAdmin && user.Id != playlist.UserId)
|
||||
{
|
||||
Logger.LogWarning("User `{0}` attempted to update Playlist Tracks `{1}`", user, playlist);
|
||||
return new OperationResult<bool>("Access Denied")
|
||||
{
|
||||
IsAccessDeniedResult = true
|
||||
};
|
||||
}
|
||||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
playlist.Tracks.Clear();
|
||||
|
||||
var tracks = (from t in DbContext.Tracks
|
||||
join plt in request.Tracks on t.RoadieId equals plt.Track.Id
|
||||
select t).ToArray();
|
||||
foreach (var newPlaylistTrack in request.Tracks.OrderBy(x => x.ListNumber))
|
||||
{
|
||||
var track = tracks.FirstOrDefault(x => x.RoadieId == newPlaylistTrack.Track.Id);
|
||||
playlist.Tracks.Add(new data.PlaylistTrack
|
||||
{
|
||||
ListNumber = newPlaylistTrack.ListNumber,
|
||||
PlayListId = playlist.Id,
|
||||
CreatedDate = now,
|
||||
TrackId = track.Id
|
||||
});
|
||||
}
|
||||
|
||||
playlist.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync();
|
||||
|
||||
// await base.UpdatePlaylistCounts(playlist.Id, now);
|
||||
|
||||
Logger.LogInformation($"UpdatePlaylistTracks `{playlist}` By User `{user}`");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = !errors.Any(),
|
||||
Data = !errors.Any(),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<OperationResult<Playlist>> PlaylistByIdAction(Guid id, IEnumerable<string> includes = null)
|
||||
{
|
||||
var timings = new Dictionary<string, long>();
|
||||
|
@ -457,13 +51,13 @@ namespace Roadie.Api.Services
|
|||
sw.Start();
|
||||
|
||||
tsw.Restart();
|
||||
var playlist = await GetPlaylist(id);
|
||||
var playlist = await GetPlaylist(id).ConfigureAwait(false);
|
||||
tsw.Stop();
|
||||
timings.Add("getPlaylist", tsw.ElapsedMilliseconds);
|
||||
|
||||
if (playlist == null)
|
||||
{
|
||||
return new OperationResult<Playlist>(true, string.Format("Playlist Not Found [{0}]", id));
|
||||
return new OperationResult<Playlist>(true, $"Playlist Not Found [{id}]");
|
||||
}
|
||||
tsw.Restart();
|
||||
var result = playlist.Adapt<Playlist>();
|
||||
|
@ -563,5 +157,416 @@ namespace Roadie.Api.Services
|
|||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<PlaylistList>> AddNewPlaylistAsync(User user, Playlist model)
|
||||
{
|
||||
var playlist = new data.Playlist
|
||||
{
|
||||
IsPublic = model.IsPublic,
|
||||
Description = model.Description,
|
||||
Name = model.Name,
|
||||
UserId = user.Id
|
||||
};
|
||||
DbContext.Playlists.Add(playlist);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
var r = await AddTracksToPlaylistAsync(playlist, model.Tracks.OrderBy(x => x.ListNumber).Select(x => x.Track.Id)).ConfigureAwait(false);
|
||||
var request = new PagedRequest
|
||||
{
|
||||
FilterToPlaylistId = playlist.RoadieId
|
||||
};
|
||||
var result = await ListAsync(request, user).ConfigureAwait(false);
|
||||
return new OperationResult<PlaylistList>
|
||||
{
|
||||
Data = result.Rows.First(),
|
||||
IsSuccess = true
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> AddTracksToPlaylistAsync(data.Playlist playlist, IEnumerable<Guid> trackIds)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
var result = false;
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
var existingTracksForPlaylist = from plt in DbContext.PlaylistTracks
|
||||
join t in DbContext.Tracks on plt.TrackId equals t.Id
|
||||
where plt.PlayListId == playlist.Id
|
||||
select t;
|
||||
var newTracksForPlaylist = await (from t in DbContext.Tracks
|
||||
where (from x in trackIds select x).Contains(t.RoadieId)
|
||||
where !(from x in existingTracksForPlaylist select x.RoadieId).Contains(t.RoadieId)
|
||||
select t)
|
||||
.ToArrayAsync()
|
||||
.ConfigureAwait(false);
|
||||
foreach (var newTrackForPlaylist in newTracksForPlaylist)
|
||||
{
|
||||
DbContext.PlaylistTracks.Add(new data.PlaylistTrack
|
||||
{
|
||||
TrackId = newTrackForPlaylist.Id,
|
||||
PlayListId = playlist.Id
|
||||
});
|
||||
}
|
||||
|
||||
playlist.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
result = true;
|
||||
|
||||
var r = await ReorderPlaylistAsync(playlist).ConfigureAwait(false);
|
||||
result = result && r.IsSuccess;
|
||||
|
||||
await UpdatePlaylistCounts(playlist.Id, now).ConfigureAwait(false);
|
||||
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = result,
|
||||
Data = result,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Playlist>> ByIdAsync(User roadieUser, Guid id, IEnumerable<string> includes = null)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
var cacheKey = $"urn:playlist_by_id_operation:{id}:{(includes == null ? "0" : string.Join("|", includes))}";
|
||||
var result = await CacheManager.GetAsync(cacheKey, async () =>
|
||||
{
|
||||
return await PlaylistByIdAction(id, includes).ConfigureAwait(false);
|
||||
}, data.Artist.CacheRegionUrn(id)).ConfigureAwait(false);
|
||||
sw.Stop();
|
||||
if (result?.Data != null && roadieUser != null)
|
||||
{
|
||||
if (result?.Data?.Tracks != null)
|
||||
{
|
||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||
foreach (var track in result.Data.Tracks)
|
||||
{
|
||||
track.Track.TrackPlayUrl = MakeTrackPlayUrl(user, HttpContext.BaseUrl, track.Track.Id);
|
||||
}
|
||||
}
|
||||
|
||||
result.Data.UserCanEdit = result.Data.Maintainer.Id == roadieUser.UserId || roadieUser.IsAdmin;
|
||||
var userBookmarkResult = await BookmarkService.ListAsync(roadieUser, new PagedRequest(), false, BookmarkType.Playlist).ConfigureAwait(false);
|
||||
if (userBookmarkResult.IsSuccess)
|
||||
{
|
||||
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x?.Bookmark?.Value == result?.Data?.Id?.ToString()) != null;
|
||||
}
|
||||
if (result.Data.Comments.Any())
|
||||
{
|
||||
var commentIds = result.Data.Comments.Select(x => x.DatabaseId).ToArray();
|
||||
var userCommentReactions = await (from cr in DbContext.CommentReactions
|
||||
where commentIds.Contains(cr.CommentId)
|
||||
where cr.UserId == roadieUser.Id
|
||||
select cr)
|
||||
.ToArrayAsync()
|
||||
.ConfigureAwait(false);
|
||||
foreach (var comment in result.Data.Comments)
|
||||
{
|
||||
var userCommentReaction = Array.Find(userCommentReactions, x => x.CommentId == comment.DatabaseId);
|
||||
comment.IsDisliked = userCommentReaction?.ReactionValue == CommentReaction.Dislike;
|
||||
comment.IsLiked = userCommentReaction?.ReactionValue == CommentReaction.Like;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new OperationResult<Playlist>(result.Messages)
|
||||
{
|
||||
Data = result?.Data,
|
||||
IsNotFoundResult = result?.IsNotFoundResult ?? false,
|
||||
Errors = result?.Errors,
|
||||
IsSuccess = result?.IsSuccess ?? false,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeletePlaylistAsync(User user, Guid id)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var playlist = await DbContext.Playlists.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||
if (playlist == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Playlist Not Found [{id}]");
|
||||
}
|
||||
if (!user.IsAdmin && user.Id != playlist.UserId)
|
||||
{
|
||||
Logger.LogWarning("User `{0}` attempted to delete Playlist `{1}`", user, playlist);
|
||||
return new OperationResult<bool>("Access Denied")
|
||||
{
|
||||
IsAccessDeniedResult = true
|
||||
};
|
||||
}
|
||||
|
||||
DbContext.Playlists.Remove(playlist);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
await BookmarkService.RemoveAllBookmarksForItemAsync(BookmarkType.Playlist, playlist.Id).ConfigureAwait(false);
|
||||
|
||||
var playlistImageFilename = playlist.PathToImage(Configuration);
|
||||
if (File.Exists(playlistImageFilename))
|
||||
{
|
||||
File.Delete(playlistImageFilename);
|
||||
}
|
||||
|
||||
Logger.LogWarning("User `{0}` deleted Playlist `{1}]`", user, playlist);
|
||||
CacheManager.ClearRegion(playlist.CacheRegion);
|
||||
sw.Stop();
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = true,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<Library.Models.Pagination.PagedResult<PlaylistList>> ListAsync(PagedRequest request, User roadieUser = null)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
var playlistWithArtistTrackIds = new int[0];
|
||||
if (request.FilterToArtistId.HasValue)
|
||||
{
|
||||
playlistWithArtistTrackIds = await (from pl in DbContext.Playlists
|
||||
join pltr in DbContext.PlaylistTracks on pl.Id equals pltr.PlayListId
|
||||
join t in DbContext.Tracks on pltr.TrackId equals t.Id
|
||||
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
join r in DbContext.Releases on rm.ReleaseId equals r.Id
|
||||
join a in DbContext.Artists on r.ArtistId equals a.Id
|
||||
where a.RoadieId == request.FilterToArtistId
|
||||
select pl.Id
|
||||
).ToArrayAsync().ConfigureAwait(false);
|
||||
}
|
||||
var playlistReleaseTrackIds = new int[0];
|
||||
if (request.FilterToReleaseId.HasValue)
|
||||
{
|
||||
playlistReleaseTrackIds = await (from pl in DbContext.Playlists
|
||||
join pltr in DbContext.PlaylistTracks on pl.Id equals pltr.PlayListId
|
||||
join t in DbContext.Tracks on pltr.TrackId equals t.Id
|
||||
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
join r in DbContext.Releases on rm.ReleaseId equals r.Id
|
||||
where r.RoadieId == request.FilterToReleaseId
|
||||
select pl.Id
|
||||
).ToArrayAsync().ConfigureAwait(false);
|
||||
}
|
||||
var normalizedFilterValue = !string.IsNullOrEmpty(request.FilterValue)
|
||||
? request.FilterValue.ToAlphanumericName()
|
||||
: null;
|
||||
var result = from pl in DbContext.Playlists
|
||||
join u in DbContext.Users on pl.UserId equals u.Id
|
||||
where request.FilterToPlaylistId == null || pl.RoadieId == request.FilterToPlaylistId
|
||||
where request.FilterToArtistId == null || playlistWithArtistTrackIds.Contains(pl.Id)
|
||||
where request.FilterToReleaseId == null || playlistReleaseTrackIds.Contains(pl.Id)
|
||||
where roadieUser == null && pl.IsPublic || roadieUser != null && u.RoadieId == roadieUser.UserId || pl.IsPublic
|
||||
where string.IsNullOrEmpty(normalizedFilterValue) || (
|
||||
pl.Name.ToLower().Contains(normalizedFilterValue) ||
|
||||
pl.AlternateNames.ToLower().Contains(normalizedFilterValue)
|
||||
)
|
||||
select new PlaylistList
|
||||
{
|
||||
Playlist = new DataToken
|
||||
{
|
||||
Text = pl.Name,
|
||||
Value = pl.RoadieId.ToString()
|
||||
},
|
||||
User = new DataToken
|
||||
{
|
||||
Text = u.UserName,
|
||||
Value = u.RoadieId.ToString()
|
||||
},
|
||||
PlaylistCount = pl.TrackCount,
|
||||
IsPublic = pl.IsPublic,
|
||||
Duration = pl.Duration,
|
||||
TrackCount = pl.TrackCount,
|
||||
CreatedDate = pl.CreatedDate,
|
||||
LastUpdated = pl.LastUpdated,
|
||||
UserThumbnail = ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, u.RoadieId),
|
||||
Id = pl.RoadieId,
|
||||
Thumbnail = ImageHelper.MakePlaylistThumbnailImage(Configuration, HttpContext, pl.RoadieId)
|
||||
};
|
||||
var sortBy = string.IsNullOrEmpty(request.Sort)
|
||||
? request.OrderValue(new Dictionary<string, string> { { "Playlist.Text", "ASC" } })
|
||||
: request.OrderValue();
|
||||
var rowCount = await result.CountAsync().ConfigureAwait(false);
|
||||
var rows = await result
|
||||
.OrderBy(sortBy)
|
||||
.Skip(request.SkipValue)
|
||||
.Take(request.LimitValue)
|
||||
.ToArrayAsync()
|
||||
.ConfigureAwait(false);
|
||||
sw.Stop();
|
||||
return new Library.Models.Pagination.PagedResult<PlaylistList>
|
||||
{
|
||||
TotalCount = rowCount,
|
||||
CurrentPage = request.PageValue,
|
||||
TotalPages = (int)Math.Ceiling((double)rowCount / request.LimitValue),
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Rows = rows
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> ReorderPlaylistAsync(data.Playlist playlist)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
var result = false;
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
if (playlist != null)
|
||||
{
|
||||
var looper = 0;
|
||||
foreach (var playlistTrack in DbContext.PlaylistTracks.Where(x => x.PlayListId == playlist.Id).OrderBy(x => x.CreatedDate))
|
||||
{
|
||||
looper++;
|
||||
playlistTrack.ListNumber = looper;
|
||||
playlistTrack.LastUpdated = now;
|
||||
}
|
||||
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
result = true;
|
||||
}
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = result,
|
||||
Data = result
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> UpdatePlaylistAsync(User user, Playlist model)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var playlist = await DbContext.Playlists.FirstOrDefaultAsync(x => x.RoadieId == model.Id).ConfigureAwait(false);
|
||||
if (playlist == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Playlist Not Found [{model.Id}]");
|
||||
}
|
||||
if (!user.IsAdmin && user.Id != playlist.UserId)
|
||||
{
|
||||
Logger.LogWarning("User `{0}` attempted to update Playlist `{1}`", user, playlist);
|
||||
return new OperationResult<bool>("Access Denied")
|
||||
{
|
||||
IsAccessDeniedResult = true
|
||||
};
|
||||
}
|
||||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
playlist.AlternateNames = model.AlternateNamesList.ToDelimitedList();
|
||||
playlist.Description = model.Description;
|
||||
playlist.IsLocked = model.IsLocked;
|
||||
playlist.IsPublic = model.IsPublic;
|
||||
var oldPathToImage = playlist.PathToImage(Configuration);
|
||||
var didChangeName = playlist.Name != model.Name;
|
||||
playlist.Name = model.Name;
|
||||
playlist.Status = SafeParser.ToEnum<Statuses>(model.Status);
|
||||
playlist.Tags = model.TagsList.ToDelimitedList();
|
||||
playlist.URLs = model.URLsList.ToDelimitedList();
|
||||
|
||||
if (didChangeName)
|
||||
{
|
||||
if (File.Exists(oldPathToImage))
|
||||
{
|
||||
File.Move(oldPathToImage, playlist.PathToImage(Configuration));
|
||||
}
|
||||
}
|
||||
|
||||
var playlistImage = ImageHelper.ImageDataFromUrl(model.NewThumbnailData);
|
||||
if (playlistImage != null)
|
||||
{
|
||||
// Save unaltered playlist image
|
||||
await File.WriteAllBytesAsync(playlist.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(playlistImage)).ConfigureAwait(false);
|
||||
}
|
||||
playlist.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
CacheManager.ClearRegion(playlist.CacheRegion);
|
||||
Logger.LogInformation($"UpdatePlaylist `{playlist}` By User `{user}`");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = errors.Count == 0,
|
||||
Data = errors.Count == 0,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> UpdatePlaylistTracksAsync(User user, PlaylistTrackModifyRequest request)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var errors = new List<Exception>();
|
||||
var playlist = await DbContext.Playlists.Include(x => x.Tracks).FirstOrDefaultAsync(x => x.RoadieId == request.Id).ConfigureAwait(false);
|
||||
if (playlist == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Label Not Found [{request.Id}]");
|
||||
}
|
||||
if (!user.IsAdmin && user.Id != playlist.UserId)
|
||||
{
|
||||
Logger.LogWarning("User `{0}` attempted to update Playlist Tracks `{1}`", user, playlist);
|
||||
return new OperationResult<bool>("Access Denied")
|
||||
{
|
||||
IsAccessDeniedResult = true
|
||||
};
|
||||
}
|
||||
try
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
playlist.Tracks.Clear();
|
||||
|
||||
var tracks = await (from t in DbContext.Tracks
|
||||
join plt in request.Tracks on t.RoadieId equals plt.Track.Id
|
||||
select t).ToArrayAsync().ConfigureAwait(false);
|
||||
foreach (var newPlaylistTrack in request.Tracks.OrderBy(x => x.ListNumber))
|
||||
{
|
||||
var track = Array.Find(tracks, x => x.RoadieId == newPlaylistTrack.Track.Id);
|
||||
playlist.Tracks.Add(new data.PlaylistTrack
|
||||
{
|
||||
ListNumber = newPlaylistTrack.ListNumber,
|
||||
PlayListId = playlist.Id,
|
||||
CreatedDate = now,
|
||||
TrackId = track.Id
|
||||
});
|
||||
}
|
||||
|
||||
playlist.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
// await base.UpdatePlaylistCounts(playlist.Id, now);
|
||||
|
||||
Logger.LogInformation($"UpdatePlaylistTracks `{playlist}` By User `{user}`");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex);
|
||||
errors.Add(ex);
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = errors.Count == 0,
|
||||
Data = errors.Count == 0,
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
Errors = errors
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -99,91 +99,91 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
return null;
|
||||
}
|
||||
return await GetArtist(artistByName.RoadieId);
|
||||
return await GetArtist(artistByName.RoadieId).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
protected Task<data.Artist> GetArtist(Guid id)
|
||||
protected async Task<data.Artist> GetArtist(Guid id)
|
||||
{
|
||||
if (id == Guid.Empty)
|
||||
{
|
||||
return Task.FromResult<data.Artist>(null);
|
||||
return null;
|
||||
}
|
||||
return CacheManager.GetAsync(data.Artist.CacheUrn(id), () =>
|
||||
return await CacheManager.GetAsync(data.Artist.CacheUrn(id), async () =>
|
||||
{
|
||||
return DbContext.Artists
|
||||
return await DbContext.Artists
|
||||
.Include(x => x.Genres)
|
||||
.Include("Genres.Genre")
|
||||
.FirstOrDefaultAsync(x => x.RoadieId == id);
|
||||
}, data.Artist.CacheRegionUrn(id));
|
||||
.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||
}, data.Artist.CacheRegionUrn(id)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
protected Task<data.Collection> GetCollection(Guid id)
|
||||
protected async Task<data.Collection> GetCollection(Guid id)
|
||||
{
|
||||
if (id == Guid.Empty)
|
||||
{
|
||||
return Task.FromResult<data.Collection>(null);
|
||||
return null;
|
||||
}
|
||||
return CacheManager.GetAsync(data.Collection.CacheUrn(id), () =>
|
||||
return await CacheManager.GetAsync(data.Collection.CacheUrn(id), async () =>
|
||||
{
|
||||
return DbContext.Collections.FirstOrDefaultAsync(x => x.RoadieId == id);
|
||||
}, data.Collection.CacheRegionUrn(id));
|
||||
return await DbContext.Collections.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||
}, data.Collection.CacheRegionUrn(id)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
protected Task<data.Genre> GetGenre(Guid id)
|
||||
protected async Task<data.Genre> GetGenre(Guid id)
|
||||
{
|
||||
if (id == Guid.Empty)
|
||||
{
|
||||
return Task.FromResult<data.Genre>(null);
|
||||
return null;
|
||||
}
|
||||
return CacheManager.GetAsync(data.Genre.CacheUrn(id), () =>
|
||||
return await CacheManager.GetAsync(data.Genre.CacheUrn(id), async () =>
|
||||
{
|
||||
return DbContext.Genres.FirstOrDefaultAsync(x => x.RoadieId == id);
|
||||
}, data.Genre.CacheRegionUrn(id));
|
||||
return await DbContext.Genres.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||
}, data.Genre.CacheRegionUrn(id)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
protected Task<data.Label> GetLabel(Guid id)
|
||||
protected async Task<data.Label> GetLabel(Guid id)
|
||||
{
|
||||
if (id == Guid.Empty)
|
||||
{
|
||||
return Task.FromResult<data.Label>(null);
|
||||
return null;
|
||||
}
|
||||
return CacheManager.GetAsync(data.Label.CacheUrn(id), () =>
|
||||
return await CacheManager.GetAsync(data.Label.CacheUrn(id), async () =>
|
||||
{
|
||||
return DbContext.Labels.FirstOrDefaultAsync(x => x.RoadieId == id);
|
||||
}, data.Label.CacheRegionUrn(id));
|
||||
return await DbContext.Labels.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||
}, data.Label.CacheRegionUrn(id)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
protected Task<data.Playlist> GetPlaylist(Guid id)
|
||||
protected async Task<data.Playlist> GetPlaylist(Guid id)
|
||||
{
|
||||
if (id == Guid.Empty)
|
||||
{
|
||||
return Task.FromResult<data.Playlist>(null);
|
||||
return null;
|
||||
}
|
||||
return CacheManager.GetAsync(data.Playlist.CacheUrn(id), () =>
|
||||
return await CacheManager.GetAsync(data.Playlist.CacheUrn(id), async () =>
|
||||
{
|
||||
return DbContext.Playlists
|
||||
return await DbContext.Playlists
|
||||
.Include(x => x.User)
|
||||
.FirstOrDefaultAsync(x => x.RoadieId == id);
|
||||
}, data.Playlist.CacheRegionUrn(id));
|
||||
.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||
}, data.Playlist.CacheRegionUrn(id)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
protected Task<data.Release> GetRelease(Guid id)
|
||||
protected async Task<data.Release> GetRelease(Guid id)
|
||||
{
|
||||
if (id == Guid.Empty)
|
||||
{
|
||||
return Task.FromResult<data.Release>(null);
|
||||
return null;
|
||||
}
|
||||
return CacheManager.GetAsync(data.Release.CacheUrn(id), () =>
|
||||
return await CacheManager.GetAsync(data.Release.CacheUrn(id), async () =>
|
||||
{
|
||||
return DbContext.Releases
|
||||
return await DbContext.Releases
|
||||
.Include(x => x.Artist)
|
||||
.Include(x => x.Genres)
|
||||
.Include("Genres.Genre")
|
||||
.Include(x => x.Medias)
|
||||
.Include("Medias.Tracks")
|
||||
.Include("Medias.Tracks.TrackArtist")
|
||||
.FirstOrDefaultAsync(x => x.RoadieId == id);
|
||||
}, data.Release.CacheRegionUrn(id));
|
||||
.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||
}, data.Release.CacheRegionUrn(id)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -193,27 +193,27 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
if (Guid.TryParse(id, out Guid trackId))
|
||||
{
|
||||
return await GetTrack(trackId);
|
||||
return await GetTrack(trackId).ConfigureAwait(false);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Only read operations
|
||||
protected Task<data.Track> GetTrack(Guid id)
|
||||
protected async Task<data.Track> GetTrack(Guid id)
|
||||
{
|
||||
if(id == Guid.Empty)
|
||||
{
|
||||
return Task.FromResult<data.Track>(null);
|
||||
return null;
|
||||
}
|
||||
return CacheManager.GetAsync(data.Track.CacheUrn(id), () =>
|
||||
return await CacheManager.GetAsync(data.Track.CacheUrn(id), async () =>
|
||||
{
|
||||
return DbContext.Tracks
|
||||
return await DbContext.Tracks
|
||||
.Include(x => x.ReleaseMedia)
|
||||
.Include(x => x.ReleaseMedia.Release)
|
||||
.Include(x => x.ReleaseMedia.Release.Artist)
|
||||
.Include(x => x.TrackArtist)
|
||||
.FirstOrDefaultAsync(x => x.RoadieId == id);
|
||||
}, data.Track.CacheRegionUrn(id));
|
||||
.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||
}, data.Track.CacheRegionUrn(id)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
protected async Task<User> GetUser(string username)
|
||||
|
@ -225,40 +225,41 @@ namespace Roadie.Api.Services
|
|||
var userByUsername = await CacheManager.GetAsync(User.CacheUrnByUsername(username), () =>
|
||||
{
|
||||
return DbContext.Users.FirstOrDefaultAsync(x => x.UserName == username);
|
||||
}, null);
|
||||
}, null).ConfigureAwait(false);
|
||||
return await GetUser(userByUsername?.RoadieId).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
protected Task<User> GetUser(Guid? id)
|
||||
protected async Task<User> GetUser(Guid? id)
|
||||
{
|
||||
if (!id.HasValue)
|
||||
{
|
||||
return Task.FromResult<User>(null);
|
||||
return null;
|
||||
}
|
||||
return CacheManager.GetAsync(User.CacheUrn(id.Value), () =>
|
||||
return await CacheManager.GetAsync(User.CacheUrn(id.Value), async () =>
|
||||
{
|
||||
return DbContext.Users
|
||||
return await DbContext.Users
|
||||
.Include(x => x.UserRoles)
|
||||
.Include("UserRoles.Role")
|
||||
.Include("UserRoles.Role.RoleClaims")
|
||||
.Include(x => x.UserClaims)
|
||||
.Include(x => x.UserQues)
|
||||
.Include("UserQues.Track")
|
||||
.FirstOrDefaultAsync(x => x.RoadieId == id);
|
||||
}, User.CacheRegionUrn(id.Value));
|
||||
.FirstOrDefaultAsync(x => x.RoadieId == id).ConfigureAwait(false);
|
||||
}, User.CacheRegionUrn(id.Value)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
protected string MakeLastFmUrl(string artistName, string releaseTitle) => "http://www.last.fm/music/" + HttpEncoder.UrlEncode($"{artistName}/{releaseTitle}");
|
||||
|
||||
protected async Task<OperationResult<short>> SetArtistRating(Guid artistId, User user, short rating)
|
||||
{
|
||||
var artist = DbContext.Artists
|
||||
var artist = await DbContext.Artists
|
||||
.Include(x => x.Genres)
|
||||
.Include("Genres.Genre")
|
||||
.FirstOrDefault(x => x.RoadieId == artistId);
|
||||
.FirstOrDefaultAsync(x => x.RoadieId == artistId)
|
||||
.ConfigureAwait(false);
|
||||
if (artist == null) return new OperationResult<short>(true, $"Invalid Artist Id [{artistId}]");
|
||||
var now = DateTime.UtcNow;
|
||||
var userArtist = DbContext.UserArtists.FirstOrDefault(x => x.ArtistId == artist.Id && x.UserId == user.Id);
|
||||
var userArtist = await DbContext.UserArtists.FirstOrDefaultAsync(x => x.ArtistId == artist.Id && x.UserId == user.Id).ConfigureAwait(false);
|
||||
if (userArtist == null)
|
||||
{
|
||||
userArtist = new data.UserArtist
|
||||
|
@ -278,7 +279,7 @@ namespace Roadie.Api.Services
|
|||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
var ratings = await DbContext.UserArtists.Where(x => x.ArtistId == artist.Id && x.Rating > 0).Select(x => x.Rating).ToListAsync().ConfigureAwait(false);
|
||||
if (ratings != null && ratings.Any())
|
||||
if (ratings != null && ratings.Count > 0)
|
||||
{
|
||||
artist.Rating = (short)ratings.Average(x => (decimal)x);
|
||||
}
|
||||
|
@ -288,7 +289,7 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
artist.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
await UpdateArtistRank(artist.Id);
|
||||
await UpdateArtistRank(artist.Id).ConfigureAwait(false);
|
||||
CacheManager.ClearRegion(user.CacheRegion);
|
||||
CacheManager.ClearRegion(artist.CacheRegion);
|
||||
|
||||
|
@ -303,19 +304,19 @@ namespace Roadie.Api.Services
|
|||
|
||||
protected async Task<OperationResult<short>> SetReleaseRating(Guid releaseId, User user, short rating)
|
||||
{
|
||||
var release = DbContext.Releases
|
||||
var release = await DbContext.Releases
|
||||
.Include(x => x.Artist)
|
||||
.Include(x => x.Genres)
|
||||
.Include("Genres.Genre")
|
||||
.Include(x => x.Medias)
|
||||
.Include("Medias.Tracks")
|
||||
.Include("Medias.Tracks.TrackArtist")
|
||||
.FirstOrDefault(x => x.RoadieId == releaseId);
|
||||
.FirstOrDefaultAsync(x => x.RoadieId == releaseId).ConfigureAwait(false);
|
||||
if (release == null)
|
||||
{
|
||||
return new OperationResult<short>(true, $"Invalid Release Id [{releaseId}]");
|
||||
}
|
||||
var userRelease = DbContext.UserReleases.FirstOrDefault(x => x.ReleaseId == release.Id && x.UserId == user.Id);
|
||||
var userRelease = await DbContext.UserReleases.FirstOrDefaultAsync(x => x.ReleaseId == release.Id && x.UserId == user.Id).ConfigureAwait(false);
|
||||
var now = DateTime.UtcNow;
|
||||
if (userRelease == null)
|
||||
{
|
||||
|
@ -325,7 +326,7 @@ namespace Roadie.Api.Services
|
|||
UserId = user.Id,
|
||||
ReleaseId = release.Id
|
||||
};
|
||||
DbContext.UserReleases.Add(userRelease);
|
||||
await DbContext.UserReleases.AddAsync(userRelease).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -333,10 +334,10 @@ namespace Roadie.Api.Services
|
|||
userRelease.LastUpdated = now;
|
||||
}
|
||||
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
var ratings = await DbContext.UserReleases.Where(x => x.ReleaseId == release.Id && x.Rating > 0).Select(x => x.Rating).ToListAsync();
|
||||
if (ratings != null && ratings.Any())
|
||||
var ratings = await DbContext.UserReleases.Where(x => x.ReleaseId == release.Id && x.Rating > 0).Select(x => x.Rating).ToListAsync().ConfigureAwait(false);
|
||||
if (ratings != null && ratings.Count > 0)
|
||||
{
|
||||
release.Rating = (short)ratings.Average(x => (decimal)x);
|
||||
}
|
||||
|
@ -345,13 +346,13 @@ namespace Roadie.Api.Services
|
|||
release.Rating = 0;
|
||||
}
|
||||
release.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync();
|
||||
await UpdateReleaseRank(release.Id);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
await UpdateReleaseRank(release.Id).ConfigureAwait(false);
|
||||
CacheManager.ClearRegion(user.CacheRegion);
|
||||
CacheManager.ClearRegion(release.CacheRegion);
|
||||
CacheManager.ClearRegion(release.Artist.CacheRegion);
|
||||
|
||||
release = await GetRelease(releaseId);
|
||||
release = await GetRelease(releaseId).ConfigureAwait(false);
|
||||
|
||||
return new OperationResult<short>
|
||||
{
|
||||
|
@ -364,18 +365,19 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
var track = DbContext.Tracks
|
||||
var track = await DbContext.Tracks
|
||||
.Include(x => x.ReleaseMedia)
|
||||
.Include(x => x.ReleaseMedia.Release)
|
||||
.Include(x => x.ReleaseMedia.Release.Artist)
|
||||
.Include(x => x.TrackArtist)
|
||||
.FirstOrDefault(x => x.RoadieId == trackId);
|
||||
.FirstOrDefaultAsync(x => x.RoadieId == trackId)
|
||||
.ConfigureAwait(false);
|
||||
if (track == null)
|
||||
{
|
||||
return new OperationResult<short>(true, $"Invalid Track Id [{trackId}]");
|
||||
}
|
||||
var now = DateTime.UtcNow;
|
||||
var userTrack = DbContext.UserTracks.FirstOrDefault(x => x.TrackId == track.Id && x.UserId == user.Id);
|
||||
var userTrack = await DbContext.UserTracks.FirstOrDefaultAsync(x => x.TrackId == track.Id && x.UserId == user.Id).ConfigureAwait(false);
|
||||
if (userTrack == null)
|
||||
{
|
||||
userTrack = new data.UserTrack
|
||||
|
@ -384,7 +386,7 @@ namespace Roadie.Api.Services
|
|||
UserId = user.Id,
|
||||
TrackId = track.Id
|
||||
};
|
||||
DbContext.UserTracks.Add(userTrack);
|
||||
await DbContext.UserTracks.AddAsync(userTrack).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -392,10 +394,10 @@ namespace Roadie.Api.Services
|
|||
userTrack.LastUpdated = now;
|
||||
}
|
||||
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
var ratings = await DbContext.UserTracks.Where(x => x.TrackId == track.Id && x.Rating > 0).Select(x => x.Rating).ToListAsync();
|
||||
if (ratings != null && ratings.Any())
|
||||
var ratings = await DbContext.UserTracks.Where(x => x.TrackId == track.Id && x.Rating > 0).Select(x => x.Rating).ToListAsync().ConfigureAwait(false);
|
||||
if (ratings != null && ratings.Count > 0)
|
||||
{
|
||||
track.Rating = (short)ratings.Average(x => (double)x);
|
||||
}
|
||||
|
@ -404,8 +406,8 @@ namespace Roadie.Api.Services
|
|||
track.Rating = 0;
|
||||
}
|
||||
track.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync();
|
||||
await UpdateReleaseRank(track.ReleaseMedia.Release.Id);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
await UpdateReleaseRank(track.ReleaseMedia.Release.Id).ConfigureAwait(false);
|
||||
|
||||
CacheManager.ClearRegion(user.CacheRegion);
|
||||
CacheManager.ClearRegion(track.CacheRegion);
|
||||
|
@ -430,12 +432,13 @@ namespace Roadie.Api.Services
|
|||
var result = false;
|
||||
try
|
||||
{
|
||||
var artist = DbContext.Artists
|
||||
var artist = await DbContext.Artists
|
||||
.Include(x => x.Genres)
|
||||
.Include("Genres.Genre")
|
||||
.FirstOrDefault(x => x.RoadieId == artistId);
|
||||
.FirstOrDefaultAsync(x => x.RoadieId == artistId)
|
||||
.ConfigureAwait(false);
|
||||
if (artist == null) return new OperationResult<bool>(true, $"Invalid Artist Id [{artistId}]");
|
||||
var userArtist = DbContext.UserArtists.FirstOrDefault(x => x.ArtistId == artist.Id && x.UserId == user.Id);
|
||||
var userArtist = await DbContext.UserArtists.FirstOrDefaultAsync(x => x.ArtistId == artist.Id && x.UserId == user.Id).ConfigureAwait(false);
|
||||
if (userArtist == null)
|
||||
{
|
||||
userArtist = new data.UserArtist
|
||||
|
@ -444,7 +447,7 @@ namespace Roadie.Api.Services
|
|||
UserId = user.Id,
|
||||
ArtistId = artist.Id
|
||||
};
|
||||
DbContext.UserArtists.Add(userArtist);
|
||||
await DbContext.UserArtists.AddAsync(userArtist).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -452,7 +455,7 @@ namespace Roadie.Api.Services
|
|||
userArtist.LastUpdated = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
CacheManager.ClearRegion(user.CacheRegion);
|
||||
CacheManager.ClearRegion(artist.CacheRegion);
|
||||
|
@ -474,12 +477,13 @@ namespace Roadie.Api.Services
|
|||
var result = false;
|
||||
try
|
||||
{
|
||||
var artist = DbContext.Artists
|
||||
var artist = await DbContext.Artists
|
||||
.Include(x => x.Genres)
|
||||
.Include("Genres.Genre")
|
||||
.FirstOrDefault(x => x.RoadieId == artistId);
|
||||
.FirstOrDefaultAsync(x => x.RoadieId == artistId)
|
||||
.ConfigureAwait(false);
|
||||
if (artist == null) return new OperationResult<bool>(true, $"Invalid Artist Id [{artistId}]");
|
||||
var userArtist = DbContext.UserArtists.FirstOrDefault(x => x.ArtistId == artist.Id && x.UserId == user.Id);
|
||||
var userArtist = await DbContext.UserArtists.FirstOrDefaultAsync(x => x.ArtistId == artist.Id && x.UserId == user.Id).ConfigureAwait(false);
|
||||
if (userArtist == null)
|
||||
{
|
||||
userArtist = new data.UserArtist
|
||||
|
@ -488,7 +492,7 @@ namespace Roadie.Api.Services
|
|||
UserId = user.Id,
|
||||
ArtistId = artist.Id
|
||||
};
|
||||
DbContext.UserArtists.Add(userArtist);
|
||||
await DbContext.UserArtists.AddAsync(userArtist).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -496,7 +500,7 @@ namespace Roadie.Api.Services
|
|||
userArtist.LastUpdated = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
CacheManager.ClearRegion(user.CacheRegion);
|
||||
CacheManager.ClearRegion(artist.CacheRegion);
|
||||
|
@ -518,19 +522,20 @@ namespace Roadie.Api.Services
|
|||
var result = false;
|
||||
try
|
||||
{
|
||||
var release = DbContext.Releases
|
||||
var release = await DbContext.Releases
|
||||
.Include(x => x.Artist)
|
||||
.Include(x => x.Genres)
|
||||
.Include("Genres.Genre")
|
||||
.Include(x => x.Medias)
|
||||
.Include("Medias.Tracks")
|
||||
.Include("Medias.Tracks.TrackArtist")
|
||||
.FirstOrDefault(x => x.RoadieId == releaseId);
|
||||
.FirstOrDefaultAsync(x => x.RoadieId == releaseId)
|
||||
.ConfigureAwait(false);
|
||||
if (release == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Invalid Release Id [{releaseId}]");
|
||||
}
|
||||
var userRelease = DbContext.UserReleases.FirstOrDefault(x => x.ReleaseId == release.Id && x.UserId == user.Id);
|
||||
var userRelease = await DbContext.UserReleases.FirstOrDefaultAsync(x => x.ReleaseId == release.Id && x.UserId == user.Id).ConfigureAwait(false);
|
||||
if (userRelease == null)
|
||||
{
|
||||
userRelease = new data.UserRelease
|
||||
|
@ -539,7 +544,7 @@ namespace Roadie.Api.Services
|
|||
UserId = user.Id,
|
||||
ReleaseId = release.Id
|
||||
};
|
||||
DbContext.UserReleases.Add(userRelease);
|
||||
await DbContext.UserReleases.AddAsync(userRelease).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -547,7 +552,7 @@ namespace Roadie.Api.Services
|
|||
userRelease.LastUpdated = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
CacheManager.ClearRegion(user.CacheRegion);
|
||||
CacheManager.ClearRegion(release.CacheRegion);
|
||||
|
@ -582,7 +587,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
return new OperationResult<bool>(true, $"Invalid Release Id [{releaseId}]");
|
||||
}
|
||||
var userRelease = DbContext.UserReleases.FirstOrDefault(x => x.ReleaseId == release.Id && x.UserId == user.Id);
|
||||
var userRelease = await DbContext.UserReleases.FirstOrDefaultAsync(x => x.ReleaseId == release.Id && x.UserId == user.Id).ConfigureAwait(false);
|
||||
if (userRelease == null)
|
||||
{
|
||||
userRelease = new data.UserRelease
|
||||
|
@ -591,7 +596,7 @@ namespace Roadie.Api.Services
|
|||
UserId = user.Id,
|
||||
ReleaseId = release.Id
|
||||
};
|
||||
DbContext.UserReleases.Add(userRelease);
|
||||
await DbContext.UserReleases.AddAsync(userRelease).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -599,7 +604,7 @@ namespace Roadie.Api.Services
|
|||
userRelease.LastUpdated = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
CacheManager.ClearRegion(user.CacheRegion);
|
||||
CacheManager.ClearRegion(release.CacheRegion);
|
||||
|
@ -622,17 +627,18 @@ namespace Roadie.Api.Services
|
|||
var result = false;
|
||||
try
|
||||
{
|
||||
var track = DbContext.Tracks
|
||||
var track = await DbContext.Tracks
|
||||
.Include(x => x.ReleaseMedia)
|
||||
.Include(x => x.ReleaseMedia.Release)
|
||||
.Include(x => x.ReleaseMedia.Release.Artist)
|
||||
.Include(x => x.TrackArtist)
|
||||
.FirstOrDefault(x => x.RoadieId == trackId);
|
||||
.FirstOrDefaultAsync(x => x.RoadieId == trackId)
|
||||
.ConfigureAwait(false);
|
||||
if (track == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Invalid Track Id [{trackId}]");
|
||||
}
|
||||
var userTrack = DbContext.UserTracks.FirstOrDefault(x => x.TrackId == track.Id && x.UserId == user.Id);
|
||||
var userTrack = await DbContext.UserTracks.FirstOrDefaultAsync(x => x.TrackId == track.Id && x.UserId == user.Id).ConfigureAwait(false);
|
||||
if (userTrack == null)
|
||||
{
|
||||
userTrack = new data.UserTrack
|
||||
|
@ -641,7 +647,7 @@ namespace Roadie.Api.Services
|
|||
UserId = user.Id,
|
||||
TrackId = track.Id
|
||||
};
|
||||
DbContext.UserTracks.Add(userTrack);
|
||||
await DbContext.UserTracks.AddAsync(userTrack).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -649,7 +655,7 @@ namespace Roadie.Api.Services
|
|||
userTrack.LastUpdated = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
CacheManager.ClearRegion(user.CacheRegion);
|
||||
CacheManager.ClearRegion(track.CacheRegion);
|
||||
|
@ -673,17 +679,18 @@ namespace Roadie.Api.Services
|
|||
var result = false;
|
||||
try
|
||||
{
|
||||
var track = DbContext.Tracks
|
||||
var track = await DbContext.Tracks
|
||||
.Include(x => x.ReleaseMedia)
|
||||
.Include(x => x.ReleaseMedia.Release)
|
||||
.Include(x => x.ReleaseMedia.Release.Artist)
|
||||
.Include(x => x.TrackArtist)
|
||||
.FirstOrDefault(x => x.RoadieId == trackId);
|
||||
.FirstOrDefaultAsync(x => x.RoadieId == trackId)
|
||||
.ConfigureAwait(false);
|
||||
if (track == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Invalid Track Id [{trackId}]");
|
||||
}
|
||||
var userTrack = DbContext.UserTracks.FirstOrDefault(x => x.TrackId == track.Id && x.UserId == user.Id);
|
||||
var userTrack = await DbContext.UserTracks.FirstOrDefaultAsync(x => x.TrackId == track.Id && x.UserId == user.Id).ConfigureAwait(false);
|
||||
if (userTrack == null)
|
||||
{
|
||||
userTrack = new data.UserTrack
|
||||
|
@ -692,7 +699,7 @@ namespace Roadie.Api.Services
|
|||
UserId = user.Id,
|
||||
TrackId = track.Id
|
||||
};
|
||||
DbContext.UserTracks.Add(userTrack);
|
||||
await DbContext.UserTracks.AddAsync(userTrack).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -700,7 +707,7 @@ namespace Roadie.Api.Services
|
|||
userTrack.LastUpdated = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
CacheManager.ClearRegion(user.CacheRegion);
|
||||
CacheManager.ClearRegion(track.CacheRegion);
|
||||
|
@ -724,18 +731,18 @@ namespace Roadie.Api.Services
|
|||
|
||||
protected async Task UpdateArtistCounts(int artistId, DateTime now)
|
||||
{
|
||||
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == artistId);
|
||||
var artist = await DbContext.Artists.FirstOrDefaultAsync(x => x.Id == artistId).ConfigureAwait(false);
|
||||
if (artist != null)
|
||||
{
|
||||
artist.ReleaseCount = await DbContext.Releases.Where(x => x.ArtistId == artistId).CountAsync();
|
||||
artist.ReleaseCount = await DbContext.Releases.Where(x => x.ArtistId == artistId).CountAsync().ConfigureAwait(false);
|
||||
artist.TrackCount = await (from r in DbContext.Releases
|
||||
join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
|
||||
join tr in DbContext.Tracks on rm.Id equals tr.ReleaseMediaId
|
||||
where tr.ArtistId == artistId || r.ArtistId == artistId
|
||||
select tr).CountAsync();
|
||||
select tr).CountAsync().ConfigureAwait(false);
|
||||
|
||||
artist.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
CacheManager.ClearRegion(artist.CacheRegion);
|
||||
}
|
||||
}
|
||||
|
@ -750,10 +757,10 @@ namespace Roadie.Api.Services
|
|||
join tr in DbContext.Tracks on rm.Id equals tr.ReleaseMediaId
|
||||
join plt in DbContext.PlaylistTracks on tr.Id equals plt.TrackId
|
||||
where r.ArtistId == artistId
|
||||
select plt.PlayListId).ToListAsync();
|
||||
select plt.PlayListId).ToListAsync().ConfigureAwait(false);
|
||||
foreach (var playlistId in playlistIds.Distinct())
|
||||
{
|
||||
await UpdatePlaylistCounts(playlistId, now);
|
||||
await UpdatePlaylistCounts(playlistId, now).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -768,10 +775,10 @@ namespace Roadie.Api.Services
|
|||
join tr in DbContext.Tracks on rm.Id equals tr.ReleaseMediaId
|
||||
join plt in DbContext.PlaylistTracks on tr.Id equals plt.TrackId
|
||||
where r.Id == releaseId
|
||||
select plt.PlayListId).ToListAsync();
|
||||
foreach(var playlistId in playlistIds.Distinct())
|
||||
select plt.PlayListId).ToListAsync().ConfigureAwait(false);
|
||||
foreach (var playlistId in playlistIds.Distinct())
|
||||
{
|
||||
await UpdatePlaylistCounts(playlistId, now);
|
||||
await UpdatePlaylistCounts(playlistId, now).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -786,11 +793,11 @@ namespace Roadie.Api.Services
|
|||
join tr in DbContext.Tracks on rm.Id equals tr.ReleaseMediaId
|
||||
where r.Id == releaseId
|
||||
where tr.ArtistId != null
|
||||
select tr.ArtistId.Value).ToListAsync();
|
||||
select tr.ArtistId.Value).ToListAsync().ConfigureAwait(false);
|
||||
trackArtistIds.Add(DbContext.Releases.FirstOrDefault(x => x.Id == releaseId).ArtistId);
|
||||
foreach (var artistId in trackArtistIds.Distinct())
|
||||
{
|
||||
await UpdateArtistCounts(artistId, now);
|
||||
await UpdateArtistCounts(artistId, now).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -802,15 +809,15 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
try
|
||||
{
|
||||
var artist = DbContext.Artists.FirstOrDefault(x => x.Id == artistId);
|
||||
var artist = await DbContext.Artists.FirstOrDefaultAsync(x => x.Id == artistId).ConfigureAwait(false);
|
||||
if (artist != null)
|
||||
{
|
||||
if (updateReleaseRanks)
|
||||
{
|
||||
var artistReleaseIds = await DbContext.Releases.Where(x => x.ArtistId == artistId).Select(x => x.Id).ToArrayAsync();
|
||||
var artistReleaseIds = await DbContext.Releases.Where(x => x.ArtistId == artistId).Select(x => x.Id).ToArrayAsync().ConfigureAwait(false);
|
||||
foreach (var artistReleaseId in artistReleaseIds)
|
||||
{
|
||||
await UpdateReleaseRank(artistReleaseId, false);
|
||||
await UpdateReleaseRank(artistReleaseId, false).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -818,20 +825,20 @@ namespace Roadie.Api.Services
|
|||
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
join ut in DbContext.UserTracks on t.Id equals ut.TrackId
|
||||
where t.ArtistId == artist.Id
|
||||
select ut.Rating).Select(x => (decimal?)x).ToArrayAsync()).Average();
|
||||
select ut.Rating).Select(x => (decimal?)x).ToArrayAsync().ConfigureAwait(false)).Average();
|
||||
|
||||
var artistReleaseRatingRating = (await (from r in DbContext.Releases
|
||||
join ur in DbContext.UserReleases on r.Id equals ur.ReleaseId
|
||||
where r.ArtistId == artist.Id
|
||||
select ur.Rating).Select(x => (decimal?)x).ToArrayAsync()).Average();
|
||||
select ur.Rating).Select(x => (decimal?)x).ToArrayAsync().ConfigureAwait(false)).Average();
|
||||
|
||||
var artistReleaseRankSum = (await (from r in DbContext.Releases
|
||||
where r.ArtistId == artist.Id
|
||||
select r.Rank).ToArrayAsync()).Sum(x => x) ?? 0;
|
||||
select r.Rank).ToArrayAsync().ConfigureAwait(false)).Sum(x => x) ?? 0;
|
||||
|
||||
artist.Rank = SafeParser.ToNumber<decimal>(artistTrackAverage + artistReleaseRatingRating) + artistReleaseRankSum + artist.Rating;
|
||||
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
CacheManager.ClearRegion(artist.CacheRegion);
|
||||
Logger.LogTrace("UpdatedArtistRank For Artist `{0}`", artist);
|
||||
}
|
||||
|
@ -858,74 +865,74 @@ namespace Roadie.Api.Services
|
|||
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
where rm.ReleaseId == release.Id
|
||||
where t.ArtistId.HasValue
|
||||
select t.ArtistId.Value).ToArrayAsync();
|
||||
select t.ArtistId.Value).ToArrayAsync().ConfigureAwait(false);
|
||||
artistsForRelease.AddRange(trackArtistsForRelease);
|
||||
foreach (var artistId in artistsForRelease.Distinct())
|
||||
{
|
||||
await UpdateArtistRank(artistId);
|
||||
await UpdateArtistRank(artistId).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task UpdateLabelCounts(int labelId, DateTime now)
|
||||
{
|
||||
var label = DbContext.Labels.FirstOrDefault(x => x.Id == labelId);
|
||||
var label = await DbContext.Labels.FirstOrDefaultAsync(x => x.Id == labelId).ConfigureAwait(false);
|
||||
if (label != null)
|
||||
{
|
||||
label.ReleaseCount = await DbContext.ReleaseLabels.Where(x => x.LabelId == label.Id).CountAsync();
|
||||
label.ReleaseCount = await DbContext.ReleaseLabels.Where(x => x.LabelId == label.Id).CountAsync().ConfigureAwait(false);
|
||||
label.ArtistCount = await (from r in DbContext.Releases
|
||||
join rl in DbContext.ReleaseLabels on r.Id equals rl.ReleaseId
|
||||
join a in DbContext.Artists on r.ArtistId equals a.Id
|
||||
where rl.LabelId == label.Id
|
||||
group a by a.Id
|
||||
into artists
|
||||
select artists).Select(x => x.Key).CountAsync();
|
||||
into artists
|
||||
select artists).Select(x => x.Key).CountAsync().ConfigureAwait(false);
|
||||
label.TrackCount = await (from r in DbContext.Releases
|
||||
join rl in DbContext.ReleaseLabels on r.Id equals rl.ReleaseId
|
||||
join rm in DbContext.ReleaseMedias on r.Id equals rm.ReleaseId
|
||||
join t in DbContext.Tracks on rm.Id equals t.ReleaseMediaId
|
||||
where rl.LabelId == label.Id
|
||||
select t).CountAsync();
|
||||
select t).CountAsync().ConfigureAwait(false);
|
||||
label.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
CacheManager.ClearRegion(label.CacheRegion);
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task UpdatePlaylistCounts(int playlistId, DateTime now)
|
||||
{
|
||||
var playlist = DbContext.Playlists.FirstOrDefault(x => x.Id == playlistId);
|
||||
var playlist = await DbContext.Playlists.FirstOrDefaultAsync(x => x.Id == playlistId).ConfigureAwait(false);
|
||||
if (playlist != null)
|
||||
{
|
||||
var playlistTracks = await DbContext.PlaylistTracks
|
||||
.Include(x => x.Track)
|
||||
.Include("Track.ReleaseMedia")
|
||||
.Where(x => x.PlayListId == playlist.Id).ToArrayAsync();
|
||||
playlist.TrackCount = (short)playlistTracks.Count();
|
||||
.Where(x => x.PlayListId == playlist.Id).ToArrayAsync().ConfigureAwait(false);
|
||||
playlist.TrackCount = (short)playlistTracks.Length;
|
||||
playlist.Duration = playlistTracks.Sum(x => x.Track.Duration);
|
||||
playlist.ReleaseCount = (short)playlistTracks.Select(x => x.Track.ReleaseMedia.ReleaseId).Distinct().Count();
|
||||
playlist.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
CacheManager.ClearRegion(playlist.CacheRegion);
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task UpdateReleaseCounts(int releaseId, DateTime now)
|
||||
{
|
||||
var release = DbContext.Releases.FirstOrDefault(x => x.Id == releaseId);
|
||||
var release = await DbContext.Releases.FirstOrDefaultAsync(x => x.Id == releaseId).ConfigureAwait(false);
|
||||
if (release != null)
|
||||
{
|
||||
release.PlayedCount = await (from t in DbContext.Tracks
|
||||
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
where rm.ReleaseId == releaseId
|
||||
where t.PlayedCount.HasValue
|
||||
select t).SumAsync(x => x.PlayedCount);
|
||||
select t).SumAsync(x => x.PlayedCount).ConfigureAwait(false);
|
||||
release.Duration = await (from t in DbContext.Tracks
|
||||
join rm in DbContext.ReleaseMedias on t.ReleaseMediaId equals rm.Id
|
||||
where rm.ReleaseId == releaseId
|
||||
select t).SumAsync(x => x.Duration);
|
||||
select t).SumAsync(x => x.Duration).ConfigureAwait(false);
|
||||
release.LastUpdated = now;
|
||||
await DbContext.SaveChangesAsync();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
CacheManager.ClearRegion(release.CacheRegion);
|
||||
}
|
||||
}
|
||||
|
@ -939,7 +946,7 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
try
|
||||
{
|
||||
var release = DbContext.Releases.FirstOrDefault(x => x.Id == releaseId);
|
||||
var release = await DbContext.Releases.FirstOrDefaultAsync(x => x.Id == releaseId).ConfigureAwait(false);
|
||||
if (release != null)
|
||||
{
|
||||
var releaseTrackAverage = (await (from ut in DbContext.UserTracks
|
||||
|
|
|
@ -26,7 +26,39 @@ namespace Roadie.Api.Services
|
|||
{
|
||||
}
|
||||
|
||||
public Task<OperationResult<LibraryStats>> LibraryStatistics()
|
||||
public Task<OperationResult<IEnumerable<DateAndCount>>> ArtistsByDateAsync()
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var result = new List<DateAndCount>();
|
||||
var dateInfos = (from r in DbContext.Artists
|
||||
orderby r.CreatedDate
|
||||
select r.CreatedDate)
|
||||
.ToArray()
|
||||
.GroupBy(x => x.ToString("yyyy-MM-dd"))
|
||||
.Select(x => new
|
||||
{
|
||||
date = x.Key,
|
||||
count = x.Count()
|
||||
});
|
||||
foreach (var dateInfo in dateInfos)
|
||||
{
|
||||
result.Add(new DateAndCount
|
||||
{
|
||||
Date = dateInfo.date,
|
||||
Count = dateInfo.count
|
||||
});
|
||||
}
|
||||
sw.Stop();
|
||||
return Task.FromResult(new OperationResult<IEnumerable<DateAndCount>>
|
||||
{
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
IsSuccess = result != null,
|
||||
Data = result
|
||||
});
|
||||
}
|
||||
|
||||
public Task<OperationResult<LibraryStats>> LibraryStatisticsAsync()
|
||||
{
|
||||
LibraryStats result = null;
|
||||
var sw = new Stopwatch();
|
||||
|
@ -65,39 +97,7 @@ namespace Roadie.Api.Services
|
|||
});
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DateAndCount>>> ArtistsByDate()
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var result = new List<DateAndCount>();
|
||||
var dateInfos = (from r in DbContext.Artists
|
||||
orderby r.CreatedDate
|
||||
select r.CreatedDate)
|
||||
.ToArray()
|
||||
.GroupBy(x => x.ToString("yyyy-MM-dd"))
|
||||
.Select(x => new
|
||||
{
|
||||
date = x.Key,
|
||||
count = x.Count()
|
||||
});
|
||||
foreach (var dateInfo in dateInfos)
|
||||
{
|
||||
result.Add(new DateAndCount
|
||||
{
|
||||
Date = dateInfo.date,
|
||||
Count = dateInfo.count
|
||||
});
|
||||
}
|
||||
sw.Stop();
|
||||
return Task.FromResult(new OperationResult<IEnumerable<DateAndCount>>
|
||||
{
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
IsSuccess = result != null,
|
||||
Data = result
|
||||
});
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDate()
|
||||
public Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDateAsync()
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -129,78 +129,14 @@ namespace Roadie.Api.Services
|
|||
});
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByUser()
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var result = new List<DateAndCount>();
|
||||
var dateInfos = (from r in DbContext.UserTracks
|
||||
join u in DbContext.Users on r.UserId equals u.Id
|
||||
select new { u.UserName, r.PlayedCount })
|
||||
.ToArray()
|
||||
.GroupBy(x => x.UserName)
|
||||
.Select(x => new
|
||||
{
|
||||
username = x.Key,
|
||||
count = x.Count()
|
||||
});
|
||||
foreach (var dateInfo in dateInfos)
|
||||
{
|
||||
result.Add(new DateAndCount
|
||||
{
|
||||
Date = dateInfo.username,
|
||||
Count = dateInfo.count
|
||||
});
|
||||
}
|
||||
sw.Stop();
|
||||
return Task.FromResult(new OperationResult<IEnumerable<DateAndCount>>
|
||||
{
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
IsSuccess = result != null,
|
||||
Data = result
|
||||
});
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByDate()
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var result = new List<DateAndCount>();
|
||||
var dateInfos = (from r in DbContext.UserTracks
|
||||
orderby r.LastPlayed
|
||||
select r.LastPlayed ?? r.CreatedDate)
|
||||
.ToArray()
|
||||
.GroupBy(x => x.ToString("yyyy-MM-dd"))
|
||||
.Select(x => new
|
||||
{
|
||||
date = x.Key,
|
||||
count = x.Count()
|
||||
});
|
||||
foreach (var dateInfo in dateInfos)
|
||||
{
|
||||
result.Add(new DateAndCount
|
||||
{
|
||||
Date = dateInfo.date,
|
||||
Count = dateInfo.count
|
||||
});
|
||||
}
|
||||
sw.Stop();
|
||||
return Task.FromResult(new OperationResult<IEnumerable<DateAndCount>>
|
||||
{
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
IsSuccess = result != null,
|
||||
Data = result
|
||||
});
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDecade()
|
||||
public Task<OperationResult<IEnumerable<DateAndCount>>> ReleasesByDecadeAsync()
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var result = new List<DateAndCount>();
|
||||
var decadeInfos = (from r in DbContext.Releases
|
||||
orderby r.ReleaseDate
|
||||
select r.ReleaseDate ?? r.CreatedDate)
|
||||
orderby r.ReleaseDate
|
||||
select r.ReleaseDate ?? r.CreatedDate)
|
||||
.ToArray()
|
||||
.GroupBy(x => x.ToString("yyyy"))
|
||||
.Select(x => new
|
||||
|
@ -235,5 +171,69 @@ namespace Roadie.Api.Services
|
|||
Data = result
|
||||
});
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByDateAsync()
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var result = new List<DateAndCount>();
|
||||
var dateInfos = (from r in DbContext.UserTracks
|
||||
orderby r.LastPlayed
|
||||
select r.LastPlayed ?? r.CreatedDate)
|
||||
.ToArray()
|
||||
.GroupBy(x => x.ToString("yyyy-MM-dd"))
|
||||
.Select(x => new
|
||||
{
|
||||
date = x.Key,
|
||||
count = x.Count()
|
||||
});
|
||||
foreach (var dateInfo in dateInfos)
|
||||
{
|
||||
result.Add(new DateAndCount
|
||||
{
|
||||
Date = dateInfo.date,
|
||||
Count = dateInfo.count
|
||||
});
|
||||
}
|
||||
sw.Stop();
|
||||
return Task.FromResult(new OperationResult<IEnumerable<DateAndCount>>
|
||||
{
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
IsSuccess = result != null,
|
||||
Data = result
|
||||
});
|
||||
}
|
||||
|
||||
public Task<OperationResult<IEnumerable<DateAndCount>>> SongsPlayedByUserAsync()
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var result = new List<DateAndCount>();
|
||||
var dateInfos = (from r in DbContext.UserTracks
|
||||
join u in DbContext.Users on r.UserId equals u.Id
|
||||
select new { u.UserName, r.PlayedCount })
|
||||
.ToArray()
|
||||
.GroupBy(x => x.UserName)
|
||||
.Select(x => new
|
||||
{
|
||||
username = x.Key,
|
||||
count = x.Count()
|
||||
});
|
||||
foreach (var dateInfo in dateInfos)
|
||||
{
|
||||
result.Add(new DateAndCount
|
||||
{
|
||||
Date = dateInfo.username,
|
||||
Count = dateInfo.count
|
||||
});
|
||||
}
|
||||
sw.Stop();
|
||||
return Task.FromResult(new OperationResult<IEnumerable<DateAndCount>>
|
||||
{
|
||||
OperationTime = sw.ElapsedMilliseconds,
|
||||
IsSuccess = result != null,
|
||||
Data = result
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -20,11 +20,11 @@ namespace Roadie.Api.Services
|
|||
_configuration = configuration;
|
||||
}
|
||||
|
||||
public async Task<string> GenerateToken(User user, UserManager<User> userManager)
|
||||
public async Task<string> GenerateTokenAsync(User user, UserManager<User> userManager)
|
||||
{
|
||||
var utcNow = DateTime.UtcNow;
|
||||
|
||||
var roles = await userManager.GetRolesAsync(user);
|
||||
var roles = await userManager.GetRolesAsync(user).ConfigureAwait(false);
|
||||
var userRoles = roles.Select(r => new Claim(ClaimTypes.Role, r)).ToArray();
|
||||
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
|
|
|
@ -37,9 +37,25 @@ namespace Roadie.Api.Services
|
|||
|
||||
private IBookmarkService BookmarkService { get; }
|
||||
|
||||
public TrackService(IRoadieSettings configuration, IHttpEncoder httpEncoder, IHttpContext httpContext,
|
||||
IRoadieDbContext dbContext, ICacheManager cacheManager, ILogger<TrackService> logger,
|
||||
IBookmarkService bookmarkService, IAdminService adminService, IAudioMetaDataHelper audioMetaDataHelper)
|
||||
public TrackService(
|
||||
IRoadieSettings configuration,
|
||||
IRoadieDbContext dbContext,
|
||||
ICacheManager cacheManager,
|
||||
ILogger logger)
|
||||
: base(configuration, null, dbContext, cacheManager, logger, null)
|
||||
{
|
||||
}
|
||||
|
||||
public TrackService(
|
||||
IRoadieSettings configuration,
|
||||
IHttpEncoder httpEncoder,
|
||||
IHttpContext httpContext,
|
||||
IRoadieDbContext dbContext,
|
||||
ICacheManager cacheManager,
|
||||
ILogger<TrackService> logger,
|
||||
IBookmarkService bookmarkService,
|
||||
IAdminService adminService,
|
||||
IAudioMetaDataHelper audioMetaDataHelper)
|
||||
: base(configuration, httpEncoder, dbContext, cacheManager, logger, httpContext)
|
||||
{
|
||||
BookmarkService = bookmarkService;
|
||||
|
@ -47,82 +63,167 @@ namespace Roadie.Api.Services
|
|||
AdminService = adminService;
|
||||
}
|
||||
|
||||
public TrackService(IRoadieSettings configuration, IRoadieDbContext dbContext, ICacheManager cacheManager, ILogger logger)
|
||||
: base(configuration, null, dbContext, cacheManager, logger, null)
|
||||
{
|
||||
}
|
||||
|
||||
public static long DetermineByteEndFromHeaders(IHeaderDictionary headers, long fileLength)
|
||||
{
|
||||
var defaultFileLength = fileLength - 1;
|
||||
if (headers?.Any(x => x.Key == "Range") != true)
|
||||
{
|
||||
return defaultFileLength;
|
||||
}
|
||||
|
||||
long? result = null;
|
||||
var rangeHeader = headers["Range"];
|
||||
string rangeEnd = null;
|
||||
var rangeBegin = rangeHeader.FirstOrDefault();
|
||||
if (!string.IsNullOrEmpty(rangeBegin))
|
||||
{
|
||||
//bytes=0-
|
||||
rangeBegin = rangeBegin.Replace("bytes=", "");
|
||||
var parts = rangeBegin.Split('-');
|
||||
rangeBegin = parts[0];
|
||||
if (parts.Length > 1)
|
||||
{
|
||||
rangeEnd = parts[1];
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(rangeEnd))
|
||||
{
|
||||
result = long.TryParse(rangeEnd, out var outValue) ? (int?)outValue : null;
|
||||
}
|
||||
}
|
||||
|
||||
return result ?? defaultFileLength;
|
||||
}
|
||||
|
||||
public static long DetermineByteStartFromHeaders(IHeaderDictionary headers)
|
||||
{
|
||||
if (headers?.Any(x => x.Key == "Range") != true)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
long result = 0;
|
||||
var rangeHeader = headers["Range"];
|
||||
var rangeBegin = rangeHeader.FirstOrDefault();
|
||||
if (!string.IsNullOrEmpty(rangeBegin))
|
||||
{
|
||||
//bytes=0-
|
||||
rangeBegin = rangeBegin.Replace("bytes=", "");
|
||||
var parts = rangeBegin.Split('-');
|
||||
rangeBegin = parts[0];
|
||||
if (!string.IsNullOrEmpty(rangeBegin))
|
||||
{
|
||||
long.TryParse(rangeBegin, out result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Track>> ById(User roadieUser, Guid id, IEnumerable<string> includes)
|
||||
private async Task<OperationResult<Track>> TrackByIdActionAsync(Guid id, IEnumerable<string> includes)
|
||||
{
|
||||
var timings = new Dictionary<string, long>();
|
||||
var tsw = new Stopwatch();
|
||||
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
var cacheKey = string.Format("urn:track_by_id_operation:{0}:{1}", id, includes == null ? "0" : string.Join("|", includes));
|
||||
|
||||
tsw.Restart();
|
||||
var track = await GetTrack(id).ConfigureAwait(false);
|
||||
tsw.Stop();
|
||||
timings.Add("getTrack", tsw.ElapsedMilliseconds);
|
||||
|
||||
if (track == null)
|
||||
{
|
||||
return new OperationResult<Track>(true, $"Track Not Found [{id}]");
|
||||
}
|
||||
tsw.Restart();
|
||||
var result = track.Adapt<Track>();
|
||||
result.IsLocked = (track.IsLocked ?? false) ||
|
||||
(track.ReleaseMedia.IsLocked ?? false) ||
|
||||
(track.ReleaseMedia.Release.IsLocked ?? false) ||
|
||||
(track.ReleaseMedia.Release.Artist.IsLocked ?? false);
|
||||
result.Thumbnail = ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, id);
|
||||
result.MediumThumbnail = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "track", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
|
||||
result.ReleaseMediaId = track.ReleaseMedia.RoadieId.ToString();
|
||||
result.Artist = ArtistList.FromDataArtist(track.ReleaseMedia.Release.Artist,
|
||||
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId));
|
||||
result.ArtistThumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId);
|
||||
result.Release = ReleaseList.FromDataRelease(track.ReleaseMedia.Release, track.ReleaseMedia.Release.Artist,
|
||||
HttpContext.BaseUrl, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId),
|
||||
ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId));
|
||||
result.ReleaseThumbnail = ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId);
|
||||
tsw.Stop();
|
||||
timings.Add("adapt", tsw.ElapsedMilliseconds);
|
||||
if (track.ArtistId.HasValue)
|
||||
{
|
||||
tsw.Restart();
|
||||
var trackArtist = DbContext.Artists.FirstOrDefault(x => x.Id == track.ArtistId);
|
||||
if (trackArtist == null)
|
||||
{
|
||||
Logger.LogWarning($"Unable to find Track Artist [{track.ArtistId}");
|
||||
}
|
||||
else
|
||||
{
|
||||
result.TrackArtist =
|
||||
ArtistList.FromDataArtist(trackArtist, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, trackArtist.RoadieId));
|
||||
result.TrackArtistToken = result.TrackArtist.Artist;
|
||||
result.TrackArtistThumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, trackArtist.RoadieId);
|
||||
}
|
||||
tsw.Stop();
|
||||
timings.Add("trackArtist", tsw.ElapsedMilliseconds);
|
||||
}
|
||||
|
||||
if (includes?.Any() == true)
|
||||
{
|
||||
if (includes.Contains("credits"))
|
||||
{
|
||||
tsw.Restart();
|
||||
|
||||
result.Credits = (await (from c in DbContext.Credits
|
||||
join cc in DbContext.CreditCategory on c.CreditCategoryId equals cc.Id
|
||||
join a in DbContext.Artists on c.ArtistId equals a.Id into agg
|
||||
from a in agg.DefaultIfEmpty()
|
||||
where c.TrackId == track.Id
|
||||
select new { c, cc, a })
|
||||
.ToListAsync().ConfigureAwait(false))
|
||||
.Select(x => new CreditList
|
||||
{
|
||||
Id = x.c.RoadieId,
|
||||
Artist = x.a == null ? null : ArtistList.FromDataArtist(x.a, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, x.a.RoadieId)),
|
||||
Category = new DataToken
|
||||
{
|
||||
Text = x.cc.Name,
|
||||
Value = x.cc.RoadieId.ToString()
|
||||
},
|
||||
CreditName = x.a?.Name ?? x.c.CreditToName,
|
||||
Description = x.c.Description
|
||||
}).ToArray();
|
||||
tsw.Stop();
|
||||
timings.Add("credits", tsw.ElapsedMilliseconds);
|
||||
}
|
||||
|
||||
if (includes.Contains("stats"))
|
||||
{
|
||||
tsw.Restart();
|
||||
result.Statistics = new TrackStatistics
|
||||
{
|
||||
FileSizeFormatted = ((long?)track.FileSize).ToFileSize(),
|
||||
Time = new TimeInfo((decimal)track.Duration).ToFullFormattedString(),
|
||||
PlayedCount = track.PlayedCount
|
||||
};
|
||||
var userTracks = (from t in DbContext.Tracks
|
||||
join ut in DbContext.UserTracks on t.Id equals ut.TrackId
|
||||
where t.Id == track.Id
|
||||
select ut).ToArray();
|
||||
if (userTracks?.Any() == true)
|
||||
{
|
||||
result.Statistics.DislikedCount = userTracks.Count(x => x.IsDisliked ?? false);
|
||||
result.Statistics.FavoriteCount = userTracks.Count(x => x.IsFavorite ?? false);
|
||||
}
|
||||
tsw.Stop();
|
||||
timings.Add("stats", tsw.ElapsedMilliseconds);
|
||||
}
|
||||
|
||||
if (includes.Contains("comments"))
|
||||
{
|
||||
tsw.Restart();
|
||||
var trackComments = DbContext.Comments.Include(x => x.User).Where(x => x.TrackId == track.Id)
|
||||
.OrderByDescending(x => x.CreatedDate).ToArray();
|
||||
if (trackComments.Length > 0)
|
||||
{
|
||||
var comments = new List<Comment>();
|
||||
var commentIds = trackComments.Select(x => x.Id).ToArray();
|
||||
var userCommentReactions = (from cr in DbContext.CommentReactions
|
||||
where commentIds.Contains(cr.CommentId)
|
||||
select cr).ToArray();
|
||||
foreach (var trackComment in trackComments)
|
||||
{
|
||||
var comment = trackComment.Adapt<Comment>();
|
||||
comment.DatabaseId = trackComment.Id;
|
||||
comment.User = UserList.FromDataUser(trackComment.User,
|
||||
ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, trackComment.User.RoadieId));
|
||||
comment.DislikedCount = userCommentReactions.Count(x =>
|
||||
x.CommentId == trackComment.Id && x.ReactionValue == CommentReaction.Dislike);
|
||||
comment.LikedCount = userCommentReactions.Count(x =>
|
||||
x.CommentId == trackComment.Id && x.ReactionValue == CommentReaction.Like);
|
||||
comments.Add(comment);
|
||||
}
|
||||
|
||||
result.Comments = comments;
|
||||
}
|
||||
tsw.Stop();
|
||||
timings.Add("comments", tsw.ElapsedMilliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
Logger.LogInformation($"ByIdAction: Track `{ track }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]");
|
||||
return new OperationResult<Track>
|
||||
{
|
||||
Data = result,
|
||||
IsSuccess = result != null,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<Track>> ByIdAsyncAsync(User roadieUser, Guid id, IEnumerable<string> includes)
|
||||
{
|
||||
var timings = new Dictionary<string, long>();
|
||||
var tsw = new Stopwatch();
|
||||
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
var cacheKey = $"urn:track_by_id_operation:{id}:{(includes == null ? "0" : string.Join("|", includes))}";
|
||||
var result = await CacheManager.GetAsync(cacheKey, async () =>
|
||||
{
|
||||
tsw.Restart();
|
||||
var rr = await TrackByIdAction(id, includes).ConfigureAwait(false);
|
||||
var rr = await TrackByIdActionAsync(id, includes).ConfigureAwait(false);
|
||||
tsw.Stop();
|
||||
timings.Add("TrackByIdAction", tsw.ElapsedMilliseconds);
|
||||
timings.Add(nameof(TrackByIdActionAsync), tsw.ElapsedMilliseconds);
|
||||
return rr;
|
||||
}, data.Track.CacheRegionUrn(id)).ConfigureAwait(false);
|
||||
if (result?.Data != null && roadieUser != null)
|
||||
|
@ -140,7 +241,7 @@ namespace Roadie.Api.Services
|
|||
result.Data.TrackPlayUrl = MakeTrackPlayUrl(user, HttpContext.BaseUrl, track.RoadieId);
|
||||
|
||||
tsw.Restart();
|
||||
var userBookmarkResult = await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Track).ConfigureAwait(false);
|
||||
var userBookmarkResult = await BookmarkService.ListAsync(roadieUser, new PagedRequest(), false, BookmarkType.Track).ConfigureAwait(false);
|
||||
if (userBookmarkResult.IsSuccess)
|
||||
{
|
||||
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x?.Bookmark?.Value == track?.RoadieId.ToString()) != null;
|
||||
|
@ -195,7 +296,64 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<Library.Models.Pagination.PagedResult<TrackList>> List(PagedRequest request, User roadieUser, bool? doRandomize = false, Guid? releaseId = null)
|
||||
public static long DetermineByteEndFromHeaders(IHeaderDictionary headers, long fileLength)
|
||||
{
|
||||
var defaultFileLength = fileLength - 1;
|
||||
if (headers?.Any(x => x.Key == "Range") != true)
|
||||
{
|
||||
return defaultFileLength;
|
||||
}
|
||||
|
||||
long? result = null;
|
||||
var rangeHeader = headers["Range"];
|
||||
string rangeEnd = null;
|
||||
var rangeBegin = rangeHeader.FirstOrDefault();
|
||||
if (!string.IsNullOrEmpty(rangeBegin))
|
||||
{
|
||||
//bytes=0-
|
||||
rangeBegin = rangeBegin.Replace("bytes=", string.Empty);
|
||||
var parts = rangeBegin.Split('-');
|
||||
rangeBegin = parts[0];
|
||||
if (parts.Length > 1)
|
||||
{
|
||||
rangeEnd = parts[1];
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(rangeEnd))
|
||||
{
|
||||
result = long.TryParse(rangeEnd, out var outValue) ? (int?)outValue : null;
|
||||
}
|
||||
}
|
||||
|
||||
return result ?? defaultFileLength;
|
||||
}
|
||||
|
||||
public static long DetermineByteStartFromHeaders(IHeaderDictionary headers)
|
||||
{
|
||||
if (headers?.Any(x => x.Key == "Range") != true)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
long result = 0;
|
||||
var rangeHeader = headers["Range"];
|
||||
var rangeBegin = rangeHeader.FirstOrDefault();
|
||||
if (!string.IsNullOrEmpty(rangeBegin))
|
||||
{
|
||||
//bytes=0-
|
||||
rangeBegin = rangeBegin.Replace("bytes=", string.Empty);
|
||||
var parts = rangeBegin.Split('-');
|
||||
rangeBegin = parts[0];
|
||||
if (!string.IsNullOrEmpty(rangeBegin))
|
||||
{
|
||||
long.TryParse(rangeBegin, out result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Library.Models.Pagination.PagedResult<TrackList>> ListAsync(PagedRequest request, User roadieUser, bool? doRandomize = false, Guid? releaseId = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -285,7 +443,7 @@ namespace Roadie.Api.Services
|
|||
if (doRandomize ?? false)
|
||||
{
|
||||
var randomLimit = roadieUser?.RandomReleaseLimit ?? request.LimitValue;
|
||||
randomTrackData = await DbContext.RandomTrackIds(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly).ConfigureAwait(false);
|
||||
randomTrackData = await DbContext.RandomTrackIdsAsync(roadieUser?.Id ?? -1, randomLimit, request.FilterFavoriteOnly, request.FilterRatedOnly).ConfigureAwait(false);
|
||||
randomTrackIds = randomTrackData.Select(x => x.Value).ToArray();
|
||||
rowCount = DbContext.Releases.Count();
|
||||
}
|
||||
|
@ -341,14 +499,14 @@ namespace Roadie.Api.Services
|
|||
where filterToTrackIds == null || filterToTrackIds.Contains(t.RoadieId)
|
||||
where releaseId == null || r.RoadieId == releaseId
|
||||
where request.FilterMinimumRating == null || t.Rating >= request.FilterMinimumRating.Value
|
||||
where string.IsNullOrEmpty(normalizedFilterValue) ||
|
||||
(trackArtist != null && trackArtist.Name.ToLower().Contains(normalizedFilterValue)) ||
|
||||
t.Title.ToLower().Contains(normalizedFilterValue) ||
|
||||
t.AlternateNames.Contains(normalizedFilterValue) ||
|
||||
where string.IsNullOrEmpty(normalizedFilterValue) ||
|
||||
(trackArtist != null && trackArtist.Name.ToLower().Contains(normalizedFilterValue)) ||
|
||||
t.Title.ToLower().Contains(normalizedFilterValue) ||
|
||||
t.AlternateNames.Contains(normalizedFilterValue) ||
|
||||
t.PartTitles.ToLower().Contains(normalizedFilterValue)
|
||||
where !isEqualFilter ||
|
||||
t.Title.ToLower().Equals(normalizedFilterValue) ||
|
||||
t.AlternateNames.ToLower().Equals(normalizedFilterValue) ||
|
||||
where !isEqualFilter ||
|
||||
t.Title.ToLower().Equals(normalizedFilterValue) ||
|
||||
t.AlternateNames.ToLower().Equals(normalizedFilterValue) ||
|
||||
t.PartTitles.ToLower().Equals(request.FilterValue)
|
||||
where !request.FilterFavoriteOnly || favoriteTrackIds.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("#"))
|
||||
{
|
||||
// Find any releases by tags
|
||||
var tagValue = request.FilterValue.Replace("#", "");
|
||||
var tagValue = request.FilterValue.Replace("#", string.Empty);
|
||||
resultQuery = resultQuery.Where(x => x.ti.Tags != null && x.ti.Tags.Contains(tagValue));
|
||||
}
|
||||
|
||||
|
@ -649,7 +807,7 @@ namespace Roadie.Api.Services
|
|||
var track = DbContext.Tracks.FirstOrDefault(x => x.RoadieId == id);
|
||||
if (track == null)
|
||||
{
|
||||
return new OperationResult<Track>(true, string.Format("Track Not Found [{0}]", id));
|
||||
return new OperationResult<Track>(true, $"Track Not Found [{id}]");
|
||||
}
|
||||
|
||||
return new OperationResult<Track>
|
||||
|
@ -659,7 +817,7 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<TrackStreamInfo>> TrackStreamInfo(Guid trackId, long beginBytes, long endBytes, User roadieUser)
|
||||
public async Task<OperationResult<TrackStreamInfo>> TrackStreamInfoAsync(Guid trackId, long beginBytes, long endBytes, User roadieUser)
|
||||
{
|
||||
var track = DbContext.Tracks.FirstOrDefault(x => x.RoadieId == trackId);
|
||||
if (!(track?.IsValid ?? true))
|
||||
|
@ -671,7 +829,7 @@ namespace Roadie.Api.Services
|
|||
select r).FirstOrDefault();
|
||||
if (!release.IsLocked ?? false && roadieUser != null)
|
||||
{
|
||||
await AdminService.ScanRelease(new Library.Identity.User
|
||||
await AdminService.ScanReleaseAsync(new Library.Identity.User
|
||||
{
|
||||
Id = roadieUser.Id.Value
|
||||
}, release.RoadieId, false, true).ConfigureAwait(false);
|
||||
|
@ -710,7 +868,7 @@ namespace Roadie.Api.Services
|
|||
select r).FirstOrDefault();
|
||||
if (!release.IsLocked ?? false && roadieUser != null)
|
||||
{
|
||||
await AdminService.ScanRelease(new Library.Identity.User
|
||||
await AdminService.ScanReleaseAsync(new Library.Identity.User
|
||||
{
|
||||
Id = roadieUser.Id.Value
|
||||
}, release.RoadieId, false, true).ConfigureAwait(false);
|
||||
|
@ -788,7 +946,7 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> UpdateTrack(User user, Track model)
|
||||
public async Task<OperationResult<bool>> UpdateTrackAsync(User user, Track model)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -800,7 +958,7 @@ namespace Roadie.Api.Services
|
|||
.FirstOrDefault(x => x.RoadieId == model.Id);
|
||||
if (track == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, string.Format("Track Not Found [{0}]", model.Id));
|
||||
return new OperationResult<bool>(true, $"Track Not Found [{model.Id}]");
|
||||
}
|
||||
|
||||
try
|
||||
|
@ -938,152 +1096,5 @@ namespace Roadie.Api.Services
|
|||
Errors = errors
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<OperationResult<Track>> TrackByIdAction(Guid id, IEnumerable<string> includes)
|
||||
{
|
||||
var timings = new Dictionary<string, long>();
|
||||
var tsw = new Stopwatch();
|
||||
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
|
||||
tsw.Restart();
|
||||
var track = await GetTrack(id).ConfigureAwait(false);
|
||||
tsw.Stop();
|
||||
timings.Add("getTrack", tsw.ElapsedMilliseconds);
|
||||
|
||||
if (track == null)
|
||||
{
|
||||
return new OperationResult<Track>(true, string.Format("Track Not Found [{0}]", id));
|
||||
}
|
||||
tsw.Restart();
|
||||
var result = track.Adapt<Track>();
|
||||
result.IsLocked = (track.IsLocked ?? false) ||
|
||||
(track.ReleaseMedia.IsLocked ?? false) ||
|
||||
(track.ReleaseMedia.Release.IsLocked ?? false) ||
|
||||
(track.ReleaseMedia.Release.Artist.IsLocked ?? false);
|
||||
result.Thumbnail = ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, id);
|
||||
result.MediumThumbnail = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "track", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
|
||||
result.ReleaseMediaId = track.ReleaseMedia.RoadieId.ToString();
|
||||
result.Artist = ArtistList.FromDataArtist(track.ReleaseMedia.Release.Artist,
|
||||
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId));
|
||||
result.ArtistThumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId);
|
||||
result.Release = ReleaseList.FromDataRelease(track.ReleaseMedia.Release, track.ReleaseMedia.Release.Artist,
|
||||
HttpContext.BaseUrl, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.Artist.RoadieId),
|
||||
ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId));
|
||||
result.ReleaseThumbnail = ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, track.ReleaseMedia.Release.RoadieId);
|
||||
tsw.Stop();
|
||||
timings.Add("adapt", tsw.ElapsedMilliseconds);
|
||||
if (track.ArtistId.HasValue)
|
||||
{
|
||||
tsw.Restart();
|
||||
var trackArtist = DbContext.Artists.FirstOrDefault(x => x.Id == track.ArtistId);
|
||||
if (trackArtist == null)
|
||||
{
|
||||
Logger.LogWarning($"Unable to find Track Artist [{track.ArtistId}");
|
||||
}
|
||||
else
|
||||
{
|
||||
result.TrackArtist =
|
||||
ArtistList.FromDataArtist(trackArtist, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, trackArtist.RoadieId));
|
||||
result.TrackArtistToken = result.TrackArtist.Artist;
|
||||
result.TrackArtistThumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, trackArtist.RoadieId);
|
||||
}
|
||||
tsw.Stop();
|
||||
timings.Add("trackArtist", tsw.ElapsedMilliseconds);
|
||||
}
|
||||
|
||||
if (includes?.Any() == true)
|
||||
{
|
||||
if (includes.Contains("credits"))
|
||||
{
|
||||
tsw.Restart();
|
||||
|
||||
result.Credits = (await (from c in DbContext.Credits
|
||||
join cc in DbContext.CreditCategory on c.CreditCategoryId equals cc.Id
|
||||
join a in DbContext.Artists on c.ArtistId equals a.Id into agg
|
||||
from a in agg.DefaultIfEmpty()
|
||||
where c.TrackId == track.Id
|
||||
select new { c, cc, a })
|
||||
.ToListAsync().ConfigureAwait(false))
|
||||
.Select(x => new CreditList
|
||||
{
|
||||
Id = x.c.RoadieId,
|
||||
Artist = x.a == null ? null : ArtistList.FromDataArtist(x.a, ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, x.a.RoadieId)),
|
||||
Category = new DataToken
|
||||
{
|
||||
Text = x.cc.Name,
|
||||
Value = x.cc.RoadieId.ToString()
|
||||
},
|
||||
CreditName = x.a?.Name ?? x.c.CreditToName,
|
||||
Description = x.c.Description
|
||||
}).ToArray();
|
||||
tsw.Stop();
|
||||
timings.Add("credits", tsw.ElapsedMilliseconds);
|
||||
}
|
||||
|
||||
if (includes.Contains("stats"))
|
||||
{
|
||||
tsw.Restart();
|
||||
result.Statistics = new TrackStatistics
|
||||
{
|
||||
FileSizeFormatted = ((long?)track.FileSize).ToFileSize(),
|
||||
Time = new TimeInfo((decimal)track.Duration).ToFullFormattedString(),
|
||||
PlayedCount = track.PlayedCount
|
||||
};
|
||||
var userTracks = (from t in DbContext.Tracks
|
||||
join ut in DbContext.UserTracks on t.Id equals ut.TrackId
|
||||
where t.Id == track.Id
|
||||
select ut).ToArray();
|
||||
if (userTracks?.Any() == true)
|
||||
{
|
||||
result.Statistics.DislikedCount = userTracks.Count(x => x.IsDisliked ?? false);
|
||||
result.Statistics.FavoriteCount = userTracks.Count(x => x.IsFavorite ?? false);
|
||||
}
|
||||
tsw.Stop();
|
||||
timings.Add("stats", tsw.ElapsedMilliseconds);
|
||||
}
|
||||
|
||||
if (includes.Contains("comments"))
|
||||
{
|
||||
tsw.Restart();
|
||||
var trackComments = DbContext.Comments.Include(x => x.User).Where(x => x.TrackId == track.Id)
|
||||
.OrderByDescending(x => x.CreatedDate).ToArray();
|
||||
if (trackComments.Length > 0)
|
||||
{
|
||||
var comments = new List<Comment>();
|
||||
var commentIds = trackComments.Select(x => x.Id).ToArray();
|
||||
var userCommentReactions = (from cr in DbContext.CommentReactions
|
||||
where commentIds.Contains(cr.CommentId)
|
||||
select cr).ToArray();
|
||||
foreach (var trackComment in trackComments)
|
||||
{
|
||||
var comment = trackComment.Adapt<Comment>();
|
||||
comment.DatabaseId = trackComment.Id;
|
||||
comment.User = UserList.FromDataUser(trackComment.User,
|
||||
ImageHelper.MakeUserThumbnailImage(Configuration, HttpContext, trackComment.User.RoadieId));
|
||||
comment.DislikedCount = userCommentReactions.Count(x =>
|
||||
x.CommentId == trackComment.Id && x.ReactionValue == CommentReaction.Dislike);
|
||||
comment.LikedCount = userCommentReactions.Count(x =>
|
||||
x.CommentId == trackComment.Id && x.ReactionValue == CommentReaction.Like);
|
||||
comments.Add(comment);
|
||||
}
|
||||
|
||||
result.Comments = comments;
|
||||
}
|
||||
tsw.Stop();
|
||||
timings.Add("comments", tsw.ElapsedMilliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
Logger.LogInformation($"ByIdAction: Track `{ track }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]");
|
||||
return new OperationResult<Track>
|
||||
{
|
||||
Data = result,
|
||||
IsSuccess = result != null,
|
||||
OperationTime = sw.ElapsedMilliseconds
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -50,7 +50,179 @@ namespace Roadie.Api.Services
|
|||
LastFmHelper = lastFmHelper;
|
||||
}
|
||||
|
||||
public async Task<OperationResult<User>> ById(User user, Guid id, IEnumerable<string> includes, bool isAccountSettingsEdit = false)
|
||||
private async Task<OperationResult<bool>> SetBookmark(Library.Identity.User user, BookmarkType bookmarktype, int bookmarkTargetId, bool isBookmarked)
|
||||
{
|
||||
var bookmark = DbContext.Bookmarks.FirstOrDefault(x => x.BookmarkTargetId == bookmarkTargetId &&
|
||||
x.BookmarkType == bookmarktype &&
|
||||
x.UserId == user.Id);
|
||||
if (!isBookmarked)
|
||||
{
|
||||
// Remove bookmark
|
||||
if (bookmark != null)
|
||||
{
|
||||
DbContext.Bookmarks.Remove(bookmark);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add bookmark
|
||||
if (bookmark == null)
|
||||
{
|
||||
await DbContext.Bookmarks.AddAsync(new data.Bookmark
|
||||
{
|
||||
UserId = user.Id,
|
||||
BookmarkTargetId = bookmarkTargetId,
|
||||
BookmarkType = bookmarktype,
|
||||
CreatedDate = DateTime.UtcNow,
|
||||
Status = Statuses.Ok
|
||||
}).ConfigureAwait(false);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
CacheManager.ClearRegion(user.CacheRegion);
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = true
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<OperationResult<bool>> UpdateLastFMSessionKey(Library.Identity.User user, string token)
|
||||
{
|
||||
var lastFmSessionKeyResult = await LastFmHelper.GetSessionKeyForUserToken(token).ConfigureAwait(false);
|
||||
if (!lastFmSessionKeyResult.IsSuccess)
|
||||
{
|
||||
return new OperationResult<bool>(false, $"Unable to Get LastFM Session Key For Token [{token}]");
|
||||
}
|
||||
// Check concurrency stamp
|
||||
if (user.ConcurrencyStamp != user.ConcurrencyStamp)
|
||||
{
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
Errors = new List<Exception> { new Exception("User data is stale.") }
|
||||
};
|
||||
}
|
||||
|
||||
user.LastFMSessionKey = lastFmSessionKeyResult.Data;
|
||||
user.LastUpdated = DateTime.UtcNow;
|
||||
user.ConcurrencyStamp = Guid.NewGuid().ToString();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
CacheManager.ClearRegion(Library.Identity.User.CacheRegionUrn(user.RoadieId));
|
||||
|
||||
Logger.LogTrace($"User `{user}` Updated LastFm SessionKey");
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = true
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<OperationResult<User>> UserByIdAction(Guid id, IEnumerable<string> includes)
|
||||
{
|
||||
var timings = new Dictionary<string, long>();
|
||||
var tsw = new Stopwatch();
|
||||
|
||||
tsw.Restart();
|
||||
var user = await GetUser(id).ConfigureAwait(false);
|
||||
tsw.Stop();
|
||||
timings.Add("getUser", tsw.ElapsedMilliseconds);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
return new OperationResult<User>(true, $"User Not Found [{id}]");
|
||||
}
|
||||
tsw.Restart();
|
||||
var model = user.Adapt<User>();
|
||||
model.MediumThumbnail = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "user", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
|
||||
model.IsAdmin = user.UserRoles?.Any(x => x.Role?.NormalizedName == "ADMIN") ?? false;
|
||||
model.IsEditor = model.IsAdmin || (user.UserRoles?.Any(x => x.Role?.NormalizedName == "EDITOR") ?? false);
|
||||
tsw.Stop();
|
||||
timings.Add("adapt", tsw.ElapsedMilliseconds);
|
||||
|
||||
if (includes?.Any() == true && includes.Contains("stats"))
|
||||
{
|
||||
tsw.Restart();
|
||||
var userArtists = DbContext.UserArtists.Include(x => x.Artist).Where(x => x.UserId == user.Id).ToArray() ?? new data.UserArtist[0];
|
||||
var userReleases = DbContext.UserReleases.Include(x => x.Release).Where(x => x.UserId == user.Id).ToArray() ?? new data.UserRelease[0];
|
||||
var userTracks = DbContext.UserTracks.Include(x => x.Track).Where(x => x.UserId == user.Id).ToArray() ?? new data.UserTrack[0];
|
||||
|
||||
var mostPlayedArtist = await DbContext.MostPlayedArtist(user.Id).ConfigureAwait(false);
|
||||
var mostPlayedRelease = await DbContext.MostPlayedRelease(user.Id).ConfigureAwait(false);
|
||||
var lastPlayedTrack = await GetTrack((await DbContext.MostPlayedTrack(user.Id).ConfigureAwait(false))?.RoadieId ?? Guid.Empty).ConfigureAwait(false);
|
||||
var mostPlayedTrack = await GetTrack((await DbContext.LastPlayedTrack(user.Id).ConfigureAwait(false))?.RoadieId ?? Guid.Empty).ConfigureAwait(false);
|
||||
model.Statistics = new UserStatistics
|
||||
{
|
||||
LastPlayedTrack = lastPlayedTrack == null
|
||||
? null
|
||||
: models.TrackList.FromDataTrack(
|
||||
MakeTrackPlayUrl(user, HttpContext.BaseUrl, lastPlayedTrack.RoadieId),
|
||||
lastPlayedTrack,
|
||||
lastPlayedTrack.ReleaseMedia.MediaNumber,
|
||||
lastPlayedTrack.ReleaseMedia.Release,
|
||||
lastPlayedTrack.ReleaseMedia.Release.Artist,
|
||||
lastPlayedTrack.TrackArtist,
|
||||
HttpContext.BaseUrl,
|
||||
ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, lastPlayedTrack.RoadieId),
|
||||
ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, lastPlayedTrack.ReleaseMedia.Release.RoadieId),
|
||||
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, lastPlayedTrack.ReleaseMedia.Release.Artist.RoadieId),
|
||||
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, lastPlayedTrack.TrackArtist == null
|
||||
? null
|
||||
: (Guid?)lastPlayedTrack.TrackArtist.RoadieId)),
|
||||
MostPlayedArtist = mostPlayedArtist == null
|
||||
? null
|
||||
: models.ArtistList.FromDataArtist(mostPlayedArtist,
|
||||
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedArtist.RoadieId)),
|
||||
MostPlayedRelease = mostPlayedRelease == null
|
||||
? null
|
||||
: ReleaseList.FromDataRelease(mostPlayedRelease,
|
||||
mostPlayedRelease.Artist,
|
||||
HttpContext.BaseUrl,
|
||||
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedRelease.Artist.RoadieId),
|
||||
ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, mostPlayedRelease.RoadieId)),
|
||||
MostPlayedTrack = mostPlayedTrack == null
|
||||
? null
|
||||
: models.TrackList.FromDataTrack(
|
||||
MakeTrackPlayUrl(user, HttpContext.BaseUrl, mostPlayedTrack.RoadieId),
|
||||
mostPlayedTrack,
|
||||
mostPlayedTrack.ReleaseMedia.MediaNumber,
|
||||
mostPlayedTrack.ReleaseMedia.Release,
|
||||
mostPlayedTrack.ReleaseMedia.Release.Artist,
|
||||
mostPlayedTrack.TrackArtist,
|
||||
HttpContext.BaseUrl,
|
||||
ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, mostPlayedTrack.RoadieId),
|
||||
ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, mostPlayedTrack.ReleaseMedia.Release.RoadieId),
|
||||
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedTrack.ReleaseMedia.Release.Artist.RoadieId),
|
||||
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedTrack.TrackArtist == null
|
||||
? null
|
||||
: (Guid?)mostPlayedTrack.TrackArtist.RoadieId)),
|
||||
RatedArtists = userArtists.Count(x => x.Rating > 0),
|
||||
FavoritedArtists = userArtists.Count(x => x.IsFavorite ?? false),
|
||||
DislikedArtists = userArtists.Count(x => x.IsDisliked ?? false),
|
||||
RatedReleases = userReleases.Count(x => x.Rating > 0),
|
||||
FavoritedReleases = userReleases.Count(x => x.IsFavorite ?? false),
|
||||
DislikedReleases = userReleases.Count(x => x.IsDisliked ?? false),
|
||||
RatedTracks = userTracks.Count(x => x.Rating > 0),
|
||||
PlayedTracks = userTracks.Where(x => x.PlayedCount.HasValue).Select(x => x.PlayedCount).Sum(),
|
||||
FavoritedTracks = userTracks.Count(x => x.IsFavorite ?? false),
|
||||
DislikedTracks = userTracks.Count(x => x.IsDisliked ?? false)
|
||||
};
|
||||
tsw.Stop();
|
||||
timings.Add("stats", tsw.ElapsedMilliseconds);
|
||||
}
|
||||
Logger.LogInformation($"ByIdAction: User `{ user }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]");
|
||||
return new OperationResult<User>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = model
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<User>> ByIdAsync(User user, Guid id, IEnumerable<string> includes, bool isAccountSettingsEdit = false)
|
||||
{
|
||||
if (isAccountSettingsEdit && user.UserId != id && !user.IsAdmin)
|
||||
{
|
||||
|
@ -61,7 +233,7 @@ namespace Roadie.Api.Services
|
|||
}
|
||||
var sw = Stopwatch.StartNew();
|
||||
sw.Start();
|
||||
var cacheKey = string.Format("urn:user_by_id_operation:{0}:{1}", id, isAccountSettingsEdit);
|
||||
var cacheKey = $"urn:user_by_id_operation:{id}:{isAccountSettingsEdit}";
|
||||
var result = await CacheManager.GetAsync(cacheKey, async () => await UserByIdAction(id, includes).ConfigureAwait(false), Library.Identity.User.CacheRegionUrn(id)).ConfigureAwait(false);
|
||||
sw.Stop();
|
||||
if (result?.Data != null)
|
||||
|
@ -83,7 +255,27 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public Task<models.Pagination.PagedResult<UserList>> List(PagedRequest request)
|
||||
public async Task<OperationResult<bool>> DeleteAllBookmarksAsync(User roadieUser)
|
||||
{
|
||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||
if (user == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
|
||||
}
|
||||
|
||||
DbContext.Bookmarks.RemoveRange(DbContext.Bookmarks.Where(x => x.UserId == user.Id));
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
CacheManager.ClearRegion(user.CacheRegion);
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = true
|
||||
};
|
||||
}
|
||||
|
||||
public Task<models.Pagination.PagedResult<UserList>> ListAsync(PagedRequest request)
|
||||
{
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
@ -162,27 +354,7 @@ namespace Roadie.Api.Services
|
|||
});
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> DeleteAllBookmarks(User roadieUser)
|
||||
{
|
||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||
if (user == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, $"Invalid User [{roadieUser}]");
|
||||
}
|
||||
|
||||
DbContext.Bookmarks.RemoveRange(DbContext.Bookmarks.Where(x => x.UserId == user.Id));
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
CacheManager.ClearRegion(user.CacheRegion);
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = true
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> SetArtistBookmark(Guid artistId, User roadieUser, bool isBookmarked)
|
||||
public async Task<OperationResult<bool>> SetArtistBookmarkAsync(Guid artistId, User roadieUser, bool isBookmarked)
|
||||
{
|
||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||
if (user == null)
|
||||
|
@ -206,7 +378,7 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> SetArtistDisliked(Guid artistId, User roadieUser, bool isDisliked)
|
||||
public async Task<OperationResult<bool>> SetArtistDislikedAsync(Guid artistId, User roadieUser, bool isDisliked)
|
||||
{
|
||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||
if (user == null)
|
||||
|
@ -216,7 +388,7 @@ namespace Roadie.Api.Services
|
|||
return await ToggleArtistDisliked(artistId, user, isDisliked).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> SetArtistFavorite(Guid artistId, User roadieUser, bool isFavorite)
|
||||
public async Task<OperationResult<bool>> SetArtistFavoriteAsync(Guid artistId, User roadieUser, bool isFavorite)
|
||||
{
|
||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||
if (user == null)
|
||||
|
@ -226,7 +398,7 @@ namespace Roadie.Api.Services
|
|||
return await ToggleArtistFavorite(artistId, user, isFavorite).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<OperationResult<short>> SetArtistRating(Guid artistId, User roadieUser, short rating)
|
||||
public async Task<OperationResult<short>> SetArtistRatingAsync(Guid artistId, User roadieUser, short rating)
|
||||
{
|
||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||
if (user == null)
|
||||
|
@ -236,7 +408,7 @@ namespace Roadie.Api.Services
|
|||
return await SetArtistRating(artistId, user, rating).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> SetCollectionBookmark(Guid collectionId, User roadieUser, bool isBookmarked)
|
||||
public async Task<OperationResult<bool>> SetCollectionBookmarkAsync(Guid collectionId, User roadieUser, bool isBookmarked)
|
||||
{
|
||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||
if (user == null)
|
||||
|
@ -259,7 +431,7 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> SetLabelBookmark(Guid labelId, User roadieUser, bool isBookmarked)
|
||||
public async Task<OperationResult<bool>> SetLabelBookmarkAsync(Guid labelId, User roadieUser, bool isBookmarked)
|
||||
{
|
||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||
if (user == null)
|
||||
|
@ -282,7 +454,7 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> SetPlaylistBookmark(Guid playlistId, User roadieUser,
|
||||
public async Task<OperationResult<bool>> SetPlaylistBookmarkAsync(Guid playlistId, User roadieUser,
|
||||
bool isBookmarked)
|
||||
{
|
||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||
|
@ -306,7 +478,7 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> SetReleaseBookmark(Guid releaseid, User roadieUser, bool isBookmarked)
|
||||
public async Task<OperationResult<bool>> SetReleaseBookmarkAsync(Guid releaseid, User roadieUser, bool isBookmarked)
|
||||
{
|
||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||
if (user == null)
|
||||
|
@ -329,7 +501,7 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> SetReleaseDisliked(Guid releaseId, User roadieUser, bool isDisliked)
|
||||
public async Task<OperationResult<bool>> SetReleaseDislikedAsync(Guid releaseId, User roadieUser, bool isDisliked)
|
||||
{
|
||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||
if (user == null)
|
||||
|
@ -339,7 +511,7 @@ namespace Roadie.Api.Services
|
|||
return await ToggleReleaseDisliked(releaseId, user, isDisliked).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> SetReleaseFavorite(Guid releaseId, User roadieUser, bool isFavorite)
|
||||
public async Task<OperationResult<bool>> SetReleaseFavoriteAsync(Guid releaseId, User roadieUser, bool isFavorite)
|
||||
{
|
||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||
if (user == null)
|
||||
|
@ -349,7 +521,7 @@ namespace Roadie.Api.Services
|
|||
return await ToggleReleaseFavorite(releaseId, user, isFavorite).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<OperationResult<short>> SetReleaseRating(Guid releaseId, User roadieUser, short rating)
|
||||
public async Task<OperationResult<short>> SetReleaseRatingAsync(Guid releaseId, User roadieUser, short rating)
|
||||
{
|
||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||
if (user == null)
|
||||
|
@ -359,7 +531,7 @@ namespace Roadie.Api.Services
|
|||
return await SetReleaseRating(releaseId, user, rating).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> SetTrackBookmark(Guid trackId, User roadieUser, bool isBookmarked)
|
||||
public async Task<OperationResult<bool>> SetTrackBookmarkAsync(Guid trackId, User roadieUser, bool isBookmarked)
|
||||
{
|
||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||
if (user == null)
|
||||
|
@ -382,7 +554,7 @@ namespace Roadie.Api.Services
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> SetTrackDisliked(Guid trackId, User roadieUser, bool isDisliked)
|
||||
public async Task<OperationResult<bool>> SetTrackDislikedAsync(Guid trackId, User roadieUser, bool isDisliked)
|
||||
{
|
||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||
if (user == null)
|
||||
|
@ -392,7 +564,7 @@ namespace Roadie.Api.Services
|
|||
return await ToggleTrackDisliked(trackId, user, isDisliked).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> SetTrackFavorite(Guid trackId, User roadieUser, bool isFavorite)
|
||||
public async Task<OperationResult<bool>> SetTrackFavoriteAsync(Guid trackId, User roadieUser, bool isFavorite)
|
||||
{
|
||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||
if (user == null)
|
||||
|
@ -402,13 +574,13 @@ namespace Roadie.Api.Services
|
|||
return await ToggleTrackFavorite(trackId, user, isFavorite).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async Task<OperationResult<short>> SetTrackRating(Guid trackId, User roadieUser, short rating)
|
||||
public async Task<OperationResult<short>> SetTrackRatingAsync(Guid trackId, User roadieUser, short rating)
|
||||
{
|
||||
var timings = new Dictionary<string, long>();
|
||||
var sw = Stopwatch.StartNew();
|
||||
var user = await GetUser(roadieUser.UserId).ConfigureAwait(false);
|
||||
sw.Stop();
|
||||
timings.Add("GetUser", sw.ElapsedMilliseconds);
|
||||
timings.Add(nameof(GetUser), sw.ElapsedMilliseconds);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
|
@ -417,7 +589,7 @@ namespace Roadie.Api.Services
|
|||
sw.Start();
|
||||
var result = await SetTrackRating(trackId, user, rating).ConfigureAwait(false);
|
||||
sw.Stop();
|
||||
timings.Add("SetTrackRating", sw.ElapsedMilliseconds);
|
||||
timings.Add(nameof(SetTrackRatingAsync), sw.ElapsedMilliseconds);
|
||||
|
||||
result.AdditionalData.Add("Timing", sw.ElapsedMilliseconds);
|
||||
Logger.LogTrace(
|
||||
|
@ -425,7 +597,7 @@ namespace Roadie.Api.Services
|
|||
return result;
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> UpdateIntegrationGrant(Guid userId, string integrationName, string token)
|
||||
public async Task<OperationResult<bool>> UpdateIntegrationGrantAsync(Guid userId, string integrationName, string token)
|
||||
{
|
||||
var user = DbContext.Users.FirstOrDefault(x => x.RoadieId == userId);
|
||||
if (user == null)
|
||||
|
@ -439,12 +611,12 @@ namespace Roadie.Api.Services
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task<OperationResult<bool>> UpdateProfile(User userPerformingUpdate, User userBeingUpdatedModel)
|
||||
public async Task<OperationResult<bool>> UpdateProfileAsync(User userPerformingUpdate, User userBeingUpdatedModel)
|
||||
{
|
||||
var user = DbContext.Users.FirstOrDefault(x => x.RoadieId == userBeingUpdatedModel.UserId);
|
||||
if (user == null)
|
||||
{
|
||||
return new OperationResult<bool>(true, string.Format("User Not Found [{0}]", userBeingUpdatedModel.UserId));
|
||||
return new OperationResult<bool>(true, $"User Not Found [{userBeingUpdatedModel.UserId}]");
|
||||
}
|
||||
if (user.Id != userPerformingUpdate.Id && !userPerformingUpdate.IsAdmin)
|
||||
{
|
||||
|
@ -556,175 +728,5 @@ namespace Roadie.Api.Services
|
|||
Data = true
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<OperationResult<bool>> SetBookmark(Library.Identity.User user, BookmarkType bookmarktype, int bookmarkTargetId, bool isBookmarked)
|
||||
{
|
||||
var bookmark = DbContext.Bookmarks.FirstOrDefault(x => x.BookmarkTargetId == bookmarkTargetId &&
|
||||
x.BookmarkType == bookmarktype &&
|
||||
x.UserId == user.Id);
|
||||
if (!isBookmarked)
|
||||
{
|
||||
// Remove bookmark
|
||||
if (bookmark != null)
|
||||
{
|
||||
DbContext.Bookmarks.Remove(bookmark);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add bookmark
|
||||
if (bookmark == null)
|
||||
{
|
||||
await DbContext.Bookmarks.AddAsync(new data.Bookmark
|
||||
{
|
||||
UserId = user.Id,
|
||||
BookmarkTargetId = bookmarkTargetId,
|
||||
BookmarkType = bookmarktype,
|
||||
CreatedDate = DateTime.UtcNow,
|
||||
Status = Statuses.Ok
|
||||
}).ConfigureAwait(false);
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
CacheManager.ClearRegion(user.CacheRegion);
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = true
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<OperationResult<bool>> UpdateLastFMSessionKey(Library.Identity.User user, string token)
|
||||
{
|
||||
var lastFmSessionKeyResult = await LastFmHelper.GetSessionKeyForUserToken(token).ConfigureAwait(false);
|
||||
if (!lastFmSessionKeyResult.IsSuccess)
|
||||
return new OperationResult<bool>(false, $"Unable to Get LastFM Session Key For Token [{token}]");
|
||||
// Check concurrency stamp
|
||||
if (user.ConcurrencyStamp != user.ConcurrencyStamp)
|
||||
{
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
Errors = new List<Exception> { new Exception("User data is stale.") }
|
||||
};
|
||||
}
|
||||
|
||||
user.LastFMSessionKey = lastFmSessionKeyResult.Data;
|
||||
user.LastUpdated = DateTime.UtcNow;
|
||||
user.ConcurrencyStamp = Guid.NewGuid().ToString();
|
||||
await DbContext.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
CacheManager.ClearRegion(Library.Identity.User.CacheRegionUrn(user.RoadieId));
|
||||
|
||||
Logger.LogTrace($"User `{user}` Updated LastFm SessionKey");
|
||||
|
||||
return new OperationResult<bool>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = true
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<OperationResult<User>> UserByIdAction(Guid id, IEnumerable<string> includes)
|
||||
{
|
||||
var timings = new Dictionary<string, long>();
|
||||
var tsw = new Stopwatch();
|
||||
|
||||
tsw.Restart();
|
||||
var user = await GetUser(id).ConfigureAwait(false);
|
||||
tsw.Stop();
|
||||
timings.Add("getUser", tsw.ElapsedMilliseconds);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
return new OperationResult<User>(true, string.Format("User Not Found [{0}]", id));
|
||||
}
|
||||
tsw.Restart();
|
||||
var model = user.Adapt<User>();
|
||||
model.MediumThumbnail = ImageHelper.MakeThumbnailImage(Configuration, HttpContext, id, "user", Configuration.MediumImageSize.Width, Configuration.MediumImageSize.Height);
|
||||
model.IsAdmin = user.UserRoles?.Any(x => x.Role?.NormalizedName == "ADMIN") ?? false;
|
||||
model.IsEditor = model.IsAdmin || (user.UserRoles?.Any(x => x.Role?.NormalizedName == "EDITOR") ?? false);
|
||||
tsw.Stop();
|
||||
timings.Add("adapt", tsw.ElapsedMilliseconds);
|
||||
|
||||
if (includes?.Any() == true && includes.Contains("stats"))
|
||||
{
|
||||
tsw.Restart();
|
||||
var userArtists = DbContext.UserArtists.Include(x => x.Artist).Where(x => x.UserId == user.Id).ToArray() ?? new data.UserArtist[0];
|
||||
var userReleases = DbContext.UserReleases.Include(x => x.Release).Where(x => x.UserId == user.Id).ToArray() ?? new data.UserRelease[0];
|
||||
var userTracks = DbContext.UserTracks.Include(x => x.Track).Where(x => x.UserId == user.Id).ToArray() ?? new data.UserTrack[0];
|
||||
|
||||
var mostPlayedArtist = await DbContext.MostPlayedArtist(user.Id).ConfigureAwait(false);
|
||||
var mostPlayedRelease = await DbContext.MostPlayedRelease(user.Id).ConfigureAwait(false);
|
||||
var lastPlayedTrack = await GetTrack((await DbContext.MostPlayedTrack(user.Id).ConfigureAwait(false))?.RoadieId ?? Guid.Empty).ConfigureAwait(false);
|
||||
var mostPlayedTrack = await GetTrack((await DbContext.LastPlayedTrack(user.Id).ConfigureAwait(false))?.RoadieId ?? Guid.Empty).ConfigureAwait(false);
|
||||
model.Statistics = new UserStatistics
|
||||
{
|
||||
LastPlayedTrack = lastPlayedTrack == null
|
||||
? null
|
||||
: models.TrackList.FromDataTrack(
|
||||
MakeTrackPlayUrl(user, HttpContext.BaseUrl, lastPlayedTrack.RoadieId),
|
||||
lastPlayedTrack,
|
||||
lastPlayedTrack.ReleaseMedia.MediaNumber,
|
||||
lastPlayedTrack.ReleaseMedia.Release,
|
||||
lastPlayedTrack.ReleaseMedia.Release.Artist,
|
||||
lastPlayedTrack.TrackArtist,
|
||||
HttpContext.BaseUrl,
|
||||
ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, lastPlayedTrack.RoadieId),
|
||||
ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, lastPlayedTrack.ReleaseMedia.Release.RoadieId),
|
||||
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, lastPlayedTrack.ReleaseMedia.Release.Artist.RoadieId),
|
||||
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, lastPlayedTrack.TrackArtist == null
|
||||
? null
|
||||
: (Guid?)lastPlayedTrack.TrackArtist.RoadieId)),
|
||||
MostPlayedArtist = mostPlayedArtist == null
|
||||
? null
|
||||
: models.ArtistList.FromDataArtist(mostPlayedArtist,
|
||||
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedArtist.RoadieId)),
|
||||
MostPlayedRelease = mostPlayedRelease == null
|
||||
? null
|
||||
: ReleaseList.FromDataRelease(mostPlayedRelease,
|
||||
mostPlayedRelease.Artist,
|
||||
HttpContext.BaseUrl,
|
||||
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedRelease.Artist.RoadieId),
|
||||
ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, mostPlayedRelease.RoadieId)),
|
||||
MostPlayedTrack = mostPlayedTrack == null
|
||||
? null
|
||||
: models.TrackList.FromDataTrack(
|
||||
MakeTrackPlayUrl(user, HttpContext.BaseUrl, mostPlayedTrack.RoadieId),
|
||||
mostPlayedTrack,
|
||||
mostPlayedTrack.ReleaseMedia.MediaNumber,
|
||||
mostPlayedTrack.ReleaseMedia.Release,
|
||||
mostPlayedTrack.ReleaseMedia.Release.Artist,
|
||||
mostPlayedTrack.TrackArtist,
|
||||
HttpContext.BaseUrl,
|
||||
ImageHelper.MakeTrackThumbnailImage(Configuration, HttpContext, mostPlayedTrack.RoadieId),
|
||||
ImageHelper.MakeReleaseThumbnailImage(Configuration, HttpContext, mostPlayedTrack.ReleaseMedia.Release.RoadieId),
|
||||
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedTrack.ReleaseMedia.Release.Artist.RoadieId),
|
||||
ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, mostPlayedTrack.TrackArtist == null
|
||||
? null
|
||||
: (Guid?)mostPlayedTrack.TrackArtist.RoadieId)),
|
||||
RatedArtists = userArtists.Count(x => x.Rating > 0),
|
||||
FavoritedArtists = userArtists.Count(x => x.IsFavorite ?? false),
|
||||
DislikedArtists = userArtists.Count(x => x.IsDisliked ?? false),
|
||||
RatedReleases = userReleases.Count(x => x.Rating > 0),
|
||||
FavoritedReleases = userReleases.Count(x => x.IsFavorite ?? false),
|
||||
DislikedReleases = userReleases.Count(x => x.IsDisliked ?? false),
|
||||
RatedTracks = userTracks.Count(x => x.Rating > 0),
|
||||
PlayedTracks = userTracks.Where(x => x.PlayedCount.HasValue).Select(x => x.PlayedCount).Sum(),
|
||||
FavoritedTracks = userTracks.Count(x => x.IsFavorite ?? false),
|
||||
DislikedTracks = userTracks.Count(x => x.IsDisliked ?? false)
|
||||
};
|
||||
tsw.Stop();
|
||||
timings.Add("stats", tsw.ElapsedMilliseconds);
|
||||
}
|
||||
Logger.LogInformation($"ByIdAction: User `{ user }`: includes [{includes.ToCSV()}], timings: [{ timings.ToTimings() }]");
|
||||
return new OperationResult<User>
|
||||
{
|
||||
IsSuccess = true,
|
||||
Data = model
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,11 +28,6 @@ namespace Roadie.Api.Controllers
|
|||
[AllowAnonymous]
|
||||
public class AccountController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<AccountController> Logger;
|
||||
private readonly SignInManager<User> SignInManager;
|
||||
private readonly ITokenService TokenService;
|
||||
private readonly UserManager<User> UserManager;
|
||||
private string _baseUrl;
|
||||
|
||||
private IAdminService AdminService { get; }
|
||||
|
||||
|
@ -43,10 +38,17 @@ namespace Roadie.Api.Controllers
|
|||
if (_baseUrl == null)
|
||||
{
|
||||
var scheme = Request.Scheme;
|
||||
if (RoadieSettings.UseSSLBehindProxy) scheme = "https";
|
||||
if (RoadieSettings.UseSSLBehindProxy)
|
||||
{
|
||||
scheme = "https";
|
||||
}
|
||||
|
||||
var host = Request.Host;
|
||||
if (!string.IsNullOrEmpty(RoadieSettings.BehindProxyHost))
|
||||
{
|
||||
host = new HostString(RoadieSettings.BehindProxyHost);
|
||||
}
|
||||
|
||||
_baseUrl = $"{scheme}://{host}";
|
||||
}
|
||||
|
||||
|
@ -62,9 +64,22 @@ namespace Roadie.Api.Controllers
|
|||
|
||||
private IRoadieSettings RoadieSettings { get; }
|
||||
|
||||
public AccountController(IAdminService adminService, UserManager<User> userManager, SignInManager<User> signInManager,
|
||||
IConfiguration configuration, ILogger<AccountController> logger, ITokenService tokenService,
|
||||
ICacheManager cacheManager, IEmailSender emailSender, IHttpContext httpContext)
|
||||
private string _baseUrl;
|
||||
private readonly ILogger<AccountController> Logger;
|
||||
private readonly SignInManager<User> SignInManager;
|
||||
private readonly ITokenService TokenService;
|
||||
private readonly UserManager<User> UserManager;
|
||||
|
||||
public AccountController(
|
||||
IAdminService adminService,
|
||||
UserManager<User> userManager,
|
||||
SignInManager<User> signInManager,
|
||||
IConfiguration configuration,
|
||||
ILogger<AccountController> logger,
|
||||
ITokenService tokenService,
|
||||
ICacheManager cacheManager,
|
||||
IEmailSender emailSender,
|
||||
IHttpContext httpContext)
|
||||
{
|
||||
UserManager = userManager;
|
||||
SignInManager = signInManager;
|
||||
|
@ -73,7 +88,7 @@ namespace Roadie.Api.Controllers
|
|||
CacheManager = cacheManager;
|
||||
|
||||
RoadieSettings = new RoadieSettings();
|
||||
configuration.GetSection("RoadieSettings").Bind(RoadieSettings);
|
||||
configuration.GetSection(nameof(RoadieSettings)).Bind(RoadieSettings);
|
||||
AdminService = adminService;
|
||||
EmailSender = emailSender;
|
||||
RoadieHttpContext = httpContext;
|
||||
|
@ -101,38 +116,41 @@ namespace Roadie.Api.Controllers
|
|||
|
||||
[HttpPost]
|
||||
[Route("token")]
|
||||
public async Task<IActionResult> CreateToken([FromBody] LoginModel model)
|
||||
public async Task<IActionResult> CreateTokenAsync([FromBody] LoginModel model)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Login user
|
||||
var loginResult = await SignInManager.PasswordSignInAsync(model.Username, model.Password, false, false);
|
||||
var loginResult = await SignInManager.PasswordSignInAsync(model.Username, model.Password, false, false).ConfigureAwait(false);
|
||||
if (!loginResult.Succeeded)
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
var user = await UserManager.FindByNameAsync(model.Username);
|
||||
var user = await UserManager.FindByNameAsync(model.Username).ConfigureAwait(false);
|
||||
var now = DateTime.UtcNow;
|
||||
user.LastLogin = now;
|
||||
user.LastUpdated = now;
|
||||
await UserManager.UpdateAsync(user);
|
||||
var t = await TokenService.GenerateToken(user, UserManager);
|
||||
await UserManager.UpdateAsync(user).ConfigureAwait(false);
|
||||
var t = await TokenService.GenerateTokenAsync(user, UserManager).ConfigureAwait(false);
|
||||
Logger.LogTrace($"Successfully authenticated User [{model.Username}]");
|
||||
if (!user.EmailConfirmed)
|
||||
{
|
||||
try
|
||||
{
|
||||
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user).ConfigureAwait(false);
|
||||
var callbackUrl = $"{BaseUrl}/auth/confirmemail?userId={user.Id}&code={code}";
|
||||
await EmailSender.SendEmailAsync(user.Email,
|
||||
$"Confirm your {RoadieSettings.SiteName} email",
|
||||
$"Please confirm your {RoadieSettings.SiteName} account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
|
||||
$"Please confirm your {RoadieSettings.SiteName} account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.")
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "Error sending confirmation Email");
|
||||
}
|
||||
}
|
||||
|
||||
CacheManager.ClearRegion(EntityControllerBase.ControllerCacheRegionUrn);
|
||||
var avatarUrl = $"{RoadieHttpContext.ImageBaseUrl}/user/{user.RoadieId}/{RoadieSettings.ThumbnailImageSize.Width}/{RoadieSettings.ThumbnailImageSize.Height}";
|
||||
|
@ -163,7 +181,7 @@ namespace Roadie.Api.Controllers
|
|||
[Authorize]
|
||||
[HttpPost]
|
||||
[Route("refreshtoken")]
|
||||
public async Task<IActionResult> RefreshToken()
|
||||
public async Task<IActionResult> RefreshTokenAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -172,8 +190,8 @@ namespace Roadie.Api.Controllers
|
|||
.FirstOrDefault();
|
||||
if (!string.IsNullOrWhiteSpace(username))
|
||||
{
|
||||
var user = await UserManager.FindByNameAsync(username);
|
||||
return Ok(await TokenService.GenerateToken(user, UserManager));
|
||||
var user = await UserManager.FindByNameAsync(username).ConfigureAwait(false);
|
||||
return Ok(await TokenService.GenerateTokenAsync(user, UserManager).ConfigureAwait(false));
|
||||
}
|
||||
ModelState.AddModelError("Authentication", "Authentication failed!");
|
||||
}
|
||||
|
@ -187,7 +205,7 @@ namespace Roadie.Api.Controllers
|
|||
[HttpPost]
|
||||
[Route("register")]
|
||||
[AllowAnonymous]
|
||||
public async Task<IActionResult> Register([FromBody] RegisterModel registerModel)
|
||||
public async Task<IActionResult> RegisterAsync([FromBody] RegisterModel registerModel)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -205,7 +223,7 @@ namespace Roadie.Api.Controllers
|
|||
|
||||
if (RoadieSettings.UseRegistrationTokens)
|
||||
{
|
||||
var tokenValidation = await AdminService.ValidateInviteToken(registerModel.InviteToken);
|
||||
var tokenValidation = await AdminService.ValidateInviteTokenAsync(registerModel.InviteToken).ConfigureAwait(false);
|
||||
if (!tokenValidation.IsSuccess)
|
||||
{
|
||||
Logger.LogTrace("Invalid Invite Token");
|
||||
|
@ -213,42 +231,46 @@ namespace Roadie.Api.Controllers
|
|||
}
|
||||
}
|
||||
|
||||
var existinUserByUsername = await UserManager.FindByNameAsync(registerModel.Username);
|
||||
var existinUserByUsername = await UserManager.FindByNameAsync(registerModel.Username).ConfigureAwait(false);
|
||||
if (existinUserByUsername != null)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.BadRequest, new { Title = "User With Username Already Exists!" });
|
||||
}
|
||||
|
||||
var existingUserByEmail = await UserManager.FindByEmailAsync(registerModel.Email);
|
||||
var existingUserByEmail = await UserManager.FindByEmailAsync(registerModel.Email).ConfigureAwait(false);
|
||||
if (existingUserByEmail != null)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.BadRequest, new { Title = "User With Email Already Exists!" });
|
||||
}
|
||||
|
||||
var identityResult = await UserManager.CreateAsync(user, registerModel.Password);
|
||||
var identityResult = await UserManager.CreateAsync(user, registerModel.Password).ConfigureAwait(false);
|
||||
if (identityResult.Succeeded)
|
||||
{
|
||||
if (user.Id == 1) await AdminService.DoInitialSetup(user, UserManager);
|
||||
if (user.Id == 1)
|
||||
{
|
||||
await AdminService.DoInitialSetupAsync(user, UserManager).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
var code = await UserManager.GenerateEmailConfirmationTokenAsync(user).ConfigureAwait(false);
|
||||
var callbackUrl = $"{BaseUrl}/auth/confirmemail?userId={user.Id}&code={code}";
|
||||
await EmailSender.SendEmailAsync(user.Email, $"Confirm your {RoadieSettings.SiteName} email",
|
||||
$"Please confirm your {RoadieSettings.SiteName} account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
|
||||
$"Please confirm your {RoadieSettings.SiteName} account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, $"Error Sending Register Email to [{registerModel.Email}]");
|
||||
}
|
||||
|
||||
await SignInManager.SignInAsync(user, false);
|
||||
var t = await TokenService.GenerateToken(user, UserManager);
|
||||
await SignInManager.SignInAsync(user, false).ConfigureAwait(false);
|
||||
var t = await TokenService.GenerateTokenAsync(user, UserManager).ConfigureAwait(false);
|
||||
Logger.LogTrace($"Successfully created and authenticated User [{registerModel.Username}]");
|
||||
CacheManager.ClearRegion(EntityControllerBase.ControllerCacheRegionUrn);
|
||||
var avatarUrl = $"{RoadieHttpContext.ImageBaseUrl}/user/{user.RoadieId}/{RoadieSettings.ThumbnailImageSize.Width}/{RoadieSettings.ThumbnailImageSize.Height}";
|
||||
if (registerModel.InviteToken.HasValue)
|
||||
{
|
||||
await AdminService.UpdateInviteTokenUsed(registerModel.InviteToken);
|
||||
await AdminService.UpdateInviteTokenUsedAsync(registerModel.InviteToken).ConfigureAwait(false);
|
||||
}
|
||||
return Ok(new
|
||||
{
|
||||
|
@ -286,22 +308,22 @@ namespace Roadie.Api.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("resetpassword")]
|
||||
public async Task<IActionResult> ResetPassword([FromBody] ResetPasswordModel resetPasswordModel)
|
||||
public async Task<IActionResult> ResetPasswordAsync([FromBody] ResetPasswordModel resetPasswordModel)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var user = await UserManager.FindByNameAsync(resetPasswordModel.Username);
|
||||
var user = await UserManager.FindByNameAsync(resetPasswordModel.Username).ConfigureAwait(false);
|
||||
var token = Encoding.ASCII.GetString(WebEncoders.Base64UrlDecode(resetPasswordModel.Token));
|
||||
var identityResult = await UserManager.ResetPasswordAsync(user, token, resetPasswordModel.Password);
|
||||
var identityResult = await UserManager.ResetPasswordAsync(user, token, resetPasswordModel.Password).ConfigureAwait(false);
|
||||
if (identityResult.Succeeded)
|
||||
{
|
||||
CacheManager.ClearRegion(EntityControllerBase.ControllerCacheRegionUrn);
|
||||
await SignInManager.SignInAsync(user, false);
|
||||
await SignInManager.SignInAsync(user, false).ConfigureAwait(false);
|
||||
var avatarUrl =
|
||||
$"{RoadieHttpContext.ImageBaseUrl}/user/{user.RoadieId}/{RoadieSettings.ThumbnailImageSize.Width}/{RoadieSettings.ThumbnailImageSize.Height}";
|
||||
var t = await TokenService.GenerateToken(user, UserManager);
|
||||
var t = await TokenService.GenerateTokenAsync(user, UserManager).ConfigureAwait(false);
|
||||
return Ok(new
|
||||
{
|
||||
Username = user.UserName,
|
||||
|
@ -329,22 +351,22 @@ namespace Roadie.Api.Controllers
|
|||
}
|
||||
|
||||
[HttpGet("sendpasswordresetemail")]
|
||||
public async Task<IActionResult> SendPasswordResetEmail(string username, string callbackUrl)
|
||||
public async Task<IActionResult> SendPasswordResetEmailAsync(string username, string callbackUrl)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = await UserManager.FindByNameAsync(username);
|
||||
var user = await UserManager.FindByNameAsync(username).ConfigureAwait(false);
|
||||
if (user == null)
|
||||
{
|
||||
Logger.LogError($"Unable to find user by username [{username}]");
|
||||
return StatusCode(500);
|
||||
}
|
||||
|
||||
var token = await UserManager.GeneratePasswordResetTokenAsync(user);
|
||||
callbackUrl = callbackUrl + "?username=" + username + "&token=" +
|
||||
WebEncoders.Base64UrlEncode(Encoding.ASCII.GetBytes(token));
|
||||
var token = await UserManager.GeneratePasswordResetTokenAsync(user).ConfigureAwait(false);
|
||||
callbackUrl = $"{callbackUrl}?username={username}&token={WebEncoders.Base64UrlEncode(Encoding.ASCII.GetBytes(token))}";
|
||||
await EmailSender.SendEmailAsync(user.Email, $"Reset your {RoadieSettings.SiteName} password",
|
||||
$"A request has been made to reset your password for your {RoadieSettings.SiteName} account. To proceed <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>click here</a>.");
|
||||
$"A request has been made to reset your password for your {RoadieSettings.SiteName} account. To proceed <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>click here</a>.")
|
||||
.ConfigureAwait(false);
|
||||
Logger.LogTrace("User [{0}] Email [{1}] Requested Password Reset Callback [{2}]", username,
|
||||
user.Email, callbackUrl);
|
||||
return Ok();
|
||||
|
|
|
@ -21,8 +21,12 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
private IAdminService AdminService { get; }
|
||||
|
||||
public AdminController(IAdminService adminService, ILogger<AdminController> logger, ICacheManager cacheManager,
|
||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
||||
public AdminController(
|
||||
IAdminService adminService,
|
||||
ILogger<AdminController> logger,
|
||||
ICacheManager cacheManager,
|
||||
UserManager<User> userManager,
|
||||
IRoadieSettings roadieSettings)
|
||||
: base(cacheManager, roadieSettings, userManager)
|
||||
{
|
||||
Logger = logger;
|
||||
|
@ -42,7 +46,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> DeleteArtist(Guid id, bool? doDeleteFile)
|
||||
{
|
||||
var result = await AdminService.DeleteArtist(await UserManager.GetUserAsync(User), id, doDeleteFile ?? true);
|
||||
var result = await AdminService.DeleteArtistAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, doDeleteFile ?? true).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Messages?.Any() ?? false)
|
||||
|
@ -58,7 +62,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> DeleteArtistReleases(Guid id)
|
||||
{
|
||||
var result = await AdminService.DeleteArtistReleases(await UserManager.GetUserAsync(User), id);
|
||||
var result = await AdminService.DeleteArtistReleasesAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Messages?.Any() ?? false)
|
||||
|
@ -74,39 +78,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> DeleteArtistSecondaryImage(Guid id, int index)
|
||||
{
|
||||
var result = await AdminService.DeleteArtistSecondaryImage(await UserManager.GetUserAsync(User), id, index);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Messages?.Any() ?? false)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.BadRequest, result.Messages);
|
||||
}
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("delete/release/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> DeleteRelease(Guid id, bool? doDeleteFiles)
|
||||
{
|
||||
var result = await AdminService.DeleteRelease(await UserManager.GetUserAsync(User), id, doDeleteFiles);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Messages?.Any() ?? false)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.BadRequest, result.Messages);
|
||||
}
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("delete/label/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> DeleteLabel(Guid id)
|
||||
{
|
||||
var result = await AdminService.DeleteLabel(await UserManager.GetUserAsync(User), id);
|
||||
var result = await AdminService.DeleteArtistSecondaryImageAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, index).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Messages?.Any() ?? false)
|
||||
|
@ -122,7 +94,39 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> DeleteGenre(Guid id)
|
||||
{
|
||||
var result = await AdminService.DeleteGenre(await UserManager.GetUserAsync(User), id);
|
||||
var result = await AdminService.DeleteGenreAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Messages?.Any() ?? false)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.BadRequest, result.Messages);
|
||||
}
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("delete/label/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> DeleteLabel(Guid id)
|
||||
{
|
||||
var result = await AdminService.DeleteLabelAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Messages?.Any() ?? false)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.BadRequest, result.Messages);
|
||||
}
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("delete/release/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> DeleteRelease(Guid id, bool? doDeleteFiles)
|
||||
{
|
||||
var result = await AdminService.DeleteReleaseAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, doDeleteFiles).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Messages?.Any() ?? false)
|
||||
|
@ -139,16 +143,20 @@ namespace Roadie.Api.Controllers
|
|||
public async Task<IActionResult> DeleteReleaseSecondaryImage(Guid id, int index)
|
||||
{
|
||||
var result =
|
||||
await AdminService.DeleteReleaseSecondaryImage(await UserManager.GetUserAsync(User), id, index);
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
await AdminService.DeleteReleaseSecondaryImageAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, index).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("delete/tracks")]
|
||||
[HttpPost("delete/track/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> DeleteTracks([FromBody]IEnumerable<Guid> ids, bool? doDeleteFile)
|
||||
public async Task<IActionResult> DeleteTrack(Guid id, bool? doDeleteFile)
|
||||
{
|
||||
var result = await AdminService.DeleteTracks(await UserManager.GetUserAsync(User), ids, doDeleteFile);
|
||||
var result = await AdminService.DeleteTracksAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), new Guid[1] { id }, doDeleteFile).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Messages?.Any() ?? false)
|
||||
|
@ -160,11 +168,11 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("delete/track/{id}")]
|
||||
[HttpPost("delete/tracks")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> DeleteTrack(Guid id, bool? doDeleteFile)
|
||||
public async Task<IActionResult> DeleteTracks([FromBody] IEnumerable<Guid> ids, bool? doDeleteFile)
|
||||
{
|
||||
var result = await AdminService.DeleteTracks(await UserManager.GetUserAsync(User), new Guid[1] { id }, doDeleteFile);
|
||||
var result = await AdminService.DeleteTracksAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), ids, doDeleteFile).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Messages?.Any() ?? false)
|
||||
|
@ -180,7 +188,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> DeleteUser(Guid id)
|
||||
{
|
||||
var result = await AdminService.DeleteUser(await UserManager.GetUserAsync(User), id);
|
||||
var result = await AdminService.DeleteUserAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Messages?.Any() ?? false)
|
||||
|
@ -196,7 +204,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> MissingCollectionReleases()
|
||||
{
|
||||
var result = await AdminService.MissingCollectionReleases(await UserManager.GetUserAsync(User));
|
||||
var result = await AdminService.MissingCollectionReleasesAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false)).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Messages?.Any() ?? false)
|
||||
|
@ -212,7 +220,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ScanAllCollections()
|
||||
{
|
||||
var result = await AdminService.ScanAllCollections(await UserManager.GetUserAsync(User).ConfigureAwait(false)).ConfigureAwait(false);
|
||||
var result = await AdminService.ScanAllCollectionsAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false)).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Messages?.Any() ?? false)
|
||||
|
@ -228,7 +236,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ScanArtist(Guid id)
|
||||
{
|
||||
var result = await AdminService.ScanArtist(await UserManager.GetUserAsync(User), id);
|
||||
var result = await AdminService.ScanArtistAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Messages?.Any() ?? false)
|
||||
|
@ -244,7 +252,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ScanArtists(IEnumerable<Guid> ids)
|
||||
{
|
||||
var result = await AdminService.ScanArtists(await UserManager.GetUserAsync(User), ids);
|
||||
var result = await AdminService.ScanArtistsAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), ids).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Messages?.Any() ?? false)
|
||||
|
@ -260,7 +268,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ScanCollection(Guid id, bool doPurgeFirst = false)
|
||||
{
|
||||
var result = await AdminService.ScanCollection(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, doPurgeFirst: doPurgeFirst).ConfigureAwait(false);
|
||||
var result = await AdminService.ScanCollectionAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, doPurgeFirst: doPurgeFirst).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Messages?.Any() ?? false)
|
||||
|
@ -276,7 +284,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ScanInbound()
|
||||
{
|
||||
var result = await AdminService.ScanInboundFolder(await UserManager.GetUserAsync(User));
|
||||
var result = await AdminService.ScanInboundFolderAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false)).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Messages?.Any() ?? false)
|
||||
|
@ -292,7 +300,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ScanLibrary()
|
||||
{
|
||||
var result = await AdminService.ScanLibraryFolder(await UserManager.GetUserAsync(User));
|
||||
var result = await AdminService.ScanLibraryFolderAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false)).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Messages?.Any() ?? false)
|
||||
|
@ -308,7 +316,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ScanRelease(Guid id)
|
||||
{
|
||||
var result = await AdminService.ScanRelease(await UserManager.GetUserAsync(User), id);
|
||||
var result = await AdminService.ScanReleaseAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Messages?.Any() ?? false)
|
||||
|
@ -324,7 +332,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ScanReleases(IEnumerable<Guid> ids)
|
||||
{
|
||||
var result = await AdminService.ScanReleases(await UserManager.GetUserAsync(User), ids);
|
||||
var result = await AdminService.ScanReleasesAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), ids).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.Messages?.Any() ?? false)
|
||||
|
|
|
@ -25,8 +25,12 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
private IArtistService ArtistService { get; }
|
||||
|
||||
public ArtistController(IArtistService artistService, ILogger<ArtistController> logger, ICacheManager cacheManager,
|
||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
||||
public ArtistController(
|
||||
IArtistService artistService,
|
||||
ILogger<ArtistController> logger,
|
||||
ICacheManager cacheManager,
|
||||
UserManager<User> userManager,
|
||||
IRoadieSettings roadieSettings)
|
||||
: base(cacheManager, roadieSettings, userManager)
|
||||
{
|
||||
Logger = logger;
|
||||
|
@ -41,13 +45,17 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
var user = await CurrentUserModel().ConfigureAwait(false);
|
||||
var result =
|
||||
await ArtistService.ById(user, id, (inc ?? models.Artist.DefaultIncludes).ToLower().Split(",")).ConfigureAwait(false);
|
||||
await ArtistService.ByIdAsync(user, id, (inc ?? models.Artist.DefaultIncludes).ToLower().Split(",")).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
|
@ -57,11 +65,15 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
try
|
||||
{
|
||||
PagedResult<models.ArtistList> result = await ArtistService.List(await CurrentUserModel().ConfigureAwait(false),
|
||||
PagedResult<models.ArtistList> result = await ArtistService.ListAsync(await CurrentUserModel().ConfigureAwait(false),
|
||||
request,
|
||||
doRandomize ?? false,
|
||||
false).ConfigureAwait(false);
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
|
@ -82,7 +94,7 @@ namespace Roadie.Api.Controllers
|
|||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> MergeArtists(Guid artistToMergeId, Guid artistToMergeIntoId)
|
||||
{
|
||||
var result = await ArtistService.MergeArtists(await UserManager.GetUserAsync(User).ConfigureAwait(false), artistToMergeId, artistToMergeIntoId).ConfigureAwait(false);
|
||||
var result = await ArtistService.MergeArtistsAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), artistToMergeId, artistToMergeIntoId).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -110,8 +122,12 @@ namespace Roadie.Api.Controllers
|
|||
public async Task<IActionResult> SetArtistImageByUrl(Guid id, string imageUrl)
|
||||
{
|
||||
var result =
|
||||
await ArtistService.SetReleaseImageByUrl(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, HttpUtility.UrlDecode(imageUrl)).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false) return NotFound();
|
||||
await ArtistService.SetReleaseImageByUrlAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, HttpUtility.UrlDecode(imageUrl)).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.IsAccessDeniedResult)
|
||||
|
@ -137,7 +153,7 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
var result = await ArtistService.UpdateArtist(await UserManager.GetUserAsync(User).ConfigureAwait(false), artist).ConfigureAwait(false);
|
||||
var result = await ArtistService.UpdateArtistAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), artist).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -163,7 +179,7 @@ namespace Roadie.Api.Controllers
|
|||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> UploadImage(Guid id, IFormFile file)
|
||||
{
|
||||
var result = await ArtistService.UploadArtistImage(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, file).ConfigureAwait(false);
|
||||
var result = await ArtistService.UploadArtistImageAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, file).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
|
|
|
@ -21,8 +21,12 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
private IBookmarkService BookmarkService { get; }
|
||||
|
||||
public BookmarkController(IBookmarkService bookmarkService, ILogger<BookmarkController> logger, ICacheManager cacheManager,
|
||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
||||
public BookmarkController(
|
||||
IBookmarkService bookmarkService,
|
||||
ILogger<BookmarkController> logger,
|
||||
ICacheManager cacheManager,
|
||||
UserManager<User> userManager,
|
||||
IRoadieSettings roadieSettings)
|
||||
: base(cacheManager, roadieSettings, userManager)
|
||||
{
|
||||
Logger = logger;
|
||||
|
@ -35,9 +39,12 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
try
|
||||
{
|
||||
var result = await BookmarkService.List(await CurrentUserModel(),
|
||||
request);
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
var result = await BookmarkService.ListAsync(await CurrentUserModel().ConfigureAwait(false), request).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
|
|
|
@ -23,9 +23,12 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
private ICollectionService CollectionService { get; }
|
||||
|
||||
public CollectionController(ICollectionService collectionService, ILogger<CollectionController> logger,
|
||||
ICacheManager cacheManager,
|
||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
||||
public CollectionController(
|
||||
ICollectionService collectionService,
|
||||
ILogger<CollectionController> logger,
|
||||
ICacheManager cacheManager,
|
||||
UserManager<User> userManager,
|
||||
IRoadieSettings roadieSettings)
|
||||
: base(cacheManager, roadieSettings, userManager)
|
||||
{
|
||||
Logger = logger;
|
||||
|
@ -37,7 +40,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> Add()
|
||||
{
|
||||
var result = CollectionService.Add(await CurrentUserModel());
|
||||
var result = CollectionService.Add(await CurrentUserModel().ConfigureAwait(false));
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.IsAccessDeniedResult)
|
||||
|
@ -59,7 +62,7 @@ namespace Roadie.Api.Controllers
|
|||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> DeleteCollection(Guid id)
|
||||
{
|
||||
var result = await CollectionService.DeleteCollection(await CurrentUserModel(), id);
|
||||
var result = await CollectionService.DeleteCollectionAsync(await CurrentUserModel().ConfigureAwait(false), id).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -84,9 +87,13 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> Get(Guid id, string inc = null)
|
||||
{
|
||||
var result = await CollectionService.ById(await CurrentUserModel(), id,
|
||||
(inc ?? Collection.DefaultIncludes).ToLower().Split(","));
|
||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
||||
var result = await CollectionService.ByIdAsync(await CurrentUserModel().ConfigureAwait(false), id,
|
||||
(inc ?? Collection.DefaultIncludes).ToLower().Split(",")).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.IsAccessDeniedResult)
|
||||
|
@ -108,8 +115,12 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
try
|
||||
{
|
||||
var result = await CollectionService.List(await CurrentUserModel(), request);
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
var result = await CollectionService.ListAsync(await CurrentUserModel().ConfigureAwait(false), request).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
|
@ -134,7 +145,7 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
var result = await CollectionService.UpdateCollection(await CurrentUserModel(), collection);
|
||||
var result = await CollectionService.UpdateCollectionAsync(await CurrentUserModel().ConfigureAwait(false), collection).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
|
|
|
@ -23,9 +23,12 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
private ICommentService CommentService { get; }
|
||||
|
||||
public CommentController(ILogger<CommentController> logger, ICacheManager cacheManager,
|
||||
UserManager<User> userManager,
|
||||
IRoadieSettings roadieSettings, ICommentService commentService)
|
||||
public CommentController(
|
||||
ILogger<CommentController> logger,
|
||||
ICacheManager cacheManager,
|
||||
UserManager<User> userManager,
|
||||
IRoadieSettings roadieSettings,
|
||||
ICommentService commentService)
|
||||
: base(cacheManager, roadieSettings, userManager)
|
||||
{
|
||||
Logger = logger;
|
||||
|
@ -37,9 +40,17 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> AddNewArtistComment(Guid id, models.Comment model)
|
||||
{
|
||||
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
||||
var result = await CommentService.AddNewArtistComment(await CurrentUserModel(), id, model.Cmt);
|
||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
||||
if (string.IsNullOrEmpty(model.Cmt))
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
||||
}
|
||||
|
||||
var result = await CommentService.AddNewArtistCommentAsync(await CurrentUserModel().ConfigureAwait(false), id, model.Cmt).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.IsAccessDeniedResult)
|
||||
|
@ -60,9 +71,17 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> AddNewCollectionComment(Guid id, models.Comment model)
|
||||
{
|
||||
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
||||
var result = await CommentService.AddNewCollectionComment(await CurrentUserModel(), id, model.Cmt);
|
||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
||||
if (string.IsNullOrEmpty(model.Cmt))
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
||||
}
|
||||
|
||||
var result = await CommentService.AddNewCollectionCommentAsync(await CurrentUserModel().ConfigureAwait(false), id, model.Cmt).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.IsAccessDeniedResult)
|
||||
|
@ -83,9 +102,17 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> AddNewGenreComment(Guid id, models.Comment model)
|
||||
{
|
||||
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
||||
var result = await CommentService.AddNewGenreComment(await CurrentUserModel(), id, model.Cmt);
|
||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
||||
if (string.IsNullOrEmpty(model.Cmt))
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
||||
}
|
||||
|
||||
var result = await CommentService.AddNewGenreCommentAsync(await CurrentUserModel().ConfigureAwait(false), id, model.Cmt).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.IsAccessDeniedResult)
|
||||
|
@ -106,9 +133,17 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> AddNewLabelComment(Guid id, models.Comment model)
|
||||
{
|
||||
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
||||
var result = await CommentService.AddNewLabelComment(await CurrentUserModel(), id, model.Cmt);
|
||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
||||
if (string.IsNullOrEmpty(model.Cmt))
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
||||
}
|
||||
|
||||
var result = await CommentService.AddNewLabelCommentAsync(await CurrentUserModel().ConfigureAwait(false), id, model.Cmt).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.IsAccessDeniedResult)
|
||||
|
@ -129,9 +164,17 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> AddNewPlaylistComment(Guid id, models.Comment model)
|
||||
{
|
||||
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
||||
var result = await CommentService.AddNewPlaylistComment(await CurrentUserModel(), id, model.Cmt);
|
||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
||||
if (string.IsNullOrEmpty(model.Cmt))
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
||||
}
|
||||
|
||||
var result = await CommentService.AddNewPlaylistCommentAsync(await CurrentUserModel().ConfigureAwait(false), id, model.Cmt).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.IsAccessDeniedResult)
|
||||
|
@ -152,9 +195,17 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> AddNewReleaseComment(Guid id, models.Comment model)
|
||||
{
|
||||
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
||||
var result = await CommentService.AddNewReleaseComment(await CurrentUserModel(), id, model.Cmt);
|
||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
||||
if (string.IsNullOrEmpty(model.Cmt))
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
||||
}
|
||||
|
||||
var result = await CommentService.AddNewReleaseCommentAsync(await CurrentUserModel().ConfigureAwait(false), id, model.Cmt).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.IsAccessDeniedResult)
|
||||
|
@ -175,9 +226,17 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> AddNewTrackComment(Guid id, models.Comment model)
|
||||
{
|
||||
if (string.IsNullOrEmpty(model.Cmt)) return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
||||
var result = await CommentService.AddNewTrackComment(await CurrentUserModel(), id, model.Cmt);
|
||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
||||
if (string.IsNullOrEmpty(model.Cmt))
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.BadRequest, "Invalid Comment");
|
||||
}
|
||||
|
||||
var result = await CommentService.AddNewTrackCommentAsync(await CurrentUserModel().ConfigureAwait(false), id, model.Cmt).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.IsAccessDeniedResult)
|
||||
|
@ -198,8 +257,12 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> DeleteComment(Guid id)
|
||||
{
|
||||
var result = await CommentService.DeleteComment(await CurrentUserModel(), id);
|
||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
||||
var result = await CommentService.DeleteCommentAsync(await CurrentUserModel().ConfigureAwait(false), id).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.IsAccessDeniedResult)
|
||||
|
@ -220,8 +283,12 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> SetCommentReaction(Guid id, CommentReaction reaction)
|
||||
{
|
||||
var result = await CommentService.SetCommentReaction(await CurrentUserModel(), id, reaction);
|
||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
||||
var result = await CommentService.SetCommentReactionAsync(await CurrentUserModel().ConfigureAwait(false), id, reaction).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.IsAccessDeniedResult)
|
||||
|
|
|
@ -22,8 +22,6 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
public const string ControllerCacheRegionUrn = "urn:controller_cache";
|
||||
|
||||
private models.User _currentUser;
|
||||
|
||||
protected ICacheManager CacheManager { get; }
|
||||
|
||||
protected ILogger Logger { get; set; }
|
||||
|
@ -32,8 +30,12 @@ namespace Roadie.Api.Controllers
|
|||
|
||||
protected UserManager<User> UserManager { get; }
|
||||
|
||||
public EntityControllerBase(ICacheManager cacheManager, IRoadieSettings roadieSettings,
|
||||
UserManager<User> userManager)
|
||||
private models.User _currentUser;
|
||||
|
||||
protected EntityControllerBase(
|
||||
ICacheManager cacheManager,
|
||||
IRoadieSettings roadieSettings,
|
||||
UserManager<User> userManager)
|
||||
{
|
||||
CacheManager = cacheManager;
|
||||
RoadieSettings = roadieSettings;
|
||||
|
@ -48,8 +50,8 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
_currentUser = await CacheManager.GetAsync($"urn:controller_user:{User.Identity.Name}", async () =>
|
||||
{
|
||||
return UserModelForUser(await UserManager.GetUserAsync(User));
|
||||
}, ControllerCacheRegionUrn);
|
||||
return UserModelForUser(await UserManager.GetUserAsync(User).ConfigureAwait(false));
|
||||
}, ControllerCacheRegionUrn).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
if (_currentUser == null)
|
||||
|
@ -67,7 +69,7 @@ namespace Roadie.Api.Controllers
|
|||
var tsw = new Stopwatch();
|
||||
|
||||
tsw.Restart();
|
||||
var user = currentUser ?? await CurrentUserModel();
|
||||
var user = currentUser ?? await CurrentUserModel().ConfigureAwait(false); ;
|
||||
var track = trackService.StreamCheckAndInfo(user, id);
|
||||
if (track == null || (track?.IsNotFoundResult ?? false))
|
||||
{
|
||||
|
@ -86,18 +88,23 @@ namespace Roadie.Api.Controllers
|
|||
timings.Add("TrackService.StreamCheckAndInfo", tsw.ElapsedMilliseconds);
|
||||
tsw.Restart();
|
||||
|
||||
var info = await trackService.TrackStreamInfo(id,
|
||||
var info = await trackService.TrackStreamInfoAsync(id,
|
||||
TrackService.DetermineByteStartFromHeaders(Request.Headers),
|
||||
TrackService.DetermineByteEndFromHeaders(Request.Headers, track.Data.FileSize),
|
||||
user);
|
||||
user).ConfigureAwait(false);
|
||||
if (!info?.IsSuccess ?? false || info?.Data == null)
|
||||
{
|
||||
if (info?.Errors != null && (info?.Errors.Any() ?? false))
|
||||
{
|
||||
Logger.LogCritical(
|
||||
$"StreamTrack: TrackStreamInfo Invalid For TrackId [{id}] OperationResult Errors [{string.Join('|', info?.Errors ?? new Exception[0])}], For User [{currentUser}]");
|
||||
$"StreamTrack: TrackStreamInfo Invalid For TrackId [{id}] OperationResult Errors [{string.Join('|', info?.Errors ?? new Exception[0])}], For User [{currentUser}]");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogCritical(
|
||||
$"StreamTrack: TrackStreamInfo Invalid For TrackId [{id}] OperationResult Messages [{string.Join('|', info?.Messages ?? new string[0])}], For User [{currentUser}]");
|
||||
$"StreamTrack: TrackStreamInfo Invalid For TrackId [{id}] OperationResult Messages [{string.Join('|', info?.Messages ?? new string[0])}], For User [{currentUser}]");
|
||||
}
|
||||
|
||||
return NotFound("Unknown TrackId");
|
||||
}
|
||||
|
||||
|
@ -129,7 +136,7 @@ namespace Roadie.Api.Controllers
|
|||
}
|
||||
Response.Headers.Add("Expires", info.Data.Expires);
|
||||
|
||||
await Response.Body.WriteAsync(info.Data.Bytes, 0, info.Data.Bytes.Length);
|
||||
await Response.Body.WriteAsync(info.Data.Bytes, 0, info.Data.Bytes.Length).ConfigureAwait(false);
|
||||
|
||||
var scrobble = new ScrobbleInfo
|
||||
{
|
||||
|
@ -137,7 +144,7 @@ namespace Roadie.Api.Controllers
|
|||
TimePlayed = DateTime.UtcNow,
|
||||
TrackId = id
|
||||
};
|
||||
await playActivityService.NowPlaying(user, scrobble);
|
||||
await playActivityService.NowPlayingAsync(user, scrobble).ConfigureAwait(false);
|
||||
sw.Stop();
|
||||
Logger.LogTrace($"StreamTrack ElapsedTime [{sw.ElapsedMilliseconds}], Timings [{JsonConvert.SerializeObject(timings)}], StreamInfo `{info?.Data}`");
|
||||
return new EmptyResult();
|
||||
|
@ -145,7 +152,11 @@ namespace Roadie.Api.Controllers
|
|||
|
||||
protected models.User UserModelForUser(User user)
|
||||
{
|
||||
if (user == null) return null;
|
||||
if (user == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var result = user.Adapt<models.User>();
|
||||
result.IsAdmin = User.IsInRole("Admin");
|
||||
result.IsEditor = User.IsInRole("Editor") || result.IsAdmin;
|
||||
|
|
|
@ -25,8 +25,12 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
private IGenreService GenreService { get; }
|
||||
|
||||
public GenreController(IGenreService genreService, ILogger<GenreController> logger, ICacheManager cacheManager,
|
||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
||||
public GenreController(
|
||||
IGenreService genreService,
|
||||
ILogger<GenreController> logger,
|
||||
ICacheManager cacheManager,
|
||||
UserManager<User> userManager,
|
||||
IRoadieSettings roadieSettings)
|
||||
: base(cacheManager, roadieSettings, userManager)
|
||||
{
|
||||
Logger = logger;
|
||||
|
@ -38,9 +42,17 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> Get(Guid id, string inc = null)
|
||||
{
|
||||
var result = await GenreService.ById(await CurrentUserModel(), id, (inc ?? models.Genre.DefaultIncludes).ToLower().Split(","));
|
||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
var result = await GenreService.ByIdAsync(await CurrentUserModel().ConfigureAwait(false), id, (inc ?? models.Genre.DefaultIncludes).ToLower().Split(",")).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
|
@ -50,10 +62,14 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
try
|
||||
{
|
||||
var result = await GenreService.List(await CurrentUserModel(),
|
||||
var result = await GenreService.ListAsync(await CurrentUserModel().ConfigureAwait(false),
|
||||
request,
|
||||
doRandomize);
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
doRandomize).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
|
@ -74,7 +90,7 @@ namespace Roadie.Api.Controllers
|
|||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> SetGenreImageByUrl(Guid id, string imageUrl)
|
||||
{
|
||||
var result = await GenreService.SetGenreImageByUrl(await CurrentUserModel(), id, HttpUtility.UrlDecode(imageUrl));
|
||||
var result = await GenreService.SetGenreImageByUrlAsync(await CurrentUserModel().ConfigureAwait(false), id, HttpUtility.UrlDecode(imageUrl)).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -94,29 +110,6 @@ namespace Roadie.Api.Controllers
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("uploadImage/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> UploadImage(Guid id, IFormFile file)
|
||||
{
|
||||
var result = await GenreService.UploadGenreImage(await CurrentUserModel(), id, file);
|
||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.IsAccessDeniedResult)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.Forbidden);
|
||||
}
|
||||
if (result.Messages?.Any() ?? false)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.BadRequest, result.Messages);
|
||||
}
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("edit")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
|
@ -127,7 +120,7 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
var result = await GenreService.UpdateGenre(await CurrentUserModel(), genre);
|
||||
var result = await GenreService.UpdateGenreAsync(await CurrentUserModel().ConfigureAwait(false), genre).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -142,5 +135,32 @@ namespace Roadie.Api.Controllers
|
|||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("uploadImage/{id}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> UploadImage(Guid id, IFormFile file)
|
||||
{
|
||||
var result = await GenreService.UploadGenreImageAsync(await CurrentUserModel().ConfigureAwait(false), id, file).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.IsAccessDeniedResult)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.Forbidden);
|
||||
}
|
||||
if (result.Messages?.Any() ?? false)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.BadRequest, result.Messages);
|
||||
}
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,20 +20,26 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
private IImageService ImageService { get; }
|
||||
|
||||
public ImageController(IImageService imageService, ILogger<ImageController> logger, ICacheManager cacheManager,
|
||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
||||
public ImageController(
|
||||
IImageService imageService,
|
||||
ILogger<ImageController> logger,
|
||||
ICacheManager cacheManager,
|
||||
UserManager<User> userManager,
|
||||
IRoadieSettings roadieSettings)
|
||||
: base(cacheManager, roadieSettings, userManager)
|
||||
{
|
||||
Logger = logger;
|
||||
ImageService = imageService;
|
||||
}
|
||||
|
||||
private IActionResult MakeFileResult(byte[] bytes, string fileName, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue eTag) => File(bytes, contentType, fileName, lastModified, eTag);
|
||||
|
||||
[HttpGet("artist/{id}/{width:int?}/{height:int?}/{cacheBuster?}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> ArtistImage(Guid id, int? width, int? height)
|
||||
{
|
||||
var result = await ImageService.ArtistImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
|
||||
var result = await ImageService.ArtistImageAsync(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -50,7 +56,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> ArtistSecondaryImage(Guid id, int imageId, int? width, int? height)
|
||||
{
|
||||
var result = await ImageService.ArtistSecondaryImage(id, imageId, width, height).ConfigureAwait(false);
|
||||
var result = await ImageService.ArtistSecondaryImageAsync(id, imageId, width, height).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -67,24 +73,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> CollectionImage(Guid id, int? width, int? height)
|
||||
{
|
||||
var result = await ImageService.CollectionImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return MakeFileResult(result.Data.Bytes, $"{id}.jpg", result.ContentType, result.LastModified, result.ETag);
|
||||
}
|
||||
|
||||
[HttpGet("label/{id}/{width:int?}/{height:int?}/{cacheBuster?}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> LabelImage(Guid id, int? width, int? height)
|
||||
{
|
||||
var result = await ImageService.LabelImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
|
||||
var result = await ImageService.CollectionImageAsync(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -101,7 +90,24 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> GenreImage(Guid id, int? width, int? height)
|
||||
{
|
||||
var result = await ImageService.GenreImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
|
||||
var result = await ImageService.GenreImageAsync(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return MakeFileResult(result.Data.Bytes, $"{id}.jpg", result.ContentType, result.LastModified, result.ETag);
|
||||
}
|
||||
|
||||
[HttpGet("label/{id}/{width:int?}/{height:int?}/{cacheBuster?}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> LabelImage(Guid id, int? width, int? height)
|
||||
{
|
||||
var result = await ImageService.LabelImageAsync(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -118,7 +124,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> PlaylistImage(Guid id, int? width, int? height)
|
||||
{
|
||||
var result = await ImageService.PlaylistImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
|
||||
var result = await ImageService.PlaylistImageAsync(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -135,7 +141,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> ReleaseImage(Guid id, int? width, int? height)
|
||||
{
|
||||
var result = await ImageService.ReleaseImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
|
||||
var result = await ImageService.ReleaseImageAsync(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -152,7 +158,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> ReleaseSecondaryImage(Guid id, int imageId, int? width, int? height)
|
||||
{
|
||||
var result = await ImageService.ReleaseSecondaryImage(id, imageId, width ?? RoadieSettings.MaximumImageSize.Width, height ?? RoadieSettings.MaximumImageSize.Height).ConfigureAwait(false);
|
||||
var result = await ImageService.ReleaseSecondaryImageAsync(id, imageId, width ?? RoadieSettings.MaximumImageSize.Width, height ?? RoadieSettings.MaximumImageSize.Height).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -169,24 +175,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> SearchForArtistImage(string query, int? resultsCount)
|
||||
{
|
||||
var result = await ImageService.Search(query, resultsCount ?? 10).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("search/label/{query}/{resultsCount:int?}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> SearchForLabelImage(string query, int? resultsCount)
|
||||
{
|
||||
var result = await ImageService.Search(query, resultsCount ?? 10).ConfigureAwait(false);
|
||||
var result = await ImageService.SearchAsync(query, resultsCount ?? 10).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -203,9 +192,34 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> SearchForGenreImage(string query, int? resultsCount)
|
||||
{
|
||||
var result = await ImageService.Search(query, resultsCount ?? 10).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false) return NotFound();
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
var result = await ImageService.SearchAsync(query, resultsCount ?? 10).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost("search/label/{query}/{resultsCount:int?}")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> SearchForLabelImage(string query, int? resultsCount)
|
||||
{
|
||||
var result = await ImageService.SearchAsync(query, resultsCount ?? 10).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
|
@ -214,9 +228,17 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> SearchForReleaseCover(string query, int? resultsCount)
|
||||
{
|
||||
var result = await ImageService.Search(query, resultsCount ?? 10).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false) return NotFound();
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
var result = await ImageService.SearchAsync(query, resultsCount ?? 10).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
|
@ -225,7 +247,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> TrackImage(Guid id, int? width, int? height)
|
||||
{
|
||||
var result = await ImageService.TrackImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
|
||||
var result = await ImageService.TrackImageAsync(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -237,8 +259,6 @@ namespace Roadie.Api.Controllers
|
|||
return MakeFileResult(result.Data.Bytes, $"{id}.jpg", result.ContentType, result.LastModified, result.ETag);
|
||||
}
|
||||
|
||||
private IActionResult MakeFileResult(byte[] bytes, string fileName, string contentType, DateTimeOffset? lastModified, EntityTagHeaderValue eTag) => File(bytes, contentType, fileName, lastModified, eTag);
|
||||
|
||||
/// <summary>
|
||||
/// NOTE that user images/avatars are GIF not JPG this is so it looks better in the menus/applications and allows for animated avatars.
|
||||
/// </summary>
|
||||
|
@ -247,7 +267,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> UserImage(Guid id, int? width, int? height)
|
||||
{
|
||||
var result = await ImageService.UserImage(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
|
||||
var result = await ImageService.UserImageAsync(id, width ?? RoadieSettings.ThumbnailImageSize.Width, height ?? RoadieSettings.ThumbnailImageSize.Height).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
|
|
|
@ -25,8 +25,12 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
private ILabelService LabelService { get; }
|
||||
|
||||
public LabelController(ILabelService labelService, ILogger<LabelController> logger, ICacheManager cacheManager,
|
||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
||||
public LabelController(
|
||||
ILabelService labelService,
|
||||
ILogger<LabelController> logger,
|
||||
ICacheManager cacheManager,
|
||||
UserManager<User> userManager,
|
||||
IRoadieSettings roadieSettings)
|
||||
: base(cacheManager, roadieSettings, userManager)
|
||||
{
|
||||
Logger = logger;
|
||||
|
@ -38,7 +42,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> Get(Guid id, string inc = null)
|
||||
{
|
||||
var result = await LabelService.ById(await CurrentUserModel(), id, (inc ?? models.Label.DefaultIncludes).ToLower().Split(","));
|
||||
var result = await LabelService.ByIdAsync(await CurrentUserModel().ConfigureAwait(false), id, (inc ?? models.Label.DefaultIncludes).ToLower().Split(",")).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -56,10 +60,14 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
try
|
||||
{
|
||||
var result = await LabelService.List(await CurrentUserModel(),
|
||||
var result = await LabelService.ListAsync(await CurrentUserModel().ConfigureAwait(false),
|
||||
request,
|
||||
doRandomize);
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
doRandomize).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
|
@ -80,7 +88,7 @@ namespace Roadie.Api.Controllers
|
|||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> MergeLabels(Guid labelToMergeId, Guid labelToMergeIntoId)
|
||||
{
|
||||
var result = await LabelService.MergeLabelsIntoLabel(await UserManager.GetUserAsync(User), labelToMergeIntoId, new Guid[1] { labelToMergeId });
|
||||
var result = await LabelService.MergeLabelsIntoLabelAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), labelToMergeIntoId, new Guid[1] { labelToMergeId }).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -98,7 +106,7 @@ namespace Roadie.Api.Controllers
|
|||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> SetLabelImageByUrl(Guid id, string imageUrl)
|
||||
{
|
||||
var result = await LabelService.SetLabelImageByUrl(await CurrentUserModel(), id, HttpUtility.UrlDecode(imageUrl));
|
||||
var result = await LabelService.SetLabelImageByUrlAsync(await CurrentUserModel().ConfigureAwait(false), id, HttpUtility.UrlDecode(imageUrl)).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -120,7 +128,7 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
var result = await LabelService.UpdateLabel(await CurrentUserModel(), label);
|
||||
var result = await LabelService.UpdateLabelAsync(await CurrentUserModel().ConfigureAwait(false), label).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -142,9 +150,17 @@ namespace Roadie.Api.Controllers
|
|||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> UploadImage(Guid id, IFormFile file)
|
||||
{
|
||||
var result = await LabelService.UploadLabelImage(await CurrentUserModel(), id, file);
|
||||
if (result == null || result.IsNotFoundResult) return NotFound();
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
var result = await LabelService.UploadLabelImageAsync(await CurrentUserModel().ConfigureAwait(false), id, file).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,12 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
private ILookupService LookupService { get; }
|
||||
|
||||
public LookupController(ILabelService labelService, ILogger<LookupController> logger, ICacheManager cacheManager,
|
||||
UserManager<User> userManager, ILookupService lookupService, IRoadieSettings roadieSettings)
|
||||
public LookupController(
|
||||
ILogger<LookupController> logger,
|
||||
ICacheManager cacheManager,
|
||||
UserManager<User> userManager,
|
||||
ILookupService lookupService,
|
||||
IRoadieSettings roadieSettings)
|
||||
: base(cacheManager, roadieSettings, userManager)
|
||||
{
|
||||
Logger = logger;
|
||||
|
@ -33,8 +37,12 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> ArtistTypes(Guid id, string inc = null)
|
||||
{
|
||||
var result = await LookupService.ArtistTypes();
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
var result = await LookupService.ArtistTypesAsync().ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
|
@ -43,8 +51,12 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> BandStatus(Guid id, string inc = null)
|
||||
{
|
||||
var result = await LookupService.BandStatus();
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
var result = await LookupService.BandStatusAsync().ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
|
@ -53,8 +65,12 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> BookmarkTypes(Guid id, string inc = null)
|
||||
{
|
||||
var result = await LookupService.BookmarkTypes();
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
var result = await LookupService.BookmarkTypesAsync().ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
|
@ -63,58 +79,12 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> CollectionTypes(Guid id, string inc = null)
|
||||
{
|
||||
var result = await LookupService.CollectionTypes();
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
return Ok(result);
|
||||
}
|
||||
var result = await LookupService.CollectionTypesAsync().ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
[HttpGet("libraryStatus")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> LibraryStatus(Guid id, string inc = null)
|
||||
{
|
||||
var result = await LookupService.LibraryStatus();
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("queMessageTypes")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> QueMessageTypes(Guid id, string inc = null)
|
||||
{
|
||||
var result = await LookupService.QueMessageTypes();
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("releaseTypes")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> ReleaseTypes(Guid id, string inc = null)
|
||||
{
|
||||
var result = await LookupService.ReleaseTypes();
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("requestStatus")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> RequestStatus(Guid id, string inc = null)
|
||||
{
|
||||
var result = await LookupService.RequestStatus();
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("status")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> Status(Guid id, string inc = null)
|
||||
{
|
||||
var result = await LookupService.Status();
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
|
@ -123,8 +93,82 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> CreditCategories(Guid id, string inc = null)
|
||||
{
|
||||
var result = await LookupService.Status();
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
var result = await LookupService.StatusAsync().ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("libraryStatus")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> LibraryStatus(Guid id, string inc = null)
|
||||
{
|
||||
var result = await LookupService.LibraryStatusAsync().ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("queMessageTypes")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> QueMessageTypes(Guid id, string inc = null)
|
||||
{
|
||||
var result = await LookupService.QueMessageTypesAsync().ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("releaseTypes")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> ReleaseTypes(Guid id, string inc = null)
|
||||
{
|
||||
var result = await LookupService.ReleaseTypesAsync().ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("requestStatus")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> RequestStatus(Guid id, string inc = null)
|
||||
{
|
||||
var result = await LookupService.RequestStatusAsync().ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("status")]
|
||||
[ProducesResponseType(200)]
|
||||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> Status(Guid id, string inc = null)
|
||||
{
|
||||
var result = await LookupService.StatusAsync().ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,9 +22,12 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
private IPlayActivityService PlayActivityService { get; }
|
||||
|
||||
public PlayActivityController(IPlayActivityService playActivityService, ILogger<PlayActivityController> logger,
|
||||
ICacheManager cacheManager,
|
||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
||||
public PlayActivityController(
|
||||
IPlayActivityService playActivityService,
|
||||
ILogger<PlayActivityController> logger,
|
||||
ICacheManager cacheManager,
|
||||
UserManager<User> userManager,
|
||||
IRoadieSettings roadieSettings)
|
||||
: base(cacheManager, roadieSettings, userManager)
|
||||
{
|
||||
Logger = logger;
|
||||
|
@ -35,8 +38,12 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> PlayActivity([FromQuery] PagedRequest request)
|
||||
{
|
||||
var result = await PlayActivityService.List(request).ConfigureAwait(false);
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
var result = await PlayActivityService.ListAsync(request).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
|
@ -45,11 +52,19 @@ namespace Roadie.Api.Controllers
|
|||
public async Task<IActionResult> PlayActivity([FromQuery] PagedRequest request, Guid userId)
|
||||
{
|
||||
var user = UserManager.Users.FirstOrDefault(x => x.RoadieId == userId);
|
||||
if (user == null) return NotFound();
|
||||
var result = await PlayActivityService.List(request,
|
||||
UserModelForUser(user)).ConfigureAwait(false);
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var result = await PlayActivityService.ListAsync(request,
|
||||
UserModelForUser(user)).ConfigureAwait(false);
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,8 +28,13 @@ namespace Roadie.Api.Controllers
|
|||
|
||||
private ITrackService TrackService { get; }
|
||||
|
||||
public PlayController(ITrackService trackService, IReleaseService releaseService, IPlayActivityService playActivityService,
|
||||
ILogger<PlayController> logger, ICacheManager cacheManager, UserManager<User> userManager,
|
||||
public PlayController(
|
||||
ITrackService trackService,
|
||||
IReleaseService releaseService,
|
||||
IPlayActivityService playActivityService,
|
||||
ILogger<PlayController> logger,
|
||||
ICacheManager cacheManager,
|
||||
UserManager<User> userManager,
|
||||
IRoadieSettings roadieSettings)
|
||||
: base(cacheManager, roadieSettings, userManager)
|
||||
{
|
||||
|
@ -43,8 +48,12 @@ namespace Roadie.Api.Controllers
|
|||
public async Task<FileResult> M3uForRelease(Guid id)
|
||||
{
|
||||
var user = await CurrentUserModel().ConfigureAwait(false);
|
||||
var release = await ReleaseService.ById(user, id, new string[1] { "tracks" }).ConfigureAwait(false);
|
||||
if (release?.IsNotFoundResult != false) Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||
var release = await ReleaseService.ByIdAsync(user, id, new string[1] { "tracks" }).ConfigureAwait(false);
|
||||
if (release?.IsNotFoundResult != false)
|
||||
{
|
||||
Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||
}
|
||||
|
||||
var m3u = M3uHelper.M3uContentForTracks(release.Data.Medias.SelectMany(x => x.Tracks));
|
||||
return File(Encoding.Default.GetBytes(m3u), "audio/mpeg-url");
|
||||
}
|
||||
|
@ -53,12 +62,20 @@ namespace Roadie.Api.Controllers
|
|||
public async Task<FileResult> M3uForTrack(Guid id)
|
||||
{
|
||||
var user = await CurrentUserModel().ConfigureAwait(false);
|
||||
var track = await TrackService.ById(user, id, null).ConfigureAwait(false);
|
||||
if (track?.IsNotFoundResult != false) Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||
var release = await ReleaseService.ById(user, track.Data.Release.Id, new string[1] { "tracks" }).ConfigureAwait(false);
|
||||
if (release?.IsNotFoundResult != false) Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||
var track = await TrackService.ByIdAsyncAsync(user, id, null).ConfigureAwait(false);
|
||||
if (track?.IsNotFoundResult != false)
|
||||
{
|
||||
Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||
}
|
||||
|
||||
var release = await ReleaseService.ByIdAsync(user, track.Data.Release.Id, new string[1] { "tracks" }).ConfigureAwait(false);
|
||||
if (release?.IsNotFoundResult != false)
|
||||
{
|
||||
Response.StatusCode = (int)HttpStatusCode.NotFound;
|
||||
}
|
||||
|
||||
var m3u = M3uHelper.M3uContentForTracks(
|
||||
release.Data.Medias.SelectMany(x => x.Tracks).Where(x => x.Id == id));
|
||||
release.Data.Medias.SelectMany(x => x.Tracks).Where(x => x.Id == id));
|
||||
return File(Encoding.Default.GetBytes(m3u), "audio/mpeg-url");
|
||||
}
|
||||
|
||||
|
@ -71,14 +88,22 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> Scrobble(Guid id, string startedPlaying, bool isRandom)
|
||||
{
|
||||
var result = await PlayActivityService.Scrobble(await CurrentUserModel().ConfigureAwait(false), new ScrobbleInfo
|
||||
var result = await PlayActivityService.ScrobbleAsync(await CurrentUserModel().ConfigureAwait(false), new ScrobbleInfo
|
||||
{
|
||||
TrackId = id,
|
||||
TimePlayed = SafeParser.ToDateTime(startedPlaying) ?? DateTime.UtcNow,
|
||||
IsRandomizedScrobble = isRandom
|
||||
}).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false) return NotFound();
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
|
@ -90,7 +115,11 @@ namespace Roadie.Api.Controllers
|
|||
public async Task<IActionResult> StreamTrack(int userId, string trackPlayToken, Guid id)
|
||||
{
|
||||
var user = UserManager.Users.FirstOrDefault(x => x.Id == userId);
|
||||
if (user == null) return StatusCode((int)HttpStatusCode.Unauthorized);
|
||||
if (user == null)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.Unauthorized);
|
||||
}
|
||||
|
||||
if (!ServiceBase.ConfirmTrackPlayToken(user, id, trackPlayToken))
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.Unauthorized);
|
||||
|
|
|
@ -23,8 +23,12 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
private IPlaylistService PlaylistService { get; }
|
||||
|
||||
public PlaylistController(IPlaylistService playlistService, ILogger<PlaylistController> logger, ICacheManager cacheManager,
|
||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
||||
public PlaylistController(
|
||||
IPlaylistService playlistService,
|
||||
ILogger<PlaylistController> logger,
|
||||
ICacheManager cacheManager,
|
||||
UserManager<User> userManager,
|
||||
IRoadieSettings roadieSettings)
|
||||
: base(cacheManager, roadieSettings, userManager)
|
||||
{
|
||||
Logger = logger;
|
||||
|
@ -36,7 +40,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> AddNewPlaylist([FromBody] Playlist model)
|
||||
{
|
||||
var result = await PlaylistService.AddNewPlaylist(await CurrentUserModel(), model);
|
||||
var result = await PlaylistService.AddNewPlaylistAsync(await CurrentUserModel().ConfigureAwait(false), model).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.IsAccessDeniedResult)
|
||||
|
@ -57,7 +61,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> DeletePlaylist(Guid id)
|
||||
{
|
||||
var result = await PlaylistService.DeletePlaylist(await CurrentUserModel(), id);
|
||||
var result = await PlaylistService.DeletePlaylistAsync(await CurrentUserModel().ConfigureAwait(false), id).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -82,7 +86,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> Get(Guid id, string inc = null)
|
||||
{
|
||||
var result = await PlaylistService.ById(await CurrentUserModel(), id, (inc ?? Playlist.DefaultIncludes).ToLower().Split(","));
|
||||
var result = await PlaylistService.ByIdAsync(await CurrentUserModel().ConfigureAwait(false), id, (inc ?? Playlist.DefaultIncludes).ToLower().Split(",")).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -106,9 +110,12 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> List([FromQuery] PagedRequest request, string inc)
|
||||
{
|
||||
var result = await PlaylistService.List(roadieUser: await CurrentUserModel(),
|
||||
request: request);
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
var result = await PlaylistService.ListAsync(roadieUser: await CurrentUserModel().ConfigureAwait(false), request: request).ConfigureAwait(false);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
|
@ -117,8 +124,12 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> Update(Playlist playlist)
|
||||
{
|
||||
if (!ModelState.IsValid) return BadRequest(ModelState);
|
||||
var result = await PlaylistService.UpdatePlaylist(await CurrentUserModel(), playlist);
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
|
||||
var result = await PlaylistService.UpdatePlaylistAsync(await CurrentUserModel().ConfigureAwait(false), playlist).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -143,7 +154,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> UpdateTracks(PlaylistTrackModifyRequest request)
|
||||
{
|
||||
var result = await PlaylistService.UpdatePlaylistTracks(await CurrentUserModel(), request);
|
||||
var result = await PlaylistService.UpdatePlaylistTracksAsync(await CurrentUserModel().ConfigureAwait(false), request).ConfigureAwait(false);
|
||||
if (result == null || result.IsNotFoundResult)
|
||||
{
|
||||
return NotFound();
|
||||
|
|
|
@ -25,8 +25,12 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
private IReleaseService ReleaseService { get; }
|
||||
|
||||
public ReleaseController(IReleaseService releaseService, ILogger<ReleaseController> logger, ICacheManager cacheManager,
|
||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
||||
public ReleaseController(
|
||||
IReleaseService releaseService,
|
||||
ILogger<ReleaseController> logger,
|
||||
ICacheManager cacheManager,
|
||||
UserManager<User> userManager,
|
||||
IRoadieSettings roadieSettings)
|
||||
: base(cacheManager, roadieSettings, userManager)
|
||||
{
|
||||
Logger = logger;
|
||||
|
@ -38,7 +42,7 @@ namespace Roadie.Api.Controllers
|
|||
[ProducesResponseType(404)]
|
||||
public async Task<IActionResult> Get(Guid id, string inc = null)
|
||||
{
|
||||
var result = await ReleaseService.ById(await CurrentUserModel().ConfigureAwait(false), id, (inc ?? Release.DefaultIncludes).ToLower().Split(",")).ConfigureAwait(false);
|
||||
var result = await ReleaseService.ByIdAsync(await CurrentUserModel().ConfigureAwait(false), id, (inc ?? Release.DefaultIncludes).ToLower().Split(",")).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -56,11 +60,15 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
try
|
||||
{
|
||||
var result = await ReleaseService.List(await CurrentUserModel().ConfigureAwait(false),
|
||||
var result = await ReleaseService.ListAsync(await CurrentUserModel().ConfigureAwait(false),
|
||||
request,
|
||||
doRandomize ?? false,
|
||||
(inc ?? Release.DefaultListIncludes).ToLower().Split(",")).ConfigureAwait(false);
|
||||
if (!result.IsSuccess) return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
return StatusCode((int)HttpStatusCode.InternalServerError);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
|
@ -81,8 +89,12 @@ namespace Roadie.Api.Controllers
|
|||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> MergeReleases(Guid releaseToMergeId, Guid releaseToMergeIntoId, bool addAsMedia)
|
||||
{
|
||||
var result = await ReleaseService.MergeReleases(await UserManager.GetUserAsync(User).ConfigureAwait(false), releaseToMergeId, releaseToMergeIntoId, addAsMedia).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false) return NotFound();
|
||||
var result = await ReleaseService.MergeReleasesAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), releaseToMergeId, releaseToMergeIntoId, addAsMedia).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.IsAccessDeniedResult)
|
||||
|
@ -104,8 +116,12 @@ namespace Roadie.Api.Controllers
|
|||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> SetReleaseImageByUrl(Guid id, string imageUrl)
|
||||
{
|
||||
var result = await ReleaseService.SetReleaseImageByUrl(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, HttpUtility.UrlDecode(imageUrl)).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false) return NotFound();
|
||||
var result = await ReleaseService.SetReleaseImageByUrlAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, HttpUtility.UrlDecode(imageUrl)).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.IsAccessDeniedResult)
|
||||
|
@ -131,7 +147,7 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
var result = await ReleaseService.UpdateRelease(await UserManager.GetUserAsync(User).ConfigureAwait(false), release).ConfigureAwait(false);
|
||||
var result = await ReleaseService.UpdateReleaseAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), release).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
|
@ -153,8 +169,12 @@ namespace Roadie.Api.Controllers
|
|||
[Authorize(Policy = "Editor")]
|
||||
public async Task<IActionResult> UploadImage(Guid id, IFormFile file)
|
||||
{
|
||||
var result = await ReleaseService.UploadReleaseImage(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, file).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false) return NotFound();
|
||||
var result = await ReleaseService.UploadReleaseImageAsync(await UserManager.GetUserAsync(User).ConfigureAwait(false), id, file).ConfigureAwait(false);
|
||||
if (result?.IsNotFoundResult != false)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (!result.IsSuccess)
|
||||
{
|
||||
if (result.IsAccessDeniedResult)
|
||||
|
|
|
@ -20,14 +20,22 @@ namespace Roadie.Api.Controllers
|
|||
{
|
||||
private IStatisticsService StatisticsService { get; }
|
||||
|
||||
public StatsController(IStatisticsService statisticsService, ILogger<StatsController> logger, ICacheManager cacheManager,
|
||||
UserManager<User> userManager, IRoadieSettings roadieSettings)
|
||||
public StatsController(
|
||||
IStatisticsService statisticsService,
|
||||
ILogger<StatsController> logger,
|
||||
ICacheManager cacheManager,
|
||||
UserManager<User> userManager,
|
||||
IRoadieSettings roadieSettings)
|
||||
: base(cacheManager, roadieSettings, userManager)
|
||||
{
|
||||
Logger = logger;
|
||||
StatisticsService = statisticsService;
|
||||
}
|
||||
|
||||
[HttpGet("artistsByDate")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ArtistsByDate() => Ok(await StatisticsService.ArtistsByDateAsync().ConfigureAwait(false));
|
||||
|
||||
[HttpGet("info")]
|
||||
[ProducesResponseType(200)]
|
||||
[AllowAnonymous]
|
||||
|
@ -39,12 +47,14 @@ namespace Roadie.Api.Controllers
|
|||
var messages = new List<string>
|
||||
{
|
||||
"▜ Memory Information: ",
|
||||
string.Format("My process used working set {0:n3} K of working set and CPU {1:n} msec",
|
||||
mem / 1024.0, cpu.TotalMilliseconds)
|
||||
$"My process used working set {mem / 1024.0:n3} K of working set and CPU {cpu.TotalMilliseconds:n} msec"
|
||||
};
|
||||
foreach (var aProc in Process.GetProcesses())
|
||||
{
|
||||
messages.Add(string.Format("Proc {0,30} CPU {1,-20:n} msec", aProc.ProcessName,
|
||||
cpu.TotalMilliseconds));
|
||||
cpu.TotalMilliseconds));
|
||||
}
|
||||
|
||||
messages.Add("▟ Memory Information: ");
|
||||
|
||||
return Ok(messages);
|
||||
|
@ -52,31 +62,27 @@ namespace Roadie.Api.Controllers
|
|||
|
||||
[HttpGet("library")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> Library() => Ok(await StatisticsService.LibraryStatistics());
|
||||
public async Task<IActionResult> Library() => Ok(await StatisticsService.LibraryStatisticsAsync().ConfigureAwait(false));
|
||||
|
||||
[HttpGet("ping")]
|
||||
[ProducesResponseType(200)]
|
||||
[AllowAnonymous]
|
||||
public IActionResult Ping() => Ok("pong");
|
||||
|
||||
[HttpGet("artistsByDate")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ArtistsByDate() => Ok(await StatisticsService.ArtistsByDate());
|
||||
|
||||
[HttpGet("releasesByDate")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ReleasesByDate() => Ok(await StatisticsService.ReleasesByDate());
|
||||
public async Task<IActionResult> ReleasesByDate() => Ok(await StatisticsService.ReleasesByDateAsync().ConfigureAwait(false));
|
||||
|
||||
[HttpGet("releasesByDecade")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> ReleasesByDecade() => Ok(await StatisticsService.ReleasesByDecade());
|
||||
public async Task<IActionResult> ReleasesByDecade() => Ok(await StatisticsService.ReleasesByDecadeAsync().ConfigureAwait(false));
|
||||
|
||||
[HttpGet("songsPlayedByDate")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> SongsPlayedByDate() => Ok(await StatisticsService.SongsPlayedByDate());
|
||||
public async Task<IActionResult> SongsPlayedByDate() => Ok(await StatisticsService.SongsPlayedByDateAsync().ConfigureAwait(false));
|
||||
|
||||
[HttpGet("songsPlayedByUser")]
|
||||
[ProducesResponseType(200)]
|
||||
public async Task<IActionResult> SongsPlayedByUser() => Ok(await StatisticsService.SongsPlayedByUser());
|
||||
public async Task<IActionResult> SongsPlayedByUser() => Ok(await StatisticsService.SongsPlayedByUserAsync().ConfigureAwait(false));
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue