Files
stream-cinema/CinemaJellyfin/CinemaQueryExtensions.cs
2025-04-03 20:51:17 +00:00

328 lines
9.4 KiB
C#

using System.Diagnostics.CodeAnalysis;
using CinemaLib.API;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Model.Entities;
namespace Jellyfin.Plugin.Cinema;
static class CinemaQueryExtensions
{
private const char VersionSeparator = '-';
public static FilterSortBy ToCinema(this ItemSortBy sortByJ)
{
switch (sortByJ)
{
default:
case ItemSortBy.Default: return FilterSortBy.Title;
case ItemSortBy.AiredEpisodeOrder: return FilterSortBy.Premiered;
//case ItemSortBy.Album: return
//case ItemSortBy.AlbumArtist: return
//case ItemSortBy.Artist: return
case ItemSortBy.DateCreated: return FilterSortBy.DateAdded;
case ItemSortBy.OfficialRating: return FilterSortBy.Score;
case ItemSortBy.DatePlayed: return FilterSortBy.LastSeen;
case ItemSortBy.PremiereDate: return FilterSortBy.Premiered;
case ItemSortBy.StartDate: return FilterSortBy.Premiered;
case ItemSortBy.SortName: return FilterSortBy.Title;
case ItemSortBy.Name: return FilterSortBy.Title;
case ItemSortBy.Random: return FilterSortBy.Trending;
//case ItemSortBy.Runtime: return
case ItemSortBy.CommunityRating: return FilterSortBy.Popularity;
case ItemSortBy.ProductionYear: return FilterSortBy.Year;
case ItemSortBy.PlayCount: return FilterSortBy.PlayCount;
case ItemSortBy.CriticRating: return FilterSortBy.Score;
//case ItemSortBy.IsFolder:
//case ItemSortBy.IsUnplayed:
//case ItemSortBy.IsPlayed:
case ItemSortBy.SeriesSortName: return FilterSortBy.Title;
//case ItemSortBy.VideoBitRate:
//case ItemSortBy.AirTime:
//case ItemSortBy.Studio:
//case ItemSortBy.IsFavoriteOrLiked:
case ItemSortBy.DateLastContentAdded: return FilterSortBy.LastChildrenDateAdded;
case ItemSortBy.SeriesDatePlayed: return FilterSortBy.LastChildPremiered;
}
}
/// <summary>
/// Tries to create a Jellyfin media item from the provided Cinema media item.
/// </summary>
/// <param name="csId">Cinema media identifier.</param>
/// <param name="media">Cinema metadata.</param>
/// <param name="parentFolder">Jellyfin parent folder.</param>
/// <param name="item">On success the created item.</param>
/// <returns>True on success, false otherwise.</returns>
public static bool TryCreateMediaItem<TContainerType>(this MediaSource? media, string csId, BaseItem? parentFolder, bool allowContainer, [NotNullWhen(true)] out BaseItem? item)
where TContainerType : Folder, new()
{
if (media == null)
{
item = null;
return false;
}
bool isNew;
bool forceUpdate = false;
bool isConcert = media.is_concert ?? false;
if (media.children_count != 0)
{
// Container
if (!allowContainer) {
item = null;
return false;
}
item = GetMediaItemById<TContainerType>(csId, null, out isNew);
}
else if (isConcert)
{
item = GetMediaItemById<CinemaMusicVideo>(csId, null, out isNew);
}
else if (media.info_labels?.mediatype == "episode")
{
item = GetMediaItemById<CinemaEpisode>(csId, null, out isNew);
}
else
{
item = GetMediaItemById<CinemaMovie>(csId, null, out isNew);
}
if (isNew && media.info_labels != null)
{
item.RunTimeTicks = (long?)(media.info_labels.duration * TimeSpan.TicksPerSecond);
}
if (isNew)
{
InfoLabelI18n? loc = GetLocalized(media);
item.Name = loc?.title ?? media.info_labels?.originaltitle;
item.Genres = media.info_labels?.genre?.ToArray();
item.Studios = media.info_labels?.studio?.ToArray();
item.CommunityRating = (float?)media.ratings?.overall?.rating;
item.Overview = loc?.plot;
// TODO
// item.IndexNumber = info.IndexNumber;
//item.ParentIndexNumber = info.ParentIndexNumber;
item.PremiereDate = media.info_labels?.premiered;
item.ProductionYear = media.info_labels?.year;
if (media.services != null)
{
item.ProviderIds = new Dictionary<string, string>();
ConvertProviderIds(media.services, item.ProviderIds);
}
//item.OfficialRating = info.OfficialRating;
item.DateCreated = media.info_labels?.dateadded ?? DateTime.UtcNow;
//item.Tags = info.Tags.ToArray();
item.OriginalTitle = media.info_labels?.originaltitle;
string? artUriS = loc?.art?.poster;
Uri? artUri;
if (artUriS != null)
{
artUri = new Uri(artUriS);
if (Metadata.TryGetThumbnail(artUri, 128, 128, out Uri? artThumbUri))
{
item.SetImagePath(ImageType.Thumb, artThumbUri.ToString());
}
item.SetImagePath(ImageType.Primary, artUri.ToString());
}
artUriS = loc?.art?.fanart;
if (artUriS != null)
{
artUri = new Uri(artUriS);
item.SetImagePath(ImageType.Backdrop, artUri.ToString());
}
}
// Indicate just HTTP CinemaMediaSourceManager and CinemaMediaSourceController will handle the rest
item.Path = "https://a/b";
if (item is IHasArtist hasArtists)
{
hasArtists.Artists = media.info_labels?.writer;
}
if (item is IHasAlbumArtist hasAlbumArtists)
{
hasAlbumArtists.AlbumArtists = media.info_labels?.director;
}
if (parentFolder != null)
item.ParentId = parentFolder.Id;
/*
if (item is IHasSeries hasSeries)
{
if (!string.Equals(hasSeries.SeriesName, info.SeriesName, StringComparison.OrdinalIgnoreCase))
{
forceUpdate = true;
_logger.LogDebug("Forcing update due to SeriesName {0}", item.Name);
}
hasSeries.SeriesName = info.SeriesName;
}*/
item.ExternalId = CinemaIdToExternalId(csId);
if (item is ICinemaChildrenCount childrenCount) {
childrenCount.ChildrenCount = media.children_count;
childrenCount.TotalChildrenCount = media.total_children_count;
}
/*
if (item is Audio channelAudioItem)
{
channelAudioItem.ExtraType = info.ExtraType;
var mediaSource = info.MediaSources.FirstOrDefault();
item.Path = mediaSource?.Path;
}
if (item is Video channelVideoItem)
{
channelVideoItem.ExtraType = info.ExtraType;
var mediaSource = info.MediaSources.FirstOrDefault();
item.Path = mediaSource?.Path;
}*/
item.OnMetadataChanged();
if (isNew)
{
// HACK: We use RegisterItem that is volatile intead of CreateItem
//_libraryManager.CreateItem(item, parentFolder);
CinemaHost.LibraryManager.RegisterItem(item);
if (media.cast != null && media.cast.Count > 0)
{
//await _libraryManager.UpdatePeopleAsync(item, info.People, cancellationToken).ConfigureAwait(false);
}
}
else if (forceUpdate)
{
// HACK our items are volatile
//item.UpdateToRepositoryAsync(ItemUpdateType.None, default).GetAwaiter().GetResult();
}
/*
if ((isNew || forceUpdate) && info.Type == ChannelItemType.Media)
{
if (enableMediaProbe && !info.IsLiveStream && item.HasPathProtocol)
{
await SaveMediaSources(item, new List<MediaSourceInfo>()).ConfigureAwait(false);
}
else
{
await SaveMediaSources(item, info.MediaSources).ConfigureAwait(false);
}
}*/
/*
if (isNew || forceUpdate || item.DateLastRefreshed == default)
{
_providerManager.QueueRefresh(item.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.Normal);
}*/
return true;
}
private static void ConvertProviderIds(ServicesIds services, Dictionary<string, string> dest)
{
if (services.imdb != null)
dest.Add("Imdb", services.imdb);
if (services.tvdb != null)
dest.Add("Tvdb", services.tvdb);
if (services.tmdb != null)
dest.Add("Tmdb", services.tmdb);
//public string? csfd { get; set; }
//public string? trakt { get; set; }
//public string? trakt_with_type { get; set; }
//public string? slug { get; set; }
}
private static InfoLabelI18n? GetLocalized(MediaSource media)
{
if (media.i18n_info_labels == null)
return null;
InfoLabelI18n? first = null;
InfoLabelI18n? preferred = null;
InfoLabelI18n? fallback = null;
foreach (InfoLabelI18n i in media.i18n_info_labels)
if (i.lang == CinemaHost.PreferredCulture)
preferred = i;
else if (i.lang == CinemaHost.FallbackCulture)
fallback = i;
else if (first == null)
first = i;
return preferred ?? fallback ?? first;
}
/// <summary>
/// Calculates Jellyfin item identifier from Cinema identifier, optionally also with version identifier.
/// </summary>
internal static Guid GetMediaItemId(string csPrimaryId, string? csVersionId)
{
string idS = csVersionId == null ? csPrimaryId : (csPrimaryId + VersionSeparator + csVersionId);
return CinemaHost.LibraryManager.GetNewItemId(idS, typeof(CinemaPlugin));
}
/// <summary>
/// Creates a new media item (non-folder) with a proper unique identifier.
/// </summary>
internal static T GetMediaItemById<T>(string csPrimaryId, string? csVersionId, out bool isNew)
where T : BaseItem, new()
{
Guid id = GetMediaItemId(csPrimaryId, csVersionId);
T? item = CinemaHost.LibraryManager.GetItemById(id) as T;
if (item == null)
{
item = new T();
isNew = true;
}
else
{
isNew = false;
}
item.Id = id;
return item;
}
internal static string CinemaIdToExternalId(string csId)
{
return CinemaPlugin.CinemaExtIdPrefix + csId;
}
internal static bool IsCinemaExternalId(string? externalId)
{
return externalId != null && externalId.StartsWith(CinemaPlugin.CinemaExtIdPrefix);
}
internal static bool TryGetCinemaIdFromExternalId(string? externalId, [NotNullWhen(true)] out string? csId)
{
if (IsCinemaExternalId(externalId))
{
csId = externalId!.Substring(CinemaPlugin.CinemaExtIdPrefix.Length);
return true;
}
else
{
csId = null;
return false;
}
}
}