Intercept GetStaticMediaSources instead of GetMediaStreams. Movie versions show in UI.
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -315,10 +315,15 @@ public abstract class StreamCinemaFilterFolder : Folder
|
||||
}
|
||||
item.SetImagePath(ImageType.Primary, artUri.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
// Identify the item as it originates from StreamCinema
|
||||
item.ProviderIds.Add(StreamCinemaPlugin.StreamCinemaProviderName, "");
|
||||
}
|
||||
// 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)
|
||||
{
|
||||
|
||||
@@ -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'">
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
// 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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user