XML playlists now store album art in an MD5 hash indexed dictionary, but continue to read the older format for backwards compatibility

CQTexperiment
Chris Moeller 2013-10-09 16:14:23 -07:00
parent 555ccc9e87
commit 754a22166a
6 changed files with 89 additions and 16 deletions

View File

@ -144,6 +144,8 @@
56C63D910D647DF300EAE25A /* NSComparisonPredicate+CogPredicate.m in Sources */ = {isa = PBXBuildFile; fileRef = 56C63D900D647DF300EAE25A /* NSComparisonPredicate+CogPredicate.m */; }; 56C63D910D647DF300EAE25A /* NSComparisonPredicate+CogPredicate.m in Sources */ = {isa = PBXBuildFile; fileRef = 56C63D900D647DF300EAE25A /* NSComparisonPredicate+CogPredicate.m */; };
56DB084C0D6717DC00453B6A /* NSNumber+CogSort.m in Sources */ = {isa = PBXBuildFile; fileRef = 56DB084B0D6717DC00453B6A /* NSNumber+CogSort.m */; }; 56DB084C0D6717DC00453B6A /* NSNumber+CogSort.m in Sources */ = {isa = PBXBuildFile; fileRef = 56DB084B0D6717DC00453B6A /* NSNumber+CogSort.m */; };
56DB08550D67185300453B6A /* NSArray+CogSort.m in Sources */ = {isa = PBXBuildFile; fileRef = 56DB08540D67185300453B6A /* NSArray+CogSort.m */; }; 56DB08550D67185300453B6A /* NSArray+CogSort.m in Sources */ = {isa = PBXBuildFile; fileRef = 56DB08540D67185300453B6A /* NSArray+CogSort.m */; };
8355D6B6180612F300D05687 /* NSData+MD5.m in Sources */ = {isa = PBXBuildFile; fileRef = 8355D6B5180612F300D05687 /* NSData+MD5.m */; };
8355D6B8180613FB00D05687 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8355D6B7180613FB00D05687 /* Security.framework */; };
8359009D17FF06570060F3ED /* ArchiveSource.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8359FF3117FEF35D0060F3ED /* ArchiveSource.bundle */; }; 8359009D17FF06570060F3ED /* ArchiveSource.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8359FF3117FEF35D0060F3ED /* ArchiveSource.bundle */; };
8360EF6D17F92E56005208A4 /* HighlyComplete.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8360EF0517F92B24005208A4 /* HighlyComplete.bundle */; }; 8360EF6D17F92E56005208A4 /* HighlyComplete.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8360EF0517F92B24005208A4 /* HighlyComplete.bundle */; };
8375B36517FFEF130092A79F /* Opus.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8375B05717FFEA410092A79F /* Opus.bundle */; }; 8375B36517FFEF130092A79F /* Opus.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8375B05717FFEA410092A79F /* Opus.bundle */; };
@ -746,6 +748,9 @@
56DB084B0D6717DC00453B6A /* NSNumber+CogSort.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSNumber+CogSort.m"; path = "Spotlight/NSNumber+CogSort.m"; sourceTree = "<group>"; }; 56DB084B0D6717DC00453B6A /* NSNumber+CogSort.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSNumber+CogSort.m"; path = "Spotlight/NSNumber+CogSort.m"; sourceTree = "<group>"; };
56DB08530D67185300453B6A /* NSArray+CogSort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSArray+CogSort.h"; path = "Spotlight/NSArray+CogSort.h"; sourceTree = "<group>"; }; 56DB08530D67185300453B6A /* NSArray+CogSort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSArray+CogSort.h"; path = "Spotlight/NSArray+CogSort.h"; sourceTree = "<group>"; };
56DB08540D67185300453B6A /* NSArray+CogSort.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSArray+CogSort.m"; path = "Spotlight/NSArray+CogSort.m"; sourceTree = "<group>"; }; 56DB08540D67185300453B6A /* NSArray+CogSort.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSArray+CogSort.m"; path = "Spotlight/NSArray+CogSort.m"; sourceTree = "<group>"; };
8355D6B4180612F300D05687 /* NSData+MD5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+MD5.h"; sourceTree = "<group>"; };
8355D6B5180612F300D05687 /* NSData+MD5.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+MD5.m"; sourceTree = "<group>"; };
8355D6B7180613FB00D05687 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
8359FF2C17FEF35C0060F3ED /* ArchiveSource.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ArchiveSource.xcodeproj; path = Plugins/ArchiveSource/ArchiveSource.xcodeproj; sourceTree = "<group>"; }; 8359FF2C17FEF35C0060F3ED /* ArchiveSource.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ArchiveSource.xcodeproj; path = Plugins/ArchiveSource/ArchiveSource.xcodeproj; sourceTree = "<group>"; };
8360EF0017F92B23005208A4 /* HighlyComplete.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = HighlyComplete.xcodeproj; path = Plugins/HighlyComplete/HighlyComplete.xcodeproj; sourceTree = "<group>"; }; 8360EF0017F92B23005208A4 /* HighlyComplete.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = HighlyComplete.xcodeproj; path = Plugins/HighlyComplete/HighlyComplete.xcodeproj; sourceTree = "<group>"; };
8375B05117FFEA400092A79F /* Opus.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Opus.xcodeproj; path = Plugins/Opus/Opus.xcodeproj; sourceTree = "<group>"; }; 8375B05117FFEA400092A79F /* Opus.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Opus.xcodeproj; path = Plugins/Opus/Opus.xcodeproj; sourceTree = "<group>"; };
@ -789,6 +794,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
8355D6B8180613FB00D05687 /* Security.framework in Frameworks */,
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
8E6889240AAA403C00AD3950 /* Carbon.framework in Frameworks */, 8E6889240AAA403C00AD3950 /* Carbon.framework in Frameworks */,
17BB5CED0B8A86010009ACB1 /* AudioToolbox.framework in Frameworks */, 17BB5CED0B8A86010009ACB1 /* AudioToolbox.framework in Frameworks */,
@ -956,6 +962,8 @@
07E18DF20D62B38400BB0E11 /* NSArray+ShuffleUtils.m */, 07E18DF20D62B38400BB0E11 /* NSArray+ShuffleUtils.m */,
17FAEBAA0F662985007C8707 /* ToolTipTextField.h */, 17FAEBAA0F662985007C8707 /* ToolTipTextField.h */,
17FAEBAB0F662985007C8707 /* ToolTipTextField.m */, 17FAEBAB0F662985007C8707 /* ToolTipTextField.m */,
8355D6B4180612F300D05687 /* NSData+MD5.h */,
8355D6B5180612F300D05687 /* NSData+MD5.m */,
); );
path = Utils; path = Utils;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1307,6 +1315,7 @@
29B97323FDCFA39411CA2CEA /* Frameworks */ = { 29B97323FDCFA39411CA2CEA /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
8355D6B7180613FB00D05687 /* Security.framework */,
1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */,
1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */,
); );
@ -1900,6 +1909,7 @@
1770429C0B8BC53600B86321 /* AppController.m in Sources */, 1770429C0B8BC53600B86321 /* AppController.m in Sources */,
1770429E0B8BC53600B86321 /* PlaybackController.m in Sources */, 1770429E0B8BC53600B86321 /* PlaybackController.m in Sources */,
1766C6930B911DF1004A7AE4 /* AudioScrobbler.m in Sources */, 1766C6930B911DF1004A7AE4 /* AudioScrobbler.m in Sources */,
8355D6B6180612F300D05687 /* NSData+MD5.m in Sources */,
1766C6950B911DF1004A7AE4 /* AudioScrobblerClient.m in Sources */, 1766C6950B911DF1004A7AE4 /* AudioScrobblerClient.m in Sources */,
1755E1F90BA0D2B600CA3560 /* PlaylistLoader.m in Sources */, 1755E1F90BA0D2B600CA3560 /* PlaylistLoader.m in Sources */,
8E9A30160BA792DC0091081B /* NSFileHandle+CreateFile.m in Sources */, 8E9A30160BA792DC0091081B /* NSFileHandle+CreateFile.m in Sources */,

View File

@ -255,18 +255,7 @@
- (void)setAlbumArt:(id)data - (void)setAlbumArt:(id)data
{ {
BOOL isData = NO; if ([data isKindOfClass:[NSData class]])
Class class = [data class];
while (class)
{
if (class == [NSData class])
{
isData = YES;
break;
}
class = [class superclass];
}
if (isData)
{ {
[self setAlbumArtInternal:data]; [self setAlbumArtInternal:data];
} }

View File

@ -23,6 +23,8 @@
#import "XMlContainer.h" #import "XMlContainer.h"
#import "NSData+MD5.h"
@implementation PlaylistLoader @implementation PlaylistLoader
- (id)init - (id)init
@ -203,6 +205,8 @@ NSMutableDictionary * dictionaryWithPropertiesOfObject(id obj, NSArray * filterL
NSArray * filterList = [NSArray arrayWithObjects:@"display", @"length", @"path", @"filename", @"status", @"statusMessage", @"spam", @"stopAfter", @"shuffleIndex", @"index", @"current", @"queued", @"currentPosition", @"queuePosition", @"error", @"removed", @"URL", @"albumArt", nil]; NSArray * filterList = [NSArray arrayWithObjects:@"display", @"length", @"path", @"filename", @"status", @"statusMessage", @"spam", @"stopAfter", @"shuffleIndex", @"index", @"current", @"queued", @"currentPosition", @"queuePosition", @"error", @"removed", @"URL", @"albumArt", nil];
NSMutableDictionary * albumArtSet = [[NSMutableDictionary alloc] init];
NSMutableArray * topLevel = [[NSMutableArray alloc] init]; NSMutableArray * topLevel = [[NSMutableArray alloc] init];
for (PlaylistEntry *pe in [playlistController content]) for (PlaylistEntry *pe in [playlistController content])
@ -215,8 +219,11 @@ NSMutableDictionary * dictionaryWithPropertiesOfObject(id obj, NSArray * filterL
NSData * albumArt = [dict objectForKey:@"albumArtInternal"]; NSData * albumArt = [dict objectForKey:@"albumArtInternal"];
if (albumArt) if (albumArt)
{ {
[dict setObject:albumArt forKey:@"albumArt"];
[dict removeObjectForKey:@"albumArtInternal"]; [dict removeObjectForKey:@"albumArtInternal"];
NSString * hash = [albumArt MD5];
if (![albumArtSet objectForKey:hash])
[albumArtSet setObject:albumArt forKey:hash];
[dict setObject:hash forKey:@"albumArt"];
} }
[topLevel addObject:dict]; [topLevel addObject:dict];
@ -224,7 +231,13 @@ NSMutableDictionary * dictionaryWithPropertiesOfObject(id obj, NSArray * filterL
[dict release]; [dict release];
} }
NSData * data = [NSPropertyListSerialization dataWithPropertyList:topLevel format:NSPropertyListXMLFormat_v1_0 options:0 error:0]; NSDictionary * dictionary = [NSDictionary dictionaryWithObjectsAndKeys:albumArtSet, @"albumArt", topLevel, @"items", nil];
NSData * data = [NSPropertyListSerialization dataWithPropertyList:dictionary format:NSPropertyListXMLFormat_v1_0 options:0 error:0];
[albumArtSet release];
[topLevel release];
[fileHandle writeData:data]; [fileHandle writeData:data];

View File

@ -70,15 +70,23 @@
NSData* plistData = [contents dataUsingEncoding:NSUTF8StringEncoding]; NSData* plistData = [contents dataUsingEncoding:NSUTF8StringEncoding];
NSPropertyListFormat format; NSPropertyListFormat format;
NSArray* plist = [NSPropertyListSerialization propertyListFromData:plistData mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&error]; id plist = [NSPropertyListSerialization propertyListFromData:plistData mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&error];
if(!plist){ if(!plist){
NSLog(@"Error: %@",error); NSLog(@"Error: %@",error);
[error release]; [error release];
return nil; return nil;
} }
BOOL isArray = [plist isKindOfClass:[NSArray class]];
BOOL isDict = [plist isKindOfClass:[NSDictionary class]];
if (!isDict && !isArray) return nil;
NSArray * items = (isArray) ? (NSArray*)plist : [(NSDictionary *)plist objectForKey:@"items"];
NSDictionary *entry; NSDictionary *entry;
NSEnumerator *e = [plist objectEnumerator]; NSDictionary *albumArt = (isArray) ? nil : [(NSDictionary *)plist objectForKey:@"albumArt"];
NSEnumerator *e = [items objectEnumerator];
NSMutableArray *entries = [NSMutableArray array]; NSMutableArray *entries = [NSMutableArray array];
while ((entry = [e nextObject])) while ((entry = [e nextObject]))
@ -87,6 +95,9 @@
[preparedEntry setObject:[self urlForPath:[preparedEntry objectForKey:@"URL"] relativeTo:filename] forKey:@"URL"]; [preparedEntry setObject:[self urlForPath:[preparedEntry objectForKey:@"URL"] relativeTo:filename] forKey:@"URL"];
if (albumArt && [preparedEntry objectForKey:@"albumArt"])
[preparedEntry setObject:[albumArt objectForKey:[preparedEntry objectForKey:@"albumArt"]] forKey:@"albumArt"];
[entries addObject:[NSDictionary dictionaryWithDictionary:preparedEntry]]; [entries addObject:[NSDictionary dictionaryWithDictionary:preparedEntry]];
} }

15
Utils/NSData+MD5.h Normal file
View File

@ -0,0 +1,15 @@
//
// NSData+MD5.h
// Cog
//
// Created by Christopher Snowhill on 10/9/13.
//
//
#import <Cocoa/Cocoa.h>
@interface NSData (MD5)
- (NSString*)MD5;
@end

35
Utils/NSData+MD5.m Normal file
View File

@ -0,0 +1,35 @@
//
// NSData+MD5.m
// Cog
//
// Created by Christopher Snowhill on 10/9/13.
//
//
#import <CommonCrypto/CommonDigest.h>
#import "NSData+MD5.h"
@implementation NSData (MD5)
- (NSString*)MD5
{
// Create pointer to the string as UTF8
const void * ptr = [self bytes];
NSUInteger len = [self length];
// Create byte array of unsigned chars
unsigned char md5Buffer[CC_MD5_DIGEST_LENGTH];
// Create 16 byte MD5 hash value, store in buffer
CC_MD5(ptr, len, md5Buffer);
// Convert MD5 value in the buffer to NSString of hex values
NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
[output appendFormat:@"%02x",md5Buffer[i]];
return output;
}
@end