diff options
Diffstat (limited to 'MediaController.cs')
| -rw-r--r-- | MediaController.cs | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/MediaController.cs b/MediaController.cs new file mode 100644 index 0000000..29a8f88 --- /dev/null +++ b/MediaController.cs @@ -0,0 +1,194 @@ +using HyperBooru.ApiRecords; +using ImageMagick; +using Microsoft.AspNetCore.Mvc; +using MimeDetective; +using System.Security.Cryptography; + +namespace HyperBooru; + +[ApiController] +[Route("/media")] +public class MediaController : Controller { + private IConfigService config; + private HyperBooruDbContext db; + + private ContentInspector inspector; + + public MediaController(IConfigService config, HyperBooruDbContext 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(); + } + + [HttpGet("{mediaId}/info")] + public IActionResult GetInfo([FromRoute] Guid mediaId) { + var media = db.Media.First(m => m.Guid == mediaId); + if(media is null) + return NotFound(); + + return Ok(new MediaInfo(media)); + } + + [HttpPatch("{mediaId}/info")] + public IActionResult UpdateInfo( + [FromRoute] Guid mediaId, + [FromBody] MediaUpdateInfo updateInfo) { + + var media = db.Media.First(m => m.Guid == mediaId); + if(media is null) + return NotFound(); + + if(updateInfo.ShortDescription is not null) + media.ShortDescription = updateInfo.ShortDescription; + if(updateInfo.LongDescription is not null) + media.LongDescription = updateInfo.LongDescription; + + db.Update(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 DbUploadedFile() { + 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) { + media = new() { + Checksum = hash, + MimeType = mime, + UploadedFiles = new() { + fileRecord + } + }; + + 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 |
