diff --git a/Jellyfin.Plugin.Danmu/ILRepack.targets b/Jellyfin.Plugin.Danmu/ILRepack.targets new file mode 100644 index 0000000..ca1d1f9 --- /dev/null +++ b/Jellyfin.Plugin.Danmu/ILRepack.targets @@ -0,0 +1,26 @@ + + + + + false + + + + + + + + + + + + + \ No newline at end of file diff --git a/Jellyfin.Plugin.Danmu/Jellyfin.Plugin.Danmu.csproj b/Jellyfin.Plugin.Danmu/Jellyfin.Plugin.Danmu.csproj index 2aeae20..7305dbe 100644 --- a/Jellyfin.Plugin.Danmu/Jellyfin.Plugin.Danmu.csproj +++ b/Jellyfin.Plugin.Danmu/Jellyfin.Plugin.Danmu.csproj @@ -6,6 +6,7 @@ true enable AllEnabledByDefault + true False @@ -14,9 +15,12 @@ False + + + diff --git a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/AssemblyInfo.cs b/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/AssemblyInfo.cs deleted file mode 100644 index 1563afa..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("ComposableAsync.Core.Test")] - diff --git a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/Awaitable/DispatcherAwaiter.cs b/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/Awaitable/DispatcherAwaiter.cs deleted file mode 100644 index 061840a..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/Awaitable/DispatcherAwaiter.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using System.Security; - -namespace ComposableAsync -{ - /// - /// Dispatcher awaiter, making a dispatcher awaitable - /// - public struct DispatcherAwaiter : INotifyCompletion - { - /// - /// Dispatcher never is synchronous - /// - public bool IsCompleted => false; - - private readonly IDispatcher _Dispatcher; - - /// - /// Construct a NotifyCompletion fom a dispatcher - /// - /// - public DispatcherAwaiter(IDispatcher dispatcher) - { - _Dispatcher = dispatcher; - } - - /// - /// Dispatch on complete - /// - /// - [SecuritySafeCritical] - public void OnCompleted(Action continuation) - { - _Dispatcher.Dispatch(continuation); - } - - /// - /// No Result - /// - public void GetResult() { } - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/DelegatingHandler/DispatcherDelegatingHandler.cs b/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/DelegatingHandler/DispatcherDelegatingHandler.cs deleted file mode 100644 index dbd8b49..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/DelegatingHandler/DispatcherDelegatingHandler.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; - -namespace ComposableAsync -{ - /// - /// A implementation based on - /// - internal class DispatcherDelegatingHandler : DelegatingHandler - { - private readonly IDispatcher _Dispatcher; - - /// - /// Build an from a - /// - /// - public DispatcherDelegatingHandler(IDispatcher dispatcher) - { - _Dispatcher = dispatcher; - InnerHandler = new HttpClientHandler(); - } - - protected override Task SendAsync(HttpRequestMessage request, - CancellationToken cancellationToken) - { - return _Dispatcher.Enqueue(() => base.SendAsync(request, cancellationToken), cancellationToken); - } - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/Dispatcher/ComposedDispatcher.cs b/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/Dispatcher/ComposedDispatcher.cs deleted file mode 100644 index aed2434..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/Dispatcher/ComposedDispatcher.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace ComposableAsync -{ - internal class ComposedDispatcher : IDispatcher, IAsyncDisposable - { - private readonly IDispatcher _First; - private readonly IDispatcher _Second; - - public ComposedDispatcher(IDispatcher first, IDispatcher second) - { - _First = first; - _Second = second; - } - - public void Dispatch(Action action) - { - _First.Dispatch(() => _Second.Dispatch(action)); - } - - public async Task Enqueue(Action action) - { - await _First.Enqueue(() => _Second.Enqueue(action)); - } - - public async Task Enqueue(Func action) - { - return await _First.Enqueue(() => _Second.Enqueue(action)); - } - - public async Task Enqueue(Func action) - { - await _First.Enqueue(() => _Second.Enqueue(action)); - } - - public async Task Enqueue(Func> action) - { - return await _First.Enqueue(() => _Second.Enqueue(action)); - } - - public async Task Enqueue(Func action, CancellationToken cancellationToken) - { - await _First.Enqueue(() => _Second.Enqueue(action, cancellationToken), cancellationToken); - } - - public async Task Enqueue(Func> action, CancellationToken cancellationToken) - { - return await _First.Enqueue(() => _Second.Enqueue(action, cancellationToken), cancellationToken); - } - - public async Task Enqueue(Func action, CancellationToken cancellationToken) - { - return await _First.Enqueue(() => _Second.Enqueue(action, cancellationToken), cancellationToken); - } - - public async Task Enqueue(Action action, CancellationToken cancellationToken) - { - await _First.Enqueue(() => _Second.Enqueue(action, cancellationToken), cancellationToken); - } - - public IDispatcher Clone() => new ComposedDispatcher(_First, _Second); - - public Task DisposeAsync() - { - return Task.WhenAll(DisposeAsync(_First), DisposeAsync(_Second)); - } - - private static Task DisposeAsync(IDispatcher disposable) => (disposable as IAsyncDisposable)?.DisposeAsync() ?? Task.CompletedTask; - - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/Dispatcher/DispatcherAdapter.cs b/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/Dispatcher/DispatcherAdapter.cs deleted file mode 100644 index d6532ad..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/Dispatcher/DispatcherAdapter.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace ComposableAsync -{ - internal class DispatcherAdapter : IDispatcher - { - private readonly IBasicDispatcher _BasicDispatcher; - - public DispatcherAdapter(IBasicDispatcher basicDispatcher) - { - _BasicDispatcher = basicDispatcher; - } - - public IDispatcher Clone() => new DispatcherAdapter(_BasicDispatcher.Clone()); - - public void Dispatch(Action action) - { - _BasicDispatcher.Enqueue(action, CancellationToken.None); - } - - public Task Enqueue(Action action) - { - return _BasicDispatcher.Enqueue(action, CancellationToken.None); - } - - public Task Enqueue(Func action) - { - return _BasicDispatcher.Enqueue(action, CancellationToken.None); - } - - public Task Enqueue(Func action) - { - return _BasicDispatcher.Enqueue(action, CancellationToken.None); - } - - public Task Enqueue(Func> action) - { - return _BasicDispatcher.Enqueue(action, CancellationToken.None); - } - - public Task Enqueue(Func action, CancellationToken cancellationToken) - { - return _BasicDispatcher.Enqueue(action, cancellationToken); - } - - public Task Enqueue(Action action, CancellationToken cancellationToken) - { - return _BasicDispatcher.Enqueue(action, cancellationToken); - } - - public Task Enqueue(Func action, CancellationToken cancellationToken) - { - return _BasicDispatcher.Enqueue(action, cancellationToken); - } - - public Task Enqueue(Func> action, CancellationToken cancellationToken) - { - return _BasicDispatcher.Enqueue(action, cancellationToken); - } - } -} \ No newline at end of file diff --git a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/Dispatcher/NullDispatcher.cs b/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/Dispatcher/NullDispatcher.cs deleted file mode 100644 index 4882f9e..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/Dispatcher/NullDispatcher.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace ComposableAsync -{ - /// - /// that run actions synchronously - /// - public sealed class NullDispatcher: IDispatcher - { - private NullDispatcher() { } - - /// - /// Returns a static null dispatcher - /// - public static IDispatcher Instance { get; } = new NullDispatcher(); - - /// - public void Dispatch(Action action) - { - action(); - } - - /// - public Task Enqueue(Action action) - { - action(); - return Task.CompletedTask; - } - - /// - public Task Enqueue(Func action) - { - return Task.FromResult(action()); - } - - /// - public async Task Enqueue(Func action) - { - await action(); - } - - /// - public async Task Enqueue(Func> action) - { - return await action(); - } - - public Task Enqueue(Func action, CancellationToken cancellationToken) - { - return Task.FromResult(action()); - } - - public Task Enqueue(Action action, CancellationToken cancellationToken) - { - action(); - return Task.CompletedTask; - } - - public async Task Enqueue(Func action, CancellationToken cancellationToken) - { - await action(); - } - - public async Task Enqueue(Func> action, CancellationToken cancellationToken) - { - return await action(); - } - - /// - public IDispatcher Clone() => Instance; - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/DispatcherExtension.cs b/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/DispatcherExtension.cs deleted file mode 100644 index ef29912..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/DispatcherExtension.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; - -namespace ComposableAsync -{ - /// - /// extension methods provider - /// - public static class DispatcherExtension - { - /// - /// Returns awaitable to enter in the dispatcher context - /// This extension method make a dispatcher awaitable - /// - /// - /// - public static DispatcherAwaiter GetAwaiter(this IDispatcher dispatcher) - { - return new DispatcherAwaiter(dispatcher); - } - - /// - /// Returns a composed dispatcher applying the given dispatcher - /// after the first one - /// - /// - /// - /// - public static IDispatcher Then(this IDispatcher dispatcher, IDispatcher other) - { - if (dispatcher == null) - throw new ArgumentNullException(nameof(dispatcher)); - - if (other == null) - throw new ArgumentNullException(nameof(other)); - - return new ComposedDispatcher(dispatcher, other); - } - - /// - /// Returns a composed dispatcher applying the given dispatchers sequentially - /// - /// - /// - /// - public static IDispatcher Then(this IDispatcher dispatcher, params IDispatcher[] others) - { - return dispatcher.Then((IEnumerable)others); - } - - /// - /// Returns a composed dispatcher applying the given dispatchers sequentially - /// - /// - /// - /// - public static IDispatcher Then(this IDispatcher dispatcher, IEnumerable others) - { - if (dispatcher == null) - throw new ArgumentNullException(nameof(dispatcher)); - - if (others == null) - throw new ArgumentNullException(nameof(others)); - - return others.Aggregate(dispatcher, (cum, val) => cum.Then(val)); - } - - /// - /// Create a from an - /// - /// - /// - public static DelegatingHandler AsDelegatingHandler(this IDispatcher dispatcher) - { - return new DispatcherDelegatingHandler(dispatcher); - } - - /// - /// Create a from an - /// - /// - /// - public static IDispatcher ToFullDispatcher(this IBasicDispatcher @basicDispatcher) - { - return new DispatcherAdapter(@basicDispatcher); - } - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/DispatcherManager/IDispatcherManager.cs b/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/DispatcherManager/IDispatcherManager.cs deleted file mode 100644 index 66c52d5..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/DispatcherManager/IDispatcherManager.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace ComposableAsync -{ - /// - /// Dispatcher manager - /// - public interface IDispatcherManager : IAsyncDisposable - { - /// - /// true if the Dispatcher should be released - /// - bool DisposeDispatcher { get; } - - /// - /// Returns a consumable Dispatcher - /// - /// - IDispatcher GetDispatcher(); - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/DispatcherManager/MonoDispatcherManager.cs b/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/DispatcherManager/MonoDispatcherManager.cs deleted file mode 100644 index f26ef5c..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/DispatcherManager/MonoDispatcherManager.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Threading.Tasks; - -namespace ComposableAsync -{ - /// - /// implementation based on single - /// - public sealed class MonoDispatcherManager : IDispatcherManager - { - /// - public bool DisposeDispatcher { get; } - - /// - public IDispatcher GetDispatcher() => _Dispatcher; - - private readonly IDispatcher _Dispatcher; - - /// - /// Create - /// - /// - /// - public MonoDispatcherManager(IDispatcher dispatcher, bool shouldDispose = false) - { - _Dispatcher = dispatcher; - DisposeDispatcher = shouldDispose; - } - - /// - public Task DisposeAsync() - { - return DisposeDispatcher && (_Dispatcher is IAsyncDisposable disposable) ? - disposable.DisposeAsync() : Task.CompletedTask; - } - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/DispatcherProviderExtension.cs b/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/DispatcherProviderExtension.cs deleted file mode 100644 index f7046a1..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/DispatcherProviderExtension.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace ComposableAsync -{ - /// - /// extension - /// - public static class DispatcherProviderExtension - { - /// - /// Returns the underlying - /// - /// - /// - public static IDispatcher GetAssociatedDispatcher(this IDispatcherProvider dispatcherProvider) - { - return dispatcherProvider?.Dispatcher ?? NullDispatcher.Instance; - } - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/Disposable/ComposableAsyncDisposable.cs b/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/Disposable/ComposableAsyncDisposable.cs deleted file mode 100644 index 541d906..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/Disposable/ComposableAsyncDisposable.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Collections.Concurrent; -using System.Linq; -using System.Threading.Tasks; - -namespace ComposableAsync -{ - /// - /// implementation aggregating other - /// - public sealed class ComposableAsyncDisposable : IAsyncDisposable - { - private readonly ConcurrentQueue _Disposables; - - /// - /// Build an empty ComposableAsyncDisposable - /// - public ComposableAsyncDisposable() - { - _Disposables = new ConcurrentQueue(); - } - - /// - /// Add an to the ComposableAsyncDisposable - /// and returns it - /// - /// - /// - /// - public T Add(T disposable) where T: IAsyncDisposable - { - if (disposable == null) - return default(T); - - _Disposables.Enqueue(disposable); - return disposable; - } - - /// - /// Dispose all the resources asynchronously - /// - /// - public Task DisposeAsync() - { - var tasks = _Disposables.ToArray().Select(disposable => disposable.DisposeAsync()).ToArray(); - return Task.WhenAll(tasks); - } - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/Disposable/IAsyncDisposable.cs b/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/Disposable/IAsyncDisposable.cs deleted file mode 100644 index 3517491..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/Disposable/IAsyncDisposable.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Threading.Tasks; - -namespace ComposableAsync -{ - /// - /// Asynchronous version of IDisposable - /// For reference see discussion: https://github.com/dotnet/roslyn/issues/114 - /// - public interface IAsyncDisposable - { - /// - /// Performs asynchronously application-defined tasks associated with freeing, - /// releasing, or resetting unmanaged resources. - /// - Task DisposeAsync(); - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/IBasicDispatcher.cs b/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/IBasicDispatcher.cs deleted file mode 100644 index 6e054dd..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/IBasicDispatcher.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace ComposableAsync -{ - /// - /// Simplified version of that can be converted - /// to a using the ToFullDispatcher extension method - /// - public interface IBasicDispatcher - { - /// - /// Clone dispatcher - /// - /// - IBasicDispatcher Clone(); - - /// - /// Enqueue the function and return a task corresponding - /// to the execution of the task - /// /// - /// - /// - /// - /// - Task Enqueue(Func action, CancellationToken cancellationToken); - - /// - /// Enqueue the action and return a task corresponding - /// to the execution of the task - /// - /// - /// - /// - Task Enqueue(Action action, CancellationToken cancellationToken); - - /// - /// Enqueue the task and return a task corresponding - /// to the execution of the task - /// - /// - /// - /// - Task Enqueue(Func action, CancellationToken cancellationToken); - - /// - /// Enqueue the task and return a task corresponding - /// to the execution of the original task - /// - /// - /// - /// - /// - Task Enqueue(Func> action, CancellationToken cancellationToken); - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/IDispatcher.cs b/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/IDispatcher.cs deleted file mode 100644 index d7eb14f..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/IDispatcher.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace ComposableAsync -{ - /// - /// Dispatcher executes an action or a function - /// on its own context - /// - public interface IDispatcher - { - /// - /// Execute action on dispatcher context in a - /// none-blocking way - /// - /// - void Dispatch(Action action); - - /// - /// Enqueue the action and return a task corresponding to - /// the completion of the action - /// - /// - /// - Task Enqueue(Action action); - - /// - /// Enqueue the function and return a task corresponding to - /// the result of the function - /// - /// - /// - /// - Task Enqueue(Func action); - - /// - /// Enqueue the task and return a task corresponding to - /// the completion of the task - /// - /// - /// - Task Enqueue(Func action); - - /// - /// Enqueue the task and return a task corresponding - /// to the execution of the original task - /// - /// - /// - /// - Task Enqueue(Func> action); - - /// - /// Enqueue the function and return a task corresponding - /// to the execution of the task - /// /// - /// - /// - /// - /// - Task Enqueue(Func action, CancellationToken cancellationToken); - - /// - /// Enqueue the action and return a task corresponding - /// to the execution of the task - /// - /// - /// - /// - Task Enqueue(Action action, CancellationToken cancellationToken); - - /// - /// Enqueue the task and return a task corresponding - /// to the execution of the task - /// - /// - /// - /// - Task Enqueue(Func action, CancellationToken cancellationToken); - - /// - /// Enqueue the task and return a task corresponding - /// to the execution of the original task - /// - /// - /// - /// - /// - Task Enqueue(Func> action, CancellationToken cancellationToken); - - /// - /// Clone dispatcher - /// - /// - IDispatcher Clone(); - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/IDispatcherProvider.cs b/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/IDispatcherProvider.cs deleted file mode 100644 index fb4c760..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/ComposableAsync.Core/IDispatcherProvider.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace ComposableAsync -{ - /// - /// Returns the fiber associated with an actor - /// - public interface IDispatcherProvider - { - /// - /// Returns the corresponding - /// - IDispatcher Dispatcher { get; } - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/AwaitableConstraintExtension.cs b/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/AwaitableConstraintExtension.cs deleted file mode 100644 index 0a2dd65..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/AwaitableConstraintExtension.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace RateLimiter -{ - /// - /// Provides extension to interface - /// - public static class AwaitableConstraintExtension - { - /// - /// Compose two awaitable constraint in a new one - /// - /// - /// - /// - public static IAwaitableConstraint Compose(this IAwaitableConstraint awaitableConstraint1, IAwaitableConstraint awaitableConstraint2) - { - if (awaitableConstraint1 == awaitableConstraint2) - return awaitableConstraint1; - - return new ComposedAwaitableConstraint(awaitableConstraint1, awaitableConstraint2); - } - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/ComposedAwaitableConstraint.cs b/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/ComposedAwaitableConstraint.cs deleted file mode 100644 index 278de53..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/ComposedAwaitableConstraint.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace RateLimiter -{ - internal class ComposedAwaitableConstraint : IAwaitableConstraint - { - private readonly IAwaitableConstraint _AwaitableConstraint1; - private readonly IAwaitableConstraint _AwaitableConstraint2; - private readonly SemaphoreSlim _Semaphore = new SemaphoreSlim(1, 1); - - internal ComposedAwaitableConstraint(IAwaitableConstraint awaitableConstraint1, IAwaitableConstraint awaitableConstraint2) - { - _AwaitableConstraint1 = awaitableConstraint1; - _AwaitableConstraint2 = awaitableConstraint2; - } - - public IAwaitableConstraint Clone() - { - return new ComposedAwaitableConstraint(_AwaitableConstraint1.Clone(), _AwaitableConstraint2.Clone()); - } - - public async Task WaitForReadiness(CancellationToken cancellationToken) - { - await _Semaphore.WaitAsync(cancellationToken); - IDisposable[] disposables; - try - { - disposables = await Task.WhenAll(_AwaitableConstraint1.WaitForReadiness(cancellationToken), _AwaitableConstraint2.WaitForReadiness(cancellationToken)); - } - catch (Exception) - { - _Semaphore.Release(); - throw; - } - return new DisposeAction(() => - { - foreach (var disposable in disposables) - { - disposable.Dispose(); - } - _Semaphore.Release(); - }); - } - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/CountByIntervalAwaitableConstraint.cs b/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/CountByIntervalAwaitableConstraint.cs deleted file mode 100644 index 460be4f..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/CountByIntervalAwaitableConstraint.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace RateLimiter -{ - /// - /// Provide an awaitable constraint based on number of times per duration - /// - public class CountByIntervalAwaitableConstraint : IAwaitableConstraint - { - /// - /// List of the last time stamps - /// - public IReadOnlyList TimeStamps => _TimeStamps.ToList(); - - /// - /// Stack of the last time stamps - /// - protected LimitedSizeStack _TimeStamps { get; } - - private int _Count { get; } - private TimeSpan _TimeSpan { get; } - private SemaphoreSlim _Semaphore { get; } = new SemaphoreSlim(1, 1); - private ITime _Time { get; } - - /// - /// Constructs a new AwaitableConstraint based on number of times per duration - /// - /// - /// - public CountByIntervalAwaitableConstraint(int count, TimeSpan timeSpan) : this(count, timeSpan, TimeSystem.StandardTime) - { - } - - internal CountByIntervalAwaitableConstraint(int count, TimeSpan timeSpan, ITime time) - { - if (count <= 0) - throw new ArgumentException("count should be strictly positive", nameof(count)); - - if (timeSpan.TotalMilliseconds <= 0) - throw new ArgumentException("timeSpan should be strictly positive", nameof(timeSpan)); - - _Count = count; - _TimeSpan = timeSpan; - _TimeStamps = new LimitedSizeStack(_Count); - _Time = time; - } - - /// - /// returns a task that will complete once the constraint is fulfilled - /// - /// - /// Cancel the wait - /// - /// - /// A disposable that should be disposed upon task completion - /// - public async Task WaitForReadiness(CancellationToken cancellationToken) - { - await _Semaphore.WaitAsync(cancellationToken); - var count = 0; - var now = _Time.GetNow(); - var target = now - _TimeSpan; - LinkedListNode element = _TimeStamps.First, last = null; - while ((element != null) && (element.Value > target)) - { - last = element; - element = element.Next; - count++; - } - - if (count < _Count) - return new DisposeAction(OnEnded); - - Debug.Assert(element == null); - Debug.Assert(last != null); - var timeToWait = last.Value.Add(_TimeSpan) - now; - try - { - await _Time.GetDelay(timeToWait, cancellationToken); - } - catch (Exception) - { - _Semaphore.Release(); - throw; - } - - return new DisposeAction(OnEnded); - } - - /// - /// Clone CountByIntervalAwaitableConstraint - /// - /// - public IAwaitableConstraint Clone() - { - return new CountByIntervalAwaitableConstraint(_Count, _TimeSpan, _Time); - } - - private void OnEnded() - { - var now = _Time.GetNow(); - _TimeStamps.Push(now); - OnEnded(now); - _Semaphore.Release(); - } - - /// - /// Called when action has been executed - /// - /// - protected virtual void OnEnded(DateTime now) - { - } - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/DisposeAction.cs b/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/DisposeAction.cs deleted file mode 100644 index 8fd44c0..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/DisposeAction.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; - -namespace RateLimiter -{ - internal class DisposeAction : IDisposable - { - private Action _Act; - - public DisposeAction(Action act) - { - _Act = act; - } - - public void Dispose() - { - _Act?.Invoke(); - _Act = null; - } - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/IAwaitableConstraint.cs b/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/IAwaitableConstraint.cs deleted file mode 100644 index a9d13d3..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/IAwaitableConstraint.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace RateLimiter -{ - /// - /// Represents a time constraints that can be awaited - /// - public interface IAwaitableConstraint - { - /// - /// returns a task that will complete once the constraint is fulfilled - /// - /// - /// Cancel the wait - /// - /// - /// A disposable that should be disposed upon task completion - /// - Task WaitForReadiness(CancellationToken cancellationToken); - - /// - /// Returns a new IAwaitableConstraint with same constraints but unused - /// - /// - IAwaitableConstraint Clone(); - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/ITime.cs b/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/ITime.cs deleted file mode 100644 index 0faa0cd..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/ITime.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace RateLimiter -{ - /// - /// Time abstraction - /// - internal interface ITime - { - /// - /// Return Now DateTime - /// - /// - DateTime GetNow(); - - /// - /// Returns a task delay - /// - /// - /// - /// - Task GetDelay(TimeSpan timespan, CancellationToken cancellationToken); - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/LimitedSizeStack.cs b/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/LimitedSizeStack.cs deleted file mode 100644 index bf1fe86..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/LimitedSizeStack.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Collections.Generic; - -namespace RateLimiter -{ - /// - /// LinkedList with a limited size - /// If the size exceeds the limit older entry are removed - /// - /// - public class LimitedSizeStack: LinkedList - { - private readonly int _MaxSize; - - /// - /// Construct the LimitedSizeStack with the given limit - /// - /// - public LimitedSizeStack(int maxSize) - { - _MaxSize = maxSize; - } - - /// - /// Push new entry. If he size exceeds the limit, the oldest entry is removed - /// - /// - public void Push(T item) - { - AddFirst(item); - - if (Count > _MaxSize) - RemoveLast(); - } - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/PersistentCountByIntervalAwaitableConstraint.cs b/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/PersistentCountByIntervalAwaitableConstraint.cs deleted file mode 100644 index cda1e92..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/PersistentCountByIntervalAwaitableConstraint.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace RateLimiter -{ - /// - /// that is able to save own state. - /// - public sealed class PersistentCountByIntervalAwaitableConstraint : CountByIntervalAwaitableConstraint - { - private readonly Action _SaveStateAction; - - /// - /// Create an instance of . - /// - /// Maximum actions allowed per time interval. - /// Time interval limits are applied for. - /// Action is used to save state. - /// Initial timestamps. - public PersistentCountByIntervalAwaitableConstraint(int count, TimeSpan timeSpan, - Action saveStateAction, IEnumerable initialTimeStamps) : base(count, timeSpan) - { - _SaveStateAction = saveStateAction; - - if (initialTimeStamps == null) - return; - - foreach (var timeStamp in initialTimeStamps) - { - _TimeStamps.Push(timeStamp); - } - } - - /// - /// Save state - /// - protected override void OnEnded(DateTime now) - { - _SaveStateAction(now); - } - } -} \ No newline at end of file diff --git a/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/TimeLimiter.cs b/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/TimeLimiter.cs deleted file mode 100644 index e36b8e9..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/TimeLimiter.cs +++ /dev/null @@ -1,206 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using ComposableAsync; - -namespace RateLimiter -{ - /// - /// TimeLimiter implementation - /// - public class TimeLimiter : IDispatcher - { - private readonly IAwaitableConstraint _AwaitableConstraint; - - internal TimeLimiter(IAwaitableConstraint awaitableConstraint) - { - _AwaitableConstraint = awaitableConstraint; - } - - /// - /// Perform the given task respecting the time constraint - /// returning the result of given function - /// - /// - /// - public Task Enqueue(Func perform) - { - return Enqueue(perform, CancellationToken.None); - } - - /// - /// Perform the given task respecting the time constraint - /// returning the result of given function - /// - /// - /// - /// - public Task Enqueue(Func> perform) - { - return Enqueue(perform, CancellationToken.None); - } - - /// - /// Perform the given task respecting the time constraint - /// - /// - /// - /// - public async Task Enqueue(Func perform, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - using (await _AwaitableConstraint.WaitForReadiness(cancellationToken)) - { - await perform(); - } - } - - /// - /// Perform the given task respecting the time constraint - /// returning the result of given function - /// - /// - /// - /// - /// - public async Task Enqueue(Func> perform, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - using (await _AwaitableConstraint.WaitForReadiness(cancellationToken)) - { - return await perform(); - } - } - - public IDispatcher Clone() => new TimeLimiter(_AwaitableConstraint.Clone()); - - private static Func Transform(Action act) - { - return () => { act(); return Task.FromResult(0); }; - } - - /// - /// Perform the given task respecting the time constraint - /// returning the result of given function - /// - /// - /// - /// - private static Func> Transform(Func compute) - { - return () => Task.FromResult(compute()); - } - - /// - /// Perform the given task respecting the time constraint - /// - /// - /// - public Task Enqueue(Action perform) - { - var transformed = Transform(perform); - return Enqueue(transformed); - } - - /// - /// Perform the given task respecting the time constraint - /// - /// - public void Dispatch(Action action) - { - Enqueue(action); - } - - /// - /// Perform the given task respecting the time constraint - /// returning the result of given function - /// - /// - /// - /// - public Task Enqueue(Func perform) - { - var transformed = Transform(perform); - return Enqueue(transformed); - } - - /// - /// Perform the given task respecting the time constraint - /// returning the result of given function - /// - /// - /// - /// - /// - public Task Enqueue(Func perform, CancellationToken cancellationToken) - { - var transformed = Transform(perform); - return Enqueue(transformed, cancellationToken); - } - - /// - /// Perform the given task respecting the time constraint - /// - /// - /// - /// - public Task Enqueue(Action perform, CancellationToken cancellationToken) - { - var transformed = Transform(perform); - return Enqueue(transformed, cancellationToken); - } - - /// - /// Returns a TimeLimiter based on a maximum number of times - /// during a given period - /// - /// - /// - /// - public static TimeLimiter GetFromMaxCountByInterval(int maxCount, TimeSpan timeSpan) - { - return new TimeLimiter(new CountByIntervalAwaitableConstraint(maxCount, timeSpan)); - } - - /// - /// Create that will save state using action passed through parameter. - /// - /// Maximum actions allowed per time interval. - /// Time interval limits are applied for. - /// Action is used to save state. - /// instance with . - public static TimeLimiter GetPersistentTimeLimiter(int maxCount, TimeSpan timeSpan, - Action saveStateAction) - { - return GetPersistentTimeLimiter(maxCount, timeSpan, saveStateAction, null); - } - - /// - /// Create with initial timestamps that will save state using action passed through parameter. - /// - /// Maximum actions allowed per time interval. - /// Time interval limits are applied for. - /// Action is used to save state. - /// Initial timestamps. - /// instance with . - public static TimeLimiter GetPersistentTimeLimiter(int maxCount, TimeSpan timeSpan, - Action saveStateAction, IEnumerable initialTimeStamps) - { - return new TimeLimiter(new PersistentCountByIntervalAwaitableConstraint(maxCount, timeSpan, saveStateAction, initialTimeStamps)); - } - - /// - /// Compose various IAwaitableConstraint in a TimeLimiter - /// - /// - /// - public static TimeLimiter Compose(params IAwaitableConstraint[] constraints) - { - var composed = constraints.Aggregate(default(IAwaitableConstraint), - (accumulated, current) => (accumulated == null) ? current : accumulated.Compose(current)); - return new TimeLimiter(composed); - } - } -} diff --git a/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/TimeSystem.cs b/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/TimeSystem.cs deleted file mode 100644 index 81b46e1..0000000 --- a/Jellyfin.Plugin.Danmu/Vendor/RateLimiter/TimeSystem.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace RateLimiter -{ - internal class TimeSystem : ITime - { - public static ITime StandardTime { get; } - - static TimeSystem() - { - StandardTime = new TimeSystem(); - } - - private TimeSystem() - { - } - - DateTime ITime.GetNow() - { - return DateTime.Now; - } - - Task ITime.GetDelay(TimeSpan timespan, CancellationToken cancellationToken) - { - return Task.Delay(timespan, cancellationToken); - } - } -} diff --git a/README.md b/README.md index e00d524..676f6db 100644 --- a/README.md +++ b/README.md @@ -74,11 +74,7 @@ ass格式: ```sh dotnet restore -dotnet publish --output=artifacts Jellyfin.Plugin.Danmu/Jellyfin.Plugin.Danmu.csproj - -# remove unused dll -cd artifacts -rm -rf MediaBrowser*.dll Microsoft*.dll Newtonsoft*.dll System*.dll Emby*.dll Jellyfin.Data*.dll Jellyfin.Extensions*.dll *.json *.pdb +dotnet publish Jellyfin.Plugin.Danmu/Jellyfin.Plugin.Danmu.csproj ``` @@ -86,7 +82,7 @@ rm -rf MediaBrowser*.dll Microsoft*.dll Newtonsoft*.dll System*.dll Emby*.dll Je 1. Build the plugin -2. Create a folder, like `danmu` and copy `artifacts/*.dll` into it +2. Create a folder, like `danmu` and copy `./Jellyfin.Plugin.Danmu/bin/Debug/net6.0/Jellyfin.Plugin.Danmu.dll` into it 3. Move folder `danmu` to jellyfin `data/plugins` folder