diff --git a/Shoko.Server/API/v3/Controllers/ImageController.cs b/Shoko.Server/API/v3/Controllers/ImageController.cs index 0fa38b474..a51c92068 100644 --- a/Shoko.Server/API/v3/Controllers/ImageController.cs +++ b/Shoko.Server/API/v3/Controllers/ImageController.cs @@ -42,7 +42,7 @@ public ActionResult GetImage([FromRoute] Image.ImageSource source, [FromRoute] I // Unrecognized combination of source, type and/or value. var dataSource = source.ToServer(); var imageEntityType = type.ToServer(); - if (imageEntityType == ImageEntityType.None || dataSource == DataSourceType.None) + if (dataSource == DataSourceType.None) return NotFound(ImageNotFound); // User avatars are stored in the database. diff --git a/Shoko.Server/Databases/DatabaseFixes.cs b/Shoko.Server/Databases/DatabaseFixes.cs index 8a15a8ca2..380e49326 100644 --- a/Shoko.Server/Databases/DatabaseFixes.cs +++ b/Shoko.Server/Databases/DatabaseFixes.cs @@ -13,6 +13,7 @@ using Shoko.Models.Enums; using Shoko.Models.Server; using Shoko.Plugin.Abstractions; +using Shoko.Plugin.Abstractions.Enums; using Shoko.Server.Filters.Legacy; using Shoko.Server.Models; using Shoko.Server.Models.CrossReference; @@ -895,4 +896,56 @@ public static void ScheduleTmdbImageUpdates() _logger.Info($"Done scheduling tmdb image updates for {movies} tmdb movies and {shows} tmdb shows."); } + + public static void MoveTmdbImagesOnDisc() + { + var imageDir = Path.Join(ImageUtils.GetBaseImagesPath(), "TMDB"); + if (!Directory.Exists(imageDir)) + return; + + var str = ServerState.Instance.ServerStartingStatus; + var imageTypes = Enum.GetValues(); + var total = 0; + foreach (var imageType in imageTypes) + { + var imageTypeDir = Path.Join(imageDir, imageType.ToString()); + if (!Directory.Exists(imageTypeDir)) + continue; + + var count = 0; + var files = Directory.GetFiles(imageTypeDir); + if (files.Length == 0) + continue; + + ServerState.Instance.ServerStartingStatus = $"{str} - 0 / {files.Length} {imageType} images"; + _logger.Info($"Moving TMDb {imageType} images on disc: {files.Length}"); + total += files.Length; + foreach (var file in files) + { + if (++count % 10 == 0 || count == files.Length) + { + _logger.Info($"Moving TMDb {imageType} images on disc... ({count}/{files.Length})"); + ServerState.Instance.ServerStartingStatus = $"{str} - {count} / {files.Length} {imageType} images"; + } + + var fileName = Path.GetFileName(file); + var folderName = fileName[..2]; + var newFile = Path.Combine(imageDir, folderName, fileName); + if (File.Exists(newFile)) + { + File.Delete(file); + continue; + } + + Directory.CreateDirectory(Path.Combine(imageDir, folderName)); + + File.Move(file, newFile); + } + + Directory.Delete(imageTypeDir); + } + + _logger.Info($"Moved {total} TMDb images on disc."); + ServerState.Instance.ServerStartingStatus = $"{str} - Moved {total} images"; + } } diff --git a/Shoko.Server/Databases/MySQL.cs b/Shoko.Server/Databases/MySQL.cs index 954758af1..3bbc1aac4 100644 --- a/Shoko.Server/Databases/MySQL.cs +++ b/Shoko.Server/Databases/MySQL.cs @@ -27,7 +27,7 @@ namespace Shoko.Server.Databases; public class MySQL : BaseDatabase { public override string Name { get; } = "MySQL"; - public override int RequiredVersion { get; } = 151; + public override int RequiredVersion { get; } = 152; private List createVersionTable = new() { @@ -940,6 +940,7 @@ public class MySQL : BaseDatabase new(150, 12, DatabaseFixes.ScheduleTmdbImageUpdates), new(151, 01, "ALTER TABLE `TMDB_Season` ADD COLUMN `PosterPath` VARCHAR(64) NULL DEFAULT NULL;"), new(151, 02, "ALTER TABLE `TMDB_Episode` ADD COLUMN `ThumbnailPath` VARCHAR(64) NULL DEFAULT NULL;"), + new(152, 01, DatabaseFixes.MoveTmdbImagesOnDisc), }; private DatabaseCommand linuxTableVersionsFix = new("RENAME TABLE versions TO Versions;"); diff --git a/Shoko.Server/Databases/SQLServer.cs b/Shoko.Server/Databases/SQLServer.cs index 29908db7c..c9bebe69a 100644 --- a/Shoko.Server/Databases/SQLServer.cs +++ b/Shoko.Server/Databases/SQLServer.cs @@ -28,7 +28,7 @@ namespace Shoko.Server.Databases; public class SQLServer : BaseDatabase { public override string Name { get; } = "SQLServer"; - public override int RequiredVersion { get; } = 143; + public override int RequiredVersion { get; } = 144; public override void BackupDatabase(string fullfilename) { @@ -892,6 +892,7 @@ public override bool HasVersionsTable() new DatabaseCommand(142, 12, DatabaseFixes.ScheduleTmdbImageUpdates), new DatabaseCommand(143, 01, "ALTER TABLE TMDB_Season ADD PosterPath NVARCHAR(64) NULL DEFAULT NULL;"), new DatabaseCommand(143, 02, "ALTER TABLE TMDB_Episode ADD ThumbnailPath NVARCHAR(64) NULL DEFAULT NULL;"), + new DatabaseCommand(144, 01, DatabaseFixes.MoveTmdbImagesOnDisc), }; private static void AlterImdbMovieIDType() diff --git a/Shoko.Server/Databases/SQLite.cs b/Shoko.Server/Databases/SQLite.cs index 32202f112..cc8da3253 100644 --- a/Shoko.Server/Databases/SQLite.cs +++ b/Shoko.Server/Databases/SQLite.cs @@ -28,7 +28,7 @@ public class SQLite : BaseDatabase { public override string Name => "SQLite"; - public override int RequiredVersion => 133; + public override int RequiredVersion => 134; public override void BackupDatabase(string fullfilename) { @@ -859,6 +859,7 @@ public override void CreateDatabase() new(132, 12, DatabaseFixes.ScheduleTmdbImageUpdates), new(133, 01, "ALTER TABLE TMDB_Season ADD COLUMN PosterPath TEXT NULL DEFAULT NULL;"), new(133, 02, "ALTER TABLE TMDB_Episode ADD COLUMN ThumbnailPath TEXT NULL DEFAULT NULL;"), + new(134, 01, DatabaseFixes.MoveTmdbImagesOnDisc), }; private static Tuple MigrateRenamers(object connection) diff --git a/Shoko.Server/Models/TMDB/TMDB_Image.cs b/Shoko.Server/Models/TMDB/TMDB_Image.cs index a8713d89d..ab1d12c4d 100644 --- a/Shoko.Server/Models/TMDB/TMDB_Image.cs +++ b/Shoko.Server/Models/TMDB/TMDB_Image.cs @@ -42,7 +42,7 @@ public override string? RemoteURL /// Relative path to the image stored locally. /// public string? RelativePath - => string.IsNullOrEmpty(RemoteFileName) ? null : Path.Join("TMDB", ImageType.ToString(), RemoteImageName); + => string.IsNullOrEmpty(RemoteFileName) ? null : Path.Join("TMDB", RemoteFileName[1..3], RemoteImageName); /// public override string? LocalPath @@ -73,6 +73,9 @@ public TMDB_Image() : base(DataSourceEnum.TMDB, ImageEntityType.None, 0) { } public TMDB_Image(string filePath, ImageEntityType type = ImageEntityType.None) : base(DataSourceEnum.TMDB, type, 0) { RemoteFileName = filePath?.Trim() ?? string.Empty; + if (!string.IsNullOrEmpty(RemoteFileName) && RemoteFileName[0] != '/') + RemoteFileName = '/' + RemoteFileName; + IsEnabled = true; }