diff --git a/Encoder/Encoder.csproj b/Encoder/Encoder.csproj
index 3ea8f06..59f3754 100644
--- a/Encoder/Encoder.csproj
+++ b/Encoder/Encoder.csproj
@@ -8,6 +8,7 @@
+
diff --git a/Encoder/EncoderService.cs b/Encoder/EncoderService.cs
new file mode 100644
index 0000000..a0b7206
--- /dev/null
+++ b/Encoder/EncoderService.cs
@@ -0,0 +1,39 @@
+namespace Encoder;
+
+public class EncoderService : IEncoderService {
+ Queue JobQueue;
+ public EncoderService(EncoderServiceOptions options) {
+ JobQueue = new Queue();
+ }
+
+ public Guid EnqueueJob(EncodingJob job) {
+ JobQueue.Enqueue(job);
+ return job.Id;
+ }
+
+ public EncodingJob? GetJobStatus(Guid jobId) {
+ return JobQueue.FirstOrDefault(j => j.Id == jobId);
+ }
+
+ public void RemoveJob(Guid jobId) {
+ var job = JobQueue.FirstOrDefault(j => j.Id == jobId);
+ if (job != null) {
+ var tempQueue = new Queue();
+ while (JobQueue.Count > 0) {
+ var currentJob = JobQueue.Dequeue();
+ if (currentJob.Id != jobId) {
+ tempQueue.Enqueue(currentJob);
+ }
+ }
+ JobQueue = tempQueue;
+ }
+ }
+
+ public Task ProcessNextJob() {
+ var job = JobQueue.Dequeue();
+ // Encode....
+
+
+ return Task.CompletedTask;
+ }
+}
\ No newline at end of file
diff --git a/Encoder/EncoderServiceOptions.cs b/Encoder/EncoderServiceOptions.cs
new file mode 100644
index 0000000..930e339
--- /dev/null
+++ b/Encoder/EncoderServiceOptions.cs
@@ -0,0 +1,6 @@
+namespace Encoder;
+
+public record class EncoderServiceOptions {
+ public string OutputPath { get; init; } = Path.GetTempPath();
+ public string FfmpegPath { get; init; } = Path.Combine(Environment.ProcessPath, "ffmpeg");
+}
\ No newline at end of file
diff --git a/Encoder/EncodingJob.cs b/Encoder/EncodingJob.cs
new file mode 100644
index 0000000..6b1bc2f
--- /dev/null
+++ b/Encoder/EncodingJob.cs
@@ -0,0 +1,9 @@
+namespace Encoder;
+
+public record EncodingJob(Guid Id) {
+ public JobStatus Status { get; set; } = JobStatus.Pending;
+ public DateTime CreatedAt { get; init; } = DateTime.Now;
+ public DateTime? CompletedAt { get; set; } = null;
+ public string OrigFilePath { get; init; } = string.Empty;
+ public string EncodedFilePath { get; set; } = string.Empty;
+}
\ No newline at end of file
diff --git a/Encoder/IEncoderService.cs b/Encoder/IEncoderService.cs
new file mode 100644
index 0000000..984a003
--- /dev/null
+++ b/Encoder/IEncoderService.cs
@@ -0,0 +1,7 @@
+namespace Encoder;
+
+public interface IEncoderService {
+ public Guid EnqueueJob(EncodingJob job);
+ public EncodingJob? GetJobStatus(Guid jobId);
+ public void RemoveJob(Guid jobId);
+}
\ No newline at end of file
diff --git a/Encoder/JobStatus.cs b/Encoder/JobStatus.cs
new file mode 100644
index 0000000..f82bd79
--- /dev/null
+++ b/Encoder/JobStatus.cs
@@ -0,0 +1,8 @@
+namespace Encoder;
+
+public enum JobStatus {
+ Pending,
+ InProgress,
+ Completed,
+ Failed
+}
\ No newline at end of file
diff --git a/Encoder/Program.cs b/Encoder/Program.cs
index 0ce2a1c..0e2b02e 100644
--- a/Encoder/Program.cs
+++ b/Encoder/Program.cs
@@ -1,14 +1,16 @@
-using System.Collections;
-using Microsoft.AspNetCore.Http.HttpResults;
-Queue JobQueue = new();
+using Encoder;
var builder = WebApplication.CreateBuilder(args);
//Settings
-string tmpFilePath = builder.Configuration.GetValue("TempFilePath") ?? Path.GetTempPath();
-
+string? tmpFilePath = builder.Configuration.GetValue("TempFilePath");
+string? ffmpegPath = builder.Configuration.GetValue("FfmpegPath");
//Services
builder.Services.AddOpenApi();
+
+var encoderOptions = new EncoderServiceOptions { OutputPath = tmpFilePath };
+builder.Services.AddSingleton(_ => new (encoderOptions));
+
var app = builder.Build();
if (app.Environment.IsDevelopment()) { app.MapOpenApi(); }
@@ -18,7 +20,7 @@ app.UseHttpsRedirection();
// Get a video file as multipart form data and schedule it for encoding
// Get video encoding settings from query parameters
// Returns the ID of the job handling the encoding
-app.MapPost("encode", context =>
+app.MapPost("encode", context =>
{
var request = context.Request;
if (!request.HasFormContentType) {
@@ -34,16 +36,25 @@ app.MapPost("encode", context =>
return context.Response.WriteAsync("No video file provided.");
}
- var Job = new EncodingJob(Guid.NewGuid());
- JobQueue.Enqueue(Job);
-
- return context.Response.WriteAsJsonAsync(new { JobId = Job.Id });
+ var job = new EncodingJob(Guid.NewGuid());
+ var encSrv = context.RequestServices.GetService();
+ if (encSrv != null) encSrv.EnqueueJob(job);
+ else {
+ context.Response.StatusCode = 500;
+ return context.Response.WriteAsync("Encoder service not available.");
+ }
+
+ context.Response.StatusCode = 200;
+ return context.Response.WriteAsJsonAsync(new { JobId = job.Id });
});
// Check the status of an encoding job by its ID
-app.MapGet("status/{jobId:guid}", (Guid jobId) =>
+app.MapGet("status/{jobId:guid}", (HttpContext context, Guid jobId) =>
{
- var job = JobQueue.FirstOrDefault(j => j.Id == jobId);
+ var encSrv = context.RequestServices.GetService();
+ if (encSrv == null) return Results.InternalServerError();
+
+ var job = encSrv.GetJobStatus(jobId);
if (job == null) {
return Results.NotFound(new { Message = "Job not found." });
}
@@ -51,44 +62,26 @@ app.MapGet("status/{jobId:guid}", (Guid jobId) =>
return Results.Ok(new {
JobId = job.Id,
Status = job.Status.ToString(),
- CreatedAt = job.CreatedAt,
- CompletedAt = job.CompletedAt
+ job.CreatedAt,
+ job.CompletedAt
});
});
-app.MapGet("file/{jobId:guid}", (Guid jobId) =>
+app.MapGet("file/{jobId:guid}", (HttpContext context, Guid jobId) =>
{
- var job = JobQueue.FirstOrDefault(j => j.Id == jobId);
- if (job == null) {
- return Results.NotFound(new { Message = "Job not found." });
- }
+ var encSrv = context.RequestServices.GetService();
+ if (encSrv == null) return Results.InternalServerError();
+
+ var job = encSrv.GetJobStatus(jobId);
+ if (job == null) return Results.NotFound(new { Message = "Job not found." });
- if (job.Status != JobStatus.Completed) {
- return Results.BadRequest(new { Message = "Job is not completed yet." });
- }
+ if (job.Status != JobStatus.Completed) return Results.BadRequest(new { Message = "Job is not completed yet." });
var filePath = job.EncodedFilePath;
- if (!File.Exists(filePath)) {
- return Results.NotFound(new { Message = "Encoded file not found." });
- }
+ if (!File.Exists(filePath)) return Results.NotFound(new { Message = "Encoded file not found." });
var fileBytes = File.ReadAllBytes(filePath);
return Results.File(fileBytes, "video/mp4", Path.GetFileName(filePath), enableRangeProcessing:true);
});
-app.Run();
-
-public enum JobStatus {
- Pending,
- InProgress,
- Completed,
- Failed
-}
-
-public record EncodingJob(Guid Id) {
- public JobStatus Status { get; set; } = JobStatus.Pending;
- public DateTime CreatedAt { get; init; } = DateTime.Now;
- public DateTime? CompletedAt { get; set; } = null;
- public string OrigFilePath { get; init; } = string.Empty;
- public string EncodedFilePath { get; set; } = string.Empty;
-}
\ No newline at end of file
+app.Run();
\ No newline at end of file
diff --git a/Encoder/appsettings.json b/Encoder/appsettings.json
index b2d2fe8..6fef078 100644
--- a/Encoder/appsettings.json
+++ b/Encoder/appsettings.json
@@ -6,5 +6,6 @@
}
},
"AllowedHosts": "*",
- "TemporaryFilesPath": "./Temp"
+ "TemporaryFilesPath": "./Temp",
+ "FfmpegPath": "./ffmpeg"
}