only the WebDavSyncService is now registered, syncing into Jellyfin’s DefaultUserViewsPath
This commit is contained in:
parent
eacb6134a0
commit
28bc6d6a28
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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;
|
||||||
Directory.CreateDirectory(localRoot);
|
if (!Directory.Exists(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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue