refactor: trakt/download hardening and cleanup sweep

This commit is contained in:
edde746
2026-04-21 13:57:03 +02:00
parent 93d196572f
commit ee020d81bd
66 changed files with 1526 additions and 2167 deletions
-5
View File
@@ -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);
+52
View File
@@ -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);
}
}
-25
View File
@@ -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?;
}
}
-11
View File
@@ -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}';
}
}