diff --git a/.env.example b/.env.example
index c5849686..d2c7391b 100644
--- a/.env.example
+++ b/.env.example
@@ -74,5 +74,6 @@ POSTGRES_PORT=5432
MEILI_HOST="http://meilisearch:7700"
MEILI_MASTER_KEY="ghvjkgisbgkbgskegblfqbgjkebbhgwkjfb"
+RABBITMQ_HOST=rabbitmq:5672
RABBITMQ_DEFAULT_USER=kyoo
RABBITMQ_DEFAULT_PASS=aohohunuhouhuhhoahothonseuhaoensuthoaentsuhha
diff --git a/back/Kyoo.sln b/back/Kyoo.sln
index db805de4..10bf4f8b 100644
--- a/back/Kyoo.sln
+++ b/back/Kyoo.sln
@@ -1,4 +1,5 @@
-Microsoft Visual Studio Solution File, Format Version 12.00
+Microsoft Visual Studio Solution File, Format Version 12.00
+#
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kyoo.Core", "src\Kyoo.Core\Kyoo.Core.csproj", "{0F8275B6-C7DD-42DF-A168-755C81B1C329}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Abstractions", "src\Kyoo.Abstractions\Kyoo.Abstractions.csproj", "{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}"
@@ -13,6 +14,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Host", "src\Kyoo.Host\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Meilisearch", "src\Kyoo.Meilisearch\Kyoo.Meilisearch.csproj", "{F8E6018A-FD51-40EB-99FF-A26BA59F2762}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{787FB205-9D7E-4946-AFE0-BD68E286F569}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.RabbitMq", "src\Kyoo.RabbitMq\Kyoo.RabbitMq.csproj", "{B97AD4A8-E6E6-41CD-87DF-5F1326FD7198}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -59,5 +64,18 @@ Global
{F8E6018A-FD51-40EB-99FF-A26BA59F2762}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F8E6018A-FD51-40EB-99FF-A26BA59F2762}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F8E6018A-FD51-40EB-99FF-A26BA59F2762}.Release|Any CPU.Build.0 = Release|Any CPU
+ {44F2208F-C015-4A01-8D6A-20F82437AFDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {44F2208F-C015-4A01-8D6A-20F82437AFDB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {44F2208F-C015-4A01-8D6A-20F82437AFDB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {44F2208F-C015-4A01-8D6A-20F82437AFDB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B97AD4A8-E6E6-41CD-87DF-5F1326FD7198}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B97AD4A8-E6E6-41CD-87DF-5F1326FD7198}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B97AD4A8-E6E6-41CD-87DF-5F1326FD7198}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B97AD4A8-E6E6-41CD-87DF-5F1326FD7198}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {0C8AA7EA-E723-4532-852F-35AA4E8AFED5} = {FEAE1B0E-D797-470F-9030-0EF743575ECC}
+ {44F2208F-C015-4A01-8D6A-20F82437AFDB} = {BB39454F-53E4-4238-9659-A39638496FB3}
+ {B97AD4A8-E6E6-41CD-87DF-5F1326FD7198} = {787FB205-9D7E-4946-AFE0-BD68E286F569}
EndGlobalSection
EndGlobal
diff --git a/back/src/Kyoo.Host/Kyoo.Host.csproj b/back/src/Kyoo.Host/Kyoo.Host.csproj
index dfed95e7..418d06f9 100644
--- a/back/src/Kyoo.Host/Kyoo.Host.csproj
+++ b/back/src/Kyoo.Host/Kyoo.Host.csproj
@@ -26,6 +26,7 @@
+
diff --git a/back/src/Kyoo.Host/PluginsStartup.cs b/back/src/Kyoo.Host/PluginsStartup.cs
index ddd6a57b..40f4c3d1 100644
--- a/back/src/Kyoo.Host/PluginsStartup.cs
+++ b/back/src/Kyoo.Host/PluginsStartup.cs
@@ -27,6 +27,7 @@ using Kyoo.Core;
using Kyoo.Host.Controllers;
using Kyoo.Meiliseach;
using Kyoo.Postgresql;
+using Kyoo.RabbitMq;
using Kyoo.Swagger;
using Kyoo.Utils;
using Microsoft.AspNetCore.Builder;
@@ -66,6 +67,7 @@ public class PluginsStartup
typeof(AuthenticationModule),
typeof(PostgresModule),
typeof(MeilisearchModule),
+ typeof(RabbitMqModule),
typeof(SwaggerModule)
);
}
diff --git a/back/src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj b/back/src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj
new file mode 100644
index 00000000..382b5b7c
--- /dev/null
+++ b/back/src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj
@@ -0,0 +1,16 @@
+
+
+ enable
+ enable
+ Kyoo.RabbitMq
+
+
+
+
+
+
+
+
+
+
+
diff --git a/back/src/Kyoo.RabbitMq/RabbitMqModule.cs b/back/src/Kyoo.RabbitMq/RabbitMqModule.cs
new file mode 100644
index 00000000..2e7031db
--- /dev/null
+++ b/back/src/Kyoo.RabbitMq/RabbitMqModule.cs
@@ -0,0 +1,53 @@
+// Kyoo - A portable and vast media library solution.
+// Copyright (c) Kyoo.
+//
+// See AUTHORS.md and LICENSE file in the project root for full license information.
+//
+// Kyoo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// Kyoo is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Kyoo. If not, see .
+
+using Autofac;
+using Kyoo.Abstractions.Controllers;
+using Microsoft.Extensions.Configuration;
+using RabbitMQ.Client;
+
+namespace Kyoo.RabbitMq;
+
+public class RabbitMqModule(IConfiguration configuration) : IPlugin
+{
+ ///
+ public string Name => "RabbitMq";
+
+ ///
+ public void Configure(ContainerBuilder builder)
+ {
+ builder
+ .Register(
+ (_) =>
+ {
+ ConnectionFactory factory =
+ new()
+ {
+ UserName = configuration.GetValue("RABBITMQ_DEFAULT_USER", "guest"),
+ Password = configuration.GetValue("RABBITMQ_DEFAULT_USER", "guest"),
+ HostName = configuration.GetValue("RABBITMQ_HOST", "rabbitmq:5672"),
+ };
+
+ return factory.CreateConnection();
+ }
+ )
+ .AsSelf()
+ .SingleInstance();
+ builder.RegisterType().AsSelf().SingleInstance().AutoActivate();
+ }
+}
diff --git a/back/src/Kyoo.RabbitMq/RabbitProducer.cs b/back/src/Kyoo.RabbitMq/RabbitProducer.cs
new file mode 100644
index 00000000..e434989a
--- /dev/null
+++ b/back/src/Kyoo.RabbitMq/RabbitProducer.cs
@@ -0,0 +1,90 @@
+// Kyoo - A portable and vast media library solution.
+// Copyright (c) Kyoo.
+//
+// See AUTHORS.md and LICENSE file in the project root for full license information.
+//
+// Kyoo is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// Kyoo is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Kyoo. If not, see .
+
+using System.Text;
+using System.Text.Json;
+using Kyoo.Abstractions.Controllers;
+using Kyoo.Abstractions.Models;
+using RabbitMQ.Client;
+
+namespace Kyoo.RabbitMq;
+
+public class RabbitProducer
+{
+ private readonly IModel _channel;
+
+ public RabbitProducer(IConnection rabbitConnection)
+ {
+ _channel = rabbitConnection.CreateModel();
+
+ _channel.ExchangeDeclare(exchange: "events.resource.collection", type: ExchangeType.Fanout);
+ IRepository.OnCreated += _Publish("events.resource.collection", "created");
+ IRepository.OnEdited += _Publish("events.resource.collection", "edited");
+ IRepository.OnDeleted += _Publish("events.resource.collection", "deleted");
+
+ _channel.ExchangeDeclare(exchange: "events.resource.movie", type: ExchangeType.Fanout);
+ IRepository.OnCreated += _Publish("events.resource.movie", "created");
+ IRepository.OnEdited += _Publish("events.resource.movie", "edited");
+ IRepository.OnDeleted += _Publish("events.resource.movie", "deleted");
+
+ _channel.ExchangeDeclare(exchange: "events.resource.show", type: ExchangeType.Fanout);
+ IRepository.OnCreated += _Publish("events.resource.show", "created");
+ IRepository.OnEdited += _Publish("events.resource.show", "edited");
+ IRepository.OnDeleted += _Publish("events.resource.show", "deleted");
+
+ _channel.ExchangeDeclare(exchange: "events.resource.season", type: ExchangeType.Fanout);
+ IRepository.OnCreated += _Publish("events.resource.season", "created");
+ IRepository.OnEdited += _Publish("events.resource.season", "edited");
+ IRepository.OnDeleted += _Publish("events.resource.season", "deleted");
+
+ _channel.ExchangeDeclare(exchange: "events.resource.episode", type: ExchangeType.Fanout);
+ IRepository.OnCreated += _Publish("events.resource.episode", "created");
+ IRepository.OnEdited += _Publish("events.resource.episode", "edited");
+ IRepository.OnDeleted += _Publish("events.resource.episode", "deleted");
+
+ _channel.ExchangeDeclare(exchange: "events.resource.studio", type: ExchangeType.Fanout);
+ IRepository.OnCreated += _Publish("events.resource.studio", "created");
+ IRepository.OnEdited += _Publish("events.resource.studio", "edited");
+ IRepository.OnDeleted += _Publish("events.resource.studio", "deleted");
+
+ _channel.ExchangeDeclare(exchange: "events.resource.user", type: ExchangeType.Fanout);
+ IRepository.OnCreated += _Publish("events.resource.user", "created");
+ IRepository.OnEdited += _Publish("events.resource.user", "edited");
+ IRepository.OnDeleted += _Publish("events.resource.user", "deleted");
+ }
+
+ private IRepository.ResourceEventHandler _Publish(string exchange, string action)
+ where T : IResource, IQuery
+ {
+ return (T resource) =>
+ {
+ var message = new
+ {
+ Action = action,
+ Type = typeof(T).Name.ToLowerInvariant(),
+ Value = resource,
+ };
+ _channel.BasicPublish(
+ exchange,
+ routingKey: string.Empty,
+ body: Encoding.UTF8.GetBytes(JsonSerializer.Serialize(message))
+ );
+ return Task.CompletedTask;
+ };
+ }
+}