mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00

* refactor: remove SourcedTrack based audio player and utilize mediakit playback system * feat: implement local (loopback) server to resolve stream source and leverage the media_kit playback API * feat: add source change support and re-add prefetching tracks * fix: assign lastId when track fetch completes regardless of error * chore: remove print statements * fix: remote queue not working * fix: increase mpv network timeout to reduce auto-skipping * fix: do not pre-fetch local tracks * fix(proxy-playlist): reset collections on load * chore: fix lint warnings * fix(mobile): player overlay should not be visible when the player is not playing * chore: fix typo in turkish translation * cd: checkout PR branch * cd: upgrade flutter version * chore: fix lint errors
112 lines
3.1 KiB
Dart
112 lines
3.1 KiB
Dart
import 'package:bonsoir/bonsoir.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:spotube/services/device_info/device_info.dart';
|
|
|
|
class ConnectClientsState {
|
|
final List<BonsoirService> services;
|
|
final ResolvedBonsoirService? resolvedService;
|
|
final BonsoirDiscovery discovery;
|
|
|
|
ConnectClientsState({
|
|
required this.services,
|
|
required this.discovery,
|
|
this.resolvedService,
|
|
});
|
|
|
|
ConnectClientsState copyWith({
|
|
List<BonsoirService>? services,
|
|
BonsoirDiscovery? discovery,
|
|
ResolvedBonsoirService? resolvedService,
|
|
}) {
|
|
return ConnectClientsState(
|
|
services: services ?? this.services,
|
|
discovery: discovery ?? this.discovery,
|
|
resolvedService: resolvedService ?? this.resolvedService,
|
|
);
|
|
}
|
|
}
|
|
|
|
class ConnectClientsNotifier extends AsyncNotifier<ConnectClientsState> {
|
|
ConnectClientsNotifier();
|
|
|
|
@override
|
|
build() async {
|
|
final discovery = BonsoirDiscovery(type: '_spotube._tcp');
|
|
final deviceId = await DeviceInfoService.instance.deviceId();
|
|
await discovery.ready;
|
|
|
|
final subscription = discovery.eventStream?.listen((event) {
|
|
// ignore device itself
|
|
if (event.service?.attributes["deviceId"] == deviceId) {
|
|
return;
|
|
}
|
|
|
|
switch (event.type) {
|
|
case BonsoirDiscoveryEventType.discoveryServiceFound:
|
|
state = AsyncData(state.value!.copyWith(
|
|
services: [
|
|
...?state.value?.services,
|
|
event.service!,
|
|
],
|
|
));
|
|
break;
|
|
case BonsoirDiscoveryEventType.discoveryServiceResolved:
|
|
state = AsyncData(
|
|
state.value!.copyWith(
|
|
resolvedService: event.service as ResolvedBonsoirService,
|
|
),
|
|
);
|
|
break;
|
|
case BonsoirDiscoveryEventType.discoveryServiceLost:
|
|
state = AsyncData(
|
|
ConnectClientsState(
|
|
services: state.value!.services
|
|
.where((s) => s.name != event.service!.name)
|
|
.toList(),
|
|
discovery: state.value!.discovery,
|
|
resolvedService: state.value?.resolvedService != null &&
|
|
event.service?.name == state.value?.resolvedService?.name
|
|
? null
|
|
: state.value!.resolvedService,
|
|
),
|
|
);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
});
|
|
|
|
ref.onDispose(() {
|
|
subscription?.cancel();
|
|
discovery.stop();
|
|
});
|
|
|
|
await discovery.start();
|
|
|
|
return ConnectClientsState(
|
|
services: [],
|
|
discovery: discovery,
|
|
);
|
|
}
|
|
|
|
Future<void> resolveService(BonsoirService service) async {
|
|
if (state.value == null) return;
|
|
await service.resolve(state.value!.discovery.serviceResolver);
|
|
}
|
|
|
|
Future<void> clearResolvedService() async {
|
|
if (state.value == null) return;
|
|
state = AsyncData(
|
|
ConnectClientsState(
|
|
services: state.value!.services,
|
|
discovery: state.value!.discovery,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
final connectClientsProvider =
|
|
AsyncNotifierProvider<ConnectClientsNotifier, ConnectClientsState>(
|
|
() => ConnectClientsNotifier(),
|
|
);
|