ocarina2/lib/api/audio/audioplayer_service.dart

193 lines
5.5 KiB
Dart
Raw Normal View History

2024-05-27 21:46:18 +02:00
import 'package:cached_network_image/cached_network_image.dart';
2024-05-24 00:10:11 +02:00
import 'package:flutter/material.dart';
2024-05-23 19:14:08 +02:00
import 'package:just_audio/just_audio.dart';
import 'package:just_audio_background/just_audio_background.dart';
import 'package:ocarina/api/subsonic/song.dart';
import 'package:ocarina/main.dart';
2024-05-24 00:10:11 +02:00
import 'package:ocarina/util/util.dart';
2024-05-23 19:14:08 +02:00
/// Service used to control the audio player
class AudioPlayerService {
/// Service used to control the audio player
factory AudioPlayerService() {
return _audioPlayerService;
}
AudioPlayerService._internal();
static final AudioPlayerService _audioPlayerService =
AudioPlayerService._internal();
/// The [AudioPlayer] instance
2024-05-24 00:10:11 +02:00
final _player = AudioPlayer();
/// Check if listeners are set up
var _setUp = false;
/// Registers listeners on the player
void setup() {
if (_setUp) return;
_player.currentIndexStream.listen((index) {
logger.d("Done fired");
songNotifier.value = index == null ? null : _songList[index];
_setColorScheme();
});
_setUp = true;
}
2024-05-24 00:10:11 +02:00
/// True if [AudioPlayer] instance is playing
bool get isPlaying => _player.playing;
2024-05-23 19:14:08 +02:00
/// Currently playing song
///
/// Null if no song is loaded
Song? get song => _player.currentIndex == null || _player.currentIndex == -1
? null
: _songList[_player.currentIndex!];
2024-05-24 00:10:11 +02:00
final _queue = ConcatenatingAudioSource(
children: [],
shuffleOrder: DefaultShuffleOrder(),
);
2024-05-24 00:10:11 +02:00
/// Seeks to the next song
Future<void> next() async {
await _player.seekToNext();
2024-05-24 00:10:11 +02:00
}
/// Previous
Future<void> previous() async {
await _player.seekToPrevious();
}
2024-05-24 00:10:11 +02:00
/// Pauses playback
Future<void> pause() async {
await _player.pause();
logger.d("Paused");
}
/// Resumes playback
void resume() {
_player.play();
logger.d("Playing ${_player.currentIndex}");
2024-05-24 00:10:11 +02:00
}
/// Sets color scheme from image
Future<void> _setColorScheme() async {
if (AudioPlayerService().song == null) {
themeNotifier.value = ColorScheme.fromSeed(seedColor: Colors.deepPurple);
}
themeNotifier.value = await ColorScheme.fromImageProvider(
2024-05-27 21:46:18 +02:00
provider: CachedNetworkImageProvider(
2024-05-24 00:10:11 +02:00
AudioPlayerService().song!.coverArtUrl,
),
);
logger.d(AudioPlayerService().song!.coverArtUrl);
}
2024-05-23 19:14:08 +02:00
final List<Song> _songList = [];
/// Adds a selected song to the queue
Future<void> addToQueue(Song song) async {
2024-05-23 19:14:08 +02:00
final doCache = sp.getBool("doCache") ?? true;
_songList.add(song);
await _queue.add(
2024-05-23 19:14:08 +02:00
doCache
? LockCachingAudioSource(
Uri.parse(song.streamUrl),
2024-05-23 19:14:08 +02:00
tag: MediaItem(
id: song.id,
title: song.title,
album: song.albumName,
artist: song.artistName,
artUri: Uri.parse(song.coverArtUrl),
),
)
: AudioSource.uri(
Uri.parse(song.streamUrl),
2024-05-23 19:14:08 +02:00
tag: MediaItem(
id: song.id,
title: song.title,
album: song.albumName,
artist: song.artistName,
artUri: Uri.parse(song.coverArtUrl),
),
),
);
}
/// Plays the passed [Song], clearing the queue
Future<void> playNow({
List<Song> queueNext = const <Song>[],
List<Song> queuePast = const <Song>[],
}) async {
if (queueNext.isEmpty) return;
final doCache = sp.getBool("doCache") ?? true;
await _queue.clear();
_songList
..clear()
..addAll(queueNext);
final q = List<AudioSource>.generate(
queuePast.length,
(i) => doCache
? LockCachingAudioSource(
Uri.parse(queuePast[i].streamUrl),
tag: MediaItem(
id: queuePast[i].id,
title: queuePast[i].title,
album: queuePast[i].albumName,
artist: queuePast[i].artistName,
artUri: Uri.parse(queuePast[i].coverArtUrl),
),
)
: AudioSource.uri(
Uri.parse(queuePast[i].streamUrl),
tag: MediaItem(
id: queuePast[i].id,
title: queuePast[i].title,
album: queuePast[i].albumName,
artist: queuePast[i].artistName,
artUri: Uri.parse(queuePast[i].coverArtUrl),
),
),
)..addAll(
List<AudioSource>.generate(
queueNext.length,
(i) => doCache
? LockCachingAudioSource(
Uri.parse(queueNext[i].streamUrl),
tag: MediaItem(
id: queueNext[i].id,
title: queueNext[i].title,
album: queueNext[i].albumName,
artist: queueNext[i].artistName,
artUri: Uri.parse(queueNext[i].coverArtUrl),
),
)
: AudioSource.uri(
Uri.parse(queueNext[i].streamUrl),
tag: MediaItem(
id: queueNext[i].id,
title: queueNext[i].title,
album: queueNext[i].albumName,
artist: queueNext[i].artistName,
artUri: Uri.parse(queueNext[i].coverArtUrl),
),
),
),
);
await _queue.addAll(
q,
);
await _player.setAudioSource(
_queue,
2024-05-28 18:47:01 +02:00
initialIndex: queuePast.length,
initialPosition: Duration.zero,
);
2024-05-24 00:10:11 +02:00
playerKey.currentState?.update();
resume();
2024-05-23 19:14:08 +02:00
}
}