This commit is contained in:
Gabrieal Jimmy
2026-07-16 13:14:58 -05:00
commit f321976d70
18 changed files with 2435 additions and 0 deletions

View File

@@ -0,0 +1,76 @@
using MediaBrowser.Model.Plugins;
namespace Jellyfin.Plugin.RedditComments.Configuration;
/// <summary>
/// Plugin configuration.
/// </summary>
public class PluginConfiguration : BasePluginConfiguration
{
/// <summary>
/// Initializes a new instance of the <see cref="PluginConfiguration"/> class.
/// </summary>
public PluginConfiguration()
{
RedditClientId = string.Empty;
RedditClientSecret = string.Empty;
RedditUserAgent = "linux:jellyfin-plugin-reddit-comments:v1.0.0 (by /u/unknown)";
Subreddits = "anime";
CacheDays = 30;
NotFoundCacheHours = 24;
MaxRequestsPerMinute = 60;
MaxComments = 150;
CommentDepth = 8;
MinScore = 1;
}
/// <summary>
/// Gets or sets the Reddit app client id (create a "script" app at https://www.reddit.com/prefs/apps).
/// </summary>
public string RedditClientId { get; set; }
/// <summary>
/// Gets or sets the Reddit app client secret.
/// </summary>
public string RedditClientSecret { get; set; }
/// <summary>
/// Gets or sets the User-Agent sent to Reddit. Reddit requires a unique, descriptive value.
/// </summary>
public string RedditUserAgent { get; set; }
/// <summary>
/// Gets or sets the comma-separated list of subreddits to search, in order (without the r/ prefix).
/// </summary>
public string Subreddits { get; set; }
/// <summary>
/// Gets or sets how many days a found thread is cached before it is fetched again.
/// </summary>
public int CacheDays { get; set; }
/// <summary>
/// Gets or sets how many hours a "no thread found" result is cached.
/// </summary>
public int NotFoundCacheHours { get; set; }
/// <summary>
/// Gets or sets the maximum number of Reddit API requests per minute (Reddit's own limit is 100).
/// </summary>
public int MaxRequestsPerMinute { get; set; }
/// <summary>
/// Gets or sets the maximum number of comments requested from Reddit per thread.
/// </summary>
public int MaxComments { get; set; }
/// <summary>
/// Gets or sets the maximum reply depth requested from Reddit.
/// </summary>
public int CommentDepth { get; set; }
/// <summary>
/// Gets or sets the minimum score a comment must have to be shown.
/// </summary>
public int MinScore { get; set; }
}

View File

@@ -0,0 +1,168 @@
<div id="RedditCommentsConfigPage" data-role="page" class="page type-interior pluginConfigurationPage" data-require="emby-input,emby-button">
<div data-role="content">
<div class="content-primary">
<style>
#RedditCommentsConfigPage .rc-accent { color: #a55aea; }
#RedditCommentsConfigPage .rc-info {
border-left: 3px solid #a55aea;
background: rgba(165, 90, 234, 0.08);
border-radius: 0.4em;
padding: 1em 1.2em;
margin-bottom: 1.5em;
line-height: 1.55;
}
#RedditCommentsConfigPage .rc-info ol { margin: 0.5em 0 0; padding-left: 1.4em; }
#RedditCommentsConfigPage .rc-info code {
background: rgba(165, 90, 234, 0.15);
border-radius: 0.3em;
padding: 0.1em 0.4em;
}
#RedditCommentsConfigPage .rc-section {
font-size: 1.1em;
font-weight: 600;
margin: 1.6em 0 0.6em;
padding-bottom: 0.3em;
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
#RedditCommentsConfigPage .rc-test-result { margin-left: 1em; font-weight: 600; }
</style>
<h2 style="margin-top:0;">Reddit Comments <span class="rc-accent" id="rcVersion"></span></h2>
<div class="rc-info">
<strong>Reddit API setup (one time):</strong>
<ol>
<li>Go to <a href="https://www.reddit.com/prefs/apps" target="_blank" rel="noopener" class="rc-accent">reddit.com/prefs/apps</a> and click <em>create app</em>.</li>
<li>Choose type <code>script</code>, any name, and <code>http://localhost</code> as the redirect uri.</li>
<li>Copy the <strong>client id</strong> (under the app name) and the <strong>secret</strong> into the fields below.</li>
</ol>
</div>
<form id="RedditCommentsConfigForm">
<div class="rc-section rc-accent">Reddit API</div>
<div class="inputContainer">
<label class="inputLabel inputLabelUnfocused" for="RedditClientId">Client ID</label>
<input is="emby-input" type="text" id="RedditClientId" />
</div>
<div class="inputContainer">
<label class="inputLabel inputLabelUnfocused" for="RedditClientSecret">Client Secret</label>
<input is="emby-input" type="password" id="RedditClientSecret" />
</div>
<div class="inputContainer">
<label class="inputLabel inputLabelUnfocused" for="RedditUserAgent">User Agent</label>
<input is="emby-input" type="text" id="RedditUserAgent" />
<div class="fieldDescription">Reddit requires a unique, descriptive user agent, e.g. <code>linux:jellyfin-reddit-comments:v1.0 (by /u/yourname)</code>.</div>
</div>
<button is="emby-button" type="button" id="rcTestButton" class="raised button-block">
<span>Test connection</span>
</button>
<span id="rcTestResult" class="rc-test-result"></span>
<div class="rc-section rc-accent">Search</div>
<div class="inputContainer">
<label class="inputLabel inputLabelUnfocused" for="Subreddits">Subreddits</label>
<input is="emby-input" type="text" id="Subreddits" />
<div class="fieldDescription">Comma-separated, without the r/ prefix. Searched in order. Default: <code>anime</code></div>
</div>
<div class="rc-section rc-accent">Caching &amp; rate limits</div>
<div class="inputContainer">
<label class="inputLabel inputLabelUnfocused" for="CacheDays">Cache found threads for (days)</label>
<input is="emby-input" type="number" id="CacheDays" min="1" max="365" />
</div>
<div class="inputContainer">
<label class="inputLabel inputLabelUnfocused" for="NotFoundCacheHours">Cache "not found" results for (hours)</label>
<input is="emby-input" type="number" id="NotFoundCacheHours" min="1" max="720" />
</div>
<div class="inputContainer">
<label class="inputLabel inputLabelUnfocused" for="MaxRequestsPerMinute">Max Reddit requests per minute</label>
<input is="emby-input" type="number" id="MaxRequestsPerMinute" min="1" max="100" />
<div class="fieldDescription">Hard cap enforced by the plugin. Reddit's own limit is 100/min; 60 is a safe default.</div>
</div>
<div class="rc-section rc-accent">Comments</div>
<div class="inputContainer">
<label class="inputLabel inputLabelUnfocused" for="MaxComments">Max comments per thread</label>
<input is="emby-input" type="number" id="MaxComments" min="1" max="500" />
</div>
<div class="inputContainer">
<label class="inputLabel inputLabelUnfocused" for="CommentDepth">Max reply depth</label>
<input is="emby-input" type="number" id="CommentDepth" min="1" max="10" />
</div>
<div class="inputContainer">
<label class="inputLabel inputLabelUnfocused" for="MinScore">Minimum comment score</label>
<input is="emby-input" type="number" id="MinScore" min="-100" max="1000" />
<div class="fieldDescription">Comments below this score are hidden. 1 filters out downvoted comments.</div>
</div>
<button is="emby-button" type="submit" class="raised button-submit block">
<span>Save</span>
</button>
</form>
</div>
</div>
<script type="text/javascript">
(function () {
var pluginId = '7b2f1c4e-9a3d-4f6b-8c5e-2d1a0f9e7b6c';
var page = document.querySelector('#RedditCommentsConfigPage');
page.addEventListener('pageshow', function () {
Dashboard.showLoadingMsg();
ApiClient.getPluginConfiguration(pluginId).then(function (config) {
page.querySelector('#RedditClientId').value = config.RedditClientId || '';
page.querySelector('#RedditClientSecret').value = config.RedditClientSecret || '';
page.querySelector('#RedditUserAgent').value = config.RedditUserAgent || '';
page.querySelector('#Subreddits').value = config.Subreddits || 'anime';
page.querySelector('#CacheDays').value = config.CacheDays;
page.querySelector('#NotFoundCacheHours').value = config.NotFoundCacheHours;
page.querySelector('#MaxRequestsPerMinute').value = config.MaxRequestsPerMinute;
page.querySelector('#MaxComments').value = config.MaxComments;
page.querySelector('#CommentDepth').value = config.CommentDepth;
page.querySelector('#MinScore').value = config.MinScore;
Dashboard.hideLoadingMsg();
});
});
page.querySelector('#rcTestButton').addEventListener('click', function () {
var result = page.querySelector('#rcTestResult');
result.textContent = 'Testing...';
result.style.color = '#aaa';
ApiClient.getJSON(ApiClient.getUrl('RedditComments/Test')).then(function (response) {
result.textContent = response.message;
result.style.color = response.ok ? '#a55aea' : '#e57373';
}).catch(function (err) {
result.textContent = 'Test failed: ' + (err && err.message ? err.message : 'unknown error');
result.style.color = '#e57373';
});
});
page.querySelector('#RedditCommentsConfigForm').addEventListener('submit', function (e) {
e.preventDefault();
Dashboard.showLoadingMsg();
ApiClient.getPluginConfiguration(pluginId).then(function (config) {
config.RedditClientId = page.querySelector('#RedditClientId').value.trim();
config.RedditClientSecret = page.querySelector('#RedditClientSecret').value.trim();
config.RedditUserAgent = page.querySelector('#RedditUserAgent').value.trim();
config.Subreddits = page.querySelector('#Subreddits').value.trim();
config.CacheDays = parseInt(page.querySelector('#CacheDays').value, 10) || 30;
config.NotFoundCacheHours = parseInt(page.querySelector('#NotFoundCacheHours').value, 10) || 24;
config.MaxRequestsPerMinute = parseInt(page.querySelector('#MaxRequestsPerMinute').value, 10) || 60;
config.MaxComments = parseInt(page.querySelector('#MaxComments').value, 10) || 150;
config.CommentDepth = parseInt(page.querySelector('#CommentDepth').value, 10) || 8;
config.MinScore = parseInt(page.querySelector('#MinScore').value, 10);
if (isNaN(config.MinScore)) { config.MinScore = 1; }
ApiClient.updatePluginConfiguration(pluginId, config).then(function (result) {
Dashboard.processPluginConfigurationUpdateResult(result);
});
});
return false;
});
})();
</script>
</div>