fix: correct jellyfin trickplay sheet geometry

close #1417
This commit is contained in:
edde746
2026-06-26 00:26:26 +02:00
parent f04691d321
commit f29030c3a0
2 changed files with 15 additions and 21 deletions
+7 -14
View File
@@ -1,4 +1,3 @@
import 'dart:math' as math;
import 'dart:ui';
import 'package:cached_network_image_ce/cached_network_image.dart';
@@ -77,9 +76,8 @@ class JellyfinTrickplayService implements ScrubPreviewSource {
}
/// Pure math helper exposed for unit tests: maps a timestamp to the
/// sheet index, tile coordinates within the sheet, and the sheet's
/// (possibly partial) row/column count. Returns `null` only when the
/// manifest is degenerate.
/// sheet index, tile coordinates within the sheet, and the sheet's full
/// row/column count. Returns `null` only when the manifest is degenerate.
TrickplayTileLocation? tileLocationFor(Duration time) {
if (_disposed) return null;
final info = _info;
@@ -94,17 +92,12 @@ class JellyfinTrickplayService implements ScrubPreviewSource {
final tileColumn = tileInSheet % info.tileWidth;
final tileRow = tileInSheet ~/ info.tileWidth;
final firstThumbInSheet = sheetIndex * tilesPerSheet;
final thumbsInSheet = math.min(tilesPerSheet, info.thumbnailCount - firstThumbInSheet);
final sheetColumns = thumbsInSheet >= info.tileWidth ? info.tileWidth : thumbsInSheet;
final sheetRows = (thumbsInSheet + info.tileWidth - 1) ~/ info.tileWidth;
return TrickplayTileLocation(
sheetIndex: sheetIndex,
tileColumn: tileColumn,
tileRow: tileRow,
sheetColumns: sheetColumns,
sheetRows: sheetRows,
sheetColumns: info.tileWidth,
sheetRows: info.tileHeight,
sourceTileSize: Size(info.width.toDouble(), info.height.toDouble()),
);
}
@@ -176,9 +169,9 @@ class JellyfinTrickplayService implements ScrubPreviewSource {
}
/// Pure data: which sheet to fetch, which tile within it to display, the
/// sheet's (possibly partial) row/column count, and the source tile's
/// pixel dimensions for aspect-correct scaling at render time. Returned
/// by [JellyfinTrickplayService.tileLocationFor] for unit tests.
/// sheet's row/column count, and the source tile's pixel dimensions for
/// aspect-correct scaling at render time. Returned by
/// [JellyfinTrickplayService.tileLocationFor] for unit tests.
class TrickplayTileLocation {
final int sheetIndex;
final int tileColumn;
@@ -95,7 +95,7 @@ void main() {
// 250 thumbnails, 1s apart, 10×10 tiles per sheet ⇒ 3 sheets.
// sheet 0: indices 0..99
// sheet 1: indices 100..199 (full)
// sheet 2: indices 200..249 (last sheet, only 50 thumbs ⇒ 5 rows)
// sheet 2: indices 200..249 (last sheet, padded to a full 10x10 grid)
setUp(() async {
client = await JellyfinClient.create(_conn());
@@ -143,9 +143,10 @@ void main() {
expect(loc.sheetIndex, 2);
expect(loc.tileColumn, 9);
expect(loc.tileRow, 4);
// Sheet 2 has 50 thumbs ⇒ 5 rows, full 10 cols
// Jellyfin pads the final tile image to the full configured grid, so
// the renderer must keep full sheet geometry even for partial sheets.
expect(loc.sheetColumns, 10);
expect(loc.sheetRows, 5);
expect(loc.sheetRows, 10);
});
test('clamps past the end to the last available thumbnail', () {
@@ -168,7 +169,7 @@ void main() {
});
});
group('JellyfinTrickplayService — partial last sheet sizing', () {
group('JellyfinTrickplayService — padded last sheet sizing', () {
late JellyfinClient client;
setUp(() async {
@@ -177,7 +178,7 @@ void main() {
tearDown(() => client.close());
test('last sheet with 1 thumbnail reports 1 col × 1 row', () {
test('last sheet with 1 thumbnail still reports the full sheet grid', () {
// 17 thumbs, 4×4 sheet ⇒ sheet 0 full (16), sheet 1 has 1 thumb only.
final svc = JellyfinTrickplayService.create(
client: client,
@@ -192,8 +193,8 @@ void main() {
expect(loc.sheetIndex, 1);
expect(loc.tileColumn, 0);
expect(loc.tileRow, 0);
expect(loc.sheetColumns, 1);
expect(loc.sheetRows, 1);
expect(loc.sheetColumns, 4);
expect(loc.sheetRows, 4);
});
});