diff --git a/Jellyfin.Xtream/CatchupChannel.cs b/Jellyfin.Xtream/CatchupChannel.cs
index 0814052..25ebd8b 100644
--- a/Jellyfin.Xtream/CatchupChannel.cs
+++ b/Jellyfin.Xtream/CatchupChannel.cs
@@ -35,7 +35,7 @@ namespace Jellyfin.Xtream;
/// The Xtream Codes API channel.
///
/// Instance of the interface.
-public class CatchupChannel(ILogger logger) : IChannel
+public class CatchupChannel(ILogger logger) : IChannel, IDisableMediaSourceDisplay
{
private readonly ILogger _logger = logger;
diff --git a/Jellyfin.Xtream/Client/Models/AudioInfo.cs b/Jellyfin.Xtream/Client/Models/AudioInfo.cs
new file mode 100644
index 0000000..8ec4799
--- /dev/null
+++ b/Jellyfin.Xtream/Client/Models/AudioInfo.cs
@@ -0,0 +1,46 @@
+// Copyright (C) 2022 Kevin Jilissen
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using Newtonsoft.Json;
+
+#pragma warning disable CS1591
+namespace Jellyfin.Xtream.Client.Models;
+
+public class AudioInfo
+{
+ [JsonProperty("index")]
+ public int Index { get; set; }
+
+ [JsonProperty("codec_name")]
+ public string CodecName { get; set; } = string.Empty;
+
+ [JsonProperty("profile")]
+ public string Profile { get; set; } = string.Empty;
+
+ [JsonProperty("sample_fmt")]
+ public string SampleFormat { get; set; } = string.Empty;
+
+ [JsonProperty("sample_rate")]
+ public int SampleRate { get; set; }
+
+ [JsonProperty("channels")]
+ public int Channels { get; set; }
+
+ [JsonProperty("channel_layout")]
+ public string ChannelLayout { get; set; } = string.Empty;
+
+ [JsonProperty("bit_rate")]
+ public int Bitrate { get; set; }
+}
diff --git a/Jellyfin.Xtream/Client/Models/EpisodeInfo.cs b/Jellyfin.Xtream/Client/Models/EpisodeInfo.cs
index 4f19b10..0519340 100644
--- a/Jellyfin.Xtream/Client/Models/EpisodeInfo.cs
+++ b/Jellyfin.Xtream/Client/Models/EpisodeInfo.cs
@@ -22,20 +22,28 @@ namespace Jellyfin.Xtream.Client.Models;
public class EpisodeInfo
{
[JsonProperty("movie_image")]
- public string MovieImage { get; set; } = string.Empty;
+ public string? MovieImage { get; set; }
[JsonProperty("plot")]
- public string Plot { get; set; } = string.Empty;
+ public string? Plot { get; set; }
[JsonProperty("releasedate")]
- public DateTime ReleaseDate { get; set; }
+ public DateTime? ReleaseDate { get; set; }
[JsonProperty("rating")]
- public decimal Rating { get; set; }
+ public decimal? Rating { get; set; }
[JsonProperty("duration_secs")]
- public int DurationSecs { get; set; }
+ public int? DurationSecs { get; set; }
[JsonProperty("bitrate")]
- public int Bitrate { get; set; }
+ public int? Bitrate { get; set; }
+
+ [JsonProperty("video")]
+ [JsonConverter(typeof(OnlyObjectConverter))]
+ public VideoInfo? Video { get; set; }
+
+ [JsonProperty("audio")]
+ [JsonConverter(typeof(OnlyObjectConverter))]
+ public AudioInfo? Audio { get; set; }
}
diff --git a/Jellyfin.Xtream/Client/Models/VideoInfo.cs b/Jellyfin.Xtream/Client/Models/VideoInfo.cs
new file mode 100644
index 0000000..12dacf0
--- /dev/null
+++ b/Jellyfin.Xtream/Client/Models/VideoInfo.cs
@@ -0,0 +1,64 @@
+// Copyright (C) 2022 Kevin Jilissen
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using Newtonsoft.Json;
+
+#pragma warning disable CS1591
+namespace Jellyfin.Xtream.Client.Models;
+
+public class VideoInfo
+{
+ [JsonProperty("index")]
+ public int Index { get; set; }
+
+ [JsonProperty("codec_name")]
+ public string CodecName { get; set; } = string.Empty;
+
+ [JsonProperty("profile")]
+ public string Profile { get; set; } = string.Empty;
+
+ [JsonProperty("width")]
+ public int Width { get; set; }
+
+ [JsonProperty("height")]
+ public int Height { get; set; }
+
+ [JsonProperty("display_aspect_ratio")]
+ public string AspectRatio { get; set; } = string.Empty;
+
+ [JsonProperty("pix_fmt")]
+ public string PixelFormat { get; set; } = string.Empty;
+
+ [JsonProperty("level")]
+ public int Level { get; set; }
+
+ [JsonProperty("color_range")]
+ public string ColorRange { get; set; } = string.Empty;
+
+ [JsonProperty("color_space")]
+ public string ColorSpace { get; set; } = string.Empty;
+
+ [JsonProperty("color_transfer")]
+ public string ColorTransfer { get; set; } = string.Empty;
+
+ [JsonProperty("color_primaries")]
+ public string ColorPrimaries { get; set; } = string.Empty;
+
+ [JsonProperty("is_avc")]
+ public bool IsAVC { get; set; }
+
+ [JsonProperty("bits_per_raw_sample")]
+ public int BitsPerRawSample { get; set; }
+}
diff --git a/Jellyfin.Xtream/Client/Models/VodInfo.cs b/Jellyfin.Xtream/Client/Models/VodInfo.cs
new file mode 100644
index 0000000..0c5db3d
--- /dev/null
+++ b/Jellyfin.Xtream/Client/Models/VodInfo.cs
@@ -0,0 +1,58 @@
+// Copyright (C) 2022 Kevin Jilissen
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using System;
+using Newtonsoft.Json;
+
+#pragma warning disable CS1591
+namespace Jellyfin.Xtream.Client.Models;
+
+public class VodInfo
+{
+ [JsonProperty("movie_image")]
+ public string? MovieImage { get; set; }
+
+ [JsonProperty("genre")]
+ public string? Genre { get; set; }
+
+ [JsonProperty("plot")]
+ public string? Plot { get; set; }
+
+ [JsonProperty("director")]
+ public string? Director { get; set; }
+
+ [JsonProperty("rating")]
+ public decimal? Rating { get; set; }
+
+ [JsonProperty("releasedate")]
+ public DateTime? ReleaseDate { get; set; }
+
+ [JsonProperty("duration_secs")]
+ public int? DurationSecs { get; set; }
+
+ [JsonProperty("tmdb_id")]
+ public int? TmdbId { get; set; }
+
+ [JsonProperty("bitrate")]
+ public int Bitrate { get; set; }
+
+ [JsonProperty("video")]
+ [JsonConverter(typeof(OnlyObjectConverter))]
+ public VideoInfo? Video { get; set; }
+
+ [JsonProperty("audio")]
+ [JsonConverter(typeof(OnlyObjectConverter))]
+ public AudioInfo? Audio { get; set; }
+}
diff --git a/Jellyfin.Xtream/Client/Models/VodStreamInfo.cs b/Jellyfin.Xtream/Client/Models/VodStreamInfo.cs
new file mode 100644
index 0000000..06e4dce
--- /dev/null
+++ b/Jellyfin.Xtream/Client/Models/VodStreamInfo.cs
@@ -0,0 +1,30 @@
+// Copyright (C) 2022 Kevin Jilissen
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using Newtonsoft.Json;
+
+#pragma warning disable CS1591
+namespace Jellyfin.Xtream.Client.Models;
+
+public class VodStreamInfo
+{
+ [JsonProperty("info")]
+ [JsonConverter(typeof(OnlyObjectConverter))]
+ public VodInfo? Info { get; set; }
+
+ [JsonProperty("movie_data")]
+ [JsonConverter(typeof(OnlyObjectConverter))]
+ public StreamInfo? MovieData { get; set; }
+}
diff --git a/Jellyfin.Xtream/Client/XtreamClient.cs b/Jellyfin.Xtream/Client/XtreamClient.cs
index b24219c..53854f3 100644
--- a/Jellyfin.Xtream/Client/XtreamClient.cs
+++ b/Jellyfin.Xtream/Client/XtreamClient.cs
@@ -71,6 +71,12 @@ public class XtreamClient(HttpClient client) : IDisposable
$"/player_api.php?username={connectionInfo.UserName}&password={connectionInfo.Password}&action=get_vod_streams&category_id={categoryId}",
cancellationToken);
+ public Task GetVodInfoAsync(ConnectionInfo connectionInfo, int streamId, CancellationToken cancellationToken) =>
+ QueryApi(
+ connectionInfo,
+ $"/player_api.php?username={connectionInfo.UserName}&password={connectionInfo.Password}&action=get_vod_info&vod_id={streamId}",
+ cancellationToken);
+
public Task> GetLiveStreamsByCategoryAsync(ConnectionInfo connectionInfo, int categoryId, CancellationToken cancellationToken) =>
QueryApi>(
connectionInfo,
diff --git a/Jellyfin.Xtream/Configuration/PluginConfiguration.cs b/Jellyfin.Xtream/Configuration/PluginConfiguration.cs
index c70caf4..7cb48c9 100644
--- a/Jellyfin.Xtream/Configuration/PluginConfiguration.cs
+++ b/Jellyfin.Xtream/Configuration/PluginConfiguration.cs
@@ -54,6 +54,11 @@ public class PluginConfiguration : BasePluginConfiguration
///
public bool IsVodVisible { get; set; }
+ ///
+ /// Gets or sets a value indicating whether the Video On-demand channel is visible.
+ ///
+ public bool IsTmdbVodOverride { get; set; } = true;
+
///
/// Gets or sets the channels displayed in Live TV.
///
diff --git a/Jellyfin.Xtream/Configuration/Web/XtreamVod.html b/Jellyfin.Xtream/Configuration/Web/XtreamVod.html
index 57d257c..40bb72d 100644
--- a/Jellyfin.Xtream/Configuration/Web/XtreamVod.html
+++ b/Jellyfin.Xtream/Configuration/Web/XtreamVod.html
@@ -9,6 +9,12 @@
Show this channel to users
+
+
+
Video On-demand selection
diff --git a/Jellyfin.Xtream/Configuration/Web/XtreamVod.js b/Jellyfin.Xtream/Configuration/Web/XtreamVod.js
index 59fb097..9b3bde0 100644
--- a/Jellyfin.Xtream/Configuration/Web/XtreamVod.js
+++ b/Jellyfin.Xtream/Configuration/Web/XtreamVod.js
@@ -11,6 +11,8 @@ export default function (view) {
const getConfig = ApiClient.getPluginConfiguration(pluginId);
const visible = view.querySelector("#Visible");
getConfig.then((config) => visible.checked = config.IsVodVisible);
+ const tmdbOverride = view.querySelector("#TmdbOverride");
+ getConfig.then((config) => TmdbOverride.checked = config.IsTmdbVodOverride);
const table = view.querySelector('#VodContent');
Xtream.populateCategoriesTable(
table,
@@ -23,6 +25,7 @@ export default function (view) {
ApiClient.getPluginConfiguration(pluginId).then((config) => {
config.IsVodVisible = visible.checked;
+ config.IsTmdbVodOverride = tmdbOverride.checked;
config.Vod = data;
ApiClient.updatePluginConfiguration(pluginId, config).then((result) => {
Dashboard.processPluginConfigurationUpdateResult(result);
diff --git a/Jellyfin.Xtream/PluginServiceRegistrator.cs b/Jellyfin.Xtream/PluginServiceRegistrator.cs
index 1303535..85cdb5d 100644
--- a/Jellyfin.Xtream/PluginServiceRegistrator.cs
+++ b/Jellyfin.Xtream/PluginServiceRegistrator.cs
@@ -13,10 +13,12 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
+using Jellyfin.Xtream.Providers;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Plugins;
+using MediaBrowser.Controller.Providers;
using Microsoft.Extensions.DependencyInjection;
namespace Jellyfin.Xtream;
@@ -31,5 +33,6 @@ public class PluginServiceRegistrator : IPluginServiceRegistrator
serviceCollection.AddSingleton();
serviceCollection.AddSingleton();
serviceCollection.AddSingleton();
+ serviceCollection.AddSingleton();
}
}
diff --git a/Jellyfin.Xtream/Providers/XtreamVodProvider.cs b/Jellyfin.Xtream/Providers/XtreamVodProvider.cs
new file mode 100644
index 0000000..37aa51a
--- /dev/null
+++ b/Jellyfin.Xtream/Providers/XtreamVodProvider.cs
@@ -0,0 +1,116 @@
+// Copyright (C) 2022 Kevin Jilissen
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Jellyfin.Xtream.Client;
+using Jellyfin.Xtream.Client.Models;
+using Jellyfin.Xtream.Service;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Providers;
+using Microsoft.Extensions.Logging;
+
+namespace Jellyfin.Xtream.Providers;
+
+///
+/// The Xtream Codes VOD metadata provider.
+///
+/// Instance of the interface.
+/// Instance of the interface.
+public class XtreamVodProvider(ILogger logger, IProviderManager providerManager) : ICustomMetadataProvider, IPreRefreshProvider
+{
+ ///
+ /// The name of the provider.
+ ///
+ public const string ProviderName = "XtreamVodProvider";
+
+ ///
+ public string Name => ProviderName;
+
+ ///
+ public async Task FetchAsync(Movie item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ {
+ string? idStr = item.GetProviderId(ProviderName);
+ if (idStr is not null)
+ {
+ logger.LogDebug("Getting metadata for movie {Id}", idStr);
+ int id = int.Parse(idStr, CultureInfo.InvariantCulture);
+ using XtreamClient client = new();
+ VodStreamInfo vod = await client.GetVodInfoAsync(Plugin.Instance.Creds, id, cancellationToken).ConfigureAwait(false);
+ VodInfo? i = vod.Info;
+
+ if (i is null)
+ {
+ return ItemUpdateType.None;
+ }
+
+ item.Overview ??= i.Plot;
+ item.PremiereDate ??= i.ReleaseDate;
+ item.RunTimeTicks ??= i.DurationSecs is not null ? TimeSpan.TicksPerSecond * i.DurationSecs : null;
+ item.TotalBitrate ??= i.Bitrate;
+
+ if (i.Genre is string genres)
+ {
+ item.Genres ??= genres.Split(',').Select(genre => genre.Trim()).ToArray();
+ }
+
+ if (!item.HasProviderId(MetadataProvider.Tmdb))
+ {
+ if (i.TmdbId is int tmdbId)
+ {
+ options.ReplaceAllMetadata = true;
+ item.SetProviderId(MetadataProvider.Tmdb, tmdbId.ToString(CultureInfo.InvariantCulture));
+ }
+ else if (Plugin.Instance.Configuration.IsTmdbVodOverride)
+ {
+ MovieInfo queryInfo = new()
+ {
+ Name = StreamService.ParseName(vod.MovieData?.Name ?? string.Empty).Title,
+ Year = item.PremiereDate?.Year,
+ };
+ // Try to fetch the TMDB id to get proper metadata.
+ RemoteSearchQuery query = new()
+ {
+ SearchInfo = queryInfo,
+ SearchProviderName = "TheMovieDb",
+ };
+ IEnumerable results = await providerManager.GetRemoteSearchResults(query, cancellationToken).ConfigureAwait(false);
+ if (results.Any())
+ {
+ RemoteSearchResult tmdbMovie = results.First();
+ if (tmdbMovie.HasProviderId(MetadataProvider.Tmdb))
+ {
+ string? queryId = tmdbMovie.GetProviderId(MetadataProvider.Tmdb);
+ if (queryId is not null)
+ {
+ options.ReplaceAllMetadata = true;
+ item.SetProviderId(MetadataProvider.Tmdb, queryId);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return ItemUpdateType.MetadataImport;
+ }
+}
diff --git a/Jellyfin.Xtream/SeriesChannel.cs b/Jellyfin.Xtream/SeriesChannel.cs
index a0f1e8e..5b72b29 100644
--- a/Jellyfin.Xtream/SeriesChannel.cs
+++ b/Jellyfin.Xtream/SeriesChannel.cs
@@ -35,7 +35,7 @@ namespace Jellyfin.Xtream;
/// The Xtream Codes API channel.
///
/// Instance of the interface.
-public class SeriesChannel(ILogger logger) : IChannel
+public class SeriesChannel(ILogger logger) : IChannel, IDisableMediaSourceDisplay
{
///
public string? Name => "Xtream Series";
@@ -198,20 +198,19 @@ public class SeriesChannel(ILogger logger) : IChannel
{
Client.Models.SeriesInfo serie = series.Info;
ParsedName parsedName = StreamService.ParseName(episode.Title);
- List sources = [
- Plugin.Instance.StreamService.GetMediaSourceInfo(StreamType.Series, episode.EpisodeId, episode.ContainerExtension)
+ List sources =
+ [
+ Plugin.Instance.StreamService.GetMediaSourceInfo(
+ StreamType.Series,
+ episode.EpisodeId,
+ episode.ContainerExtension,
+ videoInfo: episode.Info?.Video,
+ audioInfo: episode.Info?.Audio)
];
string? cover = episode.Info?.MovieImage;
- if (string.IsNullOrEmpty(cover) && season != null)
- {
- cover = season.Cover;
- }
-
- if (string.IsNullOrEmpty(cover))
- {
- cover = serie.Cover;
- }
+ cover ??= season?.Cover;
+ cover ??= serie.Cover;
return new()
{
diff --git a/Jellyfin.Xtream/Service/StreamService.cs b/Jellyfin.Xtream/Service/StreamService.cs
index c5f6abd..ce3b80f 100644
--- a/Jellyfin.Xtream/Service/StreamService.cs
+++ b/Jellyfin.Xtream/Service/StreamService.cs
@@ -24,6 +24,7 @@ using Jellyfin.Xtream.Client;
using Jellyfin.Xtream.Client.Models;
using Jellyfin.Xtream.Configuration;
using MediaBrowser.Controller.Channels;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.MediaInfo;
@@ -367,6 +368,8 @@ public partial class StreamService
/// Boolean indicating whether or not restreaming is used.
/// The datetime representing the start time of catcup TV.
/// The duration in minutes of the catcup TV stream.
+ /// The Xtream video info if known.
+ /// The Xtream audio info if known.
/// The media source info as class.
public MediaSourceInfo GetMediaSourceInfo(
StreamType type,
@@ -374,7 +377,9 @@ public partial class StreamService
string? extension = null,
bool restream = false,
DateTime? start = null,
- int durationMinutes = 0)
+ int durationMinutes = 0,
+ VideoInfo? videoInfo = null,
+ AudioInfo? audioInfo = null)
{
string prefix = string.Empty;
switch (type)
@@ -403,22 +408,41 @@ public partial class StreamService
bool isLive = type == StreamType.Live;
return new MediaSourceInfo()
{
+ Container = extension,
EncoderProtocol = MediaProtocol.Http,
Id = ToGuid(MediaSourcePrefix, (int)type, id, 0).ToString(),
IsInfiniteStream = isLive,
IsRemote = true,
- // Define media sources with unknown index and interlaced to improve compatibility.
- MediaStreams = [
+ MediaStreams =
+ [
new()
{
+ AspectRatio = videoInfo?.AspectRatio,
+ BitDepth = videoInfo?.BitsPerRawSample,
+ Codec = videoInfo?.CodecName,
+ ColorPrimaries = videoInfo?.ColorPrimaries,
+ ColorRange = videoInfo?.ColorRange,
+ ColorSpace = videoInfo?.ColorSpace,
+ ColorTransfer = videoInfo?.ColorTransfer,
+ Height = videoInfo?.Height,
+ Index = videoInfo?.Index ?? -1,
+ IsAVC = videoInfo?.IsAVC,
+ IsInterlaced = true,
+ Level = videoInfo?.Level,
+ PixelFormat = videoInfo?.PixelFormat,
+ Profile = videoInfo?.Profile,
Type = MediaStreamType.Video,
- Index = -1,
- IsInterlaced = true
},
new()
{
+ BitRate = audioInfo?.Bitrate,
+ ChannelLayout = audioInfo?.ChannelLayout,
+ Channels = audioInfo?.Channels,
+ Codec = audioInfo?.CodecName,
+ Index = audioInfo?.Index ?? -1,
+ Profile = audioInfo?.Profile,
+ SampleRate = audioInfo?.SampleRate,
Type = MediaStreamType.Audio,
- Index = -1
}
],
Name = "default",
diff --git a/Jellyfin.Xtream/VodChannel.cs b/Jellyfin.Xtream/VodChannel.cs
index b2211f9..b08397f 100644
--- a/Jellyfin.Xtream/VodChannel.cs
+++ b/Jellyfin.Xtream/VodChannel.cs
@@ -20,6 +20,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Xtream.Client.Models;
+using Jellyfin.Xtream.Providers;
using Jellyfin.Xtream.Service;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Providers;
@@ -34,7 +35,7 @@ namespace Jellyfin.Xtream;
/// The Xtream Codes API channel.
///
/// Instance of the interface.
-public class VodChannel(ILogger logger) : IChannel
+public class VodChannel(ILogger logger) : IChannel, IDisableMediaSourceDisplay
{
///
public string? Name => "Xtream Video On-Demand";
@@ -113,19 +114,23 @@ public class VodChannel(ILogger logger) : IChannel
}
}
- private ChannelItemInfo CreateChannelItemInfo(StreamInfo stream)
+ private Task CreateChannelItemInfo(StreamInfo stream)
{
long added = long.Parse(stream.Added, CultureInfo.InvariantCulture);
ParsedName parsedName = StreamService.ParseName(stream.Name);
- List sources = [
- Plugin.Instance.StreamService.GetMediaSourceInfo(StreamType.Vod, stream.StreamId, stream.ContainerExtension)
+
+ List sources =
+ [
+ Plugin.Instance.StreamService.GetMediaSourceInfo(
+ StreamType.Vod,
+ stream.StreamId,
+ stream.ContainerExtension)
];
- return new()
+ ChannelItemInfo result = new ChannelItemInfo()
{
ContentType = ChannelMediaContentType.Movie,
DateCreated = DateTimeOffset.FromUnixTimeSeconds(added).DateTime,
- FolderType = ChannelFolderType.Container,
Id = $"{StreamService.StreamPrefix}{stream.StreamId}",
ImageUrl = stream.StreamIcon,
IsLiveStream = false,
@@ -134,7 +139,10 @@ public class VodChannel(ILogger logger) : IChannel
Name = parsedName.Title,
Tags = new List(parsedName.Tags),
Type = ChannelItemType.Media,
+ ProviderIds = { { XtreamVodProvider.ProviderName, stream.StreamId.ToString(CultureInfo.InvariantCulture) } },
};
+
+ return Task.FromResult(result);
}
private async Task GetCategories(CancellationToken cancellationToken)
@@ -152,8 +160,8 @@ public class VodChannel(ILogger logger) : IChannel
private async Task GetStreams(int categoryId, CancellationToken cancellationToken)
{
IEnumerable streams = await Plugin.Instance.StreamService.GetVodStreams(categoryId, cancellationToken).ConfigureAwait(false);
- List items = new List(streams.Select(CreateChannelItemInfo));
- ChannelItemResult result = new()
+ List items = [.. await Task.WhenAll(streams.Select(CreateChannelItemInfo)).ConfigureAwait(false)];
+ ChannelItemResult result = new ChannelItemResult()
{
Items = items,
TotalRecordCount = items.Count
diff --git a/jellyfin.ruleset b/jellyfin.ruleset
index 8af791c..d6994a1 100644
--- a/jellyfin.ruleset
+++ b/jellyfin.ruleset
@@ -63,7 +63,7 @@
-
+