[mastodon] Add Support for Videos (#51)

It is now possible to play videos from toots within FeedDeck. For that
we are using the "madia_kit" package, which is already used for the
Podcast player on Windows and Linux.

The videos from a toot are saved within the "options.videos" field of an
item next to the "options.media" field. In the "ItemDetailsMastodon"
widget we are then checking if this field is present and contains a list
of video urls. These urls can then be played via the "ItemVideos"
widget.
This commit is contained in:
Rico Berger
2023-10-27 15:22:27 +02:00
committed by GitHub
parent 94d5732f6a
commit 8dc83a5d5a
14 changed files with 381 additions and 27 deletions

View File

@@ -13,8 +13,12 @@ PODS:
- FMDB/standard (2.7.5)
- just_audio (0.0.1):
- Flutter
- media_kit_libs_ios_video (1.0.4):
- Flutter
- media_kit_native_event_loop (1.0.0):
- Flutter
- media_kit_video (0.0.1):
- Flutter
- package_info_plus (0.4.5):
- Flutter
- path_provider_foundation (0.0.1):
@@ -26,6 +30,8 @@ PODS:
- PurchasesHybridCommon (7.0.0):
- RevenueCat (= 4.27.0)
- RevenueCat (4.27.0)
- screen_brightness_ios (0.1.0):
- Flutter
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
@@ -36,6 +42,10 @@ PODS:
- FMDB (>= 2.7.5)
- url_launcher_ios (0.0.1):
- Flutter
- volume_controller (0.0.1):
- Flutter
- wakelock_plus (0.0.1):
- Flutter
- webview_flutter_wkwebview (0.0.1):
- Flutter
@@ -46,14 +56,19 @@ DEPENDENCIES:
- Flutter (from `Flutter`)
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
- just_audio (from `.symlinks/plugins/just_audio/ios`)
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
- media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`)
- media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- purchases_flutter (from `.symlinks/plugins/purchases_flutter/ios`)
- screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sign_in_with_apple (from `.symlinks/plugins/sign_in_with_apple/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- volume_controller (from `.symlinks/plugins/volume_controller/ios`)
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`)
SPEC REPOS:
@@ -75,14 +90,20 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_native_splash/ios"
just_audio:
:path: ".symlinks/plugins/just_audio/ios"
media_kit_libs_ios_video:
:path: ".symlinks/plugins/media_kit_libs_ios_video/ios"
media_kit_native_event_loop:
:path: ".symlinks/plugins/media_kit_native_event_loop/ios"
media_kit_video:
:path: ".symlinks/plugins/media_kit_video/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
purchases_flutter:
:path: ".symlinks/plugins/purchases_flutter/ios"
screen_brightness_ios:
:path: ".symlinks/plugins/screen_brightness_ios/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
sign_in_with_apple:
@@ -91,6 +112,10 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/sqflite/ios"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
volume_controller:
:path: ".symlinks/plugins/volume_controller/ios"
wakelock_plus:
:path: ".symlinks/plugins/wakelock_plus/ios"
webview_flutter_wkwebview:
:path: ".symlinks/plugins/webview_flutter_wkwebview/ios"
@@ -102,16 +127,21 @@ SPEC CHECKSUMS:
flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa
media_kit_native_event_loop: f1ee9f941ec0af371b245969a3e010901c375480
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
purchases_flutter: 549ccfbbaf5e7cd195043c714b69a35e278c00f1
PurchasesHybridCommon: af3b2413f9cb999bc1fdca44770bdaf39dfb89fa
RevenueCat: 84fbe2eb9bbf63e1abf346ccd3ff9ee45d633e3b
screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440
sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9
wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47
webview_flutter_wkwebview: 2e2d318f21a5e036e2c3f26171342e95908bd60a
PODFILE CHECKSUM: ec83c31511fbc978a9918c6fda235238118483f5

View File

@@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:flutter_web_plugins/url_strategy.dart';
import 'package:just_audio_background/just_audio_background.dart';
import 'package:media_kit/media_kit.dart';
import 'package:provider/provider.dart';
import 'package:window_manager/window_manager.dart';
@@ -45,13 +46,23 @@ void main() async {
});
}
/// Initialize the [media_kit] packages, so that we can play audio and video
/// files.
MediaKit.ensureInitialized();
/// Initialize the [just_audio_background] package, so that we can play audio
/// files in the background.
await JustAudioBackground.init(
androidNotificationChannelId: 'com.ryanheise.bg_demo.channel.audio',
androidNotificationChannelName: 'Audio playback',
androidNotificationOngoing: true,
);
///
/// We can not initialize the [just_audio_background] package on Windows and
/// Linux, because then the returned duration in the `_player.durationStream`
/// isn't working correctly in the [ItemAudioPlayer] widget.
if (kIsWeb || Platform.isAndroid || Platform.isIOS || Platform.isIOS) {
await JustAudioBackground.init(
androidNotificationChannelId: 'com.ryanheise.bg_demo.channel.audio',
androidNotificationChannelName: 'Audio playback',
androidNotificationOngoing: true,
);
}
/// For the ewb we have to use the path url strategy, so that the redirect
/// within Supabase is working in all cases. On all other platforms this is a

View File

@@ -6,6 +6,7 @@ import 'package:feeddeck/utils/constants.dart';
import 'package:feeddeck/widgets/item/details/utils/item_description.dart';
import 'package:feeddeck/widgets/item/details/utils/item_media_gallery.dart';
import 'package:feeddeck/widgets/item/details/utils/item_subtitle.dart';
import 'package:feeddeck/widgets/item/details/utils/item_videos.dart';
class ItemDetailsMastodon extends StatelessWidget {
const ItemDetailsMastodon({
@@ -36,12 +37,23 @@ class ItemDetailsMastodon extends StatelessWidget {
height: Constants.spacingExtraSmall,
),
ItemMediaGallery(
itemMedias: item.options != null && item.options!.containsKey('media')
itemMedias: item.options != null &&
item.options!.containsKey('media') &&
item.options!['media'] != null
? (item.options!['media'] as List)
.map((item) => item as String)
.toList()
: null,
),
ItemVideos(
videos: item.options != null &&
item.options!.containsKey('videos') &&
item.options!['videos'] != null
? (item.options!['videos'] as List)
.map((item) => item as String)
.toList()
: null,
),
],
);
}

View File

@@ -0,0 +1,93 @@
import 'package:flutter/material.dart';
import 'package:media_kit/media_kit.dart';
import 'package:media_kit_video/media_kit_video.dart';
import 'package:feeddeck/utils/constants.dart';
/// The [ItemVideos] widget is used to display a list of videos, which can be
/// played by the user. If the [videos] list is empty or null, the widget will
/// not be displayed.
class ItemVideos extends StatelessWidget {
const ItemVideos({
super.key,
required this.videos,
});
final List<String>? videos;
@override
Widget build(BuildContext context) {
if (videos == null || videos!.isEmpty) {
return Container();
}
return Container(
padding: const EdgeInsets.only(
bottom: Constants.spacingMiddle,
),
child: ListView.separated(
shrinkWrap: true,
separatorBuilder: (context, index) {
return const SizedBox(
height: Constants.spacingMiddle,
);
},
itemCount: videos!.length,
itemBuilder: (context, index) {
return ItemVideoPlayer(video: videos![index]);
},
),
);
}
}
/// The [ItemVideoPlayer] widget is used to display a video, which can be played
/// by the user. It should be used in combination with the [ItemVideos] widget
/// and is responsible for the actual implementation of the video player.
class ItemVideoPlayer extends StatefulWidget {
const ItemVideoPlayer({
super.key,
required this.video,
});
final String video;
@override
State<ItemVideoPlayer> createState() => _ItemVideoPlayerState();
}
class _ItemVideoPlayerState extends State<ItemVideoPlayer> {
late final player = Player();
late final controller = VideoController(player);
@override
void initState() {
super.initState();
player.open(
Media(widget.video),
play: false,
);
}
@override
void dispose() {
player.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
return Center(
child: SizedBox(
width: constraints.maxWidth,
height: constraints.maxWidth * 9.0 / 16.0,
child: Video(controller: controller),
),
);
},
);
}
}

View File

@@ -38,7 +38,9 @@ class ItemPreviewMastodon extends StatelessWidget {
tagetFormat: DescriptionFormat.markdown,
),
ItemMediaGallery(
itemMedias: item.options != null && item.options!.containsKey('media')
itemMedias: item.options != null &&
item.options!.containsKey('media') &&
item.options!['media'] != null
? (item.options!['media'] as List)
.map((item) => item as String)
.toList()

View File

@@ -7,6 +7,7 @@
#include "generated_plugin_registrant.h"
#include <media_kit_libs_linux/media_kit_libs_linux_plugin.h>
#include <media_kit_video/media_kit_video_plugin.h>
#include <screen_retriever/screen_retriever_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
#include <window_manager/window_manager_plugin.h>
@@ -15,6 +16,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) media_kit_libs_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitLibsLinuxPlugin");
media_kit_libs_linux_plugin_register_with_registrar(media_kit_libs_linux_registrar);
g_autoptr(FlPluginRegistrar) media_kit_video_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitVideoPlugin");
media_kit_video_plugin_register_with_registrar(media_kit_video_registrar);
g_autoptr(FlPluginRegistrar) screen_retriever_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin");
screen_retriever_plugin_register_with_registrar(screen_retriever_registrar);

View File

@@ -4,6 +4,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
media_kit_libs_linux
media_kit_video
screen_retriever
url_launcher_linux
window_manager

View File

@@ -9,14 +9,18 @@ import app_links
import audio_service
import audio_session
import just_audio
import media_kit_libs_macos_video
import media_kit_video
import package_info_plus
import path_provider_foundation
import purchases_flutter
import screen_brightness_macos
import screen_retriever
import shared_preferences_foundation
import sign_in_with_apple
import sqflite
import url_launcher_macos
import wakelock_plus
import window_manager
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
@@ -24,13 +28,17 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin"))
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin"))
MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin"))
MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin"))
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
PurchasesFlutterPlugin.register(with: registry.registrar(forPlugin: "PurchasesFlutterPlugin"))
ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenBrightnessMacosPlugin"))
ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SignInWithApplePlugin.register(with: registry.registrar(forPlugin: "SignInWithApplePlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin"))
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
}

View File

@@ -11,8 +11,12 @@ PODS:
- FMDB/standard (2.7.5)
- just_audio (0.0.1):
- FlutterMacOS
- media_kit_libs_macos_video (1.0.4):
- FlutterMacOS
- media_kit_native_event_loop (1.0.0):
- FlutterMacOS
- media_kit_video (0.0.1):
- FlutterMacOS
- package_info_plus (0.0.1):
- FlutterMacOS
- path_provider_foundation (0.0.1):
@@ -24,6 +28,8 @@ PODS:
- PurchasesHybridCommon (7.0.0):
- RevenueCat (= 4.27.0)
- RevenueCat (4.27.0)
- screen_brightness_macos (0.1.0):
- FlutterMacOS
- screen_retriever (0.0.1):
- FlutterMacOS
- shared_preferences_foundation (0.0.1):
@@ -36,6 +42,8 @@ PODS:
- FMDB (>= 2.7.5)
- url_launcher_macos (0.0.1):
- FlutterMacOS
- wakelock_plus (0.0.1):
- FlutterMacOS
- window_manager (0.2.0):
- FlutterMacOS
@@ -45,15 +53,19 @@ DEPENDENCIES:
- audio_session (from `Flutter/ephemeral/.symlinks/plugins/audio_session/macos`)
- FlutterMacOS (from `Flutter/ephemeral`)
- just_audio (from `Flutter/ephemeral/.symlinks/plugins/just_audio/macos`)
- media_kit_libs_macos_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_video/macos`)
- media_kit_native_event_loop (from `Flutter/ephemeral/.symlinks/plugins/media_kit_native_event_loop/macos`)
- media_kit_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_video/macos`)
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
- purchases_flutter (from `Flutter/ephemeral/.symlinks/plugins/purchases_flutter/macos`)
- screen_brightness_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_brightness_macos/macos`)
- screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`)
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
- sign_in_with_apple (from `Flutter/ephemeral/.symlinks/plugins/sign_in_with_apple/macos`)
- sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
- wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`)
- window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`)
SPEC REPOS:
@@ -73,14 +85,20 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral
just_audio:
:path: Flutter/ephemeral/.symlinks/plugins/just_audio/macos
media_kit_libs_macos_video:
:path: Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_video/macos
media_kit_native_event_loop:
:path: Flutter/ephemeral/.symlinks/plugins/media_kit_native_event_loop/macos
media_kit_video:
:path: Flutter/ephemeral/.symlinks/plugins/media_kit_video/macos
package_info_plus:
:path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos
path_provider_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
purchases_flutter:
:path: Flutter/ephemeral/.symlinks/plugins/purchases_flutter/macos
screen_brightness_macos:
:path: Flutter/ephemeral/.symlinks/plugins/screen_brightness_macos/macos
screen_retriever:
:path: Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos
shared_preferences_foundation:
@@ -91,6 +109,8 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/sqflite/macos
url_launcher_macos:
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
wakelock_plus:
:path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos
window_manager:
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos
@@ -101,17 +121,21 @@ SPEC CHECKSUMS:
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
just_audio: 9b67ca7b97c61cfc9784ea23cd8cc55eb226d489
media_kit_native_event_loop: d20622d35dd6d06fe71223976bd70a2bcf595dce
media_kit_libs_macos_video: b3e2bbec2eef97c285f2b1baa7963c67c753fb82
media_kit_native_event_loop: 81fd5b45192b72f8b5b69eaf5b540f45777eb8d5
media_kit_video: c75b07f14d59706c775778e4dd47dd027de8d1e5
package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
purchases_flutter: 9aad80bf27960c38fdeafc27ab066cb55615aed5
PurchasesHybridCommon: af3b2413f9cb999bc1fdca44770bdaf39dfb89fa
RevenueCat: 84fbe2eb9bbf63e1abf346ccd3ff9ee45d633e3b
screen_brightness_macos: 2d6d3af2165592d9a55ffcd95b7550970e41ebda
screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
sign_in_with_apple: a9e97e744e8edc36aefc2723111f652102a7a727
sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea
url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95
wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269
window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8
PODFILE CHECKSUM: 8d40c19d3cbdb380d870685c3a564c989f1efa52

View File

@@ -185,6 +185,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.6"
dbus:
dependency: transitive
description:
name: dbus
sha256: "6f07cba3f7b3448d42d015bfd3d53fe12e5b36da2423f23838efc1d5fb31a263"
url: "https://pub.dev"
source: hosted
version: "0.7.8"
fake_async:
dependency: transitive
description:
@@ -403,10 +411,11 @@ packages:
just_audio_media_kit:
dependency: "direct main"
description:
name: just_audio_media_kit
sha256: d6288e898bc5ed499a938c3cf1ea99eeca4264f9b6ef7bdf92ace3e8b804e259
url: "https://pub.dev"
source: hosted
path: "."
ref: HEAD
resolved-ref: "5980ceac7cc385baf2269eda2dcb024d3e5203cc"
url: "https://github.com/feeddeck/just_audio_media_kit.git"
source: git
version: "1.0.0"
just_audio_platform_interface:
dependency: transitive
@@ -473,13 +482,29 @@ packages:
source: hosted
version: "0.5.0"
media_kit:
dependency: transitive
dependency: "direct main"
description:
name: media_kit
sha256: "3289062540e3b8b9746e5c50d95bd78a9289826b7227e253dff806d002b9e67a"
url: "https://pub.dev"
source: hosted
version: "1.1.10+1"
media_kit_libs_android_video:
dependency: transitive
description:
name: media_kit_libs_android_video
sha256: "9dd8012572e4aff47516e55f2597998f0a378e3d588d0fad0ca1f11a53ae090c"
url: "https://pub.dev"
source: hosted
version: "1.3.6"
media_kit_libs_ios_video:
dependency: transitive
description:
name: media_kit_libs_ios_video
sha256: b5382994eb37a4564c368386c154ad70ba0cc78dacdd3fb0cd9f30db6d837991
url: "https://pub.dev"
source: hosted
version: "1.1.4"
media_kit_libs_linux:
dependency: transitive
description:
@@ -488,11 +513,27 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.3"
media_kit_libs_windows_audio:
media_kit_libs_macos_video:
dependency: transitive
description:
name: media_kit_libs_windows_audio
sha256: c2fd558cc87b9d89a801141fcdffe02e338a3b21a41a18fbd63d5b221a1b8e53
name: media_kit_libs_macos_video
sha256: f26aa1452b665df288e360393758f84b911f70ffb3878032e1aabba23aa1032d
url: "https://pub.dev"
source: hosted
version: "1.1.4"
media_kit_libs_video:
dependency: "direct main"
description:
name: media_kit_libs_video
sha256: "3688e0c31482074578652bf038ce6301a5d21e1eda6b54fc3117ffeb4bdba067"
url: "https://pub.dev"
source: hosted
version: "1.0.4"
media_kit_libs_windows_video:
dependency: transitive
description:
name: media_kit_libs_windows_video
sha256: "7bace5f35d9afcc7f9b5cdadb7541d2191a66bb3fc71bfa11c1395b3360f6122"
url: "https://pub.dev"
source: hosted
version: "1.0.9"
@@ -504,6 +545,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.8"
media_kit_video:
dependency: "direct main"
description:
name: media_kit_video
sha256: c048d11a19e379aebbe810647636e3fc6d18374637e2ae12def4ff8a4b99a882
url: "https://pub.dev"
source: hosted
version: "1.2.4"
meta:
dependency: transitive
description:
@@ -720,6 +769,54 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.2"
screen_brightness:
dependency: transitive
description:
name: screen_brightness
sha256: ed8da4a4511e79422fc1aa88138e920e4008cd312b72cdaa15ccb426c0faaedd
url: "https://pub.dev"
source: hosted
version: "0.2.2+1"
screen_brightness_android:
dependency: transitive
description:
name: screen_brightness_android
sha256: "3df10961e3a9e968a5e076fe27e7f4741fa8a1d3950bdeb48cf121ed529d0caf"
url: "https://pub.dev"
source: hosted
version: "0.1.0+2"
screen_brightness_ios:
dependency: transitive
description:
name: screen_brightness_ios
sha256: "99adc3ca5490b8294284aad5fcc87f061ad685050e03cf45d3d018fe398fd9a2"
url: "https://pub.dev"
source: hosted
version: "0.1.0"
screen_brightness_macos:
dependency: transitive
description:
name: screen_brightness_macos
sha256: "64b34e7e3f4900d7687c8e8fb514246845a73ecec05ab53483ed025bd4a899fd"
url: "https://pub.dev"
source: hosted
version: "0.1.0+1"
screen_brightness_platform_interface:
dependency: transitive
description:
name: screen_brightness_platform_interface
sha256: b211d07f0c96637a15fb06f6168617e18030d5d74ad03795dd8547a52717c171
url: "https://pub.dev"
source: hosted
version: "0.1.0"
screen_brightness_windows:
dependency: transitive
description:
name: screen_brightness_windows
sha256: "9261bf33d0fc2707d8cf16339ce25768100a65e70af0fcabaf032fc12408ba86"
url: "https://pub.dev"
source: hosted
version: "0.1.3"
screen_retriever:
dependency: transitive
description:
@@ -1053,6 +1150,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.4"
volume_controller:
dependency: transitive
description:
name: volume_controller
sha256: "189bdc7a554f476b412e4c8b2f474562b09d74bc458c23667356bce3ca1d48c9"
url: "https://pub.dev"
source: hosted
version: "2.0.7"
wakelock_plus:
dependency: transitive
description:
name: wakelock_plus
sha256: "268e56b9c63f850406f54e9acb2a7d2ddf83c26c8ff9e7a125a96c3a513bf65f"
url: "https://pub.dev"
source: hosted
version: "1.1.2"
wakelock_plus_platform_interface:
dependency: transitive
description:
name: wakelock_plus_platform_interface
sha256: "40fabed5da06caff0796dc638e1f07ee395fb18801fbff3255a2372db2d80385"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
web:
dependency: transitive
description:

View File

@@ -47,7 +47,16 @@ dependencies:
intl: ^0.18.1
just_audio: ^0.9.32
just_audio_background: ^0.0.1-beta.10
just_audio_media_kit: ^1.0.0
# We use our own fork of the "just_audio_media_kit" package, where we
# replaced the "media_kit_libs_windows_audio" with
# "media_kit_libs_windows_video" package, so that we can play video files on
# Windows via the "media_kit" package.
just_audio_media_kit:
git:
url: https://github.com/feeddeck/just_audio_media_kit.git
media_kit: ^1.1.10+1
media_kit_video: ^1.2.4
media_kit_libs_video: ^1.0.4
package_info_plus: ^4.1.0
provider: ^6.0.4
purchases_flutter: ^6.0.0

View File

@@ -7,7 +7,9 @@
#include "generated_plugin_registrant.h"
#include <app_links/app_links_plugin_c_api.h>
#include <media_kit_libs_windows_audio/media_kit_libs_windows_audio_plugin_c_api.h>
#include <media_kit_libs_windows_video/media_kit_libs_windows_video_plugin_c_api.h>
#include <media_kit_video/media_kit_video_plugin_c_api.h>
#include <screen_brightness_windows/screen_brightness_windows_plugin.h>
#include <screen_retriever/screen_retriever_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h>
#include <window_manager/window_manager_plugin.h>
@@ -15,8 +17,12 @@
void RegisterPlugins(flutter::PluginRegistry* registry) {
AppLinksPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("AppLinksPluginCApi"));
MediaKitLibsWindowsAudioPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("MediaKitLibsWindowsAudioPluginCApi"));
MediaKitLibsWindowsVideoPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("MediaKitLibsWindowsVideoPluginCApi"));
MediaKitVideoPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("MediaKitVideoPluginCApi"));
ScreenBrightnessWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPlugin"));
ScreenRetrieverPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("ScreenRetrieverPlugin"));
UrlLauncherWindowsRegisterWithRegistrar(

View File

@@ -4,7 +4,9 @@
list(APPEND FLUTTER_PLUGIN_LIST
app_links
media_kit_libs_windows_audio
media_kit_libs_windows_video
media_kit_video
screen_brightness_windows
screen_retriever
url_launcher_windows
window_manager

View File

@@ -114,10 +114,22 @@ export const getMastodonFeed = async (
/**
* Create the item object and add it to the `items` array. Before the item is created we also try to get a list of
* media fils (images) and add it to the options. Since there could be multiple media files we add it to the options
* and not to the media field.
* media fils (images) and videos which will then be added to the `options`. Since there could be multiple media
* files we add it to the options and not to the media field.
*
* The implementation to generate the options field is not ideal, but is required to be compatible with older
* clients, where we just check if the options are defined and if it contains a media field, but we do not check if
* the media field is null.
*/
const options: { media?: string[]; videos?: string[] } = {};
const media = getMedia(entry);
if (media && media.length > 0) {
options["media"] = media;
}
const videos = getVideos(entry);
if (videos && videos.length > 0) {
options["videos"] = videos;
}
items.push({
id: itemId,
@@ -126,7 +138,7 @@ export const getMastodonFeed = async (
sourceId: source.id,
title: "",
link: entry.links[0].href!,
options: media && media.length > 0 ? { media: media } : undefined,
options: Object.keys(options).length === 0 ? undefined : options,
description: entry.description?.value
? unescape(entry.description.value)
: undefined,
@@ -187,8 +199,8 @@ const generateItemId = (sourceId: string, identifier: string): string => {
};
/**
* `getMedia` returns an image for the provided feed entry from it's description. If we could not get an image from the
* description we return `undefined`.
* `getMedia` returns all images for the provided feed entry from it's `media:content` field. If we could not get an
* image we return `undefined`.
*/
const getMedia = (entry: FeedEntry): string[] | undefined => {
if (entry["media:content"]) {
@@ -205,6 +217,25 @@ const getMedia = (entry: FeedEntry): string[] | undefined => {
return undefined;
};
/**
* `getVideos` returns all videos for the provided feed entry from it's `media:content` field. If we could not get a
* video we return `undefined`.
*/
const getVideos = (entry: FeedEntry): string[] | undefined => {
if (entry["media:content"]) {
const videos = [];
for (const media of entry["media:content"]) {
if (media.medium === "video" && media.url) {
videos.push(media.url);
}
}
return videos;
}
return undefined;
};
/**
* `getAuthor` returns the author for the provided feed entry based on the link to the entry.
*/