diff --git a/Jellyfin.Plugin.ShareLinks/Api/ShareLinksController.cs b/Jellyfin.Plugin.ShareLinks/Api/ShareLinksController.cs
index 096f24b..e63c564 100644
--- a/Jellyfin.Plugin.ShareLinks/Api/ShareLinksController.cs
+++ b/Jellyfin.Plugin.ShareLinks/Api/ShareLinksController.cs
@@ -269,6 +269,21 @@ public sealed class ShareLinksController : ControllerBase
return Ok(ToDto(record));
}
+ /// Removes revoked, expired and failed share links from the store.
+ [HttpPost("Admin/Cleanup")]
+ [Authorize(AuthenticationSchemes = "CustomAuthentication")]
+ public async Task Cleanup(CancellationToken cancellationToken)
+ {
+ SetNoStoreHeaders();
+ if (!User.IsInRole("Administrator"))
+ {
+ return Forbid();
+ }
+
+ var removed = await _cleanupService.PurgeFinishedAsync(cancellationToken).ConfigureAwait(false);
+ return Ok(new { removed });
+ }
+
/// Returns the guest session state for the current authenticated user.
[HttpGet("GuestState")]
[Authorize(AuthenticationSchemes = "CustomAuthentication")]
diff --git a/Jellyfin.Plugin.ShareLinks/Jellyfin.Plugin.ShareLinks.csproj b/Jellyfin.Plugin.ShareLinks/Jellyfin.Plugin.ShareLinks.csproj
index c3e6ad3..672176a 100644
--- a/Jellyfin.Plugin.ShareLinks/Jellyfin.Plugin.ShareLinks.csproj
+++ b/Jellyfin.Plugin.ShareLinks/Jellyfin.Plugin.ShareLinks.csproj
@@ -6,9 +6,9 @@
latestJellyfin.Plugin.ShareLinksJellyfin.Plugin.ShareLinks
- 1.0.3.1
- 1.0.3.1
- 1.0.3.1
+ 1.0.3.0
+ 1.0.3.0
+ 1.0.3.0truefalsedisable
diff --git a/Jellyfin.Plugin.ShareLinks/Services/ShareLinkCleanupService.cs b/Jellyfin.Plugin.ShareLinks/Services/ShareLinkCleanupService.cs
index b8a587c..04ca99e 100644
--- a/Jellyfin.Plugin.ShareLinks/Services/ShareLinkCleanupService.cs
+++ b/Jellyfin.Plugin.ShareLinks/Services/ShareLinkCleanupService.cs
@@ -75,6 +75,40 @@ public sealed class ShareLinkCleanupService : IShareLinkCleanupService
await CleanupRecordInternalAsync(record, records, force, cancellationToken).ConfigureAwait(false);
}
+ ///
+ /// Runs a normal cleanup pass and then drops every record that is finished
+ /// with, so the admin list does not grow forever. A link that can still be
+ /// used is never removed, and neither is one whose guest is still watching.
+ ///
+ public async Task PurgeFinishedAsync(CancellationToken cancellationToken)
+ {
+ // Teardown first: this expires anything past its date and removes the guest
+ // account and tags, so nothing is dropped from the store while it still has
+ // state hanging off it.
+ await CleanupAsync(cancellationToken).ConfigureAwait(false);
+
+ var records = await _store.ListAsync(cancellationToken).ConfigureAwait(false);
+ var removed = 0;
+ foreach (var record in records)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ if (record.Status is not (ShareLinkStatus.Expired or ShareLinkStatus.Revoked or ShareLinkStatus.Failed))
+ {
+ continue;
+ }
+
+ await _store.DeleteAsync(record.Id, cancellationToken).ConfigureAwait(false);
+ removed++;
+ }
+
+ if (removed > 0)
+ {
+ _logger.LogInformation("ShareLinks: purged {Count} finished share-link record(s).", removed);
+ }
+
+ return removed;
+ }
+
private async Task CleanupRecordInternalAsync(
ShareLinkRecord record,
IReadOnlyList allRecords,
diff --git a/Jellyfin.Plugin.ShareLinks/Web/configPage.html b/Jellyfin.Plugin.ShareLinks/Web/configPage.html
index a69f826..e4a1e62 100644
--- a/Jellyfin.Plugin.ShareLinks/Web/configPage.html
+++ b/Jellyfin.Plugin.ShareLinks/Web/configPage.html
@@ -173,6 +173,9 @@
+
Loading…