Jellyfin.Plugin.Webdav/WebDavSyncService.cs
2025-04-21 15:04:10 +02:00

101 lines
3.9 KiB
C#

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;
/// <summary>
/// Hosted service that synchronizes WebDAV content into the local cache directory
/// and registers it as a Jellyfin virtual folder.
/// </summary>
public sealed class WebDavSyncService : IHostedService
{
private readonly WebDavClientService client;
private readonly PluginConfiguration config;
private readonly IServerApplicationPaths appPaths;
private readonly ILibraryManager libraryManager;
/// <summary>
/// Initializes a new instance of the <see cref="WebDavSyncService"/> class.
/// </summary>
/// <param name="client">The WebDAV client service.</param>
/// <param name="config">The plugin configuration.</param>
/// <param name="appPaths">Server application paths.</param>
/// <param name="libraryManager">Library manager.</param>
public WebDavSyncService(
WebDavClientService client,
PluginConfiguration config,
IServerApplicationPaths appPaths,
ILibraryManager libraryManager)
{
this.client = client;
this.config = config;
this.appPaths = appPaths;
this.libraryManager = libraryManager;
}
/// <inheritdoc/>
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);
}
}
}
/// <inheritdoc/>
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
}