using System; using System.Collections.Generic; using System.Globalization; using System.IO; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.IO; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Library; /// /// IPathManager implementation. /// public class PathManager : IPathManager { private readonly ILogger _logger; private readonly IServerConfigurationManager _config; private readonly IApplicationPaths _appPaths; /// /// Initializes a new instance of the class. /// /// The logger. /// The server configuration manager. /// The application paths. public PathManager( ILogger logger, IServerConfigurationManager config, IApplicationPaths appPaths) { _logger = logger; _config = config; _appPaths = appPaths; } private string SubtitleCachePath => Path.Combine(_appPaths.DataPath, "subtitles"); private string AttachmentCachePath => Path.Combine(_appPaths.DataPath, "attachments"); /// public string? GetAttachmentPath(string mediaSourceId, string fileName) { var folder = GetAttachmentFolderPath(mediaSourceId); return folder is null ? null : Path.Combine(folder, fileName); } /// public string? GetAttachmentFolderPath(string mediaSourceId) { if (!Guid.TryParse(mediaSourceId, out var parsed)) { _logger.LogDebug("MediaSource Id '{MediaSourceId}' is not a GUID; no on-disk attachment folder.", mediaSourceId); return null; } var id = parsed.ToString("D", CultureInfo.InvariantCulture).AsSpan(); return Path.Join(AttachmentCachePath, id[..2], id); } /// public string? GetSubtitleFolderPath(string mediaSourceId) { if (!Guid.TryParse(mediaSourceId, out var parsed)) { _logger.LogDebug("MediaSource Id '{MediaSourceId}' is not a GUID; no on-disk subtitle folder.", mediaSourceId); return null; } var id = parsed.ToString("D", CultureInfo.InvariantCulture).AsSpan(); return Path.Join(SubtitleCachePath, id[..2], id); } /// public string? GetSubtitlePath(string mediaSourceId, int streamIndex, string extension) { var folder = GetSubtitleFolderPath(mediaSourceId); return folder is null ? null : Path.Combine(folder, streamIndex.ToString(CultureInfo.InvariantCulture) + extension); } /// public string GetTrickplayDirectory(BaseItem item, bool saveWithMedia = false) { var id = item.Id.ToString("D", CultureInfo.InvariantCulture).AsSpan(); return saveWithMedia ? Path.Combine(item.ContainingFolderPath, Path.ChangeExtension(Path.GetFileName(item.Path), ".trickplay")) : Path.Join(_config.ApplicationPaths.TrickplayPath, id[..2], id); } /// public string GetChapterImageFolderPath(BaseItem item) { return Path.Combine(item.GetInternalMetadataPath(), "chapters"); } /// public string GetChapterImagePath(BaseItem item, long chapterPositionTicks) { var filename = item.DateModified.Ticks.ToString(CultureInfo.InvariantCulture) + "_" + chapterPositionTicks.ToString(CultureInfo.InvariantCulture) + ".jpg"; return Path.Combine(GetChapterImageFolderPath(item), filename); } /// public IReadOnlyList GetExtractedDataPaths(BaseItem item) { var mediaSourceId = item.Id.ToString("N", CultureInfo.InvariantCulture); List paths = []; var attachmentFolder = GetAttachmentFolderPath(mediaSourceId); if (attachmentFolder is not null) { paths.Add(attachmentFolder); } var subtitleFolder = GetSubtitleFolderPath(mediaSourceId); if (subtitleFolder is not null) { paths.Add(subtitleFolder); } paths.Add(GetTrickplayDirectory(item, false)); paths.Add(GetTrickplayDirectory(item, true)); paths.Add(GetChapterImageFolderPath(item)); return paths; } }