summaryrefslogtreecommitdiff
path: root/Api
diff options
context:
space:
mode:
Diffstat (limited to 'Api')
-rw-r--r--Api/JCoverSharedController.cs132
-rw-r--r--Api/coverscript.js37
2 files changed, 164 insertions, 5 deletions
diff --git a/Api/JCoverSharedController.cs b/Api/JCoverSharedController.cs
index a5eecc1..47a8c8a 100644
--- a/Api/JCoverSharedController.cs
+++ b/Api/JCoverSharedController.cs
@@ -1,9 +1,139 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Web;
+using Jellyfin.Api;
+using MediaBrowser.Controller;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
namespace Jellyfin.Plugin.JCoverXtremePro.Api;
[ApiController]
[Route("JCoverXtreme")]
-public class JCoverSharedController : ControllerBase
+// [Authorize(Policy = "RequiresElevation")]
+public class JCoverSharedController : BaseJellyfinApiController
{
+ private readonly IProviderManager _providerManager;
+ private readonly ILibraryManager _libraryManager;
+
+ /// <summary>
+ /// This key is appended to image URLs to inform the frontend about the presence of a potential mass-download.
+ /// Keep in sync with coverscript.js#URL_META_KEY.
+ /// </summary>
+ public static string URL_META_KEY = "JCoverXtremeProMeta";
+
+ public JCoverSharedController(
+ IProviderManager providerManager,
+ IServerApplicationPaths applicationPaths,
+ ILibraryManager libraryManager)
+ {
+ _providerManager = providerManager;
+ _libraryManager = libraryManager;
+ }
+
+ public static string AppendUrlMeta(string baseUrl, string key, string value)
+ {
+ return baseUrl + (baseUrl.Contains('?', StringComparison.InvariantCulture) ? "&" : "?") +
+ HttpUtility.UrlEncode(key) + "=" + HttpUtility.UrlEncode(value);
+ }
+
+ public class SetMeta
+ {
+ public Guid seriesId { get; set; }
+ public string setId { get; set; }
+ }
+
+ public static string PackSetInfo(string baseUrl, Series series, POJO.Set set)
+ {
+ return AppendUrlMeta(
+ baseUrl,
+ URL_META_KEY,
+ JsonSerializer.Serialize(new SetMeta
+ {
+ setId = set.id,
+ seriesId = series.Id
+ }));
+ }
+
+ [HttpPost("DownloadSeries")]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ public async Task<ActionResult> DownloadEntireSeriesImages(
+ [FromBody, Required] JsonObject setMeta
+ )
+ {
+ // TODO: handle missing fields, local seasons missing, series missing, etc.
+ var setMetaObj = JsonSerializer.Deserialize<SetMeta>(setMeta);
+ var series = _libraryManager.GetItemById(setMetaObj.seriesId) as Series;
+ var jsonMeta = await MediuxDownloader.instance.GetMediuxMetadata($"https://mediux.pro/sets/{setMetaObj.setId}")
+ .ConfigureAwait(false);
+ var set = JsonSerializer.Deserialize<POJO.SetData>(jsonMeta).set;
+ Dictionary<string, (int, int)> lut = new();
+ foreach (var showSeason in set.show.seasons)
+ {
+ foreach (var showEpisode in showSeason.episodes)
+ {
+ lut[showEpisode.id] = (showSeason.season_number, showEpisode.episode_number);
+ }
+ }
+
+ Dictionary<(int, int), POJO.File> files = new();
+ foreach (var file in set.files)
+ {
+ var episode = file.episode_id;
+ if (episode == null)
+ {
+ continue;
+ }
+
+ var tup = lut[episode.id];
+ files[tup] = file;
+ }
+
+ foreach (var item in series.GetSeasons(null, new DtoOptions(true)))
+ {
+ var season = item as Season;
+ var seasonNumber = season.GetLookupInfo().IndexNumber.Value;
+ Plugin.Logger.LogInformation($"Season id: {seasonNumber}:");
+ foreach (var itemAgain in season.GetEpisodes())
+ {
+ var episode = itemAgain as Episode;
+ var episodeNumber = episode.GetLookupInfo().IndexNumber.Value;
+ Plugin.Logger.LogInformation($" * Episode id: {episodeNumber} {episode.Name}");
+ POJO.File file;
+ if (files.TryGetValue((seasonNumber, episodeNumber), out file))
+ {
+ Plugin.Logger.LogInformation($" Found cover: {file.downloadUrl}");
+ // await _providerManager.SaveImage(item, imageUrl, type, null, CancellationToken.None)
+ // .ConfigureAwait(false);
+
+ // await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false);
+ await _providerManager.SaveImage(
+ episode, file.downloadUrl,
+ // Note: this needs to be updated if SeriesImageProvider ever supports more image types
+ ImageType.Primary,
+ null,
+ CancellationToken.None
+ ).ConfigureAwait(false);
+
+ await episode.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None)
+ .ConfigureAwait(false);
+ }
+ }
+ }
+
+ return Empty;
+ }
} \ No newline at end of file
diff --git a/Api/coverscript.js b/Api/coverscript.js
index 24f3c34..9f3eb7f 100644
--- a/Api/coverscript.js
+++ b/Api/coverscript.js
@@ -19,9 +19,12 @@
/**
*
* @param {HTMLElement} cloneFrom
+ * @param {string} setMeta
* @return {HTMLElement}
*/
- function createDownloadSeriesButton(cloneFrom) {
+ function createDownloadSeriesButton(
+ cloneFrom,
+ setMeta) {
/*<button is="paper-icon-button-light" class="btnDownloadRemoteImage autoSize paper-icon-button-light" raised"="" title="Download"><span class="material-icons cloud_download" aria-hidden="true"></span></button>*/
//import LayersIcon from '@mui/icons-material/Layers';
//import CloudDownloadIcon from '@mui/icons-material/CloudDownload';
@@ -35,12 +38,35 @@
element.appendChild(icon)
element.addEventListener("click", ev => {
ev.preventDefault()
-
- alert("YOU HAVE JUST BEEN INTERDICTED BY THE JCOVERXTREMEPRO SERIES DOWNLOADIFICATOR")
+ console.log("Executing mass covering event! We will try to download the entirety of set " + setMeta)
+ fetch("/JCoverXtreme/DownloadSeries",
+ {
+ method: 'POST',
+ body: setMeta,
+ headers: {
+ "content-type": "application/json"
+ }
+ }).then(console.log) // TODO: check out the root somehow. for now just assume /
})
return element
}
+ /**
+ * Keep in sync with JCoverSharedController.URL_META_KEY
+ * @type {string}
+ */
+ const URL_META_KEY = "JCoverXtremeProMeta"
+
+ /**
+ * Extract the JCoverXtremePro metadata from an image url.
+ *
+ * @param {string} url
+ * @return {string}
+ */
+ function extractSetMeta(url) {
+ return new URL(url).searchParams.get(URL_META_KEY)
+ }
+
const observer = new MutationObserver(() => {
console.log("JCoverXtremePro observation was triggered!")
console.log("Listing all download buttons")
@@ -51,9 +77,12 @@
buttons.forEach(element => {
const downloadRowContainer = findParent(element, ".cardText")
+ const cardContainer = findParent(element, ".cardBox")
+ const cardImage = cardContainer.querySelector("a.cardImageContainer[href]")
+ const setMeta = extractSetMeta(cardImage.href)
if (downloadRowContainer.querySelector(`.${injectionMarker}`)) return
// TODO: extract information about the series, and check if this is at all viable
- downloadRowContainer.appendChild(createDownloadSeriesButton(element))
+ downloadRowContainer.appendChild(createDownloadSeriesButton(element, setMeta))
})
})