fix(ci): restore sanity checks
This commit is contained in:
@@ -252,8 +252,7 @@ class DiscoverProvider extends ChangeNotifier with DisposableChangeNotifierMixin
|
||||
safeNotifyListeners();
|
||||
return;
|
||||
}
|
||||
if (fetchedHubs.succeededServerIds.isEmpty &&
|
||||
(fetchedHubs.cancelledServerIds.isNotEmpty || isProfileBinding())) {
|
||||
if (fetchedHubs.succeededServerIds.isEmpty && (fetchedHubs.cancelledServerIds.isNotEmpty || isProfileBinding())) {
|
||||
appLogger.d('DiscoverProvider: hub pass disrupted with no prior content; keeping loading state');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -93,8 +93,7 @@ class PlaybackStateProvider with ChangeNotifier, DisposableChangeNotifierMixin {
|
||||
|
||||
/// The queue item the cursor currently points at, or null when no queue
|
||||
/// is active or the cursor is outside the loaded window.
|
||||
MediaItem? get currentQueueItem =>
|
||||
_currentPlayQueueItemID == null ? null : _findLoadedItem(_currentPlayQueueItemID!);
|
||||
MediaItem? get currentQueueItem => _currentPlayQueueItemID == null ? null : _findLoadedItem(_currentPlayQueueItemID!);
|
||||
|
||||
/// Set the client reference for loading more items
|
||||
void setPlayQueueWindowFetcher(PlayQueueWindowFetcher? fetcher) {
|
||||
|
||||
@@ -13,9 +13,17 @@ import '../utils/global_key_utils.dart';
|
||||
import '../utils/search_relevance.dart';
|
||||
import 'multi_server_manager.dart';
|
||||
|
||||
typedef OnDeckAggregationResult = ({List<MediaItem> items, Set<String> succeededServerIds, Set<String> cancelledServerIds});
|
||||
typedef OnDeckAggregationResult = ({
|
||||
List<MediaItem> items,
|
||||
Set<String> succeededServerIds,
|
||||
Set<String> cancelledServerIds,
|
||||
});
|
||||
typedef HubAggregationResult = ({List<MediaHub> hubs, Set<String> succeededServerIds, Set<String> cancelledServerIds});
|
||||
typedef LibraryAggregationResult = ({List<MediaLibrary> libraries, Set<String> succeededServerIds, Set<String> cancelledServerIds});
|
||||
typedef LibraryAggregationResult = ({
|
||||
List<MediaLibrary> libraries,
|
||||
Set<String> succeededServerIds,
|
||||
Set<String> cancelledServerIds,
|
||||
});
|
||||
|
||||
/// Whether [error] is a client-side abort (client teardown mid-request)
|
||||
/// rather than a genuine server failure. Aggregation reports these servers
|
||||
@@ -62,7 +70,11 @@ class DataAggregationService {
|
||||
final clients = _clientsFor(serverIds);
|
||||
if (clients.isEmpty) {
|
||||
appLogger.w('No online servers available for fetching libraries (neutral)');
|
||||
return (libraries: const <MediaLibrary>[], succeededServerIds: const <String>{}, cancelledServerIds: const <String>{});
|
||||
return (
|
||||
libraries: const <MediaLibrary>[],
|
||||
succeededServerIds: const <String>{},
|
||||
cancelledServerIds: const <String>{},
|
||||
);
|
||||
}
|
||||
final succeededServerIds = <String>{};
|
||||
final cancelledServerIds = <String>{};
|
||||
|
||||
@@ -118,6 +118,7 @@ class _SharedHttpClient extends http.BaseClient {
|
||||
void close() {}
|
||||
}
|
||||
|
||||
// ignore: unused-code
|
||||
/// Test hook: builds the throttled artwork client with an isolated limiter.
|
||||
@visibleForTesting
|
||||
http.Client createArtworkHttpClientForTest(http.Client inner, {int maxConcurrent = 6}) =>
|
||||
|
||||
@@ -136,11 +136,7 @@ class PlaybackInitializationService {
|
||||
}
|
||||
|
||||
appLogger.d('Found offline video: $readablePath');
|
||||
return (
|
||||
path: readablePath,
|
||||
mediaIndex: downloadedItem.mediaIndex,
|
||||
mediaSourceId: downloadedItem.mediaSourceId,
|
||||
);
|
||||
return (path: readablePath, mediaIndex: downloadedItem.mediaIndex, mediaSourceId: downloadedItem.mediaSourceId);
|
||||
} catch (e) {
|
||||
appLogger.w('Error checking offline video path', error: e);
|
||||
return null;
|
||||
|
||||
@@ -105,9 +105,7 @@ class DeviceIdentityService {
|
||||
/// usable remains.
|
||||
String? sanitizeHeaderValue(String? value) {
|
||||
if (value == null) return null;
|
||||
final filtered = String.fromCharCodes(
|
||||
value.codeUnits.where((unit) => unit != 0x0D && unit != 0x0A && unit <= 0xFF),
|
||||
);
|
||||
final filtered = String.fromCharCodes(value.codeUnits.where((unit) => unit != 0x0D && unit != 0x0A && unit <= 0xFF));
|
||||
final trimmed = filtered.trim();
|
||||
return trimmed.isEmpty ? null : trimmed;
|
||||
}
|
||||
|
||||
@@ -8,11 +8,7 @@ import '../database/app_database.dart';
|
||||
/// trustworthy discriminator there. Otherwise fall back to the media index.
|
||||
/// A null [requestedMediaIndex] means "any version" (the caller has no
|
||||
/// version opinion, e.g. external-player launches keyed by item only).
|
||||
bool downloadedVersionMatches(
|
||||
DownloadedMediaItem row, {
|
||||
int? requestedMediaIndex,
|
||||
String? requestedMediaSourceId,
|
||||
}) {
|
||||
bool downloadedVersionMatches(DownloadedMediaItem row, {int? requestedMediaIndex, String? requestedMediaSourceId}) {
|
||||
final downloadedSourceId = row.mediaSourceId;
|
||||
final requestedSourceId = requestedMediaSourceId?.trim();
|
||||
final comparedBySourceId =
|
||||
|
||||
@@ -177,8 +177,7 @@ Future<bool?> navigateToVideoPlayer(
|
||||
}
|
||||
}
|
||||
|
||||
final mediaIndex =
|
||||
selectedMediaIndex ?? downloadedMediaIndex ?? await savedMediaVersionIndexFor(metadata) ?? 0;
|
||||
final mediaIndex = selectedMediaIndex ?? downloadedMediaIndex ?? await savedMediaVersionIndexFor(metadata) ?? 0;
|
||||
final mediaSourceId = selectedMediaSourceId ?? downloadedMediaSourceId;
|
||||
|
||||
var markedInFlight = false;
|
||||
|
||||
@@ -118,7 +118,9 @@ class _PlayerPerformanceOverlayState extends State<PlayerPerformanceOverlay> {
|
||||
// On height-limited screens (landscape phones) widen the card so the Wrap
|
||||
// packs sections side by side instead of stacking into an off-screen column.
|
||||
final compactHeight = constraints.hasBoundedHeight && constraints.maxHeight < 500;
|
||||
final cardMaxWidth = compactHeight && constraints.hasBoundedWidth ? math.min(constraints.maxWidth, 560.0) : 400.0;
|
||||
final cardMaxWidth = compactHeight && constraints.hasBoundedWidth
|
||||
? math.min(constraints.maxWidth, 560.0)
|
||||
: 400.0;
|
||||
|
||||
// Text scaling only inflates the intrinsic size that FittedBox scales right
|
||||
// back down, trading layout sharpness for nothing on this diagnostics card.
|
||||
|
||||
@@ -8,14 +8,10 @@ import 'package:plezy/focus/input_mode_tracker.dart';
|
||||
/// must only exist in keyboard/d-pad mode: on touch it is pure dead weight
|
||||
/// multiplied by every card in a grid (see library scroll jank).
|
||||
void main() {
|
||||
Finder chromeIn(Type type) =>
|
||||
find.descendant(of: find.byType(FocusableWrapper), matching: find.byType(type));
|
||||
Finder chromeIn(Type type) => find.descendant(of: find.byType(FocusableWrapper), matching: find.byType(type));
|
||||
|
||||
Widget buildWrapper() => Scaffold(
|
||||
body: FocusableWrapper(
|
||||
onSelect: () {},
|
||||
child: const SizedBox(width: 10, height: 10),
|
||||
),
|
||||
body: FocusableWrapper(onSelect: () {}, child: const SizedBox(width: 10, height: 10)),
|
||||
);
|
||||
|
||||
testWidgets('pointer mode builds no focus chrome around the child', (tester) async {
|
||||
@@ -46,11 +42,7 @@ void main() {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: FocusableWrapper(
|
||||
focusNode: node,
|
||||
onSelect: () {},
|
||||
child: const SizedBox(width: 10, height: 10),
|
||||
),
|
||||
body: FocusableWrapper(focusNode: node, onSelect: () {}, child: const SizedBox(width: 10, height: 10)),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -360,7 +360,10 @@ void main() {
|
||||
final heroFades = tester
|
||||
.widgetList<Container>(
|
||||
find.byWidgetPredicate(
|
||||
(w) => w is Container && w.decoration is BoxDecoration && (w.decoration! as BoxDecoration).gradient is LinearGradient,
|
||||
(w) =>
|
||||
w is Container &&
|
||||
w.decoration is BoxDecoration &&
|
||||
(w.decoration! as BoxDecoration).gradient is LinearGradient,
|
||||
),
|
||||
)
|
||||
.map((c) => (c.decoration! as BoxDecoration).gradient! as LinearGradient)
|
||||
|
||||
@@ -390,14 +390,20 @@ void main() {
|
||||
|
||||
test('changed access token requires recreation', () {
|
||||
expect(
|
||||
MultiServerManager.canReuseJellyfinClient(live: base, incoming: base.copyWith(accessToken: 'rotated')),
|
||||
MultiServerManager.canReuseJellyfinClient(
|
||||
live: base,
|
||||
incoming: base.copyWith(accessToken: 'rotated'),
|
||||
),
|
||||
isFalse,
|
||||
);
|
||||
});
|
||||
|
||||
test('changed device id requires recreation', () {
|
||||
expect(
|
||||
MultiServerManager.canReuseJellyfinClient(live: base, incoming: base.copyWith(deviceId: 'other-device')),
|
||||
MultiServerManager.canReuseJellyfinClient(
|
||||
live: base,
|
||||
incoming: base.copyWith(deviceId: 'other-device'),
|
||||
),
|
||||
isFalse,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -385,8 +385,9 @@ void MpvPlayer::TryAudioReload(const char* reason, int attempt) {
|
||||
std::string reason_str = reason;
|
||||
CommandAsync({"ao-reload"}, [this, reason_str, attempt](int error) {
|
||||
audio_reload_pending_ = false;
|
||||
LogRecovery("ao-reload completed (reason=" + reason_str + ", attempt " + std::to_string(attempt) +
|
||||
", error=" + std::to_string(error) + ")");
|
||||
LogRecovery(
|
||||
"ao-reload completed (reason=" + reason_str + ", attempt " + std::to_string(attempt) +
|
||||
", error=" + std::to_string(error) + ")");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -397,8 +398,7 @@ void MpvPlayer::MaybeRunAudioRecovery() {
|
||||
if (file_loaded_) {
|
||||
resume_attempts_left_ = kResumeReloadAttempts;
|
||||
resume_next_attempt_ = now + kResumeFirstDelay;
|
||||
LogRecovery("power resume detected; scheduling ao-reload in " + std::to_string(kResumeFirstDelay.count()) +
|
||||
"ms");
|
||||
LogRecovery("power resume detected; scheduling ao-reload in " + std::to_string(kResumeFirstDelay.count()) + "ms");
|
||||
} else {
|
||||
LogRecovery("power resume detected; no file loaded, nothing to recover");
|
||||
}
|
||||
@@ -545,8 +545,8 @@ void MpvPlayer::HandleMpvEvent(mpv_event* event) {
|
||||
null_attempts_left_ = kNullRetryBudget;
|
||||
null_backoff_ = kNullFirstDelay;
|
||||
null_next_attempt_ = std::chrono::steady_clock::now() + kNullFirstDelay;
|
||||
LogRecovery("current-ao fell back to null; starting recovery (budget " + std::to_string(kNullRetryBudget) +
|
||||
")");
|
||||
LogRecovery(
|
||||
"current-ao fell back to null; starting recovery (budget " + std::to_string(kNullRetryBudget) + ")");
|
||||
} else if (!is_null && current_ao_is_null_) {
|
||||
null_attempts_left_ = 0;
|
||||
LogRecovery(std::string("current-ao is now '") + (current_ao ? current_ao : "") + "'");
|
||||
|
||||
Reference in New Issue
Block a user