load method
loads a file into mpv
Implementation
Future<void> load(String source,
{LoadMode mode = LoadMode.replace,
List<String> options = const []}) async {
// check if this was called via load() or append() for error handling purposes
String caller = utils.getCaller();
// reject if mpv is not running
if (!running) {
throw (_errorHandler.errorMessage(8, caller, args: [
source,
mode.name,
options
], options: {
'replace': 'Replace the currently playing title',
'append': 'Append the title to the playlist',
'append-play':
'Append the title and when it is the only title in the list start playback'
}));
}
// MPV accepts various protocols, but the all start with <protocol>://, leave this input as it is
// if it's a file, transform the path into the absolute filepath, such that it can be played
// by any mpv instance, started in any working directory
// also checks if the protocol is supported by mpv and throws an error otherwise
String? sourceProtocol = utils.extractProtocolFromSource(source);
if (sourceProtocol != null && !utils.validateProtocol(sourceProtocol)) {
throw (_errorHandler.errorMessage(9, caller,
args: [source, mode.name, options],
errorMessage:
'See https://mpv.io/manual/stable/#protocols for supported protocols'));
}
source = sourceProtocol != null ? source : path.absolute(source);
_initCommandObserverSocket() async {
Completer completer = Completer();
Socket observeSocket = await Socket.connect(
InternetAddress(socketURI, type: InternetAddressType.unix),
0,
);
await command(
'loadfile',
[
source,
mode.name,
options.join(","),
],
);
// get the playlist size
int playlistSize = await getPlaylistSize();
// if the mode is append resolve the promise because nothing
// will be output by the mpv player
// checking whether this source can be played or not is done when
// the source is played
if (mode == LoadMode.append && !completer.isCompleted) {
observeSocket.destroy();
completer.complete();
}
// if the mode is append-play and there are already songs in the playlist
// resolve the promise since nothing will be output
if (mode == LoadMode.appendPlay &&
playlistSize > 1 &&
!completer.isCompleted) {
observeSocket.destroy();
completer.complete();
}
// timeout
int timeout = 0;
// check if the source was started
bool started = false;
observeSocket.listen((event) {
// increase timeout
timeout += 1;
// parse the messages from the socket
List<String> messages = utf8.decode(event).split('\n');
// check every message
for (var message in messages) {
// ignore empty messages
if (message.isNotEmpty) {
Map msgMap = jsonDecode(message);
if (msgMap.containsKey("event")) {
if (msgMap["event"] == 'start-file') {
started = true;
}
// when the file has successfully been loaded resolve the promise
else if (msgMap["event"] == 'file-loaded' &&
started &&
!completer.isCompleted) {
observeSocket.destroy();
// resolve the promise
completer.complete();
}
// when the track has changed we don't need a seek event
else if (msgMap["event"] == 'end-file' && started) {
observeSocket.destroy();
completer.completeError(
_errorHandler.errorMessage(0, caller, args: [source]));
}
}
}
}
});
// reject the promise if it took to long until the playback-restart happens
// to prevent having sockets listening forever
if (timeout > 10) {
observeSocket.destroy();
completer.completeError(
_errorHandler.errorMessage(5, caller, args: [source]));
}
}
await _initCommandObserverSocket();
}