Controller.m 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. #import "Controller.h"
  2. /**********************************************************
  3. * First off, some value transformer to easily play with
  4. * bindings
  5. */
  6. @interface VLCFloat10000FoldTransformer : NSObject
  7. @end
  8. @implementation VLCFloat10000FoldTransformer
  9. + (Class)transformedValueClass
  10. {
  11. return [NSNumber class];
  12. }
  13. + (BOOL)allowsReverseTransformation
  14. {
  15. return YES;
  16. }
  17. - (id)transformedValue:(id)value
  18. {
  19. if( !value ) return nil;
  20. if(![value respondsToSelector: @selector(floatValue)])
  21. {
  22. [NSException raise: NSInternalInconsistencyException
  23. format: @"Value (%@) does not respond to -floatValue.",
  24. [value class]];
  25. return nil;
  26. }
  27. return [NSNumber numberWithFloat: [value floatValue]*10000.];
  28. }
  29. - (id)reverseTransformedValue:(id)value
  30. {
  31. if( !value ) return nil;
  32. if(![value respondsToSelector: @selector(floatValue)])
  33. {
  34. [NSException raise: NSInternalInconsistencyException
  35. format: @"Value (%@) does not respond to -floatValue.",
  36. [value class]];
  37. return nil;
  38. }
  39. return [NSNumber numberWithFloat: [value floatValue]/10000.];
  40. }
  41. @end
  42. /**********************************************************
  43. * @implementation Controller
  44. */
  45. @interface Controller ()
  46. @property (retain,readwrite) NSString * outputFolderPath;
  47. @end
  48. @implementation Controller
  49. - (id)init
  50. {
  51. if(self = [super init])
  52. {
  53. [self bind:@"outputFolderPath" toObject:[NSUserDefaultsController sharedUserDefaultsController]
  54. withKeyPath:@"values.outputFolderPath" options:nil];
  55. [[[NSUserDefaultsController sharedUserDefaultsController] values] bind:@"outputFolderPath" toObject:self
  56. withKeyPath:@"outputFolderPath" options:nil];
  57. VLCFloat10000FoldTransformer *float100fold;
  58. float100fold = [[[VLCFloat10000FoldTransformer alloc] init] autorelease];
  59. [NSValueTransformer setValueTransformer:(id)float100fold forName:@"Float10000FoldTransformer"];
  60. self.media = nil;
  61. self.streamSession = nil;
  62. selectedStreamOutput = [[NSNumber alloc] initWithInt:0];
  63. self.remoteURLAsString = [NSString stringWithString:@"http://youtube.com/watch?v=IXpx2OEWBdA&feature=bz303"];
  64. outputFilePath = nil;
  65. if( !self.outputFolderPath || [self.outputFolderPath isKindOfClass:[NSNull class]])
  66. self.outputFolderPath = [@"~/Movies/Flash Video Converted" stringByExpandingTildeInPath];
  67. }
  68. return self;
  69. }
  70. - (void)dealloc
  71. {
  72. [outputFilePath release];
  73. [remoteURLAsString release];
  74. [streamSession release];
  75. [media release];
  76. [super dealloc];
  77. }
  78. @synthesize streamSession;
  79. @synthesize selectedStreamOutput;
  80. @synthesize media;
  81. @synthesize outputFolderPath;
  82. - (void)awakeFromNib
  83. {
  84. [window setShowsResizeIndicator:NO];
  85. [NSApp setDelegate: self];
  86. }
  87. - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
  88. {
  89. [VLCLibrary sharedLibrary];
  90. }
  91. - (NSString *)remoteURLAsString
  92. {
  93. return remoteURLAsString;
  94. }
  95. - (void)setRemoteURLAsString:(NSString *)newURLAsString
  96. {
  97. [remoteURLAsString release];
  98. remoteURLAsString = [[newURLAsString copy] retain];
  99. media = [[newURLAsString copy] retain];
  100. [self setMedia:[VLCMedia mediaWithPath:newURLAsString]];
  101. }
  102. + (NSSet *)keyPathsForValuesAffectingOutputFilePath
  103. {
  104. return [NSSet setWithObjects:@"media.metaDictionary.title", nil];
  105. }
  106. - (void)freezeOutputFilePath
  107. {
  108. [outputFilePath release];
  109. outputFilePath = nil;
  110. outputFilePath = [self outputFilePath];
  111. [outputFilePath retain];
  112. }
  113. - (NSString *)outputFilePath
  114. {
  115. if(outputFilePath)
  116. return [outputFilePath copy];
  117. VLCMedia * aMedia = self.streamSession ? self.streamSession.media ? self.streamSession.media : self.media : self.media;
  118. NSString * name = [[[aMedia metaDictionary] objectForKey:@"title"] lastPathComponent];
  119. NSString * extension = [selectedStreamOutput intValue] == 2 ? @"mpeg" : @"mp4";
  120. NSString * path = [NSString stringWithFormat:@"%@/%@.%@", self.outputFolderPath, name, extension ];
  121. int i;
  122. for( i = 0; [[NSFileManager defaultManager] fileExistsAtPath:path]; i ++)
  123. {
  124. path = [NSString stringWithFormat:@"%@/%@ %d.%@", self.outputFolderPath, name, i, extension ];
  125. if( i > 256 )
  126. {
  127. /* Don't got too far */
  128. /* FIXME: Be nicer with the user and give him a choice for the new name */
  129. NSRunAlertPanelRelativeToWindow(@"File already exists",
  130. [NSString stringWithFormat:
  131. @"File '%@', already exists. The old one will be deleted when the OK button will be pressed", path],
  132. @"OK", nil, nil, window);
  133. break;
  134. }
  135. }
  136. return path;
  137. }
  138. - (IBAction)convert:(id)sender
  139. {
  140. VLCStreamOutput * streamOutput;
  141. [self.streamSession removeObserver:self forKeyPath:@"isComplete"];
  142. self.streamSession = [VLCStreamSession streamSession];
  143. [self freezeOutputFilePath];
  144. if([selectedStreamOutput intValue] == 2)
  145. {
  146. streamOutput = [VLCStreamOutput mpeg2StreamOutputWithFilePath:[self outputFilePath]];
  147. }
  148. else if([selectedStreamOutput intValue] == 1)
  149. {
  150. streamOutput = [VLCStreamOutput mpeg4StreamOutputWithFilePath:[self outputFilePath]];
  151. }
  152. else
  153. streamOutput = [VLCStreamOutput ipodStreamOutputWithFilePath:[self outputFilePath]];
  154. /* Make sure we are exporting to a well known directory */
  155. [[NSFileManager defaultManager] createDirectoryAtPath:self.outputFolderPath attributes:nil];
  156. [self.streamSession setStreamOutput:streamOutput];
  157. [self.streamSession setMedia:self.media];
  158. [self.streamSession startStreaming];
  159. [self.streamSession addObserver:self forKeyPath:@"isComplete" options:NSKeyValueObservingOptionNew context:nil];
  160. /* Show the new view */
  161. [[window contentView] addSubview:workingView];
  162. NSRect frame = [workingView frame];
  163. frame.origin.y -= NSHeight([window contentRectForFrameRect:[window frame]]) + 20.f;
  164. [workingView setFrame:frame];
  165. [[window animator] setFrame:NSMakeRect([window frame].origin.x, [window frame].origin.y-NSHeight([workingView frame]), NSWidth([window frame]), NSHeight([window frame])+NSHeight([workingView frame])) display:YES];
  166. }
  167. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
  168. {
  169. if([keyPath isEqualToString:@"isComplete"])
  170. {
  171. if([self.streamSession isComplete])
  172. {
  173. /* Notify the user */
  174. [[NSSound soundNamed:@"Glass"] play];
  175. /* Set the icon */
  176. [openConvertedFileButton setImage:[[NSWorkspace sharedWorkspace] iconForFile:[self outputFilePath]]];
  177. /* Rename the link with a nicer name */
  178. NSString * oldPath = [self outputFilePath];
  179. [self freezeOutputFilePath];
  180. [[NSFileManager defaultManager] moveItemAtPath:oldPath toPath:[self outputFilePath] error:NULL];
  181. }
  182. return;
  183. }
  184. [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
  185. }
  186. - (IBAction)openConvertedFile:(id)sender
  187. {
  188. [[NSWorkspace sharedWorkspace] openFile:[self outputFilePath]];
  189. }
  190. - (IBAction)pickOutputFolderPath:(id)sender;
  191. {
  192. NSOpenPanel * panel = [NSOpenPanel openPanel];
  193. [panel setCanChooseFiles:NO];
  194. [panel setCanChooseDirectories:YES];
  195. [panel setAllowsMultipleSelection:NO];
  196. [panel beginSheetForDirectory:self.outputFolderPath file:nil types:nil modalForWindow:[sender window] modalDelegate:self didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:nil];
  197. }
  198. - (void)openPanelDidEnd:(NSOpenPanel *)panel returnCode:(int)returnCode contextInfo:(void *)contextInfo
  199. {
  200. if(returnCode != NSOKButton || ![[panel filenames] count])
  201. return;
  202. self.outputFolderPath = [[panel filenames] objectAtIndex:0];
  203. }
  204. - (IBAction)openConvertedEnclosingFolder:(id)sender
  205. {
  206. [[NSWorkspace sharedWorkspace] selectFile:[self outputFilePath] inFileViewerRootedAtPath:[[self outputFilePath] stringByDeletingLastPathComponent]];
  207. }
  208. - (IBAction)cancel:(id)sender
  209. {
  210. [self.streamSession stop];
  211. }
  212. @end