// // TagLibMetadataReader.m // TagLib // // Created by Vincent Spader on 2/24/07. // Copyright 2007 __MyCompanyName__. All rights reserved. // #import "TagLibMetadataReader.h" #import #import #import #import #import #import #import #import #import #import #import @implementation TagLibMetadataReader + (NSDictionary *)metadataForURL:(NSURL *)url { if (![url isFileURL]) { return [NSDictionary dictionary]; } NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; // if ( !*TagLib::ascii_encoding ) { // NSStringEncoding enc = [NSString defaultCStringEncoding]; // CFStringEncoding cfenc = CFStringConvertNSStringEncodingToEncoding(enc); // NSString *ref = (NSString *)CFStringConvertEncodingToIANACharSetName(cfenc); // UInt32 cp = CFStringConvertEncodingToWindowsCodepage(cfenc); // // // Most tags are using windows codepage, so remap OS X codepage to Windows one. // // static struct { // UInt32 from, to; // } codepage_remaps[] = { // { 10001, 932 }, // Japanese Shift-JIS // { 10002, 950 }, // Traditional Chinese // { 10003, 949 }, // Korean // { 10004, 1256 }, // Arabic // { 10005, 1255 }, // Hebrew // { 10006, 1253 }, // Greek // { 10007, 1251 }, // Cyrillic // { 10008, 936 }, // Simplified Chinese // { 10029, 1250 }, // Central European (latin2) // }; // // int i; // int max = sizeof(codepage_remaps)/sizeof(codepage_remaps[0]); // for ( i=0; iartist(); albumartist = tag->albumartist(); title = tag->title();; album = tag->album(); genre = tag->genre(); comment = tag->comment(); year = tag->year(); [dict setObject:[NSNumber numberWithInt:year] forKey:@"year"]; track = tag->track(); [dict setObject:[NSNumber numberWithInt:track] forKey:@"track"]; rgAlbumGain = tag->rgAlbumGain(); rgAlbumPeak = tag->rgAlbumPeak(); rgTrackGain = tag->rgTrackGain(); rgTrackPeak = tag->rgTrackPeak(); [dict setObject:[NSNumber numberWithFloat:rgAlbumGain] forKey:@"replayGainAlbumGain"]; [dict setObject:[NSNumber numberWithFloat:rgAlbumPeak] forKey:@"replayGainAlbumPeak"]; [dict setObject:[NSNumber numberWithFloat:rgTrackGain] forKey:@"replayGainTrackGain"]; [dict setObject:[NSNumber numberWithFloat:rgTrackPeak] forKey:@"replayGainTrackPeak"]; if (!artist.isEmpty()) [dict setObject:[NSString stringWithUTF8String:artist.toCString(true)] forKey:@"artist"]; if (!albumartist.isEmpty()) [dict setObject:[NSString stringWithUTF8String:albumartist.toCString(true)] forKey:@"albumartist"]; if (!album.isEmpty()) [dict setObject:[NSString stringWithUTF8String:album.toCString(true)] forKey:@"album"]; if (!title.isEmpty()) [dict setObject:[NSString stringWithUTF8String:title.toCString(true)] forKey:@"title"]; if (!genre.isEmpty()) [dict setObject:[NSString stringWithUTF8String:genre.toCString(true)] forKey:@"genre"]; } // Try to load the image. NSData * image = nil; // Try to load the image. // WARNING: HACK TagLib::MPEG::File *mf = dynamic_cast(f.file()); if (mf) { TagLib::ID3v2::Tag *tag = mf->ID3v2Tag(); if (tag) { TagLib::ID3v2::FrameList pictures = mf->ID3v2Tag()->frameListMap()["APIC"]; if (!pictures.isEmpty()) { TagLib::ID3v2::AttachedPictureFrame *pic = static_cast(pictures.front()); image = [NSData dataWithBytes:pic->picture().data() length:pic->picture().size()]; } } } // D-D-D-DOUBLE HACK! TagLib::MP4::File *m4f = dynamic_cast(f.file()); if (m4f) { TagLib::MP4::Tag *tag = m4f->tag(); if (tag) { auto covr = tag->item("covr"); if (covr.isValid()) { auto coverArtList = covr.toCoverArtList(); if (!coverArtList.isEmpty()) { TagLib::MP4::CoverArt coverArt = coverArtList.front(); image = [NSData dataWithBytes:coverArt.data().data() length:coverArt.data().size()]; } } } } TagLib::Ogg::Vorbis::File *vorbis = dynamic_cast(f.file()); if (vorbis) { TagLib::Ogg::XiphComment *tag = vorbis->tag(); if (tag) { auto list = tag->pictureList(); if (!list.isEmpty()) { // Just get the first image for now. TagLib::FLAC::Picture* coverArt = list.front(); if (coverArt) { // Look into TagLib::FLAC::Picture::Type for type description. NSLog(@"Loading image metadata from Ogg Vorbis, type = %d", static_cast(coverArt->type())); image = [NSData dataWithBytes:coverArt->data().data() length:coverArt->data().size()]; } } } } TagLib::FLAC::File *flac = dynamic_cast(f.file()); if (flac) { auto list = flac->pictureList(); if (!list.isEmpty()) { // Just get the first image for now. TagLib::FLAC::Picture* coverArt = list.front(); if (coverArt) { // Look into TagLib::FLAC::Picture::Type for type description. NSLog(@"Loading image metadata from FLAC, type = %d", static_cast(coverArt->type())); image = [NSData dataWithBytes:coverArt->data().data() length:coverArt->data().size()]; } } } if (nil == image) { // Try to load image from external file NSString *path = [[url path] stringByDeletingLastPathComponent]; // Gather list of candidate image files NSArray *fileNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil]; NSArray *types = @[@"jpg", @"jpeg", @"png"]; NSArray *imageFileNames = [fileNames pathsMatchingExtensions:types]; for (NSString *fileName in imageFileNames) { if ([TagLibMetadataReader isCoverFile:fileName]) { image = [NSData dataWithContentsOfFile:[path stringByAppendingPathComponent:fileName]]; break; } } } if (nil != image) { [dict setObject:image forKey:@"albumArt"]; } } return dict; } + (BOOL)isCoverFile:(NSString *)fileName { for (NSString *coverFileName in [TagLibMetadataReader coverNames]) { if ([[[[fileName lastPathComponent] stringByDeletingPathExtension] lowercaseString] hasSuffix:coverFileName]) { return true; } } return false; } + (NSArray *)coverNames { return [NSArray arrayWithObjects:@"cover", @"folder", @"album", @"front", nil]; } + (NSArray *)fileTypes { //May be a way to get a list of supported formats return [NSArray arrayWithObjects:@"ape", @"asf", @"wma", @"ogg", @"opus", @"mpc", @"flac", @"m4a", @"mp3", @"tak", @"ac3", @"apl", @"dts", @"dtshd", @"tta", @"wav", @"aif", @"aiff", @"wv", @"wvp", nil]; } + (NSArray *)mimeTypes { return [NSArray arrayWithObjects:@"audio/x-ape", @"audio/x-ms-wma", @"application/ogg", @"application/x-ogg", @"audio/x-vorbis+ogg", @"audio/x-musepack", @"audio/x-flac", @"audio/x-m4a", @"audio/mpeg", @"audio/x-mp3", @"audio/x-tak", @"audio/x-ac3", @"audio/x-apl", @"audio/x-dts", @"audio/x-dtshd", @"audio/x-tta", @"audio/wav", @"audio/aiff", @"audio/x-wavpack", nil]; } + (float)priority { return 1.0f; } @end