using System; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Plugins; namespace Jellyfin.Plugin.Webdav { /// /// Hosted service that synchronizes WebDAV content into a local cache directory /// and registers it as a Jellyfin virtual folder. /// public class WebDavSyncService : IHostedService { private readonly WebDavClientService _client; private readonly PluginConfiguration _config; private readonly ILibraryManager _libraryManager; private readonly IServerApplicationHost _appHost; public WebDavSyncService(WebDavClientService client, PluginConfiguration config, ILibraryManager libraryManager, IServerApplicationHost appHost) { _client = client; _config = config; _libraryManager = libraryManager; _appHost = appHost; } public async Task StartAsync(CancellationToken cancellationToken) { // Compute local root under DefaultUserViewsPath var localRoot = Path.Combine(_appHost.ApplicationPaths.DefaultUserViewsPath, "WebDAV"); Directory.CreateDirectory(localRoot); // Sync directories recursively await SyncDirectory(_config.RootPath, localRoot, cancellationToken).ConfigureAwait(false); // Register the virtual folder pointing to the synced cache var options = new LibraryOptions(); await _libraryManager.AddVirtualFolder("WebDAV", null, options, true).ConfigureAwait(false); } private async Task SyncDirectory(string remotePath, string localPath, CancellationToken cancellationToken) { var resources = await _client.ListAsync(remotePath).ConfigureAwait(false); foreach (var res in resources.Where(r => r.DisplayName != null)) { if (cancellationToken.IsCancellationRequested) { break; } var name = res.DisplayName; var remoteSub = $"{remotePath.TrimEnd('/')}/{name}"; var localSub = Path.Combine(localPath, name); if (res.IsCollection) { Directory.CreateDirectory(localSub); await SyncDirectory(remoteSub, localSub, cancellationToken).ConfigureAwait(false); } else { using var stream = await _client.GetStreamAsync(remoteSub).ConfigureAwait(false); using var fs = File.Create(localSub); await stream.CopyToAsync(fs, cancellationToken).ConfigureAwait(false); } } } public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; } }