diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index 844a6a5ce..1cb9a24fb 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -1141,17 +1141,17 @@ namespace Emby.Dlna.Didl int? width = null; int? height = null; - try - { - var size = _imageProcessor.GetImageSize(imageInfo); + //try + //{ + // var size = _imageProcessor.GetImageSize(imageInfo); - width = Convert.ToInt32(size.Width); - height = Convert.ToInt32(size.Height); - } - catch - { + // width = Convert.ToInt32(size.Width); + // height = Convert.ToInt32(size.Height); + //} + //catch + //{ - } + //} var inputFormat = (Path.GetExtension(imageInfo.Path) ?? string.Empty) .TrimStart('.') diff --git a/Emby.Drawing.ImageMagick/ImageMagickEncoder.cs b/Emby.Drawing.ImageMagick/ImageMagickEncoder.cs index 2c40bf570..24895b483 100644 --- a/Emby.Drawing.ImageMagick/ImageMagickEncoder.cs +++ b/Emby.Drawing.ImageMagick/ImageMagickEncoder.cs @@ -148,7 +148,6 @@ namespace Emby.Drawing.ImageMagick } var originalImageSize = new ImageSize(originalImage.CurrentImage.Width, originalImage.CurrentImage.Height); - ImageHelper.SaveImageSize(inputPath, dateModified, originalImageSize); if (!options.CropWhiteSpace && options.HasDefaultOptions(inputPath, originalImageSize)) { @@ -182,7 +181,6 @@ namespace Emby.Drawing.ImageMagick using (var originalImage = new MagickWand(inputPath)) { var originalImageSize = new ImageSize(originalImage.CurrentImage.Width, originalImage.CurrentImage.Height); - ImageHelper.SaveImageSize(inputPath, dateModified, originalImageSize); var newImageSize = ImageHelper.GetNewImageSize(options, originalImageSize); diff --git a/Emby.Drawing.Skia/SkiaEncoder.cs b/Emby.Drawing.Skia/SkiaEncoder.cs index eb0602afe..e8cdd441a 100644 --- a/Emby.Drawing.Skia/SkiaEncoder.cs +++ b/Emby.Drawing.Skia/SkiaEncoder.cs @@ -40,7 +40,9 @@ namespace Emby.Drawing.Skia "jpeg", "jpg", "png", + "dng", + "webp", "gif", "bmp", @@ -459,7 +461,6 @@ namespace Emby.Drawing.Skia //_logger.Info("Color type {0}", bitmap.Info.ColorType); var originalImageSize = new ImageSize(bitmap.Width, bitmap.Height); - ImageHelper.SaveImageSize(inputPath, dateModified, originalImageSize); if (!options.CropWhiteSpace && options.HasDefaultOptions(inputPath, originalImageSize) && !autoOrient) { diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index f5a05db05..831454972 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -35,11 +35,6 @@ namespace Emby.Drawing /// protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); - /// - /// The _cached imaged sizes - /// - private readonly ConcurrentDictionary _cachedImagedSizes; - /// /// Gets the list of currently registered image processors /// Image processors are specialized metadata providers that run after the normal ones @@ -75,34 +70,7 @@ namespace Emby.Drawing _appPaths = appPaths; ImageEnhancers = new IImageEnhancer[] { }; - _saveImageSizeTimer = timerFactory.Create(SaveImageSizeCallback, null, Timeout.Infinite, Timeout.Infinite); ImageHelper.ImageProcessor = this; - - Dictionary sizeDictionary; - - try - { - sizeDictionary = jsonSerializer.DeserializeFromFile>(ImageSizeFile) ?? - new Dictionary(); - } - catch (FileNotFoundException) - { - // No biggie - sizeDictionary = new Dictionary(); - } - catch (IOException) - { - // No biggie - sizeDictionary = new Dictionary(); - } - catch (Exception ex) - { - logger.ErrorException("Error parsing image size cache file", ex); - - sizeDictionary = new Dictionary(); - } - - _cachedImagedSizes = new ConcurrentDictionary(sizeDictionary); } public IImageEncoder ImageEncoder @@ -133,7 +101,6 @@ namespace Emby.Drawing "aiff", "cr2", "crw", - "dng", // Remove until supported //"nef", @@ -275,15 +242,15 @@ namespace Emby.Drawing return new Tuple(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified); } - ImageSize? originalImageSize = GetSavedImageSize(originalImagePath, dateModified); - if (originalImageSize.HasValue && options.HasDefaultOptions(originalImagePath, originalImageSize.Value) && !autoOrient) - { - // Just spit out the original file if all the options are default - _logger.Info("Returning original image {0}", originalImagePath); - return new Tuple(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified); - } + //ImageSize? originalImageSize = GetSavedImageSize(originalImagePath, dateModified); + //if (originalImageSize.HasValue && options.HasDefaultOptions(originalImagePath, originalImageSize.Value) && !autoOrient) + //{ + // // Just spit out the original file if all the options are default + // _logger.Info("Returning original image {0}", originalImagePath); + // return new Tuple(originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified); + //} - var newSize = ImageHelper.GetNewImageSize(options, originalImageSize); + var newSize = ImageHelper.GetNewImageSize(options, null); var quality = options.Quality; var outputFormat = GetOutputFormat(options.SupportedOutputFormats, requiresTransparency); @@ -477,98 +444,30 @@ namespace Emby.Drawing public ImageSize GetImageSize(ItemImageInfo info, bool allowSlowMethods) { - return GetImageSize(info.Path, info.DateModified, allowSlowMethods); + return GetImageSize(info.Path, allowSlowMethods); } public ImageSize GetImageSize(ItemImageInfo info) { - return GetImageSize(info.Path, info.DateModified, false); + return GetImageSize(info.Path, false); } public ImageSize GetImageSize(string path) { - return GetImageSize(path, _fileSystem.GetLastWriteTimeUtc(path), false); + return GetImageSize(path, false); } /// /// Gets the size of the image. /// - /// The path. - /// The image date modified. - /// if set to true [allow slow method]. - /// ImageSize. - /// path - private ImageSize GetImageSize(string path, DateTime imageDateModified, bool allowSlowMethod) + private ImageSize GetImageSize(string path, bool allowSlowMethod) { if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException("path"); } - ImageSize size; - - var cacheHash = GetImageSizeKey(path, imageDateModified); - - if (!_cachedImagedSizes.TryGetValue(cacheHash, out size)) - { - size = GetImageSizeInternal(path, allowSlowMethod); - - SaveImageSize(size, cacheHash, false); - } - - return size; - } - - public void SaveImageSize(string path, DateTime imageDateModified, ImageSize size) - { - var cacheHash = GetImageSizeKey(path, imageDateModified); - SaveImageSize(size, cacheHash, true); - } - - private void SaveImageSize(ImageSize size, Guid cacheHash, bool checkExists) - { - if (size.Width <= 0 || size.Height <= 0) - { - return; - } - - if (checkExists && _cachedImagedSizes.ContainsKey(cacheHash)) - { - return; - } - - if (checkExists) - { - if (_cachedImagedSizes.TryAdd(cacheHash, size)) - { - StartSaveImageSizeTimer(); - } - } - else - { - StartSaveImageSizeTimer(); - _cachedImagedSizes.AddOrUpdate(cacheHash, size, (keyName, oldValue) => size); - } - } - - private Guid GetImageSizeKey(string path, DateTime imageDateModified) - { - var name = path + "datemodified=" + imageDateModified.Ticks; - return name.GetMD5(); - } - - public ImageSize? GetSavedImageSize(string path, DateTime imageDateModified) - { - ImageSize size; - - var cacheHash = GetImageSizeKey(path, imageDateModified); - - if (_cachedImagedSizes.TryGetValue(cacheHash, out size)) - { - return size; - } - - return null; + return GetImageSizeInternal(path, allowSlowMethod); } /// @@ -619,39 +518,6 @@ namespace Emby.Drawing } } - private readonly ITimer _saveImageSizeTimer; - private const int SaveImageSizeTimeout = 5000; - private readonly object _saveImageSizeLock = new object(); - private void StartSaveImageSizeTimer() - { - _saveImageSizeTimer.Change(SaveImageSizeTimeout, Timeout.Infinite); - } - - private void SaveImageSizeCallback(object state) - { - lock (_saveImageSizeLock) - { - try - { - var path = ImageSizeFile; - _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(path)); - _jsonSerializer.SerializeToFile(_cachedImagedSizes, path); - } - catch (Exception ex) - { - _logger.ErrorException("Error saving image size file", ex); - } - } - } - - private string ImageSizeFile - { - get - { - return Path.Combine(_appPaths.DataPath, "imagesizes.json"); - } - } - /// /// Gets the image cache tag. /// @@ -1016,7 +882,6 @@ namespace Emby.Drawing disposable.Dispose(); } - _saveImageSizeTimer.Dispose(); GC.SuppressFinalize(this); } diff --git a/Emby.Photos/PhotoProvider.cs b/Emby.Photos/PhotoProvider.cs index c3c30ab6d..fe77cff69 100644 --- a/Emby.Photos/PhotoProvider.cs +++ b/Emby.Photos/PhotoProvider.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; @@ -20,134 +21,152 @@ namespace Emby.Photos { private readonly ILogger _logger; private readonly IFileSystem _fileSystem; + private IImageProcessor _imageProcessor; - public PhotoProvider(ILogger logger, IFileSystem fileSystem) + public PhotoProvider(ILogger logger, IFileSystem fileSystem, IImageProcessor imageProcessor) { _logger = logger; _fileSystem = fileSystem; + _imageProcessor = imageProcessor; } + // These are causing taglib to hang + private string[] _excludeExtensions = new string[] { ".dng" }; + public Task FetchAsync(Photo item, MetadataRefreshOptions options, CancellationToken cancellationToken) { item.SetImagePath(ImageType.Primary, item.Path); // Examples: https://github.com/mono/taglib-sharp/blob/a5f6949a53d09ce63ee7495580d6802921a21f14/tests/fixtures/TagLib.Tests.Images/NullOrientationTest.cs - - try + if (!_excludeExtensions.Contains(Path.GetExtension(item.Path) ?? string.Empty, StringComparer.OrdinalIgnoreCase)) { - using (var fileStream = _fileSystem.OpenRead(item.Path)) + try { - using (var file = TagLib.File.Create(new StreamFileAbstraction(Path.GetFileName(item.Path), fileStream, null))) + using (var fileStream = _fileSystem.OpenRead(item.Path)) { - var image = file as TagLib.Image.File; - - var tag = file.GetTag(TagTypes.TiffIFD) as IFDTag; - - if (tag != null) + using (var file = TagLib.File.Create(new StreamFileAbstraction(Path.GetFileName(item.Path), fileStream, null))) { - var structure = tag.Structure; + var image = file as TagLib.Image.File; - if (structure != null) + var tag = file.GetTag(TagTypes.TiffIFD) as IFDTag; + + if (tag != null) { - var exif = structure.GetEntry(0, (ushort)IFDEntryTag.ExifIFD) as SubIFDEntry; + var structure = tag.Structure; - if (exif != null) + if (structure != null) { - var exifStructure = exif.Structure; + var exif = structure.GetEntry(0, (ushort)IFDEntryTag.ExifIFD) as SubIFDEntry; - if (exifStructure != null) + if (exif != null) { - var entry = exifStructure.GetEntry(0, (ushort)ExifEntryTag.ApertureValue) as RationalIFDEntry; + var exifStructure = exif.Structure; - if (entry != null) + if (exifStructure != null) { - double val = entry.Value.Numerator; - val /= entry.Value.Denominator; - item.Aperture = val; - } + var entry = exifStructure.GetEntry(0, (ushort)ExifEntryTag.ApertureValue) as RationalIFDEntry; - entry = exifStructure.GetEntry(0, (ushort)ExifEntryTag.ShutterSpeedValue) as RationalIFDEntry; + if (entry != null) + { + double val = entry.Value.Numerator; + val /= entry.Value.Denominator; + item.Aperture = val; + } - if (entry != null) - { - double val = entry.Value.Numerator; - val /= entry.Value.Denominator; - item.ShutterSpeed = val; + entry = exifStructure.GetEntry(0, (ushort)ExifEntryTag.ShutterSpeedValue) as RationalIFDEntry; + + if (entry != null) + { + double val = entry.Value.Numerator; + val /= entry.Value.Denominator; + item.ShutterSpeed = val; + } } } } } - } - item.CameraMake = image.ImageTag.Make; - item.CameraModel = image.ImageTag.Model; - - item.Width = image.Properties.PhotoWidth; - item.Height = image.Properties.PhotoHeight; - - var rating = image.ImageTag.Rating; - if (rating.HasValue) - { - item.CommunityRating = rating; - } - else - { - item.CommunityRating = null; - } - - item.Overview = image.ImageTag.Comment; - - if (!string.IsNullOrWhiteSpace(image.ImageTag.Title)) - { - item.Name = image.ImageTag.Title; - } - - var dateTaken = image.ImageTag.DateTime; - if (dateTaken.HasValue) - { - item.DateCreated = dateTaken.Value; - item.PremiereDate = dateTaken.Value; - item.ProductionYear = dateTaken.Value.Year; - } - - item.Genres = image.ImageTag.Genres.ToList(); - item.Tags = image.ImageTag.Keywords; - item.Software = image.ImageTag.Software; - - if (image.ImageTag.Orientation == TagLib.Image.ImageOrientation.None) - { - item.Orientation = null; - } - else - { - MediaBrowser.Model.Drawing.ImageOrientation orientation; - if (Enum.TryParse(image.ImageTag.Orientation.ToString(), true, out orientation)) + if (image != null) { - item.Orientation = orientation; + item.CameraMake = image.ImageTag.Make; + item.CameraModel = image.ImageTag.Model; + + item.Width = image.Properties.PhotoWidth; + item.Height = image.Properties.PhotoHeight; + + var rating = image.ImageTag.Rating; + if (rating.HasValue) + { + item.CommunityRating = rating; + } + else + { + item.CommunityRating = null; + } + + item.Overview = image.ImageTag.Comment; + + if (!string.IsNullOrWhiteSpace(image.ImageTag.Title)) + { + item.Name = image.ImageTag.Title; + } + + var dateTaken = image.ImageTag.DateTime; + if (dateTaken.HasValue) + { + item.DateCreated = dateTaken.Value; + item.PremiereDate = dateTaken.Value; + item.ProductionYear = dateTaken.Value.Year; + } + + item.Genres = image.ImageTag.Genres.ToList(); + item.Tags = image.ImageTag.Keywords; + item.Software = image.ImageTag.Software; + + if (image.ImageTag.Orientation == TagLib.Image.ImageOrientation.None) + { + item.Orientation = null; + } + else + { + MediaBrowser.Model.Drawing.ImageOrientation orientation; + if (Enum.TryParse(image.ImageTag.Orientation.ToString(), true, out orientation)) + { + item.Orientation = orientation; + } + } + + item.ExposureTime = image.ImageTag.ExposureTime; + item.FocalLength = image.ImageTag.FocalLength; + + item.Latitude = image.ImageTag.Latitude; + item.Longitude = image.ImageTag.Longitude; + item.Altitude = image.ImageTag.Altitude; + + if (image.ImageTag.ISOSpeedRatings.HasValue) + { + item.IsoSpeedRating = Convert.ToInt32(image.ImageTag.ISOSpeedRatings.Value); + } + else + { + item.IsoSpeedRating = null; + } } } - - item.ExposureTime = image.ImageTag.ExposureTime; - item.FocalLength = image.ImageTag.FocalLength; - - item.Latitude = image.ImageTag.Latitude; - item.Longitude = image.ImageTag.Longitude; - item.Altitude = image.ImageTag.Altitude; - - if (image.ImageTag.ISOSpeedRatings.HasValue) - { - item.IsoSpeedRating = Convert.ToInt32(image.ImageTag.ISOSpeedRatings.Value); - } - else - { - item.IsoSpeedRating = null; - } } } + catch (Exception e) + { + _logger.ErrorException("Image Provider - Error reading image tag for {0}", e, item.Path); + } } - catch (Exception e) + + if (!item.Width.HasValue || !item.Height.HasValue) { - _logger.ErrorException("Image Provider - Error reading image tag for {0}", e, item.Path); + var size = _imageProcessor.GetImageSize(item.Path); + + item.Width = Convert.ToInt32(size.Width); + item.Height = Convert.ToInt32(size.Height); } const ItemUpdateType result = ItemUpdateType.ImageUpdate | ItemUpdateType.MetadataImport; diff --git a/Emby.Server.Implementations/Activity/ActivityRepository.cs b/Emby.Server.Implementations/Activity/ActivityRepository.cs index 3dcc50ba3..1ae8e5e66 100644 --- a/Emby.Server.Implementations/Activity/ActivityRepository.cs +++ b/Emby.Server.Implementations/Activity/ActivityRepository.cs @@ -10,20 +10,39 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Model.Querying; using SQLitePCL.pretty; using MediaBrowser.Model.Extensions; +using MediaBrowser.Model.IO; namespace Emby.Server.Implementations.Activity { public class ActivityRepository : BaseSqliteRepository, IActivityRepository { private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + protected IFileSystem FileSystem { get; private set; } - public ActivityRepository(ILogger logger, IServerApplicationPaths appPaths) + public ActivityRepository(ILogger logger, IServerApplicationPaths appPaths, IFileSystem fileSystem) : base(logger) { DbFilePath = Path.Combine(appPaths.DataPath, "activitylog.db"); + FileSystem = fileSystem; } public void Initialize() + { + try + { + InitializeInternal(); + } + catch (Exception ex) + { + Logger.ErrorException("Error loading database file. Will reset and retry.", ex); + + FileSystem.DeleteFile(DbFilePath); + + InitializeInternal(); + } + } + + private void InitializeInternal() { using (var connection = CreateConnection()) { diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 47b969eca..ba43c7f35 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -879,7 +879,7 @@ namespace Emby.Server.Implementations // This is only needed for disposal purposes. If removing this, make sure to have the manager handle disposing it RegisterSingleInstance(UserRepository); - var displayPreferencesRepo = new SqliteDisplayPreferencesRepository(LogManager.GetLogger("SqliteDisplayPreferencesRepository"), JsonSerializer, ApplicationPaths, MemoryStreamFactory); + var displayPreferencesRepo = new SqliteDisplayPreferencesRepository(LogManager.GetLogger("SqliteDisplayPreferencesRepository"), JsonSerializer, ApplicationPaths, MemoryStreamFactory, FileSystemManager); DisplayPreferencesRepository = displayPreferencesRepo; RegisterSingleInstance(DisplayPreferencesRepository); @@ -997,7 +997,7 @@ namespace Emby.Server.Implementations EncodingManager = new EncodingManager(FileSystemManager, Logger, MediaEncoder, ChapterManager, LibraryManager); RegisterSingleInstance(EncodingManager); - var sharingRepo = new SharingRepository(LogManager.GetLogger("SharingRepository"), ApplicationPaths); + var sharingRepo = new SharingRepository(LogManager.GetLogger("SharingRepository"), ApplicationPaths, FileSystemManager); sharingRepo.Initialize(); // This is only needed for disposal purposes. If removing this, make sure to have the manager handle disposing it RegisterSingleInstance(sharingRepo); @@ -1351,7 +1351,7 @@ namespace Emby.Server.Implementations private IActivityRepository GetActivityLogRepository() { - var repo = new ActivityRepository(LogManager.GetLogger("ActivityRepository"), ServerConfigurationManager.ApplicationPaths); + var repo = new ActivityRepository(LogManager.GetLogger("ActivityRepository"), ServerConfigurationManager.ApplicationPaths, FileSystemManager); repo.Initialize(); diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index a34c90cb4..d207c8d4f 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -108,37 +108,49 @@ namespace Emby.Server.Implementations.Data var db = SQLite3.Open(DbFilePath, connectionFlags, null); - if (string.IsNullOrWhiteSpace(_defaultWal)) + try { - _defaultWal = db.Query("PRAGMA journal_mode").SelectScalarString().First(); + if (string.IsNullOrWhiteSpace(_defaultWal)) + { + _defaultWal = db.Query("PRAGMA journal_mode").SelectScalarString().First(); - Logger.Info("Default journal_mode for {0} is {1}", DbFilePath, _defaultWal); + Logger.Info("Default journal_mode for {0} is {1}", DbFilePath, _defaultWal); + } + + var queries = new List + { + //"PRAGMA cache size=-10000" + //"PRAGMA read_uncommitted = true", + "PRAGMA synchronous=Normal" + }; + + if (CacheSize.HasValue) + { + queries.Add("PRAGMA cache_size=" + CacheSize.Value.ToString(CultureInfo.InvariantCulture)); + } + + if (EnableTempStoreMemory) + { + queries.Add("PRAGMA temp_store = memory"); + } + else + { + queries.Add("PRAGMA temp_store = file"); + } + + foreach (var query in queries) + { + db.Execute(query); + } } + catch + { + using (db) + { - var queries = new List - { - //"PRAGMA cache size=-10000" - //"PRAGMA read_uncommitted = true", - "PRAGMA synchronous=Normal" - }; + } - if (CacheSize.HasValue) - { - queries.Add("PRAGMA cache_size=" + CacheSize.Value.ToString(CultureInfo.InvariantCulture)); - } - - if (EnableTempStoreMemory) - { - queries.Add("PRAGMA temp_store = memory"); - } - else - { - queries.Add("PRAGMA temp_store = file"); - } - - foreach (var query in queries) - { - db.Execute(query); + throw; } _connection = new ManagedConnection(db, false); @@ -265,29 +277,34 @@ namespace Emby.Server.Implementations.Data { if (dispose) { - try - { - lock (_disposeLock) - { - using (WriteLock.Write()) - { - if (_connection != null) - { - using (_connection) - { - - } - _connection = null; - } + DisposeConnection(); + } + } - CloseConnection(); + private void DisposeConnection() + { + try + { + lock (_disposeLock) + { + using (WriteLock.Write()) + { + if (_connection != null) + { + using (_connection) + { + _connection.Close(); + } + _connection = null; } + + CloseConnection(); } } - catch (Exception ex) - { - Logger.ErrorException("Error disposing database", ex); - } + } + catch (Exception ex) + { + Logger.ErrorException("Error disposing database", ex); } } diff --git a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs index 89664d158..1901ce848 100644 --- a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs @@ -19,12 +19,14 @@ namespace Emby.Server.Implementations.Data public class SqliteDisplayPreferencesRepository : BaseSqliteRepository, IDisplayPreferencesRepository { private readonly IMemoryStreamFactory _memoryStreamProvider; + protected IFileSystem FileSystem { get; private set; } - public SqliteDisplayPreferencesRepository(ILogger logger, IJsonSerializer jsonSerializer, IApplicationPaths appPaths, IMemoryStreamFactory memoryStreamProvider) + public SqliteDisplayPreferencesRepository(ILogger logger, IJsonSerializer jsonSerializer, IApplicationPaths appPaths, IMemoryStreamFactory memoryStreamProvider, IFileSystem fileSystem) : base(logger) { _jsonSerializer = jsonSerializer; _memoryStreamProvider = memoryStreamProvider; + FileSystem = fileSystem; DbFilePath = Path.Combine(appPaths.DataPath, "displaypreferences.db"); } @@ -45,11 +47,27 @@ namespace Emby.Server.Implementations.Data /// private readonly IJsonSerializer _jsonSerializer; + public void Initialize() + { + try + { + InitializeInternal(); + } + catch (Exception ex) + { + Logger.ErrorException("Error loading database file. Will reset and retry.", ex); + + FileSystem.DeleteFile(DbFilePath); + + InitializeInternal(); + } + } + /// /// Opens the connection to the database /// /// Task. - public void Initialize() + private void InitializeInternal() { using (var connection = CreateConnection()) { diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 89ffb0fce..987b1df39 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -120,13 +120,13 @@ namespace Emby.Server.Implementations.Data protected override void CloseConnection() { - base.CloseConnection(); - if (_shrinkMemoryTimer != null) { _shrinkMemoryTimer.Dispose(); _shrinkMemoryTimer = null; } + + base.CloseConnection(); } /// diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 1854829a2..5ef910e51 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -1642,6 +1642,8 @@ namespace Emby.Server.Implementations.Dto return null; } + _logger.Info("Getting image size for item type {0}", item.GetType().Name); + try { size = _imageProcessor.GetImageSize(imageInfo); @@ -1673,22 +1675,6 @@ namespace Emby.Server.Implementations.Dto return null; } - var photo = item as Photo; - if (photo != null && photo.Orientation.HasValue) - { - switch (photo.Orientation.Value) - { - case ImageOrientation.LeftBottom: - case ImageOrientation.LeftTop: - case ImageOrientation.RightBottom: - case ImageOrientation.RightTop: - var temp = height; - height = width; - width = temp; - break; - } - } - return width / height; } } diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index f5a1fe246..3e0565343 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -360,7 +360,7 @@ namespace Emby.Server.Implementations.HttpServer if (IsNotModified(requestContext, cacheKey, lastDateModified, cacheDuration)) { AddAgeHeader(responseHeaders, lastDateModified); - AddExpiresHeader(responseHeaders, cacheKeyString, cacheDuration, noCache); + AddExpiresHeader(responseHeaders, cacheKeyString, cacheDuration); var result = new HttpResult(new byte[] { }, contentType ?? "text/html", HttpStatusCode.NotModified); @@ -370,7 +370,7 @@ namespace Emby.Server.Implementations.HttpServer } } - AddCachingHeaders(responseHeaders, cacheKeyString, lastDateModified, cacheDuration, noCache); + AddCachingHeaders(responseHeaders, cacheKeyString, lastDateModified, cacheDuration); return null; } @@ -555,7 +555,7 @@ namespace Emby.Server.Implementations.HttpServer /// /// Adds the caching responseHeaders. /// - private void AddCachingHeaders(IDictionary responseHeaders, string cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, bool noCache) + private void AddCachingHeaders(IDictionary responseHeaders, string cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration) { // Don't specify both last modified and Etag, unless caching unconditionally. They are redundant // https://developers.google.com/speed/docs/best-practices/caching#LeverageBrowserCaching @@ -565,11 +565,11 @@ namespace Emby.Server.Implementations.HttpServer responseHeaders["Last-Modified"] = lastDateModified.Value.ToString("r"); } - if (!noCache && cacheDuration.HasValue) + if (cacheDuration.HasValue) { responseHeaders["Cache-Control"] = "public, max-age=" + Convert.ToInt32(cacheDuration.Value.TotalSeconds); } - else if (!noCache && !string.IsNullOrEmpty(cacheKey)) + else if (!string.IsNullOrEmpty(cacheKey)) { responseHeaders["Cache-Control"] = "public"; } @@ -579,15 +579,15 @@ namespace Emby.Server.Implementations.HttpServer responseHeaders["pragma"] = "no-cache, no-store, must-revalidate"; } - AddExpiresHeader(responseHeaders, cacheKey, cacheDuration, noCache); + AddExpiresHeader(responseHeaders, cacheKey, cacheDuration); } /// /// Adds the expires header. /// - private void AddExpiresHeader(IDictionary responseHeaders, string cacheKey, TimeSpan? cacheDuration, bool noCache) + private void AddExpiresHeader(IDictionary responseHeaders, string cacheKey, TimeSpan? cacheDuration) { - if (!noCache && cacheDuration.HasValue) + if (cacheDuration.HasValue) { responseHeaders["Expires"] = DateTime.UtcNow.Add(cacheDuration.Value).ToString("r"); } diff --git a/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs b/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs index ff152c9e9..f3a8a18ee 100644 --- a/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs +++ b/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs @@ -38,7 +38,7 @@ namespace Emby.Server.Implementations.Notifications } catch (Exception ex) { - Logger.ErrorException("Error loading notifications database file. Will reset and retry.", ex); + Logger.ErrorException("Error loading database file. Will reset and retry.", ex); FileSystem.DeleteFile(DbFilePath); diff --git a/Emby.Server.Implementations/Social/SharingRepository.cs b/Emby.Server.Implementations/Social/SharingRepository.cs index f306e76c4..f0b8cbd30 100644 --- a/Emby.Server.Implementations/Social/SharingRepository.cs +++ b/Emby.Server.Implementations/Social/SharingRepository.cs @@ -7,22 +7,42 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Model.Social; using SQLitePCL.pretty; using MediaBrowser.Model.Extensions; +using MediaBrowser.Model.IO; namespace Emby.Server.Implementations.Social { public class SharingRepository : BaseSqliteRepository, ISharingRepository { - public SharingRepository(ILogger logger, IApplicationPaths appPaths) + protected IFileSystem FileSystem { get; private set; } + + public SharingRepository(ILogger logger, IApplicationPaths appPaths, IFileSystem fileSystem) : base(logger) { + FileSystem = fileSystem; DbFilePath = Path.Combine(appPaths.DataPath, "shares.db"); } + public void Initialize() + { + try + { + InitializeInternal(); + } + catch (Exception ex) + { + Logger.ErrorException("Error loading database file. Will reset and retry.", ex); + + FileSystem.DeleteFile(DbFilePath); + + InitializeInternal(); + } + } + /// /// Opens the connection to the database /// /// Task. - public void Initialize() + private void InitializeInternal() { using (var connection = CreateConnection()) { diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index 54faa1443..f74c01994 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -32,6 +32,14 @@ namespace MediaBrowser.Controller.Channels return base.IsVisible(user); } + public override double? GetDefaultPrimaryImageAspectRatio() + { + double value = 16; + value /= 9; + + return value; + } + [IgnoreDataMember] public override bool SupportsInheritedParentImages { diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index d7b68d1e7..542fa5e08 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -117,8 +117,6 @@ namespace MediaBrowser.Controller.Drawing IImageEncoder ImageEncoder { get; set; } - void SaveImageSize(string path, DateTime imageDateModified, ImageSize size); - bool SupportsTransparency(string path); } } diff --git a/MediaBrowser.Controller/Drawing/ImageHelper.cs b/MediaBrowser.Controller/Drawing/ImageHelper.cs index 9452446a1..9936b1036 100644 --- a/MediaBrowser.Controller/Drawing/ImageHelper.cs +++ b/MediaBrowser.Controller/Drawing/ImageHelper.cs @@ -21,11 +21,6 @@ namespace MediaBrowser.Controller.Drawing public static IImageProcessor ImageProcessor { get; set; } - public static void SaveImageSize(string path, DateTime dateModified, ImageSize size) - { - ImageProcessor.SaveImageSize(path, dateModified, size); - } - private static ImageSize GetSizeEstimate(ImageProcessingOptions options) { if (options.Width.HasValue && options.Height.HasValue) diff --git a/MediaBrowser.Controller/Entities/Audio/AudioPodcast.cs b/MediaBrowser.Controller/Entities/Audio/AudioPodcast.cs index cdb6f3f61..d2b4569ba 100644 --- a/MediaBrowser.Controller/Entities/Audio/AudioPodcast.cs +++ b/MediaBrowser.Controller/Entities/Audio/AudioPodcast.cs @@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Entities.Audio public override double? GetDefaultPrimaryImageAspectRatio() { - return null; + return 1; } } } diff --git a/MediaBrowser.Controller/Entities/BasePluginFolder.cs b/MediaBrowser.Controller/Entities/BasePluginFolder.cs index a61862f28..d2459f208 100644 --- a/MediaBrowser.Controller/Entities/BasePluginFolder.cs +++ b/MediaBrowser.Controller/Entities/BasePluginFolder.cs @@ -42,5 +42,13 @@ namespace MediaBrowser.Controller.Entities return false; } } + + public override double? GetDefaultPrimaryImageAspectRatio() + { + double value = 16; + value /= 9; + + return value; + } } } diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index a83e084db..16630efe4 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -31,6 +31,14 @@ namespace MediaBrowser.Controller.Entities PhysicalFolderIds = EmptyGuidArray; } + public override double? GetDefaultPrimaryImageAspectRatio() + { + double value = 16; + value /= 9; + + return value; + } + [IgnoreDataMember] public override bool SupportsPlayedStatus { diff --git a/MediaBrowser.Controller/Entities/GameGenre.cs b/MediaBrowser.Controller/Entities/GameGenre.cs index 4e78a7fa5..6dc85f3e5 100644 --- a/MediaBrowser.Controller/Entities/GameGenre.cs +++ b/MediaBrowser.Controller/Entities/GameGenre.cs @@ -22,6 +22,11 @@ namespace MediaBrowser.Controller.Entities return GetUserDataKeys()[0]; } + public override double? GetDefaultPrimaryImageAspectRatio() + { + return 1; + } + /// /// Returns the folder containing the item. /// If the item is a folder, it returns the folder itself diff --git a/MediaBrowser.Controller/Entities/GameSystem.cs b/MediaBrowser.Controller/Entities/GameSystem.cs index bbaec14a1..c940b5953 100644 --- a/MediaBrowser.Controller/Entities/GameSystem.cs +++ b/MediaBrowser.Controller/Entities/GameSystem.cs @@ -44,6 +44,14 @@ namespace MediaBrowser.Controller.Entities } } + public override double? GetDefaultPrimaryImageAspectRatio() + { + double value = 16; + value /= 9; + + return value; + } + /// /// Gets or sets the game system. /// diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs index 790f8938e..569a0dfb8 100644 --- a/MediaBrowser.Controller/Entities/Genre.cs +++ b/MediaBrowser.Controller/Entities/Genre.cs @@ -25,6 +25,11 @@ namespace MediaBrowser.Controller.Entities return GetUserDataKeys()[0]; } + public override double? GetDefaultPrimaryImageAspectRatio() + { + return 1; + } + /// /// Returns the folder containing the item. /// If the item is a folder, it returns the folder itself diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs index 8e9eac50c..11db633ba 100644 --- a/MediaBrowser.Controller/Entities/Photo.cs +++ b/MediaBrowser.Controller/Entities/Photo.cs @@ -62,6 +62,35 @@ namespace MediaBrowser.Controller.Entities return true; } + public override double? GetDefaultPrimaryImageAspectRatio() + { + if (Width.HasValue && Height.HasValue) + { + double width = Width.Value; + double height = Height.Value; + + if (Orientation.HasValue) + { + switch (Orientation.Value) + { + case ImageOrientation.LeftBottom: + case ImageOrientation.LeftTop: + case ImageOrientation.RightBottom: + case ImageOrientation.RightTop: + var temp = height; + height = width; + width = temp; + break; + } + } + + width /= Height.Value; + return width; + } + + return base.GetDefaultPrimaryImageAspectRatio(); + } + public int? Width { get; set; } public int? Height { get; set; } public string CameraMake { get; set; } diff --git a/MediaBrowser.Controller/Entities/PhotoAlbum.cs b/MediaBrowser.Controller/Entities/PhotoAlbum.cs index af9d8c801..52d743e36 100644 --- a/MediaBrowser.Controller/Entities/PhotoAlbum.cs +++ b/MediaBrowser.Controller/Entities/PhotoAlbum.cs @@ -30,5 +30,10 @@ namespace MediaBrowser.Controller.Entities return false; } } + + public override double? GetDefaultPrimaryImageAspectRatio() + { + return 1; + } } } diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs index e9a794e79..36bbf6886 100644 --- a/MediaBrowser.Controller/Entities/User.cs +++ b/MediaBrowser.Controller/Entities/User.cs @@ -254,6 +254,11 @@ namespace MediaBrowser.Controller.Entities } } + public override double? GetDefaultPrimaryImageAspectRatio() + { + return 1; + } + /// /// Gets the configuration directory path. /// diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 66174034d..57eeafe91 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -58,6 +58,14 @@ namespace MediaBrowser.Controller.Entities } } + public override double? GetDefaultPrimaryImageAspectRatio() + { + double value = 16; + value /= 9; + + return value; + } + public override int GetChildCount(User user) { return GetChildren(user, true).Count; diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs index 7d820b007..49b967104 100644 --- a/MediaBrowser.Controller/Entities/Year.cs +++ b/MediaBrowser.Controller/Entities/Year.cs @@ -32,6 +32,14 @@ namespace MediaBrowser.Controller.Entities } } + public override double? GetDefaultPrimaryImageAspectRatio() + { + double value = 2; + value /= 3; + + return value; + } + [IgnoreDataMember] public override bool SupportsAncestors { diff --git a/SharedVersion.cs b/SharedVersion.cs index 66dd5fa2d..0dd93fc20 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.32.1")] +[assembly: AssemblyVersion("3.2.32.2")]