diff --git a/back/.editorconfig b/back/.editorconfig
index 5f7f01a5..9882c05d 100644
--- a/back/.editorconfig
+++ b/back/.editorconfig
@@ -44,9 +44,9 @@ dotnet_style_prefer_conditional_expression_over_return = true
# Disable strange throw.
csharp_style_throw_expression = false:suggestion
# Forbid "var" everywhere
-csharp_style_var_for_built_in_types = false:warning
-csharp_style_var_when_type_is_apparent = false:warning
-csharp_style_var_elsewhere = false:warning
+csharp_style_var_for_built_in_types = false:suggestion
+csharp_style_var_when_type_is_apparent = false:suggestion
+csharp_style_var_elsewhere = false:suggestion
# Prefer method-like constructs to have a block body
csharp_style_expression_bodied_methods = false:none
csharp_style_expression_bodied_constructors = false:none
diff --git a/back/src/Kyoo.Abstractions/Controllers/IRepository.cs b/back/src/Kyoo.Abstractions/Controllers/IRepository.cs
index c9fab9bf..e52afafd 100644
--- a/back/src/Kyoo.Abstractions/Controllers/IRepository.cs
+++ b/back/src/Kyoo.Abstractions/Controllers/IRepository.cs
@@ -37,7 +37,8 @@ namespace Kyoo.Abstractions.Controllers
/// The event handler type for all events of this repository.
///
/// The resource created/modified/deleted
- public delegate void ResourceEventHandler(T resource);
+ /// A representing the asynchronous operation.
+ public delegate Task ResourceEventHandler(T resource);
///
/// Get a resource from it's ID.
@@ -146,7 +147,15 @@ namespace Kyoo.Abstractions.Controllers
///
/// Called when a resource has been created.
///
- event ResourceEventHandler OnCreated;
+ static event ResourceEventHandler OnCreated;
+
+ ///
+ /// Callback that should be called after a resource has been created.
+ ///
+ /// The resource newly created.
+ /// A representing the asynchronous operation.
+ protected static Task OnResourceCreated(T obj)
+ => OnCreated?.Invoke(obj) ?? Task.CompletedTask;
///
/// Edit a resource and replace every property
@@ -171,7 +180,15 @@ namespace Kyoo.Abstractions.Controllers
///
/// Called when a resource has been edited.
///
- event ResourceEventHandler OnEdited;
+ static event ResourceEventHandler OnEdited;
+
+ ///
+ /// Callback that should be called after a resource has been edited.
+ ///
+ /// The resource newly edited.
+ /// A representing the asynchronous operation.
+ protected static Task OnResourceEdited(T obj)
+ => OnEdited?.Invoke(obj) ?? Task.CompletedTask;
///
/// Delete a resource by it's ID
@@ -207,7 +224,15 @@ namespace Kyoo.Abstractions.Controllers
///
/// Called when a resource has been edited.
///
- event ResourceEventHandler OnDeleted;
+ static event ResourceEventHandler OnDeleted;
+
+ ///
+ /// Callback that should be called after a resource has been deleted.
+ ///
+ /// The resource newly deleted.
+ /// A representing the asynchronous operation.
+ protected static Task OnResourceDeleted(T obj)
+ => OnDeleted?.Invoke(obj) ?? Task.CompletedTask;
}
///
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/CollectionRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/CollectionRepository.cs
index d054bb53..a8fe9241 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/CollectionRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/CollectionRepository.cs
@@ -68,7 +68,7 @@ namespace Kyoo.Core.Controllers
await base.Create(obj);
_database.Entry(obj).State = EntityState.Added;
await _database.SaveChangesAsync(() => Get(obj.Slug));
- OnResourceCreated(obj);
+ await IRepository.OnResourceCreated(obj);
return obj;
}
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs
index 58c4d3a6..b52f8c3e 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs
@@ -25,6 +25,7 @@ using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Utils;
using Kyoo.Postgresql;
using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.DependencyInjection;
namespace Kyoo.Core.Controllers
{
@@ -48,6 +49,25 @@ namespace Kyoo.Core.Controllers
new Sort.By(x => x.EpisodeNumber)
);
+ static EpisodeRepository()
+ {
+ // Edit episode slugs when the show's slug changes.
+ IRepository.OnEdited += async (show) =>
+ {
+ await using AsyncServiceScope scope = CoreModule.Services.CreateAsyncScope();
+ DatabaseContext database = scope.ServiceProvider.GetRequiredService();
+ List episodes = await database.Episodes.AsTracking()
+ .Where(x => x.ShowId == show.Id)
+ .ToListAsync();
+ foreach (Episode ep in episodes)
+ {
+ ep.ShowSlug = show.Slug;
+ await database.SaveChangesAsync();
+ await IRepository.OnResourceEdited(ep);
+ }
+ };
+ }
+
///
/// Create a new .
///
@@ -61,18 +81,6 @@ namespace Kyoo.Core.Controllers
{
_database = database;
_shows = shows;
-
- // Edit episode slugs when the show's slug changes.
- shows.OnEdited += (show) =>
- {
- List episodes = _database.Episodes.AsTracking().Where(x => x.ShowId == show.Id).ToList();
- foreach (Episode ep in episodes)
- {
- ep.ShowSlug = show.Slug;
- _database.SaveChanges();
- OnResourceEdited(ep);
- }
- };
}
///
@@ -96,7 +104,7 @@ namespace Kyoo.Core.Controllers
obj is { SeasonNumber: not null, EpisodeNumber: not null }
? Get(x => x.ShowId == obj.ShowId && x.SeasonNumber == obj.SeasonNumber && x.EpisodeNumber == obj.EpisodeNumber)
: Get(x => x.ShowId == obj.ShowId && x.AbsoluteNumber == obj.AbsoluteNumber));
- OnResourceCreated(obj);
+ await IRepository.OnResourceCreated(obj);
return obj;
}
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs
index 525b4003..0796dca3 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs
@@ -71,15 +71,6 @@ namespace Kyoo.Core.Controllers
///
public Type RepositoryType => typeof(T);
- ///
- public event IRepository.ResourceEventHandler OnCreated;
-
- ///
- public event IRepository.ResourceEventHandler OnEdited;
-
- ///
- public event IRepository.ResourceEventHandler OnDeleted;
-
///
/// Sort the given query.
///
@@ -434,24 +425,6 @@ namespace Kyoo.Core.Controllers
return obj;
}
- ///
- /// Callback that should be called after a resource has been created.
- ///
- /// The resource newly created.
- protected void OnResourceCreated(T obj)
- {
- OnCreated?.Invoke(obj);
- }
-
- ///
- /// Callback that should be called after a resource has been edited.
- ///
- /// The resource newly edited.
- protected void OnResourceEdited(T obj)
- {
- OnEdited?.Invoke(obj);
- }
-
///
public virtual async Task CreateIfNotExists(T obj)
{
@@ -481,7 +454,7 @@ namespace Kyoo.Core.Controllers
Merger.Complete(old, edited, x => x.GetCustomAttribute() == null);
await EditRelations(old, edited);
await Database.SaveChangesAsync();
- OnEdited?.Invoke(old);
+ await IRepository.OnResourceEdited(old);
return old;
}
finally
@@ -504,7 +477,7 @@ namespace Kyoo.Core.Controllers
throw new ArgumentException("Could not patch resource");
await Database.SaveChangesAsync();
- OnEdited?.Invoke(resource);
+ await IRepository.OnResourceEdited(resource);
return resource;
}
finally
@@ -586,7 +559,7 @@ namespace Kyoo.Core.Controllers
///
public virtual Task Delete(T obj)
{
- OnDeleted?.Invoke(obj);
+ IRepository.OnResourceDeleted(obj);
return Task.CompletedTask;
}
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs
index f1fa3e26..db1c26ac 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs
@@ -85,7 +85,7 @@ namespace Kyoo.Core.Controllers
await base.Create(obj);
_database.Entry(obj).State = EntityState.Added;
await _database.SaveChangesAsync(() => Get(obj.Slug));
- OnResourceCreated(obj);
+ await IRepository.OnResourceCreated(obj);
return obj;
}
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/PeopleRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/PeopleRepository.cs
index ecadd8e0..1a004ff9 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/PeopleRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/PeopleRepository.cs
@@ -19,7 +19,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Linq.Expressions;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
@@ -80,7 +79,7 @@ namespace Kyoo.Core.Controllers
await base.Create(obj);
_database.Entry(obj).State = EntityState.Added;
await _database.SaveChangesAsync(() => Get(obj.Slug));
- OnResourceCreated(obj);
+ await IRepository.OnResourceCreated(obj);
return obj;
}
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/SeasonRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/SeasonRepository.cs
index cb1ed67b..2b285b76 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/SeasonRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/SeasonRepository.cs
@@ -22,11 +22,10 @@ using System.Linq;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
-using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Abstractions.Models.Utils;
using Kyoo.Postgresql;
-using Kyoo.Utils;
using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.DependencyInjection;
namespace Kyoo.Core.Controllers
{
@@ -43,30 +42,35 @@ namespace Kyoo.Core.Controllers
///
protected override Sort DefaultSort => new Sort.By(x => x.SeasonNumber);
+ static SeasonRepository()
+ {
+ // Edit seasons slugs when the show's slug changes.
+ IRepository.OnEdited += async (show) =>
+ {
+ await using AsyncServiceScope scope = CoreModule.Services.CreateAsyncScope();
+ DatabaseContext database = scope.ServiceProvider.GetRequiredService();
+ List seasons = await database.Seasons.AsTracking()
+ .Where(x => x.ShowId == show.Id)
+ .ToListAsync();
+ foreach (Season season in seasons)
+ {
+ season.ShowSlug = show.Slug;
+ await database.SaveChangesAsync();
+ await IRepository.OnResourceEdited(season);
+ }
+ };
+ }
+
///
/// Create a new .
///
/// The database handle that will be used
- /// A shows repository
/// The thumbnail manager used to store images.
public SeasonRepository(DatabaseContext database,
- IRepository shows,
IThumbnailsManager thumbs)
: base(database, thumbs)
{
_database = database;
-
- // Edit seasons slugs when the show's slug changes.
- shows.OnEdited += (show) =>
- {
- List seasons = _database.Seasons.AsTracking().Where(x => x.ShowId == show.Id).ToList();
- foreach (Season season in seasons)
- {
- season.ShowSlug = show.Slug;
- _database.SaveChanges();
- OnResourceEdited(season);
- }
- };
}
///
@@ -87,7 +91,7 @@ namespace Kyoo.Core.Controllers
obj.ShowSlug = _database.Shows.First(x => x.Id == obj.ShowId).Slug;
_database.Entry(obj).State = EntityState.Added;
await _database.SaveChangesAsync(() => Get(x => x.ShowId == obj.ShowId && x.SeasonNumber == obj.SeasonNumber));
- OnResourceCreated(obj);
+ await IRepository.OnResourceCreated(obj);
return obj;
}
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/ShowRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/ShowRepository.cs
index 5f00c076..4d234454 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/ShowRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/ShowRepository.cs
@@ -86,7 +86,7 @@ namespace Kyoo.Core.Controllers
await base.Create(obj);
_database.Entry(obj).State = EntityState.Added;
await _database.SaveChangesAsync(() => Get(obj.Slug));
- OnResourceCreated(obj);
+ await IRepository.OnResourceCreated(obj);
return obj;
}
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/StudioRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/StudioRepository.cs
index 6ca571aa..31a8d920 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/StudioRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/StudioRepository.cs
@@ -69,7 +69,7 @@ namespace Kyoo.Core.Controllers
await base.Create(obj);
_database.Entry(obj).State = EntityState.Added;
await _database.SaveChangesAsync(() => Get(obj.Slug));
- OnResourceCreated(obj);
+ await IRepository.OnResourceCreated(obj);
return obj;
}
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/UserRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/UserRepository.cs
index d07753ec..daf38738 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/UserRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/UserRepository.cs
@@ -70,7 +70,7 @@ namespace Kyoo.Core.Controllers
if (obj.Logo != null)
_database.Entry(obj).Reference(x => x.Logo).TargetEntry!.State = EntityState.Added;
await _database.SaveChangesAsync(() => Get(obj.Slug));
- OnResourceCreated(obj);
+ await IRepository.OnResourceCreated(obj);
return obj;
}
diff --git a/back/src/Kyoo.Core/CoreModule.cs b/back/src/Kyoo.Core/CoreModule.cs
index 72c05456..fc9bda22 100644
--- a/back/src/Kyoo.Core/CoreModule.cs
+++ b/back/src/Kyoo.Core/CoreModule.cs
@@ -16,6 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see .
+using System;
using System.Collections.Generic;
using System.Linq;
using AspNetCore.Proxy;
@@ -41,6 +42,12 @@ namespace Kyoo.Core
///
public class CoreModule : IPlugin
{
+ ///
+ /// A service provider to access services in static context (in events for example).
+ ///
+ /// Don't forget to create a scope.
+ public static IServiceProvider Services { get; set; }
+
///
public string Name => "Core";
diff --git a/back/src/Kyoo.Host/Application.cs b/back/src/Kyoo.Host/Application.cs
index f9d15f3f..b406cd1e 100644
--- a/back/src/Kyoo.Host/Application.cs
+++ b/back/src/Kyoo.Host/Application.cs
@@ -23,6 +23,7 @@ using System.Threading;
using System.Threading.Tasks;
using Autofac;
using Autofac.Extensions.DependencyInjection;
+using Kyoo.Core;
using Kyoo.Meiliseach;
using Kyoo.Postgresql;
using Microsoft.AspNetCore.Hosting;
@@ -117,6 +118,7 @@ namespace Kyoo.Host
{
try
{
+ CoreModule.Services = host.Services;
_logger.Information("Version: {Version}", Assembly.GetExecutingAssembly().GetName().Version.ToString(3));
_logger.Information("Data directory: {DataDirectory}", Environment.CurrentDirectory);
await host.RunAsync(cancellationToken);
diff --git a/back/src/Kyoo.Meilisearch/MeilisearchModule.cs b/back/src/Kyoo.Meilisearch/MeilisearchModule.cs
index affd9cc7..d32a7f5c 100644
--- a/back/src/Kyoo.Meilisearch/MeilisearchModule.cs
+++ b/back/src/Kyoo.Meilisearch/MeilisearchModule.cs
@@ -63,12 +63,12 @@ namespace Kyoo.Meiliseach
nameof(LibraryItem.Status),
nameof(LibraryItem.AirDate),
nameof(Movie.StudioID),
+ nameof(LibraryItem.Kind),
},
SortableAttributes = new[]
{
nameof(LibraryItem.AirDate),
nameof(LibraryItem.AddedDate),
- nameof(LibraryItem.Kind),
},
DisplayedAttributes = new[]
{
@@ -94,7 +94,7 @@ namespace Kyoo.Meiliseach
_configuration.GetValue("MEILI_HOST", "http://meilisearch:7700"),
_configuration.GetValue("MEILI_MASTER_KEY")
)).SingleInstance();
- builder.RegisterType().SingleInstance();
+ builder.RegisterType().As().SingleInstance().AutoActivate();
}
}
}
diff --git a/back/src/Kyoo.Meilisearch/SearchManager.cs b/back/src/Kyoo.Meilisearch/SearchManager.cs
index ce2195d5..a3072c7c 100644
--- a/back/src/Kyoo.Meilisearch/SearchManager.cs
+++ b/back/src/Kyoo.Meilisearch/SearchManager.cs
@@ -64,9 +64,10 @@ public class SearchManager : ISearchManager
if (kind != null)
{
dynamic expando = new ExpandoObject();
+ var dictionary = (IDictionary)expando;
foreach (PropertyInfo property in item.GetType().GetProperties())
- expando.TryAdd(property.Name, property.GetValue(item));
+ dictionary.Add(property.Name, property.GetValue(item));
expando.Ref = $"{kind}/{item.Id}";
expando.Kind = kind;
return _client.Index(index).AddDocumentsAsync(new[] { item });
diff --git a/back/tests/Kyoo.Tests/Database/RepositoryActivator.cs b/back/tests/Kyoo.Tests/Database/RepositoryActivator.cs
index f2aebc4d..c68cf414 100644
--- a/back/tests/Kyoo.Tests/Database/RepositoryActivator.cs
+++ b/back/tests/Kyoo.Tests/Database/RepositoryActivator.cs
@@ -50,7 +50,7 @@ namespace Kyoo.Tests.Database
thumbs.Object);
MovieRepository movies = new(_NewContext(), studio, people, thumbs.Object);
ShowRepository show = new(_NewContext(), studio, people, thumbs.Object);
- SeasonRepository season = new(_NewContext(), show, thumbs.Object);
+ SeasonRepository season = new(_NewContext(), thumbs.Object);
LibraryItemRepository libraryItem = new(_NewContext(), thumbs.Object);
EpisodeRepository episode = new(_NewContext(), show, thumbs.Object);
UserRepository user = new(_NewContext(), thumbs.Object);