diff --git a/Cog.xcodeproj/project.pbxproj b/Cog.xcodeproj/project.pbxproj index fc52f03b9..d29da98e7 100644 --- a/Cog.xcodeproj/project.pbxproj +++ b/Cog.xcodeproj/project.pbxproj @@ -144,6 +144,8 @@ 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 */; }; 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 */; }; 8360EF6D17F92E56005208A4 /* HighlyComplete.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8360EF0517F92B24005208A4 /* HighlyComplete.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 = ""; }; 56DB08530D67185300453B6A /* NSArray+CogSort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSArray+CogSort.h"; path = "Spotlight/NSArray+CogSort.h"; sourceTree = ""; }; 56DB08540D67185300453B6A /* NSArray+CogSort.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSArray+CogSort.m"; path = "Spotlight/NSArray+CogSort.m"; sourceTree = ""; }; + 8355D6B4180612F300D05687 /* NSData+MD5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+MD5.h"; sourceTree = ""; }; + 8355D6B5180612F300D05687 /* NSData+MD5.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+MD5.m"; sourceTree = ""; }; + 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 = ""; }; 8360EF0017F92B23005208A4 /* HighlyComplete.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = HighlyComplete.xcodeproj; path = Plugins/HighlyComplete/HighlyComplete.xcodeproj; sourceTree = ""; }; 8375B05117FFEA400092A79F /* Opus.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Opus.xcodeproj; path = Plugins/Opus/Opus.xcodeproj; sourceTree = ""; }; @@ -789,6 +794,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 8355D6B8180613FB00D05687 /* Security.framework in Frameworks */, 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, 8E6889240AAA403C00AD3950 /* Carbon.framework in Frameworks */, 17BB5CED0B8A86010009ACB1 /* AudioToolbox.framework in Frameworks */, @@ -956,6 +962,8 @@ 07E18DF20D62B38400BB0E11 /* NSArray+ShuffleUtils.m */, 17FAEBAA0F662985007C8707 /* ToolTipTextField.h */, 17FAEBAB0F662985007C8707 /* ToolTipTextField.m */, + 8355D6B4180612F300D05687 /* NSData+MD5.h */, + 8355D6B5180612F300D05687 /* NSData+MD5.m */, ); path = Utils; sourceTree = ""; @@ -1307,6 +1315,7 @@ 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( + 8355D6B7180613FB00D05687 /* Security.framework */, 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, ); @@ -1900,6 +1909,7 @@ 1770429C0B8BC53600B86321 /* AppController.m in Sources */, 1770429E0B8BC53600B86321 /* PlaybackController.m in Sources */, 1766C6930B911DF1004A7AE4 /* AudioScrobbler.m in Sources */, + 8355D6B6180612F300D05687 /* NSData+MD5.m in Sources */, 1766C6950B911DF1004A7AE4 /* AudioScrobblerClient.m in Sources */, 1755E1F90BA0D2B600CA3560 /* PlaylistLoader.m in Sources */, 8E9A30160BA792DC0091081B /* NSFileHandle+CreateFile.m in Sources */, diff --git a/Playlist/PlaylistEntry.m b/Playlist/PlaylistEntry.m index eb92e7580..dff80cb23 100644 --- a/Playlist/PlaylistEntry.m +++ b/Playlist/PlaylistEntry.m @@ -255,18 +255,7 @@ - (void)setAlbumArt:(id)data { - BOOL isData = NO; - Class class = [data class]; - while (class) - { - if (class == [NSData class]) - { - isData = YES; - break; - } - class = [class superclass]; - } - if (isData) + if ([data isKindOfClass:[NSData class]]) { [self setAlbumArtInternal:data]; } diff --git a/Playlist/PlaylistLoader.m b/Playlist/PlaylistLoader.m index a3892e3ee..30cf620b7 100755 --- a/Playlist/PlaylistLoader.m +++ b/Playlist/PlaylistLoader.m @@ -23,6 +23,8 @@ #import "XMlContainer.h" +#import "NSData+MD5.h" + @implementation PlaylistLoader - (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]; + NSMutableDictionary * albumArtSet = [[NSMutableDictionary alloc] init]; + NSMutableArray * topLevel = [[NSMutableArray alloc] init]; for (PlaylistEntry *pe in [playlistController content]) @@ -215,8 +219,11 @@ NSMutableDictionary * dictionaryWithPropertiesOfObject(id obj, NSArray * filterL NSData * albumArt = [dict objectForKey:@"albumArtInternal"]; if (albumArt) { - [dict setObject:albumArt forKey:@"albumArt"]; [dict removeObjectForKey:@"albumArtInternal"]; + NSString * hash = [albumArt MD5]; + if (![albumArtSet objectForKey:hash]) + [albumArtSet setObject:albumArt forKey:hash]; + [dict setObject:hash forKey:@"albumArt"]; } [topLevel addObject:dict]; @@ -224,7 +231,13 @@ NSMutableDictionary * dictionaryWithPropertiesOfObject(id obj, NSArray * filterL [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]; diff --git a/Playlist/XmlContainer.m b/Playlist/XmlContainer.m index 91a2ec619..8517798fd 100644 --- a/Playlist/XmlContainer.m +++ b/Playlist/XmlContainer.m @@ -70,15 +70,23 @@ NSData* plistData = [contents dataUsingEncoding:NSUTF8StringEncoding]; 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){ NSLog(@"Error: %@",error); [error release]; 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; - NSEnumerator *e = [plist objectEnumerator]; + NSDictionary *albumArt = (isArray) ? nil : [(NSDictionary *)plist objectForKey:@"albumArt"]; + NSEnumerator *e = [items objectEnumerator]; NSMutableArray *entries = [NSMutableArray array]; while ((entry = [e nextObject])) @@ -87,6 +95,9 @@ [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]]; } diff --git a/Utils/NSData+MD5.h b/Utils/NSData+MD5.h new file mode 100644 index 000000000..99f3052e4 --- /dev/null +++ b/Utils/NSData+MD5.h @@ -0,0 +1,15 @@ +// +// NSData+MD5.h +// Cog +// +// Created by Christopher Snowhill on 10/9/13. +// +// + +#import + +@interface NSData (MD5) + +- (NSString*)MD5; + +@end diff --git a/Utils/NSData+MD5.m b/Utils/NSData+MD5.m new file mode 100644 index 000000000..9179aae2f --- /dev/null +++ b/Utils/NSData+MD5.m @@ -0,0 +1,35 @@ +// +// NSData+MD5.m +// Cog +// +// Created by Christopher Snowhill on 10/9/13. +// +// + +#import + +#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