Update to match master. Playback broken as GetPostedPlaybackInfo does not get MediaSourceId.
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
2025-04-03 20:51:17 +00:00
parent b18d891a2b
commit 8158dd5346
18 changed files with 88 additions and 57 deletions

View File

@@ -26,7 +26,7 @@ public class CinemaEpisode : Episode
return result;
}
public override List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
public override IReadOnlyList<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
{
var result = this.VideoGetMediaSources(enablePathSubstitution);
if (result == null)

View File

@@ -7,6 +7,7 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
using CinemaLib.API;
using Jellyfin.Database.Implementations.Enums;
namespace Jellyfin.Plugin.Cinema;

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AssemblyOriginatorKeyFile>..\key.snk</AssemblyOriginatorKeyFile>
@@ -11,10 +11,10 @@
<ItemGroup>
<ProjectReference Include="..\CinemaLib\CinemaLib.csproj" />
<PackageReference Include="Jellyfin.Controller" Version="10.10.3" />
<!--ProjectReference Include="..\..\..\jellyfin/MediaBrowser.Controller\MediaBrowser.Controller.csproj" /-->
<PackageReference Include="Jellyfin.Model" Version="10.10.3" />
<!--ProjectReference Include="..\..\..\jellyfin\MediaBrowser.Model\MediaBrowser.Model.csproj" /-->
<!--PackageReference Include="Jellyfin.Controller" Version="10.10.6" /-->
<ProjectReference Include="/home/rv/temp/jellyfin/MediaBrowser.Controller/MediaBrowser.Controller.csproj" />
<!--PackageReference Include="Jellyfin.Model" Version="10.10.6" /-->
<ProjectReference Include="/home/rv/temp/jellyfin/MediaBrowser.Model/MediaBrowser.Model.csproj" />
<PackageReference Include="ILRepack.Lib.MSBuild.Task" Version="2.0.34.2" PrivateAssets="All"/>
</ItemGroup>
@@ -28,7 +28,7 @@
<ItemGroup>
<DebugCopyFiles Include="$(TargetDir)\Cinema*.dll" />
</ItemGroup>
<MakeDir Directories="\home\code\.local\share\jellyfin\plugins\Cinema" />
<Copy SourceFiles="@(DebugCopyFiles)" DestinationFolder="\home\code\.local\share\jellyfin\plugins\Cinema" />
<MakeDir Directories="\home\rv\.local\share\jellyfin\plugins\Cinema" />
<Copy SourceFiles="@(DebugCopyFiles)" DestinationFolder="\home\rv\.local\share\jellyfin\plugins\Cinema" />
</Target>
</Project>

View File

@@ -1,5 +1,6 @@
using CinemaLib.API;
using Jellyfin.Data.Entities;
using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
@@ -15,15 +16,17 @@ using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Querying;
using Microsoft.EntityFrameworkCore;
using Jellyfin.Database.Implementations;
namespace Jellyfin.Plugin.Cinema;
sealed class CinemaLibraryManager : ILibraryManager
{
private readonly ILibraryManager _inner;
private readonly IUserDataRepository _userData;
private readonly IDbContextFactory<JellyfinDbContext> _userData;
public CinemaLibraryManager(CinemaInnerLibraryManager innerLibraryManager, IUserDataRepository userData, IServiceProvider svc)
public CinemaLibraryManager(CinemaInnerLibraryManager innerLibraryManager, IDbContextFactory<JellyfinDbContext> userData, IServiceProvider svc)
{
if (innerLibraryManager == null || svc == null)
throw new ArgumentNullException();
@@ -217,12 +220,12 @@ sealed class CinemaLibraryManager : ILibraryManager
return _inner.GetItemById<T>(id, user);
}
public List<Guid> GetItemIds(InternalItemsQuery query)
public IReadOnlyList<Guid> GetItemIds(InternalItemsQuery query)
{
return _inner.GetItemIds(query);
}
public List<BaseItem> GetItemList(InternalItemsQuery query)
public IReadOnlyList<BaseItem> GetItemList(InternalItemsQuery query)
{
string? serieOrSeasonIdS;
Guid serieOrSeasonId;
@@ -255,12 +258,12 @@ sealed class CinemaLibraryManager : ILibraryManager
}
}
public List<BaseItem> GetItemList(InternalItemsQuery query, bool allowExternalContent)
public IReadOnlyList<BaseItem> GetItemList(InternalItemsQuery query, bool allowExternalContent)
{
return _inner.GetItemList(query, allowExternalContent);
}
public List<BaseItem> GetItemList(InternalItemsQuery query, List<BaseItem> parents)
public IReadOnlyList<BaseItem> GetItemList(InternalItemsQuery query, List<BaseItem> parents)
{
return _inner.GetItemList(query, parents);
}
@@ -277,16 +280,21 @@ sealed class CinemaLibraryManager : ILibraryManager
if (query.OrderBy.FirstOrDefault().OrderBy == ItemSortBy.DatePlayed && query.User != null && query.MediaTypes.Contains(MediaType.Video))
{
// Get Resume play items
// PERF: This may quickly become very slow
var resumePlay = _userData.GetAllUserData(query.User.InternalId)
UserData[]? resumePlay;
Guid userId = query.User.Id;
using (JellyfinDbContext context = _userData.CreateDbContext())
resumePlay = context.UserData.AsNoTracking()
.Where(e => e.UserId.Equals(userId))
.OrderByDescending(x => x.Played)
.Skip(query.StartIndex ?? 0)
.Take(query.Limit ?? 20);
foreach (UserItemData i in resumePlay)
.Take(query.Limit ?? 20)
.ToArray();
foreach (UserData i in resumePlay)
{
// Note: All Cinema items override GetUserDataKeys and return ExternalId
string? csId;
if (CinemaQueryExtensions.TryGetCinemaIdFromExternalId(i.Key, out csId))
if (CinemaQueryExtensions.TryGetCinemaIdFromExternalId(i.CustomDataKey, out csId))
{
// First try to get already in-memory item
Guid itemId = CinemaQueryExtensions.GetMediaItemId(csId, null);
@@ -303,7 +311,7 @@ sealed class CinemaLibraryManager : ILibraryManager
else
{
// Try to append item from the inner result
if (Guid.TryParse(i.Key, out Guid key))
if (Guid.TryParse(i.CustomDataKey, out Guid key))
foreach (BaseItem j in result.Items)
if (j.Id == key)
{
@@ -336,6 +344,11 @@ sealed class CinemaLibraryManager : ILibraryManager
return new QueryResult<BaseItem>() { Items = resultL };
}
public IReadOnlyList<BaseItem> GetLatestItemList(InternalItemsQuery query, IReadOnlyList<BaseItem> parents, CollectionType collectionType)
{
return _inner.GetLatestItemList(query, parents, collectionType);
}
public LibraryOptions GetLibraryOptions(BaseItem item)
{
return _inner.GetLibraryOptions(item);
@@ -381,6 +394,11 @@ sealed class CinemaLibraryManager : ILibraryManager
return _inner.GetNewItemId(key, type);
}
public IReadOnlyList<string> GetNextUpSeriesKeys(InternalItemsQuery query, IReadOnlyCollection<BaseItem> parents, DateTime dateCutoff)
{
return _inner.GetNextUpSeriesKeys(query, parents, dateCutoff);
}
public BaseItem GetParentItem(Guid? parentId, Guid? userId)
{
return _inner.GetParentItem(parentId, userId);
@@ -391,22 +409,22 @@ sealed class CinemaLibraryManager : ILibraryManager
return _inner.GetPathAfterNetworkSubstitution(path, ownerItem);
}
public List<PersonInfo> GetPeople(BaseItem item)
public IReadOnlyList<PersonInfo> GetPeople(BaseItem item)
{
return _inner.GetPeople(item);
}
public List<PersonInfo> GetPeople(InternalPeopleQuery query)
public IReadOnlyList<PersonInfo> GetPeople(InternalPeopleQuery query)
{
return _inner.GetPeople(query);
}
public List<Person> GetPeopleItems(InternalPeopleQuery query)
public IReadOnlyList<Person> GetPeopleItems(InternalPeopleQuery query)
{
return _inner.GetPeopleItems(query);
}
public List<string> GetPeopleNames(InternalPeopleQuery query)
public IReadOnlyList<string> GetPeopleNames(InternalPeopleQuery query)
{
return _inner.GetPeopleNames(query);
}
@@ -416,9 +434,9 @@ sealed class CinemaLibraryManager : ILibraryManager
return _inner.GetPerson(name);
}
public int? GetSeasonNumberFromPath(string path)
public int? GetSeasonNumberFromPath(string path, Guid? parentId)
{
return _inner.GetSeasonNumberFromPath(path);
return _inner.GetSeasonNumberFromPath(path, parentId);
}
public UserView GetShadowView(BaseItem parent, CollectionType? viewType, string sortName)
@@ -556,7 +574,7 @@ sealed class CinemaLibraryManager : ILibraryManager
_inner.UpdatePeople(item, people);
}
public Task UpdatePeopleAsync(BaseItem item, List<PersonInfo> people, CancellationToken cancellationToken)
public Task UpdatePeopleAsync(BaseItem item, IReadOnlyList<PersonInfo> people, CancellationToken cancellationToken)
{
return _inner.UpdatePeopleAsync(item, people, cancellationToken);
}

View File

@@ -5,7 +5,7 @@ using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text;
using Jellyfin.Data.Entities;
using Jellyfin.Database.Implementations.Entities;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
@@ -21,6 +21,7 @@ using MediaBrowser.Controller.MediaEncoding;
using System.Runtime.CompilerServices;
using LinkGenerator = CinemaLib.Webshare.LinkGenerator;
using MediaBrowser.Controller.Configuration;
using Jellyfin.Extensions;
namespace Jellyfin.Plugin.Cinema;
@@ -130,12 +131,12 @@ sealed class CinemaMediaSourceManager : IMediaSourceManager
return _inner.GetLiveStreamWithDirectStreamProvider(id, cancellationToken);
}
public List<MediaAttachment> GetMediaAttachments(Guid itemId)
public IReadOnlyList<MediaAttachment> GetMediaAttachments(Guid itemId)
{
return _inner.GetMediaAttachments(itemId);
}
public List<MediaAttachment> GetMediaAttachments(MediaAttachmentQuery query)
public IReadOnlyList<MediaAttachment> GetMediaAttachments(MediaAttachmentQuery query)
{
return _inner.GetMediaAttachments(query);
}
@@ -145,12 +146,12 @@ sealed class CinemaMediaSourceManager : IMediaSourceManager
return _inner.GetMediaSource(item, mediaSourceId, liveStreamId, enablePathSubstitution, cancellationToken);
}
public List<MediaStream> GetMediaStreams(Guid itemId)
public IReadOnlyList<MediaStream> GetMediaStreams(Guid itemId)
{
return _inner.GetMediaStreams(itemId);
}
public List<MediaStream> GetMediaStreams(MediaStreamQuery query)
public IReadOnlyList<MediaStream> GetMediaStreams(MediaStreamQuery query)
{
return _inner.GetMediaStreams(query);
}
@@ -160,12 +161,12 @@ sealed class CinemaMediaSourceManager : IMediaSourceManager
return _inner.GetPathProtocol(path);
}
public Task<List<MediaSourceInfo>> GetRecordingStreamMediaSources(ActiveRecordingInfo info, CancellationToken cancellationToken)
public Task<IReadOnlyList<MediaSourceInfo>> GetRecordingStreamMediaSources(ActiveRecordingInfo info, CancellationToken cancellationToken)
{
return _inner.GetRecordingStreamMediaSources(info, cancellationToken);
}
public List<MediaSourceInfo> GetStaticMediaSources(BaseItem item, bool enablePathSubstitution, User? user = null)
public IReadOnlyList<MediaSourceInfo> GetStaticMediaSources(BaseItem item, bool enablePathSubstitution, User? user = null)
{
// Intercept for CinemaItems
if (item == null
@@ -173,21 +174,26 @@ sealed class CinemaMediaSourceManager : IMediaSourceManager
|| string.IsNullOrEmpty(item.ExternalId))
return _inner.GetStaticMediaSources(item, enablePathSubstitution, user);
List<MediaSourceInfo> result = GetPlaybackMediaSourcesInternal(item, user, false, enablePathSubstitution, needsPreciseStreamIndicies: false, default).GetAwaiter().GetResult();
IReadOnlyList<MediaSourceInfo> result = GetPlaybackMediaSourcesInternal(item, user, false, enablePathSubstitution, needsPreciseStreamIndicies: false, default).GetAwaiter().GetResult();
// HACK Prevent crash
if (result.Count == 0)
result.Append(new MediaSourceInfo() { MediaStreams = new List<MediaStream>() });
{
MediaSourceInfo[] result2 = new MediaSourceInfo[result.Count + 1];
result.CopyTo(result2, 0);
result2[result2.Length - 1] = new MediaSourceInfo() { MediaStreams = new List<MediaStream>() };
result = result2;
}
return result;
}
public Task<List<MediaSourceInfo>> GetPlaybackMediaSources(BaseItem item, User? user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken)
public Task<IReadOnlyList<MediaSourceInfo>> GetPlaybackMediaSources(BaseItem item, User? user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken)
{
return GetPlaybackMediaSourcesInternal(item, user, allowMediaProbe, enablePathSubstitution, needsPreciseStreamIndicies: true, cancellationToken);
}
private async Task<List<MediaSourceInfo>> GetPlaybackMediaSourcesInternal(BaseItem item, User? user, bool allowMediaProbe, bool enablePathSubstitution, bool needsPreciseStreamIndicies, CancellationToken cancellationToken)
private async Task<IReadOnlyList<MediaSourceInfo>> GetPlaybackMediaSourcesInternal(BaseItem item, User? user, bool allowMediaProbe, bool enablePathSubstitution, bool needsPreciseStreamIndicies, CancellationToken cancellationToken)
{
// Intercept for CinemaItems
if (item == null

View File

@@ -26,7 +26,7 @@ public class CinemaMovie : Movie
return result;
}
public override List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
public override IReadOnlyList<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
{
var result = this.VideoGetMediaSources(enablePathSubstitution);
if (result == null)

View File

@@ -25,7 +25,7 @@ public sealed class CinemaMusicVideo : MusicVideo
return result;
}
public override List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
public override IReadOnlyList<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
{
var result = this.VideoGetMediaSources(enablePathSubstitution);
if (result == null)

View File

@@ -46,10 +46,6 @@ static class CinemaQueryExtensions
//case ItemSortBy.IsFavoriteOrLiked:
case ItemSortBy.DateLastContentAdded: return FilterSortBy.LastChildrenDateAdded;
case ItemSortBy.SeriesDatePlayed: return FilterSortBy.LastChildPremiered;
//case ItemSortBy.ParentIndexNumber:
//case ItemSortBy.IndexNumber:
case ItemSortBy.SimilarityScore: return FilterSortBy.Score;
case ItemSortBy.SearchScore: return FilterSortBy.Score;
}
}

View File

@@ -10,7 +10,7 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
using Microsoft.Extensions.Logging;
using CinemaLib.API;
using Jellyfin.Data.Entities;
using Jellyfin.Database.Implementations.Entities;
namespace Jellyfin.Plugin.Cinema;
@@ -28,7 +28,7 @@ public abstract class CinemaRootFolder : CinemaFilterFolder, ICollectionFolder
public abstract CollectionType? CollectionType { get; }
public override bool IsHidden => _hidden;
public override bool IsVisible(User user) => !_hidden;
public override bool IsVisible(User user, bool skipAllowedTagsCheck = false) => !_hidden;
internal bool Hide
{

View File

@@ -1,6 +1,6 @@
using System.Globalization;
using CinemaLib.API;
using Jellyfin.Data.Entities;
using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;

View File

@@ -1,6 +1,6 @@
using System.Globalization;
using CinemaLib.API;
using Jellyfin.Data.Entities;
using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;

View File

@@ -11,16 +11,16 @@ public class CinemaPluginConfiguration : BasePluginConfiguration
{
}
public string MoviesFolderName { get; set; }
public string? MoviesFolderName { get; set; }
public bool HideMoviesFolder { get; set; }
public string SeriesFolderName { get; set; }
public string? SeriesFolderName { get; set; }
public bool HideSeriesFolder { get; set; }
public string AnimeFolderName { get; set; }
public string? AnimeFolderName { get; set; }
public bool HideAnimeFolder { get; set; }
public string ConcertFolderName { get; set; }
public string? ConcertFolderName { get; set; }
public bool HideConcertFolder { get; set; }
public string? WebshareUser { get; set; }

View File

@@ -4,6 +4,8 @@ namespace CinemaLib.API;
public class Art
{
#pragma warning disable CS8618
public string poster {get;set;} // imge url
public string fanart {get;set;} // image url
#pragma warning restore CS8618
}

View File

@@ -4,12 +4,14 @@ namespace CinemaLib.API;
public class Stream
{
#pragma warning disable CS8618
public string _id {get; set;}
public string? name {get;set;}
public string media {get;set;}
public string provider {get;set;}
public DateTime? date_added {get;set;}
public string ident {get;set;}
#pragma warning restore CS8618
public long? size {get;set;}
public List<StreamAudio>? audio {get;set;}
public List<StreamVideo>? video {get;set;}

View File

@@ -4,7 +4,9 @@ namespace CinemaLib.API;
public class StreamAudio
{
#pragma warning disable CS8618
public string language { get; set; } // two letter ISO code
public string codec { get; set; } // ie. AAC
#pragma warning restore CS8618
public int channels { get; set; }
}

View File

@@ -4,7 +4,9 @@ namespace CinemaLib.API;
public class StreamSubtitle
{
#pragma warning disable CS8618
public string language { get; set; } // two letter ISO code
#pragma warning restore CS8618
public bool forced { get; set; }
public string? _id { get; set; }
public string? src { get; set; } // url to external subtitles

View File

@@ -8,7 +8,9 @@ public class StreamVideo
{
public int width { get; set; } // horizontal resolution in pixels
public int height { get; set; } // vertical resolution in pixels
#pragma warning disable CS8618
public string codec { get; set; } // ie. AVC
#pragma warning restore CS8618
public double? aspect { get; set; } // aspect ratio, ie. 1.778
[JsonPropertyName("hdr")]
public JsonElement? hdr_raw_donotuse { get; set; } // ie. Dolby Vision / SMPTE ST 2086

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<!--OutputType>Exe</OutputType-->
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>