Files
claude 9e33a343ab
Some checks failed
release / build-release (push) Has been cancelled
Floatplane channel plugin for Jellyfin 10.10.x: browse, HLS proxy, cookie session, CI release
- 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>
2026-10-25 09:42:27 +01:00

99 lines
2.5 KiB
Swift

import SwiftUI
import FloatplaneAPIClient
struct PlayMediaView: View {
enum ViewMode {
case playButton
case imageCard
}
let thumbnail: ImageModelShared?
let viewMode: ViewMode
let playButtonSize: PlayButton.Size
let videoTitle: String
let playContent: (Double) -> Void
let autoPlay: Bool
@FetchRequest var watchProgresses: FetchedResults<WatchProgress>
@FocusState private var isFocused
var progress: CGFloat {
if let watchProgress = watchProgresses.first {
let progress = watchProgress.progress
return progress >= 0.95 ? 1.0 : progress
} else {
return 0.0
}
}
var body: some View {
switch viewMode {
case .playButton:
ZStack {
image
PlayButton(size: playButtonSize, videoTitle: videoTitle, action: {
self.playContent(progress)
})
.focused($isFocused)
.onFirstAppear {
if autoPlay {
Task { @MainActor in
// Issues with it happening too quickly when the view appears not working.
try? await Task.sleep(for: .milliseconds(500))
self.playContent(progress)
}
}
}
}
case .imageCard:
Button(action: {
self.playContent(progress)
}, label: {
image
})
.buttonStyle(.card)
.focused($isFocused)
.padding()
.onFirstAppear {
if autoPlay {
self.playContent(progress)
}
}
}
}
var image: some View {
MediaThumbnail(thumbnail: thumbnail, watchProgresses: _watchProgresses)
}
}
struct PlayMediaView_Previews: PreviewProvider {
static var previews: some View {
VStack {
PlayMediaView(
thumbnail: MockData.blogPosts.blogPosts.first!.thumbnail,
viewMode: .playButton,
playButtonSize: .small,
videoTitle: "video title here",
playContent: { _ in },
autoPlay: false,
watchProgresses: FetchRequest(entity: WatchProgress.entity(), sortDescriptors: [], predicate: NSPredicate(format: "blogPostId = %@", MockData.blogPosts.blogPosts.first!.id), animation: .default)
)
.environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
PlayMediaView(
thumbnail: MockData.blogPosts.blogPosts.first!.thumbnail,
viewMode: .imageCard,
playButtonSize: .default,
videoTitle: "video title here",
playContent: { _ in },
autoPlay: false,
watchProgresses: FetchRequest(entity: WatchProgress.entity(), sortDescriptors: [], predicate: NSPredicate(format: "blogPostId = %@", MockData.blogPosts.blogPosts.first!.id), animation: .default)
)
.environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}
}
}