namespace Jellyfin.Plugin.Webdav
{
using System.IO;
using MediaBrowser.Controller;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Plugin.Webdav.Configuration;
using MediaBrowser.Controller.Library;
using System.Collections.Generic;
using Microsoft.Extensions.Hosting;
using MediaBrowser.Model.Configuration;
///
/// Hosted service that synchronizes WebDAV content into the local cache directory
/// and registers it as a Jellyfin virtual folder.
///
public sealed class WebDavSyncService : IHostedService
{
private readonly WebDavClientService client;
private readonly PluginConfiguration config;
private readonly IServerApplicationPaths appPaths;
private readonly ILibraryManager libraryManager;
///
/// Initializes a new instance of the class.
///
/// The WebDAV client service.
/// The plugin configuration.
/// Server application paths.
/// Library manager.
public WebDavSyncService(
WebDavClientService client,
PluginConfiguration config,
IServerApplicationPaths appPaths,
ILibraryManager libraryManager)
{
this.client = client;
this.config = config;
this.appPaths = appPaths;
this.libraryManager = libraryManager;
}
///
public async Task StartAsync(CancellationToken cancellationToken)
{
// Determine cache root: either configured directory or default user views path
var baseCache = string.IsNullOrWhiteSpace(config.CacheDirectory)
? appPaths.DefaultUserViewsPath
: config.CacheDirectory;
var localRoot = Path.Combine(baseCache, "WebDAV");
if (!Directory.Exists(localRoot))
{
Directory.CreateDirectory(localRoot);
}
await SyncDirectoryAsync(config.RootPath.Trim('/'), localRoot, cancellationToken)
.ConfigureAwait(false);
var options = new LibraryOptions();
await libraryManager
.AddVirtualFolder("WebDAV", null, options, true)
.ConfigureAwait(false);
libraryManager.AddMediaPath("WebDAV", new MediaPathInfo { Path = localRoot });
}
private async Task SyncDirectoryAsync(string remotePath, string localPath, CancellationToken token)
{
var resources = await client.ListAsync(remotePath).ConfigureAwait(false);
foreach (var item in resources.Where(r => !string.IsNullOrEmpty(r.DisplayName)))
{
if (token.IsCancellationRequested)
{
break;
}
var name = item.DisplayName!;
var remoteItem = $"{remotePath}/{name}";
var localItem = Path.Combine(localPath, name);
if (item.IsCollection)
{
if (!Directory.Exists(localItem))
{
Directory.CreateDirectory(localItem);
}
await SyncDirectoryAsync(remoteItem, localItem, token).ConfigureAwait(false);
}
else
{
using var stream = await client.GetStreamAsync(remoteItem).ConfigureAwait(false);
using var fs = File.Create(localItem);
await stream.CopyToAsync(fs, token).ConfigureAwait(false);
}
}
}
///
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
}