using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using MediaBrowser.Common.Configuration;
namespace Jellyfin.Plugin.MediaBarEnhanced.Api
{
///
/// Controller for handling custom overlay image uploads and retrieval.
///
[ApiController]
[Route("MediaBarEnhanced")]
public class OverlayImageController : ControllerBase
{
private readonly IApplicationPaths _applicationPaths;
private readonly string _imageDirectory;
private readonly string _imagePath;
public OverlayImageController(IApplicationPaths applicationPaths)
{
_applicationPaths = applicationPaths;
// We use the plugin's data folder to store the image
_imageDirectory = MediaBarEnhancedPlugin.Instance?.DataFolderPath ?? Path.Combine(applicationPaths.DataPath, "plugins", "MediaBarEnhanced");
// We'll just overwrite this single file each time
_imagePath = Path.Combine(_imageDirectory, "custom_overlay_image.dat");
}
///
/// Uploads a new custom overlay image.
///
[HttpPost("OverlayImage")]
[Consumes("multipart/form-data")]
public async Task UploadImage([FromForm] IFormFile file)
{
if (file == null || file.Length == 0)
{
return BadRequest("No file uploaded.");
}
try
{
if (!Directory.Exists(_imageDirectory))
{
Directory.CreateDirectory(_imageDirectory);
}
// Delete is not strictly necessary and can cause locking issues if someone is currently reading it.
// FileMode.Create will truncate the file if it exists, effectively overwriting it.
// We use FileShare.None to ensure we have exclusive write access, but handle potential IOExceptions gracefully.
using (var stream = new FileStream(_imagePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
await file.CopyToAsync(stream).ConfigureAwait(false);
}
// Return the GET URL that the frontend can use
var getUrl = "/MediaBarEnhanced/OverlayImage?t=" + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
return Ok(new { url = getUrl });
}
catch (Exception ex)
{
return StatusCode(500, $"Internal server error: {ex.Message}");
}
}
///
/// Retrieves the custom overlay image.
///
[HttpGet("OverlayImage")]
public IActionResult GetImage()
{
if (!System.IO.File.Exists(_imagePath))
{
return NotFound();
}
// Read the file and return as a generic octet stream.
// We use FileShare.ReadWrite so that if someone is currently overwriting the file (uploading), we don't block them,
// and we also don't get blocked by other readers.
var stream = new FileStream(_imagePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
// "image/*" works reliably as browsers will sniff the exact image mime type (jpeg, png, webp).
return File(stream, "image/*");
}
}
}