using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Globalization; using System.Net.Mime; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace ConfusedPolarBear.Plugin.IntroSkipper.Controllers; /// <summary> /// Audio fingerprint visualization controller. Allows browsing fingerprints on a per episode basis. /// </summary> [Authorize(Policy = "RequiresElevation")] [ApiController] [Produces(MediaTypeNames.Application.Json)] [Route("Intros")] public class VisualizationController : ControllerBase { /// <summary> /// Initializes a new instance of the <see cref="VisualizationController"/> class. /// </summary> public VisualizationController() { } /// <summary> /// Returns all show names and seasons. /// </summary> /// <returns>Dictionary of show names to a list of season names.</returns> [HttpGet("Shows")] public ActionResult<Dictionary<string, HashSet<string>>> GetShowSeasons() { var showSeasons = new Dictionary<string, HashSet<string>>(); // Loop through all episodes in the analysis queue foreach (var episodes in Plugin.Instance!.AnalysisQueue) { foreach (var episode in episodes.Value) { // Add each season's name to the series hashset var series = episode.SeriesName; if (!showSeasons.ContainsKey(series)) { showSeasons[series] = new HashSet<string>(); } showSeasons[series].Add(GetSeasonName(episode)); } } return showSeasons; } /// <summary> /// Returns the names and unique identifiers of all episodes in the provided season. /// </summary> /// <param name="series">Show name.</param> /// <param name="season">Season name.</param> /// <returns>List of episode titles.</returns> [HttpGet("Show/{Series}/{Season}")] public ActionResult<List<EpisodeVisualization>> GetSeasonEpisodes( [FromRoute] string series, [FromRoute] string season) { var episodes = new List<EpisodeVisualization>(); foreach (var queuedEpisodes in Plugin.Instance!.AnalysisQueue) { var first = queuedEpisodes.Value[0]; var firstSeasonName = GetSeasonName(first); // Assert that the queued episode series and season are equal to what was requested if ( !string.Equals(first.SeriesName, series, StringComparison.OrdinalIgnoreCase) || !string.Equals(firstSeasonName, season, StringComparison.OrdinalIgnoreCase)) { continue; } foreach (var queuedEpisode in queuedEpisodes.Value) { episodes.Add(new EpisodeVisualization(queuedEpisode.EpisodeId, queuedEpisode.Name)); } } return episodes; } /// <summary> /// Fingerprint the provided episode and returns the uncompressed fingerprint data points. /// </summary> /// <param name="id">Episode id.</param> /// <returns>Read only collection of fingerprint points.</returns> [HttpGet("Fingerprint/{Id}")] public ActionResult<ReadOnlyCollection<uint>> GetEpisodeFingerprint([FromRoute] Guid id) { var queue = Plugin.Instance!.AnalysisQueue; // Search through all queued episodes to find the requested id foreach (var season in queue) { foreach (var needle in season.Value) { if (needle.EpisodeId == id) { return FPCalc.Fingerprint(needle); } } } return NotFound(); } private string GetSeasonName(QueuedEpisode episode) { return "Season " + episode.SeasonNumber.ToString(CultureInfo.InvariantCulture); } }