mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-09-30 13:19:44 +02:00
refactor(discord): remove rich presence and bundled SDK
Remove the presence setting, platform bridge, SDK archive, and SDK preparation from local and CI builds. Reject leftover Discord native libraries in release APK audits.
This commit is contained in:
1 parent
863d1536dd
commit
728d179d69
43 files changed
+37
-1171
No files matched your search
@@ -1,135 +0,0 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:audio_service/audio_service.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
/// Opt-in Rich Presence, inspired by @itsmegaaa's contribution in #575/#576.
|
||||
/// Playback remains independent of Discord availability.
|
||||
class DiscordPresenceService {
|
||||
DiscordPresenceService({
|
||||
MethodChannel channel = const MethodChannel('com.zarz.spotiflac/discord'),
|
||||
}) : _channel = channel {
|
||||
_channel.setMethodCallHandler((call) async {
|
||||
if (call.method == 'status' && _enabled && _transportReady) {
|
||||
status.value = call.arguments as String;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static final instance = DiscordPresenceService();
|
||||
final MethodChannel _channel;
|
||||
final ValueNotifier<String> status = ValueNotifier('disabled');
|
||||
StreamSubscription<MediaItem?>? _mediaSubscription;
|
||||
StreamSubscription<PlaybackState>? _stateSubscription;
|
||||
MediaItem? _item;
|
||||
PlaybackState? _playback;
|
||||
bool _enabled = false;
|
||||
bool _configured = false;
|
||||
bool _transportReady = false;
|
||||
int _generation = 0;
|
||||
String? _lastPayload;
|
||||
int? _lastStart;
|
||||
Future<void> _pending = Future.value();
|
||||
|
||||
void bind(AudioHandler handler) {
|
||||
unawaited(_mediaSubscription?.cancel());
|
||||
unawaited(_stateSubscription?.cancel());
|
||||
_mediaSubscription = handler.mediaItem.listen((item) {
|
||||
_item = item;
|
||||
_publish();
|
||||
});
|
||||
_stateSubscription = handler.playbackState.listen((state) {
|
||||
_playback = state;
|
||||
_publish();
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> setEnabled(bool enabled) {
|
||||
if (_configured && _enabled == enabled) return _pending;
|
||||
_configured = true;
|
||||
_enabled = enabled;
|
||||
_transportReady = false;
|
||||
final generation = ++_generation;
|
||||
_lastPayload = null;
|
||||
_lastStart = null;
|
||||
_pending = _pending.then((_) async {
|
||||
try {
|
||||
final result = await _channel.invokeMethod<String>('configure', {
|
||||
'enabled': enabled,
|
||||
});
|
||||
if (generation != _generation) return;
|
||||
status.value = result ?? 'unavailable';
|
||||
_transportReady = enabled && result == 'ready';
|
||||
if (_transportReady) _publish();
|
||||
} on PlatformException {
|
||||
if (generation == _generation) status.value = 'unavailable';
|
||||
} on MissingPluginException {
|
||||
if (generation == _generation) status.value = 'sdk_unavailable';
|
||||
}
|
||||
});
|
||||
return _pending;
|
||||
}
|
||||
|
||||
void _publish() {
|
||||
if (!_enabled || !_transportReady) return;
|
||||
final item = _item;
|
||||
final playback = _playback;
|
||||
final playing =
|
||||
item != null &&
|
||||
playback != null &&
|
||||
playback.playing &&
|
||||
playback.processingState == AudioProcessingState.ready;
|
||||
final position = playback?.position ?? Duration.zero;
|
||||
final now = DateTime.now().millisecondsSinceEpoch;
|
||||
final start = now - position.inMilliseconds;
|
||||
final payload = playing
|
||||
? <String, Object?>{
|
||||
'title': item.title,
|
||||
'artist': item.artist ?? '',
|
||||
'album': item.album ?? '',
|
||||
'cover': item.artUri?.scheme == 'https'
|
||||
? item.artUri.toString()
|
||||
: '',
|
||||
'start': start,
|
||||
'end': item.duration == null
|
||||
? 0
|
||||
: start + item.duration!.inMilliseconds,
|
||||
}
|
||||
: null;
|
||||
// Position streams tick frequently. Only republish on track/state changes
|
||||
// or a seek that shifts the playback timeline by at least two seconds.
|
||||
final key = playing
|
||||
? '${item.id}|${item.title}|${item.artist}|${item.album}|${item.artUri}|${item.duration}'
|
||||
: 'clear';
|
||||
if (key == _lastPayload &&
|
||||
(!playing ||
|
||||
(_lastStart != null && (start - _lastStart!).abs() < 2000))) {
|
||||
return;
|
||||
}
|
||||
_lastPayload = key;
|
||||
_lastStart = start;
|
||||
final generation = _generation;
|
||||
_pending = _pending.then((_) async {
|
||||
if (!_enabled || generation != _generation) return;
|
||||
try {
|
||||
await _channel.invokeMethod<void>(
|
||||
payload == null ? 'clear' : 'update',
|
||||
payload,
|
||||
);
|
||||
} on PlatformException {
|
||||
_lastPayload = null;
|
||||
} on MissingPluginException {
|
||||
_lastPayload = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> dispose() async {
|
||||
await _mediaSubscription?.cancel();
|
||||
await _stateSubscription?.cancel();
|
||||
await setEnabled(false);
|
||||
_channel.setMethodCallHandler(null);
|
||||
status.dispose();
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:audio_service/audio_service.dart';
|
||||
import 'package:spotiflac_android/services/discord_presence_service.dart';
|
||||
import 'package:spotiflac_android/services/player_widget_service.dart';
|
||||
import 'package:audio_session/audio_session.dart'
|
||||
show AudioSession, AudioSessionConfiguration, AudioInterruptionType;
|
||||
@@ -1648,7 +1647,6 @@ Future<MusicPlayerHandler> _doInitMusicPlayer() async {
|
||||
),
|
||||
);
|
||||
_handler = handler;
|
||||
DiscordPresenceService.instance.bind(handler);
|
||||
if (Platform.isAndroid || Platform.isIOS) {
|
||||
PlayerWidgetService.instance.bind(handler);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user