When no custom directory is set, recordings go to an "SRF Recordings" folder in the chosen library, or the first TV Shows library, so they show up without adding a library by hand. The settings page gets a library picker, a check that the directory is writable, and help for sandboxed systemd services. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
231 lines
8.3 KiB
C#
231 lines
8.3 KiB
C#
using MediaBrowser.Model.Plugins;
|
|
|
|
namespace Jellyfin.Plugin.SRFPlay.Configuration;
|
|
|
|
/// <summary>
|
|
/// Business unit options for SRF content.
|
|
/// </summary>
|
|
public enum BusinessUnit
|
|
{
|
|
/// <summary>
|
|
/// SRF (Swiss Radio and Television - German).
|
|
/// </summary>
|
|
SRF,
|
|
|
|
/// <summary>
|
|
/// RTS (Radio Télévision Suisse - French).
|
|
/// </summary>
|
|
RTS,
|
|
|
|
/// <summary>
|
|
/// RSI (Radiotelevisione svizzera - Italian).
|
|
/// </summary>
|
|
RSI,
|
|
|
|
/// <summary>
|
|
/// RTR (Radiotelevisiun Svizra Rumantscha - Romansh).
|
|
/// </summary>
|
|
RTR,
|
|
|
|
/// <summary>
|
|
/// SWI (Swiss World International).
|
|
/// </summary>
|
|
SWI
|
|
}
|
|
|
|
/// <summary>
|
|
/// Quality preference for video streams.
|
|
/// </summary>
|
|
public enum QualityPreference
|
|
{
|
|
/// <summary>
|
|
/// Automatic quality selection.
|
|
/// </summary>
|
|
Auto,
|
|
|
|
/// <summary>
|
|
/// Standard definition.
|
|
/// </summary>
|
|
SD,
|
|
|
|
/// <summary>
|
|
/// High definition.
|
|
/// </summary>
|
|
HD
|
|
}
|
|
|
|
/// <summary>
|
|
/// Plugin configuration.
|
|
/// </summary>
|
|
public class PluginConfiguration : BasePluginConfiguration
|
|
{
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="PluginConfiguration"/> class.
|
|
/// </summary>
|
|
public PluginConfiguration()
|
|
{
|
|
// Set default options
|
|
BusinessUnit = BusinessUnit.SRF;
|
|
QualityPreference = QualityPreference.Auto;
|
|
ContentRefreshIntervalHours = 6;
|
|
ExpirationCheckIntervalHours = 24;
|
|
CacheDurationMinutes = 60;
|
|
EnableLatestContent = true;
|
|
EnableTrendingContent = true;
|
|
EnableCategoryFolders = true;
|
|
EnabledTopics = new System.Collections.Generic.List<string>();
|
|
GenerateTitleCards = true;
|
|
LiveStartSegmentsBack = 3;
|
|
CleanUpResumePoints = true;
|
|
ClearLiveStreamResumePoints = true;
|
|
ResumePointMaxAgeDays = 30;
|
|
ResumePointMinPositionSeconds = 60;
|
|
ResumePointCompletedPercent = 92;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets the legacy single business unit. Retained only for backwards compatibility
|
|
/// with older configs; every unit now has its own always-on channel.
|
|
/// </summary>
|
|
public BusinessUnit BusinessUnit { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the preferred video quality.
|
|
/// </summary>
|
|
public QualityPreference QualityPreference { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the content refresh interval in hours.
|
|
/// </summary>
|
|
public int ContentRefreshIntervalHours { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the expiration check interval in hours.
|
|
/// </summary>
|
|
public int ExpirationCheckIntervalHours { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the metadata cache duration in minutes.
|
|
/// </summary>
|
|
public int CacheDurationMinutes { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether to enable latest content discovery.
|
|
/// </summary>
|
|
public bool EnableLatestContent { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether to enable trending content discovery.
|
|
/// </summary>
|
|
public bool EnableTrendingContent { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether to use a proxy for API requests.
|
|
/// </summary>
|
|
public bool UseProxy { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the proxy server address (e.g., http://proxy.example.com:8080).
|
|
/// </summary>
|
|
public string ProxyAddress { get; set; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the proxy username (optional).
|
|
/// </summary>
|
|
public string ProxyUsername { get; set; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the proxy password (optional).
|
|
/// </summary>
|
|
public string ProxyPassword { get; set; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether to enable category/topic folders in the channel.
|
|
/// </summary>
|
|
public bool EnableCategoryFolders { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the list of enabled topic IDs. If empty, all topics are shown.
|
|
/// </summary>
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "Required for configuration serialization")]
|
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1002:Do not expose generic lists", Justification = "Configuration DTO")]
|
|
public System.Collections.Generic.List<string> EnabledTopics { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the public/external server URL for remote clients (e.g., https://jellyfin.example.com:8920).
|
|
/// If not set, the plugin will use Jellyfin's GetSmartApiUrl() which may return local addresses.
|
|
/// This is important for Android and other remote clients to access streams.
|
|
/// </summary>
|
|
public string PublicServerUrl { get; set; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether to generate title card images with the content title.
|
|
/// When enabled, generates custom thumbnails instead of using SRF-provided images.
|
|
/// </summary>
|
|
public bool GenerateTitleCards { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a custom output directory for livestream recordings. Takes precedence over
|
|
/// <see cref="RecordingLibraryId"/>. Empty means record into a library.
|
|
/// </summary>
|
|
public string RecordingOutputPath { get; set; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the ItemId of the library to record into. Recordings go into an
|
|
/// "SRF Recordings" folder in the library's first location. Empty picks the first
|
|
/// TV Shows library, so recordings show up without adding a library by hand.
|
|
/// </summary>
|
|
public string RecordingLibraryId { get; set; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the time zone used for times the plugin writes as text: the start time in
|
|
/// upcoming livestream names and the timestamp in recording file names. An IANA id such as
|
|
/// "Europe/Zurich"; empty uses the server's time zone. Dates Jellyfin shows itself (e.g.
|
|
/// PremiereDate) are stored as UTC and follow each viewer's own time zone regardless.
|
|
/// </summary>
|
|
public string DisplayTimeZone { get; set; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// Gets or sets how many segments back from the live edge livestream playback should start.
|
|
/// Injected as <c>#EXT-X-START:TIME-OFFSET=-(N * targetDuration)</c> into the live media
|
|
/// playlist. This keeps the start point out of the volatile live edge, which on Android TV
|
|
/// (ExoPlayer) otherwise causes stalling/jumping until a manual skip. RFC 8216 requires the
|
|
/// offset to stay at least 3 target durations from the edge, so values below 3 are clamped.
|
|
/// Set to 0 to disable injection entirely.
|
|
/// </summary>
|
|
public int LiveStartSegmentsBack { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether the "Clean Up SRF Play Continue Watching" task
|
|
/// removes stale resume points. When false the task inspects nothing and clears nothing.
|
|
/// </summary>
|
|
public bool CleanUpResumePoints { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether resume points for livestreams are cleared.
|
|
/// A livestream has no meaningful resume position, so stopping one otherwise leaves it
|
|
/// pinned in "Continue Watching" forever. When enabled the position is also cleared
|
|
/// immediately on playback stop, not just by the scheduled task.
|
|
/// </summary>
|
|
public bool ClearLiveStreamResumePoints { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the age in days after which an untouched resume point is cleared.
|
|
/// Measured from the last time the item was played. Set to 0 to disable the age rule.
|
|
/// </summary>
|
|
public int ResumePointMaxAgeDays { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the minimum resume position in seconds. Anything at or below this is
|
|
/// treated as an accidental start rather than something worth resuming.
|
|
/// Set to 0 to disable the rule.
|
|
/// </summary>
|
|
public int ResumePointMinPositionSeconds { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the percentage of runtime at or beyond which playback counts as finished.
|
|
/// Only applied to items with a known runtime. Set to 0 to disable the rule.
|
|
/// </summary>
|
|
public int ResumePointCompletedPercent { get; set; }
|
|
}
|