Promote the Plugin Controller source file to Objective-C++, and add a simple data cache that holds on to requests for up to 5 seconds after their last access, for preventing spammed requests from hitting files over and over. This is apparently really relevant to the CUESheet reader and its embedded CUESheet handling, as that tends to reread the same file over and over as it populates the playlist with tracks. The nested reader can also lead to repeated reading even on files without CUESheets embedded. Signed-off-by: Christopher Snowhill <kode54@gmail.com>
77 lines
1.8 KiB
Objective-C
77 lines
1.8 KiB
Objective-C
//
|
|
// RedundantPlaylistDataStore.m
|
|
// Cog
|
|
//
|
|
// Created by Christopher Snowhill on 2/16/22.
|
|
//
|
|
|
|
// Coalesce an entryInfo dictionary from tag loading into a common data dictionary, to
|
|
// reduce the memory footprint of adding a lot of tracks to the playlist.
|
|
|
|
#import "RedundantPlaylistDataStore.h"
|
|
|
|
#import "SHA256Digest.h"
|
|
|
|
@implementation RedundantPlaylistDataStore
|
|
|
|
- (id)init {
|
|
self = [super init];
|
|
|
|
if(self) {
|
|
stringStore = [[NSMutableArray alloc] init];
|
|
artStore = [[NSMutableDictionary alloc] init];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (NSString *)coalesceString:(NSString *)in {
|
|
if(in == nil) return in;
|
|
|
|
NSUInteger index = [stringStore indexOfObject:in];
|
|
if(index == NSNotFound) {
|
|
[stringStore addObject:in];
|
|
return in;
|
|
} else {
|
|
return [stringStore objectAtIndex:index];
|
|
}
|
|
}
|
|
|
|
- (NSData *)coalesceArt:(NSData *)in {
|
|
if(in == nil) return in;
|
|
|
|
NSString *key = [SHA256Digest digestDataAsString:in];
|
|
|
|
NSData *ret = [artStore objectForKey:key];
|
|
if(ret == nil) {
|
|
[artStore setObject:in forKey:key];
|
|
return in;
|
|
} else {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
- (NSDictionary *)coalesceEntryInfo:(NSDictionary *)entryInfo {
|
|
__block NSMutableDictionary *ret = [[NSMutableDictionary alloc] initWithCapacity:[entryInfo count]];
|
|
|
|
[entryInfo enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL *_Nonnull stop) {
|
|
if([obj isKindOfClass:[NSString class]]) {
|
|
NSString *stringObj = (NSString *)obj;
|
|
[ret setObject:[self coalesceString:stringObj] forKey:key];
|
|
} else if([obj isKindOfClass:[NSData class]]) {
|
|
NSData *dataObj = (NSData *)obj;
|
|
[ret setObject:[self coalesceArt:dataObj] forKey:key];
|
|
} else {
|
|
[ret setObject:obj forKey:key];
|
|
}
|
|
}];
|
|
|
|
return [NSDictionary dictionaryWithDictionary:ret];
|
|
}
|
|
|
|
- (void)reset {
|
|
[stringStore removeAllObjects];
|
|
[artStore removeAllObjects];
|
|
}
|
|
|
|
@end
|