only the WebDavSyncService is now registered, syncing into Jellyfin’s DefaultUserViewsPath

This commit is contained in:
copyrights 2025-04-21 09:38:08 +02:00
parent eacb6134a0
commit 28bc6d6a28
2 changed files with 88 additions and 16 deletions

View file

@ -8,31 +8,55 @@ namespace Jellyfin.Plugin.Webdav
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Plugin.Webdav.Configuration; using Jellyfin.Plugin.Webdav.Configuration;
using WebDav.Client;
/// <summary> /// <summary>
/// Service for interacting with WebDAV endpoints. /// Service for interacting with WebDAV endpoints.
/// </summary> /// </summary>
public sealed class WebDavClientService public sealed class WebDavClientService
{ {
private readonly PluginConfiguration _configuration; private readonly PluginConfiguration _config;
private readonly WebDavClient _client;
public WebDavClientService(PluginConfiguration configuration) /// <summary>
/// Initializes a new instance of the <see cref="WebDavClientService"/> class.
/// </summary>
/// <param name="config">Plugin configuration.</param>
public WebDavClientService(PluginConfiguration config)
{ {
_configuration = configuration; _config = config;
var parameters = new WebDavClientParams
{
BaseAddress = new Uri(_config.BaseUrl.TrimEnd('/')),
Credentials = new NetworkCredential(_config.Username, _config.Password),
PreAuthenticate = true
};
_client = new WebDavClient(parameters);
} }
/// <summary>List resources at the specified WebDAV path.</summary> /// <summary>
public Task<IEnumerable<object>> ListAsync(string path) /// Lists resources at the specified WebDAV path.
/// </summary>
/// <param name="path">Remote path.</param>
/// <returns>A collection of WebDAV resources.</returns>
public async Task<IEnumerable<WebDavResource>> ListAsync(string path)
{ {
return Task.FromResult<IEnumerable<object>>(Array.Empty<object>()); var response = await _client.Propfind(path).ConfigureAwait(false);
return response.Resources;
} }
/// <summary>Get a raw file stream from the WebDAV endpoint.</summary> /// <summary>
public Task<Stream> GetStreamAsync(string path) /// Gets a raw file stream from the WebDAV endpoint.
/// </summary>
/// <param name="path">Remote file path.</param>
/// <returns>A stream for the remote file.</returns>
public async Task<Stream> GetStreamAsync(string path)
{ {
return Task.FromResult<Stream>(Stream.Null); var response = await _client.GetRawFile(path).ConfigureAwait(false);
return response.Stream;
} }
} }
} }

View file

@ -6,28 +6,39 @@
namespace Jellyfin.Plugin.Webdav namespace Jellyfin.Plugin.Webdav
{ {
using System.IO; using System.IO;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Controller; using Jellyfin.Plugin.Webdav.Configuration;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Configuration;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
/// <summary> /// <summary>
/// Hosted service that registers the WebDAV cache as a virtual folder on startup. /// Hosted service that synchronizes WebDAV content into the local cache directory
/// and registers it as a Jellyfin virtual folder.
/// </summary> /// </summary>
public sealed class WebDavSyncService : IHostedService public sealed class WebDavSyncService : IHostedService
{ {
private readonly WebDavClientService client;
private readonly PluginConfiguration config;
private readonly IServerApplicationPaths appPaths; private readonly IServerApplicationPaths appPaths;
private readonly ILibraryManager libraryManager; private readonly ILibraryManager libraryManager;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WebDavSyncService"/> class. /// Initializes a new instance of the <see cref="WebDavSyncService"/> class.
/// </summary> /// </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="appPaths">Server application paths.</param>
/// <param name="libraryManager">Library manager.</param> /// <param name="libraryManager">Library manager.</param>
public WebDavSyncService(IServerApplicationPaths appPaths, ILibraryManager libraryManager) public WebDavSyncService(
WebDavClientService client,
PluginConfiguration config,
IServerApplicationPaths appPaths,
ILibraryManager libraryManager)
{ {
this.client = client;
this.config = config;
this.appPaths = appPaths; this.appPaths = appPaths;
this.libraryManager = libraryManager; this.libraryManager = libraryManager;
} }
@ -35,15 +46,52 @@ namespace Jellyfin.Plugin.Webdav
/// <inheritdoc/> /// <inheritdoc/>
public async Task StartAsync(CancellationToken cancellationToken) public async Task StartAsync(CancellationToken cancellationToken)
{ {
var localRoot = Path.Combine(this.appPaths.DefaultUserViewsPath, "WebDAV"); var localRoot = config.CacheDirectory;
if (!Directory.Exists(localRoot))
{
Directory.CreateDirectory(localRoot); Directory.CreateDirectory(localRoot);
}
await SyncDirectoryAsync(config.RootPath.Trim('/'), localRoot, cancellationToken)
.ConfigureAwait(false);
var options = new LibraryOptions(); var options = new LibraryOptions();
await this.libraryManager await libraryManager
.AddVirtualFolder("WebDAV", null, options, true) .AddVirtualFolder("WebDAV", null, options, true)
.ConfigureAwait(false); .ConfigureAwait(false);
} }
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/> /// <inheritdoc/>
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
} }