summaryrefslogtreecommitdiff
path: root/Controllers/MediaController.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Controllers/MediaController.cs')
-rw-r--r--Controllers/MediaController.cs170
1 files changed, 170 insertions, 0 deletions
diff --git a/Controllers/MediaController.cs b/Controllers/MediaController.cs
new file mode 100644
index 0000000..3f36064
--- /dev/null
+++ b/Controllers/MediaController.cs
@@ -0,0 +1,170 @@
+using HyperBooru.Services;
+using ImageMagick;
+using Microsoft.AspNetCore.Mvc;
+using MimeDetective;
+using System.Security.Cryptography;
+
+namespace HyperBooru.Controllers;
+
+[ApiController]
+[Route("/media")]
+public class MediaController : Controller {
+ private IConfigService config;
+ private HBContext db;
+
+ private ContentInspector inspector;
+
+ public MediaController(IConfigService config, HBContext db) {
+ this.config = config;
+ this.db = db;
+
+ ContentInspectorBuilder inspectorBuilder = new() {
+ Definitions =
+ MimeDetective.Definitions.Default.FileTypes.Images.All()
+ .Union(MimeDetective.Definitions.Default.FileTypes.Video.All())
+ .ToList()
+ };
+
+ inspector = inspectorBuilder.Build();
+ }
+
+ [HttpGet("list")]
+ public IActionResult EnumerateMedia() =>
+ Ok(db.Media.Select(m => m.ObjectId).ToArray());
+
+ [HttpGet("{mediaId}")]
+ public IActionResult Fetch([FromRoute] Guid mediaId) {
+ var media = db.Media.First(m => m.Guid == mediaId);
+ if(media is null)
+ return NotFound();
+
+ var fs = System.IO.File.OpenRead(config.GetPath(media));
+
+ return new FileStreamResult(fs, media.MimeType);
+ }
+
+ [HttpGet("thumb/{mediaId}")]
+ public IActionResult Thumbnail(
+ [FromRoute] Guid mediaId,
+ [FromQuery] int? w,
+ [FromQuery] int? h) {
+
+ var media = db.Media.First(m => m.Guid == mediaId);
+ if(media is null)
+ return NotFound();
+
+ if(media.MimeType.Split("/")[0] != "image")
+ return BadRequest("Media object not an image");
+
+ using var image = new MagickImage(config.GetPath(media));
+
+ if(w is null && h is null)
+ return BadRequest("Both width and height cannot be null!");
+
+ if(w > image.Width || h > image.Height)
+ return BadRequest("Requested thumbnail size is larger than original media");
+
+ int width = (int)(w is not null ? w : image.Width * h / image.Height);
+ int height = (int)(h is not null ? h : image.Height * w / image.Width);
+
+ var thumbPath = config.GetPath(media, width, height);
+
+ if(!System.IO.File.Exists(thumbPath)) {
+ image.Resize(new MagickGeometry(width, height));
+ image.Write(thumbPath);
+ }
+
+ var fs = System.IO.File.OpenRead(thumbPath);
+
+ return new FileStreamResult(fs, "image/jpeg");
+ }
+
+ [HttpDelete("{mediaId}")]
+ public IActionResult Delete([FromRoute] Guid mediaId) {
+ var media = db.Media.First(m => m.Guid == mediaId);
+ if(media is null)
+ return NotFound();
+
+ System.IO.File.Delete(config.GetPath(media));
+
+ db.Media.Remove(media);
+ db.SaveChanges();
+ return Ok();
+ }
+
+ [HttpPost]
+ public IActionResult Upload(
+ [FromForm] string? checksum,
+ [FromForm] DateTime? lastAccessTime,
+ [FromForm] DateTime? lastWriteTime,
+ [FromForm] DateTime? createTime) {
+
+ using var transaction = db.Database.BeginTransaction();
+
+ var formFile = Request.Form.Files[0];
+ if(formFile.Length < 1)
+ return BadRequest("Empty file");
+
+ var formStream = formFile.OpenReadStream();
+
+ // Calculate the checksum using the in-memory file contents
+ var hash = BitConverter
+ .ToString(MD5.Create().ComputeHash(formStream))
+ .Replace("-", "")
+ .ToLower();
+
+ if(checksum is not null && hash != checksum.ToLower())
+ return BadRequest("Checksum does not match");
+
+ var fileRecord = new UploadedFile() {
+ Filename = formFile.FileName,
+ OriginalChecksum = hash,
+ UploadTime = DateTime.Now,
+ LastAccessTime = lastAccessTime,
+ LastWriteTime = lastWriteTime,
+ CreateTime = createTime
+ };
+
+ formStream.Seek(0, SeekOrigin.Begin);
+ var defs = inspector.Inspect(formStream);
+
+ var mime = defs.ByMimeType().FirstOrDefault()?.MimeType;
+ if(mime is null)
+ return BadRequest("Unsupported file type");
+
+ var media = db.Media
+ .FirstOrDefault(m => m.Checksum == hash);
+
+ if(media is null) {
+ var ingestTagDef = db.TagDefinitions
+ .First(td => td.Source == TagSource.Internal && td.Name == "ingest");
+
+ media = new() {
+ Checksum = hash,
+ MimeType = mime,
+ UploadedFiles = new() {
+ fileRecord
+ },
+ Tags = new() {
+ new() { TagDefinition = ingestTagDef }
+ }
+ };
+
+ using var newFile = System.IO.File.Create(config.GetPath(media));
+
+ formStream.Seek(0, SeekOrigin.Begin);
+ formStream.CopyTo(newFile);
+ newFile.Flush();
+
+ db.Media.Add(media);
+ } else {
+ media.UploadedFiles.Add(fileRecord);
+ db.Update(media);
+ }
+
+ db.SaveChanges();
+ transaction.Commit();
+
+ return Ok(media.Guid);
+ }
+} \ No newline at end of file