feat: prioritise and blacklist media and overview in setting page of progress in adding info
🏗️ Build Plugin / build (push) Successful in 1m16s
Latest Release / latest-release (push) Successful in 27s
🧪 Test Plugin / test (push) Successful in 20s
🚀 Release Plugin / build-and-release (push) Successful in 24s

This commit is contained in:
2026-07-04 21:08:59 +02:00
parent bb02c0f9b9
commit f6762fcf29
17 changed files with 1211 additions and 16 deletions
@@ -0,0 +1,22 @@
using System.Text.Json.Serialization;
namespace Jellyfin.Plugin.JRay.Models;
/// <summary>
/// One labelled row of a coverage breakdown (e.g. a single genre, or a single
/// media type such as "Film" or "TV").
/// </summary>
public class CoverageBreakdownRow
{
/// <summary>
/// Gets or sets the label for this row (genre name or media type name).
/// </summary>
[JsonPropertyName("label")]
public string Label { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the coverage counts for this row.
/// </summary>
[JsonPropertyName("counts")]
public CoverageCounts Counts { get; set; } = new();
}
@@ -0,0 +1,41 @@
using System.Text.Json.Serialization;
namespace Jellyfin.Plugin.JRay.Models;
/// <summary>
/// A count of library items bucketed by JRay coverage status. Used both for
/// the overall totals and for each per-genre / per-media-type breakdown row.
/// </summary>
public class CoverageCounts
{
/// <summary>
/// Gets or sets the total number of items in this bucket.
/// </summary>
[JsonPropertyName("total")]
public int Total { get; set; }
/// <summary>
/// Gets or sets the number of items that already have truth data.
/// </summary>
[JsonPropertyName("covered")]
public int Covered { get; set; }
/// <summary>
/// Gets or sets the number of items awaiting processing (no truth data,
/// not ignored). Includes prioritised-but-not-yet-covered items.
/// </summary>
[JsonPropertyName("pending")]
public int Pending { get; set; }
/// <summary>
/// Gets or sets the number of pending items that are prioritised.
/// </summary>
[JsonPropertyName("prioritised")]
public int Prioritised { get; set; }
/// <summary>
/// Gets or sets the number of items excluded from processing by an ignore rule.
/// </summary>
[JsonPropertyName("ignored")]
public int Ignored { get; set; }
}
@@ -0,0 +1,31 @@
using System.Collections.ObjectModel;
using System.Text.Json.Serialization;
namespace Jellyfin.Plugin.JRay.Models;
/// <summary>
/// A snapshot of how much of the library has truth data, with overall totals
/// and breakdowns by media type and by genre.
/// </summary>
public class CoverageReport
{
/// <summary>
/// Gets or sets the coverage counts across the whole library.
/// </summary>
[JsonPropertyName("total")]
public CoverageCounts Total { get; set; } = new();
/// <summary>
/// Gets the per-media-type breakdown (Film vs TV).
/// </summary>
[JsonPropertyName("by_media_type")]
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
public Collection<CoverageBreakdownRow> ByMediaType { get; } = new();
/// <summary>
/// Gets the per-genre breakdown, one row per genre present in the library.
/// </summary>
[JsonPropertyName("by_genre")]
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
public Collection<CoverageBreakdownRow> ByGenre { get; } = new();
}
@@ -0,0 +1,38 @@
using System.Text.Json.Serialization;
namespace Jellyfin.Plugin.JRay.Models;
/// <summary>
/// A single prioritise/ignore rule. A rule is uniquely identified by its
/// <see cref="Scope"/> and <see cref="Value"/>; setting a new action for an
/// existing scope+value replaces the previous one.
/// </summary>
public class MediaPolicyRule
{
/// <summary>
/// Gets or sets the scope this rule targets (genre, series, or item).
/// </summary>
[JsonPropertyName("scope")]
public PolicyScope Scope { get; set; }
/// <summary>
/// Gets or sets the target value: a genre name for <see cref="PolicyScope.Genre"/>,
/// a series id for <see cref="PolicyScope.Series"/>, or an item id for
/// <see cref="PolicyScope.Item"/>.
/// </summary>
[JsonPropertyName("value")]
public string Value { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the action to apply (prioritise or ignore).
/// </summary>
[JsonPropertyName("action")]
public PolicyAction Action { get; set; }
/// <summary>
/// Gets or sets an optional human-readable label for the target (e.g. the
/// series or item display name), shown in the rules list. Informational only.
/// </summary>
[JsonPropertyName("label")]
public string Label { get; set; } = string.Empty;
}
@@ -0,0 +1,23 @@
using System.Text.Json.Serialization;
namespace Jellyfin.Plugin.JRay.Models;
/// <summary>
/// A selectable option for the config page's rule editor (a genre or a series),
/// pairing the value stored in a rule with a human-readable label.
/// </summary>
public class PickerOption
{
/// <summary>
/// Gets or sets the value stored in a <see cref="MediaPolicyRule"/>
/// (a genre name, or a series id).
/// </summary>
[JsonPropertyName("value")]
public string Value { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the label shown to the user (genre name, or series title).
/// </summary>
[JsonPropertyName("label")]
public string Label { get; set; } = string.Empty;
}
@@ -0,0 +1,15 @@
namespace Jellyfin.Plugin.JRay.Models;
/// <summary>
/// The action a <see cref="MediaPolicyRule"/> applies to matching items.
/// A given scope+value can hold at most one action at a time, so an item
/// can never be both prioritised and ignored by the same target.
/// </summary>
public enum PolicyAction
{
/// <summary>Push matching items to the front of the work queue.</summary>
Prioritise,
/// <summary>Exclude matching items from the work queue entirely.</summary>
Ignore
}
@@ -0,0 +1,18 @@
namespace Jellyfin.Plugin.JRay.Models;
/// <summary>
/// The scope a <see cref="MediaPolicyRule"/> targets. More specific scopes
/// override broader ones when resolving an item's effective policy
/// (Item &gt; Series &gt; Genre).
/// </summary>
public enum PolicyScope
{
/// <summary>Matches every item that carries a given genre.</summary>
Genre,
/// <summary>Matches every episode of a given series (by series id).</summary>
Series,
/// <summary>Matches a single library item (by item id).</summary>
Item
}