diff --git a/lib/services/jellyfin_mappers.dart b/lib/services/jellyfin_mappers.dart index dfde435c..a701fddc 100644 --- a/lib/services/jellyfin_mappers.dart +++ b/lib/services/jellyfin_mappers.dart @@ -180,7 +180,7 @@ class JellyfinMappers { clearLogoPath: _selfImagePath(id, item, 'Logo') ?? _parentLogoImage(item), durationMs: jellyfinTicksToMs(item['RunTimeTicks']), viewOffsetMs: jellyfinTicksToMs(_userData(item)?['PlaybackPositionTicks']), - viewCount: _userData(item)?['PlayCount'] as int?, + viewCount: _viewCount(item), lastViewedAt: jellyfinIsoToEpochSeconds(_userData(item)?['LastPlayedDate'] as String?), // Plex semantics: `leafCount` = total leaf items (episodes for series). // Jellyfin's `ChildCount` is direct children (seasons for a series), @@ -304,6 +304,14 @@ class JellyfinMappers { return ud is Map ? ud : null; } + static int _viewCount(Map item) { + final ud = _userData(item); + if (ud?['Played'] != true) return 0; + final playCount = ud?['PlayCount']; + if (playCount is int && playCount > 0) return playCount; + return 1; + } + static int? _viewedLeafCount(Map item) { final ud = _userData(item); final unplayed = ud?['UnplayedItemCount'] as int?; diff --git a/test/services/jellyfin_mappers_test.dart b/test/services/jellyfin_mappers_test.dart index b353fdf4..59fdf187 100644 --- a/test/services/jellyfin_mappers_test.dart +++ b/test/services/jellyfin_mappers_test.dart @@ -79,6 +79,20 @@ void main() { expect(item.serverName, 'Home'); }); + test('does not treat Jellyfin PlayCount as watched when Played is false', () { + final json = { + 'Id': 'started-only', + 'Name': 'Started Only', + 'Type': 'Movie', + 'UserData': {'PlayCount': 1, 'Played': false}, + }; + + final item = JellyfinMappers.mediaItem(json, serverId: _serverId, absolutizer: null)!; + + expect(item.viewCount, 0); + expect(item.isWatched, isFalse); + }); + test('episode preserves series/season hierarchy', () { final json = { 'Id': 'ep1',