Files

135 lines
3.4 KiB
Dart
Raw Permalink Normal View History

2026-07-14 11:11:36 +08:00
import 'package:flutter/foundation.dart';
import '../../../core/contracts/library.dart';
import '../session/playback_target.dart';
import 'playlist.dart';
@immutable
class CrossServerPlaylistEntry {
const CrossServerPlaylistEntry({
required this.serverId,
required this.serverName,
required this.serverUrl,
required this.token,
required this.userId,
required this.itemId,
this.label = '',
this.preloadedItem,
});
final String serverId;
final String serverName;
final String serverUrl;
final String token;
final String userId;
final String itemId;
final String label;
final EmbyRawItem? preloadedItem;
PlaybackServerIdentity toIdentity() => PlaybackServerIdentity(
serverId: serverId,
baseUrl: serverUrl,
token: token,
userId: userId,
serverName: serverName,
);
@override
bool operator ==(Object other) =>
other is CrossServerPlaylistEntry &&
other.serverId == serverId &&
other.serverName == serverName &&
other.serverUrl == serverUrl &&
other.token == token &&
other.userId == userId &&
other.itemId == itemId &&
other.label == label &&
other.preloadedItem == preloadedItem;
@override
int get hashCode => Object.hash(
serverId,
serverName,
serverUrl,
token,
userId,
itemId,
label,
preloadedItem,
);
}
class CrossServerPlaylist implements Playlist {
CrossServerPlaylist({
required List<CrossServerPlaylistEntry> sequence,
required int initialIndex,
bool initialPlayFromStart = false,
}) : assert(sequence.isNotEmpty, 'cross-server sequence cannot be empty'),
assert(initialIndex >= 0 && initialIndex < sequence.length),
_entries = List.unmodifiable(sequence),
_currentIndex = ValueNotifier<int>(initialIndex),
_current = ValueNotifier<PlaylistItem>(
_toItem(sequence[initialIndex], playFromStart: initialPlayFromStart),
);
final List<CrossServerPlaylistEntry> _entries;
final ValueNotifier<PlaylistItem> _current;
final ValueNotifier<int> _currentIndex;
bool _disposed = false;
@override
ValueListenable<PlaylistItem> get current => _current;
@override
ValueListenable<int> get currentIndex => _currentIndex;
@override
int get length => _entries.length;
@override
bool get hasNext => _currentIndex.value < _entries.length - 1;
@override
bool get hasPrev => _currentIndex.value > 0;
@override
Future<void> next() => goTo(_currentIndex.value + 1);
@override
Future<void> prev() => goTo(_currentIndex.value - 1);
@override
Future<void> goTo(int index) async {
if (_disposed) return;
if (index < 0 || index >= _entries.length) return;
if (index == _currentIndex.value) return;
final target = _entries[index];
_currentIndex.value = index;
_current.value = _toItem(target);
}
@override
Future<void> goToItemId(String itemId) async {
final idx = _entries.indexWhere((e) => e.itemId == itemId);
if (idx < 0) return;
await goTo(idx);
}
static PlaylistItem _toItem(
CrossServerPlaylistEntry e, {
bool playFromStart = false,
}) => PlaylistItem(
itemId: e.itemId,
serverId: e.serverId,
serverIdentity: e.toIdentity(),
displayLabel: e.label,
playFromStart: playFromStart,
preloadedItem: e.preloadedItem,
);
@override
void dispose() {
_disposed = true;
_current.dispose();
_currentIndex.dispose();
}
}