Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Catchup day folders #145

Merged
merged 1 commit into from
Jan 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 56 additions & 18 deletions Jellyfin.Xtream/CatchupChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public CatchupChannel(ILogger<CatchupChannel> logger)
public string? Description => "Rewatch IPTV streamed from the Xtream-compatible server.";

/// <inheritdoc />
public string DataVersion => Plugin.Instance.DataVersion;
public string DataVersion => Plugin.Instance.DataVersion + DateTime.Today.ToShortDateString();

/// <inheritdoc />
public string HomePageUrl => string.Empty;
Expand Down Expand Up @@ -109,8 +109,14 @@ public async Task<ChannelItemResult> GetChannelItems(InternalChannelItemQuery qu
}

Guid guid = Guid.Parse(query.FolderId);
StreamService.FromGuid(guid, out int prefix, out int categoryId, out int channelId, out int _);
return await GetStreams(categoryId, channelId, cancellationToken).ConfigureAwait(false);
StreamService.FromGuid(guid, out int prefix, out int categoryId, out int channelId, out int date);

if (date == 0)
{
return await GetDays(categoryId, channelId, cancellationToken).ConfigureAwait(false);
}

return await GetStreams(categoryId, channelId, date, cancellationToken).ConfigureAwait(false);
}
catch (Exception ex)
{
Expand Down Expand Up @@ -150,8 +156,48 @@ private async Task<ChannelItemResult> GetChannels(CancellationToken cancellation
return result;
}

private async Task<ChannelItemResult> GetStreams(int categoryId, int channelId, CancellationToken cancellationToken)
private async Task<ChannelItemResult> GetDays(int categoryId, int channelId, CancellationToken cancellationToken)
{
Plugin plugin = Plugin.Instance;
using (XtreamClient client = new XtreamClient())
{
StreamInfo? channel = (
await client.GetLiveStreamsByCategoryAsync(plugin.Creds, categoryId, cancellationToken).ConfigureAwait(false)
).FirstOrDefault(s => s.StreamId == channelId);
if (channel == null)
{
throw new ArgumentException($"Channel with id {channelId} not found in category {categoryId}");
}

ParsedName parsedName = StreamService.ParseName(channel.Name);
List<ChannelItemInfo> items = new List<ChannelItemInfo>();
for (int i = 0; i <= channel.TvArchiveDuration; i++)
{
DateTime channelDay = DateTime.Today.AddDays(-i);
int day = (int)(channelDay - DateTime.UnixEpoch).TotalDays;
items.Add(new ChannelItemInfo()
{
Id = StreamService.ToGuid(StreamService.CatchupPrefix, channel.CategoryId, channel.StreamId, day).ToString(),
ImageUrl = channel.StreamIcon,
Name = channelDay.ToLocalTime().ToString("ddd dd'-'MM'-'yyyy", CultureInfo.InvariantCulture),
Tags = new List<string>(parsedName.Tags),
Type = ChannelItemType.Folder,
});
}

ChannelItemResult result = new ChannelItemResult()
{
Items = items,
TotalRecordCount = items.Count
};
return result;
}
}

private async Task<ChannelItemResult> GetStreams(int categoryId, int channelId, int day, CancellationToken cancellationToken)
{
DateTime start = DateTime.UnixEpoch.AddDays(day);
DateTime end = start.AddDays(1);
Plugin plugin = Plugin.Instance;
using (XtreamClient client = new XtreamClient())
{
Expand All @@ -169,18 +215,15 @@ await client.GetLiveStreamsByCategoryAsync(plugin.Creds, categoryId, cancellatio
// Create fallback single-stream catch-up if no EPG is available.
if (epgs.Listings.Count == 0)
{
DateTime now = DateTime.UtcNow;
DateTime start = now.AddDays(-channel.TvArchiveDuration);
int duration = channel.TvArchiveDuration * 24 * 60;
int duration = 24 * 60;
return new ChannelItemResult()
{
Items = new List<ChannelItemInfo>()
{
new ChannelItemInfo()
{
ContentType = ChannelMediaContentType.TvExtra,
FolderType = ChannelFolderType.Container,
Id = StreamService.ToGuid(StreamService.FallbackPrefix, channelId, 0, 0).ToString(),
Id = StreamService.ToGuid(StreamService.CatchupStreamPrefix, channelId, 0, day).ToString(),
IsLiveStream = false,
MediaSources = new List<MediaSourceInfo>()
{
Expand All @@ -191,19 +234,15 @@ await client.GetLiveStreamsByCategoryAsync(plugin.Creds, categoryId, cancellatio
Type = ChannelItemType.Media,
}
},
TotalRecordCount = items.Count
TotalRecordCount = 1
};
}

// Include all EPGs that start during the maximum cache interval of Jellyfin for channels.
DateTime startBefore = DateTime.UtcNow.AddHours(3);
DateTime startAfter = DateTime.UtcNow.AddDays(-channel.TvArchiveDuration);
foreach (EpgInfo epg in epgs.Listings.Where(epg => epg.Start < startBefore && epg.Start >= startAfter))
foreach (EpgInfo epg in epgs.Listings.Where(epg => epg.Start <= end && epg.End >= start))
{
string id = epg.Id.ToString(System.Globalization.CultureInfo.InvariantCulture);
ParsedName parsedName = StreamService.ParseName(epg.Title);
int durationMinutes = (int)Math.Ceiling((epg.End - epg.Start).TotalMinutes);
string dateTitle = epg.Start.ToLocalTime().ToString("ddd HH:mm", CultureInfo.InvariantCulture);
string dateTitle = epg.Start.ToLocalTime().ToString("HH:mm", CultureInfo.InvariantCulture);
List<MediaSourceInfo> sources = new List<MediaSourceInfo>()
{
plugin.StreamService.GetMediaSourceInfo(StreamType.CatchUp, channelId, start: epg.StartLocalTime, durationMinutes: durationMinutes)
Expand All @@ -213,8 +252,7 @@ await client.GetLiveStreamsByCategoryAsync(plugin.Creds, categoryId, cancellatio
{
ContentType = ChannelMediaContentType.TvExtra,
DateCreated = epg.Start,
FolderType = ChannelFolderType.Container,
Id = id,
Id = StreamService.ToGuid(StreamService.CatchupStreamPrefix, channel.StreamId, epg.Id, day).ToString(),
IsLiveStream = false,
MediaSources = sources,
MediaType = ChannelMediaType.Video,
Expand Down
4 changes: 2 additions & 2 deletions Jellyfin.Xtream/Service/StreamService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ public class StreamService
public const int CatchupPrefix = 0x5d774c3b;

/// <summary>
/// The id prefix for fallback EPG items.
/// The id prefix for catchup stream items.
/// </summary>
public const int FallbackPrefix = 0x5d774c3c;
public const int CatchupStreamPrefix = 0x5d774c3c;

/// <summary>
/// The id prefix for media source items.
Expand Down
Loading