Floatplane channel plugin for Jellyfin 10.10.x: browse, HLS proxy, cookie session, CI release
Some checks failed
release / build-release (push) Has been cancelled
Some checks failed
release / build-release (push) Has been cancelled
- IChannel: creators -> sub-channels -> video posts (public listing API, search mapped) - IRequiresMediaInfoCallback -> signed proxy URLs; stream controller rewrites HLS so the AES-128 key is fetched server-side with the session cookie, segments stay on the CDN - delivery/info cached per token lifetime and throttled (~2/min) - config page: paste sails.sid + validate, extra creators, quality, search test - scripts/package.sh -> plugin folder + zip + md5 + manifest.json; Gitea release workflow - research docs, HAR analysis (HAR itself gitignored), install-pi5.sh Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
166
Jellyfin.Plugin.Floatplane/Api/Models/Post.cs
Normal file
166
Jellyfin.Plugin.Floatplane/Api/Models/Post.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Jellyfin.Plugin.Floatplane.Api.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A blog post (the unit shown in Floatplane's feed). List endpoints return posts
|
||||
/// without attachment details; GET /api/v3/content/post expands them.
|
||||
/// </summary>
|
||||
public class PostModel : IHasId
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsReferenceOnly { get; set; }
|
||||
|
||||
public string? Guid { get; set; }
|
||||
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>HTML body.</summary>
|
||||
public string? Text { get; set; }
|
||||
|
||||
public string? TextMarkdown { get; set; }
|
||||
|
||||
public string? Type { get; set; }
|
||||
|
||||
public List<string> Tags { get; set; } = new();
|
||||
|
||||
public List<string> AttachmentOrder { get; set; } = new();
|
||||
|
||||
public DateTimeOffset? ReleaseDate { get; set; }
|
||||
|
||||
public int Likes { get; set; }
|
||||
|
||||
public int Dislikes { get; set; }
|
||||
|
||||
public int Score { get; set; }
|
||||
|
||||
public int Comments { get; set; }
|
||||
|
||||
public bool IsAccessible { get; set; } = true;
|
||||
|
||||
public bool WasReleasedSilently { get; set; }
|
||||
|
||||
public PostMetadata? Metadata { get; set; }
|
||||
|
||||
public ImageModel? Thumbnail { get; set; }
|
||||
|
||||
public CreatorModel? Creator { get; set; }
|
||||
|
||||
public ChannelModel? Channel { get; set; }
|
||||
|
||||
/// <summary>Full objects from /content/post; ids (or missing) from list endpoints.</summary>
|
||||
public List<VideoModel>? VideoAttachments { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public bool HasVideo => Metadata?.HasVideo ?? (VideoAttachments is { Count: > 0 });
|
||||
|
||||
[JsonIgnore]
|
||||
public double DurationSeconds => Metadata?.VideoDuration ?? 0;
|
||||
}
|
||||
|
||||
public class PostMetadata
|
||||
{
|
||||
public bool HasVideo { get; set; }
|
||||
|
||||
public int VideoCount { get; set; }
|
||||
|
||||
public double VideoDuration { get; set; }
|
||||
|
||||
public bool HasAudio { get; set; }
|
||||
|
||||
public int AudioCount { get; set; }
|
||||
|
||||
public double AudioDuration { get; set; }
|
||||
|
||||
public bool HasPicture { get; set; }
|
||||
|
||||
public int PictureCount { get; set; }
|
||||
|
||||
public bool HasGallery { get; set; }
|
||||
|
||||
public int GalleryCount { get; set; }
|
||||
|
||||
public bool IsFeatured { get; set; }
|
||||
|
||||
public double DisplayDuration { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>A video attachment (GET /api/v3/content/video or expanded in /content/post).</summary>
|
||||
public class VideoModel : IHasId
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsReferenceOnly { get; set; }
|
||||
|
||||
public string? Guid { get; set; }
|
||||
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
public string? Type { get; set; }
|
||||
|
||||
public string? Description { get; set; }
|
||||
|
||||
public double Duration { get; set; }
|
||||
|
||||
public string? Creator { get; set; }
|
||||
|
||||
public string? PrimaryBlogPost { get; set; }
|
||||
|
||||
public bool IsProcessing { get; set; }
|
||||
|
||||
public bool IsAccessible { get; set; } = true;
|
||||
|
||||
public List<VideoLevel> Levels { get; set; } = new();
|
||||
|
||||
public List<TextTrackModel> TextTracks { get; set; } = new();
|
||||
|
||||
public ImageModel? Thumbnail { get; set; }
|
||||
|
||||
public ImageModel? TimelineSprite { get; set; }
|
||||
|
||||
/// <summary>Resume position in seconds (only present when logged in).</summary>
|
||||
public double? Progress { get; set; }
|
||||
}
|
||||
|
||||
public class VideoLevel
|
||||
{
|
||||
/// <summary>"360", "480", "720", "1080", "2160".</summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
public int Width { get; set; }
|
||||
|
||||
public int Height { get; set; }
|
||||
|
||||
public string? Label { get; set; }
|
||||
|
||||
public int Order { get; set; }
|
||||
}
|
||||
|
||||
public class TextTrackModel
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>S3-presigned URL (expires after 15 minutes).</summary>
|
||||
public string Src { get; set; } = string.Empty;
|
||||
|
||||
public string? Kind { get; set; }
|
||||
|
||||
public string? Language { get; set; }
|
||||
|
||||
public bool Generated { get; set; }
|
||||
|
||||
public bool Processing { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>Entry of GET /api/v3/content/progress (percentage) or POST /content/get/progress.</summary>
|
||||
public class ProgressModel
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
|
||||
public double Progress { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user