fix: make PlexMetadata type/key/title nullable for folder items
Plex API returns Directory entries without type field, causing TypeError crash in fromJson. Made fields nullable and migrated callers to use mediaType enum and displayTitle getter instead of raw string access.
This commit is contained in:
@@ -351,7 +351,7 @@ class DiscordRPCService {
|
||||
timestamps: _buildTimestamps(),
|
||||
statusDisplayType: DiscordStatusDisplayType.details,
|
||||
largeAsset: _cachedThumbnailUrl != null
|
||||
? DiscordAsset(url: _cachedThumbnailUrl!, text: metadata.grandparentTitle ?? metadata.title)
|
||||
? DiscordAsset(url: _cachedThumbnailUrl!, text: metadata.grandparentTitle ?? metadata.title!)
|
||||
: null,
|
||||
),
|
||||
);
|
||||
@@ -392,14 +392,14 @@ class DiscordRPCService {
|
||||
switch (metadata.mediaType) {
|
||||
case PlexMediaType.movie:
|
||||
final year = metadata.year != null ? ' (${metadata.year})' : '';
|
||||
return metadata.title + year;
|
||||
return metadata.title! + year;
|
||||
|
||||
case PlexMediaType.episode:
|
||||
// Show: "Show Name" or just episode title if no show name
|
||||
return metadata.grandparentTitle ?? metadata.title;
|
||||
return metadata.grandparentTitle ?? metadata.title!;
|
||||
|
||||
default:
|
||||
return metadata.title;
|
||||
return metadata.title!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -411,9 +411,9 @@ class DiscordRPCService {
|
||||
final season = metadata.parentIndex;
|
||||
final episode = metadata.index;
|
||||
if (season != null && episode != null) {
|
||||
return 'S$season E$episode - ${metadata.title}';
|
||||
return 'S$season E$episode - ${metadata.title!}';
|
||||
}
|
||||
return metadata.title;
|
||||
return metadata.title!;
|
||||
|
||||
case PlexMediaType.movie:
|
||||
return metadata.studio;
|
||||
|
||||
@@ -341,7 +341,7 @@ class DownloadManagerService {
|
||||
serverId: metadata.serverId!,
|
||||
ratingKey: metadata.ratingKey,
|
||||
globalKey: globalKey,
|
||||
type: metadata.type,
|
||||
type: metadata.type ?? '',
|
||||
parentRatingKey: metadata.parentRatingKey,
|
||||
grandparentRatingKey: metadata.grandparentRatingKey,
|
||||
status: DownloadStatus.queued.index,
|
||||
@@ -446,8 +446,8 @@ class DownloadManagerService {
|
||||
|
||||
// Build display name for notifications
|
||||
final displayName = metadata.type == 'episode'
|
||||
? '${metadata.grandparentTitle ?? metadata.title} - ${metadata.title}'
|
||||
: metadata.title;
|
||||
? '${metadata.grandparentTitle ?? metadata.displayTitle} - ${metadata.displayTitle}'
|
||||
: metadata.displayTitle;
|
||||
|
||||
// Get WiFi-only setting for native enforcement
|
||||
final settings = await SettingsService.getInstance();
|
||||
@@ -1234,7 +1234,7 @@ class DownloadManagerService {
|
||||
|
||||
// Emit initial progress
|
||||
_emitDeletionProgress(
|
||||
DeletionProgress(globalKey: globalKey, itemTitle: metadata.title, currentItem: 0, totalItems: totalItems),
|
||||
DeletionProgress(globalKey: globalKey, itemTitle: metadata.displayTitle, currentItem: 0, totalItems: totalItems),
|
||||
);
|
||||
|
||||
// Delete files from storage (with progress updates)
|
||||
@@ -1250,7 +1250,7 @@ class DownloadManagerService {
|
||||
_emitDeletionProgress(
|
||||
DeletionProgress(
|
||||
globalKey: globalKey,
|
||||
itemTitle: metadata.title,
|
||||
itemTitle: metadata.displayTitle,
|
||||
currentItem: totalItems,
|
||||
totalItems: totalItems,
|
||||
),
|
||||
@@ -1264,17 +1264,14 @@ class DownloadManagerService {
|
||||
|
||||
/// Calculate total items to delete (for progress tracking)
|
||||
Future<int> _getTotalItemsToDelete(PlexMetadata metadata, String _) async {
|
||||
switch (metadata.type.toLowerCase()) {
|
||||
case 'episode':
|
||||
return 1; // Single episode
|
||||
case 'movie':
|
||||
return 1; // Single movie
|
||||
case 'season':
|
||||
// Count episodes in season
|
||||
switch (metadata.mediaType) {
|
||||
case PlexMediaType.episode:
|
||||
case PlexMediaType.movie:
|
||||
return 1;
|
||||
case PlexMediaType.season:
|
||||
final episodes = await _database.getEpisodesBySeason(metadata.ratingKey);
|
||||
return episodes.length;
|
||||
case 'show':
|
||||
// Count all episodes in show
|
||||
case PlexMediaType.show:
|
||||
final episodes = await _database.getEpisodesByShow(metadata.ratingKey);
|
||||
return episodes.length;
|
||||
default:
|
||||
@@ -1301,17 +1298,17 @@ class DownloadManagerService {
|
||||
}
|
||||
|
||||
// Delete based on type
|
||||
switch (metadata.type.toLowerCase()) {
|
||||
case 'episode':
|
||||
switch (metadata.mediaType) {
|
||||
case PlexMediaType.episode:
|
||||
await _deleteEpisodeFiles(metadata, serverId);
|
||||
break;
|
||||
case 'season':
|
||||
case PlexMediaType.season:
|
||||
await _deleteSeasonFiles(metadata, serverId);
|
||||
break;
|
||||
case 'show':
|
||||
case PlexMediaType.show:
|
||||
await _deleteShowFiles(metadata, serverId);
|
||||
break;
|
||||
case 'movie':
|
||||
case PlexMediaType.movie:
|
||||
await _deleteMovieFiles(metadata, serverId);
|
||||
break;
|
||||
default:
|
||||
@@ -1447,7 +1444,7 @@ class DownloadManagerService {
|
||||
episodes: episodesInSeason,
|
||||
serverId: serverId,
|
||||
parentKey: season.ratingKey,
|
||||
parentTitle: season.title,
|
||||
parentTitle: season.displayTitle,
|
||||
);
|
||||
|
||||
final seasonDir = await _storageService.getSeasonDirectory(season, showYear: showYear);
|
||||
@@ -1510,7 +1507,7 @@ class DownloadManagerService {
|
||||
episodes: episodesInShow,
|
||||
serverId: serverId,
|
||||
parentKey: show.ratingKey,
|
||||
parentTitle: show.title,
|
||||
parentTitle: show.displayTitle,
|
||||
);
|
||||
|
||||
final showDir = await _storageService.getShowDirectory(show);
|
||||
|
||||
@@ -65,7 +65,7 @@ class DownloadStorageService {
|
||||
String _formatEpisodeFileName(PlexMetadata episode) {
|
||||
final season = padNumber(episode.parentIndex ?? 0, 2);
|
||||
final ep = padNumber(episode.index ?? 0, 2);
|
||||
final episodeName = _sanitizeFileName(episode.title);
|
||||
final episodeName = _sanitizeFileName(episode.title!);
|
||||
return 'S${season}E$ep - $episodeName';
|
||||
}
|
||||
|
||||
@@ -246,13 +246,13 @@ class DownloadStorageService {
|
||||
|
||||
/// Get the folder name for a movie: "Movie Name (YYYY)"
|
||||
String _getMovieFolderName(PlexMetadata movie) {
|
||||
return _formatTitleWithYear(movie.title, movie.year);
|
||||
return _formatTitleWithYear(movie.title!, movie.year);
|
||||
}
|
||||
|
||||
/// Get the folder name for a TV show: "Show Name (YYYY)"
|
||||
/// [showYear]: Pass explicitly for episodes (episode.year may differ from show's year)
|
||||
String _getShowFolderName(PlexMetadata metadata, {int? showYear}) {
|
||||
final title = metadata.grandparentTitle ?? metadata.title;
|
||||
final title = metadata.grandparentTitle ?? metadata.title!;
|
||||
final year = showYear ?? metadata.year;
|
||||
return _formatTitleWithYear(title, year);
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ class MediaControlsManager {
|
||||
// Update OS media controls
|
||||
await OsMediaControls.setMetadata(
|
||||
MediaMetadata(
|
||||
title: metadata.title,
|
||||
title: metadata.title!,
|
||||
artist: _buildArtist(metadata),
|
||||
artworkUrl: artworkUrl,
|
||||
duration: duration,
|
||||
|
||||
@@ -134,7 +134,7 @@ class WatchNextService {
|
||||
title = item.grandparentTitle!;
|
||||
episodeTitle = item.title;
|
||||
} else {
|
||||
title = item.title;
|
||||
title = item.title!;
|
||||
episodeTitle = null;
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ class WatchNextService {
|
||||
'episodeTitle': episodeTitle,
|
||||
'description': item.summary,
|
||||
'posterUri': posterUri,
|
||||
'type': item.type.toLowerCase(),
|
||||
'type': item.mediaType.name,
|
||||
'duration': item.duration ?? 0,
|
||||
'lastPlaybackPosition': item.viewOffset ?? 0,
|
||||
'lastEngagementTime': lastEngagementTime,
|
||||
|
||||
Reference in New Issue
Block a user