« Previous entry | Next entry » Browse > Snippets

Skip to comments (2) A Cocoa class to ease iPod management
Posted by l0ne on Oct 18 2005 @ 08:54  :: 3148 unique visits

Free for everyone to use. May need tweaking (and will surely need to update its family detection) once somebody gets his hands on a video iPod this week.

L0iPod.h:

CODE: OTHER
//  L0iPod.h

#import <Cocoa/Cocoa.h>
#import <Carbon/Carbon.h>

typedef enum {
    // internal, unused
    kL0iPodUnchecked = -1,

    // cannot determine the iPod type.
    kL0iPodGeneric = 0,

    // iPod, first or second generation
    kL0iPodMechanicalOrTouchWheel = 1,

    // iPod, third generation
    kL0iPodTouchWheelAndButtons = 2,

    // iPod mini (either first or second gen.)
    kL0iPodMini = 3,

    // iPod, fourth generation
    kL0iPodClickWheel = 4,

    // iPod photo or iPod with color display
    kL0iPodColorDisplay = 5,

    // iPod, fifth generation
    kL0iPodVideo = 6,        // may change

    // iPod nano
    kL0iPodNano = 7,

    // iPod shuffle
    kL0iPodShuffle = 128
} L0iPodFamily;

@interface L0iPod : NSObject {
    FSRef iPodRef;
    L0iPodFamily family;
}

// If the given path is inside an iPod, returns the absolute
// path to that iPod's mount point. Otherwise, returns nil.
+ (NSString*) deviceRootForPath:(NSString*) path;

// Is the given path an iPod mount point?
+ (BOOL) hasControlFolder:(NSString*) path;

// Returns the mount points of all mounted iPods.
+ (NSArray*) allMountedDevices;

// Initializes a L0iPod object that refers to the iPod that
// contains the given path. Returns the new object or nil if
// the path is not inside an iPod.
- (id) initWithPath:(NSString*) path;

// The file:// URL to the iPod mount point.
// Always returns the right URL, even if it has changed since
// you created this object. Returns nil if iPod was unmounted.
- (NSURL*) fileURL;

// The absolute path to the iPod mount point.
// Always returns the right path, even if it has changed since
// you created this object. Returns nil if iPod was unmounted.
- (NSString*) path;

// Returns the iPod's icon at a size of 32x32, as currently
// displayed by the Finder.
- (NSImage*) icon;

// Returns a dictionary containing the keys and values of the
// iPod's SysInfo file.
- (NSDictionary*) deviceInformation;

// Returns the iPod's family (one of the L0iPodFamily constants
// above).
- (L0iPodFamily) family;

// Does this iPod have a display?
- (BOOL) hasDisplay;

// Does this iPod have a color display?
- (BOOL) hasColorDisplay;

// Does this iPod have the Extras > Notes submenu?
- (BOOL) hasNotes;

// Can this iPod be connected to a TV (for photo or video
// viewing)?
- (BOOL) hasTVOut;

// Can this iPod play back video?
- (BOOL) hasVideoPlayback;

// Does this iPod have photo display capabilities?
- (BOOL) hasPhotoAlbum;

// The iPod's display name, as shown by the Finder, or
// nil if the iPod was unmounted.
- (NSString*) displayName;

@end


L0iPod.m:

CODE: OTHER
//
//  L0iPod.m

#import "L0iPod.h"

@implementation L0iPod

+ (NSString*) deviceRootForPath:(NSString*) path {
    NSArray* arr = [[NSWorkspace sharedWorkspace] mountedRemovableMedia];
    NSEnumerator* enu = [arr objectEnumerator];
    NSString* root;

    while (root = [enu nextObject]) {
        if ([path hasPrefix:root] && [self hasControlFolder:root])
            return root;
    }

    return nil;
}

+ (BOOL) hasControlFolder:(NSString*) path {
    BOOL isDir;
    return [[NSFileManager defaultManager] fileExistsAtPath:[path stringByAppendingPathComponent:@"iPod_Control"] isDirectory:&isDir] && isDir;
}

+ (NSArray*) allMountedDevices {
    NSArray* arr = [[NSWorkspace sharedWorkspace] mountedRemovableMedia];
    NSEnumerator* enu = [arr objectEnumerator];
    NSMutableArray* ipods = [NSMutableArray arrayWithCapacity:[arr count]];

    NSString* path;
    while (path = [enu nextObject]) {
        if ([self hasControlFolder:path])
            [ipods addObject:[[self alloc] initWithPath:path]];
    }

    return [NSArray arrayWithArray:ipods];
}

- (id) initWithPath:(NSString*) path {
    if (self = [super init]) {
        NSString* ipodRoot = [[self class] deviceRootForPath:path];
        if (!ipodRoot) {
            [self release];
            return nil;
        }

        CFURLGetFSRef((CFURLRef)[NSURL fileURLWithPath:ipodRoot], &iPodRef);

        family = kL0iPodUnchecked;
    }

    return self;
}

- (NSURL*) fileURL {
    NSURL* url = (NSURL*) CFURLCreateFromFSRef(NULL, &iPodRef);
    return [url autorelease];
}

- (NSString*) path {
    return [[self fileURL] path];
}

- (NSImage*) icon {
    NSString* path = [self path];
    return path == nil? nil : [[NSWorkspace sharedWorkspace] iconForFile:path];   
}

- (NSDictionary*) deviceInformation {
    NSString* ipod = [self path];
    if (!ipod)
        return nil;

    NSMutableDictionary* dict = [NSMutableDictionary dictionary];
    NSString* sysInfo = [NSString stringWithContentsOfFile:[ipod stringByAppendingPathComponent:@"iPod_Control/Device/SysInfo"]];
    NSScanner* scanner = [NSScanner scannerWithString:sysInfo];

    [scanner setCharactersToBeSkipped:[NSCharacterSet whitespaceCharacterSet]];

    while (![scanner isAtEnd]) {
        NSString* key = nil, * value = nil;
        [scanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@":n"] intoString:&key];

        if ([scanner scanString:@":" intoString:nil]) {
            [scanner scanUpToString:@"n" intoString:&value];
            [dict setObject:value forKey:key];
        }

        [scanner scanString:@"n" intoString:nil];
    }

    return [NSDictionary dictionaryWithDictionary:dict];
}

- (L0iPodFamily) family {
#define L0PVT_familyInfoEquals(buildid, visid) ([buildID hasPrefix:(buildid)] && [visibleID hasPrefix:(visid)])

    if (family != kL0iPodUnchecked)
        return family;

    NSDictionary* info = [self deviceInformation];
    NSString* buildID = [info objectForKey:@"buildID"];
    NSString* visibleID = [info objectForKey:@"visibleBuildID"];

    if (L0PVT_familyInfoEquals(@"0x01508000", @"0x01508000")) {
        // mechanical/touch wheel (first & second generation)
        family =  kL0iPodMechanicalOrTouchWheel;
    } else if (L0PVT_familyInfoEquals(@"0x02308000", @"0x02308000")) {
        // touch wheel & buttons (third generation)
        family = kL0iPodTouchWheelAndButtons;
    } else if (L0PVT_familyInfoEquals(@"0x02608000", @"0x01408000")) {
        // iPod mini
        family = kL0iPodMini;
    } else if (L0PVT_familyInfoEquals(@"0x03108000",@"0x03108000")) {
        // click wheel (fourth generation)
        family = kL0iPodClickWheel;
    } else if (L0PVT_familyInfoEquals(@"0x04208000",@"0x01208000")) {
        // iPod with color display (includes iPod photo)
        family = kL0iPodColorDisplay;
    } else if (L0PVT_familyInfoEquals(@"0x05008000",@"0x01008000")) {
        // iPod nano
        family = kL0iPodNano;       
    } else if (L0PVT_familyInfoEquals(@"0x01128000",@"0x01128000")) {
        // iPod shuffle
        family = kL0iPodShuffle;
    } else {
        // Unrecognized iPod
        family = kL0iPodGeneric;
    }

    return family;

#undef L0PVT_familyInfoEquals
}

- (BOOL) hasDisplay {
    return [self family] != kL0iPodShuffle;
}

- (BOOL) hasColorDisplay {
    L0iPodFamily fam = [self family];
    return fam == kL0iPodColorDisplay || fam == kL0iPodNano || fam == kL0iPodVideo;
}

- (BOOL) hasNotes {
    L0iPodFamily fam = [self family];
    return fam != kL0iPodMechanicalOrTouchWheel && fam != kL0iPodShuffle;
}

- (BOOL) hasTVOut {
    L0iPodFamily fam = [self family];
    return fam == kL0iPodColorDisplay || fam == kL0iPodVideo;
}

- (BOOL) hasVideoPlayback {
    return [self family] == kL0iPodVideo;
}

- (BOOL) hasPhotoAlbum {
    return [self hasColorDisplay];
}

- (NSString*) displayName {
    NSString* path = [self path];
    return path? [[NSFileManager defaultManager] displayNameAtPath:path] : nil;
}

@end

2 comments posted so far
Add your own »

1. On Jun 06 2006 @ 16:31 mahdmahd wrote:

it is too nice

Add a new comment

Name:
Password: (leave empty for anonymous comment)
 
View formatting tags Comment: