/* vim: set ft=objc ts=4 et sw=4 nowrap: */ /* * GrabAudioCDHelper.m * * Copyright (c) 2002-2005 * * Author: Andreas Heppel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "GrabAudioCDHelper.h" #include "Constants.h" #include "Functions.h" #include "Track.h" #include "Project.h" #include "AppController.h" #include #include "Burn/ExternalTools.h" /* * A private helper class to hold the data for one * grabbing process. */ @interface GrabProcess : NSObject { @public NSString *cddbId; NSMutableArray *tracks; } - (id) init; - (void)setCddbId: (NSString *)newId; @end @implementation GrabProcess - (id) init { self = [super init]; cddbId = nil; tracks = [NSMutableArray new]; return self; } - (void) dealloc { RELEASE(tracks); RELEASE(cddbId); } - (void)setCddbId: (NSString *)newId { ASSIGN(cddbId, newId); } @end @implementation GrabAudioCDHelper - (id) initWithController: (BurnProgressController *)aController { self = [super init]; if (self) { controller = aController; tempFiles = nil; processes = [NSMutableArray new]; } return self; } - (void) dealloc { RELEASE(tempFiles); RELEASE(processes); } - (enum StartHelperStatus) start: (NSArray *) audioTracks { enum StartHelperStatus ret = Done; NSDictionary *burnParameters = [controller burnParameters]; NSMutableDictionary *processHelper = [NSMutableDictionary new]; NSEnumerator *eTracks = [audioTracks objectEnumerator]; Track *track = nil; if ((audioTracks == nil) || ([audioTracks count] == 0)) { return Done; } currentTool = [[AppController appController] bundleForKey: [[burnParameters objectForKey: @"SelectedTools"] objectForKey: @"RipSW"]]; if (!currentTool) { NSRunAlertPanel(APP_NAME, [NSString stringWithFormat: @"%@\n%@", _(@"GrabAudioCDHelper.noProgram"), _(@"Common.stopProcess")], _(@"Common.OK"), nil, nil); ret = Failed; goto clean_up; } /* * We iterate over the list of audio tracks. If we have an * audio cd track, we get the cddb ID and put the track into the * list associated with this ID. */ while ((track = [eTracks nextObject]) != nil) { NSString *trackType = [track type]; NSString *cddbId = nil; NSMutableArray *tracks; /* * Only handle audio cd tracks. */ if (![trackType isEqualToString: @"audio:cd"]) continue; cddbId = [[[track source] componentsSeparatedByString: @"/"] objectAtIndex: 0]; GrabProcess *process = [processHelper objectForKey: cddbId]; if (!process) { process = [GrabProcess new]; [process setCddbId: cddbId]; [processHelper setObject: process forKey: cddbId]; [processes addObject: process]; } [process->tracks addObject: track]; } if ([processes count] != 0) { ret = Started; nextCD = 0; [self startNextCD]; } clean_up: RELEASE(processHelper); return ret; } - (void) stop: (BOOL) immediately { if (currentTool != nil) { [(id)currentTool stop: immediately]; logToConsole(MessageStatusError, _(@"Common.cancelled")); } } - (void) cleanUp: (BOOL) success { NSDictionary *burnParameters = [controller burnParameters]; BOOL keepTempFiles = [[[[controller burnParameters] objectForKey: @"SessionParameters"] objectForKey: @"KeepTempWavs"] boolValue]; NSFileManager *fileMan = [NSFileManager defaultManager]; if (currentTool != nil) { [(id)currentTool cleanUp]; } if ((keepTempFiles == NO) && tempFiles) { NSString *file; int i, count = [tempFiles count]; for (i = 0; i < count; i++) { file = [tempFiles objectAtIndex: i]; logToConsole(MessageStatusInfo, [NSString stringWithFormat: _(@"Common.removeTempFile"), file]); if (![fileMan removeFileAtPath: file handler: nil]) { logToConsole(MessageStatusError, _(@"Common.removeFail")); } } RELEASE(tempFiles); tempFiles = nil; } } - (NSString *) checkCD: (NSString *)cddbId { BOOL isRightCD = NO; NSString *sourceDevice = nil; id audioCD = loadAudioCD(); if (!audioCD) { return nil; } /* * Give the AudioCD.bundle some time to load the CD. */ sleep(1); /* * We check first, whether we have the right CD and then rip the stuff. */ while (isRightCD == NO) { if (![audioCD checkForCDWithId: cddbId]) { int result = NSRunInformationalAlertPanel(APP_NAME, [NSString stringWithFormat: _(@"GrabAudioCDHelper.insertCD"), [[[controller cdList] objectForKey: cddbId] objectForKey: @"artist"], [[[controller cdList] objectForKey: cddbId] objectForKey: @"title"]], _(@"Common.OK"), _(@"Common.cancel"), nil); if (result == NSAlertAlternateReturn) { if (NSRunAlertPanel(APP_NAME, _(@"GrabAudioCDHelper.reallyStop"), _(@"Common.no"), _(@"Common.yes"), nil) == NSAlertAlternateReturn) { break; } } } else { sourceDevice = [[audioCD device] copy]; isRightCD = YES; } }; [audioCD stopCheck]; DESTROY(audioCD); return sourceDevice; } - (void) startNextCD { NSString *sourceDevice; NSDictionary *theCD; NSMutableDictionary *burnParameters = [controller burnParameters]; if (nextCD >= [processes count]) { logToConsole(MessageStatusInfo, _(@"GrabAudioCDHelper.success")); [controller nextStage: YES]; return; } GrabProcess *process = [processes objectAtIndex: nextCD++]; theCD = [[controller cdList] objectForKey: process->cddbId]; logToConsole(MessageStatusInfo, [NSString stringWithFormat: _(@"GrabAudioCDHelper.grabbing"), [theCD objectForKey: @"title"]]); sourceDevice = [self checkCD: process->cddbId]; if (!sourceDevice) { [controller nextStage: NO]; return; } [controller setTitle: _(@"GrabAudioCDHelper.title")]; [controller setEntireProgress: 0. andLabel: [NSString stringWithFormat: _(@"GrabAudioCDHelper.CDTitle"), [theCD objectForKey: @"artist"], [theCD objectForKey: @"title"]]]; [controller setTrackProgress: 0. andLabel: @""]; [burnParameters setObject: sourceDevice forKey: @"SourceDevice"]; RELEASE(sourceDevice); [burnParameters setObject: process->cddbId forKey: @"CddbId"]; // now get it [NSThread detachNewThreadSelector: @selector(ripTrackThread:) toTarget: self withObject: process]; [NSTimer scheduledTimerWithTimeInterval: 0.4 target: self selector: @selector(updateStatus:) userInfo: nil repeats: NO]; } - (void) ripTrackThread: (id)anObject { int i; BOOL result = YES; id pool = [NSAutoreleasePool new]; id ripper = currentTool; NSArray *tracks = ((GrabProcess *)anObject)->tracks; NSMutableDictionary *burnParameters = [controller burnParameters]; // start ripping result = [ripper convertTracks: tracks withParameters: burnParameters]; if (result) { if (!tempFiles) { tempFiles = [[NSMutableArray alloc] init]; } // add file to list of temporary files for (i = 0; i < [tracks count]; i++) { Track *track = [tracks objectAtIndex: i]; [tempFiles addObject: [track storage]]; } } RELEASE(pool); [NSThread exit]; } - (void) updateStatus: (id)timer { SConvertStatus status; id ripper = currentTool; status = [ripper getStatus]; [controller setMiniwindowToTrack: status.trackProgress Entire: status.entireProgress]; if (status.processStatus == isConverting) { [controller setTrackProgress: status.trackProgress andLabel: [NSString stringWithFormat: _(@"Common.trackTitle"), status.trackName]]; [controller setEntireProgress: status.entireProgress andLabel: nil]; [NSTimer scheduledTimerWithTimeInterval: 0.4 target: self selector: @selector(updateStatus:) userInfo: nil repeats: NO]; return; } // did we stop by 'Cancel' or by terminated thread? if (status.processStatus == isCancelled) { [controller nextStage: NO]; } else { [controller setTrackProgress: status.trackProgress andLabel: nil]; [controller setEntireProgress: status.entireProgress andLabel: nil]; [self startNextCD]; } } @end