Compare commits

...

3 commits

Author SHA1 Message Date
Christopher Snowhill
a76c4c7426 Tag Reading: Better handle tag names with periods
Some checks are pending
Check if Cog buildable / Build Universal Cog.app (push) Waiting to run
Oops, I forgot that Cocoa KVO treats key names with periods in them as a
special case, assuming that each dotted word is a separate nested object
from the others. Work around this by using Unicode character replacement
that will hopefully dodge the issue.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-06-07 05:44:01 -07:00
Christopher Snowhill
b5403522e0 Sandbox: Fix missing file handler crash
Apparently, NSURL path for fileURL can return nil if the resource no
longer exists, or something. Better fail gracefully than cause a crash.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-06-07 05:43:55 -07:00
Christopher Snowhill
dfd95b0a37 Rubberband: Fix end of track reset for threading
This end of track restart notification may come from a different thread
than the processing thread. Wait on the thread to complete.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
2025-06-07 05:43:50 -07:00
3 changed files with 26 additions and 8 deletions

View file

@ -363,6 +363,7 @@ static void * kDSPRubberbandNodeContext = &kDSPRubberbandNodeContext;
- (void)setEndOfStream:(BOOL)e {
if(endOfStream && !e) {
while(processEntered);
[self fullShutdown];
}
[super setEndOfStream:e];

View file

@ -21,6 +21,16 @@ extern NSMutableDictionary<NSString *, AlbumArtwork *> *kArtworkDictionary;
@implementation PlaylistEntry (Extension)
// The following is needed for handling any tag names with periods in them, as KVE wants to treat these as nested objects
// Let's hack in U+2024 and hope nobody notices!
+ (NSString *)keyForMetaTag:(NSString *)tagName {
return [tagName stringByReplacingOccurrencesOfString:@"." withString:@""];
}
+ (NSString *)metaTagForKey:(NSString *)key {
return [key stringByReplacingOccurrencesOfString:@"" withString:@"."];
}
// The following read-only keys depend on the values of other properties
+ (NSSet *)keyPathsForValuesAffectingUrl {
@ -523,7 +533,8 @@ NSURL *_Nullable urlForPath(NSString *_Nullable path) {
}
self.volume = 1;
for(NSString *key in metadata) {
NSString *lowerKey = [key lowercaseString];
NSString *tagName = [PlaylistEntry metaTagForKey:key];
NSString *lowerKey = [tagName lowercaseString];
id valueObj = [metadata objectForKey:key];
NSArray *values = nil;
NSString *firstValue = nil;
@ -582,7 +593,7 @@ NSURL *_Nullable urlForPath(NSString *_Nullable path) {
} else if([lowerKey isEqualToString:@"albumart"]) {
self.albumArt = dataValue;
} else {
[metaDict setObject:values forKey:lowerKey];
[metaDict setObject:values forKey:key];
}
}
self.metadataBlob = [NSDictionary dictionaryWithDictionary:metaDict];
@ -862,8 +873,9 @@ NSURL *_Nullable urlForPath(NSString *_Nullable path) {
if(metaObj && [metaObj isKindOfClass:[NSDictionary class]]) {
NSDictionary *metaDict = (NSDictionary *)metaObj;
NSString *realKey = [PlaylistEntry keyForMetaTag:tagName];
NSArray *values = [metaDict objectForKey:tagName];
NSArray *values = [metaDict objectForKey:realKey];
if(values) {
return [values componentsJoinedByString:@", "];
@ -883,8 +895,9 @@ NSURL *_Nullable urlForPath(NSString *_Nullable path) {
if(metaObj && [metaObj isKindOfClass:[NSDictionary class]]) {
NSDictionary *metaDict = (NSDictionary *)metaObj;
NSMutableDictionary *metaDictCopy = [metaDict mutableCopy];
NSString *realKey = [PlaylistEntry keyForMetaTag:tagName];
[metaDictCopy removeObjectForKey:tagName];
[metaDictCopy removeObjectForKey:realKey];
self.metadataBlob = [NSDictionary dictionaryWithDictionary:metaDictCopy];
}
@ -903,8 +916,9 @@ NSURL *_Nullable urlForPath(NSString *_Nullable path) {
if(metaObj && [metaObj isKindOfClass:[NSDictionary class]]) {
NSDictionary *metaDict = (NSDictionary *)metaObj;
NSMutableDictionary *metaDictCopy = [metaDict mutableCopy];
NSString *realKey = [PlaylistEntry keyForMetaTag:tagName];
[metaDictCopy setObject:values forKey:tagName];
[metaDictCopy setObject:values forKey:realKey];
self.metadataBlob = [NSDictionary dictionaryWithDictionary:metaDictCopy];
}
@ -916,8 +930,9 @@ NSURL *_Nullable urlForPath(NSString *_Nullable path) {
if(metaObj && [metaObj isKindOfClass:[NSDictionary class]]) {
NSDictionary *metaDict = (NSDictionary *)metaObj;
NSMutableDictionary *metaDictCopy = [metaDict mutableCopy];
NSString *realKey = [PlaylistEntry keyForMetaTag:tagName];
NSArray *values = [metaDictCopy objectForKey:tagName];
NSArray *values = [metaDictCopy objectForKey:realKey];
NSMutableArray *valuesCopy;
if(values) {
valuesCopy = [values mutableCopy];
@ -926,7 +941,7 @@ NSURL *_Nullable urlForPath(NSString *_Nullable path) {
}
[valuesCopy addObject:value];
values = [NSArray arrayWithArray:valuesCopy];
[metaDictCopy setObject:values forKey:tagName];
[metaDictCopy setObject:values forKey:realKey];
self.metadataBlob = [NSDictionary dictionaryWithDictionary:metaDictCopy];
}

View file

@ -100,6 +100,7 @@ static SandboxBroker *kSharedSandboxBroker = nil;
if(![url isFileURL]) return url;
NSString *s = [url path];
if(!s) return NULL; // Cool, the resource no longer exists!
NSRange fragmentRange = [s rangeOfString:@"#"
options:NSBackwardsSearch];
@ -270,6 +271,7 @@ static inline void dispatch_async_reentrant(dispatch_queue_t queue, dispatch_blo
if(![fileUrl isFileURL]) return;
NSURL *url = [SandboxBroker urlWithoutFragment:fileUrl];
if(!url) return;
dispatch_async_reentrant(dispatch_get_main_queue(), ^{
SandboxEntry *_entry = nil;
@ -422,7 +424,7 @@ static inline void dispatch_async_reentrant(dispatch_queue_t queue, dispatch_blo
- (const void *)beginFolderAccess:(NSURL *)fileUrl {
if(!fileUrl) return NULL;
NSURL *folderUrl = [SandboxBroker urlWithoutFragment:fileUrl];
if(![folderUrl isFileURL]) return NULL;
if(!folderUrl || ![folderUrl isFileURL]) return NULL;
__block SandboxEntry *_entry = nil;