From 19ebb5b0aea162553ab77b61abf03eeb0f0e0823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcus=20M=C3=BCller?= Date: Tue, 22 May 2007 14:20:59 +0000 Subject: [PATCH] Abstracted/Refactored much of the inner workings - it's possible now to also expose other libraries (iPods!) via the same interface without much effort (I guess). --- Info.plist | 2 +- README | 11 ++ Resources/English.lproj/InfoPlist.strings | 4 +- Version | 2 +- iTunesFS.xcodeproj/project.pbxproj | 12 ++ iTunesFileSystem.m | 18 +- iTunesLibrary.h | 13 +- iTunesLibrary.m | 201 ++++++---------------- iTunesPlaylist.h | 28 +++ iTunesPlaylist.m | 97 +++++++++++ iTunesTrack.h | 25 +++ iTunesTrack.m | 122 +++++++++++++ 12 files changed, 362 insertions(+), 173 deletions(-) create mode 100644 iTunesPlaylist.h create mode 100644 iTunesPlaylist.m create mode 100644 iTunesTrack.h create mode 100644 iTunesTrack.m diff --git a/Info.plist b/Info.plist index 77e954a..b61c4f9 100644 --- a/Info.plist +++ b/Info.plist @@ -17,7 +17,7 @@ CFBundleSignature ???? CFBundleVersion - 1.0.1 + 1.0.2 FUSEFileSystemClass iTunesFileSystem NSMainNibFile diff --git a/README b/README index 7e94248..b8481a8 100644 --- a/README +++ b/README @@ -18,6 +18,17 @@ DetailedTrackNames | BOOL | NO | If YES, use very detailed information track number, etc.) +TODO / IDEAS +============ + +- Expose Library and iPods at root mount point + - need to be able to identify (easy) and parse (more difficult, but already + did that for PodLifter) iPod databases + - abstract iTunesLibrary (superclass: Library) and add iPodLibrary +- Refresh libraries upon changes (need watchdog for this) + - Listen for attached/detached iPods + + References ========== diff --git a/Resources/English.lproj/InfoPlist.strings b/Resources/English.lproj/InfoPlist.strings index f0eacc8..e322d4f 100644 --- a/Resources/English.lproj/InfoPlist.strings +++ b/Resources/English.lproj/InfoPlist.strings @@ -1,6 +1,6 @@ /* Localized versions of Info.plist keys */ CFBundleName = "iTunesFS"; -CFBundleShortVersionString = "1.0.1"; -CFBundleGetInfoString = "iTunesFS version 1.0.1, Copyright 2007 Mulle kybernetiK."; +CFBundleShortVersionString = "1.0.2"; +CFBundleGetInfoString = "iTunesFS version 1.0.2, Copyright 2007 Mulle kybernetiK."; NSHumanReadableCopyright = "Copyright 2007 Mulle kybernetiK."; diff --git a/Version b/Version index 49ef4b0..becb59f 100644 --- a/Version +++ b/Version @@ -5,4 +5,4 @@ MAJOR_VERSION=1 MINOR_VERSION=0 -SUBMINOR_VERSION=1 +SUBMINOR_VERSION=2 diff --git a/iTunesFS.xcodeproj/project.pbxproj b/iTunesFS.xcodeproj/project.pbxproj index 38e5ed0..ec7f875 100644 --- a/iTunesFS.xcodeproj/project.pbxproj +++ b/iTunesFS.xcodeproj/project.pbxproj @@ -18,6 +18,8 @@ 7F74EF2D0B4C1BEC00CFA0C0 /* iTunesFileSystem.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F74EF2C0B4C1BEC00CFA0C0 /* iTunesFileSystem.m */; }; 7FEAC1D10B446B70008EF420 /* FUSEFileSystem.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FEAC1C50B446B70008EF420 /* FUSEFileSystem.m */; }; 7FEAC1D30B446B70008EF420 /* FUSEMain.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FEAC1C80B446B70008EF420 /* FUSEMain.m */; }; + AD15A2190C03208500345C9E /* iTunesPlaylist.m in Sources */ = {isa = PBXBuildFile; fileRef = AD15A2180C03208500345C9E /* iTunesPlaylist.m */; }; + AD15A22C0C03248C00345C9E /* iTunesTrack.m in Sources */ = {isa = PBXBuildFile; fileRef = AD15A22B0C03248C00345C9E /* iTunesTrack.m */; }; AD37A2040C01C58000DF1291 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = AD37A2030C01C58000DF1291 /* MainMenu.nib */; }; AD37A2970C01C87E00DF1291 /* iTunesLibrary.m in Sources */ = {isa = PBXBuildFile; fileRef = AD37A2960C01C87E00DF1291 /* iTunesLibrary.m */; }; ADBDA9200C02CF48004CF795 /* Version in Resources */ = {isa = PBXBuildFile; fileRef = ADBDA91F0C02CF48004CF795 /* Version */; }; @@ -47,6 +49,10 @@ 7FEAC1C40B446B70008EF420 /* FUSEFileSystem.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = FUSEFileSystem.h; sourceTree = ""; }; 7FEAC1C50B446B70008EF420 /* FUSEFileSystem.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = FUSEFileSystem.m; sourceTree = ""; }; 7FEAC1C80B446B70008EF420 /* FUSEMain.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = FUSEMain.m; sourceTree = ""; }; + AD15A2170C03208500345C9E /* iTunesPlaylist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iTunesPlaylist.h; sourceTree = ""; }; + AD15A2180C03208500345C9E /* iTunesPlaylist.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = iTunesPlaylist.m; sourceTree = ""; }; + AD15A22A0C03248C00345C9E /* iTunesTrack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iTunesTrack.h; sourceTree = ""; }; + AD15A22B0C03248C00345C9E /* iTunesTrack.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = iTunesTrack.m; sourceTree = ""; }; AD37A1FB0C01C57400DF1291 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MainMenu.nib; sourceTree = ""; }; AD37A2950C01C87E00DF1291 /* iTunesLibrary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iTunesLibrary.h; sourceTree = ""; }; AD37A2960C01C87E00DF1291 /* iTunesLibrary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = iTunesLibrary.m; sourceTree = ""; }; @@ -107,6 +113,10 @@ 7F74EF2C0B4C1BEC00CFA0C0 /* iTunesFileSystem.m */, AD37A2950C01C87E00DF1291 /* iTunesLibrary.h */, AD37A2960C01C87E00DF1291 /* iTunesLibrary.m */, + AD15A2170C03208500345C9E /* iTunesPlaylist.h */, + AD15A2180C03208500345C9E /* iTunesPlaylist.m */, + AD15A22A0C03248C00345C9E /* iTunesTrack.h */, + AD15A22B0C03248C00345C9E /* iTunesTrack.m */, ADBDABA70C02FF10004CF795 /* NSString+Extensions.h */, ADBDABA80C02FF10004CF795 /* NSString+Extensions.m */, ); @@ -271,6 +281,8 @@ 7F3627720B8521EE0020679E /* NSString+CarbonFSRefCreation.m in Sources */, AD37A2970C01C87E00DF1291 /* iTunesLibrary.m in Sources */, ADBDABA90C02FF10004CF795 /* NSString+Extensions.m in Sources */, + AD15A2190C03208500345C9E /* iTunesPlaylist.m in Sources */, + AD15A22C0C03248C00345C9E /* iTunesTrack.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/iTunesFileSystem.m b/iTunesFileSystem.m index a1db488..aed7037 100644 --- a/iTunesFileSystem.m +++ b/iTunesFileSystem.m @@ -91,35 +91,36 @@ - (BOOL)fileExistsAtPath:(NSString *)path isDirectory:(BOOL *)isDirectory { else if (count == 2) { /* playlist */ return [[self->lib playlistNames] containsObject:[components lastObject]]; } - return [self->lib isValidTrackName:[components objectAtIndex:2]]; + return [self->lib isValidTrackName:[components objectAtIndex:2] + inPlaylistNamed:[components objectAtIndex:1]]; } - (NSDictionary *)fileAttributesAtPath:(NSString *)_path { NSArray *components; unsigned count; - NSString *plName, *name, *trackID; + NSString *plName, *name; components = [_path pathComponents]; count = [components count]; if (count < 3) return [super fileAttributesAtPath:_path]; plName = [components objectAtIndex:1]; name = [components lastObject]; - trackID = [self->lib trackIDForPrettyTrackName:name inPlaylistNamed:plName]; - return [self->lib fileAttributesForTrackWithID:trackID]; + return [self->lib fileAttributesForTrackWithPrettyName:name + inPlaylistNamed:plName]; } - (NSData *)contentsAtPath:(NSString *)_path { NSArray *components; unsigned count; - NSString *plName, *name, *trackID; + NSString *plName, *name; components = [_path pathComponents]; count = [components count]; if (count < 3) return nil; plName = [components objectAtIndex:1]; name = [components lastObject]; - trackID = [self->lib trackIDForPrettyTrackName:name inPlaylistNamed:plName]; - return [self->lib dataForTrackWithID:trackID]; + return [self->lib fileContentForTrackWithPrettyName:name + inPlaylistNamed:plName]; } /* optional */ @@ -135,8 +136,7 @@ - (BOOL)usesResourceForks { } - (NSString *)iconFileForPath:(NSString *)_path { - if ([_path isEqualToString:@"/"]) - return fsIconPath; + if ([_path isEqualToString:@"/"]) return fsIconPath; return nil; } diff --git a/iTunesLibrary.h b/iTunesLibrary.h index 7052d4e..0e750d7 100644 --- a/iTunesLibrary.h +++ b/iTunesLibrary.h @@ -37,24 +37,23 @@ @interface iTunesLibrary : NSObject { - NSDictionary *lib; - NSArray *playlists; // retained by lib! - NSDictionary *tracks; // retained by lib! NSMutableDictionary *plMap; } - (void)reload; - (NSString *)libraryPath; + - (NSArray *)playlistNames; - (NSArray *)trackNamesForPlaylistNamed:(NSString *)_plName; -- (BOOL)isValidTrackName:(NSString *)_ptn; -- (NSString *)trackIDForPrettyTrackName:(NSString *)_ptn +- (BOOL)isValidTrackName:(NSString *)_ptn inPlaylistNamed:(NSString *)_plName; + +- (NSData *)fileContentForTrackWithPrettyName:(NSString *)_ptn inPlaylistNamed:(NSString *)_plName; -- (NSData *)dataForTrackWithID:(NSString *)_trackID; -- (NSDictionary *)fileAttributesForTrackWithID:(NSString *)_trackID; +- (NSDictionary *)fileAttributesForTrackWithPrettyName:(NSString *)_ptn + inPlaylistNamed:(NSString *)_plName; @end /* iTunesLibrary */ diff --git a/iTunesLibrary.m b/iTunesLibrary.m index e185fc3..3bf10ff 100644 --- a/iTunesLibrary.m +++ b/iTunesLibrary.m @@ -33,10 +33,12 @@ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF #import "common.h" #import "iTunesLibrary.h" #import "NSString+Extensions.h" +#import "iTunesPlaylist.h" +#import "iTunesTrack.h" @interface iTunesLibrary (Private) -- (NSString *)prettyTrackNameForTrackWithID:(NSString *)_trackID - index:(unsigned)_idx; +- (iTunesTrack *)trackWithPrettyName:(NSString *)_ptn + inPlaylistNamed:(NSString *)_plName; @end @implementation iTunesLibrary @@ -58,18 +60,19 @@ + (void)initialize { copy]; } detailedNames = [ud boolForKey:@"DetailedTrackNames"]; + [iTunesTrack setUseDetailedInformationInNames:detailedNames]; } - (id)init { self = [super init]; if (self) { + self->plMap = [[NSMutableDictionary alloc] initWithCapacity:128]; [self reload]; } return self; } - (void)dealloc { - [self->lib release]; [self->plMap release]; [super dealloc]; } @@ -77,36 +80,37 @@ - (void)dealloc { /* setup */ - (void)reload { - NSData *plist; - NSMutableDictionary *map; - unsigned i, count; - + NSData *plist; + NSDictionary *lib; + NSArray *playlists; + NSDictionary *tracks; + unsigned i, count; + + [self->plMap removeAllObjects]; plist = [NSData dataWithContentsOfFile:[self libraryPath]]; NSAssert1(plist != nil, @"Couldn't read contents of %@!", [self libraryPath]); - self->lib = [[NSPropertyListSerialization propertyListFromData:plist - mutabilityOption:NSPropertyListImmutable - format:NULL - errorDescription:NULL] retain]; - NSAssert1(self->lib != nil, @"Couldn't parse contents of %@ - wrong format?!", - [self libraryPath]); + lib = [NSPropertyListSerialization propertyListFromData:plist + mutabilityOption:NSPropertyListImmutable + format:NULL + errorDescription:NULL]; + NSAssert1(lib != nil, @"Couldn't parse contents of %@ - wrong format?!", + [self libraryPath]); - self->playlists = [self->lib objectForKey:@"Playlists"]; - self->tracks = [self->lib objectForKey:@"Tracks"]; - [self->plMap release]; - - count = [self->playlists count]; - map = [[NSMutableDictionary alloc] initWithCapacity:count]; + playlists = [lib objectForKey:@"Playlists"]; + tracks = [lib objectForKey:@"Tracks"]; + count = [playlists count]; for (i = 0; i < count; i++) { - NSDictionary *list; - NSString *name; - - list = [self->playlists objectAtIndex:i]; - name = [list objectForKey:@"Name"]; - [map setObject:list forKey:[name properlyEscapedFSRepresentation]]; + NSDictionary *plRep; + iTunesPlaylist *pl; + + plRep = [playlists objectAtIndex:i]; + pl = [[iTunesPlaylist alloc] initWithITunesRepresentation:plRep + tracks:tracks]; + [self->plMap setObject:pl forKey:[pl name]]; + [pl release]; } - self->plMap = map; } /* accessors */ @@ -120,84 +124,10 @@ - (NSArray *)playlistNames { } - (NSArray *)trackNamesForPlaylistNamed:(NSString *)_plName { - NSDictionary *list; - NSArray *items; - NSMutableArray *names; - unsigned i, count; - - list = [self->plMap objectForKey:_plName]; - if (!list) return nil; - - items = [list objectForKey:@"Playlist Items"]; - count = [items count]; - names = [[NSMutableArray alloc] initWithCapacity:count]; - for (i = 0; i < count; i++) { - NSDictionary *item; - id trackID; - NSString *name; - - item = [items objectAtIndex:i]; - trackID = [[item objectForKey:@"Track ID"] description]; - name = [self prettyTrackNameForTrackWithID:trackID index:i]; - [names addObject:name]; - } - return [names autorelease]; + return [[self->plMap objectForKey:_plName] trackNames]; } -- (NSString *)prettyTrackNameForTrackWithID:(NSString *)_trackID - index:(unsigned)_idx -{ - NSDictionary *track; - NSString *name, *artist, *album; - NSNumber *trackNumber; - NSString *location; - NSMutableString *prettyName; - - track = [self->tracks objectForKey:_trackID]; - if (!track) return nil; - - prettyName = [[NSMutableString alloc] initWithCapacity:128]; - [prettyName appendFormat:@"%03d ", _idx + 1]; - - if (detailedNames) { - artist = [track objectForKey:@"Artist"]; - if (artist) { - [prettyName appendString:artist]; - [prettyName appendString:@"_"]; - } - album = [track objectForKey:@"Album"]; - if (album) { - [prettyName appendString:album]; - [prettyName appendString:@"_"]; - } - trackNumber = [track objectForKey:@"Track Number"]; - if (trackNumber) { - [prettyName appendString:[trackNumber description]]; - [prettyName appendString:@" "]; - } - } - name = [track objectForKey:@"Name"]; - [prettyName appendString:[name properlyEscapedFSRepresentation]]; -#if 0 - [prettyName appendString:@" ["]; - [prettyName appendString:_trackID]; - [prettyName appendString:@"]"]; -#endif - location = [track objectForKey:@"Location"]; - if (location) { - [prettyName appendString:@"."]; - if ([location hasPrefix:@"file"]) { - [prettyName appendString:[location pathExtension]]; - } - else { - /* http:// stream address... */ - [prettyName appendString:@"webloc"]; - } - } - return [prettyName autorelease]; -} - -- (BOOL)isValidTrackName:(NSString *)_ptn { +- (BOOL)isValidTrackName:(NSString *)_ptn inPlaylistNamed:(NSString *)_plName { #if 0 if(![_ptn isValidTrackName]) { NSLog(@"NOT valid track name! -> %@", _ptn); @@ -209,62 +139,27 @@ - (BOOL)isValidTrackName:(NSString *)_ptn { #endif } -- (NSString *)trackIDForPrettyTrackName:(NSString *)_ptn - inPlaylistNamed:(NSString *)_plName -{ -#if 1 - NSDictionary *list, *item; - NSArray *items; - - list = [self->plMap objectForKey:_plName]; - if (!list) return nil; - - items = [list objectForKey:@"Playlist Items"]; - item = [items objectAtIndex:[_ptn playlistIndex]]; - return [[item objectForKey:@"Track ID"] description]; -#else - NSRange close, open, cover; +- (iTunesTrack *)trackWithPrettyName:(NSString *)_ptn inPlaylistNamed:(NSString *)_plName { + iTunesPlaylist *pl; + unsigned idx; - close = [_ptn rangeOfString:@"]" options:NSBackwardsSearch]; - cover = NSMakeRange(0, close.location - 1); - open = [_ptn rangeOfString:@"[" options:NSBackwardsSearch range:cover]; - cover = NSMakeRange(NSMaxRange(open), close.location - open.location - 1); - return [_ptn substringWithRange:cover]; -#endif + pl = [self->plMap objectForKey:_plName]; + if (!pl) return nil; + idx = [_ptn playlistIndex]; + return [pl trackAtIndex:idx]; } -- (NSData *)dataForTrackWithID:(NSString *)_trackID { - NSDictionary *track; - NSString *location; - NSURL *url; - NSData *data; - - track = [self->tracks objectForKey:_trackID]; - location = [track objectForKey:@"Location"]; - if (!location) return nil; - url = [NSURL URLWithString:location]; - if (!url) return nil; - if (![url isFileURL]) { /* http based audio stream... */ - return [location dataUsingEncoding:NSUTF8StringEncoding]; - } - data = [NSData dataWithContentsOfURL:url - options:NSMappedRead|NSUncachedRead - error:NULL]; - return data; +- (NSData *)fileContentForTrackWithPrettyName:(NSString *)_ptn + inPlaylistNamed:(NSString *)_plName +{ + return [[self trackWithPrettyName:_ptn inPlaylistNamed:_plName] fileContent]; } -- (NSDictionary *)fileAttributesForTrackWithID:(NSString *)_trackID { - NSDictionary *track; - NSString *location; - NSURL *url; - - track = [self->tracks objectForKey:_trackID]; - location = [track objectForKey:@"Location"]; - if (!location) return nil; - url = [NSURL URLWithString:location]; - if (![url isFileURL]) return nil; - return [[NSFileManager defaultManager] fileAttributesAtPath:[url path] - traverseLink:YES]; +- (NSDictionary *)fileAttributesForTrackWithPrettyName:(NSString *)_ptn + inPlaylistNamed:(NSString *)_plName +{ + return [[self trackWithPrettyName:_ptn inPlaylistNamed:_plName] + fileAttributes]; } @end /* iTunesLibrary */ diff --git a/iTunesPlaylist.h b/iTunesPlaylist.h new file mode 100644 index 0000000..12d4812 --- /dev/null +++ b/iTunesPlaylist.h @@ -0,0 +1,28 @@ +/*@DISCLAIMER@*/ + +#ifndef __iTunesFS_iTunesPlaylist_H +#define __iTunesFS_iTunesPlaylist_H + +#import + +@class iTunesTrack; + +@interface iTunesPlaylist : NSObject +{ + NSString *name; + NSArray *tracks; +} + +- (id)initWithITunesRepresentation:(NSDictionary *)_list + tracks:(NSDictionary *)_tracks; + +- (NSString *)name; +- (NSArray *)tracks; + +- (unsigned)count; +- (iTunesTrack *)trackAtIndex:(unsigned)_idx; +- (NSArray *)trackNames; + +@end /* iTunesPlaylist */ + +#endif /* __iTunesFS_iTunesPlaylist_H */ diff --git a/iTunesPlaylist.m b/iTunesPlaylist.m new file mode 100644 index 0000000..8cdc1c5 --- /dev/null +++ b/iTunesPlaylist.m @@ -0,0 +1,97 @@ +/*@DISCLAIMER@*/ + +#import "common.h" +#import "iTunesPlaylist.h" +#import "iTunesTrack.h" +#import "NSString+Extensions.h" + +@interface iTunesPlaylist (Private) +- (void)setName:(NSString *)_name; +- (void)setTracks:(NSArray *)_tracks; +@end + +@implementation iTunesPlaylist + +- (id)initWithITunesRepresentation:(NSDictionary *)_list + tracks:(NSDictionary *)_tracks +{ + self = [super init]; + if (self) { + NSArray *items; + NSMutableArray *ts; + unsigned i, count; + + [self setName:[_list objectForKey:@"Name"]]; + + items = [_list objectForKey:@"Playlist Items"]; + count = [items count]; + ts = [[NSMutableArray alloc] initWithCapacity:count]; + for (i = 0; i < count; i++) { + NSDictionary *item; + id trackID; + iTunesTrack *track; + + item = [items objectAtIndex:i]; + trackID = [[item objectForKey:@"Track ID"] description]; + item = [_tracks objectForKey:trackID]; + track = [[iTunesTrack alloc] initWithITunesRepresentation:item + playlistIndex:i]; + [ts addObject:track]; + [track release]; + } + [self setTracks:ts]; + [ts release]; + } + return self; +} + +- (void)dealloc { + [self->name release]; + [self->tracks release]; + [super dealloc]; +} + +/* accessors */ + +- (void)setName:(NSString *)_name { + _name = [[_name properlyEscapedFSRepresentation] copy]; + [self->name release]; + self->name = _name; +} +- (NSString *)name { + return self->name; +} + +- (void)setTracks:(NSArray *)_tracks { + _tracks = [_tracks copy]; + [self->tracks release]; + self->tracks = _tracks; +} +- (NSArray *)tracks { + return self->tracks; +} + +- (unsigned)count { + return [self->tracks count]; +} + +- (iTunesTrack *)trackAtIndex:(unsigned)_idx { + return [self->tracks objectAtIndex:_idx]; +} + +- (NSArray *)trackNames { + NSMutableArray *names; + unsigned i, count; + + count = [self->tracks count]; + names = [[NSMutableArray alloc] initWithCapacity:count]; + for (i = 0; i < count; i++) { + iTunesTrack *track; + + track = [self->tracks objectAtIndex:i]; + [names addObject:[track name]]; + } + return [names autorelease]; +} + +@end /* iTunesPlaylist */ diff --git a/iTunesTrack.h b/iTunesTrack.h new file mode 100644 index 0000000..45cb531 --- /dev/null +++ b/iTunesTrack.h @@ -0,0 +1,25 @@ +/*@DISCLAIMER@*/ + +#ifndef __iTunesFS_iTunesTrack_H +#define __iTunesFS_iTunesTrack_H + +#import + +@interface iTunesTrack : NSObject +{ + NSString *name; + NSURL *url; +} + ++ (void)setUseDetailedInformationInNames:(BOOL)_yn; + +- (id)initWithITunesRepresentation:(NSDictionary *)_track + playlistIndex:(unsigned)_idx; + +- (NSString *)name; +- (NSDictionary *)fileAttributes; +- (NSData *)fileContent; + +@end /* iTunesTrack */ + +#endif /* __iTunesFS_iTunesTrack_H */ diff --git a/iTunesTrack.m b/iTunesTrack.m new file mode 100644 index 0000000..d2f51c6 --- /dev/null +++ b/iTunesTrack.m @@ -0,0 +1,122 @@ +/*@DISCLAIMER@*/ + +#import "common.h" +#import "iTunesTrack.h" +#import "NSString+Extensions.h" + +@interface iTunesTrack (Private) +- (void)setName:(NSString *)_name; +- (void)setUrl:(NSURL *)_url; +- (NSURL *)url; +@end + +@implementation iTunesTrack + +static BOOL detailedNames = NO; + ++ (void)setUseDetailedInformationInNames:(BOOL)_yn { + detailedNames = _yn; +} + +/* init & dealloc */ + +- (id)initWithITunesRepresentation:(NSDictionary *)_track + playlistIndex:(unsigned)_idx; +{ + self = [super init]; + if (self) { + NSString *artist, *album; + NSNumber *trackNumber; + NSString *location; + NSMutableString *prettyName; + + prettyName = [[NSMutableString alloc] initWithCapacity:128]; + [prettyName appendFormat:@"%03d ", _idx + 1]; + + if (detailedNames) { + artist = [_track objectForKey:@"Artist"]; + if (artist) { + [prettyName appendString:[artist properlyEscapedFSRepresentation]]; + [prettyName appendString:@"_"]; + } + album = [_track objectForKey:@"Album"]; + if (album) { + [prettyName appendString:[album properlyEscapedFSRepresentation]]; + [prettyName appendString:@"_"]; + } + trackNumber = [_track objectForKey:@"Track Number"]; + if (trackNumber) { + [prettyName appendString:[trackNumber description]]; + [prettyName appendString:@" "]; + } + } + [prettyName appendString:[[_track objectForKey:@"Name"] + properlyEscapedFSRepresentation]]; +#if 0 + [prettyName appendString:@" ["]; + [prettyName appendString:_trackID]; + [prettyName appendString:@"]"]; +#endif + location = [_track objectForKey:@"Location"]; + if (location) { + [prettyName appendString:@"."]; + if ([location hasPrefix:@"file"]) { + [prettyName appendString:[location pathExtension]]; + } + else { + /* http:// stream address... */ + [prettyName appendString:@"webloc"]; + } + [self setUrl:[NSURL URLWithString:location]]; + } + [self setName:prettyName]; + [prettyName release]; + } + return self; +} + +- (void)dealloc { + [self->name release]; + [self->url release]; + [super dealloc]; +} + +/* accessors */ + +- (void)setName:(NSString *)_name { + _name = [[_name properlyEscapedFSRepresentation] copy]; + [self->name release]; + self->name = _name; +} +- (NSString *)name { + return self->name; +} + +- (void)setUrl:(NSURL *)_url { + // ASSIGN(self->url, _url); + _url = [_url copy]; + [self->url release]; + self->url = _url; +} +- (NSURL *)url { + return self->url; +} + +- (NSDictionary *)fileAttributes { + if (!self->url) return nil; + if (![self->url isFileURL]) return nil; + return [[NSFileManager defaultManager] fileAttributesAtPath:[self->url path] + traverseLink:YES]; +} + +- (NSData *)fileContent { + if (!self->url) return nil; + if (![self->url isFileURL]) { /* http based audio stream... */ + return [[self->url description] dataUsingEncoding:NSUTF8StringEncoding]; + } + return [NSData dataWithContentsOfURL:self->url + options:NSMappedRead|NSUncachedRead + error:NULL]; +} + +@end /* iTunesTrack */