• Project renamed and updated (Jellyfin.Plugin.Webdav.csproj) with WebDav.Client reference
• Plugin.cs set to “WebDAV” with the new GUID
• Configuration/PluginConfiguration.cs defines the connection and cache settings
• ServiceRegistrator.cs wires DI for WebDavClientService and the WebDavSyncService hosted service
• WebDavClientService.cs wraps WebDav.Client for directory listing and streaming
• WebDavSyncService.cs syncs remote files into a local cache and registers it as a virtual folder
• StreamingController.cs exposes /WebDav/Stream/{*path} for streaming
• Configuration/configPage.html implements the dashboard configuration UI
Next step: build and deploy the plugin to your Jellyfin server’s plugins folder.
75 lines
2.9 KiB
C#
75 lines
2.9 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// Hosted service that synchronizes WebDAV content into a local cache directory
|
|
/// and registers it as a Jellyfin virtual folder.
|
|
/// </summary>
|
|
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;
|
|
}
|
|
} |