summaryrefslogtreecommitdiff
path: root/Services/MediaService.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Services/MediaService.cs')
-rw-r--r--Services/MediaService.cs168
1 files changed, 167 insertions, 1 deletions
diff --git a/Services/MediaService.cs b/Services/MediaService.cs
index 1fc74cd..0ca2c1b 100644
--- a/Services/MediaService.cs
+++ b/Services/MediaService.cs
@@ -1,4 +1,7 @@
using Microsoft.EntityFrameworkCore;
+using MimeDetective;
+using MimeDetective.Definitions;
+using System.Security.Cryptography;
namespace HyperBooru.Services;
@@ -9,13 +12,43 @@ public interface IMediaService {
string? longDescription);
public void SetIngest(Media media, bool ingest);
+
+ public Media Create(
+ Stream fileData,
+ string fileName,
+ string? checksum = null,
+ DateTime? lastAccessTime = null,
+ DateTime? lastWriteTime = null,
+ DateTime? createTime = null);
+
+ public void Delete(Guid media);
+ public void Delete(Media media);
+ public string GetPath(Media media);
+ public string GetPath(Media media, int width, int height);
+
}
public class MediaService : IMediaService {
private IDbContextFactory<HBContext> dbFactory;
+ private IConfigService config;
+
+ private ContentInspector inspector;
+
+ public MediaService(IDbContextFactory<HBContext> dbFactory,
+ IConfigService config) {
- public MediaService(IDbContextFactory<HBContext> dbFactory) =>
this.dbFactory = dbFactory;
+ this.config = config;
+
+ ContentInspectorBuilder inspectorBuilder = new() {
+ Definitions =
+ Default.FileTypes.Images.All()
+ .Union(Default.FileTypes.Video.All())
+ .ToList()
+ };
+
+ inspector = inspectorBuilder.Build();
+ }
public void SetIngest(Media media, bool ingest) {
using var db = dbFactory.CreateDbContext();
@@ -54,4 +87,137 @@ public class MediaService : IMediaService {
db.SaveChanges();
}
+
+ public Media Create(
+ Stream fileData,
+ string fileName,
+ string? checksum = null,
+ DateTime? lastAccessTime = null,
+ DateTime? lastWriteTime = null,
+ DateTime? createTime = null) {
+
+ using var db = dbFactory.CreateDbContext();
+ using var transaction = db.Database.BeginTransaction();
+
+ if(fileData.Length == 0)
+ throw new MediaCreateException("File is empty");
+
+ // Calculate the checksum using the in-memory file contents
+ var hash = BitConverter
+ .ToString(MD5.Create().ComputeHash(fileData))
+ .Replace("-", "")
+ .ToLower();
+
+ if(checksum is not null && hash != checksum.ToLower())
+ throw new MediaCreateException("Checksum does not match");
+
+ var fileRecord = new UploadedFile() {
+ Filename = fileName,
+ OriginalChecksum = hash,
+ UploadTime = DateTime.UtcNow,
+ LastAccessTime = lastAccessTime,
+ LastWriteTime = lastWriteTime,
+ CreateTime = createTime
+ };
+
+ fileData.Seek(0, SeekOrigin.Begin);
+ var defs = inspector.Inspect(fileData);
+
+ var mime = defs.ByMimeType().FirstOrDefault()?.MimeType;
+ if(mime is null)
+ throw new MediaCreateException("Unsupported file type");
+
+ var media = db.Media
+ .FirstOrDefault(m => m.Checksum == hash);
+
+ if(media is null) {
+ var ingestTagDef = db.TagDefinitions
+ .First(td => td.Guid == HBContext.IngestTag);
+
+ media = new() {
+ Checksum = hash,
+ MimeType = mime,
+ UploadedFiles = new() {
+ fileRecord
+ },
+ Tags = new() {
+ new() { TagDefinition = ingestTagDef }
+ }
+ };
+
+ using var newFile = System.IO.File.Create(GetPath(media));
+
+ fileData.Seek(0, SeekOrigin.Begin);
+ fileData.CopyTo(newFile);
+ newFile.Flush();
+
+ db.Media.Add(media);
+ } else {
+ media.UploadedFiles.Add(fileRecord);
+ db.Update(media);
+ }
+
+ db.SaveChanges();
+ transaction.Commit();
+
+ return media;
+ }
+
+ public void Delete(Guid media) {
+ using var db = dbFactory.CreateDbContext();
+ var m = db.Media.First(m => m.Guid == media);
+
+ try {
+ System.IO.File.Delete(
+ Path.Join(
+ config.MediaBasePath,
+ m.Guid.ToString().Substring(0, 2),
+ m.Guid.ToString().Substring(2, 2),
+ m.Guid.ToString()));
+ } catch(IOException) {}
+
+ try {
+ System.IO.Directory.Delete(
+ Path.Join(
+ config.MediaBasePath,
+ m.Guid.ToString().Substring(0, 2),
+ m.Guid.ToString().Substring(2, 2)));
+ } catch(IOException) {}
+
+ try {
+ System.IO.Directory.Delete(
+ Path.Join(
+ config.MediaBasePath,
+ m.Guid.ToString().Substring(0, 2)));
+ } catch(IOException) {}
+
+ db.Media.Remove(m);
+ db.SaveChanges();
+ }
+
+ public void Delete(Media media) =>
+ Delete(media.Guid);
+
+ public string GetPath(Media media) {
+ var fileInfo = new FileInfo(
+ Path.Join(
+ config.MediaBasePath,
+ media.Guid.ToString().Substring(0, 2),
+ media.Guid.ToString().Substring(2, 2),
+ media.Guid.ToString()));
+
+ Directory.CreateDirectory(fileInfo.Directory.FullName);
+ return fileInfo.FullName;
+ }
+
+ public string GetPath(Media media, int width, int height) {
+ var fileInfo = new FileInfo(Path.Join(
+ config.ThumbnailBasePath,
+ media.Guid.ToString().Substring(0, 2),
+ media.Guid.ToString().Substring(2, 2),
+ $"{media.Guid.ToString()}-{width}-{height}"));
+
+ Directory.CreateDirectory(fileInfo.Directory.FullName);
+ return fileInfo.FullName;
+ }
}