fix DeezerAudioSource and playback on Windows and Linux
This commit is contained in:
parent
0667c5a7a2
commit
5ba7e932e3
|
|
@ -1,9 +1,11 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'dart:isolate';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:encrypt/encrypt.dart';
|
import 'package:encrypt/encrypt.dart';
|
||||||
|
import 'package:flutter/foundation.dart' as flutter;
|
||||||
import 'package:freezer/api/deezer.dart';
|
import 'package:freezer/api/deezer.dart';
|
||||||
import 'package:freezer/api/definitions.dart';
|
import 'package:freezer/api/definitions.dart';
|
||||||
import 'package:freezer/settings.dart';
|
import 'package:freezer/settings.dart';
|
||||||
|
|
@ -13,6 +15,13 @@ import 'package:http/http.dart' as http;
|
||||||
import 'package:dart_blowfish/dart_blowfish.dart';
|
import 'package:dart_blowfish/dart_blowfish.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
|
typedef _IsolateMessage = (
|
||||||
|
Stream<List<int>> source,
|
||||||
|
int start,
|
||||||
|
String trackId,
|
||||||
|
SendPort sendPort
|
||||||
|
);
|
||||||
|
|
||||||
// Maybe better implementation of Blowfish CBC instead of random-ass, unpublished library from github?
|
// Maybe better implementation of Blowfish CBC instead of random-ass, unpublished library from github?
|
||||||
// This class can be considered a rewrite in Dart of the Java backend (from the StreamServer.deezer() function and also from the Deezer class)
|
// This class can be considered a rewrite in Dart of the Java backend (from the StreamServer.deezer() function and also from the Deezer class)
|
||||||
class DeezerAudioSource extends StreamAudioSource {
|
class DeezerAudioSource extends StreamAudioSource {
|
||||||
|
|
@ -25,6 +34,10 @@ class DeezerAudioSource extends StreamAudioSource {
|
||||||
late String _mediaVersion;
|
late String _mediaVersion;
|
||||||
final StreamInfoCallback? onStreamObtained;
|
final StreamInfoCallback? onStreamObtained;
|
||||||
|
|
||||||
|
// some cache
|
||||||
|
int? _cachedSourceLength;
|
||||||
|
String? _cachedContentType;
|
||||||
|
|
||||||
DeezerAudioSource({
|
DeezerAudioSource({
|
||||||
required AudioQuality quality,
|
required AudioQuality quality,
|
||||||
required String trackId,
|
required String trackId,
|
||||||
|
|
@ -201,18 +214,69 @@ class DeezerAudioSource extends StreamAudioSource {
|
||||||
return decrypted;
|
return decrypted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Stream<List<int>> decryptionStream(Stream<List<int>> source,
|
||||||
|
{required int start, required String trackId}) async* {
|
||||||
|
var dropBytes = start % 2048;
|
||||||
|
final deezerStart = start - dropBytes;
|
||||||
|
int counter = deezerStart ~/ chunkSize;
|
||||||
|
final buffer = List<int>.empty(growable: true);
|
||||||
|
final key = await flutter.compute(getKey, trackId);
|
||||||
|
|
||||||
|
await for (var bytes in source) {
|
||||||
|
if (dropBytes > 0) {
|
||||||
|
bytes = bytes.sublist(dropBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.addAll(bytes);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < buffer.length; i += chunkSize) {
|
||||||
|
if (buffer.length <= i + chunkSize) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = buffer.sublist(i, i + chunkSize);
|
||||||
|
|
||||||
|
if ((counter % 3) == 0) {
|
||||||
|
bytes = decryptChunk(key, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
counter++;
|
||||||
|
yield bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < buffer.length) {
|
||||||
|
buffer.removeRange(0, i);
|
||||||
|
} else {
|
||||||
|
buffer.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add remaining items in buffer
|
||||||
|
if (buffer.isNotEmpty) yield buffer;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<StreamAudioResponse> request([int? start, int? end]) async {
|
Future<StreamAudioResponse> request([int? start, int? end]) async {
|
||||||
start ??= 0;
|
start ??= 0;
|
||||||
|
|
||||||
|
if (_cachedSourceLength != null) {
|
||||||
|
if (start == _cachedSourceLength) {
|
||||||
|
return StreamAudioResponse(
|
||||||
|
sourceLength: _cachedSourceLength,
|
||||||
|
contentLength: 0,
|
||||||
|
offset: start,
|
||||||
|
stream: const Stream<List<int>>.empty(),
|
||||||
|
contentType: _cachedContentType!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_logger.fine("authorizing...");
|
_logger.fine("authorizing...");
|
||||||
if (!await deezerAPI.authorize()) {
|
if (!await deezerAPI.authorize()) {
|
||||||
_logger.severe("authorization failed! cannot continue!");
|
_logger.severe("authorization failed! cannot continue!");
|
||||||
throw Exception("Authorization failed!");
|
throw Exception("Authorization failed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
late final StreamController<List<int>> controller;
|
|
||||||
|
|
||||||
final Uri uri;
|
final Uri uri;
|
||||||
try {
|
try {
|
||||||
uri = await _fallbackUrl();
|
uri = await _fallbackUrl();
|
||||||
|
|
@ -243,73 +307,24 @@ class DeezerAudioSource extends StreamAudioSource {
|
||||||
if (rc != HttpStatus.ok && rc != HttpStatus.partialContent) {
|
if (rc != HttpStatus.ok && rc != HttpStatus.partialContent) {
|
||||||
throw Exception(await res.stream.bytesToString());
|
throw Exception(await res.stream.bytesToString());
|
||||||
}
|
}
|
||||||
int counter = deezerStart ~/ chunkSize;
|
|
||||||
int dropBytes = start % chunkSize;
|
int dropBytes = start % chunkSize;
|
||||||
|
|
||||||
_logger.finest(
|
_logger.finest(
|
||||||
"deezerStart: $deezerStart (actual start: $start), end: $end, counter: $counter, dropBytes: $dropBytes");
|
"deezerStart: $deezerStart (actual start: $start), end: $end, dropBytes: $dropBytes");
|
||||||
var buffer = <int>[];
|
final stream = decryptionStream(res.stream, start: start, trackId: trackId);
|
||||||
final key = getKey(trackId);
|
|
||||||
|
|
||||||
int total = 0;
|
|
||||||
|
|
||||||
final subscription = res.stream.listen(
|
|
||||||
(bytes) {
|
|
||||||
// _logger.finest(
|
|
||||||
// "got stream bytes (${bytes.length}) with buffer.length = ${buffer.length}");
|
|
||||||
total += bytes.length;
|
|
||||||
buffer.addAll(bytes);
|
|
||||||
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < buffer.length; i += chunkSize) {
|
|
||||||
if (buffer.length <= i + chunkSize) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes = buffer.sublist(i, i + chunkSize);
|
|
||||||
|
|
||||||
if ((counter % 3) == 0) {
|
|
||||||
bytes = decryptChunk(key, bytes);
|
|
||||||
}
|
|
||||||
if (dropBytes > 0) {
|
|
||||||
controller.add(bytes.sublist(dropBytes));
|
|
||||||
dropBytes = 0;
|
|
||||||
counter++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
counter++;
|
|
||||||
controller.add(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.removeRange(0, i);
|
|
||||||
},
|
|
||||||
onDone: () {
|
|
||||||
total += buffer.length;
|
|
||||||
_logger.finest(
|
|
||||||
"onDone() called, remaining buffer ${buffer.length}, total: $total");
|
|
||||||
// add remaining items in buffer
|
|
||||||
if (buffer.isNotEmpty) controller.add(buffer);
|
|
||||||
controller.close();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
subscription.pause();
|
|
||||||
controller = StreamController<List<int>>(
|
|
||||||
onListen: subscription.resume,
|
|
||||||
onPause: subscription.pause,
|
|
||||||
onResume: subscription.resume,
|
|
||||||
onCancel: subscription.cancel,
|
|
||||||
);
|
|
||||||
|
|
||||||
final cl = res.contentLength! - dropBytes;
|
final cl = res.contentLength! - dropBytes;
|
||||||
|
|
||||||
|
if (end == null) {
|
||||||
|
_cachedSourceLength = cl + start;
|
||||||
|
}
|
||||||
|
|
||||||
return StreamAudioResponse(
|
return StreamAudioResponse(
|
||||||
sourceLength: cl + start,
|
sourceLength: _cachedSourceLength,
|
||||||
contentLength: cl,
|
contentLength: cl,
|
||||||
offset: start,
|
offset: start,
|
||||||
stream: controller.stream,
|
stream: stream,
|
||||||
contentType:
|
contentType: _cachedContentType =
|
||||||
quality == AudioQuality.FLAC ? "audio/flac" : "audio/mpeg");
|
quality == AudioQuality.FLAC ? "audio/flac" : "audio/mpeg");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,9 @@ class PlayerHelper {
|
||||||
final _streamInfoSubject = BehaviorSubject<StreamQualityInfo>();
|
final _streamInfoSubject = BehaviorSubject<StreamQualityInfo>();
|
||||||
ValueStream<StreamQualityInfo> get streamInfo => _streamInfoSubject.stream;
|
ValueStream<StreamQualityInfo> get streamInfo => _streamInfoSubject.stream;
|
||||||
|
|
||||||
|
final _bufferPositionSubject = BehaviorSubject<Duration>();
|
||||||
|
ValueStream<Duration> get bufferPosition => _bufferPositionSubject.stream;
|
||||||
|
|
||||||
/// Find queue index by id
|
/// Find queue index by id
|
||||||
///
|
///
|
||||||
/// The function gets more expensive the longer the queue is and the further the element is from the beginning.
|
/// The function gets more expensive the longer the queue is and the further the element is from the beginning.
|
||||||
|
|
@ -128,6 +131,9 @@ class PlayerHelper {
|
||||||
Logger('PlayerHelper').fine("streamInfo received");
|
Logger('PlayerHelper').fine("streamInfo received");
|
||||||
_streamInfoSubject.add(event['data'] as StreamQualityInfo);
|
_streamInfoSubject.add(event['data'] as StreamQualityInfo);
|
||||||
break;
|
break;
|
||||||
|
case 'bufferPosition':
|
||||||
|
_bufferPositionSubject.add(event['data'] as Duration);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
_mediaItemSubscription = audioHandler.mediaItem.listen((mediaItem) async {
|
_mediaItemSubscription = audioHandler.mediaItem.listen((mediaItem) async {
|
||||||
|
|
@ -366,8 +372,9 @@ class AudioPlayerTask extends BaseAudioHandler {
|
||||||
int _queueAutoIncrement = 0;
|
int _queueAutoIncrement = 0;
|
||||||
|
|
||||||
//Stream subscriptions
|
//Stream subscriptions
|
||||||
StreamSubscription? _eventSub;
|
StreamSubscription? _eventSubscription;
|
||||||
StreamSubscription? _audioSessionSub;
|
StreamSubscription? _bufferPositionSubscription;
|
||||||
|
StreamSubscription? _audioSessionSubscription;
|
||||||
StreamSubscription? _visualizerSubscription;
|
StreamSubscription? _visualizerSubscription;
|
||||||
|
|
||||||
/// Android Auto helper class for navigation
|
/// Android Auto helper class for navigation
|
||||||
|
|
@ -430,7 +437,7 @@ class AudioPlayerTask extends BaseAudioHandler {
|
||||||
|
|
||||||
_box = await Hive.openLazyBox('playback',
|
_box = await Hive.openLazyBox('playback',
|
||||||
path: (await getTemporaryDirectory()).path);
|
path: (await getTemporaryDirectory()).path);
|
||||||
|
|
||||||
_player = AudioPlayer(
|
_player = AudioPlayer(
|
||||||
handleInterruptions: !initArgs.ignoreInterruptions,
|
handleInterruptions: !initArgs.ignoreInterruptions,
|
||||||
androidApplyAudioAttributes: true,
|
androidApplyAudioAttributes: true,
|
||||||
|
|
@ -455,7 +462,7 @@ class AudioPlayerTask extends BaseAudioHandler {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//Update state on all clients on change
|
//Update state on all clients on change
|
||||||
_eventSub = _player.playbackEventStream.listen((event) {
|
_eventSubscription = _player.playbackEventStream.listen((event) {
|
||||||
//Update
|
//Update
|
||||||
_broadcastState();
|
_broadcastState();
|
||||||
}, onError: (Object e, StackTrace st) {
|
}, onError: (Object e, StackTrace st) {
|
||||||
|
|
@ -466,10 +473,8 @@ class AudioPlayerTask extends BaseAudioHandler {
|
||||||
case ProcessingState.completed:
|
case ProcessingState.completed:
|
||||||
//Player ended, get more songs
|
//Player ended, get more songs
|
||||||
if (_queueIndex == queue.value.length - 1) {
|
if (_queueIndex == queue.value.length - 1) {
|
||||||
customEvent.add({
|
customEvent.add(
|
||||||
'action': 'queueEnd',
|
{'action': 'queueEnd', 'queueSource': queueSource!.toJson()});
|
||||||
'queueSource': queueSource!.toJson()
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -477,8 +482,14 @@ class AudioPlayerTask extends BaseAudioHandler {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_bufferPositionSubscription =
|
||||||
|
_player.bufferedPositionStream.listen((bufferPosition) {
|
||||||
|
customEvent.add({'action': 'bufferPosition', 'data': bufferPosition});
|
||||||
|
});
|
||||||
|
|
||||||
//Audio session
|
//Audio session
|
||||||
_audioSessionSub = _player.androidAudioSessionIdStream.listen((event) {
|
_audioSessionSubscription =
|
||||||
|
_player.androidAudioSessionIdStream.listen((event) {
|
||||||
customEvent.add({'action': 'audioSession', 'id': event});
|
customEvent.add({'action': 'audioSession', 'id': event});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -772,7 +783,9 @@ class AudioPlayerTask extends BaseAudioHandler {
|
||||||
//Load in just_audio
|
//Load in just_audio
|
||||||
try {
|
try {
|
||||||
await _player.setAudioSource(_audioSource,
|
await _player.setAudioSource(_audioSource,
|
||||||
initialIndex: _queueIndex, initialPosition: Duration.zero, preload: kIsWeb || defaultTargetPlatform != TargetPlatform.linux);
|
initialIndex: _queueIndex,
|
||||||
|
initialPosition: Duration.zero,
|
||||||
|
preload: kIsWeb || defaultTargetPlatform != TargetPlatform.linux);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
//Error loading tracks
|
//Error loading tracks
|
||||||
}
|
}
|
||||||
|
|
@ -931,9 +944,10 @@ class AudioPlayerTask extends BaseAudioHandler {
|
||||||
Future<void> stop() async {
|
Future<void> stop() async {
|
||||||
await _saveQueue();
|
await _saveQueue();
|
||||||
_player.stop();
|
_player.stop();
|
||||||
_eventSub?.cancel();
|
_eventSubscription?.cancel();
|
||||||
_audioSessionSub?.cancel();
|
_audioSessionSubscription?.cancel();
|
||||||
_visualizerSubscription?.cancel();
|
_visualizerSubscription?.cancel();
|
||||||
|
_bufferPositionSubscription?.cancel();
|
||||||
await super.stop();
|
await super.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -406,19 +406,21 @@ class _PlayPauseButtonState extends State<PlayPauseButton>
|
||||||
late final AnimationController _controller;
|
late final AnimationController _controller;
|
||||||
late final Animation<double> _animation;
|
late final Animation<double> _animation;
|
||||||
late StreamSubscription _subscription;
|
late StreamSubscription _subscription;
|
||||||
late bool _canPlay = audioHandler.playbackState.value.playing ||
|
late bool _canPlay = audioHandler.playbackState.value.processingState ==
|
||||||
|
AudioProcessingState.ready ||
|
||||||
audioHandler.playbackState.value.processingState ==
|
audioHandler.playbackState.value.processingState ==
|
||||||
AudioProcessingState.ready;
|
AudioProcessingState.idle;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_controller = AnimationController(
|
_controller = AnimationController(
|
||||||
vsync: this, duration: const Duration(milliseconds: 200));
|
vsync: this, duration: const Duration(milliseconds: 200));
|
||||||
_animation = CurvedAnimation(parent: _controller, curve: Curves.easeInOut);
|
_animation = CurvedAnimation(parent: _controller, curve: Curves.easeInOut);
|
||||||
|
|
||||||
_subscription = audioHandler.playbackState.listen((playbackState) {
|
_subscription = audioHandler.playbackState.listen((playbackState) {
|
||||||
if (playbackState.playing ||
|
if (playbackState.processingState == AudioProcessingState.ready ||
|
||||||
playbackState.processingState == AudioProcessingState.ready) {
|
audioHandler.playbackState.value.processingState ==
|
||||||
|
AudioProcessingState.idle) {
|
||||||
if (playbackState.playing) {
|
if (playbackState.playing) {
|
||||||
_controller.forward();
|
_controller.forward();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -480,7 +482,6 @@ class _PlayPauseButtonState extends State<PlayPauseButton>
|
||||||
switch (audioHandler.playbackState.value.processingState) {
|
switch (audioHandler.playbackState.value.processingState) {
|
||||||
//Stopped/Error
|
//Stopped/Error
|
||||||
case AudioProcessingState.error:
|
case AudioProcessingState.error:
|
||||||
case AudioProcessingState.idle:
|
|
||||||
child = null;
|
child = null;
|
||||||
break;
|
break;
|
||||||
//Loading, connecting, rewinding...
|
//Loading, connecting, rewinding...
|
||||||
|
|
|
||||||
|
|
@ -933,25 +933,31 @@ class _SeekBarState extends State<SeekBar> {
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
ValueListenableBuilder<Duration>(
|
ValueListenableBuilder<Duration>(
|
||||||
valueListenable: position,
|
valueListenable: position,
|
||||||
builder: (context, value, _) => Slider(
|
builder: (context, value, _) => StreamBuilder<Duration>(
|
||||||
focusNode: FocusNode(
|
stream: playerHelper.bufferPosition,
|
||||||
canRequestFocus: false,
|
builder: (context, snapshot) {
|
||||||
skipTraversal:
|
return Slider(
|
||||||
true), // Don't focus on Slider - it doesn't work (and not needed)
|
secondaryTrackValue:
|
||||||
value: parseDuration(value),
|
parseDuration(snapshot.data ?? Duration.zero),
|
||||||
max: duration.inMilliseconds.toDouble(),
|
focusNode: FocusNode(
|
||||||
onChangeStart: (double d) {
|
canRequestFocus: false,
|
||||||
_seeking = true;
|
skipTraversal:
|
||||||
position.value = Duration(milliseconds: d.toInt());
|
true), // Don't focus on Slider - it doesn't work (and not needed)
|
||||||
},
|
value: parseDuration(value),
|
||||||
onChanged: (double d) {
|
max: duration.inMilliseconds.toDouble(),
|
||||||
position.value = Duration(milliseconds: d.toInt());
|
onChangeStart: (double d) {
|
||||||
},
|
_seeking = true;
|
||||||
onChangeEnd: (double d) {
|
position.value = Duration(milliseconds: d.toInt());
|
||||||
_seeking = false;
|
},
|
||||||
audioHandler.seek(Duration(milliseconds: d.toInt()));
|
onChanged: (double d) {
|
||||||
},
|
position.value = Duration(milliseconds: d.toInt());
|
||||||
)),
|
},
|
||||||
|
onChangeEnd: (double d) {
|
||||||
|
_seeking = false;
|
||||||
|
audioHandler.seek(Duration(milliseconds: d.toInt()));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
})),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <dynamic_color/dynamic_color_plugin.h>
|
#include <dynamic_color/dynamic_color_plugin.h>
|
||||||
#include <isar_flutter_libs/isar_flutter_libs_plugin.h>
|
#include <isar_flutter_libs/isar_flutter_libs_plugin.h>
|
||||||
|
#include <media_kit_libs_linux/media_kit_libs_linux_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) {
|
||||||
|
|
@ -17,6 +18,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
g_autoptr(FlPluginRegistrar) isar_flutter_libs_registrar =
|
g_autoptr(FlPluginRegistrar) isar_flutter_libs_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "IsarFlutterLibsPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "IsarFlutterLibsPlugin");
|
||||||
isar_flutter_libs_plugin_register_with_registrar(isar_flutter_libs_registrar);
|
isar_flutter_libs_plugin_register_with_registrar(isar_flutter_libs_registrar);
|
||||||
|
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) 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);
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,12 @@
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
dynamic_color
|
dynamic_color
|
||||||
isar_flutter_libs
|
isar_flutter_libs
|
||||||
|
media_kit_libs_linux
|
||||||
url_launcher_linux
|
url_launcher_linux
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
media_kit_native_event_loop
|
||||||
)
|
)
|
||||||
|
|
||||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||||
|
|
|
||||||
109
pubspec.lock
109
pubspec.lock
|
|
@ -17,6 +17,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.13.0"
|
version: "5.13.0"
|
||||||
|
archive:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: archive
|
||||||
|
sha256: "7e0d52067d05f2e0324268097ba723b71cb41ac8a6a2b24d1edf9c536b987b03"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.4.6"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -363,14 +371,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.5"
|
version: "2.0.5"
|
||||||
eventify:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: eventify
|
|
||||||
sha256: b829429f08586cc2001c628e7499e3e3c2493a1d895fd73b00ecb23351aa5a66
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.1"
|
|
||||||
fading_edge_scrollview:
|
fading_edge_scrollview:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -663,6 +663,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.0.2"
|
version: "9.0.2"
|
||||||
|
image:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image
|
||||||
|
sha256: "028f61960d56f26414eb616b48b04eb37d700cbe477b7fb09bf1d7ce57fd9271"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.3"
|
||||||
infinite_listview:
|
infinite_listview:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -743,14 +751,13 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.9.35"
|
version: "0.9.35"
|
||||||
just_audio_mpv:
|
just_audio_media_kit:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: just_audio_mpv
|
path: "../just_audio_media_kit"
|
||||||
sha256: d6e4e9fd20bfb9d2fd5e3dcd7906c90ed07f83d1d2f44f31204160821ab62fed
|
relative: true
|
||||||
url: "https://pub.dev"
|
source: path
|
||||||
source: hosted
|
version: "0.0.1"
|
||||||
version: "0.1.7"
|
|
||||||
just_audio_platform_interface:
|
just_audio_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -767,14 +774,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.8"
|
version: "0.4.8"
|
||||||
just_audio_windows:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: just_audio_windows
|
|
||||||
sha256: "7b8801f3987e98a2002cd23b5600b2daf162248ff1413266fb44c84448c1c0d3"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.2.0"
|
|
||||||
lints:
|
lints:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -815,6 +814,38 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.0"
|
version: "0.5.0"
|
||||||
|
media_kit:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: media_kit
|
||||||
|
sha256: "1283b500341d41f033478706204a2b4ae2612e9b331c934bc4fad8c4bb869f6d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.8+2"
|
||||||
|
media_kit_libs_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: media_kit_libs_linux
|
||||||
|
sha256: e186891c31daa6bedab4d74dcdb4e8adfccc7d786bfed6ad81fe24a3b3010310
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.3"
|
||||||
|
media_kit_libs_windows_audio:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: media_kit_libs_windows_audio
|
||||||
|
sha256: c2fd558cc87b9d89a801141fcdffe02e338a3b21a41a18fbd63d5b221a1b8e53
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.9"
|
||||||
|
media_kit_native_event_loop:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: media_kit_native_event_loop
|
||||||
|
sha256: a605cf185499d14d58935b8784955a92a4bf0ff4e19a23de3d17a9106303930e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.8"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -839,14 +870,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.2"
|
version: "1.0.2"
|
||||||
mpv_dart:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: mpv_dart
|
|
||||||
sha256: a33bd9a68439b496b7a5f36fecd3aa3cf6cbf0176ae15b9b60b12ae96e58f5a4
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.0.1"
|
|
||||||
nested:
|
nested:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1143,6 +1166,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.27.7"
|
version: "0.27.7"
|
||||||
|
safe_local_storage:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: safe_local_storage
|
||||||
|
sha256: ede4eb6cb7d88a116b3d3bf1df70790b9e2038bc37cb19112e381217c74d9440
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.2"
|
||||||
scrobblenaut:
|
scrobblenaut:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -1365,6 +1396,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.2"
|
version: "2.2.2"
|
||||||
|
universal_platform:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: universal_platform
|
||||||
|
sha256: d315be0f6641898b280ffa34e2ddb14f3d12b1a37882557869646e0cc363d0cc
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0+1"
|
||||||
|
uri_parser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: uri_parser
|
||||||
|
sha256: "6543c9fd86d2862fac55d800a43e67c0dcd1a41677cb69c2f8edfe73bbcf1835"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.2"
|
||||||
url_launcher:
|
url_launcher:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -1534,5 +1581,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.1.0 <4.0.0"
|
dart: ">=3.1.3 <4.0.0"
|
||||||
flutter: ">=3.13.0"
|
flutter: ">=3.13.0"
|
||||||
|
|
|
||||||
|
|
@ -86,8 +86,8 @@ dependencies:
|
||||||
ref: main
|
ref: main
|
||||||
logging: ^1.2.0
|
logging: ^1.2.0
|
||||||
just_audio: ^0.9.35
|
just_audio: ^0.9.35
|
||||||
just_audio_mpv: ^0.1.7
|
just_audio_media_kit:
|
||||||
just_audio_windows: ^0.2.0
|
git: https://github.com/Pato05/just_audio_media_kit.git
|
||||||
rxdart: ^0.27.7
|
rxdart: ^0.27.7
|
||||||
flutter_isolate: ^2.0.4
|
flutter_isolate: ^2.0.4
|
||||||
isar: ^3.1.0+1
|
isar: ^3.1.0+1
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
||||||
#include <dynamic_color/dynamic_color_plugin_c_api.h>
|
#include <dynamic_color/dynamic_color_plugin_c_api.h>
|
||||||
#include <isar_flutter_libs/isar_flutter_libs_plugin.h>
|
#include <isar_flutter_libs/isar_flutter_libs_plugin.h>
|
||||||
#include <just_audio_windows/just_audio_windows_plugin.h>
|
#include <media_kit_libs_windows_audio/media_kit_libs_windows_audio_plugin_c_api.h>
|
||||||
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||||
#include <share_plus/share_plus_windows_plugin_c_api.h>
|
#include <share_plus/share_plus_windows_plugin_c_api.h>
|
||||||
#include <url_launcher_windows/url_launcher_windows.h>
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
|
|
@ -21,8 +21,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
registry->GetRegistrarForPlugin("DynamicColorPluginCApi"));
|
registry->GetRegistrarForPlugin("DynamicColorPluginCApi"));
|
||||||
IsarFlutterLibsPluginRegisterWithRegistrar(
|
IsarFlutterLibsPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("IsarFlutterLibsPlugin"));
|
registry->GetRegistrarForPlugin("IsarFlutterLibsPlugin"));
|
||||||
JustAudioWindowsPluginRegisterWithRegistrar(
|
MediaKitLibsWindowsAudioPluginCApiRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("JustAudioWindowsPlugin"));
|
registry->GetRegistrarForPlugin("MediaKitLibsWindowsAudioPluginCApi"));
|
||||||
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
||||||
SharePlusWindowsPluginCApiRegisterWithRegistrar(
|
SharePlusWindowsPluginCApiRegisterWithRegistrar(
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,14 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
connectivity_plus
|
connectivity_plus
|
||||||
dynamic_color
|
dynamic_color
|
||||||
isar_flutter_libs
|
isar_flutter_libs
|
||||||
just_audio_windows
|
media_kit_libs_windows_audio
|
||||||
permission_handler_windows
|
permission_handler_windows
|
||||||
share_plus
|
share_plus
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
media_kit_native_event_loop
|
||||||
)
|
)
|
||||||
|
|
||||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue