refactor: trakt/download hardening and cleanup sweep
This commit is contained in:
@@ -89,12 +89,7 @@ extension PlexMetadataType on PlexMetadata {
|
||||
bool get isMovie => _lowerType == ContentTypes.movie;
|
||||
bool get isSeason => _lowerType == ContentTypes.season;
|
||||
bool get isEpisode => _lowerType == ContentTypes.episode;
|
||||
bool get isArtist => _lowerType == ContentTypes.artist;
|
||||
bool get isAlbum => _lowerType == ContentTypes.album;
|
||||
bool get isTrack => _lowerType == ContentTypes.track;
|
||||
bool get isCollection => _lowerType == ContentTypes.collection;
|
||||
bool get isPlaylist => _lowerType == ContentTypes.playlist;
|
||||
bool get isClip => _lowerType == ContentTypes.clip;
|
||||
bool get isMusicContent => ContentTypes.musicTypes.contains(_lowerType);
|
||||
bool get isVideoContent => ContentTypes.videoTypes.contains(_lowerType);
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import '../models/plex_metadata.dart';
|
||||
import '../services/plex_client.dart';
|
||||
import '../utils/app_logger.dart';
|
||||
import '../utils/content_utils.dart';
|
||||
|
||||
/// Walk the children of a show and collect every episode into [out].
|
||||
///
|
||||
/// - Per-season fetch failures are logged and skipped (one bad season doesn't
|
||||
/// discard progress from the others).
|
||||
/// - A failure to fetch the show's own children is logged and leaves [out]
|
||||
/// empty.
|
||||
/// - [unwatchedOnly] skips episodes that are watched and have no active
|
||||
/// progress.
|
||||
Future<void> collectEpisodesForShow(
|
||||
PlexClient client,
|
||||
String showRatingKey, {
|
||||
required bool unwatchedOnly,
|
||||
required List<PlexMetadata> out,
|
||||
}) async {
|
||||
final List<PlexMetadata> seasons;
|
||||
try {
|
||||
seasons = await client.getChildren(showRatingKey);
|
||||
} catch (e) {
|
||||
appLogger.w('Episode collection: show $showRatingKey getChildren failed, skipping', error: e);
|
||||
return;
|
||||
}
|
||||
for (final season in seasons) {
|
||||
if (season.type != ContentTypes.season) continue;
|
||||
try {
|
||||
await collectEpisodesForSeason(client, season.ratingKey, unwatchedOnly: unwatchedOnly, out: out);
|
||||
} catch (e) {
|
||||
appLogger.w('Episode collection: season ${season.ratingKey} fetch failed, skipping', error: e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch the episodes of a season and append the ones passing [unwatchedOnly]
|
||||
/// to [out]. Throws if the underlying `getChildren` fails — callers that want
|
||||
/// per-season resilience should wrap in try/catch (see [collectEpisodesForShow]).
|
||||
Future<void> collectEpisodesForSeason(
|
||||
PlexClient client,
|
||||
String seasonRatingKey, {
|
||||
required bool unwatchedOnly,
|
||||
required List<PlexMetadata> out,
|
||||
}) async {
|
||||
final episodes = await client.getChildren(seasonRatingKey);
|
||||
for (final ep in episodes) {
|
||||
if (ep.type != ContentTypes.episode) continue;
|
||||
if (unwatchedOnly && ep.isWatched && !ep.hasActiveProgress) continue;
|
||||
out.add(ep);
|
||||
}
|
||||
}
|
||||
@@ -21,35 +21,10 @@ class PlexCacheParser {
|
||||
return list.first as Map<String, dynamic>;
|
||||
}
|
||||
|
||||
/// Check if a cached response has valid metadata
|
||||
static bool hasMetadata(Map<String, dynamic>? cached) {
|
||||
final list = extractMetadataList(cached);
|
||||
return list != null && list.isNotEmpty;
|
||||
}
|
||||
|
||||
/// Extract Directory list from a cached response (for libraries, playlists)
|
||||
static List<dynamic>? extractDirectoryList(Map<String, dynamic>? cached) {
|
||||
if (cached == null) return null;
|
||||
return cached['MediaContainer']?['Directory'] as List?;
|
||||
}
|
||||
|
||||
/// Extract Hub list from a cached response
|
||||
static List<dynamic>? extractHubList(Map<String, dynamic>? cached) {
|
||||
if (cached == null) return null;
|
||||
return cached['MediaContainer']?['Hub'] as List?;
|
||||
}
|
||||
|
||||
/// Extract Chapter list from the first metadata item
|
||||
static List<dynamic>? extractChapters(Map<String, dynamic>? cached) {
|
||||
final metadata = extractFirstMetadata(cached);
|
||||
if (metadata == null) return null;
|
||||
return metadata['Chapter'] as List?;
|
||||
}
|
||||
|
||||
/// Extract Marker list from the first metadata item
|
||||
static List<dynamic>? extractMarkers(Map<String, dynamic>? cached) {
|
||||
final metadata = extractFirstMetadata(cached);
|
||||
if (metadata == null) return null;
|
||||
return metadata['Marker'] as List?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,15 +243,4 @@ class PlexImageHelper {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Creates a consistent cache key for rounded dimensions
|
||||
static String generateCacheKey({
|
||||
required String originalPath,
|
||||
required int width,
|
||||
required int height,
|
||||
String? serverId,
|
||||
}) {
|
||||
final serverPrefix = serverId != null ? '${serverId}_' : '';
|
||||
return '${serverPrefix}transcode_${width}x${height}_${originalPath.hashCode}';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user