Monitor a folder for torrent files, adding them as they are added (by polling the folder). Growl notifications for import, and only try to reimport the same torrent if the setting is changed, the app is restarted, or the torrent file is moved to a different folder then moved back.

Original code from Steve (brilla on the forums).
This commit is contained in:
Mitchell Livingston
2006-07-07 01:03:52 +00:00
parent 59ddd1f75c
commit cb8baebb35
8 changed files with 173 additions and 32 deletions

View File

@@ -71,6 +71,9 @@
io_connect_t fRootPort; io_connect_t fRootPort;
NSTimer * fTimer; NSTimer * fTimer;
NSTimer * fAutoImportTimer;
NSArray * fAutoImportedNames;
BOOL fHasGrowl; BOOL fHasGrowl;
Badger * fBadger; Badger * fBadger;
BOOL fUpdateInProgress; BOOL fUpdateInProgress;
@@ -142,6 +145,9 @@
- (void) reloadInspectorSettings: (NSNotification *) notification; - (void) reloadInspectorSettings: (NSNotification *) notification;
- (void) checkAutoImportDirectory: (NSTimer *) t;
- (void) autoImportChange: (NSNotification *) notification;
- (void) sleepCallBack: (natural_t) messageType argument: - (void) sleepCallBack: (natural_t) messageType argument:
(void *) messageArgument; (void *) messageArgument;
@@ -155,7 +161,7 @@
- (void) linkHomepage: (id) sender; - (void) linkHomepage: (id) sender;
- (void) linkForums: (id) sender; - (void) linkForums: (id) sender;
- (void) notifyGrowl: (NSString *) file; - (void) notifyGrowl: (NSString * ) title message: (NSString *) message notification: (NSString *) notification;
- (void) growlRegister; - (void) growlRegister;
- (void) checkUpdate: (id) sender; - (void) checkUpdate: (id) sender;

View File

@@ -89,6 +89,7 @@ static void sleepCallBack(void * controller, io_service_t y,
[fInfoController release]; [fInfoController release];
[fBadger release]; [fBadger release];
[fSortType release]; [fSortType release];
[fAutoImportedNames release];
tr_close( fLib ); tr_close( fLib );
[super dealloc]; [super dealloc];
@@ -243,15 +244,27 @@ static void sleepCallBack(void * controller, io_service_t y,
//change that just impacts the inspector //change that just impacts the inspector
[nc addObserver: self selector: @selector(reloadInspectorSettings:) [nc addObserver: self selector: @selector(reloadInspectorSettings:)
name: @"TorrentSettingChange" object: nil]; name: @"TorrentSettingChange" object: nil];
//reset auto import
[nc addObserver: self selector: @selector(autoImportChange:)
name: @"AutoImportSettingChange" object: nil];
//timer to update the interface //timer to update the interface every second
fCompleted = 0; fCompleted = 0;
[self updateUI: nil]; [self updateUI: nil];
fTimer = [NSTimer scheduledTimerWithTimeInterval: 1.0 target: self fTimer = [NSTimer scheduledTimerWithTimeInterval: 1.0 target: self
selector: @selector( updateUI: ) userInfo: nil repeats: YES]; selector: @selector(updateUI:) userInfo: nil repeats: YES];
[[NSRunLoop currentRunLoop] addTimer: fTimer forMode: NSModalPanelRunLoopMode]; [[NSRunLoop currentRunLoop] addTimer: fTimer forMode: NSModalPanelRunLoopMode];
[[NSRunLoop currentRunLoop] addTimer: fTimer forMode: NSEventTrackingRunLoopMode]; [[NSRunLoop currentRunLoop] addTimer: fTimer forMode: NSEventTrackingRunLoopMode];
//timer for auto import, will check every 60 seconds
fAutoImportedNames = [[NSArray alloc] init];
[self checkAutoImportDirectory: nil];
fAutoImportTimer = [NSTimer scheduledTimerWithTimeInterval: 5.0 target: self
selector: @selector(checkAutoImportDirectory:) userInfo: nil repeats: YES];
[[NSRunLoop currentRunLoop] addTimer: fAutoImportTimer forMode: NSDefaultRunLoopMode];
[self sortTorrents]; [self sortTorrents];
[fWindow makeKeyAndOrderFront: nil]; [fWindow makeKeyAndOrderFront: nil];
@@ -310,7 +323,8 @@ static void sleepCallBack(void * controller, io_service_t y,
- (void) applicationWillTerminate: (NSNotification *) notification - (void) applicationWillTerminate: (NSNotification *) notification
{ {
//stop updating the interface //stop timers
[fAutoImportTimer invalidate];
[fTimer invalidate]; [fTimer invalidate];
//save history and stop running torrents //save history and stop running torrents
@@ -456,11 +470,6 @@ static void sleepCallBack(void * controller, io_service_t y,
@selector(openSheetClosed:returnCode:contextInfo:) contextInfo: nil]; @selector(openSheetClosed:returnCode:contextInfo:) contextInfo: nil];
} }
- (void) openFromSheet: (NSArray *) filenames
{
[self application: NSApp openFiles: filenames];
}
- (void) openSheetClosed: (NSOpenPanel *) panel returnCode: (int) code - (void) openSheetClosed: (NSOpenPanel *) panel returnCode: (int) code
contextInfo: (void *) info contextInfo: (void *) info
{ {
@@ -469,6 +478,11 @@ static void sleepCallBack(void * controller, io_service_t y,
withObject: [panel filenames] waitUntilDone: NO]; withObject: [panel filenames] waitUntilDone: NO];
} }
- (void) openFromSheet: (NSArray *) filenames
{
[self application: NSApp openFiles: filenames];
}
- (void) resumeTorrent: (id) sender - (void) resumeTorrent: (id) sender
{ {
[self resumeTorrentWithIndex: [fTableView selectedRowIndexes]]; [self resumeTorrentWithIndex: [fTableView selectedRowIndexes]];
@@ -771,7 +785,7 @@ static void sleepCallBack(void * controller, io_service_t y,
[self checkWaitingForFinished: torrent]; [self checkWaitingForFinished: torrent];
//notifications //notifications
[self notifyGrowl: [torrent name]]; [self notifyGrowl: @"Download Complete" message: [torrent name] notification: @"Download Complete"];
if (![fWindow isKeyWindow]) if (![fWindow isKeyWindow])
fCompleted++; fCompleted++;
} }
@@ -1127,6 +1141,52 @@ static void sleepCallBack(void * controller, io_service_t y,
[fInfoController updateInfoStatsAndSettings]; [fInfoController updateInfoStatsAndSettings];
} }
- (void) checkAutoImportDirectory: (NSTimer *) timer
{
if (![fDefaults boolForKey: @"AutoImport"])
return;
NSString * path = [[fDefaults stringForKey: @"AutoImportDirectory"] stringByExpandingTildeInPath];
//if folder cannot be found simply give up
NSArray * allFileNames;
if (!(allFileNames = [[NSFileManager defaultManager] directoryContentsAtPath: path]))
return;
//try to add files that haven't already been added
NSMutableArray * newFileNames = [NSMutableArray arrayWithArray: allFileNames];
[newFileNames removeObjectsInArray: fAutoImportedNames];
//save the current list of files
[fAutoImportedNames release];
fAutoImportedNames = [allFileNames retain];
NSEnumerator * enumerator = [newFileNames objectEnumerator];
NSString * file;
unsigned oldCount;
while ((file = [enumerator nextObject]))
if ([[file pathExtension] caseInsensitiveCompare: @"torrent"] == NSOrderedSame)
{
NSString * fullPath = [path stringByAppendingPathComponent: file];
oldCount = [fTorrents count];
[self openFromSheet: [NSArray arrayWithObject: fullPath]];
//import only actually happened if the torrent array is larger
if (oldCount < [fTorrents count])
[self notifyGrowl: [file stringByAppendingString: @" Imported"] message: @"Torrent file imported"
notification: @"Import Performed"];
}
}
- (void) autoImportChange: (NSNotification *) notification
{
[fAutoImportedNames release];
fAutoImportedNames = [[NSArray alloc] init];
[self checkAutoImportDirectory: nil];
}
- (int) numberOfRowsInTableView: (NSTableView *) t - (int) numberOfRowsInTableView: (NSTableView *) t
{ {
return [fTorrents count]; return [fTorrents count];
@@ -1700,7 +1760,7 @@ static void sleepCallBack(void * controller, io_service_t y,
[[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString: FORUM_URL]]; [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString: FORUM_URL]];
} }
- (void) notifyGrowl: (NSString * ) file - (void) notifyGrowl: (NSString * ) title message: (NSString *) message notification: (NSString *) notification
{ {
if (!fHasGrowl) if (!fHasGrowl)
return; return;
@@ -1709,13 +1769,13 @@ static void sleepCallBack(void * controller, io_service_t y,
@"tell application \"System Events\"\n" @"tell application \"System Events\"\n"
" if exists application process \"GrowlHelperApp\" then\n" " if exists application process \"GrowlHelperApp\" then\n"
" tell application \"GrowlHelperApp\"\n " " tell application \"GrowlHelperApp\"\n "
" notify with name \"Download Complete\"" " notify with name \"%@\""
" title \"Download Complete\"" " title \"%@\""
" description \"%@\"" " description \"%@\""
" application name \"Transmission\"\n" " application name \"Transmission\"\n"
" end tell\n" " end tell\n"
" end if\n" " end if\n"
"end tell", file]; "end tell", notification, title, message];
NSAppleScript * appleScript = [[NSAppleScript alloc] initWithSource: growlScript]; NSAppleScript * appleScript = [[NSAppleScript alloc] initWithSource: growlScript];
NSDictionary * error; NSDictionary * error;
@@ -1729,17 +1789,16 @@ static void sleepCallBack(void * controller, io_service_t y,
if (!fHasGrowl) if (!fHasGrowl)
return; return;
NSString * growlScript = [NSString stringWithFormat: NSString * growlScript = @"tell application \"System Events\"\n"
@"tell application \"System Events\"\n"
" if exists application process \"GrowlHelperApp\" then\n" " if exists application process \"GrowlHelperApp\" then\n"
" tell application \"GrowlHelperApp\"\n" " tell application \"GrowlHelperApp\"\n"
" register as application \"Transmission\" " " register as application \"Transmission\" "
" all notifications {\"Download Complete\"}" " all notifications {\"Download Complete\", \"Import Performed\"}"
" default notifications {\"Download Complete\"}" " default notifications {\"Download Complete\", \"Import Performed\"}"
" icon of application \"Transmission\"\n" " icon of application \"Transmission\"\n"
" end tell\n" " end tell\n"
" end if\n" " end if\n"
"end tell"]; "end tell";
NSAppleScript * appleScript = [[NSAppleScript alloc] initWithSource: growlScript]; NSAppleScript * appleScript = [[NSAppleScript alloc] initWithSource: growlScript];
NSDictionary * error; NSDictionary * error;

View File

@@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>AutoImport</key>
<false/>
<key>AutoImportDirectory</key>
<string>~/Desktop</string>
<key>BadgeDownloadRate</key> <key>BadgeDownloadRate</key>
<false/> <false/>
<key>BadgeUploadRate</key> <key>BadgeUploadRate</key>

View File

@@ -5,6 +5,8 @@
{ {
ACTIONS = { ACTIONS = {
folderSheetShow = id; folderSheetShow = id;
importFolderSheetShow = id;
setAutoImport = id;
setBadge = id; setBadge = id;
setDownloadLocation = id; setDownloadLocation = id;
setLimit = id; setLimit = id;
@@ -22,6 +24,7 @@
CLASS = PrefsController; CLASS = PrefsController;
LANGUAGE = ObjC; LANGUAGE = ObjC;
OUTLETS = { OUTLETS = {
fAutoImportCheck = NSButton;
fBadgeDownloadRateCheck = NSButton; fBadgeDownloadRateCheck = NSButton;
fBadgeUploadRateCheck = NSButton; fBadgeUploadRateCheck = NSButton;
fBandwidthView = NSView; fBandwidthView = NSView;
@@ -31,6 +34,7 @@
fDownloadField = NSTextField; fDownloadField = NSTextField;
fFolderPopUp = NSPopUpButton; fFolderPopUp = NSPopUpButton;
fGeneralView = NSView; fGeneralView = NSView;
fImportFolderPopUp = NSPopUpButton;
fNetworkView = NSView; fNetworkView = NSView;
fPortField = NSTextField; fPortField = NSTextField;
fQuitCheck = NSButton; fQuitCheck = NSButton;

View File

@@ -9,18 +9,21 @@
<key>153</key> <key>153</key>
<string>275 334 554 217 0 0 1152 842 </string> <string>275 334 554 217 0 0 1152 842 </string>
<key>28</key> <key>28</key>
<string>299 451 554 254 0 0 1152 842 </string> <string>443 473 554 254 0 0 1440 878 </string>
<key>41</key> <key>41</key>
<string>299 429 554 297 0 0 1152 842 </string> <string>241 434 554 342 0 0 1440 878 </string>
<key>66</key> <key>66</key>
<string>299 526 554 104 0 0 1152 842 </string> <string>299 526 554 104 0 0 1152 842 </string>
</dict> </dict>
<key>IBFramework Version</key> <key>IBFramework Version</key>
<string>446.1</string> <string>446.1</string>
<<<<<<< .mine
=======
<key>IBOpenObjects</key> <key>IBOpenObjects</key>
<array> <array>
<integer>153</integer> <integer>153</integer>
</array> </array>
>>>>>>> .r537
<key>IBSystem Version</key> <key>IBSystem Version</key>
<string>8J135</string> <string>8J135</string>
</dict> </dict>

View File

@@ -33,11 +33,13 @@
NSToolbar * fToolbar; NSToolbar * fToolbar;
IBOutlet NSView * fGeneralView, * fTransfersView, * fBandwidthView, * fNetworkView; IBOutlet NSView * fGeneralView, * fTransfersView, * fBandwidthView, * fNetworkView;
IBOutlet NSPopUpButton * fFolderPopUp; IBOutlet NSPopUpButton * fFolderPopUp, * fImportFolderPopUp;
IBOutlet NSButton * fQuitCheck, * fRemoveCheck, IBOutlet NSButton * fQuitCheck, * fRemoveCheck,
* fQuitDownloadingCheck, * fRemoveDownloadingCheck, * fQuitDownloadingCheck, * fRemoveDownloadingCheck,
* fBadgeDownloadRateCheck, * fBadgeUploadRateCheck, * fBadgeDownloadRateCheck, * fBadgeUploadRateCheck,
* fCopyTorrentCheck, * fDeleteOriginalTorrentCheck; * fCopyTorrentCheck, * fDeleteOriginalTorrentCheck,
* fAutoImportCheck;
IBOutlet NSPopUpButton * fUpdatePopUp; IBOutlet NSPopUpButton * fUpdatePopUp;
IBOutlet NSTextField * fUploadField, * fDownloadField, IBOutlet NSTextField * fUploadField, * fDownloadField,
@@ -54,7 +56,7 @@
IBOutlet SUUpdater * fUpdater; IBOutlet SUUpdater * fUpdater;
NSString * fDownloadFolder; NSString * fDownloadFolder, * fImportFolder;
NSUserDefaults * fDefaults; NSUserDefaults * fDefaults;
} }
@@ -82,6 +84,9 @@
- (void) enableSpeedLimit: (BOOL) enable; - (void) enableSpeedLimit: (BOOL) enable;
- (void) setAutoImport: (id) sender;
- (void) importFolderSheetShow: (id) sender;
- (void) setRatio: (id) sender; - (void) setRatio: (id) sender;
- (void) setRatioCheck: (id) sender; - (void) setRatioCheck: (id) sender;
- (void) setRatioEnabled: (BOOL) enable; - (void) setRatioEnabled: (BOOL) enable;

View File

@@ -57,6 +57,9 @@
- (void) folderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info; - (void) folderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info;
- (void) updatePopUp; - (void) updatePopUp;
- (void) importFolderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info;
- (void) updateImportPopUp;
@end @end
@implementation PrefsController @implementation PrefsController
@@ -91,9 +94,7 @@
//set download folder //set download folder
NSString * downloadChoice = [fDefaults stringForKey: @"DownloadChoice"]; NSString * downloadChoice = [fDefaults stringForKey: @"DownloadChoice"];
fDownloadFolder = [[fDefaults stringForKey: @"DownloadFolder"] stringByExpandingTildeInPath]; fDownloadFolder = [[[fDefaults stringForKey: @"DownloadFolder"] stringByExpandingTildeInPath] retain];
[fDownloadFolder retain];
if ([downloadChoice isEqualToString: @"Constant"]) if ([downloadChoice isEqualToString: @"Constant"])
[fFolderPopUp selectItemAtIndex: DOWNLOAD_FOLDER]; [fFolderPopUp selectItemAtIndex: DOWNLOAD_FOLDER];
else if ([downloadChoice isEqualToString: @"Torrent"]) else if ([downloadChoice isEqualToString: @"Torrent"])
@@ -101,7 +102,15 @@
else else
[fFolderPopUp selectItemAtIndex: DOWNLOAD_ASK]; [fFolderPopUp selectItemAtIndex: DOWNLOAD_ASK];
[self updatePopUp]; [self updatePopUp];
//set auto import
fImportFolder = [[[fDefaults stringForKey: @"AutoImportDirectory"] stringByExpandingTildeInPath] retain];
[self updateImportPopUp];
BOOL autoImport = [fDefaults boolForKey: @"AutoImport"];
[fAutoImportCheck setState: autoImport];
[fImportFolderPopUp setEnabled: autoImport];
//set bind port //set bind port
int bindPort = [fDefaults integerForKey: @"BindPort"]; int bindPort = [fDefaults integerForKey: @"BindPort"];
[fPortField setIntValue: bindPort]; [fPortField setIntValue: bindPort];
@@ -597,8 +606,31 @@
[panel beginSheetForDirectory: nil file: nil types: nil [panel beginSheetForDirectory: nil file: nil types: nil
modalForWindow: [self window] modalDelegate: self didEndSelector: modalForWindow: [self window] modalDelegate: self didEndSelector:
@selector( folderSheetClosed:returnCode:contextInfo: ) @selector(folderSheetClosed:returnCode:contextInfo:) contextInfo: nil];
contextInfo: nil]; }
- (void) setAutoImport: (id) sender
{
int state = [fAutoImportCheck state];
[fDefaults setBool: state forKey: @"AutoImport"];
[fImportFolderPopUp setEnabled: state];
[[NSNotificationCenter defaultCenter] postNotificationName: @"AutoImportSettingChange" object: self];
}
- (void) importFolderSheetShow: (id) sender
{
NSOpenPanel * panel = [NSOpenPanel openPanel];
[panel setPrompt: @"Select"];
[panel setAllowsMultipleSelection: NO];
[panel setCanChooseFiles: NO];
[panel setCanChooseDirectories: YES];
[panel setCanCreateDirectories: YES];
[panel beginSheetForDirectory: nil file: nil types: nil
modalForWindow: [self window] modalDelegate: self didEndSelector:
@selector(importFolderSheetClosed:returnCode:contextInfo:) contextInfo: nil];
} }
- (void) windowWillClose: (NSNotification *) notification - (void) windowWillClose: (NSNotification *) notification
@@ -652,8 +684,7 @@
if (code == NSOKButton) if (code == NSOKButton)
{ {
[fDownloadFolder release]; [fDownloadFolder release];
fDownloadFolder = [[openPanel filenames] objectAtIndex: 0]; fDownloadFolder = [[[openPanel filenames] objectAtIndex: 0] retain];
[fDownloadFolder retain];
[fFolderPopUp selectItemAtIndex: DOWNLOAD_FOLDER]; [fFolderPopUp selectItemAtIndex: DOWNLOAD_FOLDER];
[fDefaults setObject: fDownloadFolder forKey: @"DownloadFolder"]; [fDefaults setObject: fDownloadFolder forKey: @"DownloadFolder"];
@@ -687,4 +718,33 @@
[menuItem setImage: icon]; [menuItem setImage: icon];
} }
- (void) importFolderSheetClosed: (NSOpenPanel *) openPanel returnCode: (int) code contextInfo: (void *) info
{
if (code == NSOKButton)
{
[fImportFolder release];
fImportFolder = [[[openPanel filenames] objectAtIndex: 0] retain];
[fDefaults setObject: fImportFolder forKey: @"AutoImportDirectory"];
[self updateImportPopUp];
[[NSNotificationCenter defaultCenter] postNotificationName: @"AutoImportSettingChange" object: self];
}
[fImportFolderPopUp selectItemAtIndex: 0];
}
- (void) updateImportPopUp
{
//get and resize the icon
NSImage * icon = [[NSWorkspace sharedWorkspace] iconForFile: fImportFolder];
[icon setScalesWhenResized: YES];
[icon setSize: NSMakeSize(16.0, 16.0)];
//update menu item
NSMenuItem * menuItem = (NSMenuItem *) [fImportFolderPopUp itemAtIndex: 0];
[menuItem setTitle: [fImportFolder lastPathComponent]];
[menuItem setImage: icon];
}
@end @end