initial ingration with audioplayers flutter plugin

seek doesn't work on Endeavour OS (Arch)
This commit is contained in:
Kingkor Roy Tirtho 2022-07-01 11:10:50 +06:00
parent 4321668806
commit f896f65095
17 changed files with 202 additions and 166 deletions

View File

@ -0,0 +1,28 @@
name: audioplayers integration build
on:
push:
branches:
- build
workflow_dispatch:
jobs:
build_ubuntu:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: subosito/flutter-action@v2.2.0
with:
cache: true
- run: |
sudo apt-get update -y
sudo apt-get install -y tar clang cmake ninja-build pkg-config libgtk-3-dev make python3-pip python3-setuptools patchelf desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace fuse libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
- run: flutter config --enable-linux-desktop
- run: flutter pub get
- run: dart bin/create-secrets.dart '${{ secrets.LYRICS_SECRET }}' '${{ secrets.SPOTIFY_SECRET }}'
- run: flutter clean
- run: flutter build linux
- run: make tar
- uses: actions/upload-artifact@v2
with:
name: Spotube-Linux-Bundle
path: build/Spotube-linux-x86_64.tar.xz

View File

@ -12,12 +12,16 @@ All types of contributions are encouraged and valued. See the [Table of Contents
## Table of Contents ## Table of Contents
- [Code of Conduct](#code-of-conduct) - [Contributing to Spotube](#contributing-to-spotube)
- [I Have a Question](#i-have-a-question) - [Table of Contents](#table-of-contents)
- [I Want To Contribute](#i-want-to-contribute) - [Code of Conduct](#code-of-conduct)
- [Reporting Bugs](#reporting-bugs) - [I Have a Question](#i-have-a-question)
- [Suggesting Enhancements](#suggesting-enhancements) - [I Want To Contribute](#i-want-to-contribute)
- [Your First Code Contribution](#your-first-code-contribution) - [Reporting Bugs](#reporting-bugs)
- [Before Submitting a Bug Report](#before-submitting-a-bug-report)
- [How Do I Submit a Good Bug Report?](#how-do-i-submit-a-good-bug-report)
- [Suggesting Enhancements](#suggesting-enhancements)
- [Your First Code Contribution](#your-first-code-contribution)
## Code of Conduct ## Code of Conduct
@ -109,6 +113,9 @@ Enhancement suggestions are tracked as [GitHub issues](https://github.com/KRTirt
### Your First Code Contribution ### Your First Code Contribution
<!-- Download -->
audioplayers requirement https://github.com/bluefireteam/audioplayers/blob/main/packages/audioplayers_linux/requirements.md
Do the following: Do the following:
- Download the latest Flutter SDK (>=2.15.1) & enable desktop support - Download the latest Flutter SDK (>=2.15.1) & enable desktop support
- Install Development dependencies in linux - Install Development dependencies in linux

View File

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@ -34,24 +35,6 @@ class Player extends HookConsumerWidget {
final AsyncSnapshot<SharedPreferences?> localStorage = final AsyncSnapshot<SharedPreferences?> localStorage =
useFuture(future, initialData: null); useFuture(future, initialData: null);
useEffect(() {
/// warm up the audio player before playing actual audio
/// It's for resolving unresolved issue related to just_audio's
/// [disposeAllPlayers] method which is throwing
/// [UnimplementedException] in the [PlatformInterface]
/// implementation
player.core.setAsset("assets/warmer.mp3");
return null;
}, []);
useEffect(() {
if (localStorage.hasData) {
_volume.value = localStorage.data?.getDouble(LocalStorageKeys.volume) ??
player.core.volume;
}
return null;
}, [localStorage.data]);
String albumArt = useMemoized( String albumArt = useMemoized(
() => imageToUrlString( () => imageToUrlString(
playback.currentTrack?.album?.images, playback.currentTrack?.album?.images,

View File

@ -33,7 +33,7 @@ class PlayerControls extends HookConsumerWidget {
child: Column( child: Column(
children: [ children: [
StreamBuilder<Duration>( StreamBuilder<Duration>(
stream: player.core.positionStream, stream: player.core.onPositionChanged,
builder: (context, snapshot) { builder: (context, snapshot) {
final totalMinutes = final totalMinutes =
zeroPadNumStr(duration.inMinutes.remainder(60)); zeroPadNumStr(duration.inMinutes.remainder(60));
@ -48,23 +48,41 @@ class PlayerControls extends HookConsumerWidget {
final sliderMax = duration.inSeconds; final sliderMax = duration.inSeconds;
final sliderValue = snapshot.data?.inSeconds ?? 0; final sliderValue = snapshot.data?.inSeconds ?? 0;
// final value = (sliderMax == 0 || sliderValue > sliderMax)
// ? 0
// : sliderValue / sliderMax;
final _duration = playback.duration;
final _position = snapshot.data;
final value = (_position != null &&
_duration != null &&
_position.inMilliseconds > 0 &&
_position.inMilliseconds < _duration.inMilliseconds)
? _position.inMilliseconds / _duration.inMilliseconds
: 0.0;
return Column( return Column(
children: [ children: [
Slider.adaptive( Slider.adaptive(
// cannot divide by zero // cannot divide by zero
// there's an edge case for value being bigger // there's an edge case for value being bigger
// than total duration. Keeping it resolved // than total duration. Keeping it resolved
value: (sliderMax == 0 || sliderValue > sliderMax) value: value,
? 0 onChanged: (v) async {
: sliderValue / sliderMax, final duration = _duration;
onChanged: (value) {}, if (duration == null) {
onChangeEnd: (value) { return;
player.seek( }
Duration( final position = v * duration.inMilliseconds;
seconds: (value * sliderMax).toInt(), await player
), .seek(Duration(milliseconds: position.round()));
);
}, },
// onChangeEnd: (value) async {
// await player.seek(
// Duration(
// seconds: (value * sliderMax).toInt(),
// ),
// );
// },
activeColor: iconColor, activeColor: iconColor,
), ),
Padding( Padding(

View File

@ -107,10 +107,8 @@ Future<SpotubeTrack> toSpotubeTrack({
"[YouTube Matched Track] ${ytVideo.title} | ${ytVideo.author} - ${ytVideo.url}", "[YouTube Matched Track] ${ytVideo.title} | ${ytVideo.author} - ${ytVideo.url}",
); );
final audioManifest = (Platform.isMacOS || Platform.isIOS) final audioManifest = trackManifest.audioOnly
? trackManifest.audioOnly .where((info) => info.codec.mimeType == "audio/mp4");
.where((info) => info.codec.mimeType == "audio/mp4")
: trackManifest.audioOnly;
final ytUri = (audioQuality == AudioQuality.high final ytUri = (audioQuality == AudioQuality.high
? audioManifest.withHighestBitrate() ? audioManifest.withHighestBitrate()

View File

@ -6,7 +6,7 @@ useSyncedLyrics(WidgetRef ref, Map<int, String> lyricsMap) {
final player = ref.watch(playbackProvider.select( final player = ref.watch(playbackProvider.select(
(value) => (value.player), (value) => (value.player),
)); ));
final stream = player.core.positionStream; final stream = player.core.onPositionChanged;
final currentTime = useState(0); final currentTime = useState(0);

View File

@ -1,8 +1,8 @@
// This file was generated using the following command and may be overwritten. // This file was generated using the following command and may be overwritten.
// dart-dbus generate-object defs/org.mpris.MediaPlayer2.Player.xml // dart-dbus generate-object defs/org.mpris.MediaPlayer2.Player.xml
import 'package:audioplayers/audioplayers.dart';
import 'package:dbus/dbus.dart'; import 'package:dbus/dbus.dart';
import 'package:just_audio/just_audio.dart';
import 'package:spotube/helpers/image-to-url-string.dart'; import 'package:spotube/helpers/image-to-url-string.dart';
import 'package:spotube/models/SpotubeTrack.dart'; import 'package:spotube/models/SpotubeTrack.dart';
import 'package:spotube/provider/Playback.dart'; import 'package:spotube/provider/Playback.dart';
@ -19,7 +19,7 @@ class Player_Interface extends DBusObject {
/// Gets value of property org.mpris.MediaPlayer2.Player.PlaybackStatus /// Gets value of property org.mpris.MediaPlayer2.Player.PlaybackStatus
Future<DBusMethodResponse> getPlaybackStatus() async { Future<DBusMethodResponse> getPlaybackStatus() async {
final status = player.playing final status = player.state == PlayerState.playing
? "Playing" ? "Playing"
: playback.currentPlaylist == null : playback.currentPlaylist == null
? "Stopped" ? "Stopped"
@ -40,12 +40,12 @@ class Player_Interface extends DBusObject {
/// Gets value of property org.mpris.MediaPlayer2.Player.Rate /// Gets value of property org.mpris.MediaPlayer2.Player.Rate
Future<DBusMethodResponse> getRate() async { Future<DBusMethodResponse> getRate() async {
return DBusMethodSuccessResponse([DBusDouble(player.speed)]); return DBusMethodSuccessResponse([DBusDouble(1)]);
} }
/// Sets property org.mpris.MediaPlayer2.Player.Rate /// Sets property org.mpris.MediaPlayer2.Player.Rate
Future<DBusMethodResponse> setRate(double value) async { Future<DBusMethodResponse> setRate(double value) async {
player.setSpeed(value); player.setPlaybackRate(value);
return DBusMethodSuccessResponse(); return DBusMethodSuccessResponse();
} }
@ -104,19 +104,19 @@ class Player_Interface extends DBusObject {
/// Gets value of property org.mpris.MediaPlayer2.Player.Volume /// Gets value of property org.mpris.MediaPlayer2.Player.Volume
Future<DBusMethodResponse> getVolume() async { Future<DBusMethodResponse> getVolume() async {
return DBusMethodSuccessResponse([DBusDouble(player.volume)]); return DBusMethodSuccessResponse([DBusDouble(playback.volume)]);
} }
/// Sets property org.mpris.MediaPlayer2.Player.Volume /// Sets property org.mpris.MediaPlayer2.Player.Volume
Future<DBusMethodResponse> setVolume(double value) async { Future<DBusMethodResponse> setVolume(double value) async {
player.setVolume(value); playback.setVolume(value);
return DBusMethodSuccessResponse(); return DBusMethodSuccessResponse();
} }
/// Gets value of property org.mpris.MediaPlayer2.Player.Position /// Gets value of property org.mpris.MediaPlayer2.Player.Position
Future<DBusMethodResponse> getPosition() async { Future<DBusMethodResponse> getPosition() async {
return DBusMethodSuccessResponse([ return DBusMethodSuccessResponse([
DBusInt64(player.position.inMicroseconds), DBusInt64((await player.getDuration())?.inMicroseconds ?? 0),
]); ]);
} }
@ -188,7 +188,7 @@ class Player_Interface extends DBusObject {
/// Implementation of org.mpris.MediaPlayer2.Player.PlayPause() /// Implementation of org.mpris.MediaPlayer2.Player.PlayPause()
Future<DBusMethodResponse> doPlayPause() async { Future<DBusMethodResponse> doPlayPause() async {
player.playing ? player.pause() : player.play(); player.state == PlayerState.playing ? player.pause() : player.resume();
return DBusMethodSuccessResponse(); return DBusMethodSuccessResponse();
} }
@ -202,7 +202,7 @@ class Player_Interface extends DBusObject {
/// Implementation of org.mpris.MediaPlayer2.Player.Play() /// Implementation of org.mpris.MediaPlayer2.Player.Play()
Future<DBusMethodResponse> doPlay() async { Future<DBusMethodResponse> doPlay() async {
player.play(); player.resume();
return DBusMethodSuccessResponse(); return DBusMethodSuccessResponse();
} }

View File

@ -1,5 +1,5 @@
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:just_audio/just_audio.dart';
final audioPlayerProvider = Provider<AudioPlayer>((ref) { final audioPlayerProvider = Provider<AudioPlayer>((ref) {
return AudioPlayer(); return AudioPlayer();

View File

@ -3,11 +3,11 @@ import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:audio_service/audio_service.dart'; import 'package:audio_service/audio_service.dart';
import 'package:audioplayers/audioplayers.dart';
import 'package:dbus/dbus.dart'; import 'package:dbus/dbus.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:just_audio/just_audio.dart';
import 'package:spotify/spotify.dart'; import 'package:spotify/spotify.dart';
import 'package:spotube/entities/CacheTrack.dart'; import 'package:spotube/entities/CacheTrack.dart';
import 'package:spotube/helpers/artist-to-string.dart'; import 'package:spotube/helpers/artist-to-string.dart';
@ -25,7 +25,7 @@ import 'package:spotube/utils/PersistedChangeNotifier.dart';
import 'package:youtube_explode_dart/youtube_explode_dart.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart';
class Playback extends PersistedChangeNotifier { class Playback extends PersistedChangeNotifier {
AudioSource? _currentAudioSource; UrlSource? _currentAudioSource;
final _logger = getLogger(Playback); final _logger = getLogger(Playback);
CurrentPlaylist? _currentPlaylist; CurrentPlaylist? _currentPlaylist;
Track? _currentTrack; Track? _currentTrack;
@ -34,7 +34,6 @@ class Playback extends PersistedChangeNotifier {
bool _isPlaying = false; bool _isPlaying = false;
Duration? duration; Duration? duration;
Duration _prevPosition = Duration.zero;
bool _shuffled = false; bool _shuffled = false;
AudioPlayerHandler player; AudioPlayerHandler player;
@ -48,6 +47,8 @@ class Playback extends PersistedChangeNotifier {
final Media_Player _media_player; final Media_Player _media_player;
late final Player_Interface _mpris; late final Player_Interface _mpris;
double volume = 1;
Playback({ Playback({
required this.player, required this.player,
required this.youtube, required this.youtube,
@ -71,8 +72,8 @@ class Playback extends PersistedChangeNotifier {
} }
StreamSubscription<Duration?>? _durationStream; StreamSubscription<Duration?>? _durationStream;
StreamSubscription<PlayerState>? _playingStream;
StreamSubscription<Duration>? _positionStream; StreamSubscription<Duration>? _positionStream;
StreamSubscription<bool>? _playingStream;
void _init() async { void _init() async {
// dbus m.p.r.i.s stuff // dbus m.p.r.i.s stuff
@ -90,60 +91,40 @@ class Playback extends PersistedChangeNotifier {
cacheTrackBox = await Hive.openLazyBox<CacheTrack>("track-cache"); cacheTrackBox = await Hive.openLazyBox<CacheTrack>("track-cache");
_playingStream = player.core.playingStream.listen( _playingStream = player.core.onPlayerStateChanged.listen(
(playing) { (state) async {
_isPlaying = playing; _isPlaying = state == PlayerState.playing;
if (state == PlayerState.completed) {
if (_currentTrack?.id != null) {
movePlaylistPositionBy(1);
} else {
_isPlaying = false;
duration = null;
}
}
notifyListeners(); notifyListeners();
}, },
); );
_durationStream = player.core.durationStream.listen((event) async { _durationStream = player.core.onDurationChanged.listen((event) {
if (event != null) { duration = event;
// Actually things doesn't work all the time as they were notifyListeners();
// described. So instead of listening to a `_ready`
// stream, it has to listen to duration stream since duration
// is always added to the Stream sink after all icyMetadata has
// been loaded thus indicating buffering started
if (event != Duration.zero && event != duration) {
// this line is for prev/next or already playing playlist
if (player.core.playing) await player.pause();
await player.play();
}
duration = event;
notifyListeners();
}
}); });
_positionStream = _positionStream = player.core.onPositionChanged.listen((pos) async {
player.core.createPositionStream().listen((position) async { if (pos > Duration.zero &&
// detecting multiple same call (duration == null || duration == Duration.zero)) {
if (_prevPosition.inSeconds == position.inSeconds) return; duration = await player.core.getDuration();
_prevPosition = position; notifyListeners();
/// Because of ProcessingState.complete never gets set bug using a
/// custom solution to know when the audio stops playing
///
/// Details: https://github.com/KRTirtho/spotube/issues/46
if (duration != Duration.zero &&
duration?.isNegative == false &&
position.inSeconds == duration?.inSeconds) {
if (_currentTrack?.id != null) {
await player.pause();
movePlaylistPositionBy(1);
} else {
_isPlaying = false;
duration = null;
notifyListeners();
}
} }
}); });
} }
@override @override
void dispose() { void dispose() {
_positionStream?.cancel();
_playingStream?.cancel(); _playingStream?.cancel();
_durationStream?.cancel(); _durationStream?.cancel();
_positionStream?.cancel();
cacheTrackBox?.close(); cacheTrackBox?.close();
dbus.unregisterObject(_media_player); dbus.unregisterObject(_media_player);
dbus.unregisterObject(_mpris); dbus.unregisterObject(_mpris);
@ -180,6 +161,12 @@ class Playback extends PersistedChangeNotifier {
updatePersistence(clearNullEntries: true); updatePersistence(clearNullEntries: true);
} }
void setVolume(double newVolume) {
volume = newVolume;
notifyListeners();
updatePersistence();
}
/// sets the provided id matched track's uri\ /// sets the provided id matched track's uri\
/// Doesn't notify listeners\ /// Doesn't notify listeners\
/// @returns `bool` - `true` if succeed & `false` when failed /// @returns `bool` - `true` if succeed & `false` when failed
@ -238,11 +225,10 @@ class Playback extends PersistedChangeNotifier {
); );
player.addItem(tag); player.addItem(tag);
if (parsedUri != null && parsedUri.hasAbsolutePath) { if (parsedUri != null && parsedUri.hasAbsolutePath) {
_currentAudioSource = AudioSource.uri(parsedUri); _currentAudioSource = UrlSource(parsedUri.toString());
await player.core await player.core
.setAudioSource( .play(
_currentAudioSource!, _currentAudioSource!,
preload: true,
) )
.then((value) async { .then((value) async {
_currentTrack = track; _currentTrack = track;
@ -262,11 +248,10 @@ class Playback extends PersistedChangeNotifier {
); );
if (setTrackUriById(track.id!, spotubeTrack.ytUri)) { if (setTrackUriById(track.id!, spotubeTrack.ytUri)) {
logger.v("[Track Direct Source] - ${spotubeTrack.ytUri}"); logger.v("[Track Direct Source] - ${spotubeTrack.ytUri}");
_currentAudioSource = AudioSource.uri(Uri.parse(spotubeTrack.ytUri)); _currentAudioSource = UrlSource(spotubeTrack.ytUri);
await player.core await player.core
.setAudioSource( .play(
_currentAudioSource!, _currentAudioSource!,
preload: true,
) )
.then((value) { .then((value) {
_currentTrack = spotubeTrack; _currentTrack = spotubeTrack;
@ -304,13 +289,14 @@ class Playback extends PersistedChangeNotifier {
_currentTrack = Track.fromJson(jsonDecode(map["currentTrack"])); _currentTrack = Track.fromJson(jsonDecode(map["currentTrack"]));
startPlaying().then((_) { startPlaying().then((_) {
Timer.periodic(const Duration(milliseconds: 100), (timer) { Timer.periodic(const Duration(milliseconds: 100), (timer) {
if (player.core.playing) { if (player.core.state == PlayerState.playing) {
player.pause(); player.pause();
timer.cancel(); timer.cancel();
} }
}); });
}); });
} }
volume = map["volume"] ?? volume;
} }
@override @override
@ -321,6 +307,7 @@ class Playback extends PersistedChangeNotifier {
: null, : null,
"currentTrack": "currentTrack":
currentTrack != null ? jsonEncode(currentTrack?.toJson()) : null, currentTrack != null ? jsonEncode(currentTrack?.toJson()) : null,
"volume": volume,
}; };
} }
} }

View File

@ -1,7 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:audio_service/audio_service.dart'; import 'package:audio_service/audio_service.dart';
import 'package:just_audio/just_audio.dart'; import 'package:audioplayers/audioplayers.dart';
/// An [AudioHandler] for playing a single item. /// An [AudioHandler] for playing a single item.
class AudioPlayerHandler extends BaseAudioHandler { class AudioPlayerHandler extends BaseAudioHandler {
@ -15,7 +15,16 @@ class AudioPlayerHandler extends BaseAudioHandler {
// So that our clients (the Flutter UI and the system notification) know // So that our clients (the Flutter UI and the system notification) know
// what state to display, here we set up our audio handler to broadcast all // what state to display, here we set up our audio handler to broadcast all
// playback state changes as they happen via playbackState... // playback state changes as they happen via playbackState...
_player.playbackEventStream.map(_transformEvent).pipe(playbackState); // _player.
_player.onPlayerStateChanged.listen((state) async {
playbackState.add(await _transformEvent());
});
_player.onDurationChanged.listen((duration) async {
playbackState.add(await _transformEvent());
});
_player.onPositionChanged.listen((state) async {
playbackState.add(await _transformEvent());
});
} }
AudioPlayer get core => _player; AudioPlayer get core => _player;
@ -30,7 +39,7 @@ class AudioPlayerHandler extends BaseAudioHandler {
// your audio playback logic in one place. // your audio playback logic in one place.
@override @override
Future<void> play() => _player.play(); Future<void> play() => _player.resume();
@override @override
Future<void> pause() => _player.pause(); Future<void> pause() => _player.pause();
@ -64,27 +73,20 @@ class AudioPlayerHandler extends BaseAudioHandler {
/// This method is used from the constructor. Every event received from the /// This method is used from the constructor. Every event received from the
/// just_audio player will be transformed into an audio_service state so that /// just_audio player will be transformed into an audio_service state so that
/// it can be broadcast to audio_service clients. /// it can be broadcast to audio_service clients.
PlaybackState _transformEvent(PlaybackEvent event) { Future<PlaybackState> _transformEvent() async {
return PlaybackState( return PlaybackState(
controls: [ controls: [
MediaControl.skipToPrevious, MediaControl.skipToPrevious,
if (_player.playing) MediaControl.pause else MediaControl.play, if (_player.state == PlayerState.playing)
MediaControl.pause
else
MediaControl.play,
MediaControl.skipToNext, MediaControl.skipToNext,
MediaControl.stop, MediaControl.stop,
], ],
androidCompactActionIndices: const [0, 1, 2], androidCompactActionIndices: const [0, 1, 2],
processingState: const { playing: _player.state == PlayerState.playing,
ProcessingState.idle: AudioProcessingState.idle, updatePosition: (await _player.getCurrentPosition()) ?? Duration.zero,
ProcessingState.loading: AudioProcessingState.loading,
ProcessingState.buffering: AudioProcessingState.buffering,
ProcessingState.ready: AudioProcessingState.ready,
ProcessingState.completed: AudioProcessingState.completed,
}[_player.processingState]!,
playing: _player.playing,
updatePosition: _player.position,
bufferedPosition: _player.bufferedPosition,
speed: _player.speed,
queueIndex: event.currentIndex,
); );
} }
} }

View File

@ -6,17 +6,17 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <audioplayers_linux/audioplayers_linux_plugin.h>
#include <bitsdojo_window_linux/bitsdojo_window_plugin.h> #include <bitsdojo_window_linux/bitsdojo_window_plugin.h>
#include <libwinmedia/libwinmedia_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h> #include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) { void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "AudioplayersLinuxPlugin");
audioplayers_linux_plugin_register_with_registrar(audioplayers_linux_registrar);
g_autoptr(FlPluginRegistrar) bitsdojo_window_linux_registrar = g_autoptr(FlPluginRegistrar) bitsdojo_window_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "BitsdojoWindowPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "BitsdojoWindowPlugin");
bitsdojo_window_plugin_register_with_registrar(bitsdojo_window_linux_registrar); bitsdojo_window_plugin_register_with_registrar(bitsdojo_window_linux_registrar);
g_autoptr(FlPluginRegistrar) libwinmedia_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "LibwinmediaPlugin");
libwinmedia_plugin_register_with_registrar(libwinmedia_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);

View File

@ -3,8 +3,8 @@
# #
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
audioplayers_linux
bitsdojo_window_linux bitsdojo_window_linux
libwinmedia
url_launcher_linux url_launcher_linux
) )

View File

@ -7,8 +7,8 @@ import Foundation
import audio_service import audio_service
import audio_session import audio_session
import audioplayers_darwin
import bitsdojo_window_macos import bitsdojo_window_macos
import just_audio
import package_info_plus_macos import package_info_plus_macos
import path_provider_macos import path_provider_macos
import shared_preferences_macos import shared_preferences_macos
@ -18,8 +18,8 @@ import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin")) AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin"))
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin"))
BitsdojoWindowPlugin.register(with: registry.registrar(forPlugin: "BitsdojoWindowPlugin")) BitsdojoWindowPlugin.register(with: registry.registrar(forPlugin: "BitsdojoWindowPlugin"))
JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin"))
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))

View File

@ -71,6 +71,55 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.6+1" version: "0.1.6+1"
audioplayers:
dependency: "direct main"
description:
name: audioplayers
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
audioplayers_android:
dependency: transitive
description:
name: audioplayers_android
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
audioplayers_darwin:
dependency: transitive
description:
name: audioplayers_darwin
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
audioplayers_linux:
dependency: transitive
description:
name: audioplayers_linux
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
audioplayers_platform_interface:
dependency: transitive
description:
name: audioplayers_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
audioplayers_web:
dependency: transitive
description:
name: audioplayers_web
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
audioplayers_windows:
dependency: transitive
description:
name: audioplayers_windows
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
bitsdojo_window: bitsdojo_window:
dependency: "direct main" dependency: "direct main"
description: description:
@ -499,41 +548,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.5.0" version: "4.5.0"
just_audio:
dependency: "direct main"
description:
name: just_audio
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.21"
just_audio_libwinmedia:
dependency: "direct main"
description:
name: just_audio_libwinmedia
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.4"
just_audio_platform_interface:
dependency: transitive
description:
name: just_audio_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "4.1.0"
just_audio_web:
dependency: transitive
description:
name: just_audio_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.7"
libwinmedia:
dependency: transitive
description:
name: libwinmedia
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.7"
lints: lints:
dependency: transitive dependency: transitive
description: description:

View File

@ -42,8 +42,6 @@ dependencies:
url_launcher: ^6.0.17 url_launcher: ^6.0.17
youtube_explode_dart: ^1.10.8 youtube_explode_dart: ^1.10.8
bitsdojo_window: ^0.1.2 bitsdojo_window: ^0.1.2
just_audio: ^0.9.18
just_audio_libwinmedia: ^0.0.4
path: ^1.8.0 path: ^1.8.0
path_provider: ^2.0.8 path_provider: ^2.0.8
collection: ^1.15.0 collection: ^1.15.0
@ -64,6 +62,7 @@ dependencies:
hive: ^2.2.2 hive: ^2.2.2
hive_flutter: ^1.1.0 hive_flutter: ^1.1.0
dbus: ^0.7.3 dbus: ^0.7.3
audioplayers: ^1.0.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -6,16 +6,16 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <audioplayers_windows/audioplayers_windows_plugin.h>
#include <bitsdojo_window_windows/bitsdojo_window_plugin.h> #include <bitsdojo_window_windows/bitsdojo_window_plugin.h>
#include <libwinmedia/libwinmedia_plugin.h>
#include <permission_handler_windows/permission_handler_windows_plugin.h> #include <permission_handler_windows/permission_handler_windows_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h> #include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) { void RegisterPlugins(flutter::PluginRegistry* registry) {
AudioplayersWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin"));
BitsdojoWindowPluginRegisterWithRegistrar( BitsdojoWindowPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("BitsdojoWindowPlugin")); registry->GetRegistrarForPlugin("BitsdojoWindowPlugin"));
LibwinmediaPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("LibwinmediaPlugin"));
PermissionHandlerWindowsPluginRegisterWithRegistrar( PermissionHandlerWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
UrlLauncherWindowsRegisterWithRegistrar( UrlLauncherWindowsRegisterWithRegistrar(

View File

@ -3,8 +3,8 @@
# #
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
audioplayers_windows
bitsdojo_window_windows bitsdojo_window_windows
libwinmedia
permission_handler_windows permission_handler_windows
url_launcher_windows url_launcher_windows
) )