summaryrefslogtreecommitdiff
path: root/Services
diff options
context:
space:
mode:
authorJake Mannens <jake@asger.xyz>2023-08-25 11:11:38 +1000
committerJake Mannens <jake@asger.xyz>2025-08-20 00:48:36 +1000
commita26e9b6a628cfd311b08e1c4d2bf612d9af9bb7c (patch)
tree03302cce70acfd7c79703d2b3676c1b1f5ea1473 /Services
parent9a99c6859c2e740e1b6afe3c8c1020343a848197 (diff)
Moved media controller upload functionality into media service
Multiple uploads can now be handled
Diffstat (limited to 'Services')
-rw-r--r--Services/ConfigService.cs29
-rw-r--r--Services/MediaService.cs169
2 files changed, 171 insertions, 27 deletions
diff --git a/Services/ConfigService.cs b/Services/ConfigService.cs
index 814a47b..b42b80c 100644
--- a/Services/ConfigService.cs
+++ b/Services/ConfigService.cs
@@ -4,9 +4,7 @@ public interface IConfigService {
public string DataPath { get; }
public string DbConnectionString { get; }
public string MediaBasePath { get; }
-
- public string GetPath(Media media);
- public string GetPath(Media media, int width, int height);
+ public string ThumbnailBasePath { get; }
}
public class ConfigService : IConfigService {
@@ -39,7 +37,8 @@ public class ConfigService : IConfigService {
}
public string DbConnectionString =>
- config.GetConnectionString("DefaultConnection");
+ config.GetConnectionString("DefaultConnection") ??
+ throw new HBException("Unable to get default connection string");
public string MediaBasePath =>
Path.Join(DataPath, "media");
@@ -52,28 +51,6 @@ public class ConfigService : IConfigService {
InitDirectoryStructure();
}
- public string GetPath(Media media) {
- var fileInfo = new FileInfo(Path.Join(
- 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(
- 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;
- }
-
private void InitDirectoryStructure() {
Directory.CreateDirectory(DataPath);
Directory.CreateDirectory(MediaBasePath);
diff --git a/Services/MediaService.cs b/Services/MediaService.cs
index 2f84b27..460e0c7 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();
@@ -57,4 +90,138 @@ 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() {
+ 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);
+ db.SaveChanges();
+ media.CurrentUploadedFile = fileRecord;
+ db.SaveChanges();
+ } 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;
+ }
}