mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-08 23:18:16 -07:00
feature: Add support for mediaSegments (#138)
Co-authored-by: PartyDonut <PartyDonut@users.noreply.github.com>
This commit is contained in:
parent
36758bd508
commit
5c560e54b5
28 changed files with 6823 additions and 8312 deletions
|
|
@ -1,9 +1,9 @@
|
|||
import 'package:fladder/providers/video_player_provider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
|
||||
import 'package:fladder/providers/video_player_provider.dart';
|
||||
import 'package:fladder/screens/video_player/components/video_player_chapters.dart';
|
||||
import 'package:fladder/screens/video_player/components/video_player_queue.dart';
|
||||
|
||||
|
|
@ -84,10 +84,10 @@ class IntroSkipButton extends ConsumerWidget {
|
|||
}
|
||||
}
|
||||
|
||||
class CreditsSkipButton extends ConsumerWidget {
|
||||
class OutroSkipButton extends ConsumerWidget {
|
||||
final bool isOverlayVisible;
|
||||
final Function()? skipCredits;
|
||||
const CreditsSkipButton({this.skipCredits, required this.isOverlayVisible, super.key});
|
||||
final Function()? skipOutro;
|
||||
const OutroSkipButton({this.skipOutro, required this.isOverlayVisible, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -96,7 +96,7 @@ class CreditsSkipButton extends ConsumerWidget {
|
|||
opacity: 1,
|
||||
duration: const Duration(milliseconds: 250),
|
||||
child: ElevatedButton(
|
||||
onPressed: () => skipCredits?.call(),
|
||||
onPressed: () => skipOutro?.call(),
|
||||
style: ElevatedButton.styleFrom(shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5))),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(8),
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ class _VideoPlayerNextWrapperState extends ConsumerState<VideoPlayerNextWrapper>
|
|||
return;
|
||||
}
|
||||
|
||||
final credits = ref.read(playBackModel)?.introSkipModel?.credits;
|
||||
final credits = ref.read(playBackModel)?.mediaSegments?.outro;
|
||||
|
||||
if (nextType == AutoNextType.static || credits == null) {
|
||||
if ((model.duration - model.position).abs() < const Duration(seconds: 32)) {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import 'package:collection/collection.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import 'package:fladder/models/items/chapters_model.dart';
|
||||
import 'package:fladder/models/items/intro_skip_model.dart';
|
||||
import 'package:fladder/models/items/media_segments_model.dart';
|
||||
import 'package:fladder/providers/video_player_provider.dart';
|
||||
import 'package:fladder/util/duration_extensions.dart';
|
||||
import 'package:fladder/util/list_padding.dart';
|
||||
|
|
@ -54,7 +54,7 @@ class _ChapterProgressSliderState extends ConsumerState<VideoProgressBar> {
|
|||
final isVisible = (onDragStart ? true : onHoverStart);
|
||||
final player = ref.watch(videoPlayerProvider);
|
||||
final position = onDragStart ? currentDuration : widget.position;
|
||||
final IntroOutSkipModel? introCreditsModel = ref.read(playBackModel.select((value) => value?.introSkipModel));
|
||||
final MediaSegmentsModel? mediaSegments = ref.read(playBackModel.select((value) => value?.mediaSegments));
|
||||
final relativeFraction = position.inMilliseconds / widget.duration.inMilliseconds;
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
|
|
@ -138,36 +138,22 @@ class _ChapterProgressSliderState extends ConsumerState<VideoProgressBar> {
|
|||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
if (introCreditsModel?.intro?.start != null && introCreditsModel?.intro?.end != null)
|
||||
Positioned(
|
||||
left: calculateStartOffset(constraints, introCreditsModel!.intro!.start),
|
||||
right: calculateRightOffset(constraints, introCreditsModel.intro!.end),
|
||||
...?mediaSegments?.segments.map(
|
||||
(segment) => Positioned(
|
||||
left: calculateStartOffset(constraints, segment.start),
|
||||
right: calculateRightOffset(constraints, segment.end),
|
||||
bottom: 0,
|
||||
child: Container(
|
||||
height: 6,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.greenAccent.withOpacity(0.8),
|
||||
borderRadius: BorderRadius.circular(
|
||||
100,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (introCreditsModel?.credits?.start != null && introCreditsModel?.credits?.end != null)
|
||||
Positioned(
|
||||
left: calculateStartOffset(constraints, introCreditsModel!.credits!.start),
|
||||
right: calculateRightOffset(constraints, introCreditsModel.credits!.end),
|
||||
bottom: 0,
|
||||
child: Container(
|
||||
height: 6,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.orangeAccent.withOpacity(0.8),
|
||||
color: segment.type.color,
|
||||
borderRadius: BorderRadius.circular(
|
||||
100,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!widget.buffering) ...{
|
||||
//VideoBufferBar
|
||||
Positioned(
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import 'package:screen_brightness/screen_brightness.dart';
|
|||
import 'package:universal_html/html.dart' as html;
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
import 'package:fladder/models/items/intro_skip_model.dart';
|
||||
import 'package:fladder/models/items/media_segments_model.dart';
|
||||
import 'package:fladder/models/media_playback_model.dart';
|
||||
import 'package:fladder/models/playback/playback_model.dart';
|
||||
import 'package:fladder/providers/settings/client_settings_provider.dart';
|
||||
|
|
@ -57,10 +57,10 @@ class _DesktopControlsState extends ConsumerState<DesktopControls> {
|
|||
late final double bottomPadding = MediaQuery.of(context).viewPadding.bottom;
|
||||
|
||||
bool _onKey(KeyEvent value) {
|
||||
final introSkipModel = ref.read(playBackModel.select((value) => value?.introSkipModel));
|
||||
final mediaSegments = ref.read(playBackModel.select((value) => value?.mediaSegments));
|
||||
final position = ref.read(mediaPlaybackProvider).position;
|
||||
bool showIntroSkipButton = introSkipModel?.introInRange(position) ?? false;
|
||||
bool showCreditSkipButton = introSkipModel?.creditsInRange(position) ?? false;
|
||||
bool showIntroSkipButton = mediaSegments?.intro?.inRange(position) ?? false;
|
||||
bool showOutroSkipButton = mediaSegments?.outro?.inRange(position) ?? false;
|
||||
if (value is KeyRepeatEvent) {
|
||||
if (value.logicalKey == LogicalKeyboardKey.arrowUp) {
|
||||
resetTimer();
|
||||
|
|
@ -76,9 +76,9 @@ class _DesktopControlsState extends ConsumerState<DesktopControls> {
|
|||
if (value is KeyDownEvent) {
|
||||
if (value.logicalKey == LogicalKeyboardKey.keyS) {
|
||||
if (showIntroSkipButton) {
|
||||
skipIntro(introSkipModel);
|
||||
} else if (showCreditSkipButton) {
|
||||
skipCredits(introSkipModel);
|
||||
skipIntro(mediaSegments);
|
||||
} else if (showOutroSkipButton) {
|
||||
skipOutro(mediaSegments);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -116,7 +116,7 @@ class _DesktopControlsState extends ConsumerState<DesktopControls> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final introSkipModel = ref.watch(playBackModel.select((value) => value?.introSkipModel));
|
||||
final mediaSegments = ref.watch(playBackModel.select((value) => value?.mediaSegments));
|
||||
final player = ref.watch(videoPlayerProvider.select((value) => value.controller));
|
||||
return InputHandler(
|
||||
autoFocus: false,
|
||||
|
|
@ -167,8 +167,8 @@ class _DesktopControlsState extends ConsumerState<DesktopControls> {
|
|||
Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final position = ref.watch(mediaPlaybackProvider.select((value) => value.position));
|
||||
bool showIntroSkipButton = introSkipModel?.introInRange(position) ?? false;
|
||||
bool showCreditSkipButton = introSkipModel?.creditsInRange(position) ?? false;
|
||||
bool showIntroSkipButton = mediaSegments?.intro?.inRange(position) ?? false;
|
||||
bool showOutroSkipButton = mediaSegments?.outro?.inRange(position) ?? false;
|
||||
return Stack(
|
||||
children: [
|
||||
if (showIntroSkipButton)
|
||||
|
|
@ -178,18 +178,18 @@ class _DesktopControlsState extends ConsumerState<DesktopControls> {
|
|||
padding: const EdgeInsets.all(32),
|
||||
child: IntroSkipButton(
|
||||
isOverlayVisible: showOverlay,
|
||||
skipIntro: () => skipIntro(introSkipModel),
|
||||
skipIntro: () => skipIntro(mediaSegments),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (showCreditSkipButton)
|
||||
if (showOutroSkipButton)
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(32),
|
||||
child: CreditsSkipButton(
|
||||
child: OutroSkipButton(
|
||||
isOverlayVisible: showOverlay,
|
||||
skipCredits: () => skipCredits(introSkipModel),
|
||||
skipOutro: () => skipOutro(mediaSegments),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -582,17 +582,17 @@ class _DesktopControlsState extends ConsumerState<DesktopControls> {
|
|||
);
|
||||
}
|
||||
|
||||
void skipIntro(IntroOutSkipModel? introSkipModel) {
|
||||
void skipIntro(MediaSegmentsModel? mediaSegments) {
|
||||
resetTimer();
|
||||
final end = introSkipModel?.intro?.end;
|
||||
final end = mediaSegments?.intro?.end;
|
||||
if (end != null) {
|
||||
ref.read(videoPlayerProvider).seek(end);
|
||||
}
|
||||
}
|
||||
|
||||
void skipCredits(IntroOutSkipModel? introSkipModel) {
|
||||
void skipOutro(MediaSegmentsModel? mediaSegments) {
|
||||
resetTimer();
|
||||
final end = introSkipModel?.credits?.end;
|
||||
final end = mediaSegments?.outro?.end;
|
||||
if (end != null) {
|
||||
ref.read(videoPlayerProvider).seek(end);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue