Intercept GetStaticMediaSources instead of GetMediaStreams. Movie versions show in UI.
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2024-11-28 00:31:15 +01:00
parent 4b92508b10
commit affd2fc4a4
5 changed files with 199 additions and 72 deletions

View File

@@ -315,11 +315,16 @@ public abstract class StreamCinemaFilterFolder : Folder
}
item.SetImagePath(ImageType.Primary, artUri.ToString());
}
// Identify the item as it originates from StreamCinema
item.ProviderIds.Add(StreamCinemaPlugin.StreamCinemaProviderName, "");
}
// Identify the item as it originates from StreamCinema
// Note: This is getting lost in persisted items
if (item.ProviderIds == null)
item.ProviderIds = new Dictionary<string, string>();
item.ProviderIds[StreamCinemaPlugin.StreamCinemaProviderName] = "";
item.Path = "https://a/b";
if (item is IHasArtist hasArtists)
{
hasArtists.Artists = media.info_labels?.writer;

View File

@@ -8,10 +8,10 @@
<ItemGroup>
<ProjectReference Include="..\StreamCinemaLib/StreamCinemaLib.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.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" /-->
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Debug'">

View File

@@ -4,6 +4,7 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text;
using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
@@ -107,6 +108,8 @@ public class StreamCinemaMediaSourceManager : IMediaSourceManager
public List<MediaStream> GetMediaStreams(Guid itemId)
{
return _inner.GetMediaStreams(itemId);
/*
// Intercept for StreamCinemaItems
Video? item = _libraryManager.GetItemById<Video>(itemId);
if (item == null
@@ -115,68 +118,10 @@ public class StreamCinemaMediaSourceManager : IMediaSourceManager
|| string.IsNullOrEmpty(item.ExternalId))
return _inner.GetMediaStreams(itemId);
StreamCinemaLib.API.Stream? stream = GetVersion(item, default).GetAwaiter().GetResult();
StreamCinemaLib.API.Stream? ver = GetVersion(item, default).GetAwaiter().GetResult();
List<MediaStream> result = new List<MediaStream>();
if (stream != null)
{
// HACK: Those values are read after we return (not before)
item.Size = stream.size;
//stream_id;
//stream.name;
//stream.provider
//stream.ident;
//stream.media
//stream.date_added
if (stream.video != null)
{
foreach (StreamVideo j in stream.video)
{
MediaStream a = new MediaStream();
result.Add(a);
a.Type = MediaStreamType.Video;
a.Width = j.width;
a.Height = j.height;
a.Codec = j.codec;
a.AspectRatio = j.aspect.ToString();
ConvertHdr(j.hasHdr, j.hdrQuality, a);
// HACK: Those values are read after we return (not before)
item.RunTimeTicks = (long?)(j.duration * TimeSpan.TicksPerSecond);
if (j.is3d)
// Just a probability guess
item.Video3DFormat = Video3DFormat.HalfSideBySide;
}
}
if (stream.audio != null)
{
foreach (StreamAudio j in stream.audio)
{
MediaStream a = new MediaStream();
result.Add(a);
a.Type = MediaStreamType.Audio;
a.Language = j.language;
a.Codec = j.codec;
a.Channels = j.channels;
}
}
if (stream.subtitles != null)
{
foreach (StreamSubtitle j in stream.subtitles)
{
MediaStream a = new MediaStream();
result.Add(a);
a.Type = MediaStreamType.Subtitle;
a.Language = j.language;
a.IsForced = j.forced;
a.Path = j.src;
}
}
}
return result;
return ver != null ? VersionToMediaStreams(item, ver) : new List<MediaStream>();
*/
}
public List<MediaStream> GetMediaStreams(MediaStreamQuery query)
@@ -201,7 +146,32 @@ public class StreamCinemaMediaSourceManager : IMediaSourceManager
public List<MediaSourceInfo> GetStaticMediaSources(BaseItem item, bool enablePathSubstitution, User? user = null)
{
return _inner.GetStaticMediaSources(item, enablePathSubstitution, user);
// Intercept for StreamCinemaItems
if (item == null
|| item.ProviderIds == null
|| !item.ProviderIds.ContainsKey(StreamCinemaPlugin.StreamCinemaProviderName)
|| string.IsNullOrEmpty(item.ExternalId))
return _inner.GetStaticMediaSources(item, enablePathSubstitution, user);
List<MediaSourceInfo> result = new List<MediaSourceInfo>();
switch (item)
{
case Video video:
VersionSetEntry ver = GetVersionSet(video, out _, default).GetAwaiter().GetResult();
if (ver.Streams != null)
foreach (var i in ver.Streams)
result.Add(GetVersionInfo(video, i));
/*MediaSourceInfo? videoInfo = GetVersionInfo(video, default).GetAwaiter().GetResult();
if (videoInfo != null)
result.Add(videoInfo);*/
break;
}
// HACK Prevent crash
if (result.Count == 0)
result.Append(new MediaSourceInfo() { MediaStreams = new List<MediaStream>() });
return result;
}
public Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, CancellationToken cancellationToken)
@@ -330,7 +300,6 @@ public class StreamCinemaMediaSourceManager : IMediaSourceManager
return result;
}
private async Task<StreamCinemaLib.API.Stream?> GetVersion(Video item, CancellationToken cancel)
{
VersionSetEntry vers = await GetVersionSet(item, out BaseItem? primary, cancel);
@@ -356,6 +325,131 @@ public class StreamCinemaMediaSourceManager : IMediaSourceManager
return null;
}
public async Task<MediaSourceInfo?> GetVersionInfo(Video item, CancellationToken cancel)
{
if (item == null)
throw new ArgumentNullException();
StreamCinemaLib.API.Stream? ver = await GetVersion(item, cancel);
if (ver == null)
return null;
return GetVersionInfo(item, ver);
}
private MediaSourceInfo GetVersionInfo(Video item, StreamCinemaLib.API.Stream ver)
{
MediaSourceInfo result = new MediaSourceInfo();
result.VideoType = VideoType.VideoFile;
result.Id = ver._id;
result.Protocol = MediaProtocol.Http;
// Warning: We set some properties on item that get used below
result.MediaStreams = VersionToMediaStreams(item, ver);
string name = $"{Math.Round((double)(ver.size ?? 0) / (1024 * 1024 * 1024), 2)} GB ({ver.date_added?.ToShortDateString()})"
+ $" {Math.Round((item.RunTimeTicks ?? 0.0) / TimeSpan.TicksPerMinute)} min";
MediaStream? firstVid = result.MediaStreams.Where(x => x.Type == MediaStreamType.Video).FirstOrDefault();
if (firstVid != null)
{
var hdr = firstVid.VideoRangeType;
var hdr2 = firstVid.VideoDoViTitle;
string hdrS = hdr == Data.Enums.VideoRangeType.Unknown || hdr == Data.Enums.VideoRangeType.SDR
? " SDR"
: " HDR" + (string.IsNullOrEmpty(hdr2) ? "" : "[" + hdr2 + "]");
string is3DS = ver!.video!.First().is3d ? " (3D)" : "";
name += " " + firstVid.Width.ToString() + "x" + firstVid.Height.ToString() + hdrS + is3DS;
}
StringBuilder audioAndSub = new StringBuilder();
if (ver.audio != null) {
foreach (StreamAudio i in ver.audio)
audioAndSub.Append($"{i.language} {i.codec} {i.channels}").Append(",");
if (audioAndSub.Length != 0) {
audioAndSub.Remove(audioAndSub.Length - 1, 1);
name += " {" + audioAndSub + "}";
audioAndSub.Clear();
}
}
if (ver.subtitles != null) {
foreach (StreamSubtitle i in ver.subtitles)
audioAndSub.Append($"{i.language}").Append(",");
if (audioAndSub.Length != 0) {
audioAndSub.Remove(audioAndSub.Length - 1, 1);
name += " [" + audioAndSub + "]";
audioAndSub.Clear();
}
}
result.Name = name;
//Path = enablePathSubstitution ? GetMappedPath(item, item.Path, protocol) : item.Path,
result.Container = item.Container;
result.RunTimeTicks = item.RunTimeTicks;
result.Size = item.Size;
return result;
}
private static List<MediaStream> VersionToMediaStreams(Video item, StreamCinemaLib.API.Stream ver)
{
List<MediaStream> result = new List<MediaStream>();
// HACK: Propagate some values to the item also
item.Size = ver.size;
//stream_id;
//stream.name;
//stream.provider
//stream.ident;
//stream.media
//stream.date_added
if (ver.video != null)
{
foreach (StreamVideo j in ver.video)
{
MediaStream a = new MediaStream();
result.Add(a);
a.Type = MediaStreamType.Video;
a.Width = j.width;
a.Height = j.height;
a.Codec = j.codec;
a.AspectRatio = j.aspect.ToString();
ConvertHdr(j.hasHdr, j.hdrQuality, a);
// HACK: Those values are read after we return (not before)
item.RunTimeTicks = (long?)(j.duration * TimeSpan.TicksPerSecond);
if (j.is3d)
// Just a probability guess
item.Video3DFormat = Video3DFormat.HalfSideBySide;
}
}
if (ver.audio != null)
{
foreach (StreamAudio j in ver.audio)
{
MediaStream a = new MediaStream();
result.Add(a);
a.Type = MediaStreamType.Audio;
a.Language = j.language;
a.Codec = j.codec;
a.Channels = j.channels;
}
}
if (ver.subtitles != null)
{
foreach (StreamSubtitle j in ver.subtitles)
{
MediaStream a = new MediaStream();
result.Add(a);
a.Type = MediaStreamType.Subtitle;
a.Language = j.language;
a.IsForced = j.forced;
a.Path = j.src;
}
}
return result;
}
private static void ConvertHdr(bool isHdr, string? hdr, MediaStream dst)
{
if (!isHdr)

View File

@@ -8,14 +8,25 @@ namespace Jellyfin.Plugin.StreamCinema;
/// <summary>
/// Movie media item from Stream Cinema.
/// </summary>
public class StreamCinemaMovie : Movie {
public class StreamCinemaMovie : Movie
{
public sealed override string GetClientTypeName() => BaseItemKind.Movie.ToString();
protected override IEnumerable<(BaseItem Item, MediaSourceType MediaSourceType)> GetAllItemsForMediaSources() {
protected override IEnumerable<(BaseItem Item, MediaSourceType MediaSourceType)> GetAllItemsForMediaSources()
{
var result = this.VideoGetAllItemsForMediaSources();
if (result == null)
return base.GetAllItemsForMediaSources();
else
return result;
}
public override List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
{
var result = this.VideoGetMediaSources(enablePathSubstitution);
if (result == null)
return base.GetMediaSources(enablePathSubstitution);
else
return result;
}
}

View File

@@ -33,4 +33,21 @@ static class StreamCinemaVideoExtensions
foreach (T i in versions)
yield return (i, MediaSourceType.Grouping);
}
public static List<MediaSourceInfo> VideoGetMediaSources<T>(this T @this, bool enablePathSubstitution)
where T : Video, new()
{
List<MediaSourceInfo> result = new List<MediaSourceInfo>();
// Our media source manager must be present
StreamCinemaMediaSourceManager? msm;
if (!StreamCinemaMediaSourceManager.TryGetInstance(out msm))
return result;
var a = msm.GetVersionInfo(@this, default).GetAwaiter().GetResult();
if (a != null)
result.Add(a);
return result;
}
}