1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
using HyperBooru.Services;
using HyperBooru.Util;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace HyperBooru.Controllers;
[ApiController]
[Route("/media")]
public class MediaController : Controller {
private IHttpContextAccessor httpContextAccessor;
private IMediaService mediaService;
private IConfigService config;
private HBContext db;
private readonly string[] FormatPriority = [
"image/webp",
"image/png"
];
public MediaController(
IHttpContextAccessor httpContextAccessor,
IMediaService mediaService,
IConfigService config,
HBContext db) {
this.httpContextAccessor = httpContextAccessor;
this.mediaService = mediaService;
this.config = config;
this.db = db;
}
[HttpGet("{mediaId}")]
public IActionResult Fetch([FromRoute] Guid mediaId) {
var media = db.Media
.Include(m => m.CurrentUploadedFile)
.First(m => m.Guid == mediaId);
if(media is null)
return NotFound();
// Check if the requested media item is a HEIC image and if it is, convert it
// otherwise, return the original file content, unaltered
if(media.CurrentUploadedFile!.MimeType == "image/heic") {
// If the media needs to be converted, check the HTTP request for allowed
// media formats, and convert to the best available format or WebP otherwise
var allowedTypes = httpContextAccessor
.HttpContext?
.Request
.GetTypedHeaders().Accept.Select(h => h.MediaType.ToString()) ?? Array.Empty<string>();
var format = FormatPriority.FirstOrDefault(f => allowedTypes.Contains(f)) ?? "image/webp";
var fs = mediaService.GetConverted(media, format);
return new FileStreamResult(fs, format);
} else {
var fs = System.IO.File.OpenRead(mediaService.GetPath(media));
return new FileStreamResult(fs, media.CurrentUploadedFile!.MimeType);
}
}
[HttpGet("thumb/{mediaId}")]
public IActionResult Thumbnail(
[FromRoute] Guid mediaId,
[FromQuery(Name = "w")] int? width,
[FromQuery(Name = "h")] int? height) {
try {
var thumb = mediaService.GetThumbnail(mediaId, width, height);
return new FileStreamResult(thumb, "image/jpeg");
} catch(ThumbnailException e) {
return BadRequest(e.Message);
} catch(ObjectNotFoundException e) {
return NotFound(e.Message);
}
}
[HttpDelete("{mediaId}")]
public void Delete([FromRoute] Guid mediaId) {
mediaService.Delete(mediaId);
}
[HttpPost]
public IActionResult Upload() {
if(Request.Form.Files.Count == 0)
return BadRequest("No files");
Media media = new();
foreach(var formFile in Request.Form.Files) {
try {
// Parse timestamps from headers
DateTime? lastAccessTime =
formFile.Headers["X-HyperBooru-LastAccessTime"]
.ElementAtOrDefault(0)?
.TryParseDateTimeUtc();
DateTime? lastWriteTime =
formFile.Headers["X-HyperBooru-LastWriteTime"]
.ElementAtOrDefault(0)?
.TryParseDateTimeUtc();
DateTime? createTime =
formFile.Headers["X-HyperBooru-CreateTime"]
.ElementAtOrDefault(0)?
.TryParseDateTimeUtc();
// Parse original path from headers
string? path =
formFile.Headers["X-HyperBooru-Path"]
.ElementAtOrDefault(0);
object? pathType = null;
string? pathTypeString =
formFile.Headers["X-HyperBooru-PathType"]
.ElementAtOrDefault(0);
Enum.TryParse(typeof(PathType), pathTypeString, true, out pathType);
// Parse tag IDs from headers
Guid[]? tagIds = formFile.Headers["X-HyperBooru-Tags"]
.ElementAtOrDefault(0)?
.Split(',')
.Select(t => Guid.Parse(t))
.ToArray();
media = mediaService.Create(
formFile.OpenReadStream(),
formFile.FileName,
formFile.Headers["X-HyperBooru-Checksum"]
.ElementAtOrDefault(0),
lastAccessTime,
lastWriteTime,
createTime,
path,
(PathType?) pathType,
tagIds);
// Return the GUID of the new media object if requested
bool returnMetadataParsed = bool.TryParse(
formFile.Headers["X-HyperBooru-ReturnMediaId"], out var returnMetadata);
if(returnMetadataParsed && returnMetadata)
return Content(media.Guid.ToString());
} catch(MediaCreateException e) {
return BadRequest(e.Message);
}
}
if(Request.Form.Files.Count == 1)
return Redirect($"/ViewMedia?m={media.Guid}");
else
return Redirect($"/Gallery");
}
}
|