init
This commit is contained in:
170
Jellyfin.Plugin.RedditComments/Api/RedditCommentsController.cs
Normal file
170
Jellyfin.Plugin.RedditComments/Api/RedditCommentsController.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Plugin.RedditComments.Models;
|
||||
using Jellyfin.Plugin.RedditComments.Services;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Jellyfin.Plugin.RedditComments.Api;
|
||||
|
||||
/// <summary>
|
||||
/// API endpoints for the Reddit Comments plugin.
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("RedditComments")]
|
||||
public class RedditCommentsController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<RedditCommentsController> _logger;
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly RedditCommentsService _commentsService;
|
||||
private readonly RedditClient _redditClient;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RedditCommentsController"/> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">Logger.</param>
|
||||
/// <param name="libraryManager">Library manager.</param>
|
||||
/// <param name="commentsService">Comments service.</param>
|
||||
/// <param name="redditClient">Reddit client.</param>
|
||||
public RedditCommentsController(
|
||||
ILogger<RedditCommentsController> logger,
|
||||
ILibraryManager libraryManager,
|
||||
RedditCommentsService commentsService,
|
||||
RedditClient redditClient)
|
||||
{
|
||||
_logger = logger;
|
||||
_libraryManager = libraryManager;
|
||||
_commentsService = commentsService;
|
||||
_redditClient = redditClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Reddit discussion comments for a Jellyfin item. Served from the local cache
|
||||
/// unless this is the first lookup or the cache expired.
|
||||
/// </summary>
|
||||
/// <param name="itemId">The Jellyfin item id.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The comments response.</returns>
|
||||
[HttpGet("Item/{itemId}")]
|
||||
[Authorize]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<CommentsResponse>> GetComments([FromRoute] Guid itemId, CancellationToken cancellationToken)
|
||||
{
|
||||
var item = _libraryManager.GetItemById(itemId);
|
||||
if (item is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return await _commentsService.GetForItemAsync(item, forceRefresh: false, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to get Reddit comments for item {ItemId}", itemId);
|
||||
return new CommentsResponse
|
||||
{
|
||||
Found = false,
|
||||
ItemId = itemId.ToString("N", CultureInfo.InvariantCulture),
|
||||
Message = "Failed to fetch Reddit comments: " + ex.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forces a fresh lookup for an item, bypassing and replacing the cache.
|
||||
/// </summary>
|
||||
/// <param name="itemId">The Jellyfin item id.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>The comments response.</returns>
|
||||
[HttpPost("Item/{itemId}/Refresh")]
|
||||
[Authorize]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<CommentsResponse>> RefreshComments([FromRoute] Guid itemId, CancellationToken cancellationToken)
|
||||
{
|
||||
var item = _libraryManager.GetItemById(itemId);
|
||||
if (item is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return await _commentsService.GetForItemAsync(item, forceRefresh: true, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to refresh Reddit comments for item {ItemId}", itemId);
|
||||
return new CommentsResponse
|
||||
{
|
||||
Found = false,
|
||||
ItemId = itemId.ToString("N", CultureInfo.InvariantCulture),
|
||||
Message = "Failed to fetch Reddit comments: " + ex.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests the configured Reddit API credentials. Admin only.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>Whether the credentials work.</returns>
|
||||
[HttpGet("Test")]
|
||||
[Authorize(Policy = "RequiresElevation")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<object>> TestCredentials(CancellationToken cancellationToken)
|
||||
{
|
||||
if (!RedditClient.IsConfigured)
|
||||
{
|
||||
return new { ok = false, message = "Client id and secret are not configured." };
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await _redditClient.TestCredentialsAsync(cancellationToken).ConfigureAwait(false);
|
||||
return new { ok = true, message = "Successfully authenticated with Reddit." };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new { ok = false, message = ex.Message };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serves the web client script that adds the comments button/sidebar to the player.
|
||||
/// </summary>
|
||||
/// <returns>The JavaScript file.</returns>
|
||||
[HttpGet("Static/reddit-comments.js")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public ActionResult GetScript()
|
||||
{
|
||||
var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Jellyfin.Plugin.RedditComments.Web.reddit-comments.js");
|
||||
if (stream is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
// Cache for an hour so restarts/plugin updates pick up changes reasonably fast.
|
||||
Response.Headers.CacheControl = "public, max-age=3600";
|
||||
return File(stream, "text/javascript");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user