From 47fa67fe7c4e32ec731f0e3b9c142c5d54697ba8 Mon Sep 17 00:00:00 2001 From: Marko Jurkovic Date: Fri, 17 Jul 2026 14:41:53 +0200 Subject: [PATCH] Preload metadata for embedded CUE tracks --- Playlist/PlaylistLoader.m | 41 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/Playlist/PlaylistLoader.m b/Playlist/PlaylistLoader.m index db836a115..e6a29fceb 100644 --- a/Playlist/PlaylistLoader.m +++ b/Playlist/PlaylistLoader.m @@ -293,10 +293,45 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc } } +static inline BOOL cueSheetValueHasContent(id value) { + if([value isKindOfClass:[NSString class]]) { + return [value length] > 0; + } + if([value isKindOfClass:[NSArray class]]) { + for(id item in value) { + if([item isKindOfClass:[NSString class]] && [item length] > 0) { + return YES; + } + } + } + return NO; +} + static inline BOOL isCueSheetTrackURL(NSURL *url) { - return [url isFileURL] && - [[url fragment] length] && - [[url pathExtension] caseInsensitiveCompare:@"cue"] == NSOrderedSame; + if(![url isFileURL] || ![[url fragment] length]) { + return NO; + } + if([[url pathExtension] caseInsensitiveCompare:@"cue"] == NSOrderedSame) { + return YES; + } + + // Embedded CUE tracks retain the audio file's extension (for example, + // album.flac#01). Inspect the underlying file without its track fragment; + // checking the fragment alone would also match unrelated subsong URLs. + NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO]; + components.fragment = nil; + NSURL *baseURL = components.URL; + if(!baseURL) { + return NO; + } + + NSDictionary *metadata = [AudioMetadataReader metadataForURL:baseURL skipCue:YES]; + if(cueSheetValueHasContent(metadata[@"cuesheet"])) { + return YES; + } + + NSDictionary *properties = [AudioPropertiesReader propertiesForURL:baseURL skipCue:YES]; + return cueSheetValueHasContent(properties[@"cuesheet"]); } - (void)beginProgress:(NSString *)localizedDescription {