Skip to content

Commit

Permalink
feat: expose community rating for images if available
Browse files Browse the repository at this point in the history
  • Loading branch information
revam committed Dec 15, 2024
1 parent ce03a05 commit 2610d84
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 11 deletions.
5 changes: 5 additions & 0 deletions Shokofin/API/Models/Image.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ public class Image {
public virtual bool IsAvailable
=> !string.IsNullOrEmpty(LocalPath);

/// <summary>
/// Community rating for the image, if available.
/// </summary>
public Rating? CommunityRating { get; set; }

/// <summary>
/// Get an URL to both download the image on the backend and preview it for
/// the clients.
Expand Down
14 changes: 14 additions & 0 deletions Shokofin/Configuration/PluginConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,18 @@ public DescriptionProvider[] ThirdPartyIdProviderList {
/// </summary>
public ImageType[] AddImageLanguageCodeForMovies { get; set; }

/// <summary>
/// Add community rating to image metadata provided to shows in Jellyfin for
/// it to select the correct image to use for the library.
/// </summary>
public ImageType[] AddImageCommunityRatingForShows { get; set; }

/// <summary>
/// Add community rating to image metadata provided to movies in Jellyfin for
/// it to select the correct image to use for the library.
/// </summary>
public ImageType[] AddImageCommunityRatingForMovies { get; set; }

/// <summary>
/// This isn't used anymore, but is kept for upgrading the config in a
/// backwards compatible manner.
Expand Down Expand Up @@ -672,6 +684,8 @@ public PluginConfiguration() {
AddImageLanguageCode = null;
AddImageLanguageCodeForShows = [];
AddImageLanguageCodeForMovies = [];
AddImageCommunityRatingForMovies = [];
AddImageCommunityRatingForShows = [];
RespectPreferredImage = null;
RespectPreferredImagePerStructureType = [
SeriesStructureType.AniDB_Anime,
Expand Down
4 changes: 4 additions & 0 deletions Shokofin/Pages/Scripts/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,8 @@ function applyFormToConfig(form, config) {
config.SynopsisRemoveSummary = form.querySelector("#CleanupAniDBDescriptions").checked;
config.AddImageLanguageCodeForShows = retrieveCheckboxList(form, "AddImageLanguageCodeForShows");
config.AddImageLanguageCodeForMovies = retrieveCheckboxList(form, "AddImageLanguageCodeForMovies");
config.AddImageCommunityRatingForShows = retrieveCheckboxList(form, "AddImageCommunityRatingForShows");
config.AddImageCommunityRatingForMovies = retrieveCheckboxList(form, "AddImageCommunityRatingForMovies");
config.RespectPreferredImagePerStructureType = retrieveCheckboxList(form, "RespectPreferredImagePerStructureType");
config.HideUnverifiedTags = form.querySelector("#HideUnverifiedTags").checked;
config.TagSources = retrieveCheckboxList(form, "TagSources").join(", ");
Expand Down Expand Up @@ -532,6 +534,8 @@ async function applyConfigToForm(form, config) {
);
renderCheckboxList(form, "AddImageLanguageCodeForShows", config.AddImageLanguageCodeForShows);
renderCheckboxList(form, "AddImageLanguageCodeForMovies", config.AddImageLanguageCodeForMovies);
renderCheckboxList(form, "AddImageCommunityRatingForShows", config.AddImageCommunityRatingForShows);
renderCheckboxList(form, "AddImageCommunityRatingForMovies", config.AddImageCommunityRatingForMovies);
renderCheckboxList(form, "RespectPreferredImagePerStructureType", config.RespectPreferredImagePerStructureType.map(s => s.trim()).filter(s => s));
form.querySelector("#HideUnverifiedTags").checked = config.HideUnverifiedTags;
renderCheckboxList(form, "TagSources", config.TagSources.split(",").map(s => s.trim()).filter(s => s));
Expand Down
66 changes: 66 additions & 0 deletions Shokofin/Pages/Settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,72 @@ <h3 class="listItemBodyText">Logos</h3>
</div>
<div class="fieldDescription">Add the language code to image metadata for movie libraries provided to Jellyfin, which it can use to prioritize images based on a library's configured metadata language. If a library has no language set, Jellyfin will prioritize English labeled images if this option is set, and will otherwise use the first available image.</div>
</div>
<div id="AddImageCommunityRatingForShows" is="checkbox-list" style="margin-bottom: 2em;">
<h3 class="checkboxListLabel">Add Community Rating for Shows</h3>
<div class="checkboxList paperList checkboxList-paperList">
<div class="listItem">
<label class="listItemCheckboxContainer">
<input is="emby-checkbox" type="checkbox" data-option="Primary">
<span></span>
</label>
<div class="listItemBody">
<h3 class="listItemBodyText">Posters</h3>
</div>
</div>
<div class="listItem">
<label class="listItemCheckboxContainer">
<input is="emby-checkbox" type="checkbox" data-option="Backdrop">
<span></span>
</label>
<div class="listItemBody">
<h3 class="listItemBodyText">Backdrops</h3>
</div>
</div>
<div class="listItem">
<label class="listItemCheckboxContainer">
<input is="emby-checkbox" type="checkbox" data-option="Logo">
<span></span>
</label>
<div class="listItemBody">
<h3 class="listItemBodyText">Logos</h3>
</div>
</div>
</div>
<div class="fieldDescription">Add the community rating to image metadata for show libraries provided to Jellyfin, which it can use to prioritize images based on a library's configured metadata language. If a library has no language set, Jellyfin will prioritize English labeled images if this option is set, and will otherwise use the first available image.</div>
</div>
<div id="AddImageCommunityRatingForMovies" is="checkbox-list" style="margin-bottom: 2em;">
<h3 class="checkboxListLabel">Add Community Rating for Movies</h3>
<div class="checkboxList paperList checkboxList-paperList">
<div class="listItem">
<label class="listItemCheckboxContainer">
<input is="emby-checkbox" type="checkbox" data-option="Primary">
<span></span>
</label>
<div class="listItemBody">
<h3 class="listItemBodyText">Posters</h3>
</div>
</div>
<div class="listItem">
<label class="listItemCheckboxContainer">
<input is="emby-checkbox" type="checkbox" data-option="Backdrop">
<span></span>
</label>
<div class="listItemBody">
<h3 class="listItemBodyText">Backdrops</h3>
</div>
</div>
<div class="listItem">
<label class="listItemCheckboxContainer">
<input is="emby-checkbox" type="checkbox" data-option="Logo">
<span></span>
</label>
<div class="listItemBody">
<h3 class="listItemBodyText">Logos</h3>
</div>
</div>
</div>
<div class="fieldDescription">Add the community rating to image metadata for movie libraries provided to Jellyfin, which it can use to prioritize images based on a library's configured metadata language. If a library has no language set, Jellyfin will prioritize English labeled images if this option is set, and will otherwise use the first available image.</div>
</div>
<div id="RespectPreferredImagePerStructureType" is="checkbox-list" class="expert-only" style="margin-bottom: 2em;">
<h3 class="checkboxListLabel">Respect Preferred Image</h3>
<div class="checkboxList paperList checkboxList-paperList">
Expand Down
47 changes: 36 additions & 11 deletions Shokofin/Providers/ImageProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
using Shokofin.API;
using Shokofin.ExternalIds;

using RatingType = MediaBrowser.Model.Dto.RatingType;

namespace Shokofin.Providers;

public class ImageProvider(IHttpClientFactory _httpClientFactory, ILogger<ImageProvider> _logger, ShokoApiManager _apiManager, IIdLookup _lookup) : IRemoteImageProvider, IHasOrder {
Expand Down Expand Up @@ -127,49 +129,63 @@ public static void AddImagesForEpisode(ref List<RemoteImageInfo> list, API.Model
? images.Thumbnails.Concat(images.Backdrops).OrderByDescending(image => image.IsPreferred).ThenByDescending(image => image.Type is API.Models.ImageType.Thumbnail)
: images.Thumbnails.Concat(images.Backdrops).OrderByDescending(image => image.Type is API.Models.ImageType.Thumbnail);
foreach (var image in imagesList)
AddImage(ref list, ImageType.Primary, image, metadataLanguage);
AddImage(ref list, ImageType.Primary, image, metadataLanguage, overridePreferred: sortList);
}

private static void AddImagesForSeries(ref List<RemoteImageInfo> list, API.Models.Images images, string metadataLanguage, bool sortList, BaseItemKind baseKind = BaseItemKind.Series) {
IEnumerable<API.Models.Image> imagesList = sortList
? images.Posters.OrderByDescending(image => image.IsPreferred)
: images.Posters;
foreach (var image in imagesList)
AddImage(ref list, ImageType.Primary, image, sortList ? metadataLanguage : null, baseKind);
AddImage(ref list, ImageType.Primary, image, sortList ? metadataLanguage : null, baseKind, sortList);

imagesList = sortList
? images.Backdrops.OrderByDescending(image => image.IsPreferred)
: images.Backdrops;
foreach (var image in imagesList)
AddImage(ref list, ImageType.Backdrop, image, sortList ? metadataLanguage : null, baseKind);
AddImage(ref list, ImageType.Backdrop, image, sortList ? metadataLanguage : null, baseKind, sortList);

imagesList = sortList
? images.Banners.OrderByDescending(image => image.IsPreferred)
: images.Banners;
foreach (var image in imagesList)
AddImage(ref list, ImageType.Banner, image, sortList ? metadataLanguage : null, baseKind);
AddImage(ref list, ImageType.Banner, image, metadataLanguage, baseKind, sortList);

imagesList = sortList
? images.Logos.OrderByDescending(image => image.IsPreferred)
: images.Logos;
foreach (var image in imagesList)
AddImage(ref list, ImageType.Logo, image, sortList ? metadataLanguage : null, baseKind);
AddImage(ref list, ImageType.Logo, image, metadataLanguage, baseKind, sortList);
}

private static void AddImage(ref List<RemoteImageInfo> list, ImageType imageType, API.Models.Image? image, string? metadataLanguage, BaseItemKind baseKind = BaseItemKind.Series) {
private static void AddImage(ref List<RemoteImageInfo> list, ImageType imageType, API.Models.Image? image, string? metadataLanguage, BaseItemKind baseKind = BaseItemKind.Series, bool overridePreferred = false) {
if (image is not { IsAvailable: true })
return;

list.Add(new RemoteImageInfo {
var imageDto = new RemoteImageInfo {
ProviderName = $"{image.Source.ToString().Replace("TMDB", "TheMovieDb")} ({Plugin.MetadataProviderName})",
Type = imageType,
Width = image.Width,
Height = image.Height,
Url = image.ToURLString(),
Language = UseLanguageCode(imageType, baseKind)
? !string.IsNullOrEmpty(metadataLanguage) && image.IsPreferred ? metadataLanguage : image.LanguageCode
: null,
});
};
if (UseLanguageCode(imageType, baseKind))
imageDto.Language = !string.IsNullOrEmpty(metadataLanguage) && overridePreferred && image.IsPreferred ? metadataLanguage : image.LanguageCode;

if (UseCommunityRating(imageType, baseKind)) {
if (overridePreferred && image.IsPreferred) {
imageDto.CommunityRating = 10;
imageDto.VoteCount = 1337;
imageDto.RatingType = RatingType.Score;
}
else if (image.CommunityRating is { } rating) {
imageDto.CommunityRating = rating.ToFloat();
imageDto.VoteCount = rating.Votes;
imageDto.RatingType = RatingType.Score;
}
}

list.Add(imageDto);
}

private static bool UseLanguageCode(ImageType imageType, BaseItemKind baseKind) {
Expand All @@ -181,6 +197,15 @@ private static bool UseLanguageCode(ImageType imageType, BaseItemKind baseKind)
return array.Contains(imageType);
}

private static bool UseCommunityRating(ImageType imageType, BaseItemKind baseKind) {
var array = baseKind switch {
BaseItemKind.Movie => Plugin.Instance.Configuration.AddImageCommunityRatingForMovies,
BaseItemKind.Series => Plugin.Instance.Configuration.AddImageCommunityRatingForShows,
_ => [],
};
return array.Contains(imageType);
}

public IEnumerable<ImageType> GetSupportedImages(BaseItem item)
=> [ImageType.Primary, ImageType.Backdrop, ImageType.Banner, ImageType.Logo];

Expand Down

0 comments on commit 2610d84

Please sign in to comment.