Now storing all album art internally as its original format and synthesizing NSImage objects on demand
This commit is contained in:
parent
a63e27f95c
commit
555ccc9e87
6 changed files with 78 additions and 90 deletions
|
@ -59,7 +59,7 @@
|
||||||
[GrowlApplicationBridge notifyWithTitle:[pe title]
|
[GrowlApplicationBridge notifyWithTitle:[pe title]
|
||||||
description:[pe artist]
|
description:[pe artist]
|
||||||
notificationName:@"Stream Changed"
|
notificationName:@"Stream Changed"
|
||||||
iconData:[[pe albumArt] TIFFRepresentation]
|
iconData:[pe albumArtInternal]
|
||||||
priority:0
|
priority:0
|
||||||
isSticky:NO
|
isSticky:NO
|
||||||
clickContext:nil];
|
clickContext:nil];
|
||||||
|
|
|
@ -31,7 +31,8 @@
|
||||||
NSString *genre;
|
NSString *genre;
|
||||||
NSNumber *year;
|
NSNumber *year;
|
||||||
NSNumber *track;
|
NSNumber *track;
|
||||||
NSImage *albumArt;
|
|
||||||
|
NSData *albumArtInternal;
|
||||||
|
|
||||||
float replayGainAlbumGain;
|
float replayGainAlbumGain;
|
||||||
float replayGainAlbumPeak;
|
float replayGainAlbumPeak;
|
||||||
|
@ -63,6 +64,7 @@
|
||||||
+ (NSSet *)keyPathsForValuesAffectingStatus;
|
+ (NSSet *)keyPathsForValuesAffectingStatus;
|
||||||
+ (NSSet *)keyPathsForValuesAffectingStatusMessage;
|
+ (NSSet *)keyPathsForValuesAffectingStatusMessage;
|
||||||
+ (NSSet *)keyPathsForValuesAffectingSpam;
|
+ (NSSet *)keyPathsForValuesAffectingSpam;
|
||||||
|
+ (NSSet *)keyPathsForValuesAffectingAlbumArt;
|
||||||
|
|
||||||
@property(readonly) NSString *display;
|
@property(readonly) NSString *display;
|
||||||
@property(retain, readonly) NSNumber *length;
|
@property(retain, readonly) NSNumber *length;
|
||||||
|
@ -96,7 +98,9 @@
|
||||||
@property(retain) NSString *genre;
|
@property(retain) NSString *genre;
|
||||||
@property(retain) NSNumber *year;
|
@property(retain) NSNumber *year;
|
||||||
@property(retain) NSNumber *track;
|
@property(retain) NSNumber *track;
|
||||||
@property(retain) NSImage *albumArt;
|
|
||||||
|
@property(retain, readonly) NSImage *albumArt;
|
||||||
|
@property(retain) NSData *albumArtInternal;
|
||||||
|
|
||||||
@property long long totalFrames;
|
@property long long totalFrames;
|
||||||
@property int bitrate;
|
@property int bitrate;
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
@synthesize genre;
|
@synthesize genre;
|
||||||
@synthesize year;
|
@synthesize year;
|
||||||
@synthesize track;
|
@synthesize track;
|
||||||
@synthesize albumArt;
|
|
||||||
|
|
||||||
@synthesize totalFrames;
|
@synthesize totalFrames;
|
||||||
@synthesize bitrate;
|
@synthesize bitrate;
|
||||||
|
@ -93,6 +92,11 @@
|
||||||
return [NSSet setWithObjects:@"artist", @"title", @"album", @"track", @"totalFrames", @"currentPosition", @"bitrate", nil];
|
return [NSSet setWithObjects:@"artist", @"title", @"album", @"track", @"totalFrames", @"currentPosition", @"bitrate", nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (NSSet *)keyPathsForValuesAffectingAlbumArt
|
||||||
|
{
|
||||||
|
return [NSSet setWithObject:@"albumArtInternal"];
|
||||||
|
}
|
||||||
|
|
||||||
- (NSString *)description
|
- (NSString *)description
|
||||||
{
|
{
|
||||||
return [NSString stringWithFormat:@"PlaylistEntry %i:(%@)", self.index, self.URL];
|
return [NSString stringWithFormat:@"PlaylistEntry %i:(%@)", self.index, self.URL];
|
||||||
|
@ -122,7 +126,7 @@
|
||||||
self.genre = nil;
|
self.genre = nil;
|
||||||
self.year = nil;
|
self.year = nil;
|
||||||
self.track = nil;
|
self.track = nil;
|
||||||
self.albumArt = nil;
|
self.albumArtInternal = nil;
|
||||||
|
|
||||||
self.endian = nil;
|
self.endian = nil;
|
||||||
|
|
||||||
|
@ -230,6 +234,44 @@
|
||||||
return [elements componentsJoinedByString:@""];
|
return [elements componentsJoinedByString:@""];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@synthesize albumArtInternal;
|
||||||
|
|
||||||
|
@dynamic albumArt;
|
||||||
|
- (NSImage *)albumArt
|
||||||
|
{
|
||||||
|
if (!albumArtInternal) return nil;
|
||||||
|
|
||||||
|
NSString *imageCacheTag = [NSString stringWithFormat:@"%@-%@-%@-%@", album, artist, genre, year];
|
||||||
|
NSImage *image = [NSImage imageNamed:imageCacheTag];
|
||||||
|
|
||||||
|
if (image == nil)
|
||||||
|
{
|
||||||
|
image = [[[NSImage alloc] initWithData:albumArtInternal] autorelease];
|
||||||
|
[image setName:imageCacheTag];
|
||||||
|
}
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (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)
|
||||||
|
{
|
||||||
|
[self setAlbumArtInternal:data];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@dynamic length;
|
@dynamic length;
|
||||||
- (NSNumber *)length
|
- (NSNumber *)length
|
||||||
{
|
{
|
||||||
|
|
|
@ -201,7 +201,7 @@ NSMutableDictionary * dictionaryWithPropertiesOfObject(id obj, NSArray * filterL
|
||||||
}
|
}
|
||||||
[fileHandle truncateFileAtOffset:0];
|
[fileHandle truncateFileAtOffset:0];
|
||||||
|
|
||||||
NSArray * filterList = [NSArray arrayWithObjects:@"display", @"length", @"path", @"filename", @"status", @"statusMessage", @"spam", @"stopAfter", @"shuffleIndex", @"index", @"current", @"queued", @"currentPosition", @"queuePosition", @"error", @"removed", @"URL", nil];
|
NSArray * filterList = [NSArray arrayWithObjects:@"display", @"length", @"path", @"filename", @"status", @"statusMessage", @"spam", @"stopAfter", @"shuffleIndex", @"index", @"current", @"queued", @"currentPosition", @"queuePosition", @"error", @"removed", @"URL", @"albumArt", nil];
|
||||||
|
|
||||||
NSMutableArray * topLevel = [[NSMutableArray alloc] init];
|
NSMutableArray * topLevel = [[NSMutableArray alloc] init];
|
||||||
|
|
||||||
|
@ -212,29 +212,11 @@ NSMutableDictionary * dictionaryWithPropertiesOfObject(id obj, NSArray * filterL
|
||||||
NSString *path = [self relativePathFrom:filename toURL:[pe URL]];
|
NSString *path = [self relativePathFrom:filename toURL:[pe URL]];
|
||||||
|
|
||||||
[dict setObject:path forKey:@"URL"];
|
[dict setObject:path forKey:@"URL"];
|
||||||
|
NSData * albumArt = [dict objectForKey:@"albumArtInternal"];
|
||||||
NSImage * image = [dict objectForKey:@"albumArt"];
|
if (albumArt)
|
||||||
if (image)
|
|
||||||
{
|
{
|
||||||
NSBitmapImageRep* requiredBitmap = nil;
|
[dict setObject:albumArt forKey:@"albumArt"];
|
||||||
BOOL setValue =NO;
|
[dict removeObjectForKey:@"albumArtInternal"];
|
||||||
|
|
||||||
for(NSBitmapImageRep* imagerep in [image representations])
|
|
||||||
{
|
|
||||||
if ([imagerep isKindOfClass:[NSBitmapImageRep class]])
|
|
||||||
{
|
|
||||||
if (!setValue) {
|
|
||||||
requiredBitmap = imagerep;
|
|
||||||
setValue =YES;
|
|
||||||
}
|
|
||||||
if ([requiredBitmap pixelsHigh]<[imagerep pixelsHigh]) {
|
|
||||||
requiredBitmap = imagerep;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[dict setObject:[requiredBitmap representationUsingType:NSJPEG2000FileType properties:nil] forKey:@"albumArt"];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[topLevel addObject:dict];
|
[topLevel addObject:dict];
|
||||||
|
|
|
@ -87,10 +87,6 @@
|
||||||
|
|
||||||
[preparedEntry setObject:[self urlForPath:[preparedEntry objectForKey:@"URL"] relativeTo:filename] forKey:@"URL"];
|
[preparedEntry setObject:[self urlForPath:[preparedEntry objectForKey:@"URL"] relativeTo:filename] forKey:@"URL"];
|
||||||
|
|
||||||
NSData * data = [preparedEntry objectForKey:@"albumArt"];
|
|
||||||
if (data)
|
|
||||||
[preparedEntry setObject:[[[NSImage alloc] initWithData:data] autorelease] forKey:@"albumArt"];
|
|
||||||
|
|
||||||
[entries addObject:[NSDictionary dictionaryWithDictionary:preparedEntry]];
|
[entries addObject:[NSDictionary dictionaryWithDictionary:preparedEntry]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,77 +69,41 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *imageCacheTag = [NSString stringWithFormat:@"%@-%@-%@-%@", [dict objectForKey:@"album"], [dict objectForKey:@"artist"], [dict objectForKey:@"genre"], [dict objectForKey:@"year"]];
|
NSString *imageCacheTag = [NSString stringWithFormat:@"%@-%@-%@-%@", [dict objectForKey:@"album"], [dict objectForKey:@"artist"], [dict objectForKey:@"genre"], [dict objectForKey:@"year"]];
|
||||||
NSImage *image = [NSImage imageNamed:imageCacheTag];
|
|
||||||
|
|
||||||
if (nil == image) {
|
// Try to load the image.
|
||||||
// Try to load the image.
|
NSData * image = nil;
|
||||||
|
|
||||||
// WARNING: HACK
|
// WARNING: HACK
|
||||||
TagLib::MPEG::File *mf = dynamic_cast<TagLib::MPEG::File *>(f.file());
|
TagLib::MPEG::File *mf = dynamic_cast<TagLib::MPEG::File *>(f.file());
|
||||||
if (mf) {
|
if (mf) {
|
||||||
TagLib::ID3v2::Tag *tag = mf->ID3v2Tag();
|
TagLib::ID3v2::Tag *tag = mf->ID3v2Tag();
|
||||||
if (tag) {
|
if (tag) {
|
||||||
TagLib::ID3v2::FrameList pictures = mf->ID3v2Tag()->frameListMap()["APIC"];
|
TagLib::ID3v2::FrameList pictures = mf->ID3v2Tag()->frameListMap()["APIC"];
|
||||||
if (!pictures.isEmpty()) {
|
if (!pictures.isEmpty()) {
|
||||||
TagLib::ID3v2::AttachedPictureFrame *pic = static_cast<TagLib::ID3v2::AttachedPictureFrame *>(pictures.front());
|
TagLib::ID3v2::AttachedPictureFrame *pic = static_cast<TagLib::ID3v2::AttachedPictureFrame *>(pictures.front());
|
||||||
|
|
||||||
NSData *data = [[NSData alloc] initWithBytes:pic->picture().data() length:pic->picture().size()];
|
image = [NSData dataWithBytes:pic->picture().data() length:pic->picture().size()];
|
||||||
image = [[[NSImage alloc] initWithData:data] autorelease];
|
|
||||||
[data release];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nil != image) {
|
|
||||||
[image setName:imageCacheTag];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nil == image) {
|
if (nil == image) {
|
||||||
// Try to load image from external file
|
// Try to load image from external file
|
||||||
|
|
||||||
// If we find an appropriately-named image in this directory, it will
|
|
||||||
// be tagged with the first image cache tag. Subsequent directory entries
|
|
||||||
// may have a different tag, but an image search would result in the same
|
|
||||||
// artwork.
|
|
||||||
|
|
||||||
static NSString *lastImagePath = nil;
|
|
||||||
static NSString *lastCacheTag = nil;
|
|
||||||
|
|
||||||
NSString *path = [[url path] stringByDeletingLastPathComponent];
|
NSString *path = [[url path] stringByDeletingLastPathComponent];
|
||||||
|
|
||||||
if ([path isEqualToString:lastImagePath]) {
|
|
||||||
// Use whatever image may have been stored with the initial tag for the path
|
|
||||||
// (might be nil but no point scanning again)
|
|
||||||
|
|
||||||
image = [NSImage imageNamed:lastCacheTag];
|
|
||||||
} else {
|
|
||||||
// Book-keeping...
|
|
||||||
|
|
||||||
if (nil != lastImagePath)
|
|
||||||
[lastImagePath release];
|
|
||||||
|
|
||||||
lastImagePath = [path retain];
|
|
||||||
|
|
||||||
if (nil != lastCacheTag)
|
|
||||||
[lastCacheTag release];
|
|
||||||
|
|
||||||
lastCacheTag = [imageCacheTag retain];
|
|
||||||
|
|
||||||
// Gather list of candidate image files
|
// Gather list of candidate image files
|
||||||
|
|
||||||
NSArray *fileNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
|
NSArray *fileNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
|
||||||
NSArray *imageFileNames = [fileNames pathsMatchingExtensions:[NSImage imageFileTypes]];
|
NSArray *imageFileNames = [fileNames pathsMatchingExtensions:[NSImage imageFileTypes]];
|
||||||
|
|
||||||
NSEnumerator *imageEnumerator = [imageFileNames objectEnumerator];
|
NSEnumerator *imageEnumerator = [imageFileNames objectEnumerator];
|
||||||
NSString *fileName;
|
NSString *fileName;
|
||||||
|
|
||||||
while (fileName = [imageEnumerator nextObject]) {
|
while (fileName = [imageEnumerator nextObject]) {
|
||||||
if ([TagLibMetadataReader isCoverFile:fileName]) {
|
if ([TagLibMetadataReader isCoverFile:fileName]) {
|
||||||
image = [[[NSImage alloc] initByReferencingFile:[path stringByAppendingPathComponent:fileName]] autorelease];
|
image = [NSData dataWithContentsOfFile:[path stringByAppendingPathComponent:fileName]];
|
||||||
[image setName:imageCacheTag];
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue