diff --git a/Application/AppController.h b/Application/AppController.h index 574377e76..dd510828b 100644 --- a/Application/AppController.h +++ b/Application/AppController.h @@ -2,22 +2,23 @@ #import -#import "PlaybackController.h" - -#import "PlaylistController.h" -#import "PlaylistView.h" - -#import "FileTreeController.h" -#import "FileOutlineView.h" - #import "NDHotKeyEvent.h" -#import "AppleRemote.h" +@class PlaybackController; +@class PlaylistController; +@class PlaylistView; +@class FileTreeController; +@class FileOutlineView; +@class AppleRemote; +@class PlaylistLoader; + @interface AppController : NSObject { - IBOutlet PlaylistController *playlistController; IBOutlet PlaybackController *playbackController; + + IBOutlet PlaylistController *playlistController; + IBOutlet PlaylistLoader *playlistLoader; IBOutlet NSPanel *mainWindow; diff --git a/Application/AppController.m b/Application/AppController.m index 3a98603a9..f1844d071 100644 --- a/Application/AppController.m +++ b/Application/AppController.m @@ -1,5 +1,13 @@ #import "AppController.h" #import "KFTypeSelectTableView.h"" +#import "PlaybackController.h" +#import "PlaylistController.h" +#import "PlaylistView.h" +#import "FileTreeController.h" +#import "FileOutlineView.h" +#import "NDHotKeyEvent.h" +#import "AppleRemote.h" +#import "PlaylistLoader.h" @implementation AppController @@ -124,7 +132,7 @@ increase/decrease as long as the user holds the left/right, plus/minus button */ [p setCanChooseDirectories:YES]; [p setAllowsMultipleSelection:YES]; - [p beginSheetForDirectory:nil file:nil types:[playlistController acceptableFileTypes] modalForWindow:mainWindow modalDelegate:self didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL]; + [p beginSheetForDirectory:nil file:nil types:[playlistLoader acceptableFileTypes] modalForWindow:mainWindow modalDelegate:self didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL]; // [p beginForDirectory:nil file:nil types:[playlistController acceptableFileTypes] modelessDelegate:self didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:nil]; /* if ([p runModalForTypes:[playlistController acceptableFileTypes]] == NSOKButton) @@ -138,7 +146,7 @@ increase/decrease as long as the user holds the left/right, plus/minus button */ { if (returnCode == NSOKButton) { - [playlistController addPaths:[panel filenames] sort:YES]; + [playlistLoader addURLs:[panel URLs] sort:YES]; } // [panel release]; @@ -238,8 +246,8 @@ increase/decrease as long as the user holds the left/right, plus/minus button */ } - NSString *filename = @"~/Library/Application Support/Cog/Default.playlist"; - [playlistController loadPlaylist:[filename stringByExpandingTildeInPath]]; + NSString *filename = @"~/Library/Application Support/Cog/Default.m3u"; + [playlistLoader loadM3u:[filename stringByExpandingTildeInPath]]; } - (void)applicationWillTerminate:(NSNotification *)aNotification @@ -257,18 +265,15 @@ increase/decrease as long as the user holds the left/right, plus/minus button */ [fileManager createDirectoryAtPath: folder attributes: nil]; } - NSString *fileName = @"Default.playlist"; + NSString *fileName = @"Default.m3u"; - [playlistController savePlaylist:[folder stringByAppendingPathComponent: fileName]]; + [playlistLoader saveM3u:[folder stringByAppendingPathComponent: fileName]]; } - (IBAction)savePlaylist:(id)sender { - if ([playlistController playlistFilename] == nil) - [self savePlaylistAs:sender]; - - [playlistController savePlaylist:[playlistController playlistFilename]]; + [playlistLoader save]; } - (IBAction)savePlaylistAs:(id)sender { @@ -276,13 +281,11 @@ increase/decrease as long as the user holds the left/right, plus/minus button */ p = [NSSavePanel savePanel]; - [p setAllowedFileTypes:[playlistController acceptablePlaylistTypes]]; + [p setAllowedFileTypes:[playlistLoader acceptablePlaylistTypes]]; - if ([p runModalForDirectory:nil file:[[playlistController playlistFilename] lastPathComponent]] == NSOKButton) + if ([p runModalForDirectory:nil file:[[playlistLoader currentFile] lastPathComponent]] == NSOKButton) { - [playlistController setPlaylistFilename:[p filename]]; - - [playlistController savePlaylist:[p filename]]; + [playlistLoader save:[p filename]]; } } @@ -295,11 +298,9 @@ increase/decrease as long as the user holds the left/right, plus/minus button */ [p setCanChooseDirectories:NO]; [p setAllowsMultipleSelection:NO]; - if ([p runModalForTypes:[playlistController acceptablePlaylistTypes]] == NSOKButton) + if ([p runModalForTypes:[playlistLoader acceptablePlaylistTypes]] == NSOKButton) { - [playlistController setPlaylistFilename:[p filename]]; - - [playlistController loadPlaylist:[p filename]]; + [playlistLoader load:[p filename]]; } [mainWindow makeKeyAndOrderFront:self]; @@ -316,16 +317,24 @@ increase/decrease as long as the user holds the left/right, plus/minus button */ - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename { DBLog(@"Adding path: %@", filename); - [playlistController addPaths:[NSArray arrayWithObject:filename] sort:NO]; + [playlistLoader addURLs:[NSArray arrayWithObject:[NSURL fileURLWithPath:filename]] sort:NO]; return YES; } - (void)application:(NSApplication *)theApplication openFiles:(NSArray *)filenames { - DBLog(@"Adding paths: %@", filenames); + //Need to convert to urls + NSMutableArray *urls = [NSMutableArray array]; + NSEnumerator *e = [filenames objectEnumerator]; + NSString *filename; + + while (filename = [e nextObject]) + { + [urls addObject:[NSURL fileURLWithPath:filename]]; + } + [playlistLoader addURLs:urls sort:YES]; - [playlistController addPaths:filenames sort:YES]; [theApplication replyToOpenOrPrint:NSApplicationDelegateReplySuccess]; } diff --git a/Audio/AudioPlayer.h b/Audio/AudioPlayer.h index 6dfe7b1c8..17975d5eb 100644 --- a/Audio/AudioPlayer.h +++ b/Audio/AudioPlayer.h @@ -45,6 +45,7 @@ - (void)setNextStream:(NSURL *)url withUserInfo:(id)userInfo; + (NSArray *)fileTypes; ++ (NSArray *)schemes; @end diff --git a/Audio/AudioPlayer.m b/Audio/AudioPlayer.m index a799c5360..8a63e4a7c 100644 --- a/Audio/AudioPlayer.m +++ b/Audio/AudioPlayer.m @@ -280,5 +280,12 @@ return [types allObjects]; } ++ (NSArray *)schemes +{ + PluginController *pluginController = [PluginController sharedPluginController]; + + return [[pluginController sources] allKeys]; +} + @end diff --git a/Cog.xcodeproj/project.pbxproj b/Cog.xcodeproj/project.pbxproj index 6c1cc6b08..12553ff21 100644 --- a/Cog.xcodeproj/project.pbxproj +++ b/Cog.xcodeproj/project.pbxproj @@ -11,6 +11,8 @@ 170680630B950158006BA573 /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 170680620B950158006BA573 /* Growl.framework */; }; 170680840B950164006BA573 /* Growl.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 170680620B950158006BA573 /* Growl.framework */; }; 171678C00AC8C39E00C28CF3 /* SmartFolderNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 171678BE0AC8C39E00C28CF3 /* SmartFolderNode.m */; }; + 1755E1F80BA0D2B600CA3560 /* PlaylistLoader.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1755E1F60BA0D2B600CA3560 /* PlaylistLoader.h */; }; + 1755E1F90BA0D2B600CA3560 /* PlaylistLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1755E1F70BA0D2B600CA3560 /* PlaylistLoader.m */; }; 175D8B640B9A514C005B3CD9 /* CogAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 175D8B630B9A514C005B3CD9 /* CogAudio.framework */; }; 175D8B670B9A5153005B3CD9 /* CogAudio.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 175D8B630B9A514C005B3CD9 /* CogAudio.framework */; }; 1766C6930B911DF1004A7AE4 /* AudioScrobbler.m in Sources */ = {isa = PBXBuildFile; fileRef = 1766C68F0B911DF1004A7AE4 /* AudioScrobbler.m */; }; @@ -138,6 +140,7 @@ 175D8B670B9A5153005B3CD9 /* CogAudio.framework in CopyFiles */, 170680840B950164006BA573 /* Growl.framework in CopyFiles */, 17F94CCD0B8D090800A34E87 /* Sparkle.framework in CopyFiles */, + 1755E1F80BA0D2B600CA3560 /* PlaylistLoader.h in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -150,6 +153,8 @@ 170680620B950158006BA573 /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Growl.framework; path = ThirdParty/Frameworks/Growl.framework; sourceTree = ""; }; 171678BD0AC8C39E00C28CF3 /* SmartFolderNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SmartFolderNode.h; sourceTree = ""; }; 171678BE0AC8C39E00C28CF3 /* SmartFolderNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SmartFolderNode.m; sourceTree = ""; }; + 1755E1F60BA0D2B600CA3560 /* PlaylistLoader.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PlaylistLoader.h; sourceTree = ""; }; + 1755E1F70BA0D2B600CA3560 /* PlaylistLoader.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = PlaylistLoader.m; sourceTree = ""; }; 175D8B630B9A514C005B3CD9 /* CogAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CogAudio.framework; path = Audio/build/Release/CogAudio.framework; sourceTree = ""; }; 1766C68E0B911DF1004A7AE4 /* AudioScrobbler.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = AudioScrobbler.h; sourceTree = ""; }; 1766C68F0B911DF1004A7AE4 /* AudioScrobbler.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = AudioScrobbler.m; sourceTree = ""; }; @@ -613,6 +618,8 @@ children = ( 8E1296D80A2BA9CE00443124 /* PlaylistHeaderView.h */, 8E1296D90A2BA9CE00443124 /* PlaylistHeaderView.m */, + 1755E1F60BA0D2B600CA3560 /* PlaylistLoader.h */, + 1755E1F70BA0D2B600CA3560 /* PlaylistLoader.m */, 8E75752B09F31D5A0080F1EE /* DNDArrayController.h */, 8E75752C09F31D5A0080F1EE /* DNDArrayController.m */, 8E75752D09F31D5A0080F1EE /* PlaylistController.h */, @@ -638,7 +645,6 @@ 8EFFCD410AA093AF00C458A5 /* FileDrawer */ = { isa = PBXGroup; children = ( - 8EFFCD540AA093AF00C458A5 /* UKKQueue */, 8EFFCD440AA093AF00C458A5 /* FileIconCell.h */, 8EFFCD450AA093AF00C458A5 /* FileIconCell.m */, 8EFFCD500AA093AF00C458A5 /* PathIcon.h */, @@ -661,13 +667,6 @@ path = FileDrawer; sourceTree = ""; }; - 8EFFCD540AA093AF00C458A5 /* UKKQueue */ = { - isa = PBXGroup; - children = ( - ); - path = UKKQueue; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -796,6 +795,7 @@ 1770429E0B8BC53600B86321 /* PlaybackController.m in Sources */, 1766C6930B911DF1004A7AE4 /* AudioScrobbler.m in Sources */, 1766C6950B911DF1004A7AE4 /* AudioScrobblerClient.m in Sources */, + 1755E1F90BA0D2B600CA3560 /* PlaylistLoader.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -836,21 +836,9 @@ buildSettings = { COPY_PHASE_STRIP = NO; FRAMEWORK_SEARCH_PATHS = ( - "$(SRCROOT)/Frameworks/CogAudio/build/Release", + "$(SRCROOT)/Audio/build/Release", "$(SRCROOT)/ThirdParty/Frameworks/", - "$(FRAMEWORK_SEARCH_PATHS_QUOTED_1)", - "$(FRAMEWORK_SEARCH_PATHS_QUOTED_2)", - "$(FRAMEWORK_SEARCH_PATHS_QUOTED_3)", - "$(FRAMEWORK_SEARCH_PATHS_QUOTED_4)", - "$(FRAMEWORK_SEARCH_PATHS_QUOTED_5)", - "$(FRAMEWORK_SEARCH_PATHS_QUOTED_6)", ); - FRAMEWORK_SEARCH_PATHS_QUOTED_1 = "\"$(SRCROOT)/Frameworks/CogAudio/build/Debug\""; - FRAMEWORK_SEARCH_PATHS_QUOTED_2 = "\"$(SRCROOT)/Audio/build/Release\""; - FRAMEWORK_SEARCH_PATHS_QUOTED_3 = "\"$(SRCROOT)/Audio/build/Debug\""; - FRAMEWORK_SEARCH_PATHS_QUOTED_4 = "\"$(SRCROOT)/Audio/build/Release\""; - FRAMEWORK_SEARCH_PATHS_QUOTED_5 = "\"$(SRCROOT)/Audio/build/Release\""; - FRAMEWORK_SEARCH_PATHS_QUOTED_6 = "\"$(SRCROOT)/Audio/build/Debug\""; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_ENABLE_OBJC_EXCEPTIONS = YES; @@ -881,21 +869,9 @@ i386, ); FRAMEWORK_SEARCH_PATHS = ( - "$(SRCROOT)/Frameworks/CogAudio/build/Release", + "$(SRCROOT)/Audio/build/Release", "$(SRCROOT)/ThirdParty/Frameworks/", - "$(FRAMEWORK_SEARCH_PATHS_QUOTED_1)", - "$(FRAMEWORK_SEARCH_PATHS_QUOTED_2)", - "$(FRAMEWORK_SEARCH_PATHS_QUOTED_3)", - "$(FRAMEWORK_SEARCH_PATHS_QUOTED_4)", - "$(FRAMEWORK_SEARCH_PATHS_QUOTED_5)", - "$(FRAMEWORK_SEARCH_PATHS_QUOTED_6)", ); - FRAMEWORK_SEARCH_PATHS_QUOTED_1 = "\"$(SRCROOT)/Frameworks/CogAudio/build/Debug\""; - FRAMEWORK_SEARCH_PATHS_QUOTED_2 = "\"$(SRCROOT)/Audio/build/Release\""; - FRAMEWORK_SEARCH_PATHS_QUOTED_3 = "\"$(SRCROOT)/Audio/build/Debug\""; - FRAMEWORK_SEARCH_PATHS_QUOTED_4 = "\"$(SRCROOT)/Audio/build/Release\""; - FRAMEWORK_SEARCH_PATHS_QUOTED_5 = "\"$(SRCROOT)/Audio/build/Release\""; - FRAMEWORK_SEARCH_PATHS_QUOTED_6 = "\"$(SRCROOT)/Audio/build/Debug\""; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_MODEL_TUNING = G5; diff --git a/English.lproj/MainMenu.nib/classes.nib b/English.lproj/MainMenu.nib/classes.nib index 8c8c8f6f5..7c9b6d260 100644 --- a/English.lproj/MainMenu.nib/classes.nib +++ b/English.lproj/MainMenu.nib/classes.nib @@ -41,6 +41,7 @@ playButton = NSButton; playbackController = PlaybackController; playlistController = PlaylistController; + playlistLoader = PlaylistLoader; playlistView = PlaylistView; prevButton = NSButton; repeatButton = NSButton; @@ -87,7 +88,7 @@ { CLASS = FileTreeController; LANGUAGE = ObjC; - OUTLETS = {playlistController = PlaylistController; }; + OUTLETS = {playlistLoader = PlaylistLoader; }; SUPERCLASS = NSTreeController; }, {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, @@ -127,16 +128,22 @@ }, { ACTIONS = { - showFileInFinder = id; - sortByPath = id; + showEntryInFinder = id; takeRepeatFromObject = id; takeShuffleFromObject = id; }; CLASS = PlaylistController; LANGUAGE = ObjC; + OUTLETS = {playlistLoader = PlaylistLoader; }; SUPERCLASS = DNDArrayController; }, {CLASS = PlaylistEntry; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + { + CLASS = PlaylistLoader; + LANGUAGE = ObjC; + OUTLETS = {playlistController = PlaylistController; }; + SUPERCLASS = NSObject; + }, { ACTIONS = {shufflePlaylist = id; sortByPath = id; toggleColumn = id; }; CLASS = PlaylistView; diff --git a/English.lproj/MainMenu.nib/info.nib b/English.lproj/MainMenu.nib/info.nib index 935210722..dff491ab7 100644 --- a/English.lproj/MainMenu.nib/info.nib +++ b/English.lproj/MainMenu.nib/info.nib @@ -15,7 +15,7 @@ 463 669 637 341 145 0 0 1680 1028 513 - 1026 274 125 137 0 0 1680 1028 + 352 836 125 137 0 0 1680 1028 IBFramework Version 446.1 @@ -32,12 +32,12 @@ 4 IBOpenObjects - 463 - 29 - 1156 - 1307 513 + 29 + 463 + 1156 21 + 1307 IBSystem Version 8L2127 diff --git a/English.lproj/MainMenu.nib/keyedobjects.nib b/English.lproj/MainMenu.nib/keyedobjects.nib index d5ce8cebf..8d48334cf 100644 Binary files a/English.lproj/MainMenu.nib/keyedobjects.nib and b/English.lproj/MainMenu.nib/keyedobjects.nib differ diff --git a/Feedback/FeedbackController.m b/Feedback/FeedbackController.m index 0af3b839c..bd4b1e31a 100644 --- a/Feedback/FeedbackController.m +++ b/Feedback/FeedbackController.m @@ -23,7 +23,7 @@ - (void)alertDidEnd:(NSAlert *)alert returnCode:(int)returnCode contextInfo:(void *)contextInfo { - if (contextInfo == YES) + if ([(NSNumber *)contextInfo boolValue]== YES) { [feedbackWindow close]; } @@ -39,7 +39,7 @@ [alert setMessageText:NSLocalizedString(@"FeedbackFailedMessageText", @"")]; [alert setInformativeText:NSLocalizedString(@"FeedbackFailedInformativeText", @"")]; - [alert beginSheetModalForWindow:feedbackWindow modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:NO]; + [alert beginSheetModalForWindow:feedbackWindow modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:[NSNumber numberWithBool:NO]]; } - (void)FeedbackSent:(NSNotification *)aNotification @@ -52,7 +52,7 @@ [alert setMessageText:NSLocalizedString(@"FeedbackSuccessMessageText", @"")]; [alert setInformativeText:NSLocalizedString(@"FeedbackSuccessInformativeText", @"")]; - [alert beginSheetModalForWindow:feedbackWindow modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:YES]; + [alert beginSheetModalForWindow:feedbackWindow modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:[NSNumber numberWithBool:YES]]; } diff --git a/FileDrawer/FileTreeController.h b/FileDrawer/FileTreeController.h index ae3ed0771..cad5f8f93 100644 --- a/FileDrawer/FileTreeController.h +++ b/FileDrawer/FileTreeController.h @@ -7,12 +7,13 @@ // #import -#import "FileTreeWatcher.h" -#import "PlaylistController.h" + +@class FileTreeWatcher; +@class PlaylistLoader; @interface FileTreeController : NSTreeController { - IBOutlet PlaylistController *playlistController; + IBOutlet PlaylistLoader *playlistLoader; NSString *rootPath; @@ -21,5 +22,6 @@ - (id)rootPath; - (void)setRootPath:(id)r; +- (void) refreshRoot; @end diff --git a/FileDrawer/FileTreeController.m b/FileDrawer/FileTreeController.m index 922491c6c..ce9c7ad5c 100644 --- a/FileDrawer/FileTreeController.m +++ b/FileDrawer/FileTreeController.m @@ -7,9 +7,11 @@ // #import "FileTreeController.h" +#import "FileTreeWatcher.h" #import "DirectoryNode.h" #import "ImageTextCell.h" #import "KFTypeSelectTableView.h" +#import "PlaylistLoader.h" @implementation FileTreeController @@ -109,7 +111,7 @@ - (NSArray *)acceptableFileTypes { - return [playlistController acceptableFileTypes]; + return [playlistLoader acceptableFileTypes]; } - (FileTreeWatcher *)watcher @@ -119,22 +121,21 @@ - (BOOL)outlineView:(NSOutlineView *)olv writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard { //Get selected paths - NSLog(@"Items: %@", items); NSMutableArray *paths = [NSMutableArray arrayWithCapacity:[items count]]; - id p; NSEnumerator *e = [items objectEnumerator]; + id p; while (p = [e nextObject]) { int i; PathNode *n = nil; NSIndexPath *ip = [p indexPath]; - NSLog(@"Content: %@", n); + for (i = 0; i < [ip length]; i++) { NSArray *a = (n == nil) ? [self content] : [n subpaths]; n = [a objectAtIndex:[ip indexAtPosition:i]]; } - NSLog(@"Path: %@", n); + [paths addObject:[n path]]; } @@ -193,17 +194,20 @@ //End type-select - (void)addSelectedToPlaylist { - NSMutableArray *paths = [[NSMutableArray alloc] init]; + NSMutableArray *urls = [[NSMutableArray alloc] init]; NSArray *nodes = [self selectedObjects]; NSEnumerator *e = [nodes objectEnumerator]; id n; while (n = [e nextObject]) { - [paths addObject:[n path]]; + NSURL *url = [[NSURL alloc] initFileURLWithPath:[n path]]; + [urls addObject:url]; + [url release]; } - [playlistController addPaths:paths sort:YES]; - [paths release]; + NSLog(@"Adding URLs: %@", urls); + [playlistLoader addURLs:urls sort:YES]; + [urls release]; } diff --git a/FileDrawer/FileTreeWatcher.h b/FileDrawer/FileTreeWatcher.h index 3aa4cda9c..f80b4c70e 100644 --- a/FileDrawer/FileTreeWatcher.h +++ b/FileDrawer/FileTreeWatcher.h @@ -19,4 +19,6 @@ - (void)addPath: (NSString *)path; - (void)removePath: (NSString *)path; +-(void) setDelegate: (id)d; + @end diff --git a/Playlist/DNDArrayController.m b/Playlist/DNDArrayController.m index e8c0576a8..e5bd6aef8 100755 --- a/Playlist/DNDArrayController.m +++ b/Playlist/DNDArrayController.m @@ -11,15 +11,8 @@ NSString *iTunesDropType = @"CorePasteboardFlavorType 0x6974756E"; - (void)awakeFromNib { // register for drag and drop - NSLog(@"AWOKE"); - [tableView registerForDraggedTypes:[NSArray arrayWithObjects:MovedRowsType, NSFilenamesPboardType, iTunesDropType, nil]]; - -// [tableView setVerticalMotionCanBeginDrag:YES]; -// [tableView setAllowsMultipleSelection:NO]; -// [super awakeFromNib]; -// DBLog(@"HERE: %@", [tableView registeredDraggedTypes]); } @@ -27,8 +20,6 @@ NSString *iTunesDropType = @"CorePasteboardFlavorType 0x6974756E"; writeRows:(NSArray*)rows toPasteboard:(NSPasteboard*)pboard { - NSLog(@"WRITE ROWS"); - NSData *data; data = [NSKeyedArchiver archivedDataWithRootObject:rows]; @@ -66,11 +57,10 @@ NSString *iTunesDropType = @"CorePasteboardFlavorType 0x6974756E"; { row = 0; } - NSLog(@"ACCEPTATING"); + // if drag source is self, it's a move if ([info draggingSource] == tableView) { -// DBLog(@"ACCEPTATED"); NSArray *rows = [NSKeyedUnarchiver unarchiveObjectWithData:[[info draggingPasteboard] dataForType: MovedRowsType]]; NSIndexSet *indexSet = [self indexSetFromRows:rows]; diff --git a/Playlist/PlaylistController.h b/Playlist/PlaylistController.h index 3bee2101e..fb248b3d6 100644 --- a/Playlist/PlaylistController.h +++ b/Playlist/PlaylistController.h @@ -8,13 +8,13 @@ #import #import "DNDArrayController.h" -#import "PlaylistEntry.h" + +@class PlaylistLoader; +@class PlaylistEntry; @interface PlaylistController : DNDArrayController { - NSArray *acceptableFileTypes; - NSArray *acceptablePlaylistTypes; - - NSString *playlistFilename; + IBOutlet PlaylistLoader *playlistLoader; + NSString *totalTimeDisplay; NSMutableArray *shuffleList; @@ -27,22 +27,12 @@ int selectedRow; } -//All these return the number of things actually added //Private Methods -//- (int)addPath:(NSString *)path; -//- (int)insertPath:(NSString *)path atIndex:(int)index; -//- (int)insertFile:(NSString *)filename atIndex:(int)index; -//- (int)addFile:(NSString *)filename; - (void)updateIndexesFromRow:(int) row; - (void)updateTotalTime; //PUBLIC METHODS -- (void)addPaths:(NSArray *)paths sort:(BOOL)sort; -- (void)insertPaths:(NSArray *)paths atIndex:(int)index sort:(BOOL)sort; - -- (NSArray *)acceptableFileTypes; - - (void)setShuffle:(BOOL)s; - (BOOL)shuffle; - (void)setRepeat:(BOOL)r; @@ -51,7 +41,10 @@ - (IBAction)takeShuffleFromObject:(id)sender; - (IBAction)takeRepeatFromObject:(id)sender; -- (IBAction)sortByPath:(id)sender; +- (IBAction)sortByPath; +- (IBAction)randomizeList; + +- (IBAction)showEntryInFinder:(id)sender; - (void)setTotalTimeDisplay:(NSString *)ttd; - (NSString *)totalTimeDisplay; @@ -63,21 +56,10 @@ - (BOOL)next; - (BOOL)prev; -- (PlaylistEntry *)entryAtIndex:(int)i; - - (void)addShuffledListToBack; - (void)addShuffledListToFront; - (void)resetShuffleList; -//load/save playlist -- (void)loadPlaylist:(NSString *)filename; -- (void)savePlaylist:(NSString *)filename; - -- (NSString *)playlistFilename; -- (void)setPlaylistFilename:(NSString *)pf; -- (NSArray *)acceptablePlaylistTypes; - -- (IBAction)showFileInFinder:(id)sender; - - (void)handlePlaylistViewHeaderNotification:(NSNotification*)notif; + @end diff --git a/Playlist/PlaylistController.m b/Playlist/PlaylistController.m index 27c993ffc..197ed881d 100644 --- a/Playlist/PlaylistController.m +++ b/Playlist/PlaylistController.m @@ -6,6 +6,7 @@ // Copyright 2005 Vincent Spader All rights reserved. // +#import "PlaylistLoader.h" #import "PlaylistController.h" #import "PlaylistEntry.h" #import "Shuffle.h" @@ -22,11 +23,7 @@ if (self) { - acceptableFileTypes = [[AudioPlayer fileTypes] retain]; - acceptablePlaylistTypes = [[NSArray alloc] initWithObjects:@"playlist",nil]; - shuffleList = [[NSMutableArray alloc] init]; -// DBLog(@"DAH BUTTER CHORNAR: %@", history); } return self; @@ -40,150 +37,6 @@ [ns addObserver:self selector:@selector(handlePlaylistViewHeaderNotification:) name:@"PlaylistViewColumnSeparatorDoubleClick" object:nil]; } -- (NSArray *)filesAtPath:(NSString *)path -{ - BOOL isDir; - NSFileManager *manager; - - manager = [NSFileManager defaultManager]; - - NSLog(@"Checking if path is a directory: %@", path); - if ([manager fileExistsAtPath:path isDirectory:&isDir] && isDir == YES) - { - DBLog(@"path is directory"); - int j; - NSArray *subpaths; - NSMutableArray *validPaths = [[NSMutableArray alloc] init]; - - subpaths = [manager subpathsAtPath:path]; - - DBLog(@"Subpaths: %@", subpaths); - for (j = 0; j < [subpaths count]; j++) - { - NSString *filepath; - - filepath = [NSString pathWithComponents:[NSArray arrayWithObjects:path,[subpaths objectAtIndex:j],nil]]; - if ([manager fileExistsAtPath:filepath isDirectory:&isDir] && isDir == NO) - { - if ([acceptableFileTypes containsObject:[[filepath pathExtension] lowercaseString]] && [[NSFileManager defaultManager] fileExistsAtPath:filepath]) - { - [validPaths addObject:filepath]; - } - } - } - - return [validPaths autorelease]; - } - else - { - NSLog(@"path is a file"); - if ([acceptableFileTypes containsObject:[[path pathExtension] lowercaseString]] && [[NSFileManager defaultManager] fileExistsAtPath:path]) - { - NSLog(@"RETURNING THING"); - return [NSArray arrayWithObject:path]; - } - else - { - return nil; - } - } -} - -- (void)insertPaths:(NSArray *)paths atIndex:(int)index sort:(BOOL)sort -{ - NSArray *sortedFiles; - NSMutableArray *files = [[NSMutableArray alloc] init]; - NSMutableArray *entries= [[NSMutableArray alloc] init]; - int i; - - if (!paths) - return; - - if (index < 0) - index = 0; - - for(i=0; i < [paths count]; i++) - { - [files addObjectsFromArray:[self filesAtPath:[paths objectAtIndex:i]]]; - NSLog(@"files is: %i", [files count]); - } - - DBLog(@"Sorting paths"); - if (sort == YES) - { - sortedFiles = [files sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]; - } - else - { - sortedFiles = files; - } - - for (i = 0; i < [sortedFiles count]; i++) - { - PlaylistEntry *pe = [[PlaylistEntry alloc] init]; - - [pe setURL:[NSURL fileURLWithPath:[sortedFiles objectAtIndex:i]]]; - [pe setIndex:index+i]; - [pe setTitle:[[sortedFiles objectAtIndex:i] lastPathComponent]]; -// [pe performSelectorOnMainThread:@selector(readTags) withObject:nil waitUntilDone:NO]; -// [pe performSelectorOnMainThread:@selector(readInfo) withObject:nil waitUntilDone:NO]; - - [entries addObject:pe]; - [pe release]; - } - - NSRange r = NSMakeRange(index, [entries count]); - NSLog(@"MAking range from: %i to %i", index, index + [entries count]); - NSIndexSet *is = [NSIndexSet indexSetWithIndexesInRange:r]; - NSLog(@"INDex set: %@", is); - NSLog(@"Adding: %i files", [entries count]); - [self insertObjects:entries atArrangedObjectIndexes:is]; - - if (shuffle == YES) - [self resetShuffleList]; - - [self setSelectionIndex:index]; - - //Other thread will release entries....crazy crazy bad idea...whatever - [NSThread detachNewThreadSelector:@selector(readMetaData:) toTarget:self withObject:entries]; - - [files release]; - - return; -} - -- (void)readMetaData:(id)entries -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - int i; - for (i = 0; i < [entries count]; i++) - { - PlaylistEntry *pe =[entries objectAtIndex:i]; - - [pe readInfoThreaded]; - - [pe readTagsThreaded]; - - //Hack so the display gets updated - if (pe == [self currentEntry]) - [self performSelectorOnMainThread:@selector(setCurrentEntry:) withObject:[self currentEntry] waitUntilDone:YES]; - } - - [self performSelectorOnMainThread:@selector(updateTotalTime) withObject:nil waitUntilDone:NO]; - - [entries release]; - [pool release]; -} - -- (void)addPaths:(NSArray *)paths sort:(BOOL)sort -{ - [self insertPaths:paths atIndex:[[self arrangedObjects] count] sort:sort]; -} - -- (NSArray *)acceptableFileTypes -{ - return acceptableFileTypes; -} - (void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn @@ -199,27 +52,20 @@ row:(int)row dropOperation:(NSTableViewDropOperation)op { - int i; - NSLog(@"DROPPED"); [super tableView:tv acceptDrop:info row:row dropOperation:op]; if ([info draggingSource] == tableView) { - //DNDArrayController handles moving...still need to update the uhm...indices - NSLog(@"Archive stuff"); + //DNDArrayController handles moving...still need to update the indexes + + int i; NSArray *rows = [NSKeyedUnarchiver unarchiveObjectWithData:[[info draggingPasteboard] dataForType: MovedRowsType]]; - NSLog(@"Whatever"); - NSIndexSet *indexSet = [self indexSetFromRows:rows]; - int firstIndex = [indexSet firstIndex]; + int firstIndex = [[self indexSetFromRows:rows] firstIndex]; + if (firstIndex > row) - { i = row; - } else - { i = firstIndex; - } - NSLog(@"Updating indexes: %i", i); [self updateIndexesFromRow:i]; return YES; @@ -235,10 +81,18 @@ // Get files from a normal file drop (such as from Finder) if ([bestType isEqualToString:NSFilenamesPboardType]) { - NSArray *files = [[info draggingPasteboard] propertyListForType:NSFilenamesPboardType]; + NSMutableArray *urls = [[NSMutableArray alloc] init]; + + NSEnumerator *e = [[[info draggingPasteboard] propertyListForType:NSFilenamesPboardType] objectEnumerator]; + NSString *file; + while (file = [e nextObject]) + { + [urls addObject:[NSURL fileURLWithPath:file]]; + } - NSLog(@"INSERTING PATHS: %@", files); - [self insertPaths:files atIndex:row sort:YES]; + [playlistLoader insertURLs:urls atIndex:row sort:YES]; + + [urls release]; } // Get files from an iTunes drop @@ -246,26 +100,19 @@ NSDictionary *iTunesDict = [pboard propertyListForType:iTunesDropType]; NSDictionary *tracks = [iTunesDict valueForKey:@"Tracks"]; - // Convert the iTunes URLs to filenames - NSMutableArray *files = [[NSMutableArray alloc] init]; + // Convert the iTunes URLs to URLs....MWAHAHAH! + NSMutableArray *urls = [[NSMutableArray alloc] init]; + NSEnumerator *e = [[tracks allValues] objectEnumerator]; NSDictionary *trackInfo; - NSURL *url; while (trackInfo = [e nextObject]) { - url = [[NSURL alloc] initWithString:[trackInfo valueForKey:@"Location"]]; - if ([url isFileURL]) { - [files addObject:[url path]]; - } - - [url release]; + [urls addObject:[NSURL URLWithString:[trackInfo valueForKey:@"Location"]]]; } - NSLog(@"INSERTING ITUNES PATHS: %@", files); - [self insertPaths:files atIndex:row sort:YES]; - [files release]; + [playlistLoader insertURLs:urls atIndex:row sort:YES]; + [urls release]; } - NSLog(@"UPDATING"); [self updateIndexesFromRow:row]; [self updateTotalTime]; @@ -295,7 +142,6 @@ [ttd retain]; [totalTimeDisplay release]; totalTimeDisplay = ttd; - NSLog(@"Displaying: %@", ttd); } - (NSString *)totalTimeDisplay; @@ -305,7 +151,6 @@ - (void)updateIndexesFromRow:(int) row { -// DBLog(@"UPDATE INDEXES: %i", row); int j; for (j = row; j < [[self arrangedObjects] count]; j++) { @@ -318,20 +163,8 @@ - (void)removeObjectsAtArrangedObjectIndexes:(NSIndexSet *)indexes { - unsigned int *indexBuffer; - NSMutableArray *a = [[NSMutableArray alloc] init]; - int i; - - //10.3 fix - indexBuffer = malloc([indexes count]*sizeof(unsigned int)); - [indexes getIndexes:indexBuffer maxCount:[indexes count] inIndexRange:nil]; - for (i = 0; i < [indexes count]; i++) - { - NSLog(@"REMOVING FROM INDEX: %i", indexBuffer[i]); - [a addObject:[[self arrangedObjects] objectAtIndex:(indexBuffer[i])]]; - } - -// a = [[self arrangedObjects] objectsAtIndexes:indexes]; //10.4 only + NSLog(@"REMOVING"); + NSArray *a = [[self arrangedObjects] objectsAtIndexes:indexes]; //Screw 10.3 if ([a containsObject:currentEntry]) { @@ -344,8 +177,6 @@ if (shuffle == YES) [self resetShuffleList]; - - [a release]; } - (void)setSortDescriptors:(NSArray *)sortDescriptors @@ -363,7 +194,7 @@ [super setSortDescriptors:sortDescriptors]; } -- (IBAction)sortByPath:(id)sender +- (IBAction)sortByPath { NSSortDescriptor *s = [[NSSortDescriptor alloc] initWithKey:@"url" ascending:YES selector:@selector(compare:)]; @@ -378,7 +209,7 @@ [self updateIndexesFromRow:0]; } -- (void)randomizeList +- (IBAction)randomizeList { [self setSortDescriptors:nil]; @@ -423,9 +254,9 @@ return [[self arrangedObjects] objectAtIndex:i]; } + - (PlaylistEntry *)shuffledEntryAtIndex:(int)i { - // NSLog(@"SHUFFLE: %i %i %i %i", i, shuffleIndex, offset, [shuffleList count]); while (i < 0) { if (repeat == YES) @@ -455,67 +286,6 @@ return [shuffleList objectAtIndex:i]; } -/*- (PlaylistEntry *)entryAtOffset:(int)offset -{ - if (shuffle == YES) - { - int i = shuffleIndex; - i += offset; -// NSLog(@"SHUFFLE: %i %i %i %i", i, shuffleIndex, offset, [shuffleList count]); - while (i < 0) - { - if (repeat == YES) - { - [self addShuffledListToFront]; - //change i appropriately - i += [[self arrangedObjects] count]; - } - else - { - return nil; - } - } - while (i >= [shuffleList count]) - { - if (repeat == YES) - { - NSLog(@"Adding shuffled list to back!"); - [self addShuffledListToBack]; - } - else - { - return nil; - } - } - - return [shuffleList objectAtIndex:i]; - } - else - { - int i; - i = [currentEntry index]; - i += (offset-1); - - if (i < 0) - { - if (repeat == YES) - i += [[self arrangedObjects] count]; - else - return nil; - } - else if (i >= [[self arrangedObjects] count]) - { - if (repeat == YES) - i -= [[self arrangedObjects] count]; - else - return nil; - } - - return [[self arrangedObjects] objectAtIndex:i]; - } -} -*/ - - (PlaylistEntry *)getNextEntry:(PlaylistEntry *)pe { if (shuffle == YES) @@ -673,75 +443,18 @@ { [super setFilterPredicate:filterPredicate]; - int j; - for (j = 0; j < [[self content] count]; j++) - { - PlaylistEntry *p; - p = [[self content] objectAtIndex:j]; - - [p setIndex:-1]; - } - [self updateIndexesFromRow:0]; } -- (void)savePlaylist:(NSString *)filename -{ -// DBLog(@"SAVING PLAYLIST: %@", filename); - NSString *fileContents; - NSMutableArray *filenames = [NSMutableArray array]; - - NSEnumerator *enumerator; - PlaylistEntry *entry; - enumerator = [[self content] objectEnumerator]; - while (entry = [enumerator nextObject]) - { - [filenames addObject:[[entry url] path]]; - } - - fileContents = [filenames componentsJoinedByString:@"\n"]; - [fileContents writeToFile:filename atomically:NO]; -} - -- (void)loadPlaylist:(NSString *)filename -{ - NSString *fileContents; - - [self removeObjects:[self arrangedObjects]]; - fileContents = [NSString stringWithContentsOfFile:filename]; - if (fileContents) - { - NSArray *filenames = [fileContents componentsSeparatedByString:@"\n"]; -// DBLog(@"filenames: %@", filenames); - [self addPaths:filenames sort:NO]; - } -} - -- (NSArray *)acceptablePlaylistTypes -{ - return acceptablePlaylistTypes; -} - -- (NSString *)playlistFilename -{ - return playlistFilename; -} -- (void)setPlaylistFilename:(NSString *)pf -{ - [pf retain]; - [playlistFilename release]; - - playlistFilename = pf; -} - -- (IBAction)showFileInFinder:(id)sender +- (IBAction)showEntryInFinder:(id)sender { NSWorkspace* ws = [NSWorkspace sharedWorkspace]; if ([self selectionIndex] < 0) return; - PlaylistEntry* curr = [self entryAtIndex:[self selectionIndex]]; - [ws selectFile:[[curr url] path] inFileViewerRootedAtPath:[[curr url] path]]; + NSURL *url = [[self entryAtIndex:[self selectionIndex]] url]; + if ([url isFileURL]) + [ws selectFile:[url path] inFileViewerRootedAtPath:[url path]]; } - (void)handlePlaylistViewHeaderNotification:(NSNotification*)notif @@ -750,6 +463,9 @@ NSNumber *colIdx = [[notif userInfo] objectForKey:@"column"]; NSTableColumn *col = [[tv tableColumns] objectAtIndex:[colIdx intValue]]; + //Change to use NSSelectorFromString and NSMethodSignature returnType, see http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articles/chapter_5_section_7.html for info + //Maybe we can pull the column bindings out somehow, instead of selectorfromstring + // find which function to call on PlaylistEntry* SEL sel; NSString* identifier = [col identifier]; diff --git a/Playlist/PlaylistEntry.h b/Playlist/PlaylistEntry.h index c16bd8983..51da6d7fb 100644 --- a/Playlist/PlaylistEntry.h +++ b/Playlist/PlaylistEntry.h @@ -34,16 +34,16 @@ int displayIdx; } --(void)setIndex:(int)i; --(int)index; +- (void)setIndex:(int)i; +- (int)index; --(void)setShuffleIndex:(int)si; --(int)shuffleIndex; +- (void)setShuffleIndex:(int)si; +- (int)shuffleIndex; --(void)setURL:(NSURL *)u; --(NSURL *)url; --(void)setCurrent:(BOOL) b; --(BOOL)current; +- (void)setURL:(NSURL *)u; +- (NSURL *)url; +- (void)setCurrent:(BOOL) b; +- (BOOL)current; - (void)setArtist:(NSString *)s; - (NSString *)artist; @@ -57,10 +57,10 @@ - (NSString *)lengthString; - (void)setLengthString:(double)l; --(void)setYear:(NSString *)y; --(NSString *)year; --(void)setTrack:(int)y; --(int)track; +- (void)setYear:(NSString *)y; +- (NSString *)year; +- (void)setTrack:(int)y; +- (int)track; - (void)setLength:(double)l; - (void)setBitrate:(int) br; @@ -74,9 +74,9 @@ - (int)bitsPerSample; - (float)sampleRate; -- (void)readTags; -- (void)readTagsThreaded; -- (void)readInfo; -- (void)readInfoThreaded; +- (void)setMetadata: (NSDictionary *)m; +- (void)readMetadataThread; +- (void)setProperties: (NSDictionary *)p; +- (void)readPropertiesThread; @end diff --git a/Playlist/PlaylistEntry.m b/Playlist/PlaylistEntry.m index fc889c600..f85529e5b 100644 --- a/Playlist/PlaylistEntry.m +++ b/Playlist/PlaylistEntry.m @@ -164,7 +164,7 @@ return track; } -- (void)readInfoThreadedSetVariables:(NSDictionary *)dict +- (void)setProperties:(NSDictionary *)dict { [self setLength: [[dict objectForKey:@"length" ] doubleValue]]; [self setBitrate: [[dict objectForKey:@"bitrate" ] intValue]]; @@ -175,11 +175,11 @@ [self setLengthString:[[dict objectForKey:@"length"] doubleValue]]; } -- (void)readInfoThreaded +- (void)readPropertiesThread { NSDictionary *properties = [AudioPropertiesReader propertiesForURL:url]; - [self performSelectorOnMainThread:@selector(readInfoThreadedSetVariables:) withObject:properties waitUntilDone:YES]; + [self performSelectorOnMainThread:@selector(setProperties:) withObject:properties waitUntilDone:YES]; } - (NSString *)lengthString @@ -240,7 +240,7 @@ return sampleRate; } -- (void)readTagsThreadedSetVariables: (NSDictionary *)m +- (void)setMetadata: (NSDictionary *)m { NSString *ti = [m objectForKey:@"title"]; @@ -248,7 +248,7 @@ [self setTitle:[[url path] lastPathComponent]]; } else { - [self setTitle:[m objectForKey:@"title"]]; + [self setTitle:ti]; } [self setArtist:[m objectForKey:@"artist"]]; @@ -258,11 +258,11 @@ [self setTrack:[[m objectForKey:@"track"] intValue]]; } -- (void)readTagsThreaded +- (void)readMetadataThread { NSDictionary *metadata = [AudioMetadataReader metadataForURL:url]; - [self performSelectorOnMainThread:@selector(readTagsThreadedSetVariables:) withObject:metadata waitUntilDone:YES]; + [self performSelectorOnMainThread:@selector(setMetadata:) withObject:metadata waitUntilDone:YES]; } diff --git a/Playlist/PlaylistLoader.h b/Playlist/PlaylistLoader.h index ee8c5888b..67070026b 100755 --- a/Playlist/PlaylistLoader.h +++ b/Playlist/PlaylistLoader.h @@ -16,13 +16,15 @@ typedef enum { } PlaylistType; @interface PlaylistLoader : NSObject { - PlaylistController *playlistController; + IBOutlet PlaylistController *playlistController; PlaylistType currentType; //m3u or pls NSString *currentFile; } - +//load arrays of urls... +- (void)addURLs:(NSArray *)urls sort:(BOOL)sort; +- (void)insertURLs:(NSArray *)urls atIndex:(int)index sort:(BOOL)sort; //load playlist auto-determines type to be either pls or m3u. - (BOOL)load:(NSString *)filename; @@ -37,6 +39,7 @@ typedef enum { - (BOOL)saveM3u:(NSString *)filename; - (BOOL)savePls:(NSString *)filename; +- (NSArray *)acceptableFileTypes; - (NSArray *)acceptablePlaylistTypes; - (PlaylistType)currentType; diff --git a/Playlist/PlaylistLoader.m b/Playlist/PlaylistLoader.m index f35545e33..35f7beb2e 100755 --- a/Playlist/PlaylistLoader.m +++ b/Playlist/PlaylistLoader.m @@ -10,6 +10,8 @@ #import "PlaylistController.h" #import "PlaylistEntry.h" +#import "CogAudio/AudioPlayer.h" + @implementation PlaylistLoader //load/save playlist auto-determines type to be either pls or m3u. @@ -32,7 +34,7 @@ - (BOOL)save { - [self save:currentFilename asType:currentType]; + return [self save:currentFile asType:currentType]; } - (BOOL)save:(NSString *)filename @@ -62,20 +64,15 @@ return NO; } -- (BOOL)loadM3u:(NSString *)filename -{ -} - -- (NSString *)pathRelativeTo:(NSString *)filename forEntry:(PlaylistEntry *)pe +- (NSString *)relativePathFrom:(NSString *)filename toURL:(NSURL *)entryURL { NSString *basePath = [[[filename stringByStandardizingPath] stringByDeletingLastPathComponent] stringByAppendingString:@"/"]; - NSURL *entryURL = [pe url]; - if ([[entryURL scheme] isEqualToString:@"file"]) { + if ([entryURL isFileURL]) { //We want relative paths. NSMutableString *entryPath = [[[[entryURL path] stringByStandardizingPath] mutableCopy] autorelease]; - [entryPath replaceOccurrencesOfString:basePath withString:@"" options:(NSAnchoredSearch | NSLiteralSearch | NSCaseInsensitiveSearch) range:NSMakeRange(0, [entryURL length])]; + [entryPath replaceOccurrencesOfString:basePath withString:@"" options:(NSAnchoredSearch | NSLiteralSearch | NSCaseInsensitiveSearch) range:NSMakeRange(0, [entryPath length])]; return entryPath; } @@ -85,7 +82,56 @@ } } - return paths; +- (NSURL *)urlForPath:(NSString *)path relativeTo:(NSString *)baseFilename +{ + if ([path hasPrefix:@"/"]) { + return [NSURL fileURLWithPath:path]; + } + + NSEnumerator *e = [[AudioPlayer schemes] objectEnumerator]; + NSString *scheme; + while (scheme = [e nextObject]) + { + if ([path hasPrefix:[scheme stringByAppendingString:@"://"]]) + { + return [NSURL URLWithString:path]; + } + } + + NSString *basePath = [[[baseFilename stringByStandardizingPath] stringByDeletingLastPathComponent] stringByAppendingString:@"/"]; + + return [NSURL fileURLWithPath:[basePath stringByAppendingString:path]]; +} + + +- (BOOL)loadM3u:(NSString *)filename +{ + NSLog(@"Loading playlist: %@", filename); + + + NSError *error = nil; + NSString *contents = [NSString stringWithContentsOfFile:filename encoding:NSUTF8StringEncoding error:&error]; + if (error || !contents) { + NSLog(@"Could not open file...%@ %@", contents, error); + return NO; + } + + NSString *entry; + NSEnumerator *e = [[contents componentsSeparatedByString:@"\n"] objectEnumerator]; + NSMutableArray *entries = [NSMutableArray array]; + + while (entry = [[e nextObject] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]) + { + if ([entry hasPrefix:@"#"] || [entry isEqualToString:@""]) //Ignore extra info + continue; + + //Need to add basePath, and convert to URL + [entries addObject:[self urlForPath:entry relativeTo:filename]]; + } + + [self addURLs:entries sort:NO]; + + return YES; } - (BOOL)saveM3u:(NSString *)filename @@ -94,18 +140,23 @@ if (!fileHandle) { return NO; } + [fileHandle truncateFileAtOffset:0]; + + NSLog(@"Saving: %@", filename); PlaylistEntry *pe; NSEnumerator *e = [[playlistController content] objectEnumerator]; while (pe = [e nextObject]) { - NSString *path = [self pathRelativeTo:filename forEntry:pe]; + NSString *path = [self relativePathFrom:filename toURL:[pe url]]; [fileHandle writeData:[[path stringByAppendingString:@"\n"] dataUsingEncoding:NSUTF8StringEncoding]]; } + [fileHandle closeFile]; + [self setCurrentFile:filename]; - [self setType:kPlaylistM3u]; + [self setCurrentType:kPlaylistM3u]; return YES; } @@ -113,34 +164,37 @@ - (BOOL)loadPls:(NSString *)filename { NSError *error; - NSStringEncoding enc; - NSString *contents = [NSString stringWithContentsOfFile:filename encoding:&enc error:&error]; + NSString *contents = [NSString stringWithContentsOfFile:filename encoding:NSUTF8StringEncoding error:&error]; if (error || !contents) { return NO; } NSString *entry; NSEnumerator *e = [[contents componentsSeparatedByString:@"\n"] objectEnumerator]; + NSMutableArray *entries = [NSMutableArray array]; - while (entry = [e nextObject]) + while (entry = [[e nextObject] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]) { + NSScanner *scanner = [[NSScanner alloc] initWithString:entry]; NSString *lhs = nil; - if (![scanner scanUpToString:@"=" intoString:&lhs]) //get LHS - continue; - if (![scanner scanString:@"=" intoString:nil]) //skip the = - continue; - NSString *nameString = nil; - if (![scanner scanUpToString:@"" intoString:&rhs]) //get RHS - continue; + NSString *rhs = nil; - if (![lhs isEqualToString:@"File"]) + if (![scanner scanUpToString:@"=" intoString:&lhs] || // get LHS + ![scanner scanString:@"=" intoString:nil] || // skip the = + ![scanner scanUpToString:@"" intoString:&rhs] || // get RHS + ![lhs isEqualToString:@"File"]) // We only want file entries + { + [scanner release]; continue; - - //get url if its a file? -// [entries addObject:nameString]; + } + + //need to add basepath if its a file, and convert to URL + [entries addObject:[self urlForPath:rhs relativeTo:filename]]; + + [scanner release]; } - [playlistController addURLs:urls]; + [self addURLs:entries sort:NO]; return YES; } @@ -151,28 +205,188 @@ if (!fileHandle) { return NO; } + [fileHandle truncateFileAtOffset:0]; + + [fileHandle writeData:[[NSString stringWithFormat:@"[playlist]\nnumberOfEntries=%i\n\n",[[playlistController content] count]] dataUsingEncoding:NSUTF8StringEncoding]]; NSEnumerator *e = [[playlistController content] objectEnumerator]; PlaylistEntry *pe; int i = 1; while (pe = [e nextObject]) { - NSString *path = [self pathRelativeTo:filename forEntry:pe]; + NSString *path = [self relativePathFrom:filename toURL:[pe url]]; NSString *entry = [NSString stringWithFormat:@"File%i=%@\n",i,path]; [fileHandle writeData:[entry dataUsingEncoding:NSUTF8StringEncoding]]; i++; } + [fileHandle writeData:[@"\nVERSION=2" dataUsingEncoding:NSUTF8StringEncoding]]; + [fileHandle closeFile]; + [self setCurrentFile:filename]; - [self setType:kPlaylistM3u]; + [self setCurrentType:kPlaylistM3u]; return YES; } +- (NSArray *)fileURLsAtPath:(NSString *)path +{ + NSFileManager *manager = [NSFileManager defaultManager]; + + NSMutableArray *urls = [NSMutableArray array]; + + NSString *subpath; + NSArray *subpaths = [manager subpathsAtPath:path]; + NSEnumerator *e = [subpaths objectEnumerator]; + + while(subpath = [e nextObject]) + { + NSString *absoluteSubpath = [NSString pathWithComponents:[NSArray arrayWithObjects:path,subpath,nil]]; + + BOOL isDir; + if ( [manager fileExistsAtPath:absoluteSubpath isDirectory:&isDir] && isDir == NO) + { + [urls addObject:[NSURL fileURLWithPath:absoluteSubpath]]; + } + } + + return urls; +} + +- (void)insertURLs:(NSArray *)urls atIndex:(int)index sort:(BOOL)sort +{ + NSMutableArray *allURLs = [[NSMutableArray alloc] init]; + NSMutableArray *validURLs = [[NSMutableArray alloc] init]; + NSArray *finalURLs; + + if (!urls) + return; + + if (index < 0) + index = 0; + + NSLog(@"URLS: %@", urls); + NSEnumerator *urlEnumerator = [urls objectEnumerator]; + NSURL *url; + while (url = [urlEnumerator nextObject]) + { + if ([url isFileURL]) { + BOOL isDir; + if ([[NSFileManager defaultManager] fileExistsAtPath:[url path] isDirectory:&isDir]) + { + if (isDir == YES) + { + //Get subpaths + [allURLs addObjectsFromArray:[self fileURLsAtPath:[url path]]]; + } + else + { + //File url + [allURLs addObject:url]; + } + } + } + else + { + //Non-file URL.. + [allURLs addObject:url]; + } + } + + + urlEnumerator = [allURLs objectEnumerator]; + while (url = [urlEnumerator nextObject]) + { + if (![[AudioPlayer schemes] containsObject:[url scheme]]) + continue; + + //Need a better way to determine acceptable file types than basing it on extensions. + if (![[self acceptableFileTypes] containsObject:[[[url path] pathExtension] lowercaseString]]) + continue; + + [validURLs addObject:url]; + } + + finalURLs = validURLs; + if (sort == YES) + { + NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"absoluteString" ascending:YES]; + + finalURLs = [validURLs sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]]; + + [sortDescriptor release]; + } + + //Create actual entries + int i; + NSMutableArray *entries = [NSMutableArray array]; + for (i = 0; i < [finalURLs count]; i++) + { + PlaylistEntry *pe = [[PlaylistEntry alloc] init]; + NSURL *url = [finalURLs objectAtIndex:i]; + + [pe setURL:url]; + [pe setIndex:index+i]; + [pe setTitle:[[url path] lastPathComponent]]; + + [entries addObject:pe]; + + [pe release]; + } + + NSIndexSet *is = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, [entries count])]; + + [playlistController insertObjects:entries atArrangedObjectIndexes:is]; + + //Select the first entry in the group that was just added + [playlistController setSelectionIndex:index]; + + //Other thread for reading things... + [NSThread detachNewThreadSelector:@selector(readEntriesInfoThread:) toTarget:self withObject:entries]; + + [allURLs release]; + [validURLs release]; + + return; +} + +- (void)readEntriesInfoThread:(NSArray *)entries +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSEnumerator *e = [entries objectEnumerator]; + PlaylistEntry *pe; + while (pe = [e nextObject]) + { + [pe readPropertiesThread]; + + [pe readMetadataThread]; + + //Hack so the display gets updated + if (pe == [playlistController currentEntry]) + [playlistController performSelectorOnMainThread:@selector(setCurrentEntry:) withObject:[playlistController currentEntry] waitUntilDone:YES]; + } + + + [playlistController performSelectorOnMainThread:@selector(updateTotalTime) withObject:nil waitUntilDone:NO]; + + [pool release]; +} + +- (void)addURLs:(NSArray *)urls sort:(BOOL)sort +{ + [self insertURLs:urls atIndex:[[playlistController content] count] sort:sort]; +} + +- (NSArray *)acceptableFileTypes +{ + return [AudioPlayer fileTypes]; +} + - (NSArray *)acceptablePlaylistTypes { - return [NSArray arrayWithObject:@"m3u",@"pls",nil]; + return [NSArray arrayWithObjects:@"m3u",@"pls",nil]; } - (PlaylistType)currentType