refactor(plex): drop the test-only raw-JSON mapper flavours and title obfuscation branches
PlexMappers advertised a parse-and-map FromJson flavour of every mapper 'for callers that haven't already parsed a DTO' — no such production caller exists; every call site uses the DTO-typed flavour. Tests now parse the DTO and map it, preserving every assertion. The kBlurArtwork JSON-walking branches in the DTO factories (title/summary vowel rotation on the decode hot path) are deleted with the flag's title half.
This commit is contained in:
@@ -32,7 +32,6 @@ import '../media/media_version.dart';
|
||||
import '../utils/app_logger.dart';
|
||||
import '../utils/global_key_utils.dart';
|
||||
import '../utils/json_utils.dart';
|
||||
import '../utils/obfuscation_utils.dart';
|
||||
import 'file_info_parser.dart';
|
||||
import 'plex_constants.dart';
|
||||
|
||||
@@ -42,14 +41,6 @@ part 'plex_mappers.g.dart';
|
||||
/// `com.plexapp.agents.none://` and new-style `tv.plex.agents.none://`.
|
||||
const _unmatchedAgentMarker = 'agents.none://';
|
||||
|
||||
Map<String, dynamic> _obfuscatePlaylistJson(Map<String, dynamic> json) {
|
||||
final copy = Map<String, dynamic>.from(json);
|
||||
for (final key in const ['title', 'summary']) {
|
||||
if (copy[key] is String) copy[key] = obfuscateText(copy[key] as String);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
Map? _firstPartMap(Object? raw) {
|
||||
final parts = _partMaps(raw);
|
||||
return parts.isEmpty ? null : parts.first;
|
||||
@@ -240,7 +231,7 @@ List<MediaPart> _mediaPartsFromReadValue(Object? raw) {
|
||||
|
||||
String _hubTitleFromJson(Object? raw) {
|
||||
final title = raw as String? ?? t.common.unknown;
|
||||
return kBlurArtwork ? obfuscateText(title) : title;
|
||||
return title;
|
||||
}
|
||||
|
||||
Object? _readHubItems(Map json, String _) {
|
||||
@@ -484,8 +475,7 @@ class PlexPlaylistDto {
|
||||
this.serverName,
|
||||
});
|
||||
|
||||
factory PlexPlaylistDto.fromJson(Map<String, dynamic> json) =>
|
||||
_$PlexPlaylistDtoFromJson(kBlurArtwork ? _obfuscatePlaylistJson(json) : json);
|
||||
factory PlexPlaylistDto.fromJson(Map<String, dynamic> json) => _$PlexPlaylistDtoFromJson(json);
|
||||
|
||||
PlexPlaylistDto copyWith({ServerId? serverId, String? serverName}) {
|
||||
return PlexPlaylistDto(
|
||||
@@ -751,8 +741,7 @@ class PlexMetadataDto {
|
||||
this.flattenSeasons,
|
||||
});
|
||||
|
||||
factory PlexMetadataDto.fromJson(Map<String, dynamic> rawJson) {
|
||||
final json = kBlurArtwork ? _obfuscateJson(rawJson) : rawJson;
|
||||
factory PlexMetadataDto.fromJson(Map<String, dynamic> json) {
|
||||
try {
|
||||
return _$PlexMetadataDtoFromJson(json);
|
||||
} on TypeError catch (e, st) {
|
||||
@@ -795,14 +784,6 @@ class PlexMetadataDto {
|
||||
return PlexMetadataDto.fromJson(enriched);
|
||||
}
|
||||
|
||||
static Map<String, dynamic> _obfuscateJson(Map<String, dynamic> json) {
|
||||
final copy = Map<String, dynamic>.from(json);
|
||||
for (final key in const ['title', 'summary', 'tagline', 'grandparentTitle', 'parentTitle', 'studio']) {
|
||||
if (copy[key] is String) copy[key] = obfuscateText(copy[key] as String);
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
String get globalKey => serverId != null ? buildGlobalKey(ServerId(serverId!), ratingKey) : ratingKey;
|
||||
|
||||
bool get isUnmatched => guid == null || guid!.isEmpty || guid!.contains(_unmatchedAgentMarker);
|
||||
@@ -1038,12 +1019,11 @@ String? _nonEmptyRatingString(Object? value) {
|
||||
|
||||
/// Pure JSON/DTO→neutral-type mappers for Plex. Mirrors [JellyfinMappers].
|
||||
///
|
||||
/// Methods come in two flavours:
|
||||
/// * `<type>FromJson` — accept raw Plex JSON and parse + map in one step.
|
||||
/// Used by tests and by callers that haven't already parsed a DTO.
|
||||
/// * `<type>` (DTO-typed) — accept an already-parsed DTO. Used by the
|
||||
/// [PlexClient] which keeps a DTO step internally for caching, copying,
|
||||
/// and OnDeck composition.
|
||||
/// Methods accept already-parsed DTOs (`mediaItem`, `mediaHub`, …); the
|
||||
/// [PlexClient] keeps the DTO step internally for caching, copying, and
|
||||
/// OnDeck composition. A few raw-JSON helpers remain for callers without a
|
||||
/// DTO surface: [mediaItemFromCacheJson] (offline cache),
|
||||
/// [mediaVersionFromJson], and [displayCriteriaFromJson].
|
||||
///
|
||||
/// Pure: no HTTP, no client state, no token-aware image-URL resolution.
|
||||
/// Token-aware image URLs are layered on at the [PlexClient] boundary via
|
||||
@@ -1053,12 +1033,6 @@ String? _nonEmptyRatingString(Object? value) {
|
||||
class PlexMappers {
|
||||
PlexMappers._();
|
||||
|
||||
/// Map a Plex `Metadata` JSON entry directly into a [PlexMediaItem].
|
||||
static PlexMediaItem mediaItemFromJson(Map<String, dynamic> json, {ServerId? serverId, String? serverName}) {
|
||||
final dto = PlexMetadataDto.fromJsonWithImages(json).copyWith(serverId: serverId, serverName: serverName);
|
||||
return mediaItem(dto);
|
||||
}
|
||||
|
||||
/// Parse a Plex `/library/metadata/{id}` JSON object into a neutral
|
||||
/// [MediaItem]. Used by the offline cache layer to convert persisted Plex
|
||||
/// JSON back into MediaItem without depending on the Plex client surface.
|
||||
@@ -1246,19 +1220,6 @@ class PlexMappers {
|
||||
);
|
||||
}
|
||||
|
||||
/// Map a Plex `/library/sections` Directory entry into a [MediaLibrary].
|
||||
static MediaLibrary mediaLibraryFromJson(
|
||||
Map<String, dynamic> json, {
|
||||
ServerId? serverId,
|
||||
String? serverName,
|
||||
bool isShared = false,
|
||||
}) {
|
||||
final dto = PlexLibraryDto.fromJson(
|
||||
json,
|
||||
).copyWith(serverId: serverIdOrNull(serverId), serverName: serverName, isShared: isShared);
|
||||
return mediaLibrary(dto);
|
||||
}
|
||||
|
||||
/// Map a parsed [PlexHubDto] into a [MediaHub].
|
||||
static MediaHub mediaHub(PlexHubDto dto) {
|
||||
return MediaHub(
|
||||
@@ -1274,11 +1235,6 @@ class PlexMappers {
|
||||
);
|
||||
}
|
||||
|
||||
/// Map a Plex `/hubs` Hub JSON entry directly into a [MediaHub].
|
||||
static MediaHub mediaHubFromJson(Map<String, dynamic> json, {ServerId? serverId, String? serverName}) {
|
||||
return mediaHub(PlexHubDto.fromJson(json, serverId: serverId, serverName: serverName));
|
||||
}
|
||||
|
||||
/// Map a parsed [PlexPlaylistDto] into a [MediaPlaylist].
|
||||
static MediaPlaylist mediaPlaylist(PlexPlaylistDto dto) {
|
||||
return MediaPlaylist(
|
||||
@@ -1301,12 +1257,6 @@ class PlexMappers {
|
||||
serverName: dto.serverName,
|
||||
);
|
||||
}
|
||||
|
||||
/// Map a Plex `/playlists` Metadata entry directly into a [MediaPlaylist].
|
||||
static MediaPlaylist mediaPlaylistFromJson(Map<String, dynamic> json, {ServerId? serverId, String? serverName}) {
|
||||
final dto = PlexPlaylistDto.fromJson(json).copyWith(serverId: serverId, serverName: serverName);
|
||||
return mediaPlaylist(dto);
|
||||
}
|
||||
}
|
||||
|
||||
/// Build a [MediaSourceInfo] from a Plex `/library/metadata/{id}` JSON
|
||||
|
||||
@@ -5,7 +5,11 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:plezy/media/ids.dart';
|
||||
import 'package:plezy/media/media_backend.dart';
|
||||
import 'package:plezy/media/media_display_criteria.dart';
|
||||
import 'package:plezy/media/media_hub.dart';
|
||||
import 'package:plezy/media/media_item.dart';
|
||||
import 'package:plezy/media/media_kind.dart';
|
||||
import 'package:plezy/media/media_library.dart';
|
||||
import 'package:plezy/media/media_playlist.dart';
|
||||
import 'package:plezy/media/media_stream.dart';
|
||||
import 'package:plezy/services/plex_mappers.dart';
|
||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
@@ -13,6 +17,30 @@ import 'package:sentry_flutter/sentry_flutter.dart';
|
||||
const _serverId = 'plex-machine-1';
|
||||
const _serverName = 'Home';
|
||||
|
||||
PlexMediaItem _mediaItemFromJson(Map<String, dynamic> json, {ServerId? serverId, String? serverName}) {
|
||||
final dto = PlexMetadataDto.fromJsonWithImages(json).copyWith(serverId: serverId, serverName: serverName);
|
||||
return PlexMappers.mediaItem(dto);
|
||||
}
|
||||
|
||||
MediaLibrary _mediaLibraryFromJson(
|
||||
Map<String, dynamic> json, {
|
||||
ServerId? serverId,
|
||||
String? serverName,
|
||||
bool isShared = false,
|
||||
}) {
|
||||
final dto = PlexLibraryDto.fromJson(json).copyWith(serverId: serverId, serverName: serverName, isShared: isShared);
|
||||
return PlexMappers.mediaLibrary(dto);
|
||||
}
|
||||
|
||||
MediaHub _mediaHubFromJson(Map<String, dynamic> json, {ServerId? serverId, String? serverName}) {
|
||||
return PlexMappers.mediaHub(PlexHubDto.fromJson(json, serverId: serverId, serverName: serverName));
|
||||
}
|
||||
|
||||
MediaPlaylist _mediaPlaylistFromJson(Map<String, dynamic> json, {ServerId? serverId, String? serverName}) {
|
||||
final dto = PlexPlaylistDto.fromJson(json).copyWith(serverId: serverId, serverName: serverName);
|
||||
return PlexMappers.mediaPlaylist(dto);
|
||||
}
|
||||
|
||||
void _expectSafePlexMapperEvent(
|
||||
SentryEvent event, {
|
||||
required Iterable<String> responseMarkers,
|
||||
@@ -111,7 +139,7 @@ void main() {
|
||||
'guid': 7,
|
||||
};
|
||||
|
||||
final hub = PlexMappers.mediaHubFromJson({
|
||||
final hub = _mediaHubFromJson({
|
||||
'key': '/hubs/cc004',
|
||||
'title': 'Synthetic hub',
|
||||
'type': 'movie',
|
||||
@@ -240,7 +268,7 @@ void main() {
|
||||
],
|
||||
};
|
||||
|
||||
final item = PlexMappers.mediaItemFromJson(json, serverId: ServerId(_serverId), serverName: _serverName);
|
||||
final item = _mediaItemFromJson(json, serverId: ServerId(_serverId), serverName: _serverName);
|
||||
|
||||
expect(item.id, '12345');
|
||||
expect(item.backend, MediaBackend.plex);
|
||||
@@ -309,7 +337,7 @@ void main() {
|
||||
test('a section listing yields the scalar pair alone', () {
|
||||
// Plex sends no `Rating[]` outside /library/metadata/{id}, and no query
|
||||
// parameter adds it, so listing-backed cards get one or two scores.
|
||||
final item = PlexMappers.mediaItemFromJson({
|
||||
final item = _mediaItemFromJson({
|
||||
'ratingKey': 'listing-1',
|
||||
'type': 'movie',
|
||||
'rating': 9.4,
|
||||
@@ -323,17 +351,14 @@ void main() {
|
||||
});
|
||||
|
||||
test('an unrated item reports no ratings rather than an empty list', () {
|
||||
final item = PlexMappers.mediaItemFromJson({
|
||||
'ratingKey': 'unrated-1',
|
||||
'type': 'movie',
|
||||
}, serverId: ServerId(_serverId));
|
||||
final item = _mediaItemFromJson({'ratingKey': 'unrated-1', 'type': 'movie'}, serverId: ServerId(_serverId));
|
||||
|
||||
expect(item.rating, isNull);
|
||||
expect(item.ratings, isNull);
|
||||
});
|
||||
|
||||
test('scores outside the reportable range are dropped, not folded', () {
|
||||
final item = PlexMappers.mediaItemFromJson({
|
||||
final item = _mediaItemFromJson({
|
||||
'ratingKey': 'noisy-1',
|
||||
'type': 'movie',
|
||||
'rating': 140,
|
||||
@@ -349,7 +374,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('normalizes aggregate watch counts off leaf items', () {
|
||||
final item = PlexMappers.mediaItemFromJson({
|
||||
final item = _mediaItemFromJson({
|
||||
'ratingKey': 'leaf-with-counts',
|
||||
'type': 'movie',
|
||||
'viewCount': 0,
|
||||
@@ -377,7 +402,7 @@ void main() {
|
||||
'year': 2008,
|
||||
};
|
||||
|
||||
final item = PlexMappers.mediaItemFromJson(json, serverId: ServerId(_serverId));
|
||||
final item = _mediaItemFromJson(json, serverId: ServerId(_serverId));
|
||||
expect(item.kind, MediaKind.show);
|
||||
expect(item.leafCount, 62);
|
||||
expect(item.viewedLeafCount, 62);
|
||||
@@ -395,7 +420,7 @@ void main() {
|
||||
'flattenSeasons': '1',
|
||||
};
|
||||
|
||||
final item = PlexMappers.mediaItemFromJson(json, serverId: ServerId(_serverId));
|
||||
final item = _mediaItemFromJson(json, serverId: ServerId(_serverId));
|
||||
|
||||
expect(item.raw, containsPair('key', '/library/metadata/500'));
|
||||
expect(item.raw, containsPair('skipChildren', true));
|
||||
@@ -415,7 +440,7 @@ void main() {
|
||||
'viewedLeafCount': 3,
|
||||
};
|
||||
|
||||
final item = PlexMappers.mediaItemFromJson(json, serverId: ServerId(_serverId));
|
||||
final item = _mediaItemFromJson(json, serverId: ServerId(_serverId));
|
||||
expect(item.kind, MediaKind.season);
|
||||
expect(item.index, 1);
|
||||
expect(item.parentId, '500');
|
||||
@@ -445,7 +470,7 @@ void main() {
|
||||
'viewOffset': 1410000,
|
||||
};
|
||||
|
||||
final item = PlexMappers.mediaItemFromJson(json, serverId: ServerId(_serverId));
|
||||
final item = _mediaItemFromJson(json, serverId: ServerId(_serverId));
|
||||
expect(item.kind, MediaKind.episode);
|
||||
expect(item.index, 1);
|
||||
expect(item.parentIndex, 1);
|
||||
@@ -475,7 +500,7 @@ void main() {
|
||||
'leafCount': 13,
|
||||
};
|
||||
|
||||
final item = PlexMappers.mediaItemFromJson(json, serverId: ServerId(_serverId));
|
||||
final item = _mediaItemFromJson(json, serverId: ServerId(_serverId));
|
||||
expect(item.kind, MediaKind.album);
|
||||
expect(item.title, 'Random Access Memories');
|
||||
expect(item.parentId, '699');
|
||||
@@ -499,7 +524,7 @@ void main() {
|
||||
'duration': 369000,
|
||||
};
|
||||
|
||||
final item = PlexMappers.mediaItemFromJson(json, serverId: ServerId(_serverId));
|
||||
final item = _mediaItemFromJson(json, serverId: ServerId(_serverId));
|
||||
expect(item.kind, MediaKind.track);
|
||||
expect(item.title, 'Get Lucky');
|
||||
expect(item.index, 8);
|
||||
@@ -552,7 +577,7 @@ void main() {
|
||||
],
|
||||
};
|
||||
|
||||
final item = PlexMappers.mediaItemFromJson(json, serverId: ServerId(_serverId));
|
||||
final item = _mediaItemFromJson(json, serverId: ServerId(_serverId));
|
||||
expect(item.mediaVersions, isNotNull);
|
||||
final v = item.mediaVersions!.single;
|
||||
expect(v.id, '1');
|
||||
@@ -601,7 +626,7 @@ void main() {
|
||||
],
|
||||
};
|
||||
|
||||
final item = PlexMappers.mediaItemFromJson(json, serverId: ServerId(_serverId));
|
||||
final item = _mediaItemFromJson(json, serverId: ServerId(_serverId));
|
||||
final part = item.mediaVersions!.single.parts.single;
|
||||
final video = part.streams.firstWhere((stream) => stream.kind == MediaStreamKind.video);
|
||||
final audio = part.streams.firstWhere((stream) => stream.kind == MediaStreamKind.audio);
|
||||
@@ -627,7 +652,7 @@ void main() {
|
||||
],
|
||||
};
|
||||
|
||||
final item = PlexMappers.mediaItemFromJson(json, serverId: ServerId(_serverId));
|
||||
final item = _mediaItemFromJson(json, serverId: ServerId(_serverId));
|
||||
expect(item.clearLogoPath, '/library/metadata/12345/clearLogo');
|
||||
expect(item.backgroundSquarePath, '/library/metadata/12345/squareBg');
|
||||
});
|
||||
@@ -646,7 +671,7 @@ void main() {
|
||||
'hidden': 0,
|
||||
};
|
||||
|
||||
final lib = PlexMappers.mediaLibraryFromJson(json, serverId: ServerId(_serverId), serverName: _serverName);
|
||||
final lib = _mediaLibraryFromJson(json, serverId: ServerId(_serverId), serverName: _serverName);
|
||||
expect(lib.id, '1');
|
||||
expect(lib.backend, MediaBackend.plex);
|
||||
expect(lib.title, 'Movies');
|
||||
@@ -662,13 +687,13 @@ void main() {
|
||||
|
||||
test('shared library is marked isShared', () {
|
||||
final json = {'key': 'shared', 'title': 'Shared with you', 'type': 'movie'};
|
||||
final lib = PlexMappers.mediaLibraryFromJson(json, serverId: ServerId(_serverId), isShared: true);
|
||||
final lib = _mediaLibraryFromJson(json, serverId: ServerId(_serverId), isShared: true);
|
||||
expect(lib.isShared, isTrue);
|
||||
});
|
||||
|
||||
test('hidden=1 maps to true', () {
|
||||
final json = {'key': '2', 'title': 'Hidden', 'type': 'show', 'hidden': 1};
|
||||
final lib = PlexMappers.mediaLibraryFromJson(json, serverId: ServerId(_serverId));
|
||||
final lib = _mediaLibraryFromJson(json, serverId: ServerId(_serverId));
|
||||
expect(lib.hidden, isTrue);
|
||||
});
|
||||
|
||||
@@ -701,7 +726,7 @@ void main() {
|
||||
// PlexLibraryDto.fromJson would throw TypeError when Plex omitted
|
||||
// either field. Confirms graceful degradation.
|
||||
final json = {'key': '99'};
|
||||
final lib = PlexMappers.mediaLibraryFromJson(json, serverId: ServerId(_serverId));
|
||||
final lib = _mediaLibraryFromJson(json, serverId: ServerId(_serverId));
|
||||
expect(lib.id, '99');
|
||||
expect(lib.title, '');
|
||||
expect(lib.kind, MediaKind.unknown);
|
||||
@@ -723,7 +748,7 @@ void main() {
|
||||
],
|
||||
};
|
||||
|
||||
final hub = PlexMappers.mediaHubFromJson(json, serverId: ServerId(_serverId), serverName: _serverName);
|
||||
final hub = _mediaHubFromJson(json, serverId: ServerId(_serverId), serverName: _serverName);
|
||||
expect(hub.id, '/hubs/movie.recentlyAdded');
|
||||
expect(hub.identifier, 'movie.recentlyAdded.1');
|
||||
expect(hub.title, 'Recently Added Movies');
|
||||
@@ -753,7 +778,7 @@ void main() {
|
||||
],
|
||||
};
|
||||
|
||||
final hub = PlexMappers.mediaHubFromJson(json, serverId: ServerId(_serverId));
|
||||
final hub = _mediaHubFromJson(json, serverId: ServerId(_serverId));
|
||||
expect(hub.items.length, 2);
|
||||
expect(hub.items[0].kind, MediaKind.show);
|
||||
expect(hub.items[1].kind, MediaKind.folder);
|
||||
@@ -772,7 +797,7 @@ void main() {
|
||||
],
|
||||
};
|
||||
|
||||
final hub = PlexMappers.mediaHubFromJson(json, serverId: ServerId(_serverId));
|
||||
final hub = _mediaHubFromJson(json, serverId: ServerId(_serverId));
|
||||
expect(hub.items.length, 2);
|
||||
expect(hub.items[0].kind, MediaKind.movie);
|
||||
expect(hub.items[1].kind, MediaKind.show);
|
||||
@@ -799,7 +824,7 @@ void main() {
|
||||
'thumb': '/playlists/999/thumb',
|
||||
};
|
||||
|
||||
final p = PlexMappers.mediaPlaylistFromJson(json, serverId: ServerId(_serverId), serverName: _serverName);
|
||||
final p = _mediaPlaylistFromJson(json, serverId: ServerId(_serverId), serverName: _serverName);
|
||||
expect(p.id, '999');
|
||||
expect(p.backend, MediaBackend.plex);
|
||||
expect(p.title, 'Date Night');
|
||||
@@ -828,7 +853,7 @@ void main() {
|
||||
'playlistType': 'audio',
|
||||
};
|
||||
|
||||
final p = PlexMappers.mediaPlaylistFromJson(json, serverId: ServerId(_serverId));
|
||||
final p = _mediaPlaylistFromJson(json, serverId: ServerId(_serverId));
|
||||
expect(p.smart, isTrue);
|
||||
expect(p.playlistType, 'audio');
|
||||
});
|
||||
@@ -838,7 +863,7 @@ void main() {
|
||||
// PlexPlaylistDto.fromJson would throw TypeError when Plex omitted
|
||||
// optional fields. Confirms graceful degradation.
|
||||
final json = {'ratingKey': '777', 'title': 'Bare', 'summary': null};
|
||||
final p = PlexMappers.mediaPlaylistFromJson(json, serverId: ServerId(_serverId));
|
||||
final p = _mediaPlaylistFromJson(json, serverId: ServerId(_serverId));
|
||||
expect(p.id, '777');
|
||||
expect(p.title, 'Bare');
|
||||
expect(p.smart, isFalse);
|
||||
|
||||
@@ -8,14 +8,19 @@
|
||||
// dashboard shows fewer scores than the detail screen, and this suite pins it.
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:plezy/media/ids.dart';
|
||||
import 'package:plezy/media/media_item.dart';
|
||||
import 'package:plezy/services/plex_mappers.dart';
|
||||
|
||||
const _serverId = 'plex-machine-1';
|
||||
|
||||
PlexMediaItem _mediaItemFromJson(Map<String, dynamic> json, {ServerId? serverId}) {
|
||||
return PlexMappers.mediaItem(PlexMetadataDto.fromJsonWithImages(json).copyWith(serverId: serverId));
|
||||
}
|
||||
|
||||
void main() {
|
||||
group('live Plex payloads', () {
|
||||
test('detail response surfaces IMDb alongside Rotten Tomatoes and TMDB', () {
|
||||
final item = PlexMappers.mediaItemFromJson({
|
||||
final item = _mediaItemFromJson({
|
||||
'ratingKey': '2254',
|
||||
'type': 'show',
|
||||
'title': '【OSHI NO KO】',
|
||||
@@ -35,7 +40,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('listing response carries only the scalar the server chose', () {
|
||||
final item = PlexMappers.mediaItemFromJson({
|
||||
final item = _mediaItemFromJson({
|
||||
'ratingKey': '2254',
|
||||
'type': 'show',
|
||||
'title': '【OSHI NO KO】',
|
||||
|
||||
@@ -87,7 +87,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('formats Plex season child fallback metadata', () {
|
||||
final item = PlexMappers.mediaItemFromJson({
|
||||
final item = _mediaItemFromJson({
|
||||
'ratingKey': '6048',
|
||||
'type': 'episode',
|
||||
'title': 'Hello, Ms. Cobel',
|
||||
@@ -115,7 +115,7 @@ void main() {
|
||||
});
|
||||
|
||||
test('formats Plex movie full-detail stream metadata', () {
|
||||
final item = PlexMappers.mediaItemFromJson({
|
||||
final item = _mediaItemFromJson({
|
||||
'ratingKey': 'movie-1',
|
||||
'type': 'movie',
|
||||
'title': 'Movie',
|
||||
@@ -269,6 +269,10 @@ void main() {
|
||||
});
|
||||
}
|
||||
|
||||
PlexMediaItem _mediaItemFromJson(Map<String, dynamic> json, {ServerId? serverId}) {
|
||||
return PlexMappers.mediaItem(PlexMetadataDto.fromJsonWithImages(json).copyWith(serverId: serverId));
|
||||
}
|
||||
|
||||
MediaItem _episodeWithVersion(MediaVersion? version) {
|
||||
return testMediaItem(
|
||||
id: 'episode-1',
|
||||
|
||||
Reference in New Issue
Block a user